quick hack to protect css/js subpages of userpages. Should be replaced by some more...
[mediawiki.git] / includes / Skin.php
blob16e57116ca6859ef13d3dde5787e0e6180705d43
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 class RCCacheEntry extends RecentChange
29 var $secureName, $link;
30 var $curlink , $lastlink , $usertalklink , $versionlink ;
31 var $userlink, $timestamp, $watched;
33 function newFromParent( $rc )
35 $rc2 = new RCCacheEntry;
36 $rc2->mAttribs = $rc->mAttribs;
37 $rc2->mExtra = $rc->mExtra;
38 return $rc2;
40 } ;
42 class Skin {
44 /* private */ var $lastdate, $lastline;
45 var $linktrail ; # linktrail regexp
46 var $rc_cache ; # Cache for Enhanced Recent Changes
47 var $rcCacheIndex ; # Recent Changes Cache Counter for visibility toggle
48 var $rcMoveIndex;
50 function Skin()
52 $this->linktrail = wfMsg("linktrail");
55 function getSkinNames()
57 global $wgValidSkinNames;
58 return $wgValidSkinNames;
61 function getStylesheet()
63 return "wikistandard.css";
66 function qbSetting()
68 global $wgOut, $wgUser;
70 if ( $wgOut->isQuickbarSuppressed() ) { return 0; }
71 $q = $wgUser->getOption( "quickbar" );
72 if ( "" == $q ) { $q = 0; }
73 return $q;
76 function initPage( &$out )
78 $fname = "Skin::initPage";
79 wfProfileIn( $fname );
81 $out->addLink( array( "rel" => "shortcut icon", "href" => "/favicon.ico" ) );
83 $this->addMetadataLinks($out);
85 wfProfileOut( $fname );
88 function addMetadataLinks( &$out ) {
89 global $wgTitle, $wgEnableDublinCoreRdf, $wgEnableCreativeCommonsRdf, $wgRdfMimeType, $action;
90 global $wgRightsPage, $wgRightsUrl;
92 if( $out->isArticleRelated() ) {
93 # note: buggy CC software only reads first "meta" link
94 if( $wgEnableCreativeCommonsRdf ) {
95 $out->addMetadataLink( array(
96 'title' => 'Creative Commons',
97 'type' => 'application/rdf+xml',
98 'href' => $wgTitle->getLocalURL( "action=creativecommons") ) );
100 if( $wgEnableDublinCoreRdf ) {
101 $out->addMetadataLink( array(
102 'title' => 'Dublin Core',
103 'type' => 'application/rdf+xml',
104 'href' => $wgTitle->getLocalURL( "action=dublincore" ) ) );
107 $copyright = "";
108 if( $wgRightsPage ) {
109 $copy = Title::newFromText( $wgRightsPage );
110 if( $copy ) {
111 $copyright = $copy->getLocalURL();
114 if( !$copyright && $wgRightsUrl ) {
115 $copyright = $wgRightsUrl;
117 if( $copyright ) {
118 $out->addLink( array(
119 "rel" => "copyright",
120 "href" => $copyright ) );
124 function outputPage( &$out ) {
125 global $wgDebugComments;
127 wfProfileIn( "Skin::outputPage" );
128 $this->initPage( $out );
129 $out->out( $out->headElement() );
131 $out->out( "\n<body" );
132 $ops = $this->getBodyOptions();
133 foreach ( $ops as $name => $val ) {
134 $out->out( " $name='$val'" );
136 $out->out( ">\n" );
137 if ( $wgDebugComments ) {
138 $out->out( "<!-- Wiki debugging output:\n" .
139 $out->mDebugtext . "-->\n" );
141 $out->out( $this->beforeContent() );
143 $out->out( $out->mBodytext . "\n" );
145 $out->out( $this->afterContent() );
147 wfProfileClose();
148 $out->out( $out->reportTime() );
150 $out->out( "\n</body></html>" );
153 function getHeadScripts() {
154 global $wgStylePath;
155 $r = "<script type=\"text/javascript\" src=\"{$wgStylePath}/wikibits.js\"></script>\n";
156 return $r;
159 function getUserStyles()
161 global $wgOut, $wgStylePath;
162 $sheet = $this->getStylesheet();
163 $s = "<style type='text/css'>\n";
164 $s .= "/*/*/\n"; # <-- Hide the styles from Netscape 4 without hiding them from IE/Mac
165 $s .= "@import url(\"$wgStylePath/$sheet\");\n";
166 $s .= $this->doGetUserStyles();
167 $s .= "/* */\n";
168 $s .= "</style>\n";
169 return $s;
172 function doGetUserStyles()
174 global $wgUser;
176 $s = "";
177 if ( 1 == $wgUser->getOption( "underline" ) ) {
178 # Don't override browser settings
179 } else {
180 # CHECK MERGE @@@
181 # Force no underline
182 $s .= "a { " .
183 "text-decoration: none; }\n";
185 if ( 1 == $wgUser->getOption( "highlightbroken" ) ) {
186 $s .= "a.new, #quickbar a.new { color: #CC2200; }\n";
188 if ( 1 == $wgUser->getOption( "justify" ) ) {
189 $s .= "#article { text-align: justify; }\n";
191 return $s;
194 function getBodyOptions()
196 global $wgUser, $wgTitle, $wgNamespaceBackgrounds, $wgOut, $wgRequest;
198 extract( $wgRequest->getValues( 'oldid', 'redirect', 'diff' ) );
200 if ( 0 != $wgTitle->getNamespace() ) {
201 $a = array( "bgcolor" => "#ffffec" );
203 else $a = array( "bgcolor" => "#FFFFFF" );
204 if($wgOut->isArticle() && $wgUser->getOption("editondblclick") &&
205 (!$wgTitle->isProtected() || $wgUser->isSysop()) ) {
206 $t = wfMsg( "editthispage" );
207 $oid = $red = "";
208 if ( !empty($redirect) ) {
209 $red = "&redirect={$redirect}";
211 if ( !empty($oldid) && ! isset( $diff ) ) {
212 $oid = "&oldid={$oldid}";
214 $s = $wgTitle->getFullURL( "action=edit{$oid}{$red}" );
215 $s = "document.location = \"" .$s ."\";";
216 $a += array ("ondblclick" => $s);
219 $a['onload'] = $wgOut->getOnloadHandler();
220 return $a;
223 function getExternalLinkAttributes( $link, $text )
225 global $wgUser, $wgOut, $wgLang;
227 $link = urldecode( $link );
228 $link = $wgLang->checkTitleEncoding( $link );
229 $link = str_replace( "_", " ", $link );
230 $link = wfEscapeHTML( $link );
232 $r = " class='external'";
234 if ( 1 == $wgUser->getOption( "hover" ) ) {
235 $r .= " title=\"{$link}\"";
237 return $r;
240 function getInternalLinkAttributes( $link, $text, $broken = false )
242 global $wgUser, $wgOut;
244 $link = urldecode( $link );
245 $link = str_replace( "_", " ", $link );
246 $link = wfEscapeHTML( $link );
248 if ( $broken == "stub" ) {
249 $r = " class='stub'";
250 } else if ( $broken == "yes" ) {
251 $r = " class='new'";
252 } else {
253 $r = "";
256 if ( 1 == $wgUser->getOption( "hover" ) ) {
257 $r .= " title=\"{$link}\"";
259 return $r;
262 function getInternalLinkAttributesObj( &$nt, $text, $broken = false )
264 global $wgUser, $wgOut;
266 if ( $broken == "stub" ) {
267 $r = " class='stub'";
268 } else if ( $broken == "yes" ) {
269 $r = " class='new'";
270 } else {
271 $r = "";
274 if ( 1 == $wgUser->getOption( "hover" ) ) {
275 $r .= ' title ="' . $nt->getEscapedText() . '"';
277 return $r;
280 function getLogo()
282 global $wgLogo;
283 return $wgLogo;
286 # This will be called immediately after the <body> tag. Split into
287 # two functions to make it easier to subclass.
289 function beforeContent()
291 global $wgUser, $wgOut, $wgSiteNotice;
293 if( $wgSiteNotice ) {
294 $note = "\n<div id='notice' style='font-weight: bold; color: red; text-align: center'>$wgSiteNotice</div>\n";
295 } else {
296 $note = "";
298 return $this->doBeforeContent() . $note;
301 function doBeforeContent()
303 global $wgUser, $wgOut, $wgTitle, $wgLang;
304 $fname = "Skin::doBeforeContent";
305 wfProfileIn( $fname );
307 $s = "";
308 $qb = $this->qbSetting();
310 if( $langlinks = $this->otherLanguages() ) {
311 $rows = 2;
312 $borderhack = "";
313 } else {
314 $rows = 1;
315 $langlinks = false;
316 $borderhack = "class='top'";
319 $s .= "\n<div id='content'>\n<div id='topbar'>\n" .
320 "<table border='0' cellspacing='0' width='98%'>\n<tr>\n";
322 $shove = ($qb != 0);
323 $left = ($qb == 1 || $qb == 3);
324 if($wgLang->isRTL()) $left = !$left;
326 if ( !$shove ) {
327 $s .= "<td class='top' align='left' valign='top' rowspan='{$rows}'>\n" .
328 $this->logoText() . "</td>";
329 } elseif( $left ) {
330 $s .= $this->getQuickbarCompensator( $rows );
332 $l = $wgLang->isRTL() ? "right" : "left";
333 $s .= "<td {$borderhack} align='$l' valign='top'>\n";
335 $s .= $this->topLinks() ;
336 $s .= "<p class='subtitle'>" . $this->pageTitleLinks() . "</p>\n";
338 $r = $wgLang->isRTL() ? "left" : "right";
339 $s .= "</td>\n<td {$borderhack} valign='top' align='$r' nowrap='nowrap'>";
340 $s .= $this->nameAndLogin();
341 $s .= "\n<br />" . $this->searchForm() . "</td>";
343 if ( $langlinks ) {
344 $s .= "</tr>\n<tr>\n<td class='top' colspan=\"2\">$langlinks</td>\n";
347 if ( $shove && !$left ) { # Right
348 $s .= $this->getQuickbarCompensator( $rows );
350 $s .= "</tr>\n</table>\n</div>\n";
351 $s .= "\n<div id='article'>\n";
353 $s .= $this->pageTitle();
354 $s .= $this->pageSubtitle() ;
355 $s .= $this->getCategories();
356 wfProfileOut( $fname );
357 return $s;
360 function getCategories () {
361 global $wgOut, $wgTitle, $wgUser, $wgParser;
362 global $wgUseCategoryMagic;
363 if( !$wgUseCategoryMagic ) return "" ;
364 if( count( $wgOut->mCategoryLinks ) == 0 ) return "";
365 if( !$wgOut->isArticle() ) return "";
367 $t = implode ( " | " , $wgOut->mCategoryLinks ) ;
368 $s = $this->makeKnownLink( "Special:Categories",
369 wfMsg( "categories" ), "article=" . urlencode( $wgTitle->getPrefixedDBkey() ) )
370 . ": " . $t;
371 return "<p class='catlinks'>$s</p>";
374 function getQuickbarCompensator( $rows = 1 )
376 return "<td width='152' rowspan='{$rows}'>&nbsp;</td>";
379 # This gets called immediately before the </body> tag.
381 function afterContent()
383 global $wgUser, $wgOut, $wgServer;
384 global $wgTitle, $wgLang;
386 $printfooter = "<div class=\"printfooter\">\n" . $this->printFooter() . "</div>\n";
387 return $printfooter . $this->doAfterContent();
390 function printFooter() {
391 global $wgTitle;
392 $url = htmlspecialchars( $wgTitle->getFullURL() );
393 return "<p>" . wfMsg( "retrievedfrom", "<a href=\"$url\">$url</a>" ) .
394 "</p>\n\n<p>" . $this->pageStats() . "</p>\n";
397 function doAfterContent()
399 global $wgUser, $wgOut, $wgLang;
400 $fname = "Skin::doAfterContent";
401 wfProfileIn( $fname );
402 wfProfileIn( "$fname-1" );
404 $s = "\n</div><br clear='all' />\n";
405 $s .= "\n<div id='footer'>";
406 $s .= "<table border='0' cellspacing='0'><tr>";
408 wfProfileOut( "$fname-1" );
409 wfProfileIn( "$fname-2" );
411 $qb = $this->qbSetting();
412 $shove = ($qb != 0);
413 $left = ($qb == 1 || $qb == 3);
414 if($wgLang->isRTL()) $left = !$left;
416 if ( $shove && $left ) { # Left
417 $s .= $this->getQuickbarCompensator();
419 wfProfileOut( "$fname-2" );
420 wfProfileIn( "$fname-3" );
421 $l = $wgLang->isRTL() ? "right" : "left";
422 $s .= "<td class='bottom' align='$l' valign='top'>";
424 $s .= $this->bottomLinks();
425 $s .= "\n<br />" . $this->mainPageLink()
426 . " | " . $this->aboutLink()
427 . " | " . $this->specialLink( "recentchanges" )
428 . " | " . $this->searchForm()
429 . "<br /><span id='pagestats'>" . $this->pageStats() . "</span>";
431 $s .= "</td>";
432 if ( $shove && !$left ) { # Right
433 $s .= $this->getQuickbarCompensator();
435 $s .= "</tr></table>\n</div>\n</div>\n";
437 wfProfileOut( "$fname-3" );
438 wfProfileIn( "$fname-4" );
439 if ( 0 != $qb ) { $s .= $this->quickBar(); }
440 wfProfileOut( "$fname-4" );
441 wfProfileOut( $fname );
442 return $s;
445 function pageTitleLinks()
447 global $wgOut, $wgTitle, $wgUser, $wgLang, $wgUseApproval, $wgRequest;
449 extract( $wgRequest->getValues( 'oldid', 'diff' ) );
450 $action = $wgRequest->getText( 'action' );
452 $s = $this->printableLink();
453 if ( wfMsg ( "disclaimers" ) != "-" ) $s .= " | " . $this->makeKnownLink( wfMsg( "disclaimerpage" ), wfMsg( "disclaimers" ) ) ;
455 if ( $wgOut->isArticleRelated() ) {
456 if ( $wgTitle->getNamespace() == Namespace::getImage() ) {
457 $name = $wgTitle->getDBkey();
458 $link = wfEscapeHTML( Image::wfImageUrl( $name ) );
459 $style = $this->getInternalLinkAttributes( $link, $name );
460 $s .= " | <a href=\"{$link}\"{$style}>{$name}</a>";
462 # This will show the "Approve" link if $wgUseApproval=true;
463 if ( isset ( $wgUseApproval ) && $wgUseApproval )
465 $t = $wgTitle->getDBkey();
466 $name = "Approve this article" ;
467 $link = "http://test.wikipedia.org/w/magnus/wiki.phtml?title={$t}&action=submit&doit=1" ;
468 #wfEscapeHTML( wfImageUrl( $name ) );
469 $style = $this->getExternalLinkAttributes( $link, $name );
470 $s .= " | <a href=\"{$link}\"{$style}>{$name}</a>" ;
473 if ( "history" == $action || isset( $diff ) || isset( $oldid ) ) {
474 $s .= " | " . $this->makeKnownLink( $wgTitle->getPrefixedText(),
475 wfMsg( "currentrev" ) );
478 if ( $wgUser->getNewtalk() ) {
479 # do not show "You have new messages" text when we are viewing our
480 # own talk page
482 if(!(strcmp($wgTitle->getText(),$wgUser->getName()) == 0 &&
483 $wgTitle->getNamespace()==Namespace::getTalk(Namespace::getUser()))) {
484 $n =$wgUser->getName();
485 $tl = $this->makeKnownLink( $wgLang->getNsText(
486 Namespace::getTalk( Namespace::getUser() ) ) . ":{$n}",
487 wfMsg("newmessageslink") );
488 $s.=" | <strong>". wfMsg( "newmessages", $tl ) . "</strong>";
491 if( $wgUser->isSysop() &&
492 (($wgTitle->getArticleId() == 0) || ($action == "history")) &&
493 ($n = $wgTitle->isDeleted() ) ) {
494 $s .= " | " . wfMsg( "thisisdeleted",
495 $this->makeKnownLink(
496 $wgLang->SpecialPage( "Undelete/" . $wgTitle->getPrefixedDBkey() ),
497 wfMsg( "restorelink", $n ) ) );
499 return $s;
502 function printableLink()
504 global $wgOut, $wgFeedClasses, $wgRequest;
506 $baseurl = $_SERVER['REQUEST_URI'];
507 if( strpos( "?", $baseurl ) == false ) {
508 $baseurl .= "?";
509 } else {
510 $baseurl .= "&";
512 $baseurl = htmlspecialchars( $baseurl );
513 $printurl = $wgRequest->escapeAppendQuery( "printable=yes" );
515 $s = "<a href=\"$printurl\">" . wfMsg( "printableversion" ) . "</a>";
516 if( $wgOut->isSyndicated() ) {
517 foreach( $wgFeedClasses as $format => $class ) {
518 $feedurl = $wgRequest->escapeAppendQuery( "feed=$format" );
519 $s .= " | <a href=\"$feedurl\">{$format}</a>";
522 return $s;
525 function pageTitle()
527 global $wgOut, $wgTitle, $wgUser;
529 $s = "<h1 class='pagetitle'>" . htmlspecialchars( $wgOut->getPageTitle() ) . "</h1>";
530 if($wgUser->getOption("editsectiononrightclick") && $wgTitle->userCanEdit()) { $s=$this->editSectionScript(0,$s);}
531 return $s;
534 function pageSubtitle()
536 global $wgOut;
538 $sub = $wgOut->getSubtitle();
539 if ( "" == $sub ) {
540 global $wgExtraSubtitle;
541 $sub = wfMsg( "fromwikipedia" ) . $wgExtraSubtitle;
543 $subpages = $this->subPageSubtitle();
544 $sub .= !empty($subpages)?"</p><p class='subpages'>$subpages":'';
545 $s = "<p class='subtitle'>{$sub}</p>\n";
546 return $s;
549 function subPageSubtitle()
551 global $wgOut,$wgTitle,$wgNamespacesWithSubpages;
552 $subpages = '';
553 if($wgOut->isArticle() && !empty($wgNamespacesWithSubpages[$wgTitle->getNamespace()])) {
554 $ptext=$wgTitle->getPrefixedText();
555 if(preg_match("/\//",$ptext)) {
556 $links=explode("/",$ptext);
557 $c=0;
558 $growinglink="";
559 foreach($links as $link) {
560 $c++;
561 if ($c<count($links)) {
562 $growinglink .= $link;
563 $getlink = $this->makeLink( $growinglink, $link );
564 if(preg_match("/class='new'/i",$getlink)) { break; } # this is a hack, but it saves time
565 if ($c>1) {
566 $subpages .= " | ";
567 } else {
568 $subpages .="&lt; ";
570 $subpages .= $getlink;
571 $growinglink.="/";
576 return $subpages;
579 function nameAndLogin()
581 global $wgUser, $wgTitle, $wgLang, $wgShowIPinHeader, $wgIP;
583 $li = $wgLang->specialPage( "Userlogin" );
584 $lo = $wgLang->specialPage( "Userlogout" );
586 $s = "";
587 if ( 0 == $wgUser->getID() ) {
588 if( $wgShowIPinHeader && isset( $_COOKIE[ini_get("session.name")] ) ) {
589 $n = $wgIP;
591 $tl = $this->makeKnownLink( $wgLang->getNsText(
592 Namespace::getTalk( Namespace::getUser() ) ) . ":{$n}",
593 $wgLang->getNsText( Namespace::getTalk( 0 ) ) );
595 $s .= $n . " (".$tl.")";
596 } else {
597 $s .= wfMsg("notloggedin");
600 $rt = $wgTitle->getPrefixedURL();
601 if ( 0 == strcasecmp( urlencode( $lo ), $rt ) ) {
602 $q = "";
603 } else { $q = "returnto={$rt}"; }
605 $s .= "\n<br />" . $this->makeKnownLink( $li,
606 wfMsg( "login" ), $q );
607 } else {
608 $n = $wgUser->getName();
609 $rt = $wgTitle->getPrefixedURL();
610 $tl = $this->makeKnownLink( $wgLang->getNsText(
611 Namespace::getTalk( Namespace::getUser() ) ) . ":{$n}",
612 $wgLang->getNsText( Namespace::getTalk( 0 ) ) );
614 $tl = " ({$tl})";
616 $s .= $this->makeKnownLink( $wgLang->getNsText(
617 Namespace::getUser() ) . ":{$n}", $n ) . "{$tl}<br />" .
618 $this->makeKnownLink( $lo, wfMsg( "logout" ),
619 "returnto={$rt}" ) . " | " .
620 $this->specialLink( "preferences" );
622 $s .= " | " . $this->makeKnownLink( wfMsg( "helppage" ),
623 wfMsg( "help" ) );
625 return $s;
628 function getSearchLink() {
629 $searchPage =& Title::makeTitle( NS_SPECIAL, "Search" );
630 return $searchPage->getLocalURL();
633 function escapeSearchLink() {
634 return htmlspecialchars( $this->getSearchLink() );
637 function searchForm()
639 global $wgRequest;
640 $search = $wgRequest->getText( 'search' );
642 $s = "<form name='search' class='inline' method='post' action=\""
643 . $this->escapeSearchLink() . "\">\n"
644 . "<input type='text' name=\"search\" size='19' value=\""
645 . htmlspecialchars(substr($search,0,256)) . "\" />\n"
646 . "<input type='submit' name=\"go\" value=\"" . wfMsg ("go") . "\" />&nbsp;"
647 . "<input type='submit' name=\"fulltext\" value=\"" . wfMsg ("search") . "\" />\n</form>";
649 return $s;
652 function topLinks()
654 global $wgOut;
655 $sep = " |\n";
657 $s = $this->mainPageLink() . $sep
658 . $this->specialLink( "recentchanges" );
660 if ( $wgOut->isArticleRelated() ) {
661 $s .= $sep . $this->editThisPage()
662 . $sep . $this->historyLink();
664 # Many people don't like this dropdown box
665 #$s .= $sep . $this->specialPagesList();
667 return $s;
670 function bottomLinks()
672 global $wgOut, $wgUser, $wgTitle;
673 $sep = " |\n";
675 $s = "";
676 if ( $wgOut->isArticleRelated() ) {
677 $s .= "<strong>" . $this->editThisPage() . "</strong>";
678 if ( 0 != $wgUser->getID() ) {
679 $s .= $sep . $this->watchThisPage();
681 $s .= $sep . $this->talkLink()
682 . $sep . $this->historyLink()
683 . $sep . $this->whatLinksHere()
684 . $sep . $this->watchPageLinksLink();
686 if ( $wgTitle->getNamespace() == Namespace::getUser()
687 || $wgTitle->getNamespace() == Namespace::getTalk(Namespace::getUser()) )
690 $id=User::idFromName($wgTitle->getText());
691 $ip=User::isIP($wgTitle->getText());
693 if($id || $ip) { # both anons and non-anons have contri list
694 $s .= $sep . $this->userContribsLink();
696 if ( 0 != $wgUser->getID() ) { # show only to signed in users
697 if($id) { # can only email non-anons
698 $s .= $sep . $this->emailUserLink();
702 if ( $wgUser->isSysop() && $wgTitle->getArticleId() ) {
703 $s .= "\n<br />" . $this->deleteThisPage() .
704 $sep . $this->protectThisPage() .
705 $sep . $this->moveThisPage();
707 $s .= "<br />\n" . $this->otherLanguages();
709 return $s;
712 function pageStats()
714 global $wgOut, $wgLang, $wgArticle, $wgRequest;
715 global $wgDisableCounters, $wgMaxCredits;
717 extract( $wgRequest->getValues( 'oldid', 'diff' ) );
718 if ( ! $wgOut->isArticle() ) { return ""; }
719 if ( isset( $oldid ) || isset( $diff ) ) { return ""; }
720 if ( 0 == $wgArticle->getID() ) { return ""; }
722 $s = "";
723 if ( !$wgDisableCounters ) {
724 $count = $wgLang->formatNum( $wgArticle->getCount() );
725 if ( $count ) {
726 $s = wfMsg( "viewcount", $count );
729 if (!isset($wgMaxCredits) || $wgMaxCredits <= 0) {
730 $s .= $this->lastModified();
731 } else {
732 $s .= " " . $this->getCredits();
735 return $s . " " . $this->getCopyright();
738 function getCredits() {
739 $s = $this->getAuthorCredits();
740 $s .= "<br />\n " . $this->getContributorCredits();
741 return $s;
744 function getAuthorCredits() {
745 global $wgLang, $wgArticle;
747 $last_author = $wgArticle->getUser();
749 if ($last_author == 0) {
750 $author_credit = wfMsg("anonymous");
751 } else {
752 $real_name = User::whoIsReal($last_author);
753 if (!empty($real_name)) {
754 $author_credit = $real_name;
755 } else {
756 $author_credit = wfMsg("siteuser", User::whoIs($last_author));
760 $timestamp = $wgArticle->getTimestamp();
761 if ( $timestamp ) {
762 $d = $wgLang->timeanddate( $wgArticle->getTimestamp(), true );
763 } else {
764 $d = "";
766 return wfMsg("lastmodifiedby", $d, $author_credit);
769 function getContributorCredits() {
771 global $wgArticle, $wgMaxCredits, $wgLang;
773 $contributors = $wgArticle->getContributors($wgMaxCredits);
775 $real_names = array();
776 $user_names = array();
778 # Sift for real versus user names
780 foreach ($contributors as $user_id => $user_parts) {
781 if ($user_id != 0) {
782 if (!empty($user_parts[1])) {
783 $real_names[$user_id] = $user_parts[1];
784 } else {
785 $user_names[$user_id] = $user_parts[0];
790 $real = $wgLang->listToText(array_values($real_names));
791 $user = $wgLang->listToText(array_values($user_names));
793 if (!empty($user)) {
794 $user = wfMsg("siteusers", $user);
797 if ($contributors[0] && $contributors[0][0] > 0) {
798 $anon = wfMsg("anonymous");
799 } else {
800 $anon = '';
803 $creds = $wgLang->listToText(array($real, $user, $anon));
805 return wfMsg("contributions", $creds);
808 function getCopyright() {
809 global $wgRightsPage, $wgRightsUrl, $wgRightsText;
810 $out = "";
811 if( $wgRightsPage ) {
812 $link = $this->makeKnownLink( $wgRightsPage, $wgRightsText );
813 } elseif( $wgRightsUrl ) {
814 $link = $this->makeExternalLink( $wgRightsUrl, $wgRightsText );
815 } else {
816 # Give up now
817 return $out;
819 $out .= wfMsg( "copyright", $link );
820 return $out;
823 function getCopyrightIcon() {
824 global $wgRightsPage, $wgRightsUrl, $wgRightsText, $wgRightsIcon;
825 $out = "";
826 if( $wgRightsIcon ) {
827 $icon = htmlspecialchars( $wgRightsIcon );
828 if( $wgRightsUrl ) {
829 $url = htmlspecialchars( $wgRightsUrl );
830 $out .= "<a href=\"$url\">";
832 $text = htmlspecialchars( $wgRightsText );
833 $out .= "<img src=\"$icon\" alt='$text' />";
834 if( $wgRightsUrl ) {
835 $out .= "</a>";
838 return $out;
841 function getPoweredBy() {
842 global $wgStylePath;
843 $url = htmlspecialchars( "$wgStylePath/images/poweredby_mediawiki_88x31.png" );
844 $img = "<a href='http://www.mediawiki.org/'><img src='$url' alt='MediaWiki' /></a>";
845 return $img;
848 function lastModified()
850 global $wgLang, $wgArticle;
852 $timestamp = $wgArticle->getTimestamp();
853 if ( $timestamp ) {
854 $d = $wgLang->timeanddate( $wgArticle->getTimestamp(), true );
855 $s = " " . wfMsg( "lastmodified", $d );
856 } else {
857 $s = "";
859 return $s;
862 function logoText( $align = "" )
864 if ( "" != $align ) { $a = " align='{$align}'"; }
865 else { $a = ""; }
867 $mp = wfMsg( "mainpage" );
868 $titleObj = Title::newFromText( $mp );
869 $s = "<a href=\"" . $titleObj->escapeLocalURL()
870 . "\"><img{$a} src=\""
871 . $this->getLogo() . "\" alt=\"" . "[{$mp}]\" /></a>";
872 return $s;
875 function quickBar()
877 global $wgOut, $wgTitle, $wgUser, $wgRequest, $wgLang;
878 global $wgDisableUploads, $wgRemoteUploads;
880 $fname = "Skin::quickBar";
881 wfProfileIn( $fname );
883 $action = $wgRequest->getText( 'action' );
884 $wpPreview = $wgRequest->getBool( 'wpPreview' );
885 $tns=$wgTitle->getNamespace();
887 $s = "\n<div id='quickbar'>";
888 $s .= "\n" . $this->logoText() . "\n<hr class='sep' />";
890 $sep = "\n<br />";
891 $s .= $this->mainPageLink()
892 . $sep . $this->specialLink( "recentchanges" )
893 . $sep . $this->specialLink( "randompage" );
894 if ($wgUser->getID()) {
895 $s.= $sep . $this->specialLink( "watchlist" ) ;
896 $s .= $sep .$this->makeKnownLink( $wgLang->specialPage( "Contributions" ),
897 wfMsg( "mycontris" ), "target=" . wfUrlencode($wgUser->getName() ) );
900 // only show watchlist link if logged in
901 if ( wfMsg ( "currentevents" ) != "-" ) $s .= $sep . $this->makeKnownLink( wfMsg( "currentevents" ), "" ) ;
902 $s .= "\n<br /><hr class='sep' />";
903 $articleExists = $wgTitle->getArticleId();
904 if ( $wgOut->isArticle() || $action =="edit" || $action =="history" || $wpPreview) {
905 if($wgOut->isArticle()) {
906 $s .= "<strong>" . $this->editThisPage() . "</strong>";
907 } else { # backlink to the article in edit or history mode
908 if($articleExists){ # no backlink if no article
909 switch($tns) {
910 case 0:
911 $text = wfMsg("articlepage");
912 break;
913 case 1:
914 $text = wfMsg("viewtalkpage");
915 break;
916 case 2:
917 $text = wfMsg("userpage");
918 break;
919 case 3:
920 $text = wfMsg("viewtalkpage");
921 break;
922 case 4:
923 $text = wfMsg("wikipediapage");
924 break;
925 case 5:
926 $text = wfMsg("viewtalkpage");
927 break;
928 case 6:
929 $text = wfMsg("imagepage");
930 break;
931 case 7:
932 $text = wfMsg("viewtalkpage");
933 break;
934 default:
935 $text= wfMsg("articlepage");
938 $link = $wgTitle->getText();
939 if ($nstext = $wgLang->getNsText($tns) ) { # add namespace if necessary
940 $link = $nstext . ":" . $link ;
943 $s .= $this->makeLink( $link, $text );
944 } elseif( $wgTitle->getNamespace() != Namespace::getSpecial() ) {
945 # we just throw in a "New page" text to tell the user that he's in edit mode,
946 # and to avoid messing with the separator that is prepended to the next item
947 $s .= "<strong>" . wfMsg("newpage") . "</strong>";
953 if( $tns%2 && $action!="edit" && !$wpPreview) {
954 $s.="<br />".$this->makeKnownLink($wgTitle->getPrefixedText(),wfMsg("postcomment"),"action=edit&section=new");
958 watching could cause problems in edit mode:
959 if user edits article, then loads "watch this article" in background and then saves
960 article with "Watch this article" checkbox disabled, the article is transparently
961 unwatched. Therefore we do not show the "Watch this page" link in edit mode
963 if ( 0 != $wgUser->getID() && $articleExists) {
964 if($action!="edit" && $action != "submit" )
966 $s .= $sep . $this->watchThisPage();
968 if ( $wgTitle->userCanEdit() )
969 $s .= $sep . $this->moveThisPage();
971 if ( $wgUser->isSysop() and $articleExists ) {
972 $s .= $sep . $this->deleteThisPage() .
973 $sep . $this->protectThisPage();
975 $s .= $sep . $this->talkLink();
976 if ($articleExists && $action !="history") {
977 $s .= $sep . $this->historyLink();
979 $s.=$sep . $this->whatLinksHere();
981 if($wgOut->isArticleRelated()) {
982 $s .= $sep . $this->watchPageLinksLink();
985 if ( Namespace::getUser() == $wgTitle->getNamespace()
986 || $wgTitle->getNamespace() == Namespace::getTalk(Namespace::getUser())
989 $id=User::idFromName($wgTitle->getText());
990 $ip=User::isIP($wgTitle->getText());
992 if($id||$ip) {
993 $s .= $sep . $this->userContribsLink();
995 if ( 0 != $wgUser->getID() ) {
996 if($id) { # can only email real users
997 $s .= $sep . $this->emailUserLink();
1001 $s .= "\n<br /><hr class='sep' />";
1004 if ( 0 != $wgUser->getID() && ( !$wgDisableUploads || $wgRemoteUploads ) ) {
1005 $s .= $this->specialLink( "upload" ) . $sep;
1007 $s .= $this->specialLink( "specialpages" )
1008 . $sep . $this->bugReportsLink();
1010 global $wgSiteSupportPage;
1011 if( $wgSiteSupportPage ) {
1012 $s .= "\n<br /><a href=\"" . htmlspecialchars( $wgSiteSupportPage ) .
1013 "\" class=\"internal\">" . wfMsg( "sitesupport" ) . "</a>";
1016 $s .= "\n<br /></div>\n";
1017 wfProfileOut( $fname );
1018 return $s;
1021 function specialPagesList()
1023 global $wgUser, $wgOut, $wgLang, $wgServer, $wgRedirectScript;
1024 $a = array();
1026 $validSP = $wgLang->getValidSpecialPages();
1028 foreach ( $validSP as $name => $desc ) {
1029 if ( "" == $desc ) { continue; }
1030 $a[$name] = $desc;
1032 if ( $wgUser->isSysop() )
1034 $sysopSP = $wgLang->getSysopSpecialPages();
1036 foreach ( $sysopSP as $name => $desc ) {
1037 if ( "" == $desc ) { continue; }
1038 $a[$name] = $desc ;
1041 if ( $wgUser->isDeveloper() )
1043 $devSP = $wgLang->getDeveloperSpecialPages();
1045 foreach ( $devSP as $name => $desc ) {
1046 if ( "" == $desc ) { continue; }
1047 $a[$name] = $desc ;
1050 $go = wfMsg( "go" );
1051 $sp = wfMsg( "specialpages" );
1052 $spp = $wgLang->specialPage( "Specialpages" );
1054 $s = "<form id=\"specialpages\" method=\"get\" class=\"inline\" " .
1055 "action=\"" . htmlspecialchars( "{$wgServer}{$wgRedirectScript}" ) . "\">\n";
1056 $s .= "<select name=\"wpDropdown\">\n";
1057 $s .= "<option value=\"{$spp}\">{$sp}</option>\n";
1059 foreach ( $a as $name => $desc ) {
1060 $p = $wgLang->specialPage( $name );
1061 $s .= "<option value=\"{$p}\">{$desc}</option>\n";
1063 $s .= "</select>\n";
1064 $s .= "<input type='submit' value=\"{$go}\" name='redirect' />\n";
1065 $s .= "</form>\n";
1066 return $s;
1069 function mainPageLink()
1071 $mp = wfMsg( "mainpage" );
1072 $s = $this->makeKnownLink( $mp, $mp );
1073 return $s;
1076 function copyrightLink()
1078 $s = $this->makeKnownLink( wfMsg( "copyrightpage" ),
1079 wfMsg( "copyrightpagename" ) );
1080 return $s;
1083 function aboutLink()
1085 $s = $this->makeKnownLink( wfMsg( "aboutpage" ),
1086 wfMsg( "aboutwikipedia" ) );
1087 return $s;
1091 function disclaimerLink()
1093 $s = $this->makeKnownLink( wfMsg( "disclaimerpage" ),
1094 wfMsg( "disclaimers" ) );
1095 return $s;
1098 function editThisPage()
1100 global $wgOut, $wgTitle, $wgRequest;
1102 $oldid = $wgRequest->getVal( 'oldid' );
1103 $diff = $wgRequest->getVal( 'diff' );
1104 $redirect = $wgRequest->getVal( 'redirect' );
1106 if ( ! $wgOut->isArticleRelated() ) {
1107 $s = wfMsg( "protectedpage" );
1108 } else {
1109 $n = $wgTitle->getPrefixedText();
1110 if ( $wgTitle->userCanEdit() ) {
1111 $t = wfMsg( "editthispage" );
1112 } else {
1113 #$t = wfMsg( "protectedpage" );
1114 $t = wfMsg( "viewsource" );
1116 $oid = $red = "";
1118 if ( !is_null( $redirect ) ) { $red = "&redirect={$redirect}"; }
1119 if ( $oldid && ! isset( $diff ) ) {
1120 $oid = "&oldid={$oldid}";
1122 $s = $this->makeKnownLink( $n, $t, "action=edit{$oid}{$red}" );
1124 return $s;
1127 function deleteThisPage()
1129 global $wgUser, $wgOut, $wgTitle, $wgRequest;
1131 $diff = $wgRequest->getVal( 'diff' );
1132 if ( $wgTitle->getArticleId() && ( ! $diff ) && $wgUser->isSysop() ) {
1133 $n = $wgTitle->getPrefixedText();
1134 $t = wfMsg( "deletethispage" );
1136 $s = $this->makeKnownLink( $n, $t, "action=delete" );
1137 } else {
1138 $s = "";
1140 return $s;
1143 function protectThisPage()
1145 global $wgUser, $wgOut, $wgTitle, $wgRequest;
1147 $diff = $wgRequest->getVal( 'diff' );
1148 if ( $wgTitle->getArticleId() && ( ! $diff ) && $wgUser->isSysop() ) {
1149 $n = $wgTitle->getPrefixedText();
1151 if ( $wgTitle->isProtected() ) {
1152 $t = wfMsg( "unprotectthispage" );
1153 $q = "action=unprotect";
1154 } else {
1155 $t = wfMsg( "protectthispage" );
1156 $q = "action=protect";
1158 $s = $this->makeKnownLink( $n, $t, $q );
1159 } else {
1160 $s = "";
1162 return $s;
1165 function watchThisPage()
1167 global $wgUser, $wgOut, $wgTitle;
1169 if ( $wgOut->isArticleRelated() ) {
1170 $n = $wgTitle->getPrefixedText();
1172 if ( $wgTitle->userIsWatching() ) {
1173 $t = wfMsg( "unwatchthispage" );
1174 $q = "action=unwatch";
1175 } else {
1176 $t = wfMsg( "watchthispage" );
1177 $q = "action=watch";
1179 $s = $this->makeKnownLink( $n, $t, $q );
1180 } else {
1181 $s = wfMsg( "notanarticle" );
1183 return $s;
1186 function moveThisPage()
1188 global $wgTitle, $wgLang;
1190 if ( $wgTitle->userCanEdit() ) {
1191 $s = $this->makeKnownLink( $wgLang->specialPage( "Movepage" ),
1192 wfMsg( "movethispage" ), "target=" . $wgTitle->getPrefixedURL() );
1193 } // no message if page is protected - would be redundant
1194 return $s;
1197 function historyLink()
1199 global $wgTitle;
1201 $s = $this->makeKnownLink( $wgTitle->getPrefixedText(),
1202 wfMsg( "history" ), "action=history" );
1203 return $s;
1206 function whatLinksHere()
1208 global $wgTitle, $wgLang;
1210 $s = $this->makeKnownLink( $wgLang->specialPage( "Whatlinkshere" ),
1211 wfMsg( "whatlinkshere" ), "target=" . $wgTitle->getPrefixedURL() );
1212 return $s;
1215 function userContribsLink()
1217 global $wgTitle, $wgLang;
1219 $s = $this->makeKnownLink( $wgLang->specialPage( "Contributions" ),
1220 wfMsg( "contributions" ), "target=" . $wgTitle->getPartialURL() );
1221 return $s;
1224 function emailUserLink()
1226 global $wgTitle, $wgLang;
1228 $s = $this->makeKnownLink( $wgLang->specialPage( "Emailuser" ),
1229 wfMsg( "emailuser" ), "target=" . $wgTitle->getPartialURL() );
1230 return $s;
1233 function watchPageLinksLink()
1235 global $wgOut, $wgTitle, $wgLang;
1237 if ( ! $wgOut->isArticleRelated() ) {
1238 $s = "(" . wfMsg( "notanarticle" ) . ")";
1239 } else {
1240 $s = $this->makeKnownLink( $wgLang->specialPage(
1241 "Recentchangeslinked" ), wfMsg( "recentchangeslinked" ),
1242 "target=" . $wgTitle->getPrefixedURL() );
1244 return $s;
1247 function otherLanguages()
1249 global $wgOut, $wgLang, $wgTitle, $wgUseNewInterlanguage;
1251 $a = $wgOut->getLanguageLinks();
1252 if ( 0 == count( $a ) ) {
1253 if ( !$wgUseNewInterlanguage ) return "";
1254 $ns = $wgLang->getNsIndex ( $wgTitle->getNamespace () ) ;
1255 if ( $ns != 0 AND $ns != 1 ) return "" ;
1256 $pn = "Intl" ;
1257 $x = "mode=addlink&xt=".$wgTitle->getDBkey() ;
1258 return $this->makeKnownLink( $wgLang->specialPage( $pn ),
1259 wfMsg( "intl" ) , $x );
1262 if ( !$wgUseNewInterlanguage ) {
1263 $s = wfMsg( "otherlanguages" ) . ": ";
1264 } else {
1265 global $wgLanguageCode ;
1266 $x = "mode=zoom&xt=".$wgTitle->getDBkey() ;
1267 $x .= "&xl=".$wgLanguageCode ;
1268 $s = $this->makeKnownLink( $wgLang->specialPage( "Intl" ),
1269 wfMsg( "otherlanguages" ) , $x ) . ": " ;
1272 $s = wfMsg( "otherlanguages" ) . ": ";
1273 $first = true;
1274 if($wgLang->isRTL()) $s .= "<span dir='LTR'>";
1275 foreach( $a as $l ) {
1276 if ( ! $first ) { $s .= " | "; }
1277 $first = false;
1279 $nt = Title::newFromText( $l );
1280 $url = $nt->getFullURL();
1281 $text = $wgLang->getLanguageName( $nt->getInterwiki() );
1283 if ( "" == $text ) { $text = $l; }
1284 $style = $this->getExternalLinkAttributes( $l, $text );
1285 $s .= "<a href=\"{$url}\"{$style}>{$text}</a>";
1287 if($wgLang->isRTL()) $s .= "</span>";
1288 return $s;
1291 function bugReportsLink()
1293 $s = $this->makeKnownLink( wfMsg( "bugreportspage" ),
1294 wfMsg( "bugreports" ) );
1295 return $s;
1298 function dateLink()
1300 global $wgLinkCache;
1301 $t1 = Title::newFromText( gmdate( "F j" ) );
1302 $t2 = Title::newFromText( gmdate( "Y" ) );
1304 $wgLinkCache->suspend();
1305 $id = $t1->getArticleID();
1306 $wgLinkCache->resume();
1308 if ( 0 == $id ) {
1309 $s = $this->makeBrokenLink( $t1->getText() );
1310 } else {
1311 $s = $this->makeKnownLink( $t1->getText() );
1313 $s .= ", ";
1315 $wgLinkCache->suspend();
1316 $id = $t2->getArticleID();
1317 $wgLinkCache->resume();
1319 if ( 0 == $id ) {
1320 $s .= $this->makeBrokenLink( $t2->getText() );
1321 } else {
1322 $s .= $this->makeKnownLink( $t2->getText() );
1324 return $s;
1327 function talkLink()
1329 global $wgLang, $wgTitle, $wgLinkCache;
1331 $tns = $wgTitle->getNamespace();
1332 if ( -1 == $tns ) { return ""; }
1334 $pn = $wgTitle->getText();
1335 $tp = wfMsg( "talkpage" );
1336 if ( Namespace::isTalk( $tns ) ) {
1337 $lns = Namespace::getSubject( $tns );
1338 switch($tns) {
1339 case 1:
1340 $text = wfMsg("articlepage");
1341 break;
1342 case 3:
1343 $text = wfMsg("userpage");
1344 break;
1345 case 5:
1346 $text = wfMsg("wikipediapage");
1347 break;
1348 case 7:
1349 $text = wfMsg("imagepage");
1350 break;
1351 default:
1352 $text= wfMsg("articlepage");
1354 } else {
1356 $lns = Namespace::getTalk( $tns );
1357 $text=$tp;
1359 $n = $wgLang->getNsText( $lns );
1360 if ( "" == $n ) { $link = $pn; }
1361 else { $link = "{$n}:{$pn}"; }
1363 $wgLinkCache->suspend();
1364 $s = $this->makeLink( $link, $text );
1365 $wgLinkCache->resume();
1367 return $s;
1370 function commentLink()
1372 global $wgLang, $wgTitle, $wgLinkCache;
1374 $tns = $wgTitle->getNamespace();
1375 if ( -1 == $tns ) { return ""; }
1377 $lns = ( Namespace::isTalk( $tns ) ) ? $tns : Namespace::getTalk( $tns );
1379 # assert Namespace::isTalk( $lns )
1381 $n = $wgLang->getNsText( $lns );
1382 $pn = $wgTitle->getText();
1384 $link = "{$n}:{$pn}";
1386 $wgLinkCache->suspend();
1387 $s = $this->makeKnownLink($link, wfMsg("postcomment"), "action=edit&section=new");
1388 $wgLinkCache->resume();
1390 return $s;
1393 # After all the page content is transformed into HTML, it makes
1394 # a final pass through here for things like table backgrounds.
1396 function transformContent( $text )
1398 return $text;
1401 # Note: This function MUST call getArticleID() on the link,
1402 # otherwise the cache won't get updated properly. See LINKCACHE.DOC.
1404 function makeLink( $title, $text = "", $query = "", $trail = "" ) {
1405 wfProfileIn( "Skin::makeLink" );
1406 $nt = Title::newFromText( $title );
1407 if ($nt) {
1408 $result = $this->makeLinkObj( Title::newFromText( $title ), $text, $query, $trail );
1409 } else {
1410 wfDebug( "Invalid title passed to Skin::makeLink(): \"$title\"\n" );
1411 $result = $text == "" ? $title : $text;
1414 wfProfileOut( "Skin::makeLink" );
1415 return $result;
1418 function makeKnownLink( $title, $text = "", $query = "", $trail = "", $prefix = '',$aprops = '') {
1419 $nt = Title::newFromText( $title );
1420 if ($nt) {
1421 return $this->makeKnownLinkObj( Title::newFromText( $title ), $text, $query, $trail, $prefix , $aprops );
1422 } else {
1423 wfDebug( "Invalid title passed to Skin::makeKnownLink(): \"$title\"\n" );
1424 return $text == "" ? $title : $text;
1428 function makeBrokenLink( $title, $text = "", $query = "", $trail = "" ) {
1429 $nt = Title::newFromText( $title );
1430 if ($nt) {
1431 return $this->makeBrokenLinkObj( Title::newFromText( $title ), $text, $query, $trail );
1432 } else {
1433 wfDebug( "Invalid title passed to Skin::makeBrokenLink(): \"$title\"\n" );
1434 return $text == "" ? $title : $text;
1438 function makeStubLink( $title, $text = "", $query = "", $trail = "" ) {
1439 $nt = Title::newFromText( $title );
1440 if ($nt) {
1441 return $this->makeStubLinkObj( Title::newFromText( $title ), $text, $query, $trail );
1442 } else {
1443 wfDebug( "Invalid title passed to Skin::makeStubLink(): \"$title\"\n" );
1444 return $text == "" ? $title : $text;
1448 # Pass a title object, not a title string
1449 function makeLinkObj( &$nt, $text= "", $query = "", $trail = "", $prefix = "" )
1451 global $wgOut, $wgUser;
1452 if ( $nt->isExternal() ) {
1453 $u = $nt->getFullURL();
1454 $link = $nt->getPrefixedURL();
1455 if ( "" == $text ) { $text = $nt->getPrefixedText(); }
1456 $style = $this->getExternalLinkAttributes( $link, $text );
1458 $inside = "";
1459 if ( "" != $trail ) {
1460 if ( preg_match( "/^([a-z]+)(.*)$$/sD", $trail, $m ) ) {
1461 $inside = $m[1];
1462 $trail = $m[2];
1465 $retVal = "<a href=\"{$u}\"{$style}>{$text}{$inside}</a>{$trail}";
1466 } elseif ( 0 == $nt->getNamespace() && "" == $nt->getText() ) {
1467 $retVal = $this->makeKnownLinkObj( $nt, $text, $query, $trail, $prefix );
1468 } elseif ( ( -1 == $nt->getNamespace() ) ||
1469 ( Namespace::getImage() == $nt->getNamespace() ) ) {
1470 $retVal = $this->makeKnownLinkObj( $nt, $text, $query, $trail, $prefix );
1471 } else {
1472 $aid = $nt->getArticleID() ;
1473 if ( 0 == $aid ) {
1474 $retVal = $this->makeBrokenLinkObj( $nt, $text, $query, $trail, $prefix );
1475 } else {
1476 $threshold = $wgUser->getOption("stubthreshold") ;
1477 if ( $threshold > 0 ) {
1478 $res = wfQuery ( "SELECT LENGTH(cur_text) AS x, cur_namespace, cur_is_redirect FROM cur WHERE cur_id='{$aid}'", DB_READ ) ;
1480 if ( wfNumRows( $res ) > 0 ) {
1481 $s = wfFetchObject( $res );
1482 $size = $s->x;
1483 if ( $s->cur_is_redirect OR $s->cur_namespace != 0 ) {
1484 $size = $threshold*2 ; # Really big
1486 wfFreeResult( $res );
1487 } else {
1488 $size = $threshold*2 ; # Really big
1490 } else {
1491 $size = 1 ;
1493 if ( $size < $threshold ) {
1494 $retVal = $this->makeStubLinkObj( $nt, $text, $query, $trail, $prefix );
1495 } else {
1496 $retVal = $this->makeKnownLinkObj( $nt, $text, $query, $trail, $prefix );
1500 return $retVal;
1503 # Pass a title object, not a title string
1504 function makeKnownLinkObj( &$nt, $text = "", $query = "", $trail = "", $prefix = "" , $aprops = '')
1506 global $wgOut, $wgTitle;
1508 $fname = "Skin::makeKnownLinkObj";
1509 wfProfileIn( $fname );
1511 $link = $nt->getPrefixedURL();
1513 if ( "" == $link ) {
1514 $u = "";
1515 if ( "" == $text ) {
1516 $text = htmlspecialchars( $nt->getFragment() );
1518 } else {
1519 $u = $nt->escapeLocalURL( $query );
1521 if ( "" != $nt->getFragment() ) {
1522 $u .= "#" . htmlspecialchars( $nt->getFragment() );
1524 if ( "" == $text ) {
1525 $text = htmlspecialchars( $nt->getPrefixedText() );
1527 $style = $this->getInternalLinkAttributesObj( $nt, $text );
1529 $inside = "";
1530 if ( "" != $trail ) {
1531 if ( preg_match( $this->linktrail, $trail, $m ) ) {
1532 $inside = $m[1];
1533 $trail = $m[2];
1536 $r = "<a href=\"{$u}\"{$style}{$aprops}>{$prefix}{$text}{$inside}</a>{$trail}";
1537 wfProfileOut( $fname );
1538 return $r;
1541 # Pass a title object, not a title string
1542 function makeBrokenLinkObj( &$nt, $text = "", $query = "", $trail = "", $prefix = "" )
1544 global $wgOut, $wgUser;
1546 $fname = "Skin::makeBrokenLinkObj";
1547 wfProfileIn( $fname );
1549 if ( "" == $query ) {
1550 $q = "action=edit";
1551 } else {
1552 $q = "action=edit&{$query}";
1554 $u = $nt->escapeLocalURL( $q );
1556 if ( "" == $text ) {
1557 $text = htmlspecialchars( $nt->getPrefixedText() );
1559 $style = $this->getInternalLinkAttributesObj( $nt, $text, "yes" );
1561 $inside = "";
1562 if ( "" != $trail ) {
1563 if ( preg_match( $this->linktrail, $trail, $m ) ) {
1564 $inside = $m[1];
1565 $trail = $m[2];
1568 if ( $wgUser->getOption( "highlightbroken" ) ) {
1569 $s = "<a href=\"{$u}\"{$style}>{$prefix}{$text}{$inside}</a>{$trail}";
1570 } else {
1571 $s = "{$prefix}{$text}{$inside}<a href=\"{$u}\"{$style}>?</a>{$trail}";
1574 wfProfileOut( $fname );
1575 return $s;
1578 # Pass a title object, not a title string
1579 function makeStubLinkObj( &$nt, $text = "", $query = "", $trail = "", $prefix = "" )
1581 global $wgOut, $wgUser;
1583 $link = $nt->getPrefixedURL();
1585 $u = $nt->escapeLocalURL( $query );
1587 if ( "" == $text ) {
1588 $text = htmlspecialchars( $nt->getPrefixedText() );
1590 $style = $this->getInternalLinkAttributesObj( $nt, $text, "stub" );
1592 $inside = "";
1593 if ( "" != $trail ) {
1594 if ( preg_match( $this->linktrail, $trail, $m ) ) {
1595 $inside = $m[1];
1596 $trail = $m[2];
1599 if ( $wgUser->getOption( "highlightbroken" ) ) {
1600 $s = "<a href=\"{$u}\"{$style}>{$prefix}{$text}{$inside}</a>{$trail}";
1601 } else {
1602 $s = "{$prefix}{$text}{$inside}<a href=\"{$u}\"{$style}>!</a>{$trail}";
1604 return $s;
1607 function makeSelfLinkObj( &$nt, $text = "", $query = "", $trail = "", $prefix = "" )
1609 $u = $nt->escapeLocalURL( $query );
1610 if ( "" == $text ) {
1611 $text = htmlspecialchars( $nt->getPrefixedText() );
1613 $inside = "";
1614 if ( "" != $trail ) {
1615 if ( preg_match( $this->linktrail, $trail, $m ) ) {
1616 $inside = $m[1];
1617 $trail = $m[2];
1620 return "<strong>{$prefix}{$text}{$inside}</strong>{$trail}";
1623 function fnamePart( $url )
1625 $basename = strrchr( $url, "/" );
1626 if ( false === $basename ) { $basename = $url; }
1627 else { $basename = substr( $basename, 1 ); }
1628 return wfEscapeHTML( $basename );
1631 function makeImage( $url, $alt = "" )
1633 global $wgOut;
1635 if ( "" == $alt ) { $alt = $this->fnamePart( $url ); }
1636 $s = "<img src=\"{$url}\" alt=\"{$alt}\" />";
1637 return $s;
1640 function makeImageLink( $name, $url, $alt = "" ) {
1641 $nt = Title::makeTitle( Namespace::getImage(), $name );
1642 return $this->makeImageLinkObj( $nt, $alt );
1645 function makeImageLinkObj( $nt, $alt = "" ) {
1646 global $wgLang, $wgUseImageResize;
1647 $img = Image::newFromTitle( $nt );
1648 $url = $img->getURL();
1650 $align = "";
1651 $prefix = $postfix = "";
1653 if ( $wgUseImageResize ) {
1654 # Check if the alt text is of the form "options|alt text"
1655 # Options are:
1656 # * thumbnail make a thumbnail with enlarge-icon and caption, alignment depends on lang
1657 # * left no resizing, just left align. label is used for alt= only
1658 # * right same, but right aligned
1659 # * none same, but not aligned
1660 # * ___px scale to ___ pixels width, no aligning. e.g. use in taxobox
1661 # * center center the image
1662 # * framed Keep original image size, no magnify-button.
1664 $part = explode( "|", $alt);
1666 $mwThumb =& MagicWord::get( MAG_IMG_THUMBNAIL );
1667 $mwLeft =& MagicWord::get( MAG_IMG_LEFT );
1668 $mwRight =& MagicWord::get( MAG_IMG_RIGHT );
1669 $mwNone =& MagicWord::get( MAG_IMG_NONE );
1670 $mwWidth =& MagicWord::get( MAG_IMG_WIDTH );
1671 $mwCenter =& MagicWord::get( MAG_IMG_CENTER );
1672 $mwFramed =& MagicWord::get( MAG_IMG_FRAMED );
1673 $alt = $part[count($part)-1];
1675 $framed=$thumb=false;
1677 foreach( $part as $key => $val ) {
1678 if ( ! is_null( $mwThumb->matchVariableStartToEnd($val) ) ) {
1679 $thumb=true;
1680 } elseif ( ! is_null( $mwRight->matchVariableStartToEnd($val) ) ) {
1681 # remember to set an alignment, don't render immediately
1682 $align = "right";
1683 } elseif ( ! is_null( $mwLeft->matchVariableStartToEnd($val) ) ) {
1684 # remember to set an alignment, don't render immediately
1685 $align = "left";
1686 } elseif ( ! is_null( $mwCenter->matchVariableStartToEnd($val) ) ) {
1687 # remember to set an alignment, don't render immediately
1688 $align = "center";
1689 } elseif ( ! is_null( $mwNone->matchVariableStartToEnd($val) ) ) {
1690 # remember to set an alignment, don't render immediately
1691 $align = "none";
1692 } elseif ( ! is_null( $match = $mwWidth->matchVariableStartToEnd($val) ) ) {
1693 # $match is the image width in pixels
1694 $width = intval($match);
1695 } elseif ( ! is_null( $mwFramed->matchVariableStartToEnd($val) ) ) {
1696 $framed=true;
1699 if ( "center" == $align )
1701 $prefix = '<span style="text-align: center">';
1702 $postfix = '</span>';
1703 $align = "none";
1706 if ( $thumb || $framed ) {
1708 # Create a thumbnail. Alignment depends on language
1709 # writing direction, # right aligned for left-to-right-
1710 # languages ("Western languages"), left-aligned
1711 # for right-to-left-languages ("Semitic languages")
1713 # If thumbnail width has not been provided, it is set
1714 # here to 180 pixels
1715 if ( $align == "" ) {
1716 $align = $wgLang->isRTL() ? "left" : "right";
1718 if ( ! isset($width) ) {
1719 $width = 180;
1721 return $prefix.$this->makeThumbLinkObj( $img, $alt, $align, $width, $framed ).$postfix;
1723 } elseif ( isset($width) ) {
1725 # Create a resized image, without the additional thumbnail
1726 # features
1727 $url = $img->createThumb( $width );
1729 } # endif $wgUseImageResize
1731 if ( empty( $alt ) ) {
1732 $alt = preg_replace( '/\.(.+?)^/', '', $img->getName() );
1734 $alt = htmlspecialchars( $alt );
1736 $u = $nt->escapeLocalURL();
1737 if ( $url == "" )
1739 $s = str_replace( "$1", $img->getName(), wfMsg("missingimage") );
1740 $s .= "<br>{$alt}<br>{$url}<br>\n";
1741 } else {
1742 $s = "<a href=\"{$u}\" class='image' title=\"{$alt}\">" .
1743 "<img src=\"{$url}\" alt=\"{$alt}\" /></a>";
1745 if ( "" != $align ) {
1746 $s = "<div class=\"float{$align}\"><span>{$s}</span>\n</div>";
1748 return $prefix.$s.$postfix;
1752 function makeThumbLinkObj( $img, $label = "", $align = "right", $boxwidth = 180, $framed=false ) {
1753 global $wgStylePath, $wgLang;
1754 # $image = Title::makeTitle( Namespace::getImage(), $name );
1755 $url = $img->getURL();
1757 #$label = htmlspecialchars( $label );
1758 $alt = preg_replace( "/<[^>]*>/", "", $label);
1759 $alt = htmlspecialchars( $alt );
1761 if ( $img->exists() )
1763 $width = $img->getWidth();
1764 $height = $img->getHeight();
1765 } else {
1766 $width = $height = 200;
1768 if ( $framed )
1770 // Use image dimensions, don't scale
1771 $boxwidth = $width;
1772 $boxheight = $height;
1773 $thumbUrl = $url;
1774 } else {
1775 $boxheight = intval( $height/($width/$boxwidth) );
1776 if ( $boxwidth > $width ) {
1777 $boxwidth = $width;
1778 $boxheight = $height;
1780 $thumbUrl = $img->createThumb( $boxwidth );
1782 $oboxwidth = $boxwidth + 2;
1784 $u = $img->getEscapeLocalURL();
1786 $more = htmlspecialchars( wfMsg( "thumbnail-more" ) );
1787 $magnifyalign = $wgLang->isRTL() ? "left" : "right";
1788 $textalign = $wgLang->isRTL() ? ' style="text-align:right"' : "";
1790 $s = "<div class=\"thumb t{$align}\"><div style=\"width:{$oboxwidth}px;\">";
1791 if ( $thumbUrl == "" ) {
1792 $s .= str_replace( "$1", $img->getName(), wfMsg("missingimage") );
1793 $zoomicon = '';
1794 } else {
1795 $s .= '<a href="'.$u.'" class="internal" title="'.$alt.'">'.
1796 '<img src="'.$thumbUrl.'" alt="'.$alt.'" ' .
1797 'width="'.$boxwidth.'" height="'.$boxheight.'" /></a>';
1798 if ( $framed ) {
1799 $zoomicon="";
1800 } else {
1801 $zoomicon = '<div class="magnify" style="float:'.$magnifyalign.'">'.
1802 '<a href="'.$u.'" class="internal" title="'.$more.'">'.
1803 '<img src="'.$wgStylePath.'/images/magnify-clip.png" ' .
1804 'width="15" height="11" alt="'.$more.'" /></a></div>';
1807 $s .= ' <div class="thumbcaption" '.$textalign.'>'.$zoomicon.$label."</div></div>\n</div>";
1808 return $s;
1811 function makeMediaLink( $name, $url, $alt = "" ) {
1812 $nt = Title::makeTitle( Namespace::getMedia(), $name );
1813 return $this->makeMediaLinkObj( $nt, $alt );
1816 function makeMediaLinkObj( $nt, $alt = "" )
1818 $name = $nt->getDBKey();
1819 $url = Image::wfImageUrl( $name );
1820 if ( empty( $alt ) ) {
1821 $alt = preg_replace( '/\.(.+?)^/', '', $name );
1824 $u = htmlspecialchars( $url );
1825 $s = "<a href=\"{$u}\" class='internal' title=\"{$alt}\">{$alt}</a>";
1826 return $s;
1829 function specialLink( $name, $key = "" )
1831 global $wgLang;
1833 if ( "" == $key ) { $key = strtolower( $name ); }
1834 $pn = $wgLang->ucfirst( $name );
1835 return $this->makeKnownLink( $wgLang->specialPage( $pn ),
1836 wfMsg( $key ) );
1839 function makeExternalLink( $url, $text, $escape = true ) {
1840 $style = $this->getExternalLinkAttributes( $url, $text );
1841 $url = htmlspecialchars( $url );
1842 if( $escape ) {
1843 $text = htmlspecialchars( $text );
1845 return "<a href=\"$url\"$style>$text</a>";
1848 # Called by history lists and recent changes
1851 # Returns text for the start of the tabular part of RC
1852 function beginRecentChangesList()
1854 $this->rc_cache = array() ;
1855 $this->rcMoveIndex = 0;
1856 $this->rcCacheIndex = 0 ;
1857 $this->lastdate = "";
1858 $this->rclistOpen = false;
1859 return "";
1862 function beginImageHistoryList()
1864 $s = "\n<h2>" . wfMsg( "imghistory" ) . "</h2>\n" .
1865 "<p>" . wfMsg( "imghistlegend" ) . "</p>\n<ul class='special'>";
1866 return $s;
1869 # Returns text for the end of RC
1870 # If enhanced RC is in use, returns pretty much all the text
1871 function endRecentChangesList()
1873 $s = $this->recentChangesBlock() ;
1874 if( $this->rclistOpen ) {
1875 $s .= "</ul>\n";
1877 return $s;
1880 # Enhanced RC ungrouped line
1881 function recentChangesBlockLine ( $rcObj )
1883 global $wgStylePath, $wgLang ;
1885 # Get rc_xxxx variables
1886 extract( $rcObj->mAttribs ) ;
1887 $curIdEq = "curid=$rc_cur_id";
1889 # Spacer image
1890 $r = "" ;
1892 $r .= "<img src='{$wgStylePath}/images/Arr_.png' width='12' height='12' border='0' />" ; $r .= "<tt>" ;
1894 if ( $rc_type == RC_MOVE ) {
1895 $r .= "&nbsp;&nbsp;";
1896 } else {
1897 # M & N (minor & new)
1898 $M = wfMsg( "minoreditletter" );
1899 $N = wfMsg( "newpageletter" );
1901 if ( $rc_type == RC_NEW ) {
1902 $r .= $N ;
1903 } else {
1904 $r .= "&nbsp;" ;
1906 if ( $rc_minor ) {
1907 $r .= $M ;
1908 } else {
1909 $r .= "&nbsp;" ;
1913 # Timestamp
1914 $r .= " ".$rcObj->timestamp." " ;
1915 $r .= "</tt>" ;
1917 # Article link
1918 $link = $rcObj->link ;
1919 if ( $rcObj->watched ) $link = "<strong>{$link}</strong>" ;
1920 $r .= $link ;
1922 # Cur
1923 $r .= " (" ;
1924 $r .= $rcObj->curlink ;
1925 $r .= "; " ;
1927 # Hist
1928 $r .= $this->makeKnownLinkObj( $rcObj->getTitle(), wfMsg( "hist" ), "{$curIdEq}&action=history" );
1930 # User/talk
1931 $r .= ") . . ".$rcObj->userlink ;
1932 $r .= $rcObj->usertalklink ;
1934 # Comment
1935 if ( $rc_comment != "" && $rc_type != RC_MOVE ) {
1936 $rc_comment=$this->formatComment($rc_comment);
1937 $r .= $wgLang->emphasize( " (".$rc_comment.")" );
1940 $r .= "<br />\n" ;
1941 return $r ;
1944 # Enhanced RC group
1945 function recentChangesBlockGroup ( $block )
1947 global $wgStylePath, $wgLang ;
1949 $r = "" ;
1950 $M = wfMsg( "minoreditletter" );
1951 $N = wfMsg( "newpageletter" );
1953 # Collate list of users
1954 $isnew = false ;
1955 $userlinks = array () ;
1956 foreach ( $block AS $rcObj ) {
1957 $oldid = $rcObj->mAttribs['rc_last_oldid'];
1958 if ( $rcObj->mAttribs['rc_new'] ) $isnew = true ;
1959 $u = $rcObj->userlink ;
1960 if ( !isset ( $userlinks[$u] ) ) $userlinks[$u] = 0 ;
1961 $userlinks[$u]++ ;
1964 # Sort the list and convert to text
1965 krsort ( $userlinks ) ;
1966 asort ( $userlinks ) ;
1967 $users = array () ;
1968 foreach ( $userlinks as $userlink => $count) {
1969 $text = $userlink ;
1970 if ( $count > 1 ) $text .= " ({$count}&times;)" ;
1971 array_push ( $users , $text ) ;
1973 $users = " <font size='-1'>[".implode("; ",$users)."]</font>" ;
1975 # Arrow
1976 $rci = "RCI{$this->rcCacheIndex}" ;
1977 $rcl = "RCL{$this->rcCacheIndex}" ;
1978 $rcm = "RCM{$this->rcCacheIndex}" ;
1979 $toggleLink = "javascript:toggleVisibility(\"{$rci}\",\"{$rcm}\",\"{$rcl}\")" ;
1980 $arrowdir = $wgLang->isRTL() ? "l" : "r";
1981 $tl = "<span id='{$rcm}'><a href='$toggleLink'><img src='{$wgStylePath}/images/Arr_{$arrowdir}.png' width='12' height='12' /></a></span>" ;
1982 $tl .= "<span id='{$rcl}' style='display:none'><a href='$toggleLink'><img src='{$wgStylePath}/images/Arr_d.png' width='12' height='12' /></a></span>" ;
1983 $r .= $tl ;
1985 # Main line
1986 # M/N
1987 $r .= "<tt>" ;
1988 if ( $isnew ) $r .= $N ;
1989 else $r .= "&nbsp;" ;
1990 $r .= "&nbsp;" ; # Minor
1992 # Timestamp
1993 $r .= " ".$block[0]->timestamp." " ;
1994 $r .= "</tt>" ;
1996 # Article link
1997 $link = $block[0]->link ;
1998 if ( $block[0]->watched ) $link = "<strong>{$link}</strong>" ;
1999 $r .= $link ;
2001 $curIdEq = "curid=" . $block[0]->mAttribs['rc_cur_id'];
2002 if ( $block[0]->mAttribs['rc_type'] != RC_LOG ) {
2003 # Changes
2004 $r .= " (".count($block)." " ;
2005 if ( $isnew ) $r .= wfMsg("changes");
2006 else $r .= $this->makeKnownLinkObj( $block[0]->getTitle() , wfMsg("changes") ,
2007 "{$curIdEq}&diff=0&oldid=".$oldid ) ;
2008 $r .= "; " ;
2010 # History
2011 $r .= $this->makeKnownLinkObj( $block[0]->getTitle(), wfMsg( "history" ), "{$curIdEq}&action=history" );
2012 $r .= ")" ;
2015 $r .= $users ;
2016 $r .= "<br />\n" ;
2018 # Sub-entries
2019 $r .= "<div id='{$rci}' style='display:none'>" ;
2020 foreach ( $block AS $rcObj ) {
2021 # Get rc_xxxx variables
2022 extract( $rcObj->mAttribs );
2024 $r .= "<img src='{$wgStylePath}/images/Arr_.png' width=12 height=12 />";
2025 $r .= "<tt>&nbsp; &nbsp; &nbsp; &nbsp;" ;
2026 if ( $rc_new ) $r .= $N ;
2027 else $r .= "&nbsp;" ;
2028 if ( $rc_minor ) $r .= $M ;
2029 else $r .= "&nbsp;" ;
2030 $r .= "</tt>" ;
2032 $o = "" ;
2033 if ( $rc_last_oldid != 0 ) {
2034 $o = "oldid=".$rc_last_oldid ;
2036 if ( $rc_type == RC_LOG ) {
2037 $link = $rcObj->timestamp ;
2038 } else {
2039 $link = $this->makeKnownLinkObj( $rcObj->getTitle(), $rcObj->timestamp , "{$curIdEq}&$o" ) ;
2041 $link = "<tt>{$link}</tt>" ;
2043 $r .= $link ;
2044 $r .= " (" ;
2045 $r .= $rcObj->curlink ;
2046 $r .= "; " ;
2047 $r .= $rcObj->lastlink ;
2048 $r .= ") . . ".$rcObj->userlink ;
2049 $r .= $rcObj->usertalklink ;
2050 if ( $rc_comment != "" ) {
2051 $rc_comment=$this->formatComment($rc_comment);
2052 $r .= $wgLang->emphasize( " (".$rc_comment.")" ) ;
2054 $r .= "<br />\n" ;
2056 $r .= "</div>\n" ;
2058 $this->rcCacheIndex++ ;
2059 return $r ;
2062 # If enhanced RC is in use, this function takes the previously cached
2063 # RC lines, arranges them, and outputs the HTML
2064 function recentChangesBlock ()
2066 global $wgStylePath ;
2067 if ( count ( $this->rc_cache ) == 0 ) return "" ;
2068 $blockOut = "";
2069 foreach ( $this->rc_cache AS $secureName => $block ) {
2070 if ( count ( $block ) < 2 ) {
2071 $blockOut .= $this->recentChangesBlockLine ( array_shift ( $block ) ) ;
2072 } else {
2073 $blockOut .= $this->recentChangesBlockGroup ( $block ) ;
2077 return "<div>{$blockOut}</div>" ;
2080 # Called in a loop over all displayed RC entries
2081 # Either returns the line, or caches it for later use
2082 function recentChangesLine( &$rc, $watched = false )
2084 global $wgUser ;
2085 $usenew = $wgUser->getOption( "usenewrc" );
2086 if ( $usenew )
2087 $line = $this->recentChangesLineNew ( $rc, $watched ) ;
2088 else
2089 $line = $this->recentChangesLineOld ( $rc, $watched ) ;
2090 return $line ;
2093 function recentChangesLineOld( &$rc, $watched = false )
2095 global $wgTitle, $wgLang, $wgUser, $wgRCSeconds;
2097 # Extract DB fields into local scope
2098 extract( $rc->mAttribs );
2099 $curIdEq = "curid=" . $rc_cur_id;
2101 # Make date header if necessary
2102 $date = $wgLang->date( $rc_timestamp, true);
2103 $s = "";
2104 if ( $date != $this->lastdate ) {
2105 if ( "" != $this->lastdate ) { $s .= "</ul>\n"; }
2106 $s .= "<h4>{$date}</h4>\n<ul class='special'>";
2107 $this->lastdate = $date;
2108 $this->rclistOpen = true;
2110 $s .= "<li> ";
2112 if ( $rc_type == RC_MOVE ) {
2113 # Diff
2114 $s .= "(" . wfMsg( "diff" ) . ") (";
2115 # Hist
2116 $s .= $this->makeKnownLinkObj( $rc->getMovedToTitle(), wfMsg( "hist" ), "action=history" ) .
2117 ") . . ";
2119 # "[[x]] moved to [[y]]"
2121 $s .= wfMsg( "1movedto2", $this->makeKnownLinkObj( $rc->getTitle(), "", "redirect=no" ),
2122 $this->makeKnownLinkObj( $rc->getMovedToTitle(), "" ) );
2124 } else {
2125 # Diff link
2126 if ( $rc_type == RC_NEW || $rc_type == RC_LOG ) {
2127 $diffLink = wfMsg( "diff" );
2128 } else {
2129 $diffLink = $this->makeKnownLinkObj( $rc->getTitle(), wfMsg( "diff" ),
2130 "{$curIdEq}&diff={$rc_this_oldid}&oldid={$rc_last_oldid}" ,'' ,'' , ' tabindex="'.$rc->counter.'"');
2132 $s .= "($diffLink) (";
2134 # History link
2135 $s .= $this->makeKnownLinkObj( $rc->getTitle(), wfMsg( "hist" ), "{$curIdEq}&action=history" );
2136 $s .= ") . . ";
2138 # M and N (minor and new)
2139 $M = wfMsg( "minoreditletter" );
2140 $N = wfMsg( "newpageletter" );
2141 if ( $rc_minor ) { $s .= " <strong>{$M}</strong>"; }
2142 if ( $rc_type == RC_NEW ) { $s .= "<strong>{$N}</strong>"; }
2144 # Article link
2145 $articleLink = $this->makeKnownLinkObj( $rc->getTitle(), "" );
2147 if ( $watched ) {
2148 $articleLink = "<strong>{$articleLink}</strong>";
2150 $s .= " $articleLink";
2154 # Timestamp
2155 $s .= "; " . $wgLang->time( $rc_timestamp, true, $wgRCSeconds ) . " . . ";
2157 # User link (or contributions for unregistered users)
2158 if ( 0 == $rc_user ) {
2159 $userLink = $this->makeKnownLink( $wgLang->specialPage( "Contributions" ),
2160 $rc_user_text, "target=" . $rc_user_text );
2161 } else {
2162 $userLink = $this->makeLink( $wgLang->getNsText( NS_USER ) . ":{$rc_user_text}", $rc_user_text );
2164 $s .= $userLink;
2166 # User talk link
2167 $talkname=$wgLang->getNsText(NS_TALK); # use the shorter name
2168 global $wgDisableAnonTalk;
2169 if( 0 == $rc_user && $wgDisableAnonTalk ) {
2170 $userTalkLink = "";
2171 } else {
2172 $utns=$wgLang->getNsText(NS_USER_TALK);
2173 $userTalkLink= $this->makeLink($utns . ":{$rc_user_text}", $talkname );
2175 # Block link
2176 $blockLink="";
2177 if ( ( 0 == $rc_user ) && $wgUser->isSysop() ) {
2178 $blockLink = $this->makeKnownLink( $wgLang->specialPage(
2179 "Blockip" ), wfMsg( "blocklink" ), "ip={$rc_user_text}" );
2182 if($blockLink) {
2183 if($userTalkLink) $userTalkLink .= " | ";
2184 $userTalkLink .= $blockLink;
2186 if($userTalkLink) $s.=" ({$userTalkLink})";
2188 # Add comment
2189 if ( "" != $rc_comment && "*" != $rc_comment && $rc_type != RC_MOVE ) {
2190 $rc_comment=$this->formatComment($rc_comment);
2191 $s .= $wgLang->emphasize(" (" . $rc_comment . ")");
2193 $s .= "</li>\n";
2195 return $s;
2198 # function recentChangesLineNew( $ts, $u, $ut, $ns, $ttl, $c, $isminor, $isnew, $watched = false, $oldid = 0 , $diffid = 0 )
2199 function recentChangesLineNew( &$baseRC, $watched = false )
2201 global $wgTitle, $wgLang, $wgUser, $wgRCSeconds;
2203 # Create a specialised object
2204 $rc = RCCacheEntry::newFromParent( $baseRC ) ;
2206 # Extract fields from DB into the function scope (rc_xxxx variables)
2207 extract( $rc->mAttribs );
2208 $curIdEq = "curid=" . $rc_cur_id;
2210 # If it's a new day, add the headline and flush the cache
2211 $date = $wgLang->date( $rc_timestamp, true);
2212 $ret = "" ;
2213 if ( $date != $this->lastdate ) {
2214 # Process current cache
2215 $ret = $this->recentChangesBlock () ;
2216 $this->rc_cache = array() ;
2217 $ret .= "<h4>{$date}</h4>\n";
2218 $this->lastdate = $date;
2221 # Make article link
2222 if ( $rc_type == RC_MOVE ) {
2223 $clink = $this->makeKnownLinkObj( $rc->getTitle(), "", "redirect=no" );
2224 $clink .= " " . wfMsg("movedto") . " ";
2225 $clink .= $this->makeKnownLinkObj( $rc->getMovedToTitle(), "" );
2226 } else {
2227 $clink = $this->makeKnownLinkObj( $rc->getTitle(), "" ) ;
2230 $time = $wgLang->time( $rc_timestamp, true, $wgRCSeconds );
2231 $rc->watched = $watched ;
2232 $rc->link = $clink ;
2233 $rc->timestamp = $time;
2235 # Make "cur" link
2236 if ( ( $rc_type == RC_NEW && $rc_this_oldid == 0 ) || $rc_type == RC_LOG || $rc_type == RC_MOVE) {
2237 $curLink = wfMsg( "cur" );
2238 } else {
2239 $curLink = $this->makeKnownLinkObj( $rc->getTitle(), wfMsg( "cur" ),
2240 "{$curIdEq}&diff=0&oldid={$rc_this_oldid}" ,'' ,'' , ' tabindex="'.$baseRC->counter.'"' );
2243 # Make "last" link
2244 $titleObj = $rc->getTitle();
2245 if ( $rc_last_oldid == 0 || $rc_type == RC_LOG || $rc_type == RC_MOVE ) {
2246 $lastLink = wfMsg( "last" );
2247 } else {
2248 $lastLink = $this->makeKnownLinkObj( $rc->getTitle(), wfMsg( "last" ),
2249 "{$curIdEq}&diff={$rc_this_oldid}&oldid={$rc_last_oldid}" );
2252 # Make user link (or user contributions for unregistered users)
2253 if ( 0 == $rc_user ) {
2254 $userLink = $this->makeKnownLink( $wgLang->specialPage( "Contributions" ),
2255 $rc_user_text, "target=" . $rc_user_text );
2256 } else {
2257 $userLink = $this->makeLink( $wgLang->getNsText(
2258 Namespace::getUser() ) . ":{$rc_user_text}", $rc_user_text );
2261 $rc->userlink = $userLink ;
2262 $rc->lastlink = $lastLink ;
2263 $rc->curlink = $curLink ;
2265 # Make user talk link
2266 $utns=$wgLang->getNsText(NS_USER_TALK);
2267 $talkname=$wgLang->getNsText(NS_TALK); # use the shorter name
2268 $userTalkLink= $this->makeLink($utns . ":{$rc_user_text}", $talkname );
2270 global $wgDisableAnonTalk;
2271 if ( ( 0 == $rc_user ) && $wgUser->isSysop() ) {
2272 $blockLink = $this->makeKnownLink( $wgLang->specialPage(
2273 "Blockip" ), wfMsg( "blocklink" ), "ip={$rc_user_text}" );
2274 if( $wgDisableAnonTalk )
2275 $rc->usertalklink = " ({$blockLink})";
2276 else
2277 $rc->usertalklink = " ({$userTalkLink} | {$blockLink})";
2278 } else {
2279 if( $wgDisableAnonTalk && ($rc_user == 0) )
2280 $rc->usertalklink = "";
2281 else
2282 $rc->usertalklink = " ({$userTalkLink})";
2285 # Put accumulated information into the cache, for later display
2286 # Page moves go on their own line
2287 $title = $rc->getTitle();
2288 $secureName = $title->getPrefixedDBkey();
2289 if ( $rc_type == RC_MOVE ) {
2290 # Use an @ character to prevent collision with page names
2291 $this->rc_cache["@@" . ($this->rcMoveIndex++)] = array($rc);
2292 } else {
2293 if ( !isset ( $this->rc_cache[$secureName] ) ) $this->rc_cache[$secureName] = array() ;
2294 array_push ( $this->rc_cache[$secureName] , $rc ) ;
2296 return $ret;
2299 function endImageHistoryList()
2301 $s = "</ul>\n";
2302 return $s;
2305 /* This function is called by all recent changes variants, by the page history,
2306 and by the user contributions list. It is responsible for formatting edit
2307 comments. It escapes any HTML in the comment, but adds some CSS to format
2308 auto-generated comments (from section editing) and formats [[wikilinks]].
2309 Main author: Erik Möller (moeller@scireview.de)
2311 function formatComment($comment)
2313 global $wgLang;
2314 $comment=wfEscapeHTML($comment);
2316 # The pattern for autogen comments is / * foo * /, which makes for
2317 # some nasty regex.
2318 # We look for all comments, match any text before and after the comment,
2319 # add a separator where needed and format the comment itself with CSS
2320 while (preg_match("/(.*)\/\*\s*(.*?)\s*\*\/(.*)/", $comment,$match)) {
2321 $pre=$match[1];
2322 $auto=$match[2];
2323 $post=$match[3];
2324 $sep="-";
2325 if($pre) { $auto="$sep ".$auto; }
2326 if($post) { $auto.=" $sep"; }
2327 $auto="<span class=\"autocomment\">".$auto."</span>";
2328 $comment=$pre.$auto.$post;
2331 # format regular and media links - all other wiki formatting
2332 # is ignored
2333 while(preg_match("/\[\[(.*?)(\|(.*?))*\]\]/",$comment,$match)) {
2335 $medians = $wgLang->getNsText(Namespace::getMedia());
2336 $func="makeLink";
2337 if(preg_match("/^".$medians."/i",$match[1])) {
2338 $func="makeMediaLink";
2340 if(isset($match[3]) ) {
2341 $comment=
2342 preg_replace("/\[\[(.*?)\]\]/",
2343 $this->$func($match[1],$match[3]),$comment,1);
2344 } else {
2345 $comment=
2346 preg_replace("/\[\[(.*?)\]\]/",
2347 $this->$func($match[1],$match[1]),$comment,1);
2351 return $comment;
2355 function imageHistoryLine( $iscur, $ts, $img, $u, $ut, $size, $c )
2357 global $wgUser, $wgLang, $wgTitle;
2359 $dt = $wgLang->timeanddate( $ts, true );
2360 $del = wfMsg( "deleteimg" );
2361 $cur = wfMsg( "cur" );
2363 if ( $iscur ) {
2364 $url = Image::wfImageUrl( $img );
2365 $rlink = $cur;
2366 if ( $wgUser->isSysop() ) {
2367 $link = $wgTitle->escapeLocalURL( "image=" . $wgTitle->getPartialURL() .
2368 "&action=delete" );
2369 $style = $this->getInternalLinkAttributes( $link, $del );
2371 $dlink = "<a href=\"{$link}\"{$style}>{$del}</a>";
2372 } else {
2373 $dlink = $del;
2375 } else {
2376 $url = wfEscapeHTML( wfImageArchiveUrl( $img ) );
2377 if( $wgUser->getID() != 0 ) {
2378 $rlink = $this->makeKnownLink( $wgTitle->getPrefixedText(),
2379 wfMsg( "revertimg" ), "action=revert&oldimage=" .
2380 urlencode( $img ) );
2381 $dlink = $this->makeKnownLink( $wgTitle->getPrefixedText(),
2382 $del, "action=delete&oldimage=" . urlencode( $img ) );
2383 } else {
2384 # Having live active links for non-logged in users
2385 # means that bots and spiders crawling our site can
2386 # inadvertently change content. Baaaad idea.
2387 $rlink = wfMsg( "revertimg" );
2388 $dlink = $del;
2391 if ( 0 == $u ) { $ul = $ut; }
2392 else { $ul = $this->makeLink( $wgLang->getNsText(
2393 Namespace::getUser() ) . ":{$ut}", $ut ); }
2395 $nb = wfMsg( "nbytes", $size );
2396 $style = $this->getInternalLinkAttributes( $url, $dt );
2398 $s = "<li> ({$dlink}) ({$rlink}) <a href=\"{$url}\"{$style}>{$dt}</a>"
2399 . " . . {$ul} ({$nb})";
2401 if ( "" != $c && "*" != $c ) {
2402 $sk=$wgUser->getSkin();
2403 $s .= $wgLang->emphasize(" (" . $sk->formatComment($c) . ")");
2405 $s .= "</li>\n";
2406 return $s;
2409 function tocIndent($level) {
2410 return str_repeat( "<div class='tocindent'>\n", $level>0 ? $level : 0 );
2413 function tocUnindent($level) {
2414 return str_repeat( "</div>\n", $level>0 ? $level : 0 );
2417 # parameter level defines if we are on an indentation level
2418 function tocLine( $anchor, $tocline, $level ) {
2419 $link = "<a href=\"#$anchor\">$tocline</a><br />";
2420 if($level) {
2421 return "$link\n";
2422 } else {
2423 return "<div class='tocline'>$link</div>\n";
2428 function tocTable($toc) {
2429 # note to CSS fanatics: putting this in a div does not work -- div won't auto-expand
2430 # try min-width & co when somebody gets a chance
2431 $hideline = " <script type='text/javascript'>showTocToggle(\"" . addslashes( wfMsg("showtoc") ) . "\",\"" . addslashes( wfMsg("hidetoc") ) . "\")</script>";
2432 return
2433 "<table border=\"0\" id=\"toc\"><tr><td align=\"center\">\n".
2434 "<b>".wfMsg("toc")."</b>" .
2435 $hideline .
2436 "</td></tr><tr id='tocinside'><td>\n".
2437 $toc."</td></tr></table>\n";
2440 # These two do not check for permissions: check $wgTitle->userCanEdit before calling them
2441 function editSectionScript( $section, $head ) {
2442 global $wgTitle, $wgRequest;
2443 if( $wgRequest->getInt( "oldid" ) && ( $wgRequest->getVal( "diff" ) != "0" ) ) {
2444 return $head;
2446 $url = $wgTitle->escapeLocalURL( "action=edit&section=$section" );
2447 return "<span oncontextmenu='document.location=\"$url\";return false;'>{$head}</span>";
2450 function editSectionLink( $section ) {
2451 global $wgRequest;
2452 global $wgTitle, $wgUser, $wgLang;
2454 if( $wgRequest->getInt( "oldid" ) && ( $wgRequest->getVal( "diff" ) != "0" ) ) {
2455 # Section edit links would be out of sync on an old page.
2456 # But, if we're diffing to the current page, they'll be
2457 # correct.
2458 return "";
2461 $editurl = "&section={$section}";
2462 $url = $this->makeKnownLink($wgTitle->getPrefixedText(),wfMsg("editsection"),"action=edit".$editurl);
2464 if( $wgLang->isRTL() ) {
2465 $farside = "left";
2466 $nearside = "right";
2467 } else {
2468 $farside = "right";
2469 $nearside = "left";
2471 return "<div class=\"editsection\" style=\"float:$farside;margin-$nearside:5px;\">[".$url."]</div>";
2475 // This function is called by EditPage.php and shows a bulletin board style
2476 // toolbar for common editing functions. It can be disabled in the user preferences.
2477 // The necsesary JavaScript code can be found in style/wikibits.js.
2478 function getEditToolbar() {
2479 global $wgStylePath, $wgLang, $wgMimeType;
2481 // toolarray an array of arrays which each include the filename of
2482 // the button image (without path), the opening tag, the closing tag,
2483 // and optionally a sample text that is inserted between the two when no
2484 // selection is highlighted.
2485 // The tip text is shown when the user moves the mouse over the button.
2487 // Already here are accesskeys (key), which are not used yet until someone
2488 // can figure out a way to make them work in IE. However, we should make
2489 // sure these keys are not defined on the edit page.
2490 $toolarray=array(
2491 array( "image"=>"button_bold.png",
2492 "open"=>"\'\'\'",
2493 "close"=>"\'\'\'",
2494 "sample"=>wfMsg("bold_sample"),
2495 "tip"=>wfMsg("bold_tip"),
2496 "key"=>"B"
2498 array( "image"=>"button_italic.png",
2499 "open"=>"\'\'",
2500 "close"=>"\'\'",
2501 "sample"=>wfMsg("italic_sample"),
2502 "tip"=>wfMsg("italic_tip"),
2503 "key"=>"I"
2505 array( "image"=>"button_link.png",
2506 "open"=>"[[",
2507 "close"=>"]]",
2508 "sample"=>wfMsg("link_sample"),
2509 "tip"=>wfMsg("link_tip"),
2510 "key"=>"L"
2512 array( "image"=>"button_extlink.png",
2513 "open"=>"[",
2514 "close"=>"]",
2515 "sample"=>wfMsg("extlink_sample"),
2516 "tip"=>wfMsg("extlink_tip"),
2517 "key"=>"X"
2519 array( "image"=>"button_headline.png",
2520 "open"=>"\\n== ",
2521 "close"=>" ==\\n",
2522 "sample"=>wfMsg("headline_sample"),
2523 "tip"=>wfMsg("headline_tip"),
2524 "key"=>"H"
2526 array( "image"=>"button_image.png",
2527 "open"=>"[[".$wgLang->getNsText(NS_IMAGE).":",
2528 "close"=>"]]",
2529 "sample"=>wfMsg("image_sample"),
2530 "tip"=>wfMsg("image_tip"),
2531 "key"=>"D"
2533 array( "image"=>"button_media.png",
2534 "open"=>"[[".$wgLang->getNsText(NS_MEDIA).":",
2535 "close"=>"]]",
2536 "sample"=>wfMsg("media_sample"),
2537 "tip"=>wfMsg("media_tip"),
2538 "key"=>"M"
2540 array( "image"=>"button_math.png",
2541 "open"=>"\\<math\\>",
2542 "close"=>"\\</math\\>",
2543 "sample"=>wfMsg("math_sample"),
2544 "tip"=>wfMsg("math_tip"),
2545 "key"=>"C"
2547 array( "image"=>"button_nowiki.png",
2548 "open"=>"\\<nowiki\\>",
2549 "close"=>"\\</nowiki\\>",
2550 "sample"=>wfMsg("nowiki_sample"),
2551 "tip"=>wfMsg("nowiki_tip"),
2552 "key"=>"N"
2554 array( "image"=>"button_sig.png",
2555 "open"=>"--~~~~",
2556 "close"=>"",
2557 "sample"=>"",
2558 "tip"=>wfMsg("sig_tip"),
2559 "key"=>"Y"
2561 array( "image"=>"button_hr.png",
2562 "open"=>"\\n----\\n",
2563 "close"=>"",
2564 "sample"=>"",
2565 "tip"=>wfMsg("hr_tip"),
2566 "key"=>"R"
2569 $toolbar ="<script type='text/javascript'>\n/*<![CDATA[*/\n";
2571 $toolbar.="document.writeln(\"<div id='toolbar'>\");\n";
2572 foreach($toolarray as $tool) {
2574 $image=$wgStylePath."/images/".$tool["image"];
2575 $open=$tool["open"];
2576 $close=$tool["close"];
2577 $sample = addslashes( $tool["sample"] );
2579 // Note that we use the tip both for the ALT tag and the TITLE tag of the image.
2580 // Older browsers show a "speedtip" type message only for ALT.
2581 // Ideally these should be different, realistically they
2582 // probably don't need to be.
2583 $tip = addslashes( $tool["tip"] );
2585 #$key = $tool["key"];
2587 $toolbar.="addButton('$image','$tip','$open','$close','$sample');\n";
2590 $toolbar.="addInfobox('" . addslashes( wfMsg( "infobox" ) ) . "','" . addslashes(wfMsg("infobox_alert")) . "');\n";
2591 $toolbar.="document.writeln(\"</div>\");\n";
2593 $toolbar.="/*]]>*/\n</script>";
2594 return $toolbar;
2598 include_once( "SkinStandard.php" );
2599 include_once( "SkinNostalgia.php" );
2600 include_once( "SkinCologneBlue.php" );
2602 if( $wgUsePHPTal ) {
2603 include_once( "SkinPHPTal.php" );