ShortPages and LongPages are almsot identical; remove some duplication.
[mediawiki.git] / includes / Skin.php
blob8194e2b46d1eed337eabba3a8ed1340b05f522da
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 global $wgLinkHolders;
57 $wgLinkHolders = array(
58 'namespaces' => array(),
59 'dbkeys' => array(),
60 'queries' => array(),
61 'texts' => array(),
62 'titles' => array()
64 global $wgInterwikiLinkHolders;
65 $wgInterwikiLinkHolders = array();
67 /**
68 * @todo document
69 * @package MediaWiki
71 class RCCacheEntry extends RecentChange
73 var $secureName, $link;
74 var $curlink , $difflink, $lastlink , $usertalklink , $versionlink ;
75 var $userlink, $timestamp, $watched;
77 function newFromParent( $rc )
79 $rc2 = new RCCacheEntry;
80 $rc2->mAttribs = $rc->mAttribs;
81 $rc2->mExtra = $rc->mExtra;
82 return $rc2;
84 } ;
87 /**
88 * The main skin class that provide methods and properties for all other skins
89 * including PHPTal skins.
90 * This base class is also the "Standard" skin.
91 * @package MediaWiki
93 class Skin {
94 /**#@+
95 * @access private
97 var $lastdate, $lastline;
98 var $linktrail ; # linktrail regexp
99 var $rc_cache ; # Cache for Enhanced Recent Changes
100 var $rcCacheIndex ; # Recent Changes Cache Counter for visibility toggle
101 var $rcMoveIndex;
102 var $postParseLinkColour = true;
103 /**#@-*/
105 function Skin() {
106 global $wgUseOldExistenceCheck;
107 $postParseLinkColour = !$wgUseOldExistenceCheck;
108 $this->linktrail = wfMsg('linktrail');
111 function getSkinNames() {
112 global $wgValidSkinNames;
113 return $wgValidSkinNames;
116 function getStylesheet() {
117 return 'common/wikistandard.css';
120 function getSkinName() {
121 return 'standard';
125 * Get/set accessor for delayed link colouring
127 function postParseLinkColour( $setting = NULL ) {
128 return wfSetVar( $this->postParseLinkColour, $setting );
131 function qbSetting() {
132 global $wgOut, $wgUser;
134 if ( $wgOut->isQuickbarSuppressed() ) { return 0; }
135 $q = $wgUser->getOption( 'quickbar' );
136 if ( '' == $q ) { $q = 0; }
137 return $q;
140 function initPage( &$out ) {
141 $fname = 'Skin::initPage';
142 wfProfileIn( $fname );
144 $out->addLink( array( 'rel' => 'shortcut icon', 'href' => '/favicon.ico' ) );
146 $this->addMetadataLinks($out);
148 wfProfileOut( $fname );
151 function addMetadataLinks( &$out ) {
152 global $wgTitle, $wgEnableDublinCoreRdf, $wgEnableCreativeCommonsRdf, $wgRdfMimeType, $action;
153 global $wgRightsPage, $wgRightsUrl;
155 if( $out->isArticleRelated() ) {
156 # note: buggy CC software only reads first "meta" link
157 if( $wgEnableCreativeCommonsRdf ) {
158 $out->addMetadataLink( array(
159 'title' => 'Creative Commons',
160 'type' => 'application/rdf+xml',
161 'href' => $wgTitle->getLocalURL( 'action=creativecommons') ) );
163 if( $wgEnableDublinCoreRdf ) {
164 $out->addMetadataLink( array(
165 'title' => 'Dublin Core',
166 'type' => 'application/rdf+xml',
167 'href' => $wgTitle->getLocalURL( 'action=dublincore' ) ) );
170 $copyright = '';
171 if( $wgRightsPage ) {
172 $copy = Title::newFromText( $wgRightsPage );
173 if( $copy ) {
174 $copyright = $copy->getLocalURL();
177 if( !$copyright && $wgRightsUrl ) {
178 $copyright = $wgRightsUrl;
180 if( $copyright ) {
181 $out->addLink( array(
182 'rel' => 'copyright',
183 'href' => $copyright ) );
187 function outputPage( &$out ) {
188 global $wgDebugComments;
190 wfProfileIn( 'Skin::outputPage' );
191 $this->initPage( $out );
192 $out->out( $out->headElement() );
194 $out->out( "\n<body" );
195 $ops = $this->getBodyOptions();
196 foreach ( $ops as $name => $val ) {
197 $out->out( " $name='$val'" );
199 $out->out( ">\n" );
200 if ( $wgDebugComments ) {
201 $out->out( "<!-- Wiki debugging output:\n" .
202 $out->mDebugtext . "-->\n" );
204 $out->out( $this->beforeContent() );
206 $out->out( $out->mBodytext . "\n" );
208 $out->out( $this->afterContent() );
210 wfProfileClose();
211 $out->out( $out->reportTime() );
213 $out->out( "\n</body></html>" );
216 function getHeadScripts() {
217 global $wgStylePath, $wgUser, $wgContLang, $wgAllowUserJs;
218 $r = "<script type=\"text/javascript\" src=\"{$wgStylePath}/common/wikibits.js\"></script>\n";
219 if( $wgAllowUserJs && $wgUser->getID() != 0 ) { # logged in
220 $userpage = $wgContLang->getNsText( Namespace::getUser() ) . ":" . $wgUser->getName();
221 $userjs = htmlspecialchars($this->makeUrl($userpage.'/'.$this->getSkinName().'.js', 'action=raw&ctype=text/javascript'));
222 $r .= '<script type="text/javascript" src="'.$userjs."\"></script>\n";
224 return $r;
227 # get the user/site-specific stylesheet, SkinPHPTal called from RawPage.php (settings are cached that way)
228 function getUserStylesheet() {
229 global $wgOut, $wgStylePath, $wgContLang, $wgUser, $wgRequest, $wgTitle, $wgAllowUserCss;
230 $sheet = $this->getStylesheet();
231 $action = $wgRequest->getText('action');
232 $s = "@import \"$wgStylePath/$sheet\";\n";
233 if($wgContLang->isRTL()) $s .= "@import \"$wgStylePath/common/common_rtl.css\";\n";
234 if( $wgAllowUserCss && $wgUser->getID() != 0 ) { # logged in
235 if($wgTitle->isCssSubpage() and $action == 'submit' and $wgTitle->userCanEditCssJsSubpage()) {
236 $s .= $wgRequest->getText('wpTextbox1');
237 } else {
238 $userpage = $wgContLang->getNsText( Namespace::getUser() ) . ":" . $wgUser->getName();
239 $s.= '@import "'.$this->makeUrl($userpage.'/'.$this->getSkinName().'.css', 'action=raw&ctype=text/css').'";'."\n";
242 $s .= $this->doGetUserStyles();
243 return $s."\n";
247 * placeholder, returns generated js in monobook
249 function getUserJs() { return; }
252 * Return html code that include User stylesheets
254 function getUserStyles() {
255 global $wgOut, $wgStylePath, $wgLang;
256 $s = "<style type='text/css'>\n";
257 $s .= "/*/*/ /*<![CDATA[*/\n"; # <-- Hide the styles from Netscape 4 without hiding them from IE/Mac
258 $s .= $this->getUserStylesheet();
259 $s .= "/*]]>*/ /* */\n";
260 $s .= "</style>\n";
261 return $s;
265 * Some styles that are set by user through the user settings interface.
267 function doGetUserStyles() {
268 global $wgUser, $wgContLang;
270 $csspage = $wgContLang->getNsText( NS_MEDIAWIKI ) . ':' . $this->getSkinName() . '.css';
271 $s = '@import "'.$this->makeUrl($csspage, 'action=raw&ctype=text/css')."\";\n";
273 if ( 1 == $wgUser->getOption( 'underline' ) ) {
274 # Don't override browser settings
275 } else {
276 # CHECK MERGE @@@
277 # Force no underline
278 $s .= "a { text-decoration: none; }\n";
280 if ( 1 == $wgUser->getOption( 'highlightbroken' ) ) {
281 $s .= "a.new, #quickbar a.new { color: #CC2200; }\n";
283 if ( 1 == $wgUser->getOption( 'justify' ) ) {
284 $s .= "#article { text-align: justify; }\n";
286 return $s;
289 function getBodyOptions() {
290 global $wgUser, $wgTitle, $wgNamespaceBackgrounds, $wgOut, $wgRequest;
292 extract( $wgRequest->getValues( 'oldid', 'redirect', 'diff' ) );
294 if ( 0 != $wgTitle->getNamespace() ) {
295 $a = array( 'bgcolor' => '#ffffec' );
297 else $a = array( 'bgcolor' => '#FFFFFF' );
298 if($wgOut->isArticle() && $wgUser->getOption('editondblclick') &&
299 (!$wgTitle->isProtected() || $wgUser->isSysop()) ) {
300 $t = wfMsg( 'editthispage' );
301 $oid = $red = '';
302 if ( !empty($redirect) ) {
303 $red = "&redirect={$redirect}";
305 if ( !empty($oldid) && ! isset( $diff ) ) {
306 $oid = "&oldid={$oldid}";
308 $s = $wgTitle->getFullURL( "action=edit{$oid}{$red}" );
309 $s = 'document.location = "' .$s .'";';
310 $a += array ('ondblclick' => $s);
313 $a['onload'] = $wgOut->getOnloadHandler();
314 return $a;
317 function getExternalLinkAttributes( $link, $text, $class='' ) {
318 global $wgUser, $wgOut, $wgContLang;
320 $same = ($link == $text);
321 $link = urldecode( $link );
322 $link = $wgContLang->checkTitleEncoding( $link );
323 $link = str_replace( '_', ' ', $link );
324 $link = htmlspecialchars( $link );
326 $r = ($class != '') ? " class='$class'" : " class='external'";
328 if ( !$same && $wgUser->getOption( 'hover' ) ) {
329 $r .= " title=\"{$link}\"";
331 return $r;
334 function getInternalLinkAttributes( $link, $text, $broken = false ) {
335 global $wgUser, $wgOut;
337 $link = urldecode( $link );
338 $link = str_replace( '_', ' ', $link );
339 $link = htmlspecialchars( $link );
341 if ( $broken == 'stub' ) {
342 $r = ' class="stub"';
343 } else if ( $broken == 'yes' ) {
344 $r = ' class="new"';
345 } else {
346 $r = '';
349 if ( 1 == $wgUser->getOption( 'hover' ) ) {
350 $r .= " title=\"{$link}\"";
352 return $r;
356 * @param bool $broken
358 function getInternalLinkAttributesObj( &$nt, $text, $broken = false ) {
359 global $wgUser, $wgOut;
361 if ( $broken == 'stub' ) {
362 $r = ' class="stub"';
363 } else if ( $broken == 'yes' ) {
364 $r = ' class="new"';
365 } else {
366 $r = '';
369 if ( 1 == $wgUser->getOption( 'hover' ) ) {
370 $r .= ' title="' . $nt->getEscapedText() . '"';
372 return $r;
376 * URL to the logo
378 function getLogo() {
379 global $wgLogo;
380 return $wgLogo;
384 * This will be called immediately after the <body> tag. Split into
385 * two functions to make it easier to subclass.
387 function beforeContent() {
388 global $wgUser, $wgOut;
390 return $this->doBeforeContent();
393 function doBeforeContent() {
394 global $wgUser, $wgOut, $wgTitle, $wgContLang, $wgSiteNotice;
395 $fname = 'Skin::doBeforeContent';
396 wfProfileIn( $fname );
398 $s = '';
399 $qb = $this->qbSetting();
401 if( $langlinks = $this->otherLanguages() ) {
402 $rows = 2;
403 $borderhack = '';
404 } else {
405 $rows = 1;
406 $langlinks = false;
407 $borderhack = 'class="top"';
410 $s .= "\n<div id='content'>\n<div id='topbar'>\n" .
411 "<table border='0' cellspacing='0' width='98%'>\n<tr>\n";
413 $shove = ($qb != 0);
414 $left = ($qb == 1 || $qb == 3);
415 if($wgContLang->isRTL()) $left = !$left;
417 if ( !$shove ) {
418 $s .= "<td class='top' align='left' valign='top' rowspan='{$rows}'>\n" .
419 $this->logoText() . '</td>';
420 } elseif( $left ) {
421 $s .= $this->getQuickbarCompensator( $rows );
423 $l = $wgContLang->isRTL() ? 'right' : 'left';
424 $s .= "<td {$borderhack} align='$l' valign='top'>\n";
426 $s .= $this->topLinks() ;
427 $s .= "<p class='subtitle'>" . $this->pageTitleLinks() . "</p>\n";
429 $r = $wgContLang->isRTL() ? "left" : "right";
430 $s .= "</td>\n<td {$borderhack} valign='top' align='$r' nowrap='nowrap'>";
431 $s .= $this->nameAndLogin();
432 $s .= "\n<br />" . $this->searchForm() . "</td>";
434 if ( $langlinks ) {
435 $s .= "</tr>\n<tr>\n<td class='top' colspan=\"2\">$langlinks</td>\n";
438 if ( $shove && !$left ) { # Right
439 $s .= $this->getQuickbarCompensator( $rows );
441 $s .= "</tr>\n</table>\n</div>\n";
442 $s .= "\n<div id='article'>\n";
444 if( $wgSiteNotice ) {
445 $s .= "\n<div id='siteNotice'>$wgSiteNotice</div>\n";
447 $s .= $this->pageTitle();
448 $s .= $this->pageSubtitle() ;
449 $s .= $this->getCategories();
450 wfProfileOut( $fname );
451 return $s;
454 function getCategoryLinks () {
455 global $wgOut, $wgTitle, $wgUser, $wgParser;
456 global $wgUseCategoryMagic, $wgUseCategoryBrowser, $wgLang;
458 if( !$wgUseCategoryMagic ) return '' ;
459 if( count( $wgOut->mCategoryLinks ) == 0 ) return '';
461 # Taken out so that they will be displayed in previews -- TS
462 #if( !$wgOut->isArticle() ) return '';
464 $t = implode ( ' | ' , $wgOut->mCategoryLinks ) ;
465 $s = $this->makeKnownLink( 'Special:Categories',
466 wfMsg( 'categories' ), 'article=' . urlencode( $wgTitle->getPrefixedDBkey() ) )
467 . ': ' . $t;
469 # optional 'dmoz-like' category browser. Will be shown under the list
470 # of categories an article belong to
471 if($wgUseCategoryBrowser) {
472 $s .= '<br/><hr/>';
474 # get a big array of the parents tree
475 $parenttree = $wgTitle->getCategorieBrowser();
477 # Render the array as a serie of links
478 function walkThrough ($tree) {
479 global $wgUser;
480 $sk = $wgUser->getSkin();
481 $return = '';
482 foreach($tree as $element => $parent) {
483 if(empty($parent)) {
484 # element start a new list
485 $return .= '<br />';
486 } else {
487 # grab the others elements
488 $return .= walkThrough($parent);
490 # add our current element to the list
491 $eltitle = Title::NewFromText($element);
492 # FIXME : should be makeLink() [AV]
493 $return .= $sk->makeKnownLink($element, $eltitle->getText()).' &gt; ';
495 return $return;
498 $s .= walkThrough($parenttree);
501 return $s;
504 function getCategories() {
505 $catlinks=$this->getCategoryLinks();
506 if(!empty($catlinks)) {
507 return "<p class='catlinks'>{$catlinks}</p>";
511 function getQuickbarCompensator( $rows = 1 ) {
512 return "<td width='152' rowspan='{$rows}'>&nbsp;</td>";
515 # This gets called immediately before the </body> tag.
517 function afterContent() {
518 global $wgUser, $wgOut, $wgServer;
519 global $wgTitle, $wgLang;
521 $printfooter = "<div class=\"printfooter\">\n" . $this->printFooter() . "</div>\n";
522 return $printfooter . $this->doAfterContent();
525 function printSource() {
526 global $wgTitle;
527 $url = htmlspecialchars( $wgTitle->getFullURL() );
528 return wfMsg( "retrievedfrom", "<a href=\"$url\">$url</a>" );
531 function printFooter() {
532 return "<p>" . $this->printSource() .
533 "</p>\n\n<p>" . $this->pageStats() . "</p>\n";
536 function doAfterContent() {
537 # overloaded by derived classes
540 function pageTitleLinks() {
541 global $wgOut, $wgTitle, $wgUser, $wgContLang, $wgUseApproval, $wgRequest;
543 extract( $wgRequest->getValues( 'oldid', 'diff' ) );
544 $action = $wgRequest->getText( 'action' );
546 $s = $this->printableLink();
547 if ( wfMsgForContent ( 'disclaimers' ) != '-' )
548 $s .= ' | ' . $this->makeKnownLink(
549 wfMsgForContent( 'disclaimerpage' ),
550 wfMsgForContent( 'disclaimers' ) ) ;
552 if ( $wgOut->isArticleRelated() ) {
553 if ( $wgTitle->getNamespace() == Namespace::getImage() ) {
554 $name = $wgTitle->getDBkey();
555 $link = htmlspecialchars( Image::wfImageUrl( $name ) );
556 $style = $this->getInternalLinkAttributes( $link, $name );
557 $s .= " | <a href=\"{$link}\"{$style}>{$name}</a>";
559 # This will show the "Approve" link if $wgUseApproval=true;
560 if ( isset ( $wgUseApproval ) && $wgUseApproval )
562 $t = $wgTitle->getDBkey();
563 $name = 'Approve this article' ;
564 $link = "http://test.wikipedia.org/w/magnus/wiki.phtml?title={$t}&action=submit&doit=1" ;
565 #htmlspecialchars( wfImageUrl( $name ) );
566 $style = $this->getExternalLinkAttributes( $link, $name );
567 $s .= " | <a href=\"{$link}\"{$style}>{$name}</a>" ;
570 if ( 'history' == $action || isset( $diff ) || isset( $oldid ) ) {
571 $s .= ' | ' . $this->makeKnownLink( $wgTitle->getPrefixedText(),
572 wfMsg( 'currentrev' ) );
575 if ( $wgUser->getNewtalk() ) {
576 # do not show "You have new messages" text when we are viewing our
577 # own talk page
579 if(!(strcmp($wgTitle->getText(),$wgUser->getName()) == 0 &&
580 $wgTitle->getNamespace()==Namespace::getTalk(Namespace::getUser()))) {
581 $n =$wgUser->getName();
582 $tl = $this->makeKnownLink( $wgContLang->getNsText(
583 Namespace::getTalk( Namespace::getUser() ) ) . ":{$n}",
584 wfMsg('newmessageslink') );
585 $s.= ' | <strong>'. wfMsg( 'newmessages', $tl ) . '</strong>';
586 # disable caching
587 $wgOut->setSquidMaxage(0);
591 $undelete = $this->getUndeleteLink();
592 if( !empty( $undelete ) ) {
593 $s .= ' | '.$undelete;
595 return $s;
598 function getUndeleteLink() {
599 global $wgUser, $wgTitle, $wgContLang, $action;
600 if( $wgUser->isSysop() &&
601 (($wgTitle->getArticleId() == 0) || ($action == "history")) &&
602 ($n = $wgTitle->isDeleted() ) ) {
603 return wfMsg( 'thisisdeleted',
604 $this->makeKnownLink(
605 $wgContLang->SpecialPage( 'Undelete/' . $wgTitle->getPrefixedDBkey() ),
606 wfMsg( 'restorelink', $n ) ) );
608 return '';
611 function printableLink() {
612 global $wgOut, $wgFeedClasses, $wgRequest;
614 $baseurl = $_SERVER['REQUEST_URI'];
615 if( strpos( '?', $baseurl ) == false ) {
616 $baseurl .= '?';
617 } else {
618 $baseurl .= '&';
620 $baseurl = htmlspecialchars( $baseurl );
621 $printurl = $wgRequest->escapeAppendQuery( 'printable=yes' );
623 $s = "<a href=\"$printurl\">" . wfMsg( 'printableversion' ) . '</a>';
624 if( $wgOut->isSyndicated() ) {
625 foreach( $wgFeedClasses as $format => $class ) {
626 $feedurl = $wgRequest->escapeAppendQuery( "feed=$format" );
627 $s .= " | <a href=\"$feedurl\">{$format}</a>";
630 return $s;
633 function pageTitle() {
634 global $wgOut, $wgTitle, $wgUser;
636 $s = '<h1 class="pagetitle">' . htmlspecialchars( $wgOut->getPageTitle() ) . '</h1>';
637 if($wgUser->getOption( 'editsectiononrightclick' ) && $wgTitle->userCanEdit()) { $s=$this->editSectionScript(0,$s);}
638 return $s;
641 function pageSubtitle() {
642 global $wgOut;
644 $sub = $wgOut->getSubtitle();
645 if ( '' == $sub ) {
646 global $wgExtraSubtitle;
647 $sub = wfMsg( 'tagline' ) . $wgExtraSubtitle;
649 $subpages = $this->subPageSubtitle();
650 $sub .= !empty($subpages)?"</p><p class='subpages'>$subpages":'';
651 $s = "<p class='subtitle'>{$sub}</p>\n";
652 return $s;
655 function subPageSubtitle() {
656 global $wgOut,$wgTitle,$wgNamespacesWithSubpages;
657 $subpages = '';
658 if($wgOut->isArticle() && !empty($wgNamespacesWithSubpages[$wgTitle->getNamespace()])) {
659 $ptext=$wgTitle->getPrefixedText();
660 if(preg_match('/\//',$ptext)) {
661 $links = explode('/',$ptext);
662 $c = 0;
663 $growinglink = '';
664 foreach($links as $link) {
665 $c++;
666 if ($c<count($links)) {
667 $growinglink .= $link;
668 $getlink = $this->makeLink( $growinglink, $link );
669 if(preg_match('/class="new"/i',$getlink)) { break; } # this is a hack, but it saves time
670 if ($c>1) {
671 $subpages .= ' | ';
672 } else {
673 $subpages .= '&lt; ';
675 $subpages .= $getlink;
676 $growinglink .= '/';
681 return $subpages;
684 function nameAndLogin() {
685 global $wgUser, $wgTitle, $wgLang, $wgContLang, $wgShowIPinHeader, $wgIP;
687 $li = $wgContLang->specialPage( 'Userlogin' );
688 $lo = $wgContLang->specialPage( 'Userlogout' );
690 $s = '';
691 if ( 0 == $wgUser->getID() ) {
692 if( $wgShowIPinHeader && isset( $_COOKIE[ini_get('session.name')] ) ) {
693 $n = $wgIP;
695 $tl = $this->makeKnownLink( $wgContLang->getNsText(
696 Namespace::getTalk( Namespace::getUser() ) ) . ":{$n}",
697 $wgContLang->getNsText( Namespace::getTalk( 0 ) ) );
699 $s .= $n . ' ('.$tl.')';
700 } else {
701 $s .= wfMsg('notloggedin');
704 $rt = $wgTitle->getPrefixedURL();
705 if ( 0 == strcasecmp( urlencode( $lo ), $rt ) ) {
706 $q = '';
707 } else { $q = "returnto={$rt}"; }
709 $s .= "\n<br />" . $this->makeKnownLink( $li,
710 wfMsg( 'login' ), $q );
711 } else {
712 $n = $wgUser->getName();
713 $rt = $wgTitle->getPrefixedURL();
714 $tl = $this->makeKnownLink( $wgContLang->getNsText(
715 Namespace::getTalk( Namespace::getUser() ) ) . ":{$n}",
716 $wgContLang->getNsText( Namespace::getTalk( 0 ) ) );
718 $tl = " ({$tl})";
720 $s .= $this->makeKnownLink( $wgContLang->getNsText(
721 Namespace::getUser() ) . ":{$n}", $n ) . "{$tl}<br />" .
722 $this->makeKnownLink( $lo, wfMsg( 'logout' ),
723 "returnto={$rt}" ) . ' | ' .
724 $this->specialLink( 'preferences' );
726 $s .= ' | ' . $this->makeKnownLink( wfMsgForContent( 'helppage' ),
727 wfMsg( 'help' ) );
729 return $s;
732 function getSearchLink() {
733 $searchPage =& Title::makeTitle( NS_SPECIAL, 'Search' );
734 return $searchPage->getLocalURL();
737 function escapeSearchLink() {
738 return htmlspecialchars( $this->getSearchLink() );
741 function searchForm() {
742 global $wgRequest;
743 $search = $wgRequest->getText( 'search' );
745 $s = '<form name="search" class="inline" method="post" action="'
746 . $this->escapeSearchLink() . "\">\n"
747 . '<input type="text" name="search" size="19" value="'
748 . htmlspecialchars(substr($search,0,256)) . "\" />\n"
749 . '<input type="submit" name="go" value="' . wfMsg ('go') . '" />&nbsp;'
750 . '<input type="submit" name="fulltext" value="' . wfMsg ('search') . "\" />\n</form>";
752 return $s;
755 function topLinks() {
756 global $wgOut;
757 $sep = " |\n";
759 $s = $this->mainPageLink() . $sep
760 . $this->specialLink( 'recentchanges' );
762 if ( $wgOut->isArticleRelated() ) {
763 $s .= $sep . $this->editThisPage()
764 . $sep . $this->historyLink();
766 # Many people don't like this dropdown box
767 #$s .= $sep . $this->specialPagesList();
769 return $s;
772 function bottomLinks() {
773 global $wgOut, $wgUser, $wgTitle;
774 $sep = " |\n";
776 $s = '';
777 if ( $wgOut->isArticleRelated() ) {
778 $s .= '<strong>' . $this->editThisPage() . '</strong>';
779 if ( 0 != $wgUser->getID() ) {
780 $s .= $sep . $this->watchThisPage();
782 $s .= $sep . $this->talkLink()
783 . $sep . $this->historyLink()
784 . $sep . $this->whatLinksHere()
785 . $sep . $this->watchPageLinksLink();
787 if ( $wgTitle->getNamespace() == Namespace::getUser()
788 || $wgTitle->getNamespace() == Namespace::getTalk(Namespace::getUser()) )
791 $id=User::idFromName($wgTitle->getText());
792 $ip=User::isIP($wgTitle->getText());
794 if($id || $ip) { # both anons and non-anons have contri list
795 $s .= $sep . $this->userContribsLink();
797 if ( 0 != $wgUser->getID() ) { # show only to signed in users
798 if($id) { # can only email non-anons
799 $s .= $sep . $this->emailUserLink();
803 if ( $wgUser->isSysop() && $wgTitle->getArticleId() ) {
804 $s .= "\n<br />" . $this->deleteThisPage() .
805 $sep . $this->protectThisPage() .
806 $sep . $this->moveThisPage();
808 $s .= "<br />\n" . $this->otherLanguages();
810 return $s;
813 function pageStats() {
814 global $wgOut, $wgLang, $wgArticle, $wgRequest;
815 global $wgDisableCounters, $wgMaxCredits, $wgShowCreditsIfMax;
817 extract( $wgRequest->getValues( 'oldid', 'diff' ) );
818 if ( ! $wgOut->isArticle() ) { return ''; }
819 if ( isset( $oldid ) || isset( $diff ) ) { return ''; }
820 if ( 0 == $wgArticle->getID() ) { return ''; }
822 $s = '';
823 if ( !$wgDisableCounters ) {
824 $count = $wgLang->formatNum( $wgArticle->getCount() );
825 if ( $count ) {
826 $s = wfMsg( 'viewcount', $count );
830 if (isset($wgMaxCredits) && $wgMaxCredits != 0) {
831 require_once("Credits.php");
832 $s .= ' ' . getCredits($wgArticle, $wgMaxCredits, $wgShowCreditsIfMax);
833 } else {
834 $s .= $this->lastModified();
837 return $s . ' ' . $this->getCopyright();
840 function getCopyright() {
841 global $wgRightsPage, $wgRightsUrl, $wgRightsText, $wgRequest;
844 $oldid = $wgRequest->getVal( 'oldid' );
845 $diff = $wgRequest->getVal( 'diff' );
847 if ( !is_null( $oldid ) && is_null( $diff ) && wfMsgForContent( 'history_copyright' ) !== '-' ) {
848 $msg = 'history_copyright';
849 } else {
850 $msg = 'copyright';
853 $out = '';
854 if( $wgRightsPage ) {
855 $link = $this->makeKnownLink( $wgRightsPage, $wgRightsText );
856 } elseif( $wgRightsUrl ) {
857 $link = $this->makeExternalLink( $wgRightsUrl, $wgRightsText );
858 } else {
859 # Give up now
860 return $out;
862 $out .= wfMsgForContent( $msg, $link );
863 return $out;
866 function getCopyrightIcon() {
867 global $wgRightsPage, $wgRightsUrl, $wgRightsText, $wgRightsIcon;
868 $out = '';
869 if( $wgRightsIcon ) {
870 $icon = htmlspecialchars( $wgRightsIcon );
871 if( $wgRightsUrl ) {
872 $url = htmlspecialchars( $wgRightsUrl );
873 $out .= '<a href="'.$url.'">';
875 $text = htmlspecialchars( $wgRightsText );
876 $out .= "<img src=\"$icon\" alt='$text' />";
877 if( $wgRightsUrl ) {
878 $out .= '</a>';
881 return $out;
884 function getPoweredBy() {
885 global $wgStylePath;
886 $url = htmlspecialchars( "$wgStylePath/common/images/poweredby_mediawiki_88x31.png" );
887 $img = '<a href="http://www.mediawiki.org/"><img src="'.$url.'" alt="MediaWiki" /></a>';
888 return $img;
891 function lastModified() {
892 global $wgLang, $wgArticle;
894 $timestamp = $wgArticle->getTimestamp();
895 if ( $timestamp ) {
896 $d = $wgLang->timeanddate( $wgArticle->getTimestamp(), true );
897 $s = ' ' . wfMsg( 'lastmodified', $d );
898 } else {
899 $s = '';
901 return $s;
904 function logoText( $align = '' ) {
905 if ( '' != $align ) { $a = " align='{$align}'"; }
906 else { $a = ''; }
908 $mp = wfMsg( 'mainpage' );
909 $titleObj = Title::newFromText( $mp );
910 if ( is_object( $titleObj ) ) {
911 $url = $titleObj->escapeLocalURL();
912 } else {
913 $url = '';
916 $logourl = $this->getLogo();
917 $s = "<a href='{$url}'><img{$a} src='{$logourl}' alt='[{$mp}]' /></a>";
918 return $s;
921 function quickBar() {
922 global $wgOut, $wgTitle, $wgUser, $wgRequest, $wgContLang;
923 global $wgDisableUploads, $wgRemoteUploads;
925 $fname = 'Skin::quickBar';
926 wfProfileIn( $fname );
928 $action = $wgRequest->getText( 'action' );
929 $wpPreview = $wgRequest->getBool( 'wpPreview' );
930 $tns=$wgTitle->getNamespace();
932 $s = "\n<div id='quickbar'>";
933 $s .= "\n" . $this->logoText() . "\n<hr class='sep' />";
935 $sep = "\n<br />";
936 $s .= $this->mainPageLink()
937 . $sep . $this->specialLink( 'recentchanges' )
938 . $sep . $this->specialLink( 'randompage' );
939 if ($wgUser->getID()) {
940 $s.= $sep . $this->specialLink( 'watchlist' ) ;
941 $s .= $sep .$this->makeKnownLink( $wgContLang->specialPage( 'Contributions' ),
942 wfMsg( 'mycontris' ), 'target=' . wfUrlencode($wgUser->getName() ) );
945 // only show watchlist link if logged in
946 if ( wfMsgForContent ( 'currentevents' ) != '-' )
947 $s .= $sep . $this->makeKnownLink( wfMsgForContent( 'currentevents' ), '' ) ;
948 $s .= "\n<br /><hr class='sep' />";
949 $articleExists = $wgTitle->getArticleId();
950 if ( $wgOut->isArticle() || $action =='edit' || $action =='history' || $wpPreview) {
951 if($wgOut->isArticle()) {
952 $s .= '<strong>' . $this->editThisPage() . '</strong>';
953 } else { # backlink to the article in edit or history mode
954 if($articleExists){ # no backlink if no article
955 switch($tns) {
956 case 0:
957 $text = wfMsg('articlepage');
958 break;
959 case 1:
960 $text = wfMsg('viewtalkpage');
961 break;
962 case 2:
963 $text = wfMsg('userpage');
964 break;
965 case 3:
966 $text = wfMsg('viewtalkpage');
967 break;
968 case 4:
969 $text = wfMsg('wikipediapage');
970 break;
971 case 5:
972 $text = wfMsg('viewtalkpage');
973 break;
974 case 6:
975 $text = wfMsg('imagepage');
976 break;
977 case 7:
978 $text = wfMsg('viewtalkpage');
979 break;
980 default:
981 $text= wfMsg('articlepage');
984 $link = $wgTitle->getText();
985 if ($nstext = $wgContLang->getNsText($tns) ) { # add namespace if necessary
986 $link = $nstext . ':' . $link ;
989 $s .= $this->makeLink( $link, $text );
990 } elseif( $wgTitle->getNamespace() != Namespace::getSpecial() ) {
991 # we just throw in a "New page" text to tell the user that he's in edit mode,
992 # and to avoid messing with the separator that is prepended to the next item
993 $s .= '<strong>' . wfMsg('newpage') . '</strong>';
999 if( $tns%2 && $action!='edit' && !$wpPreview) {
1000 $s.= '<br />'.$this->makeKnownLink($wgTitle->getPrefixedText(),wfMsg('postcomment'),'action=edit&section=new');
1004 watching could cause problems in edit mode:
1005 if user edits article, then loads "watch this article" in background and then saves
1006 article with "Watch this article" checkbox disabled, the article is transparently
1007 unwatched. Therefore we do not show the "Watch this page" link in edit mode
1009 if ( 0 != $wgUser->getID() && $articleExists) {
1010 if($action!='edit' && $action != 'submit' )
1012 $s .= $sep . $this->watchThisPage();
1014 if ( $wgTitle->userCanEdit() )
1015 $s .= $sep . $this->moveThisPage();
1017 if ( $wgUser->isSysop() and $articleExists ) {
1018 $s .= $sep . $this->deleteThisPage() .
1019 $sep . $this->protectThisPage();
1021 $s .= $sep . $this->talkLink();
1022 if ($articleExists && $action !='history') {
1023 $s .= $sep . $this->historyLink();
1025 $s.=$sep . $this->whatLinksHere();
1027 if($wgOut->isArticleRelated()) {
1028 $s .= $sep . $this->watchPageLinksLink();
1031 if ( Namespace::getUser() == $wgTitle->getNamespace()
1032 || $wgTitle->getNamespace() == Namespace::getTalk(Namespace::getUser())
1035 $id=User::idFromName($wgTitle->getText());
1036 $ip=User::isIP($wgTitle->getText());
1038 if($id||$ip) {
1039 $s .= $sep . $this->userContribsLink();
1041 if ( 0 != $wgUser->getID() ) {
1042 if($id) { # can only email real users
1043 $s .= $sep . $this->emailUserLink();
1047 $s .= "\n<br /><hr class='sep' />";
1050 if ( 0 != $wgUser->getID() && ( !$wgDisableUploads || $wgRemoteUploads ) ) {
1051 $s .= $this->specialLink( 'upload' ) . $sep;
1053 $s .= $this->specialLink( 'specialpages' )
1054 . $sep . $this->bugReportsLink();
1056 global $wgSiteSupportPage;
1057 if( $wgSiteSupportPage ) {
1058 $s .= "\n<br /><a href=\"" . htmlspecialchars( $wgSiteSupportPage ) .
1059 '" class="internal">' . wfMsg( 'sitesupport' ) . '</a>';
1062 $s .= "\n<br /></div>\n";
1063 wfProfileOut( $fname );
1064 return $s;
1067 function specialPagesList() {
1068 global $wgUser, $wgOut, $wgContLang, $wgServer, $wgRedirectScript;
1069 require_once('SpecialPage.php');
1070 $a = array();
1071 $pages = SpecialPage::getPages();
1073 foreach ( $pages[''] as $name => $page ) {
1074 $a[$name] = $page->getDescription();
1076 if ( $wgUser->isSysop() )
1078 foreach ( $pages['sysop'] as $name => $page ) {
1079 $a[$name] = $page->getDescription();
1082 if ( $wgUser->isDeveloper() )
1084 foreach ( $pages['developer'] as $name => $page ) {
1085 $a[$name] = $page->getDescription() ;
1088 $go = wfMsg( 'go' );
1089 $sp = wfMsg( 'specialpages' );
1090 $spp = $wgContLang->specialPage( 'Specialpages' );
1092 $s = '<form id="specialpages" method="get" class="inline" ' .
1093 'action="' . htmlspecialchars( "{$wgServer}{$wgRedirectScript}" ) . "\">\n";
1094 $s .= "<select name=\"wpDropdown\">\n";
1095 $s .= "<option value=\"{$spp}\">{$sp}</option>\n";
1097 foreach ( $a as $name => $desc ) {
1098 $p = $wgContLang->specialPage( $name );
1099 $s .= "<option value=\"{$p}\">{$desc}</option>\n";
1101 $s .= "</select>\n";
1102 $s .= "<input type='submit' value=\"{$go}\" name='redirect' />\n";
1103 $s .= "</form>\n";
1104 return $s;
1107 function mainPageLink() {
1108 $mp = wfMsgForContent( 'mainpage' );
1109 $mptxt = wfMsg( 'mainpage');
1110 $s = $this->makeKnownLink( $mp, $mptxt );
1111 return $s;
1114 function copyrightLink() {
1115 $s = $this->makeKnownLink( wfMsgForContent( 'copyrightpage' ),
1116 wfMsg( 'copyrightpagename' ) );
1117 return $s;
1120 function aboutLink() {
1121 $s = $this->makeKnownLink( wfMsgForContent( 'aboutpage' ),
1122 wfMsg( 'aboutsite' ) );
1123 return $s;
1127 function disclaimerLink() {
1128 $s = $this->makeKnownLink( wfMsgForContent( 'disclaimerpage' ),
1129 wfMsg( 'disclaimers' ) );
1130 return $s;
1133 function editThisPage() {
1134 global $wgOut, $wgTitle, $wgRequest;
1136 $oldid = $wgRequest->getVal( 'oldid' );
1137 $diff = $wgRequest->getVal( 'diff' );
1138 $redirect = $wgRequest->getVal( 'redirect' );
1140 if ( ! $wgOut->isArticleRelated() ) {
1141 $s = wfMsg( 'protectedpage' );
1142 } else {
1143 $n = $wgTitle->getPrefixedText();
1144 if ( $wgTitle->userCanEdit() ) {
1145 $t = wfMsg( 'editthispage' );
1146 } else {
1147 #$t = wfMsg( "protectedpage" );
1148 $t = wfMsg( 'viewsource' );
1150 $oid = $red = '';
1152 if ( !is_null( $redirect ) ) { $red = "&redirect={$redirect}"; }
1153 if ( $oldid && ! isset( $diff ) ) {
1154 $oid = '&oldid='.$oldid;
1156 $s = $this->makeKnownLink( $n, $t, "action=edit{$oid}{$red}" );
1158 return $s;
1161 function deleteThisPage() {
1162 global $wgUser, $wgOut, $wgTitle, $wgRequest;
1164 $diff = $wgRequest->getVal( 'diff' );
1165 if ( $wgTitle->getArticleId() && ( ! $diff ) && $wgUser->isSysop() ) {
1166 $n = $wgTitle->getPrefixedText();
1167 $t = wfMsg( 'deletethispage' );
1169 $s = $this->makeKnownLink( $n, $t, 'action=delete' );
1170 } else {
1171 $s = '';
1173 return $s;
1176 function protectThisPage() {
1177 global $wgUser, $wgOut, $wgTitle, $wgRequest;
1179 $diff = $wgRequest->getVal( 'diff' );
1180 if ( $wgTitle->getArticleId() && ( ! $diff ) && $wgUser->isSysop() ) {
1181 $n = $wgTitle->getPrefixedText();
1183 if ( $wgTitle->isProtected() ) {
1184 $t = wfMsg( 'unprotectthispage' );
1185 $q = 'action=unprotect';
1186 } else {
1187 $t = wfMsg( 'protectthispage' );
1188 $q = 'action=protect';
1190 $s = $this->makeKnownLink( $n, $t, $q );
1191 } else {
1192 $s = '';
1194 return $s;
1197 function watchThisPage() {
1198 global $wgUser, $wgOut, $wgTitle;
1200 if ( $wgOut->isArticleRelated() ) {
1201 $n = $wgTitle->getPrefixedText();
1203 if ( $wgTitle->userIsWatching() ) {
1204 $t = wfMsg( 'unwatchthispage' );
1205 $q = 'action=unwatch';
1206 } else {
1207 $t = wfMsg( 'watchthispage' );
1208 $q = 'action=watch';
1210 $s = $this->makeKnownLink( $n, $t, $q );
1211 } else {
1212 $s = wfMsg( 'notanarticle' );
1214 return $s;
1217 function moveThisPage() {
1218 global $wgTitle, $wgContLang;
1220 if ( $wgTitle->userCanEdit() ) {
1221 $s = $this->makeKnownLink( $wgContLang->specialPage( 'Movepage' ),
1222 wfMsg( 'movethispage' ), 'target=' . $wgTitle->getPrefixedURL() );
1223 } // no message if page is protected - would be redundant
1224 return $s;
1227 function historyLink() {
1228 global $wgTitle;
1230 $s = $this->makeKnownLink( $wgTitle->getPrefixedText(),
1231 wfMsg( 'history' ), 'action=history' );
1232 return $s;
1235 function whatLinksHere() {
1236 global $wgTitle, $wgContLang;
1238 $s = $this->makeKnownLink( $wgContLang->specialPage( 'Whatlinkshere' ),
1239 wfMsg( 'whatlinkshere' ), 'target=' . $wgTitle->getPrefixedURL() );
1240 return $s;
1243 function userContribsLink() {
1244 global $wgTitle, $wgContLang;
1246 $s = $this->makeKnownLink( $wgContLang->specialPage( 'Contributions' ),
1247 wfMsg( 'contributions' ), 'target=' . $wgTitle->getPartialURL() );
1248 return $s;
1251 function emailUserLink() {
1252 global $wgTitle, $wgContLang;
1254 $s = $this->makeKnownLink( $wgContLang->specialPage( 'Emailuser' ),
1255 wfMsg( 'emailuser' ), 'target=' . $wgTitle->getPartialURL() );
1256 return $s;
1259 function watchPageLinksLink() {
1260 global $wgOut, $wgTitle, $wgContLang;
1262 if ( ! $wgOut->isArticleRelated() ) {
1263 $s = '(' . wfMsg( 'notanarticle' ) . ')';
1264 } else {
1265 $s = $this->makeKnownLink( $wgContLang->specialPage(
1266 'Recentchangeslinked' ), wfMsg( 'recentchangeslinked' ),
1267 'target=' . $wgTitle->getPrefixedURL() );
1269 return $s;
1272 function otherLanguages() {
1273 global $wgOut, $wgContLang, $wgTitle, $wgUseNewInterlanguage;
1275 $a = $wgOut->getLanguageLinks();
1276 if ( 0 == count( $a ) ) {
1277 if ( !$wgUseNewInterlanguage ) return '';
1278 $ns = $wgContLang->getNsIndex ( $wgTitle->getNamespace () ) ;
1279 if ( $ns != 0 AND $ns != 1 ) return '' ;
1280 $pn = 'Intl' ;
1281 $x = 'mode=addlink&xt='.$wgTitle->getDBkey() ;
1282 return $this->makeKnownLink( $wgContLang->specialPage( $pn ),
1283 wfMsg( 'intl' ) , $x );
1286 if ( !$wgUseNewInterlanguage ) {
1287 $s = wfMsg( 'otherlanguages' ) . ': ';
1288 } else {
1289 global $wgContLanguageCode ;
1290 $x = 'mode=zoom&xt='.$wgTitle->getDBkey() ;
1291 $x .= '&xl='.$wgContLanguageCode ;
1292 $s = $this->makeKnownLink( $wgContLang->specialPage( 'Intl' ),
1293 wfMsg( 'otherlanguages' ) , $x ) . ': ' ;
1296 $s = wfMsg( 'otherlanguages' ) . ': ';
1297 $first = true;
1298 if($wgContLang->isRTL()) $s .= '<span dir="LTR">';
1299 foreach( $a as $l ) {
1300 if ( ! $first ) { $s .= ' | '; }
1301 $first = false;
1303 $nt = Title::newFromText( $l );
1304 $url = $nt->getFullURL();
1305 $text = $wgContLang->getLanguageName( $nt->getInterwiki() );
1307 if ( '' == $text ) { $text = $l; }
1308 $style = $this->getExternalLinkAttributes( $l, $text );
1309 $s .= "<a href=\"{$url}\"{$style}>{$text}</a>";
1311 if($wgContLang->isRTL()) $s .= '</span>';
1312 return $s;
1315 function bugReportsLink() {
1316 $s = $this->makeKnownLink( wfMsgForContent( 'bugreportspage' ),
1317 wfMsg( 'bugreports' ) );
1318 return $s;
1321 function dateLink() {
1322 global $wgLinkCache;
1323 $t1 = Title::newFromText( gmdate( 'F j' ) );
1324 $t2 = Title::newFromText( gmdate( 'Y' ) );
1326 $wgLinkCache->suspend();
1327 $id = $t1->getArticleID();
1328 $wgLinkCache->resume();
1330 if ( 0 == $id ) {
1331 $s = $this->makeBrokenLink( $t1->getText() );
1332 } else {
1333 $s = $this->makeKnownLink( $t1->getText() );
1335 $s .= ', ';
1337 $wgLinkCache->suspend();
1338 $id = $t2->getArticleID();
1339 $wgLinkCache->resume();
1341 if ( 0 == $id ) {
1342 $s .= $this->makeBrokenLink( $t2->getText() );
1343 } else {
1344 $s .= $this->makeKnownLink( $t2->getText() );
1346 return $s;
1349 function talkLink() {
1350 global $wgContLang, $wgTitle, $wgLinkCache;
1352 $tns = $wgTitle->getNamespace();
1353 if ( -1 == $tns ) { return ''; }
1355 $pn = $wgTitle->getText();
1356 $tp = wfMsg( 'talkpage' );
1357 if ( Namespace::isTalk( $tns ) ) {
1358 $lns = Namespace::getSubject( $tns );
1359 switch($tns) {
1360 case 1:
1361 $text = wfMsg('articlepage');
1362 break;
1363 case 3:
1364 $text = wfMsg('userpage');
1365 break;
1366 case 5:
1367 $text = wfMsg('wikipediapage');
1368 break;
1369 case 7:
1370 $text = wfMsg('imagepage');
1371 break;
1372 default:
1373 $text= wfMsg('articlepage');
1375 } else {
1377 $lns = Namespace::getTalk( $tns );
1378 $text=$tp;
1380 $n = $wgContLang->getNsText( $lns );
1381 if ( '' == $n ) { $link = $pn; }
1382 else { $link = $n.':'.$pn; }
1384 $wgLinkCache->suspend();
1385 $s = $this->makeLink( $link, $text );
1386 $wgLinkCache->resume();
1388 return $s;
1391 function commentLink() {
1392 global $wgContLang, $wgTitle, $wgLinkCache;
1394 $tns = $wgTitle->getNamespace();
1395 if ( -1 == $tns ) { return ''; }
1397 $lns = ( Namespace::isTalk( $tns ) ) ? $tns : Namespace::getTalk( $tns );
1399 # assert Namespace::isTalk( $lns )
1401 $n = $wgContLang->getNsText( $lns );
1402 $pn = $wgTitle->getText();
1404 $link = $n.':'.$pn;
1406 $wgLinkCache->suspend();
1407 $s = $this->makeKnownLink($link, wfMsg('postcomment'), 'action=edit&section=new');
1408 $wgLinkCache->resume();
1410 return $s;
1414 * After all the page content is transformed into HTML, it makes
1415 * a final pass through here for things like table backgrounds.
1416 * @todo probably deprecated [AV]
1418 function transformContent( $text ) {
1419 return $text;
1423 * Note: This function MUST call getArticleID() on the link,
1424 * otherwise the cache won't get updated properly. See LINKCACHE.DOC.
1426 function makeLink( $title, $text = '', $query = '', $trail = '' ) {
1427 wfProfileIn( 'Skin::makeLink' );
1428 $nt = Title::newFromText( $title );
1429 if ($nt) {
1430 $result = $this->makeLinkObj( Title::newFromText( $title ), $text, $query, $trail );
1431 } else {
1432 wfDebug( 'Invalid title passed to Skin::makeLink(): "'.$title."\"\n" );
1433 $result = $text == "" ? $title : $text;
1436 wfProfileOut( 'Skin::makeLink' );
1437 return $result;
1440 function makeKnownLink( $title, $text = '', $query = '', $trail = '', $prefix = '',$aprops = '') {
1441 $nt = Title::newFromText( $title );
1442 if ($nt) {
1443 return $this->makeKnownLinkObj( Title::newFromText( $title ), $text, $query, $trail, $prefix , $aprops );
1444 } else {
1445 wfDebug( 'Invalid title passed to Skin::makeKnownLink(): "'.$title."\"\n" );
1446 return $text == '' ? $title : $text;
1450 function makeBrokenLink( $title, $text = '', $query = '', $trail = '' ) {
1451 $nt = Title::newFromText( $title );
1452 if ($nt) {
1453 return $this->makeBrokenLinkObj( Title::newFromText( $title ), $text, $query, $trail );
1454 } else {
1455 wfDebug( 'Invalid title passed to Skin::makeBrokenLink(): "'.$title."\"\n" );
1456 return $text == '' ? $title : $text;
1460 function makeStubLink( $title, $text = '', $query = '', $trail = '' ) {
1461 $nt = Title::newFromText( $title );
1462 if ($nt) {
1463 return $this->makeStubLinkObj( Title::newFromText( $title ), $text, $query, $trail );
1464 } else {
1465 wfDebug( 'Invalid title passed to Skin::makeStubLink(): "'.$title."\"\n" );
1466 return $text == '' ? $title : $text;
1471 * Pass a title object, not a title string
1473 function makeLinkObj( &$nt, $text= '', $query = '', $trail = '', $prefix = '' ) {
1474 global $wgOut, $wgUser, $wgLinkHolders;
1475 $fname = 'Skin::makeLinkObj';
1477 # Fail gracefully
1478 if ( ! isset($nt) ) {
1479 # wfDebugDieBacktrace();
1480 return "<!-- ERROR -->{$prefix}{$text}{$trail}";
1483 if ( $nt->isExternal() ) {
1484 $u = $nt->getFullURL();
1485 $link = $nt->getPrefixedURL();
1486 if ( '' == $text ) { $text = $nt->getPrefixedText(); }
1487 $style = $this->getExternalLinkAttributes( $link, $text, 'extiw' );
1489 $inside = '';
1490 if ( '' != $trail ) {
1491 if ( preg_match( '/^([a-z]+)(.*)$$/sD', $trail, $m ) ) {
1492 $inside = $m[1];
1493 $trail = $m[2];
1496 # Assume $this->postParseLinkColour(). This prevents
1497 # interwiki links from being parsed as external links.
1498 global $wgInterwikiLinkHolders;
1499 $t = "<a href=\"{$u}\"{$style}>{$text}{$inside}</a>";
1500 $nr = array_push($wgInterwikiLinkHolders, $t);
1501 $retVal = '<!--IWLINK '. ($nr-1) ."-->{$trail}";
1502 } elseif ( 0 == $nt->getNamespace() && "" == $nt->getText() ) {
1503 $retVal = $this->makeKnownLinkObj( $nt, $text, $query, $trail, $prefix );
1504 } elseif ( ( -1 == $nt->getNamespace() ) ||
1505 ( Namespace::getImage() == $nt->getNamespace() ) ) {
1506 $retVal = $this->makeKnownLinkObj( $nt, $text, $query, $trail, $prefix );
1507 } else {
1508 if ( $this->postParseLinkColour() ) {
1509 $inside = '';
1510 if ( '' != $trail ) {
1511 if ( preg_match( $this->linktrail, $trail, $m ) ) {
1512 $inside = $m[1];
1513 $trail = $m[2];
1517 # Allows wiki to bypass using linkcache, see OutputPage::parseLinkHolders()
1518 $nr = array_push( $wgLinkHolders['namespaces'], $nt->getNamespace() );
1519 $wgLinkHolders['dbkeys'][] = $nt->getDBkey();
1520 $wgLinkHolders['queries'][] = $query;
1521 $wgLinkHolders['texts'][] = $prefix.$text.$inside;
1522 $wgLinkHolders['titles'][] = $nt;
1524 $retVal = '<!--LINK '. ($nr-1) ."-->{$trail}";
1525 } else {
1526 # Work out link colour immediately
1527 $aid = $nt->getArticleID() ;
1528 if ( 0 == $aid ) {
1529 $retVal = $this->makeBrokenLinkObj( $nt, $text, $query, $trail, $prefix );
1530 } else {
1531 $threshold = $wgUser->getOption('stubthreshold') ;
1532 if ( $threshold > 0 ) {
1533 $dbr =& wfGetDB( DB_SLAVE );
1534 $s = $dbr->selectRow( 'cur', array( 'LENGTH(cur_text) AS x', 'cur_namespace',
1535 'cur_is_redirect' ), array( 'cur_id' => $aid ), $fname ) ;
1536 if ( $s !== false ) {
1537 $size = $s->x;
1538 if ( $s->cur_is_redirect OR $s->cur_namespace != 0 ) {
1539 $size = $threshold*2 ; # Really big
1541 $dbr->freeResult( $res );
1542 } else {
1543 $size = $threshold*2 ; # Really big
1545 } else {
1546 $size = 1 ;
1548 if ( $size < $threshold ) {
1549 $retVal = $this->makeStubLinkObj( $nt, $text, $query, $trail, $prefix );
1550 } else {
1551 $retVal = $this->makeKnownLinkObj( $nt, $text, $query, $trail, $prefix );
1556 return $retVal;
1560 * Pass a title object, not a title string
1562 function makeKnownLinkObj( &$nt, $text = '', $query = '', $trail = '', $prefix = '' , $aprops = '' ) {
1563 global $wgOut, $wgTitle, $wgInputEncoding;
1565 $fname = 'Skin::makeKnownLinkObj';
1566 wfProfileIn( $fname );
1568 if ( !is_object( $nt ) ) {
1569 return $text;
1571 $link = $nt->getPrefixedURL();
1572 # if ( '' != $section && substr($section,0,1) != "#" ) {
1573 # $section = ''
1575 if ( '' == $link ) {
1576 $u = '';
1577 if ( '' == $text ) {
1578 $text = htmlspecialchars( $nt->getFragment() );
1580 } else {
1581 $u = $nt->escapeLocalURL( $query );
1583 if ( '' != $nt->getFragment() ) {
1584 $anchor = urlencode( do_html_entity_decode( str_replace(' ', '_', $nt->getFragment()), ENT_COMPAT, $wgInputEncoding ) );
1585 $replacearray = array(
1586 '%3A' => ':',
1587 '%' => '.'
1589 $u .= '#' . str_replace(array_keys($replacearray),array_values($replacearray),$anchor);
1591 if ( '' == $text ) {
1592 $text = htmlspecialchars( $nt->getPrefixedText() );
1594 $style = $this->getInternalLinkAttributesObj( $nt, $text );
1596 $inside = '';
1597 if ( '' != $trail ) {
1598 if ( preg_match( $this->linktrail, $trail, $m ) ) {
1599 $inside = $m[1];
1600 $trail = $m[2];
1603 $r = "<a href=\"{$u}\"{$style}{$aprops}>{$prefix}{$text}{$inside}</a>{$trail}";
1604 wfProfileOut( $fname );
1605 return $r;
1609 * Pass a title object, not a title string
1611 function makeBrokenLinkObj( &$nt, $text = '', $query = '', $trail = '', $prefix = '' ) {
1612 global $wgOut, $wgUser;
1614 # Fail gracefully
1615 if ( ! isset($nt) ) {
1616 # wfDebugDieBacktrace();
1617 return "<!-- ERROR -->{$prefix}{$text}{$trail}";
1620 $fname = 'Skin::makeBrokenLinkObj';
1621 wfProfileIn( $fname );
1623 if ( '' == $query ) {
1624 $q = 'action=edit';
1625 } else {
1626 $q = 'action=edit&'.$query;
1628 $u = $nt->escapeLocalURL( $q );
1630 if ( '' == $text ) {
1631 $text = htmlspecialchars( $nt->getPrefixedText() );
1633 $style = $this->getInternalLinkAttributesObj( $nt, $text, "yes" );
1635 $inside = '';
1636 if ( '' != $trail ) {
1637 if ( preg_match( $this->linktrail, $trail, $m ) ) {
1638 $inside = $m[1];
1639 $trail = $m[2];
1642 if ( $wgUser->getOption( 'highlightbroken' ) ) {
1643 $s = "<a href=\"{$u}\"{$style}>{$prefix}{$text}{$inside}</a>{$trail}";
1644 } else {
1645 $s = "{$prefix}{$text}{$inside}<a href=\"{$u}\"{$style}>?</a>{$trail}";
1648 wfProfileOut( $fname );
1649 return $s;
1653 * Pass a title object, not a title string
1655 function makeStubLinkObj( &$nt, $text = '', $query = '', $trail = '', $prefix = '' ) {
1656 global $wgOut, $wgUser;
1658 $link = $nt->getPrefixedURL();
1660 $u = $nt->escapeLocalURL( $query );
1662 if ( '' == $text ) {
1663 $text = htmlspecialchars( $nt->getPrefixedText() );
1665 $style = $this->getInternalLinkAttributesObj( $nt, $text, 'stub' );
1667 $inside = '';
1668 if ( '' != $trail ) {
1669 if ( preg_match( $this->linktrail, $trail, $m ) ) {
1670 $inside = $m[1];
1671 $trail = $m[2];
1674 if ( $wgUser->getOption( 'highlightbroken' ) ) {
1675 $s = "<a href=\"{$u}\"{$style}>{$prefix}{$text}{$inside}</a>{$trail}";
1676 } else {
1677 $s = "{$prefix}{$text}{$inside}<a href=\"{$u}\"{$style}>!</a>{$trail}";
1679 return $s;
1682 function makeSelfLinkObj( &$nt, $text = '', $query = '', $trail = '', $prefix = '' ) {
1683 $u = $nt->escapeLocalURL( $query );
1684 if ( '' == $text ) {
1685 $text = htmlspecialchars( $nt->getPrefixedText() );
1687 $inside = '';
1688 if ( '' != $trail ) {
1689 if ( preg_match( $this->linktrail, $trail, $m ) ) {
1690 $inside = $m[1];
1691 $trail = $m[2];
1694 return "<strong>{$prefix}{$text}{$inside}</strong>{$trail}";
1697 /* these are used extensively in SkinPHPTal, but also some other places */
1698 /*static*/ function makeSpecialUrl( $name, $urlaction='' ) {
1699 $title = Title::makeTitle( NS_SPECIAL, $name );
1700 $this->checkTitle($title, $name);
1701 return $title->getLocalURL( $urlaction );
1703 /*static*/ function makeTalkUrl ( $name, $urlaction='' ) {
1704 $title = Title::newFromText( $name );
1705 $title = $title->getTalkPage();
1706 $this->checkTitle($title, $name);
1707 return $title->getLocalURL( $urlaction );
1709 /*static*/ function makeArticleUrl ( $name, $urlaction='' ) {
1710 $title = Title::newFromText( $name );
1711 $title= $title->getSubjectPage();
1712 $this->checkTitle($title, $name);
1713 return $title->getLocalURL( $urlaction );
1715 /*static*/ function makeI18nUrl ( $name, $urlaction='' ) {
1716 $title = Title::newFromText( wfMsgForContent($name) );
1717 $this->checkTitle($title, $name);
1718 return $title->getLocalURL( $urlaction );
1720 /*static*/ function makeUrl ( $name, $urlaction='' ) {
1721 $title = Title::newFromText( $name );
1722 $this->checkTitle($title, $name);
1723 return $title->getLocalURL( $urlaction );
1726 # If url string starts with http, consider as external URL, else
1727 # internal
1728 /*static*/ function makeInternalOrExternalUrl( $name ) {
1729 if ( strncmp( $name, 'http', 4 ) == 0 ) {
1730 return $name;
1731 } else {
1732 return $this->makeUrl( $name );
1736 # this can be passed the NS number as defined in Language.php
1737 /*static*/ function makeNSUrl( $name, $urlaction='', $namespace=0 ) {
1738 $title = Title::makeTitleSafe( $namespace, $name );
1739 $this->checkTitle($title, $name);
1740 return $title->getLocalURL( $urlaction );
1743 /* these return an array with the 'href' and boolean 'exists' */
1744 /*static*/ function makeUrlDetails ( $name, $urlaction='' ) {
1745 $title = Title::newFromText( $name );
1746 $this->checkTitle($title, $name);
1747 return array(
1748 'href' => $title->getLocalURL( $urlaction ),
1749 'exists' => $title->getArticleID() != 0?true:false
1752 /*static*/ function makeTalkUrlDetails ( $name, $urlaction='' ) {
1753 $title = Title::newFromText( $name );
1754 $title = $title->getTalkPage();
1755 $this->checkTitle($title, $name);
1756 return array(
1757 'href' => $title->getLocalURL( $urlaction ),
1758 'exists' => $title->getArticleID() != 0?true:false
1761 /*static*/ function makeArticleUrlDetails ( $name, $urlaction='' ) {
1762 $title = Title::newFromText( $name );
1763 $title= $title->getSubjectPage();
1764 $this->checkTitle($title, $name);
1765 return array(
1766 'href' => $title->getLocalURL( $urlaction ),
1767 'exists' => $title->getArticleID() != 0?true:false
1770 /*static*/ function makeI18nUrlDetails ( $name, $urlaction='' ) {
1771 $title = Title::newFromText( wfMsgForContent($name) );
1772 $this->checkTitle($title, $name);
1773 return array(
1774 'href' => $title->getLocalURL( $urlaction ),
1775 'exists' => $title->getArticleID() != 0?true:false
1779 # make sure we have some title to operate on
1780 /*static*/ function checkTitle ( &$title, &$name ) {
1781 if(!is_object($title)) {
1782 $title = Title::newFromText( $name );
1783 if(!is_object($title)) {
1784 $title = Title::newFromText( '--error: link target missing--' );
1789 function fnamePart( $url ) {
1790 $basename = strrchr( $url, '/' );
1791 if ( false === $basename ) {
1792 $basename = $url;
1793 } else {
1794 $basename = substr( $basename, 1 );
1796 return htmlspecialchars( $basename );
1799 function makeImage( $url, $alt = '' ) {
1800 global $wgOut;
1802 if ( '' == $alt ) {
1803 $alt = $this->fnamePart( $url );
1805 $s = '<img src="'.$url.'" alt="'.$alt.'" />';
1806 return $s;
1809 function makeImageLink( $name, $url, $alt = '' ) {
1810 $nt = Title::makeTitleSafe( NS_IMAGE, $name );
1811 return $this->makeImageLinkObj( $nt, $alt );
1814 function makeImageLinkObj( $nt, $alt = '' ) {
1815 global $wgContLang, $wgUseImageResize;
1816 $img = Image::newFromTitle( $nt );
1817 $url = $img->getURL();
1819 $align = '';
1820 $prefix = $postfix = '';
1822 if ( $wgUseImageResize ) {
1823 # Check if the alt text is of the form "options|alt text"
1824 # Options are:
1825 # * thumbnail make a thumbnail with enlarge-icon and caption, alignment depends on lang
1826 # * left no resizing, just left align. label is used for alt= only
1827 # * right same, but right aligned
1828 # * none same, but not aligned
1829 # * ___px scale to ___ pixels width, no aligning. e.g. use in taxobox
1830 # * center center the image
1831 # * framed Keep original image size, no magnify-button.
1833 $part = explode( '|', $alt);
1835 $mwThumb =& MagicWord::get( MAG_IMG_THUMBNAIL );
1836 $mwLeft =& MagicWord::get( MAG_IMG_LEFT );
1837 $mwRight =& MagicWord::get( MAG_IMG_RIGHT );
1838 $mwNone =& MagicWord::get( MAG_IMG_NONE );
1839 $mwWidth =& MagicWord::get( MAG_IMG_WIDTH );
1840 $mwCenter =& MagicWord::get( MAG_IMG_CENTER );
1841 $mwFramed =& MagicWord::get( MAG_IMG_FRAMED );
1842 $alt = $part[count($part)-1];
1844 $height = $framed = $thumb = false;
1845 $manual_thumb = "" ;
1847 foreach( $part as $key => $val ) {
1848 $val_parts = explode ( "=" , $val , 2 ) ;
1849 $left_part = array_shift ( $val_parts ) ;
1850 if ( ! is_null( $mwThumb->matchVariableStartToEnd($val) ) ) {
1851 $thumb=true;
1852 } elseif ( count ( $val_parts ) == 1 && ! is_null( $mwThumb->matchVariableStartToEnd($left_part) ) ) {
1853 # use manually specified thumbnail
1854 $thumb=true;
1855 $manual_thumb = array_shift ( $val_parts ) ;
1856 } elseif ( ! is_null( $mwRight->matchVariableStartToEnd($val) ) ) {
1857 # remember to set an alignment, don't render immediately
1858 $align = 'right';
1859 } elseif ( ! is_null( $mwLeft->matchVariableStartToEnd($val) ) ) {
1860 # remember to set an alignment, don't render immediately
1861 $align = 'left';
1862 } elseif ( ! is_null( $mwCenter->matchVariableStartToEnd($val) ) ) {
1863 # remember to set an alignment, don't render immediately
1864 $align = 'center';
1865 } elseif ( ! is_null( $mwNone->matchVariableStartToEnd($val) ) ) {
1866 # remember to set an alignment, don't render immediately
1867 $align = 'none';
1868 } elseif ( ! is_null( $match = $mwWidth->matchVariableStartToEnd($val) ) ) {
1869 # $match is the image width in pixels
1870 if ( preg_match( '/^([0-9]*)x([0-9]*)$/', $match, $m ) ) {
1871 $width = intval( $m[1] );
1872 $height = intval( $m[2] );
1873 } else {
1874 $width = intval($match);
1876 } elseif ( ! is_null( $mwFramed->matchVariableStartToEnd($val) ) ) {
1877 $framed=true;
1880 if ( 'center' == $align )
1882 $prefix = '<span style="text-align: center">';
1883 $postfix = '</span>';
1884 $align = 'none';
1887 if ( $thumb || $framed ) {
1889 # Create a thumbnail. Alignment depends on language
1890 # writing direction, # right aligned for left-to-right-
1891 # languages ("Western languages"), left-aligned
1892 # for right-to-left-languages ("Semitic languages")
1894 # If thumbnail width has not been provided, it is set
1895 # here to 180 pixels
1896 if ( $align == '' ) {
1897 $align = $wgContLang->isRTL() ? 'left' : 'right';
1899 if ( ! isset($width) ) {
1900 $width = 180;
1902 return $prefix.$this->makeThumbLinkObj( $img, $alt, $align, $width, $height, $framed, $manual_thumb ).$postfix;
1904 } elseif ( isset($width) ) {
1906 # Create a resized image, without the additional thumbnail
1907 # features
1909 if ( ( ! $height === false )
1910 && ( $img->getHeight() * $width / $img->getWidth() > $height ) ) {
1911 print "height=$height<br>\nimg->getHeight() = ".$img->getHeight()."<br>\n";
1912 print 'rescaling by factor '. $height / $img->getHeight() . "<br>\n";
1913 $width = $img->getWidth() * $height / $img->getHeight();
1915 if ( '' == $manual_thumb ) $url = $img->createThumb( $width );
1917 } # endif $wgUseImageResize
1919 if ( empty( $alt ) ) {
1920 $alt = preg_replace( '/\.(.+?)^/', '', $img->getName() );
1922 $alt = htmlspecialchars( $alt );
1924 $u = $nt->escapeLocalURL();
1925 if ( $url == '' )
1927 $s = wfMsg( 'missingimage', $img->getName() );
1928 $s .= "<br>{$alt}<br>{$url}<br>\n";
1929 } else {
1930 $s = '<a href="'.$u.'" class="image" title="'.$alt.'">' .
1931 '<img src="'.$url.'" alt="'.$alt.'" /></a>';
1933 if ( '' != $align ) {
1934 $s = "<div class=\"float{$align}\"><span>{$s}</span></div>";
1936 return str_replace("\n", ' ',$prefix.$s.$postfix);
1940 * Make HTML for a thumbnail including image, border and caption
1941 * $img is an Image object
1943 function makeThumbLinkObj( $img, $label = '', $align = 'right', $boxwidth = 180, $boxheight=false, $framed=false , $manual_thumb = "" ) {
1944 global $wgStylePath, $wgContLang;
1945 # $image = Title::makeTitleSafe( NS_IMAGE, $name );
1946 $url = $img->getURL();
1948 #$label = htmlspecialchars( $label );
1949 $alt = preg_replace( '/<[^>]*>/', '', $label);
1950 $alt = htmlspecialchars( $alt );
1952 $width = $height = 0;
1953 if ( $img->exists() )
1955 $width = $img->getWidth();
1956 $height = $img->getHeight();
1958 if ( 0 == $width || 0 == $height )
1960 $width = $height = 200;
1962 if ( $boxwidth == 0 )
1964 $boxwidth = 200;
1966 if ( $framed )
1968 // Use image dimensions, don't scale
1969 $boxwidth = $width;
1970 $oboxwidth = $boxwidth + 2;
1971 $boxheight = $height;
1972 $thumbUrl = $url;
1973 } else {
1974 $h = intval( $height/($width/$boxwidth) );
1975 $oboxwidth = $boxwidth + 2;
1976 if ( ( ! $boxheight === false ) && ( $h > $boxheight ) )
1978 $boxwidth *= $boxheight/$h;
1979 } else {
1980 $boxheight = $h;
1982 if ( '' == $manual_thumb ) $thumbUrl = $img->createThumb( $boxwidth );
1985 if ( $manual_thumb != '' ) # Use manually specified thumbnail
1987 $manual_title = Title::makeTitleSafe( NS_IMAGE, $manual_thumb ); #new Title ( $manual_thumb ) ;
1988 $manual_img = Image::newFromTitle( $manual_title );
1989 $thumbUrl = $manual_img->getURL();
1990 if ( $manual_img->exists() )
1992 $width = $manual_img->getWidth();
1993 $height = $manual_img->getHeight();
1994 $boxwidth = $width ;
1995 $boxheight = $height ;
1996 $oboxwidth = $boxwidth + 2 ;
2000 $u = $img->getEscapeLocalURL();
2002 $more = htmlspecialchars( wfMsg( 'thumbnail-more' ) );
2003 $magnifyalign = $wgContLang->isRTL() ? 'left' : 'right';
2004 $textalign = $wgContLang->isRTL() ? ' style="text-align:right"' : '';
2006 $s = "<div class=\"thumb t{$align}\"><div style=\"width:{$oboxwidth}px;\">";
2007 if ( $thumbUrl == '' ) {
2008 $s .= wfMsg( 'missingimage', $img->getName() );
2009 $zoomicon = '';
2010 } else {
2011 $s .= '<a href="'.$u.'" class="internal" title="'.$alt.'">'.
2012 '<img src="'.$thumbUrl.'" alt="'.$alt.'" ' .
2013 'width="'.$boxwidth.'" height="'.$boxheight.'" /></a>';
2014 if ( $framed ) {
2015 $zoomicon="";
2016 } else {
2017 $zoomicon = '<div class="magnify" style="float:'.$magnifyalign.'">'.
2018 '<a href="'.$u.'" class="internal" title="'.$more.'">'.
2019 '<img src="'.$wgStylePath.'/common/images/magnify-clip.png" ' .
2020 'width="15" height="11" alt="'.$more.'" /></a></div>';
2023 $s .= ' <div class="thumbcaption" '.$textalign.'>'.$zoomicon.$label."</div></div></div>";
2024 return str_replace("\n", ' ', $s);
2027 function makeMediaLink( $name, $url, $alt = '' ) {
2028 $nt = Title::makeTitleSafe( Namespace::getMedia(), $name );
2029 return $this->makeMediaLinkObj( $nt, $alt );
2032 function makeMediaLinkObj( $nt, $alt = '' ) {
2033 if ( ! isset( $nt ) )
2035 ### HOTFIX. Instead of breaking, return empty string.
2036 $s = $alt;
2037 } else {
2038 $name = $nt->getDBKey();
2039 $url = Image::wfImageUrl( $name );
2040 if ( empty( $alt ) ) {
2041 $alt = preg_replace( '/\.(.+?)^/', '', $name );
2044 $u = htmlspecialchars( $url );
2045 $s = "<a href=\"{$u}\" class='internal' title=\"{$alt}\">{$alt}</a>";
2047 return $s;
2050 function specialLink( $name, $key = '' ) {
2051 global $wgContLang;
2053 if ( '' == $key ) { $key = strtolower( $name ); }
2054 $pn = $wgContLang->ucfirst( $name );
2055 return $this->makeKnownLink( $wgContLang->specialPage( $pn ),
2056 wfMsg( $key ) );
2059 function makeExternalLink( $url, $text, $escape = true ) {
2060 $style = $this->getExternalLinkAttributes( $url, $text );
2061 $url = htmlspecialchars( $url );
2062 if( $escape ) {
2063 $text = htmlspecialchars( $text );
2065 return '<a href="'.$url.'"'.$style.'>'.$text.'</a>';
2068 # Called by history lists and recent changes
2071 # Returns text for the start of the tabular part of RC
2072 function beginRecentChangesList() {
2073 $this->rc_cache = array() ;
2074 $this->rcMoveIndex = 0;
2075 $this->rcCacheIndex = 0 ;
2076 $this->lastdate = '';
2077 $this->rclistOpen = false;
2078 return '';
2081 function beginImageHistoryList() {
2082 $s = "\n<h2>" . wfMsg( 'imghistory' ) . "</h2>\n" .
2083 "<p>" . wfMsg( 'imghistlegend' ) . "</p>\n".'<ul class="special">';
2084 return $s;
2088 * Returns text for the end of RC
2089 * If enhanced RC is in use, returns pretty much all the text
2091 function endRecentChangesList() {
2092 $s = $this->recentChangesBlock() ;
2093 if( $this->rclistOpen ) {
2094 $s .= "</ul>\n";
2096 return $s;
2100 * Enhanced RC ungrouped line
2102 function recentChangesBlockLine ( $rcObj ) {
2103 global $wgStylePath, $wgContLang ;
2105 # Get rc_xxxx variables
2106 extract( $rcObj->mAttribs ) ;
2107 $curIdEq = 'curid='.$rc_cur_id;
2109 # Spacer image
2110 $r = '' ;
2112 $r .= '<img src="'.$wgStylePath.'/common/images/Arr_.png" width="12" height="12" border="0" />' ;
2113 $r .= '<tt>' ;
2115 if ( $rc_type == RC_MOVE || $rc_type == RC_MOVE_OVER_REDIRECT ) {
2116 $r .= '&nbsp;&nbsp;';
2117 } else {
2118 # M & N (minor & new)
2119 $M = wfMsg( 'minoreditletter' );
2120 $N = wfMsg( 'newpageletter' );
2122 if ( $rc_type == RC_NEW ) {
2123 $r .= $N ;
2124 } else {
2125 $r .= '&nbsp;' ;
2127 if ( $rc_minor ) {
2128 $r .= $M ;
2129 } else {
2130 $r .= '&nbsp;' ;
2134 # Timestamp
2135 $r .= ' '.$rcObj->timestamp.' ' ;
2136 $r .= '</tt>' ;
2138 # Article link
2139 $link = $rcObj->link ;
2140 if ( $rcObj->watched ) $link = '<strong>'.$link.'</strong>' ;
2141 $r .= $link ;
2143 # Diff
2144 $r .= ' (' ;
2145 $r .= $rcObj->difflink ;
2146 $r .= '; ' ;
2148 # Hist
2149 $r .= $this->makeKnownLinkObj( $rcObj->getTitle(), wfMsg( 'hist' ), $curIdEq.'&action=history' );
2151 # User/talk
2152 $r .= ') . . '.$rcObj->userlink ;
2153 $r .= $rcObj->usertalklink ;
2155 # Comment
2156 if ( $rc_comment != '' && $rc_type != RC_MOVE && $rc_type != RC_MOVE_OVER_REDIRECT ) {
2157 $rc_comment=$this->formatComment($rc_comment, $rcObj->getTitle());
2158 $r .= $wgContLang->emphasize( ' ('.$rc_comment.')' );
2161 $r .= "<br />\n" ;
2162 return $r ;
2166 * Enhanced RC group
2168 function recentChangesBlockGroup ( $block ) {
2169 global $wgStylePath, $wgContLang ;
2171 $r = '' ;
2172 $M = wfMsg( 'minoreditletter' );
2173 $N = wfMsg( 'newpageletter' );
2175 # Collate list of users
2176 $isnew = false ;
2177 $userlinks = array () ;
2178 foreach ( $block AS $rcObj ) {
2179 $oldid = $rcObj->mAttribs['rc_last_oldid'];
2180 if ( $rcObj->mAttribs['rc_new'] ) $isnew = true ;
2181 $u = $rcObj->userlink ;
2182 if ( !isset ( $userlinks[$u] ) ) $userlinks[$u] = 0 ;
2183 $userlinks[$u]++ ;
2186 # Sort the list and convert to text
2187 krsort ( $userlinks ) ;
2188 asort ( $userlinks ) ;
2189 $users = array () ;
2190 foreach ( $userlinks as $userlink => $count) {
2191 $text = $userlink ;
2192 if ( $count > 1 ) $text .= " ({$count}&times;)" ;
2193 array_push ( $users , $text ) ;
2195 $users = ' <font size="-1">['.implode('; ',$users).']</font>' ;
2197 # Arrow
2198 $rci = 'RCI'.$this->rcCacheIndex ;
2199 $rcl = 'RCL'.$this->rcCacheIndex ;
2200 $rcm = 'RCM'.$this->rcCacheIndex ;
2201 $toggleLink = "javascript:toggleVisibility('$rci','$rcm','$rcl')" ;
2202 $arrowdir = $wgContLang->isRTL() ? 'l' : 'r';
2203 $tl = '<span id="'.$rcm.'"><a href="'.$toggleLink.'"><img src="'.$wgStylePath.'/common/images/Arr_'.$arrowdir.'.png" width="12" height="12" /></a></span>' ;
2204 $tl .= '<span id="'.$rcl.'" style="display:none"><a href="'.$toggleLink.'"><img src="'.$wgStylePath.'/common/images/Arr_d.png" width="12" height="12" /></a></span>' ;
2205 $r .= $tl ;
2207 # Main line
2208 # M/N
2209 $r .= '<tt>' ;
2210 if ( $isnew ) $r .= $N ;
2211 else $r .= '&nbsp;' ;
2212 $r .= '&nbsp;' ; # Minor
2214 # Timestamp
2215 $r .= ' '.$block[0]->timestamp.' ' ;
2216 $r .= '</tt>' ;
2218 # Article link
2219 $link = $block[0]->link ;
2220 if ( $block[0]->watched ) $link = '<strong>'.$link.'</strong>' ;
2221 $r .= $link ;
2223 $curIdEq = 'curid=' . $block[0]->mAttribs['rc_cur_id'];
2224 if ( $block[0]->mAttribs['rc_type'] != RC_LOG ) {
2225 # Changes
2226 $r .= ' ('.count($block).' ' ;
2227 if ( $isnew ) $r .= wfMsg('changes');
2228 else $r .= $this->makeKnownLinkObj( $block[0]->getTitle() , wfMsg('changes') ,
2229 $curIdEq.'&diff=0&oldid='.$oldid ) ;
2230 $r .= '; ' ;
2232 # History
2233 $r .= $this->makeKnownLinkObj( $block[0]->getTitle(), wfMsg( 'history' ), $curIdEq.'&action=history' );
2234 $r .= ')' ;
2237 $r .= $users ;
2238 $r .= "<br />\n" ;
2240 # Sub-entries
2241 $r .= '<div id="'.$rci.'" style="display:none">' ;
2242 foreach ( $block AS $rcObj ) {
2243 # Get rc_xxxx variables
2244 extract( $rcObj->mAttribs );
2246 $r .= '<img src="'.$wgStylePath.'/common/images/Arr_.png" width="12" height="12" />';
2247 $r .= '<tt>&nbsp; &nbsp; &nbsp; &nbsp;' ;
2248 if ( $rc_new ) $r .= $N ;
2249 else $r .= '&nbsp;' ;
2250 if ( $rc_minor ) $r .= $M ;
2251 else $r .= '&nbsp;' ;
2252 $r .= '</tt>' ;
2254 $o = '' ;
2255 if ( $rc_last_oldid != 0 ) {
2256 $o = 'oldid='.$rc_last_oldid ;
2258 if ( $rc_type == RC_LOG ) {
2259 $link = $rcObj->timestamp ;
2260 } else {
2261 $link = $this->makeKnownLinkObj( $rcObj->getTitle(), $rcObj->timestamp , "{$curIdEq}&$o" ) ;
2263 $link = '<tt>'.$link.'</tt>' ;
2265 $r .= $link ;
2266 $r .= ' (' ;
2267 $r .= $rcObj->curlink ;
2268 $r .= '; ' ;
2269 $r .= $rcObj->lastlink ;
2270 $r .= ') . . '.$rcObj->userlink ;
2271 $r .= $rcObj->usertalklink ;
2272 if ( $rc_comment != '' ) {
2273 $rc_comment=$this->formatComment($rc_comment, $rcObj->getTitle());
2274 $r .= $wgContLang->emphasize( ' ('.$rc_comment.')' ) ;
2276 $r .= "<br />\n" ;
2278 $r .= "</div>\n" ;
2280 $this->rcCacheIndex++ ;
2281 return $r ;
2285 * If enhanced RC is in use, this function takes the previously cached
2286 * RC lines, arranges them, and outputs the HTML
2288 function recentChangesBlock () {
2289 global $wgStylePath ;
2290 if ( count ( $this->rc_cache ) == 0 ) return '' ;
2291 $blockOut = '';
2292 foreach ( $this->rc_cache AS $secureName => $block ) {
2293 if ( count ( $block ) < 2 ) {
2294 $blockOut .= $this->recentChangesBlockLine ( array_shift ( $block ) ) ;
2295 } else {
2296 $blockOut .= $this->recentChangesBlockGroup ( $block ) ;
2300 return '<div>'.$blockOut.'</div>' ;
2304 * Called in a loop over all displayed RC entries
2305 * Either returns the line, or caches it for later use
2307 function recentChangesLine( &$rc, $watched = false ) {
2308 global $wgUser ;
2309 $usenew = $wgUser->getOption( 'usenewrc' );
2310 if ( $usenew )
2311 $line = $this->recentChangesLineNew ( $rc, $watched ) ;
2312 else
2313 $line = $this->recentChangesLineOld ( $rc, $watched ) ;
2314 return $line ;
2317 function recentChangesLineOld( &$rc, $watched = false ) {
2318 global $wgTitle, $wgLang, $wgContLang, $wgUser, $wgRCSeconds, $wgUseRCPatrol, $wgOnlySysopsCanPatrol;
2320 # Extract DB fields into local scope
2321 extract( $rc->mAttribs );
2322 $curIdEq = 'curid=' . $rc_cur_id;
2324 # Make date header if necessary
2325 $date = $wgContLang->date( $rc_timestamp, true);
2326 $uidate = $wgLang->date( $rc_timestamp, true);
2327 $s = '';
2328 if ( $date != $this->lastdate ) {
2329 if ( '' != $this->lastdate ) { $s .= "</ul>\n"; }
2330 $s .= "<h4>{$uidate}</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( $wgContLang->specialPage( 'Contributions' ),
2400 $rc_user_text, 'target=' . $rc_user_text );
2401 } else {
2402 $userLink = $this->makeLink( $wgContLang->getNsText( NS_USER ) . ':'.$rc_user_text, $rc_user_text );
2404 $s .= $userLink;
2406 # User talk link
2407 $talkname=$wgContLang->getNsText(NS_TALK); # use the shorter name
2408 global $wgDisableAnonTalk;
2409 if( 0 == $rc_user && $wgDisableAnonTalk ) {
2410 $userTalkLink = '';
2411 } else {
2412 $utns=$wgContLang->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( $wgContLang->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 .= $wgContLang->emphasize(' (' . $rc_comment . ')');
2433 $s .= "</li>\n";
2435 return $s;
2438 function recentChangesLineNew( &$baseRC, $watched = false ) {
2439 global $wgTitle, $wgLang, $wgContLang, $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 = $wgContLang->date( $rc_timestamp, true);
2450 $uidate = $wgLang->date( $rc_timestamp, true);
2451 $ret = '';
2452 if ( $date != $this->lastdate ) {
2453 # Process current cache
2454 $ret = $this->recentChangesBlock () ;
2455 $this->rc_cache = array() ;
2456 $ret .= "<h4>{$uidate}</h4>\n";
2457 $this->lastdate = $date;
2460 # Make article link
2461 if ( $rc_type == RC_MOVE || $rc_type == RC_MOVE_OVER_REDIRECT ) {
2462 $msg = ( $rc_type == RC_MOVE ) ? "1movedto2" : "1movedto2_redir";
2463 $clink = wfMsg( $msg, $this->makeKnownLinkObj( $rc->getTitle(), '', 'redirect=no' ),
2464 $this->makeKnownLinkObj( $rc->getMovedToTitle(), '' ) );
2465 } elseif( $rc_namespace == NS_SPECIAL && preg_match( '!^Log/(.*)$!', $rc_title, $matches ) ) {
2466 # Log updates, etc
2467 $logtype = $matches[1];
2468 $logname = LogPage::logName( $logtype );
2469 $clink = '(' . $this->makeKnownLinkObj( $rc->getTitle(), $logname ) . ')';
2470 } else {
2471 $clink = $this->makeKnownLinkObj( $rc->getTitle(), '' ) ;
2474 $time = $wgContLang->time( $rc_timestamp, true, $wgRCSeconds );
2475 $rc->watched = $watched ;
2476 $rc->link = $clink ;
2477 $rc->timestamp = $time;
2479 # Make "cur" and "diff" links
2480 if ( ( $rc_type == RC_NEW && $rc_this_oldid == 0 ) || $rc_type == RC_LOG || $rc_type == RC_MOVE || $rc_type == RC_MOVE_OVER_REDIRECT ) {
2481 $curLink = wfMsg( 'cur' );
2482 $diffLink = wfMsg( 'diff' );
2483 } else {
2484 $query = $curIdEq.'&diff=0&oldid='.$rc_this_oldid;
2485 $aprops = ' tabindex="'.$baseRC->counter.'"';
2486 $curLink = $this->makeKnownLinkObj( $rc->getTitle(), wfMsg( 'cur' ), $query, '' ,'' , $aprops );
2487 $diffLink = $this->makeKnownLinkObj( $rc->getTitle(), wfMsg( 'diff'), $query, '' ,'' , $aprops );
2490 # Make "last" link
2491 $titleObj = $rc->getTitle();
2492 if ( $rc_last_oldid == 0 || $rc_type == RC_LOG || $rc_type == RC_MOVE || $rc_type == RC_MOVE_OVER_REDIRECT ) {
2493 $lastLink = wfMsg( 'last' );
2494 } else {
2495 $lastLink = $this->makeKnownLinkObj( $rc->getTitle(), wfMsg( 'last' ),
2496 $curIdEq.'&diff='.$rc_this_oldid.'&oldid='.$rc_last_oldid );
2499 # Make user link (or user contributions for unregistered users)
2500 if ( $rc_user == 0 ) {
2501 $userLink = $this->makeKnownLink( $wgContLang->specialPage( 'Contributions' ),
2502 $rc_user_text, 'target=' . $rc_user_text );
2503 } else {
2504 $userLink = $this->makeLink( $wgContLang->getNsText(
2505 Namespace::getUser() ) . ':'.$rc_user_text, $rc_user_text );
2508 $rc->userlink = $userLink;
2509 $rc->lastlink = $lastLink;
2510 $rc->curlink = $curLink;
2511 $rc->difflink = $diffLink;
2513 # Make user talk link
2514 $utns=$wgContLang->getNsText(NS_USER_TALK);
2515 $talkname=$wgContLang->getNsText(NS_TALK); # use the shorter name
2516 $userTalkLink= $this->makeLink($utns . ':'.$rc_user_text, $talkname );
2518 global $wgDisableAnonTalk;
2519 if ( ( 0 == $rc_user ) && $wgUser->isSysop() ) {
2520 $blockLink = $this->makeKnownLink( $wgContLang->specialPage(
2521 'Blockip' ), wfMsg( 'blocklink' ), 'ip='.$rc_user_text );
2522 if( $wgDisableAnonTalk )
2523 $rc->usertalklink = ' ('.$blockLink.')';
2524 else
2525 $rc->usertalklink = ' ('.$userTalkLink.' | '.$blockLink.')';
2526 } else {
2527 if( $wgDisableAnonTalk && ($rc_user == 0) )
2528 $rc->usertalklink = '';
2529 else
2530 $rc->usertalklink = ' ('.$userTalkLink.')';
2533 # Put accumulated information into the cache, for later display
2534 # Page moves go on their own line
2535 $title = $rc->getTitle();
2536 $secureName = $title->getPrefixedDBkey();
2537 if ( $rc_type == RC_MOVE || $rc_type == RC_MOVE_OVER_REDIRECT ) {
2538 # Use an @ character to prevent collision with page names
2539 $this->rc_cache['@@' . ($this->rcMoveIndex++)] = array($rc);
2540 } else {
2541 if ( !isset ( $this->rc_cache[$secureName] ) ) $this->rc_cache[$secureName] = array() ;
2542 array_push ( $this->rc_cache[$secureName] , $rc ) ;
2544 return $ret;
2547 function endImageHistoryList() {
2548 $s = "</ul>\n";
2549 return $s;
2553 * This function is called by all recent changes variants, by the page history,
2554 * and by the user contributions list. It is responsible for formatting edit
2555 * comments. It escapes any HTML in the comment, but adds some CSS to format
2556 * auto-generated comments (from section editing) and formats [[wikilinks]].
2558 * The &$title parameter must be a title OBJECT. It is used to generate a
2559 * direct link to the section in the autocomment.
2560 * @author Erik Moeller <moeller@scireview.de>
2562 * Note: there's not always a title to pass to this function.
2563 * Since you can't set a default parameter for a reference, I've turned it
2564 * temporarily to a value pass. Should be adjusted further. --brion
2566 function formatComment($comment, $title = NULL) {
2567 global $wgContLang;
2568 $comment = htmlspecialchars( $comment );
2570 # The pattern for autogen comments is / * foo * /, which makes for
2571 # some nasty regex.
2572 # We look for all comments, match any text before and after the comment,
2573 # add a separator where needed and format the comment itself with CSS
2574 while (preg_match('/(.*)\/\*\s*(.*?)\s*\*\/(.*)/', $comment,$match)) {
2575 $pre=$match[1];
2576 $auto=$match[2];
2577 $post=$match[3];
2578 $link='';
2579 if($title) {
2580 $section=$auto;
2582 # This is hackish but should work in most cases.
2583 $section=str_replace('[[','',$section);
2584 $section=str_replace(']]','',$section);
2585 $title->mFragment=$section;
2586 $link=$this->makeKnownLinkObj($title,wfMsg('sectionlink'));
2588 $sep='-';
2589 $auto=$link.$auto;
2590 if($pre) { $auto = $sep.' '.$auto; }
2591 if($post) { $auto .= ' '.$sep; }
2592 $auto='<span class="autocomment">'.$auto.'</span>';
2593 $comment=$pre.$auto.$post;
2596 # format regular and media links - all other wiki formatting
2597 # is ignored
2598 $medians = $wgContLang->getNsText(Namespace::getMedia()).':';
2599 while(preg_match('/\[\[(.*?)(\|(.*?))*\]\](.*)$/',$comment,$match)) {
2600 # Handle link renaming [[foo|text]] will show link as "text"
2601 if( "" != $match[3] ) {
2602 $text = $match[3];
2603 } else {
2604 $text = $match[1];
2606 if( preg_match( '/^' . $medians . '(.*)$/i', $match[1], $submatch ) ) {
2607 # Media link; trail not supported.
2608 $linkRegexp = '/\[\[(.*?)\]\]/';
2609 $thelink = $this->makeMediaLink( $submatch[1], "", $text );
2610 } else {
2611 # Other kind of link
2612 if( preg_match( wfMsgForContent( "linktrail" ), $match[4], $submatch ) ) {
2613 $trail = $submatch[1];
2614 } else {
2615 $trail = "";
2617 $linkRegexp = '/\[\[(.*?)\]\]' . preg_quote( $trail, '/' ) . '/';
2618 if ($match[1][0] == ':')
2619 $match[1] = substr($match[1], 1);
2620 $thelink = $this->makeLink( $match[1], $text, "", $trail );
2622 $comment = preg_replace( $linkRegexp, $thelink, $comment, 1 );
2624 return $comment;
2627 function imageHistoryLine( $iscur, $timestamp, $img, $user, $usertext, $size, $description ) {
2628 global $wgUser, $wgLang, $wgContLang, $wgTitle;
2630 $datetime = $wgLang->timeanddate( $timestamp, true );
2631 $del = wfMsg( 'deleteimg' );
2632 $delall = wfMsg( 'deleteimgcompletely' );
2633 $cur = wfMsg( 'cur' );
2635 if ( $iscur ) {
2636 $url = Image::wfImageUrl( $img );
2637 $rlink = $cur;
2638 if ( $wgUser->isSysop() ) {
2639 $link = $wgTitle->escapeLocalURL( 'image=' . $wgTitle->getPartialURL() .
2640 '&action=delete' );
2641 $style = $this->getInternalLinkAttributes( $link, $delall );
2643 $dlink = '<a href="'.$link.'"'.$style.'>'.$delall.'</a>';
2644 } else {
2645 $dlink = $del;
2647 } else {
2648 $url = htmlspecialchars( wfImageArchiveUrl( $img ) );
2649 if( $wgUser->getID() != 0 && $wgTitle->userCanEdit() ) {
2650 $rlink = $this->makeKnownLink( $wgTitle->getPrefixedText(),
2651 wfMsg( 'revertimg' ), 'action=revert&oldimage=' .
2652 urlencode( $img ) );
2653 $dlink = $this->makeKnownLink( $wgTitle->getPrefixedText(),
2654 $del, 'action=delete&oldimage=' . urlencode( $img ) );
2655 } else {
2656 # Having live active links for non-logged in users
2657 # means that bots and spiders crawling our site can
2658 # inadvertently change content. Baaaad idea.
2659 $rlink = wfMsg( 'revertimg' );
2660 $dlink = $del;
2663 if ( 0 == $user ) {
2664 $userlink = $usertext;
2665 } else {
2666 $userlink = $this->makeLink( $wgContLang->getNsText( Namespace::getUser() ) .
2667 ':'.$usertext, $usertext );
2669 $nbytes = wfMsg( 'nbytes', $size );
2670 $style = $this->getInternalLinkAttributes( $url, $datetime );
2672 $s = "<li> ({$dlink}) ({$rlink}) <a href=\"{$url}\"{$style}>{$datetime}</a>"
2673 . " . . {$userlink} ({$nbytes})";
2675 if ( '' != $description && '*' != $description ) {
2676 $sk=$wgUser->getSkin();
2677 $s .= $wgContLang->emphasize(' (' . $sk->formatComment($description,$wgTitle) . ')');
2679 $s .= "</li>\n";
2680 return $s;
2683 function tocIndent($level) {
2684 return str_repeat( '<div class="tocindent">'."\n", $level>0 ? $level : 0 );
2687 function tocUnindent($level) {
2688 return str_repeat( "</div>\n", $level>0 ? $level : 0 );
2692 * parameter level defines if we are on an indentation level
2694 function tocLine( $anchor, $tocline, $level ) {
2695 $link = '<a href="#'.$anchor.'">'.$tocline.'</a><br />';
2696 if($level) {
2697 return $link."\n";
2698 } else {
2699 return '<div class="tocline">'.$link."</div>\n";
2704 function tocTable($toc) {
2705 # note to CSS fanatics: putting this in a div does not work -- div won't auto-expand
2706 # try min-width & co when somebody gets a chance
2707 $hideline = ' <script type="text/javascript">showTocToggle("' . addslashes( wfMsg('showtoc') ) . '","' . addslashes( wfMsg('hidetoc') ) . '")</script>';
2708 return
2709 '<table border="0" id="toc"><tr id="toctitle"><td align="center">'."\n".
2710 '<b>'.wfMsg('toc').'</b>' .
2711 $hideline .
2712 '</td></tr><tr id="tocinside"><td>'."\n".
2713 $toc."</td></tr></table>\n";
2717 * These two do not check for permissions: check $wgTitle->userCanEdit
2718 * before calling them
2720 function editSectionScriptForOther( $title, $section, $head ) {
2721 $ttl = Title::newFromText( $title );
2722 $url = $ttl->escapeLocalURL( 'action=edit&section='.$section );
2723 return '<span oncontextmenu=\'document.location="'.$url.'";return false;\'>'.$head.'</span>';
2726 function editSectionScript( $section, $head ) {
2727 global $wgTitle, $wgRequest;
2728 if( $wgRequest->getInt( 'oldid' ) && ( $wgRequest->getVal( 'diff' ) != '0' ) ) {
2729 return $head;
2731 $url = $wgTitle->escapeLocalURL( 'action=edit&section='.$section );
2732 return '<span oncontextmenu=\'document.location="'.$url.'";return false;\'>'.$head.'</span>';
2735 function editSectionLinkForOther( $title, $section ) {
2736 global $wgRequest;
2737 global $wgUser, $wgContLang;
2739 $title = Title::newFromText($title);
2740 $editurl = '&section='.$section;
2741 $url = $this->makeKnownLink($title->getPrefixedText(),wfMsg('editsection'),'action=edit'.$editurl);
2743 if( $wgContLang->isRTL() ) {
2744 $farside = 'left';
2745 $nearside = 'right';
2746 } else {
2747 $farside = 'right';
2748 $nearside = 'left';
2750 return "<div class=\"editsection\" style=\"float:$farside;margin-$nearside:5px;\">[".$url."]</div>";
2754 function editSectionLink( $section ) {
2755 global $wgRequest;
2756 global $wgTitle, $wgUser, $wgContLang;
2758 if( $wgRequest->getInt( 'oldid' ) && ( $wgRequest->getVal( 'diff' ) != '0' ) ) {
2759 # Section edit links would be out of sync on an old page.
2760 # But, if we're diffing to the current page, they'll be
2761 # correct.
2762 return '';
2765 $editurl = '&section='.$section;
2766 $url = $this->makeKnownLink($wgTitle->getPrefixedText(),wfMsg('editsection'),'action=edit'.$editurl);
2768 if( $wgContLang->isRTL() ) {
2769 $farside = 'left';
2770 $nearside = 'right';
2771 } else {
2772 $farside = 'right';
2773 $nearside = 'left';
2775 return "<div class=\"editsection\" style=\"float:$farside;margin-$nearside:5px;\">[".$url."]</div>";
2780 * This function is called by EditPage.php and shows a bulletin board style
2781 * toolbar for common editing functions. It can be disabled in the user
2782 * preferences.
2783 * The necessary JavaScript code can be found in style/wikibits.js.
2785 function getEditToolbar() {
2786 global $wgStylePath, $wgLang, $wgMimeType;
2789 * toolarray an array of arrays which each include the filename of
2790 * the button image (without path), the opening tag, the closing tag,
2791 * and optionally a sample text that is inserted between the two when no
2792 * selection is highlighted.
2793 * The tip text is shown when the user moves the mouse over the button.
2795 * Already here are accesskeys (key), which are not used yet until someone
2796 * can figure out a way to make them work in IE. However, we should make
2797 * sure these keys are not defined on the edit page.
2799 $toolarray=array(
2800 array( 'image'=>'button_bold.png',
2801 'open' => "\'\'\'",
2802 'close' => "\'\'\'",
2803 'sample'=> wfMsg('bold_sample'),
2804 'tip' => wfMsg('bold_tip'),
2805 'key' => 'B'
2807 array( 'image'=>'button_italic.png',
2808 'open' => "\'\'",
2809 'close' => "\'\'",
2810 'sample'=> wfMsg('italic_sample'),
2811 'tip' => wfMsg('italic_tip'),
2812 'key' => 'I'
2814 array( 'image'=>'button_link.png',
2815 'open' => '[[',
2816 'close' => ']]',
2817 'sample'=> wfMsg('link_sample'),
2818 'tip' => wfMsg('link_tip'),
2819 'key' => 'L'
2821 array( 'image'=>'button_extlink.png',
2822 'open' => '[',
2823 'close' => ']',
2824 'sample'=> wfMsg('extlink_sample'),
2825 'tip' => wfMsg('extlink_tip'),
2826 'key' => 'X'
2828 array( 'image'=>'button_headline.png',
2829 'open' => "\\n== ",
2830 'close' => " ==\\n",
2831 'sample'=> wfMsg('headline_sample'),
2832 'tip' => wfMsg('headline_tip'),
2833 'key' => 'H'
2835 array( 'image'=>'button_image.png',
2836 'open' => '[['.$wgLang->getNsText(NS_IMAGE).":",
2837 'close' => ']]',
2838 'sample'=> wfMsg('image_sample'),
2839 'tip' => wfMsg('image_tip'),
2840 'key' => 'D'
2842 array( 'image' => 'button_media.png',
2843 'open' => '[['.$wgLang->getNsText(NS_MEDIA).':',
2844 'close' => ']]',
2845 'sample'=> wfMsg('media_sample'),
2846 'tip' => wfMsg('media_tip'),
2847 'key' => 'M'
2849 array( 'image' => 'button_math.png',
2850 'open' => "\\<math\\>",
2851 'close' => "\\</math\\>",
2852 'sample'=> wfMsg('math_sample'),
2853 'tip' => wfMsg('math_tip'),
2854 'key' => 'C'
2856 array( 'image' => 'button_nowiki.png',
2857 'open' => "\\<nowiki\\>",
2858 'close' => "\\</nowiki\\>",
2859 'sample'=> wfMsg('nowiki_sample'),
2860 'tip' => wfMsg('nowiki_tip'),
2861 'key' => 'N'
2863 array( 'image' => 'button_sig.png',
2864 'open' => '--~~~~',
2865 'close' => '',
2866 'sample'=> '',
2867 'tip' => wfMsg('sig_tip'),
2868 'key' => 'Y'
2870 array( 'image' => 'button_hr.png',
2871 'open' => "\\n----\\n",
2872 'close' => '',
2873 'sample'=> '',
2874 'tip' => wfMsg('hr_tip'),
2875 'key' => 'R'
2878 $toolbar ="<script type='text/javascript'>\n/*<![CDATA[*/\n";
2880 $toolbar.="document.writeln(\"<div id='toolbar'>\");\n";
2881 foreach($toolarray as $tool) {
2883 $image=$wgStylePath.'/common/images/'.$tool['image'];
2884 $open=$tool['open'];
2885 $close=$tool['close'];
2886 $sample = addslashes( $tool['sample'] );
2888 // Note that we use the tip both for the ALT tag and the TITLE tag of the image.
2889 // Older browsers show a "speedtip" type message only for ALT.
2890 // Ideally these should be different, realistically they
2891 // probably don't need to be.
2892 $tip = addslashes( $tool['tip'] );
2894 #$key = $tool["key"];
2896 $toolbar.="addButton('$image','$tip','$open','$close','$sample');\n";
2899 $toolbar.="addInfobox('" . addslashes( wfMsg( "infobox" ) ) . "','" . addslashes(wfMsg("infobox_alert")) . "');\n";
2900 $toolbar.="document.writeln(\"</div>\");\n";
2902 $toolbar.="/*]]>*/\n</script>";
2903 return $toolbar;
2907 * @access public
2909 function suppressUrlExpansion() {
2910 return false;