Removed CardSet, not needed with Gabriel's solution
[mediawiki.git] / includes / Skin.php
blob336a868c5888b47a40e1548bb751d971fea3cb47
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();
1037 $validSP = $wgLang->getValidSpecialPages();
1039 foreach ( $validSP as $name => $desc ) {
1040 if ( "" == $desc ) { continue; }
1041 $a[$name] = $desc;
1043 if ( $wgUser->isSysop() )
1045 $sysopSP = $wgLang->getSysopSpecialPages();
1047 foreach ( $sysopSP as $name => $desc ) {
1048 if ( "" == $desc ) { continue; }
1049 $a[$name] = $desc ;
1052 if ( $wgUser->isDeveloper() )
1054 $devSP = $wgLang->getDeveloperSpecialPages();
1056 foreach ( $devSP as $name => $desc ) {
1057 if ( "" == $desc ) { continue; }
1058 $a[$name] = $desc ;
1061 $go = wfMsg( "go" );
1062 $sp = wfMsg( "specialpages" );
1063 $spp = $wgLang->specialPage( "Specialpages" );
1065 $s = "<form id=\"specialpages\" method=\"get\" class=\"inline\" " .
1066 "action=\"" . htmlspecialchars( "{$wgServer}{$wgRedirectScript}" ) . "\">\n";
1067 $s .= "<select name=\"wpDropdown\">\n";
1068 $s .= "<option value=\"{$spp}\">{$sp}</option>\n";
1070 foreach ( $a as $name => $desc ) {
1071 $p = $wgLang->specialPage( $name );
1072 $s .= "<option value=\"{$p}\">{$desc}</option>\n";
1074 $s .= "</select>\n";
1075 $s .= "<input type='submit' value=\"{$go}\" name='redirect' />\n";
1076 $s .= "</form>\n";
1077 return $s;
1080 function mainPageLink()
1082 $mp = wfMsg( "mainpage" );
1083 $s = $this->makeKnownLink( $mp, $mp );
1084 return $s;
1087 function copyrightLink()
1089 $s = $this->makeKnownLink( wfMsg( "copyrightpage" ),
1090 wfMsg( "copyrightpagename" ) );
1091 return $s;
1094 function aboutLink()
1096 $s = $this->makeKnownLink( wfMsg( "aboutpage" ),
1097 wfMsg( "aboutwikipedia" ) );
1098 return $s;
1102 function disclaimerLink()
1104 $s = $this->makeKnownLink( wfMsg( "disclaimerpage" ),
1105 wfMsg( "disclaimers" ) );
1106 return $s;
1109 function editThisPage()
1111 global $wgOut, $wgTitle, $wgRequest;
1113 $oldid = $wgRequest->getVal( 'oldid' );
1114 $diff = $wgRequest->getVal( 'diff' );
1115 $redirect = $wgRequest->getVal( 'redirect' );
1117 if ( ! $wgOut->isArticleRelated() ) {
1118 $s = wfMsg( "protectedpage" );
1119 } else {
1120 $n = $wgTitle->getPrefixedText();
1121 if ( $wgTitle->userCanEdit() ) {
1122 $t = wfMsg( "editthispage" );
1123 } else {
1124 #$t = wfMsg( "protectedpage" );
1125 $t = wfMsg( "viewsource" );
1127 $oid = $red = "";
1129 if ( !is_null( $redirect ) ) { $red = "&redirect={$redirect}"; }
1130 if ( $oldid && ! isset( $diff ) ) {
1131 $oid = "&oldid={$oldid}";
1133 $s = $this->makeKnownLink( $n, $t, "action=edit{$oid}{$red}" );
1135 return $s;
1138 function deleteThisPage()
1140 global $wgUser, $wgOut, $wgTitle, $wgRequest;
1142 $diff = $wgRequest->getVal( 'diff' );
1143 if ( $wgTitle->getArticleId() && ( ! $diff ) && $wgUser->isSysop() ) {
1144 $n = $wgTitle->getPrefixedText();
1145 $t = wfMsg( "deletethispage" );
1147 $s = $this->makeKnownLink( $n, $t, "action=delete" );
1148 } else {
1149 $s = "";
1151 return $s;
1154 function protectThisPage()
1156 global $wgUser, $wgOut, $wgTitle, $wgRequest;
1158 $diff = $wgRequest->getVal( 'diff' );
1159 if ( $wgTitle->getArticleId() && ( ! $diff ) && $wgUser->isSysop() ) {
1160 $n = $wgTitle->getPrefixedText();
1162 if ( $wgTitle->isProtected() ) {
1163 $t = wfMsg( "unprotectthispage" );
1164 $q = "action=unprotect";
1165 } else {
1166 $t = wfMsg( "protectthispage" );
1167 $q = "action=protect";
1169 $s = $this->makeKnownLink( $n, $t, $q );
1170 } else {
1171 $s = "";
1173 return $s;
1176 function watchThisPage()
1178 global $wgUser, $wgOut, $wgTitle;
1180 if ( $wgOut->isArticleRelated() ) {
1181 $n = $wgTitle->getPrefixedText();
1183 if ( $wgTitle->userIsWatching() ) {
1184 $t = wfMsg( "unwatchthispage" );
1185 $q = "action=unwatch";
1186 } else {
1187 $t = wfMsg( "watchthispage" );
1188 $q = "action=watch";
1190 $s = $this->makeKnownLink( $n, $t, $q );
1191 } else {
1192 $s = wfMsg( "notanarticle" );
1194 return $s;
1197 function moveThisPage()
1199 global $wgTitle, $wgLang;
1201 if ( $wgTitle->userCanEdit() ) {
1202 $s = $this->makeKnownLink( $wgLang->specialPage( "Movepage" ),
1203 wfMsg( "movethispage" ), "target=" . $wgTitle->getPrefixedURL() );
1204 } // no message if page is protected - would be redundant
1205 return $s;
1208 function historyLink()
1210 global $wgTitle;
1212 $s = $this->makeKnownLink( $wgTitle->getPrefixedText(),
1213 wfMsg( "history" ), "action=history" );
1214 return $s;
1217 function whatLinksHere()
1219 global $wgTitle, $wgLang;
1221 $s = $this->makeKnownLink( $wgLang->specialPage( "Whatlinkshere" ),
1222 wfMsg( "whatlinkshere" ), "target=" . $wgTitle->getPrefixedURL() );
1223 return $s;
1226 function userContribsLink()
1228 global $wgTitle, $wgLang;
1230 $s = $this->makeKnownLink( $wgLang->specialPage( "Contributions" ),
1231 wfMsg( "contributions" ), "target=" . $wgTitle->getPartialURL() );
1232 return $s;
1235 function emailUserLink()
1237 global $wgTitle, $wgLang;
1239 $s = $this->makeKnownLink( $wgLang->specialPage( "Emailuser" ),
1240 wfMsg( "emailuser" ), "target=" . $wgTitle->getPartialURL() );
1241 return $s;
1244 function watchPageLinksLink()
1246 global $wgOut, $wgTitle, $wgLang;
1248 if ( ! $wgOut->isArticleRelated() ) {
1249 $s = "(" . wfMsg( "notanarticle" ) . ")";
1250 } else {
1251 $s = $this->makeKnownLink( $wgLang->specialPage(
1252 "Recentchangeslinked" ), wfMsg( "recentchangeslinked" ),
1253 "target=" . $wgTitle->getPrefixedURL() );
1255 return $s;
1258 function otherLanguages()
1260 global $wgOut, $wgLang, $wgTitle, $wgUseNewInterlanguage;
1262 $a = $wgOut->getLanguageLinks();
1263 if ( 0 == count( $a ) ) {
1264 if ( !$wgUseNewInterlanguage ) return "";
1265 $ns = $wgLang->getNsIndex ( $wgTitle->getNamespace () ) ;
1266 if ( $ns != 0 AND $ns != 1 ) return "" ;
1267 $pn = "Intl" ;
1268 $x = "mode=addlink&xt=".$wgTitle->getDBkey() ;
1269 return $this->makeKnownLink( $wgLang->specialPage( $pn ),
1270 wfMsg( "intl" ) , $x );
1273 if ( !$wgUseNewInterlanguage ) {
1274 $s = wfMsg( "otherlanguages" ) . ": ";
1275 } else {
1276 global $wgLanguageCode ;
1277 $x = "mode=zoom&xt=".$wgTitle->getDBkey() ;
1278 $x .= "&xl=".$wgLanguageCode ;
1279 $s = $this->makeKnownLink( $wgLang->specialPage( "Intl" ),
1280 wfMsg( "otherlanguages" ) , $x ) . ": " ;
1283 $s = wfMsg( "otherlanguages" ) . ": ";
1284 $first = true;
1285 if($wgLang->isRTL()) $s .= "<span dir='LTR'>";
1286 foreach( $a as $l ) {
1287 if ( ! $first ) { $s .= " | "; }
1288 $first = false;
1290 $nt = Title::newFromText( $l );
1291 $url = $nt->getFullURL();
1292 $text = $wgLang->getLanguageName( $nt->getInterwiki() );
1294 if ( "" == $text ) { $text = $l; }
1295 $style = $this->getExternalLinkAttributes( $l, $text );
1296 $s .= "<a href=\"{$url}\"{$style}>{$text}</a>";
1298 if($wgLang->isRTL()) $s .= "</span>";
1299 return $s;
1302 function bugReportsLink()
1304 $s = $this->makeKnownLink( wfMsg( "bugreportspage" ),
1305 wfMsg( "bugreports" ) );
1306 return $s;
1309 function dateLink()
1311 global $wgLinkCache;
1312 $t1 = Title::newFromText( gmdate( "F j" ) );
1313 $t2 = Title::newFromText( gmdate( "Y" ) );
1315 $wgLinkCache->suspend();
1316 $id = $t1->getArticleID();
1317 $wgLinkCache->resume();
1319 if ( 0 == $id ) {
1320 $s = $this->makeBrokenLink( $t1->getText() );
1321 } else {
1322 $s = $this->makeKnownLink( $t1->getText() );
1324 $s .= ", ";
1326 $wgLinkCache->suspend();
1327 $id = $t2->getArticleID();
1328 $wgLinkCache->resume();
1330 if ( 0 == $id ) {
1331 $s .= $this->makeBrokenLink( $t2->getText() );
1332 } else {
1333 $s .= $this->makeKnownLink( $t2->getText() );
1335 return $s;
1338 function talkLink()
1340 global $wgLang, $wgTitle, $wgLinkCache;
1342 $tns = $wgTitle->getNamespace();
1343 if ( -1 == $tns ) { return ""; }
1345 $pn = $wgTitle->getText();
1346 $tp = wfMsg( "talkpage" );
1347 if ( Namespace::isTalk( $tns ) ) {
1348 $lns = Namespace::getSubject( $tns );
1349 switch($tns) {
1350 case 1:
1351 $text = wfMsg("articlepage");
1352 break;
1353 case 3:
1354 $text = wfMsg("userpage");
1355 break;
1356 case 5:
1357 $text = wfMsg("wikipediapage");
1358 break;
1359 case 7:
1360 $text = wfMsg("imagepage");
1361 break;
1362 default:
1363 $text= wfMsg("articlepage");
1365 } else {
1367 $lns = Namespace::getTalk( $tns );
1368 $text=$tp;
1370 $n = $wgLang->getNsText( $lns );
1371 if ( "" == $n ) { $link = $pn; }
1372 else { $link = "{$n}:{$pn}"; }
1374 $wgLinkCache->suspend();
1375 $s = $this->makeLink( $link, $text );
1376 $wgLinkCache->resume();
1378 return $s;
1381 function commentLink()
1383 global $wgLang, $wgTitle, $wgLinkCache;
1385 $tns = $wgTitle->getNamespace();
1386 if ( -1 == $tns ) { return ""; }
1388 $lns = ( Namespace::isTalk( $tns ) ) ? $tns : Namespace::getTalk( $tns );
1390 # assert Namespace::isTalk( $lns )
1392 $n = $wgLang->getNsText( $lns );
1393 $pn = $wgTitle->getText();
1395 $link = "{$n}:{$pn}";
1397 $wgLinkCache->suspend();
1398 $s = $this->makeKnownLink($link, wfMsg("postcomment"), "action=edit&section=new");
1399 $wgLinkCache->resume();
1401 return $s;
1404 # After all the page content is transformed into HTML, it makes
1405 # a final pass through here for things like table backgrounds.
1407 function transformContent( $text )
1409 return $text;
1412 # Note: This function MUST call getArticleID() on the link,
1413 # otherwise the cache won't get updated properly. See LINKCACHE.DOC.
1415 function makeLink( $title, $text = "", $query = "", $trail = "" ) {
1416 wfProfileIn( "Skin::makeLink" );
1417 $nt = Title::newFromText( $title );
1418 if ($nt) {
1419 $result = $this->makeLinkObj( Title::newFromText( $title ), $text, $query, $trail );
1420 } else {
1421 wfDebug( "Invalid title passed to Skin::makeLink(): \"$title\"\n" );
1422 $result = $text == "" ? $title : $text;
1425 wfProfileOut( "Skin::makeLink" );
1426 return $result;
1429 function makeKnownLink( $title, $text = "", $query = "", $trail = "", $prefix = '',$aprops = '') {
1430 $nt = Title::newFromText( $title );
1431 if ($nt) {
1432 return $this->makeKnownLinkObj( Title::newFromText( $title ), $text, $query, $trail, $prefix , $aprops );
1433 } else {
1434 wfDebug( "Invalid title passed to Skin::makeKnownLink(): \"$title\"\n" );
1435 return $text == "" ? $title : $text;
1439 function makeBrokenLink( $title, $text = "", $query = "", $trail = "" ) {
1440 $nt = Title::newFromText( $title );
1441 if ($nt) {
1442 return $this->makeBrokenLinkObj( Title::newFromText( $title ), $text, $query, $trail );
1443 } else {
1444 wfDebug( "Invalid title passed to Skin::makeBrokenLink(): \"$title\"\n" );
1445 return $text == "" ? $title : $text;
1449 function makeStubLink( $title, $text = "", $query = "", $trail = "" ) {
1450 $nt = Title::newFromText( $title );
1451 if ($nt) {
1452 return $this->makeStubLinkObj( Title::newFromText( $title ), $text, $query, $trail );
1453 } else {
1454 wfDebug( "Invalid title passed to Skin::makeStubLink(): \"$title\"\n" );
1455 return $text == "" ? $title : $text;
1459 # Pass a title object, not a title string
1460 function makeLinkObj( &$nt, $text= "", $query = "", $trail = "", $prefix = "" )
1462 global $wgOut, $wgUser;
1463 if ( $nt->isExternal() ) {
1464 $u = $nt->getFullURL();
1465 $link = $nt->getPrefixedURL();
1466 if ( "" == $text ) { $text = $nt->getPrefixedText(); }
1467 $style = $this->getExternalLinkAttributes( $link, $text );
1469 $inside = "";
1470 if ( "" != $trail ) {
1471 if ( preg_match( "/^([a-z]+)(.*)$$/sD", $trail, $m ) ) {
1472 $inside = $m[1];
1473 $trail = $m[2];
1476 $retVal = "<a href=\"{$u}\"{$style}>{$text}{$inside}</a>{$trail}";
1477 } elseif ( 0 == $nt->getNamespace() && "" == $nt->getText() ) {
1478 $retVal = $this->makeKnownLinkObj( $nt, $text, $query, $trail, $prefix );
1479 } elseif ( ( -1 == $nt->getNamespace() ) ||
1480 ( Namespace::getImage() == $nt->getNamespace() ) ) {
1481 $retVal = $this->makeKnownLinkObj( $nt, $text, $query, $trail, $prefix );
1482 } else {
1483 $aid = $nt->getArticleID() ;
1484 if ( 0 == $aid ) {
1485 $retVal = $this->makeBrokenLinkObj( $nt, $text, $query, $trail, $prefix );
1486 } else {
1487 $threshold = $wgUser->getOption("stubthreshold") ;
1488 if ( $threshold > 0 ) {
1489 $res = wfQuery ( "SELECT LENGTH(cur_text) AS x, cur_namespace, cur_is_redirect FROM cur WHERE cur_id='{$aid}'", DB_READ ) ;
1491 if ( wfNumRows( $res ) > 0 ) {
1492 $s = wfFetchObject( $res );
1493 $size = $s->x;
1494 if ( $s->cur_is_redirect OR $s->cur_namespace != 0 ) {
1495 $size = $threshold*2 ; # Really big
1497 wfFreeResult( $res );
1498 } else {
1499 $size = $threshold*2 ; # Really big
1501 } else {
1502 $size = 1 ;
1504 if ( $size < $threshold ) {
1505 $retVal = $this->makeStubLinkObj( $nt, $text, $query, $trail, $prefix );
1506 } else {
1507 $retVal = $this->makeKnownLinkObj( $nt, $text, $query, $trail, $prefix );
1511 return $retVal;
1514 # Pass a title object, not a title string
1515 function makeKnownLinkObj( &$nt, $text = "", $query = "", $trail = "", $prefix = "" , $aprops = '')
1517 global $wgOut, $wgTitle;
1519 $fname = "Skin::makeKnownLinkObj";
1520 wfProfileIn( $fname );
1522 $link = $nt->getPrefixedURL();
1524 if ( "" == $link ) {
1525 $u = "";
1526 if ( "" == $text ) {
1527 $text = htmlspecialchars( $nt->getFragment() );
1529 } else {
1530 $u = $nt->escapeLocalURL( $query );
1532 if ( "" != $nt->getFragment() ) {
1533 $u .= "#" . htmlspecialchars( $nt->getFragment() );
1535 if ( "" == $text ) {
1536 $text = htmlspecialchars( $nt->getPrefixedText() );
1538 $style = $this->getInternalLinkAttributesObj( $nt, $text );
1540 $inside = "";
1541 if ( "" != $trail ) {
1542 if ( preg_match( $this->linktrail, $trail, $m ) ) {
1543 $inside = $m[1];
1544 $trail = $m[2];
1547 $r = "<a href=\"{$u}\"{$style}{$aprops}>{$prefix}{$text}{$inside}</a>{$trail}";
1548 wfProfileOut( $fname );
1549 return $r;
1552 # Pass a title object, not a title string
1553 function makeBrokenLinkObj( &$nt, $text = "", $query = "", $trail = "", $prefix = "" )
1555 global $wgOut, $wgUser;
1557 $fname = "Skin::makeBrokenLinkObj";
1558 wfProfileIn( $fname );
1560 if ( "" == $query ) {
1561 $q = "action=edit";
1562 } else {
1563 $q = "action=edit&{$query}";
1565 $u = $nt->escapeLocalURL( $q );
1567 if ( "" == $text ) {
1568 $text = htmlspecialchars( $nt->getPrefixedText() );
1570 $style = $this->getInternalLinkAttributesObj( $nt, $text, "yes" );
1572 $inside = "";
1573 if ( "" != $trail ) {
1574 if ( preg_match( $this->linktrail, $trail, $m ) ) {
1575 $inside = $m[1];
1576 $trail = $m[2];
1579 if ( $wgUser->getOption( "highlightbroken" ) ) {
1580 $s = "<a href=\"{$u}\"{$style}>{$prefix}{$text}{$inside}</a>{$trail}";
1581 } else {
1582 $s = "{$prefix}{$text}{$inside}<a href=\"{$u}\"{$style}>?</a>{$trail}";
1585 wfProfileOut( $fname );
1586 return $s;
1589 # Pass a title object, not a title string
1590 function makeStubLinkObj( &$nt, $text = "", $query = "", $trail = "", $prefix = "" )
1592 global $wgOut, $wgUser;
1594 $link = $nt->getPrefixedURL();
1596 $u = $nt->escapeLocalURL( $query );
1598 if ( "" == $text ) {
1599 $text = htmlspecialchars( $nt->getPrefixedText() );
1601 $style = $this->getInternalLinkAttributesObj( $nt, $text, "stub" );
1603 $inside = "";
1604 if ( "" != $trail ) {
1605 if ( preg_match( $this->linktrail, $trail, $m ) ) {
1606 $inside = $m[1];
1607 $trail = $m[2];
1610 if ( $wgUser->getOption( "highlightbroken" ) ) {
1611 $s = "<a href=\"{$u}\"{$style}>{$prefix}{$text}{$inside}</a>{$trail}";
1612 } else {
1613 $s = "{$prefix}{$text}{$inside}<a href=\"{$u}\"{$style}>!</a>{$trail}";
1615 return $s;
1618 function makeSelfLinkObj( &$nt, $text = "", $query = "", $trail = "", $prefix = "" )
1620 $u = $nt->escapeLocalURL( $query );
1621 if ( "" == $text ) {
1622 $text = htmlspecialchars( $nt->getPrefixedText() );
1624 $inside = "";
1625 if ( "" != $trail ) {
1626 if ( preg_match( $this->linktrail, $trail, $m ) ) {
1627 $inside = $m[1];
1628 $trail = $m[2];
1631 return "<strong>{$prefix}{$text}{$inside}</strong>{$trail}";
1634 /* these are used extensively in SkinPHPTal, but also some other places */
1635 /*static*/ function makeSpecialUrl( $name, $urlaction='' ) {
1636 $title = Title::makeTitle( NS_SPECIAL, $name );
1637 $this->checkTitle($title, $name);
1638 return $title->getLocalURL( $urlaction );
1640 /*static*/ function makeTalkUrl ( $name, $urlaction='' ) {
1641 $title = Title::newFromText( $name );
1642 $title = $title->getTalkPage();
1643 $this->checkTitle($title, $name);
1644 return $title->getLocalURL( $urlaction );
1646 /*static*/ function makeArticleUrl ( $name, $urlaction='' ) {
1647 $title = Title::newFromText( $name );
1648 $title= $title->getSubjectPage();
1649 $this->checkTitle($title, $name);
1650 return $title->getLocalURL( $urlaction );
1652 /*static*/ function makeI18nUrl ( $name, $urlaction='' ) {
1653 $title = Title::newFromText( wfMsg($name) );
1654 $this->checkTitle($title, $name);
1655 return $title->getLocalURL( $urlaction );
1657 /*static*/ function makeUrl ( $name, $urlaction='' ) {
1658 $title = Title::newFromText( $name );
1659 $this->checkTitle($title, $name);
1660 return $title->getLocalURL( $urlaction );
1663 /* these return an array with the 'href' and boolean 'exists' */
1664 /*static*/ function makeUrlDetails ( $name, $urlaction='' ) {
1665 $title = Title::newFromText( $name );
1666 $this->checkTitle($title, $name);
1667 return array(
1668 'href' => $title->getLocalURL( $urlaction ),
1669 'exists' => $title->getArticleID() != 0?true:false
1672 /*static*/ function makeTalkUrlDetails ( $name, $urlaction='' ) {
1673 $title = Title::newFromText( $name );
1674 $title = $title->getTalkPage();
1675 $this->checkTitle($title, $name);
1676 return array(
1677 'href' => $title->getLocalURL( $urlaction ),
1678 'exists' => $title->getArticleID() != 0?true:false
1681 /*static*/ function makeArticleUrlDetails ( $name, $urlaction='' ) {
1682 $title = Title::newFromText( $name );
1683 $title= $title->getSubjectPage();
1684 $this->checkTitle($title, $name);
1685 return array(
1686 'href' => $title->getLocalURL( $urlaction ),
1687 'exists' => $title->getArticleID() != 0?true:false
1690 /*static*/ function makeI18nUrlDetails ( $name, $urlaction='' ) {
1691 $title = Title::newFromText( wfMsg($name) );
1692 $this->checkTitle($title, $name);
1693 return array(
1694 'href' => $title->getLocalURL( $urlaction ),
1695 'exists' => $title->getArticleID() != 0?true:false
1699 # make sure we have some title to operate on
1700 /*static*/ function checkTitle ( &$title, &$name ) {
1701 if(!is_object($title)) {
1702 $title = Title::newFromText( $name );
1703 if(!is_object($title)) {
1704 $title = Title::newFromText( '<error: link target missing>' );
1709 function fnamePart( $url )
1711 $basename = strrchr( $url, "/" );
1712 if ( false === $basename ) { $basename = $url; }
1713 else { $basename = substr( $basename, 1 ); }
1714 return wfEscapeHTML( $basename );
1717 function makeImage( $url, $alt = "" )
1719 global $wgOut;
1721 if ( "" == $alt ) { $alt = $this->fnamePart( $url ); }
1722 $s = "<img src=\"{$url}\" alt=\"{$alt}\" />";
1723 return $s;
1726 function makeImageLink( $name, $url, $alt = "" ) {
1727 $nt = Title::makeTitle( Namespace::getImage(), $name );
1728 return $this->makeImageLinkObj( $nt, $alt );
1731 function makeImageLinkObj( $nt, $alt = "" ) {
1732 global $wgLang, $wgUseImageResize;
1733 $img = Image::newFromTitle( $nt );
1734 $url = $img->getURL();
1736 $align = "";
1737 $prefix = $postfix = "";
1739 if ( $wgUseImageResize ) {
1740 # Check if the alt text is of the form "options|alt text"
1741 # Options are:
1742 # * thumbnail make a thumbnail with enlarge-icon and caption, alignment depends on lang
1743 # * left no resizing, just left align. label is used for alt= only
1744 # * right same, but right aligned
1745 # * none same, but not aligned
1746 # * ___px scale to ___ pixels width, no aligning. e.g. use in taxobox
1747 # * center center the image
1748 # * framed Keep original image size, no magnify-button.
1750 $part = explode( "|", $alt);
1752 $mwThumb =& MagicWord::get( MAG_IMG_THUMBNAIL );
1753 $mwLeft =& MagicWord::get( MAG_IMG_LEFT );
1754 $mwRight =& MagicWord::get( MAG_IMG_RIGHT );
1755 $mwNone =& MagicWord::get( MAG_IMG_NONE );
1756 $mwWidth =& MagicWord::get( MAG_IMG_WIDTH );
1757 $mwCenter =& MagicWord::get( MAG_IMG_CENTER );
1758 $mwFramed =& MagicWord::get( MAG_IMG_FRAMED );
1759 $alt = $part[count($part)-1];
1761 $height = $framed = $thumb = false;
1763 foreach( $part as $key => $val ) {
1764 if ( ! is_null( $mwThumb->matchVariableStartToEnd($val) ) ) {
1765 $thumb=true;
1766 } elseif ( ! is_null( $mwRight->matchVariableStartToEnd($val) ) ) {
1767 # remember to set an alignment, don't render immediately
1768 $align = "right";
1769 } elseif ( ! is_null( $mwLeft->matchVariableStartToEnd($val) ) ) {
1770 # remember to set an alignment, don't render immediately
1771 $align = "left";
1772 } elseif ( ! is_null( $mwCenter->matchVariableStartToEnd($val) ) ) {
1773 # remember to set an alignment, don't render immediately
1774 $align = "center";
1775 } elseif ( ! is_null( $mwNone->matchVariableStartToEnd($val) ) ) {
1776 # remember to set an alignment, don't render immediately
1777 $align = "none";
1778 } elseif ( ! is_null( $match = $mwWidth->matchVariableStartToEnd($val) ) ) {
1779 # $match is the image width in pixels
1780 if ( preg_match( "/^([0-9]*)x([0-9]*)$/", $match, $m ) ) {
1781 $width = intval( $m[1] );
1782 $height = intval( $m[2] );
1783 } else {
1784 $width = intval($match);
1786 } elseif ( ! is_null( $mwFramed->matchVariableStartToEnd($val) ) ) {
1787 $framed=true;
1790 if ( "center" == $align )
1792 $prefix = '<span style="text-align: center">';
1793 $postfix = '</span>';
1794 $align = "none";
1797 if ( $thumb || $framed ) {
1799 # Create a thumbnail. Alignment depends on language
1800 # writing direction, # right aligned for left-to-right-
1801 # languages ("Western languages"), left-aligned
1802 # for right-to-left-languages ("Semitic languages")
1804 # If thumbnail width has not been provided, it is set
1805 # here to 180 pixels
1806 if ( $align == "" ) {
1807 $align = $wgLang->isRTL() ? "left" : "right";
1809 if ( ! isset($width) ) {
1810 $width = 180;
1812 return $prefix.$this->makeThumbLinkObj( $img, $alt, $align, $width, $height, $framed ).$postfix;
1814 } elseif ( isset($width) ) {
1816 # Create a resized image, without the additional thumbnail
1817 # features
1819 if ( ( ! $height === false )
1820 && ( $img->getHeight() * $width / $img->getWidth() > $height ) ) {
1821 print "height=$height<br>\nimg->getHeight() = ".$img->getHeight()."<br>\n";
1822 print "rescaling by factor ". $height / $img->getHeight() . "<br>\n";
1823 $width = $img->getWidth() * $height / $img->getHeight();
1825 $url = $img->createThumb( $width );
1827 } # endif $wgUseImageResize
1829 if ( empty( $alt ) ) {
1830 $alt = preg_replace( '/\.(.+?)^/', '', $img->getName() );
1832 $alt = htmlspecialchars( $alt );
1834 $u = $nt->escapeLocalURL();
1835 if ( $url == "" )
1837 $s = str_replace( "$1", $img->getName(), wfMsg("missingimage") );
1838 $s .= "<br>{$alt}<br>{$url}<br>\n";
1839 } else {
1840 $s = "<a href=\"{$u}\" class='image' title=\"{$alt}\">" .
1841 "<img src=\"{$url}\" alt=\"{$alt}\" /></a>";
1843 if ( "" != $align ) {
1844 $s = "<div class=\"float{$align}\"><span>{$s}</span>\n</div>";
1846 return $prefix.$s.$postfix;
1850 function makeThumbLinkObj( $img, $label = "", $align = "right", $boxwidth = 180, $boxheight=false, $framed=false ) {
1851 global $wgStylePath, $wgLang;
1852 # $image = Title::makeTitle( Namespace::getImage(), $name );
1853 $url = $img->getURL();
1855 #$label = htmlspecialchars( $label );
1856 $alt = preg_replace( "/<[^>]*>/", "", $label);
1857 $alt = htmlspecialchars( $alt );
1859 if ( $img->exists() )
1861 $width = $img->getWidth();
1862 $height = $img->getHeight();
1863 } else {
1864 $width = $height = 200;
1866 if ( $framed )
1868 // Use image dimensions, don't scale
1869 $boxwidth = $width;
1870 $oboxwidth = $boxwidth + 2;
1871 $boxheight = $height;
1872 $thumbUrl = $url;
1873 } else {
1874 $h = intval( $height/($width/$boxwidth) );
1875 $oboxwidth = $boxwidth + 2;
1876 if ( ( ! $boxheight === false ) && ( $h > $boxheight ) )
1878 $boxwidth *= $boxheight/$h;
1879 } else {
1880 $boxheight = $h;
1882 $thumbUrl = $img->createThumb( $boxwidth );
1885 $u = $img->getEscapeLocalURL();
1887 $more = htmlspecialchars( wfMsg( "thumbnail-more" ) );
1888 $magnifyalign = $wgLang->isRTL() ? "left" : "right";
1889 $textalign = $wgLang->isRTL() ? ' style="text-align:right"' : "";
1891 $s = "<div class=\"thumb t{$align}\"><div style=\"width:{$oboxwidth}px;\">";
1892 if ( $thumbUrl == "" ) {
1893 $s .= str_replace( "$1", $img->getName(), wfMsg("missingimage") );
1894 $zoomicon = '';
1895 } else {
1896 $s .= '<a href="'.$u.'" class="internal" title="'.$alt.'">'.
1897 '<img src="'.$thumbUrl.'" alt="'.$alt.'" ' .
1898 'width="'.$boxwidth.'" height="'.$boxheight.'" /></a>';
1899 if ( $framed ) {
1900 $zoomicon="";
1901 } else {
1902 $zoomicon = '<div class="magnify" style="float:'.$magnifyalign.'">'.
1903 '<a href="'.$u.'" class="internal" title="'.$more.'">'.
1904 '<img src="'.$wgStylePath.'/images/magnify-clip.png" ' .
1905 'width="15" height="11" alt="'.$more.'" /></a></div>';
1908 $s .= ' <div class="thumbcaption" '.$textalign.'>'.$zoomicon.$label."</div></div>\n</div>";
1909 return $s;
1912 function makeMediaLink( $name, $url, $alt = "" ) {
1913 $nt = Title::makeTitle( Namespace::getMedia(), $name );
1914 return $this->makeMediaLinkObj( $nt, $alt );
1917 function makeMediaLinkObj( $nt, $alt = "" )
1919 $name = $nt->getDBKey();
1920 $url = Image::wfImageUrl( $name );
1921 if ( empty( $alt ) ) {
1922 $alt = preg_replace( '/\.(.+?)^/', '', $name );
1925 $u = htmlspecialchars( $url );
1926 $s = "<a href=\"{$u}\" class='internal' title=\"{$alt}\">{$alt}</a>";
1927 return $s;
1930 function specialLink( $name, $key = "" )
1932 global $wgLang;
1934 if ( "" == $key ) { $key = strtolower( $name ); }
1935 $pn = $wgLang->ucfirst( $name );
1936 return $this->makeKnownLink( $wgLang->specialPage( $pn ),
1937 wfMsg( $key ) );
1940 function makeExternalLink( $url, $text, $escape = true ) {
1941 $style = $this->getExternalLinkAttributes( $url, $text );
1942 $url = htmlspecialchars( $url );
1943 if( $escape ) {
1944 $text = htmlspecialchars( $text );
1946 return "<a href=\"$url\"$style>$text</a>";
1949 # Called by history lists and recent changes
1952 # Returns text for the start of the tabular part of RC
1953 function beginRecentChangesList()
1955 $this->rc_cache = array() ;
1956 $this->rcMoveIndex = 0;
1957 $this->rcCacheIndex = 0 ;
1958 $this->lastdate = "";
1959 $this->rclistOpen = false;
1960 return "";
1963 function beginImageHistoryList()
1965 $s = "\n<h2>" . wfMsg( "imghistory" ) . "</h2>\n" .
1966 "<p>" . wfMsg( "imghistlegend" ) . "</p>\n<ul class='special'>";
1967 return $s;
1970 # Returns text for the end of RC
1971 # If enhanced RC is in use, returns pretty much all the text
1972 function endRecentChangesList()
1974 $s = $this->recentChangesBlock() ;
1975 if( $this->rclistOpen ) {
1976 $s .= "</ul>\n";
1978 return $s;
1981 # Enhanced RC ungrouped line
1982 function recentChangesBlockLine ( $rcObj )
1984 global $wgStylePath, $wgLang ;
1986 # Get rc_xxxx variables
1987 extract( $rcObj->mAttribs ) ;
1988 $curIdEq = "curid=$rc_cur_id";
1990 # Spacer image
1991 $r = "" ;
1993 $r .= "<img src='{$wgStylePath}/images/Arr_.png' width='12' height='12' border='0' />" ; $r .= "<tt>" ;
1995 if ( $rc_type == RC_MOVE ) {
1996 $r .= "&nbsp;&nbsp;";
1997 } else {
1998 # M & N (minor & new)
1999 $M = wfMsg( "minoreditletter" );
2000 $N = wfMsg( "newpageletter" );
2002 if ( $rc_type == RC_NEW ) {
2003 $r .= $N ;
2004 } else {
2005 $r .= "&nbsp;" ;
2007 if ( $rc_minor ) {
2008 $r .= $M ;
2009 } else {
2010 $r .= "&nbsp;" ;
2014 # Timestamp
2015 $r .= " ".$rcObj->timestamp." " ;
2016 $r .= "</tt>" ;
2018 # Article link
2019 $link = $rcObj->link ;
2020 if ( $rcObj->watched ) $link = "<strong>{$link}</strong>" ;
2021 $r .= $link ;
2023 # Cur
2024 $r .= " (" ;
2025 $r .= $rcObj->curlink ;
2026 $r .= "; " ;
2028 # Hist
2029 $r .= $this->makeKnownLinkObj( $rcObj->getTitle(), wfMsg( "hist" ), "{$curIdEq}&action=history" );
2031 # User/talk
2032 $r .= ") . . ".$rcObj->userlink ;
2033 $r .= $rcObj->usertalklink ;
2035 # Comment
2036 if ( $rc_comment != "" && $rc_type != RC_MOVE ) {
2037 $rc_comment=$this->formatComment($rc_comment);
2038 $r .= $wgLang->emphasize( " (".$rc_comment.")" );
2041 $r .= "<br />\n" ;
2042 return $r ;
2045 # Enhanced RC group
2046 function recentChangesBlockGroup ( $block )
2048 global $wgStylePath, $wgLang ;
2050 $r = "" ;
2051 $M = wfMsg( "minoreditletter" );
2052 $N = wfMsg( "newpageletter" );
2054 # Collate list of users
2055 $isnew = false ;
2056 $userlinks = array () ;
2057 foreach ( $block AS $rcObj ) {
2058 $oldid = $rcObj->mAttribs['rc_last_oldid'];
2059 if ( $rcObj->mAttribs['rc_new'] ) $isnew = true ;
2060 $u = $rcObj->userlink ;
2061 if ( !isset ( $userlinks[$u] ) ) $userlinks[$u] = 0 ;
2062 $userlinks[$u]++ ;
2065 # Sort the list and convert to text
2066 krsort ( $userlinks ) ;
2067 asort ( $userlinks ) ;
2068 $users = array () ;
2069 foreach ( $userlinks as $userlink => $count) {
2070 $text = $userlink ;
2071 if ( $count > 1 ) $text .= " ({$count}&times;)" ;
2072 array_push ( $users , $text ) ;
2074 $users = " <font size='-1'>[".implode("; ",$users)."]</font>" ;
2076 # Arrow
2077 $rci = "RCI{$this->rcCacheIndex}" ;
2078 $rcl = "RCL{$this->rcCacheIndex}" ;
2079 $rcm = "RCM{$this->rcCacheIndex}" ;
2080 $toggleLink = "javascript:toggleVisibility(\"{$rci}\",\"{$rcm}\",\"{$rcl}\")" ;
2081 $arrowdir = $wgLang->isRTL() ? "l" : "r";
2082 $tl = "<span id='{$rcm}'><a href='$toggleLink'><img src='{$wgStylePath}/images/Arr_{$arrowdir}.png' width='12' height='12' /></a></span>" ;
2083 $tl .= "<span id='{$rcl}' style='display:none'><a href='$toggleLink'><img src='{$wgStylePath}/images/Arr_d.png' width='12' height='12' /></a></span>" ;
2084 $r .= $tl ;
2086 # Main line
2087 # M/N
2088 $r .= "<tt>" ;
2089 if ( $isnew ) $r .= $N ;
2090 else $r .= "&nbsp;" ;
2091 $r .= "&nbsp;" ; # Minor
2093 # Timestamp
2094 $r .= " ".$block[0]->timestamp." " ;
2095 $r .= "</tt>" ;
2097 # Article link
2098 $link = $block[0]->link ;
2099 if ( $block[0]->watched ) $link = "<strong>{$link}</strong>" ;
2100 $r .= $link ;
2102 $curIdEq = "curid=" . $block[0]->mAttribs['rc_cur_id'];
2103 if ( $block[0]->mAttribs['rc_type'] != RC_LOG ) {
2104 # Changes
2105 $r .= " (".count($block)." " ;
2106 if ( $isnew ) $r .= wfMsg("changes");
2107 else $r .= $this->makeKnownLinkObj( $block[0]->getTitle() , wfMsg("changes") ,
2108 "{$curIdEq}&diff=0&oldid=".$oldid ) ;
2109 $r .= "; " ;
2111 # History
2112 $r .= $this->makeKnownLinkObj( $block[0]->getTitle(), wfMsg( "history" ), "{$curIdEq}&action=history" );
2113 $r .= ")" ;
2116 $r .= $users ;
2117 $r .= "<br />\n" ;
2119 # Sub-entries
2120 $r .= "<div id='{$rci}' style='display:none'>" ;
2121 foreach ( $block AS $rcObj ) {
2122 # Get rc_xxxx variables
2123 extract( $rcObj->mAttribs );
2125 $r .= "<img src='{$wgStylePath}/images/Arr_.png' width=12 height=12 />";
2126 $r .= "<tt>&nbsp; &nbsp; &nbsp; &nbsp;" ;
2127 if ( $rc_new ) $r .= $N ;
2128 else $r .= "&nbsp;" ;
2129 if ( $rc_minor ) $r .= $M ;
2130 else $r .= "&nbsp;" ;
2131 $r .= "</tt>" ;
2133 $o = "" ;
2134 if ( $rc_last_oldid != 0 ) {
2135 $o = "oldid=".$rc_last_oldid ;
2137 if ( $rc_type == RC_LOG ) {
2138 $link = $rcObj->timestamp ;
2139 } else {
2140 $link = $this->makeKnownLinkObj( $rcObj->getTitle(), $rcObj->timestamp , "{$curIdEq}&$o" ) ;
2142 $link = "<tt>{$link}</tt>" ;
2144 $r .= $link ;
2145 $r .= " (" ;
2146 $r .= $rcObj->curlink ;
2147 $r .= "; " ;
2148 $r .= $rcObj->lastlink ;
2149 $r .= ") . . ".$rcObj->userlink ;
2150 $r .= $rcObj->usertalklink ;
2151 if ( $rc_comment != "" ) {
2152 $rc_comment=$this->formatComment($rc_comment);
2153 $r .= $wgLang->emphasize( " (".$rc_comment.")" ) ;
2155 $r .= "<br />\n" ;
2157 $r .= "</div>\n" ;
2159 $this->rcCacheIndex++ ;
2160 return $r ;
2163 # If enhanced RC is in use, this function takes the previously cached
2164 # RC lines, arranges them, and outputs the HTML
2165 function recentChangesBlock ()
2167 global $wgStylePath ;
2168 if ( count ( $this->rc_cache ) == 0 ) return "" ;
2169 $blockOut = "";
2170 foreach ( $this->rc_cache AS $secureName => $block ) {
2171 if ( count ( $block ) < 2 ) {
2172 $blockOut .= $this->recentChangesBlockLine ( array_shift ( $block ) ) ;
2173 } else {
2174 $blockOut .= $this->recentChangesBlockGroup ( $block ) ;
2178 return "<div>{$blockOut}</div>" ;
2181 # Called in a loop over all displayed RC entries
2182 # Either returns the line, or caches it for later use
2183 function recentChangesLine( &$rc, $watched = false )
2185 global $wgUser ;
2186 $usenew = $wgUser->getOption( "usenewrc" );
2187 if ( $usenew )
2188 $line = $this->recentChangesLineNew ( $rc, $watched ) ;
2189 else
2190 $line = $this->recentChangesLineOld ( $rc, $watched ) ;
2191 return $line ;
2194 function recentChangesLineOld( &$rc, $watched = false )
2196 global $wgTitle, $wgLang, $wgUser, $wgRCSeconds;
2198 # Extract DB fields into local scope
2199 extract( $rc->mAttribs );
2200 $curIdEq = "curid=" . $rc_cur_id;
2202 # Make date header if necessary
2203 $date = $wgLang->date( $rc_timestamp, true);
2204 $s = "";
2205 if ( $date != $this->lastdate ) {
2206 if ( "" != $this->lastdate ) { $s .= "</ul>\n"; }
2207 $s .= "<h4>{$date}</h4>\n<ul class='special'>";
2208 $this->lastdate = $date;
2209 $this->rclistOpen = true;
2211 $s .= "<li> ";
2213 if ( $rc_type == RC_MOVE ) {
2214 # Diff
2215 $s .= "(" . wfMsg( "diff" ) . ") (";
2216 # Hist
2217 $s .= $this->makeKnownLinkObj( $rc->getMovedToTitle(), wfMsg( "hist" ), "action=history" ) .
2218 ") . . ";
2220 # "[[x]] moved to [[y]]"
2222 $s .= wfMsg( "1movedto2", $this->makeKnownLinkObj( $rc->getTitle(), "", "redirect=no" ),
2223 $this->makeKnownLinkObj( $rc->getMovedToTitle(), "" ) );
2225 } else {
2226 # Diff link
2227 if ( $rc_type == RC_NEW || $rc_type == RC_LOG ) {
2228 $diffLink = wfMsg( "diff" );
2229 } else {
2230 $diffLink = $this->makeKnownLinkObj( $rc->getTitle(), wfMsg( "diff" ),
2231 "{$curIdEq}&diff={$rc_this_oldid}&oldid={$rc_last_oldid}" ,'' ,'' , ' tabindex="'.$rc->counter.'"');
2233 $s .= "($diffLink) (";
2235 # History link
2236 $s .= $this->makeKnownLinkObj( $rc->getTitle(), wfMsg( "hist" ), "{$curIdEq}&action=history" );
2237 $s .= ") . . ";
2239 # M and N (minor and new)
2240 $M = wfMsg( "minoreditletter" );
2241 $N = wfMsg( "newpageletter" );
2242 if ( $rc_minor ) { $s .= " <strong>{$M}</strong>"; }
2243 if ( $rc_type == RC_NEW ) { $s .= "<strong>{$N}</strong>"; }
2245 # Article link
2246 $articleLink = $this->makeKnownLinkObj( $rc->getTitle(), "" );
2248 if ( $watched ) {
2249 $articleLink = "<strong>{$articleLink}</strong>";
2251 $s .= " $articleLink";
2255 # Timestamp
2256 $s .= "; " . $wgLang->time( $rc_timestamp, true, $wgRCSeconds ) . " . . ";
2258 # User link (or contributions for unregistered users)
2259 if ( 0 == $rc_user ) {
2260 $userLink = $this->makeKnownLink( $wgLang->specialPage( "Contributions" ),
2261 $rc_user_text, "target=" . $rc_user_text );
2262 } else {
2263 $userLink = $this->makeLink( $wgLang->getNsText( NS_USER ) . ":{$rc_user_text}", $rc_user_text );
2265 $s .= $userLink;
2267 # User talk link
2268 $talkname=$wgLang->getNsText(NS_TALK); # use the shorter name
2269 global $wgDisableAnonTalk;
2270 if( 0 == $rc_user && $wgDisableAnonTalk ) {
2271 $userTalkLink = "";
2272 } else {
2273 $utns=$wgLang->getNsText(NS_USER_TALK);
2274 $userTalkLink= $this->makeLink($utns . ":{$rc_user_text}", $talkname );
2276 # Block link
2277 $blockLink="";
2278 if ( ( 0 == $rc_user ) && $wgUser->isSysop() ) {
2279 $blockLink = $this->makeKnownLink( $wgLang->specialPage(
2280 "Blockip" ), wfMsg( "blocklink" ), "ip={$rc_user_text}" );
2283 if($blockLink) {
2284 if($userTalkLink) $userTalkLink .= " | ";
2285 $userTalkLink .= $blockLink;
2287 if($userTalkLink) $s.=" ({$userTalkLink})";
2289 # Add comment
2290 if ( "" != $rc_comment && "*" != $rc_comment && $rc_type != RC_MOVE ) {
2291 $rc_comment=$this->formatComment($rc_comment);
2292 $s .= $wgLang->emphasize(" (" . $rc_comment . ")");
2294 $s .= "</li>\n";
2296 return $s;
2299 # function recentChangesLineNew( $ts, $u, $ut, $ns, $ttl, $c, $isminor, $isnew, $watched = false, $oldid = 0 , $diffid = 0 )
2300 function recentChangesLineNew( &$baseRC, $watched = false )
2302 global $wgTitle, $wgLang, $wgUser, $wgRCSeconds;
2304 # Create a specialised object
2305 $rc = RCCacheEntry::newFromParent( $baseRC ) ;
2307 # Extract fields from DB into the function scope (rc_xxxx variables)
2308 extract( $rc->mAttribs );
2309 $curIdEq = "curid=" . $rc_cur_id;
2311 # If it's a new day, add the headline and flush the cache
2312 $date = $wgLang->date( $rc_timestamp, true);
2313 $ret = "" ;
2314 if ( $date != $this->lastdate ) {
2315 # Process current cache
2316 $ret = $this->recentChangesBlock () ;
2317 $this->rc_cache = array() ;
2318 $ret .= "<h4>{$date}</h4>\n";
2319 $this->lastdate = $date;
2322 # Make article link
2323 if ( $rc_type == RC_MOVE ) {
2324 $clink = $this->makeKnownLinkObj( $rc->getTitle(), "", "redirect=no" );
2325 $clink .= " " . wfMsg("movedto") . " ";
2326 $clink .= $this->makeKnownLinkObj( $rc->getMovedToTitle(), "" );
2327 } else {
2328 $clink = $this->makeKnownLinkObj( $rc->getTitle(), "" ) ;
2331 $time = $wgLang->time( $rc_timestamp, true, $wgRCSeconds );
2332 $rc->watched = $watched ;
2333 $rc->link = $clink ;
2334 $rc->timestamp = $time;
2336 # Make "cur" link
2337 if ( ( $rc_type == RC_NEW && $rc_this_oldid == 0 ) || $rc_type == RC_LOG || $rc_type == RC_MOVE) {
2338 $curLink = wfMsg( "cur" );
2339 } else {
2340 $curLink = $this->makeKnownLinkObj( $rc->getTitle(), wfMsg( "cur" ),
2341 "{$curIdEq}&diff=0&oldid={$rc_this_oldid}" ,'' ,'' , ' tabindex="'.$baseRC->counter.'"' );
2344 # Make "last" link
2345 $titleObj = $rc->getTitle();
2346 if ( $rc_last_oldid == 0 || $rc_type == RC_LOG || $rc_type == RC_MOVE ) {
2347 $lastLink = wfMsg( "last" );
2348 } else {
2349 $lastLink = $this->makeKnownLinkObj( $rc->getTitle(), wfMsg( "last" ),
2350 "{$curIdEq}&diff={$rc_this_oldid}&oldid={$rc_last_oldid}" );
2353 # Make user link (or user contributions for unregistered users)
2354 if ( 0 == $rc_user ) {
2355 $userLink = $this->makeKnownLink( $wgLang->specialPage( "Contributions" ),
2356 $rc_user_text, "target=" . $rc_user_text );
2357 } else {
2358 $userLink = $this->makeLink( $wgLang->getNsText(
2359 Namespace::getUser() ) . ":{$rc_user_text}", $rc_user_text );
2362 $rc->userlink = $userLink ;
2363 $rc->lastlink = $lastLink ;
2364 $rc->curlink = $curLink ;
2366 # Make user talk link
2367 $utns=$wgLang->getNsText(NS_USER_TALK);
2368 $talkname=$wgLang->getNsText(NS_TALK); # use the shorter name
2369 $userTalkLink= $this->makeLink($utns . ":{$rc_user_text}", $talkname );
2371 global $wgDisableAnonTalk;
2372 if ( ( 0 == $rc_user ) && $wgUser->isSysop() ) {
2373 $blockLink = $this->makeKnownLink( $wgLang->specialPage(
2374 "Blockip" ), wfMsg( "blocklink" ), "ip={$rc_user_text}" );
2375 if( $wgDisableAnonTalk )
2376 $rc->usertalklink = " ({$blockLink})";
2377 else
2378 $rc->usertalklink = " ({$userTalkLink} | {$blockLink})";
2379 } else {
2380 if( $wgDisableAnonTalk && ($rc_user == 0) )
2381 $rc->usertalklink = "";
2382 else
2383 $rc->usertalklink = " ({$userTalkLink})";
2386 # Put accumulated information into the cache, for later display
2387 # Page moves go on their own line
2388 $title = $rc->getTitle();
2389 $secureName = $title->getPrefixedDBkey();
2390 if ( $rc_type == RC_MOVE ) {
2391 # Use an @ character to prevent collision with page names
2392 $this->rc_cache["@@" . ($this->rcMoveIndex++)] = array($rc);
2393 } else {
2394 if ( !isset ( $this->rc_cache[$secureName] ) ) $this->rc_cache[$secureName] = array() ;
2395 array_push ( $this->rc_cache[$secureName] , $rc ) ;
2397 return $ret;
2400 function endImageHistoryList()
2402 $s = "</ul>\n";
2403 return $s;
2406 /* This function is called by all recent changes variants, by the page history,
2407 and by the user contributions list. It is responsible for formatting edit
2408 comments. It escapes any HTML in the comment, but adds some CSS to format
2409 auto-generated comments (from section editing) and formats [[wikilinks]].
2410 Main author: Erik Möller (moeller@scireview.de)
2412 function formatComment($comment)
2414 global $wgLang;
2415 $comment=wfEscapeHTML($comment);
2417 # The pattern for autogen comments is / * foo * /, which makes for
2418 # some nasty regex.
2419 # We look for all comments, match any text before and after the comment,
2420 # add a separator where needed and format the comment itself with CSS
2421 while (preg_match("/(.*)\/\*\s*(.*?)\s*\*\/(.*)/", $comment,$match)) {
2422 $pre=$match[1];
2423 $auto=$match[2];
2424 $post=$match[3];
2425 $sep="-";
2426 if($pre) { $auto="$sep ".$auto; }
2427 if($post) { $auto.=" $sep"; }
2428 $auto="<span class=\"autocomment\">".$auto."</span>";
2429 $comment=$pre.$auto.$post;
2432 # format regular and media links - all other wiki formatting
2433 # is ignored
2434 while(preg_match("/\[\[(.*?)(\|(.*?))*\]\]/",$comment,$match)) {
2436 $medians = $wgLang->getNsText(Namespace::getMedia());
2437 $func="makeLink";
2438 if(preg_match("/^".$medians."/i",$match[1])) {
2439 $func="makeMediaLink";
2441 if(isset($match[3]) ) {
2442 $comment=
2443 preg_replace("/\[\[(.*?)\]\]/",
2444 $this->$func($match[1],$match[3]),$comment,1);
2445 } else {
2446 $comment=
2447 preg_replace("/\[\[(.*?)\]\]/",
2448 $this->$func($match[1],$match[1]),$comment,1);
2452 return $comment;
2456 function imageHistoryLine( $iscur, $timestamp, $img, $user, $usertext, $size, $description )
2458 global $wgUser, $wgLang, $wgTitle;
2460 $datetime = $wgLang->timeanddate( $timestamp, true );
2461 $del = wfMsg( "deleteimg" );
2462 $cur = wfMsg( "cur" );
2464 if ( $iscur ) {
2465 $url = Image::wfImageUrl( $img );
2466 $rlink = $cur;
2467 if ( $wgUser->isSysop() ) {
2468 $link = $wgTitle->escapeLocalURL( "image=" . $wgTitle->getPartialURL() .
2469 "&action=delete" );
2470 $style = $this->getInternalLinkAttributes( $link, $del );
2472 $dlink = "<a href=\"{$link}\"{$style}>{$del}</a>";
2473 } else {
2474 $dlink = $del;
2476 } else {
2477 $url = wfEscapeHTML( wfImageArchiveUrl( $img ) );
2478 if( $wgUser->getID() != 0 ) {
2479 $rlink = $this->makeKnownLink( $wgTitle->getPrefixedText(),
2480 wfMsg( "revertimg" ), "action=revert&oldimage=" .
2481 urlencode( $img ) );
2482 $dlink = $this->makeKnownLink( $wgTitle->getPrefixedText(),
2483 $del, "action=delete&oldimage=" . urlencode( $img ) );
2484 } else {
2485 # Having live active links for non-logged in users
2486 # means that bots and spiders crawling our site can
2487 # inadvertently change content. Baaaad idea.
2488 $rlink = wfMsg( "revertimg" );
2489 $dlink = $del;
2492 if ( 0 == $user ) {
2493 $userlink = $usertext;
2494 } else {
2495 $userlink = $this->makeLink( $wgLang->getNsText( Namespace::getUser() ) .
2496 ":{$usertext}", $usertext );
2498 $nbytes = wfMsg( "nbytes", $size );
2499 $style = $this->getInternalLinkAttributes( $url, $datetime );
2501 $s = "<li> ({$dlink}) ({$rlink}) <a href=\"{$url}\"{$style}>{$datetime}</a>"
2502 . " . . {$userlink} ({$nbytes})";
2504 if ( "" != $description && "*" != $description ) {
2505 $sk=$wgUser->getSkin();
2506 $s .= $wgLang->emphasize(" (" . $sk->formatComment($description) . ")");
2508 $s .= "</li>\n";
2509 return $s;
2512 function tocIndent($level) {
2513 return str_repeat( "<div class='tocindent'>\n", $level>0 ? $level : 0 );
2516 function tocUnindent($level) {
2517 return str_repeat( "</div>\n", $level>0 ? $level : 0 );
2520 # parameter level defines if we are on an indentation level
2521 function tocLine( $anchor, $tocline, $level ) {
2522 $link = "<a href=\"#$anchor\">$tocline</a><br />";
2523 if($level) {
2524 return "$link\n";
2525 } else {
2526 return "<div class='tocline'>$link</div>\n";
2531 function tocTable($toc) {
2532 # note to CSS fanatics: putting this in a div does not work -- div won't auto-expand
2533 # try min-width & co when somebody gets a chance
2534 $hideline = " <script type='text/javascript'>showTocToggle(\"" . addslashes( wfMsg("showtoc") ) . "\",\"" . addslashes( wfMsg("hidetoc") ) . "\")</script>";
2535 return
2536 "<table border=\"0\" id=\"toc\"><tr><td align=\"center\">\n".
2537 "<b>".wfMsg("toc")."</b>" .
2538 $hideline .
2539 "</td></tr><tr id='tocinside'><td>\n".
2540 $toc."</td></tr></table>\n";
2543 # These two do not check for permissions: check $wgTitle->userCanEdit before calling them
2544 function editSectionScript( $section, $head ) {
2545 global $wgTitle, $wgRequest;
2546 if( $wgRequest->getInt( "oldid" ) && ( $wgRequest->getVal( "diff" ) != "0" ) ) {
2547 return $head;
2549 $url = $wgTitle->escapeLocalURL( "action=edit&section=$section" );
2550 return "<span oncontextmenu='document.location=\"$url\";return false;'>{$head}</span>";
2553 function editSectionLink( $section ) {
2554 global $wgRequest;
2555 global $wgTitle, $wgUser, $wgLang;
2557 if( $wgRequest->getInt( "oldid" ) && ( $wgRequest->getVal( "diff" ) != "0" ) ) {
2558 # Section edit links would be out of sync on an old page.
2559 # But, if we're diffing to the current page, they'll be
2560 # correct.
2561 return "";
2564 $editurl = "&section={$section}";
2565 $url = $this->makeKnownLink($wgTitle->getPrefixedText(),wfMsg("editsection"),"action=edit".$editurl);
2567 if( $wgLang->isRTL() ) {
2568 $farside = "left";
2569 $nearside = "right";
2570 } else {
2571 $farside = "right";
2572 $nearside = "left";
2574 return "<div class=\"editsection\" style=\"float:$farside;margin-$nearside:5px;\">[".$url."]</div>";
2578 // This function is called by EditPage.php and shows a bulletin board style
2579 // toolbar for common editing functions. It can be disabled in the user preferences.
2580 // The necsesary JavaScript code can be found in style/wikibits.js.
2581 function getEditToolbar() {
2582 global $wgStylePath, $wgLang, $wgMimeType;
2584 // toolarray an array of arrays which each include the filename of
2585 // the button image (without path), the opening tag, the closing tag,
2586 // and optionally a sample text that is inserted between the two when no
2587 // selection is highlighted.
2588 // The tip text is shown when the user moves the mouse over the button.
2590 // Already here are accesskeys (key), which are not used yet until someone
2591 // can figure out a way to make them work in IE. However, we should make
2592 // sure these keys are not defined on the edit page.
2593 $toolarray=array(
2594 array( "image"=>"button_bold.png",
2595 "open"=>"\'\'\'",
2596 "close"=>"\'\'\'",
2597 "sample"=>wfMsg("bold_sample"),
2598 "tip"=>wfMsg("bold_tip"),
2599 "key"=>"B"
2601 array( "image"=>"button_italic.png",
2602 "open"=>"\'\'",
2603 "close"=>"\'\'",
2604 "sample"=>wfMsg("italic_sample"),
2605 "tip"=>wfMsg("italic_tip"),
2606 "key"=>"I"
2608 array( "image"=>"button_link.png",
2609 "open"=>"[[",
2610 "close"=>"]]",
2611 "sample"=>wfMsg("link_sample"),
2612 "tip"=>wfMsg("link_tip"),
2613 "key"=>"L"
2615 array( "image"=>"button_extlink.png",
2616 "open"=>"[",
2617 "close"=>"]",
2618 "sample"=>wfMsg("extlink_sample"),
2619 "tip"=>wfMsg("extlink_tip"),
2620 "key"=>"X"
2622 array( "image"=>"button_headline.png",
2623 "open"=>"\\n== ",
2624 "close"=>" ==\\n",
2625 "sample"=>wfMsg("headline_sample"),
2626 "tip"=>wfMsg("headline_tip"),
2627 "key"=>"H"
2629 array( "image"=>"button_image.png",
2630 "open"=>"[[".$wgLang->getNsText(NS_IMAGE).":",
2631 "close"=>"]]",
2632 "sample"=>wfMsg("image_sample"),
2633 "tip"=>wfMsg("image_tip"),
2634 "key"=>"D"
2636 array( "image"=>"button_media.png",
2637 "open"=>"[[".$wgLang->getNsText(NS_MEDIA).":",
2638 "close"=>"]]",
2639 "sample"=>wfMsg("media_sample"),
2640 "tip"=>wfMsg("media_tip"),
2641 "key"=>"M"
2643 array( "image"=>"button_math.png",
2644 "open"=>"\\<math\\>",
2645 "close"=>"\\</math\\>",
2646 "sample"=>wfMsg("math_sample"),
2647 "tip"=>wfMsg("math_tip"),
2648 "key"=>"C"
2650 array( "image"=>"button_nowiki.png",
2651 "open"=>"\\<nowiki\\>",
2652 "close"=>"\\</nowiki\\>",
2653 "sample"=>wfMsg("nowiki_sample"),
2654 "tip"=>wfMsg("nowiki_tip"),
2655 "key"=>"N"
2657 array( "image"=>"button_sig.png",
2658 "open"=>"--~~~~",
2659 "close"=>"",
2660 "sample"=>"",
2661 "tip"=>wfMsg("sig_tip"),
2662 "key"=>"Y"
2664 array( "image"=>"button_hr.png",
2665 "open"=>"\\n----\\n",
2666 "close"=>"",
2667 "sample"=>"",
2668 "tip"=>wfMsg("hr_tip"),
2669 "key"=>"R"
2672 $toolbar ="<script type='text/javascript'>\n/*<![CDATA[*/\n";
2674 $toolbar.="document.writeln(\"<div id='toolbar'>\");\n";
2675 foreach($toolarray as $tool) {
2677 $image=$wgStylePath."/images/".$tool["image"];
2678 $open=$tool["open"];
2679 $close=$tool["close"];
2680 $sample = addslashes( $tool["sample"] );
2682 // Note that we use the tip both for the ALT tag and the TITLE tag of the image.
2683 // Older browsers show a "speedtip" type message only for ALT.
2684 // Ideally these should be different, realistically they
2685 // probably don't need to be.
2686 $tip = addslashes( $tool["tip"] );
2688 #$key = $tool["key"];
2690 $toolbar.="addButton('$image','$tip','$open','$close','$sample');\n";
2693 $toolbar.="addInfobox('" . addslashes( wfMsg( "infobox" ) ) . "','" . addslashes(wfMsg("infobox_alert")) . "');\n";
2694 $toolbar.="document.writeln(\"</div>\");\n";
2696 $toolbar.="/*]]>*/\n</script>";
2697 return $toolbar;
2702 require_once( "SkinStandard.php" );
2703 require_once( "SkinNostalgia.php" );
2704 require_once( "SkinCologneBlue.php" );
2706 if( $wgUsePHPTal ) {
2707 require_once( "SkinPHPTal.php" );