Use <i> and <b> for '' and ''' instead of <em> and <strong>. There's no
[mediawiki.git] / includes / Skin.php
blobc3df976a063a7924ebee3d36b9c8e8589793dbde
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
15 require_once( 'Feed.php' ); // should not be called if the actual page isn't feed enabled
16 require_once( 'Image.php' );
18 # These are the INTERNAL names, which get mapped directly to class names and
19 # file names in ./skins/. For display purposes, the Language class has
20 # internationalized names
23 $wgValidSkinNames = array(
24 'standard' => 'Standard',
25 'nostalgia' => 'Nostalgia',
26 'cologneblue' => 'CologneBlue'
28 if( $wgUsePHPTal ) {
29 #$wgValidSkinNames[] = 'PHPTal';
30 #$wgValidSkinNames['davinci'] = 'DaVinci';
31 #$wgValidSkinNames['mono'] = 'Mono';
32 #$wgValidSkinNames['monobookminimal'] = 'MonoBookMinimal';
33 $wgValidSkinNames['monobook'] = 'MonoBook';
34 $wgValidSkinNames['myskin'] = 'MySkin';
35 $wgValidSkinNames['chick'] = 'Chick';
39 # Get a list of all skins available in /skins/
40 # Build using the regular expression '^(.*).php$'
41 # Array keys are all lower case, array value keep the case used by filename
44 $skinDir = dir($IP.'/skins');
46 # while code from www.php.net
47 while (false !== ($file = $skinDir->read())) {
48 if(preg_match('/^(.*).php$/',$file, $matches)) {
49 $aSkin = $matches[1];
50 $wgValidSkinNames[strtolower($aSkin)] = $aSkin;
53 $skinDir->close();
54 unset($matches);
56 require_once( 'RecentChange.php' );
58 /**
59 * @todo document
60 * @package MediaWiki
62 class RCCacheEntry extends RecentChange
64 var $secureName, $link;
65 var $curlink , $difflink, $lastlink , $usertalklink , $versionlink ;
66 var $userlink, $timestamp, $watched;
68 function newFromParent( $rc )
70 $rc2 = new RCCacheEntry;
71 $rc2->mAttribs = $rc->mAttribs;
72 $rc2->mExtra = $rc->mExtra;
73 return $rc2;
75 } ;
78 /**
79 * The main skin class that provide methods and properties for all other skins
80 * including PHPTal skins.
81 * This base class is also the "Standard" skin.
82 * @package MediaWiki
84 class Skin {
85 /**#@+
86 * @access private
88 var $lastdate, $lastline;
89 var $linktrail ; # linktrail regexp
90 var $rc_cache ; # Cache for Enhanced Recent Changes
91 var $rcCacheIndex ; # Recent Changes Cache Counter for visibility toggle
92 var $rcMoveIndex;
93 var $postParseLinkColour = true;
94 /**#@-*/
96 function Skin() {
97 global $wgUseOldExistenceCheck;
98 $postParseLinkColour = !$wgUseOldExistenceCheck;
99 $this->linktrail = wfMsg('linktrail');
102 function getSkinNames() {
103 global $wgValidSkinNames;
104 return $wgValidSkinNames;
107 function getStylesheet() {
108 return 'common/wikistandard.css';
111 function getSkinName() {
112 return 'standard';
116 * Get/set accessor for delayed link colouring
118 function postParseLinkColour( $setting = NULL ) {
119 return wfSetVar( $this->postParseLinkColour, $setting );
122 function qbSetting() {
123 global $wgOut, $wgUser;
125 if ( $wgOut->isQuickbarSuppressed() ) { return 0; }
126 $q = $wgUser->getOption( 'quickbar' );
127 if ( '' == $q ) { $q = 0; }
128 return $q;
131 function initPage( &$out ) {
132 $fname = 'Skin::initPage';
133 wfProfileIn( $fname );
135 $out->addLink( array( 'rel' => 'shortcut icon', 'href' => '/favicon.ico' ) );
137 $this->addMetadataLinks($out);
139 wfProfileOut( $fname );
142 function addMetadataLinks( &$out ) {
143 global $wgTitle, $wgEnableDublinCoreRdf, $wgEnableCreativeCommonsRdf, $wgRdfMimeType, $action;
144 global $wgRightsPage, $wgRightsUrl;
146 if( $out->isArticleRelated() ) {
147 # note: buggy CC software only reads first "meta" link
148 if( $wgEnableCreativeCommonsRdf ) {
149 $out->addMetadataLink( array(
150 'title' => 'Creative Commons',
151 'type' => 'application/rdf+xml',
152 'href' => $wgTitle->getLocalURL( 'action=creativecommons') ) );
154 if( $wgEnableDublinCoreRdf ) {
155 $out->addMetadataLink( array(
156 'title' => 'Dublin Core',
157 'type' => 'application/rdf+xml',
158 'href' => $wgTitle->getLocalURL( 'action=dublincore' ) ) );
161 $copyright = '';
162 if( $wgRightsPage ) {
163 $copy = Title::newFromText( $wgRightsPage );
164 if( $copy ) {
165 $copyright = $copy->getLocalURL();
168 if( !$copyright && $wgRightsUrl ) {
169 $copyright = $wgRightsUrl;
171 if( $copyright ) {
172 $out->addLink( array(
173 'rel' => 'copyright',
174 'href' => $copyright ) );
178 function outputPage( &$out ) {
179 global $wgDebugComments;
181 wfProfileIn( 'Skin::outputPage' );
182 $this->initPage( $out );
183 $out->out( $out->headElement() );
185 $out->out( "\n<body" );
186 $ops = $this->getBodyOptions();
187 foreach ( $ops as $name => $val ) {
188 $out->out( " $name='$val'" );
190 $out->out( ">\n" );
191 if ( $wgDebugComments ) {
192 $out->out( "<!-- Wiki debugging output:\n" .
193 $out->mDebugtext . "-->\n" );
195 $out->out( $this->beforeContent() );
197 $out->out( $out->mBodytext . "\n" );
199 $out->out( $this->afterContent() );
201 wfProfileClose();
202 $out->out( $out->reportTime() );
204 $out->out( "\n</body></html>" );
207 function getHeadScripts() {
208 global $wgStylePath, $wgUser, $wgLang, $wgAllowUserJs;
209 $r = "<script type=\"text/javascript\" src=\"{$wgStylePath}/common/wikibits.js\"></script>\n";
210 if( $wgAllowUserJs && $wgUser->getID() != 0 ) { # logged in
211 $userpage = $wgLang->getNsText( Namespace::getUser() ) . ":" . $wgUser->getName();
212 $userjs = htmlspecialchars($this->makeUrl($userpage.'/'.$this->getSkinName().'.js', 'action=raw&ctype=text/javascript'));
213 $r .= '<script type="text/javascript" src="'.$userjs."\"></script>\n";
215 return $r;
218 # get the user/site-specific stylesheet, SkinPHPTal called from RawPage.php (settings are cached that way)
219 function getUserStylesheet() {
220 global $wgOut, $wgStylePath, $wgLang, $wgUser, $wgRequest, $wgTitle, $wgAllowUserCss;
221 $sheet = $this->getStylesheet();
222 $action = $wgRequest->getText('action');
223 $s = "@import \"$wgStylePath/$sheet\";\n";
224 if($wgLang->isRTL()) $s .= "@import \"$wgStylePath/common/common_rtl.css\";\n";
225 if( $wgAllowUserCss && $wgUser->getID() != 0 ) { # logged in
226 if($wgTitle->isCssSubpage() and $action == 'submit' and $wgTitle->userCanEditCssJsSubpage()) {
227 $s .= $wgRequest->getText('wpTextbox1');
228 } else {
229 $userpage = $wgLang->getNsText( Namespace::getUser() ) . ":" . $wgUser->getName();
230 $s.= '@import "'.$this->makeUrl($userpage.'/'.$this->getSkinName().'.css', 'action=raw&ctype=text/css').'";'."\n";
233 $s .= $this->doGetUserStyles();
234 return $s."\n";
238 * placeholder, returns generated js in monobook
240 function getUserJs() { return; }
243 * Return html code that include User stylesheets
245 function getUserStyles() {
246 global $wgOut, $wgStylePath, $wgLang;
247 $s = "<style type='text/css'>\n";
248 $s .= "/*/*/ /*<![CDATA[*/\n"; # <-- Hide the styles from Netscape 4 without hiding them from IE/Mac
249 $s .= $this->getUserStylesheet();
250 $s .= "/*]]>*/ /* */\n";
251 $s .= "</style>\n";
252 return $s;
256 * Some styles that are set by user through the user settings interface.
258 function doGetUserStyles() {
259 global $wgUser, $wgLang;
261 $csspage = $wgLang->getNsText( NS_MEDIAWIKI ) . ':' . $this->getSkinName() . '.css';
262 $s = '@import "'.$this->makeUrl($csspage, 'action=raw&ctype=text/css')."\";\n";
264 if ( 1 == $wgUser->getOption( 'underline' ) ) {
265 # Don't override browser settings
266 } else {
267 # CHECK MERGE @@@
268 # Force no underline
269 $s .= "a { text-decoration: none; }\n";
271 if ( 1 == $wgUser->getOption( 'highlightbroken' ) ) {
272 $s .= "a.new, #quickbar a.new { color: #CC2200; }\n";
274 if ( 1 == $wgUser->getOption( 'justify' ) ) {
275 $s .= "#article { text-align: justify; }\n";
277 return $s;
280 function getBodyOptions() {
281 global $wgUser, $wgTitle, $wgNamespaceBackgrounds, $wgOut, $wgRequest;
283 extract( $wgRequest->getValues( 'oldid', 'redirect', 'diff' ) );
285 if ( 0 != $wgTitle->getNamespace() ) {
286 $a = array( 'bgcolor' => '#ffffec' );
288 else $a = array( 'bgcolor' => '#FFFFFF' );
289 if($wgOut->isArticle() && $wgUser->getOption('editondblclick') &&
290 (!$wgTitle->isProtected() || $wgUser->isSysop()) ) {
291 $t = wfMsg( 'editthispage' );
292 $oid = $red = '';
293 if ( !empty($redirect) ) {
294 $red = "&redirect={$redirect}";
296 if ( !empty($oldid) && ! isset( $diff ) ) {
297 $oid = "&oldid={$oldid}";
299 $s = $wgTitle->getFullURL( "action=edit{$oid}{$red}" );
300 $s = 'document.location = "' .$s .'";';
301 $a += array ('ondblclick' => $s);
304 $a['onload'] = $wgOut->getOnloadHandler();
305 return $a;
308 function getExternalLinkAttributes( $link, $text, $class='' ) {
309 global $wgUser, $wgOut, $wgLang;
311 $link = urldecode( $link );
312 $link = $wgLang->checkTitleEncoding( $link );
313 $link = str_replace( '_', ' ', $link );
314 $link = htmlspecialchars( $link );
316 $r = ($class != '') ? " class='$class'" : " class='external'";
318 if ( 1 == $wgUser->getOption( 'hover' ) ) {
319 $r .= " title=\"{$link}\"";
321 return $r;
324 function getInternalLinkAttributes( $link, $text, $broken = false ) {
325 global $wgUser, $wgOut;
327 $link = urldecode( $link );
328 $link = str_replace( '_', ' ', $link );
329 $link = htmlspecialchars( $link );
331 if ( $broken == 'stub' ) {
332 $r = ' class="stub"';
333 } else if ( $broken == 'yes' ) {
334 $r = ' class="new"';
335 } else {
336 $r = '';
339 if ( 1 == $wgUser->getOption( 'hover' ) ) {
340 $r .= " title=\"{$link}\"";
342 return $r;
346 * @param bool $broken
348 function getInternalLinkAttributesObj( &$nt, $text, $broken = false ) {
349 global $wgUser, $wgOut;
351 if ( $broken == 'stub' ) {
352 $r = ' class="stub"';
353 } else if ( $broken == 'yes' ) {
354 $r = ' class="new"';
355 } else {
356 $r = '';
359 if ( 1 == $wgUser->getOption( 'hover' ) ) {
360 $r .= ' title ="' . $nt->getEscapedText() . '"';
362 return $r;
366 * URL to the logo
368 function getLogo() {
369 global $wgLogo;
370 return $wgLogo;
374 * This will be called immediately after the <body> tag. Split into
375 * two functions to make it easier to subclass.
377 function beforeContent() {
378 global $wgUser, $wgOut;
380 return $this->doBeforeContent();
383 function doBeforeContent() {
384 global $wgUser, $wgOut, $wgTitle, $wgLang, $wgSiteNotice;
385 $fname = 'Skin::doBeforeContent';
386 wfProfileIn( $fname );
388 $s = '';
389 $qb = $this->qbSetting();
391 if( $langlinks = $this->otherLanguages() ) {
392 $rows = 2;
393 $borderhack = '';
394 } else {
395 $rows = 1;
396 $langlinks = false;
397 $borderhack = 'class="top"';
400 $s .= "\n<div id='content'>\n<div id='topbar'>\n" .
401 "<table border='0' cellspacing='0' width='98%'>\n<tr>\n";
403 $shove = ($qb != 0);
404 $left = ($qb == 1 || $qb == 3);
405 if($wgLang->isRTL()) $left = !$left;
407 if ( !$shove ) {
408 $s .= "<td class='top' align='left' valign='top' rowspan='{$rows}'>\n" .
409 $this->logoText() . '</td>';
410 } elseif( $left ) {
411 $s .= $this->getQuickbarCompensator( $rows );
413 $l = $wgLang->isRTL() ? 'right' : 'left';
414 $s .= "<td {$borderhack} align='$l' valign='top'>\n";
416 $s .= $this->topLinks() ;
417 $s .= "<p class='subtitle'>" . $this->pageTitleLinks() . "</p>\n";
419 $r = $wgLang->isRTL() ? "left" : "right";
420 $s .= "</td>\n<td {$borderhack} valign='top' align='$r' nowrap='nowrap'>";
421 $s .= $this->nameAndLogin();
422 $s .= "\n<br />" . $this->searchForm() . "</td>";
424 if ( $langlinks ) {
425 $s .= "</tr>\n<tr>\n<td class='top' colspan=\"2\">$langlinks</td>\n";
428 if ( $shove && !$left ) { # Right
429 $s .= $this->getQuickbarCompensator( $rows );
431 $s .= "</tr>\n</table>\n</div>\n";
432 $s .= "\n<div id='article'>\n";
434 if( $wgSiteNotice ) {
435 $s .= "\n<div id='siteNotice'>$wgSiteNotice</div>\n";
437 $s .= $this->pageTitle();
438 $s .= $this->pageSubtitle() ;
439 $s .= $this->getCategories();
440 wfProfileOut( $fname );
441 return $s;
444 function getCategoryLinks () {
445 global $wgOut, $wgTitle, $wgUser, $wgParser;
446 global $wgUseCategoryMagic, $wgUseCategoryBrowser, $wgLang;
448 if( !$wgUseCategoryMagic ) return '' ;
449 if( count( $wgOut->mCategoryLinks ) == 0 ) return '';
451 # Taken out so that they will be displayed in previews -- TS
452 #if( !$wgOut->isArticle() ) return '';
454 $t = implode ( ' | ' , $wgOut->mCategoryLinks ) ;
455 $s = $this->makeKnownLink( 'Special:Categories',
456 wfMsg( 'categories' ), 'article=' . urlencode( $wgTitle->getPrefixedDBkey() ) )
457 . ': ' . $t;
459 # optional 'dmoz-like' category browser. Will be shown under the list
460 # of categories an article belong to
461 if($wgUseCategoryBrowser) {
462 $s .= '<br/><hr/>';
464 # get a big array of the parents tree
465 $parenttree = $wgTitle->getCategorieBrowser();
467 # Render the array as a serie of links
468 function walkThrough ($tree) {
469 global $wgUser;
470 $sk = $wgUser->getSkin();
471 $return = '';
472 foreach($tree as $element => $parent) {
473 if(empty($parent)) {
474 # element start a new list
475 $return .= '<br />';
476 } else {
477 # grab the others elements
478 $return .= walkThrough($parent);
480 # add our current element to the list
481 $eltitle = Title::NewFromText($element);
482 # FIXME : should be makeLink() [AV]
483 $return .= $sk->makeKnownLink($element, $eltitle->getText()).' &gt; ';
485 return $return;
488 $s .= walkThrough($parenttree);
491 return $s;
494 function getCategories() {
495 $catlinks=$this->getCategoryLinks();
496 if(!empty($catlinks)) {
497 return "<p class='catlinks'>{$catlinks}</p>";
501 function getQuickbarCompensator( $rows = 1 ) {
502 return "<td width='152' rowspan='{$rows}'>&nbsp;</td>";
505 # This gets called immediately before the </body> tag.
507 function afterContent() {
508 global $wgUser, $wgOut, $wgServer;
509 global $wgTitle, $wgLang;
511 $printfooter = "<div class=\"printfooter\">\n" . $this->printFooter() . "</div>\n";
512 return $printfooter . $this->doAfterContent();
515 function printSource() {
516 global $wgTitle;
517 $url = htmlspecialchars( $wgTitle->getFullURL() );
518 return wfMsg( "retrievedfrom", "<a href=\"$url\">$url</a>" );
521 function printFooter() {
522 return "<p>" . $this->printSource() .
523 "</p>\n\n<p>" . $this->pageStats() . "</p>\n";
526 function doAfterContent() {
527 global $wgUser, $wgOut, $wgLang;
528 $fname = 'Skin::doAfterContent';
529 wfProfileIn( $fname );
530 wfProfileIn( $fname.'-1' );
532 $s = "\n</div><br style=\"clear:both\" />\n";
533 $s .= "\n<div id='footer'>";
534 $s .= '<table border="0" cellspacing="0"><tr>';
536 wfProfileOut( $fname.'-1' );
537 wfProfileIn( $fname.'-2' );
539 $qb = $this->qbSetting();
540 $shove = ($qb != 0);
541 $left = ($qb == 1 || $qb == 3);
542 if($wgLang->isRTL()) $left = !$left;
544 if ( $shove && $left ) { # Left
545 $s .= $this->getQuickbarCompensator();
547 wfProfileOut( $fname.'-2' );
548 wfProfileIn( $fname.'-3' );
549 $l = $wgLang->isRTL() ? 'right' : 'left';
550 $s .= "<td class='bottom' align='$l' valign='top'>";
552 $s .= $this->bottomLinks();
553 $s .= "\n<br />" . $this->mainPageLink()
554 . ' | ' . $this->aboutLink()
555 . ' | ' . $this->specialLink( 'recentchanges' )
556 . ' | ' . $this->searchForm()
557 . '<br /><span id="pagestats">' . $this->pageStats() . '</span>';
559 $s .= "</td>";
560 if ( $shove && !$left ) { # Right
561 $s .= $this->getQuickbarCompensator();
563 $s .= "</tr></table>\n</div>\n</div>\n";
565 wfProfileOut( $fname.'-3' );
566 wfProfileIn( $fname.'-4' );
567 if ( 0 != $qb ) { $s .= $this->quickBar(); }
568 wfProfileOut( $fname.'-4' );
569 wfProfileOut( $fname );
570 return $s;
573 function pageTitleLinks() {
574 global $wgOut, $wgTitle, $wgUser, $wgLang, $wgUseApproval, $wgRequest;
576 extract( $wgRequest->getValues( 'oldid', 'diff' ) );
577 $action = $wgRequest->getText( 'action' );
579 $s = $this->printableLink();
580 if ( wfMsg ( 'disclaimers' ) != '-' ) $s .= ' | ' . $this->makeKnownLink( wfMsg( 'disclaimerpage' ), wfMsg( 'disclaimers' ) ) ;
582 if ( $wgOut->isArticleRelated() ) {
583 if ( $wgTitle->getNamespace() == Namespace::getImage() ) {
584 $name = $wgTitle->getDBkey();
585 $link = htmlspecialchars( Image::wfImageUrl( $name ) );
586 $style = $this->getInternalLinkAttributes( $link, $name );
587 $s .= " | <a href=\"{$link}\"{$style}>{$name}</a>";
589 # This will show the "Approve" link if $wgUseApproval=true;
590 if ( isset ( $wgUseApproval ) && $wgUseApproval )
592 $t = $wgTitle->getDBkey();
593 $name = 'Approve this article' ;
594 $link = "http://test.wikipedia.org/w/magnus/wiki.phtml?title={$t}&action=submit&doit=1" ;
595 #htmlspecialchars( wfImageUrl( $name ) );
596 $style = $this->getExternalLinkAttributes( $link, $name );
597 $s .= " | <a href=\"{$link}\"{$style}>{$name}</a>" ;
600 if ( 'history' == $action || isset( $diff ) || isset( $oldid ) ) {
601 $s .= ' | ' . $this->makeKnownLink( $wgTitle->getPrefixedText(),
602 wfMsg( 'currentrev' ) );
605 if ( $wgUser->getNewtalk() ) {
606 # do not show "You have new messages" text when we are viewing our
607 # own talk page
609 if(!(strcmp($wgTitle->getText(),$wgUser->getName()) == 0 &&
610 $wgTitle->getNamespace()==Namespace::getTalk(Namespace::getUser()))) {
611 $n =$wgUser->getName();
612 $tl = $this->makeKnownLink( $wgLang->getNsText(
613 Namespace::getTalk( Namespace::getUser() ) ) . ":{$n}",
614 wfMsg('newmessageslink') );
615 $s.= ' | <strong>'. wfMsg( 'newmessages', $tl ) . '</strong>';
616 # disable caching
617 $wgOut->setSquidMaxage(0);
621 $undelete = $this->getUndeleteLink();
622 if( !empty( $undelete ) ) {
623 $s .= ' | '.$undelete;
625 return $s;
628 function getUndeleteLink() {
629 global $wgUser, $wgTitle, $wgLang, $action;
630 if( $wgUser->isSysop() &&
631 (($wgTitle->getArticleId() == 0) || ($action == "history")) &&
632 ($n = $wgTitle->isDeleted() ) ) {
633 return wfMsg( 'thisisdeleted',
634 $this->makeKnownLink(
635 $wgLang->SpecialPage( 'Undelete/' . $wgTitle->getPrefixedDBkey() ),
636 wfMsg( 'restorelink', $n ) ) );
638 return '';
641 function printableLink() {
642 global $wgOut, $wgFeedClasses, $wgRequest;
644 $baseurl = $_SERVER['REQUEST_URI'];
645 if( strpos( '?', $baseurl ) == false ) {
646 $baseurl .= '?';
647 } else {
648 $baseurl .= '&';
650 $baseurl = htmlspecialchars( $baseurl );
651 $printurl = $wgRequest->escapeAppendQuery( 'printable=yes' );
653 $s = "<a href=\"$printurl\">" . wfMsg( 'printableversion' ) . '</a>';
654 if( $wgOut->isSyndicated() ) {
655 foreach( $wgFeedClasses as $format => $class ) {
656 $feedurl = $wgRequest->escapeAppendQuery( "feed=$format" );
657 $s .= " | <a href=\"$feedurl\">{$format}</a>";
660 return $s;
663 function pageTitle() {
664 global $wgOut, $wgTitle, $wgUser;
666 $s = '<h1 class="pagetitle">' . htmlspecialchars( $wgOut->getPageTitle() ) . '</h1>';
667 if($wgUser->getOption( 'editsectiononrightclick' ) && $wgTitle->userCanEdit()) { $s=$this->editSectionScript(0,$s);}
668 return $s;
671 function pageSubtitle() {
672 global $wgOut;
674 $sub = $wgOut->getSubtitle();
675 if ( '' == $sub ) {
676 global $wgExtraSubtitle;
677 $sub = wfMsg( 'tagline' ) . $wgExtraSubtitle;
679 $subpages = $this->subPageSubtitle();
680 $sub .= !empty($subpages)?"</p><p class='subpages'>$subpages":'';
681 $s = "<p class='subtitle'>{$sub}</p>\n";
682 return $s;
685 function subPageSubtitle() {
686 global $wgOut,$wgTitle,$wgNamespacesWithSubpages;
687 $subpages = '';
688 if($wgOut->isArticle() && !empty($wgNamespacesWithSubpages[$wgTitle->getNamespace()])) {
689 $ptext=$wgTitle->getPrefixedText();
690 if(preg_match('/\//',$ptext)) {
691 $links = explode('/',$ptext);
692 $c = 0;
693 $growinglink = '';
694 foreach($links as $link) {
695 $c++;
696 if ($c<count($links)) {
697 $growinglink .= $link;
698 $getlink = $this->makeLink( $growinglink, $link );
699 if(preg_match('/class="new"/i',$getlink)) { break; } # this is a hack, but it saves time
700 if ($c>1) {
701 $subpages .= ' | ';
702 } else {
703 $subpages .= '&lt; ';
705 $subpages .= $getlink;
706 $growinglink .= '/';
711 return $subpages;
714 function nameAndLogin() {
715 global $wgUser, $wgTitle, $wgLang, $wgShowIPinHeader, $wgIP;
717 $li = $wgLang->specialPage( 'Userlogin' );
718 $lo = $wgLang->specialPage( 'Userlogout' );
720 $s = '';
721 if ( 0 == $wgUser->getID() ) {
722 if( $wgShowIPinHeader && isset( $_COOKIE[ini_get('session.name')] ) ) {
723 $n = $wgIP;
725 $tl = $this->makeKnownLink( $wgLang->getNsText(
726 Namespace::getTalk( Namespace::getUser() ) ) . ":{$n}",
727 $wgLang->getNsText( Namespace::getTalk( 0 ) ) );
729 $s .= $n . ' ('.$tl.')';
730 } else {
731 $s .= wfMsg('notloggedin');
734 $rt = $wgTitle->getPrefixedURL();
735 if ( 0 == strcasecmp( urlencode( $lo ), $rt ) ) {
736 $q = '';
737 } else { $q = "returnto={$rt}"; }
739 $s .= "\n<br />" . $this->makeKnownLink( $li,
740 wfMsg( 'login' ), $q );
741 } else {
742 $n = $wgUser->getName();
743 $rt = $wgTitle->getPrefixedURL();
744 $tl = $this->makeKnownLink( $wgLang->getNsText(
745 Namespace::getTalk( Namespace::getUser() ) ) . ":{$n}",
746 $wgLang->getNsText( Namespace::getTalk( 0 ) ) );
748 $tl = " ({$tl})";
750 $s .= $this->makeKnownLink( $wgLang->getNsText(
751 Namespace::getUser() ) . ":{$n}", $n ) . "{$tl}<br />" .
752 $this->makeKnownLink( $lo, wfMsg( 'logout' ),
753 "returnto={$rt}" ) . ' | ' .
754 $this->specialLink( 'preferences' );
756 $s .= ' | ' . $this->makeKnownLink( wfMsg( 'helppage' ),
757 wfMsg( 'help' ) );
759 return $s;
762 function getSearchLink() {
763 $searchPage =& Title::makeTitle( NS_SPECIAL, 'Search' );
764 return $searchPage->getLocalURL();
767 function escapeSearchLink() {
768 return htmlspecialchars( $this->getSearchLink() );
771 function searchForm() {
772 global $wgRequest;
773 $search = $wgRequest->getText( 'search' );
775 $s = '<form name="search" class="inline" method="post" action="'
776 . $this->escapeSearchLink() . "\">\n"
777 . '<input type="text" name="search" size="19" value="'
778 . htmlspecialchars(substr($search,0,256)) . "\" />\n"
779 . '<input type="submit" name="go" value="' . wfMsg ('go') . '" />&nbsp;'
780 . '<input type="submit" name="fulltext" value="' . wfMsg ('search') . "\" />\n</form>";
782 return $s;
785 function topLinks() {
786 global $wgOut;
787 $sep = " |\n";
789 $s = $this->mainPageLink() . $sep
790 . $this->specialLink( 'recentchanges' );
792 if ( $wgOut->isArticleRelated() ) {
793 $s .= $sep . $this->editThisPage()
794 . $sep . $this->historyLink();
796 # Many people don't like this dropdown box
797 #$s .= $sep . $this->specialPagesList();
799 return $s;
802 function bottomLinks() {
803 global $wgOut, $wgUser, $wgTitle;
804 $sep = " |\n";
806 $s = '';
807 if ( $wgOut->isArticleRelated() ) {
808 $s .= '<strong>' . $this->editThisPage() . '</strong>';
809 if ( 0 != $wgUser->getID() ) {
810 $s .= $sep . $this->watchThisPage();
812 $s .= $sep . $this->talkLink()
813 . $sep . $this->historyLink()
814 . $sep . $this->whatLinksHere()
815 . $sep . $this->watchPageLinksLink();
817 if ( $wgTitle->getNamespace() == Namespace::getUser()
818 || $wgTitle->getNamespace() == Namespace::getTalk(Namespace::getUser()) )
821 $id=User::idFromName($wgTitle->getText());
822 $ip=User::isIP($wgTitle->getText());
824 if($id || $ip) { # both anons and non-anons have contri list
825 $s .= $sep . $this->userContribsLink();
827 if ( 0 != $wgUser->getID() ) { # show only to signed in users
828 if($id) { # can only email non-anons
829 $s .= $sep . $this->emailUserLink();
833 if ( $wgUser->isSysop() && $wgTitle->getArticleId() ) {
834 $s .= "\n<br />" . $this->deleteThisPage() .
835 $sep . $this->protectThisPage() .
836 $sep . $this->moveThisPage();
838 $s .= "<br />\n" . $this->otherLanguages();
840 return $s;
843 function pageStats() {
844 global $wgOut, $wgLang, $wgArticle, $wgRequest;
845 global $wgDisableCounters, $wgMaxCredits, $wgShowCreditsIfMax;
847 extract( $wgRequest->getValues( 'oldid', 'diff' ) );
848 if ( ! $wgOut->isArticle() ) { return ''; }
849 if ( isset( $oldid ) || isset( $diff ) ) { return ''; }
850 if ( 0 == $wgArticle->getID() ) { return ''; }
852 $s = '';
853 if ( !$wgDisableCounters ) {
854 $count = $wgLang->formatNum( $wgArticle->getCount() );
855 if ( $count ) {
856 $s = wfMsg( 'viewcount', $count );
860 if (isset($wgMaxCredits) && $wgMaxCredits != 0) {
861 require_once("Credits.php");
862 $s .= ' ' . getCredits($wgArticle, $wgMaxCredits, $wgShowCreditsIfMax);
863 } else {
864 $s .= $this->lastModified();
867 return $s . ' ' . $this->getCopyright();
870 function getCopyright() {
871 global $wgRightsPage, $wgRightsUrl, $wgRightsText, $wgRequest;
874 $oldid = $wgRequest->getVal( 'oldid' );
875 $diff = $wgRequest->getVal( 'diff' );
877 if ( !is_null( $oldid ) && is_null( $diff ) && wfMsg( 'history_copyright' ) !== '-' ) {
878 $msg = 'history_copyright';
879 } else {
880 $msg = 'copyright';
883 $out = '';
884 if( $wgRightsPage ) {
885 $link = $this->makeKnownLink( $wgRightsPage, $wgRightsText );
886 } elseif( $wgRightsUrl ) {
887 $link = $this->makeExternalLink( $wgRightsUrl, $wgRightsText );
888 } else {
889 # Give up now
890 return $out;
892 $out .= wfMsg( $msg, $link );
893 return $out;
896 function getCopyrightIcon() {
897 global $wgRightsPage, $wgRightsUrl, $wgRightsText, $wgRightsIcon;
898 $out = '';
899 if( $wgRightsIcon ) {
900 $icon = htmlspecialchars( $wgRightsIcon );
901 if( $wgRightsUrl ) {
902 $url = htmlspecialchars( $wgRightsUrl );
903 $out .= '<a href="'.$url.'">';
905 $text = htmlspecialchars( $wgRightsText );
906 $out .= "<img src=\"$icon\" alt='$text' />";
907 if( $wgRightsUrl ) {
908 $out .= '</a>';
911 return $out;
914 function getPoweredBy() {
915 global $wgStylePath;
916 $url = htmlspecialchars( "$wgStylePath/common/images/poweredby_mediawiki_88x31.png" );
917 $img = '<a href="http://www.mediawiki.org/"><img src="'.$url.'" alt="MediaWiki" /></a>';
918 return $img;
921 function lastModified() {
922 global $wgLang, $wgArticle;
924 $timestamp = $wgArticle->getTimestamp();
925 if ( $timestamp ) {
926 $d = $wgLang->timeanddate( $wgArticle->getTimestamp(), true );
927 $s = ' ' . wfMsg( 'lastmodified', $d );
928 } else {
929 $s = '';
931 return $s;
934 function logoText( $align = '' ) {
935 if ( '' != $align ) { $a = " align='{$align}'"; }
936 else { $a = ''; }
938 $mp = wfMsg( 'mainpage' );
939 $titleObj = Title::newFromText( $mp );
940 if ( is_object( $titleObj ) ) {
941 $url = $titleObj->escapeLocalURL();
942 } else {
943 $url = '';
946 $logourl = $this->getLogo();
947 $s = "<a href='{$url}'><img{$a} src='{$logourl}' alt='[{$mp}]' /></a>";
948 return $s;
951 function quickBar() {
952 global $wgOut, $wgTitle, $wgUser, $wgRequest, $wgLang;
953 global $wgDisableUploads, $wgRemoteUploads;
955 $fname = 'Skin::quickBar';
956 wfProfileIn( $fname );
958 $action = $wgRequest->getText( 'action' );
959 $wpPreview = $wgRequest->getBool( 'wpPreview' );
960 $tns=$wgTitle->getNamespace();
962 $s = "\n<div id='quickbar'>";
963 $s .= "\n" . $this->logoText() . "\n<hr class='sep' />";
965 $sep = "\n<br />";
966 $s .= $this->mainPageLink()
967 . $sep . $this->specialLink( 'recentchanges' )
968 . $sep . $this->specialLink( 'randompage' );
969 if ($wgUser->getID()) {
970 $s.= $sep . $this->specialLink( 'watchlist' ) ;
971 $s .= $sep .$this->makeKnownLink( $wgLang->specialPage( 'Contributions' ),
972 wfMsg( 'mycontris' ), 'target=' . wfUrlencode($wgUser->getName() ) );
975 // only show watchlist link if logged in
976 if ( wfMsg ( 'currentevents' ) != '-' ) $s .= $sep . $this->makeKnownLink( wfMsg( 'currentevents' ), '' ) ;
977 $s .= "\n<br /><hr class='sep' />";
978 $articleExists = $wgTitle->getArticleId();
979 if ( $wgOut->isArticle() || $action =='edit' || $action =='history' || $wpPreview) {
980 if($wgOut->isArticle()) {
981 $s .= '<strong>' . $this->editThisPage() . '</strong>';
982 } else { # backlink to the article in edit or history mode
983 if($articleExists){ # no backlink if no article
984 switch($tns) {
985 case 0:
986 $text = wfMsg('articlepage');
987 break;
988 case 1:
989 $text = wfMsg('viewtalkpage');
990 break;
991 case 2:
992 $text = wfMsg('userpage');
993 break;
994 case 3:
995 $text = wfMsg('viewtalkpage');
996 break;
997 case 4:
998 $text = wfMsg('wikipediapage');
999 break;
1000 case 5:
1001 $text = wfMsg('viewtalkpage');
1002 break;
1003 case 6:
1004 $text = wfMsg('imagepage');
1005 break;
1006 case 7:
1007 $text = wfMsg('viewtalkpage');
1008 break;
1009 default:
1010 $text= wfMsg('articlepage');
1013 $link = $wgTitle->getText();
1014 if ($nstext = $wgLang->getNsText($tns) ) { # add namespace if necessary
1015 $link = $nstext . ':' . $link ;
1018 $s .= $this->makeLink( $link, $text );
1019 } elseif( $wgTitle->getNamespace() != Namespace::getSpecial() ) {
1020 # we just throw in a "New page" text to tell the user that he's in edit mode,
1021 # and to avoid messing with the separator that is prepended to the next item
1022 $s .= '<strong>' . wfMsg('newpage') . '</strong>';
1028 if( $tns%2 && $action!='edit' && !$wpPreview) {
1029 $s.= '<br />'.$this->makeKnownLink($wgTitle->getPrefixedText(),wfMsg('postcomment'),'action=edit&section=new');
1033 watching could cause problems in edit mode:
1034 if user edits article, then loads "watch this article" in background and then saves
1035 article with "Watch this article" checkbox disabled, the article is transparently
1036 unwatched. Therefore we do not show the "Watch this page" link in edit mode
1038 if ( 0 != $wgUser->getID() && $articleExists) {
1039 if($action!='edit' && $action != 'submit' )
1041 $s .= $sep . $this->watchThisPage();
1043 if ( $wgTitle->userCanEdit() )
1044 $s .= $sep . $this->moveThisPage();
1046 if ( $wgUser->isSysop() and $articleExists ) {
1047 $s .= $sep . $this->deleteThisPage() .
1048 $sep . $this->protectThisPage();
1050 $s .= $sep . $this->talkLink();
1051 if ($articleExists && $action !='history') {
1052 $s .= $sep . $this->historyLink();
1054 $s.=$sep . $this->whatLinksHere();
1056 if($wgOut->isArticleRelated()) {
1057 $s .= $sep . $this->watchPageLinksLink();
1060 if ( Namespace::getUser() == $wgTitle->getNamespace()
1061 || $wgTitle->getNamespace() == Namespace::getTalk(Namespace::getUser())
1064 $id=User::idFromName($wgTitle->getText());
1065 $ip=User::isIP($wgTitle->getText());
1067 if($id||$ip) {
1068 $s .= $sep . $this->userContribsLink();
1070 if ( 0 != $wgUser->getID() ) {
1071 if($id) { # can only email real users
1072 $s .= $sep . $this->emailUserLink();
1076 $s .= "\n<br /><hr class='sep' />";
1079 if ( 0 != $wgUser->getID() && ( !$wgDisableUploads || $wgRemoteUploads ) ) {
1080 $s .= $this->specialLink( 'upload' ) . $sep;
1082 $s .= $this->specialLink( 'specialpages' )
1083 . $sep . $this->bugReportsLink();
1085 global $wgSiteSupportPage;
1086 if( $wgSiteSupportPage ) {
1087 $s .= "\n<br /><a href=\"" . htmlspecialchars( $wgSiteSupportPage ) .
1088 '" class="internal">' . wfMsg( 'sitesupport' ) . '</a>';
1091 $s .= "\n<br /></div>\n";
1092 wfProfileOut( $fname );
1093 return $s;
1096 function specialPagesList() {
1097 global $wgUser, $wgOut, $wgLang, $wgServer, $wgRedirectScript;
1098 require_once('SpecialPage.php');
1099 $a = array();
1100 $pages = SpecialPage::getPages();
1102 foreach ( $pages[''] as $name => $page ) {
1103 $a[$name] = $page->getDescription();
1105 if ( $wgUser->isSysop() )
1107 foreach ( $pages['sysop'] as $name => $page ) {
1108 $a[$name] = $page->getDescription();
1111 if ( $wgUser->isDeveloper() )
1113 foreach ( $pages['developer'] as $name => $page ) {
1114 $a[$name] = $page->getDescription() ;
1117 $go = wfMsg( 'go' );
1118 $sp = wfMsg( 'specialpages' );
1119 $spp = $wgLang->specialPage( 'Specialpages' );
1121 $s = '<form id="specialpages" method="get" class="inline" ' .
1122 'action="' . htmlspecialchars( "{$wgServer}{$wgRedirectScript}" ) . "\">\n";
1123 $s .= "<select name=\"wpDropdown\">\n";
1124 $s .= "<option value=\"{$spp}\">{$sp}</option>\n";
1126 foreach ( $a as $name => $desc ) {
1127 $p = $wgLang->specialPage( $name );
1128 $s .= "<option value=\"{$p}\">{$desc}</option>\n";
1130 $s .= "</select>\n";
1131 $s .= "<input type='submit' value=\"{$go}\" name='redirect' />\n";
1132 $s .= "</form>\n";
1133 return $s;
1136 function mainPageLink() {
1137 $mp = wfMsg( 'mainpage' );
1138 $s = $this->makeKnownLink( $mp, $mp );
1139 return $s;
1142 function copyrightLink() {
1143 $s = $this->makeKnownLink( wfMsg( 'copyrightpage' ),
1144 wfMsg( 'copyrightpagename' ) );
1145 return $s;
1148 function aboutLink() {
1149 $s = $this->makeKnownLink( wfMsg( 'aboutpage' ),
1150 wfMsg( 'aboutsite' ) );
1151 return $s;
1155 function disclaimerLink() {
1156 $s = $this->makeKnownLink( wfMsg( 'disclaimerpage' ),
1157 wfMsg( 'disclaimers' ) );
1158 return $s;
1161 function editThisPage() {
1162 global $wgOut, $wgTitle, $wgRequest;
1164 $oldid = $wgRequest->getVal( 'oldid' );
1165 $diff = $wgRequest->getVal( 'diff' );
1166 $redirect = $wgRequest->getVal( 'redirect' );
1168 if ( ! $wgOut->isArticleRelated() ) {
1169 $s = wfMsg( 'protectedpage' );
1170 } else {
1171 $n = $wgTitle->getPrefixedText();
1172 if ( $wgTitle->userCanEdit() ) {
1173 $t = wfMsg( 'editthispage' );
1174 } else {
1175 #$t = wfMsg( "protectedpage" );
1176 $t = wfMsg( 'viewsource' );
1178 $oid = $red = '';
1180 if ( !is_null( $redirect ) ) { $red = "&redirect={$redirect}"; }
1181 if ( $oldid && ! isset( $diff ) ) {
1182 $oid = '&oldid='.$oldid;
1184 $s = $this->makeKnownLink( $n, $t, "action=edit{$oid}{$red}" );
1186 return $s;
1189 function deleteThisPage() {
1190 global $wgUser, $wgOut, $wgTitle, $wgRequest;
1192 $diff = $wgRequest->getVal( 'diff' );
1193 if ( $wgTitle->getArticleId() && ( ! $diff ) && $wgUser->isSysop() ) {
1194 $n = $wgTitle->getPrefixedText();
1195 $t = wfMsg( 'deletethispage' );
1197 $s = $this->makeKnownLink( $n, $t, 'action=delete' );
1198 } else {
1199 $s = '';
1201 return $s;
1204 function protectThisPage() {
1205 global $wgUser, $wgOut, $wgTitle, $wgRequest;
1207 $diff = $wgRequest->getVal( 'diff' );
1208 if ( $wgTitle->getArticleId() && ( ! $diff ) && $wgUser->isSysop() ) {
1209 $n = $wgTitle->getPrefixedText();
1211 if ( $wgTitle->isProtected() ) {
1212 $t = wfMsg( 'unprotectthispage' );
1213 $q = 'action=unprotect';
1214 } else {
1215 $t = wfMsg( 'protectthispage' );
1216 $q = 'action=protect';
1218 $s = $this->makeKnownLink( $n, $t, $q );
1219 } else {
1220 $s = '';
1222 return $s;
1225 function watchThisPage() {
1226 global $wgUser, $wgOut, $wgTitle;
1228 if ( $wgOut->isArticleRelated() ) {
1229 $n = $wgTitle->getPrefixedText();
1231 if ( $wgTitle->userIsWatching() ) {
1232 $t = wfMsg( 'unwatchthispage' );
1233 $q = 'action=unwatch';
1234 } else {
1235 $t = wfMsg( 'watchthispage' );
1236 $q = 'action=watch';
1238 $s = $this->makeKnownLink( $n, $t, $q );
1239 } else {
1240 $s = wfMsg( 'notanarticle' );
1242 return $s;
1245 function moveThisPage() {
1246 global $wgTitle, $wgLang;
1248 if ( $wgTitle->userCanEdit() ) {
1249 $s = $this->makeKnownLink( $wgLang->specialPage( 'Movepage' ),
1250 wfMsg( 'movethispage' ), 'target=' . $wgTitle->getPrefixedURL() );
1251 } // no message if page is protected - would be redundant
1252 return $s;
1255 function historyLink() {
1256 global $wgTitle;
1258 $s = $this->makeKnownLink( $wgTitle->getPrefixedText(),
1259 wfMsg( 'history' ), 'action=history' );
1260 return $s;
1263 function whatLinksHere() {
1264 global $wgTitle, $wgLang;
1266 $s = $this->makeKnownLink( $wgLang->specialPage( 'Whatlinkshere' ),
1267 wfMsg( 'whatlinkshere' ), 'target=' . $wgTitle->getPrefixedURL() );
1268 return $s;
1271 function userContribsLink() {
1272 global $wgTitle, $wgLang;
1274 $s = $this->makeKnownLink( $wgLang->specialPage( 'Contributions' ),
1275 wfMsg( 'contributions' ), 'target=' . $wgTitle->getPartialURL() );
1276 return $s;
1279 function emailUserLink() {
1280 global $wgTitle, $wgLang;
1282 $s = $this->makeKnownLink( $wgLang->specialPage( 'Emailuser' ),
1283 wfMsg( 'emailuser' ), 'target=' . $wgTitle->getPartialURL() );
1284 return $s;
1287 function watchPageLinksLink() {
1288 global $wgOut, $wgTitle, $wgLang;
1290 if ( ! $wgOut->isArticleRelated() ) {
1291 $s = '(' . wfMsg( 'notanarticle' ) . ')';
1292 } else {
1293 $s = $this->makeKnownLink( $wgLang->specialPage(
1294 'Recentchangeslinked' ), wfMsg( 'recentchangeslinked' ),
1295 'target=' . $wgTitle->getPrefixedURL() );
1297 return $s;
1300 function otherLanguages() {
1301 global $wgOut, $wgLang, $wgTitle, $wgUseNewInterlanguage;
1303 $a = $wgOut->getLanguageLinks();
1304 if ( 0 == count( $a ) ) {
1305 if ( !$wgUseNewInterlanguage ) return '';
1306 $ns = $wgLang->getNsIndex ( $wgTitle->getNamespace () ) ;
1307 if ( $ns != 0 AND $ns != 1 ) return '' ;
1308 $pn = 'Intl' ;
1309 $x = 'mode=addlink&xt='.$wgTitle->getDBkey() ;
1310 return $this->makeKnownLink( $wgLang->specialPage( $pn ),
1311 wfMsg( 'intl' ) , $x );
1314 if ( !$wgUseNewInterlanguage ) {
1315 $s = wfMsg( 'otherlanguages' ) . ': ';
1316 } else {
1317 global $wgLanguageCode ;
1318 $x = 'mode=zoom&xt='.$wgTitle->getDBkey() ;
1319 $x .= '&xl='.$wgLanguageCode ;
1320 $s = $this->makeKnownLink( $wgLang->specialPage( 'Intl' ),
1321 wfMsg( 'otherlanguages' ) , $x ) . ': ' ;
1324 $s = wfMsg( 'otherlanguages' ) . ': ';
1325 $first = true;
1326 if($wgLang->isRTL()) $s .= '<span dir="LTR">';
1327 foreach( $a as $l ) {
1328 if ( ! $first ) { $s .= ' | '; }
1329 $first = false;
1331 $nt = Title::newFromText( $l );
1332 $url = $nt->getFullURL();
1333 $text = $wgLang->getLanguageName( $nt->getInterwiki() );
1335 if ( '' == $text ) { $text = $l; }
1336 $style = $this->getExternalLinkAttributes( $l, $text );
1337 $s .= "<a href=\"{$url}\"{$style}>{$text}</a>";
1339 if($wgLang->isRTL()) $s .= '</span>';
1340 return $s;
1343 function bugReportsLink() {
1344 $s = $this->makeKnownLink( wfMsg( 'bugreportspage' ),
1345 wfMsg( 'bugreports' ) );
1346 return $s;
1349 function dateLink() {
1350 global $wgLinkCache;
1351 $t1 = Title::newFromText( gmdate( 'F j' ) );
1352 $t2 = Title::newFromText( gmdate( 'Y' ) );
1354 $wgLinkCache->suspend();
1355 $id = $t1->getArticleID();
1356 $wgLinkCache->resume();
1358 if ( 0 == $id ) {
1359 $s = $this->makeBrokenLink( $t1->getText() );
1360 } else {
1361 $s = $this->makeKnownLink( $t1->getText() );
1363 $s .= ', ';
1365 $wgLinkCache->suspend();
1366 $id = $t2->getArticleID();
1367 $wgLinkCache->resume();
1369 if ( 0 == $id ) {
1370 $s .= $this->makeBrokenLink( $t2->getText() );
1371 } else {
1372 $s .= $this->makeKnownLink( $t2->getText() );
1374 return $s;
1377 function talkLink() {
1378 global $wgLang, $wgTitle, $wgLinkCache;
1380 $tns = $wgTitle->getNamespace();
1381 if ( -1 == $tns ) { return ''; }
1383 $pn = $wgTitle->getText();
1384 $tp = wfMsg( 'talkpage' );
1385 if ( Namespace::isTalk( $tns ) ) {
1386 $lns = Namespace::getSubject( $tns );
1387 switch($tns) {
1388 case 1:
1389 $text = wfMsg('articlepage');
1390 break;
1391 case 3:
1392 $text = wfMsg('userpage');
1393 break;
1394 case 5:
1395 $text = wfMsg('wikipediapage');
1396 break;
1397 case 7:
1398 $text = wfMsg('imagepage');
1399 break;
1400 default:
1401 $text= wfMsg('articlepage');
1403 } else {
1405 $lns = Namespace::getTalk( $tns );
1406 $text=$tp;
1408 $n = $wgLang->getNsText( $lns );
1409 if ( '' == $n ) { $link = $pn; }
1410 else { $link = $n.':'.$pn; }
1412 $wgLinkCache->suspend();
1413 $s = $this->makeLink( $link, $text );
1414 $wgLinkCache->resume();
1416 return $s;
1419 function commentLink() {
1420 global $wgLang, $wgTitle, $wgLinkCache;
1422 $tns = $wgTitle->getNamespace();
1423 if ( -1 == $tns ) { return ''; }
1425 $lns = ( Namespace::isTalk( $tns ) ) ? $tns : Namespace::getTalk( $tns );
1427 # assert Namespace::isTalk( $lns )
1429 $n = $wgLang->getNsText( $lns );
1430 $pn = $wgTitle->getText();
1432 $link = $n.':'.$pn;
1434 $wgLinkCache->suspend();
1435 $s = $this->makeKnownLink($link, wfMsg('postcomment'), 'action=edit&section=new');
1436 $wgLinkCache->resume();
1438 return $s;
1442 * After all the page content is transformed into HTML, it makes
1443 * a final pass through here for things like table backgrounds.
1444 * @todo probably deprecated [AV]
1446 function transformContent( $text ) {
1447 return $text;
1451 * Note: This function MUST call getArticleID() on the link,
1452 * otherwise the cache won't get updated properly. See LINKCACHE.DOC.
1454 function makeLink( $title, $text = '', $query = '', $trail = '' ) {
1455 wfProfileIn( 'Skin::makeLink' );
1456 $nt = Title::newFromText( $title );
1457 if ($nt) {
1458 $result = $this->makeLinkObj( Title::newFromText( $title ), $text, $query, $trail );
1459 } else {
1460 wfDebug( 'Invalid title passed to Skin::makeLink(): "'.$title."\"\n" );
1461 $result = $text == "" ? $title : $text;
1464 wfProfileOut( 'Skin::makeLink' );
1465 return $result;
1468 function makeKnownLink( $title, $text = '', $query = '', $trail = '', $prefix = '',$aprops = '') {
1469 $nt = Title::newFromText( $title );
1470 if ($nt) {
1471 return $this->makeKnownLinkObj( Title::newFromText( $title ), $text, $query, $trail, $prefix , $aprops );
1472 } else {
1473 wfDebug( 'Invalid title passed to Skin::makeKnownLink(): "'.$title."\"\n" );
1474 return $text == '' ? $title : $text;
1478 function makeBrokenLink( $title, $text = '', $query = '', $trail = '' ) {
1479 $nt = Title::newFromText( $title );
1480 if ($nt) {
1481 return $this->makeBrokenLinkObj( Title::newFromText( $title ), $text, $query, $trail );
1482 } else {
1483 wfDebug( 'Invalid title passed to Skin::makeBrokenLink(): "'.$title."\"\n" );
1484 return $text == '' ? $title : $text;
1488 function makeStubLink( $title, $text = '', $query = '', $trail = '' ) {
1489 $nt = Title::newFromText( $title );
1490 if ($nt) {
1491 return $this->makeStubLinkObj( Title::newFromText( $title ), $text, $query, $trail );
1492 } else {
1493 wfDebug( 'Invalid title passed to Skin::makeStubLink(): "'.$title."\"\n" );
1494 return $text == '' ? $title : $text;
1499 * Pass a title object, not a title string
1501 function makeLinkObj( &$nt, $text= '', $query = '', $trail = '', $prefix = '' ) {
1502 global $wgOut, $wgUser;
1503 $fname = 'Skin::makeLinkObj';
1505 # Fail gracefully
1506 if ( ! isset($nt) )
1507 return "<!-- ERROR -->{$prefix}{$text}{$trail}";
1509 if ( $nt->isExternal() ) {
1510 $u = $nt->getFullURL();
1511 $link = $nt->getPrefixedURL();
1512 if ( '' == $text ) { $text = $nt->getPrefixedText(); }
1513 $style = $this->getExternalLinkAttributes( $link, $text, 'extiw' );
1515 $inside = '';
1516 if ( '' != $trail ) {
1517 if ( preg_match( '/^([a-z]+)(.*)$$/sD', $trail, $m ) ) {
1518 $inside = $m[1];
1519 $trail = $m[2];
1522 $retVal = "<a href=\"{$u}\"{$style}>{$text}{$inside}</a>{$trail}";
1523 } elseif ( 0 == $nt->getNamespace() && "" == $nt->getText() ) {
1524 $retVal = $this->makeKnownLinkObj( $nt, $text, $query, $trail, $prefix );
1525 } elseif ( ( -1 == $nt->getNamespace() ) ||
1526 ( Namespace::getImage() == $nt->getNamespace() ) ) {
1527 $retVal = $this->makeKnownLinkObj( $nt, $text, $query, $trail, $prefix );
1528 } else {
1529 if ( $this->postParseLinkColour() ) {
1530 $inside = '';
1531 if ( '' != $trail ) {
1532 if ( preg_match( $this->linktrail, $trail, $m ) ) {
1533 $inside = $m[1];
1534 $trail = $m[2];
1538 # Allows wiki to bypass using linkcache, see OutputPage::parseLinkHolders()
1539 $retVal = '<!--LINK ' . implode( ' ', array( $nt->getNamespace(), $nt->getDBkey(),
1540 $query, $prefix . $text . $inside ) ) . "-->{$trail}";
1541 } else {
1542 # Work out link colour immediately
1543 $aid = $nt->getArticleID() ;
1544 if ( 0 == $aid ) {
1545 $retVal = $this->makeBrokenLinkObj( $nt, $text, $query, $trail, $prefix );
1546 } else {
1547 $threshold = $wgUser->getOption('stubthreshold') ;
1548 if ( $threshold > 0 ) {
1549 $dbr =& wfGetDB( DB_SLAVE );
1550 $s = $dbr->selectRow( 'cur', array( 'LENGTH(cur_text) AS x', 'cur_namespace',
1551 'cur_is_redirect' ), array( 'cur_id' => $aid ), $fname ) ;
1552 if ( $s !== false ) {
1553 $size = $s->x;
1554 if ( $s->cur_is_redirect OR $s->cur_namespace != 0 ) {
1555 $size = $threshold*2 ; # Really big
1557 $dbr->freeResult( $res );
1558 } else {
1559 $size = $threshold*2 ; # Really big
1561 } else {
1562 $size = 1 ;
1564 if ( $size < $threshold ) {
1565 $retVal = $this->makeStubLinkObj( $nt, $text, $query, $trail, $prefix );
1566 } else {
1567 $retVal = $this->makeKnownLinkObj( $nt, $text, $query, $trail, $prefix );
1572 return $retVal;
1576 * Pass a title object, not a title string
1578 function makeKnownLinkObj( &$nt, $text = '', $query = '', $trail = '', $prefix = '' , $aprops = '' ) {
1579 global $wgOut, $wgTitle, $wgInputEncoding;
1581 $fname = 'Skin::makeKnownLinkObj';
1582 wfProfileIn( $fname );
1584 if ( !is_object( $nt ) ) {
1585 return $text;
1587 $link = $nt->getPrefixedURL();
1588 # if ( '' != $section && substr($section,0,1) != "#" ) {
1589 # $section = ''
1591 if ( '' == $link ) {
1592 $u = '';
1593 if ( '' == $text ) {
1594 $text = htmlspecialchars( $nt->getFragment() );
1596 } else {
1597 $u = $nt->escapeLocalURL( $query );
1599 if ( '' != $nt->getFragment() ) {
1600 $anchor = urlencode( do_html_entity_decode( str_replace(' ', '_', $nt->getFragment()), ENT_COMPAT, $wgInputEncoding ) );
1601 $replacearray = array(
1602 '%3A' => ':',
1603 '%' => '.'
1605 $u .= '#' . str_replace(array_keys($replacearray),array_values($replacearray),$anchor);
1607 if ( '' == $text ) {
1608 $text = htmlspecialchars( $nt->getPrefixedText() );
1610 $style = $this->getInternalLinkAttributesObj( $nt, $text );
1612 $inside = '';
1613 if ( '' != $trail ) {
1614 if ( preg_match( $this->linktrail, $trail, $m ) ) {
1615 $inside = $m[1];
1616 $trail = $m[2];
1619 $r = "<a href=\"{$u}\"{$style}{$aprops}>{$prefix}{$text}{$inside}</a>{$trail}";
1620 wfProfileOut( $fname );
1621 return $r;
1625 * Pass a title object, not a title string
1627 function makeBrokenLinkObj( &$nt, $text = '', $query = '', $trail = '', $prefix = '' ) {
1628 global $wgOut, $wgUser;
1630 # Fail gracefully
1631 if ( ! isset($nt) )
1632 return "<!-- ERROR -->{$prefix}{$text}{$trail}";
1634 $fname = 'Skin::makeBrokenLinkObj';
1635 wfProfileIn( $fname );
1637 if ( '' == $query ) {
1638 $q = 'action=edit';
1639 } else {
1640 $q = 'action=edit&'.$query;
1642 $u = $nt->escapeLocalURL( $q );
1644 if ( '' == $text ) {
1645 $text = htmlspecialchars( $nt->getPrefixedText() );
1647 $style = $this->getInternalLinkAttributesObj( $nt, $text, "yes" );
1649 $inside = '';
1650 if ( '' != $trail ) {
1651 if ( preg_match( $this->linktrail, $trail, $m ) ) {
1652 $inside = $m[1];
1653 $trail = $m[2];
1656 if ( $wgUser->getOption( 'highlightbroken' ) ) {
1657 $s = "<a href=\"{$u}\"{$style}>{$prefix}{$text}{$inside}</a>{$trail}";
1658 } else {
1659 $s = "{$prefix}{$text}{$inside}<a href=\"{$u}\"{$style}>?</a>{$trail}";
1662 wfProfileOut( $fname );
1663 return $s;
1667 * Pass a title object, not a title string
1669 function makeStubLinkObj( &$nt, $text = '', $query = '', $trail = '', $prefix = '' ) {
1670 global $wgOut, $wgUser;
1672 $link = $nt->getPrefixedURL();
1674 $u = $nt->escapeLocalURL( $query );
1676 if ( '' == $text ) {
1677 $text = htmlspecialchars( $nt->getPrefixedText() );
1679 $style = $this->getInternalLinkAttributesObj( $nt, $text, 'stub' );
1681 $inside = '';
1682 if ( '' != $trail ) {
1683 if ( preg_match( $this->linktrail, $trail, $m ) ) {
1684 $inside = $m[1];
1685 $trail = $m[2];
1688 if ( $wgUser->getOption( 'highlightbroken' ) ) {
1689 $s = "<a href=\"{$u}\"{$style}>{$prefix}{$text}{$inside}</a>{$trail}";
1690 } else {
1691 $s = "{$prefix}{$text}{$inside}<a href=\"{$u}\"{$style}>!</a>{$trail}";
1693 return $s;
1696 function makeSelfLinkObj( &$nt, $text = '', $query = '', $trail = '', $prefix = '' ) {
1697 $u = $nt->escapeLocalURL( $query );
1698 if ( '' == $text ) {
1699 $text = htmlspecialchars( $nt->getPrefixedText() );
1701 $inside = '';
1702 if ( '' != $trail ) {
1703 if ( preg_match( $this->linktrail, $trail, $m ) ) {
1704 $inside = $m[1];
1705 $trail = $m[2];
1708 return "<strong>{$prefix}{$text}{$inside}</strong>{$trail}";
1711 /* these are used extensively in SkinPHPTal, but also some other places */
1712 /*static*/ function makeSpecialUrl( $name, $urlaction='' ) {
1713 $title = Title::makeTitle( NS_SPECIAL, $name );
1714 $this->checkTitle($title, $name);
1715 return $title->getLocalURL( $urlaction );
1717 /*static*/ function makeTalkUrl ( $name, $urlaction='' ) {
1718 $title = Title::newFromText( $name );
1719 $title = $title->getTalkPage();
1720 $this->checkTitle($title, $name);
1721 return $title->getLocalURL( $urlaction );
1723 /*static*/ function makeArticleUrl ( $name, $urlaction='' ) {
1724 $title = Title::newFromText( $name );
1725 $title= $title->getSubjectPage();
1726 $this->checkTitle($title, $name);
1727 return $title->getLocalURL( $urlaction );
1729 /*static*/ function makeI18nUrl ( $name, $urlaction='' ) {
1730 $title = Title::newFromText( wfMsg($name) );
1731 $this->checkTitle($title, $name);
1732 return $title->getLocalURL( $urlaction );
1734 /*static*/ function makeUrl ( $name, $urlaction='' ) {
1735 $title = Title::newFromText( $name );
1736 $this->checkTitle($title, $name);
1737 return $title->getLocalURL( $urlaction );
1739 # this can be passed the NS number as defined in Language.php
1740 /*static*/ function makeNSUrl( $name, $urlaction='', $namespace=0 ) {
1741 $title = Title::makeTitleSafe( $namespace, $name );
1742 $this->checkTitle($title, $name);
1743 return $title->getLocalURL( $urlaction );
1746 /* these return an array with the 'href' and boolean 'exists' */
1747 /*static*/ function makeUrlDetails ( $name, $urlaction='' ) {
1748 $title = Title::newFromText( $name );
1749 $this->checkTitle($title, $name);
1750 return array(
1751 'href' => $title->getLocalURL( $urlaction ),
1752 'exists' => $title->getArticleID() != 0?true:false
1755 /*static*/ function makeTalkUrlDetails ( $name, $urlaction='' ) {
1756 $title = Title::newFromText( $name );
1757 $title = $title->getTalkPage();
1758 $this->checkTitle($title, $name);
1759 return array(
1760 'href' => $title->getLocalURL( $urlaction ),
1761 'exists' => $title->getArticleID() != 0?true:false
1764 /*static*/ function makeArticleUrlDetails ( $name, $urlaction='' ) {
1765 $title = Title::newFromText( $name );
1766 $title= $title->getSubjectPage();
1767 $this->checkTitle($title, $name);
1768 return array(
1769 'href' => $title->getLocalURL( $urlaction ),
1770 'exists' => $title->getArticleID() != 0?true:false
1773 /*static*/ function makeI18nUrlDetails ( $name, $urlaction='' ) {
1774 $title = Title::newFromText( wfMsg($name) );
1775 $this->checkTitle($title, $name);
1776 return array(
1777 'href' => $title->getLocalURL( $urlaction ),
1778 'exists' => $title->getArticleID() != 0?true:false
1782 # make sure we have some title to operate on
1783 /*static*/ function checkTitle ( &$title, &$name ) {
1784 if(!is_object($title)) {
1785 $title = Title::newFromText( $name );
1786 if(!is_object($title)) {
1787 $title = Title::newFromText( '--error: link target missing--' );
1792 function fnamePart( $url ) {
1793 $basename = strrchr( $url, '/' );
1794 if ( false === $basename ) {
1795 $basename = $url;
1796 } else {
1797 $basename = substr( $basename, 1 );
1799 return htmlspecialchars( $basename );
1802 function makeImage( $url, $alt = '' ) {
1803 global $wgOut;
1805 if ( '' == $alt ) {
1806 $alt = $this->fnamePart( $url );
1808 $s = '<img src="'.$url.'" alt="'.$alt.'" />';
1809 return $s;
1812 function makeImageLink( $name, $url, $alt = '' ) {
1813 $nt = Title::makeTitleSafe( NS_IMAGE, $name );
1814 return $this->makeImageLinkObj( $nt, $alt );
1817 function makeImageLinkObj( $nt, $alt = '' ) {
1818 global $wgLang, $wgUseImageResize;
1819 $img = Image::newFromTitle( $nt );
1820 $url = $img->getURL();
1822 $align = '';
1823 $prefix = $postfix = '';
1825 if ( $wgUseImageResize ) {
1826 # Check if the alt text is of the form "options|alt text"
1827 # Options are:
1828 # * thumbnail make a thumbnail with enlarge-icon and caption, alignment depends on lang
1829 # * left no resizing, just left align. label is used for alt= only
1830 # * right same, but right aligned
1831 # * none same, but not aligned
1832 # * ___px scale to ___ pixels width, no aligning. e.g. use in taxobox
1833 # * center center the image
1834 # * framed Keep original image size, no magnify-button.
1836 $part = explode( '|', $alt);
1838 $mwThumb =& MagicWord::get( MAG_IMG_THUMBNAIL );
1839 $mwLeft =& MagicWord::get( MAG_IMG_LEFT );
1840 $mwRight =& MagicWord::get( MAG_IMG_RIGHT );
1841 $mwNone =& MagicWord::get( MAG_IMG_NONE );
1842 $mwWidth =& MagicWord::get( MAG_IMG_WIDTH );
1843 $mwCenter =& MagicWord::get( MAG_IMG_CENTER );
1844 $mwFramed =& MagicWord::get( MAG_IMG_FRAMED );
1845 $alt = $part[count($part)-1];
1847 $height = $framed = $thumb = false;
1848 $manual_thumb = "" ;
1850 foreach( $part as $key => $val ) {
1851 $val_parts = explode ( "=" , $val , 2 ) ;
1852 $left_part = array_shift ( $val_parts ) ;
1853 if ( ! is_null( $mwThumb->matchVariableStartToEnd($val) ) ) {
1854 $thumb=true;
1855 } elseif ( count ( $val_parts ) == 1 && ! is_null( $mwThumb->matchVariableStartToEnd($left_part) ) ) {
1856 # use manually specified thumbnail
1857 $thumb=true;
1858 $manual_thumb = array_shift ( $val_parts ) ;
1859 } elseif ( ! is_null( $mwRight->matchVariableStartToEnd($val) ) ) {
1860 # remember to set an alignment, don't render immediately
1861 $align = 'right';
1862 } elseif ( ! is_null( $mwLeft->matchVariableStartToEnd($val) ) ) {
1863 # remember to set an alignment, don't render immediately
1864 $align = 'left';
1865 } elseif ( ! is_null( $mwCenter->matchVariableStartToEnd($val) ) ) {
1866 # remember to set an alignment, don't render immediately
1867 $align = 'center';
1868 } elseif ( ! is_null( $mwNone->matchVariableStartToEnd($val) ) ) {
1869 # remember to set an alignment, don't render immediately
1870 $align = 'none';
1871 } elseif ( ! is_null( $match = $mwWidth->matchVariableStartToEnd($val) ) ) {
1872 # $match is the image width in pixels
1873 if ( preg_match( '/^([0-9]*)x([0-9]*)$/', $match, $m ) ) {
1874 $width = intval( $m[1] );
1875 $height = intval( $m[2] );
1876 } else {
1877 $width = intval($match);
1879 } elseif ( ! is_null( $mwFramed->matchVariableStartToEnd($val) ) ) {
1880 $framed=true;
1883 if ( 'center' == $align )
1885 $prefix = '<span style="text-align: center">';
1886 $postfix = '</span>';
1887 $align = 'none';
1890 if ( $thumb || $framed ) {
1892 # Create a thumbnail. Alignment depends on language
1893 # writing direction, # right aligned for left-to-right-
1894 # languages ("Western languages"), left-aligned
1895 # for right-to-left-languages ("Semitic languages")
1897 # If thumbnail width has not been provided, it is set
1898 # here to 180 pixels
1899 if ( $align == '' ) {
1900 $align = $wgLang->isRTL() ? 'left' : 'right';
1902 if ( ! isset($width) ) {
1903 $width = 180;
1905 return $prefix.$this->makeThumbLinkObj( $img, $alt, $align, $width, $height, $framed, $manual_thumb ).$postfix;
1907 } elseif ( isset($width) ) {
1909 # Create a resized image, without the additional thumbnail
1910 # features
1912 if ( ( ! $height === false )
1913 && ( $img->getHeight() * $width / $img->getWidth() > $height ) ) {
1914 print "height=$height<br>\nimg->getHeight() = ".$img->getHeight()."<br>\n";
1915 print 'rescaling by factor '. $height / $img->getHeight() . "<br>\n";
1916 $width = $img->getWidth() * $height / $img->getHeight();
1918 if ( '' == $manual_thumb ) $url = $img->createThumb( $width );
1920 } # endif $wgUseImageResize
1922 if ( empty( $alt ) ) {
1923 $alt = preg_replace( '/\.(.+?)^/', '', $img->getName() );
1925 $alt = htmlspecialchars( $alt );
1927 $u = $nt->escapeLocalURL();
1928 if ( $url == '' )
1930 $s = wfMsg( 'missingimage', $img->getName() );
1931 $s .= "<br>{$alt}<br>{$url}<br>\n";
1932 } else {
1933 $s = '<a href="'.$u.'" class="image" title="'.$alt.'">' .
1934 '<img src="'.$url.'" alt="'.$alt.'" /></a>';
1936 if ( '' != $align ) {
1937 $s = "<div class=\"float{$align}\"><span>{$s}</span></div>";
1939 return str_replace("\n", ' ',$prefix.$s.$postfix);
1943 * Make HTML for a thumbnail including image, border and caption
1944 * $img is an Image object
1946 function makeThumbLinkObj( $img, $label = '', $align = 'right', $boxwidth = 180, $boxheight=false, $framed=false , $manual_thumb = "" ) {
1947 global $wgStylePath, $wgLang;
1948 # $image = Title::makeTitleSafe( NS_IMAGE, $name );
1949 $url = $img->getURL();
1951 #$label = htmlspecialchars( $label );
1952 $alt = preg_replace( '/<[^>]*>/', '', $label);
1953 $alt = htmlspecialchars( $alt );
1955 $width = $height = 0;
1956 if ( $img->exists() )
1958 $width = $img->getWidth();
1959 $height = $img->getHeight();
1961 if ( 0 == $width || 0 == $height )
1963 $width = $height = 200;
1965 if ( $boxwidth == 0 )
1967 $boxwidth = 200;
1969 if ( $framed )
1971 // Use image dimensions, don't scale
1972 $boxwidth = $width;
1973 $oboxwidth = $boxwidth + 2;
1974 $boxheight = $height;
1975 $thumbUrl = $url;
1976 } else {
1977 $h = intval( $height/($width/$boxwidth) );
1978 $oboxwidth = $boxwidth + 2;
1979 if ( ( ! $boxheight === false ) && ( $h > $boxheight ) )
1981 $boxwidth *= $boxheight/$h;
1982 } else {
1983 $boxheight = $h;
1985 if ( '' == $manual_thumb ) $thumbUrl = $img->createThumb( $boxwidth );
1988 if ( $manual_thumb != '' ) # Use manually specified thumbnail
1990 $manual_title = Title::makeTitleSafe( NS_IMAGE, $manual_thumb ); #new Title ( $manual_thumb ) ;
1991 $manual_img = Image::newFromTitle( $manual_title );
1992 $thumbUrl = $manual_img->getURL();
1993 if ( $manual_img->exists() )
1995 $width = $manual_img->getWidth();
1996 $height = $manual_img->getHeight();
1997 $boxwidth = $width ;
1998 $boxheight = $height ;
1999 $oboxwidth = $boxwidth + 2 ;
2003 $u = $img->getEscapeLocalURL();
2005 $more = htmlspecialchars( wfMsg( 'thumbnail-more' ) );
2006 $magnifyalign = $wgLang->isRTL() ? 'left' : 'right';
2007 $textalign = $wgLang->isRTL() ? ' style="text-align:right"' : '';
2009 $s = "<div class=\"thumb t{$align}\"><div style=\"width:{$oboxwidth}px;\">";
2010 if ( $thumbUrl == '' ) {
2011 $s .= wfMsg( 'missingimage', $img->getName() );
2012 $zoomicon = '';
2013 } else {
2014 $s .= '<a href="'.$u.'" class="internal" title="'.$alt.'">'.
2015 '<img src="'.$thumbUrl.'" alt="'.$alt.'" ' .
2016 'width="'.$boxwidth.'" height="'.$boxheight.'" /></a>';
2017 if ( $framed ) {
2018 $zoomicon="";
2019 } else {
2020 $zoomicon = '<div class="magnify" style="float:'.$magnifyalign.'">'.
2021 '<a href="'.$u.'" class="internal" title="'.$more.'">'.
2022 '<img src="'.$wgStylePath.'/common/images/magnify-clip.png" ' .
2023 'width="15" height="11" alt="'.$more.'" /></a></div>';
2026 $s .= ' <div class="thumbcaption" '.$textalign.'>'.$zoomicon.$label."</div></div></div>";
2027 return str_replace("\n", ' ', $s);
2030 function makeMediaLink( $name, $url, $alt = '' ) {
2031 $nt = Title::makeTitleSafe( Namespace::getMedia(), $name );
2032 return $this->makeMediaLinkObj( $nt, $alt );
2035 function makeMediaLinkObj( $nt, $alt = '' ) {
2036 if ( ! isset( $nt ) )
2038 ### HOTFIX. Instead of breaking, return empty string.
2039 $s = $alt;
2040 } else {
2041 $name = $nt->getDBKey();
2042 $url = Image::wfImageUrl( $name );
2043 if ( empty( $alt ) ) {
2044 $alt = preg_replace( '/\.(.+?)^/', '', $name );
2047 $u = htmlspecialchars( $url );
2048 $s = "<a href=\"{$u}\" class='internal' title=\"{$alt}\">{$alt}</a>";
2050 return $s;
2053 function specialLink( $name, $key = '' ) {
2054 global $wgLang;
2056 if ( '' == $key ) { $key = strtolower( $name ); }
2057 $pn = $wgLang->ucfirst( $name );
2058 return $this->makeKnownLink( $wgLang->specialPage( $pn ),
2059 wfMsg( $key ) );
2062 function makeExternalLink( $url, $text, $escape = true ) {
2063 $style = $this->getExternalLinkAttributes( $url, $text );
2064 $url = htmlspecialchars( $url );
2065 if( $escape ) {
2066 $text = htmlspecialchars( $text );
2068 return '<a href="'.$url.'"'.$style.'>'.$text.'</a>';
2071 # Called by history lists and recent changes
2074 # Returns text for the start of the tabular part of RC
2075 function beginRecentChangesList() {
2076 $this->rc_cache = array() ;
2077 $this->rcMoveIndex = 0;
2078 $this->rcCacheIndex = 0 ;
2079 $this->lastdate = '';
2080 $this->rclistOpen = false;
2081 return '';
2084 function beginImageHistoryList() {
2085 $s = "\n<h2>" . wfMsg( 'imghistory' ) . "</h2>\n" .
2086 "<p>" . wfMsg( 'imghistlegend' ) . "</p>\n".'<ul class="special">';
2087 return $s;
2091 * Returns text for the end of RC
2092 * If enhanced RC is in use, returns pretty much all the text
2094 function endRecentChangesList() {
2095 $s = $this->recentChangesBlock() ;
2096 if( $this->rclistOpen ) {
2097 $s .= "</ul>\n";
2099 return $s;
2103 * Enhanced RC ungrouped line
2105 function recentChangesBlockLine ( $rcObj ) {
2106 global $wgStylePath, $wgLang ;
2108 # Get rc_xxxx variables
2109 extract( $rcObj->mAttribs ) ;
2110 $curIdEq = 'curid='.$rc_cur_id;
2112 # Spacer image
2113 $r = '' ;
2115 $r .= '<img src="'.$wgStylePath.'/common/images/Arr_.png" width="12" height="12" border="0" />' ;
2116 $r .= '<tt>' ;
2118 if ( $rc_type == RC_MOVE || $rc_type == RC_MOVE_OVER_REDIRECT ) {
2119 $r .= '&nbsp;&nbsp;';
2120 } else {
2121 # M & N (minor & new)
2122 $M = wfMsg( 'minoreditletter' );
2123 $N = wfMsg( 'newpageletter' );
2125 if ( $rc_type == RC_NEW ) {
2126 $r .= $N ;
2127 } else {
2128 $r .= '&nbsp;' ;
2130 if ( $rc_minor ) {
2131 $r .= $M ;
2132 } else {
2133 $r .= '&nbsp;' ;
2137 # Timestamp
2138 $r .= ' '.$rcObj->timestamp.' ' ;
2139 $r .= '</tt>' ;
2141 # Article link
2142 $link = $rcObj->link ;
2143 if ( $rcObj->watched ) $link = '<strong>'.$link.'</strong>' ;
2144 $r .= $link ;
2146 # Diff
2147 $r .= ' (' ;
2148 $r .= $rcObj->difflink ;
2149 $r .= '; ' ;
2151 # Hist
2152 $r .= $this->makeKnownLinkObj( $rcObj->getTitle(), wfMsg( 'hist' ), $curIdEq.'&action=history' );
2154 # User/talk
2155 $r .= ') . . '.$rcObj->userlink ;
2156 $r .= $rcObj->usertalklink ;
2158 # Comment
2159 if ( $rc_comment != '' && $rc_type != RC_MOVE && $rc_type != RC_MOVE_OVER_REDIRECT ) {
2160 $rc_comment=$this->formatComment($rc_comment, $rcObj->getTitle());
2161 $r .= $wgLang->emphasize( ' ('.$rc_comment.')' );
2164 $r .= "<br />\n" ;
2165 return $r ;
2169 * Enhanced RC group
2171 function recentChangesBlockGroup ( $block ) {
2172 global $wgStylePath, $wgLang ;
2174 $r = '' ;
2175 $M = wfMsg( 'minoreditletter' );
2176 $N = wfMsg( 'newpageletter' );
2178 # Collate list of users
2179 $isnew = false ;
2180 $userlinks = array () ;
2181 foreach ( $block AS $rcObj ) {
2182 $oldid = $rcObj->mAttribs['rc_last_oldid'];
2183 if ( $rcObj->mAttribs['rc_new'] ) $isnew = true ;
2184 $u = $rcObj->userlink ;
2185 if ( !isset ( $userlinks[$u] ) ) $userlinks[$u] = 0 ;
2186 $userlinks[$u]++ ;
2189 # Sort the list and convert to text
2190 krsort ( $userlinks ) ;
2191 asort ( $userlinks ) ;
2192 $users = array () ;
2193 foreach ( $userlinks as $userlink => $count) {
2194 $text = $userlink ;
2195 if ( $count > 1 ) $text .= " ({$count}&times;)" ;
2196 array_push ( $users , $text ) ;
2198 $users = ' <font size="-1">['.implode('; ',$users).']</font>' ;
2200 # Arrow
2201 $rci = 'RCI'.$this->rcCacheIndex ;
2202 $rcl = 'RCL'.$this->rcCacheIndex ;
2203 $rcm = 'RCM'.$this->rcCacheIndex ;
2204 $toggleLink = "javascript:toggleVisibility('$rci','$rcm','$rcl')" ;
2205 $arrowdir = $wgLang->isRTL() ? 'l' : 'r';
2206 $tl = '<span id="'.$rcm.'"><a href="'.$toggleLink.'"><img src="'.$wgStylePath.'/common/images/Arr_'.$arrowdir.'.png" width="12" height="12" /></a></span>' ;
2207 $tl .= '<span id="'.$rcl.'" style="display:none"><a href="'.$toggleLink.'"><img src="'.$wgStylePath.'/common/images/Arr_d.png" width="12" height="12" /></a></span>' ;
2208 $r .= $tl ;
2210 # Main line
2211 # M/N
2212 $r .= '<tt>' ;
2213 if ( $isnew ) $r .= $N ;
2214 else $r .= '&nbsp;' ;
2215 $r .= '&nbsp;' ; # Minor
2217 # Timestamp
2218 $r .= ' '.$block[0]->timestamp.' ' ;
2219 $r .= '</tt>' ;
2221 # Article link
2222 $link = $block[0]->link ;
2223 if ( $block[0]->watched ) $link = '<strong>'.$link.'</strong>' ;
2224 $r .= $link ;
2226 $curIdEq = 'curid=' . $block[0]->mAttribs['rc_cur_id'];
2227 if ( $block[0]->mAttribs['rc_type'] != RC_LOG ) {
2228 # Changes
2229 $r .= ' ('.count($block).' ' ;
2230 if ( $isnew ) $r .= wfMsg('changes');
2231 else $r .= $this->makeKnownLinkObj( $block[0]->getTitle() , wfMsg('changes') ,
2232 $curIdEq.'&diff=0&oldid='.$oldid ) ;
2233 $r .= '; ' ;
2235 # History
2236 $r .= $this->makeKnownLinkObj( $block[0]->getTitle(), wfMsg( 'history' ), $curIdEq.'&action=history' );
2237 $r .= ')' ;
2240 $r .= $users ;
2241 $r .= "<br />\n" ;
2243 # Sub-entries
2244 $r .= '<div id="'.$rci.'" style="display:none">' ;
2245 foreach ( $block AS $rcObj ) {
2246 # Get rc_xxxx variables
2247 extract( $rcObj->mAttribs );
2249 $r .= '<img src="'.$wgStylePath.'/common/images/Arr_.png" width="12" height="12" />';
2250 $r .= '<tt>&nbsp; &nbsp; &nbsp; &nbsp;' ;
2251 if ( $rc_new ) $r .= $N ;
2252 else $r .= '&nbsp;' ;
2253 if ( $rc_minor ) $r .= $M ;
2254 else $r .= '&nbsp;' ;
2255 $r .= '</tt>' ;
2257 $o = '' ;
2258 if ( $rc_last_oldid != 0 ) {
2259 $o = 'oldid='.$rc_last_oldid ;
2261 if ( $rc_type == RC_LOG ) {
2262 $link = $rcObj->timestamp ;
2263 } else {
2264 $link = $this->makeKnownLinkObj( $rcObj->getTitle(), $rcObj->timestamp , "{$curIdEq}&$o" ) ;
2266 $link = '<tt>'.$link.'</tt>' ;
2268 $r .= $link ;
2269 $r .= ' (' ;
2270 $r .= $rcObj->curlink ;
2271 $r .= '; ' ;
2272 $r .= $rcObj->lastlink ;
2273 $r .= ') . . '.$rcObj->userlink ;
2274 $r .= $rcObj->usertalklink ;
2275 if ( $rc_comment != '' ) {
2276 $rc_comment=$this->formatComment($rc_comment, $rcObj->getTitle());
2277 $r .= $wgLang->emphasize( ' ('.$rc_comment.')' ) ;
2279 $r .= "<br />\n" ;
2281 $r .= "</div>\n" ;
2283 $this->rcCacheIndex++ ;
2284 return $r ;
2288 * If enhanced RC is in use, this function takes the previously cached
2289 * RC lines, arranges them, and outputs the HTML
2291 function recentChangesBlock () {
2292 global $wgStylePath ;
2293 if ( count ( $this->rc_cache ) == 0 ) return '' ;
2294 $blockOut = '';
2295 foreach ( $this->rc_cache AS $secureName => $block ) {
2296 if ( count ( $block ) < 2 ) {
2297 $blockOut .= $this->recentChangesBlockLine ( array_shift ( $block ) ) ;
2298 } else {
2299 $blockOut .= $this->recentChangesBlockGroup ( $block ) ;
2303 return '<div>'.$blockOut.'</div>' ;
2307 * Called in a loop over all displayed RC entries
2308 * Either returns the line, or caches it for later use
2310 function recentChangesLine( &$rc, $watched = false ) {
2311 global $wgUser ;
2312 $usenew = $wgUser->getOption( 'usenewrc' );
2313 if ( $usenew )
2314 $line = $this->recentChangesLineNew ( $rc, $watched ) ;
2315 else
2316 $line = $this->recentChangesLineOld ( $rc, $watched ) ;
2317 return $line ;
2320 function recentChangesLineOld( &$rc, $watched = false ) {
2321 global $wgTitle, $wgLang, $wgUser, $wgRCSeconds, $wgUseRCPatrol, $wgOnlySysopsCanPatrol;
2323 # Extract DB fields into local scope
2324 extract( $rc->mAttribs );
2325 $curIdEq = 'curid=' . $rc_cur_id;
2327 # Make date header if necessary
2328 $date = $wgLang->date( $rc_timestamp, true);
2329 $s = '';
2330 if ( $date != $this->lastdate ) {
2331 if ( '' != $this->lastdate ) { $s .= "</ul>\n"; }
2332 $s .= "<h4>{$date}</h4>\n<ul class='special'>";
2333 $this->lastdate = $date;
2334 $this->rclistOpen = true;
2337 # If this edit has not yet been patrolled, make it stick out
2338 $s .= ( ! $wgUseRCPatrol || $rc_patrolled ) ? '<li> ' : '<li class="not_patrolled"> ';
2340 if ( $rc_type == RC_MOVE || $rc_type == RC_MOVE_OVER_REDIRECT ) {
2341 # Diff
2342 $s .= '(' . wfMsg( 'diff' ) . ') (';
2343 # Hist
2344 $s .= $this->makeKnownLinkObj( $rc->getMovedToTitle(), wfMsg( 'hist' ), 'action=history' ) .
2345 ') . . ';
2347 # "[[x]] moved to [[y]]"
2348 $msg = ( $rc_type == RC_MOVE ) ? '1movedto2' : '1movedto2_redir';
2349 $s .= wfMsg( $msg, $this->makeKnownLinkObj( $rc->getTitle(), '', 'redirect=no' ),
2350 $this->makeKnownLinkObj( $rc->getMovedToTitle(), '' ) );
2351 } elseif( $rc_namespace == NS_SPECIAL && preg_match( '!^Log/(.*)$!', $rc_title, $matches ) ) {
2352 # Log updates, etc
2353 $logtype = $matches[1];
2354 $logname = LogPage::logName( $logtype );
2355 $s .= '(' . $this->makeKnownLinkObj( $rc->getTitle(), $logname ) . ')';
2356 } else {
2357 # Diff link
2358 if ( $rc_type == RC_NEW || $rc_type == RC_LOG ) {
2359 $diffLink = wfMsg( 'diff' );
2360 } else {
2361 if ( $wgUseRCPatrol && $rc_patrolled == 0 && $wgUser->getID() != 0 &&
2362 ( $wgUser->isSysop() || !$wgOnlySysopsCanPatrol ) )
2363 $rcidparam = "&rcid={$rc_id}";
2364 else
2365 $rcidparam = "";
2366 $diffLink = $this->makeKnownLinkObj( $rc->getTitle(), wfMsg( 'diff' ),
2367 "{$curIdEq}&diff={$rc_this_oldid}&oldid={$rc_last_oldid}{$rcidparam}",
2368 '', '', ' tabindex="'.$rc->counter.'"');
2370 $s .= '('.$diffLink.') (';
2372 # History link
2373 $s .= $this->makeKnownLinkObj( $rc->getTitle(), wfMsg( 'hist' ), $curIdEq.'&action=history' );
2374 $s .= ') . . ';
2376 # M and N (minor and new)
2377 if ( $rc_minor ) { $s .= ' <span class="minor">'.wfMsg( "minoreditletter" ).'</span>'; }
2378 if ( $rc_type == RC_NEW ) { $s .= '<span class="newpage">'.wfMsg( "newpageletter" ).'</span>'; }
2380 # Article link
2381 # If it's a new article, there is no diff link, but if it hasn't been
2382 # patrolled yet, we need to give users a way to do so
2383 if ( $wgUseRCPatrol && $rc_type == RC_NEW && $rc_patrolled == 0 &&
2384 $wgUser->getID() != 0 && ( $wgUser->isSysop() || !$wgOnlySysopsCanPatrol ) )
2385 $articleLink = $this->makeKnownLinkObj( $rc->getTitle(), '', "rcid={$rc_id}" );
2386 else
2387 $articleLink = $this->makeKnownLinkObj( $rc->getTitle(), '' );
2389 if ( $watched ) {
2390 $articleLink = '<strong>'.$articleLink.'</strong>';
2392 $s .= ' '.$articleLink;
2396 # Timestamp
2397 $s .= '; ' . $wgLang->time( $rc_timestamp, true, $wgRCSeconds ) . ' . . ';
2399 # User link (or contributions for unregistered users)
2400 if ( 0 == $rc_user ) {
2401 $userLink = $this->makeKnownLink( $wgLang->specialPage( 'Contributions' ),
2402 $rc_user_text, 'target=' . $rc_user_text );
2403 } else {
2404 $userLink = $this->makeLink( $wgLang->getNsText( NS_USER ) . ':'.$rc_user_text, $rc_user_text );
2406 $s .= $userLink;
2408 # User talk link
2409 $talkname=$wgLang->getNsText(NS_TALK); # use the shorter name
2410 global $wgDisableAnonTalk;
2411 if( 0 == $rc_user && $wgDisableAnonTalk ) {
2412 $userTalkLink = '';
2413 } else {
2414 $utns=$wgLang->getNsText(NS_USER_TALK);
2415 $userTalkLink= $this->makeLink($utns . ':'.$rc_user_text, $talkname );
2417 # Block link
2418 $blockLink='';
2419 if ( ( 0 == $rc_user ) && $wgUser->isSysop() ) {
2420 $blockLink = $this->makeKnownLink( $wgLang->specialPage(
2421 'Blockip' ), wfMsg( 'blocklink' ), 'ip='.$rc_user_text );
2424 if($blockLink) {
2425 if($userTalkLink) $userTalkLink .= ' | ';
2426 $userTalkLink .= $blockLink;
2428 if($userTalkLink) $s.=' ('.$userTalkLink.')';
2430 # Add comment
2431 if ( '' != $rc_comment && '*' != $rc_comment && $rc_type != RC_MOVE && $rc_type != RC_MOVE_OVER_REDIRECT ) {
2432 $rc_comment=$this->formatComment($rc_comment,$rc->getTitle());
2433 $s .= $wgLang->emphasize(' (' . $rc_comment . ')');
2435 $s .= "</li>\n";
2437 return $s;
2440 function recentChangesLineNew( &$baseRC, $watched = false ) {
2441 global $wgTitle, $wgLang, $wgUser, $wgRCSeconds;
2443 # Create a specialised object
2444 $rc = RCCacheEntry::newFromParent( $baseRC ) ;
2446 # Extract fields from DB into the function scope (rc_xxxx variables)
2447 extract( $rc->mAttribs );
2448 $curIdEq = 'curid=' . $rc_cur_id;
2450 # If it's a new day, add the headline and flush the cache
2451 $date = $wgLang->date( $rc_timestamp, true);
2452 $ret = '';
2453 if ( $date != $this->lastdate ) {
2454 # Process current cache
2455 $ret = $this->recentChangesBlock () ;
2456 $this->rc_cache = array() ;
2457 $ret .= "<h4>{$date}</h4>\n";
2458 $this->lastdate = $date;
2461 # Make article link
2462 if ( $rc_type == RC_MOVE || $rc_type == RC_MOVE_OVER_REDIRECT ) {
2463 $msg = ( $rc_type == RC_MOVE ) ? "1movedto2" : "1movedto2_redir";
2464 $clink = wfMsg( $msg, $this->makeKnownLinkObj( $rc->getTitle(), '', 'redirect=no' ),
2465 $this->makeKnownLinkObj( $rc->getMovedToTitle(), '' ) );
2466 } elseif( $rc_namespace == NS_SPECIAL && preg_match( '!^Log/(.*)$!', $rc_title, $matches ) ) {
2467 # Log updates, etc
2468 $logtype = $matches[1];
2469 $logname = LogPage::logName( $logtype );
2470 $clink = '(' . $this->makeKnownLinkObj( $rc->getTitle(), $logname ) . ')';
2471 } else {
2472 $clink = $this->makeKnownLinkObj( $rc->getTitle(), '' ) ;
2475 $time = $wgLang->time( $rc_timestamp, true, $wgRCSeconds );
2476 $rc->watched = $watched ;
2477 $rc->link = $clink ;
2478 $rc->timestamp = $time;
2480 # Make "cur" and "diff" links
2481 if ( ( $rc_type == RC_NEW && $rc_this_oldid == 0 ) || $rc_type == RC_LOG || $rc_type == RC_MOVE || $rc_type == RC_MOVE_OVER_REDIRECT ) {
2482 $curLink = wfMsg( 'cur' );
2483 $diffLink = wfMsg( 'diff' );
2484 } else {
2485 $query = $curIdEq.'&diff=0&oldid='.$rc_this_oldid;
2486 $aprops = ' tabindex="'.$baseRC->counter.'"';
2487 $curLink = $this->makeKnownLinkObj( $rc->getTitle(), wfMsg( 'cur' ), $query, '' ,'' , $aprops );
2488 $diffLink = $this->makeKnownLinkObj( $rc->getTitle(), wfMsg( 'diff'), $query, '' ,'' , $aprops );
2491 # Make "last" link
2492 $titleObj = $rc->getTitle();
2493 if ( $rc_last_oldid == 0 || $rc_type == RC_LOG || $rc_type == RC_MOVE || $rc_type == RC_MOVE_OVER_REDIRECT ) {
2494 $lastLink = wfMsg( 'last' );
2495 } else {
2496 $lastLink = $this->makeKnownLinkObj( $rc->getTitle(), wfMsg( 'last' ),
2497 $curIdEq.'&diff='.$rc_this_oldid.'&oldid='.$rc_last_oldid );
2500 # Make user link (or user contributions for unregistered users)
2501 if ( $rc_user == 0 ) {
2502 $userLink = $this->makeKnownLink( $wgLang->specialPage( 'Contributions' ),
2503 $rc_user_text, 'target=' . $rc_user_text );
2504 } else {
2505 $userLink = $this->makeLink( $wgLang->getNsText(
2506 Namespace::getUser() ) . ':'.$rc_user_text, $rc_user_text );
2509 $rc->userlink = $userLink;
2510 $rc->lastlink = $lastLink;
2511 $rc->curlink = $curLink;
2512 $rc->difflink = $diffLink;
2514 # Make user talk link
2515 $utns=$wgLang->getNsText(NS_USER_TALK);
2516 $talkname=$wgLang->getNsText(NS_TALK); # use the shorter name
2517 $userTalkLink= $this->makeLink($utns . ':'.$rc_user_text, $talkname );
2519 global $wgDisableAnonTalk;
2520 if ( ( 0 == $rc_user ) && $wgUser->isSysop() ) {
2521 $blockLink = $this->makeKnownLink( $wgLang->specialPage(
2522 'Blockip' ), wfMsg( 'blocklink' ), 'ip='.$rc_user_text );
2523 if( $wgDisableAnonTalk )
2524 $rc->usertalklink = ' ('.$blockLink.')';
2525 else
2526 $rc->usertalklink = ' ('.$userTalkLink.' | '.$blockLink.')';
2527 } else {
2528 if( $wgDisableAnonTalk && ($rc_user == 0) )
2529 $rc->usertalklink = '';
2530 else
2531 $rc->usertalklink = ' ('.$userTalkLink.')';
2534 # Put accumulated information into the cache, for later display
2535 # Page moves go on their own line
2536 $title = $rc->getTitle();
2537 $secureName = $title->getPrefixedDBkey();
2538 if ( $rc_type == RC_MOVE || $rc_type == RC_MOVE_OVER_REDIRECT ) {
2539 # Use an @ character to prevent collision with page names
2540 $this->rc_cache['@@' . ($this->rcMoveIndex++)] = array($rc);
2541 } else {
2542 if ( !isset ( $this->rc_cache[$secureName] ) ) $this->rc_cache[$secureName] = array() ;
2543 array_push ( $this->rc_cache[$secureName] , $rc ) ;
2545 return $ret;
2548 function endImageHistoryList() {
2549 $s = "</ul>\n";
2550 return $s;
2554 * This function is called by all recent changes variants, by the page history,
2555 * and by the user contributions list. It is responsible for formatting edit
2556 * comments. It escapes any HTML in the comment, but adds some CSS to format
2557 * auto-generated comments (from section editing) and formats [[wikilinks]].
2559 * The &$title parameter must be a title OBJECT. It is used to generate a
2560 * direct link to the section in the autocomment.
2561 * @author Erik Moeller <moeller@scireview.de>
2563 * Note: there's not always a title to pass to this function.
2564 * Since you can't set a default parameter for a reference, I've turned it
2565 * temporarily to a value pass. Should be adjusted further. --brion
2567 function formatComment($comment, $title = NULL) {
2568 global $wgLang;
2569 $comment = htmlspecialchars( $comment );
2571 # The pattern for autogen comments is / * foo * /, which makes for
2572 # some nasty regex.
2573 # We look for all comments, match any text before and after the comment,
2574 # add a separator where needed and format the comment itself with CSS
2575 while (preg_match('/(.*)\/\*\s*(.*?)\s*\*\/(.*)/', $comment,$match)) {
2576 $pre=$match[1];
2577 $auto=$match[2];
2578 $post=$match[3];
2579 $link='';
2580 if($title) {
2581 $section=$auto;
2583 # This is hackish but should work in most cases.
2584 $section=str_replace('[[','',$section);
2585 $section=str_replace(']]','',$section);
2586 $title->mFragment=$section;
2587 $link=$this->makeKnownLinkObj($title,wfMsg('sectionlink'));
2589 $sep='-';
2590 $auto=$link.$auto;
2591 if($pre) { $auto = $sep.' '.$auto; }
2592 if($post) { $auto .= ' '.$sep; }
2593 $auto='<span class="autocomment">'.$auto.'</span>';
2594 $comment=$pre.$auto.$post;
2597 # format regular and media links - all other wiki formatting
2598 # is ignored
2599 $medians = $wgLang->getNsText(Namespace::getMedia()).':';
2600 while(preg_match('/\[\[(.*?)(\|(.*?))*\]\](.*)$/',$comment,$match)) {
2601 # Handle link renaming [[foo|text]] will show link as "text"
2602 if( "" != $match[3] ) {
2603 $text = $match[3];
2604 } else {
2605 $text = $match[1];
2607 if( preg_match( '/^' . $medians . '(.*)$/i', $match[1], $submatch ) ) {
2608 # Media link; trail not supported.
2609 $linkRegexp = '/\[\[(.*?)\]\]/';
2610 $thelink = $this->makeMediaLink( $submatch[1], "", $text );
2611 } else {
2612 # Other kind of link
2613 if( preg_match( wfMsg( "linktrail" ), $match[4], $submatch ) ) {
2614 $trail = $submatch[1];
2615 } else {
2616 $trail = "";
2618 $linkRegexp = '/\[\[(.*?)\]\]' . preg_quote( $trail, '/' ) . '/';
2619 if ($match[1][0] == ':')
2620 $match[1] = substr($match[1], 1);
2621 $thelink = $this->makeLink( $match[1], $text, "", $trail );
2623 $comment = preg_replace( $linkRegexp, $thelink, $comment, 1 );
2625 return $comment;
2628 function imageHistoryLine( $iscur, $timestamp, $img, $user, $usertext, $size, $description ) {
2629 global $wgUser, $wgLang, $wgTitle;
2631 $datetime = $wgLang->timeanddate( $timestamp, true );
2632 $del = wfMsg( 'deleteimg' );
2633 $delall = wfMsg( 'deleteimgcompletely' );
2634 $cur = wfMsg( 'cur' );
2636 if ( $iscur ) {
2637 $url = Image::wfImageUrl( $img );
2638 $rlink = $cur;
2639 if ( $wgUser->isSysop() ) {
2640 $link = $wgTitle->escapeLocalURL( 'image=' . $wgTitle->getPartialURL() .
2641 '&action=delete' );
2642 $style = $this->getInternalLinkAttributes( $link, $delall );
2644 $dlink = '<a href="'.$link.'"'.$style.'>'.$delall.'</a>';
2645 } else {
2646 $dlink = $del;
2648 } else {
2649 $url = htmlspecialchars( wfImageArchiveUrl( $img ) );
2650 if( $wgUser->getID() != 0 && $wgTitle->userCanEdit() ) {
2651 $rlink = $this->makeKnownLink( $wgTitle->getPrefixedText(),
2652 wfMsg( 'revertimg' ), 'action=revert&oldimage=' .
2653 urlencode( $img ) );
2654 $dlink = $this->makeKnownLink( $wgTitle->getPrefixedText(),
2655 $del, 'action=delete&oldimage=' . urlencode( $img ) );
2656 } else {
2657 # Having live active links for non-logged in users
2658 # means that bots and spiders crawling our site can
2659 # inadvertently change content. Baaaad idea.
2660 $rlink = wfMsg( 'revertimg' );
2661 $dlink = $del;
2664 if ( 0 == $user ) {
2665 $userlink = $usertext;
2666 } else {
2667 $userlink = $this->makeLink( $wgLang->getNsText( Namespace::getUser() ) .
2668 ':'.$usertext, $usertext );
2670 $nbytes = wfMsg( 'nbytes', $size );
2671 $style = $this->getInternalLinkAttributes( $url, $datetime );
2673 $s = "<li> ({$dlink}) ({$rlink}) <a href=\"{$url}\"{$style}>{$datetime}</a>"
2674 . " . . {$userlink} ({$nbytes})";
2676 if ( '' != $description && '*' != $description ) {
2677 $sk=$wgUser->getSkin();
2678 $s .= $wgLang->emphasize(' (' . $sk->formatComment($description,$wgTitle) . ')');
2680 $s .= "</li>\n";
2681 return $s;
2684 function tocIndent($level) {
2685 return str_repeat( '<div class="tocindent">'."\n", $level>0 ? $level : 0 );
2688 function tocUnindent($level) {
2689 return str_repeat( "</div>\n", $level>0 ? $level : 0 );
2693 * parameter level defines if we are on an indentation level
2695 function tocLine( $anchor, $tocline, $level ) {
2696 $link = '<a href="#'.$anchor.'">'.$tocline.'</a><br />';
2697 if($level) {
2698 return $link."\n";
2699 } else {
2700 return '<div class="tocline">'.$link."</div>\n";
2705 function tocTable($toc) {
2706 # note to CSS fanatics: putting this in a div does not work -- div won't auto-expand
2707 # try min-width & co when somebody gets a chance
2708 $hideline = ' <script type="text/javascript">showTocToggle("' . addslashes( wfMsg('showtoc') ) . '","' . addslashes( wfMsg('hidetoc') ) . '")</script>';
2709 return
2710 '<table border="0" id="toc"><tr id="toctitle"><td align="center">'."\n".
2711 '<b>'.wfMsg('toc').'</b>' .
2712 $hideline .
2713 '</td></tr><tr id="tocinside"><td>'."\n".
2714 $toc."</td></tr></table>\n";
2718 * These two do not check for permissions: check $wgTitle->userCanEdit
2719 * before calling them
2721 function editSectionScript( $section, $head ) {
2722 global $wgTitle, $wgRequest;
2723 if( $wgRequest->getInt( 'oldid' ) && ( $wgRequest->getVal( 'diff' ) != '0' ) ) {
2724 return $head;
2726 $url = $wgTitle->escapeLocalURL( 'action=edit&section='.$section );
2727 return '<span oncontextmenu=\'document.location="'.$url.'";return false;\'>'.$head.'</span>';
2730 function editSectionLink( $section ) {
2731 global $wgRequest;
2732 global $wgTitle, $wgUser, $wgLang;
2734 if( $wgRequest->getInt( 'oldid' ) && ( $wgRequest->getVal( 'diff' ) != '0' ) ) {
2735 # Section edit links would be out of sync on an old page.
2736 # But, if we're diffing to the current page, they'll be
2737 # correct.
2738 return '';
2741 $editurl = '&section='.$section;
2742 $url = $this->makeKnownLink($wgTitle->getPrefixedText(),wfMsg('editsection'),'action=edit'.$editurl);
2744 if( $wgLang->isRTL() ) {
2745 $farside = 'left';
2746 $nearside = 'right';
2747 } else {
2748 $farside = 'right';
2749 $nearside = 'left';
2751 return "<div class=\"editsection\" style=\"float:$farside;margin-$nearside:5px;\">[".$url."]</div>";
2756 * This function is called by EditPage.php and shows a bulletin board style
2757 * toolbar for common editing functions. It can be disabled in the user
2758 * preferences.
2759 * The necessary JavaScript code can be found in style/wikibits.js.
2761 function getEditToolbar() {
2762 global $wgStylePath, $wgLang, $wgMimeType;
2765 * toolarray an array of arrays which each include the filename of
2766 * the button image (without path), the opening tag, the closing tag,
2767 * and optionally a sample text that is inserted between the two when no
2768 * selection is highlighted.
2769 * The tip text is shown when the user moves the mouse over the button.
2771 * Already here are accesskeys (key), which are not used yet until someone
2772 * can figure out a way to make them work in IE. However, we should make
2773 * sure these keys are not defined on the edit page.
2775 $toolarray=array(
2776 array( 'image'=>'button_bold.png',
2777 'open' => "\'\'\'",
2778 'close' => "\'\'\'",
2779 'sample'=> wfMsg('bold_sample'),
2780 'tip' => wfMsg('bold_tip'),
2781 'key' => 'B'
2783 array( 'image'=>'button_italic.png',
2784 'open' => "\'\'",
2785 'close' => "\'\'",
2786 'sample'=> wfMsg('italic_sample'),
2787 'tip' => wfMsg('italic_tip'),
2788 'key' => 'I'
2790 array( 'image'=>'button_link.png',
2791 'open' => '[[',
2792 'close' => ']]',
2793 'sample'=> wfMsg('link_sample'),
2794 'tip' => wfMsg('link_tip'),
2795 'key' => 'L'
2797 array( 'image'=>'button_extlink.png',
2798 'open' => '[',
2799 'close' => ']',
2800 'sample'=> wfMsg('extlink_sample'),
2801 'tip' => wfMsg('extlink_tip'),
2802 'key' => 'X'
2804 array( 'image'=>'button_headline.png',
2805 'open' => "\\n== ",
2806 'close' => " ==\\n",
2807 'sample'=> wfMsg('headline_sample'),
2808 'tip' => wfMsg('headline_tip'),
2809 'key' => 'H'
2811 array( 'image'=>'button_image.png',
2812 'open' => '[['.$wgLang->getNsText(NS_IMAGE).":",
2813 'close' => ']]',
2814 'sample'=> wfMsg('image_sample'),
2815 'tip' => wfMsg('image_tip'),
2816 'key' => 'D'
2818 array( 'image' => 'button_media.png',
2819 'open' => '[['.$wgLang->getNsText(NS_MEDIA).':',
2820 'close' => ']]',
2821 'sample'=> wfMsg('media_sample'),
2822 'tip' => wfMsg('media_tip'),
2823 'key' => 'M'
2825 array( 'image' => 'button_math.png',
2826 'open' => "\\<math\\>",
2827 'close' => "\\</math\\>",
2828 'sample'=> wfMsg('math_sample'),
2829 'tip' => wfMsg('math_tip'),
2830 'key' => 'C'
2832 array( 'image' => 'button_nowiki.png',
2833 'open' => "\\<nowiki\\>",
2834 'close' => "\\</nowiki\\>",
2835 'sample'=> wfMsg('nowiki_sample'),
2836 'tip' => wfMsg('nowiki_tip'),
2837 'key' => 'N'
2839 array( 'image' => 'button_sig.png',
2840 'open' => '--~~~~',
2841 'close' => '',
2842 'sample'=> '',
2843 'tip' => wfMsg('sig_tip'),
2844 'key' => 'Y'
2846 array( 'image' => 'button_hr.png',
2847 'open' => "\\n----\\n",
2848 'close' => '',
2849 'sample'=> '',
2850 'tip' => wfMsg('hr_tip'),
2851 'key' => 'R'
2854 $toolbar ="<script type='text/javascript'>\n/*<![CDATA[*/\n";
2856 $toolbar.="document.writeln(\"<div id='toolbar'>\");\n";
2857 foreach($toolarray as $tool) {
2859 $image=$wgStylePath.'/common/images/'.$tool['image'];
2860 $open=$tool['open'];
2861 $close=$tool['close'];
2862 $sample = addslashes( $tool['sample'] );
2864 // Note that we use the tip both for the ALT tag and the TITLE tag of the image.
2865 // Older browsers show a "speedtip" type message only for ALT.
2866 // Ideally these should be different, realistically they
2867 // probably don't need to be.
2868 $tip = addslashes( $tool['tip'] );
2870 #$key = $tool["key"];
2872 $toolbar.="addButton('$image','$tip','$open','$close','$sample');\n";
2875 $toolbar.="addInfobox('" . addslashes( wfMsg( "infobox" ) ) . "','" . addslashes(wfMsg("infobox_alert")) . "');\n";
2876 $toolbar.="document.writeln(\"</div>\");\n";
2878 $toolbar.="/*]]>*/\n</script>";
2879 return $toolbar;
2883 * @access public
2885 function suppressUrlExpansion() {
2886 return false;