Fix http://bugzilla.wikipedia.org/show_bug.cgi?id=511 . Stop showing whatlinkshere...
[mediawiki.git] / includes / Skin.php
blob262c497f4ea81b0388a4a87bf822932fdf3fe416
1 <?php
3 /**
5 * @package MediaWiki
6 */
8 /**
9 * This is not a valid entry point, perform no further processing unless MEDIAWIKI is defined
11 if( defined( "MEDIAWIKI" ) ) {
13 # See skin.doc
14 require_once( 'Image.php' );
16 # These are the INTERNAL names, which get mapped directly to class names and
17 # file names in ./skins/. For display purposes, the Language class has
18 # internationalized names
21 $wgValidSkinNames = array(
22 'standard' => 'Standard',
23 'nostalgia' => 'Nostalgia',
24 'cologneblue' => 'CologneBlue'
26 if( $wgUsePHPTal ) {
27 #$wgValidSkinNames[] = 'PHPTal';
28 #$wgValidSkinNames['davinci'] = 'DaVinci';
29 #$wgValidSkinNames['mono'] = 'Mono';
30 #$wgValidSkinNames['monobookminimal'] = 'MonoBookMinimal';
31 $wgValidSkinNames['monobook'] = 'MonoBook';
32 $wgValidSkinNames['myskin'] = 'MySkin';
33 $wgValidSkinNames['chick'] = 'Chick';
37 # Get a list of all skins available in /skins/
38 # Build using the regular expression '^(.*).php$'
39 # Array keys are all lower case, array value keep the case used by filename
42 $skinDir = dir($IP.'/skins');
44 # while code from www.php.net
45 while (false !== ($file = $skinDir->read())) {
46 if(preg_match('/^(.*).php$/',$file, $matches)) {
47 $aSkin = $matches[1];
48 $wgValidSkinNames[strtolower($aSkin)] = $aSkin;
51 $skinDir->close();
52 unset($matches);
54 require_once( 'RecentChange.php' );
56 /**
57 * @todo document
58 * @package MediaWiki
60 class RCCacheEntry extends RecentChange
62 var $secureName, $link;
63 var $curlink , $difflink, $lastlink , $usertalklink , $versionlink ;
64 var $userlink, $timestamp, $watched;
66 function newFromParent( $rc )
68 $rc2 = new RCCacheEntry;
69 $rc2->mAttribs = $rc->mAttribs;
70 $rc2->mExtra = $rc->mExtra;
71 return $rc2;
73 } ;
76 /**
77 * The main skin class that provide methods and properties for all other skins
78 * including PHPTal skins.
79 * This base class is also the "Standard" skin.
80 * @package MediaWiki
82 class Skin {
83 /**#@+
84 * @access private
86 var $lastdate, $lastline;
87 var $linktrail ; # linktrail regexp
88 var $rc_cache ; # Cache for Enhanced Recent Changes
89 var $rcCacheIndex ; # Recent Changes Cache Counter for visibility toggle
90 var $rcMoveIndex;
91 var $postParseLinkColour = true;
92 /**#@-*/
94 function Skin() {
95 global $wgUseOldExistenceCheck;
96 $postParseLinkColour = !$wgUseOldExistenceCheck;
97 $this->linktrail = wfMsg('linktrail');
100 function getSkinNames() {
101 global $wgValidSkinNames;
102 return $wgValidSkinNames;
105 function getStylesheet() {
106 return 'common/wikistandard.css';
109 function getSkinName() {
110 return 'standard';
114 * Get/set accessor for delayed link colouring
116 function postParseLinkColour( $setting = NULL ) {
117 return wfSetVar( $this->postParseLinkColour, $setting );
120 function qbSetting() {
121 global $wgOut, $wgUser;
123 if ( $wgOut->isQuickbarSuppressed() ) { return 0; }
124 $q = $wgUser->getOption( 'quickbar' );
125 if ( '' == $q ) { $q = 0; }
126 return $q;
129 function initPage( &$out ) {
130 $fname = 'Skin::initPage';
131 wfProfileIn( $fname );
133 $out->addLink( array( 'rel' => 'shortcut icon', 'href' => '/favicon.ico' ) );
135 $this->addMetadataLinks($out);
137 wfProfileOut( $fname );
140 function addMetadataLinks( &$out ) {
141 global $wgTitle, $wgEnableDublinCoreRdf, $wgEnableCreativeCommonsRdf, $wgRdfMimeType, $action;
142 global $wgRightsPage, $wgRightsUrl;
144 if( $out->isArticleRelated() ) {
145 # note: buggy CC software only reads first "meta" link
146 if( $wgEnableCreativeCommonsRdf ) {
147 $out->addMetadataLink( array(
148 'title' => 'Creative Commons',
149 'type' => 'application/rdf+xml',
150 'href' => $wgTitle->getLocalURL( 'action=creativecommons') ) );
152 if( $wgEnableDublinCoreRdf ) {
153 $out->addMetadataLink( array(
154 'title' => 'Dublin Core',
155 'type' => 'application/rdf+xml',
156 'href' => $wgTitle->getLocalURL( 'action=dublincore' ) ) );
159 $copyright = '';
160 if( $wgRightsPage ) {
161 $copy = Title::newFromText( $wgRightsPage );
162 if( $copy ) {
163 $copyright = $copy->getLocalURL();
166 if( !$copyright && $wgRightsUrl ) {
167 $copyright = $wgRightsUrl;
169 if( $copyright ) {
170 $out->addLink( array(
171 'rel' => 'copyright',
172 'href' => $copyright ) );
176 function outputPage( &$out ) {
177 global $wgDebugComments;
179 wfProfileIn( 'Skin::outputPage' );
180 $this->initPage( $out );
181 $out->out( $out->headElement() );
183 $out->out( "\n<body" );
184 $ops = $this->getBodyOptions();
185 foreach ( $ops as $name => $val ) {
186 $out->out( " $name='$val'" );
188 $out->out( ">\n" );
189 if ( $wgDebugComments ) {
190 $out->out( "<!-- Wiki debugging output:\n" .
191 $out->mDebugtext . "-->\n" );
193 $out->out( $this->beforeContent() );
195 $out->out( $out->mBodytext . "\n" );
197 $out->out( $this->afterContent() );
199 wfProfileClose();
200 $out->out( $out->reportTime() );
202 $out->out( "\n</body></html>" );
205 function getHeadScripts() {
206 global $wgStylePath, $wgUser, $wgLang, $wgAllowUserJs;
207 $r = "<script type=\"text/javascript\" src=\"{$wgStylePath}/common/wikibits.js\"></script>\n";
208 if( $wgAllowUserJs && $wgUser->getID() != 0 ) { # logged in
209 $userpage = $wgLang->getNsText( Namespace::getUser() ) . ":" . $wgUser->getName();
210 $userjs = htmlspecialchars($this->makeUrl($userpage.'/'.$this->getSkinName().'.js', 'action=raw&ctype=text/javascript'));
211 $r .= '<script type="text/javascript" src="'.$userjs."\"></script>\n";
213 return $r;
216 # get the user/site-specific stylesheet, SkinPHPTal called from RawPage.php (settings are cached that way)
217 function getUserStylesheet() {
218 global $wgOut, $wgStylePath, $wgLang, $wgUser, $wgRequest, $wgTitle, $wgAllowUserCss;
219 $sheet = $this->getStylesheet();
220 $action = $wgRequest->getText('action');
221 $s = "@import \"$wgStylePath/$sheet\";\n";
222 if($wgLang->isRTL()) $s .= "@import \"$wgStylePath/common/common_rtl.css\";\n";
223 if( $wgAllowUserCss && $wgUser->getID() != 0 ) { # logged in
224 if($wgTitle->isCssSubpage() and $action == 'submit' and $wgTitle->userCanEditCssJsSubpage()) {
225 $s .= $wgRequest->getText('wpTextbox1');
226 } else {
227 $userpage = $wgLang->getNsText( Namespace::getUser() ) . ":" . $wgUser->getName();
228 $s.= '@import "'.$this->makeUrl($userpage.'/'.$this->getSkinName().'.css', 'action=raw&ctype=text/css').'";'."\n";
231 $s .= $this->doGetUserStyles();
232 return $s."\n";
236 * placeholder, returns generated js in monobook
238 function getUserJs() { return; }
241 * Return html code that include User stylesheets
243 function getUserStyles() {
244 global $wgOut, $wgStylePath, $wgLang;
245 $s = "<style type='text/css'>\n";
246 $s .= "/*/*/ /*<![CDATA[*/\n"; # <-- Hide the styles from Netscape 4 without hiding them from IE/Mac
247 $s .= $this->getUserStylesheet();
248 $s .= "/*]]>*/ /* */\n";
249 $s .= "</style>\n";
250 return $s;
254 * Some styles that are set by user through the user settings interface.
256 function doGetUserStyles() {
257 global $wgUser, $wgLang;
259 $csspage = $wgLang->getNsText( NS_MEDIAWIKI ) . ':' . $this->getSkinName() . '.css';
260 $s = '@import "'.$this->makeUrl($csspage, 'action=raw&ctype=text/css')."\";\n";
262 if ( 1 == $wgUser->getOption( 'underline' ) ) {
263 # Don't override browser settings
264 } else {
265 # CHECK MERGE @@@
266 # Force no underline
267 $s .= "a { text-decoration: none; }\n";
269 if ( 1 == $wgUser->getOption( 'highlightbroken' ) ) {
270 $s .= "a.new, #quickbar a.new { color: #CC2200; }\n";
272 if ( 1 == $wgUser->getOption( 'justify' ) ) {
273 $s .= "#article { text-align: justify; }\n";
275 return $s;
278 function getBodyOptions() {
279 global $wgUser, $wgTitle, $wgNamespaceBackgrounds, $wgOut, $wgRequest;
281 extract( $wgRequest->getValues( 'oldid', 'redirect', 'diff' ) );
283 if ( 0 != $wgTitle->getNamespace() ) {
284 $a = array( 'bgcolor' => '#ffffec' );
286 else $a = array( 'bgcolor' => '#FFFFFF' );
287 if($wgOut->isArticle() && $wgUser->getOption('editondblclick') &&
288 (!$wgTitle->isProtected() || $wgUser->isSysop()) ) {
289 $t = wfMsg( 'editthispage' );
290 $oid = $red = '';
291 if ( !empty($redirect) ) {
292 $red = "&redirect={$redirect}";
294 if ( !empty($oldid) && ! isset( $diff ) ) {
295 $oid = "&oldid={$oldid}";
297 $s = $wgTitle->getFullURL( "action=edit{$oid}{$red}" );
298 $s = 'document.location = "' .$s .'";';
299 $a += array ('ondblclick' => $s);
302 $a['onload'] = $wgOut->getOnloadHandler();
303 return $a;
306 function getExternalLinkAttributes( $link, $text, $class='' ) {
307 global $wgUser, $wgOut, $wgLang;
309 $link = urldecode( $link );
310 $link = $wgLang->checkTitleEncoding( $link );
311 $link = str_replace( '_', ' ', $link );
312 $link = htmlspecialchars( $link );
314 $r = ($class != '') ? " class='$class'" : " class='external'";
316 if ( 1 == $wgUser->getOption( 'hover' ) ) {
317 $r .= " title=\"{$link}\"";
319 return $r;
322 function getInternalLinkAttributes( $link, $text, $broken = false ) {
323 global $wgUser, $wgOut;
325 $link = urldecode( $link );
326 $link = str_replace( '_', ' ', $link );
327 $link = htmlspecialchars( $link );
329 if ( $broken == 'stub' ) {
330 $r = ' class="stub"';
331 } else if ( $broken == 'yes' ) {
332 $r = ' class="new"';
333 } else {
334 $r = '';
337 if ( 1 == $wgUser->getOption( 'hover' ) ) {
338 $r .= " title=\"{$link}\"";
340 return $r;
344 * @param bool $broken
346 function getInternalLinkAttributesObj( &$nt, $text, $broken = false ) {
347 global $wgUser, $wgOut;
349 if ( $broken == 'stub' ) {
350 $r = ' class="stub"';
351 } else if ( $broken == 'yes' ) {
352 $r = ' class="new"';
353 } else {
354 $r = '';
357 if ( 1 == $wgUser->getOption( 'hover' ) ) {
358 $r .= ' title ="' . $nt->getEscapedText() . '"';
360 return $r;
364 * URL to the logo
366 function getLogo() {
367 global $wgLogo;
368 return $wgLogo;
372 * This will be called immediately after the <body> tag. Split into
373 * two functions to make it easier to subclass.
375 function beforeContent() {
376 global $wgUser, $wgOut;
378 return $this->doBeforeContent();
381 function doBeforeContent() {
382 global $wgUser, $wgOut, $wgTitle, $wgLang, $wgSiteNotice;
383 $fname = 'Skin::doBeforeContent';
384 wfProfileIn( $fname );
386 $s = '';
387 $qb = $this->qbSetting();
389 if( $langlinks = $this->otherLanguages() ) {
390 $rows = 2;
391 $borderhack = '';
392 } else {
393 $rows = 1;
394 $langlinks = false;
395 $borderhack = 'class="top"';
398 $s .= "\n<div id='content'>\n<div id='topbar'>\n" .
399 "<table border='0' cellspacing='0' width='98%'>\n<tr>\n";
401 $shove = ($qb != 0);
402 $left = ($qb == 1 || $qb == 3);
403 if($wgLang->isRTL()) $left = !$left;
405 if ( !$shove ) {
406 $s .= "<td class='top' align='left' valign='top' rowspan='{$rows}'>\n" .
407 $this->logoText() . '</td>';
408 } elseif( $left ) {
409 $s .= $this->getQuickbarCompensator( $rows );
411 $l = $wgLang->isRTL() ? 'right' : 'left';
412 $s .= "<td {$borderhack} align='$l' valign='top'>\n";
414 $s .= $this->topLinks() ;
415 $s .= "<p class='subtitle'>" . $this->pageTitleLinks() . "</p>\n";
417 $r = $wgLang->isRTL() ? "left" : "right";
418 $s .= "</td>\n<td {$borderhack} valign='top' align='$r' nowrap='nowrap'>";
419 $s .= $this->nameAndLogin();
420 $s .= "\n<br />" . $this->searchForm() . "</td>";
422 if ( $langlinks ) {
423 $s .= "</tr>\n<tr>\n<td class='top' colspan=\"2\">$langlinks</td>\n";
426 if ( $shove && !$left ) { # Right
427 $s .= $this->getQuickbarCompensator( $rows );
429 $s .= "</tr>\n</table>\n</div>\n";
430 $s .= "\n<div id='article'>\n";
432 if( $wgSiteNotice ) {
433 $s .= "\n<div id='siteNotice'>$wgSiteNotice</div>\n";
435 $s .= $this->pageTitle();
436 $s .= $this->pageSubtitle() ;
437 $s .= $this->getCategories();
438 wfProfileOut( $fname );
439 return $s;
442 function getCategoryLinks () {
443 global $wgOut, $wgTitle, $wgUser, $wgParser;
444 global $wgUseCategoryMagic, $wgUseCategoryBrowser, $wgLang;
446 if( !$wgUseCategoryMagic ) return '' ;
447 if( count( $wgOut->mCategoryLinks ) == 0 ) return '';
449 # Taken out so that they will be displayed in previews -- TS
450 #if( !$wgOut->isArticle() ) return '';
452 $t = implode ( ' | ' , $wgOut->mCategoryLinks ) ;
453 $s = $this->makeKnownLink( 'Special:Categories',
454 wfMsg( 'categories' ), 'article=' . urlencode( $wgTitle->getPrefixedDBkey() ) )
455 . ': ' . $t;
457 # optional 'dmoz-like' category browser. Will be shown under the list
458 # of categories an article belong to
459 if($wgUseCategoryBrowser) {
460 $s .= '<br/><hr/>';
462 # get a big array of the parents tree
463 $parenttree = $wgTitle->getCategorieBrowser();
465 # Render the array as a serie of links
466 function walkThrough ($tree) {
467 global $wgUser;
468 $sk = $wgUser->getSkin();
469 $return = '';
470 foreach($tree as $element => $parent) {
471 if(empty($parent)) {
472 # element start a new list
473 $return .= '<br />';
474 } else {
475 # grab the others elements
476 $return .= walkThrough($parent);
478 # add our current element to the list
479 $eltitle = Title::NewFromText($element);
480 # FIXME : should be makeLink() [AV]
481 $return .= $sk->makeKnownLink($element, $eltitle->getText()).' &gt; ';
483 return $return;
486 $s .= walkThrough($parenttree);
489 return $s;
492 function getCategories() {
493 $catlinks=$this->getCategoryLinks();
494 if(!empty($catlinks)) {
495 return "<p class='catlinks'>{$catlinks}</p>";
499 function getQuickbarCompensator( $rows = 1 ) {
500 return "<td width='152' rowspan='{$rows}'>&nbsp;</td>";
503 # This gets called immediately before the </body> tag.
505 function afterContent() {
506 global $wgUser, $wgOut, $wgServer;
507 global $wgTitle, $wgLang;
509 $printfooter = "<div class=\"printfooter\">\n" . $this->printFooter() . "</div>\n";
510 return $printfooter . $this->doAfterContent();
513 function printSource() {
514 global $wgTitle;
515 $url = htmlspecialchars( $wgTitle->getFullURL() );
516 return wfMsg( "retrievedfrom", "<a href=\"$url\">$url</a>" );
519 function printFooter() {
520 return "<p>" . $this->printSource() .
521 "</p>\n\n<p>" . $this->pageStats() . "</p>\n";
524 function doAfterContent() {
525 global $wgUser, $wgOut, $wgLang;
526 $fname = 'Skin::doAfterContent';
527 wfProfileIn( $fname );
528 wfProfileIn( $fname.'-1' );
530 $s = "\n</div><br style=\"clear:both\" />\n";
531 $s .= "\n<div id='footer'>";
532 $s .= '<table border="0" cellspacing="0"><tr>';
534 wfProfileOut( $fname.'-1' );
535 wfProfileIn( $fname.'-2' );
537 $qb = $this->qbSetting();
538 $shove = ($qb != 0);
539 $left = ($qb == 1 || $qb == 3);
540 if($wgLang->isRTL()) $left = !$left;
542 if ( $shove && $left ) { # Left
543 $s .= $this->getQuickbarCompensator();
545 wfProfileOut( $fname.'-2' );
546 wfProfileIn( $fname.'-3' );
547 $l = $wgLang->isRTL() ? 'right' : 'left';
548 $s .= "<td class='bottom' align='$l' valign='top'>";
550 $s .= $this->bottomLinks();
551 $s .= "\n<br />" . $this->mainPageLink()
552 . ' | ' . $this->aboutLink()
553 . ' | ' . $this->specialLink( 'recentchanges' )
554 . ' | ' . $this->searchForm()
555 . '<br /><span id="pagestats">' . $this->pageStats() . '</span>';
557 $s .= "</td>";
558 if ( $shove && !$left ) { # Right
559 $s .= $this->getQuickbarCompensator();
561 $s .= "</tr></table>\n</div>\n</div>\n";
563 wfProfileOut( $fname.'-3' );
564 wfProfileIn( $fname.'-4' );
565 if ( 0 != $qb ) { $s .= $this->quickBar(); }
566 wfProfileOut( $fname.'-4' );
567 wfProfileOut( $fname );
568 return $s;
571 function pageTitleLinks() {
572 global $wgOut, $wgTitle, $wgUser, $wgLang, $wgUseApproval, $wgRequest;
574 extract( $wgRequest->getValues( 'oldid', 'diff' ) );
575 $action = $wgRequest->getText( 'action' );
577 $s = $this->printableLink();
578 if ( wfMsg ( 'disclaimers' ) != '-' ) $s .= ' | ' . $this->makeKnownLink( wfMsg( 'disclaimerpage' ), wfMsg( 'disclaimers' ) ) ;
580 if ( $wgOut->isArticleRelated() ) {
581 if ( $wgTitle->getNamespace() == Namespace::getImage() ) {
582 $name = $wgTitle->getDBkey();
583 $link = htmlspecialchars( Image::wfImageUrl( $name ) );
584 $style = $this->getInternalLinkAttributes( $link, $name );
585 $s .= " | <a href=\"{$link}\"{$style}>{$name}</a>";
587 # This will show the "Approve" link if $wgUseApproval=true;
588 if ( isset ( $wgUseApproval ) && $wgUseApproval )
590 $t = $wgTitle->getDBkey();
591 $name = 'Approve this article' ;
592 $link = "http://test.wikipedia.org/w/magnus/wiki.phtml?title={$t}&action=submit&doit=1" ;
593 #htmlspecialchars( wfImageUrl( $name ) );
594 $style = $this->getExternalLinkAttributes( $link, $name );
595 $s .= " | <a href=\"{$link}\"{$style}>{$name}</a>" ;
598 if ( 'history' == $action || isset( $diff ) || isset( $oldid ) ) {
599 $s .= ' | ' . $this->makeKnownLink( $wgTitle->getPrefixedText(),
600 wfMsg( 'currentrev' ) );
603 if ( $wgUser->getNewtalk() ) {
604 # do not show "You have new messages" text when we are viewing our
605 # own talk page
607 if(!(strcmp($wgTitle->getText(),$wgUser->getName()) == 0 &&
608 $wgTitle->getNamespace()==Namespace::getTalk(Namespace::getUser()))) {
609 $n =$wgUser->getName();
610 $tl = $this->makeKnownLink( $wgLang->getNsText(
611 Namespace::getTalk( Namespace::getUser() ) ) . ":{$n}",
612 wfMsg('newmessageslink') );
613 $s.= ' | <strong>'. wfMsg( 'newmessages', $tl ) . '</strong>';
614 # disable caching
615 $wgOut->setSquidMaxage(0);
619 $undelete = $this->getUndeleteLink();
620 if( !empty( $undelete ) ) {
621 $s .= ' | '.$undelete;
623 return $s;
626 function getUndeleteLink() {
627 global $wgUser, $wgTitle, $wgLang, $action;
628 if( $wgUser->isSysop() &&
629 (($wgTitle->getArticleId() == 0) || ($action == "history")) &&
630 ($n = $wgTitle->isDeleted() ) ) {
631 return wfMsg( 'thisisdeleted',
632 $this->makeKnownLink(
633 $wgLang->SpecialPage( 'Undelete/' . $wgTitle->getPrefixedDBkey() ),
634 wfMsg( 'restorelink', $n ) ) );
636 return '';
639 function printableLink() {
640 global $wgOut, $wgFeedClasses, $wgRequest;
642 $baseurl = $_SERVER['REQUEST_URI'];
643 if( strpos( '?', $baseurl ) == false ) {
644 $baseurl .= '?';
645 } else {
646 $baseurl .= '&';
648 $baseurl = htmlspecialchars( $baseurl );
649 $printurl = $wgRequest->escapeAppendQuery( 'printable=yes' );
651 $s = "<a href=\"$printurl\">" . wfMsg( 'printableversion' ) . '</a>';
652 if( $wgOut->isSyndicated() ) {
653 foreach( $wgFeedClasses as $format => $class ) {
654 $feedurl = $wgRequest->escapeAppendQuery( "feed=$format" );
655 $s .= " | <a href=\"$feedurl\">{$format}</a>";
658 return $s;
661 function pageTitle() {
662 global $wgOut, $wgTitle, $wgUser;
664 $s = '<h1 class="pagetitle">' . htmlspecialchars( $wgOut->getPageTitle() ) . '</h1>';
665 if($wgUser->getOption( 'editsectiononrightclick' ) && $wgTitle->userCanEdit()) { $s=$this->editSectionScript(0,$s);}
666 return $s;
669 function pageSubtitle() {
670 global $wgOut;
672 $sub = $wgOut->getSubtitle();
673 if ( '' == $sub ) {
674 global $wgExtraSubtitle;
675 $sub = wfMsg( 'tagline' ) . $wgExtraSubtitle;
677 $subpages = $this->subPageSubtitle();
678 $sub .= !empty($subpages)?"</p><p class='subpages'>$subpages":'';
679 $s = "<p class='subtitle'>{$sub}</p>\n";
680 return $s;
683 function subPageSubtitle() {
684 global $wgOut,$wgTitle,$wgNamespacesWithSubpages;
685 $subpages = '';
686 if($wgOut->isArticle() && !empty($wgNamespacesWithSubpages[$wgTitle->getNamespace()])) {
687 $ptext=$wgTitle->getPrefixedText();
688 if(preg_match('/\//',$ptext)) {
689 $links = explode('/',$ptext);
690 $c = 0;
691 $growinglink = '';
692 foreach($links as $link) {
693 $c++;
694 if ($c<count($links)) {
695 $growinglink .= $link;
696 $getlink = $this->makeLink( $growinglink, $link );
697 if(preg_match('/class="new"/i',$getlink)) { break; } # this is a hack, but it saves time
698 if ($c>1) {
699 $subpages .= ' | ';
700 } else {
701 $subpages .= '&lt; ';
703 $subpages .= $getlink;
704 $growinglink .= '/';
709 return $subpages;
712 function nameAndLogin() {
713 global $wgUser, $wgTitle, $wgLang, $wgShowIPinHeader, $wgIP;
715 $li = $wgLang->specialPage( 'Userlogin' );
716 $lo = $wgLang->specialPage( 'Userlogout' );
718 $s = '';
719 if ( 0 == $wgUser->getID() ) {
720 if( $wgShowIPinHeader && isset( $_COOKIE[ini_get('session.name')] ) ) {
721 $n = $wgIP;
723 $tl = $this->makeKnownLink( $wgLang->getNsText(
724 Namespace::getTalk( Namespace::getUser() ) ) . ":{$n}",
725 $wgLang->getNsText( Namespace::getTalk( 0 ) ) );
727 $s .= $n . ' ('.$tl.')';
728 } else {
729 $s .= wfMsg('notloggedin');
732 $rt = $wgTitle->getPrefixedURL();
733 if ( 0 == strcasecmp( urlencode( $lo ), $rt ) ) {
734 $q = '';
735 } else { $q = "returnto={$rt}"; }
737 $s .= "\n<br />" . $this->makeKnownLink( $li,
738 wfMsg( 'login' ), $q );
739 } else {
740 $n = $wgUser->getName();
741 $rt = $wgTitle->getPrefixedURL();
742 $tl = $this->makeKnownLink( $wgLang->getNsText(
743 Namespace::getTalk( Namespace::getUser() ) ) . ":{$n}",
744 $wgLang->getNsText( Namespace::getTalk( 0 ) ) );
746 $tl = " ({$tl})";
748 $s .= $this->makeKnownLink( $wgLang->getNsText(
749 Namespace::getUser() ) . ":{$n}", $n ) . "{$tl}<br />" .
750 $this->makeKnownLink( $lo, wfMsg( 'logout' ),
751 "returnto={$rt}" ) . ' | ' .
752 $this->specialLink( 'preferences' );
754 $s .= ' | ' . $this->makeKnownLink( wfMsg( 'helppage' ),
755 wfMsg( 'help' ) );
757 return $s;
760 function getSearchLink() {
761 $searchPage =& Title::makeTitle( NS_SPECIAL, 'Search' );
762 return $searchPage->getLocalURL();
765 function escapeSearchLink() {
766 return htmlspecialchars( $this->getSearchLink() );
769 function searchForm() {
770 global $wgRequest;
771 $search = $wgRequest->getText( 'search' );
773 $s = '<form name="search" class="inline" method="post" action="'
774 . $this->escapeSearchLink() . "\">\n"
775 . '<input type="text" name="search" size="19" value="'
776 . htmlspecialchars(substr($search,0,256)) . "\" />\n"
777 . '<input type="submit" name="go" value="' . wfMsg ('go') . '" />&nbsp;'
778 . '<input type="submit" name="fulltext" value="' . wfMsg ('search') . "\" />\n</form>";
780 return $s;
783 function topLinks() {
784 global $wgOut;
785 $sep = " |\n";
787 $s = $this->mainPageLink() . $sep
788 . $this->specialLink( 'recentchanges' );
790 if ( $wgOut->isArticleRelated() ) {
791 $s .= $sep . $this->editThisPage()
792 . $sep . $this->historyLink();
794 # Many people don't like this dropdown box
795 #$s .= $sep . $this->specialPagesList();
797 return $s;
800 function bottomLinks() {
801 global $wgOut, $wgUser, $wgTitle;
802 $sep = " |\n";
804 $s = '';
805 if ( $wgOut->isArticleRelated() ) {
806 $s .= '<strong>' . $this->editThisPage() . '</strong>';
807 if ( 0 != $wgUser->getID() ) {
808 $s .= $sep . $this->watchThisPage();
810 $s .= $sep . $this->talkLink()
811 . $sep . $this->historyLink()
812 . $sep . $this->whatLinksHere()
813 . $sep . $this->watchPageLinksLink();
815 if ( $wgTitle->getNamespace() == Namespace::getUser()
816 || $wgTitle->getNamespace() == Namespace::getTalk(Namespace::getUser()) )
819 $id=User::idFromName($wgTitle->getText());
820 $ip=User::isIP($wgTitle->getText());
822 if($id || $ip) { # both anons and non-anons have contri list
823 $s .= $sep . $this->userContribsLink();
825 if ( 0 != $wgUser->getID() ) { # show only to signed in users
826 if($id) { # can only email non-anons
827 $s .= $sep . $this->emailUserLink();
831 if ( $wgUser->isSysop() && $wgTitle->getArticleId() ) {
832 $s .= "\n<br />" . $this->deleteThisPage() .
833 $sep . $this->protectThisPage() .
834 $sep . $this->moveThisPage();
836 $s .= "<br />\n" . $this->otherLanguages();
838 return $s;
841 function pageStats() {
842 global $wgOut, $wgLang, $wgArticle, $wgRequest;
843 global $wgDisableCounters, $wgMaxCredits, $wgShowCreditsIfMax;
845 extract( $wgRequest->getValues( 'oldid', 'diff' ) );
846 if ( ! $wgOut->isArticle() ) { return ''; }
847 if ( isset( $oldid ) || isset( $diff ) ) { return ''; }
848 if ( 0 == $wgArticle->getID() ) { return ''; }
850 $s = '';
851 if ( !$wgDisableCounters ) {
852 $count = $wgLang->formatNum( $wgArticle->getCount() );
853 if ( $count ) {
854 $s = wfMsg( 'viewcount', $count );
858 if (isset($wgMaxCredits) && $wgMaxCredits != 0) {
859 require_once("Credits.php");
860 $s .= ' ' . getCredits($wgArticle, $wgMaxCredits, $wgShowCreditsIfMax);
861 } else {
862 $s .= $this->lastModified();
865 return $s . ' ' . $this->getCopyright();
868 function getCopyright() {
869 global $wgRightsPage, $wgRightsUrl, $wgRightsText, $wgRequest;
872 $oldid = $wgRequest->getVal( 'oldid' );
873 $diff = $wgRequest->getVal( 'diff' );
875 if ( !is_null( $oldid ) && is_null( $diff ) && wfMsg( 'history_copyright' ) !== '-' ) {
876 $msg = 'history_copyright';
877 } else {
878 $msg = 'copyright';
881 $out = '';
882 if( $wgRightsPage ) {
883 $link = $this->makeKnownLink( $wgRightsPage, $wgRightsText );
884 } elseif( $wgRightsUrl ) {
885 $link = $this->makeExternalLink( $wgRightsUrl, $wgRightsText );
886 } else {
887 # Give up now
888 return $out;
890 $out .= wfMsg( $msg, $link );
891 return $out;
894 function getCopyrightIcon() {
895 global $wgRightsPage, $wgRightsUrl, $wgRightsText, $wgRightsIcon;
896 $out = '';
897 if( $wgRightsIcon ) {
898 $icon = htmlspecialchars( $wgRightsIcon );
899 if( $wgRightsUrl ) {
900 $url = htmlspecialchars( $wgRightsUrl );
901 $out .= '<a href="'.$url.'">';
903 $text = htmlspecialchars( $wgRightsText );
904 $out .= "<img src=\"$icon\" alt='$text' />";
905 if( $wgRightsUrl ) {
906 $out .= '</a>';
909 return $out;
912 function getPoweredBy() {
913 global $wgStylePath;
914 $url = htmlspecialchars( "$wgStylePath/common/images/poweredby_mediawiki_88x31.png" );
915 $img = '<a href="http://www.mediawiki.org/"><img src="'.$url.'" alt="MediaWiki" /></a>';
916 return $img;
919 function lastModified() {
920 global $wgLang, $wgArticle;
922 $timestamp = $wgArticle->getTimestamp();
923 if ( $timestamp ) {
924 $d = $wgLang->timeanddate( $wgArticle->getTimestamp(), true );
925 $s = ' ' . wfMsg( 'lastmodified', $d );
926 } else {
927 $s = '';
929 return $s;
932 function logoText( $align = '' ) {
933 if ( '' != $align ) { $a = " align='{$align}'"; }
934 else { $a = ''; }
936 $mp = wfMsg( 'mainpage' );
937 $titleObj = Title::newFromText( $mp );
938 if ( is_object( $titleObj ) ) {
939 $url = $titleObj->escapeLocalURL();
940 } else {
941 $url = '';
944 $logourl = $this->getLogo();
945 $s = "<a href='{$url}'><img{$a} src='{$logourl}' alt='[{$mp}]' /></a>";
946 return $s;
949 function quickBar() {
950 global $wgOut, $wgTitle, $wgUser, $wgRequest, $wgLang;
951 global $wgDisableUploads, $wgRemoteUploads;
953 $fname = 'Skin::quickBar';
954 wfProfileIn( $fname );
956 $action = $wgRequest->getText( 'action' );
957 $wpPreview = $wgRequest->getBool( 'wpPreview' );
958 $tns=$wgTitle->getNamespace();
960 $s = "\n<div id='quickbar'>";
961 $s .= "\n" . $this->logoText() . "\n<hr class='sep' />";
963 $sep = "\n<br />";
964 $s .= $this->mainPageLink()
965 . $sep . $this->specialLink( 'recentchanges' )
966 . $sep . $this->specialLink( 'randompage' );
967 if ($wgUser->getID()) {
968 $s.= $sep . $this->specialLink( 'watchlist' ) ;
969 $s .= $sep .$this->makeKnownLink( $wgLang->specialPage( 'Contributions' ),
970 wfMsg( 'mycontris' ), 'target=' . wfUrlencode($wgUser->getName() ) );
973 // only show watchlist link if logged in
974 if ( wfMsg ( 'currentevents' ) != '-' ) $s .= $sep . $this->makeKnownLink( wfMsg( 'currentevents' ), '' ) ;
975 $s .= "\n<br /><hr class='sep' />";
976 $articleExists = $wgTitle->getArticleId();
977 if ( $wgOut->isArticle() || $action =='edit' || $action =='history' || $wpPreview) {
978 if($wgOut->isArticle()) {
979 $s .= '<strong>' . $this->editThisPage() . '</strong>';
980 } else { # backlink to the article in edit or history mode
981 if($articleExists){ # no backlink if no article
982 switch($tns) {
983 case 0:
984 $text = wfMsg('articlepage');
985 break;
986 case 1:
987 $text = wfMsg('viewtalkpage');
988 break;
989 case 2:
990 $text = wfMsg('userpage');
991 break;
992 case 3:
993 $text = wfMsg('viewtalkpage');
994 break;
995 case 4:
996 $text = wfMsg('wikipediapage');
997 break;
998 case 5:
999 $text = wfMsg('viewtalkpage');
1000 break;
1001 case 6:
1002 $text = wfMsg('imagepage');
1003 break;
1004 case 7:
1005 $text = wfMsg('viewtalkpage');
1006 break;
1007 default:
1008 $text= wfMsg('articlepage');
1011 $link = $wgTitle->getText();
1012 if ($nstext = $wgLang->getNsText($tns) ) { # add namespace if necessary
1013 $link = $nstext . ':' . $link ;
1016 $s .= $this->makeLink( $link, $text );
1017 } elseif( $wgTitle->getNamespace() != Namespace::getSpecial() ) {
1018 # we just throw in a "New page" text to tell the user that he's in edit mode,
1019 # and to avoid messing with the separator that is prepended to the next item
1020 $s .= '<strong>' . wfMsg('newpage') . '</strong>';
1026 if( $tns%2 && $action!='edit' && !$wpPreview) {
1027 $s.= '<br />'.$this->makeKnownLink($wgTitle->getPrefixedText(),wfMsg('postcomment'),'action=edit&section=new');
1031 watching could cause problems in edit mode:
1032 if user edits article, then loads "watch this article" in background and then saves
1033 article with "Watch this article" checkbox disabled, the article is transparently
1034 unwatched. Therefore we do not show the "Watch this page" link in edit mode
1036 if ( 0 != $wgUser->getID() && $articleExists) {
1037 if($action!='edit' && $action != 'submit' )
1039 $s .= $sep . $this->watchThisPage();
1041 if ( $wgTitle->userCanEdit() )
1042 $s .= $sep . $this->moveThisPage();
1044 if ( $wgUser->isSysop() and $articleExists ) {
1045 $s .= $sep . $this->deleteThisPage() .
1046 $sep . $this->protectThisPage();
1048 $s .= $sep . $this->talkLink();
1049 if ($articleExists && $action !='history') {
1050 $s .= $sep . $this->historyLink();
1052 $s.=$sep . $this->whatLinksHere();
1054 if($wgOut->isArticleRelated()) {
1055 $s .= $sep . $this->watchPageLinksLink();
1058 if ( Namespace::getUser() == $wgTitle->getNamespace()
1059 || $wgTitle->getNamespace() == Namespace::getTalk(Namespace::getUser())
1062 $id=User::idFromName($wgTitle->getText());
1063 $ip=User::isIP($wgTitle->getText());
1065 if($id||$ip) {
1066 $s .= $sep . $this->userContribsLink();
1068 if ( 0 != $wgUser->getID() ) {
1069 if($id) { # can only email real users
1070 $s .= $sep . $this->emailUserLink();
1074 $s .= "\n<br /><hr class='sep' />";
1077 if ( 0 != $wgUser->getID() && ( !$wgDisableUploads || $wgRemoteUploads ) ) {
1078 $s .= $this->specialLink( 'upload' ) . $sep;
1080 $s .= $this->specialLink( 'specialpages' )
1081 . $sep . $this->bugReportsLink();
1083 global $wgSiteSupportPage;
1084 if( $wgSiteSupportPage ) {
1085 $s .= "\n<br /><a href=\"" . htmlspecialchars( $wgSiteSupportPage ) .
1086 '" class="internal">' . wfMsg( 'sitesupport' ) . '</a>';
1089 $s .= "\n<br /></div>\n";
1090 wfProfileOut( $fname );
1091 return $s;
1094 function specialPagesList() {
1095 global $wgUser, $wgOut, $wgLang, $wgServer, $wgRedirectScript;
1096 require_once('SpecialPage.php');
1097 $a = array();
1098 $pages = SpecialPage::getPages();
1100 foreach ( $pages[''] as $name => $page ) {
1101 $a[$name] = $page->getDescription();
1103 if ( $wgUser->isSysop() )
1105 foreach ( $pages['sysop'] as $name => $page ) {
1106 $a[$name] = $page->getDescription();
1109 if ( $wgUser->isDeveloper() )
1111 foreach ( $pages['developer'] as $name => $page ) {
1112 $a[$name] = $page->getDescription() ;
1115 $go = wfMsg( 'go' );
1116 $sp = wfMsg( 'specialpages' );
1117 $spp = $wgLang->specialPage( 'Specialpages' );
1119 $s = '<form id="specialpages" method="get" class="inline" ' .
1120 'action="' . htmlspecialchars( "{$wgServer}{$wgRedirectScript}" ) . "\">\n";
1121 $s .= "<select name=\"wpDropdown\">\n";
1122 $s .= "<option value=\"{$spp}\">{$sp}</option>\n";
1124 foreach ( $a as $name => $desc ) {
1125 $p = $wgLang->specialPage( $name );
1126 $s .= "<option value=\"{$p}\">{$desc}</option>\n";
1128 $s .= "</select>\n";
1129 $s .= "<input type='submit' value=\"{$go}\" name='redirect' />\n";
1130 $s .= "</form>\n";
1131 return $s;
1134 function mainPageLink() {
1135 $mp = wfMsg( 'mainpage' );
1136 $s = $this->makeKnownLink( $mp, $mp );
1137 return $s;
1140 function copyrightLink() {
1141 $s = $this->makeKnownLink( wfMsg( 'copyrightpage' ),
1142 wfMsg( 'copyrightpagename' ) );
1143 return $s;
1146 function aboutLink() {
1147 $s = $this->makeKnownLink( wfMsg( 'aboutpage' ),
1148 wfMsg( 'aboutsite' ) );
1149 return $s;
1153 function disclaimerLink() {
1154 $s = $this->makeKnownLink( wfMsg( 'disclaimerpage' ),
1155 wfMsg( 'disclaimers' ) );
1156 return $s;
1159 function editThisPage() {
1160 global $wgOut, $wgTitle, $wgRequest;
1162 $oldid = $wgRequest->getVal( 'oldid' );
1163 $diff = $wgRequest->getVal( 'diff' );
1164 $redirect = $wgRequest->getVal( 'redirect' );
1166 if ( ! $wgOut->isArticleRelated() ) {
1167 $s = wfMsg( 'protectedpage' );
1168 } else {
1169 $n = $wgTitle->getPrefixedText();
1170 if ( $wgTitle->userCanEdit() ) {
1171 $t = wfMsg( 'editthispage' );
1172 } else {
1173 #$t = wfMsg( "protectedpage" );
1174 $t = wfMsg( 'viewsource' );
1176 $oid = $red = '';
1178 if ( !is_null( $redirect ) ) { $red = "&redirect={$redirect}"; }
1179 if ( $oldid && ! isset( $diff ) ) {
1180 $oid = '&oldid='.$oldid;
1182 $s = $this->makeKnownLink( $n, $t, "action=edit{$oid}{$red}" );
1184 return $s;
1187 function deleteThisPage() {
1188 global $wgUser, $wgOut, $wgTitle, $wgRequest;
1190 $diff = $wgRequest->getVal( 'diff' );
1191 if ( $wgTitle->getArticleId() && ( ! $diff ) && $wgUser->isSysop() ) {
1192 $n = $wgTitle->getPrefixedText();
1193 $t = wfMsg( 'deletethispage' );
1195 $s = $this->makeKnownLink( $n, $t, 'action=delete' );
1196 } else {
1197 $s = '';
1199 return $s;
1202 function protectThisPage() {
1203 global $wgUser, $wgOut, $wgTitle, $wgRequest;
1205 $diff = $wgRequest->getVal( 'diff' );
1206 if ( $wgTitle->getArticleId() && ( ! $diff ) && $wgUser->isSysop() ) {
1207 $n = $wgTitle->getPrefixedText();
1209 if ( $wgTitle->isProtected() ) {
1210 $t = wfMsg( 'unprotectthispage' );
1211 $q = 'action=unprotect';
1212 } else {
1213 $t = wfMsg( 'protectthispage' );
1214 $q = 'action=protect';
1216 $s = $this->makeKnownLink( $n, $t, $q );
1217 } else {
1218 $s = '';
1220 return $s;
1223 function watchThisPage() {
1224 global $wgUser, $wgOut, $wgTitle;
1226 if ( $wgOut->isArticleRelated() ) {
1227 $n = $wgTitle->getPrefixedText();
1229 if ( $wgTitle->userIsWatching() ) {
1230 $t = wfMsg( 'unwatchthispage' );
1231 $q = 'action=unwatch';
1232 } else {
1233 $t = wfMsg( 'watchthispage' );
1234 $q = 'action=watch';
1236 $s = $this->makeKnownLink( $n, $t, $q );
1237 } else {
1238 $s = wfMsg( 'notanarticle' );
1240 return $s;
1243 function moveThisPage() {
1244 global $wgTitle, $wgLang;
1246 if ( $wgTitle->userCanEdit() ) {
1247 $s = $this->makeKnownLink( $wgLang->specialPage( 'Movepage' ),
1248 wfMsg( 'movethispage' ), 'target=' . $wgTitle->getPrefixedURL() );
1249 } // no message if page is protected - would be redundant
1250 return $s;
1253 function historyLink() {
1254 global $wgTitle;
1256 $s = $this->makeKnownLink( $wgTitle->getPrefixedText(),
1257 wfMsg( 'history' ), 'action=history' );
1258 return $s;
1261 function whatLinksHere() {
1262 global $wgTitle, $wgLang;
1264 $s = $this->makeKnownLink( $wgLang->specialPage( 'Whatlinkshere' ),
1265 wfMsg( 'whatlinkshere' ), 'target=' . $wgTitle->getPrefixedURL() );
1266 return $s;
1269 function userContribsLink() {
1270 global $wgTitle, $wgLang;
1272 $s = $this->makeKnownLink( $wgLang->specialPage( 'Contributions' ),
1273 wfMsg( 'contributions' ), 'target=' . $wgTitle->getPartialURL() );
1274 return $s;
1277 function emailUserLink() {
1278 global $wgTitle, $wgLang;
1280 $s = $this->makeKnownLink( $wgLang->specialPage( 'Emailuser' ),
1281 wfMsg( 'emailuser' ), 'target=' . $wgTitle->getPartialURL() );
1282 return $s;
1285 function watchPageLinksLink() {
1286 global $wgOut, $wgTitle, $wgLang;
1288 if ( ! $wgOut->isArticleRelated() ) {
1289 $s = '(' . wfMsg( 'notanarticle' ) . ')';
1290 } else {
1291 $s = $this->makeKnownLink( $wgLang->specialPage(
1292 'Recentchangeslinked' ), wfMsg( 'recentchangeslinked' ),
1293 'target=' . $wgTitle->getPrefixedURL() );
1295 return $s;
1298 function otherLanguages() {
1299 global $wgOut, $wgLang, $wgTitle, $wgUseNewInterlanguage;
1301 $a = $wgOut->getLanguageLinks();
1302 if ( 0 == count( $a ) ) {
1303 if ( !$wgUseNewInterlanguage ) return '';
1304 $ns = $wgLang->getNsIndex ( $wgTitle->getNamespace () ) ;
1305 if ( $ns != 0 AND $ns != 1 ) return '' ;
1306 $pn = 'Intl' ;
1307 $x = 'mode=addlink&xt='.$wgTitle->getDBkey() ;
1308 return $this->makeKnownLink( $wgLang->specialPage( $pn ),
1309 wfMsg( 'intl' ) , $x );
1312 if ( !$wgUseNewInterlanguage ) {
1313 $s = wfMsg( 'otherlanguages' ) . ': ';
1314 } else {
1315 global $wgLanguageCode ;
1316 $x = 'mode=zoom&xt='.$wgTitle->getDBkey() ;
1317 $x .= '&xl='.$wgLanguageCode ;
1318 $s = $this->makeKnownLink( $wgLang->specialPage( 'Intl' ),
1319 wfMsg( 'otherlanguages' ) , $x ) . ': ' ;
1322 $s = wfMsg( 'otherlanguages' ) . ': ';
1323 $first = true;
1324 if($wgLang->isRTL()) $s .= '<span dir="LTR">';
1325 foreach( $a as $l ) {
1326 if ( ! $first ) { $s .= ' | '; }
1327 $first = false;
1329 $nt = Title::newFromText( $l );
1330 $url = $nt->getFullURL();
1331 $text = $wgLang->getLanguageName( $nt->getInterwiki() );
1333 if ( '' == $text ) { $text = $l; }
1334 $style = $this->getExternalLinkAttributes( $l, $text );
1335 $s .= "<a href=\"{$url}\"{$style}>{$text}</a>";
1337 if($wgLang->isRTL()) $s .= '</span>';
1338 return $s;
1341 function bugReportsLink() {
1342 $s = $this->makeKnownLink( wfMsg( 'bugreportspage' ),
1343 wfMsg( 'bugreports' ) );
1344 return $s;
1347 function dateLink() {
1348 global $wgLinkCache;
1349 $t1 = Title::newFromText( gmdate( 'F j' ) );
1350 $t2 = Title::newFromText( gmdate( 'Y' ) );
1352 $wgLinkCache->suspend();
1353 $id = $t1->getArticleID();
1354 $wgLinkCache->resume();
1356 if ( 0 == $id ) {
1357 $s = $this->makeBrokenLink( $t1->getText() );
1358 } else {
1359 $s = $this->makeKnownLink( $t1->getText() );
1361 $s .= ', ';
1363 $wgLinkCache->suspend();
1364 $id = $t2->getArticleID();
1365 $wgLinkCache->resume();
1367 if ( 0 == $id ) {
1368 $s .= $this->makeBrokenLink( $t2->getText() );
1369 } else {
1370 $s .= $this->makeKnownLink( $t2->getText() );
1372 return $s;
1375 function talkLink() {
1376 global $wgLang, $wgTitle, $wgLinkCache;
1378 $tns = $wgTitle->getNamespace();
1379 if ( -1 == $tns ) { return ''; }
1381 $pn = $wgTitle->getText();
1382 $tp = wfMsg( 'talkpage' );
1383 if ( Namespace::isTalk( $tns ) ) {
1384 $lns = Namespace::getSubject( $tns );
1385 switch($tns) {
1386 case 1:
1387 $text = wfMsg('articlepage');
1388 break;
1389 case 3:
1390 $text = wfMsg('userpage');
1391 break;
1392 case 5:
1393 $text = wfMsg('wikipediapage');
1394 break;
1395 case 7:
1396 $text = wfMsg('imagepage');
1397 break;
1398 default:
1399 $text= wfMsg('articlepage');
1401 } else {
1403 $lns = Namespace::getTalk( $tns );
1404 $text=$tp;
1406 $n = $wgLang->getNsText( $lns );
1407 if ( '' == $n ) { $link = $pn; }
1408 else { $link = $n.':'.$pn; }
1410 $wgLinkCache->suspend();
1411 $s = $this->makeLink( $link, $text );
1412 $wgLinkCache->resume();
1414 return $s;
1417 function commentLink() {
1418 global $wgLang, $wgTitle, $wgLinkCache;
1420 $tns = $wgTitle->getNamespace();
1421 if ( -1 == $tns ) { return ''; }
1423 $lns = ( Namespace::isTalk( $tns ) ) ? $tns : Namespace::getTalk( $tns );
1425 # assert Namespace::isTalk( $lns )
1427 $n = $wgLang->getNsText( $lns );
1428 $pn = $wgTitle->getText();
1430 $link = $n.':'.$pn;
1432 $wgLinkCache->suspend();
1433 $s = $this->makeKnownLink($link, wfMsg('postcomment'), 'action=edit&section=new');
1434 $wgLinkCache->resume();
1436 return $s;
1440 * After all the page content is transformed into HTML, it makes
1441 * a final pass through here for things like table backgrounds.
1442 * @todo probably deprecated [AV]
1444 function transformContent( $text ) {
1445 return $text;
1449 * Note: This function MUST call getArticleID() on the link,
1450 * otherwise the cache won't get updated properly. See LINKCACHE.DOC.
1452 function makeLink( $title, $text = '', $query = '', $trail = '' ) {
1453 wfProfileIn( 'Skin::makeLink' );
1454 $nt = Title::newFromText( $title );
1455 if ($nt) {
1456 $result = $this->makeLinkObj( Title::newFromText( $title ), $text, $query, $trail );
1457 } else {
1458 wfDebug( 'Invalid title passed to Skin::makeLink(): "'.$title."\"\n" );
1459 $result = $text == "" ? $title : $text;
1462 wfProfileOut( 'Skin::makeLink' );
1463 return $result;
1466 function makeKnownLink( $title, $text = '', $query = '', $trail = '', $prefix = '',$aprops = '') {
1467 $nt = Title::newFromText( $title );
1468 if ($nt) {
1469 return $this->makeKnownLinkObj( Title::newFromText( $title ), $text, $query, $trail, $prefix , $aprops );
1470 } else {
1471 wfDebug( 'Invalid title passed to Skin::makeKnownLink(): "'.$title."\"\n" );
1472 return $text == '' ? $title : $text;
1476 function makeBrokenLink( $title, $text = '', $query = '', $trail = '' ) {
1477 $nt = Title::newFromText( $title );
1478 if ($nt) {
1479 return $this->makeBrokenLinkObj( Title::newFromText( $title ), $text, $query, $trail );
1480 } else {
1481 wfDebug( 'Invalid title passed to Skin::makeBrokenLink(): "'.$title."\"\n" );
1482 return $text == '' ? $title : $text;
1486 function makeStubLink( $title, $text = '', $query = '', $trail = '' ) {
1487 $nt = Title::newFromText( $title );
1488 if ($nt) {
1489 return $this->makeStubLinkObj( Title::newFromText( $title ), $text, $query, $trail );
1490 } else {
1491 wfDebug( 'Invalid title passed to Skin::makeStubLink(): "'.$title."\"\n" );
1492 return $text == '' ? $title : $text;
1497 * Pass a title object, not a title string
1499 function makeLinkObj( &$nt, $text= '', $query = '', $trail = '', $prefix = '' ) {
1500 global $wgOut, $wgUser;
1501 $fname = 'Skin::makeLinkObj';
1503 # Fail gracefully
1504 if ( ! isset($nt) )
1505 return "<!-- ERROR -->{$prefix}{$text}{$trail}";
1507 if ( $nt->isExternal() ) {
1508 $u = $nt->getFullURL();
1509 $link = $nt->getPrefixedURL();
1510 if ( '' == $text ) { $text = $nt->getPrefixedText(); }
1511 $style = $this->getExternalLinkAttributes( $link, $text, 'extiw' );
1513 $inside = '';
1514 if ( '' != $trail ) {
1515 if ( preg_match( '/^([a-z]+)(.*)$$/sD', $trail, $m ) ) {
1516 $inside = $m[1];
1517 $trail = $m[2];
1520 $retVal = "<a href=\"{$u}\"{$style}>{$text}{$inside}</a>{$trail}";
1521 } elseif ( 0 == $nt->getNamespace() && "" == $nt->getText() ) {
1522 $retVal = $this->makeKnownLinkObj( $nt, $text, $query, $trail, $prefix );
1523 } elseif ( ( -1 == $nt->getNamespace() ) ||
1524 ( Namespace::getImage() == $nt->getNamespace() ) ) {
1525 $retVal = $this->makeKnownLinkObj( $nt, $text, $query, $trail, $prefix );
1526 } else {
1527 if ( $this->postParseLinkColour() ) {
1528 $inside = '';
1529 if ( '' != $trail ) {
1530 if ( preg_match( $this->linktrail, $trail, $m ) ) {
1531 $inside = $m[1];
1532 $trail = $m[2];
1536 # Allows wiki to bypass using linkcache, see OutputPage::parseLinkHolders()
1537 $retVal = '<!--LINK ' . implode( ' ', array( $nt->getNamespace(), $nt->getDBkey(),
1538 $query, $prefix . $text . $inside ) ) . "-->{$trail}";
1539 } else {
1540 # Work out link colour immediately
1541 $aid = $nt->getArticleID() ;
1542 if ( 0 == $aid ) {
1543 $retVal = $this->makeBrokenLinkObj( $nt, $text, $query, $trail, $prefix );
1544 } else {
1545 $threshold = $wgUser->getOption('stubthreshold') ;
1546 if ( $threshold > 0 ) {
1547 $dbr =& wfGetDB( DB_SLAVE );
1548 $s = $dbr->selectRow( 'cur', array( 'LENGTH(cur_text) AS x', 'cur_namespace',
1549 'cur_is_redirect' ), array( 'cur_id' => $aid ), $fname ) ;
1550 if ( $s !== false ) {
1551 $size = $s->x;
1552 if ( $s->cur_is_redirect OR $s->cur_namespace != 0 ) {
1553 $size = $threshold*2 ; # Really big
1555 $dbr->freeResult( $res );
1556 } else {
1557 $size = $threshold*2 ; # Really big
1559 } else {
1560 $size = 1 ;
1562 if ( $size < $threshold ) {
1563 $retVal = $this->makeStubLinkObj( $nt, $text, $query, $trail, $prefix );
1564 } else {
1565 $retVal = $this->makeKnownLinkObj( $nt, $text, $query, $trail, $prefix );
1570 return $retVal;
1574 * Pass a title object, not a title string
1576 function makeKnownLinkObj( &$nt, $text = '', $query = '', $trail = '', $prefix = '' , $aprops = '' ) {
1577 global $wgOut, $wgTitle, $wgInputEncoding;
1579 $fname = 'Skin::makeKnownLinkObj';
1580 wfProfileIn( $fname );
1582 if ( !is_object( $nt ) ) {
1583 return $text;
1585 $link = $nt->getPrefixedURL();
1586 # if ( '' != $section && substr($section,0,1) != "#" ) {
1587 # $section = ''
1589 if ( '' == $link ) {
1590 $u = '';
1591 if ( '' == $text ) {
1592 $text = htmlspecialchars( $nt->getFragment() );
1594 } else {
1595 $u = $nt->escapeLocalURL( $query );
1597 if ( '' != $nt->getFragment() ) {
1598 $anchor = urlencode( do_html_entity_decode( str_replace(' ', '_', $nt->getFragment()), ENT_COMPAT, $wgInputEncoding ) );
1599 $replacearray = array(
1600 '%3A' => ':',
1601 '%' => '.'
1603 $u .= '#' . str_replace(array_keys($replacearray),array_values($replacearray),$anchor);
1605 if ( '' == $text ) {
1606 $text = htmlspecialchars( $nt->getPrefixedText() );
1608 $style = $this->getInternalLinkAttributesObj( $nt, $text );
1610 $inside = '';
1611 if ( '' != $trail ) {
1612 if ( preg_match( $this->linktrail, $trail, $m ) ) {
1613 $inside = $m[1];
1614 $trail = $m[2];
1617 $r = "<a href=\"{$u}\"{$style}{$aprops}>{$prefix}{$text}{$inside}</a>{$trail}";
1618 wfProfileOut( $fname );
1619 return $r;
1623 * Pass a title object, not a title string
1625 function makeBrokenLinkObj( &$nt, $text = '', $query = '', $trail = '', $prefix = '' ) {
1626 global $wgOut, $wgUser;
1628 # Fail gracefully
1629 if ( ! isset($nt) )
1630 return "<!-- ERROR -->{$prefix}{$text}{$trail}";
1632 $fname = 'Skin::makeBrokenLinkObj';
1633 wfProfileIn( $fname );
1635 if ( '' == $query ) {
1636 $q = 'action=edit';
1637 } else {
1638 $q = 'action=edit&'.$query;
1640 $u = $nt->escapeLocalURL( $q );
1642 if ( '' == $text ) {
1643 $text = htmlspecialchars( $nt->getPrefixedText() );
1645 $style = $this->getInternalLinkAttributesObj( $nt, $text, "yes" );
1647 $inside = '';
1648 if ( '' != $trail ) {
1649 if ( preg_match( $this->linktrail, $trail, $m ) ) {
1650 $inside = $m[1];
1651 $trail = $m[2];
1654 if ( $wgUser->getOption( 'highlightbroken' ) ) {
1655 $s = "<a href=\"{$u}\"{$style}>{$prefix}{$text}{$inside}</a>{$trail}";
1656 } else {
1657 $s = "{$prefix}{$text}{$inside}<a href=\"{$u}\"{$style}>?</a>{$trail}";
1660 wfProfileOut( $fname );
1661 return $s;
1665 * Pass a title object, not a title string
1667 function makeStubLinkObj( &$nt, $text = '', $query = '', $trail = '', $prefix = '' ) {
1668 global $wgOut, $wgUser;
1670 $link = $nt->getPrefixedURL();
1672 $u = $nt->escapeLocalURL( $query );
1674 if ( '' == $text ) {
1675 $text = htmlspecialchars( $nt->getPrefixedText() );
1677 $style = $this->getInternalLinkAttributesObj( $nt, $text, 'stub' );
1679 $inside = '';
1680 if ( '' != $trail ) {
1681 if ( preg_match( $this->linktrail, $trail, $m ) ) {
1682 $inside = $m[1];
1683 $trail = $m[2];
1686 if ( $wgUser->getOption( 'highlightbroken' ) ) {
1687 $s = "<a href=\"{$u}\"{$style}>{$prefix}{$text}{$inside}</a>{$trail}";
1688 } else {
1689 $s = "{$prefix}{$text}{$inside}<a href=\"{$u}\"{$style}>!</a>{$trail}";
1691 return $s;
1694 function makeSelfLinkObj( &$nt, $text = '', $query = '', $trail = '', $prefix = '' ) {
1695 $u = $nt->escapeLocalURL( $query );
1696 if ( '' == $text ) {
1697 $text = htmlspecialchars( $nt->getPrefixedText() );
1699 $inside = '';
1700 if ( '' != $trail ) {
1701 if ( preg_match( $this->linktrail, $trail, $m ) ) {
1702 $inside = $m[1];
1703 $trail = $m[2];
1706 return "<strong>{$prefix}{$text}{$inside}</strong>{$trail}";
1709 /* these are used extensively in SkinPHPTal, but also some other places */
1710 /*static*/ function makeSpecialUrl( $name, $urlaction='' ) {
1711 $title = Title::makeTitle( NS_SPECIAL, $name );
1712 $this->checkTitle($title, $name);
1713 return $title->getLocalURL( $urlaction );
1715 /*static*/ function makeTalkUrl ( $name, $urlaction='' ) {
1716 $title = Title::newFromText( $name );
1717 $title = $title->getTalkPage();
1718 $this->checkTitle($title, $name);
1719 return $title->getLocalURL( $urlaction );
1721 /*static*/ function makeArticleUrl ( $name, $urlaction='' ) {
1722 $title = Title::newFromText( $name );
1723 $title= $title->getSubjectPage();
1724 $this->checkTitle($title, $name);
1725 return $title->getLocalURL( $urlaction );
1727 /*static*/ function makeI18nUrl ( $name, $urlaction='' ) {
1728 $title = Title::newFromText( wfMsg($name) );
1729 $this->checkTitle($title, $name);
1730 return $title->getLocalURL( $urlaction );
1732 /*static*/ function makeUrl ( $name, $urlaction='' ) {
1733 $title = Title::newFromText( $name );
1734 $this->checkTitle($title, $name);
1735 return $title->getLocalURL( $urlaction );
1737 # this can be passed the NS number as defined in Language.php
1738 /*static*/ function makeNSUrl( $name, $urlaction='', $namespace=0 ) {
1739 $title = Title::makeTitleSafe( $namespace, $name );
1740 $this->checkTitle($title, $name);
1741 return $title->getLocalURL( $urlaction );
1744 /* these return an array with the 'href' and boolean 'exists' */
1745 /*static*/ function makeUrlDetails ( $name, $urlaction='' ) {
1746 $title = Title::newFromText( $name );
1747 $this->checkTitle($title, $name);
1748 return array(
1749 'href' => $title->getLocalURL( $urlaction ),
1750 'exists' => $title->getArticleID() != 0?true:false
1753 /*static*/ function makeTalkUrlDetails ( $name, $urlaction='' ) {
1754 $title = Title::newFromText( $name );
1755 $title = $title->getTalkPage();
1756 $this->checkTitle($title, $name);
1757 return array(
1758 'href' => $title->getLocalURL( $urlaction ),
1759 'exists' => $title->getArticleID() != 0?true:false
1762 /*static*/ function makeArticleUrlDetails ( $name, $urlaction='' ) {
1763 $title = Title::newFromText( $name );
1764 $title= $title->getSubjectPage();
1765 $this->checkTitle($title, $name);
1766 return array(
1767 'href' => $title->getLocalURL( $urlaction ),
1768 'exists' => $title->getArticleID() != 0?true:false
1771 /*static*/ function makeI18nUrlDetails ( $name, $urlaction='' ) {
1772 $title = Title::newFromText( wfMsg($name) );
1773 $this->checkTitle($title, $name);
1774 return array(
1775 'href' => $title->getLocalURL( $urlaction ),
1776 'exists' => $title->getArticleID() != 0?true:false
1780 # make sure we have some title to operate on
1781 /*static*/ function checkTitle ( &$title, &$name ) {
1782 if(!is_object($title)) {
1783 $title = Title::newFromText( $name );
1784 if(!is_object($title)) {
1785 $title = Title::newFromText( '--error: link target missing--' );
1790 function fnamePart( $url ) {
1791 $basename = strrchr( $url, '/' );
1792 if ( false === $basename ) {
1793 $basename = $url;
1794 } else {
1795 $basename = substr( $basename, 1 );
1797 return htmlspecialchars( $basename );
1800 function makeImage( $url, $alt = '' ) {
1801 global $wgOut;
1803 if ( '' == $alt ) {
1804 $alt = $this->fnamePart( $url );
1806 $s = '<img src="'.$url.'" alt="'.$alt.'" />';
1807 return $s;
1810 function makeImageLink( $name, $url, $alt = '' ) {
1811 $nt = Title::makeTitleSafe( NS_IMAGE, $name );
1812 return $this->makeImageLinkObj( $nt, $alt );
1815 function makeImageLinkObj( $nt, $alt = '' ) {
1816 global $wgLang, $wgUseImageResize;
1817 $img = Image::newFromTitle( $nt );
1818 $url = $img->getURL();
1820 $align = '';
1821 $prefix = $postfix = '';
1823 if ( $wgUseImageResize ) {
1824 # Check if the alt text is of the form "options|alt text"
1825 # Options are:
1826 # * thumbnail make a thumbnail with enlarge-icon and caption, alignment depends on lang
1827 # * left no resizing, just left align. label is used for alt= only
1828 # * right same, but right aligned
1829 # * none same, but not aligned
1830 # * ___px scale to ___ pixels width, no aligning. e.g. use in taxobox
1831 # * center center the image
1832 # * framed Keep original image size, no magnify-button.
1834 $part = explode( '|', $alt);
1836 $mwThumb =& MagicWord::get( MAG_IMG_THUMBNAIL );
1837 $mwLeft =& MagicWord::get( MAG_IMG_LEFT );
1838 $mwRight =& MagicWord::get( MAG_IMG_RIGHT );
1839 $mwNone =& MagicWord::get( MAG_IMG_NONE );
1840 $mwWidth =& MagicWord::get( MAG_IMG_WIDTH );
1841 $mwCenter =& MagicWord::get( MAG_IMG_CENTER );
1842 $mwFramed =& MagicWord::get( MAG_IMG_FRAMED );
1843 $alt = $part[count($part)-1];
1845 $height = $framed = $thumb = false;
1846 $manual_thumb = "" ;
1848 foreach( $part as $key => $val ) {
1849 $val_parts = explode ( "=" , $val , 2 ) ;
1850 $left_part = array_shift ( $val_parts ) ;
1851 if ( ! is_null( $mwThumb->matchVariableStartToEnd($val) ) ) {
1852 $thumb=true;
1853 } elseif ( count ( $val_parts ) == 1 && ! is_null( $mwThumb->matchVariableStartToEnd($left_part) ) ) {
1854 # use manually specified thumbnail
1855 $thumb=true;
1856 $manual_thumb = array_shift ( $val_parts ) ;
1857 } elseif ( ! is_null( $mwRight->matchVariableStartToEnd($val) ) ) {
1858 # remember to set an alignment, don't render immediately
1859 $align = 'right';
1860 } elseif ( ! is_null( $mwLeft->matchVariableStartToEnd($val) ) ) {
1861 # remember to set an alignment, don't render immediately
1862 $align = 'left';
1863 } elseif ( ! is_null( $mwCenter->matchVariableStartToEnd($val) ) ) {
1864 # remember to set an alignment, don't render immediately
1865 $align = 'center';
1866 } elseif ( ! is_null( $mwNone->matchVariableStartToEnd($val) ) ) {
1867 # remember to set an alignment, don't render immediately
1868 $align = 'none';
1869 } elseif ( ! is_null( $match = $mwWidth->matchVariableStartToEnd($val) ) ) {
1870 # $match is the image width in pixels
1871 if ( preg_match( '/^([0-9]*)x([0-9]*)$/', $match, $m ) ) {
1872 $width = intval( $m[1] );
1873 $height = intval( $m[2] );
1874 } else {
1875 $width = intval($match);
1877 } elseif ( ! is_null( $mwFramed->matchVariableStartToEnd($val) ) ) {
1878 $framed=true;
1881 if ( 'center' == $align )
1883 $prefix = '<span style="text-align: center">';
1884 $postfix = '</span>';
1885 $align = 'none';
1888 if ( $thumb || $framed ) {
1890 # Create a thumbnail. Alignment depends on language
1891 # writing direction, # right aligned for left-to-right-
1892 # languages ("Western languages"), left-aligned
1893 # for right-to-left-languages ("Semitic languages")
1895 # If thumbnail width has not been provided, it is set
1896 # here to 180 pixels
1897 if ( $align == '' ) {
1898 $align = $wgLang->isRTL() ? 'left' : 'right';
1900 if ( ! isset($width) ) {
1901 $width = 180;
1903 return $prefix.$this->makeThumbLinkObj( $img, $alt, $align, $width, $height, $framed, $manual_thumb ).$postfix;
1905 } elseif ( isset($width) ) {
1907 # Create a resized image, without the additional thumbnail
1908 # features
1910 if ( ( ! $height === false )
1911 && ( $img->getHeight() * $width / $img->getWidth() > $height ) ) {
1912 print "height=$height<br>\nimg->getHeight() = ".$img->getHeight()."<br>\n";
1913 print 'rescaling by factor '. $height / $img->getHeight() . "<br>\n";
1914 $width = $img->getWidth() * $height / $img->getHeight();
1916 if ( '' == $manual_thumb ) $url = $img->createThumb( $width );
1918 } # endif $wgUseImageResize
1920 if ( empty( $alt ) ) {
1921 $alt = preg_replace( '/\.(.+?)^/', '', $img->getName() );
1923 $alt = htmlspecialchars( $alt );
1925 $u = $nt->escapeLocalURL();
1926 if ( $url == '' )
1928 $s = wfMsg( 'missingimage', $img->getName() );
1929 $s .= "<br>{$alt}<br>{$url}<br>\n";
1930 } else {
1931 $s = '<a href="'.$u.'" class="image" title="'.$alt.'">' .
1932 '<img src="'.$url.'" alt="'.$alt.'" /></a>';
1934 if ( '' != $align ) {
1935 $s = "<div class=\"float{$align}\"><span>{$s}</span></div>";
1937 return str_replace("\n", ' ',$prefix.$s.$postfix);
1941 * Make HTML for a thumbnail including image, border and caption
1942 * $img is an Image object
1944 function makeThumbLinkObj( $img, $label = '', $align = 'right', $boxwidth = 180, $boxheight=false, $framed=false , $manual_thumb = "" ) {
1945 global $wgStylePath, $wgLang;
1946 # $image = Title::makeTitleSafe( NS_IMAGE, $name );
1947 $url = $img->getURL();
1949 #$label = htmlspecialchars( $label );
1950 $alt = preg_replace( '/<[^>]*>/', '', $label);
1951 $alt = htmlspecialchars( $alt );
1953 $width = $height = 0;
1954 if ( $img->exists() )
1956 $width = $img->getWidth();
1957 $height = $img->getHeight();
1959 if ( 0 == $width || 0 == $height )
1961 $width = $height = 200;
1963 if ( $boxwidth == 0 )
1965 $boxwidth = 200;
1967 if ( $framed )
1969 // Use image dimensions, don't scale
1970 $boxwidth = $width;
1971 $oboxwidth = $boxwidth + 2;
1972 $boxheight = $height;
1973 $thumbUrl = $url;
1974 } else {
1975 $h = intval( $height/($width/$boxwidth) );
1976 $oboxwidth = $boxwidth + 2;
1977 if ( ( ! $boxheight === false ) && ( $h > $boxheight ) )
1979 $boxwidth *= $boxheight/$h;
1980 } else {
1981 $boxheight = $h;
1983 if ( '' == $manual_thumb ) $thumbUrl = $img->createThumb( $boxwidth );
1986 if ( $manual_thumb != '' ) # Use manually specified thumbnail
1988 $manual_title = Title::makeTitleSafe( NS_IMAGE, $manual_thumb ); #new Title ( $manual_thumb ) ;
1989 $manual_img = Image::newFromTitle( $manual_title );
1990 $thumbUrl = $manual_img->getURL();
1991 if ( $manual_img->exists() )
1993 $width = $manual_img->getWidth();
1994 $height = $manual_img->getHeight();
1995 $boxwidth = $width ;
1996 $boxheight = $height ;
1997 $oboxwidth = $boxwidth + 2 ;
2001 $u = $img->getEscapeLocalURL();
2003 $more = htmlspecialchars( wfMsg( 'thumbnail-more' ) );
2004 $magnifyalign = $wgLang->isRTL() ? 'left' : 'right';
2005 $textalign = $wgLang->isRTL() ? ' style="text-align:right"' : '';
2007 $s = "<div class=\"thumb t{$align}\"><div style=\"width:{$oboxwidth}px;\">";
2008 if ( $thumbUrl == '' ) {
2009 $s .= wfMsg( 'missingimage', $img->getName() );
2010 $zoomicon = '';
2011 } else {
2012 $s .= '<a href="'.$u.'" class="internal" title="'.$alt.'">'.
2013 '<img src="'.$thumbUrl.'" alt="'.$alt.'" ' .
2014 'width="'.$boxwidth.'" height="'.$boxheight.'" /></a>';
2015 if ( $framed ) {
2016 $zoomicon="";
2017 } else {
2018 $zoomicon = '<div class="magnify" style="float:'.$magnifyalign.'">'.
2019 '<a href="'.$u.'" class="internal" title="'.$more.'">'.
2020 '<img src="'.$wgStylePath.'/common/images/magnify-clip.png" ' .
2021 'width="15" height="11" alt="'.$more.'" /></a></div>';
2024 $s .= ' <div class="thumbcaption" '.$textalign.'>'.$zoomicon.$label."</div></div></div>";
2025 return str_replace("\n", ' ', $s);
2028 function makeMediaLink( $name, $url, $alt = '' ) {
2029 $nt = Title::makeTitleSafe( Namespace::getMedia(), $name );
2030 return $this->makeMediaLinkObj( $nt, $alt );
2033 function makeMediaLinkObj( $nt, $alt = '' ) {
2034 if ( ! isset( $nt ) )
2036 ### HOTFIX. Instead of breaking, return empty string.
2037 $s = $alt;
2038 } else {
2039 $name = $nt->getDBKey();
2040 $url = Image::wfImageUrl( $name );
2041 if ( empty( $alt ) ) {
2042 $alt = preg_replace( '/\.(.+?)^/', '', $name );
2045 $u = htmlspecialchars( $url );
2046 $s = "<a href=\"{$u}\" class='internal' title=\"{$alt}\">{$alt}</a>";
2048 return $s;
2051 function specialLink( $name, $key = '' ) {
2052 global $wgLang;
2054 if ( '' == $key ) { $key = strtolower( $name ); }
2055 $pn = $wgLang->ucfirst( $name );
2056 return $this->makeKnownLink( $wgLang->specialPage( $pn ),
2057 wfMsg( $key ) );
2060 function makeExternalLink( $url, $text, $escape = true ) {
2061 $style = $this->getExternalLinkAttributes( $url, $text );
2062 $url = htmlspecialchars( $url );
2063 if( $escape ) {
2064 $text = htmlspecialchars( $text );
2066 return '<a href="'.$url.'"'.$style.'>'.$text.'</a>';
2069 # Called by history lists and recent changes
2072 # Returns text for the start of the tabular part of RC
2073 function beginRecentChangesList() {
2074 $this->rc_cache = array() ;
2075 $this->rcMoveIndex = 0;
2076 $this->rcCacheIndex = 0 ;
2077 $this->lastdate = '';
2078 $this->rclistOpen = false;
2079 return '';
2082 function beginImageHistoryList() {
2083 $s = "\n<h2>" . wfMsg( 'imghistory' ) . "</h2>\n" .
2084 "<p>" . wfMsg( 'imghistlegend' ) . "</p>\n".'<ul class="special">';
2085 return $s;
2089 * Returns text for the end of RC
2090 * If enhanced RC is in use, returns pretty much all the text
2092 function endRecentChangesList() {
2093 $s = $this->recentChangesBlock() ;
2094 if( $this->rclistOpen ) {
2095 $s .= "</ul>\n";
2097 return $s;
2101 * Enhanced RC ungrouped line
2103 function recentChangesBlockLine ( $rcObj ) {
2104 global $wgStylePath, $wgLang ;
2106 # Get rc_xxxx variables
2107 extract( $rcObj->mAttribs ) ;
2108 $curIdEq = 'curid='.$rc_cur_id;
2110 # Spacer image
2111 $r = '' ;
2113 $r .= '<img src="'.$wgStylePath.'/common/images/Arr_.png" width="12" height="12" border="0" />' ;
2114 $r .= '<tt>' ;
2116 if ( $rc_type == RC_MOVE || $rc_type == RC_MOVE_OVER_REDIRECT ) {
2117 $r .= '&nbsp;&nbsp;';
2118 } else {
2119 # M & N (minor & new)
2120 $M = wfMsg( 'minoreditletter' );
2121 $N = wfMsg( 'newpageletter' );
2123 if ( $rc_type == RC_NEW ) {
2124 $r .= $N ;
2125 } else {
2126 $r .= '&nbsp;' ;
2128 if ( $rc_minor ) {
2129 $r .= $M ;
2130 } else {
2131 $r .= '&nbsp;' ;
2135 # Timestamp
2136 $r .= ' '.$rcObj->timestamp.' ' ;
2137 $r .= '</tt>' ;
2139 # Article link
2140 $link = $rcObj->link ;
2141 if ( $rcObj->watched ) $link = '<strong>'.$link.'</strong>' ;
2142 $r .= $link ;
2144 # Diff
2145 $r .= ' (' ;
2146 $r .= $rcObj->difflink ;
2147 $r .= '; ' ;
2149 # Hist
2150 $r .= $this->makeKnownLinkObj( $rcObj->getTitle(), wfMsg( 'hist' ), $curIdEq.'&action=history' );
2152 # User/talk
2153 $r .= ') . . '.$rcObj->userlink ;
2154 $r .= $rcObj->usertalklink ;
2156 # Comment
2157 if ( $rc_comment != '' && $rc_type != RC_MOVE && $rc_type != RC_MOVE_OVER_REDIRECT ) {
2158 $rc_comment=$this->formatComment($rc_comment, $rcObj->getTitle());
2159 $r .= $wgLang->emphasize( ' ('.$rc_comment.')' );
2162 $r .= "<br />\n" ;
2163 return $r ;
2167 * Enhanced RC group
2169 function recentChangesBlockGroup ( $block ) {
2170 global $wgStylePath, $wgLang ;
2172 $r = '' ;
2173 $M = wfMsg( 'minoreditletter' );
2174 $N = wfMsg( 'newpageletter' );
2176 # Collate list of users
2177 $isnew = false ;
2178 $userlinks = array () ;
2179 foreach ( $block AS $rcObj ) {
2180 $oldid = $rcObj->mAttribs['rc_last_oldid'];
2181 if ( $rcObj->mAttribs['rc_new'] ) $isnew = true ;
2182 $u = $rcObj->userlink ;
2183 if ( !isset ( $userlinks[$u] ) ) $userlinks[$u] = 0 ;
2184 $userlinks[$u]++ ;
2187 # Sort the list and convert to text
2188 krsort ( $userlinks ) ;
2189 asort ( $userlinks ) ;
2190 $users = array () ;
2191 foreach ( $userlinks as $userlink => $count) {
2192 $text = $userlink ;
2193 if ( $count > 1 ) $text .= " ({$count}&times;)" ;
2194 array_push ( $users , $text ) ;
2196 $users = ' <font size="-1">['.implode('; ',$users).']</font>' ;
2198 # Arrow
2199 $rci = 'RCI'.$this->rcCacheIndex ;
2200 $rcl = 'RCL'.$this->rcCacheIndex ;
2201 $rcm = 'RCM'.$this->rcCacheIndex ;
2202 $toggleLink = "javascript:toggleVisibility('$rci','$rcm','$rcl')" ;
2203 $arrowdir = $wgLang->isRTL() ? 'l' : 'r';
2204 $tl = '<span id="'.$rcm.'"><a href="'.$toggleLink.'"><img src="'.$wgStylePath.'/common/images/Arr_'.$arrowdir.'.png" width="12" height="12" /></a></span>' ;
2205 $tl .= '<span id="'.$rcl.'" style="display:none"><a href="'.$toggleLink.'"><img src="'.$wgStylePath.'/common/images/Arr_d.png" width="12" height="12" /></a></span>' ;
2206 $r .= $tl ;
2208 # Main line
2209 # M/N
2210 $r .= '<tt>' ;
2211 if ( $isnew ) $r .= $N ;
2212 else $r .= '&nbsp;' ;
2213 $r .= '&nbsp;' ; # Minor
2215 # Timestamp
2216 $r .= ' '.$block[0]->timestamp.' ' ;
2217 $r .= '</tt>' ;
2219 # Article link
2220 $link = $block[0]->link ;
2221 if ( $block[0]->watched ) $link = '<strong>'.$link.'</strong>' ;
2222 $r .= $link ;
2224 $curIdEq = 'curid=' . $block[0]->mAttribs['rc_cur_id'];
2225 if ( $block[0]->mAttribs['rc_type'] != RC_LOG ) {
2226 # Changes
2227 $r .= ' ('.count($block).' ' ;
2228 if ( $isnew ) $r .= wfMsg('changes');
2229 else $r .= $this->makeKnownLinkObj( $block[0]->getTitle() , wfMsg('changes') ,
2230 $curIdEq.'&diff=0&oldid='.$oldid ) ;
2231 $r .= '; ' ;
2233 # History
2234 $r .= $this->makeKnownLinkObj( $block[0]->getTitle(), wfMsg( 'history' ), $curIdEq.'&action=history' );
2235 $r .= ')' ;
2238 $r .= $users ;
2239 $r .= "<br />\n" ;
2241 # Sub-entries
2242 $r .= '<div id="'.$rci.'" style="display:none">' ;
2243 foreach ( $block AS $rcObj ) {
2244 # Get rc_xxxx variables
2245 extract( $rcObj->mAttribs );
2247 $r .= '<img src="'.$wgStylePath.'/common/images/Arr_.png" width="12" height="12" />';
2248 $r .= '<tt>&nbsp; &nbsp; &nbsp; &nbsp;' ;
2249 if ( $rc_new ) $r .= $N ;
2250 else $r .= '&nbsp;' ;
2251 if ( $rc_minor ) $r .= $M ;
2252 else $r .= '&nbsp;' ;
2253 $r .= '</tt>' ;
2255 $o = '' ;
2256 if ( $rc_last_oldid != 0 ) {
2257 $o = 'oldid='.$rc_last_oldid ;
2259 if ( $rc_type == RC_LOG ) {
2260 $link = $rcObj->timestamp ;
2261 } else {
2262 $link = $this->makeKnownLinkObj( $rcObj->getTitle(), $rcObj->timestamp , "{$curIdEq}&$o" ) ;
2264 $link = '<tt>'.$link.'</tt>' ;
2266 $r .= $link ;
2267 $r .= ' (' ;
2268 $r .= $rcObj->curlink ;
2269 $r .= '; ' ;
2270 $r .= $rcObj->lastlink ;
2271 $r .= ') . . '.$rcObj->userlink ;
2272 $r .= $rcObj->usertalklink ;
2273 if ( $rc_comment != '' ) {
2274 $rc_comment=$this->formatComment($rc_comment, $rcObj->getTitle());
2275 $r .= $wgLang->emphasize( ' ('.$rc_comment.')' ) ;
2277 $r .= "<br />\n" ;
2279 $r .= "</div>\n" ;
2281 $this->rcCacheIndex++ ;
2282 return $r ;
2286 * If enhanced RC is in use, this function takes the previously cached
2287 * RC lines, arranges them, and outputs the HTML
2289 function recentChangesBlock () {
2290 global $wgStylePath ;
2291 if ( count ( $this->rc_cache ) == 0 ) return '' ;
2292 $blockOut = '';
2293 foreach ( $this->rc_cache AS $secureName => $block ) {
2294 if ( count ( $block ) < 2 ) {
2295 $blockOut .= $this->recentChangesBlockLine ( array_shift ( $block ) ) ;
2296 } else {
2297 $blockOut .= $this->recentChangesBlockGroup ( $block ) ;
2301 return '<div>'.$blockOut.'</div>' ;
2305 * Called in a loop over all displayed RC entries
2306 * Either returns the line, or caches it for later use
2308 function recentChangesLine( &$rc, $watched = false ) {
2309 global $wgUser ;
2310 $usenew = $wgUser->getOption( 'usenewrc' );
2311 if ( $usenew )
2312 $line = $this->recentChangesLineNew ( $rc, $watched ) ;
2313 else
2314 $line = $this->recentChangesLineOld ( $rc, $watched ) ;
2315 return $line ;
2318 function recentChangesLineOld( &$rc, $watched = false ) {
2319 global $wgTitle, $wgLang, $wgUser, $wgRCSeconds, $wgUseRCPatrol, $wgOnlySysopsCanPatrol;
2321 # Extract DB fields into local scope
2322 extract( $rc->mAttribs );
2323 $curIdEq = 'curid=' . $rc_cur_id;
2325 # Make date header if necessary
2326 $date = $wgLang->date( $rc_timestamp, true);
2327 $s = '';
2328 if ( $date != $this->lastdate ) {
2329 if ( '' != $this->lastdate ) { $s .= "</ul>\n"; }
2330 $s .= "<h4>{$date}</h4>\n<ul class='special'>";
2331 $this->lastdate = $date;
2332 $this->rclistOpen = true;
2335 # If this edit has not yet been patrolled, make it stick out
2336 $s .= ( ! $wgUseRCPatrol || $rc_patrolled ) ? '<li> ' : '<li class="not_patrolled"> ';
2338 if ( $rc_type == RC_MOVE || $rc_type == RC_MOVE_OVER_REDIRECT ) {
2339 # Diff
2340 $s .= '(' . wfMsg( 'diff' ) . ') (';
2341 # Hist
2342 $s .= $this->makeKnownLinkObj( $rc->getMovedToTitle(), wfMsg( 'hist' ), 'action=history' ) .
2343 ') . . ';
2345 # "[[x]] moved to [[y]]"
2346 $msg = ( $rc_type == RC_MOVE ) ? '1movedto2' : '1movedto2_redir';
2347 $s .= wfMsg( $msg, $this->makeKnownLinkObj( $rc->getTitle(), '', 'redirect=no' ),
2348 $this->makeKnownLinkObj( $rc->getMovedToTitle(), '' ) );
2349 } elseif( $rc_namespace == NS_SPECIAL && preg_match( '!^Log/(.*)$!', $rc_title, $matches ) ) {
2350 # Log updates, etc
2351 $logtype = $matches[1];
2352 $logname = LogPage::logName( $logtype );
2353 $s .= '(' . $this->makeKnownLinkObj( $rc->getTitle(), $logname ) . ')';
2354 } else {
2355 # Diff link
2356 if ( $rc_type == RC_NEW || $rc_type == RC_LOG ) {
2357 $diffLink = wfMsg( 'diff' );
2358 } else {
2359 if ( $wgUseRCPatrol && $rc_patrolled == 0 && $wgUser->getID() != 0 &&
2360 ( $wgUser->isSysop() || !$wgOnlySysopsCanPatrol ) )
2361 $rcidparam = "&rcid={$rc_id}";
2362 else
2363 $rcidparam = "";
2364 $diffLink = $this->makeKnownLinkObj( $rc->getTitle(), wfMsg( 'diff' ),
2365 "{$curIdEq}&diff={$rc_this_oldid}&oldid={$rc_last_oldid}{$rcidparam}",
2366 '', '', ' tabindex="'.$rc->counter.'"');
2368 $s .= '('.$diffLink.') (';
2370 # History link
2371 $s .= $this->makeKnownLinkObj( $rc->getTitle(), wfMsg( 'hist' ), $curIdEq.'&action=history' );
2372 $s .= ') . . ';
2374 # M and N (minor and new)
2375 if ( $rc_minor ) { $s .= ' <span class="minor">'.wfMsg( "minoreditletter" ).'</span>'; }
2376 if ( $rc_type == RC_NEW ) { $s .= '<span class="newpage">'.wfMsg( "newpageletter" ).'</span>'; }
2378 # Article link
2379 # If it's a new article, there is no diff link, but if it hasn't been
2380 # patrolled yet, we need to give users a way to do so
2381 if ( $wgUseRCPatrol && $rc_type == RC_NEW && $rc_patrolled == 0 &&
2382 $wgUser->getID() != 0 && ( $wgUser->isSysop() || !$wgOnlySysopsCanPatrol ) )
2383 $articleLink = $this->makeKnownLinkObj( $rc->getTitle(), '', "rcid={$rc_id}" );
2384 else
2385 $articleLink = $this->makeKnownLinkObj( $rc->getTitle(), '' );
2387 if ( $watched ) {
2388 $articleLink = '<strong>'.$articleLink.'</strong>';
2390 $s .= ' '.$articleLink;
2394 # Timestamp
2395 $s .= '; ' . $wgLang->time( $rc_timestamp, true, $wgRCSeconds ) . ' . . ';
2397 # User link (or contributions for unregistered users)
2398 if ( 0 == $rc_user ) {
2399 $userLink = $this->makeKnownLink( $wgLang->specialPage( 'Contributions' ),
2400 $rc_user_text, 'target=' . $rc_user_text );
2401 } else {
2402 $userLink = $this->makeLink( $wgLang->getNsText( NS_USER ) . ':'.$rc_user_text, $rc_user_text );
2404 $s .= $userLink;
2406 # User talk link
2407 $talkname=$wgLang->getNsText(NS_TALK); # use the shorter name
2408 global $wgDisableAnonTalk;
2409 if( 0 == $rc_user && $wgDisableAnonTalk ) {
2410 $userTalkLink = '';
2411 } else {
2412 $utns=$wgLang->getNsText(NS_USER_TALK);
2413 $userTalkLink= $this->makeLink($utns . ':'.$rc_user_text, $talkname );
2415 # Block link
2416 $blockLink='';
2417 if ( ( 0 == $rc_user ) && $wgUser->isSysop() ) {
2418 $blockLink = $this->makeKnownLink( $wgLang->specialPage(
2419 'Blockip' ), wfMsg( 'blocklink' ), 'ip='.$rc_user_text );
2422 if($blockLink) {
2423 if($userTalkLink) $userTalkLink .= ' | ';
2424 $userTalkLink .= $blockLink;
2426 if($userTalkLink) $s.=' ('.$userTalkLink.')';
2428 # Add comment
2429 if ( '' != $rc_comment && '*' != $rc_comment && $rc_type != RC_MOVE && $rc_type != RC_MOVE_OVER_REDIRECT ) {
2430 $rc_comment=$this->formatComment($rc_comment,$rc->getTitle());
2431 $s .= $wgLang->emphasize(' (' . $rc_comment . ')');
2433 $s .= "</li>\n";
2435 return $s;
2438 function recentChangesLineNew( &$baseRC, $watched = false ) {
2439 global $wgTitle, $wgLang, $wgUser, $wgRCSeconds;
2441 # Create a specialised object
2442 $rc = RCCacheEntry::newFromParent( $baseRC ) ;
2444 # Extract fields from DB into the function scope (rc_xxxx variables)
2445 extract( $rc->mAttribs );
2446 $curIdEq = 'curid=' . $rc_cur_id;
2448 # If it's a new day, add the headline and flush the cache
2449 $date = $wgLang->date( $rc_timestamp, true);
2450 $ret = '';
2451 if ( $date != $this->lastdate ) {
2452 # Process current cache
2453 $ret = $this->recentChangesBlock () ;
2454 $this->rc_cache = array() ;
2455 $ret .= "<h4>{$date}</h4>\n";
2456 $this->lastdate = $date;
2459 # Make article link
2460 if ( $rc_type == RC_MOVE || $rc_type == RC_MOVE_OVER_REDIRECT ) {
2461 $msg = ( $rc_type == RC_MOVE ) ? "1movedto2" : "1movedto2_redir";
2462 $clink = wfMsg( $msg, $this->makeKnownLinkObj( $rc->getTitle(), '', 'redirect=no' ),
2463 $this->makeKnownLinkObj( $rc->getMovedToTitle(), '' ) );
2464 } elseif( $rc_namespace == NS_SPECIAL && preg_match( '!^Log/(.*)$!', $rc_title, $matches ) ) {
2465 # Log updates, etc
2466 $logtype = $matches[1];
2467 $logname = LogPage::logName( $logtype );
2468 $clink = '(' . $this->makeKnownLinkObj( $rc->getTitle(), $logname ) . ')';
2469 } else {
2470 $clink = $this->makeKnownLinkObj( $rc->getTitle(), '' ) ;
2473 $time = $wgLang->time( $rc_timestamp, true, $wgRCSeconds );
2474 $rc->watched = $watched ;
2475 $rc->link = $clink ;
2476 $rc->timestamp = $time;
2478 # Make "cur" and "diff" links
2479 if ( ( $rc_type == RC_NEW && $rc_this_oldid == 0 ) || $rc_type == RC_LOG || $rc_type == RC_MOVE || $rc_type == RC_MOVE_OVER_REDIRECT ) {
2480 $curLink = wfMsg( 'cur' );
2481 $diffLink = wfMsg( 'diff' );
2482 } else {
2483 $query = $curIdEq.'&diff=0&oldid='.$rc_this_oldid;
2484 $aprops = ' tabindex="'.$baseRC->counter.'"';
2485 $curLink = $this->makeKnownLinkObj( $rc->getTitle(), wfMsg( 'cur' ), $query, '' ,'' , $aprops );
2486 $diffLink = $this->makeKnownLinkObj( $rc->getTitle(), wfMsg( 'diff'), $query, '' ,'' , $aprops );
2489 # Make "last" link
2490 $titleObj = $rc->getTitle();
2491 if ( $rc_last_oldid == 0 || $rc_type == RC_LOG || $rc_type == RC_MOVE || $rc_type == RC_MOVE_OVER_REDIRECT ) {
2492 $lastLink = wfMsg( 'last' );
2493 } else {
2494 $lastLink = $this->makeKnownLinkObj( $rc->getTitle(), wfMsg( 'last' ),
2495 $curIdEq.'&diff='.$rc_this_oldid.'&oldid='.$rc_last_oldid );
2498 # Make user link (or user contributions for unregistered users)
2499 if ( $rc_user == 0 ) {
2500 $userLink = $this->makeKnownLink( $wgLang->specialPage( 'Contributions' ),
2501 $rc_user_text, 'target=' . $rc_user_text );
2502 } else {
2503 $userLink = $this->makeLink( $wgLang->getNsText(
2504 Namespace::getUser() ) . ':'.$rc_user_text, $rc_user_text );
2507 $rc->userlink = $userLink;
2508 $rc->lastlink = $lastLink;
2509 $rc->curlink = $curLink;
2510 $rc->difflink = $diffLink;
2512 # Make user talk link
2513 $utns=$wgLang->getNsText(NS_USER_TALK);
2514 $talkname=$wgLang->getNsText(NS_TALK); # use the shorter name
2515 $userTalkLink= $this->makeLink($utns . ':'.$rc_user_text, $talkname );
2517 global $wgDisableAnonTalk;
2518 if ( ( 0 == $rc_user ) && $wgUser->isSysop() ) {
2519 $blockLink = $this->makeKnownLink( $wgLang->specialPage(
2520 'Blockip' ), wfMsg( 'blocklink' ), 'ip='.$rc_user_text );
2521 if( $wgDisableAnonTalk )
2522 $rc->usertalklink = ' ('.$blockLink.')';
2523 else
2524 $rc->usertalklink = ' ('.$userTalkLink.' | '.$blockLink.')';
2525 } else {
2526 if( $wgDisableAnonTalk && ($rc_user == 0) )
2527 $rc->usertalklink = '';
2528 else
2529 $rc->usertalklink = ' ('.$userTalkLink.')';
2532 # Put accumulated information into the cache, for later display
2533 # Page moves go on their own line
2534 $title = $rc->getTitle();
2535 $secureName = $title->getPrefixedDBkey();
2536 if ( $rc_type == RC_MOVE || $rc_type == RC_MOVE_OVER_REDIRECT ) {
2537 # Use an @ character to prevent collision with page names
2538 $this->rc_cache['@@' . ($this->rcMoveIndex++)] = array($rc);
2539 } else {
2540 if ( !isset ( $this->rc_cache[$secureName] ) ) $this->rc_cache[$secureName] = array() ;
2541 array_push ( $this->rc_cache[$secureName] , $rc ) ;
2543 return $ret;
2546 function endImageHistoryList() {
2547 $s = "</ul>\n";
2548 return $s;
2552 * This function is called by all recent changes variants, by the page history,
2553 * and by the user contributions list. It is responsible for formatting edit
2554 * comments. It escapes any HTML in the comment, but adds some CSS to format
2555 * auto-generated comments (from section editing) and formats [[wikilinks]].
2557 * The &$title parameter must be a title OBJECT. It is used to generate a
2558 * direct link to the section in the autocomment.
2559 * @author Erik Moeller <moeller@scireview.de>
2561 * Note: there's not always a title to pass to this function.
2562 * Since you can't set a default parameter for a reference, I've turned it
2563 * temporarily to a value pass. Should be adjusted further. --brion
2565 function formatComment($comment, $title = NULL) {
2566 global $wgLang;
2567 $comment = htmlspecialchars( $comment );
2569 # The pattern for autogen comments is / * foo * /, which makes for
2570 # some nasty regex.
2571 # We look for all comments, match any text before and after the comment,
2572 # add a separator where needed and format the comment itself with CSS
2573 while (preg_match('/(.*)\/\*\s*(.*?)\s*\*\/(.*)/', $comment,$match)) {
2574 $pre=$match[1];
2575 $auto=$match[2];
2576 $post=$match[3];
2577 $link='';
2578 if($title) {
2579 $section=$auto;
2581 # This is hackish but should work in most cases.
2582 $section=str_replace('[[','',$section);
2583 $section=str_replace(']]','',$section);
2584 $title->mFragment=$section;
2585 $link=$this->makeKnownLinkObj($title,wfMsg('sectionlink'));
2587 $sep='-';
2588 $auto=$link.$auto;
2589 if($pre) { $auto = $sep.' '.$auto; }
2590 if($post) { $auto .= ' '.$sep; }
2591 $auto='<span class="autocomment">'.$auto.'</span>';
2592 $comment=$pre.$auto.$post;
2595 # format regular and media links - all other wiki formatting
2596 # is ignored
2597 $medians = $wgLang->getNsText(Namespace::getMedia()).':';
2598 while(preg_match('/\[\[(.*?)(\|(.*?))*\]\](.*)$/',$comment,$match)) {
2599 # Handle link renaming [[foo|text]] will show link as "text"
2600 if( "" != $match[3] ) {
2601 $text = $match[3];
2602 } else {
2603 $text = $match[1];
2605 if( preg_match( '/^' . $medians . '(.*)$/i', $match[1], $submatch ) ) {
2606 # Media link; trail not supported.
2607 $linkRegexp = '/\[\[(.*?)\]\]/';
2608 $thelink = $this->makeMediaLink( $submatch[1], "", $text );
2609 } else {
2610 # Other kind of link
2611 if( preg_match( wfMsg( "linktrail" ), $match[4], $submatch ) ) {
2612 $trail = $submatch[1];
2613 } else {
2614 $trail = "";
2616 $linkRegexp = '/\[\[(.*?)\]\]' . preg_quote( $trail, '/' ) . '/';
2617 if ($match[1][0] == ':')
2618 $match[1] = substr($match[1], 1);
2619 $thelink = $this->makeLink( $match[1], $text, "", $trail );
2621 $comment = preg_replace( $linkRegexp, $thelink, $comment, 1 );
2623 return $comment;
2626 function imageHistoryLine( $iscur, $timestamp, $img, $user, $usertext, $size, $description ) {
2627 global $wgUser, $wgLang, $wgTitle;
2629 $datetime = $wgLang->timeanddate( $timestamp, true );
2630 $del = wfMsg( 'deleteimg' );
2631 $delall = wfMsg( 'deleteimgcompletely' );
2632 $cur = wfMsg( 'cur' );
2634 if ( $iscur ) {
2635 $url = Image::wfImageUrl( $img );
2636 $rlink = $cur;
2637 if ( $wgUser->isSysop() ) {
2638 $link = $wgTitle->escapeLocalURL( 'image=' . $wgTitle->getPartialURL() .
2639 '&action=delete' );
2640 $style = $this->getInternalLinkAttributes( $link, $delall );
2642 $dlink = '<a href="'.$link.'"'.$style.'>'.$delall.'</a>';
2643 } else {
2644 $dlink = $del;
2646 } else {
2647 $url = htmlspecialchars( wfImageArchiveUrl( $img ) );
2648 if( $wgUser->getID() != 0 && $wgTitle->userCanEdit() ) {
2649 $rlink = $this->makeKnownLink( $wgTitle->getPrefixedText(),
2650 wfMsg( 'revertimg' ), 'action=revert&oldimage=' .
2651 urlencode( $img ) );
2652 $dlink = $this->makeKnownLink( $wgTitle->getPrefixedText(),
2653 $del, 'action=delete&oldimage=' . urlencode( $img ) );
2654 } else {
2655 # Having live active links for non-logged in users
2656 # means that bots and spiders crawling our site can
2657 # inadvertently change content. Baaaad idea.
2658 $rlink = wfMsg( 'revertimg' );
2659 $dlink = $del;
2662 if ( 0 == $user ) {
2663 $userlink = $usertext;
2664 } else {
2665 $userlink = $this->makeLink( $wgLang->getNsText( Namespace::getUser() ) .
2666 ':'.$usertext, $usertext );
2668 $nbytes = wfMsg( 'nbytes', $size );
2669 $style = $this->getInternalLinkAttributes( $url, $datetime );
2671 $s = "<li> ({$dlink}) ({$rlink}) <a href=\"{$url}\"{$style}>{$datetime}</a>"
2672 . " . . {$userlink} ({$nbytes})";
2674 if ( '' != $description && '*' != $description ) {
2675 $sk=$wgUser->getSkin();
2676 $s .= $wgLang->emphasize(' (' . $sk->formatComment($description,$wgTitle) . ')');
2678 $s .= "</li>\n";
2679 return $s;
2682 function tocIndent($level) {
2683 return str_repeat( '<div class="tocindent">'."\n", $level>0 ? $level : 0 );
2686 function tocUnindent($level) {
2687 return str_repeat( "</div>\n", $level>0 ? $level : 0 );
2691 * parameter level defines if we are on an indentation level
2693 function tocLine( $anchor, $tocline, $level ) {
2694 $link = '<a href="#'.$anchor.'">'.$tocline.'</a><br />';
2695 if($level) {
2696 return $link."\n";
2697 } else {
2698 return '<div class="tocline">'.$link."</div>\n";
2703 function tocTable($toc) {
2704 # note to CSS fanatics: putting this in a div does not work -- div won't auto-expand
2705 # try min-width & co when somebody gets a chance
2706 $hideline = ' <script type="text/javascript">showTocToggle("' . addslashes( wfMsg('showtoc') ) . '","' . addslashes( wfMsg('hidetoc') ) . '")</script>';
2707 return
2708 '<table border="0" id="toc"><tr id="toctitle"><td align="center">'."\n".
2709 '<b>'.wfMsg('toc').'</b>' .
2710 $hideline .
2711 '</td></tr><tr id="tocinside"><td>'."\n".
2712 $toc."</td></tr></table>\n";
2716 * These two do not check for permissions: check $wgTitle->userCanEdit
2717 * before calling them
2719 function editSectionScript( $section, $head ) {
2720 global $wgTitle, $wgRequest;
2721 if( $wgRequest->getInt( 'oldid' ) && ( $wgRequest->getVal( 'diff' ) != '0' ) ) {
2722 return $head;
2724 $url = $wgTitle->escapeLocalURL( 'action=edit&section='.$section );
2725 return '<span oncontextmenu=\'document.location="'.$url.'";return false;\'>'.$head.'</span>';
2728 function editSectionLink( $section ) {
2729 global $wgRequest;
2730 global $wgTitle, $wgUser, $wgLang;
2732 if( $wgRequest->getInt( 'oldid' ) && ( $wgRequest->getVal( 'diff' ) != '0' ) ) {
2733 # Section edit links would be out of sync on an old page.
2734 # But, if we're diffing to the current page, they'll be
2735 # correct.
2736 return '';
2739 $editurl = '&section='.$section;
2740 $url = $this->makeKnownLink($wgTitle->getPrefixedText(),wfMsg('editsection'),'action=edit'.$editurl);
2742 if( $wgLang->isRTL() ) {
2743 $farside = 'left';
2744 $nearside = 'right';
2745 } else {
2746 $farside = 'right';
2747 $nearside = 'left';
2749 return "<div class=\"editsection\" style=\"float:$farside;margin-$nearside:5px;\">[".$url."]</div>";
2754 * This function is called by EditPage.php and shows a bulletin board style
2755 * toolbar for common editing functions. It can be disabled in the user
2756 * preferences.
2757 * The necessary JavaScript code can be found in style/wikibits.js.
2759 function getEditToolbar() {
2760 global $wgStylePath, $wgLang, $wgMimeType;
2763 * toolarray an array of arrays which each include the filename of
2764 * the button image (without path), the opening tag, the closing tag,
2765 * and optionally a sample text that is inserted between the two when no
2766 * selection is highlighted.
2767 * The tip text is shown when the user moves the mouse over the button.
2769 * Already here are accesskeys (key), which are not used yet until someone
2770 * can figure out a way to make them work in IE. However, we should make
2771 * sure these keys are not defined on the edit page.
2773 $toolarray=array(
2774 array( 'image'=>'button_bold.png',
2775 'open' => "\'\'\'",
2776 'close' => "\'\'\'",
2777 'sample'=> wfMsg('bold_sample'),
2778 'tip' => wfMsg('bold_tip'),
2779 'key' => 'B'
2781 array( 'image'=>'button_italic.png',
2782 'open' => "\'\'",
2783 'close' => "\'\'",
2784 'sample'=> wfMsg('italic_sample'),
2785 'tip' => wfMsg('italic_tip'),
2786 'key' => 'I'
2788 array( 'image'=>'button_link.png',
2789 'open' => '[[',
2790 'close' => ']]',
2791 'sample'=> wfMsg('link_sample'),
2792 'tip' => wfMsg('link_tip'),
2793 'key' => 'L'
2795 array( 'image'=>'button_extlink.png',
2796 'open' => '[',
2797 'close' => ']',
2798 'sample'=> wfMsg('extlink_sample'),
2799 'tip' => wfMsg('extlink_tip'),
2800 'key' => 'X'
2802 array( 'image'=>'button_headline.png',
2803 'open' => "\\n== ",
2804 'close' => " ==\\n",
2805 'sample'=> wfMsg('headline_sample'),
2806 'tip' => wfMsg('headline_tip'),
2807 'key' => 'H'
2809 array( 'image'=>'button_image.png',
2810 'open' => '[['.$wgLang->getNsText(NS_IMAGE).":",
2811 'close' => ']]',
2812 'sample'=> wfMsg('image_sample'),
2813 'tip' => wfMsg('image_tip'),
2814 'key' => 'D'
2816 array( 'image' => 'button_media.png',
2817 'open' => '[['.$wgLang->getNsText(NS_MEDIA).':',
2818 'close' => ']]',
2819 'sample'=> wfMsg('media_sample'),
2820 'tip' => wfMsg('media_tip'),
2821 'key' => 'M'
2823 array( 'image' => 'button_math.png',
2824 'open' => "\\<math\\>",
2825 'close' => "\\</math\\>",
2826 'sample'=> wfMsg('math_sample'),
2827 'tip' => wfMsg('math_tip'),
2828 'key' => 'C'
2830 array( 'image' => 'button_nowiki.png',
2831 'open' => "\\<nowiki\\>",
2832 'close' => "\\</nowiki\\>",
2833 'sample'=> wfMsg('nowiki_sample'),
2834 'tip' => wfMsg('nowiki_tip'),
2835 'key' => 'N'
2837 array( 'image' => 'button_sig.png',
2838 'open' => '--~~~~',
2839 'close' => '',
2840 'sample'=> '',
2841 'tip' => wfMsg('sig_tip'),
2842 'key' => 'Y'
2844 array( 'image' => 'button_hr.png',
2845 'open' => "\\n----\\n",
2846 'close' => '',
2847 'sample'=> '',
2848 'tip' => wfMsg('hr_tip'),
2849 'key' => 'R'
2852 $toolbar ="<script type='text/javascript'>\n/*<![CDATA[*/\n";
2854 $toolbar.="document.writeln(\"<div id='toolbar'>\");\n";
2855 foreach($toolarray as $tool) {
2857 $image=$wgStylePath.'/common/images/'.$tool['image'];
2858 $open=$tool['open'];
2859 $close=$tool['close'];
2860 $sample = addslashes( $tool['sample'] );
2862 // Note that we use the tip both for the ALT tag and the TITLE tag of the image.
2863 // Older browsers show a "speedtip" type message only for ALT.
2864 // Ideally these should be different, realistically they
2865 // probably don't need to be.
2866 $tip = addslashes( $tool['tip'] );
2868 #$key = $tool["key"];
2870 $toolbar.="addButton('$image','$tip','$open','$close','$sample');\n";
2873 $toolbar.="addInfobox('" . addslashes( wfMsg( "infobox" ) ) . "','" . addslashes(wfMsg("infobox_alert")) . "');\n";
2874 $toolbar.="document.writeln(\"</div>\");\n";
2876 $toolbar.="/*]]>*/\n</script>";
2877 return $toolbar;
2881 * @access public
2883 function suppressUrlExpansion() {
2884 return false;