Removed PST <br> conversion, unnecessary, was annoying people
[mediawiki.git] / includes / Skin.php
blobca7aed5a0fcc3cce6b9fdf0cd6ebe42b4273714c
1 <?php
3 require_once( "Feed.php" );
4 require_once( "Image.php" );
6 # See skin.doc
8 # These are the INTERNAL names, which get mapped
9 # directly to class names. For display purposes, the
10 # Language class has internationalized names
12 /* private */ $wgValidSkinNames = array(
13 'standard' => "Standard",
14 'nostalgia' => "Nostalgia",
15 'cologneblue' => "CologneBlue"
17 if( $wgUsePHPTal ) {
18 #$wgValidSkinNames[] = "PHPTal";
19 #$wgValidSkinNames['davinci'] = "DaVinci";
20 #$wgValidSkinNames['mono'] = "Mono";
21 $wgValidSkinNames['monobook'] = "MonoBook";
22 #$wgValidSkinNames['monobookminimal'] = "MonoBookMinimal";
25 require_once( "RecentChange.php" );
27 class RCCacheEntry extends RecentChange
29 var $secureName, $link;
30 var $curlink , $lastlink , $usertalklink , $versionlink ;
31 var $userlink, $timestamp, $watched;
33 function newFromParent( $rc )
35 $rc2 = new RCCacheEntry;
36 $rc2->mAttribs = $rc->mAttribs;
37 $rc2->mExtra = $rc->mExtra;
38 return $rc2;
40 } ;
42 class Skin {
44 /* private */ var $lastdate, $lastline;
45 var $linktrail ; # linktrail regexp
46 var $rc_cache ; # Cache for Enhanced Recent Changes
47 var $rcCacheIndex ; # Recent Changes Cache Counter for visibility toggle
48 var $rcMoveIndex;
50 function Skin()
52 $this->linktrail = wfMsg("linktrail");
55 function getSkinNames()
57 global $wgValidSkinNames;
58 return $wgValidSkinNames;
61 function getStylesheet()
63 return "wikistandard.css";
66 function qbSetting()
68 global $wgOut, $wgUser;
70 if ( $wgOut->isQuickbarSuppressed() ) { return 0; }
71 $q = $wgUser->getOption( "quickbar" );
72 if ( "" == $q ) { $q = 0; }
73 return $q;
76 function initPage( &$out )
78 $fname = "Skin::initPage";
79 wfProfileIn( $fname );
81 $out->addLink( array( "rel" => "shortcut icon", "href" => "/favicon.ico" ) );
83 $this->addMetadataLinks($out);
85 wfProfileOut( $fname );
88 function addMetadataLinks( &$out ) {
89 global $wgTitle, $wgEnableDublinCoreRdf, $wgEnableCreativeCommonsRdf, $wgRdfMimeType, $action;
90 global $wgRightsPage, $wgRightsUrl;
92 if( $out->isArticleRelated() ) {
93 # note: buggy CC software only reads first "meta" link
94 if( $wgEnableCreativeCommonsRdf ) {
95 $out->addMetadataLink( array(
96 'title' => 'Creative Commons',
97 'type' => 'application/rdf+xml',
98 'href' => $wgTitle->getLocalURL( "action=creativecommons") ) );
100 if( $wgEnableDublinCoreRdf ) {
101 $out->addMetadataLink( array(
102 'title' => 'Dublin Core',
103 'type' => 'application/rdf+xml',
104 'href' => $wgTitle->getLocalURL( "action=dublincore" ) ) );
107 $copyright = "";
108 if( $wgRightsPage ) {
109 $copy = Title::newFromText( $wgRightsPage );
110 if( $copy ) {
111 $copyright = $copy->getLocalURL();
114 if( !$copyright && $wgRightsUrl ) {
115 $copyright = $wgRightsUrl;
117 if( $copyright ) {
118 $out->addLink( array(
119 "rel" => "copyright",
120 "href" => $copyright ) );
124 function outputPage( &$out ) {
125 global $wgDebugComments;
127 wfProfileIn( "Skin::outputPage" );
128 $this->initPage( $out );
129 $out->out( $out->headElement() );
131 $out->out( "\n<body" );
132 $ops = $this->getBodyOptions();
133 foreach ( $ops as $name => $val ) {
134 $out->out( " $name='$val'" );
136 $out->out( ">\n" );
137 if ( $wgDebugComments ) {
138 $out->out( "<!-- Wiki debugging output:\n" .
139 $out->mDebugtext . "-->\n" );
141 $out->out( $this->beforeContent() );
143 $out->out( $out->mBodytext . "\n" );
145 $out->out( $this->afterContent() );
147 wfProfileClose();
148 $out->out( $out->reportTime() );
150 $out->out( "\n</body></html>" );
153 function getHeadScripts() {
154 global $wgStylePath;
155 $r = "<script type=\"text/javascript\" src=\"{$wgStylePath}/wikibits.js\"></script>\n";
156 return $r;
159 function getUserStyles()
161 global $wgOut, $wgStylePath, $wgLang;
162 $sheet = $this->getStylesheet();
163 $s = "<style type='text/css'>\n";
164 $s .= "/*/*/\n"; # <-- Hide the styles from Netscape 4 without hiding them from IE/Mac
165 $s .= "@import url(\"$wgStylePath/$sheet\");\n";
166 if($wgLang->isRTL()) $s .= "@import url(\"$wgStylePath/common_rtl.css\");\n";
167 $s .= $this->doGetUserStyles();
168 $s .= "/* */\n";
169 $s .= "</style>\n";
170 return $s;
173 function doGetUserStyles()
175 global $wgUser;
177 $s = "";
178 if ( 1 == $wgUser->getOption( "underline" ) ) {
179 # Don't override browser settings
180 } else {
181 # CHECK MERGE @@@
182 # Force no underline
183 $s .= "a { " .
184 "text-decoration: none; }\n";
186 if ( 1 == $wgUser->getOption( "highlightbroken" ) ) {
187 $s .= "a.new, #quickbar a.new { color: #CC2200; }\n";
189 if ( 1 == $wgUser->getOption( "justify" ) ) {
190 $s .= "#article { text-align: justify; }\n";
192 return $s;
195 function getBodyOptions()
197 global $wgUser, $wgTitle, $wgNamespaceBackgrounds, $wgOut, $wgRequest;
199 extract( $wgRequest->getValues( 'oldid', 'redirect', 'diff' ) );
201 if ( 0 != $wgTitle->getNamespace() ) {
202 $a = array( "bgcolor" => "#ffffec" );
204 else $a = array( "bgcolor" => "#FFFFFF" );
205 if($wgOut->isArticle() && $wgUser->getOption("editondblclick") &&
206 (!$wgTitle->isProtected() || $wgUser->isSysop()) ) {
207 $t = wfMsg( "editthispage" );
208 $oid = $red = "";
209 if ( !empty($redirect) ) {
210 $red = "&redirect={$redirect}";
212 if ( !empty($oldid) && ! isset( $diff ) ) {
213 $oid = "&oldid={$oldid}";
215 $s = $wgTitle->getFullURL( "action=edit{$oid}{$red}" );
216 $s = "document.location = \"" .$s ."\";";
217 $a += array ("ondblclick" => $s);
220 $a['onload'] = $wgOut->getOnloadHandler();
221 return $a;
224 function getExternalLinkAttributes( $link, $text )
226 global $wgUser, $wgOut, $wgLang;
228 $link = urldecode( $link );
229 $link = $wgLang->checkTitleEncoding( $link );
230 $link = str_replace( "_", " ", $link );
231 $link = wfEscapeHTML( $link );
233 $r = " class='external'";
235 if ( 1 == $wgUser->getOption( "hover" ) ) {
236 $r .= " title=\"{$link}\"";
238 return $r;
241 function getInternalLinkAttributes( $link, $text, $broken = false )
243 global $wgUser, $wgOut;
245 $link = urldecode( $link );
246 $link = str_replace( "_", " ", $link );
247 $link = wfEscapeHTML( $link );
249 if ( $broken == "stub" ) {
250 $r = " class='stub'";
251 } else if ( $broken == "yes" ) {
252 $r = " class='new'";
253 } else {
254 $r = "";
257 if ( 1 == $wgUser->getOption( "hover" ) ) {
258 $r .= " title=\"{$link}\"";
260 return $r;
263 function getInternalLinkAttributesObj( &$nt, $text, $broken = false )
265 global $wgUser, $wgOut;
267 if ( $broken == "stub" ) {
268 $r = " class='stub'";
269 } else if ( $broken == "yes" ) {
270 $r = " class='new'";
271 } else {
272 $r = "";
275 if ( 1 == $wgUser->getOption( "hover" ) ) {
276 $r .= ' title ="' . $nt->getEscapedText() . '"';
278 return $r;
281 function getLogo()
283 global $wgLogo;
284 return $wgLogo;
287 # This will be called immediately after the <body> tag. Split into
288 # two functions to make it easier to subclass.
290 function beforeContent()
292 global $wgUser, $wgOut, $wgSiteNotice;
294 if( $wgSiteNotice ) {
295 $note = "\n<div id='notice' style='font-weight: bold; color: red; text-align: center'>$wgSiteNotice</div>\n";
296 } else {
297 $note = "";
299 return $this->doBeforeContent() . $note;
302 function doBeforeContent()
304 global $wgUser, $wgOut, $wgTitle, $wgLang;
305 $fname = "Skin::doBeforeContent";
306 wfProfileIn( $fname );
308 $s = "";
309 $qb = $this->qbSetting();
311 if( $langlinks = $this->otherLanguages() ) {
312 $rows = 2;
313 $borderhack = "";
314 } else {
315 $rows = 1;
316 $langlinks = false;
317 $borderhack = "class='top'";
320 $s .= "\n<div id='content'>\n<div id='topbar'>\n" .
321 "<table border='0' cellspacing='0' width='98%'>\n<tr>\n";
323 $shove = ($qb != 0);
324 $left = ($qb == 1 || $qb == 3);
325 if($wgLang->isRTL()) $left = !$left;
327 if ( !$shove ) {
328 $s .= "<td class='top' align='left' valign='top' rowspan='{$rows}'>\n" .
329 $this->logoText() . "</td>";
330 } elseif( $left ) {
331 $s .= $this->getQuickbarCompensator( $rows );
333 $l = $wgLang->isRTL() ? "right" : "left";
334 $s .= "<td {$borderhack} align='$l' valign='top'>\n";
336 $s .= $this->topLinks() ;
337 $s .= "<p class='subtitle'>" . $this->pageTitleLinks() . "</p>\n";
339 $r = $wgLang->isRTL() ? "left" : "right";
340 $s .= "</td>\n<td {$borderhack} valign='top' align='$r' nowrap='nowrap'>";
341 $s .= $this->nameAndLogin();
342 $s .= "\n<br />" . $this->searchForm() . "</td>";
344 if ( $langlinks ) {
345 $s .= "</tr>\n<tr>\n<td class='top' colspan=\"2\">$langlinks</td>\n";
348 if ( $shove && !$left ) { # Right
349 $s .= $this->getQuickbarCompensator( $rows );
351 $s .= "</tr>\n</table>\n</div>\n";
352 $s .= "\n<div id='article'>\n";
354 $s .= $this->pageTitle();
355 $s .= $this->pageSubtitle() ;
356 $s .= $this->getCategories();
357 wfProfileOut( $fname );
358 return $s;
361 function getCategories () {
362 global $wgOut, $wgTitle, $wgUser, $wgParser;
363 global $wgUseCategoryMagic;
364 if( !$wgUseCategoryMagic ) return "" ;
365 if( count( $wgOut->mCategoryLinks ) == 0 ) return "";
366 if( !$wgOut->isArticle() ) return "";
368 $t = implode ( " | " , $wgOut->mCategoryLinks ) ;
369 $s = $this->makeKnownLink( "Special:Categories",
370 wfMsg( "categories" ), "article=" . urlencode( $wgTitle->getPrefixedDBkey() ) )
371 . ": " . $t;
372 return "<p class='catlinks'>$s</p>";
375 function getQuickbarCompensator( $rows = 1 )
377 return "<td width='152' rowspan='{$rows}'>&nbsp;</td>";
380 # This gets called immediately before the </body> tag.
382 function afterContent()
384 global $wgUser, $wgOut, $wgServer;
385 global $wgTitle, $wgLang;
387 $printfooter = "<div class=\"printfooter\">\n" . $this->printFooter() . "</div>\n";
388 return $printfooter . $this->doAfterContent();
391 function printFooter() {
392 global $wgTitle;
393 $url = htmlspecialchars( $wgTitle->getFullURL() );
394 return "<p>" . wfMsg( "retrievedfrom", "<a href=\"$url\">$url</a>" ) .
395 "</p>\n\n<p>" . $this->pageStats() . "</p>\n";
398 function doAfterContent()
400 global $wgUser, $wgOut, $wgLang;
401 $fname = "Skin::doAfterContent";
402 wfProfileIn( $fname );
403 wfProfileIn( "$fname-1" );
405 $s = "\n</div><br style=\"clear:both\" />\n";
406 $s .= "\n<div id='footer'>";
407 $s .= "<table border='0' cellspacing='0'><tr>";
409 wfProfileOut( "$fname-1" );
410 wfProfileIn( "$fname-2" );
412 $qb = $this->qbSetting();
413 $shove = ($qb != 0);
414 $left = ($qb == 1 || $qb == 3);
415 if($wgLang->isRTL()) $left = !$left;
417 if ( $shove && $left ) { # Left
418 $s .= $this->getQuickbarCompensator();
420 wfProfileOut( "$fname-2" );
421 wfProfileIn( "$fname-3" );
422 $l = $wgLang->isRTL() ? "right" : "left";
423 $s .= "<td class='bottom' align='$l' valign='top'>";
425 $s .= $this->bottomLinks();
426 $s .= "\n<br />" . $this->mainPageLink()
427 . " | " . $this->aboutLink()
428 . " | " . $this->specialLink( "recentchanges" )
429 . " | " . $this->searchForm()
430 . "<br /><span id='pagestats'>" . $this->pageStats() . "</span>";
432 $s .= "</td>";
433 if ( $shove && !$left ) { # Right
434 $s .= $this->getQuickbarCompensator();
436 $s .= "</tr></table>\n</div>\n</div>\n";
438 wfProfileOut( "$fname-3" );
439 wfProfileIn( "$fname-4" );
440 if ( 0 != $qb ) { $s .= $this->quickBar(); }
441 wfProfileOut( "$fname-4" );
442 wfProfileOut( $fname );
443 return $s;
446 function pageTitleLinks()
448 global $wgOut, $wgTitle, $wgUser, $wgLang, $wgUseApproval, $wgRequest;
450 extract( $wgRequest->getValues( 'oldid', 'diff' ) );
451 $action = $wgRequest->getText( 'action' );
453 $s = $this->printableLink();
454 if ( wfMsg ( "disclaimers" ) != "-" ) $s .= " | " . $this->makeKnownLink( wfMsg( "disclaimerpage" ), wfMsg( "disclaimers" ) ) ;
456 if ( $wgOut->isArticleRelated() ) {
457 if ( $wgTitle->getNamespace() == Namespace::getImage() ) {
458 $name = $wgTitle->getDBkey();
459 $link = wfEscapeHTML( Image::wfImageUrl( $name ) );
460 $style = $this->getInternalLinkAttributes( $link, $name );
461 $s .= " | <a href=\"{$link}\"{$style}>{$name}</a>";
463 # This will show the "Approve" link if $wgUseApproval=true;
464 if ( isset ( $wgUseApproval ) && $wgUseApproval )
466 $t = $wgTitle->getDBkey();
467 $name = "Approve this article" ;
468 $link = "http://test.wikipedia.org/w/magnus/wiki.phtml?title={$t}&action=submit&doit=1" ;
469 #wfEscapeHTML( wfImageUrl( $name ) );
470 $style = $this->getExternalLinkAttributes( $link, $name );
471 $s .= " | <a href=\"{$link}\"{$style}>{$name}</a>" ;
474 if ( "history" == $action || isset( $diff ) || isset( $oldid ) ) {
475 $s .= " | " . $this->makeKnownLink( $wgTitle->getPrefixedText(),
476 wfMsg( "currentrev" ) );
479 if ( $wgUser->getNewtalk() ) {
480 # do not show "You have new messages" text when we are viewing our
481 # own talk page
483 if(!(strcmp($wgTitle->getText(),$wgUser->getName()) == 0 &&
484 $wgTitle->getNamespace()==Namespace::getTalk(Namespace::getUser()))) {
485 $n =$wgUser->getName();
486 $tl = $this->makeKnownLink( $wgLang->getNsText(
487 Namespace::getTalk( Namespace::getUser() ) ) . ":{$n}",
488 wfMsg("newmessageslink") );
489 $s.=" | <strong>". wfMsg( "newmessages", $tl ) . "</strong>";
492 if( $wgUser->isSysop() &&
493 (($wgTitle->getArticleId() == 0) || ($action == "history")) &&
494 ($n = $wgTitle->isDeleted() ) ) {
495 $s .= " | " . wfMsg( "thisisdeleted",
496 $this->makeKnownLink(
497 $wgLang->SpecialPage( "Undelete/" . $wgTitle->getPrefixedDBkey() ),
498 wfMsg( "restorelink", $n ) ) );
500 return $s;
503 function printableLink()
505 global $wgOut, $wgFeedClasses, $wgRequest;
507 $baseurl = $_SERVER['REQUEST_URI'];
508 if( strpos( "?", $baseurl ) == false ) {
509 $baseurl .= "?";
510 } else {
511 $baseurl .= "&";
513 $baseurl = htmlspecialchars( $baseurl );
514 $printurl = $wgRequest->escapeAppendQuery( "printable=yes" );
516 $s = "<a href=\"$printurl\">" . wfMsg( "printableversion" ) . "</a>";
517 if( $wgOut->isSyndicated() ) {
518 foreach( $wgFeedClasses as $format => $class ) {
519 $feedurl = $wgRequest->escapeAppendQuery( "feed=$format" );
520 $s .= " | <a href=\"$feedurl\">{$format}</a>";
523 return $s;
526 function pageTitle()
528 global $wgOut, $wgTitle, $wgUser;
530 $s = "<h1 class='pagetitle'>" . htmlspecialchars( $wgOut->getPageTitle() ) . "</h1>";
531 if($wgUser->getOption("editsectiononrightclick") && $wgTitle->userCanEdit()) { $s=$this->editSectionScript(0,$s);}
532 return $s;
535 function pageSubtitle()
537 global $wgOut;
539 $sub = $wgOut->getSubtitle();
540 if ( "" == $sub ) {
541 global $wgExtraSubtitle;
542 $sub = wfMsg( "fromwikipedia" ) . $wgExtraSubtitle;
544 $subpages = $this->subPageSubtitle();
545 $sub .= !empty($subpages)?"</p><p class='subpages'>$subpages":'';
546 $s = "<p class='subtitle'>{$sub}</p>\n";
547 return $s;
550 function subPageSubtitle()
552 global $wgOut,$wgTitle,$wgNamespacesWithSubpages;
553 $subpages = '';
554 if($wgOut->isArticle() && !empty($wgNamespacesWithSubpages[$wgTitle->getNamespace()])) {
555 $ptext=$wgTitle->getPrefixedText();
556 if(preg_match("/\//",$ptext)) {
557 $links=explode("/",$ptext);
558 $c=0;
559 $growinglink="";
560 foreach($links as $link) {
561 $c++;
562 if ($c<count($links)) {
563 $growinglink .= $link;
564 $getlink = $this->makeLink( $growinglink, $link );
565 if(preg_match("/class='new'/i",$getlink)) { break; } # this is a hack, but it saves time
566 if ($c>1) {
567 $subpages .= " | ";
568 } else {
569 $subpages .="&lt; ";
571 $subpages .= $getlink;
572 $growinglink.="/";
577 return $subpages;
580 function nameAndLogin()
582 global $wgUser, $wgTitle, $wgLang, $wgShowIPinHeader, $wgIP;
584 $li = $wgLang->specialPage( "Userlogin" );
585 $lo = $wgLang->specialPage( "Userlogout" );
587 $s = "";
588 if ( 0 == $wgUser->getID() ) {
589 if( $wgShowIPinHeader && isset( $_COOKIE[ini_get("session.name")] ) ) {
590 $n = $wgIP;
592 $tl = $this->makeKnownLink( $wgLang->getNsText(
593 Namespace::getTalk( Namespace::getUser() ) ) . ":{$n}",
594 $wgLang->getNsText( Namespace::getTalk( 0 ) ) );
596 $s .= $n . " (".$tl.")";
597 } else {
598 $s .= wfMsg("notloggedin");
601 $rt = $wgTitle->getPrefixedURL();
602 if ( 0 == strcasecmp( urlencode( $lo ), $rt ) ) {
603 $q = "";
604 } else { $q = "returnto={$rt}"; }
606 $s .= "\n<br />" . $this->makeKnownLink( $li,
607 wfMsg( "login" ), $q );
608 } else {
609 $n = $wgUser->getName();
610 $rt = $wgTitle->getPrefixedURL();
611 $tl = $this->makeKnownLink( $wgLang->getNsText(
612 Namespace::getTalk( Namespace::getUser() ) ) . ":{$n}",
613 $wgLang->getNsText( Namespace::getTalk( 0 ) ) );
615 $tl = " ({$tl})";
617 $s .= $this->makeKnownLink( $wgLang->getNsText(
618 Namespace::getUser() ) . ":{$n}", $n ) . "{$tl}<br />" .
619 $this->makeKnownLink( $lo, wfMsg( "logout" ),
620 "returnto={$rt}" ) . " | " .
621 $this->specialLink( "preferences" );
623 $s .= " | " . $this->makeKnownLink( wfMsg( "helppage" ),
624 wfMsg( "help" ) );
626 return $s;
629 function getSearchLink() {
630 $searchPage =& Title::makeTitle( NS_SPECIAL, "Search" );
631 return $searchPage->getLocalURL();
634 function escapeSearchLink() {
635 return htmlspecialchars( $this->getSearchLink() );
638 function searchForm()
640 global $wgRequest;
641 $search = $wgRequest->getText( 'search' );
643 $s = "<form name='search' class='inline' method='post' action=\""
644 . $this->escapeSearchLink() . "\">\n"
645 . "<input type='text' name=\"search\" size='19' value=\""
646 . htmlspecialchars(substr($search,0,256)) . "\" />\n"
647 . "<input type='submit' name=\"go\" value=\"" . wfMsg ("go") . "\" />&nbsp;"
648 . "<input type='submit' name=\"fulltext\" value=\"" . wfMsg ("search") . "\" />\n</form>";
650 return $s;
653 function topLinks()
655 global $wgOut;
656 $sep = " |\n";
658 $s = $this->mainPageLink() . $sep
659 . $this->specialLink( "recentchanges" );
661 if ( $wgOut->isArticleRelated() ) {
662 $s .= $sep . $this->editThisPage()
663 . $sep . $this->historyLink();
665 # Many people don't like this dropdown box
666 #$s .= $sep . $this->specialPagesList();
668 return $s;
671 function bottomLinks()
673 global $wgOut, $wgUser, $wgTitle;
674 $sep = " |\n";
676 $s = "";
677 if ( $wgOut->isArticleRelated() ) {
678 $s .= "<strong>" . $this->editThisPage() . "</strong>";
679 if ( 0 != $wgUser->getID() ) {
680 $s .= $sep . $this->watchThisPage();
682 $s .= $sep . $this->talkLink()
683 . $sep . $this->historyLink()
684 . $sep . $this->whatLinksHere()
685 . $sep . $this->watchPageLinksLink();
687 if ( $wgTitle->getNamespace() == Namespace::getUser()
688 || $wgTitle->getNamespace() == Namespace::getTalk(Namespace::getUser()) )
691 $id=User::idFromName($wgTitle->getText());
692 $ip=User::isIP($wgTitle->getText());
694 if($id || $ip) { # both anons and non-anons have contri list
695 $s .= $sep . $this->userContribsLink();
697 if ( 0 != $wgUser->getID() ) { # show only to signed in users
698 if($id) { # can only email non-anons
699 $s .= $sep . $this->emailUserLink();
703 if ( $wgUser->isSysop() && $wgTitle->getArticleId() ) {
704 $s .= "\n<br />" . $this->deleteThisPage() .
705 $sep . $this->protectThisPage() .
706 $sep . $this->moveThisPage();
708 $s .= "<br />\n" . $this->otherLanguages();
710 return $s;
713 function pageStats()
715 global $wgOut, $wgLang, $wgArticle, $wgRequest;
716 global $wgDisableCounters;
718 extract( $wgRequest->getValues( 'oldid', 'diff' ) );
719 if ( ! $wgOut->isArticle() ) { return ""; }
720 if ( isset( $oldid ) || isset( $diff ) ) { return ""; }
721 if ( 0 == $wgArticle->getID() ) { return ""; }
723 $s = "";
724 if ( !$wgDisableCounters ) {
725 $count = $wgLang->formatNum( $wgArticle->getCount() );
726 if ( $count ) {
727 $s = wfMsg( "viewcount", $count );
731 $s .= " " . $this->getCredits();
733 return $s . " " . $this->getCopyright();
736 function getCredits() {
737 global $wgMaxCredits;
739 $s = '';
741 if (!isset($wgMaxCredits) || $wgMaxCredits == 0) {
742 $s = $this->lastModified();
743 } else {
744 $s = $this->getAuthorCredits();
745 if ($wgMaxCredits > 1) {
746 $s .= " " . $this->getContributorCredits();
750 return $s;
753 function getAuthorCredits() {
754 global $wgLang, $wgArticle;
756 $last_author = $wgArticle->getUser();
758 if ($last_author == 0) {
759 $author_credit = wfMsg("anonymous");
760 } else {
761 $real_name = User::whoIsReal($last_author);
762 if (!empty($real_name)) {
763 $author_credit = $real_name;
764 } else {
765 $author_credit = wfMsg("siteuser", User::whoIs($last_author));
769 $timestamp = $wgArticle->getTimestamp();
770 if ( $timestamp ) {
771 $d = $wgLang->timeanddate( $wgArticle->getTimestamp(), true );
772 } else {
773 $d = "";
775 return wfMsg("lastmodifiedby", $d, $author_credit);
778 function getContributorCredits() {
780 global $wgArticle, $wgMaxCredits, $wgLang;
782 # don't count last editor
784 $contributors = $wgArticle->getContributors($wgMaxCredits - 1);
786 $real_names = array();
787 $user_names = array();
789 # Sift for real versus user names
791 foreach ($contributors as $user_id => $user_parts) {
792 if ($user_id != 0) {
793 if (!empty($user_parts[1])) {
794 $real_names[$user_id] = $user_parts[1];
795 } else {
796 $user_names[$user_id] = $user_parts[0];
801 $real = $wgLang->listToText(array_values($real_names));
802 $user = $wgLang->listToText(array_values($user_names));
804 if (!empty($user)) {
805 $user = wfMsg("siteusers", $user);
808 if ($contributors[0] && $contributors[0][0] > 0) {
809 $anon = wfMsg("anonymous");
810 } else {
811 $anon = '';
814 $creds = $wgLang->listToText(array($real, $user, $anon));
816 return wfMsg("othercontribs", $creds);
819 function getCopyright() {
820 global $wgRightsPage, $wgRightsUrl, $wgRightsText;
821 $out = "";
822 if( $wgRightsPage ) {
823 $link = $this->makeKnownLink( $wgRightsPage, $wgRightsText );
824 } elseif( $wgRightsUrl ) {
825 $link = $this->makeExternalLink( $wgRightsUrl, $wgRightsText );
826 } else {
827 # Give up now
828 return $out;
830 $out .= wfMsg( "copyright", $link );
831 return $out;
834 function getCopyrightIcon() {
835 global $wgRightsPage, $wgRightsUrl, $wgRightsText, $wgRightsIcon;
836 $out = "";
837 if( $wgRightsIcon ) {
838 $icon = htmlspecialchars( $wgRightsIcon );
839 if( $wgRightsUrl ) {
840 $url = htmlspecialchars( $wgRightsUrl );
841 $out .= "<a href=\"$url\">";
843 $text = htmlspecialchars( $wgRightsText );
844 $out .= "<img src=\"$icon\" alt='$text' />";
845 if( $wgRightsUrl ) {
846 $out .= "</a>";
849 return $out;
852 function getPoweredBy() {
853 global $wgStylePath;
854 $url = htmlspecialchars( "$wgStylePath/images/poweredby_mediawiki_88x31.png" );
855 $img = "<a href='http://www.mediawiki.org/'><img src='$url' alt='MediaWiki' /></a>";
856 return $img;
859 function lastModified()
861 global $wgLang, $wgArticle;
863 $timestamp = $wgArticle->getTimestamp();
864 if ( $timestamp ) {
865 $d = $wgLang->timeanddate( $wgArticle->getTimestamp(), true );
866 $s = " " . wfMsg( "lastmodified", $d );
867 } else {
868 $s = "";
870 return $s;
873 function logoText( $align = "" )
875 if ( "" != $align ) { $a = " align='{$align}'"; }
876 else { $a = ""; }
878 $mp = wfMsg( "mainpage" );
879 $titleObj = Title::newFromText( $mp );
880 $s = "<a href=\"" . $titleObj->escapeLocalURL()
881 . "\"><img{$a} src=\""
882 . $this->getLogo() . "\" alt=\"" . "[{$mp}]\" /></a>";
883 return $s;
886 function quickBar()
888 global $wgOut, $wgTitle, $wgUser, $wgRequest, $wgLang;
889 global $wgDisableUploads, $wgRemoteUploads;
891 $fname = "Skin::quickBar";
892 wfProfileIn( $fname );
894 $action = $wgRequest->getText( 'action' );
895 $wpPreview = $wgRequest->getBool( 'wpPreview' );
896 $tns=$wgTitle->getNamespace();
898 $s = "\n<div id='quickbar'>";
899 $s .= "\n" . $this->logoText() . "\n<hr class='sep' />";
901 $sep = "\n<br />";
902 $s .= $this->mainPageLink()
903 . $sep . $this->specialLink( "recentchanges" )
904 . $sep . $this->specialLink( "randompage" );
905 if ($wgUser->getID()) {
906 $s.= $sep . $this->specialLink( "watchlist" ) ;
907 $s .= $sep .$this->makeKnownLink( $wgLang->specialPage( "Contributions" ),
908 wfMsg( "mycontris" ), "target=" . wfUrlencode($wgUser->getName() ) );
911 // only show watchlist link if logged in
912 if ( wfMsg ( "currentevents" ) != "-" ) $s .= $sep . $this->makeKnownLink( wfMsg( "currentevents" ), "" ) ;
913 $s .= "\n<br /><hr class='sep' />";
914 $articleExists = $wgTitle->getArticleId();
915 if ( $wgOut->isArticle() || $action =="edit" || $action =="history" || $wpPreview) {
916 if($wgOut->isArticle()) {
917 $s .= "<strong>" . $this->editThisPage() . "</strong>";
918 } else { # backlink to the article in edit or history mode
919 if($articleExists){ # no backlink if no article
920 switch($tns) {
921 case 0:
922 $text = wfMsg("articlepage");
923 break;
924 case 1:
925 $text = wfMsg("viewtalkpage");
926 break;
927 case 2:
928 $text = wfMsg("userpage");
929 break;
930 case 3:
931 $text = wfMsg("viewtalkpage");
932 break;
933 case 4:
934 $text = wfMsg("wikipediapage");
935 break;
936 case 5:
937 $text = wfMsg("viewtalkpage");
938 break;
939 case 6:
940 $text = wfMsg("imagepage");
941 break;
942 case 7:
943 $text = wfMsg("viewtalkpage");
944 break;
945 default:
946 $text= wfMsg("articlepage");
949 $link = $wgTitle->getText();
950 if ($nstext = $wgLang->getNsText($tns) ) { # add namespace if necessary
951 $link = $nstext . ":" . $link ;
954 $s .= $this->makeLink( $link, $text );
955 } elseif( $wgTitle->getNamespace() != Namespace::getSpecial() ) {
956 # we just throw in a "New page" text to tell the user that he's in edit mode,
957 # and to avoid messing with the separator that is prepended to the next item
958 $s .= "<strong>" . wfMsg("newpage") . "</strong>";
964 if( $tns%2 && $action!="edit" && !$wpPreview) {
965 $s.="<br />".$this->makeKnownLink($wgTitle->getPrefixedText(),wfMsg("postcomment"),"action=edit&section=new");
969 watching could cause problems in edit mode:
970 if user edits article, then loads "watch this article" in background and then saves
971 article with "Watch this article" checkbox disabled, the article is transparently
972 unwatched. Therefore we do not show the "Watch this page" link in edit mode
974 if ( 0 != $wgUser->getID() && $articleExists) {
975 if($action!="edit" && $action != "submit" )
977 $s .= $sep . $this->watchThisPage();
979 if ( $wgTitle->userCanEdit() )
980 $s .= $sep . $this->moveThisPage();
982 if ( $wgUser->isSysop() and $articleExists ) {
983 $s .= $sep . $this->deleteThisPage() .
984 $sep . $this->protectThisPage();
986 $s .= $sep . $this->talkLink();
987 if ($articleExists && $action !="history") {
988 $s .= $sep . $this->historyLink();
990 $s.=$sep . $this->whatLinksHere();
992 if($wgOut->isArticleRelated()) {
993 $s .= $sep . $this->watchPageLinksLink();
996 if ( Namespace::getUser() == $wgTitle->getNamespace()
997 || $wgTitle->getNamespace() == Namespace::getTalk(Namespace::getUser())
1000 $id=User::idFromName($wgTitle->getText());
1001 $ip=User::isIP($wgTitle->getText());
1003 if($id||$ip) {
1004 $s .= $sep . $this->userContribsLink();
1006 if ( 0 != $wgUser->getID() ) {
1007 if($id) { # can only email real users
1008 $s .= $sep . $this->emailUserLink();
1012 $s .= "\n<br /><hr class='sep' />";
1015 if ( 0 != $wgUser->getID() && ( !$wgDisableUploads || $wgRemoteUploads ) ) {
1016 $s .= $this->specialLink( "upload" ) . $sep;
1018 $s .= $this->specialLink( "specialpages" )
1019 . $sep . $this->bugReportsLink();
1021 global $wgSiteSupportPage;
1022 if( $wgSiteSupportPage ) {
1023 $s .= "\n<br /><a href=\"" . htmlspecialchars( $wgSiteSupportPage ) .
1024 "\" class=\"internal\">" . wfMsg( "sitesupport" ) . "</a>";
1027 $s .= "\n<br /></div>\n";
1028 wfProfileOut( $fname );
1029 return $s;
1032 function specialPagesList()
1034 global $wgUser, $wgOut, $wgLang, $wgServer, $wgRedirectScript;
1035 $a = array();
1036 $pages = SpecialPage::getPages();
1038 foreach ( $pages[""] as $name => $page ) {
1039 $a[$name] = $page->getDescription();
1041 if ( $wgUser->isSysop() )
1043 foreach ( $pages["sysop"] as $name => $page ) {
1044 $a[$name] = $page->getDescription();
1047 if ( $wgUser->isDeveloper() )
1049 foreach ( $pages["developer"] as $name => $page ) {
1050 $a[$name] = $page->getDescription() ;
1053 $go = wfMsg( "go" );
1054 $sp = wfMsg( "specialpages" );
1055 $spp = $wgLang->specialPage( "Specialpages" );
1057 $s = "<form id=\"specialpages\" method=\"get\" class=\"inline\" " .
1058 "action=\"" . htmlspecialchars( "{$wgServer}{$wgRedirectScript}" ) . "\">\n";
1059 $s .= "<select name=\"wpDropdown\">\n";
1060 $s .= "<option value=\"{$spp}\">{$sp}</option>\n";
1062 foreach ( $a as $name => $desc ) {
1063 $p = $wgLang->specialPage( $name );
1064 $s .= "<option value=\"{$p}\">{$desc}</option>\n";
1066 $s .= "</select>\n";
1067 $s .= "<input type='submit' value=\"{$go}\" name='redirect' />\n";
1068 $s .= "</form>\n";
1069 return $s;
1072 function mainPageLink()
1074 $mp = wfMsg( "mainpage" );
1075 $s = $this->makeKnownLink( $mp, $mp );
1076 return $s;
1079 function copyrightLink()
1081 $s = $this->makeKnownLink( wfMsg( "copyrightpage" ),
1082 wfMsg( "copyrightpagename" ) );
1083 return $s;
1086 function aboutLink()
1088 $s = $this->makeKnownLink( wfMsg( "aboutpage" ),
1089 wfMsg( "aboutwikipedia" ) );
1090 return $s;
1094 function disclaimerLink()
1096 $s = $this->makeKnownLink( wfMsg( "disclaimerpage" ),
1097 wfMsg( "disclaimers" ) );
1098 return $s;
1101 function editThisPage()
1103 global $wgOut, $wgTitle, $wgRequest;
1105 $oldid = $wgRequest->getVal( 'oldid' );
1106 $diff = $wgRequest->getVal( 'diff' );
1107 $redirect = $wgRequest->getVal( 'redirect' );
1109 if ( ! $wgOut->isArticleRelated() ) {
1110 $s = wfMsg( "protectedpage" );
1111 } else {
1112 $n = $wgTitle->getPrefixedText();
1113 if ( $wgTitle->userCanEdit() ) {
1114 $t = wfMsg( "editthispage" );
1115 } else {
1116 #$t = wfMsg( "protectedpage" );
1117 $t = wfMsg( "viewsource" );
1119 $oid = $red = "";
1121 if ( !is_null( $redirect ) ) { $red = "&redirect={$redirect}"; }
1122 if ( $oldid && ! isset( $diff ) ) {
1123 $oid = "&oldid={$oldid}";
1125 $s = $this->makeKnownLink( $n, $t, "action=edit{$oid}{$red}" );
1127 return $s;
1130 function deleteThisPage()
1132 global $wgUser, $wgOut, $wgTitle, $wgRequest;
1134 $diff = $wgRequest->getVal( 'diff' );
1135 if ( $wgTitle->getArticleId() && ( ! $diff ) && $wgUser->isSysop() ) {
1136 $n = $wgTitle->getPrefixedText();
1137 $t = wfMsg( "deletethispage" );
1139 $s = $this->makeKnownLink( $n, $t, "action=delete" );
1140 } else {
1141 $s = "";
1143 return $s;
1146 function protectThisPage()
1148 global $wgUser, $wgOut, $wgTitle, $wgRequest;
1150 $diff = $wgRequest->getVal( 'diff' );
1151 if ( $wgTitle->getArticleId() && ( ! $diff ) && $wgUser->isSysop() ) {
1152 $n = $wgTitle->getPrefixedText();
1154 if ( $wgTitle->isProtected() ) {
1155 $t = wfMsg( "unprotectthispage" );
1156 $q = "action=unprotect";
1157 } else {
1158 $t = wfMsg( "protectthispage" );
1159 $q = "action=protect";
1161 $s = $this->makeKnownLink( $n, $t, $q );
1162 } else {
1163 $s = "";
1165 return $s;
1168 function watchThisPage()
1170 global $wgUser, $wgOut, $wgTitle;
1172 if ( $wgOut->isArticleRelated() ) {
1173 $n = $wgTitle->getPrefixedText();
1175 if ( $wgTitle->userIsWatching() ) {
1176 $t = wfMsg( "unwatchthispage" );
1177 $q = "action=unwatch";
1178 } else {
1179 $t = wfMsg( "watchthispage" );
1180 $q = "action=watch";
1182 $s = $this->makeKnownLink( $n, $t, $q );
1183 } else {
1184 $s = wfMsg( "notanarticle" );
1186 return $s;
1189 function moveThisPage()
1191 global $wgTitle, $wgLang;
1193 if ( $wgTitle->userCanEdit() ) {
1194 $s = $this->makeKnownLink( $wgLang->specialPage( "Movepage" ),
1195 wfMsg( "movethispage" ), "target=" . $wgTitle->getPrefixedURL() );
1196 } // no message if page is protected - would be redundant
1197 return $s;
1200 function historyLink()
1202 global $wgTitle;
1204 $s = $this->makeKnownLink( $wgTitle->getPrefixedText(),
1205 wfMsg( "history" ), "action=history" );
1206 return $s;
1209 function whatLinksHere()
1211 global $wgTitle, $wgLang;
1213 $s = $this->makeKnownLink( $wgLang->specialPage( "Whatlinkshere" ),
1214 wfMsg( "whatlinkshere" ), "target=" . $wgTitle->getPrefixedURL() );
1215 return $s;
1218 function userContribsLink()
1220 global $wgTitle, $wgLang;
1222 $s = $this->makeKnownLink( $wgLang->specialPage( "Contributions" ),
1223 wfMsg( "contributions" ), "target=" . $wgTitle->getPartialURL() );
1224 return $s;
1227 function emailUserLink()
1229 global $wgTitle, $wgLang;
1231 $s = $this->makeKnownLink( $wgLang->specialPage( "Emailuser" ),
1232 wfMsg( "emailuser" ), "target=" . $wgTitle->getPartialURL() );
1233 return $s;
1236 function watchPageLinksLink()
1238 global $wgOut, $wgTitle, $wgLang;
1240 if ( ! $wgOut->isArticleRelated() ) {
1241 $s = "(" . wfMsg( "notanarticle" ) . ")";
1242 } else {
1243 $s = $this->makeKnownLink( $wgLang->specialPage(
1244 "Recentchangeslinked" ), wfMsg( "recentchangeslinked" ),
1245 "target=" . $wgTitle->getPrefixedURL() );
1247 return $s;
1250 function otherLanguages()
1252 global $wgOut, $wgLang, $wgTitle, $wgUseNewInterlanguage;
1254 $a = $wgOut->getLanguageLinks();
1255 if ( 0 == count( $a ) ) {
1256 if ( !$wgUseNewInterlanguage ) return "";
1257 $ns = $wgLang->getNsIndex ( $wgTitle->getNamespace () ) ;
1258 if ( $ns != 0 AND $ns != 1 ) return "" ;
1259 $pn = "Intl" ;
1260 $x = "mode=addlink&xt=".$wgTitle->getDBkey() ;
1261 return $this->makeKnownLink( $wgLang->specialPage( $pn ),
1262 wfMsg( "intl" ) , $x );
1265 if ( !$wgUseNewInterlanguage ) {
1266 $s = wfMsg( "otherlanguages" ) . ": ";
1267 } else {
1268 global $wgLanguageCode ;
1269 $x = "mode=zoom&xt=".$wgTitle->getDBkey() ;
1270 $x .= "&xl=".$wgLanguageCode ;
1271 $s = $this->makeKnownLink( $wgLang->specialPage( "Intl" ),
1272 wfMsg( "otherlanguages" ) , $x ) . ": " ;
1275 $s = wfMsg( "otherlanguages" ) . ": ";
1276 $first = true;
1277 if($wgLang->isRTL()) $s .= "<span dir='LTR'>";
1278 foreach( $a as $l ) {
1279 if ( ! $first ) { $s .= " | "; }
1280 $first = false;
1282 $nt = Title::newFromText( $l );
1283 $url = $nt->getFullURL();
1284 $text = $wgLang->getLanguageName( $nt->getInterwiki() );
1286 if ( "" == $text ) { $text = $l; }
1287 $style = $this->getExternalLinkAttributes( $l, $text );
1288 $s .= "<a href=\"{$url}\"{$style}>{$text}</a>";
1290 if($wgLang->isRTL()) $s .= "</span>";
1291 return $s;
1294 function bugReportsLink()
1296 $s = $this->makeKnownLink( wfMsg( "bugreportspage" ),
1297 wfMsg( "bugreports" ) );
1298 return $s;
1301 function dateLink()
1303 global $wgLinkCache;
1304 $t1 = Title::newFromText( gmdate( "F j" ) );
1305 $t2 = Title::newFromText( gmdate( "Y" ) );
1307 $wgLinkCache->suspend();
1308 $id = $t1->getArticleID();
1309 $wgLinkCache->resume();
1311 if ( 0 == $id ) {
1312 $s = $this->makeBrokenLink( $t1->getText() );
1313 } else {
1314 $s = $this->makeKnownLink( $t1->getText() );
1316 $s .= ", ";
1318 $wgLinkCache->suspend();
1319 $id = $t2->getArticleID();
1320 $wgLinkCache->resume();
1322 if ( 0 == $id ) {
1323 $s .= $this->makeBrokenLink( $t2->getText() );
1324 } else {
1325 $s .= $this->makeKnownLink( $t2->getText() );
1327 return $s;
1330 function talkLink()
1332 global $wgLang, $wgTitle, $wgLinkCache;
1334 $tns = $wgTitle->getNamespace();
1335 if ( -1 == $tns ) { return ""; }
1337 $pn = $wgTitle->getText();
1338 $tp = wfMsg( "talkpage" );
1339 if ( Namespace::isTalk( $tns ) ) {
1340 $lns = Namespace::getSubject( $tns );
1341 switch($tns) {
1342 case 1:
1343 $text = wfMsg("articlepage");
1344 break;
1345 case 3:
1346 $text = wfMsg("userpage");
1347 break;
1348 case 5:
1349 $text = wfMsg("wikipediapage");
1350 break;
1351 case 7:
1352 $text = wfMsg("imagepage");
1353 break;
1354 default:
1355 $text= wfMsg("articlepage");
1357 } else {
1359 $lns = Namespace::getTalk( $tns );
1360 $text=$tp;
1362 $n = $wgLang->getNsText( $lns );
1363 if ( "" == $n ) { $link = $pn; }
1364 else { $link = "{$n}:{$pn}"; }
1366 $wgLinkCache->suspend();
1367 $s = $this->makeLink( $link, $text );
1368 $wgLinkCache->resume();
1370 return $s;
1373 function commentLink()
1375 global $wgLang, $wgTitle, $wgLinkCache;
1377 $tns = $wgTitle->getNamespace();
1378 if ( -1 == $tns ) { return ""; }
1380 $lns = ( Namespace::isTalk( $tns ) ) ? $tns : Namespace::getTalk( $tns );
1382 # assert Namespace::isTalk( $lns )
1384 $n = $wgLang->getNsText( $lns );
1385 $pn = $wgTitle->getText();
1387 $link = "{$n}:{$pn}";
1389 $wgLinkCache->suspend();
1390 $s = $this->makeKnownLink($link, wfMsg("postcomment"), "action=edit&section=new");
1391 $wgLinkCache->resume();
1393 return $s;
1396 # After all the page content is transformed into HTML, it makes
1397 # a final pass through here for things like table backgrounds.
1399 function transformContent( $text )
1401 return $text;
1404 # Note: This function MUST call getArticleID() on the link,
1405 # otherwise the cache won't get updated properly. See LINKCACHE.DOC.
1407 function makeLink( $title, $text = "", $query = "", $trail = "" ) {
1408 wfProfileIn( "Skin::makeLink" );
1409 $nt = Title::newFromText( $title );
1410 if ($nt) {
1411 $result = $this->makeLinkObj( Title::newFromText( $title ), $text, $query, $trail );
1412 } else {
1413 wfDebug( "Invalid title passed to Skin::makeLink(): \"$title\"\n" );
1414 $result = $text == "" ? $title : $text;
1417 wfProfileOut( "Skin::makeLink" );
1418 return $result;
1421 function makeKnownLink( $title, $text = "", $query = "", $trail = "", $prefix = '',$aprops = '') {
1422 $nt = Title::newFromText( $title );
1423 if ($nt) {
1424 return $this->makeKnownLinkObj( Title::newFromText( $title ), $text, $query, $trail, $prefix , $aprops );
1425 } else {
1426 wfDebug( "Invalid title passed to Skin::makeKnownLink(): \"$title\"\n" );
1427 return $text == "" ? $title : $text;
1431 function makeBrokenLink( $title, $text = "", $query = "", $trail = "" ) {
1432 $nt = Title::newFromText( $title );
1433 if ($nt) {
1434 return $this->makeBrokenLinkObj( Title::newFromText( $title ), $text, $query, $trail );
1435 } else {
1436 wfDebug( "Invalid title passed to Skin::makeBrokenLink(): \"$title\"\n" );
1437 return $text == "" ? $title : $text;
1441 function makeStubLink( $title, $text = "", $query = "", $trail = "" ) {
1442 $nt = Title::newFromText( $title );
1443 if ($nt) {
1444 return $this->makeStubLinkObj( Title::newFromText( $title ), $text, $query, $trail );
1445 } else {
1446 wfDebug( "Invalid title passed to Skin::makeStubLink(): \"$title\"\n" );
1447 return $text == "" ? $title : $text;
1451 # Pass a title object, not a title string
1452 function makeLinkObj( &$nt, $text= "", $query = "", $trail = "", $prefix = "" )
1454 global $wgOut, $wgUser;
1455 if ( $nt->isExternal() ) {
1456 $u = $nt->getFullURL();
1457 $link = $nt->getPrefixedURL();
1458 if ( "" == $text ) { $text = $nt->getPrefixedText(); }
1459 $style = $this->getExternalLinkAttributes( $link, $text );
1461 $inside = "";
1462 if ( "" != $trail ) {
1463 if ( preg_match( "/^([a-z]+)(.*)$$/sD", $trail, $m ) ) {
1464 $inside = $m[1];
1465 $trail = $m[2];
1468 $retVal = "<a href=\"{$u}\"{$style}>{$text}{$inside}</a>{$trail}";
1469 } elseif ( 0 == $nt->getNamespace() && "" == $nt->getText() ) {
1470 $retVal = $this->makeKnownLinkObj( $nt, $text, $query, $trail, $prefix );
1471 } elseif ( ( -1 == $nt->getNamespace() ) ||
1472 ( Namespace::getImage() == $nt->getNamespace() ) ) {
1473 $retVal = $this->makeKnownLinkObj( $nt, $text, $query, $trail, $prefix );
1474 } else {
1475 $aid = $nt->getArticleID() ;
1476 if ( 0 == $aid ) {
1477 $retVal = $this->makeBrokenLinkObj( $nt, $text, $query, $trail, $prefix );
1478 } else {
1479 $threshold = $wgUser->getOption("stubthreshold") ;
1480 if ( $threshold > 0 ) {
1481 $res = wfQuery ( "SELECT LENGTH(cur_text) AS x, cur_namespace, cur_is_redirect FROM cur WHERE cur_id='{$aid}'", DB_READ ) ;
1483 if ( wfNumRows( $res ) > 0 ) {
1484 $s = wfFetchObject( $res );
1485 $size = $s->x;
1486 if ( $s->cur_is_redirect OR $s->cur_namespace != 0 ) {
1487 $size = $threshold*2 ; # Really big
1489 wfFreeResult( $res );
1490 } else {
1491 $size = $threshold*2 ; # Really big
1493 } else {
1494 $size = 1 ;
1496 if ( $size < $threshold ) {
1497 $retVal = $this->makeStubLinkObj( $nt, $text, $query, $trail, $prefix );
1498 } else {
1499 $retVal = $this->makeKnownLinkObj( $nt, $text, $query, $trail, $prefix );
1503 return $retVal;
1506 # Pass a title object, not a title string
1507 function makeKnownLinkObj( &$nt, $text = "", $query = "", $trail = "", $prefix = "" , $aprops = '')
1509 global $wgOut, $wgTitle;
1511 $fname = "Skin::makeKnownLinkObj";
1512 wfProfileIn( $fname );
1514 $link = $nt->getPrefixedURL();
1516 if ( "" == $link ) {
1517 $u = "";
1518 if ( "" == $text ) {
1519 $text = htmlspecialchars( $nt->getFragment() );
1521 } else {
1522 $u = $nt->escapeLocalURL( $query );
1524 if ( "" != $nt->getFragment() ) {
1525 $u .= "#" . htmlspecialchars( $nt->getFragment() );
1527 if ( "" == $text ) {
1528 $text = htmlspecialchars( $nt->getPrefixedText() );
1530 $style = $this->getInternalLinkAttributesObj( $nt, $text );
1532 $inside = "";
1533 if ( "" != $trail ) {
1534 if ( preg_match( $this->linktrail, $trail, $m ) ) {
1535 $inside = $m[1];
1536 $trail = $m[2];
1539 $r = "<a href=\"{$u}\"{$style}{$aprops}>{$prefix}{$text}{$inside}</a>{$trail}";
1540 wfProfileOut( $fname );
1541 return $r;
1544 # Pass a title object, not a title string
1545 function makeBrokenLinkObj( &$nt, $text = "", $query = "", $trail = "", $prefix = "" )
1547 global $wgOut, $wgUser;
1549 $fname = "Skin::makeBrokenLinkObj";
1550 wfProfileIn( $fname );
1552 if ( "" == $query ) {
1553 $q = "action=edit";
1554 } else {
1555 $q = "action=edit&{$query}";
1557 $u = $nt->escapeLocalURL( $q );
1559 if ( "" == $text ) {
1560 $text = htmlspecialchars( $nt->getPrefixedText() );
1562 $style = $this->getInternalLinkAttributesObj( $nt, $text, "yes" );
1564 $inside = "";
1565 if ( "" != $trail ) {
1566 if ( preg_match( $this->linktrail, $trail, $m ) ) {
1567 $inside = $m[1];
1568 $trail = $m[2];
1571 if ( $wgUser->getOption( "highlightbroken" ) ) {
1572 $s = "<a href=\"{$u}\"{$style}>{$prefix}{$text}{$inside}</a>{$trail}";
1573 } else {
1574 $s = "{$prefix}{$text}{$inside}<a href=\"{$u}\"{$style}>?</a>{$trail}";
1577 wfProfileOut( $fname );
1578 return $s;
1581 # Pass a title object, not a title string
1582 function makeStubLinkObj( &$nt, $text = "", $query = "", $trail = "", $prefix = "" )
1584 global $wgOut, $wgUser;
1586 $link = $nt->getPrefixedURL();
1588 $u = $nt->escapeLocalURL( $query );
1590 if ( "" == $text ) {
1591 $text = htmlspecialchars( $nt->getPrefixedText() );
1593 $style = $this->getInternalLinkAttributesObj( $nt, $text, "stub" );
1595 $inside = "";
1596 if ( "" != $trail ) {
1597 if ( preg_match( $this->linktrail, $trail, $m ) ) {
1598 $inside = $m[1];
1599 $trail = $m[2];
1602 if ( $wgUser->getOption( "highlightbroken" ) ) {
1603 $s = "<a href=\"{$u}\"{$style}>{$prefix}{$text}{$inside}</a>{$trail}";
1604 } else {
1605 $s = "{$prefix}{$text}{$inside}<a href=\"{$u}\"{$style}>!</a>{$trail}";
1607 return $s;
1610 function makeSelfLinkObj( &$nt, $text = "", $query = "", $trail = "", $prefix = "" )
1612 $u = $nt->escapeLocalURL( $query );
1613 if ( "" == $text ) {
1614 $text = htmlspecialchars( $nt->getPrefixedText() );
1616 $inside = "";
1617 if ( "" != $trail ) {
1618 if ( preg_match( $this->linktrail, $trail, $m ) ) {
1619 $inside = $m[1];
1620 $trail = $m[2];
1623 return "<strong>{$prefix}{$text}{$inside}</strong>{$trail}";
1626 /* these are used extensively in SkinPHPTal, but also some other places */
1627 /*static*/ function makeSpecialUrl( $name, $urlaction='' ) {
1628 $title = Title::makeTitle( NS_SPECIAL, $name );
1629 $this->checkTitle($title, $name);
1630 return $title->getLocalURL( $urlaction );
1632 /*static*/ function makeTalkUrl ( $name, $urlaction='' ) {
1633 $title = Title::newFromText( $name );
1634 $title = $title->getTalkPage();
1635 $this->checkTitle($title, $name);
1636 return $title->getLocalURL( $urlaction );
1638 /*static*/ function makeArticleUrl ( $name, $urlaction='' ) {
1639 $title = Title::newFromText( $name );
1640 $title= $title->getSubjectPage();
1641 $this->checkTitle($title, $name);
1642 return $title->getLocalURL( $urlaction );
1644 /*static*/ function makeI18nUrl ( $name, $urlaction='' ) {
1645 $title = Title::newFromText( wfMsg($name) );
1646 $this->checkTitle($title, $name);
1647 return $title->getLocalURL( $urlaction );
1649 /*static*/ function makeUrl ( $name, $urlaction='' ) {
1650 $title = Title::newFromText( $name );
1651 $this->checkTitle($title, $name);
1652 return $title->getLocalURL( $urlaction );
1655 /* these return an array with the 'href' and boolean 'exists' */
1656 /*static*/ function makeUrlDetails ( $name, $urlaction='' ) {
1657 $title = Title::newFromText( $name );
1658 $this->checkTitle($title, $name);
1659 return array(
1660 'href' => $title->getLocalURL( $urlaction ),
1661 'exists' => $title->getArticleID() != 0?true:false
1664 /*static*/ function makeTalkUrlDetails ( $name, $urlaction='' ) {
1665 $title = Title::newFromText( $name );
1666 $title = $title->getTalkPage();
1667 $this->checkTitle($title, $name);
1668 return array(
1669 'href' => $title->getLocalURL( $urlaction ),
1670 'exists' => $title->getArticleID() != 0?true:false
1673 /*static*/ function makeArticleUrlDetails ( $name, $urlaction='' ) {
1674 $title = Title::newFromText( $name );
1675 $title= $title->getSubjectPage();
1676 $this->checkTitle($title, $name);
1677 return array(
1678 'href' => $title->getLocalURL( $urlaction ),
1679 'exists' => $title->getArticleID() != 0?true:false
1682 /*static*/ function makeI18nUrlDetails ( $name, $urlaction='' ) {
1683 $title = Title::newFromText( wfMsg($name) );
1684 $this->checkTitle($title, $name);
1685 return array(
1686 'href' => $title->getLocalURL( $urlaction ),
1687 'exists' => $title->getArticleID() != 0?true:false
1691 # make sure we have some title to operate on
1692 /*static*/ function checkTitle ( &$title, &$name ) {
1693 if(!is_object($title)) {
1694 $title = Title::newFromText( $name );
1695 if(!is_object($title)) {
1696 $title = Title::newFromText( '<error: link target missing>' );
1701 function fnamePart( $url )
1703 $basename = strrchr( $url, "/" );
1704 if ( false === $basename ) { $basename = $url; }
1705 else { $basename = substr( $basename, 1 ); }
1706 return wfEscapeHTML( $basename );
1709 function makeImage( $url, $alt = "" )
1711 global $wgOut;
1713 if ( "" == $alt ) { $alt = $this->fnamePart( $url ); }
1714 $s = "<img src=\"{$url}\" alt=\"{$alt}\" />";
1715 return $s;
1718 function makeImageLink( $name, $url, $alt = "" ) {
1719 $nt = Title::makeTitle( Namespace::getImage(), $name );
1720 return $this->makeImageLinkObj( $nt, $alt );
1723 function makeImageLinkObj( $nt, $alt = "" ) {
1724 global $wgLang, $wgUseImageResize;
1725 $img = Image::newFromTitle( $nt );
1726 $url = $img->getURL();
1728 $align = "";
1729 $prefix = $postfix = "";
1731 if ( $wgUseImageResize ) {
1732 # Check if the alt text is of the form "options|alt text"
1733 # Options are:
1734 # * thumbnail make a thumbnail with enlarge-icon and caption, alignment depends on lang
1735 # * left no resizing, just left align. label is used for alt= only
1736 # * right same, but right aligned
1737 # * none same, but not aligned
1738 # * ___px scale to ___ pixels width, no aligning. e.g. use in taxobox
1739 # * center center the image
1740 # * framed Keep original image size, no magnify-button.
1742 $part = explode( "|", $alt);
1744 $mwThumb =& MagicWord::get( MAG_IMG_THUMBNAIL );
1745 $mwLeft =& MagicWord::get( MAG_IMG_LEFT );
1746 $mwRight =& MagicWord::get( MAG_IMG_RIGHT );
1747 $mwNone =& MagicWord::get( MAG_IMG_NONE );
1748 $mwWidth =& MagicWord::get( MAG_IMG_WIDTH );
1749 $mwCenter =& MagicWord::get( MAG_IMG_CENTER );
1750 $mwFramed =& MagicWord::get( MAG_IMG_FRAMED );
1751 $alt = $part[count($part)-1];
1753 $height = $framed = $thumb = false;
1755 foreach( $part as $key => $val ) {
1756 if ( ! is_null( $mwThumb->matchVariableStartToEnd($val) ) ) {
1757 $thumb=true;
1758 } elseif ( ! is_null( $mwRight->matchVariableStartToEnd($val) ) ) {
1759 # remember to set an alignment, don't render immediately
1760 $align = "right";
1761 } elseif ( ! is_null( $mwLeft->matchVariableStartToEnd($val) ) ) {
1762 # remember to set an alignment, don't render immediately
1763 $align = "left";
1764 } elseif ( ! is_null( $mwCenter->matchVariableStartToEnd($val) ) ) {
1765 # remember to set an alignment, don't render immediately
1766 $align = "center";
1767 } elseif ( ! is_null( $mwNone->matchVariableStartToEnd($val) ) ) {
1768 # remember to set an alignment, don't render immediately
1769 $align = "none";
1770 } elseif ( ! is_null( $match = $mwWidth->matchVariableStartToEnd($val) ) ) {
1771 # $match is the image width in pixels
1772 if ( preg_match( "/^([0-9]*)x([0-9]*)$/", $match, $m ) ) {
1773 $width = intval( $m[1] );
1774 $height = intval( $m[2] );
1775 } else {
1776 $width = intval($match);
1778 } elseif ( ! is_null( $mwFramed->matchVariableStartToEnd($val) ) ) {
1779 $framed=true;
1782 if ( "center" == $align )
1784 $prefix = '<span style="text-align: center">';
1785 $postfix = '</span>';
1786 $align = "none";
1789 if ( $thumb || $framed ) {
1791 # Create a thumbnail. Alignment depends on language
1792 # writing direction, # right aligned for left-to-right-
1793 # languages ("Western languages"), left-aligned
1794 # for right-to-left-languages ("Semitic languages")
1796 # If thumbnail width has not been provided, it is set
1797 # here to 180 pixels
1798 if ( $align == "" ) {
1799 $align = $wgLang->isRTL() ? "left" : "right";
1801 if ( ! isset($width) ) {
1802 $width = 180;
1804 return $prefix.$this->makeThumbLinkObj( $img, $alt, $align, $width, $height, $framed ).$postfix;
1806 } elseif ( isset($width) ) {
1808 # Create a resized image, without the additional thumbnail
1809 # features
1811 if ( ( ! $height === false )
1812 && ( $img->getHeight() * $width / $img->getWidth() > $height ) ) {
1813 print "height=$height<br>\nimg->getHeight() = ".$img->getHeight()."<br>\n";
1814 print "rescaling by factor ". $height / $img->getHeight() . "<br>\n";
1815 $width = $img->getWidth() * $height / $img->getHeight();
1817 $url = $img->createThumb( $width );
1819 } # endif $wgUseImageResize
1821 if ( empty( $alt ) ) {
1822 $alt = preg_replace( '/\.(.+?)^/', '', $img->getName() );
1824 $alt = htmlspecialchars( $alt );
1826 $u = $nt->escapeLocalURL();
1827 if ( $url == "" )
1829 $s = str_replace( "$1", $img->getName(), wfMsg("missingimage") );
1830 $s .= "<br>{$alt}<br>{$url}<br>\n";
1831 } else {
1832 $s = "<a href=\"{$u}\" class='image' title=\"{$alt}\">" .
1833 "<img src=\"{$url}\" alt=\"{$alt}\" /></a>";
1835 if ( "" != $align ) {
1836 $s = "<div class=\"float{$align}\"><span>{$s}</span></div>";
1838 return str_replace("\n", ' ',$prefix.$s.$postfix);
1842 function makeThumbLinkObj( $img, $label = "", $align = "right", $boxwidth = 180, $boxheight=false, $framed=false ) {
1843 global $wgStylePath, $wgLang;
1844 # $image = Title::makeTitle( Namespace::getImage(), $name );
1845 $url = $img->getURL();
1847 #$label = htmlspecialchars( $label );
1848 $alt = preg_replace( "/<[^>]*>/", "", $label);
1849 $alt = htmlspecialchars( $alt );
1851 if ( $img->exists() )
1853 $width = $img->getWidth();
1854 $height = $img->getHeight();
1855 } else {
1856 $width = $height = 200;
1858 if ( $framed )
1860 // Use image dimensions, don't scale
1861 $boxwidth = $width;
1862 $oboxwidth = $boxwidth + 2;
1863 $boxheight = $height;
1864 $thumbUrl = $url;
1865 } else {
1866 $h = intval( $height/($width/$boxwidth) );
1867 $oboxwidth = $boxwidth + 2;
1868 if ( ( ! $boxheight === false ) && ( $h > $boxheight ) )
1870 $boxwidth *= $boxheight/$h;
1871 } else {
1872 $boxheight = $h;
1874 $thumbUrl = $img->createThumb( $boxwidth );
1877 $u = $img->getEscapeLocalURL();
1879 $more = htmlspecialchars( wfMsg( "thumbnail-more" ) );
1880 $magnifyalign = $wgLang->isRTL() ? "left" : "right";
1881 $textalign = $wgLang->isRTL() ? ' style="text-align:right"' : "";
1883 $s = "<div class=\"thumb t{$align}\"><div style=\"width:{$oboxwidth}px;\">";
1884 if ( $thumbUrl == "" ) {
1885 $s .= str_replace( "$1", $img->getName(), wfMsg("missingimage") );
1886 $zoomicon = '';
1887 } else {
1888 $s .= '<a href="'.$u.'" class="internal" title="'.$alt.'">'.
1889 '<img src="'.$thumbUrl.'" alt="'.$alt.'" ' .
1890 'width="'.$boxwidth.'" height="'.$boxheight.'" /></a>';
1891 if ( $framed ) {
1892 $zoomicon="";
1893 } else {
1894 $zoomicon = '<div class="magnify" style="float:'.$magnifyalign.'">'.
1895 '<a href="'.$u.'" class="internal" title="'.$more.'">'.
1896 '<img src="'.$wgStylePath.'/images/magnify-clip.png" ' .
1897 'width="15" height="11" alt="'.$more.'" /></a></div>';
1900 $s .= ' <div class="thumbcaption" '.$textalign.'>'.$zoomicon.$label."</div></div></div>";
1901 return str_replace("\n", ' ', $s);
1904 function makeMediaLink( $name, $url, $alt = "" ) {
1905 $nt = Title::makeTitle( Namespace::getMedia(), $name );
1906 return $this->makeMediaLinkObj( $nt, $alt );
1909 function makeMediaLinkObj( $nt, $alt = "" )
1911 $name = $nt->getDBKey();
1912 $url = Image::wfImageUrl( $name );
1913 if ( empty( $alt ) ) {
1914 $alt = preg_replace( '/\.(.+?)^/', '', $name );
1917 $u = htmlspecialchars( $url );
1918 $s = "<a href=\"{$u}\" class='internal' title=\"{$alt}\">{$alt}</a>";
1919 return $s;
1922 function specialLink( $name, $key = "" )
1924 global $wgLang;
1926 if ( "" == $key ) { $key = strtolower( $name ); }
1927 $pn = $wgLang->ucfirst( $name );
1928 return $this->makeKnownLink( $wgLang->specialPage( $pn ),
1929 wfMsg( $key ) );
1932 function makeExternalLink( $url, $text, $escape = true ) {
1933 $style = $this->getExternalLinkAttributes( $url, $text );
1934 $url = htmlspecialchars( $url );
1935 if( $escape ) {
1936 $text = htmlspecialchars( $text );
1938 return "<a href=\"$url\"$style>$text</a>";
1941 # Called by history lists and recent changes
1944 # Returns text for the start of the tabular part of RC
1945 function beginRecentChangesList()
1947 $this->rc_cache = array() ;
1948 $this->rcMoveIndex = 0;
1949 $this->rcCacheIndex = 0 ;
1950 $this->lastdate = "";
1951 $this->rclistOpen = false;
1952 return "";
1955 function beginImageHistoryList()
1957 $s = "\n<h2>" . wfMsg( "imghistory" ) . "</h2>\n" .
1958 "<p>" . wfMsg( "imghistlegend" ) . "</p>\n<ul class='special'>";
1959 return $s;
1962 # Returns text for the end of RC
1963 # If enhanced RC is in use, returns pretty much all the text
1964 function endRecentChangesList()
1966 $s = $this->recentChangesBlock() ;
1967 if( $this->rclistOpen ) {
1968 $s .= "</ul>\n";
1970 return $s;
1973 # Enhanced RC ungrouped line
1974 function recentChangesBlockLine ( $rcObj )
1976 global $wgStylePath, $wgLang ;
1978 # Get rc_xxxx variables
1979 extract( $rcObj->mAttribs ) ;
1980 $curIdEq = "curid=$rc_cur_id";
1982 # Spacer image
1983 $r = "" ;
1985 $r .= "<img src='{$wgStylePath}/images/Arr_.png' width='12' height='12' border='0' />" ; $r .= "<tt>" ;
1987 if ( $rc_type == RC_MOVE ) {
1988 $r .= "&nbsp;&nbsp;";
1989 } else {
1990 # M & N (minor & new)
1991 $M = wfMsg( "minoreditletter" );
1992 $N = wfMsg( "newpageletter" );
1994 if ( $rc_type == RC_NEW ) {
1995 $r .= $N ;
1996 } else {
1997 $r .= "&nbsp;" ;
1999 if ( $rc_minor ) {
2000 $r .= $M ;
2001 } else {
2002 $r .= "&nbsp;" ;
2006 # Timestamp
2007 $r .= " ".$rcObj->timestamp." " ;
2008 $r .= "</tt>" ;
2010 # Article link
2011 $link = $rcObj->link ;
2012 if ( $rcObj->watched ) $link = "<strong>{$link}</strong>" ;
2013 $r .= $link ;
2015 # Cur
2016 $r .= " (" ;
2017 $r .= $rcObj->curlink ;
2018 $r .= "; " ;
2020 # Hist
2021 $r .= $this->makeKnownLinkObj( $rcObj->getTitle(), wfMsg( "hist" ), "{$curIdEq}&action=history" );
2023 # User/talk
2024 $r .= ") . . ".$rcObj->userlink ;
2025 $r .= $rcObj->usertalklink ;
2027 # Comment
2028 if ( $rc_comment != "" && $rc_type != RC_MOVE ) {
2029 $rc_comment=$this->formatComment($rc_comment);
2030 $r .= $wgLang->emphasize( " (".$rc_comment.")" );
2033 $r .= "<br />\n" ;
2034 return $r ;
2037 # Enhanced RC group
2038 function recentChangesBlockGroup ( $block )
2040 global $wgStylePath, $wgLang ;
2042 $r = "" ;
2043 $M = wfMsg( "minoreditletter" );
2044 $N = wfMsg( "newpageletter" );
2046 # Collate list of users
2047 $isnew = false ;
2048 $userlinks = array () ;
2049 foreach ( $block AS $rcObj ) {
2050 $oldid = $rcObj->mAttribs['rc_last_oldid'];
2051 if ( $rcObj->mAttribs['rc_new'] ) $isnew = true ;
2052 $u = $rcObj->userlink ;
2053 if ( !isset ( $userlinks[$u] ) ) $userlinks[$u] = 0 ;
2054 $userlinks[$u]++ ;
2057 # Sort the list and convert to text
2058 krsort ( $userlinks ) ;
2059 asort ( $userlinks ) ;
2060 $users = array () ;
2061 foreach ( $userlinks as $userlink => $count) {
2062 $text = $userlink ;
2063 if ( $count > 1 ) $text .= " ({$count}&times;)" ;
2064 array_push ( $users , $text ) ;
2066 $users = " <font size='-1'>[".implode("; ",$users)."]</font>" ;
2068 # Arrow
2069 $rci = "RCI{$this->rcCacheIndex}" ;
2070 $rcl = "RCL{$this->rcCacheIndex}" ;
2071 $rcm = "RCM{$this->rcCacheIndex}" ;
2072 $toggleLink = "javascript:toggleVisibility(\"{$rci}\",\"{$rcm}\",\"{$rcl}\")" ;
2073 $arrowdir = $wgLang->isRTL() ? "l" : "r";
2074 $tl = "<span id='{$rcm}'><a href='$toggleLink'><img src='{$wgStylePath}/images/Arr_{$arrowdir}.png' width='12' height='12' /></a></span>" ;
2075 $tl .= "<span id='{$rcl}' style='display:none'><a href='$toggleLink'><img src='{$wgStylePath}/images/Arr_d.png' width='12' height='12' /></a></span>" ;
2076 $r .= $tl ;
2078 # Main line
2079 # M/N
2080 $r .= "<tt>" ;
2081 if ( $isnew ) $r .= $N ;
2082 else $r .= "&nbsp;" ;
2083 $r .= "&nbsp;" ; # Minor
2085 # Timestamp
2086 $r .= " ".$block[0]->timestamp." " ;
2087 $r .= "</tt>" ;
2089 # Article link
2090 $link = $block[0]->link ;
2091 if ( $block[0]->watched ) $link = "<strong>{$link}</strong>" ;
2092 $r .= $link ;
2094 $curIdEq = "curid=" . $block[0]->mAttribs['rc_cur_id'];
2095 if ( $block[0]->mAttribs['rc_type'] != RC_LOG ) {
2096 # Changes
2097 $r .= " (".count($block)." " ;
2098 if ( $isnew ) $r .= wfMsg("changes");
2099 else $r .= $this->makeKnownLinkObj( $block[0]->getTitle() , wfMsg("changes") ,
2100 "{$curIdEq}&diff=0&oldid=".$oldid ) ;
2101 $r .= "; " ;
2103 # History
2104 $r .= $this->makeKnownLinkObj( $block[0]->getTitle(), wfMsg( "history" ), "{$curIdEq}&action=history" );
2105 $r .= ")" ;
2108 $r .= $users ;
2109 $r .= "<br />\n" ;
2111 # Sub-entries
2112 $r .= "<div id='{$rci}' style='display:none'>" ;
2113 foreach ( $block AS $rcObj ) {
2114 # Get rc_xxxx variables
2115 extract( $rcObj->mAttribs );
2117 $r .= "<img src='{$wgStylePath}/images/Arr_.png' width=12 height=12 />";
2118 $r .= "<tt>&nbsp; &nbsp; &nbsp; &nbsp;" ;
2119 if ( $rc_new ) $r .= $N ;
2120 else $r .= "&nbsp;" ;
2121 if ( $rc_minor ) $r .= $M ;
2122 else $r .= "&nbsp;" ;
2123 $r .= "</tt>" ;
2125 $o = "" ;
2126 if ( $rc_last_oldid != 0 ) {
2127 $o = "oldid=".$rc_last_oldid ;
2129 if ( $rc_type == RC_LOG ) {
2130 $link = $rcObj->timestamp ;
2131 } else {
2132 $link = $this->makeKnownLinkObj( $rcObj->getTitle(), $rcObj->timestamp , "{$curIdEq}&$o" ) ;
2134 $link = "<tt>{$link}</tt>" ;
2136 $r .= $link ;
2137 $r .= " (" ;
2138 $r .= $rcObj->curlink ;
2139 $r .= "; " ;
2140 $r .= $rcObj->lastlink ;
2141 $r .= ") . . ".$rcObj->userlink ;
2142 $r .= $rcObj->usertalklink ;
2143 if ( $rc_comment != "" ) {
2144 $rc_comment=$this->formatComment($rc_comment);
2145 $r .= $wgLang->emphasize( " (".$rc_comment.")" ) ;
2147 $r .= "<br />\n" ;
2149 $r .= "</div>\n" ;
2151 $this->rcCacheIndex++ ;
2152 return $r ;
2155 # If enhanced RC is in use, this function takes the previously cached
2156 # RC lines, arranges them, and outputs the HTML
2157 function recentChangesBlock ()
2159 global $wgStylePath ;
2160 if ( count ( $this->rc_cache ) == 0 ) return "" ;
2161 $blockOut = "";
2162 foreach ( $this->rc_cache AS $secureName => $block ) {
2163 if ( count ( $block ) < 2 ) {
2164 $blockOut .= $this->recentChangesBlockLine ( array_shift ( $block ) ) ;
2165 } else {
2166 $blockOut .= $this->recentChangesBlockGroup ( $block ) ;
2170 return "<div>{$blockOut}</div>" ;
2173 # Called in a loop over all displayed RC entries
2174 # Either returns the line, or caches it for later use
2175 function recentChangesLine( &$rc, $watched = false )
2177 global $wgUser ;
2178 $usenew = $wgUser->getOption( "usenewrc" );
2179 if ( $usenew )
2180 $line = $this->recentChangesLineNew ( $rc, $watched ) ;
2181 else
2182 $line = $this->recentChangesLineOld ( $rc, $watched ) ;
2183 return $line ;
2186 function recentChangesLineOld( &$rc, $watched = false )
2188 global $wgTitle, $wgLang, $wgUser, $wgRCSeconds;
2190 # Extract DB fields into local scope
2191 extract( $rc->mAttribs );
2192 $curIdEq = "curid=" . $rc_cur_id;
2194 # Make date header if necessary
2195 $date = $wgLang->date( $rc_timestamp, true);
2196 $s = "";
2197 if ( $date != $this->lastdate ) {
2198 if ( "" != $this->lastdate ) { $s .= "</ul>\n"; }
2199 $s .= "<h4>{$date}</h4>\n<ul class='special'>";
2200 $this->lastdate = $date;
2201 $this->rclistOpen = true;
2203 $s .= "<li> ";
2205 if ( $rc_type == RC_MOVE ) {
2206 # Diff
2207 $s .= "(" . wfMsg( "diff" ) . ") (";
2208 # Hist
2209 $s .= $this->makeKnownLinkObj( $rc->getMovedToTitle(), wfMsg( "hist" ), "action=history" ) .
2210 ") . . ";
2212 # "[[x]] moved to [[y]]"
2214 $s .= wfMsg( "1movedto2", $this->makeKnownLinkObj( $rc->getTitle(), "", "redirect=no" ),
2215 $this->makeKnownLinkObj( $rc->getMovedToTitle(), "" ) );
2217 } else {
2218 # Diff link
2219 if ( $rc_type == RC_NEW || $rc_type == RC_LOG ) {
2220 $diffLink = wfMsg( "diff" );
2221 } else {
2222 $diffLink = $this->makeKnownLinkObj( $rc->getTitle(), wfMsg( "diff" ),
2223 "{$curIdEq}&diff={$rc_this_oldid}&oldid={$rc_last_oldid}" ,'' ,'' , ' tabindex="'.$rc->counter.'"');
2225 $s .= "($diffLink) (";
2227 # History link
2228 $s .= $this->makeKnownLinkObj( $rc->getTitle(), wfMsg( "hist" ), "{$curIdEq}&action=history" );
2229 $s .= ") . . ";
2231 # M and N (minor and new)
2232 $M = wfMsg( "minoreditletter" );
2233 $N = wfMsg( "newpageletter" );
2234 if ( $rc_minor ) { $s .= " <strong>{$M}</strong>"; }
2235 if ( $rc_type == RC_NEW ) { $s .= "<strong>{$N}</strong>"; }
2237 # Article link
2238 $articleLink = $this->makeKnownLinkObj( $rc->getTitle(), "" );
2240 if ( $watched ) {
2241 $articleLink = "<strong>{$articleLink}</strong>";
2243 $s .= " $articleLink";
2247 # Timestamp
2248 $s .= "; " . $wgLang->time( $rc_timestamp, true, $wgRCSeconds ) . " . . ";
2250 # User link (or contributions for unregistered users)
2251 if ( 0 == $rc_user ) {
2252 $userLink = $this->makeKnownLink( $wgLang->specialPage( "Contributions" ),
2253 $rc_user_text, "target=" . $rc_user_text );
2254 } else {
2255 $userLink = $this->makeLink( $wgLang->getNsText( NS_USER ) . ":{$rc_user_text}", $rc_user_text );
2257 $s .= $userLink;
2259 # User talk link
2260 $talkname=$wgLang->getNsText(NS_TALK); # use the shorter name
2261 global $wgDisableAnonTalk;
2262 if( 0 == $rc_user && $wgDisableAnonTalk ) {
2263 $userTalkLink = "";
2264 } else {
2265 $utns=$wgLang->getNsText(NS_USER_TALK);
2266 $userTalkLink= $this->makeLink($utns . ":{$rc_user_text}", $talkname );
2268 # Block link
2269 $blockLink="";
2270 if ( ( 0 == $rc_user ) && $wgUser->isSysop() ) {
2271 $blockLink = $this->makeKnownLink( $wgLang->specialPage(
2272 "Blockip" ), wfMsg( "blocklink" ), "ip={$rc_user_text}" );
2275 if($blockLink) {
2276 if($userTalkLink) $userTalkLink .= " | ";
2277 $userTalkLink .= $blockLink;
2279 if($userTalkLink) $s.=" ({$userTalkLink})";
2281 # Add comment
2282 if ( "" != $rc_comment && "*" != $rc_comment && $rc_type != RC_MOVE ) {
2283 $rc_comment=$this->formatComment($rc_comment);
2284 $s .= $wgLang->emphasize(" (" . $rc_comment . ")");
2286 $s .= "</li>\n";
2288 return $s;
2291 # function recentChangesLineNew( $ts, $u, $ut, $ns, $ttl, $c, $isminor, $isnew, $watched = false, $oldid = 0 , $diffid = 0 )
2292 function recentChangesLineNew( &$baseRC, $watched = false )
2294 global $wgTitle, $wgLang, $wgUser, $wgRCSeconds;
2296 # Create a specialised object
2297 $rc = RCCacheEntry::newFromParent( $baseRC ) ;
2299 # Extract fields from DB into the function scope (rc_xxxx variables)
2300 extract( $rc->mAttribs );
2301 $curIdEq = "curid=" . $rc_cur_id;
2303 # If it's a new day, add the headline and flush the cache
2304 $date = $wgLang->date( $rc_timestamp, true);
2305 $ret = "" ;
2306 if ( $date != $this->lastdate ) {
2307 # Process current cache
2308 $ret = $this->recentChangesBlock () ;
2309 $this->rc_cache = array() ;
2310 $ret .= "<h4>{$date}</h4>\n";
2311 $this->lastdate = $date;
2314 # Make article link
2315 if ( $rc_type == RC_MOVE ) {
2316 $clink = $this->makeKnownLinkObj( $rc->getTitle(), "", "redirect=no" );
2317 $clink .= " " . wfMsg("movedto") . " ";
2318 $clink .= $this->makeKnownLinkObj( $rc->getMovedToTitle(), "" );
2319 } else {
2320 $clink = $this->makeKnownLinkObj( $rc->getTitle(), "" ) ;
2323 $time = $wgLang->time( $rc_timestamp, true, $wgRCSeconds );
2324 $rc->watched = $watched ;
2325 $rc->link = $clink ;
2326 $rc->timestamp = $time;
2328 # Make "cur" link
2329 if ( ( $rc_type == RC_NEW && $rc_this_oldid == 0 ) || $rc_type == RC_LOG || $rc_type == RC_MOVE) {
2330 $curLink = wfMsg( "cur" );
2331 } else {
2332 $curLink = $this->makeKnownLinkObj( $rc->getTitle(), wfMsg( "cur" ),
2333 "{$curIdEq}&diff=0&oldid={$rc_this_oldid}" ,'' ,'' , ' tabindex="'.$baseRC->counter.'"' );
2336 # Make "last" link
2337 $titleObj = $rc->getTitle();
2338 if ( $rc_last_oldid == 0 || $rc_type == RC_LOG || $rc_type == RC_MOVE ) {
2339 $lastLink = wfMsg( "last" );
2340 } else {
2341 $lastLink = $this->makeKnownLinkObj( $rc->getTitle(), wfMsg( "last" ),
2342 "{$curIdEq}&diff={$rc_this_oldid}&oldid={$rc_last_oldid}" );
2345 # Make user link (or user contributions for unregistered users)
2346 if ( 0 == $rc_user ) {
2347 $userLink = $this->makeKnownLink( $wgLang->specialPage( "Contributions" ),
2348 $rc_user_text, "target=" . $rc_user_text );
2349 } else {
2350 $userLink = $this->makeLink( $wgLang->getNsText(
2351 Namespace::getUser() ) . ":{$rc_user_text}", $rc_user_text );
2354 $rc->userlink = $userLink ;
2355 $rc->lastlink = $lastLink ;
2356 $rc->curlink = $curLink ;
2358 # Make user talk link
2359 $utns=$wgLang->getNsText(NS_USER_TALK);
2360 $talkname=$wgLang->getNsText(NS_TALK); # use the shorter name
2361 $userTalkLink= $this->makeLink($utns . ":{$rc_user_text}", $talkname );
2363 global $wgDisableAnonTalk;
2364 if ( ( 0 == $rc_user ) && $wgUser->isSysop() ) {
2365 $blockLink = $this->makeKnownLink( $wgLang->specialPage(
2366 "Blockip" ), wfMsg( "blocklink" ), "ip={$rc_user_text}" );
2367 if( $wgDisableAnonTalk )
2368 $rc->usertalklink = " ({$blockLink})";
2369 else
2370 $rc->usertalklink = " ({$userTalkLink} | {$blockLink})";
2371 } else {
2372 if( $wgDisableAnonTalk && ($rc_user == 0) )
2373 $rc->usertalklink = "";
2374 else
2375 $rc->usertalklink = " ({$userTalkLink})";
2378 # Put accumulated information into the cache, for later display
2379 # Page moves go on their own line
2380 $title = $rc->getTitle();
2381 $secureName = $title->getPrefixedDBkey();
2382 if ( $rc_type == RC_MOVE ) {
2383 # Use an @ character to prevent collision with page names
2384 $this->rc_cache["@@" . ($this->rcMoveIndex++)] = array($rc);
2385 } else {
2386 if ( !isset ( $this->rc_cache[$secureName] ) ) $this->rc_cache[$secureName] = array() ;
2387 array_push ( $this->rc_cache[$secureName] , $rc ) ;
2389 return $ret;
2392 function endImageHistoryList()
2394 $s = "</ul>\n";
2395 return $s;
2398 /* This function is called by all recent changes variants, by the page history,
2399 and by the user contributions list. It is responsible for formatting edit
2400 comments. It escapes any HTML in the comment, but adds some CSS to format
2401 auto-generated comments (from section editing) and formats [[wikilinks]].
2402 Main author: Erik Möller (moeller@scireview.de)
2404 function formatComment($comment)
2406 global $wgLang;
2407 $comment=wfEscapeHTML($comment);
2409 # The pattern for autogen comments is / * foo * /, which makes for
2410 # some nasty regex.
2411 # We look for all comments, match any text before and after the comment,
2412 # add a separator where needed and format the comment itself with CSS
2413 while (preg_match("/(.*)\/\*\s*(.*?)\s*\*\/(.*)/", $comment,$match)) {
2414 $pre=$match[1];
2415 $auto=$match[2];
2416 $post=$match[3];
2417 $sep="-";
2418 if($pre) { $auto="$sep ".$auto; }
2419 if($post) { $auto.=" $sep"; }
2420 $auto="<span class=\"autocomment\">".$auto."</span>";
2421 $comment=$pre.$auto.$post;
2424 # format regular and media links - all other wiki formatting
2425 # is ignored
2426 while(preg_match("/\[\[(.*?)(\|(.*?))*\]\]/",$comment,$match)) {
2428 $medians = $wgLang->getNsText(Namespace::getMedia());
2429 $func="makeLink";
2430 if(preg_match("/^".$medians."/i",$match[1])) {
2431 $func="makeMediaLink";
2433 if(isset($match[3]) ) {
2434 $comment=
2435 preg_replace("/\[\[(.*?)\]\]/",
2436 $this->$func($match[1],$match[3]),$comment,1);
2437 } else {
2438 $comment=
2439 preg_replace("/\[\[(.*?)\]\]/",
2440 $this->$func($match[1],$match[1]),$comment,1);
2444 return $comment;
2448 function imageHistoryLine( $iscur, $timestamp, $img, $user, $usertext, $size, $description )
2450 global $wgUser, $wgLang, $wgTitle;
2452 $datetime = $wgLang->timeanddate( $timestamp, true );
2453 $del = wfMsg( "deleteimg" );
2454 $cur = wfMsg( "cur" );
2456 if ( $iscur ) {
2457 $url = Image::wfImageUrl( $img );
2458 $rlink = $cur;
2459 if ( $wgUser->isSysop() ) {
2460 $link = $wgTitle->escapeLocalURL( "image=" . $wgTitle->getPartialURL() .
2461 "&action=delete" );
2462 $style = $this->getInternalLinkAttributes( $link, $del );
2464 $dlink = "<a href=\"{$link}\"{$style}>{$del}</a>";
2465 } else {
2466 $dlink = $del;
2468 } else {
2469 $url = wfEscapeHTML( wfImageArchiveUrl( $img ) );
2470 if( $wgUser->getID() != 0 ) {
2471 $rlink = $this->makeKnownLink( $wgTitle->getPrefixedText(),
2472 wfMsg( "revertimg" ), "action=revert&oldimage=" .
2473 urlencode( $img ) );
2474 $dlink = $this->makeKnownLink( $wgTitle->getPrefixedText(),
2475 $del, "action=delete&oldimage=" . urlencode( $img ) );
2476 } else {
2477 # Having live active links for non-logged in users
2478 # means that bots and spiders crawling our site can
2479 # inadvertently change content. Baaaad idea.
2480 $rlink = wfMsg( "revertimg" );
2481 $dlink = $del;
2484 if ( 0 == $user ) {
2485 $userlink = $usertext;
2486 } else {
2487 $userlink = $this->makeLink( $wgLang->getNsText( Namespace::getUser() ) .
2488 ":{$usertext}", $usertext );
2490 $nbytes = wfMsg( "nbytes", $size );
2491 $style = $this->getInternalLinkAttributes( $url, $datetime );
2493 $s = "<li> ({$dlink}) ({$rlink}) <a href=\"{$url}\"{$style}>{$datetime}</a>"
2494 . " . . {$userlink} ({$nbytes})";
2496 if ( "" != $description && "*" != $description ) {
2497 $sk=$wgUser->getSkin();
2498 $s .= $wgLang->emphasize(" (" . $sk->formatComment($description) . ")");
2500 $s .= "</li>\n";
2501 return $s;
2504 function tocIndent($level) {
2505 return str_repeat( "<div class='tocindent'>\n", $level>0 ? $level : 0 );
2508 function tocUnindent($level) {
2509 return str_repeat( "</div>\n", $level>0 ? $level : 0 );
2512 # parameter level defines if we are on an indentation level
2513 function tocLine( $anchor, $tocline, $level ) {
2514 $link = "<a href=\"#$anchor\">$tocline</a><br />";
2515 if($level) {
2516 return "$link\n";
2517 } else {
2518 return "<div class='tocline'>$link</div>\n";
2523 function tocTable($toc) {
2524 # note to CSS fanatics: putting this in a div does not work -- div won't auto-expand
2525 # try min-width & co when somebody gets a chance
2526 $hideline = " <script type='text/javascript'>showTocToggle(\"" . addslashes( wfMsg("showtoc") ) . "\",\"" . addslashes( wfMsg("hidetoc") ) . "\")</script>";
2527 return
2528 "<table border=\"0\" id=\"toc\"><tr><td align=\"center\">\n".
2529 "<b>".wfMsg("toc")."</b>" .
2530 $hideline .
2531 "</td></tr><tr id='tocinside'><td>\n".
2532 $toc."</td></tr></table>\n";
2535 # These two do not check for permissions: check $wgTitle->userCanEdit before calling them
2536 function editSectionScript( $section, $head ) {
2537 global $wgTitle, $wgRequest;
2538 if( $wgRequest->getInt( "oldid" ) && ( $wgRequest->getVal( "diff" ) != "0" ) ) {
2539 return $head;
2541 $url = $wgTitle->escapeLocalURL( "action=edit&section=$section" );
2542 return "<span oncontextmenu='document.location=\"$url\";return false;'>{$head}</span>";
2545 function editSectionLink( $section ) {
2546 global $wgRequest;
2547 global $wgTitle, $wgUser, $wgLang;
2549 if( $wgRequest->getInt( "oldid" ) && ( $wgRequest->getVal( "diff" ) != "0" ) ) {
2550 # Section edit links would be out of sync on an old page.
2551 # But, if we're diffing to the current page, they'll be
2552 # correct.
2553 return "";
2556 $editurl = "&section={$section}";
2557 $url = $this->makeKnownLink($wgTitle->getPrefixedText(),wfMsg("editsection"),"action=edit".$editurl);
2559 if( $wgLang->isRTL() ) {
2560 $farside = "left";
2561 $nearside = "right";
2562 } else {
2563 $farside = "right";
2564 $nearside = "left";
2566 return "<div class=\"editsection\" style=\"float:$farside;margin-$nearside:5px;\">[".$url."]</div>";
2570 // This function is called by EditPage.php and shows a bulletin board style
2571 // toolbar for common editing functions. It can be disabled in the user preferences.
2572 // The necsesary JavaScript code can be found in style/wikibits.js.
2573 function getEditToolbar() {
2574 global $wgStylePath, $wgLang, $wgMimeType;
2576 // toolarray an array of arrays which each include the filename of
2577 // the button image (without path), the opening tag, the closing tag,
2578 // and optionally a sample text that is inserted between the two when no
2579 // selection is highlighted.
2580 // The tip text is shown when the user moves the mouse over the button.
2582 // Already here are accesskeys (key), which are not used yet until someone
2583 // can figure out a way to make them work in IE. However, we should make
2584 // sure these keys are not defined on the edit page.
2585 $toolarray=array(
2586 array( "image"=>"button_bold.png",
2587 "open"=>"\'\'\'",
2588 "close"=>"\'\'\'",
2589 "sample"=>wfMsg("bold_sample"),
2590 "tip"=>wfMsg("bold_tip"),
2591 "key"=>"B"
2593 array( "image"=>"button_italic.png",
2594 "open"=>"\'\'",
2595 "close"=>"\'\'",
2596 "sample"=>wfMsg("italic_sample"),
2597 "tip"=>wfMsg("italic_tip"),
2598 "key"=>"I"
2600 array( "image"=>"button_link.png",
2601 "open"=>"[[",
2602 "close"=>"]]",
2603 "sample"=>wfMsg("link_sample"),
2604 "tip"=>wfMsg("link_tip"),
2605 "key"=>"L"
2607 array( "image"=>"button_extlink.png",
2608 "open"=>"[",
2609 "close"=>"]",
2610 "sample"=>wfMsg("extlink_sample"),
2611 "tip"=>wfMsg("extlink_tip"),
2612 "key"=>"X"
2614 array( "image"=>"button_headline.png",
2615 "open"=>"\\n== ",
2616 "close"=>" ==\\n",
2617 "sample"=>wfMsg("headline_sample"),
2618 "tip"=>wfMsg("headline_tip"),
2619 "key"=>"H"
2621 array( "image"=>"button_image.png",
2622 "open"=>"[[".$wgLang->getNsText(NS_IMAGE).":",
2623 "close"=>"]]",
2624 "sample"=>wfMsg("image_sample"),
2625 "tip"=>wfMsg("image_tip"),
2626 "key"=>"D"
2628 array( "image"=>"button_media.png",
2629 "open"=>"[[".$wgLang->getNsText(NS_MEDIA).":",
2630 "close"=>"]]",
2631 "sample"=>wfMsg("media_sample"),
2632 "tip"=>wfMsg("media_tip"),
2633 "key"=>"M"
2635 array( "image"=>"button_math.png",
2636 "open"=>"\\<math\\>",
2637 "close"=>"\\</math\\>",
2638 "sample"=>wfMsg("math_sample"),
2639 "tip"=>wfMsg("math_tip"),
2640 "key"=>"C"
2642 array( "image"=>"button_nowiki.png",
2643 "open"=>"\\<nowiki\\>",
2644 "close"=>"\\</nowiki\\>",
2645 "sample"=>wfMsg("nowiki_sample"),
2646 "tip"=>wfMsg("nowiki_tip"),
2647 "key"=>"N"
2649 array( "image"=>"button_sig.png",
2650 "open"=>"--~~~~",
2651 "close"=>"",
2652 "sample"=>"",
2653 "tip"=>wfMsg("sig_tip"),
2654 "key"=>"Y"
2656 array( "image"=>"button_hr.png",
2657 "open"=>"\\n----\\n",
2658 "close"=>"",
2659 "sample"=>"",
2660 "tip"=>wfMsg("hr_tip"),
2661 "key"=>"R"
2664 $toolbar ="<script type='text/javascript'>\n/*<![CDATA[*/\n";
2666 $toolbar.="document.writeln(\"<div id='toolbar'>\");\n";
2667 foreach($toolarray as $tool) {
2669 $image=$wgStylePath."/images/".$tool["image"];
2670 $open=$tool["open"];
2671 $close=$tool["close"];
2672 $sample = addslashes( $tool["sample"] );
2674 // Note that we use the tip both for the ALT tag and the TITLE tag of the image.
2675 // Older browsers show a "speedtip" type message only for ALT.
2676 // Ideally these should be different, realistically they
2677 // probably don't need to be.
2678 $tip = addslashes( $tool["tip"] );
2680 #$key = $tool["key"];
2682 $toolbar.="addButton('$image','$tip','$open','$close','$sample');\n";
2685 $toolbar.="addInfobox('" . addslashes( wfMsg( "infobox" ) ) . "','" . addslashes(wfMsg("infobox_alert")) . "');\n";
2686 $toolbar.="document.writeln(\"</div>\");\n";
2688 $toolbar.="/*]]>*/\n</script>";
2689 return $toolbar;
2694 require_once( "SkinStandard.php" );
2695 require_once( "SkinNostalgia.php" );
2696 require_once( "SkinCologneBlue.php" );
2698 if( $wgUsePHPTal ) {
2699 require_once( "SkinPHPTal.php" );