* td background set to White to avoid header border shining through
[mediawiki.git] / includes / Skin.php
blob806ef1591d9964941d2ae8210d4be743a85fb19d
1 <?php
3 include_once( "Feed.php" );
5 # See skin.doc
7 # These are the INTERNAL names, which get mapped
8 # directly to class names. For display purposes, the
9 # Language class has internationalized names
11 /* private */ $wgValidSkinNames = array(
12 'standard' => "Standard",
13 'nostalgia' => "Nostalgia",
14 'cologneblue' => "CologneBlue"
16 if( $wgUsePHPTal ) {
17 #$wgValidSkinNames[] = "PHPTal";
18 #$wgValidSkinNames['davinci'] = "DaVinci";
19 #$wgValidSkinNames['mono'] = "Mono";
20 $wgValidSkinNames['monobook'] = "MonoBook";
21 #$wgValidSkinNames['monobookminimal'] = "MonoBookMinimal";
24 include_once( "RecentChange.php" );
26 # For some odd PHP bug, this function can't be part of a class
27 function getCategories ()
29 global $wgOut , $wgTitle , $wgUseCategoryMagic , $wgUser , $wgParser ;
30 if ( !isset ( $wgUseCategoryMagic ) || !$wgUseCategoryMagic ) return "" ;
31 if ( count ( $wgOut->mCategoryLinks ) == 0 ) return "" ;
32 if ( !$wgOut->isArticle() ) return "" ;
33 $sk = $wgUser->getSkin() ;
34 $s = "" ;
35 $s .= $sk->makeKnownLink ( "Special:Categories" , "Categories" , "article=".$wgTitle->getDBkey() ) ;
36 $t = implode ( " | " , $wgOut->mCategoryLinks ) ;
37 if ( $t != "" ) $s .= ": " ;
38 $s .= $t ;
39 return "<p class='catlinks'>$s</p>";
42 class RCCacheEntry extends RecentChange
44 var $secureName, $link;
45 var $curlink , $lastlink , $usertalklink , $versionlink ;
46 var $userlink, $timestamp, $watched;
48 function newFromParent( $rc )
50 $rc2 = new RCCacheEntry;
51 $rc2->mAttribs = $rc->mAttribs;
52 $rc2->mExtra = $rc->mExtra;
53 return $rc2;
55 } ;
57 class Skin {
59 /* private */ var $lastdate, $lastline;
60 var $linktrail ; # linktrail regexp
61 var $rc_cache ; # Cache for Enhanced Recent Changes
62 var $rcCacheIndex ; # Recent Changes Cache Counter for visibility toggle
63 var $rcMoveIndex;
65 function Skin()
67 $this->linktrail = wfMsg("linktrail");
70 function getSkinNames()
72 global $wgValidSkinNames;
73 return $wgValidSkinNames;
76 function getStylesheet()
78 return "wikistandard.css";
81 function qbSetting()
83 global $wgOut, $wgUser;
85 if ( $wgOut->isQuickbarSuppressed() ) { return 0; }
86 $q = $wgUser->getOption( "quickbar" );
87 if ( "" == $q ) { $q = 0; }
88 return $q;
91 function initPage( &$out )
93 $fname = "Skin::initPage";
94 wfProfileIn( $fname );
96 $out->addLink( array( "rel" => "shortcut icon", "href" => "/favicon.ico" ) );
98 $this->addMetadataLinks($out);
100 wfProfileOut( $fname );
103 function addMetadataLinks( &$out ) {
104 global $wgTitle, $wgEnableDublinCoreRdf, $wgEnableCreativeCommonsRdf, $wgRdfMimeType, $action;
105 global $wgRightsPage, $wgRightsUrl;
107 if( $out->isArticleRelated() ) {
108 # note: buggy CC software only reads first "meta" link
109 if( $wgEnableCreativeCommonsRdf ) {
110 $out->addMetadataLink( array(
111 'title' => 'Creative Commons',
112 'type' => 'application/rdf+xml',
113 'href' => $wgTitle->getLocalURL( "action=creativecommons") ) );
115 if( $wgEnableDublinCoreRdf ) {
116 $out->addMetadataLink( array(
117 'title' => 'Dublin Core',
118 'type' => 'application/rdf+xml',
119 'href' => $wgTitle->getLocalURL( "action=dublincore" ) ) );
122 $copyright = "";
123 if( $wgRightsPage ) {
124 $copy = Title::newFromText( $wgRightsPage );
125 if( $copy ) {
126 $copyright = $copy->getLocalURL();
129 if( !$copyright && $wgRightsUrl ) {
130 $copyright = $wgRightsUrl;
132 if( $copyright ) {
133 $out->addLink( array(
134 "rel" => "copyright",
135 "href" => $copyright ) );
139 function outputPage( &$out ) {
140 global $wgDebugComments;
142 wfProfileIn( "Skin::outputPage" );
143 $this->initPage( $out );
144 $out->out( $out->headElement() );
146 $out->out( "\n<body" );
147 $ops = $this->getBodyOptions();
148 foreach ( $ops as $name => $val ) {
149 $out->out( " $name='$val'" );
151 $out->out( ">\n" );
152 if ( $wgDebugComments ) {
153 $out->out( "<!-- Wiki debugging output:\n" .
154 $out->mDebugtext . "-->\n" );
156 $out->out( $this->beforeContent() );
158 $out->out( $out->mBodytext . "\n" );
160 $out->out( $this->afterContent() );
162 wfProfileClose();
163 $out->out( $out->reportTime() );
165 $out->out( "\n</body></html>" );
168 function getHeadScripts() {
169 global $wgStyleSheetPath;
170 $r = "<script type=\"text/javascript\" src=\"{$wgStyleSheetPath}/wikibits.js\"></script>\n";
171 return $r;
174 function getUserStyles()
176 global $wgOut, $wgStyleSheetPath;
177 $sheet = $this->getStylesheet();
178 $s = "<style type='text/css'>\n";
179 $s .= "/*/*/\n"; # <-- Hide the styles from Netscape 4 without hiding them from IE/Mac
180 $s .= "@import url(\"$wgStyleSheetPath/$sheet\");\n";
181 $s .= $this->doGetUserStyles();
182 $s .= "/* */\n";
183 $s .= "</style>\n";
184 return $s;
187 function doGetUserStyles()
189 global $wgUser;
191 $s = "";
192 if ( 1 == $wgUser->getOption( "underline" ) ) {
193 # Don't override browser settings
194 } else {
195 # CHECK MERGE @@@
196 # Force no underline
197 $s .= "a { " .
198 "text-decoration: none; }\n";
200 if ( 1 == $wgUser->getOption( "highlightbroken" ) ) {
201 $s .= "a.new, #quickbar a.new { color: #CC2200; }\n";
203 if ( 1 == $wgUser->getOption( "justify" ) ) {
204 $s .= "#article { text-align: justify; }\n";
206 return $s;
209 function getBodyOptions()
211 global $wgUser, $wgTitle, $wgNamespaceBackgrounds, $wgOut, $wgRequest;
213 extract( $wgRequest->getValues( 'oldid', 'redirect', 'diff' ) );
215 if ( 0 != $wgTitle->getNamespace() ) {
216 $a = array( "bgcolor" => "#ffffec" );
218 else $a = array( "bgcolor" => "#FFFFFF" );
219 if($wgOut->isArticle() && $wgUser->getOption("editondblclick") &&
220 (!$wgTitle->isProtected() || $wgUser->isSysop()) ) {
221 $t = wfMsg( "editthispage" );
222 $oid = $red = "";
223 if ( $redirect ) {
224 $red = "&redirect={$redirect}";
226 if ( !empty($oldid) && ! isset( $diff ) ) {
227 $oid = "&oldid={$oldid}";
229 $s = $wgTitle->getFullURL( "action=edit{$oid}{$red}" );
230 $s = "document.location = \"" .$s ."\";";
231 $a += array ("ondblclick" => $s);
234 $a['onload'] = $wgOut->getOnloadHandler();
235 return $a;
238 function getExternalLinkAttributes( $link, $text )
240 global $wgUser, $wgOut, $wgLang;
242 $link = urldecode( $link );
243 $link = $wgLang->checkTitleEncoding( $link );
244 $link = str_replace( "_", " ", $link );
245 $link = wfEscapeHTML( $link );
247 $r = " class='external'";
249 if ( 1 == $wgUser->getOption( "hover" ) ) {
250 $r .= " title=\"{$link}\"";
252 return $r;
255 function getInternalLinkAttributes( $link, $text, $broken = false )
257 global $wgUser, $wgOut;
259 $link = urldecode( $link );
260 $link = str_replace( "_", " ", $link );
261 $link = wfEscapeHTML( $link );
263 if ( $broken == "stub" ) {
264 $r = " class='stub'";
265 } else if ( $broken == "yes" ) {
266 $r = " class='new'";
267 } else {
268 $r = "";
271 if ( 1 == $wgUser->getOption( "hover" ) ) {
272 $r .= " title=\"{$link}\"";
274 return $r;
277 function getInternalLinkAttributesObj( &$nt, $text, $broken = false )
279 global $wgUser, $wgOut;
281 if ( $broken == "stub" ) {
282 $r = " class='stub'";
283 } else if ( $broken == "yes" ) {
284 $r = " class='new'";
285 } else {
286 $r = "";
289 if ( 1 == $wgUser->getOption( "hover" ) ) {
290 $r .= ' title ="' . $nt->getEscapedText() . '"';
292 return $r;
295 function getLogo()
297 global $wgLogo;
298 return $wgLogo;
301 # This will be called immediately after the <body> tag. Split into
302 # two functions to make it easier to subclass.
304 function beforeContent()
306 global $wgUser, $wgOut, $wgSiteNotice;
308 if( $wgSiteNotice ) {
309 $note = "\n<div id='notice' style='font-weight: bold; color: red; text-align: center'>$wgSiteNotice</div>\n";
310 } else {
311 $note = "";
313 return $this->doBeforeContent() . $note;
316 function doBeforeContent()
318 global $wgUser, $wgOut, $wgTitle, $wgLang;
319 $fname = "Skin::doBeforeContent";
320 wfProfileIn( $fname );
322 $s = "";
323 $qb = $this->qbSetting();
325 if( $langlinks = $this->otherLanguages() ) {
326 $rows = 2;
327 $borderhack = "";
328 } else {
329 $rows = 1;
330 $langlinks = false;
331 $borderhack = "class='top'";
334 $s .= "\n<div id='content'>\n<div id='topbar'>\n" .
335 "<table border='0' cellspacing='0' width='98%'>\n<tr>\n";
337 $shove = ($qb != 0);
338 $left = ($qb == 1 || $qb == 3);
339 if($wgLang->isRTL()) $left = !$left;
341 if ( !$shove ) {
342 $s .= "<td class='top' align='left' valign='top' rowspan='{$rows}'>\n" .
343 $this->logoText() . "</td>";
344 } elseif( $left ) {
345 $s .= $this->getQuickbarCompensator( $rows );
347 $l = $wgLang->isRTL() ? "right" : "left";
348 $s .= "<td {$borderhack} align='$l' valign='top'>\n";
350 $s .= $this->topLinks() ;
351 $s .= "<p class='subtitle'>" . $this->pageTitleLinks() . "</p>\n";
353 $r = $wgLang->isRTL() ? "left" : "right";
354 $s .= "</td>\n<td {$borderhack} valign='top' align='$r' nowrap='nowrap'>";
355 $s .= $this->nameAndLogin();
356 $s .= "\n<br />" . $this->searchForm() . "</td>";
358 if ( $langlinks ) {
359 $s .= "</tr>\n<tr>\n<td class='top' colspan=\"2\">$langlinks</td>\n";
362 if ( $shove && !$left ) { # Right
363 $s .= $this->getQuickbarCompensator( $rows );
365 $s .= "</tr>\n</table>\n</div>\n";
366 $s .= "\n<div id='article'>\n";
368 $s .= $this->pageTitle();
369 $s .= $this->pageSubtitle() ;
370 $s .= getCategories(); // For some odd reason, zhis can't be a function of the object
371 wfProfileOut( $fname );
372 return $s;
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 clear='all' />\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( 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,$wgTitle,$wgNamespacesWithSubpages;
539 $sub = $wgOut->getSubtitle();
540 if ( "" == $sub ) {
541 global $wgExtraSubtitle;
542 $sub = wfMsg( "fromwikipedia" ) . $wgExtraSubtitle;
544 if($wgOut->isArticle() && $wgNamespacesWithSubpages[$wgTitle->getNamespace()]) {
545 $ptext=$wgTitle->getPrefixedText();
546 if(preg_match("/\//",$ptext)) {
547 $sub.="</p><p class='subpages'>";
548 $links=explode("/",$ptext);
549 $c=0;
550 $growinglink="";
551 foreach($links as $link) {
552 $c++;
553 if ($c<count($links)) {
554 $growinglink .= $link;
555 $getlink = $this->makeLink( $growinglink, $link );
556 if(preg_match("/class='new'/i",$getlink)) { break; } # this is a hack, but it saves time
557 if ($c>1) {
558 $sub .= " | ";
559 } else {
560 $sub .="&lt; ";
562 $sub .= $getlink;
563 $growinglink.="/";
569 $s = "<p class='subtitle'>{$sub}</p>\n";
570 return $s;
573 function nameAndLogin()
575 global $wgUser, $wgTitle, $wgLang, $wgShowIPinHeader, $wgIP;
577 $li = $wgLang->specialPage( "Userlogin" );
578 $lo = $wgLang->specialPage( "Userlogout" );
580 $s = "";
581 if ( 0 == $wgUser->getID() ) {
582 if( $wgShowIPinHeader && isset( $_COOKIE[ini_get("session.name")] ) ) {
583 $n = $wgIP;
585 $tl = $this->makeKnownLink( $wgLang->getNsText(
586 Namespace::getTalk( Namespace::getUser() ) ) . ":{$n}",
587 $wgLang->getNsText( Namespace::getTalk( 0 ) ) );
589 $s .= $n . " (".$tl.")";
590 } else {
591 $s .= wfMsg("notloggedin");
594 $rt = $wgTitle->getPrefixedURL();
595 if ( 0 == strcasecmp( urlencode( $lo ), $rt ) ) {
596 $q = "";
597 } else { $q = "returnto={$rt}"; }
599 $s .= "\n<br />" . $this->makeKnownLink( $li,
600 wfMsg( "login" ), $q );
601 } else {
602 $n = $wgUser->getName();
603 $rt = $wgTitle->getPrefixedURL();
604 $tl = $this->makeKnownLink( $wgLang->getNsText(
605 Namespace::getTalk( Namespace::getUser() ) ) . ":{$n}",
606 $wgLang->getNsText( Namespace::getTalk( 0 ) ) );
608 $tl = " ({$tl})";
610 $s .= $this->makeKnownLink( $wgLang->getNsText(
611 Namespace::getUser() ) . ":{$n}", $n ) . "{$tl}<br />" .
612 $this->makeKnownLink( $lo, wfMsg( "logout" ),
613 "returnto={$rt}" ) . " | " .
614 $this->specialLink( "preferences" );
616 $s .= " | " . $this->makeKnownLink( wfMsg( "helppage" ),
617 wfMsg( "help" ) );
619 return $s;
622 function searchForm()
624 global $wgRequest;
626 $search = $wgRequest->getText( 'search' );;
628 $s = "<form name='search' class='inline' method='post' action=\""
629 . wfLocalUrl( "" ) . "\">\n"
630 . "<input type='text' name=\"search\" size='19' value=\""
631 . htmlspecialchars(substr($search,0,256)) . "\" />\n"
632 . "<input type='submit' name=\"go\" value=\"" . wfMsg ("go") . "\" />&nbsp;"
633 . "<input type='submit' name=\"fulltext\" value=\"" . wfMsg ("search") . "\" />\n</form>";
635 return $s;
638 function topLinks()
640 global $wgOut;
641 $sep = " |\n";
643 $s = $this->mainPageLink() . $sep
644 . $this->specialLink( "recentchanges" );
646 if ( $wgOut->isArticleRelated() ) {
647 $s .= $sep . $this->editThisPage()
648 . $sep . $this->historyLink();
650 # Many people don't like this dropdown box
651 #$s .= $sep . $this->specialPagesList();
653 return $s;
656 function bottomLinks()
658 global $wgOut, $wgUser, $wgTitle;
659 $sep = " |\n";
661 $s = "";
662 if ( $wgOut->isArticleRelated() ) {
663 $s .= "<strong>" . $this->editThisPage() . "</strong>";
664 if ( 0 != $wgUser->getID() ) {
665 $s .= $sep . $this->watchThisPage();
667 $s .= $sep . $this->talkLink()
668 . $sep . $this->historyLink()
669 . $sep . $this->whatLinksHere()
670 . $sep . $this->watchPageLinksLink();
672 if ( $wgTitle->getNamespace() == Namespace::getUser()
673 || $wgTitle->getNamespace() == Namespace::getTalk(Namespace::getUser()) )
676 $id=User::idFromName($wgTitle->getText());
677 $ip=User::isIP($wgTitle->getText());
679 if($id || $ip) { # both anons and non-anons have contri list
680 $s .= $sep . $this->userContribsLink();
682 if ( 0 != $wgUser->getID() ) { # show only to signed in users
683 if($id) { # can only email non-anons
684 $s .= $sep . $this->emailUserLink();
688 if ( $wgUser->isSysop() && $wgTitle->getArticleId() ) {
689 $s .= "\n<br />" . $this->deleteThisPage() .
690 $sep . $this->protectThisPage() .
691 $sep . $this->moveThisPage();
693 $s .= "<br />\n" . $this->otherLanguages();
695 return $s;
698 function pageStats()
700 global $wgOut, $wgLang, $wgArticle, $wgRequest;
701 global $wgDisableCounters;
703 extract( $wgRequest->getValues( 'oldid', 'diff' ) );
704 if ( ! $wgOut->isArticle() ) { return ""; }
705 if ( isset( $oldid ) || isset( $diff ) ) { return ""; }
706 if ( 0 == $wgArticle->getID() ) { return ""; }
708 $s = "";
709 if ( !$wgDisableCounters ) {
710 $count = $wgLang->formatNum( $wgArticle->getCount() );
711 if ( $count ) {
712 $s = wfMsg( "viewcount", $count );
715 $s .= $this->lastModified();
716 return $s . " " . $this->getCopyright();
719 function getCopyright() {
720 global $wgRightsPage, $wgRightsUrl, $wgRightsText;
721 $out = "";
722 if( $wgRightsPage ) {
723 $link = $this->makeKnownLink( $wgRightsPage, $wgRightsText );
724 } elseif( $wgRightsUrl ) {
725 $link = $this->makeExternalLink( $wgRightsUrl, $wgRightsText );
726 } else {
727 # Give up now
728 return $out;
730 $out .= wfMsg( "copyright", $link );
731 return $out;
734 function getCopyrightIcon() {
735 global $wgRightsPage, $wgRightsUrl, $wgRightsText, $wgRightsIcon;
736 $out = "";
737 if( $wgRightsIcon ) {
738 $icon = htmlspecialchars( $wgRightsIcon );
739 if( $wgRightsUrl ) {
740 $url = htmlspecialchars( $wgRightsUrl );
741 $out .= "<a href=\"$url\">";
743 $text = htmlspecialchars( $wgRightsText );
744 $out .= "<img src=\"$icon\" alt='$text' />";
745 if( $wgRightsUrl ) {
746 $out .= "</a>";
749 return $out;
752 function getPoweredBy() {
753 global $wgUploadPath;
754 $url = htmlspecialchars( "$wgUploadPath/poweredby_mediawiki_88x31.png" );
755 $img = "<a href='http://www.mediawiki.org/'><img src='$url' alt='MediaWiki' /></a>";
756 return $img;
759 function lastModified()
761 global $wgLang, $wgArticle;
763 $timestamp = $wgArticle->getTimestamp();
764 if ( $timestamp ) {
765 $d = $wgLang->timeanddate( $wgArticle->getTimestamp(), true );
766 $s = " " . wfMsg( "lastmodified", $d );
767 } else {
768 $s = "";
770 return $s;
773 function logoText( $align = "" )
775 if ( "" != $align ) { $a = " align='{$align}'"; }
776 else { $a = ""; }
778 $mp = wfMsg( "mainpage" );
779 $titleObj = Title::newFromText( $mp );
780 $s = "<a href=\"" . $titleObj->escapeLocalURL()
781 . "\"><img{$a} src=\""
782 . $this->getLogo() . "\" alt=\"" . "[{$mp}]\" /></a>";
783 return $s;
786 function quickBar()
788 global $wgOut, $wgTitle, $wgUser, $wgRequest, $wgLang;
789 global $wgDisableUploads, $wgRemoteUploads;
791 $fname = "Skin::quickBar";
792 wfProfileIn( $fname );
794 $action = $wgRequest->getText( 'action' );
795 $wpPreview = $wgRequest->getBool( 'wpPreview' );
796 $tns=$wgTitle->getNamespace();
798 $s = "\n<div id='quickbar'>";
799 $s .= "\n" . $this->logoText() . "\n<hr class='sep' />";
801 $sep = "\n<br />";
802 $s .= $this->mainPageLink()
803 . $sep . $this->specialLink( "recentchanges" )
804 . $sep . $this->specialLink( "randompage" );
805 if ($wgUser->getID()) {
806 $s.= $sep . $this->specialLink( "watchlist" ) ;
807 $s .= $sep .$this->makeKnownLink( $wgLang->specialPage( "Contributions" ),
808 wfMsg( "mycontris" ), "target=" . wfUrlencode($wgUser->getName() ) );
811 // only show watchlist link if logged in
812 if ( wfMsg ( "currentevents" ) != "" ) $s .= $sep . $this->makeKnownLink( wfMsg( "currentevents" ), "" ) ;
813 $s .= "\n<br /><hr class='sep' />";
814 $articleExists = $wgTitle->getArticleId();
815 if ( $wgOut->isArticle() || $action =="edit" || $action =="history" || $wpPreview) {
816 if($wgOut->isArticle()) {
817 $s .= "<strong>" . $this->editThisPage() . "</strong>";
818 } else { # backlink to the article in edit or history mode
819 if($articleExists){ # no backlink if no article
820 switch($tns) {
821 case 0:
822 $text = wfMsg("articlepage");
823 break;
824 case 1:
825 $text = wfMsg("viewtalkpage");
826 break;
827 case 2:
828 $text = wfMsg("userpage");
829 break;
830 case 3:
831 $text = wfMsg("viewtalkpage");
832 break;
833 case 4:
834 $text = wfMsg("wikipediapage");
835 break;
836 case 5:
837 $text = wfMsg("viewtalkpage");
838 break;
839 case 6:
840 $text = wfMsg("imagepage");
841 break;
842 case 7:
843 $text = wfMsg("viewtalkpage");
844 break;
845 default:
846 $text= wfMsg("articlepage");
849 $link = $wgTitle->getText();
850 if ($nstext = $wgLang->getNsText($tns) ) { # add namespace if necessary
851 $link = $nstext . ":" . $link ;
854 $s .= $this->makeLink( $link, $text );
855 } elseif( $wgTitle->getNamespace() != Namespace::getSpecial() ) {
856 # we just throw in a "New page" text to tell the user that he's in edit mode,
857 # and to avoid messing with the separator that is prepended to the next item
858 $s .= "<strong>" . wfMsg("newpage") . "</strong>";
864 if( $tns%2 && $action!="edit" && !$wpPreview) {
865 $s.="<br />".$this->makeKnownLink($wgTitle->getPrefixedText(),wfMsg("postcomment"),"action=edit&section=new");
869 watching could cause problems in edit mode:
870 if user edits article, then loads "watch this article" in background and then saves
871 article with "Watch this article" checkbox disabled, the article is transparently
872 unwatched. Therefore we do not show the "Watch this page" link in edit mode
874 if ( 0 != $wgUser->getID() && $articleExists) {
875 if($action!="edit" && $action != "submit" )
877 $s .= $sep . $this->watchThisPage();
879 if ( $wgTitle->userCanEdit() )
880 $s .= $sep . $this->moveThisPage();
882 if ( $wgUser->isSysop() and $articleExists ) {
883 $s .= $sep . $this->deleteThisPage() .
884 $sep . $this->protectThisPage();
886 $s .= $sep . $this->talkLink();
887 if ($articleExists && $action !="history") {
888 $s .= $sep . $this->historyLink();
890 $s.=$sep . $this->whatLinksHere();
892 if($wgOut->isArticleRelated()) {
893 $s .= $sep . $this->watchPageLinksLink();
896 if ( Namespace::getUser() == $wgTitle->getNamespace()
897 || $wgTitle->getNamespace() == Namespace::getTalk(Namespace::getUser())
900 $id=User::idFromName($wgTitle->getText());
901 $ip=User::isIP($wgTitle->getText());
903 if($id||$ip) {
904 $s .= $sep . $this->userContribsLink();
906 if ( 0 != $wgUser->getID() ) {
907 if($id) { # can only email real users
908 $s .= $sep . $this->emailUserLink();
912 $s .= "\n<br /><hr class='sep' />";
915 if ( 0 != $wgUser->getID() && ( !$wgDisableUploads || $wgRemoteUploads ) ) {
916 $s .= $this->specialLink( "upload" ) . $sep;
918 $s .= $this->specialLink( "specialpages" )
919 . $sep . $this->bugReportsLink();
921 global $wgSiteSupportPage;
922 if( $wgSiteSupportPage ) {
923 $s .= "\n<br /><a href=\"" . htmlspecialchars( $wgSiteSupportPage ) .
924 "\" class=\"internal\">" . wfMsg( "sitesupport" ) . "</a>";
927 $s .= "\n<br /></div>\n";
928 wfProfileOut( $fname );
929 return $s;
932 function specialPagesList()
934 global $wgUser, $wgOut, $wgLang, $wgServer, $wgRedirectScript;
935 $a = array();
937 $validSP = $wgLang->getValidSpecialPages();
939 foreach ( $validSP as $name => $desc ) {
940 if ( "" == $desc ) { continue; }
941 $a[$name] = $desc;
943 if ( $wgUser->isSysop() )
945 $sysopSP = $wgLang->getSysopSpecialPages();
947 foreach ( $sysopSP as $name => $desc ) {
948 if ( "" == $desc ) { continue; }
949 $a[$name] = $desc ;
952 if ( $wgUser->isDeveloper() )
954 $devSP = $wgLang->getDeveloperSpecialPages();
956 foreach ( $devSP as $name => $desc ) {
957 if ( "" == $desc ) { continue; }
958 $a[$name] = $desc ;
961 $go = wfMsg( "go" );
962 $sp = wfMsg( "specialpages" );
963 $spp = $wgLang->specialPage( "Specialpages" );
965 $s = "<form id=\"specialpages\" method=\"get\" class=\"inline\" " .
966 "action=\"" . htmlspecialchars( "{$wgServer}{$wgRedirectScript}" ) . "\">\n";
967 $s .= "<select name=\"wpDropdown\">\n";
968 $s .= "<option value=\"{$spp}\">{$sp}</option>\n";
970 foreach ( $a as $name => $desc ) {
971 $p = $wgLang->specialPage( $name );
972 $s .= "<option value=\"{$p}\">{$desc}</option>\n";
974 $s .= "</select>\n";
975 $s .= "<input type='submit' value=\"{$go}\" name='redirect' />\n";
976 $s .= "</form>\n";
977 return $s;
980 function mainPageLink()
982 $mp = wfMsg( "mainpage" );
983 $s = $this->makeKnownLink( $mp, $mp );
984 return $s;
987 function copyrightLink()
989 $s = $this->makeKnownLink( wfMsg( "copyrightpage" ),
990 wfMsg( "copyrightpagename" ) );
991 return $s;
994 function aboutLink()
996 $s = $this->makeKnownLink( wfMsg( "aboutpage" ),
997 wfMsg( "aboutwikipedia" ) );
998 return $s;
1002 function disclaimerLink()
1004 $s = $this->makeKnownLink( wfMsg( "disclaimerpage" ),
1005 wfMsg( "disclaimers" ) );
1006 return $s;
1009 function editThisPage()
1011 global $wgOut, $wgTitle, $wgRequest;
1013 $oldid = $wgRequest->getVal( 'oldid' );
1014 $diff = $wgRequest->getVal( 'diff' );
1015 $redirect = $wgRequest->getVal( 'redirect' );
1017 if ( ! $wgOut->isArticleRelated() ) {
1018 $s = wfMsg( "protectedpage" );
1019 } else {
1020 $n = $wgTitle->getPrefixedText();
1021 if ( $wgTitle->userCanEdit() ) {
1022 $t = wfMsg( "editthispage" );
1023 } else {
1024 #$t = wfMsg( "protectedpage" );
1025 $t = wfMsg( "viewsource" );
1027 $oid = $red = "";
1029 if ( !is_null( $redirect ) ) { $red = "&redirect={$redirect}"; }
1030 if ( $oldid && ! isset( $diff ) ) {
1031 $oid = "&oldid={$oldid}";
1033 $s = $this->makeKnownLink( $n, $t, "action=edit{$oid}{$red}" );
1035 return $s;
1038 function deleteThisPage()
1040 global $wgUser, $wgOut, $wgTitle, $wgRequest;
1042 $diff = $wgRequest->getVal( 'diff' );
1043 if ( $wgTitle->getArticleId() && ( ! $diff ) && $wgUser->isSysop() ) {
1044 $n = $wgTitle->getPrefixedText();
1045 $t = wfMsg( "deletethispage" );
1047 $s = $this->makeKnownLink( $n, $t, "action=delete" );
1048 } else {
1049 $s = "";
1051 return $s;
1054 function protectThisPage()
1056 global $wgUser, $wgOut, $wgTitle, $wgRequest;
1058 $diff = $wgRequest->getVal( 'diff' );
1059 if ( $wgTitle->getArticleId() && ( ! $diff ) && $wgUser->isSysop() ) {
1060 $n = $wgTitle->getPrefixedText();
1062 if ( $wgTitle->isProtected() ) {
1063 $t = wfMsg( "unprotectthispage" );
1064 $q = "action=unprotect";
1065 } else {
1066 $t = wfMsg( "protectthispage" );
1067 $q = "action=protect";
1069 $s = $this->makeKnownLink( $n, $t, $q );
1070 } else {
1071 $s = "";
1073 return $s;
1076 function watchThisPage()
1078 global $wgUser, $wgOut, $wgTitle;
1080 if ( $wgOut->isArticleRelated() ) {
1081 $n = $wgTitle->getPrefixedText();
1083 if ( $wgTitle->userIsWatching() ) {
1084 $t = wfMsg( "unwatchthispage" );
1085 $q = "action=unwatch";
1086 } else {
1087 $t = wfMsg( "watchthispage" );
1088 $q = "action=watch";
1090 $s = $this->makeKnownLink( $n, $t, $q );
1091 } else {
1092 $s = wfMsg( "notanarticle" );
1094 return $s;
1097 function moveThisPage()
1099 global $wgTitle, $wgLang;
1101 if ( $wgTitle->userCanEdit() ) {
1102 $s = $this->makeKnownLink( $wgLang->specialPage( "Movepage" ),
1103 wfMsg( "movethispage" ), "target=" . $wgTitle->getPrefixedURL() );
1104 } // no message if page is protected - would be redundant
1105 return $s;
1108 function historyLink()
1110 global $wgTitle;
1112 $s = $this->makeKnownLink( $wgTitle->getPrefixedText(),
1113 wfMsg( "history" ), "action=history" );
1114 return $s;
1117 function whatLinksHere()
1119 global $wgTitle, $wgLang;
1121 $s = $this->makeKnownLink( $wgLang->specialPage( "Whatlinkshere" ),
1122 wfMsg( "whatlinkshere" ), "target=" . $wgTitle->getPrefixedURL() );
1123 return $s;
1126 function userContribsLink()
1128 global $wgTitle, $wgLang;
1130 $s = $this->makeKnownLink( $wgLang->specialPage( "Contributions" ),
1131 wfMsg( "contributions" ), "target=" . $wgTitle->getPartialURL() );
1132 return $s;
1135 function emailUserLink()
1137 global $wgTitle, $wgLang;
1139 $s = $this->makeKnownLink( $wgLang->specialPage( "Emailuser" ),
1140 wfMsg( "emailuser" ), "target=" . $wgTitle->getPartialURL() );
1141 return $s;
1144 function watchPageLinksLink()
1146 global $wgOut, $wgTitle, $wgLang;
1148 if ( ! $wgOut->isArticleRelated() ) {
1149 $s = "(" . wfMsg( "notanarticle" ) . ")";
1150 } else {
1151 $s = $this->makeKnownLink( $wgLang->specialPage(
1152 "Recentchangeslinked" ), wfMsg( "recentchangeslinked" ),
1153 "target=" . $wgTitle->getPrefixedURL() );
1155 return $s;
1158 function otherLanguages()
1160 global $wgOut, $wgLang, $wgTitle, $wgUseNewInterlanguage;
1162 $a = $wgOut->getLanguageLinks();
1163 if ( 0 == count( $a ) ) {
1164 if ( !$wgUseNewInterlanguage ) return "";
1165 $ns = $wgLang->getNsIndex ( $wgTitle->getNamespace () ) ;
1166 if ( $ns != 0 AND $ns != 1 ) return "" ;
1167 $pn = "Intl" ;
1168 $x = "mode=addlink&xt=".$wgTitle->getDBkey() ;
1169 return $this->makeKnownLink( $wgLang->specialPage( $pn ),
1170 wfMsg( "intl" ) , $x );
1173 if ( !$wgUseNewInterlanguage ) {
1174 $s = wfMsg( "otherlanguages" ) . ": ";
1175 } else {
1176 global $wgLanguageCode ;
1177 $x = "mode=zoom&xt=".$wgTitle->getDBkey() ;
1178 $x .= "&xl=".$wgLanguageCode ;
1179 $s = $this->makeKnownLink( $wgLang->specialPage( "Intl" ),
1180 wfMsg( "otherlanguages" ) , $x ) . ": " ;
1183 $s = wfMsg( "otherlanguages" ) . ": ";
1184 $first = true;
1185 if($wgLang->isRTL()) $s .= "<span dir='LTR'>";
1186 foreach( $a as $l ) {
1187 if ( ! $first ) { $s .= " | "; }
1188 $first = false;
1190 $nt = Title::newFromText( $l );
1191 $url = $nt->getFullURL();
1192 $text = $wgLang->getLanguageName( $nt->getInterwiki() );
1194 if ( "" == $text ) { $text = $l; }
1195 $style = $this->getExternalLinkAttributes( $l, $text );
1196 $s .= "<a href=\"{$url}\"{$style}>{$text}</a>";
1198 if($wgLang->isRTL()) $s .= "</span>";
1199 return $s;
1202 function bugReportsLink()
1204 $s = $this->makeKnownLink( wfMsg( "bugreportspage" ),
1205 wfMsg( "bugreports" ) );
1206 return $s;
1209 function dateLink()
1211 global $wgLinkCache;
1212 $t1 = Title::newFromText( gmdate( "F j" ) );
1213 $t2 = Title::newFromText( gmdate( "Y" ) );
1215 $wgLinkCache->suspend();
1216 $id = $t1->getArticleID();
1217 $wgLinkCache->resume();
1219 if ( 0 == $id ) {
1220 $s = $this->makeBrokenLink( $t1->getText() );
1221 } else {
1222 $s = $this->makeKnownLink( $t1->getText() );
1224 $s .= ", ";
1226 $wgLinkCache->suspend();
1227 $id = $t2->getArticleID();
1228 $wgLinkCache->resume();
1230 if ( 0 == $id ) {
1231 $s .= $this->makeBrokenLink( $t2->getText() );
1232 } else {
1233 $s .= $this->makeKnownLink( $t2->getText() );
1235 return $s;
1238 function talkLink()
1240 global $wgLang, $wgTitle, $wgLinkCache;
1242 $tns = $wgTitle->getNamespace();
1243 if ( -1 == $tns ) { return ""; }
1245 $pn = $wgTitle->getText();
1246 $tp = wfMsg( "talkpage" );
1247 if ( Namespace::isTalk( $tns ) ) {
1248 $lns = Namespace::getSubject( $tns );
1249 switch($tns) {
1250 case 1:
1251 $text = wfMsg("articlepage");
1252 break;
1253 case 3:
1254 $text = wfMsg("userpage");
1255 break;
1256 case 5:
1257 $text = wfMsg("wikipediapage");
1258 break;
1259 case 7:
1260 $text = wfMsg("imagepage");
1261 break;
1262 default:
1263 $text= wfMsg("articlepage");
1265 } else {
1267 $lns = Namespace::getTalk( $tns );
1268 $text=$tp;
1270 $n = $wgLang->getNsText( $lns );
1271 if ( "" == $n ) { $link = $pn; }
1272 else { $link = "{$n}:{$pn}"; }
1274 $wgLinkCache->suspend();
1275 $s = $this->makeLink( $link, $text );
1276 $wgLinkCache->resume();
1278 return $s;
1281 function commentLink()
1283 global $wgLang, $wgTitle, $wgLinkCache;
1285 $tns = $wgTitle->getNamespace();
1286 if ( -1 == $tns ) { return ""; }
1288 $lns = ( Namespace::isTalk( $tns ) ) ? $tns : Namespace::getTalk( $tns );
1290 # assert Namespace::isTalk( $lns )
1292 $n = $wgLang->getNsText( $lns );
1293 $pn = $wgTitle->getText();
1295 $link = "{$n}:{$pn}";
1297 $wgLinkCache->suspend();
1298 $s = $this->makeKnownLink($link, wfMsg("postcomment"), "action=edit&section=new");
1299 $wgLinkCache->resume();
1301 return $s;
1304 # After all the page content is transformed into HTML, it makes
1305 # a final pass through here for things like table backgrounds.
1307 function transformContent( $text )
1309 return $text;
1312 # Note: This function MUST call getArticleID() on the link,
1313 # otherwise the cache won't get updated properly. See LINKCACHE.DOC.
1315 function makeLink( $title, $text = "", $query = "", $trail = "" ) {
1316 wfProfileIn( "Skin::makeLink" );
1317 $nt = Title::newFromText( $title );
1318 if ($nt) {
1319 $result = $this->makeLinkObj( Title::newFromText( $title ), $text, $query, $trail );
1320 } else {
1321 wfDebug( "Invalid title passed to Skin::makeLink(): \"$title\"\n" );
1322 $result = $text == "" ? $title : $text;
1325 wfProfileOut( "Skin::makeLink" );
1326 return $result;
1329 function makeKnownLink( $title, $text = "", $query = "", $trail = "", $prefix = '',$aprops = '') {
1330 $nt = Title::newFromText( $title );
1331 if ($nt) {
1332 return $this->makeKnownLinkObj( Title::newFromText( $title ), $text, $query, $trail, $prefix , $aprops );
1333 } else {
1334 wfDebug( "Invalid title passed to Skin::makeKnownLink(): \"$title\"\n" );
1335 return $text == "" ? $title : $text;
1339 function makeBrokenLink( $title, $text = "", $query = "", $trail = "" ) {
1340 $nt = Title::newFromText( $title );
1341 if ($nt) {
1342 return $this->makeBrokenLinkObj( Title::newFromText( $title ), $text, $query, $trail );
1343 } else {
1344 wfDebug( "Invalid title passed to Skin::makeBrokenLink(): \"$title\"\n" );
1345 return $text == "" ? $title : $text;
1349 function makeStubLink( $title, $text = "", $query = "", $trail = "" ) {
1350 $nt = Title::newFromText( $title );
1351 if ($nt) {
1352 return $this->makeStubLinkObj( Title::newFromText( $title ), $text, $query, $trail );
1353 } else {
1354 wfDebug( "Invalid title passed to Skin::makeStubLink(): \"$title\"\n" );
1355 return $text == "" ? $title : $text;
1359 # Pass a title object, not a title string
1360 function makeLinkObj( &$nt, $text= "", $query = "", $trail = "", $prefix = "" )
1362 global $wgOut, $wgUser;
1363 if ( $nt->isExternal() ) {
1364 $u = $nt->getFullURL();
1365 $link = $nt->getPrefixedURL();
1366 if ( "" == $text ) { $text = $nt->getPrefixedText(); }
1367 $style = $this->getExternalLinkAttributes( $link, $text );
1369 $inside = "";
1370 if ( "" != $trail ) {
1371 if ( preg_match( "/^([a-z]+)(.*)$$/sD", $trail, $m ) ) {
1372 $inside = $m[1];
1373 $trail = $m[2];
1376 $retVal = "<a href=\"{$u}\"{$style}>{$text}{$inside}</a>{$trail}";
1377 } elseif ( 0 == $nt->getNamespace() && "" == $nt->getText() ) {
1378 $retVal = $this->makeKnownLinkObj( $nt, $text, $query, $trail, $prefix );
1379 } elseif ( ( -1 == $nt->getNamespace() ) ||
1380 ( Namespace::getImage() == $nt->getNamespace() ) ) {
1381 $retVal = $this->makeKnownLinkObj( $nt, $text, $query, $trail, $prefix );
1382 } else {
1383 $aid = $nt->getArticleID() ;
1384 if ( 0 == $aid ) {
1385 $retVal = $this->makeBrokenLinkObj( $nt, $text, $query, $trail, $prefix );
1386 } else {
1387 $threshold = $wgUser->getOption("stubthreshold") ;
1388 if ( $threshold > 0 ) {
1389 $res = wfQuery ( "SELECT LENGTH(cur_text) AS x, cur_namespace, cur_is_redirect FROM cur WHERE cur_id='{$aid}'", DB_READ ) ;
1391 if ( wfNumRows( $res ) > 0 ) {
1392 $s = wfFetchObject( $res );
1393 $size = $s->x;
1394 if ( $s->cur_is_redirect OR $s->cur_namespace != 0 ) {
1395 $size = $threshold*2 ; # Really big
1397 wfFreeResult( $res );
1398 } else {
1399 $size = $threshold*2 ; # Really big
1401 } else {
1402 $size = 1 ;
1404 if ( $size < $threshold ) {
1405 $retVal = $this->makeStubLinkObj( $nt, $text, $query, $trail, $prefix );
1406 } else {
1407 $retVal = $this->makeKnownLinkObj( $nt, $text, $query, $trail, $prefix );
1411 return $retVal;
1414 # Pass a title object, not a title string
1415 function makeKnownLinkObj( &$nt, $text = "", $query = "", $trail = "", $prefix = "" , $aprops = '')
1417 global $wgOut, $wgTitle;
1419 $fname = "Skin::makeKnownLinkObj";
1420 wfProfileIn( $fname );
1422 $link = $nt->getPrefixedURL();
1424 if ( "" == $link ) {
1425 $u = "";
1426 if ( "" == $text ) {
1427 $text = htmlspecialchars( $nt->getFragment() );
1429 } else {
1430 $u = $nt->escapeLocalURL( $query );
1432 if ( "" != $nt->getFragment() ) {
1433 $u .= "#" . htmlspecialchars( $nt->getFragment() );
1435 if ( "" == $text ) {
1436 $text = htmlspecialchars( $nt->getPrefixedText() );
1438 $style = $this->getInternalLinkAttributesObj( $nt, $text );
1440 $inside = "";
1441 if ( "" != $trail ) {
1442 if ( preg_match( $this->linktrail, $trail, $m ) ) {
1443 $inside = $m[1];
1444 $trail = $m[2];
1447 $r = "<a href=\"{$u}\"{$style}{$aprops}>{$prefix}{$text}{$inside}</a>{$trail}";
1448 wfProfileOut( $fname );
1449 return $r;
1452 # Pass a title object, not a title string
1453 function makeBrokenLinkObj( &$nt, $text = "", $query = "", $trail = "", $prefix = "" )
1455 global $wgOut, $wgUser;
1457 $fname = "Skin::makeBrokenLinkObj";
1458 wfProfileIn( $fname );
1460 if ( "" == $query ) {
1461 $q = "action=edit";
1462 } else {
1463 $q = "action=edit&{$query}";
1465 $u = $nt->escapeLocalURL( $q );
1467 if ( "" == $text ) {
1468 $text = htmlspecialchars( $nt->getPrefixedText() );
1470 $style = $this->getInternalLinkAttributesObj( $nt, $text, "yes" );
1472 $inside = "";
1473 if ( "" != $trail ) {
1474 if ( preg_match( $this->linktrail, $trail, $m ) ) {
1475 $inside = $m[1];
1476 $trail = $m[2];
1479 if ( $wgUser->getOption( "highlightbroken" ) ) {
1480 $s = "<a href=\"{$u}\"{$style}>{$prefix}{$text}{$inside}</a>{$trail}";
1481 } else {
1482 $s = "{$prefix}{$text}{$inside}<a href=\"{$u}\"{$style}>?</a>{$trail}";
1485 wfProfileOut( $fname );
1486 return $s;
1489 # Pass a title object, not a title string
1490 function makeStubLinkObj( &$nt, $text = "", $query = "", $trail = "", $prefix = "" )
1492 global $wgOut, $wgUser;
1494 $link = $nt->getPrefixedURL();
1496 $u = $nt->escapeLocalURL( $query );
1498 if ( "" == $text ) {
1499 $text = htmlspecialchars( $nt->getPrefixedText() );
1501 $style = $this->getInternalLinkAttributesObj( $nt, $text, "stub" );
1503 $inside = "";
1504 if ( "" != $trail ) {
1505 if ( preg_match( $this->linktrail, $trail, $m ) ) {
1506 $inside = $m[1];
1507 $trail = $m[2];
1510 if ( $wgUser->getOption( "highlightbroken" ) ) {
1511 $s = "<a href=\"{$u}\"{$style}>{$prefix}{$text}{$inside}</a>{$trail}";
1512 } else {
1513 $s = "{$prefix}{$text}{$inside}<a href=\"{$u}\"{$style}>!</a>{$trail}";
1515 return $s;
1518 function fnamePart( $url )
1520 $basename = strrchr( $url, "/" );
1521 if ( false === $basename ) { $basename = $url; }
1522 else { $basename = substr( $basename, 1 ); }
1523 return wfEscapeHTML( $basename );
1526 function makeImage( $url, $alt = "" )
1528 global $wgOut;
1530 if ( "" == $alt ) { $alt = $this->fnamePart( $url ); }
1531 $s = "<img src=\"{$url}\" alt=\"{$alt}\" />";
1532 return $s;
1535 function makeImageLink( $name, $url, $alt = "" ) {
1536 $nt = Title::makeTitle( Namespace::getImage(), $name );
1537 return $this->makeImageLinkObj( $nt, $alt );
1540 function makeImageLinkObj( $nt, $alt = "" ) {
1541 global $wgLang, $wgUseImageResize;
1542 $name = $nt->getDBKey();
1543 $url = wfImageUrl( $name );
1544 $align = "";
1545 $prefix = $postfix = "";
1547 if ( $wgUseImageResize ) {
1548 # Check if the alt text is of the form "options|alt text"
1549 # Options are:
1550 # * thumbnail make a thumbnail with enlarge-icon and caption, alignment depends on lang
1551 # * left no resizing, just left align. label is used for alt= only
1552 # * right same, but right aligned
1553 # * none same, but not aligned
1554 # * ___px scale to ___ pixels width, no aligning. e.g. use in taxobox
1556 $part = explode( "|", $alt);
1558 $mwThumb =& MagicWord::get( MAG_IMG_THUMBNAIL );
1559 $mwLeft =& MagicWord::get( MAG_IMG_LEFT );
1560 $mwRight =& MagicWord::get( MAG_IMG_RIGHT );
1561 $mwNone =& MagicWord::get( MAG_IMG_NONE );
1562 $mwWidth =& MagicWord::get( MAG_IMG_WIDTH );
1563 $mwCenter =& MagicWord::get( MAG_IMG_CENTER );
1564 $alt = $part[count($part)-1];
1566 $thumb=false;
1568 foreach( $part as $key => $val ) {
1569 if ( ! is_null( $mwThumb->matchVariableStartToEnd($val) ) ) {
1570 $thumb=true;
1571 } elseif ( ! is_null( $mwRight->matchVariableStartToEnd($val) ) ) {
1572 # remember to set an alignment, don't render immediately
1573 $align = "right";
1574 } elseif ( ! is_null( $mwLeft->matchVariableStartToEnd($val) ) ) {
1575 # remember to set an alignment, don't render immediately
1576 $align = "left";
1577 } elseif ( ! is_null( $mwCenter->matchVariableStartToEnd($val) ) ) {
1578 # remember to set an alignment, don't render immediately
1579 $align = "center";
1580 } elseif ( ! is_null( $mwNone->matchVariableStartToEnd($val) ) ) {
1581 # remember to set an alignment, don't render immediately
1582 $align = "none";
1583 } elseif ( ! is_null( $match = $mwWidth->matchVariableStartToEnd($val) ) ) {
1584 # $match is the image width in pixels
1585 $width = intval($match);
1588 if ( "center" == $align )
1590 $prefix = '<span style="text-align: center">';
1591 $postfix = '</span>';
1592 $align = "none";
1595 if ( $thumb ) {
1597 # Create a thumbnail. Alignment depends on language
1598 # writing direction, # right aligned for left-to-right-
1599 # languages ("Western languages"), left-aligned
1600 # for right-to-left-languages ("Semitic languages")
1602 # If thumbnail width has not been provided, it is set
1603 # here to 180 pixels
1604 if ( $align == "" ) {
1605 $align = $wgLang->isRTL() ? "left" : "right";
1607 if ( ! isset($width) ) {
1608 $width = 180;
1610 return $prefix.$this->makeThumbLinkObj( $nt, $alt, $align, $width ).$postfix;
1612 } elseif ( isset($width) ) {
1614 # Create a resized image, without the additional thumbnail
1615 # features
1616 $url = $this->createThumb( $name, $width );
1618 } # endif $wgUseImageResize
1620 if ( empty( $alt ) ) {
1621 $alt = preg_replace( '/\.(.+?)^/', '', $name );
1623 $alt = htmlspecialchars( $alt );
1625 $u = $nt->escapeLocalURL();
1626 if ( $url == "" )
1628 $s = str_replace( "$1", $name, wfMsg("missingimage") );
1629 } else {
1630 $s = "<a href=\"{$u}\" class='image' title=\"{$alt}\">" .
1631 "<img src=\"{$url}\" alt=\"{$alt}\" /></a>";
1633 if ( "" != $align ) {
1634 $s = "<div class=\"float{$align}\"><span>{$s}</span>\n</div>";
1636 return $prefix.$s.$postfix;
1639 function createThumb( $name, $width ) {
1640 global $wgUploadDirectory;
1641 global $wgImageMagickConvertCommand;
1642 global $wgUseImageMagick;
1643 global $wgUseSquid, $wgInternalServer;
1644 $imgPath = wfImagePath( $name );
1645 $thumbName = $width."px-".$name;
1646 $thumbPath = wfImageThumbDir( $thumbName )."/".$thumbName;
1647 $thumbUrl = wfImageThumbUrl( $thumbName );
1649 if ( ! file_exists( $imgPath ) )
1651 # If there is no image, there will be no thumbnail
1652 return "";
1655 if ( (! file_exists( $thumbPath ) )
1656 || ( filemtime($thumbPath) < filemtime($imgPath) ) ) {
1657 # Squid purging
1658 if ( $wgUseSquid ) {
1659 $urlArr = Array(
1660 $wgInternalServer.$thumbUrl
1662 wfPurgeSquidServers($urlArr);
1665 if ( $wgUseImageMagick ) {
1666 # use ImageMagick
1667 $cmd = $wgImageMagickConvertCommand .
1668 " -quality 85 -geometry {$width} ".
1669 escapeshellarg($imgPath) . " " .
1670 escapeshellarg($thumbPath);
1671 $conv = shell_exec( $cmd );
1672 } else {
1673 # Use PHP's builtin GD library functions.
1675 # First find out what kind of file this is, and select the correct
1676 # input routine for this.
1677 list($src_width, $src_height, $src_type, $src_attr) = getimagesize( $imgPath );
1678 switch( $src_type ) {
1679 case 1: # GIF
1680 $src_image = imagecreatefromgif( $imgPath );
1681 break;
1682 case 2: # JPG
1683 $src_image = imagecreatefromjpeg( $imgPath );
1684 break;
1685 case 3: # PNG
1686 $src_image = imagecreatefrompng( $imgPath );
1687 break;
1688 case 15: # WBMP for WML
1689 $src_image = imagecreatefromwbmp( $imgPath );
1690 break;
1691 case 16: # XBM
1692 $src_image = imagecreatefromxbm( $imgPath );
1693 break;
1694 default:
1695 return "Image type not supported";
1696 break;
1698 $height = floor( $src_height * ( $width/$src_width ) );
1699 $dst_image = imagecreatetruecolor( $width, $height );
1700 imagecopyresampled( $dst_image, $src_image,
1701 0,0,0,0,
1702 $width, $height, $src_width, $src_height );
1703 switch( $src_type ) {
1704 case 1: # GIF
1705 case 3: # PNG
1706 case 15: # WBMP
1707 case 16: # XBM
1708 #$thumbUrl .= ".png";
1709 #$thumbPath .= ".png";
1710 imagepng( $dst_image, $thumbPath );
1711 break;
1712 case 2: # JPEG
1713 #$thumbUrl .= ".jpg";
1714 #$thumbPath .= ".jpg";
1715 imageinterlace( $dst_image );
1716 imagejpeg( $dst_image, $thumbPath, 95 );
1717 break;
1718 default:
1719 break;
1721 imagedestroy( $dst_image );
1722 imagedestroy( $src_image );
1727 # Check for zero-sized thumbnails. Those can be generated when
1728 # no disk space is available or some other error occurs
1730 $thumbstat = stat( $thumbPath );
1731 $imgstat = stat( $imgPath );
1732 if( $thumbstat["size"] == 0 )
1734 unlink( $thumbPath );
1738 return $thumbUrl;
1741 function makeThumbLinkObj( $nt, $label = "", $align = "right", $boxwidth = 180 ) {
1742 global $wgUploadPath, $wgLang;
1743 $name = $nt->getDBKey();
1744 $image = Title::makeTitle( Namespace::getImage(), $name );
1745 $url = wfImageUrl( $name );
1746 $path = wfImagePath( $name );
1748 #$label = htmlspecialchars( $label );
1749 $alt = preg_replace( "/<[^>]*>/", "", $label);
1750 $alt = htmlspecialchars( $alt );
1752 if ( file_exists( $path ) )
1754 list($width, $height, $type, $attr) = getimagesize( $path );
1755 } else {
1756 $width = $height = 200;
1758 $boxheight = intval( $height/($width/$boxwidth) );
1759 if ( $boxwidth > $width ) {
1760 $boxwidth = $width;
1761 $boxheight = $height;
1764 $thumbUrl = $this->createThumb( $name, $boxwidth );
1766 $u = $nt->escapeLocalURL();
1768 $more = htmlspecialchars( wfMsg( "thumbnail-more" ) );
1769 $magnifyalign = $wgLang->isRTL() ? "left" : "right";
1770 $textalign = $wgLang->isRTL() ? " style=\"text-align:right\"" : "";
1772 $s = "<div class=\"thumbnail-{$align}\" style=\"width:{$boxwidth}px;\"><div>";
1773 if ( $thumbUrl == "" ) {
1774 $s .= str_replace( "$1", $name, wfMsg("missingimage") );
1775 } else {
1776 $s .= '<a href="'.$u.'" class="internal" title="'.$alt.'">'.
1777 '<img src="'.$thumbUrl.'" alt="'.$alt.'" ' .
1778 'width="'.$boxwidth.'" height="'.$boxheight.'" /></a>'.
1779 '<a href="'.$u.'" class="internal" title="'.$more.'"> '.
1780 '<img src="'.$wgUploadPath.'/magnify-clip.png" ' .
1781 'width="26" height="24" align="'.$magnifyalign.'" alt="'.$more.'" /> </a>';
1783 $s .= ' <div'.$textalign.'>'.$label."</div></div>\n</div>";
1784 return $s;
1787 function makeMediaLink( $name, $url, $alt = "" ) {
1788 $nt = Title::makeTitle( Namespace::getMedia(), $name );
1789 return $this->makeMediaLinkObj( $nt, $alt );
1792 function makeMediaLinkObj( $nt, $alt = "" )
1794 $name = $nt->getDBKey();
1795 $url = wfImageUrl( $name );
1796 if ( empty( $alt ) ) {
1797 $alt = preg_replace( '/\.(.+?)^/', '', $name );
1800 $u = htmlspecialchars( $url );
1801 $s = "<a href=\"{$u}\" class='internal' title=\"{$alt}\">{$alt}</a>";
1802 return $s;
1805 function specialLink( $name, $key = "" )
1807 global $wgLang;
1809 if ( "" == $key ) { $key = strtolower( $name ); }
1810 $pn = $wgLang->ucfirst( $name );
1811 return $this->makeKnownLink( $wgLang->specialPage( $pn ),
1812 wfMsg( $key ) );
1815 function makeExternalLink( $url, $text, $escape = true ) {
1816 $style = $this->getExternalLinkAttributes( $url, $text );
1817 $url = htmlspecialchars( $url );
1818 if( $escape ) {
1819 $text = htmlspecialchars( $text );
1821 return "<a href=\"$url\"$style>$text</a>";
1824 # Called by history lists and recent changes
1827 # Returns text for the start of the tabular part of RC
1828 function beginRecentChangesList()
1830 $this->rc_cache = array() ;
1831 $this->rcMoveIndex = 0;
1832 $this->rcCacheIndex = 0 ;
1833 $this->lastdate = "";
1834 $this->rclistOpen = false;
1835 return "";
1838 function beginImageHistoryList()
1840 $s = "\n<h2>" . wfMsg( "imghistory" ) . "</h2>\n" .
1841 "<p>" . wfMsg( "imghistlegend" ) . "</p>\n<ul class='special'>";
1842 return $s;
1845 # Returns text for the end of RC
1846 # If enhanced RC is in use, returns pretty much all the text
1847 function endRecentChangesList()
1849 $s = $this->recentChangesBlock() ;
1850 if( $this->rclistOpen ) {
1851 $s .= "</ul>\n";
1853 return $s;
1856 # Enhanced RC ungrouped line
1857 function recentChangesBlockLine ( $rcObj )
1859 global $wgUploadPath, $wgLang ;
1861 # Get rc_xxxx variables
1862 extract( $rcObj->mAttribs ) ;
1863 $curIdEq = "curid=$rc_cur_id";
1865 # Spacer image
1866 $r = "" ;
1868 $r .= "<img src='{$wgUploadPath}/Arr_.png' width='12' height='12' border='0' />" ; $r .= "<tt>" ;
1870 if ( $rc_type == RC_MOVE ) {
1871 $r .= "&nbsp;&nbsp;";
1872 } else {
1873 # M & N (minor & new)
1874 $M = wfMsg( "minoreditletter" );
1875 $N = wfMsg( "newpageletter" );
1877 if ( $rc_type == RC_NEW ) {
1878 $r .= $N ;
1879 } else {
1880 $r .= "&nbsp;" ;
1882 if ( $rc_minor ) {
1883 $r .= $M ;
1884 } else {
1885 $r .= "&nbsp;" ;
1889 # Timestamp
1890 $r .= " ".$rcObj->timestamp." " ;
1891 $r .= "</tt>" ;
1893 # Article link
1894 $link = $rcObj->link ;
1895 if ( $rcObj->watched ) $link = "<strong>{$link}</strong>" ;
1896 $r .= $link ;
1898 # Cur
1899 $r .= " (" ;
1900 $r .= $rcObj->curlink ;
1901 $r .= "; " ;
1903 # Hist
1904 $r .= $this->makeKnownLinkObj( $rcObj->getTitle(), wfMsg( "hist" ), "{$curIdEq}&action=history" );
1906 # User/talk
1907 $r .= ") . . ".$rcObj->userlink ;
1908 $r .= $rcObj->usertalklink ;
1910 # Comment
1911 if ( $rc_comment != "" && $rc_type != RC_MOVE ) {
1912 $rc_comment=$this->formatComment($rc_comment);
1913 $r .= $wgLang->emphasize( " (".$rc_comment.")" );
1916 $r .= "<br />\n" ;
1917 return $r ;
1920 # Enhanced RC group
1921 function recentChangesBlockGroup ( $block )
1923 global $wgUploadPath, $wgLang ;
1925 $r = "" ;
1926 $M = wfMsg( "minoreditletter" );
1927 $N = wfMsg( "newpageletter" );
1929 # Collate list of users
1930 $isnew = false ;
1931 $userlinks = array () ;
1932 foreach ( $block AS $rcObj ) {
1933 $oldid = $rcObj->mAttribs['rc_last_oldid'];
1934 if ( $rcObj->mAttribs['rc_new'] ) $isnew = true ;
1935 $u = $rcObj->userlink ;
1936 if ( !isset ( $userlinks[$u] ) ) $userlinks[$u] = 0 ;
1937 $userlinks[$u]++ ;
1940 # Sort the list and convert to text
1941 krsort ( $userlinks ) ;
1942 asort ( $userlinks ) ;
1943 $users = array () ;
1944 foreach ( $userlinks as $userlink => $count) {
1945 $text = $userlink ;
1946 if ( $count > 1 ) $text .= " ({$count}&times;)" ;
1947 array_push ( $users , $text ) ;
1949 $users = " <font size='-1'>[".implode("; ",$users)."]</font>" ;
1951 # Arrow
1952 $rci = "RCI{$this->rcCacheIndex}" ;
1953 $rcl = "RCL{$this->rcCacheIndex}" ;
1954 $rcm = "RCM{$this->rcCacheIndex}" ;
1955 $toggleLink = "javascript:toggleVisibility(\"{$rci}\",\"{$rcm}\",\"{$rcl}\")" ;
1956 $arrowdir = $wgLang->isRTL() ? "l" : "r";
1957 $tl = "<span id='{$rcm}'><a href='$toggleLink'><img src='{$wgUploadPath}/Arr_{$arrowdir}.png' width='12' height='12' /></a></span>" ;
1958 $tl .= "<span id='{$rcl}' style='display:none'><a href='$toggleLink'><img src='{$wgUploadPath}/Arr_d.png' width='12' height='12' /></a></span>" ;
1959 $r .= $tl ;
1961 # Main line
1962 # M/N
1963 $r .= "<tt>" ;
1964 if ( $isnew ) $r .= $N ;
1965 else $r .= "&nbsp;" ;
1966 $r .= "&nbsp;" ; # Minor
1968 # Timestamp
1969 $r .= " ".$block[0]->timestamp." " ;
1970 $r .= "</tt>" ;
1972 # Article link
1973 $link = $block[0]->link ;
1974 if ( $block[0]->watched ) $link = "<strong>{$link}</strong>" ;
1975 $r .= $link ;
1977 $curIdEq = "curid=" . $block[0]->mAttribs['rc_cur_id'];
1978 if ( $block[0]->mAttribs['rc_type'] != RC_LOG ) {
1979 # Changes
1980 $r .= " (".count($block)." " ;
1981 if ( $isnew ) $r .= wfMsg("changes");
1982 else $r .= $this->makeKnownLinkObj( $block[0]->getTitle() , wfMsg("changes") ,
1983 "{$curIdEq}&diff=0&oldid=".$oldid ) ;
1984 $r .= "; " ;
1986 # History
1987 $r .= $this->makeKnownLinkObj( $block[0]->getTitle(), wfMsg( "history" ), "{$curIdEq}&action=history" );
1988 $r .= ")" ;
1991 $r .= $users ;
1992 $r .= "<br />\n" ;
1994 # Sub-entries
1995 $r .= "<div id='{$rci}' style='display:none'>" ;
1996 foreach ( $block AS $rcObj ) {
1997 # Get rc_xxxx variables
1998 extract( $rcObj->mAttribs );
2000 $r .= "<img src='{$wgUploadPath}/Arr_.png' width=12 height=12 />";
2001 $r .= "<tt>&nbsp; &nbsp; &nbsp; &nbsp;" ;
2002 if ( $rc_new ) $r .= $N ;
2003 else $r .= "&nbsp;" ;
2004 if ( $rc_minor ) $r .= $M ;
2005 else $r .= "&nbsp;" ;
2006 $r .= "</tt>" ;
2008 $o = "" ;
2009 if ( $rc_last_oldid != 0 ) {
2010 $o = "oldid=".$rc_last_oldid ;
2012 if ( $rc_type == RC_LOG ) {
2013 $link = $rcObj->timestamp ;
2014 } else {
2015 $link = $this->makeKnownLinkObj( $rcObj->getTitle(), $rcObj->timestamp , "{$curIdEq}&$o" ) ;
2017 $link = "<tt>{$link}</tt>" ;
2019 $r .= $link ;
2020 $r .= " (" ;
2021 $r .= $rcObj->curlink ;
2022 $r .= "; " ;
2023 $r .= $rcObj->lastlink ;
2024 $r .= ") . . ".$rcObj->userlink ;
2025 $r .= $rcObj->usertalklink ;
2026 if ( $rc_comment != "" ) {
2027 $rc_comment=$this->formatComment($rc_comment);
2028 $r .= $wgLang->emphasize( " (".$rc_comment.")" ) ;
2030 $r .= "<br />\n" ;
2032 $r .= "</div>\n" ;
2034 $this->rcCacheIndex++ ;
2035 return $r ;
2038 # If enhanced RC is in use, this function takes the previously cached
2039 # RC lines, arranges them, and outputs the HTML
2040 function recentChangesBlock ()
2042 global $wgUploadPath ;
2043 if ( count ( $this->rc_cache ) == 0 ) return "" ;
2044 $blockOut = "";
2045 foreach ( $this->rc_cache AS $secureName => $block ) {
2046 if ( count ( $block ) < 2 ) {
2047 $blockOut .= $this->recentChangesBlockLine ( array_shift ( $block ) ) ;
2048 } else {
2049 $blockOut .= $this->recentChangesBlockGroup ( $block ) ;
2053 return "<div>{$blockOut}</div>" ;
2056 # Called in a loop over all displayed RC entries
2057 # Either returns the line, or caches it for later use
2058 function recentChangesLine( &$rc, $watched = false )
2060 global $wgUser ;
2061 $usenew = $wgUser->getOption( "usenewrc" );
2062 if ( $usenew )
2063 $line = $this->recentChangesLineNew ( $rc, $watched ) ;
2064 else
2065 $line = $this->recentChangesLineOld ( $rc, $watched ) ;
2066 return $line ;
2069 function recentChangesLineOld( &$rc, $watched = false )
2071 global $wgTitle, $wgLang, $wgUser, $wgRCSeconds;
2073 # Extract DB fields into local scope
2074 extract( $rc->mAttribs );
2075 $curIdEq = "curid=" . $rc_cur_id;
2077 # Make date header if necessary
2078 $date = $wgLang->date( $rc_timestamp, true);
2079 $s = "";
2080 if ( $date != $this->lastdate ) {
2081 if ( "" != $this->lastdate ) { $s .= "</ul>\n"; }
2082 $s .= "<h4>{$date}</h4>\n<ul class='special'>";
2083 $this->lastdate = $date;
2084 $this->rclistOpen = true;
2086 $s .= "<li> ";
2088 if ( $rc_type == RC_MOVE ) {
2089 # Diff
2090 $s .= "(" . wfMsg( "diff" ) . ") (";
2091 # Hist
2092 $s .= $this->makeKnownLinkObj( $rc->getMovedToTitle(), wfMsg( "hist" ), "action=history" ) .
2093 ") . . ";
2095 # "[[x]] moved to [[y]]"
2097 $s .= wfMsg( "1movedto2", $this->makeKnownLinkObj( $rc->getTitle(), "", "redirect=no" ),
2098 $this->makeKnownLinkObj( $rc->getMovedToTitle(), "" ) );
2100 } else {
2101 # Diff link
2102 if ( $rc_type == RC_NEW || $rc_type == RC_LOG ) {
2103 $diffLink = wfMsg( "diff" );
2104 } else {
2105 $diffLink = $this->makeKnownLinkObj( $rc->getTitle(), wfMsg( "diff" ),
2106 "{$curIdEq}&diff={$rc_this_oldid}&oldid={$rc_last_oldid}" ,'' ,'' , ' tabindex="'.$rc->counter.'"');
2108 $s .= "($diffLink) (";
2110 # History link
2111 $s .= $this->makeKnownLinkObj( $rc->getTitle(), wfMsg( "hist" ), "{$curIdEq}&action=history" );
2112 $s .= ") . . ";
2114 # M and N (minor and new)
2115 $M = wfMsg( "minoreditletter" );
2116 $N = wfMsg( "newpageletter" );
2117 if ( $rc_minor ) { $s .= " <strong>{$M}</strong>"; }
2118 if ( $rc_type == RC_NEW ) { $s .= "<strong>{$N}</strong>"; }
2120 # Article link
2121 $articleLink = $this->makeKnownLinkObj( $rc->getTitle(), "" );
2123 if ( $watched ) {
2124 $articleLink = "<strong>{$articleLink}</strong>";
2126 $s .= " $articleLink";
2130 # Timestamp
2131 $s .= "; " . $wgLang->time( $rc_timestamp, true, $wgRCSeconds ) . " . . ";
2133 # User link (or contributions for unregistered users)
2134 if ( 0 == $rc_user ) {
2135 $userLink = $this->makeKnownLink( $wgLang->specialPage( "Contributions" ),
2136 $rc_user_text, "target=" . $rc_user_text );
2137 } else {
2138 $userLink = $this->makeLink( $wgLang->getNsText( NS_USER ) . ":{$rc_user_text}", $rc_user_text );
2140 $s .= $userLink;
2142 # User talk link
2143 $talkname=$wgLang->getNsText(NS_TALK); # use the shorter name
2144 global $wgDisableAnonTalk;
2145 if( 0 == $rc_user && $wgDisableAnonTalk ) {
2146 $userTalkLink = "";
2147 } else {
2148 $utns=$wgLang->getNsText(NS_USER_TALK);
2149 $userTalkLink= $this->makeLink($utns . ":{$rc_user_text}", $talkname );
2151 # Block link
2152 $blockLink="";
2153 if ( ( 0 == $rc_user ) && $wgUser->isSysop() ) {
2154 $blockLink = $this->makeKnownLink( $wgLang->specialPage(
2155 "Blockip" ), wfMsg( "blocklink" ), "ip={$rc_user_text}" );
2158 if($blockLink) {
2159 if($userTalkLink) $userTalkLink .= " | ";
2160 $userTalkLink .= $blockLink;
2162 if($userTalkLink) $s.=" ({$userTalkLink})";
2164 # Add comment
2165 if ( "" != $rc_comment && "*" != $rc_comment && $rc_type != RC_MOVE ) {
2166 $rc_comment=$this->formatComment($rc_comment);
2167 $s .= $wgLang->emphasize(" (" . $rc_comment . ")");
2169 $s .= "</li>\n";
2171 return $s;
2174 # function recentChangesLineNew( $ts, $u, $ut, $ns, $ttl, $c, $isminor, $isnew, $watched = false, $oldid = 0 , $diffid = 0 )
2175 function recentChangesLineNew( &$baseRC, $watched = false )
2177 global $wgTitle, $wgLang, $wgUser, $wgRCSeconds;
2179 # Create a specialised object
2180 $rc = RCCacheEntry::newFromParent( $baseRC ) ;
2182 # Extract fields from DB into the function scope (rc_xxxx variables)
2183 extract( $rc->mAttribs );
2184 $curIdEq = "curid=" . $rc_cur_id;
2186 # If it's a new day, add the headline and flush the cache
2187 $date = $wgLang->date( $rc_timestamp, true);
2188 $ret = "" ;
2189 if ( $date != $this->lastdate ) {
2190 # Process current cache
2191 $ret = $this->recentChangesBlock () ;
2192 $this->rc_cache = array() ;
2193 $ret .= "<h4>{$date}</h4>\n";
2194 $this->lastdate = $date;
2197 # Make article link
2198 if ( $rc_type == RC_MOVE ) {
2199 $clink = $this->makeKnownLinkObj( $rc->getTitle(), "", "redirect=no" );
2200 $clink .= " " . wfMsg("movedto") . " ";
2201 $clink .= $this->makeKnownLinkObj( $rc->getMovedToTitle(), "" );
2202 } else {
2203 $clink = $this->makeKnownLinkObj( $rc->getTitle(), "" ) ;
2206 $time = $wgLang->time( $rc_timestamp, true, $wgRCSeconds );
2207 $rc->watched = $watched ;
2208 $rc->link = $clink ;
2209 $rc->timestamp = $time;
2211 # Make "cur" link
2212 if ( ( $rc_type == RC_NEW && $rc_this_oldid == 0 ) || $rc_type == RC_LOG || $rc_type == RC_MOVE) {
2213 $curLink = wfMsg( "cur" );
2214 } else {
2215 $curLink = $this->makeKnownLinkObj( $rc->getTitle(), wfMsg( "cur" ),
2216 "{$curIdEq}&diff=0&oldid={$rc_this_oldid}" ,'' ,'' , ' tabindex="'.$baseRC->counter.'"' );
2219 # Make "last" link
2220 $titleObj = $rc->getTitle();
2221 if ( $rc_last_oldid == 0 || $rc_type == RC_LOG || $rc_type == RC_MOVE ) {
2222 $lastLink = wfMsg( "last" );
2223 } else {
2224 $lastLink = $this->makeKnownLinkObj( $rc->getTitle(), wfMsg( "last" ),
2225 "{$curIdEq}&diff={$rc_this_oldid}&oldid={$rc_last_oldid}" );
2228 # Make user link (or user contributions for unregistered users)
2229 if ( 0 == $rc_user ) {
2230 $userLink = $this->makeKnownLink( $wgLang->specialPage( "Contributions" ),
2231 $rc_user_text, "target=" . $rc_user_text );
2232 } else {
2233 $userLink = $this->makeLink( $wgLang->getNsText(
2234 Namespace::getUser() ) . ":{$rc_user_text}", $rc_user_text );
2237 $rc->userlink = $userLink ;
2238 $rc->lastlink = $lastLink ;
2239 $rc->curlink = $curLink ;
2241 # Make user talk link
2242 $utns=$wgLang->getNsText(NS_USER_TALK);
2243 $talkname=$wgLang->getNsText(NS_TALK); # use the shorter name
2244 $userTalkLink= $this->makeLink($utns . ":{$rc_user_text}", $talkname );
2246 global $wgDisableAnonTalk;
2247 if ( ( 0 == $rc_user ) && $wgUser->isSysop() ) {
2248 $blockLink = $this->makeKnownLink( $wgLang->specialPage(
2249 "Blockip" ), wfMsg( "blocklink" ), "ip={$rc_user_text}" );
2250 if( $wgDisableAnonTalk )
2251 $rc->usertalklink = " ({$blockLink})";
2252 else
2253 $rc->usertalklink = " ({$userTalkLink} | {$blockLink})";
2254 } else {
2255 if( $wgDisableAnonTalk && ($rc_user == 0) )
2256 $rc->usertalklink = "";
2257 else
2258 $rc->usertalklink = " ({$userTalkLink})";
2261 # Put accumulated information into the cache, for later display
2262 # Page moves go on their own line
2263 $title = $rc->getTitle();
2264 $secureName = $title->getPrefixedDBkey();
2265 if ( $rc_type == RC_MOVE ) {
2266 # Use an @ character to prevent collision with page names
2267 $this->rc_cache["@@" . ($this->rcMoveIndex++)] = array($rc);
2268 } else {
2269 if ( !isset ( $this->rc_cache[$secureName] ) ) $this->rc_cache[$secureName] = array() ;
2270 array_push ( $this->rc_cache[$secureName] , $rc ) ;
2272 return $ret;
2275 function endImageHistoryList()
2277 $s = "</ul>\n";
2278 return $s;
2281 /* This function is called by all recent changes variants, by the page history,
2282 and by the user contributions list. It is responsible for formatting edit
2283 comments. It escapes any HTML in the comment, but adds some CSS to format
2284 auto-generated comments (from section editing) and formats [[wikilinks]].
2285 Main author: Erik Möller (moeller@scireview.de)
2287 function formatComment($comment)
2289 global $wgLang;
2290 $comment=wfEscapeHTML($comment);
2292 # The pattern for autogen comments is / * foo * /, which makes for
2293 # some nasty regex.
2294 # We look for all comments, match any text before and after the comment,
2295 # add a separator where needed and format the comment itself with CSS
2296 while (preg_match("/(.*)\/\*\s*(.*?)\s*\*\/(.*)/", $comment,$match)) {
2297 $pre=$match[1];
2298 $auto=$match[2];
2299 $post=$match[3];
2300 $sep="-";
2301 if($pre) { $auto="$sep ".$auto; }
2302 if($post) { $auto.=" $sep"; }
2303 $auto="<span class=\"autocomment\">".$auto."</span>";
2304 $comment=$pre.$auto.$post;
2307 # format regular and media links - all other wiki formatting
2308 # is ignored
2309 while(preg_match("/\[\[(.*?)(\|(.*?))*\]\]/",$comment,$match)) {
2311 $medians = $wgLang->getNsText(Namespace::getMedia());
2312 $func="makeLink";
2313 if(preg_match("/^".$medians."/i",$match[1])) {
2314 $func="makeMediaLink";
2316 if(isset($match[3]) ) {
2317 $comment=
2318 preg_replace("/\[\[(.*?)\]\]/",
2319 $this->$func($match[1],$match[3]),$comment,1);
2320 } else {
2321 $comment=
2322 preg_replace("/\[\[(.*?)\]\]/",
2323 $this->$func($match[1],$match[1]),$comment,1);
2327 return $comment;
2331 function imageHistoryLine( $iscur, $ts, $img, $u, $ut, $size, $c )
2333 global $wgUser, $wgLang, $wgTitle;
2335 $dt = $wgLang->timeanddate( $ts, true );
2336 $del = wfMsg( "deleteimg" );
2337 $cur = wfMsg( "cur" );
2339 if ( $iscur ) {
2340 $url = wfImageUrl( $img );
2341 $rlink = $cur;
2342 if ( $wgUser->isSysop() ) {
2343 $link = $wgTitle->escapeLocalURL( "image=" . $wgTitle->getPartialURL() .
2344 "&action=delete" );
2345 $style = $this->getInternalLinkAttributes( $link, $del );
2347 $dlink = "<a href=\"{$link}\"{$style}>{$del}</a>";
2348 } else {
2349 $dlink = $del;
2351 } else {
2352 $url = wfEscapeHTML( wfImageArchiveUrl( $img ) );
2353 if( $wgUser->getID() != 0 ) {
2354 $rlink = $this->makeKnownLink( $wgTitle->getPrefixedText(),
2355 wfMsg( "revertimg" ), "action=revert&oldimage=" .
2356 urlencode( $img ) );
2357 $dlink = $this->makeKnownLink( $wgTitle->getPrefixedText(),
2358 $del, "action=delete&oldimage=" . urlencode( $img ) );
2359 } else {
2360 # Having live active links for non-logged in users
2361 # means that bots and spiders crawling our site can
2362 # inadvertently change content. Baaaad idea.
2363 $rlink = wfMsg( "revertimg" );
2364 $dlink = $del;
2367 if ( 0 == $u ) { $ul = $ut; }
2368 else { $ul = $this->makeLink( $wgLang->getNsText(
2369 Namespace::getUser() ) . ":{$ut}", $ut ); }
2371 $nb = wfMsg( "nbytes", $size );
2372 $style = $this->getInternalLinkAttributes( $url, $dt );
2374 $s = "<li> ({$dlink}) ({$rlink}) <a href=\"{$url}\"{$style}>{$dt}</a>"
2375 . " . . {$ul} ({$nb})";
2377 if ( "" != $c && "*" != $c ) {
2378 $sk=$wgUser->getSkin();
2379 $s .= $wgLang->emphasize(" (" . $sk->formatComment($c) . ")");
2381 $s .= "</li>\n";
2382 return $s;
2385 function tocIndent($level) {
2386 return str_repeat( "<div class='tocindent'>\n", $level>0 ? $level : 0 );
2389 function tocUnindent($level) {
2390 return str_repeat( "</div>\n", $level>0 ? $level : 0 );
2393 # parameter level defines if we are on an indentation level
2394 function tocLine( $anchor, $tocline, $level ) {
2395 $link = "<a href=\"#$anchor\">$tocline</a><br />";
2396 if($level) {
2397 return "$link\n";
2398 } else {
2399 return "<div class='tocline'>$link</div>\n";
2404 function tocTable($toc) {
2405 # note to CSS fanatics: putting this in a div does not work -- div won't auto-expand
2406 # try min-width & co when somebody gets a chance
2407 $hideline = " <script type='text/javascript'>showTocToggle(\"" . addslashes( wfMsg("showtoc") ) . "\",\"" . addslashes( wfMsg("hidetoc") ) . "\")</script>";
2408 return
2409 "<table border=\"0\" id=\"toc\"><tr><td align=\"center\">\n".
2410 "<b>".wfMsg("toc")."</b>" .
2411 $hideline .
2412 "</td></tr><tr id='tocinside'><td>\n".
2413 $toc."</td></tr></table>\n";
2416 # These two do not check for permissions: check $wgTitle->userCanEdit before calling them
2417 function editSectionScript( $section, $head ) {
2418 global $wgTitle, $wgRequest;
2419 if( $wgRequest->getInt( "oldid" ) && ( $wgRequest->getVal( "diff" ) != "0" ) ) {
2420 return $head;
2422 $url = $wgTitle->escapeLocalURL( "action=edit&section=$section" );
2423 return "<span oncontextmenu='document.location=\"$url\";return false;'>{$head}</span>";
2426 function editSectionLink( $section ) {
2427 global $wgRequest;
2428 global $wgTitle, $wgUser, $wgLang;
2430 if( $wgRequest->getInt( "oldid" ) && ( $wgRequest->getVal( "diff" ) != "0" ) ) {
2431 # Section edit links would be out of sync on an old page.
2432 # But, if we're diffing to the current page, they'll be
2433 # correct.
2434 return "";
2437 $editurl = "&section={$section}";
2438 $url = $this->makeKnownLink($wgTitle->getPrefixedText(),wfMsg("editsection"),"action=edit".$editurl);
2440 if( $wgLang->isRTL() ) {
2441 $farside = "left";
2442 $nearside = "right";
2443 } else {
2444 $farside = "right";
2445 $nearside = "left";
2447 return "<div class=\"editsection\" style=\"float:$farside;margin-$nearside:5px;\">[".$url."]</div>";
2451 // This function is called by EditPage.php and shows a bulletin board style
2452 // toolbar for common editing functions. It can be disabled in the user preferences.
2453 // The necsesary JavaScript code can be found in style/wikibits.js.
2454 function getEditToolbar() {
2455 global $wgUploadPath, $wgLang, $wgMimeType;
2457 // toolarray an array of arrays which each include the filename of
2458 // the button image (without path), the opening tag, the closing tag,
2459 // and optionally a sample text that is inserted between the two when no
2460 // selection is highlighted.
2461 // The tip text is shown when the user moves the mouse over the button.
2463 // Already here are accesskeys (key), which are not used yet until someone
2464 // can figure out a way to make them work in IE. However, we should make
2465 // sure these keys are not defined on the edit page.
2466 $toolarray=array(
2467 array( "image"=>"button_bold.png",
2468 "open"=>"\'\'\'",
2469 "close"=>"\'\'\'",
2470 "sample"=>wfMsg("bold_sample"),
2471 "tip"=>wfMsg("bold_tip"),
2472 "key"=>"B"
2474 array( "image"=>"button_italic.png",
2475 "open"=>"\'\'",
2476 "close"=>"\'\'",
2477 "sample"=>wfMsg("italic_sample"),
2478 "tip"=>wfMsg("italic_tip"),
2479 "key"=>"I"
2481 array( "image"=>"button_link.png",
2482 "open"=>"[[",
2483 "close"=>"]]",
2484 "sample"=>wfMsg("link_sample"),
2485 "tip"=>wfMsg("link_tip"),
2486 "key"=>"L"
2488 array( "image"=>"button_extlink.png",
2489 "open"=>"[",
2490 "close"=>"]",
2491 "sample"=>wfMsg("extlink_sample"),
2492 "tip"=>wfMsg("extlink_tip"),
2493 "key"=>"X"
2495 array( "image"=>"button_headline.png",
2496 "open"=>"\\n== ",
2497 "close"=>" ==\\n",
2498 "sample"=>wfMsg("headline_sample"),
2499 "tip"=>wfMsg("headline_tip"),
2500 "key"=>"H"
2502 array( "image"=>"button_image.png",
2503 "open"=>"[[".$wgLang->getNsText(NS_IMAGE).":",
2504 "close"=>"]]",
2505 "sample"=>wfMsg("image_sample"),
2506 "tip"=>wfMsg("image_tip"),
2507 "key"=>"D"
2509 array( "image"=>"button_media.png",
2510 "open"=>"[[".$wgLang->getNsText(NS_MEDIA).":",
2511 "close"=>"]]",
2512 "sample"=>wfMsg("media_sample"),
2513 "tip"=>wfMsg("media_tip"),
2514 "key"=>"M"
2516 array( "image"=>"button_math.png",
2517 "open"=>"\\<math\\>",
2518 "close"=>"\\</math\\>",
2519 "sample"=>wfMsg("math_sample"),
2520 "tip"=>wfMsg("math_tip"),
2521 "key"=>"C"
2523 array( "image"=>"button_nowiki.png",
2524 "open"=>"\\<nowiki\\>",
2525 "close"=>"\\</nowiki\\>",
2526 "sample"=>wfMsg("nowiki_sample"),
2527 "tip"=>wfMsg("nowiki_tip"),
2528 "key"=>"N"
2530 array( "image"=>"button_sig.png",
2531 "open"=>"--~~~~",
2532 "close"=>"",
2533 "sample"=>"",
2534 "tip"=>wfMsg("sig_tip"),
2535 "key"=>"Y"
2537 array( "image"=>"button_hr.png",
2538 "open"=>"\\n----\\n",
2539 "close"=>"",
2540 "sample"=>"",
2541 "tip"=>wfMsg("hr_tip"),
2542 "key"=>"R"
2545 $toolbar ="<script type='text/javascript'>\n/*<![CDATA[*/\n";
2547 $toolbar.="document.writeln(\"<div id='toolbar' tabindex='4000000'>\");\n";
2548 foreach($toolarray as $tool) {
2550 $image=$wgUploadPath."/".$tool["image"];
2551 $open=$tool["open"];
2552 $close=$tool["close"];
2553 $sample = addslashes( $tool["sample"] );
2555 // Note that we use the tip both for the ALT tag and the TITLE tag of the image.
2556 // Older browsers show a "speedtip" type message only for ALT.
2557 // Ideally these should be different, realistically they
2558 // probably don't need to be.
2559 $tip = addslashes( $tool["tip"] );
2561 #$key = $tool["key"];
2563 $toolbar.="addButton('$image','$tip','$open','$close','$sample');\n";
2566 $toolbar.="addInfobox('" . addslashes( wfMsg( "infobox" ) ) . "','" . addslashes(wfMsg("infobox_alert")) . "');\n";
2567 $toolbar.="document.writeln(\"</div>\");\n";
2569 $toolbar.="/*]]>*/</script>";
2570 return $toolbar;
2574 include_once( "SkinStandard.php" );
2575 include_once( "SkinNostalgia.php" );
2576 include_once( "SkinCologneBlue.php" );
2578 if( $wgUsePHPTal ) {
2579 include_once( "SkinPHPTal.php" );