"REPLACE" is a "DB_WRITE" action
[mediawiki.git] / includes / Skin.php
blob97997f5998be4d72c165a9ec8d23c18e7148238a
1 <?php
3 include_once( "Feed.php" );
4 include_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 include_once( "RecentChange.php" );
27 # For some odd PHP bug, this function can't be part of a class
28 function getCategories ()
30 global $wgOut , $wgTitle , $wgUseCategoryMagic , $wgUser , $wgParser ;
31 if ( !isset ( $wgUseCategoryMagic ) || !$wgUseCategoryMagic ) return "" ;
32 if ( count ( $wgOut->mCategoryLinks ) == 0 ) return "" ;
33 if ( !$wgOut->isArticle() ) return "" ;
34 $sk = $wgUser->getSkin() ;
35 $s = "" ;
36 $s .= $sk->makeKnownLink ( "Special:Categories" , "Categories" , "article=".$wgTitle->getDBkey() ) ;
37 $t = implode ( " | " , $wgOut->mCategoryLinks ) ;
38 if ( $t != "" ) $s .= ": " ;
39 $s .= $t ;
40 return "<p class='catlinks'>$s</p>";
43 class RCCacheEntry extends RecentChange
45 var $secureName, $link;
46 var $curlink , $lastlink , $usertalklink , $versionlink ;
47 var $userlink, $timestamp, $watched;
49 function newFromParent( $rc )
51 $rc2 = new RCCacheEntry;
52 $rc2->mAttribs = $rc->mAttribs;
53 $rc2->mExtra = $rc->mExtra;
54 return $rc2;
56 } ;
58 class Skin {
60 /* private */ var $lastdate, $lastline;
61 var $linktrail ; # linktrail regexp
62 var $rc_cache ; # Cache for Enhanced Recent Changes
63 var $rcCacheIndex ; # Recent Changes Cache Counter for visibility toggle
64 var $rcMoveIndex;
66 function Skin()
68 $this->linktrail = wfMsg("linktrail");
71 function getSkinNames()
73 global $wgValidSkinNames;
74 return $wgValidSkinNames;
77 function getStylesheet()
79 return "wikistandard.css";
82 function qbSetting()
84 global $wgOut, $wgUser;
86 if ( $wgOut->isQuickbarSuppressed() ) { return 0; }
87 $q = $wgUser->getOption( "quickbar" );
88 if ( "" == $q ) { $q = 0; }
89 return $q;
92 function initPage( &$out )
94 $fname = "Skin::initPage";
95 wfProfileIn( $fname );
97 $out->addLink( array( "rel" => "shortcut icon", "href" => "/favicon.ico" ) );
99 $this->addMetadataLinks($out);
101 wfProfileOut( $fname );
104 function addMetadataLinks( &$out ) {
105 global $wgTitle, $wgEnableDublinCoreRdf, $wgEnableCreativeCommonsRdf, $wgRdfMimeType, $action;
106 global $wgRightsPage, $wgRightsUrl;
108 if( $out->isArticleRelated() ) {
109 # note: buggy CC software only reads first "meta" link
110 if( $wgEnableCreativeCommonsRdf ) {
111 $out->addMetadataLink( array(
112 'title' => 'Creative Commons',
113 'type' => 'application/rdf+xml',
114 'href' => $wgTitle->getLocalURL( "action=creativecommons") ) );
116 if( $wgEnableDublinCoreRdf ) {
117 $out->addMetadataLink( array(
118 'title' => 'Dublin Core',
119 'type' => 'application/rdf+xml',
120 'href' => $wgTitle->getLocalURL( "action=dublincore" ) ) );
123 $copyright = "";
124 if( $wgRightsPage ) {
125 $copy = Title::newFromText( $wgRightsPage );
126 if( $copy ) {
127 $copyright = $copy->getLocalURL();
130 if( !$copyright && $wgRightsUrl ) {
131 $copyright = $wgRightsUrl;
133 if( $copyright ) {
134 $out->addLink( array(
135 "rel" => "copyright",
136 "href" => $copyright ) );
140 function outputPage( &$out ) {
141 global $wgDebugComments;
143 wfProfileIn( "Skin::outputPage" );
144 $this->initPage( $out );
145 $out->out( $out->headElement() );
147 $out->out( "\n<body" );
148 $ops = $this->getBodyOptions();
149 foreach ( $ops as $name => $val ) {
150 $out->out( " $name='$val'" );
152 $out->out( ">\n" );
153 if ( $wgDebugComments ) {
154 $out->out( "<!-- Wiki debugging output:\n" .
155 $out->mDebugtext . "-->\n" );
157 $out->out( $this->beforeContent() );
159 $out->out( $out->mBodytext . "\n" );
161 $out->out( $this->afterContent() );
163 wfProfileClose();
164 $out->out( $out->reportTime() );
166 $out->out( "\n</body></html>" );
169 function getHeadScripts() {
170 global $wgStyleSheetPath;
171 $r = "<script type=\"text/javascript\" src=\"{$wgStyleSheetPath}/wikibits.js\"></script>\n";
172 return $r;
175 function getUserStyles()
177 global $wgOut, $wgStyleSheetPath;
178 $sheet = $this->getStylesheet();
179 $s = "<style type='text/css'>\n";
180 $s .= "/*/*/\n"; # <-- Hide the styles from Netscape 4 without hiding them from IE/Mac
181 $s .= "@import url(\"$wgStyleSheetPath/$sheet\");\n";
182 $s .= $this->doGetUserStyles();
183 $s .= "/* */\n";
184 $s .= "</style>\n";
185 return $s;
188 function doGetUserStyles()
190 global $wgUser;
192 $s = "";
193 if ( 1 == $wgUser->getOption( "underline" ) ) {
194 # Don't override browser settings
195 } else {
196 # CHECK MERGE @@@
197 # Force no underline
198 $s .= "a { " .
199 "text-decoration: none; }\n";
201 if ( 1 == $wgUser->getOption( "highlightbroken" ) ) {
202 $s .= "a.new, #quickbar a.new { color: #CC2200; }\n";
204 if ( 1 == $wgUser->getOption( "justify" ) ) {
205 $s .= "#article { text-align: justify; }\n";
207 return $s;
210 function getBodyOptions()
212 global $wgUser, $wgTitle, $wgNamespaceBackgrounds, $wgOut, $wgRequest;
214 extract( $wgRequest->getValues( 'oldid', 'redirect', 'diff' ) );
216 if ( 0 != $wgTitle->getNamespace() ) {
217 $a = array( "bgcolor" => "#ffffec" );
219 else $a = array( "bgcolor" => "#FFFFFF" );
220 if($wgOut->isArticle() && $wgUser->getOption("editondblclick") &&
221 (!$wgTitle->isProtected() || $wgUser->isSysop()) ) {
222 $t = wfMsg( "editthispage" );
223 $oid = $red = "";
224 if ( !empty($redirect) ) {
225 $red = "&redirect={$redirect}";
227 if ( !empty($oldid) && ! isset( $diff ) ) {
228 $oid = "&oldid={$oldid}";
230 $s = $wgTitle->getFullURL( "action=edit{$oid}{$red}" );
231 $s = "document.location = \"" .$s ."\";";
232 $a += array ("ondblclick" => $s);
235 $a['onload'] = $wgOut->getOnloadHandler();
236 return $a;
239 function getExternalLinkAttributes( $link, $text )
241 global $wgUser, $wgOut, $wgLang;
243 $link = urldecode( $link );
244 $link = $wgLang->checkTitleEncoding( $link );
245 $link = str_replace( "_", " ", $link );
246 $link = wfEscapeHTML( $link );
248 $r = " class='external'";
250 if ( 1 == $wgUser->getOption( "hover" ) ) {
251 $r .= " title=\"{$link}\"";
253 return $r;
256 function getInternalLinkAttributes( $link, $text, $broken = false )
258 global $wgUser, $wgOut;
260 $link = urldecode( $link );
261 $link = str_replace( "_", " ", $link );
262 $link = wfEscapeHTML( $link );
264 if ( $broken == "stub" ) {
265 $r = " class='stub'";
266 } else if ( $broken == "yes" ) {
267 $r = " class='new'";
268 } else {
269 $r = "";
272 if ( 1 == $wgUser->getOption( "hover" ) ) {
273 $r .= " title=\"{$link}\"";
275 return $r;
278 function getInternalLinkAttributesObj( &$nt, $text, $broken = false )
280 global $wgUser, $wgOut;
282 if ( $broken == "stub" ) {
283 $r = " class='stub'";
284 } else if ( $broken == "yes" ) {
285 $r = " class='new'";
286 } else {
287 $r = "";
290 if ( 1 == $wgUser->getOption( "hover" ) ) {
291 $r .= ' title ="' . $nt->getEscapedText() . '"';
293 return $r;
296 function getLogo()
298 global $wgLogo;
299 return $wgLogo;
302 # This will be called immediately after the <body> tag. Split into
303 # two functions to make it easier to subclass.
305 function beforeContent()
307 global $wgUser, $wgOut, $wgSiteNotice;
309 if( $wgSiteNotice ) {
310 $note = "\n<div id='notice' style='font-weight: bold; color: red; text-align: center'>$wgSiteNotice</div>\n";
311 } else {
312 $note = "";
314 return $this->doBeforeContent() . $note;
317 function doBeforeContent()
319 global $wgUser, $wgOut, $wgTitle, $wgLang;
320 $fname = "Skin::doBeforeContent";
321 wfProfileIn( $fname );
323 $s = "";
324 $qb = $this->qbSetting();
326 if( $langlinks = $this->otherLanguages() ) {
327 $rows = 2;
328 $borderhack = "";
329 } else {
330 $rows = 1;
331 $langlinks = false;
332 $borderhack = "class='top'";
335 $s .= "\n<div id='content'>\n<div id='topbar'>\n" .
336 "<table border='0' cellspacing='0' width='98%'>\n<tr>\n";
338 $shove = ($qb != 0);
339 $left = ($qb == 1 || $qb == 3);
340 if($wgLang->isRTL()) $left = !$left;
342 if ( !$shove ) {
343 $s .= "<td class='top' align='left' valign='top' rowspan='{$rows}'>\n" .
344 $this->logoText() . "</td>";
345 } elseif( $left ) {
346 $s .= $this->getQuickbarCompensator( $rows );
348 $l = $wgLang->isRTL() ? "right" : "left";
349 $s .= "<td {$borderhack} align='$l' valign='top'>\n";
351 $s .= $this->topLinks() ;
352 $s .= "<p class='subtitle'>" . $this->pageTitleLinks() . "</p>\n";
354 $r = $wgLang->isRTL() ? "left" : "right";
355 $s .= "</td>\n<td {$borderhack} valign='top' align='$r' nowrap='nowrap'>";
356 $s .= $this->nameAndLogin();
357 $s .= "\n<br />" . $this->searchForm() . "</td>";
359 if ( $langlinks ) {
360 $s .= "</tr>\n<tr>\n<td class='top' colspan=\"2\">$langlinks</td>\n";
363 if ( $shove && !$left ) { # Right
364 $s .= $this->getQuickbarCompensator( $rows );
366 $s .= "</tr>\n</table>\n</div>\n";
367 $s .= "\n<div id='article'>\n";
369 $s .= $this->pageTitle();
370 $s .= $this->pageSubtitle() ;
371 $s .= getCategories(); // For some odd reason, zhis can't be a function of the object
372 wfProfileOut( $fname );
373 return $s;
376 function getQuickbarCompensator( $rows = 1 )
378 return "<td width='152' rowspan='{$rows}'>&nbsp;</td>";
381 # This gets called immediately before the </body> tag.
383 function afterContent()
385 global $wgUser, $wgOut, $wgServer;
386 global $wgTitle, $wgLang;
388 $printfooter = "<div class=\"printfooter\">\n" . $this->printFooter() . "</div>\n";
389 return $printfooter . $this->doAfterContent();
392 function printFooter() {
393 global $wgTitle;
394 $url = htmlspecialchars( $wgTitle->getFullURL() );
395 return "<p>" . wfMsg( "retrievedfrom", "<a href=\"$url\">$url</a>" ) .
396 "</p>\n\n<p>" . $this->pageStats() . "</p>\n";
399 function doAfterContent()
401 global $wgUser, $wgOut, $wgLang;
402 $fname = "Skin::doAfterContent";
403 wfProfileIn( $fname );
404 wfProfileIn( "$fname-1" );
406 $s = "\n</div><br clear='all' />\n";
407 $s .= "\n<div id='footer'>";
408 $s .= "<table border='0' cellspacing='0'><tr>";
410 wfProfileOut( "$fname-1" );
411 wfProfileIn( "$fname-2" );
413 $qb = $this->qbSetting();
414 $shove = ($qb != 0);
415 $left = ($qb == 1 || $qb == 3);
416 if($wgLang->isRTL()) $left = !$left;
418 if ( $shove && $left ) { # Left
419 $s .= $this->getQuickbarCompensator();
421 wfProfileOut( "$fname-2" );
422 wfProfileIn( "$fname-3" );
423 $l = $wgLang->isRTL() ? "right" : "left";
424 $s .= "<td class='bottom' align='$l' valign='top'>";
426 $s .= $this->bottomLinks();
427 $s .= "\n<br />" . $this->mainPageLink()
428 . " | " . $this->aboutLink()
429 . " | " . $this->specialLink( "recentchanges" )
430 . " | " . $this->searchForm()
431 . "<br /><span id='pagestats'>" . $this->pageStats() . "</span>";
433 $s .= "</td>";
434 if ( $shove && !$left ) { # Right
435 $s .= $this->getQuickbarCompensator();
437 $s .= "</tr></table>\n</div>\n</div>\n";
439 wfProfileOut( "$fname-3" );
440 wfProfileIn( "$fname-4" );
441 if ( 0 != $qb ) { $s .= $this->quickBar(); }
442 wfProfileOut( "$fname-4" );
443 wfProfileOut( $fname );
444 return $s;
447 function pageTitleLinks()
449 global $wgOut, $wgTitle, $wgUser, $wgLang, $wgUseApproval, $wgRequest;
451 extract( $wgRequest->getValues( 'oldid', 'diff' ) );
452 $action = $wgRequest->getText( 'action' );
454 $s = $this->printableLink();
455 if ( wfMsg ( "disclaimers" ) != "" ) $s .= " | " . $this->makeKnownLink( wfMsg( "disclaimerpage" ), wfMsg( "disclaimers" ) ) ;
457 if ( $wgOut->isArticleRelated() ) {
458 if ( $wgTitle->getNamespace() == Namespace::getImage() ) {
459 $name = $wgTitle->getDBkey();
460 $link = wfEscapeHTML( Image::wfImageUrl( $name ) );
461 $style = $this->getInternalLinkAttributes( $link, $name );
462 $s .= " | <a href=\"{$link}\"{$style}>{$name}</a>";
464 # This will show the "Approve" link if $wgUseApproval=true;
465 if ( isset ( $wgUseApproval ) && $wgUseApproval )
467 $t = $wgTitle->getDBkey();
468 $name = "Approve this article" ;
469 $link = "http://test.wikipedia.org/w/magnus/wiki.phtml?title={$t}&action=submit&doit=1" ;
470 #wfEscapeHTML( wfImageUrl( $name ) );
471 $style = $this->getExternalLinkAttributes( $link, $name );
472 $s .= " | <a href=\"{$link}\"{$style}>{$name}</a>" ;
475 if ( "history" == $action || isset( $diff ) || isset( $oldid ) ) {
476 $s .= " | " . $this->makeKnownLink( $wgTitle->getPrefixedText(),
477 wfMsg( "currentrev" ) );
480 if ( $wgUser->getNewtalk() ) {
481 # do not show "You have new messages" text when we are viewing our
482 # own talk page
484 if(!(strcmp($wgTitle->getText(),$wgUser->getName()) == 0 &&
485 $wgTitle->getNamespace()==Namespace::getTalk(Namespace::getUser()))) {
486 $n =$wgUser->getName();
487 $tl = $this->makeKnownLink( $wgLang->getNsText(
488 Namespace::getTalk( Namespace::getUser() ) ) . ":{$n}",
489 wfMsg("newmessageslink") );
490 $s.=" | <strong>". wfMsg( "newmessages", $tl ) . "</strong>";
493 if( $wgUser->isSysop() &&
494 (($wgTitle->getArticleId() == 0) || ($action == "history")) &&
495 ($n = $wgTitle->isDeleted() ) ) {
496 $s .= " | " . wfMsg( "thisisdeleted",
497 $this->makeKnownLink(
498 $wgLang->SpecialPage( "Undelete/" . $wgTitle->getPrefixedDBkey() ),
499 wfMsg( "restorelink", $n ) ) );
501 return $s;
504 function printableLink()
506 global $wgOut, $wgFeedClasses, $wgRequest;
508 $baseurl = $_SERVER['REQUEST_URI'];
509 if( strpos( "?", $baseurl ) == false ) {
510 $baseurl .= "?";
511 } else {
512 $baseurl .= "&";
514 $baseurl = htmlspecialchars( $baseurl );
515 $printurl = $wgRequest->escapeAppendQuery( "printable=yes" );
517 $s = "<a href=\"$printurl\">" . wfMsg( "printableversion" ) . "</a>";
518 if( $wgOut->isSyndicated() ) {
519 foreach( $wgFeedClasses as $format => $class ) {
520 $feedurl = $wgRequest->escapeAppendQuery( "feed=$format" );
521 $s .= " | <a href=\"$feedurl\">{$format}</a>";
524 return $s;
527 function pageTitle()
529 global $wgOut, $wgTitle, $wgUser;
531 $s = "<h1 class='pagetitle'>" . htmlspecialchars( $wgOut->getPageTitle() ) . "</h1>";
532 if($wgUser->getOption("editsectiononrightclick") && $wgTitle->userCanEdit()) { $s=$this->editSectionScript(0,$s);}
533 return $s;
536 function pageSubtitle()
538 global $wgOut,$wgTitle,$wgNamespacesWithSubpages;
540 $sub = $wgOut->getSubtitle();
541 if ( "" == $sub ) {
542 global $wgExtraSubtitle;
543 $sub = wfMsg( "fromwikipedia" ) . $wgExtraSubtitle;
545 if($wgOut->isArticle() && !empty($wgNamespacesWithSubpages[$wgTitle->getNamespace()])) {
546 $ptext=$wgTitle->getPrefixedText();
547 if(preg_match("/\//",$ptext)) {
548 $sub.="</p><p class='subpages'>";
549 $links=explode("/",$ptext);
550 $c=0;
551 $growinglink="";
552 foreach($links as $link) {
553 $c++;
554 if ($c<count($links)) {
555 $growinglink .= $link;
556 $getlink = $this->makeLink( $growinglink, $link );
557 if(preg_match("/class='new'/i",$getlink)) { break; } # this is a hack, but it saves time
558 if ($c>1) {
559 $sub .= " | ";
560 } else {
561 $sub .="&lt; ";
563 $sub .= $getlink;
564 $growinglink.="/";
570 $s = "<p class='subtitle'>{$sub}</p>\n";
571 return $s;
574 function nameAndLogin()
576 global $wgUser, $wgTitle, $wgLang, $wgShowIPinHeader, $wgIP;
578 $li = $wgLang->specialPage( "Userlogin" );
579 $lo = $wgLang->specialPage( "Userlogout" );
581 $s = "";
582 if ( 0 == $wgUser->getID() ) {
583 if( $wgShowIPinHeader && isset( $_COOKIE[ini_get("session.name")] ) ) {
584 $n = $wgIP;
586 $tl = $this->makeKnownLink( $wgLang->getNsText(
587 Namespace::getTalk( Namespace::getUser() ) ) . ":{$n}",
588 $wgLang->getNsText( Namespace::getTalk( 0 ) ) );
590 $s .= $n . " (".$tl.")";
591 } else {
592 $s .= wfMsg("notloggedin");
595 $rt = $wgTitle->getPrefixedURL();
596 if ( 0 == strcasecmp( urlencode( $lo ), $rt ) ) {
597 $q = "";
598 } else { $q = "returnto={$rt}"; }
600 $s .= "\n<br />" . $this->makeKnownLink( $li,
601 wfMsg( "login" ), $q );
602 } else {
603 $n = $wgUser->getName();
604 $rt = $wgTitle->getPrefixedURL();
605 $tl = $this->makeKnownLink( $wgLang->getNsText(
606 Namespace::getTalk( Namespace::getUser() ) ) . ":{$n}",
607 $wgLang->getNsText( Namespace::getTalk( 0 ) ) );
609 $tl = " ({$tl})";
611 $s .= $this->makeKnownLink( $wgLang->getNsText(
612 Namespace::getUser() ) . ":{$n}", $n ) . "{$tl}<br />" .
613 $this->makeKnownLink( $lo, wfMsg( "logout" ),
614 "returnto={$rt}" ) . " | " .
615 $this->specialLink( "preferences" );
617 $s .= " | " . $this->makeKnownLink( wfMsg( "helppage" ),
618 wfMsg( "help" ) );
620 return $s;
623 function getSearchLink() {
624 $searchPage =& Title::makeTitle( NS_SPECIAL, "Search" );
625 return $searchPage->getLocalURL();
628 function escapeSearchLink() {
629 return htmlspecialchars( $this->getSearchLink() );
632 function searchForm()
634 global $wgRequest;
635 $search = $wgRequest->getText( 'search' );
637 $s = "<form name='search' class='inline' method='post' action=\""
638 . $this->escapeSearchLink() . "\">\n"
639 . "<input type='text' name=\"search\" size='19' value=\""
640 . htmlspecialchars(substr($search,0,256)) . "\" />\n"
641 . "<input type='submit' name=\"go\" value=\"" . wfMsg ("go") . "\" />&nbsp;"
642 . "<input type='submit' name=\"fulltext\" value=\"" . wfMsg ("search") . "\" />\n</form>";
644 return $s;
647 function topLinks()
649 global $wgOut;
650 $sep = " |\n";
652 $s = $this->mainPageLink() . $sep
653 . $this->specialLink( "recentchanges" );
655 if ( $wgOut->isArticleRelated() ) {
656 $s .= $sep . $this->editThisPage()
657 . $sep . $this->historyLink();
659 # Many people don't like this dropdown box
660 #$s .= $sep . $this->specialPagesList();
662 return $s;
665 function bottomLinks()
667 global $wgOut, $wgUser, $wgTitle;
668 $sep = " |\n";
670 $s = "";
671 if ( $wgOut->isArticleRelated() ) {
672 $s .= "<strong>" . $this->editThisPage() . "</strong>";
673 if ( 0 != $wgUser->getID() ) {
674 $s .= $sep . $this->watchThisPage();
676 $s .= $sep . $this->talkLink()
677 . $sep . $this->historyLink()
678 . $sep . $this->whatLinksHere()
679 . $sep . $this->watchPageLinksLink();
681 if ( $wgTitle->getNamespace() == Namespace::getUser()
682 || $wgTitle->getNamespace() == Namespace::getTalk(Namespace::getUser()) )
685 $id=User::idFromName($wgTitle->getText());
686 $ip=User::isIP($wgTitle->getText());
688 if($id || $ip) { # both anons and non-anons have contri list
689 $s .= $sep . $this->userContribsLink();
691 if ( 0 != $wgUser->getID() ) { # show only to signed in users
692 if($id) { # can only email non-anons
693 $s .= $sep . $this->emailUserLink();
697 if ( $wgUser->isSysop() && $wgTitle->getArticleId() ) {
698 $s .= "\n<br />" . $this->deleteThisPage() .
699 $sep . $this->protectThisPage() .
700 $sep . $this->moveThisPage();
702 $s .= "<br />\n" . $this->otherLanguages();
704 return $s;
707 function pageStats()
709 global $wgOut, $wgLang, $wgArticle, $wgRequest;
710 global $wgDisableCounters, $wgMaxCredits;
712 extract( $wgRequest->getValues( 'oldid', 'diff' ) );
713 if ( ! $wgOut->isArticle() ) { return ""; }
714 if ( isset( $oldid ) || isset( $diff ) ) { return ""; }
715 if ( 0 == $wgArticle->getID() ) { return ""; }
717 $s = "";
718 if ( !$wgDisableCounters ) {
719 $count = $wgLang->formatNum( $wgArticle->getCount() );
720 if ( $count ) {
721 $s = wfMsg( "viewcount", $count );
724 if (!isset($wgMaxCredits) || $wgMaxCredits <= 0) {
725 $s .= $this->lastModified();
726 } else {
727 $s .= " " . $this->getCredits();
730 return $s . " " . $this->getCopyright();
733 function getCredits() {
734 $s = $this->getAuthorCredits();
735 $s .= "<br />\n " . $this->getContributorCredits();
736 return $s;
739 function getAuthorCredits() {
740 global $wgLang, $wgArticle;
742 $last_author = $wgArticle->getUser();
744 if ($last_author == 0) {
745 $author_credit = wfMsg("anonymous");
746 } else {
747 $real_name = User::whoIsReal($last_author);
748 if (!empty($real_name)) {
749 $author_credit = $real_name;
750 } else {
751 $author_credit = wfMsg("siteuser", User::whoIs($last_author));
755 $timestamp = $wgArticle->getTimestamp();
756 if ( $timestamp ) {
757 $d = $wgLang->timeanddate( $wgArticle->getTimestamp(), true );
758 } else {
759 $d = "";
761 return wfMsg("lastmodifiedby", $d, $author_credit);
764 function getContributorCredits() {
766 global $wgArticle, $wgMaxCredits, $wgLang;
768 $contributors = $wgArticle->getContributors($wgMaxCredits);
770 $real_names = array();
771 $user_names = array();
773 # Sift for real versus user names
775 foreach ($contributors as $user_id => $user_parts) {
776 if ($user_id != 0) {
777 if (!empty($user_parts[1])) {
778 $real_names[$user_id] = $user_parts[1];
779 } else {
780 $user_names[$user_id] = $user_parts[0];
785 $real = $wgLang->listToText(array_values($real_names));
786 $user = $wgLang->listToText(array_values($user_names));
788 if (!empty($user)) {
789 $user = wfMsg("siteusers", $user);
792 if ($contributors[0] && $contributors[0][0] > 0) {
793 $anon = wfMsg("anonymous");
794 } else {
795 $anon = '';
798 $creds = $wgLang->listToText(array($real, $user, $anon));
800 return wfMsg("contributions", $creds);
803 function getCopyright() {
804 global $wgRightsPage, $wgRightsUrl, $wgRightsText;
805 $out = "";
806 if( $wgRightsPage ) {
807 $link = $this->makeKnownLink( $wgRightsPage, $wgRightsText );
808 } elseif( $wgRightsUrl ) {
809 $link = $this->makeExternalLink( $wgRightsUrl, $wgRightsText );
810 } else {
811 # Give up now
812 return $out;
814 $out .= wfMsg( "copyright", $link );
815 return $out;
818 function getCopyrightIcon() {
819 global $wgRightsPage, $wgRightsUrl, $wgRightsText, $wgRightsIcon;
820 $out = "";
821 if( $wgRightsIcon ) {
822 $icon = htmlspecialchars( $wgRightsIcon );
823 if( $wgRightsUrl ) {
824 $url = htmlspecialchars( $wgRightsUrl );
825 $out .= "<a href=\"$url\">";
827 $text = htmlspecialchars( $wgRightsText );
828 $out .= "<img src=\"$icon\" alt='$text' />";
829 if( $wgRightsUrl ) {
830 $out .= "</a>";
833 return $out;
836 function getPoweredBy() {
837 global $wgUploadPath;
838 $url = htmlspecialchars( "$wgUploadPath/poweredby_mediawiki_88x31.png" );
839 $img = "<a href='http://www.mediawiki.org/'><img src='$url' alt='MediaWiki' /></a>";
840 return $img;
843 function lastModified()
845 global $wgLang, $wgArticle;
847 $timestamp = $wgArticle->getTimestamp();
848 if ( $timestamp ) {
849 $d = $wgLang->timeanddate( $wgArticle->getTimestamp(), true );
850 $s = " " . wfMsg( "lastmodified", $d );
851 } else {
852 $s = "";
854 return $s;
857 function logoText( $align = "" )
859 if ( "" != $align ) { $a = " align='{$align}'"; }
860 else { $a = ""; }
862 $mp = wfMsg( "mainpage" );
863 $titleObj = Title::newFromText( $mp );
864 $s = "<a href=\"" . $titleObj->escapeLocalURL()
865 . "\"><img{$a} src=\""
866 . $this->getLogo() . "\" alt=\"" . "[{$mp}]\" /></a>";
867 return $s;
870 function quickBar()
872 global $wgOut, $wgTitle, $wgUser, $wgRequest, $wgLang;
873 global $wgDisableUploads, $wgRemoteUploads;
875 $fname = "Skin::quickBar";
876 wfProfileIn( $fname );
878 $action = $wgRequest->getText( 'action' );
879 $wpPreview = $wgRequest->getBool( 'wpPreview' );
880 $tns=$wgTitle->getNamespace();
882 $s = "\n<div id='quickbar'>";
883 $s .= "\n" . $this->logoText() . "\n<hr class='sep' />";
885 $sep = "\n<br />";
886 $s .= $this->mainPageLink()
887 . $sep . $this->specialLink( "recentchanges" )
888 . $sep . $this->specialLink( "randompage" );
889 if ($wgUser->getID()) {
890 $s.= $sep . $this->specialLink( "watchlist" ) ;
891 $s .= $sep .$this->makeKnownLink( $wgLang->specialPage( "Contributions" ),
892 wfMsg( "mycontris" ), "target=" . wfUrlencode($wgUser->getName() ) );
895 // only show watchlist link if logged in
896 if ( wfMsg ( "currentevents" ) != "" ) $s .= $sep . $this->makeKnownLink( wfMsg( "currentevents" ), "" ) ;
897 $s .= "\n<br /><hr class='sep' />";
898 $articleExists = $wgTitle->getArticleId();
899 if ( $wgOut->isArticle() || $action =="edit" || $action =="history" || $wpPreview) {
900 if($wgOut->isArticle()) {
901 $s .= "<strong>" . $this->editThisPage() . "</strong>";
902 } else { # backlink to the article in edit or history mode
903 if($articleExists){ # no backlink if no article
904 switch($tns) {
905 case 0:
906 $text = wfMsg("articlepage");
907 break;
908 case 1:
909 $text = wfMsg("viewtalkpage");
910 break;
911 case 2:
912 $text = wfMsg("userpage");
913 break;
914 case 3:
915 $text = wfMsg("viewtalkpage");
916 break;
917 case 4:
918 $text = wfMsg("wikipediapage");
919 break;
920 case 5:
921 $text = wfMsg("viewtalkpage");
922 break;
923 case 6:
924 $text = wfMsg("imagepage");
925 break;
926 case 7:
927 $text = wfMsg("viewtalkpage");
928 break;
929 default:
930 $text= wfMsg("articlepage");
933 $link = $wgTitle->getText();
934 if ($nstext = $wgLang->getNsText($tns) ) { # add namespace if necessary
935 $link = $nstext . ":" . $link ;
938 $s .= $this->makeLink( $link, $text );
939 } elseif( $wgTitle->getNamespace() != Namespace::getSpecial() ) {
940 # we just throw in a "New page" text to tell the user that he's in edit mode,
941 # and to avoid messing with the separator that is prepended to the next item
942 $s .= "<strong>" . wfMsg("newpage") . "</strong>";
948 if( $tns%2 && $action!="edit" && !$wpPreview) {
949 $s.="<br />".$this->makeKnownLink($wgTitle->getPrefixedText(),wfMsg("postcomment"),"action=edit&section=new");
953 watching could cause problems in edit mode:
954 if user edits article, then loads "watch this article" in background and then saves
955 article with "Watch this article" checkbox disabled, the article is transparently
956 unwatched. Therefore we do not show the "Watch this page" link in edit mode
958 if ( 0 != $wgUser->getID() && $articleExists) {
959 if($action!="edit" && $action != "submit" )
961 $s .= $sep . $this->watchThisPage();
963 if ( $wgTitle->userCanEdit() )
964 $s .= $sep . $this->moveThisPage();
966 if ( $wgUser->isSysop() and $articleExists ) {
967 $s .= $sep . $this->deleteThisPage() .
968 $sep . $this->protectThisPage();
970 $s .= $sep . $this->talkLink();
971 if ($articleExists && $action !="history") {
972 $s .= $sep . $this->historyLink();
974 $s.=$sep . $this->whatLinksHere();
976 if($wgOut->isArticleRelated()) {
977 $s .= $sep . $this->watchPageLinksLink();
980 if ( Namespace::getUser() == $wgTitle->getNamespace()
981 || $wgTitle->getNamespace() == Namespace::getTalk(Namespace::getUser())
984 $id=User::idFromName($wgTitle->getText());
985 $ip=User::isIP($wgTitle->getText());
987 if($id||$ip) {
988 $s .= $sep . $this->userContribsLink();
990 if ( 0 != $wgUser->getID() ) {
991 if($id) { # can only email real users
992 $s .= $sep . $this->emailUserLink();
996 $s .= "\n<br /><hr class='sep' />";
999 if ( 0 != $wgUser->getID() && ( !$wgDisableUploads || $wgRemoteUploads ) ) {
1000 $s .= $this->specialLink( "upload" ) . $sep;
1002 $s .= $this->specialLink( "specialpages" )
1003 . $sep . $this->bugReportsLink();
1005 global $wgSiteSupportPage;
1006 if( $wgSiteSupportPage ) {
1007 $s .= "\n<br /><a href=\"" . htmlspecialchars( $wgSiteSupportPage ) .
1008 "\" class=\"internal\">" . wfMsg( "sitesupport" ) . "</a>";
1011 $s .= "\n<br /></div>\n";
1012 wfProfileOut( $fname );
1013 return $s;
1016 function specialPagesList()
1018 global $wgUser, $wgOut, $wgLang, $wgServer, $wgRedirectScript;
1019 $a = array();
1021 $validSP = $wgLang->getValidSpecialPages();
1023 foreach ( $validSP as $name => $desc ) {
1024 if ( "" == $desc ) { continue; }
1025 $a[$name] = $desc;
1027 if ( $wgUser->isSysop() )
1029 $sysopSP = $wgLang->getSysopSpecialPages();
1031 foreach ( $sysopSP as $name => $desc ) {
1032 if ( "" == $desc ) { continue; }
1033 $a[$name] = $desc ;
1036 if ( $wgUser->isDeveloper() )
1038 $devSP = $wgLang->getDeveloperSpecialPages();
1040 foreach ( $devSP as $name => $desc ) {
1041 if ( "" == $desc ) { continue; }
1042 $a[$name] = $desc ;
1045 $go = wfMsg( "go" );
1046 $sp = wfMsg( "specialpages" );
1047 $spp = $wgLang->specialPage( "Specialpages" );
1049 $s = "<form id=\"specialpages\" method=\"get\" class=\"inline\" " .
1050 "action=\"" . htmlspecialchars( "{$wgServer}{$wgRedirectScript}" ) . "\">\n";
1051 $s .= "<select name=\"wpDropdown\">\n";
1052 $s .= "<option value=\"{$spp}\">{$sp}</option>\n";
1054 foreach ( $a as $name => $desc ) {
1055 $p = $wgLang->specialPage( $name );
1056 $s .= "<option value=\"{$p}\">{$desc}</option>\n";
1058 $s .= "</select>\n";
1059 $s .= "<input type='submit' value=\"{$go}\" name='redirect' />\n";
1060 $s .= "</form>\n";
1061 return $s;
1064 function mainPageLink()
1066 $mp = wfMsg( "mainpage" );
1067 $s = $this->makeKnownLink( $mp, $mp );
1068 return $s;
1071 function copyrightLink()
1073 $s = $this->makeKnownLink( wfMsg( "copyrightpage" ),
1074 wfMsg( "copyrightpagename" ) );
1075 return $s;
1078 function aboutLink()
1080 $s = $this->makeKnownLink( wfMsg( "aboutpage" ),
1081 wfMsg( "aboutwikipedia" ) );
1082 return $s;
1086 function disclaimerLink()
1088 $s = $this->makeKnownLink( wfMsg( "disclaimerpage" ),
1089 wfMsg( "disclaimers" ) );
1090 return $s;
1093 function editThisPage()
1095 global $wgOut, $wgTitle, $wgRequest;
1097 $oldid = $wgRequest->getVal( 'oldid' );
1098 $diff = $wgRequest->getVal( 'diff' );
1099 $redirect = $wgRequest->getVal( 'redirect' );
1101 if ( ! $wgOut->isArticleRelated() ) {
1102 $s = wfMsg( "protectedpage" );
1103 } else {
1104 $n = $wgTitle->getPrefixedText();
1105 if ( $wgTitle->userCanEdit() ) {
1106 $t = wfMsg( "editthispage" );
1107 } else {
1108 #$t = wfMsg( "protectedpage" );
1109 $t = wfMsg( "viewsource" );
1111 $oid = $red = "";
1113 if ( !is_null( $redirect ) ) { $red = "&redirect={$redirect}"; }
1114 if ( $oldid && ! isset( $diff ) ) {
1115 $oid = "&oldid={$oldid}";
1117 $s = $this->makeKnownLink( $n, $t, "action=edit{$oid}{$red}" );
1119 return $s;
1122 function deleteThisPage()
1124 global $wgUser, $wgOut, $wgTitle, $wgRequest;
1126 $diff = $wgRequest->getVal( 'diff' );
1127 if ( $wgTitle->getArticleId() && ( ! $diff ) && $wgUser->isSysop() ) {
1128 $n = $wgTitle->getPrefixedText();
1129 $t = wfMsg( "deletethispage" );
1131 $s = $this->makeKnownLink( $n, $t, "action=delete" );
1132 } else {
1133 $s = "";
1135 return $s;
1138 function protectThisPage()
1140 global $wgUser, $wgOut, $wgTitle, $wgRequest;
1142 $diff = $wgRequest->getVal( 'diff' );
1143 if ( $wgTitle->getArticleId() && ( ! $diff ) && $wgUser->isSysop() ) {
1144 $n = $wgTitle->getPrefixedText();
1146 if ( $wgTitle->isProtected() ) {
1147 $t = wfMsg( "unprotectthispage" );
1148 $q = "action=unprotect";
1149 } else {
1150 $t = wfMsg( "protectthispage" );
1151 $q = "action=protect";
1153 $s = $this->makeKnownLink( $n, $t, $q );
1154 } else {
1155 $s = "";
1157 return $s;
1160 function watchThisPage()
1162 global $wgUser, $wgOut, $wgTitle;
1164 if ( $wgOut->isArticleRelated() ) {
1165 $n = $wgTitle->getPrefixedText();
1167 if ( $wgTitle->userIsWatching() ) {
1168 $t = wfMsg( "unwatchthispage" );
1169 $q = "action=unwatch";
1170 } else {
1171 $t = wfMsg( "watchthispage" );
1172 $q = "action=watch";
1174 $s = $this->makeKnownLink( $n, $t, $q );
1175 } else {
1176 $s = wfMsg( "notanarticle" );
1178 return $s;
1181 function moveThisPage()
1183 global $wgTitle, $wgLang;
1185 if ( $wgTitle->userCanEdit() ) {
1186 $s = $this->makeKnownLink( $wgLang->specialPage( "Movepage" ),
1187 wfMsg( "movethispage" ), "target=" . $wgTitle->getPrefixedURL() );
1188 } // no message if page is protected - would be redundant
1189 return $s;
1192 function historyLink()
1194 global $wgTitle;
1196 $s = $this->makeKnownLink( $wgTitle->getPrefixedText(),
1197 wfMsg( "history" ), "action=history" );
1198 return $s;
1201 function whatLinksHere()
1203 global $wgTitle, $wgLang;
1205 $s = $this->makeKnownLink( $wgLang->specialPage( "Whatlinkshere" ),
1206 wfMsg( "whatlinkshere" ), "target=" . $wgTitle->getPrefixedURL() );
1207 return $s;
1210 function userContribsLink()
1212 global $wgTitle, $wgLang;
1214 $s = $this->makeKnownLink( $wgLang->specialPage( "Contributions" ),
1215 wfMsg( "contributions" ), "target=" . $wgTitle->getPartialURL() );
1216 return $s;
1219 function emailUserLink()
1221 global $wgTitle, $wgLang;
1223 $s = $this->makeKnownLink( $wgLang->specialPage( "Emailuser" ),
1224 wfMsg( "emailuser" ), "target=" . $wgTitle->getPartialURL() );
1225 return $s;
1228 function watchPageLinksLink()
1230 global $wgOut, $wgTitle, $wgLang;
1232 if ( ! $wgOut->isArticleRelated() ) {
1233 $s = "(" . wfMsg( "notanarticle" ) . ")";
1234 } else {
1235 $s = $this->makeKnownLink( $wgLang->specialPage(
1236 "Recentchangeslinked" ), wfMsg( "recentchangeslinked" ),
1237 "target=" . $wgTitle->getPrefixedURL() );
1239 return $s;
1242 function otherLanguages()
1244 global $wgOut, $wgLang, $wgTitle, $wgUseNewInterlanguage;
1246 $a = $wgOut->getLanguageLinks();
1247 if ( 0 == count( $a ) ) {
1248 if ( !$wgUseNewInterlanguage ) return "";
1249 $ns = $wgLang->getNsIndex ( $wgTitle->getNamespace () ) ;
1250 if ( $ns != 0 AND $ns != 1 ) return "" ;
1251 $pn = "Intl" ;
1252 $x = "mode=addlink&xt=".$wgTitle->getDBkey() ;
1253 return $this->makeKnownLink( $wgLang->specialPage( $pn ),
1254 wfMsg( "intl" ) , $x );
1257 if ( !$wgUseNewInterlanguage ) {
1258 $s = wfMsg( "otherlanguages" ) . ": ";
1259 } else {
1260 global $wgLanguageCode ;
1261 $x = "mode=zoom&xt=".$wgTitle->getDBkey() ;
1262 $x .= "&xl=".$wgLanguageCode ;
1263 $s = $this->makeKnownLink( $wgLang->specialPage( "Intl" ),
1264 wfMsg( "otherlanguages" ) , $x ) . ": " ;
1267 $s = wfMsg( "otherlanguages" ) . ": ";
1268 $first = true;
1269 if($wgLang->isRTL()) $s .= "<span dir='LTR'>";
1270 foreach( $a as $l ) {
1271 if ( ! $first ) { $s .= " | "; }
1272 $first = false;
1274 $nt = Title::newFromText( $l );
1275 $url = $nt->getFullURL();
1276 $text = $wgLang->getLanguageName( $nt->getInterwiki() );
1278 if ( "" == $text ) { $text = $l; }
1279 $style = $this->getExternalLinkAttributes( $l, $text );
1280 $s .= "<a href=\"{$url}\"{$style}>{$text}</a>";
1282 if($wgLang->isRTL()) $s .= "</span>";
1283 return $s;
1286 function bugReportsLink()
1288 $s = $this->makeKnownLink( wfMsg( "bugreportspage" ),
1289 wfMsg( "bugreports" ) );
1290 return $s;
1293 function dateLink()
1295 global $wgLinkCache;
1296 $t1 = Title::newFromText( gmdate( "F j" ) );
1297 $t2 = Title::newFromText( gmdate( "Y" ) );
1299 $wgLinkCache->suspend();
1300 $id = $t1->getArticleID();
1301 $wgLinkCache->resume();
1303 if ( 0 == $id ) {
1304 $s = $this->makeBrokenLink( $t1->getText() );
1305 } else {
1306 $s = $this->makeKnownLink( $t1->getText() );
1308 $s .= ", ";
1310 $wgLinkCache->suspend();
1311 $id = $t2->getArticleID();
1312 $wgLinkCache->resume();
1314 if ( 0 == $id ) {
1315 $s .= $this->makeBrokenLink( $t2->getText() );
1316 } else {
1317 $s .= $this->makeKnownLink( $t2->getText() );
1319 return $s;
1322 function talkLink()
1324 global $wgLang, $wgTitle, $wgLinkCache;
1326 $tns = $wgTitle->getNamespace();
1327 if ( -1 == $tns ) { return ""; }
1329 $pn = $wgTitle->getText();
1330 $tp = wfMsg( "talkpage" );
1331 if ( Namespace::isTalk( $tns ) ) {
1332 $lns = Namespace::getSubject( $tns );
1333 switch($tns) {
1334 case 1:
1335 $text = wfMsg("articlepage");
1336 break;
1337 case 3:
1338 $text = wfMsg("userpage");
1339 break;
1340 case 5:
1341 $text = wfMsg("wikipediapage");
1342 break;
1343 case 7:
1344 $text = wfMsg("imagepage");
1345 break;
1346 default:
1347 $text= wfMsg("articlepage");
1349 } else {
1351 $lns = Namespace::getTalk( $tns );
1352 $text=$tp;
1354 $n = $wgLang->getNsText( $lns );
1355 if ( "" == $n ) { $link = $pn; }
1356 else { $link = "{$n}:{$pn}"; }
1358 $wgLinkCache->suspend();
1359 $s = $this->makeLink( $link, $text );
1360 $wgLinkCache->resume();
1362 return $s;
1365 function commentLink()
1367 global $wgLang, $wgTitle, $wgLinkCache;
1369 $tns = $wgTitle->getNamespace();
1370 if ( -1 == $tns ) { return ""; }
1372 $lns = ( Namespace::isTalk( $tns ) ) ? $tns : Namespace::getTalk( $tns );
1374 # assert Namespace::isTalk( $lns )
1376 $n = $wgLang->getNsText( $lns );
1377 $pn = $wgTitle->getText();
1379 $link = "{$n}:{$pn}";
1381 $wgLinkCache->suspend();
1382 $s = $this->makeKnownLink($link, wfMsg("postcomment"), "action=edit&section=new");
1383 $wgLinkCache->resume();
1385 return $s;
1388 # After all the page content is transformed into HTML, it makes
1389 # a final pass through here for things like table backgrounds.
1391 function transformContent( $text )
1393 return $text;
1396 # Note: This function MUST call getArticleID() on the link,
1397 # otherwise the cache won't get updated properly. See LINKCACHE.DOC.
1399 function makeLink( $title, $text = "", $query = "", $trail = "" ) {
1400 wfProfileIn( "Skin::makeLink" );
1401 $nt = Title::newFromText( $title );
1402 if ($nt) {
1403 $result = $this->makeLinkObj( Title::newFromText( $title ), $text, $query, $trail );
1404 } else {
1405 wfDebug( "Invalid title passed to Skin::makeLink(): \"$title\"\n" );
1406 $result = $text == "" ? $title : $text;
1409 wfProfileOut( "Skin::makeLink" );
1410 return $result;
1413 function makeKnownLink( $title, $text = "", $query = "", $trail = "", $prefix = '',$aprops = '') {
1414 $nt = Title::newFromText( $title );
1415 if ($nt) {
1416 return $this->makeKnownLinkObj( Title::newFromText( $title ), $text, $query, $trail, $prefix , $aprops );
1417 } else {
1418 wfDebug( "Invalid title passed to Skin::makeKnownLink(): \"$title\"\n" );
1419 return $text == "" ? $title : $text;
1423 function makeBrokenLink( $title, $text = "", $query = "", $trail = "" ) {
1424 $nt = Title::newFromText( $title );
1425 if ($nt) {
1426 return $this->makeBrokenLinkObj( Title::newFromText( $title ), $text, $query, $trail );
1427 } else {
1428 wfDebug( "Invalid title passed to Skin::makeBrokenLink(): \"$title\"\n" );
1429 return $text == "" ? $title : $text;
1433 function makeStubLink( $title, $text = "", $query = "", $trail = "" ) {
1434 $nt = Title::newFromText( $title );
1435 if ($nt) {
1436 return $this->makeStubLinkObj( Title::newFromText( $title ), $text, $query, $trail );
1437 } else {
1438 wfDebug( "Invalid title passed to Skin::makeStubLink(): \"$title\"\n" );
1439 return $text == "" ? $title : $text;
1443 # Pass a title object, not a title string
1444 function makeLinkObj( &$nt, $text= "", $query = "", $trail = "", $prefix = "" )
1446 global $wgOut, $wgUser;
1447 if ( $nt->isExternal() ) {
1448 $u = $nt->getFullURL();
1449 $link = $nt->getPrefixedURL();
1450 if ( "" == $text ) { $text = $nt->getPrefixedText(); }
1451 $style = $this->getExternalLinkAttributes( $link, $text );
1453 $inside = "";
1454 if ( "" != $trail ) {
1455 if ( preg_match( "/^([a-z]+)(.*)$$/sD", $trail, $m ) ) {
1456 $inside = $m[1];
1457 $trail = $m[2];
1460 $retVal = "<a href=\"{$u}\"{$style}>{$text}{$inside}</a>{$trail}";
1461 } elseif ( 0 == $nt->getNamespace() && "" == $nt->getText() ) {
1462 $retVal = $this->makeKnownLinkObj( $nt, $text, $query, $trail, $prefix );
1463 } elseif ( ( -1 == $nt->getNamespace() ) ||
1464 ( Namespace::getImage() == $nt->getNamespace() ) ) {
1465 $retVal = $this->makeKnownLinkObj( $nt, $text, $query, $trail, $prefix );
1466 } else {
1467 $aid = $nt->getArticleID() ;
1468 if ( 0 == $aid ) {
1469 $retVal = $this->makeBrokenLinkObj( $nt, $text, $query, $trail, $prefix );
1470 } else {
1471 $threshold = $wgUser->getOption("stubthreshold") ;
1472 if ( $threshold > 0 ) {
1473 $res = wfQuery ( "SELECT LENGTH(cur_text) AS x, cur_namespace, cur_is_redirect FROM cur WHERE cur_id='{$aid}'", DB_READ ) ;
1475 if ( wfNumRows( $res ) > 0 ) {
1476 $s = wfFetchObject( $res );
1477 $size = $s->x;
1478 if ( $s->cur_is_redirect OR $s->cur_namespace != 0 ) {
1479 $size = $threshold*2 ; # Really big
1481 wfFreeResult( $res );
1482 } else {
1483 $size = $threshold*2 ; # Really big
1485 } else {
1486 $size = 1 ;
1488 if ( $size < $threshold ) {
1489 $retVal = $this->makeStubLinkObj( $nt, $text, $query, $trail, $prefix );
1490 } else {
1491 $retVal = $this->makeKnownLinkObj( $nt, $text, $query, $trail, $prefix );
1495 return $retVal;
1498 # Pass a title object, not a title string
1499 function makeKnownLinkObj( &$nt, $text = "", $query = "", $trail = "", $prefix = "" , $aprops = '')
1501 global $wgOut, $wgTitle;
1503 $fname = "Skin::makeKnownLinkObj";
1504 wfProfileIn( $fname );
1506 $link = $nt->getPrefixedURL();
1508 if ( "" == $link ) {
1509 $u = "";
1510 if ( "" == $text ) {
1511 $text = htmlspecialchars( $nt->getFragment() );
1513 } else {
1514 $u = $nt->escapeLocalURL( $query );
1516 if ( "" != $nt->getFragment() ) {
1517 $u .= "#" . htmlspecialchars( $nt->getFragment() );
1519 if ( "" == $text ) {
1520 $text = htmlspecialchars( $nt->getPrefixedText() );
1522 $style = $this->getInternalLinkAttributesObj( $nt, $text );
1524 $inside = "";
1525 if ( "" != $trail ) {
1526 if ( preg_match( $this->linktrail, $trail, $m ) ) {
1527 $inside = $m[1];
1528 $trail = $m[2];
1531 $r = "<a href=\"{$u}\"{$style}{$aprops}>{$prefix}{$text}{$inside}</a>{$trail}";
1532 wfProfileOut( $fname );
1533 return $r;
1536 # Pass a title object, not a title string
1537 function makeBrokenLinkObj( &$nt, $text = "", $query = "", $trail = "", $prefix = "" )
1539 global $wgOut, $wgUser;
1541 $fname = "Skin::makeBrokenLinkObj";
1542 wfProfileIn( $fname );
1544 if ( "" == $query ) {
1545 $q = "action=edit";
1546 } else {
1547 $q = "action=edit&{$query}";
1549 $u = $nt->escapeLocalURL( $q );
1551 if ( "" == $text ) {
1552 $text = htmlspecialchars( $nt->getPrefixedText() );
1554 $style = $this->getInternalLinkAttributesObj( $nt, $text, "yes" );
1556 $inside = "";
1557 if ( "" != $trail ) {
1558 if ( preg_match( $this->linktrail, $trail, $m ) ) {
1559 $inside = $m[1];
1560 $trail = $m[2];
1563 if ( $wgUser->getOption( "highlightbroken" ) ) {
1564 $s = "<a href=\"{$u}\"{$style}>{$prefix}{$text}{$inside}</a>{$trail}";
1565 } else {
1566 $s = "{$prefix}{$text}{$inside}<a href=\"{$u}\"{$style}>?</a>{$trail}";
1569 wfProfileOut( $fname );
1570 return $s;
1573 # Pass a title object, not a title string
1574 function makeStubLinkObj( &$nt, $text = "", $query = "", $trail = "", $prefix = "" )
1576 global $wgOut, $wgUser;
1578 $link = $nt->getPrefixedURL();
1580 $u = $nt->escapeLocalURL( $query );
1582 if ( "" == $text ) {
1583 $text = htmlspecialchars( $nt->getPrefixedText() );
1585 $style = $this->getInternalLinkAttributesObj( $nt, $text, "stub" );
1587 $inside = "";
1588 if ( "" != $trail ) {
1589 if ( preg_match( $this->linktrail, $trail, $m ) ) {
1590 $inside = $m[1];
1591 $trail = $m[2];
1594 if ( $wgUser->getOption( "highlightbroken" ) ) {
1595 $s = "<a href=\"{$u}\"{$style}>{$prefix}{$text}{$inside}</a>{$trail}";
1596 } else {
1597 $s = "{$prefix}{$text}{$inside}<a href=\"{$u}\"{$style}>!</a>{$trail}";
1599 return $s;
1602 function makeSelfLinkObj( &$nt, $text = "", $query = "", $trail = "", $prefix = "" )
1604 $u = $nt->escapeLocalURL( $query );
1605 if ( "" == $text ) {
1606 $text = htmlspecialchars( $nt->getPrefixedText() );
1608 $inside = "";
1609 if ( "" != $trail ) {
1610 if ( preg_match( $this->linktrail, $trail, $m ) ) {
1611 $inside = $m[1];
1612 $trail = $m[2];
1615 return "<strong>{$prefix}{$text}{$inside}</strong>{$trail}";
1618 function fnamePart( $url )
1620 $basename = strrchr( $url, "/" );
1621 if ( false === $basename ) { $basename = $url; }
1622 else { $basename = substr( $basename, 1 ); }
1623 return wfEscapeHTML( $basename );
1626 function makeImage( $url, $alt = "" )
1628 global $wgOut;
1630 if ( "" == $alt ) { $alt = $this->fnamePart( $url ); }
1631 $s = "<img src=\"{$url}\" alt=\"{$alt}\" />";
1632 return $s;
1635 function makeImageLink( $name, $url, $alt = "" ) {
1636 $nt = Title::makeTitle( Namespace::getImage(), $name );
1637 return $this->makeImageLinkObj( $nt, $alt );
1640 function makeImageLinkObj( $nt, $alt = "" ) {
1641 global $wgLang, $wgUseImageResize;
1642 $img = Image::newFromTitle( $nt );
1643 $url = $img->getURL();
1645 $align = "";
1646 $prefix = $postfix = "";
1648 if ( $wgUseImageResize ) {
1649 # Check if the alt text is of the form "options|alt text"
1650 # Options are:
1651 # * thumbnail make a thumbnail with enlarge-icon and caption, alignment depends on lang
1652 # * left no resizing, just left align. label is used for alt= only
1653 # * right same, but right aligned
1654 # * none same, but not aligned
1655 # * ___px scale to ___ pixels width, no aligning. e.g. use in taxobox
1656 # * center center the image
1657 # * framed Keep original image size, no magnify-button.
1659 $part = explode( "|", $alt);
1661 $mwThumb =& MagicWord::get( MAG_IMG_THUMBNAIL );
1662 $mwLeft =& MagicWord::get( MAG_IMG_LEFT );
1663 $mwRight =& MagicWord::get( MAG_IMG_RIGHT );
1664 $mwNone =& MagicWord::get( MAG_IMG_NONE );
1665 $mwWidth =& MagicWord::get( MAG_IMG_WIDTH );
1666 $mwCenter =& MagicWord::get( MAG_IMG_CENTER );
1667 $mwFramed =& MagicWord::get( MAG_IMG_FRAMED );
1668 $alt = $part[count($part)-1];
1670 $framed=$thumb=false;
1672 foreach( $part as $key => $val ) {
1673 if ( ! is_null( $mwThumb->matchVariableStartToEnd($val) ) ) {
1674 $thumb=true;
1675 } elseif ( ! is_null( $mwRight->matchVariableStartToEnd($val) ) ) {
1676 # remember to set an alignment, don't render immediately
1677 $align = "right";
1678 } elseif ( ! is_null( $mwLeft->matchVariableStartToEnd($val) ) ) {
1679 # remember to set an alignment, don't render immediately
1680 $align = "left";
1681 } elseif ( ! is_null( $mwCenter->matchVariableStartToEnd($val) ) ) {
1682 # remember to set an alignment, don't render immediately
1683 $align = "center";
1684 } elseif ( ! is_null( $mwNone->matchVariableStartToEnd($val) ) ) {
1685 # remember to set an alignment, don't render immediately
1686 $align = "none";
1687 } elseif ( ! is_null( $match = $mwWidth->matchVariableStartToEnd($val) ) ) {
1688 # $match is the image width in pixels
1689 $width = intval($match);
1690 } elseif ( ! is_null( $mwFramed->matchVariableStartToEnd($val) ) ) {
1691 $framed=true;
1694 if ( "center" == $align )
1696 $prefix = '<span style="text-align: center">';
1697 $postfix = '</span>';
1698 $align = "none";
1701 if ( $thumb || $framed ) {
1703 # Create a thumbnail. Alignment depends on language
1704 # writing direction, # right aligned for left-to-right-
1705 # languages ("Western languages"), left-aligned
1706 # for right-to-left-languages ("Semitic languages")
1708 # If thumbnail width has not been provided, it is set
1709 # here to 180 pixels
1710 if ( $align == "" ) {
1711 $align = $wgLang->isRTL() ? "left" : "right";
1713 if ( ! isset($width) ) {
1714 $width = 180;
1716 return $prefix.$this->makeThumbLinkObj( $img, $alt, $align, $width, $framed ).$postfix;
1718 } elseif ( isset($width) ) {
1720 # Create a resized image, without the additional thumbnail
1721 # features
1722 $url = $img->createThumb( $width );
1724 } # endif $wgUseImageResize
1726 if ( empty( $alt ) ) {
1727 $alt = preg_replace( '/\.(.+?)^/', '', $img->getName() );
1729 $alt = htmlspecialchars( $alt );
1731 $u = $nt->escapeLocalURL();
1732 if ( $url == "" )
1734 $s = str_replace( "$1", $img->getName(), wfMsg("missingimage") );
1735 $s .= "<br>{$alt}<br>{$url}<br>\n";
1736 } else {
1737 $s = "<a href=\"{$u}\" class='image' title=\"{$alt}\">" .
1738 "<img src=\"{$url}\" alt=\"{$alt}\" /></a>";
1740 if ( "" != $align ) {
1741 $s = "<div class=\"float{$align}\"><span>{$s}</span>\n</div>";
1743 return $prefix.$s.$postfix;
1747 function makeThumbLinkObj( $img, $label = "", $align = "right", $boxwidth = 180, $framed=false ) {
1748 global $wgUploadPath, $wgLang;
1749 # $image = Title::makeTitle( Namespace::getImage(), $name );
1750 $url = $img->getURL();
1752 #$label = htmlspecialchars( $label );
1753 $alt = preg_replace( "/<[^>]*>/", "", $label);
1754 $alt = htmlspecialchars( $alt );
1756 if ( $img->exists() )
1758 $width = $img->getWidth();
1759 $height = $img->getHeight();
1760 } else {
1761 $width = $height = 200;
1763 if ( $framed )
1765 // Use image dimensions, don't scale
1766 $boxwidth = $width;
1767 $boxheight = $height;
1768 $thumbUrl = $url;
1769 } else {
1770 $boxheight = intval( $height/($width/$boxwidth) );
1771 if ( $boxwidth > $width ) {
1772 $boxwidth = $width;
1773 $boxheight = $height;
1775 $thumbUrl = $img->createThumb( $boxwidth );
1777 $oboxwidth = $boxwidth + 2;
1779 $u = $img->getEscapeLocalURL();
1781 $more = htmlspecialchars( wfMsg( "thumbnail-more" ) );
1782 $magnifyalign = $wgLang->isRTL() ? "left" : "right";
1783 $textalign = $wgLang->isRTL() ? ' style="text-align:right"' : "";
1785 $s = "<div class=\"thumb t{$align}\"\"><div style=\"width:{$oboxwidth}px;\">";
1786 if ( $thumbUrl == "" ) {
1787 $s .= str_replace( "$1", $img->getName(), wfMsg("missingimage") );
1788 $zoomicon = '';
1789 } else {
1790 $s .= '<a href="'.$u.'" class="internal" title="'.$alt.'">'.
1791 '<img src="'.$thumbUrl.'" alt="'.$alt.'" ' .
1792 'width="'.$boxwidth.'" height="'.$boxheight.'" /></a>';
1793 if ( $framed ) {
1794 $zoomicon="";
1795 } else {
1796 $zoomicon = '<div class="magnify" style="float:'.$magnifyalign.'">'.
1797 '<a href="'.$u.'" class="internal" title="'.$more.'">'.
1798 '<img src="'.$wgUploadPath.'/magnify-clip.png" ' .
1799 'width="15" height="11" alt="'.$more.'" /></a></div>';
1802 $s .= ' <div class="thumbcaption" '.$textalign.'>'.$zoomicon.$label."</div></div>\n</div>";
1803 return $s;
1806 function makeMediaLink( $name, $url, $alt = "" ) {
1807 $nt = Title::makeTitle( Namespace::getMedia(), $name );
1808 return $this->makeMediaLinkObj( $nt, $alt );
1811 function makeMediaLinkObj( $nt, $alt = "" )
1813 $name = $nt->getDBKey();
1814 $url = Image::wfImageUrl( $name );
1815 if ( empty( $alt ) ) {
1816 $alt = preg_replace( '/\.(.+?)^/', '', $name );
1819 $u = htmlspecialchars( $url );
1820 $s = "<a href=\"{$u}\" class='internal' title=\"{$alt}\">{$alt}</a>";
1821 return $s;
1824 function specialLink( $name, $key = "" )
1826 global $wgLang;
1828 if ( "" == $key ) { $key = strtolower( $name ); }
1829 $pn = $wgLang->ucfirst( $name );
1830 return $this->makeKnownLink( $wgLang->specialPage( $pn ),
1831 wfMsg( $key ) );
1834 function makeExternalLink( $url, $text, $escape = true ) {
1835 $style = $this->getExternalLinkAttributes( $url, $text );
1836 $url = htmlspecialchars( $url );
1837 if( $escape ) {
1838 $text = htmlspecialchars( $text );
1840 return "<a href=\"$url\"$style>$text</a>";
1843 # Called by history lists and recent changes
1846 # Returns text for the start of the tabular part of RC
1847 function beginRecentChangesList()
1849 $this->rc_cache = array() ;
1850 $this->rcMoveIndex = 0;
1851 $this->rcCacheIndex = 0 ;
1852 $this->lastdate = "";
1853 $this->rclistOpen = false;
1854 return "";
1857 function beginImageHistoryList()
1859 $s = "\n<h2>" . wfMsg( "imghistory" ) . "</h2>\n" .
1860 "<p>" . wfMsg( "imghistlegend" ) . "</p>\n<ul class='special'>";
1861 return $s;
1864 # Returns text for the end of RC
1865 # If enhanced RC is in use, returns pretty much all the text
1866 function endRecentChangesList()
1868 $s = $this->recentChangesBlock() ;
1869 if( $this->rclistOpen ) {
1870 $s .= "</ul>\n";
1872 return $s;
1875 # Enhanced RC ungrouped line
1876 function recentChangesBlockLine ( $rcObj )
1878 global $wgUploadPath, $wgLang ;
1880 # Get rc_xxxx variables
1881 extract( $rcObj->mAttribs ) ;
1882 $curIdEq = "curid=$rc_cur_id";
1884 # Spacer image
1885 $r = "" ;
1887 $r .= "<img src='{$wgUploadPath}/Arr_.png' width='12' height='12' border='0' />" ; $r .= "<tt>" ;
1889 if ( $rc_type == RC_MOVE ) {
1890 $r .= "&nbsp;&nbsp;";
1891 } else {
1892 # M & N (minor & new)
1893 $M = wfMsg( "minoreditletter" );
1894 $N = wfMsg( "newpageletter" );
1896 if ( $rc_type == RC_NEW ) {
1897 $r .= $N ;
1898 } else {
1899 $r .= "&nbsp;" ;
1901 if ( $rc_minor ) {
1902 $r .= $M ;
1903 } else {
1904 $r .= "&nbsp;" ;
1908 # Timestamp
1909 $r .= " ".$rcObj->timestamp." " ;
1910 $r .= "</tt>" ;
1912 # Article link
1913 $link = $rcObj->link ;
1914 if ( $rcObj->watched ) $link = "<strong>{$link}</strong>" ;
1915 $r .= $link ;
1917 # Cur
1918 $r .= " (" ;
1919 $r .= $rcObj->curlink ;
1920 $r .= "; " ;
1922 # Hist
1923 $r .= $this->makeKnownLinkObj( $rcObj->getTitle(), wfMsg( "hist" ), "{$curIdEq}&action=history" );
1925 # User/talk
1926 $r .= ") . . ".$rcObj->userlink ;
1927 $r .= $rcObj->usertalklink ;
1929 # Comment
1930 if ( $rc_comment != "" && $rc_type != RC_MOVE ) {
1931 $rc_comment=$this->formatComment($rc_comment);
1932 $r .= $wgLang->emphasize( " (".$rc_comment.")" );
1935 $r .= "<br />\n" ;
1936 return $r ;
1939 # Enhanced RC group
1940 function recentChangesBlockGroup ( $block )
1942 global $wgUploadPath, $wgLang ;
1944 $r = "" ;
1945 $M = wfMsg( "minoreditletter" );
1946 $N = wfMsg( "newpageletter" );
1948 # Collate list of users
1949 $isnew = false ;
1950 $userlinks = array () ;
1951 foreach ( $block AS $rcObj ) {
1952 $oldid = $rcObj->mAttribs['rc_last_oldid'];
1953 if ( $rcObj->mAttribs['rc_new'] ) $isnew = true ;
1954 $u = $rcObj->userlink ;
1955 if ( !isset ( $userlinks[$u] ) ) $userlinks[$u] = 0 ;
1956 $userlinks[$u]++ ;
1959 # Sort the list and convert to text
1960 krsort ( $userlinks ) ;
1961 asort ( $userlinks ) ;
1962 $users = array () ;
1963 foreach ( $userlinks as $userlink => $count) {
1964 $text = $userlink ;
1965 if ( $count > 1 ) $text .= " ({$count}&times;)" ;
1966 array_push ( $users , $text ) ;
1968 $users = " <font size='-1'>[".implode("; ",$users)."]</font>" ;
1970 # Arrow
1971 $rci = "RCI{$this->rcCacheIndex}" ;
1972 $rcl = "RCL{$this->rcCacheIndex}" ;
1973 $rcm = "RCM{$this->rcCacheIndex}" ;
1974 $toggleLink = "javascript:toggleVisibility(\"{$rci}\",\"{$rcm}\",\"{$rcl}\")" ;
1975 $arrowdir = $wgLang->isRTL() ? "l" : "r";
1976 $tl = "<span id='{$rcm}'><a href='$toggleLink'><img src='{$wgUploadPath}/Arr_{$arrowdir}.png' width='12' height='12' /></a></span>" ;
1977 $tl .= "<span id='{$rcl}' style='display:none'><a href='$toggleLink'><img src='{$wgUploadPath}/Arr_d.png' width='12' height='12' /></a></span>" ;
1978 $r .= $tl ;
1980 # Main line
1981 # M/N
1982 $r .= "<tt>" ;
1983 if ( $isnew ) $r .= $N ;
1984 else $r .= "&nbsp;" ;
1985 $r .= "&nbsp;" ; # Minor
1987 # Timestamp
1988 $r .= " ".$block[0]->timestamp." " ;
1989 $r .= "</tt>" ;
1991 # Article link
1992 $link = $block[0]->link ;
1993 if ( $block[0]->watched ) $link = "<strong>{$link}</strong>" ;
1994 $r .= $link ;
1996 $curIdEq = "curid=" . $block[0]->mAttribs['rc_cur_id'];
1997 if ( $block[0]->mAttribs['rc_type'] != RC_LOG ) {
1998 # Changes
1999 $r .= " (".count($block)." " ;
2000 if ( $isnew ) $r .= wfMsg("changes");
2001 else $r .= $this->makeKnownLinkObj( $block[0]->getTitle() , wfMsg("changes") ,
2002 "{$curIdEq}&diff=0&oldid=".$oldid ) ;
2003 $r .= "; " ;
2005 # History
2006 $r .= $this->makeKnownLinkObj( $block[0]->getTitle(), wfMsg( "history" ), "{$curIdEq}&action=history" );
2007 $r .= ")" ;
2010 $r .= $users ;
2011 $r .= "<br />\n" ;
2013 # Sub-entries
2014 $r .= "<div id='{$rci}' style='display:none'>" ;
2015 foreach ( $block AS $rcObj ) {
2016 # Get rc_xxxx variables
2017 extract( $rcObj->mAttribs );
2019 $r .= "<img src='{$wgUploadPath}/Arr_.png' width=12 height=12 />";
2020 $r .= "<tt>&nbsp; &nbsp; &nbsp; &nbsp;" ;
2021 if ( $rc_new ) $r .= $N ;
2022 else $r .= "&nbsp;" ;
2023 if ( $rc_minor ) $r .= $M ;
2024 else $r .= "&nbsp;" ;
2025 $r .= "</tt>" ;
2027 $o = "" ;
2028 if ( $rc_last_oldid != 0 ) {
2029 $o = "oldid=".$rc_last_oldid ;
2031 if ( $rc_type == RC_LOG ) {
2032 $link = $rcObj->timestamp ;
2033 } else {
2034 $link = $this->makeKnownLinkObj( $rcObj->getTitle(), $rcObj->timestamp , "{$curIdEq}&$o" ) ;
2036 $link = "<tt>{$link}</tt>" ;
2038 $r .= $link ;
2039 $r .= " (" ;
2040 $r .= $rcObj->curlink ;
2041 $r .= "; " ;
2042 $r .= $rcObj->lastlink ;
2043 $r .= ") . . ".$rcObj->userlink ;
2044 $r .= $rcObj->usertalklink ;
2045 if ( $rc_comment != "" ) {
2046 $rc_comment=$this->formatComment($rc_comment);
2047 $r .= $wgLang->emphasize( " (".$rc_comment.")" ) ;
2049 $r .= "<br />\n" ;
2051 $r .= "</div>\n" ;
2053 $this->rcCacheIndex++ ;
2054 return $r ;
2057 # If enhanced RC is in use, this function takes the previously cached
2058 # RC lines, arranges them, and outputs the HTML
2059 function recentChangesBlock ()
2061 global $wgUploadPath ;
2062 if ( count ( $this->rc_cache ) == 0 ) return "" ;
2063 $blockOut = "";
2064 foreach ( $this->rc_cache AS $secureName => $block ) {
2065 if ( count ( $block ) < 2 ) {
2066 $blockOut .= $this->recentChangesBlockLine ( array_shift ( $block ) ) ;
2067 } else {
2068 $blockOut .= $this->recentChangesBlockGroup ( $block ) ;
2072 return "<div>{$blockOut}</div>" ;
2075 # Called in a loop over all displayed RC entries
2076 # Either returns the line, or caches it for later use
2077 function recentChangesLine( &$rc, $watched = false )
2079 global $wgUser ;
2080 $usenew = $wgUser->getOption( "usenewrc" );
2081 if ( $usenew )
2082 $line = $this->recentChangesLineNew ( $rc, $watched ) ;
2083 else
2084 $line = $this->recentChangesLineOld ( $rc, $watched ) ;
2085 return $line ;
2088 function recentChangesLineOld( &$rc, $watched = false )
2090 global $wgTitle, $wgLang, $wgUser, $wgRCSeconds;
2092 # Extract DB fields into local scope
2093 extract( $rc->mAttribs );
2094 $curIdEq = "curid=" . $rc_cur_id;
2096 # Make date header if necessary
2097 $date = $wgLang->date( $rc_timestamp, true);
2098 $s = "";
2099 if ( $date != $this->lastdate ) {
2100 if ( "" != $this->lastdate ) { $s .= "</ul>\n"; }
2101 $s .= "<h4>{$date}</h4>\n<ul class='special'>";
2102 $this->lastdate = $date;
2103 $this->rclistOpen = true;
2105 $s .= "<li> ";
2107 if ( $rc_type == RC_MOVE ) {
2108 # Diff
2109 $s .= "(" . wfMsg( "diff" ) . ") (";
2110 # Hist
2111 $s .= $this->makeKnownLinkObj( $rc->getMovedToTitle(), wfMsg( "hist" ), "action=history" ) .
2112 ") . . ";
2114 # "[[x]] moved to [[y]]"
2116 $s .= wfMsg( "1movedto2", $this->makeKnownLinkObj( $rc->getTitle(), "", "redirect=no" ),
2117 $this->makeKnownLinkObj( $rc->getMovedToTitle(), "" ) );
2119 } else {
2120 # Diff link
2121 if ( $rc_type == RC_NEW || $rc_type == RC_LOG ) {
2122 $diffLink = wfMsg( "diff" );
2123 } else {
2124 $diffLink = $this->makeKnownLinkObj( $rc->getTitle(), wfMsg( "diff" ),
2125 "{$curIdEq}&diff={$rc_this_oldid}&oldid={$rc_last_oldid}" ,'' ,'' , ' tabindex="'.$rc->counter.'"');
2127 $s .= "($diffLink) (";
2129 # History link
2130 $s .= $this->makeKnownLinkObj( $rc->getTitle(), wfMsg( "hist" ), "{$curIdEq}&action=history" );
2131 $s .= ") . . ";
2133 # M and N (minor and new)
2134 $M = wfMsg( "minoreditletter" );
2135 $N = wfMsg( "newpageletter" );
2136 if ( $rc_minor ) { $s .= " <strong>{$M}</strong>"; }
2137 if ( $rc_type == RC_NEW ) { $s .= "<strong>{$N}</strong>"; }
2139 # Article link
2140 $articleLink = $this->makeKnownLinkObj( $rc->getTitle(), "" );
2142 if ( $watched ) {
2143 $articleLink = "<strong>{$articleLink}</strong>";
2145 $s .= " $articleLink";
2149 # Timestamp
2150 $s .= "; " . $wgLang->time( $rc_timestamp, true, $wgRCSeconds ) . " . . ";
2152 # User link (or contributions for unregistered users)
2153 if ( 0 == $rc_user ) {
2154 $userLink = $this->makeKnownLink( $wgLang->specialPage( "Contributions" ),
2155 $rc_user_text, "target=" . $rc_user_text );
2156 } else {
2157 $userLink = $this->makeLink( $wgLang->getNsText( NS_USER ) . ":{$rc_user_text}", $rc_user_text );
2159 $s .= $userLink;
2161 # User talk link
2162 $talkname=$wgLang->getNsText(NS_TALK); # use the shorter name
2163 global $wgDisableAnonTalk;
2164 if( 0 == $rc_user && $wgDisableAnonTalk ) {
2165 $userTalkLink = "";
2166 } else {
2167 $utns=$wgLang->getNsText(NS_USER_TALK);
2168 $userTalkLink= $this->makeLink($utns . ":{$rc_user_text}", $talkname );
2170 # Block link
2171 $blockLink="";
2172 if ( ( 0 == $rc_user ) && $wgUser->isSysop() ) {
2173 $blockLink = $this->makeKnownLink( $wgLang->specialPage(
2174 "Blockip" ), wfMsg( "blocklink" ), "ip={$rc_user_text}" );
2177 if($blockLink) {
2178 if($userTalkLink) $userTalkLink .= " | ";
2179 $userTalkLink .= $blockLink;
2181 if($userTalkLink) $s.=" ({$userTalkLink})";
2183 # Add comment
2184 if ( "" != $rc_comment && "*" != $rc_comment && $rc_type != RC_MOVE ) {
2185 $rc_comment=$this->formatComment($rc_comment);
2186 $s .= $wgLang->emphasize(" (" . $rc_comment . ")");
2188 $s .= "</li>\n";
2190 return $s;
2193 # function recentChangesLineNew( $ts, $u, $ut, $ns, $ttl, $c, $isminor, $isnew, $watched = false, $oldid = 0 , $diffid = 0 )
2194 function recentChangesLineNew( &$baseRC, $watched = false )
2196 global $wgTitle, $wgLang, $wgUser, $wgRCSeconds;
2198 # Create a specialised object
2199 $rc = RCCacheEntry::newFromParent( $baseRC ) ;
2201 # Extract fields from DB into the function scope (rc_xxxx variables)
2202 extract( $rc->mAttribs );
2203 $curIdEq = "curid=" . $rc_cur_id;
2205 # If it's a new day, add the headline and flush the cache
2206 $date = $wgLang->date( $rc_timestamp, true);
2207 $ret = "" ;
2208 if ( $date != $this->lastdate ) {
2209 # Process current cache
2210 $ret = $this->recentChangesBlock () ;
2211 $this->rc_cache = array() ;
2212 $ret .= "<h4>{$date}</h4>\n";
2213 $this->lastdate = $date;
2216 # Make article link
2217 if ( $rc_type == RC_MOVE ) {
2218 $clink = $this->makeKnownLinkObj( $rc->getTitle(), "", "redirect=no" );
2219 $clink .= " " . wfMsg("movedto") . " ";
2220 $clink .= $this->makeKnownLinkObj( $rc->getMovedToTitle(), "" );
2221 } else {
2222 $clink = $this->makeKnownLinkObj( $rc->getTitle(), "" ) ;
2225 $time = $wgLang->time( $rc_timestamp, true, $wgRCSeconds );
2226 $rc->watched = $watched ;
2227 $rc->link = $clink ;
2228 $rc->timestamp = $time;
2230 # Make "cur" link
2231 if ( ( $rc_type == RC_NEW && $rc_this_oldid == 0 ) || $rc_type == RC_LOG || $rc_type == RC_MOVE) {
2232 $curLink = wfMsg( "cur" );
2233 } else {
2234 $curLink = $this->makeKnownLinkObj( $rc->getTitle(), wfMsg( "cur" ),
2235 "{$curIdEq}&diff=0&oldid={$rc_this_oldid}" ,'' ,'' , ' tabindex="'.$baseRC->counter.'"' );
2238 # Make "last" link
2239 $titleObj = $rc->getTitle();
2240 if ( $rc_last_oldid == 0 || $rc_type == RC_LOG || $rc_type == RC_MOVE ) {
2241 $lastLink = wfMsg( "last" );
2242 } else {
2243 $lastLink = $this->makeKnownLinkObj( $rc->getTitle(), wfMsg( "last" ),
2244 "{$curIdEq}&diff={$rc_this_oldid}&oldid={$rc_last_oldid}" );
2247 # Make user link (or user contributions for unregistered users)
2248 if ( 0 == $rc_user ) {
2249 $userLink = $this->makeKnownLink( $wgLang->specialPage( "Contributions" ),
2250 $rc_user_text, "target=" . $rc_user_text );
2251 } else {
2252 $userLink = $this->makeLink( $wgLang->getNsText(
2253 Namespace::getUser() ) . ":{$rc_user_text}", $rc_user_text );
2256 $rc->userlink = $userLink ;
2257 $rc->lastlink = $lastLink ;
2258 $rc->curlink = $curLink ;
2260 # Make user talk link
2261 $utns=$wgLang->getNsText(NS_USER_TALK);
2262 $talkname=$wgLang->getNsText(NS_TALK); # use the shorter name
2263 $userTalkLink= $this->makeLink($utns . ":{$rc_user_text}", $talkname );
2265 global $wgDisableAnonTalk;
2266 if ( ( 0 == $rc_user ) && $wgUser->isSysop() ) {
2267 $blockLink = $this->makeKnownLink( $wgLang->specialPage(
2268 "Blockip" ), wfMsg( "blocklink" ), "ip={$rc_user_text}" );
2269 if( $wgDisableAnonTalk )
2270 $rc->usertalklink = " ({$blockLink})";
2271 else
2272 $rc->usertalklink = " ({$userTalkLink} | {$blockLink})";
2273 } else {
2274 if( $wgDisableAnonTalk && ($rc_user == 0) )
2275 $rc->usertalklink = "";
2276 else
2277 $rc->usertalklink = " ({$userTalkLink})";
2280 # Put accumulated information into the cache, for later display
2281 # Page moves go on their own line
2282 $title = $rc->getTitle();
2283 $secureName = $title->getPrefixedDBkey();
2284 if ( $rc_type == RC_MOVE ) {
2285 # Use an @ character to prevent collision with page names
2286 $this->rc_cache["@@" . ($this->rcMoveIndex++)] = array($rc);
2287 } else {
2288 if ( !isset ( $this->rc_cache[$secureName] ) ) $this->rc_cache[$secureName] = array() ;
2289 array_push ( $this->rc_cache[$secureName] , $rc ) ;
2291 return $ret;
2294 function endImageHistoryList()
2296 $s = "</ul>\n";
2297 return $s;
2300 /* This function is called by all recent changes variants, by the page history,
2301 and by the user contributions list. It is responsible for formatting edit
2302 comments. It escapes any HTML in the comment, but adds some CSS to format
2303 auto-generated comments (from section editing) and formats [[wikilinks]].
2304 Main author: Erik Möller (moeller@scireview.de)
2306 function formatComment($comment)
2308 global $wgLang;
2309 $comment=wfEscapeHTML($comment);
2311 # The pattern for autogen comments is / * foo * /, which makes for
2312 # some nasty regex.
2313 # We look for all comments, match any text before and after the comment,
2314 # add a separator where needed and format the comment itself with CSS
2315 while (preg_match("/(.*)\/\*\s*(.*?)\s*\*\/(.*)/", $comment,$match)) {
2316 $pre=$match[1];
2317 $auto=$match[2];
2318 $post=$match[3];
2319 $sep="-";
2320 if($pre) { $auto="$sep ".$auto; }
2321 if($post) { $auto.=" $sep"; }
2322 $auto="<span class=\"autocomment\">".$auto."</span>";
2323 $comment=$pre.$auto.$post;
2326 # format regular and media links - all other wiki formatting
2327 # is ignored
2328 while(preg_match("/\[\[(.*?)(\|(.*?))*\]\]/",$comment,$match)) {
2330 $medians = $wgLang->getNsText(Namespace::getMedia());
2331 $func="makeLink";
2332 if(preg_match("/^".$medians."/i",$match[1])) {
2333 $func="makeMediaLink";
2335 if(isset($match[3]) ) {
2336 $comment=
2337 preg_replace("/\[\[(.*?)\]\]/",
2338 $this->$func($match[1],$match[3]),$comment,1);
2339 } else {
2340 $comment=
2341 preg_replace("/\[\[(.*?)\]\]/",
2342 $this->$func($match[1],$match[1]),$comment,1);
2346 return $comment;
2350 function imageHistoryLine( $iscur, $ts, $img, $u, $ut, $size, $c )
2352 global $wgUser, $wgLang, $wgTitle;
2354 $dt = $wgLang->timeanddate( $ts, true );
2355 $del = wfMsg( "deleteimg" );
2356 $cur = wfMsg( "cur" );
2358 if ( $iscur ) {
2359 $url = Image::wfImageUrl( $img );
2360 $rlink = $cur;
2361 if ( $wgUser->isSysop() ) {
2362 $link = $wgTitle->escapeLocalURL( "image=" . $wgTitle->getPartialURL() .
2363 "&action=delete" );
2364 $style = $this->getInternalLinkAttributes( $link, $del );
2366 $dlink = "<a href=\"{$link}\"{$style}>{$del}</a>";
2367 } else {
2368 $dlink = $del;
2370 } else {
2371 $url = wfEscapeHTML( wfImageArchiveUrl( $img ) );
2372 if( $wgUser->getID() != 0 ) {
2373 $rlink = $this->makeKnownLink( $wgTitle->getPrefixedText(),
2374 wfMsg( "revertimg" ), "action=revert&oldimage=" .
2375 urlencode( $img ) );
2376 $dlink = $this->makeKnownLink( $wgTitle->getPrefixedText(),
2377 $del, "action=delete&oldimage=" . urlencode( $img ) );
2378 } else {
2379 # Having live active links for non-logged in users
2380 # means that bots and spiders crawling our site can
2381 # inadvertently change content. Baaaad idea.
2382 $rlink = wfMsg( "revertimg" );
2383 $dlink = $del;
2386 if ( 0 == $u ) { $ul = $ut; }
2387 else { $ul = $this->makeLink( $wgLang->getNsText(
2388 Namespace::getUser() ) . ":{$ut}", $ut ); }
2390 $nb = wfMsg( "nbytes", $size );
2391 $style = $this->getInternalLinkAttributes( $url, $dt );
2393 $s = "<li> ({$dlink}) ({$rlink}) <a href=\"{$url}\"{$style}>{$dt}</a>"
2394 . " . . {$ul} ({$nb})";
2396 if ( "" != $c && "*" != $c ) {
2397 $sk=$wgUser->getSkin();
2398 $s .= $wgLang->emphasize(" (" . $sk->formatComment($c) . ")");
2400 $s .= "</li>\n";
2401 return $s;
2404 function tocIndent($level) {
2405 return str_repeat( "<div class='tocindent'>\n", $level>0 ? $level : 0 );
2408 function tocUnindent($level) {
2409 return str_repeat( "</div>\n", $level>0 ? $level : 0 );
2412 # parameter level defines if we are on an indentation level
2413 function tocLine( $anchor, $tocline, $level ) {
2414 $link = "<a href=\"#$anchor\">$tocline</a><br />";
2415 if($level) {
2416 return "$link\n";
2417 } else {
2418 return "<div class='tocline'>$link</div>\n";
2423 function tocTable($toc) {
2424 # note to CSS fanatics: putting this in a div does not work -- div won't auto-expand
2425 # try min-width & co when somebody gets a chance
2426 $hideline = " <script type='text/javascript'>showTocToggle(\"" . addslashes( wfMsg("showtoc") ) . "\",\"" . addslashes( wfMsg("hidetoc") ) . "\")</script>";
2427 return
2428 "<table border=\"0\" id=\"toc\"><tr><td align=\"center\">\n".
2429 "<b>".wfMsg("toc")."</b>" .
2430 $hideline .
2431 "</td></tr><tr id='tocinside'><td>\n".
2432 $toc."</td></tr></table>\n";
2435 # These two do not check for permissions: check $wgTitle->userCanEdit before calling them
2436 function editSectionScript( $section, $head ) {
2437 global $wgTitle, $wgRequest;
2438 if( $wgRequest->getInt( "oldid" ) && ( $wgRequest->getVal( "diff" ) != "0" ) ) {
2439 return $head;
2441 $url = $wgTitle->escapeLocalURL( "action=edit&section=$section" );
2442 return "<span oncontextmenu='document.location=\"$url\";return false;'>{$head}</span>";
2445 function editSectionLink( $section ) {
2446 global $wgRequest;
2447 global $wgTitle, $wgUser, $wgLang;
2449 if( $wgRequest->getInt( "oldid" ) && ( $wgRequest->getVal( "diff" ) != "0" ) ) {
2450 # Section edit links would be out of sync on an old page.
2451 # But, if we're diffing to the current page, they'll be
2452 # correct.
2453 return "";
2456 $editurl = "&section={$section}";
2457 $url = $this->makeKnownLink($wgTitle->getPrefixedText(),wfMsg("editsection"),"action=edit".$editurl);
2459 if( $wgLang->isRTL() ) {
2460 $farside = "left";
2461 $nearside = "right";
2462 } else {
2463 $farside = "right";
2464 $nearside = "left";
2466 return "<div class=\"editsection\" style=\"float:$farside;margin-$nearside:5px;\">[".$url."]</div>";
2470 // This function is called by EditPage.php and shows a bulletin board style
2471 // toolbar for common editing functions. It can be disabled in the user preferences.
2472 // The necsesary JavaScript code can be found in style/wikibits.js.
2473 function getEditToolbar() {
2474 global $wgUploadPath, $wgLang, $wgMimeType;
2476 // toolarray an array of arrays which each include the filename of
2477 // the button image (without path), the opening tag, the closing tag,
2478 // and optionally a sample text that is inserted between the two when no
2479 // selection is highlighted.
2480 // The tip text is shown when the user moves the mouse over the button.
2482 // Already here are accesskeys (key), which are not used yet until someone
2483 // can figure out a way to make them work in IE. However, we should make
2484 // sure these keys are not defined on the edit page.
2485 $toolarray=array(
2486 array( "image"=>"button_bold.png",
2487 "open"=>"\'\'\'",
2488 "close"=>"\'\'\'",
2489 "sample"=>wfMsg("bold_sample"),
2490 "tip"=>wfMsg("bold_tip"),
2491 "key"=>"B"
2493 array( "image"=>"button_italic.png",
2494 "open"=>"\'\'",
2495 "close"=>"\'\'",
2496 "sample"=>wfMsg("italic_sample"),
2497 "tip"=>wfMsg("italic_tip"),
2498 "key"=>"I"
2500 array( "image"=>"button_link.png",
2501 "open"=>"[[",
2502 "close"=>"]]",
2503 "sample"=>wfMsg("link_sample"),
2504 "tip"=>wfMsg("link_tip"),
2505 "key"=>"L"
2507 array( "image"=>"button_extlink.png",
2508 "open"=>"[",
2509 "close"=>"]",
2510 "sample"=>wfMsg("extlink_sample"),
2511 "tip"=>wfMsg("extlink_tip"),
2512 "key"=>"X"
2514 array( "image"=>"button_headline.png",
2515 "open"=>"\\n== ",
2516 "close"=>" ==\\n",
2517 "sample"=>wfMsg("headline_sample"),
2518 "tip"=>wfMsg("headline_tip"),
2519 "key"=>"H"
2521 array( "image"=>"button_image.png",
2522 "open"=>"[[".$wgLang->getNsText(NS_IMAGE).":",
2523 "close"=>"]]",
2524 "sample"=>wfMsg("image_sample"),
2525 "tip"=>wfMsg("image_tip"),
2526 "key"=>"D"
2528 array( "image"=>"button_media.png",
2529 "open"=>"[[".$wgLang->getNsText(NS_MEDIA).":",
2530 "close"=>"]]",
2531 "sample"=>wfMsg("media_sample"),
2532 "tip"=>wfMsg("media_tip"),
2533 "key"=>"M"
2535 array( "image"=>"button_math.png",
2536 "open"=>"\\<math\\>",
2537 "close"=>"\\</math\\>",
2538 "sample"=>wfMsg("math_sample"),
2539 "tip"=>wfMsg("math_tip"),
2540 "key"=>"C"
2542 array( "image"=>"button_nowiki.png",
2543 "open"=>"\\<nowiki\\>",
2544 "close"=>"\\</nowiki\\>",
2545 "sample"=>wfMsg("nowiki_sample"),
2546 "tip"=>wfMsg("nowiki_tip"),
2547 "key"=>"N"
2549 array( "image"=>"button_sig.png",
2550 "open"=>"--~~~~",
2551 "close"=>"",
2552 "sample"=>"",
2553 "tip"=>wfMsg("sig_tip"),
2554 "key"=>"Y"
2556 array( "image"=>"button_hr.png",
2557 "open"=>"\\n----\\n",
2558 "close"=>"",
2559 "sample"=>"",
2560 "tip"=>wfMsg("hr_tip"),
2561 "key"=>"R"
2564 $toolbar ="<script type='text/javascript'>\n/*<![CDATA[*/\n";
2566 $toolbar.="document.writeln(\"<div id='toolbar'>\");\n";
2567 foreach($toolarray as $tool) {
2569 $image=$wgUploadPath."/".$tool["image"];
2570 $open=$tool["open"];
2571 $close=$tool["close"];
2572 $sample = addslashes( $tool["sample"] );
2574 // Note that we use the tip both for the ALT tag and the TITLE tag of the image.
2575 // Older browsers show a "speedtip" type message only for ALT.
2576 // Ideally these should be different, realistically they
2577 // probably don't need to be.
2578 $tip = addslashes( $tool["tip"] );
2580 #$key = $tool["key"];
2582 $toolbar.="addButton('$image','$tip','$open','$close','$sample');\n";
2585 $toolbar.="addInfobox('" . addslashes( wfMsg( "infobox" ) ) . "','" . addslashes(wfMsg("infobox_alert")) . "');\n";
2586 $toolbar.="document.writeln(\"</div>\");\n";
2588 $toolbar.="/*]]>*/\n</script>";
2589 return $toolbar;
2593 include_once( "SkinStandard.php" );
2594 include_once( "SkinNostalgia.php" );
2595 include_once( "SkinCologneBlue.php" );
2597 if( $wgUsePHPTal ) {
2598 include_once( "SkinPHPTal.php" );