Starting code cleanup. Beginning to separate database logic from display output,...
[mediawiki.git] / includes / Skin.php
blobbfda48b175f8bc3c79b1263b48623d58666cb6ee
1 <?php
3 # This is not a valid entry point, perform no further processing unless MEDIAWIKI is defined
4 if( defined( "MEDIAWIKI" ) ) {
6 # See skin.doc
8 require_once( 'Feed.php' ); // should not be called if the actual page isn't feed enabled
9 require_once( 'Image.php' );
11 # These are the INTERNAL names, which get mapped
12 # directly to class names. For display purposes, the
13 # Language class has internationalized names
15 /* private */ $wgValidSkinNames = array(
16 'standard' => 'Standard',
17 'nostalgia' => 'Nostalgia',
18 'cologneblue' => 'CologneBlue'
20 if( $wgUsePHPTal ) {
21 #$wgValidSkinNames[] = 'PHPTal';
22 #$wgValidSkinNames['davinci'] = 'DaVinci';
23 #$wgValidSkinNames['mono'] = 'Mono';
24 $wgValidSkinNames['monobook'] = 'MonoBook';
25 $wgValidSkinNames['myskin'] = 'MySkin';
26 #$wgValidSkinNames['monobookminimal'] = 'MonoBookMinimal';
27 $wgValidSkinNames['chick'] = 'Chick';
30 require_once( 'RecentChange.php' );
32 class RCCacheEntry extends RecentChange
34 var $secureName, $link;
35 var $curlink , $difflink, $lastlink , $usertalklink , $versionlink ;
36 var $userlink, $timestamp, $watched;
38 function newFromParent( $rc )
40 $rc2 = new RCCacheEntry;
41 $rc2->mAttribs = $rc->mAttribs;
42 $rc2->mExtra = $rc->mExtra;
43 return $rc2;
45 } ;
47 class Skin {
49 /* private */ var $lastdate, $lastline;
50 var $linktrail ; # linktrail regexp
51 var $rc_cache ; # Cache for Enhanced Recent Changes
52 var $rcCacheIndex ; # Recent Changes Cache Counter for visibility toggle
53 var $rcMoveIndex;
54 var $postParseLinkColour = true;
56 function Skin()
58 global $wgUseOldExistenceCheck;
59 $postParseLinkColour = !$wgUseOldExistenceCheck;
60 $this->linktrail = wfMsg('linktrail');
63 function getSkinNames()
65 global $wgValidSkinNames;
66 return $wgValidSkinNames;
69 function getStylesheet()
71 return 'wikistandard.css';
73 function getSkinName() {
74 return "standard";
77 # Get/set accessor for delayed link colouring
78 function postParseLinkColour( $setting = NULL ) {
79 return wfSetVar( $this->postParseLinkColour, $setting );
82 function qbSetting()
84 global $wgOut, $wgUser;
86 if ( $wgOut->isQuickbarSuppressed() ) { return 0; }
87 $q = $wgUser->getOption( 'quickbar' );
88 if ( '' == $q ) { $q = 0; }
89 return $q;
92 function initPage( &$out )
94 $fname = 'Skin::initPage';
95 wfProfileIn( $fname );
97 $out->addLink( array( 'rel' => 'shortcut icon', 'href' => '/favicon.ico' ) );
99 $this->addMetadataLinks($out);
101 wfProfileOut( $fname );
104 function addMetadataLinks( &$out ) {
105 global $wgTitle, $wgEnableDublinCoreRdf, $wgEnableCreativeCommonsRdf, $wgRdfMimeType, $action;
106 global $wgRightsPage, $wgRightsUrl;
108 if( $out->isArticleRelated() ) {
109 # note: buggy CC software only reads first "meta" link
110 if( $wgEnableCreativeCommonsRdf ) {
111 $out->addMetadataLink( array(
112 'title' => 'Creative Commons',
113 'type' => 'application/rdf+xml',
114 'href' => $wgTitle->getLocalURL( 'action=creativecommons') ) );
116 if( $wgEnableDublinCoreRdf ) {
117 $out->addMetadataLink( array(
118 'title' => 'Dublin Core',
119 'type' => 'application/rdf+xml',
120 'href' => $wgTitle->getLocalURL( 'action=dublincore' ) ) );
123 $copyright = '';
124 if( $wgRightsPage ) {
125 $copy = Title::newFromText( $wgRightsPage );
126 if( $copy ) {
127 $copyright = $copy->getLocalURL();
130 if( !$copyright && $wgRightsUrl ) {
131 $copyright = $wgRightsUrl;
133 if( $copyright ) {
134 $out->addLink( array(
135 'rel' => 'copyright',
136 'href' => $copyright ) );
140 function outputPage( &$out ) {
141 global $wgDebugComments;
143 wfProfileIn( 'Skin::outputPage' );
144 $this->initPage( $out );
145 $out->out( $out->headElement() );
147 $out->out( "\n<body" );
148 $ops = $this->getBodyOptions();
149 foreach ( $ops as $name => $val ) {
150 $out->out( " $name='$val'" );
152 $out->out( ">\n" );
153 if ( $wgDebugComments ) {
154 $out->out( "<!-- Wiki debugging output:\n" .
155 $out->mDebugtext . "-->\n" );
157 $out->out( $this->beforeContent() );
159 $out->out( $out->mBodytext . "\n" );
161 $out->out( $this->afterContent() );
163 wfProfileClose();
164 $out->out( $out->reportTime() );
166 $out->out( "\n</body></html>" );
169 function getHeadScripts() {
170 global $wgStylePath, $wgUser, $wgLang, $wgAllowUserJs;
171 $r = "<script type=\"text/javascript\" src=\"{$wgStylePath}/wikibits.js\"></script>\n";
172 if( $wgAllowUserJs && $wgUser->getID() != 0 ) { # logged in
173 $userpage = $wgLang->getNsText( Namespace::getUser() ) . ":" . $wgUser->getName();
174 $userjs = htmlspecialchars($this->makeUrl($userpage.'/'.$this->getSkinName().'.js', 'action=raw&ctype=text/javascript'));
175 $r .= '<script type="text/javascript" src="'.$userjs."\"></script>\n";
177 return $r;
180 # get the user/site-specific stylesheet, SkinPHPTal called from RawPage.php (settings are cached that way)
181 function getUserStylesheet() {
182 global $wgOut, $wgStylePath, $wgLang, $wgUser, $wgRequest, $wgTitle, $wgAllowUserCss;
183 $sheet = $this->getStylesheet();
184 $action = $wgRequest->getText('action');
185 $s = "@import \"$wgStylePath/$sheet\";\n";
186 if($wgLang->isRTL()) $s .= "@import \"$wgStylePath/common_rtl.css\";\n";
187 if( $wgAllowUserCss && $wgUser->getID() != 0 ) { # logged in
188 if($wgTitle->isCssSubpage() and $action == 'submit' and $wgTitle->userCanEditCssJsSubpage()) {
189 $s .= $wgRequest->getText('wpTextbox1');
190 } else {
191 $userpage = $wgLang->getNsText( Namespace::getUser() ) . ":" . $wgUser->getName();
192 $s.= '@import "'.$this->makeUrl($userpage.'/'.$this->getSkinName().'.css', 'action=raw&ctype=text/css').'";'."\n";
195 $s .= $this->doGetUserStyles();
196 return $s."\n";
198 # placeholder, returns generated js in monobook
199 function getUserJs() {
200 return;
203 function getUserStyles()
205 global $wgOut, $wgStylePath, $wgLang;
206 $s = "<style type='text/css'>\n";
207 $s .= "/*/*/ /*<![CDATA[*/\n"; # <-- Hide the styles from Netscape 4 without hiding them from IE/Mac
208 $s .= $this->getUserStylesheet();
209 $s .= "/*]]>*/ /* */\n";
210 $s .= "</style>\n";
211 return $s;
214 function doGetUserStyles()
216 global $wgUser, $wgLang;
218 $csspage = $wgLang->getNsText( NS_MEDIAWIKI ) . ":" . $this->getSkinName() . ".css";
219 $s = '@import "'.$this->makeUrl($csspage, 'action=raw&ctype=text/css')."\";\n";
221 if ( 1 == $wgUser->getOption( 'underline' ) ) {
222 # Don't override browser settings
223 } else {
224 # CHECK MERGE @@@
225 # Force no underline
226 $s .= "a { text-decoration: none; }\n";
228 if ( 1 == $wgUser->getOption( 'highlightbroken' ) ) {
229 $s .= "a.new, #quickbar a.new { color: #CC2200; }\n";
231 if ( 1 == $wgUser->getOption( 'justify' ) ) {
232 $s .= "#article { text-align: justify; }\n";
234 return $s;
237 function getBodyOptions()
239 global $wgUser, $wgTitle, $wgNamespaceBackgrounds, $wgOut, $wgRequest;
241 extract( $wgRequest->getValues( 'oldid', 'redirect', 'diff' ) );
243 if ( 0 != $wgTitle->getNamespace() ) {
244 $a = array( 'bgcolor' => '#ffffec' );
246 else $a = array( 'bgcolor' => '#FFFFFF' );
247 if($wgOut->isArticle() && $wgUser->getOption('editondblclick') &&
248 (!$wgTitle->isProtected() || $wgUser->isSysop()) ) {
249 $t = wfMsg( 'editthispage' );
250 $oid = $red = '';
251 if ( !empty($redirect) ) {
252 $red = "&redirect={$redirect}";
254 if ( !empty($oldid) && ! isset( $diff ) ) {
255 $oid = "&oldid={$oldid}";
257 $s = $wgTitle->getFullURL( "action=edit{$oid}{$red}" );
258 $s = 'document.location = "' .$s .'";';
259 $a += array ('ondblclick' => $s);
262 $a['onload'] = $wgOut->getOnloadHandler();
263 return $a;
266 function getExternalLinkAttributes( $link, $text, $class='' )
268 global $wgUser, $wgOut, $wgLang;
270 $link = urldecode( $link );
271 $link = $wgLang->checkTitleEncoding( $link );
272 $link = str_replace( '_', ' ', $link );
273 $link = htmlspecialchars( $link );
275 $r = ($class != '') ? " class='$class'" : " class='external'";
277 if ( 1 == $wgUser->getOption( 'hover' ) ) {
278 $r .= " title=\"{$link}\"";
280 return $r;
283 function getInternalLinkAttributes( $link, $text, $broken = false )
285 global $wgUser, $wgOut;
287 $link = urldecode( $link );
288 $link = str_replace( '_', ' ', $link );
289 $link = htmlspecialchars( $link );
291 if ( $broken == 'stub' ) {
292 $r = ' class="stub"';
293 } else if ( $broken == 'yes' ) {
294 $r = ' class="new"';
295 } else {
296 $r = '';
299 if ( 1 == $wgUser->getOption( 'hover' ) ) {
300 $r .= " title=\"{$link}\"";
302 return $r;
305 function getInternalLinkAttributesObj( &$nt, $text, $broken = false )
307 global $wgUser, $wgOut;
309 if ( $broken == 'stub' ) {
310 $r = ' class="stub"';
311 } else if ( $broken == 'yes' ) {
312 $r = ' class="new"';
313 } else {
314 $r = '';
317 if ( 1 == $wgUser->getOption( 'hover' ) ) {
318 $r .= ' title ="' . $nt->getEscapedText() . '"';
320 return $r;
323 function getLogo()
325 global $wgLogo;
326 return $wgLogo;
329 # This will be called immediately after the <body> tag. Split into
330 # two functions to make it easier to subclass.
332 function beforeContent()
334 global $wgUser, $wgOut;
336 return $this->doBeforeContent();
339 function doBeforeContent()
341 global $wgUser, $wgOut, $wgTitle, $wgLang, $wgSiteNotice;
342 $fname = 'Skin::doBeforeContent';
343 wfProfileIn( $fname );
345 $s = '';
346 $qb = $this->qbSetting();
348 if( $langlinks = $this->otherLanguages() ) {
349 $rows = 2;
350 $borderhack = '';
351 } else {
352 $rows = 1;
353 $langlinks = false;
354 $borderhack = 'class="top"';
357 $s .= "\n<div id='content'>\n<div id='topbar'>\n" .
358 "<table border='0' cellspacing='0' width='98%'>\n<tr>\n";
360 $shove = ($qb != 0);
361 $left = ($qb == 1 || $qb == 3);
362 if($wgLang->isRTL()) $left = !$left;
364 if ( !$shove ) {
365 $s .= "<td class='top' align='left' valign='top' rowspan='{$rows}'>\n" .
366 $this->logoText() . '</td>';
367 } elseif( $left ) {
368 $s .= $this->getQuickbarCompensator( $rows );
370 $l = $wgLang->isRTL() ? 'right' : 'left';
371 $s .= "<td {$borderhack} align='$l' valign='top'>\n";
373 $s .= $this->topLinks() ;
374 $s .= "<p class='subtitle'>" . $this->pageTitleLinks() . "</p>\n";
376 $r = $wgLang->isRTL() ? "left" : "right";
377 $s .= "</td>\n<td {$borderhack} valign='top' align='$r' nowrap='nowrap'>";
378 $s .= $this->nameAndLogin();
379 $s .= "\n<br />" . $this->searchForm() . "</td>";
381 if ( $langlinks ) {
382 $s .= "</tr>\n<tr>\n<td class='top' colspan=\"2\">$langlinks</td>\n";
385 if ( $shove && !$left ) { # Right
386 $s .= $this->getQuickbarCompensator( $rows );
388 $s .= "</tr>\n</table>\n</div>\n";
389 $s .= "\n<div id='article'>\n";
391 if( $wgSiteNotice ) {
392 $s .= "\n<div id='siteNotice'>$wgSiteNotice</div>\n";
394 $s .= $this->pageTitle();
395 $s .= $this->pageSubtitle() ;
396 $s .= $this->getCategories();
397 wfProfileOut( $fname );
398 return $s;
401 function getCategoryLinks () {
402 global $wgOut, $wgTitle, $wgUser, $wgParser;
403 global $wgUseCategoryMagic, $wgUseCategoryBrowser, $wgLang;
405 if( !$wgUseCategoryMagic ) return '' ;
406 if( count( $wgOut->mCategoryLinks ) == 0 ) return '';
408 # Taken out so that they will be displayed in previews -- TS
409 #if( !$wgOut->isArticle() ) return '';
411 $t = implode ( ' | ' , $wgOut->mCategoryLinks ) ;
412 $s = $this->makeKnownLink( 'Special:Categories',
413 wfMsg( 'categories' ), 'article=' . urlencode( $wgTitle->getPrefixedDBkey() ) )
414 . ': ' . $t;
416 if($wgUseCategoryBrowser) {
417 $s .= '<br/><hr/>';
418 $catstack = array();
419 $s.= $wgTitle->getAllParentCategories($catstack);
422 return $s;
425 function getCategories() {
426 $catlinks=$this->getCategoryLinks();
427 if(!empty($catlinks)) {
428 return "<p class='catlinks'>{$catlinks}</p>";
432 function getQuickbarCompensator( $rows = 1 )
434 return "<td width='152' rowspan='{$rows}'>&nbsp;</td>";
437 # This gets called immediately before the </body> tag.
439 function afterContent()
441 global $wgUser, $wgOut, $wgServer;
442 global $wgTitle, $wgLang;
444 $printfooter = "<div class=\"printfooter\">\n" . $this->printFooter() . "</div>\n";
445 return $printfooter . $this->doAfterContent();
448 function printSource() {
449 global $wgTitle;
450 $url = htmlspecialchars( $wgTitle->getFullURL() );
451 return wfMsg( "retrievedfrom", "<a href=\"$url\">$url</a>" );
454 function printFooter() {
455 return "<p>" . $this->printSource() .
456 "</p>\n\n<p>" . $this->pageStats() . "</p>\n";
459 function doAfterContent()
461 global $wgUser, $wgOut, $wgLang;
462 $fname = 'Skin::doAfterContent';
463 wfProfileIn( $fname );
464 wfProfileIn( $fname.'-1' );
466 $s = "\n</div><br style=\"clear:both\" />\n";
467 $s .= "\n<div id='footer'>";
468 $s .= '<table border="0" cellspacing="0"><tr>';
470 wfProfileOut( $fname.'-1' );
471 wfProfileIn( $fname.'-2' );
473 $qb = $this->qbSetting();
474 $shove = ($qb != 0);
475 $left = ($qb == 1 || $qb == 3);
476 if($wgLang->isRTL()) $left = !$left;
478 if ( $shove && $left ) { # Left
479 $s .= $this->getQuickbarCompensator();
481 wfProfileOut( $fname.'-2' );
482 wfProfileIn( $fname.'-3' );
483 $l = $wgLang->isRTL() ? 'right' : 'left';
484 $s .= "<td class='bottom' align='$l' valign='top'>";
486 $s .= $this->bottomLinks();
487 $s .= "\n<br />" . $this->mainPageLink()
488 . ' | ' . $this->aboutLink()
489 . ' | ' . $this->specialLink( 'recentchanges' )
490 . ' | ' . $this->searchForm()
491 . '<br /><span id="pagestats">' . $this->pageStats() . '</span>';
493 $s .= "</td>";
494 if ( $shove && !$left ) { # Right
495 $s .= $this->getQuickbarCompensator();
497 $s .= "</tr></table>\n</div>\n</div>\n";
499 wfProfileOut( $fname.'-3' );
500 wfProfileIn( $fname.'-4' );
501 if ( 0 != $qb ) { $s .= $this->quickBar(); }
502 wfProfileOut( $fname.'-4' );
503 wfProfileOut( $fname );
504 return $s;
507 function pageTitleLinks()
509 global $wgOut, $wgTitle, $wgUser, $wgLang, $wgUseApproval, $wgRequest;
511 extract( $wgRequest->getValues( 'oldid', 'diff' ) );
512 $action = $wgRequest->getText( 'action' );
514 $s = $this->printableLink();
515 if ( wfMsg ( 'disclaimers' ) != '-' ) $s .= ' | ' . $this->makeKnownLink( wfMsg( 'disclaimerpage' ), wfMsg( 'disclaimers' ) ) ;
517 if ( $wgOut->isArticleRelated() ) {
518 if ( $wgTitle->getNamespace() == Namespace::getImage() ) {
519 $name = $wgTitle->getDBkey();
520 $link = htmlspecialchars( Image::wfImageUrl( $name ) );
521 $style = $this->getInternalLinkAttributes( $link, $name );
522 $s .= " | <a href=\"{$link}\"{$style}>{$name}</a>";
524 # This will show the "Approve" link if $wgUseApproval=true;
525 if ( isset ( $wgUseApproval ) && $wgUseApproval )
527 $t = $wgTitle->getDBkey();
528 $name = 'Approve this article' ;
529 $link = "http://test.wikipedia.org/w/magnus/wiki.phtml?title={$t}&action=submit&doit=1" ;
530 #htmlspecialchars( wfImageUrl( $name ) );
531 $style = $this->getExternalLinkAttributes( $link, $name );
532 $s .= " | <a href=\"{$link}\"{$style}>{$name}</a>" ;
535 if ( 'history' == $action || isset( $diff ) || isset( $oldid ) ) {
536 $s .= ' | ' . $this->makeKnownLink( $wgTitle->getPrefixedText(),
537 wfMsg( 'currentrev' ) );
540 if ( $wgUser->getNewtalk() ) {
541 # do not show "You have new messages" text when we are viewing our
542 # own talk page
544 if(!(strcmp($wgTitle->getText(),$wgUser->getName()) == 0 &&
545 $wgTitle->getNamespace()==Namespace::getTalk(Namespace::getUser()))) {
546 $n =$wgUser->getName();
547 $tl = $this->makeKnownLink( $wgLang->getNsText(
548 Namespace::getTalk( Namespace::getUser() ) ) . ":{$n}",
549 wfMsg('newmessageslink') );
550 $s.= ' | <strong>'. wfMsg( 'newmessages', $tl ) . '</strong>';
554 $undelete = $this->getUndeleteLink();
555 if( !empty( $undelete ) ) {
556 $s .= ' | '.$undelete;
558 return $s;
561 function getUndeleteLink() {
562 global $wgUser, $wgTitle, $wgLang, $action;
563 if( $wgUser->isSysop() &&
564 (($wgTitle->getArticleId() == 0) || ($action == "history")) &&
565 ($n = $wgTitle->isDeleted() ) ) {
566 return wfMsg( 'thisisdeleted',
567 $this->makeKnownLink(
568 $wgLang->SpecialPage( 'Undelete/' . $wgTitle->getPrefixedDBkey() ),
569 wfMsg( 'restorelink', $n ) ) );
571 return '';
574 function printableLink()
576 global $wgOut, $wgFeedClasses, $wgRequest;
578 $baseurl = $_SERVER['REQUEST_URI'];
579 if( strpos( '?', $baseurl ) == false ) {
580 $baseurl .= '?';
581 } else {
582 $baseurl .= '&';
584 $baseurl = htmlspecialchars( $baseurl );
585 $printurl = $wgRequest->escapeAppendQuery( 'printable=yes' );
587 $s = "<a href=\"$printurl\">" . wfMsg( 'printableversion' ) . '</a>';
588 if( $wgOut->isSyndicated() ) {
589 foreach( $wgFeedClasses as $format => $class ) {
590 $feedurl = $wgRequest->escapeAppendQuery( "feed=$format" );
591 $s .= " | <a href=\"$feedurl\">{$format}</a>";
594 return $s;
597 function pageTitle()
599 global $wgOut, $wgTitle, $wgUser;
601 $s = '<h1 class="pagetitle">' . htmlspecialchars( $wgOut->getPageTitle() ) . '</h1>';
602 if($wgUser->getOption( 'editsectiononrightclick' ) && $wgTitle->userCanEdit()) { $s=$this->editSectionScript(0,$s);}
603 return $s;
606 function pageSubtitle()
608 global $wgOut;
610 $sub = $wgOut->getSubtitle();
611 if ( '' == $sub ) {
612 global $wgExtraSubtitle;
613 $sub = wfMsg( 'fromwikipedia' ) . $wgExtraSubtitle;
615 $subpages = $this->subPageSubtitle();
616 $sub .= !empty($subpages)?"</p><p class='subpages'>$subpages":'';
617 $s = "<p class='subtitle'>{$sub}</p>\n";
618 return $s;
621 function subPageSubtitle()
623 global $wgOut,$wgTitle,$wgNamespacesWithSubpages;
624 $subpages = '';
625 if($wgOut->isArticle() && !empty($wgNamespacesWithSubpages[$wgTitle->getNamespace()])) {
626 $ptext=$wgTitle->getPrefixedText();
627 if(preg_match('/\//',$ptext)) {
628 $links = explode('/',$ptext);
629 $c = 0;
630 $growinglink = '';
631 foreach($links as $link) {
632 $c++;
633 if ($c<count($links)) {
634 $growinglink .= $link;
635 $getlink = $this->makeLink( $growinglink, $link );
636 if(preg_match('/class="new"/i',$getlink)) { break; } # this is a hack, but it saves time
637 if ($c>1) {
638 $subpages .= ' | ';
639 } else {
640 $subpages .= '&lt; ';
642 $subpages .= $getlink;
643 $growinglink .= '/';
648 return $subpages;
651 function nameAndLogin()
653 global $wgUser, $wgTitle, $wgLang, $wgShowIPinHeader, $wgIP;
655 $li = $wgLang->specialPage( 'Userlogin' );
656 $lo = $wgLang->specialPage( 'Userlogout' );
658 $s = '';
659 if ( 0 == $wgUser->getID() ) {
660 if( $wgShowIPinHeader && isset( $_COOKIE[ini_get('session.name')] ) ) {
661 $n = $wgIP;
663 $tl = $this->makeKnownLink( $wgLang->getNsText(
664 Namespace::getTalk( Namespace::getUser() ) ) . ":{$n}",
665 $wgLang->getNsText( Namespace::getTalk( 0 ) ) );
667 $s .= $n . ' ('.$tl.')';
668 } else {
669 $s .= wfMsg('notloggedin');
672 $rt = $wgTitle->getPrefixedURL();
673 if ( 0 == strcasecmp( urlencode( $lo ), $rt ) ) {
674 $q = '';
675 } else { $q = "returnto={$rt}"; }
677 $s .= "\n<br />" . $this->makeKnownLink( $li,
678 wfMsg( 'login' ), $q );
679 } else {
680 $n = $wgUser->getName();
681 $rt = $wgTitle->getPrefixedURL();
682 $tl = $this->makeKnownLink( $wgLang->getNsText(
683 Namespace::getTalk( Namespace::getUser() ) ) . ":{$n}",
684 $wgLang->getNsText( Namespace::getTalk( 0 ) ) );
686 $tl = " ({$tl})";
688 $s .= $this->makeKnownLink( $wgLang->getNsText(
689 Namespace::getUser() ) . ":{$n}", $n ) . "{$tl}<br />" .
690 $this->makeKnownLink( $lo, wfMsg( 'logout' ),
691 "returnto={$rt}" ) . ' | ' .
692 $this->specialLink( 'preferences' );
694 $s .= ' | ' . $this->makeKnownLink( wfMsg( 'helppage' ),
695 wfMsg( 'help' ) );
697 return $s;
700 function getSearchLink() {
701 $searchPage =& Title::makeTitle( NS_SPECIAL, 'Search' );
702 return $searchPage->getLocalURL();
705 function escapeSearchLink() {
706 return htmlspecialchars( $this->getSearchLink() );
709 function searchForm()
711 global $wgRequest;
712 $search = $wgRequest->getText( 'search' );
714 $s = '<form name="search" class="inline" method="post" action="'
715 . $this->escapeSearchLink() . "\">\n"
716 . '<input type="text" name="search" size="19" value="'
717 . htmlspecialchars(substr($search,0,256)) . "\" />\n"
718 . '<input type="submit" name="go" value="' . wfMsg ('go') . '" />&nbsp;'
719 . '<input type="submit" name="fulltext" value="' . wfMsg ('search') . "\" />\n</form>";
721 return $s;
724 function topLinks()
726 global $wgOut;
727 $sep = " |\n";
729 $s = $this->mainPageLink() . $sep
730 . $this->specialLink( 'recentchanges' );
732 if ( $wgOut->isArticleRelated() ) {
733 $s .= $sep . $this->editThisPage()
734 . $sep . $this->historyLink();
736 # Many people don't like this dropdown box
737 #$s .= $sep . $this->specialPagesList();
739 return $s;
742 function bottomLinks()
744 global $wgOut, $wgUser, $wgTitle;
745 $sep = " |\n";
747 $s = '';
748 if ( $wgOut->isArticleRelated() ) {
749 $s .= '<strong>' . $this->editThisPage() . '</strong>';
750 if ( 0 != $wgUser->getID() ) {
751 $s .= $sep . $this->watchThisPage();
753 $s .= $sep . $this->talkLink()
754 . $sep . $this->historyLink()
755 . $sep . $this->whatLinksHere()
756 . $sep . $this->watchPageLinksLink();
758 if ( $wgTitle->getNamespace() == Namespace::getUser()
759 || $wgTitle->getNamespace() == Namespace::getTalk(Namespace::getUser()) )
762 $id=User::idFromName($wgTitle->getText());
763 $ip=User::isIP($wgTitle->getText());
765 if($id || $ip) { # both anons and non-anons have contri list
766 $s .= $sep . $this->userContribsLink();
768 if ( 0 != $wgUser->getID() ) { # show only to signed in users
769 if($id) { # can only email non-anons
770 $s .= $sep . $this->emailUserLink();
774 if ( $wgUser->isSysop() && $wgTitle->getArticleId() ) {
775 $s .= "\n<br />" . $this->deleteThisPage() .
776 $sep . $this->protectThisPage() .
777 $sep . $this->moveThisPage();
779 $s .= "<br />\n" . $this->otherLanguages();
781 return $s;
784 function pageStats()
786 global $wgOut, $wgLang, $wgArticle, $wgRequest;
787 global $wgDisableCounters, $wgMaxCredits, $wgShowCreditsIfMax;
789 extract( $wgRequest->getValues( 'oldid', 'diff' ) );
790 if ( ! $wgOut->isArticle() ) { return ''; }
791 if ( isset( $oldid ) || isset( $diff ) ) { return ''; }
792 if ( 0 == $wgArticle->getID() ) { return ''; }
794 $s = '';
795 if ( !$wgDisableCounters ) {
796 $count = $wgLang->formatNum( $wgArticle->getCount() );
797 if ( $count ) {
798 $s = wfMsg( 'viewcount', $count );
802 if (isset($wgMaxCredits) && $wgMaxCredits != 0) {
803 require_once("Credits.php");
804 $s .= ' ' . getCredits($wgArticle, $wgMaxCredits, $wgShowCreditsIfMax);
805 } else {
806 $s .= $this->lastModified();
809 return $s . ' ' . $this->getCopyright();
812 function getCopyright() {
813 global $wgRightsPage, $wgRightsUrl, $wgRightsText, $wgRequest;
816 $oldid = $wgRequest->getVal( 'oldid' );
817 $diff = $wgRequest->getVal( 'diff' );
819 if ( !is_null( $oldid ) && is_null( $diff ) && wfMsg( 'history_copyright' ) !== '-' ) {
820 $msg = 'history_copyright';
821 } else {
822 $msg = 'copyright';
825 $out = '';
826 if( $wgRightsPage ) {
827 $link = $this->makeKnownLink( $wgRightsPage, $wgRightsText );
828 } elseif( $wgRightsUrl ) {
829 $link = $this->makeExternalLink( $wgRightsUrl, $wgRightsText );
830 } else {
831 # Give up now
832 return $out;
834 $out .= wfMsg( $msg, $link );
835 return $out;
838 function getCopyrightIcon() {
839 global $wgRightsPage, $wgRightsUrl, $wgRightsText, $wgRightsIcon;
840 $out = '';
841 if( $wgRightsIcon ) {
842 $icon = htmlspecialchars( $wgRightsIcon );
843 if( $wgRightsUrl ) {
844 $url = htmlspecialchars( $wgRightsUrl );
845 $out .= '<a href="'.$url.'">';
847 $text = htmlspecialchars( $wgRightsText );
848 $out .= "<img src=\"$icon\" alt='$text' />";
849 if( $wgRightsUrl ) {
850 $out .= '</a>';
853 return $out;
856 function getPoweredBy() {
857 global $wgStylePath;
858 $url = htmlspecialchars( "$wgStylePath/images/poweredby_mediawiki_88x31.png" );
859 $img = '<a href="http://www.mediawiki.org/"><img src="'.$url.'" alt="MediaWiki" /></a>';
860 return $img;
863 function lastModified()
865 global $wgLang, $wgArticle;
867 $timestamp = $wgArticle->getTimestamp();
868 if ( $timestamp ) {
869 $d = $wgLang->timeanddate( $wgArticle->getTimestamp(), true );
870 $s = ' ' . wfMsg( 'lastmodified', $d );
871 } else {
872 $s = '';
874 return $s;
877 function logoText( $align = '' )
879 if ( '' != $align ) { $a = ' align="'.$align.'"'; }
880 else { $a = ''; }
882 $mp = wfMsg( 'mainpage' );
883 $titleObj = Title::newFromText( $mp );
884 $s = '<a href="' . $titleObj->escapeLocalURL()
885 . '"><img'.$a.' src="'
886 . $this->getLogo() . '" alt="' . "[{$mp}]\" /></a>";
887 return $s;
890 function quickBar()
892 global $wgOut, $wgTitle, $wgUser, $wgRequest, $wgLang;
893 global $wgDisableUploads, $wgRemoteUploads;
895 $fname = 'Skin::quickBar';
896 wfProfileIn( $fname );
898 $action = $wgRequest->getText( 'action' );
899 $wpPreview = $wgRequest->getBool( 'wpPreview' );
900 $tns=$wgTitle->getNamespace();
902 $s = "\n<div id='quickbar'>";
903 $s .= "\n" . $this->logoText() . "\n<hr class='sep' />";
905 $sep = "\n<br />";
906 $s .= $this->mainPageLink()
907 . $sep . $this->specialLink( 'recentchanges' )
908 . $sep . $this->specialLink( 'randompage' );
909 if ($wgUser->getID()) {
910 $s.= $sep . $this->specialLink( 'watchlist' ) ;
911 $s .= $sep .$this->makeKnownLink( $wgLang->specialPage( 'Contributions' ),
912 wfMsg( 'mycontris' ), 'target=' . wfUrlencode($wgUser->getName() ) );
915 // only show watchlist link if logged in
916 if ( wfMsg ( 'currentevents' ) != '-' ) $s .= $sep . $this->makeKnownLink( wfMsg( 'currentevents' ), '' ) ;
917 $s .= "\n<br /><hr class='sep' />";
918 $articleExists = $wgTitle->getArticleId();
919 if ( $wgOut->isArticle() || $action =='edit' || $action =='history' || $wpPreview) {
920 if($wgOut->isArticle()) {
921 $s .= '<strong>' . $this->editThisPage() . '</strong>';
922 } else { # backlink to the article in edit or history mode
923 if($articleExists){ # no backlink if no article
924 switch($tns) {
925 case 0:
926 $text = wfMsg('articlepage');
927 break;
928 case 1:
929 $text = wfMsg('viewtalkpage');
930 break;
931 case 2:
932 $text = wfMsg('userpage');
933 break;
934 case 3:
935 $text = wfMsg('viewtalkpage');
936 break;
937 case 4:
938 $text = wfMsg('wikipediapage');
939 break;
940 case 5:
941 $text = wfMsg('viewtalkpage');
942 break;
943 case 6:
944 $text = wfMsg('imagepage');
945 break;
946 case 7:
947 $text = wfMsg('viewtalkpage');
948 break;
949 default:
950 $text= wfMsg('articlepage');
953 $link = $wgTitle->getText();
954 if ($nstext = $wgLang->getNsText($tns) ) { # add namespace if necessary
955 $link = $nstext . ':' . $link ;
958 $s .= $this->makeLink( $link, $text );
959 } elseif( $wgTitle->getNamespace() != Namespace::getSpecial() ) {
960 # we just throw in a "New page" text to tell the user that he's in edit mode,
961 # and to avoid messing with the separator that is prepended to the next item
962 $s .= '<strong>' . wfMsg('newpage') . '</strong>';
968 if( $tns%2 && $action!='edit' && !$wpPreview) {
969 $s.= '<br />'.$this->makeKnownLink($wgTitle->getPrefixedText(),wfMsg('postcomment'),'action=edit&section=new');
973 watching could cause problems in edit mode:
974 if user edits article, then loads "watch this article" in background and then saves
975 article with "Watch this article" checkbox disabled, the article is transparently
976 unwatched. Therefore we do not show the "Watch this page" link in edit mode
978 if ( 0 != $wgUser->getID() && $articleExists) {
979 if($action!='edit' && $action != 'submit' )
981 $s .= $sep . $this->watchThisPage();
983 if ( $wgTitle->userCanEdit() )
984 $s .= $sep . $this->moveThisPage();
986 if ( $wgUser->isSysop() and $articleExists ) {
987 $s .= $sep . $this->deleteThisPage() .
988 $sep . $this->protectThisPage();
990 $s .= $sep . $this->talkLink();
991 if ($articleExists && $action !='history') {
992 $s .= $sep . $this->historyLink();
994 $s.=$sep . $this->whatLinksHere();
996 if($wgOut->isArticleRelated()) {
997 $s .= $sep . $this->watchPageLinksLink();
1000 if ( Namespace::getUser() == $wgTitle->getNamespace()
1001 || $wgTitle->getNamespace() == Namespace::getTalk(Namespace::getUser())
1004 $id=User::idFromName($wgTitle->getText());
1005 $ip=User::isIP($wgTitle->getText());
1007 if($id||$ip) {
1008 $s .= $sep . $this->userContribsLink();
1010 if ( 0 != $wgUser->getID() ) {
1011 if($id) { # can only email real users
1012 $s .= $sep . $this->emailUserLink();
1016 $s .= "\n<br /><hr class='sep' />";
1019 if ( 0 != $wgUser->getID() && ( !$wgDisableUploads || $wgRemoteUploads ) ) {
1020 $s .= $this->specialLink( 'upload' ) . $sep;
1022 $s .= $this->specialLink( 'specialpages' )
1023 . $sep . $this->bugReportsLink();
1025 global $wgSiteSupportPage;
1026 if( $wgSiteSupportPage ) {
1027 $s .= "\n<br /><a href=\"" . htmlspecialchars( $wgSiteSupportPage ) .
1028 '" class="internal">' . wfMsg( 'sitesupport' ) . '</a>';
1031 $s .= "\n<br /></div>\n";
1032 wfProfileOut( $fname );
1033 return $s;
1036 function specialPagesList()
1038 global $wgUser, $wgOut, $wgLang, $wgServer, $wgRedirectScript;
1039 require_once('SpecialPage.php');
1040 $a = array();
1041 $pages = SpecialPage::getPages();
1043 foreach ( $pages[''] as $name => $page ) {
1044 $a[$name] = $page->getDescription();
1046 if ( $wgUser->isSysop() )
1048 foreach ( $pages['sysop'] as $name => $page ) {
1049 $a[$name] = $page->getDescription();
1052 if ( $wgUser->isDeveloper() )
1054 foreach ( $pages['developer'] as $name => $page ) {
1055 $a[$name] = $page->getDescription() ;
1058 $go = wfMsg( 'go' );
1059 $sp = wfMsg( 'specialpages' );
1060 $spp = $wgLang->specialPage( 'Specialpages' );
1062 $s = '<form id="specialpages" method="get" class="inline" ' .
1063 'action="' . htmlspecialchars( "{$wgServer}{$wgRedirectScript}" ) . "\">\n";
1064 $s .= "<select name=\"wpDropdown\">\n";
1065 $s .= "<option value=\"{$spp}\">{$sp}</option>\n";
1067 foreach ( $a as $name => $desc ) {
1068 $p = $wgLang->specialPage( $name );
1069 $s .= "<option value=\"{$p}\">{$desc}</option>\n";
1071 $s .= "</select>\n";
1072 $s .= "<input type='submit' value=\"{$go}\" name='redirect' />\n";
1073 $s .= "</form>\n";
1074 return $s;
1077 function mainPageLink()
1079 $mp = wfMsg( 'mainpage' );
1080 $s = $this->makeKnownLink( $mp, $mp );
1081 return $s;
1084 function copyrightLink()
1086 $s = $this->makeKnownLink( wfMsg( 'copyrightpage' ),
1087 wfMsg( 'copyrightpagename' ) );
1088 return $s;
1091 function aboutLink()
1093 $s = $this->makeKnownLink( wfMsg( 'aboutpage' ),
1094 wfMsg( 'aboutwikipedia' ) );
1095 return $s;
1099 function disclaimerLink()
1101 $s = $this->makeKnownLink( wfMsg( 'disclaimerpage' ),
1102 wfMsg( 'disclaimers' ) );
1103 return $s;
1106 function editThisPage()
1108 global $wgOut, $wgTitle, $wgRequest;
1110 $oldid = $wgRequest->getVal( 'oldid' );
1111 $diff = $wgRequest->getVal( 'diff' );
1112 $redirect = $wgRequest->getVal( 'redirect' );
1114 if ( ! $wgOut->isArticleRelated() ) {
1115 $s = wfMsg( 'protectedpage' );
1116 } else {
1117 $n = $wgTitle->getPrefixedText();
1118 if ( $wgTitle->userCanEdit() ) {
1119 $t = wfMsg( 'editthispage' );
1120 } else {
1121 #$t = wfMsg( "protectedpage" );
1122 $t = wfMsg( 'viewsource' );
1124 $oid = $red = '';
1126 if ( !is_null( $redirect ) ) { $red = "&redirect={$redirect}"; }
1127 if ( $oldid && ! isset( $diff ) ) {
1128 $oid = "&oldid={$oldid}";
1130 $s = $this->makeKnownLink( $n, $t, "action=edit{$oid}{$red}" );
1132 return $s;
1135 function deleteThisPage()
1137 global $wgUser, $wgOut, $wgTitle, $wgRequest;
1139 $diff = $wgRequest->getVal( 'diff' );
1140 if ( $wgTitle->getArticleId() && ( ! $diff ) && $wgUser->isSysop() ) {
1141 $n = $wgTitle->getPrefixedText();
1142 $t = wfMsg( 'deletethispage' );
1144 $s = $this->makeKnownLink( $n, $t, 'action=delete' );
1145 } else {
1146 $s = '';
1148 return $s;
1151 function protectThisPage()
1153 global $wgUser, $wgOut, $wgTitle, $wgRequest;
1155 $diff = $wgRequest->getVal( 'diff' );
1156 if ( $wgTitle->getArticleId() && ( ! $diff ) && $wgUser->isSysop() ) {
1157 $n = $wgTitle->getPrefixedText();
1159 if ( $wgTitle->isProtected() ) {
1160 $t = wfMsg( 'unprotectthispage' );
1161 $q = 'action=unprotect';
1162 } else {
1163 $t = wfMsg( 'protectthispage' );
1164 $q = 'action=protect';
1166 $s = $this->makeKnownLink( $n, $t, $q );
1167 } else {
1168 $s = '';
1170 return $s;
1173 function watchThisPage()
1175 global $wgUser, $wgOut, $wgTitle;
1177 if ( $wgOut->isArticleRelated() ) {
1178 $n = $wgTitle->getPrefixedText();
1180 if ( $wgTitle->userIsWatching() ) {
1181 $t = wfMsg( 'unwatchthispage' );
1182 $q = 'action=unwatch';
1183 } else {
1184 $t = wfMsg( 'watchthispage' );
1185 $q = 'action=watch';
1187 $s = $this->makeKnownLink( $n, $t, $q );
1188 } else {
1189 $s = wfMsg( 'notanarticle' );
1191 return $s;
1194 function moveThisPage()
1196 global $wgTitle, $wgLang;
1198 if ( $wgTitle->userCanEdit() ) {
1199 $s = $this->makeKnownLink( $wgLang->specialPage( 'Movepage' ),
1200 wfMsg( 'movethispage' ), 'target=' . $wgTitle->getPrefixedURL() );
1201 } // no message if page is protected - would be redundant
1202 return $s;
1205 function historyLink()
1207 global $wgTitle;
1209 $s = $this->makeKnownLink( $wgTitle->getPrefixedText(),
1210 wfMsg( 'history' ), 'action=history' );
1211 return $s;
1214 function whatLinksHere()
1216 global $wgTitle, $wgLang;
1218 $s = $this->makeKnownLink( $wgLang->specialPage( 'Whatlinkshere' ),
1219 wfMsg( 'whatlinkshere' ), 'target=' . $wgTitle->getPrefixedURL() );
1220 return $s;
1223 function userContribsLink()
1225 global $wgTitle, $wgLang;
1227 $s = $this->makeKnownLink( $wgLang->specialPage( 'Contributions' ),
1228 wfMsg( 'contributions' ), 'target=' . $wgTitle->getPartialURL() );
1229 return $s;
1232 function emailUserLink()
1234 global $wgTitle, $wgLang;
1236 $s = $this->makeKnownLink( $wgLang->specialPage( 'Emailuser' ),
1237 wfMsg( 'emailuser' ), 'target=' . $wgTitle->getPartialURL() );
1238 return $s;
1241 function watchPageLinksLink()
1243 global $wgOut, $wgTitle, $wgLang;
1245 if ( ! $wgOut->isArticleRelated() ) {
1246 $s = '(' . wfMsg( 'notanarticle' ) . ')';
1247 } else {
1248 $s = $this->makeKnownLink( $wgLang->specialPage(
1249 'Recentchangeslinked' ), wfMsg( 'recentchangeslinked' ),
1250 'target=' . $wgTitle->getPrefixedURL() );
1252 return $s;
1255 function otherLanguages()
1257 global $wgOut, $wgLang, $wgTitle, $wgUseNewInterlanguage;
1259 $a = $wgOut->getLanguageLinks();
1260 if ( 0 == count( $a ) ) {
1261 if ( !$wgUseNewInterlanguage ) return '';
1262 $ns = $wgLang->getNsIndex ( $wgTitle->getNamespace () ) ;
1263 if ( $ns != 0 AND $ns != 1 ) return '' ;
1264 $pn = 'Intl' ;
1265 $x = 'mode=addlink&xt='.$wgTitle->getDBkey() ;
1266 return $this->makeKnownLink( $wgLang->specialPage( $pn ),
1267 wfMsg( 'intl' ) , $x );
1270 if ( !$wgUseNewInterlanguage ) {
1271 $s = wfMsg( 'otherlanguages' ) . ': ';
1272 } else {
1273 global $wgLanguageCode ;
1274 $x = 'mode=zoom&xt='.$wgTitle->getDBkey() ;
1275 $x .= '&xl='.$wgLanguageCode ;
1276 $s = $this->makeKnownLink( $wgLang->specialPage( 'Intl' ),
1277 wfMsg( 'otherlanguages' ) , $x ) . ': ' ;
1280 $s = wfMsg( 'otherlanguages' ) . ': ';
1281 $first = true;
1282 if($wgLang->isRTL()) $s .= '<span dir="LTR">';
1283 foreach( $a as $l ) {
1284 if ( ! $first ) { $s .= ' | '; }
1285 $first = false;
1287 $nt = Title::newFromText( $l );
1288 $url = $nt->getFullURL();
1289 $text = $wgLang->getLanguageName( $nt->getInterwiki() );
1291 if ( '' == $text ) { $text = $l; }
1292 $style = $this->getExternalLinkAttributes( $l, $text );
1293 $s .= "<a href=\"{$url}\"{$style}>{$text}</a>";
1295 if($wgLang->isRTL()) $s .= '</span>';
1296 return $s;
1299 function bugReportsLink()
1301 $s = $this->makeKnownLink( wfMsg( 'bugreportspage' ),
1302 wfMsg( 'bugreports' ) );
1303 return $s;
1306 function dateLink()
1308 global $wgLinkCache;
1309 $t1 = Title::newFromText( gmdate( 'F j' ) );
1310 $t2 = Title::newFromText( gmdate( 'Y' ) );
1312 $wgLinkCache->suspend();
1313 $id = $t1->getArticleID();
1314 $wgLinkCache->resume();
1316 if ( 0 == $id ) {
1317 $s = $this->makeBrokenLink( $t1->getText() );
1318 } else {
1319 $s = $this->makeKnownLink( $t1->getText() );
1321 $s .= ', ';
1323 $wgLinkCache->suspend();
1324 $id = $t2->getArticleID();
1325 $wgLinkCache->resume();
1327 if ( 0 == $id ) {
1328 $s .= $this->makeBrokenLink( $t2->getText() );
1329 } else {
1330 $s .= $this->makeKnownLink( $t2->getText() );
1332 return $s;
1335 function talkLink()
1337 global $wgLang, $wgTitle, $wgLinkCache;
1339 $tns = $wgTitle->getNamespace();
1340 if ( -1 == $tns ) { return ''; }
1342 $pn = $wgTitle->getText();
1343 $tp = wfMsg( 'talkpage' );
1344 if ( Namespace::isTalk( $tns ) ) {
1345 $lns = Namespace::getSubject( $tns );
1346 switch($tns) {
1347 case 1:
1348 $text = wfMsg('articlepage');
1349 break;
1350 case 3:
1351 $text = wfMsg('userpage');
1352 break;
1353 case 5:
1354 $text = wfMsg('wikipediapage');
1355 break;
1356 case 7:
1357 $text = wfMsg('imagepage');
1358 break;
1359 default:
1360 $text= wfMsg('articlepage');
1362 } else {
1364 $lns = Namespace::getTalk( $tns );
1365 $text=$tp;
1367 $n = $wgLang->getNsText( $lns );
1368 if ( '' == $n ) { $link = $pn; }
1369 else { $link = $n.':'.$pn; }
1371 $wgLinkCache->suspend();
1372 $s = $this->makeLink( $link, $text );
1373 $wgLinkCache->resume();
1375 return $s;
1378 function commentLink()
1380 global $wgLang, $wgTitle, $wgLinkCache;
1382 $tns = $wgTitle->getNamespace();
1383 if ( -1 == $tns ) { return ''; }
1385 $lns = ( Namespace::isTalk( $tns ) ) ? $tns : Namespace::getTalk( $tns );
1387 # assert Namespace::isTalk( $lns )
1389 $n = $wgLang->getNsText( $lns );
1390 $pn = $wgTitle->getText();
1392 $link = $n.':'.$pn;
1394 $wgLinkCache->suspend();
1395 $s = $this->makeKnownLink($link, wfMsg('postcomment'), 'action=edit&section=new');
1396 $wgLinkCache->resume();
1398 return $s;
1401 # After all the page content is transformed into HTML, it makes
1402 # a final pass through here for things like table backgrounds.
1404 function transformContent( $text )
1406 return $text;
1409 # Note: This function MUST call getArticleID() on the link,
1410 # otherwise the cache won't get updated properly. See LINKCACHE.DOC.
1412 function makeLink( $title, $text = '', $query = '', $trail = '' ) {
1413 wfProfileIn( 'Skin::makeLink' );
1414 $nt = Title::newFromText( $title );
1415 if ($nt) {
1416 $result = $this->makeLinkObj( Title::newFromText( $title ), $text, $query, $trail );
1417 } else {
1418 wfDebug( 'Invalid title passed to Skin::makeLink(): "'.$title."\"\n" );
1419 $result = $text == "" ? $title : $text;
1422 wfProfileOut( 'Skin::makeLink' );
1423 return $result;
1426 function makeKnownLink( $title, $text = '', $query = '', $trail = '', $prefix = '',$aprops = '') {
1427 $nt = Title::newFromText( $title );
1428 if ($nt) {
1429 return $this->makeKnownLinkObj( Title::newFromText( $title ), $text, $query, $trail, $prefix , $aprops );
1430 } else {
1431 wfDebug( 'Invalid title passed to Skin::makeKnownLink(): "'.$title."\"\n" );
1432 return $text == '' ? $title : $text;
1436 function makeBrokenLink( $title, $text = '', $query = '', $trail = '' ) {
1437 $nt = Title::newFromText( $title );
1438 if ($nt) {
1439 return $this->makeBrokenLinkObj( Title::newFromText( $title ), $text, $query, $trail );
1440 } else {
1441 wfDebug( 'Invalid title passed to Skin::makeBrokenLink(): "'.$title."\"\n" );
1442 return $text == '' ? $title : $text;
1446 function makeStubLink( $title, $text = '', $query = '', $trail = '' ) {
1447 $nt = Title::newFromText( $title );
1448 if ($nt) {
1449 return $this->makeStubLinkObj( Title::newFromText( $title ), $text, $query, $trail );
1450 } else {
1451 wfDebug( 'Invalid title passed to Skin::makeStubLink(): "'.$title."\"\n" );
1452 return $text == '' ? $title : $text;
1456 # Pass a title object, not a title string
1457 function makeLinkObj( &$nt, $text= '', $query = '', $trail = '', $prefix = '' )
1459 global $wgOut, $wgUser;
1460 $fname = 'Skin::makeLinkObj';
1462 # Fail gracefully
1463 if ( ! isset($nt) )
1464 return "<!-- ERROR -->{$prefix}{$text}{$trail}";
1466 if ( $nt->isExternal() ) {
1467 $u = $nt->getFullURL();
1468 $link = $nt->getPrefixedURL();
1469 if ( '' == $text ) { $text = $nt->getPrefixedText(); }
1470 $style = $this->getExternalLinkAttributes( $link, $text, 'extiw' );
1472 $inside = '';
1473 if ( '' != $trail ) {
1474 if ( preg_match( '/^([a-z]+)(.*)$$/sD', $trail, $m ) ) {
1475 $inside = $m[1];
1476 $trail = $m[2];
1479 $retVal = "<a href=\"{$u}\"{$style}>{$text}{$inside}</a>{$trail}";
1480 } elseif ( 0 == $nt->getNamespace() && "" == $nt->getText() ) {
1481 $retVal = $this->makeKnownLinkObj( $nt, $text, $query, $trail, $prefix );
1482 } elseif ( ( -1 == $nt->getNamespace() ) ||
1483 ( Namespace::getImage() == $nt->getNamespace() ) ) {
1484 $retVal = $this->makeKnownLinkObj( $nt, $text, $query, $trail, $prefix );
1485 } else {
1486 if ( $this->postParseLinkColour() ) {
1487 $inside = '';
1488 if ( '' != $trail ) {
1489 if ( preg_match( $this->linktrail, $trail, $m ) ) {
1490 $inside = $m[1];
1491 $trail = $m[2];
1495 # Allows wiki to bypass using linkcache, see OutputPage::parseLinkHolders()
1496 $retVal = '<!--LINK ' . implode( ' ', array( $nt->getNamespace(), $nt->getDBkey(),
1497 $query, $prefix . $text . $inside ) ) . "-->{$trail}";
1498 } else {
1499 # Work out link colour immediately
1500 $aid = $nt->getArticleID() ;
1501 if ( 0 == $aid ) {
1502 $retVal = $this->makeBrokenLinkObj( $nt, $text, $query, $trail, $prefix );
1503 } else {
1504 $threshold = $wgUser->getOption('stubthreshold') ;
1505 if ( $threshold > 0 ) {
1506 $dbr =& wfGetDB( DB_SLAVE );
1507 $s = $dbr->selectRow( 'cur', array( 'LENGTH(cur_text) AS x', 'cur_namespace',
1508 'cur_is_redirect' ), array( 'cur_id' => $aid ), $fname ) ;
1509 if ( $s !== false ) {
1510 $size = $s->x;
1511 if ( $s->cur_is_redirect OR $s->cur_namespace != 0 ) {
1512 $size = $threshold*2 ; # Really big
1514 $dbr->freeResult( $res );
1515 } else {
1516 $size = $threshold*2 ; # Really big
1518 } else {
1519 $size = 1 ;
1521 if ( $size < $threshold ) {
1522 $retVal = $this->makeStubLinkObj( $nt, $text, $query, $trail, $prefix );
1523 } else {
1524 $retVal = $this->makeKnownLinkObj( $nt, $text, $query, $trail, $prefix );
1529 return $retVal;
1532 # Pass a title object, not a title string
1533 function makeKnownLinkObj( &$nt, $text = '', $query = '', $trail = '', $prefix = '' , $aprops = '')
1535 global $wgOut, $wgTitle, $wgInputEncoding;
1537 $fname = 'Skin::makeKnownLinkObj';
1538 wfProfileIn( $fname );
1540 if ( !is_object( $nt ) ) {
1541 return $text;
1543 $link = $nt->getPrefixedURL();
1545 if ( '' == $link ) {
1546 $u = '';
1547 if ( '' == $text ) {
1548 $text = htmlspecialchars( $nt->getFragment() );
1550 } else {
1551 $u = $nt->escapeLocalURL( $query );
1553 if ( '' != $nt->getFragment() ) {
1554 $anchor = urlencode( do_html_entity_decode( str_replace(' ', '_', $nt->getFragment()), ENT_COMPAT, $wgInputEncoding ) );
1555 $replacearray = array(
1556 '%3A' => ':',
1557 '%' => '.'
1559 $u .= '#' . str_replace(array_keys($replacearray),array_values($replacearray),$anchor);
1561 if ( '' == $text ) {
1562 $text = htmlspecialchars( $nt->getPrefixedText() );
1564 $style = $this->getInternalLinkAttributesObj( $nt, $text );
1566 $inside = '';
1567 if ( '' != $trail ) {
1568 if ( preg_match( $this->linktrail, $trail, $m ) ) {
1569 $inside = $m[1];
1570 $trail = $m[2];
1573 $r = "<a href=\"{$u}\"{$style}{$aprops}>{$prefix}{$text}{$inside}</a>{$trail}";
1574 wfProfileOut( $fname );
1575 return $r;
1578 # Pass a title object, not a title string
1579 function makeBrokenLinkObj( &$nt, $text = '', $query = '', $trail = '', $prefix = '' )
1581 global $wgOut, $wgUser;
1583 $fname = 'Skin::makeBrokenLinkObj';
1584 wfProfileIn( $fname );
1586 if ( '' == $query ) {
1587 $q = 'action=edit';
1588 } else {
1589 $q = 'action=edit&'.$query;
1591 $u = $nt->escapeLocalURL( $q );
1593 if ( '' == $text ) {
1594 $text = htmlspecialchars( $nt->getPrefixedText() );
1596 $style = $this->getInternalLinkAttributesObj( $nt, $text, "yes" );
1598 $inside = '';
1599 if ( '' != $trail ) {
1600 if ( preg_match( $this->linktrail, $trail, $m ) ) {
1601 $inside = $m[1];
1602 $trail = $m[2];
1605 if ( $wgUser->getOption( 'highlightbroken' ) ) {
1606 $s = "<a href=\"{$u}\"{$style}>{$prefix}{$text}{$inside}</a>{$trail}";
1607 } else {
1608 $s = "{$prefix}{$text}{$inside}<a href=\"{$u}\"{$style}>?</a>{$trail}";
1611 wfProfileOut( $fname );
1612 return $s;
1615 # Pass a title object, not a title string
1616 function makeStubLinkObj( &$nt, $text = '', $query = '', $trail = '', $prefix = '' )
1618 global $wgOut, $wgUser;
1620 $link = $nt->getPrefixedURL();
1622 $u = $nt->escapeLocalURL( $query );
1624 if ( '' == $text ) {
1625 $text = htmlspecialchars( $nt->getPrefixedText() );
1627 $style = $this->getInternalLinkAttributesObj( $nt, $text, 'stub' );
1629 $inside = '';
1630 if ( '' != $trail ) {
1631 if ( preg_match( $this->linktrail, $trail, $m ) ) {
1632 $inside = $m[1];
1633 $trail = $m[2];
1636 if ( $wgUser->getOption( 'highlightbroken' ) ) {
1637 $s = "<a href=\"{$u}\"{$style}>{$prefix}{$text}{$inside}</a>{$trail}";
1638 } else {
1639 $s = "{$prefix}{$text}{$inside}<a href=\"{$u}\"{$style}>!</a>{$trail}";
1641 return $s;
1644 function makeSelfLinkObj( &$nt, $text = '', $query = '', $trail = '', $prefix = '' )
1646 $u = $nt->escapeLocalURL( $query );
1647 if ( '' == $text ) {
1648 $text = htmlspecialchars( $nt->getPrefixedText() );
1650 $inside = '';
1651 if ( '' != $trail ) {
1652 if ( preg_match( $this->linktrail, $trail, $m ) ) {
1653 $inside = $m[1];
1654 $trail = $m[2];
1657 return "<strong>{$prefix}{$text}{$inside}</strong>{$trail}";
1660 /* these are used extensively in SkinPHPTal, but also some other places */
1661 /*static*/ function makeSpecialUrl( $name, $urlaction='' ) {
1662 $title = Title::makeTitle( NS_SPECIAL, $name );
1663 $this->checkTitle($title, $name);
1664 return $title->getLocalURL( $urlaction );
1666 /*static*/ function makeTalkUrl ( $name, $urlaction='' ) {
1667 $title = Title::newFromText( $name );
1668 $title = $title->getTalkPage();
1669 $this->checkTitle($title, $name);
1670 return $title->getLocalURL( $urlaction );
1672 /*static*/ function makeArticleUrl ( $name, $urlaction='' ) {
1673 $title = Title::newFromText( $name );
1674 $title= $title->getSubjectPage();
1675 $this->checkTitle($title, $name);
1676 return $title->getLocalURL( $urlaction );
1678 /*static*/ function makeI18nUrl ( $name, $urlaction='' ) {
1679 $title = Title::newFromText( wfMsg($name) );
1680 $this->checkTitle($title, $name);
1681 return $title->getLocalURL( $urlaction );
1683 /*static*/ function makeUrl ( $name, $urlaction='' ) {
1684 $title = Title::newFromText( $name );
1685 $this->checkTitle($title, $name);
1686 return $title->getLocalURL( $urlaction );
1688 # this can be passed the NS number as defined in Language.php
1689 /*static*/ function makeNSUrl( $name, $urlaction='', $namespace=0 ) {
1690 $title = Title::makeTitle( $namespace, $name );
1691 $this->checkTitle($title, $name);
1692 return $title->getLocalURL( $urlaction );
1695 /* these return an array with the 'href' and boolean 'exists' */
1696 /*static*/ function makeUrlDetails ( $name, $urlaction='' ) {
1697 $title = Title::newFromText( $name );
1698 $this->checkTitle($title, $name);
1699 return array(
1700 'href' => $title->getLocalURL( $urlaction ),
1701 'exists' => $title->getArticleID() != 0?true:false
1704 /*static*/ function makeTalkUrlDetails ( $name, $urlaction='' ) {
1705 $title = Title::newFromText( $name );
1706 $title = $title->getTalkPage();
1707 $this->checkTitle($title, $name);
1708 return array(
1709 'href' => $title->getLocalURL( $urlaction ),
1710 'exists' => $title->getArticleID() != 0?true:false
1713 /*static*/ function makeArticleUrlDetails ( $name, $urlaction='' ) {
1714 $title = Title::newFromText( $name );
1715 $title= $title->getSubjectPage();
1716 $this->checkTitle($title, $name);
1717 return array(
1718 'href' => $title->getLocalURL( $urlaction ),
1719 'exists' => $title->getArticleID() != 0?true:false
1722 /*static*/ function makeI18nUrlDetails ( $name, $urlaction='' ) {
1723 $title = Title::newFromText( wfMsg($name) );
1724 $this->checkTitle($title, $name);
1725 return array(
1726 'href' => $title->getLocalURL( $urlaction ),
1727 'exists' => $title->getArticleID() != 0?true:false
1731 # make sure we have some title to operate on
1732 /*static*/ function checkTitle ( &$title, &$name ) {
1733 if(!is_object($title)) {
1734 $title = Title::newFromText( $name );
1735 if(!is_object($title)) {
1736 $title = Title::newFromText( '--error: link target missing--' );
1741 function fnamePart( $url )
1743 $basename = strrchr( $url, '/' );
1744 if ( false === $basename ) {
1745 $basename = $url;
1746 } else {
1747 $basename = substr( $basename, 1 );
1749 return htmlspecialchars( $basename );
1752 function makeImage( $url, $alt = '' )
1754 global $wgOut;
1756 if ( '' == $alt ) {
1757 $alt = $this->fnamePart( $url );
1759 $s = '<img src="'.$url.'" alt="'.$alt.'" />';
1760 return $s;
1763 function makeImageLink( $name, $url, $alt = '' ) {
1764 $nt = Title::makeTitle( Namespace::getImage(), $name );
1765 return $this->makeImageLinkObj( $nt, $alt );
1768 function makeImageLinkObj( $nt, $alt = '' ) {
1769 global $wgLang, $wgUseImageResize;
1770 $img = Image::newFromTitle( $nt );
1771 $url = $img->getURL();
1773 $align = '';
1774 $prefix = $postfix = '';
1776 if ( $wgUseImageResize ) {
1777 # Check if the alt text is of the form "options|alt text"
1778 # Options are:
1779 # * thumbnail make a thumbnail with enlarge-icon and caption, alignment depends on lang
1780 # * left no resizing, just left align. label is used for alt= only
1781 # * right same, but right aligned
1782 # * none same, but not aligned
1783 # * ___px scale to ___ pixels width, no aligning. e.g. use in taxobox
1784 # * center center the image
1785 # * framed Keep original image size, no magnify-button.
1787 $part = explode( '|', $alt);
1789 $mwThumb =& MagicWord::get( MAG_IMG_THUMBNAIL );
1790 $mwLeft =& MagicWord::get( MAG_IMG_LEFT );
1791 $mwRight =& MagicWord::get( MAG_IMG_RIGHT );
1792 $mwNone =& MagicWord::get( MAG_IMG_NONE );
1793 $mwWidth =& MagicWord::get( MAG_IMG_WIDTH );
1794 $mwCenter =& MagicWord::get( MAG_IMG_CENTER );
1795 $mwFramed =& MagicWord::get( MAG_IMG_FRAMED );
1796 $alt = $part[count($part)-1];
1798 $height = $framed = $thumb = false;
1799 $manual_thumb = "" ;
1801 foreach( $part as $key => $val ) {
1802 $val_parts = explode ( "=" , $val , 2 ) ;
1803 $left_part = array_shift ( $val_parts ) ;
1804 if ( ! is_null( $mwThumb->matchVariableStartToEnd($val) ) ) {
1805 $thumb=true;
1806 } elseif ( count ( $val_parts ) == 1 && ! is_null( $mwThumb->matchVariableStartToEnd($left_part) ) ) {
1807 # use manually specified thumbnail
1808 $thumb=true;
1809 $manual_thumb = array_shift ( $val_parts ) ;
1810 } elseif ( ! is_null( $mwRight->matchVariableStartToEnd($val) ) ) {
1811 # remember to set an alignment, don't render immediately
1812 $align = 'right';
1813 } elseif ( ! is_null( $mwLeft->matchVariableStartToEnd($val) ) ) {
1814 # remember to set an alignment, don't render immediately
1815 $align = 'left';
1816 } elseif ( ! is_null( $mwCenter->matchVariableStartToEnd($val) ) ) {
1817 # remember to set an alignment, don't render immediately
1818 $align = 'center';
1819 } elseif ( ! is_null( $mwNone->matchVariableStartToEnd($val) ) ) {
1820 # remember to set an alignment, don't render immediately
1821 $align = 'none';
1822 } elseif ( ! is_null( $match = $mwWidth->matchVariableStartToEnd($val) ) ) {
1823 # $match is the image width in pixels
1824 if ( preg_match( '/^([0-9]*)x([0-9]*)$/', $match, $m ) ) {
1825 $width = intval( $m[1] );
1826 $height = intval( $m[2] );
1827 } else {
1828 $width = intval($match);
1830 } elseif ( ! is_null( $mwFramed->matchVariableStartToEnd($val) ) ) {
1831 $framed=true;
1834 if ( 'center' == $align )
1836 $prefix = '<span style="text-align: center">';
1837 $postfix = '</span>';
1838 $align = 'none';
1841 if ( $thumb || $framed ) {
1843 # Create a thumbnail. Alignment depends on language
1844 # writing direction, # right aligned for left-to-right-
1845 # languages ("Western languages"), left-aligned
1846 # for right-to-left-languages ("Semitic languages")
1848 # If thumbnail width has not been provided, it is set
1849 # here to 180 pixels
1850 if ( $align == '' ) {
1851 $align = $wgLang->isRTL() ? 'left' : 'right';
1853 if ( ! isset($width) ) {
1854 $width = 180;
1856 return $prefix.$this->makeThumbLinkObj( $img, $alt, $align, $width, $height, $framed, $manual_thumb ).$postfix;
1858 } elseif ( isset($width) ) {
1860 # Create a resized image, without the additional thumbnail
1861 # features
1863 if ( ( ! $height === false )
1864 && ( $img->getHeight() * $width / $img->getWidth() > $height ) ) {
1865 print "height=$height<br>\nimg->getHeight() = ".$img->getHeight()."<br>\n";
1866 print 'rescaling by factor '. $height / $img->getHeight() . "<br>\n";
1867 $width = $img->getWidth() * $height / $img->getHeight();
1869 if ( '' == $manual_thumb ) $url = $img->createThumb( $width );
1871 } # endif $wgUseImageResize
1873 if ( empty( $alt ) ) {
1874 $alt = preg_replace( '/\.(.+?)^/', '', $img->getName() );
1876 $alt = htmlspecialchars( $alt );
1878 $u = $nt->escapeLocalURL();
1879 if ( $url == '' )
1881 $s = wfMsg( 'missingimage', $img->getName() );
1882 $s .= "<br>{$alt}<br>{$url}<br>\n";
1883 } else {
1884 $s = '<a href="'.$u.'" class="image" title="'.$alt.'">' .
1885 '<img src="'.$url.'" alt="'.$alt.'" /></a>';
1887 if ( '' != $align ) {
1888 $s = "<div class=\"float{$align}\"><span>{$s}</span></div>";
1890 return str_replace("\n", ' ',$prefix.$s.$postfix);
1893 # Make HTML for a thumbnail including image, border and caption
1894 # $img is an Image object
1895 function makeThumbLinkObj( $img, $label = '', $align = 'right', $boxwidth = 180, $boxheight=false, $framed=false , $manual_thumb = "" ) {
1896 global $wgStylePath, $wgLang;
1897 # $image = Title::makeTitle( Namespace::getImage(), $name );
1898 $url = $img->getURL();
1900 #$label = htmlspecialchars( $label );
1901 $alt = preg_replace( '/<[^>]*>/', '', $label);
1902 $alt = htmlspecialchars( $alt );
1904 $width = $height = 0;
1905 if ( $img->exists() )
1907 $width = $img->getWidth();
1908 $height = $img->getHeight();
1910 if ( 0 == $width || 0 == $height )
1912 $width = $height = 200;
1914 if ( $boxwidth == 0 )
1916 $boxwidth = 200;
1918 if ( $framed )
1920 // Use image dimensions, don't scale
1921 $boxwidth = $width;
1922 $oboxwidth = $boxwidth + 2;
1923 $boxheight = $height;
1924 $thumbUrl = $url;
1925 } else {
1926 $h = intval( $height/($width/$boxwidth) );
1927 $oboxwidth = $boxwidth + 2;
1928 if ( ( ! $boxheight === false ) && ( $h > $boxheight ) )
1930 $boxwidth *= $boxheight/$h;
1931 } else {
1932 $boxheight = $h;
1934 if ( '' == $manual_thumb ) $thumbUrl = $img->createThumb( $boxwidth );
1937 if ( $manual_thumb != '' ) # Use manually specified thumbnail
1939 $manual_title = Title::makeTitle( Namespace::getImage(), $manual_thumb ); #new Title ( $manual_thumb ) ;
1940 $manual_img = Image::newFromTitle( $manual_title );
1941 $thumbUrl = $manual_img->getURL();
1942 if ( $manual_img->exists() )
1944 $width = $manual_img->getWidth();
1945 $height = $manual_img->getHeight();
1946 $boxwidth = $width ;
1947 $boxheight = $height ;
1948 $oboxwidth = $boxwidth + 2 ;
1952 $u = $img->getEscapeLocalURL();
1954 $more = htmlspecialchars( wfMsg( 'thumbnail-more' ) );
1955 $magnifyalign = $wgLang->isRTL() ? 'left' : 'right';
1956 $textalign = $wgLang->isRTL() ? ' style="text-align:right"' : '';
1958 $s = "<div class=\"thumb t{$align}\"><div style=\"width:{$oboxwidth}px;\">";
1959 if ( $thumbUrl == '' ) {
1960 $s .= wfMsg( 'missingimage', $img->getName() );
1961 $zoomicon = '';
1962 } else {
1963 $s .= '<a href="'.$u.'" class="internal" title="'.$alt.'">'.
1964 '<img src="'.$thumbUrl.'" alt="'.$alt.'" ' .
1965 'width="'.$boxwidth.'" height="'.$boxheight.'" /></a>';
1966 if ( $framed ) {
1967 $zoomicon="";
1968 } else {
1969 $zoomicon = '<div class="magnify" style="float:'.$magnifyalign.'">'.
1970 '<a href="'.$u.'" class="internal" title="'.$more.'">'.
1971 '<img src="'.$wgStylePath.'/images/magnify-clip.png" ' .
1972 'width="15" height="11" alt="'.$more.'" /></a></div>';
1975 $s .= ' <div class="thumbcaption" '.$textalign.'>'.$zoomicon.$label."</div></div></div>";
1976 return str_replace("\n", ' ', $s);
1979 function makeMediaLink( $name, $url, $alt = "" ) {
1980 $nt = Title::makeTitle( Namespace::getMedia(), $name );
1981 return $this->makeMediaLinkObj( $nt, $alt );
1984 function makeMediaLinkObj( $nt, $alt = "" )
1986 if ( ! isset( $nt ) )
1988 ### HOTFIX. Instead of breaking, return empty string.
1989 $s = $alt;
1990 } else {
1991 $name = $nt->getDBKey();
1992 $url = Image::wfImageUrl( $name );
1993 if ( empty( $alt ) ) {
1994 $alt = preg_replace( '/\.(.+?)^/', '', $name );
1997 $u = htmlspecialchars( $url );
1998 $s = "<a href=\"{$u}\" class='internal' title=\"{$alt}\">{$alt}</a>";
2000 return $s;
2003 function specialLink( $name, $key = "" )
2005 global $wgLang;
2007 if ( '' == $key ) { $key = strtolower( $name ); }
2008 $pn = $wgLang->ucfirst( $name );
2009 return $this->makeKnownLink( $wgLang->specialPage( $pn ),
2010 wfMsg( $key ) );
2013 function makeExternalLink( $url, $text, $escape = true ) {
2014 $style = $this->getExternalLinkAttributes( $url, $text );
2015 $url = htmlspecialchars( $url );
2016 if( $escape ) {
2017 $text = htmlspecialchars( $text );
2019 return '<a href="'.$url.'"'.$style.'>'.$text.'</a>';
2022 # Called by history lists and recent changes
2025 # Returns text for the start of the tabular part of RC
2026 function beginRecentChangesList()
2028 $this->rc_cache = array() ;
2029 $this->rcMoveIndex = 0;
2030 $this->rcCacheIndex = 0 ;
2031 $this->lastdate = '';
2032 $this->rclistOpen = false;
2033 return '';
2036 function beginImageHistoryList()
2038 $s = "\n<h2>" . wfMsg( 'imghistory' ) . "</h2>\n" .
2039 "<p>" . wfMsg( 'imghistlegend' ) . "</p>\n".'<ul class="special">';
2040 return $s;
2043 # Returns text for the end of RC
2044 # If enhanced RC is in use, returns pretty much all the text
2045 function endRecentChangesList()
2047 $s = $this->recentChangesBlock() ;
2048 if( $this->rclistOpen ) {
2049 $s .= "</ul>\n";
2051 return $s;
2054 # Enhanced RC ungrouped line
2055 function recentChangesBlockLine ( $rcObj )
2057 global $wgStylePath, $wgLang ;
2059 # Get rc_xxxx variables
2060 extract( $rcObj->mAttribs ) ;
2061 $curIdEq = 'curid='.$rc_cur_id;
2063 # Spacer image
2064 $r = '' ;
2066 $r .= '<img src="'.$wgStylePath.'/images/Arr_.png" width="12" height="12" border="0" />' ;
2067 $r .= '<tt>' ;
2069 if ( $rc_type == RC_MOVE || $rc_type == RC_MOVE_OVER_REDIRECT ) {
2070 $r .= '&nbsp;&nbsp;';
2071 } else {
2072 # M & N (minor & new)
2073 $M = wfMsg( 'minoreditletter' );
2074 $N = wfMsg( 'newpageletter' );
2076 if ( $rc_type == RC_NEW ) {
2077 $r .= $N ;
2078 } else {
2079 $r .= '&nbsp;' ;
2081 if ( $rc_minor ) {
2082 $r .= $M ;
2083 } else {
2084 $r .= '&nbsp;' ;
2088 # Timestamp
2089 $r .= ' '.$rcObj->timestamp.' ' ;
2090 $r .= '</tt>' ;
2092 # Article link
2093 $link = $rcObj->link ;
2094 if ( $rcObj->watched ) $link = '<strong>'.$link.'</strong>' ;
2095 $r .= $link ;
2097 # Diff
2098 $r .= ' (' ;
2099 $r .= $rcObj->difflink ;
2100 $r .= '; ' ;
2102 # Hist
2103 $r .= $this->makeKnownLinkObj( $rcObj->getTitle(), wfMsg( 'hist' ), $curIdEq.'&action=history' );
2105 # User/talk
2106 $r .= ') . . '.$rcObj->userlink ;
2107 $r .= $rcObj->usertalklink ;
2109 # Comment
2110 if ( $rc_comment != '' && $rc_type != RC_MOVE && $rc_type != RC_MOVE_OVER_REDIRECT ) {
2111 $rc_comment=$this->formatComment($rc_comment);
2112 $r .= $wgLang->emphasize( ' ('.$rc_comment.')' );
2115 $r .= "<br />\n" ;
2116 return $r ;
2119 # Enhanced RC group
2120 function recentChangesBlockGroup ( $block )
2122 global $wgStylePath, $wgLang ;
2124 $r = '' ;
2125 $M = wfMsg( 'minoreditletter' );
2126 $N = wfMsg( 'newpageletter' );
2128 # Collate list of users
2129 $isnew = false ;
2130 $userlinks = array () ;
2131 foreach ( $block AS $rcObj ) {
2132 $oldid = $rcObj->mAttribs['rc_last_oldid'];
2133 if ( $rcObj->mAttribs['rc_new'] ) $isnew = true ;
2134 $u = $rcObj->userlink ;
2135 if ( !isset ( $userlinks[$u] ) ) $userlinks[$u] = 0 ;
2136 $userlinks[$u]++ ;
2139 # Sort the list and convert to text
2140 krsort ( $userlinks ) ;
2141 asort ( $userlinks ) ;
2142 $users = array () ;
2143 foreach ( $userlinks as $userlink => $count) {
2144 $text = $userlink ;
2145 if ( $count > 1 ) $text .= " ({$count}&times;)" ;
2146 array_push ( $users , $text ) ;
2148 $users = ' <font size="-1">['.implode('; ',$users).']</font>' ;
2150 # Arrow
2151 $rci = 'RCI'.$this->rcCacheIndex ;
2152 $rcl = 'RCL'.$this->rcCacheIndex ;
2153 $rcm = 'RCM'.$this->rcCacheIndex ;
2154 $toggleLink = "javascript:toggleVisibility('$rci','$rcm','$rcl')" ;
2155 $arrowdir = $wgLang->isRTL() ? 'l' : 'r';
2156 $tl = '<span id="'.$rcm.'"><a href="'.$toggleLink.'"><img src="'.$wgStylePath.'/images/Arr_'.$arrowdir.'.png" width="12" height="12" /></a></span>' ;
2157 $tl .= '<span id="'.$rcl.'" style="display:none"><a href="'.$toggleLink.'"><img src="'.$wgStylePath.'/images/Arr_d.png" width="12" height="12" /></a></span>' ;
2158 $r .= $tl ;
2160 # Main line
2161 # M/N
2162 $r .= '<tt>' ;
2163 if ( $isnew ) $r .= $N ;
2164 else $r .= '&nbsp;' ;
2165 $r .= '&nbsp;' ; # Minor
2167 # Timestamp
2168 $r .= ' '.$block[0]->timestamp.' ' ;
2169 $r .= '</tt>' ;
2171 # Article link
2172 $link = $block[0]->link ;
2173 if ( $block[0]->watched ) $link = '<strong>'.$link.'</strong>' ;
2174 $r .= $link ;
2176 $curIdEq = 'curid=' . $block[0]->mAttribs['rc_cur_id'];
2177 if ( $block[0]->mAttribs['rc_type'] != RC_LOG ) {
2178 # Changes
2179 $r .= ' ('.count($block).' ' ;
2180 if ( $isnew ) $r .= wfMsg('changes');
2181 else $r .= $this->makeKnownLinkObj( $block[0]->getTitle() , wfMsg('changes') ,
2182 $curIdEq.'&diff=0&oldid='.$oldid ) ;
2183 $r .= '; ' ;
2185 # History
2186 $r .= $this->makeKnownLinkObj( $block[0]->getTitle(), wfMsg( 'history' ), $curIdEq.'&action=history' );
2187 $r .= ')' ;
2190 $r .= $users ;
2191 $r .= "<br />\n" ;
2193 # Sub-entries
2194 $r .= '<div id="'.$rci.'" style="display:none">' ;
2195 foreach ( $block AS $rcObj ) {
2196 # Get rc_xxxx variables
2197 extract( $rcObj->mAttribs );
2199 $r .= '<img src="'.$wgStylePath.'/images/Arr_.png" width="12" height="12" />';
2200 $r .= '<tt>&nbsp; &nbsp; &nbsp; &nbsp;' ;
2201 if ( $rc_new ) $r .= $N ;
2202 else $r .= '&nbsp;' ;
2203 if ( $rc_minor ) $r .= $M ;
2204 else $r .= '&nbsp;' ;
2205 $r .= '</tt>' ;
2207 $o = '' ;
2208 if ( $rc_last_oldid != 0 ) {
2209 $o = 'oldid='.$rc_last_oldid ;
2211 if ( $rc_type == RC_LOG ) {
2212 $link = $rcObj->timestamp ;
2213 } else {
2214 $link = $this->makeKnownLinkObj( $rcObj->getTitle(), $rcObj->timestamp , "{$curIdEq}&$o" ) ;
2216 $link = '<tt>'.$link.'</tt>' ;
2218 $r .= $link ;
2219 $r .= ' (' ;
2220 $r .= $rcObj->curlink ;
2221 $r .= '; ' ;
2222 $r .= $rcObj->lastlink ;
2223 $r .= ') . . '.$rcObj->userlink ;
2224 $r .= $rcObj->usertalklink ;
2225 if ( $rc_comment != '' ) {
2226 $rc_comment=$this->formatComment($rc_comment);
2227 $r .= $wgLang->emphasize( ' ('.$rc_comment.')' ) ;
2229 $r .= "<br />\n" ;
2231 $r .= "</div>\n" ;
2233 $this->rcCacheIndex++ ;
2234 return $r ;
2237 # If enhanced RC is in use, this function takes the previously cached
2238 # RC lines, arranges them, and outputs the HTML
2239 function recentChangesBlock ()
2241 global $wgStylePath ;
2242 if ( count ( $this->rc_cache ) == 0 ) return '' ;
2243 $blockOut = '';
2244 foreach ( $this->rc_cache AS $secureName => $block ) {
2245 if ( count ( $block ) < 2 ) {
2246 $blockOut .= $this->recentChangesBlockLine ( array_shift ( $block ) ) ;
2247 } else {
2248 $blockOut .= $this->recentChangesBlockGroup ( $block ) ;
2252 return '<div>'.$blockOut.'</div>' ;
2255 # Called in a loop over all displayed RC entries
2256 # Either returns the line, or caches it for later use
2257 function recentChangesLine( &$rc, $watched = false )
2259 global $wgUser ;
2260 $usenew = $wgUser->getOption( 'usenewrc' );
2261 if ( $usenew )
2262 $line = $this->recentChangesLineNew ( $rc, $watched ) ;
2263 else
2264 $line = $this->recentChangesLineOld ( $rc, $watched ) ;
2265 return $line ;
2268 function recentChangesLineOld( &$rc, $watched = false )
2270 global $wgTitle, $wgLang, $wgUser, $wgRCSeconds, $wgUseRCPatrol, $wgOnlySysopsCanPatrol;
2272 # Extract DB fields into local scope
2273 extract( $rc->mAttribs );
2274 $curIdEq = 'curid=' . $rc_cur_id;
2276 # Make date header if necessary
2277 $date = $wgLang->date( $rc_timestamp, true);
2278 $s = '';
2279 if ( $date != $this->lastdate ) {
2280 if ( '' != $this->lastdate ) { $s .= "</ul>\n"; }
2281 $s .= "<h4>{$date}</h4>\n<ul class='special'>";
2282 $this->lastdate = $date;
2283 $this->rclistOpen = true;
2286 # If this edit has not yet been patrolled, make it stick out
2287 $s .= ( ! $wgUseRCPatrol || $rc_patrolled ) ? '<li> ' : '<li class="not_patrolled"> ';
2289 if ( $rc_type == RC_MOVE || $rc_type == RC_MOVE_OVER_REDIRECT ) {
2290 # Diff
2291 $s .= '(' . wfMsg( 'diff' ) . ') (';
2292 # Hist
2293 $s .= $this->makeKnownLinkObj( $rc->getMovedToTitle(), wfMsg( 'hist' ), 'action=history' ) .
2294 ') . . ';
2296 # "[[x]] moved to [[y]]"
2297 $msg = ( $rc_type == RC_MOVE ) ? '1movedto2' : '1movedto2_redir';
2298 $s .= wfMsg( $msg, $this->makeKnownLinkObj( $rc->getTitle(), '', 'redirect=no' ),
2299 $this->makeKnownLinkObj( $rc->getMovedToTitle(), '' ) );
2300 } else {
2301 # Diff link
2302 if ( $rc_type == RC_NEW || $rc_type == RC_LOG ) {
2303 $diffLink = wfMsg( 'diff' );
2304 } else {
2305 if ( $wgUseRCPatrol && $rc_patrolled == 0 && $wgUser->getID() != 0 &&
2306 ( $wgUser->isSysop() || !$wgOnlySysopsCanPatrol ) )
2307 $rcidparam = "&rcid={$rc_id}";
2308 else
2309 $rcidparam = "";
2310 $diffLink = $this->makeKnownLinkObj( $rc->getTitle(), wfMsg( 'diff' ),
2311 "{$curIdEq}&diff={$rc_this_oldid}&oldid={$rc_last_oldid}{$rcidparam}",
2312 '', '', ' tabindex="'.$rc->counter.'"');
2314 $s .= '('.$diffLink.') (';
2316 # History link
2317 $s .= $this->makeKnownLinkObj( $rc->getTitle(), wfMsg( 'hist' ), $curIdEq.'&action=history' );
2318 $s .= ') . . ';
2320 # M and N (minor and new)
2321 if ( $rc_minor ) { $s .= ' <span class="minor">'.wfMsg( "minoreditletter" ).'</span>'; }
2322 if ( $rc_type == RC_NEW ) { $s .= '<span class="newpage">'.wfMsg( "newpageletter" ).'</span>'; }
2324 # Article link
2325 # If it's a new article, there is no diff link, but if it hasn't been
2326 # patrolled yet, we need to give users a way to do so
2327 if ( $wgUseRCPatrol && $rc_type == RC_NEW && $rc_patrolled == 0 &&
2328 $wgUser->getID() != 0 && ( $wgUser->isSysop() || !$wgOnlySysopsCanPatrol ) )
2329 $articleLink = $this->makeKnownLinkObj( $rc->getTitle(), '', "rcid={$rc_id}" );
2330 else
2331 $articleLink = $this->makeKnownLinkObj( $rc->getTitle(), '' );
2333 if ( $watched ) {
2334 $articleLink = '<strong>'.$articleLink.'</strong>';
2336 $s .= ' '.$articleLink;
2340 # Timestamp
2341 $s .= '; ' . $wgLang->time( $rc_timestamp, true, $wgRCSeconds ) . ' . . ';
2343 # User link (or contributions for unregistered users)
2344 if ( 0 == $rc_user ) {
2345 $userLink = $this->makeKnownLink( $wgLang->specialPage( 'Contributions' ),
2346 $rc_user_text, 'target=' . $rc_user_text );
2347 } else {
2348 $userLink = $this->makeLink( $wgLang->getNsText( NS_USER ) . ':'.$rc_user_text, $rc_user_text );
2350 $s .= $userLink;
2352 # User talk link
2353 $talkname=$wgLang->getNsText(NS_TALK); # use the shorter name
2354 global $wgDisableAnonTalk;
2355 if( 0 == $rc_user && $wgDisableAnonTalk ) {
2356 $userTalkLink = '';
2357 } else {
2358 $utns=$wgLang->getNsText(NS_USER_TALK);
2359 $userTalkLink= $this->makeLink($utns . ':'.$rc_user_text, $talkname );
2361 # Block link
2362 $blockLink='';
2363 if ( ( 0 == $rc_user ) && $wgUser->isSysop() ) {
2364 $blockLink = $this->makeKnownLink( $wgLang->specialPage(
2365 'Blockip' ), wfMsg( 'blocklink' ), 'ip='.$rc_user_text );
2368 if($blockLink) {
2369 if($userTalkLink) $userTalkLink .= ' | ';
2370 $userTalkLink .= $blockLink;
2372 if($userTalkLink) $s.=' ('.$userTalkLink.')';
2374 # Add comment
2375 if ( '' != $rc_comment && '*' != $rc_comment && $rc_type != RC_MOVE && $rc_type != RC_MOVE_OVER_REDIRECT ) {
2376 $rc_comment=$this->formatComment($rc_comment);
2377 $s .= $wgLang->emphasize(' (' . $rc_comment . ')');
2379 $s .= "</li>\n";
2381 return $s;
2384 function recentChangesLineNew( &$baseRC, $watched = false )
2386 global $wgTitle, $wgLang, $wgUser, $wgRCSeconds;
2388 # Create a specialised object
2389 $rc = RCCacheEntry::newFromParent( $baseRC ) ;
2391 # Extract fields from DB into the function scope (rc_xxxx variables)
2392 extract( $rc->mAttribs );
2393 $curIdEq = 'curid=' . $rc_cur_id;
2395 # If it's a new day, add the headline and flush the cache
2396 $date = $wgLang->date( $rc_timestamp, true);
2397 $ret = '';
2398 if ( $date != $this->lastdate ) {
2399 # Process current cache
2400 $ret = $this->recentChangesBlock () ;
2401 $this->rc_cache = array() ;
2402 $ret .= "<h4>{$date}</h4>\n";
2403 $this->lastdate = $date;
2406 # Make article link
2407 if ( $rc_type == RC_MOVE || $rc_type == RC_MOVE_OVER_REDIRECT ) {
2408 $msg = ( $rc_type == RC_MOVE ) ? "1movedto2" : "1movedto2_redir";
2409 $clink = wfMsg( $msg, $this->makeKnownLinkObj( $rc->getTitle(), '', 'redirect=no' ),
2410 $this->makeKnownLinkObj( $rc->getMovedToTitle(), '' ) );
2411 } else {
2412 $clink = $this->makeKnownLinkObj( $rc->getTitle(), '' ) ;
2415 $time = $wgLang->time( $rc_timestamp, true, $wgRCSeconds );
2416 $rc->watched = $watched ;
2417 $rc->link = $clink ;
2418 $rc->timestamp = $time;
2420 # Make "cur" and "diff" links
2421 if ( ( $rc_type == RC_NEW && $rc_this_oldid == 0 ) || $rc_type == RC_LOG || $rc_type == RC_MOVE || $rc_type == RC_MOVE_OVER_REDIRECT ) {
2422 $curLink = wfMsg( 'cur' );
2423 $diffLink = wfMsg( 'diff' );
2424 } else {
2425 $query = $curIdEq.'&diff=0&oldid='.$rc_this_oldid;
2426 $aprops = ' tabindex="'.$baseRC->counter.'"';
2427 $curLink = $this->makeKnownLinkObj( $rc->getTitle(), wfMsg( 'cur' ), $query, '' ,'' , $aprops );
2428 $diffLink = $this->makeKnownLinkObj( $rc->getTitle(), wfMsg( 'diff'), $query, '' ,'' , $aprops );
2431 # Make "last" link
2432 $titleObj = $rc->getTitle();
2433 if ( $rc_last_oldid == 0 || $rc_type == RC_LOG || $rc_type == RC_MOVE || $rc_type == RC_MOVE_OVER_REDIRECT ) {
2434 $lastLink = wfMsg( 'last' );
2435 } else {
2436 $lastLink = $this->makeKnownLinkObj( $rc->getTitle(), wfMsg( 'last' ),
2437 $curIdEq.'&diff='.$rc_this_oldid.'&oldid='.$rc_last_oldid );
2440 # Make user link (or user contributions for unregistered users)
2441 if ( $rc_user == 0 ) {
2442 $userLink = $this->makeKnownLink( $wgLang->specialPage( 'Contributions' ),
2443 $rc_user_text, 'target=' . $rc_user_text );
2444 } else {
2445 $userLink = $this->makeLink( $wgLang->getNsText(
2446 Namespace::getUser() ) . ':'.$rc_user_text, $rc_user_text );
2449 $rc->userlink = $userLink;
2450 $rc->lastlink = $lastLink;
2451 $rc->curlink = $curLink;
2452 $rc->difflink = $diffLink;
2454 # Make user talk link
2455 $utns=$wgLang->getNsText(NS_USER_TALK);
2456 $talkname=$wgLang->getNsText(NS_TALK); # use the shorter name
2457 $userTalkLink= $this->makeLink($utns . ':'.$rc_user_text, $talkname );
2459 global $wgDisableAnonTalk;
2460 if ( ( 0 == $rc_user ) && $wgUser->isSysop() ) {
2461 $blockLink = $this->makeKnownLink( $wgLang->specialPage(
2462 'Blockip' ), wfMsg( 'blocklink' ), 'ip='.$rc_user_text );
2463 if( $wgDisableAnonTalk )
2464 $rc->usertalklink = ' ('.$blockLink.')';
2465 else
2466 $rc->usertalklink = ' ('.$userTalkLink.' | '.$blockLink.')';
2467 } else {
2468 if( $wgDisableAnonTalk && ($rc_user == 0) )
2469 $rc->usertalklink = '';
2470 else
2471 $rc->usertalklink = ' ('.$userTalkLink.')';
2474 # Put accumulated information into the cache, for later display
2475 # Page moves go on their own line
2476 $title = $rc->getTitle();
2477 $secureName = $title->getPrefixedDBkey();
2478 if ( $rc_type == RC_MOVE || $rc_type == RC_MOVE_OVER_REDIRECT ) {
2479 # Use an @ character to prevent collision with page names
2480 $this->rc_cache['@@' . ($this->rcMoveIndex++)] = array($rc);
2481 } else {
2482 if ( !isset ( $this->rc_cache[$secureName] ) ) $this->rc_cache[$secureName] = array() ;
2483 array_push ( $this->rc_cache[$secureName] , $rc ) ;
2485 return $ret;
2488 function endImageHistoryList()
2490 $s = "</ul>\n";
2491 return $s;
2494 /* This function is called by all recent changes variants, by the page history,
2495 and by the user contributions list. It is responsible for formatting edit
2496 comments. It escapes any HTML in the comment, but adds some CSS to format
2497 auto-generated comments (from section editing) and formats [[wikilinks]].
2498 Main author: Erik Möller (moeller@scireview.de)
2500 function formatComment($comment)
2502 global $wgLang;
2503 $comment = htmlspecialchars( $comment );
2505 # The pattern for autogen comments is / * foo * /, which makes for
2506 # some nasty regex.
2507 # We look for all comments, match any text before and after the comment,
2508 # add a separator where needed and format the comment itself with CSS
2509 while (preg_match('/(.*)\/\*\s*(.*?)\s*\*\/(.*)/', $comment,$match)) {
2510 $pre=$match[1];
2511 $auto=$match[2];
2512 $post=$match[3];
2513 $sep='-';
2514 if($pre) { $auto = $sep.' '.$auto; }
2515 if($post) { $auto .= ' '.$sep; }
2516 $auto='<span class="autocomment">'.$auto.'</span>';
2517 $comment=$pre.$auto.$post;
2520 # format regular and media links - all other wiki formatting
2521 # is ignored
2522 $medians = $wgLang->getNsText(Namespace::getMedia()).':';
2523 while(preg_match('/\[\[(.*?)(\|(.*?))*\]\](.*)$/',$comment,$match)) {
2524 # Handle link renaming [[foo|text]] will show link as "text"
2525 if( "" != $match[3] ) {
2526 $text = $match[3];
2527 } else {
2528 $text = $match[1];
2530 if( preg_match( '/^' . $medians . '(.*)$/i', $match[1], $submatch ) ) {
2531 # Media link; trail not supported.
2532 $linkRegexp = '/\[\[(.*?)\]\]/';
2533 $thelink = $this->makeMediaLink( $submatch[1], "", $text );
2534 } else {
2535 # Other kind of link
2536 if( preg_match( wfMsg( "linktrail" ), $match[4], $submatch ) ) {
2537 $trail = $submatch[1];
2538 } else {
2539 $trail = "";
2541 $linkRegexp = '/\[\[(.*?)\]\]' . preg_quote( $trail, '/' ) . '/';
2542 $thelink = $this->makeLink( $match[1], $text, "", $trail );
2544 $comment = preg_replace( $linkRegexp, $thelink, $comment, 1 );
2546 return $comment;
2549 function imageHistoryLine( $iscur, $timestamp, $img, $user, $usertext, $size, $description )
2551 global $wgUser, $wgLang, $wgTitle;
2553 $datetime = $wgLang->timeanddate( $timestamp, true );
2554 $del = wfMsg( 'deleteimg' );
2555 $delall = wfMsg( 'deleteimgcompletely' );
2556 $cur = wfMsg( 'cur' );
2558 if ( $iscur ) {
2559 $url = Image::wfImageUrl( $img );
2560 $rlink = $cur;
2561 if ( $wgUser->isSysop() ) {
2562 $link = $wgTitle->escapeLocalURL( 'image=' . $wgTitle->getPartialURL() .
2563 '&action=delete' );
2564 $style = $this->getInternalLinkAttributes( $link, $delall );
2566 $dlink = '<a href="'.$link.'"'.$style.'>'.$delall.'</a>';
2567 } else {
2568 $dlink = $del;
2570 } else {
2571 $url = htmlspecialchars( wfImageArchiveUrl( $img ) );
2572 if( $wgUser->getID() != 0 && $wgTitle->userCanEdit() ) {
2573 $rlink = $this->makeKnownLink( $wgTitle->getPrefixedText(),
2574 wfMsg( 'revertimg' ), 'action=revert&oldimage=' .
2575 urlencode( $img ) );
2576 $dlink = $this->makeKnownLink( $wgTitle->getPrefixedText(),
2577 $del, 'action=delete&oldimage=' . urlencode( $img ) );
2578 } else {
2579 # Having live active links for non-logged in users
2580 # means that bots and spiders crawling our site can
2581 # inadvertently change content. Baaaad idea.
2582 $rlink = wfMsg( 'revertimg' );
2583 $dlink = $del;
2586 if ( 0 == $user ) {
2587 $userlink = $usertext;
2588 } else {
2589 $userlink = $this->makeLink( $wgLang->getNsText( Namespace::getUser() ) .
2590 ':'.$usertext, $usertext );
2592 $nbytes = wfMsg( 'nbytes', $size );
2593 $style = $this->getInternalLinkAttributes( $url, $datetime );
2595 $s = "<li> ({$dlink}) ({$rlink}) <a href=\"{$url}\"{$style}>{$datetime}</a>"
2596 . " . . {$userlink} ({$nbytes})";
2598 if ( '' != $description && '*' != $description ) {
2599 $sk=$wgUser->getSkin();
2600 $s .= $wgLang->emphasize(' (' . $sk->formatComment($description) . ')');
2602 $s .= "</li>\n";
2603 return $s;
2606 function tocIndent($level) {
2607 return str_repeat( '<div class="tocindent">'."\n", $level>0 ? $level : 0 );
2610 function tocUnindent($level) {
2611 return str_repeat( "</div>\n", $level>0 ? $level : 0 );
2614 # parameter level defines if we are on an indentation level
2615 function tocLine( $anchor, $tocline, $level ) {
2616 $link = '<a href="#'.$anchor.'">'.$tocline.'</a><br />';
2617 if($level) {
2618 return $link."\n";
2619 } else {
2620 return '<div class="tocline">'.$link."</div>\n";
2625 function tocTable($toc) {
2626 # note to CSS fanatics: putting this in a div does not work -- div won't auto-expand
2627 # try min-width & co when somebody gets a chance
2628 $hideline = ' <script type="text/javascript">showTocToggle("' . addslashes( wfMsg('showtoc') ) . '","' . addslashes( wfMsg('hidetoc') ) . '")</script>';
2629 return
2630 '<table border="0" id="toc"><tr id="toctitle"><td align="center">'."\n".
2631 '<b>'.wfMsg('toc').'</b>' .
2632 $hideline .
2633 '</td></tr><tr id="tocinside"><td>'."\n".
2634 $toc."</td></tr></table>\n";
2637 # These two do not check for permissions: check $wgTitle->userCanEdit before calling them
2638 function editSectionScript( $section, $head ) {
2639 global $wgTitle, $wgRequest;
2640 if( $wgRequest->getInt( 'oldid' ) && ( $wgRequest->getVal( 'diff' ) != '0' ) ) {
2641 return $head;
2643 $url = $wgTitle->escapeLocalURL( 'action=edit&section='.$section );
2644 return '<span oncontextmenu=\'document.location="'.$url.'";return false;\'>'.$head.'</span>';
2647 function editSectionLink( $section ) {
2648 global $wgRequest;
2649 global $wgTitle, $wgUser, $wgLang;
2651 if( $wgRequest->getInt( 'oldid' ) && ( $wgRequest->getVal( 'diff' ) != '0' ) ) {
2652 # Section edit links would be out of sync on an old page.
2653 # But, if we're diffing to the current page, they'll be
2654 # correct.
2655 return '';
2658 $editurl = '&section='.$section;
2659 $url = $this->makeKnownLink($wgTitle->getPrefixedText(),wfMsg('editsection'),'action=edit'.$editurl);
2661 if( $wgLang->isRTL() ) {
2662 $farside = 'left';
2663 $nearside = 'right';
2664 } else {
2665 $farside = 'right';
2666 $nearside = 'left';
2668 return "<div class=\"editsection\" style=\"float:$farside;margin-$nearside:5px;\">[".$url."]</div>";
2672 // This function is called by EditPage.php and shows a bulletin board style
2673 // toolbar for common editing functions. It can be disabled in the user preferences.
2674 // The necsesary JavaScript code can be found in style/wikibits.js.
2675 function getEditToolbar() {
2676 global $wgStylePath, $wgLang, $wgMimeType;
2678 // toolarray an array of arrays which each include the filename of
2679 // the button image (without path), the opening tag, the closing tag,
2680 // and optionally a sample text that is inserted between the two when no
2681 // selection is highlighted.
2682 // The tip text is shown when the user moves the mouse over the button.
2684 // Already here are accesskeys (key), which are not used yet until someone
2685 // can figure out a way to make them work in IE. However, we should make
2686 // sure these keys are not defined on the edit page.
2687 $toolarray=array(
2688 array( 'image'=>'button_bold.png',
2689 'open'=>"\'\'\'",
2690 'close'=>"\'\'\'",
2691 'sample'=>wfMsg('bold_sample'),
2692 'tip'=>wfMsg('bold_tip'),
2693 'key'=>'B'
2695 array( "image"=>"button_italic.png",
2696 "open"=>"\'\'",
2697 "close"=>"\'\'",
2698 "sample"=>wfMsg("italic_sample"),
2699 "tip"=>wfMsg("italic_tip"),
2700 "key"=>"I"
2702 array( "image"=>"button_link.png",
2703 "open"=>"[[",
2704 "close"=>"]]",
2705 "sample"=>wfMsg("link_sample"),
2706 "tip"=>wfMsg("link_tip"),
2707 "key"=>"L"
2709 array( "image"=>"button_extlink.png",
2710 "open"=>"[",
2711 "close"=>"]",
2712 "sample"=>wfMsg("extlink_sample"),
2713 "tip"=>wfMsg("extlink_tip"),
2714 "key"=>"X"
2716 array( "image"=>"button_headline.png",
2717 "open"=>"\\n== ",
2718 "close"=>" ==\\n",
2719 "sample"=>wfMsg("headline_sample"),
2720 "tip"=>wfMsg("headline_tip"),
2721 "key"=>"H"
2723 array( "image"=>"button_image.png",
2724 "open"=>"[[".$wgLang->getNsText(NS_IMAGE).":",
2725 "close"=>"]]",
2726 "sample"=>wfMsg("image_sample"),
2727 "tip"=>wfMsg("image_tip"),
2728 "key"=>"D"
2730 array( "image"=>"button_media.png",
2731 "open"=>"[[".$wgLang->getNsText(NS_MEDIA).":",
2732 "close"=>"]]",
2733 "sample"=>wfMsg("media_sample"),
2734 "tip"=>wfMsg("media_tip"),
2735 "key"=>"M"
2737 array( "image"=>"button_math.png",
2738 "open"=>"\\<math\\>",
2739 "close"=>"\\</math\\>",
2740 "sample"=>wfMsg("math_sample"),
2741 "tip"=>wfMsg("math_tip"),
2742 "key"=>"C"
2744 array( "image"=>"button_nowiki.png",
2745 "open"=>"\\<nowiki\\>",
2746 "close"=>"\\</nowiki\\>",
2747 "sample"=>wfMsg("nowiki_sample"),
2748 "tip"=>wfMsg("nowiki_tip"),
2749 "key"=>"N"
2751 array( "image"=>"button_sig.png",
2752 "open"=>"--~~~~",
2753 "close"=>"",
2754 "sample"=>"",
2755 "tip"=>wfMsg("sig_tip"),
2756 "key"=>"Y"
2758 array( "image"=>"button_hr.png",
2759 "open"=>"\\n----\\n",
2760 "close"=>"",
2761 "sample"=>"",
2762 "tip"=>wfMsg("hr_tip"),
2763 "key"=>"R"
2766 $toolbar ="<script type='text/javascript'>\n/*<![CDATA[*/\n";
2768 $toolbar.="document.writeln(\"<div id='toolbar'>\");\n";
2769 foreach($toolarray as $tool) {
2771 $image=$wgStylePath.'/images/'.$tool['image'];
2772 $open=$tool['open'];
2773 $close=$tool['close'];
2774 $sample = addslashes( $tool['sample'] );
2776 // Note that we use the tip both for the ALT tag and the TITLE tag of the image.
2777 // Older browsers show a "speedtip" type message only for ALT.
2778 // Ideally these should be different, realistically they
2779 // probably don't need to be.
2780 $tip = addslashes( $tool['tip'] );
2782 #$key = $tool["key"];
2784 $toolbar.="addButton('$image','$tip','$open','$close','$sample');\n";
2787 $toolbar.="addInfobox('" . addslashes( wfMsg( "infobox" ) ) . "','" . addslashes(wfMsg("infobox_alert")) . "');\n";
2788 $toolbar.="document.writeln(\"</div>\");\n";
2790 $toolbar.="/*]]>*/\n</script>";
2791 return $toolbar;
2794 /* public */ function suppressUrlExpansion() {
2795 return false;