* Fix for XHTML valid output
[mediawiki.git] / includes / Skin.php
blob872238d423bb175d6461dfd1843f2c794b50a29b
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 global $wgUser, $wgOut, $wgContLang;
538 $fname = 'Skin::doAfterContent';
539 wfProfileIn( $fname );
540 wfProfileIn( $fname.'-1' );
542 $s = "\n</div><br style=\"clear:both\" />\n";
543 $s .= "\n<div id='footer'>";
544 $s .= '<table border="0" cellspacing="0"><tr>';
546 wfProfileOut( $fname.'-1' );
547 wfProfileIn( $fname.'-2' );
549 $qb = $this->qbSetting();
550 $shove = ($qb != 0);
551 $left = ($qb == 1 || $qb == 3);
552 if($wgContLang->isRTL()) $left = !$left;
554 if ( $shove && $left ) { # Left
555 $s .= $this->getQuickbarCompensator();
557 wfProfileOut( $fname.'-2' );
558 wfProfileIn( $fname.'-3' );
559 $l = $wgContLang->isRTL() ? 'right' : 'left';
560 $s .= "<td class='bottom' align='$l' valign='top'>";
562 $s .= $this->bottomLinks();
563 $s .= "\n<br />" . $this->mainPageLink()
564 . ' | ' . $this->aboutLink()
565 . ' | ' . $this->specialLink( 'recentchanges' )
566 . ' | ' . $this->searchForm()
567 . '<br /><span id="pagestats">' . $this->pageStats() . '</span>';
569 $s .= "</td>";
570 if ( $shove && !$left ) { # Right
571 $s .= $this->getQuickbarCompensator();
573 $s .= "</tr></table>\n</div>\n</div>\n";
575 wfProfileOut( $fname.'-3' );
576 wfProfileIn( $fname.'-4' );
577 if ( 0 != $qb ) { $s .= $this->quickBar(); }
578 wfProfileOut( $fname.'-4' );
579 wfProfileOut( $fname );
580 return $s;
583 function pageTitleLinks() {
584 global $wgOut, $wgTitle, $wgUser, $wgContLang, $wgUseApproval, $wgRequest;
586 extract( $wgRequest->getValues( 'oldid', 'diff' ) );
587 $action = $wgRequest->getText( 'action' );
589 $s = $this->printableLink();
590 if ( wfMsgForContent ( 'disclaimers' ) != '-' )
591 $s .= ' | ' . $this->makeKnownLink(
592 wfMsgForContent( 'disclaimerpage' ),
593 wfMsgForContent( 'disclaimers' ) ) ;
595 if ( $wgOut->isArticleRelated() ) {
596 if ( $wgTitle->getNamespace() == Namespace::getImage() ) {
597 $name = $wgTitle->getDBkey();
598 $link = htmlspecialchars( Image::wfImageUrl( $name ) );
599 $style = $this->getInternalLinkAttributes( $link, $name );
600 $s .= " | <a href=\"{$link}\"{$style}>{$name}</a>";
602 # This will show the "Approve" link if $wgUseApproval=true;
603 if ( isset ( $wgUseApproval ) && $wgUseApproval )
605 $t = $wgTitle->getDBkey();
606 $name = 'Approve this article' ;
607 $link = "http://test.wikipedia.org/w/magnus/wiki.phtml?title={$t}&action=submit&doit=1" ;
608 #htmlspecialchars( wfImageUrl( $name ) );
609 $style = $this->getExternalLinkAttributes( $link, $name );
610 $s .= " | <a href=\"{$link}\"{$style}>{$name}</a>" ;
613 if ( 'history' == $action || isset( $diff ) || isset( $oldid ) ) {
614 $s .= ' | ' . $this->makeKnownLink( $wgTitle->getPrefixedText(),
615 wfMsg( 'currentrev' ) );
618 if ( $wgUser->getNewtalk() ) {
619 # do not show "You have new messages" text when we are viewing our
620 # own talk page
622 if(!(strcmp($wgTitle->getText(),$wgUser->getName()) == 0 &&
623 $wgTitle->getNamespace()==Namespace::getTalk(Namespace::getUser()))) {
624 $n =$wgUser->getName();
625 $tl = $this->makeKnownLink( $wgContLang->getNsText(
626 Namespace::getTalk( Namespace::getUser() ) ) . ":{$n}",
627 wfMsg('newmessageslink') );
628 $s.= ' | <strong>'. wfMsg( 'newmessages', $tl ) . '</strong>';
629 # disable caching
630 $wgOut->setSquidMaxage(0);
634 $undelete = $this->getUndeleteLink();
635 if( !empty( $undelete ) ) {
636 $s .= ' | '.$undelete;
638 return $s;
641 function getUndeleteLink() {
642 global $wgUser, $wgTitle, $wgContLang, $action;
643 if( $wgUser->isSysop() &&
644 (($wgTitle->getArticleId() == 0) || ($action == "history")) &&
645 ($n = $wgTitle->isDeleted() ) ) {
646 return wfMsg( 'thisisdeleted',
647 $this->makeKnownLink(
648 $wgContLang->SpecialPage( 'Undelete/' . $wgTitle->getPrefixedDBkey() ),
649 wfMsg( 'restorelink', $n ) ) );
651 return '';
654 function printableLink() {
655 global $wgOut, $wgFeedClasses, $wgRequest;
657 $baseurl = $_SERVER['REQUEST_URI'];
658 if( strpos( '?', $baseurl ) == false ) {
659 $baseurl .= '?';
660 } else {
661 $baseurl .= '&';
663 $baseurl = htmlspecialchars( $baseurl );
664 $printurl = $wgRequest->escapeAppendQuery( 'printable=yes' );
666 $s = "<a href=\"$printurl\">" . wfMsg( 'printableversion' ) . '</a>';
667 if( $wgOut->isSyndicated() ) {
668 foreach( $wgFeedClasses as $format => $class ) {
669 $feedurl = $wgRequest->escapeAppendQuery( "feed=$format" );
670 $s .= " | <a href=\"$feedurl\">{$format}</a>";
673 return $s;
676 function pageTitle() {
677 global $wgOut, $wgTitle, $wgUser;
679 $s = '<h1 class="pagetitle">' . htmlspecialchars( $wgOut->getPageTitle() ) . '</h1>';
680 if($wgUser->getOption( 'editsectiononrightclick' ) && $wgTitle->userCanEdit()) { $s=$this->editSectionScript(0,$s);}
681 return $s;
684 function pageSubtitle() {
685 global $wgOut;
687 $sub = $wgOut->getSubtitle();
688 if ( '' == $sub ) {
689 global $wgExtraSubtitle;
690 $sub = wfMsg( 'tagline' ) . $wgExtraSubtitle;
692 $subpages = $this->subPageSubtitle();
693 $sub .= !empty($subpages)?"</p><p class='subpages'>$subpages":'';
694 $s = "<p class='subtitle'>{$sub}</p>\n";
695 return $s;
698 function subPageSubtitle() {
699 global $wgOut,$wgTitle,$wgNamespacesWithSubpages;
700 $subpages = '';
701 if($wgOut->isArticle() && !empty($wgNamespacesWithSubpages[$wgTitle->getNamespace()])) {
702 $ptext=$wgTitle->getPrefixedText();
703 if(preg_match('/\//',$ptext)) {
704 $links = explode('/',$ptext);
705 $c = 0;
706 $growinglink = '';
707 foreach($links as $link) {
708 $c++;
709 if ($c<count($links)) {
710 $growinglink .= $link;
711 $getlink = $this->makeLink( $growinglink, $link );
712 if(preg_match('/class="new"/i',$getlink)) { break; } # this is a hack, but it saves time
713 if ($c>1) {
714 $subpages .= ' | ';
715 } else {
716 $subpages .= '&lt; ';
718 $subpages .= $getlink;
719 $growinglink .= '/';
724 return $subpages;
727 function nameAndLogin() {
728 global $wgUser, $wgTitle, $wgLang, $wgContLang, $wgShowIPinHeader, $wgIP;
730 $li = $wgContLang->specialPage( 'Userlogin' );
731 $lo = $wgContLang->specialPage( 'Userlogout' );
733 $s = '';
734 if ( 0 == $wgUser->getID() ) {
735 if( $wgShowIPinHeader && isset( $_COOKIE[ini_get('session.name')] ) ) {
736 $n = $wgIP;
738 $tl = $this->makeKnownLink( $wgContLang->getNsText(
739 Namespace::getTalk( Namespace::getUser() ) ) . ":{$n}",
740 $wgContLang->getNsText( Namespace::getTalk( 0 ) ) );
742 $s .= $n . ' ('.$tl.')';
743 } else {
744 $s .= wfMsg('notloggedin');
747 $rt = $wgTitle->getPrefixedURL();
748 if ( 0 == strcasecmp( urlencode( $lo ), $rt ) ) {
749 $q = '';
750 } else { $q = "returnto={$rt}"; }
752 $s .= "\n<br />" . $this->makeKnownLink( $li,
753 wfMsg( 'login' ), $q );
754 } else {
755 $n = $wgUser->getName();
756 $rt = $wgTitle->getPrefixedURL();
757 $tl = $this->makeKnownLink( $wgContLang->getNsText(
758 Namespace::getTalk( Namespace::getUser() ) ) . ":{$n}",
759 $wgContLang->getNsText( Namespace::getTalk( 0 ) ) );
761 $tl = " ({$tl})";
763 $s .= $this->makeKnownLink( $wgContLang->getNsText(
764 Namespace::getUser() ) . ":{$n}", $n ) . "{$tl}<br />" .
765 $this->makeKnownLink( $lo, wfMsg( 'logout' ),
766 "returnto={$rt}" ) . ' | ' .
767 $this->specialLink( 'preferences' );
769 $s .= ' | ' . $this->makeKnownLink( wfMsgForContent( 'helppage' ),
770 wfMsg( 'help' ) );
772 return $s;
775 function getSearchLink() {
776 $searchPage =& Title::makeTitle( NS_SPECIAL, 'Search' );
777 return $searchPage->getLocalURL();
780 function escapeSearchLink() {
781 return htmlspecialchars( $this->getSearchLink() );
784 function searchForm() {
785 global $wgRequest;
786 $search = $wgRequest->getText( 'search' );
788 $s = '<form name="search" class="inline" method="post" action="'
789 . $this->escapeSearchLink() . "\">\n"
790 . '<input type="text" name="search" size="19" value="'
791 . htmlspecialchars(substr($search,0,256)) . "\" />\n"
792 . '<input type="submit" name="go" value="' . wfMsg ('go') . '" />&nbsp;'
793 . '<input type="submit" name="fulltext" value="' . wfMsg ('search') . "\" />\n</form>";
795 return $s;
798 function topLinks() {
799 global $wgOut;
800 $sep = " |\n";
802 $s = $this->mainPageLink() . $sep
803 . $this->specialLink( 'recentchanges' );
805 if ( $wgOut->isArticleRelated() ) {
806 $s .= $sep . $this->editThisPage()
807 . $sep . $this->historyLink();
809 # Many people don't like this dropdown box
810 #$s .= $sep . $this->specialPagesList();
812 return $s;
815 function bottomLinks() {
816 global $wgOut, $wgUser, $wgTitle;
817 $sep = " |\n";
819 $s = '';
820 if ( $wgOut->isArticleRelated() ) {
821 $s .= '<strong>' . $this->editThisPage() . '</strong>';
822 if ( 0 != $wgUser->getID() ) {
823 $s .= $sep . $this->watchThisPage();
825 $s .= $sep . $this->talkLink()
826 . $sep . $this->historyLink()
827 . $sep . $this->whatLinksHere()
828 . $sep . $this->watchPageLinksLink();
830 if ( $wgTitle->getNamespace() == Namespace::getUser()
831 || $wgTitle->getNamespace() == Namespace::getTalk(Namespace::getUser()) )
834 $id=User::idFromName($wgTitle->getText());
835 $ip=User::isIP($wgTitle->getText());
837 if($id || $ip) { # both anons and non-anons have contri list
838 $s .= $sep . $this->userContribsLink();
840 if ( 0 != $wgUser->getID() ) { # show only to signed in users
841 if($id) { # can only email non-anons
842 $s .= $sep . $this->emailUserLink();
846 if ( $wgUser->isSysop() && $wgTitle->getArticleId() ) {
847 $s .= "\n<br />" . $this->deleteThisPage() .
848 $sep . $this->protectThisPage() .
849 $sep . $this->moveThisPage();
851 $s .= "<br />\n" . $this->otherLanguages();
853 return $s;
856 function pageStats() {
857 global $wgOut, $wgLang, $wgArticle, $wgRequest;
858 global $wgDisableCounters, $wgMaxCredits, $wgShowCreditsIfMax;
860 extract( $wgRequest->getValues( 'oldid', 'diff' ) );
861 if ( ! $wgOut->isArticle() ) { return ''; }
862 if ( isset( $oldid ) || isset( $diff ) ) { return ''; }
863 if ( 0 == $wgArticle->getID() ) { return ''; }
865 $s = '';
866 if ( !$wgDisableCounters ) {
867 $count = $wgLang->formatNum( $wgArticle->getCount() );
868 if ( $count ) {
869 $s = wfMsg( 'viewcount', $count );
873 if (isset($wgMaxCredits) && $wgMaxCredits != 0) {
874 require_once("Credits.php");
875 $s .= ' ' . getCredits($wgArticle, $wgMaxCredits, $wgShowCreditsIfMax);
876 } else {
877 $s .= $this->lastModified();
880 return $s . ' ' . $this->getCopyright();
883 function getCopyright() {
884 global $wgRightsPage, $wgRightsUrl, $wgRightsText, $wgRequest;
887 $oldid = $wgRequest->getVal( 'oldid' );
888 $diff = $wgRequest->getVal( 'diff' );
890 if ( !is_null( $oldid ) && is_null( $diff ) && wfMsgForContent( 'history_copyright' ) !== '-' ) {
891 $msg = 'history_copyright';
892 } else {
893 $msg = 'copyright';
896 $out = '';
897 if( $wgRightsPage ) {
898 $link = $this->makeKnownLink( $wgRightsPage, $wgRightsText );
899 } elseif( $wgRightsUrl ) {
900 $link = $this->makeExternalLink( $wgRightsUrl, $wgRightsText );
901 } else {
902 # Give up now
903 return $out;
905 $out .= wfMsgForContent( $msg, $link );
906 return $out;
909 function getCopyrightIcon() {
910 global $wgRightsPage, $wgRightsUrl, $wgRightsText, $wgRightsIcon;
911 $out = '';
912 if( $wgRightsIcon ) {
913 $icon = htmlspecialchars( $wgRightsIcon );
914 if( $wgRightsUrl ) {
915 $url = htmlspecialchars( $wgRightsUrl );
916 $out .= '<a href="'.$url.'">';
918 $text = htmlspecialchars( $wgRightsText );
919 $out .= "<img src=\"$icon\" alt='$text' />";
920 if( $wgRightsUrl ) {
921 $out .= '</a>';
924 return $out;
927 function getPoweredBy() {
928 global $wgStylePath;
929 $url = htmlspecialchars( "$wgStylePath/common/images/poweredby_mediawiki_88x31.png" );
930 $img = '<a href="http://www.mediawiki.org/"><img src="'.$url.'" alt="MediaWiki" /></a>';
931 return $img;
934 function lastModified() {
935 global $wgLang, $wgArticle;
937 $timestamp = $wgArticle->getTimestamp();
938 if ( $timestamp ) {
939 $d = $wgLang->timeanddate( $wgArticle->getTimestamp(), true );
940 $s = ' ' . wfMsg( 'lastmodified', $d );
941 } else {
942 $s = '';
944 return $s;
947 function logoText( $align = '' ) {
948 if ( '' != $align ) { $a = " align='{$align}'"; }
949 else { $a = ''; }
951 $mp = wfMsg( 'mainpage' );
952 $titleObj = Title::newFromText( $mp );
953 if ( is_object( $titleObj ) ) {
954 $url = $titleObj->escapeLocalURL();
955 } else {
956 $url = '';
959 $logourl = $this->getLogo();
960 $s = "<a href='{$url}'><img{$a} src='{$logourl}' alt='[{$mp}]' /></a>";
961 return $s;
964 function quickBar() {
965 global $wgOut, $wgTitle, $wgUser, $wgRequest, $wgContLang;
966 global $wgDisableUploads, $wgRemoteUploads;
968 $fname = 'Skin::quickBar';
969 wfProfileIn( $fname );
971 $action = $wgRequest->getText( 'action' );
972 $wpPreview = $wgRequest->getBool( 'wpPreview' );
973 $tns=$wgTitle->getNamespace();
975 $s = "\n<div id='quickbar'>";
976 $s .= "\n" . $this->logoText() . "\n<hr class='sep' />";
978 $sep = "\n<br />";
979 $s .= $this->mainPageLink()
980 . $sep . $this->specialLink( 'recentchanges' )
981 . $sep . $this->specialLink( 'randompage' );
982 if ($wgUser->getID()) {
983 $s.= $sep . $this->specialLink( 'watchlist' ) ;
984 $s .= $sep .$this->makeKnownLink( $wgContLang->specialPage( 'Contributions' ),
985 wfMsg( 'mycontris' ), 'target=' . wfUrlencode($wgUser->getName() ) );
988 // only show watchlist link if logged in
989 if ( wfMsgForContent ( 'currentevents' ) != '-' )
990 $s .= $sep . $this->makeKnownLink( wfMsgForContent( 'currentevents' ), '' ) ;
991 $s .= "\n<br /><hr class='sep' />";
992 $articleExists = $wgTitle->getArticleId();
993 if ( $wgOut->isArticle() || $action =='edit' || $action =='history' || $wpPreview) {
994 if($wgOut->isArticle()) {
995 $s .= '<strong>' . $this->editThisPage() . '</strong>';
996 } else { # backlink to the article in edit or history mode
997 if($articleExists){ # no backlink if no article
998 switch($tns) {
999 case 0:
1000 $text = wfMsg('articlepage');
1001 break;
1002 case 1:
1003 $text = wfMsg('viewtalkpage');
1004 break;
1005 case 2:
1006 $text = wfMsg('userpage');
1007 break;
1008 case 3:
1009 $text = wfMsg('viewtalkpage');
1010 break;
1011 case 4:
1012 $text = wfMsg('wikipediapage');
1013 break;
1014 case 5:
1015 $text = wfMsg('viewtalkpage');
1016 break;
1017 case 6:
1018 $text = wfMsg('imagepage');
1019 break;
1020 case 7:
1021 $text = wfMsg('viewtalkpage');
1022 break;
1023 default:
1024 $text= wfMsg('articlepage');
1027 $link = $wgTitle->getText();
1028 if ($nstext = $wgContLang->getNsText($tns) ) { # add namespace if necessary
1029 $link = $nstext . ':' . $link ;
1032 $s .= $this->makeLink( $link, $text );
1033 } elseif( $wgTitle->getNamespace() != Namespace::getSpecial() ) {
1034 # we just throw in a "New page" text to tell the user that he's in edit mode,
1035 # and to avoid messing with the separator that is prepended to the next item
1036 $s .= '<strong>' . wfMsg('newpage') . '</strong>';
1042 if( $tns%2 && $action!='edit' && !$wpPreview) {
1043 $s.= '<br />'.$this->makeKnownLink($wgTitle->getPrefixedText(),wfMsg('postcomment'),'action=edit&section=new');
1047 watching could cause problems in edit mode:
1048 if user edits article, then loads "watch this article" in background and then saves
1049 article with "Watch this article" checkbox disabled, the article is transparently
1050 unwatched. Therefore we do not show the "Watch this page" link in edit mode
1052 if ( 0 != $wgUser->getID() && $articleExists) {
1053 if($action!='edit' && $action != 'submit' )
1055 $s .= $sep . $this->watchThisPage();
1057 if ( $wgTitle->userCanEdit() )
1058 $s .= $sep . $this->moveThisPage();
1060 if ( $wgUser->isSysop() and $articleExists ) {
1061 $s .= $sep . $this->deleteThisPage() .
1062 $sep . $this->protectThisPage();
1064 $s .= $sep . $this->talkLink();
1065 if ($articleExists && $action !='history') {
1066 $s .= $sep . $this->historyLink();
1068 $s.=$sep . $this->whatLinksHere();
1070 if($wgOut->isArticleRelated()) {
1071 $s .= $sep . $this->watchPageLinksLink();
1074 if ( Namespace::getUser() == $wgTitle->getNamespace()
1075 || $wgTitle->getNamespace() == Namespace::getTalk(Namespace::getUser())
1078 $id=User::idFromName($wgTitle->getText());
1079 $ip=User::isIP($wgTitle->getText());
1081 if($id||$ip) {
1082 $s .= $sep . $this->userContribsLink();
1084 if ( 0 != $wgUser->getID() ) {
1085 if($id) { # can only email real users
1086 $s .= $sep . $this->emailUserLink();
1090 $s .= "\n<br /><hr class='sep' />";
1093 if ( 0 != $wgUser->getID() && ( !$wgDisableUploads || $wgRemoteUploads ) ) {
1094 $s .= $this->specialLink( 'upload' ) . $sep;
1096 $s .= $this->specialLink( 'specialpages' )
1097 . $sep . $this->bugReportsLink();
1099 global $wgSiteSupportPage;
1100 if( $wgSiteSupportPage ) {
1101 $s .= "\n<br /><a href=\"" . htmlspecialchars( $wgSiteSupportPage ) .
1102 '" class="internal">' . wfMsg( 'sitesupport' ) . '</a>';
1105 $s .= "\n<br /></div>\n";
1106 wfProfileOut( $fname );
1107 return $s;
1110 function specialPagesList() {
1111 global $wgUser, $wgOut, $wgContLang, $wgServer, $wgRedirectScript;
1112 require_once('SpecialPage.php');
1113 $a = array();
1114 $pages = SpecialPage::getPages();
1116 foreach ( $pages[''] as $name => $page ) {
1117 $a[$name] = $page->getDescription();
1119 if ( $wgUser->isSysop() )
1121 foreach ( $pages['sysop'] as $name => $page ) {
1122 $a[$name] = $page->getDescription();
1125 if ( $wgUser->isDeveloper() )
1127 foreach ( $pages['developer'] as $name => $page ) {
1128 $a[$name] = $page->getDescription() ;
1131 $go = wfMsg( 'go' );
1132 $sp = wfMsg( 'specialpages' );
1133 $spp = $wgContLang->specialPage( 'Specialpages' );
1135 $s = '<form id="specialpages" method="get" class="inline" ' .
1136 'action="' . htmlspecialchars( "{$wgServer}{$wgRedirectScript}" ) . "\">\n";
1137 $s .= "<select name=\"wpDropdown\">\n";
1138 $s .= "<option value=\"{$spp}\">{$sp}</option>\n";
1140 foreach ( $a as $name => $desc ) {
1141 $p = $wgContLang->specialPage( $name );
1142 $s .= "<option value=\"{$p}\">{$desc}</option>\n";
1144 $s .= "</select>\n";
1145 $s .= "<input type='submit' value=\"{$go}\" name='redirect' />\n";
1146 $s .= "</form>\n";
1147 return $s;
1150 function mainPageLink() {
1151 $mp = wfMsgForContent( 'mainpage' );
1152 $mptxt = wfMsg( 'mainpage');
1153 $s = $this->makeKnownLink( $mp, $mptxt );
1154 return $s;
1157 function copyrightLink() {
1158 $s = $this->makeKnownLink( wfMsgForContent( 'copyrightpage' ),
1159 wfMsg( 'copyrightpagename' ) );
1160 return $s;
1163 function aboutLink() {
1164 $s = $this->makeKnownLink( wfMsgForContent( 'aboutpage' ),
1165 wfMsg( 'aboutsite' ) );
1166 return $s;
1170 function disclaimerLink() {
1171 $s = $this->makeKnownLink( wfMsgForContent( 'disclaimerpage' ),
1172 wfMsg( 'disclaimers' ) );
1173 return $s;
1176 function editThisPage() {
1177 global $wgOut, $wgTitle, $wgRequest;
1179 $oldid = $wgRequest->getVal( 'oldid' );
1180 $diff = $wgRequest->getVal( 'diff' );
1181 $redirect = $wgRequest->getVal( 'redirect' );
1183 if ( ! $wgOut->isArticleRelated() ) {
1184 $s = wfMsg( 'protectedpage' );
1185 } else {
1186 $n = $wgTitle->getPrefixedText();
1187 if ( $wgTitle->userCanEdit() ) {
1188 $t = wfMsg( 'editthispage' );
1189 } else {
1190 #$t = wfMsg( "protectedpage" );
1191 $t = wfMsg( 'viewsource' );
1193 $oid = $red = '';
1195 if ( !is_null( $redirect ) ) { $red = "&redirect={$redirect}"; }
1196 if ( $oldid && ! isset( $diff ) ) {
1197 $oid = '&oldid='.$oldid;
1199 $s = $this->makeKnownLink( $n, $t, "action=edit{$oid}{$red}" );
1201 return $s;
1204 function deleteThisPage() {
1205 global $wgUser, $wgOut, $wgTitle, $wgRequest;
1207 $diff = $wgRequest->getVal( 'diff' );
1208 if ( $wgTitle->getArticleId() && ( ! $diff ) && $wgUser->isSysop() ) {
1209 $n = $wgTitle->getPrefixedText();
1210 $t = wfMsg( 'deletethispage' );
1212 $s = $this->makeKnownLink( $n, $t, 'action=delete' );
1213 } else {
1214 $s = '';
1216 return $s;
1219 function protectThisPage() {
1220 global $wgUser, $wgOut, $wgTitle, $wgRequest;
1222 $diff = $wgRequest->getVal( 'diff' );
1223 if ( $wgTitle->getArticleId() && ( ! $diff ) && $wgUser->isSysop() ) {
1224 $n = $wgTitle->getPrefixedText();
1226 if ( $wgTitle->isProtected() ) {
1227 $t = wfMsg( 'unprotectthispage' );
1228 $q = 'action=unprotect';
1229 } else {
1230 $t = wfMsg( 'protectthispage' );
1231 $q = 'action=protect';
1233 $s = $this->makeKnownLink( $n, $t, $q );
1234 } else {
1235 $s = '';
1237 return $s;
1240 function watchThisPage() {
1241 global $wgUser, $wgOut, $wgTitle;
1243 if ( $wgOut->isArticleRelated() ) {
1244 $n = $wgTitle->getPrefixedText();
1246 if ( $wgTitle->userIsWatching() ) {
1247 $t = wfMsg( 'unwatchthispage' );
1248 $q = 'action=unwatch';
1249 } else {
1250 $t = wfMsg( 'watchthispage' );
1251 $q = 'action=watch';
1253 $s = $this->makeKnownLink( $n, $t, $q );
1254 } else {
1255 $s = wfMsg( 'notanarticle' );
1257 return $s;
1260 function moveThisPage() {
1261 global $wgTitle, $wgContLang;
1263 if ( $wgTitle->userCanEdit() ) {
1264 $s = $this->makeKnownLink( $wgContLang->specialPage( 'Movepage' ),
1265 wfMsg( 'movethispage' ), 'target=' . $wgTitle->getPrefixedURL() );
1266 } // no message if page is protected - would be redundant
1267 return $s;
1270 function historyLink() {
1271 global $wgTitle;
1273 $s = $this->makeKnownLink( $wgTitle->getPrefixedText(),
1274 wfMsg( 'history' ), 'action=history' );
1275 return $s;
1278 function whatLinksHere() {
1279 global $wgTitle, $wgContLang;
1281 $s = $this->makeKnownLink( $wgContLang->specialPage( 'Whatlinkshere' ),
1282 wfMsg( 'whatlinkshere' ), 'target=' . $wgTitle->getPrefixedURL() );
1283 return $s;
1286 function userContribsLink() {
1287 global $wgTitle, $wgContLang;
1289 $s = $this->makeKnownLink( $wgContLang->specialPage( 'Contributions' ),
1290 wfMsg( 'contributions' ), 'target=' . $wgTitle->getPartialURL() );
1291 return $s;
1294 function emailUserLink() {
1295 global $wgTitle, $wgContLang;
1297 $s = $this->makeKnownLink( $wgContLang->specialPage( 'Emailuser' ),
1298 wfMsg( 'emailuser' ), 'target=' . $wgTitle->getPartialURL() );
1299 return $s;
1302 function watchPageLinksLink() {
1303 global $wgOut, $wgTitle, $wgContLang;
1305 if ( ! $wgOut->isArticleRelated() ) {
1306 $s = '(' . wfMsg( 'notanarticle' ) . ')';
1307 } else {
1308 $s = $this->makeKnownLink( $wgContLang->specialPage(
1309 'Recentchangeslinked' ), wfMsg( 'recentchangeslinked' ),
1310 'target=' . $wgTitle->getPrefixedURL() );
1312 return $s;
1315 function otherLanguages() {
1316 global $wgOut, $wgContLang, $wgTitle, $wgUseNewInterlanguage;
1318 $a = $wgOut->getLanguageLinks();
1319 if ( 0 == count( $a ) ) {
1320 if ( !$wgUseNewInterlanguage ) return '';
1321 $ns = $wgContLang->getNsIndex ( $wgTitle->getNamespace () ) ;
1322 if ( $ns != 0 AND $ns != 1 ) return '' ;
1323 $pn = 'Intl' ;
1324 $x = 'mode=addlink&xt='.$wgTitle->getDBkey() ;
1325 return $this->makeKnownLink( $wgContLang->specialPage( $pn ),
1326 wfMsg( 'intl' ) , $x );
1329 if ( !$wgUseNewInterlanguage ) {
1330 $s = wfMsg( 'otherlanguages' ) . ': ';
1331 } else {
1332 global $wgContLanguageCode ;
1333 $x = 'mode=zoom&xt='.$wgTitle->getDBkey() ;
1334 $x .= '&xl='.$wgContLanguageCode ;
1335 $s = $this->makeKnownLink( $wgContLang->specialPage( 'Intl' ),
1336 wfMsg( 'otherlanguages' ) , $x ) . ': ' ;
1339 $s = wfMsg( 'otherlanguages' ) . ': ';
1340 $first = true;
1341 if($wgContLang->isRTL()) $s .= '<span dir="LTR">';
1342 foreach( $a as $l ) {
1343 if ( ! $first ) { $s .= ' | '; }
1344 $first = false;
1346 $nt = Title::newFromText( $l );
1347 $url = $nt->getFullURL();
1348 $text = $wgContLang->getLanguageName( $nt->getInterwiki() );
1350 if ( '' == $text ) { $text = $l; }
1351 $style = $this->getExternalLinkAttributes( $l, $text );
1352 $s .= "<a href=\"{$url}\"{$style}>{$text}</a>";
1354 if($wgContLang->isRTL()) $s .= '</span>';
1355 return $s;
1358 function bugReportsLink() {
1359 $s = $this->makeKnownLink( wfMsgForContent( 'bugreportspage' ),
1360 wfMsg( 'bugreports' ) );
1361 return $s;
1364 function dateLink() {
1365 global $wgLinkCache;
1366 $t1 = Title::newFromText( gmdate( 'F j' ) );
1367 $t2 = Title::newFromText( gmdate( 'Y' ) );
1369 $wgLinkCache->suspend();
1370 $id = $t1->getArticleID();
1371 $wgLinkCache->resume();
1373 if ( 0 == $id ) {
1374 $s = $this->makeBrokenLink( $t1->getText() );
1375 } else {
1376 $s = $this->makeKnownLink( $t1->getText() );
1378 $s .= ', ';
1380 $wgLinkCache->suspend();
1381 $id = $t2->getArticleID();
1382 $wgLinkCache->resume();
1384 if ( 0 == $id ) {
1385 $s .= $this->makeBrokenLink( $t2->getText() );
1386 } else {
1387 $s .= $this->makeKnownLink( $t2->getText() );
1389 return $s;
1392 function talkLink() {
1393 global $wgContLang, $wgTitle, $wgLinkCache;
1395 $tns = $wgTitle->getNamespace();
1396 if ( -1 == $tns ) { return ''; }
1398 $pn = $wgTitle->getText();
1399 $tp = wfMsg( 'talkpage' );
1400 if ( Namespace::isTalk( $tns ) ) {
1401 $lns = Namespace::getSubject( $tns );
1402 switch($tns) {
1403 case 1:
1404 $text = wfMsg('articlepage');
1405 break;
1406 case 3:
1407 $text = wfMsg('userpage');
1408 break;
1409 case 5:
1410 $text = wfMsg('wikipediapage');
1411 break;
1412 case 7:
1413 $text = wfMsg('imagepage');
1414 break;
1415 default:
1416 $text= wfMsg('articlepage');
1418 } else {
1420 $lns = Namespace::getTalk( $tns );
1421 $text=$tp;
1423 $n = $wgContLang->getNsText( $lns );
1424 if ( '' == $n ) { $link = $pn; }
1425 else { $link = $n.':'.$pn; }
1427 $wgLinkCache->suspend();
1428 $s = $this->makeLink( $link, $text );
1429 $wgLinkCache->resume();
1431 return $s;
1434 function commentLink() {
1435 global $wgContLang, $wgTitle, $wgLinkCache;
1437 $tns = $wgTitle->getNamespace();
1438 if ( -1 == $tns ) { return ''; }
1440 $lns = ( Namespace::isTalk( $tns ) ) ? $tns : Namespace::getTalk( $tns );
1442 # assert Namespace::isTalk( $lns )
1444 $n = $wgContLang->getNsText( $lns );
1445 $pn = $wgTitle->getText();
1447 $link = $n.':'.$pn;
1449 $wgLinkCache->suspend();
1450 $s = $this->makeKnownLink($link, wfMsg('postcomment'), 'action=edit&section=new');
1451 $wgLinkCache->resume();
1453 return $s;
1457 * After all the page content is transformed into HTML, it makes
1458 * a final pass through here for things like table backgrounds.
1459 * @todo probably deprecated [AV]
1461 function transformContent( $text ) {
1462 return $text;
1466 * Note: This function MUST call getArticleID() on the link,
1467 * otherwise the cache won't get updated properly. See LINKCACHE.DOC.
1469 function makeLink( $title, $text = '', $query = '', $trail = '' ) {
1470 wfProfileIn( 'Skin::makeLink' );
1471 $nt = Title::newFromText( $title );
1472 if ($nt) {
1473 $result = $this->makeLinkObj( Title::newFromText( $title ), $text, $query, $trail );
1474 } else {
1475 wfDebug( 'Invalid title passed to Skin::makeLink(): "'.$title."\"\n" );
1476 $result = $text == "" ? $title : $text;
1479 wfProfileOut( 'Skin::makeLink' );
1480 return $result;
1483 function makeKnownLink( $title, $text = '', $query = '', $trail = '', $prefix = '',$aprops = '') {
1484 $nt = Title::newFromText( $title );
1485 if ($nt) {
1486 return $this->makeKnownLinkObj( Title::newFromText( $title ), $text, $query, $trail, $prefix , $aprops );
1487 } else {
1488 wfDebug( 'Invalid title passed to Skin::makeKnownLink(): "'.$title."\"\n" );
1489 return $text == '' ? $title : $text;
1493 function makeBrokenLink( $title, $text = '', $query = '', $trail = '' ) {
1494 $nt = Title::newFromText( $title );
1495 if ($nt) {
1496 return $this->makeBrokenLinkObj( Title::newFromText( $title ), $text, $query, $trail );
1497 } else {
1498 wfDebug( 'Invalid title passed to Skin::makeBrokenLink(): "'.$title."\"\n" );
1499 return $text == '' ? $title : $text;
1503 function makeStubLink( $title, $text = '', $query = '', $trail = '' ) {
1504 $nt = Title::newFromText( $title );
1505 if ($nt) {
1506 return $this->makeStubLinkObj( Title::newFromText( $title ), $text, $query, $trail );
1507 } else {
1508 wfDebug( 'Invalid title passed to Skin::makeStubLink(): "'.$title."\"\n" );
1509 return $text == '' ? $title : $text;
1514 * Pass a title object, not a title string
1516 function makeLinkObj( &$nt, $text= '', $query = '', $trail = '', $prefix = '' ) {
1517 global $wgOut, $wgUser, $wgLinkHolders;
1518 $fname = 'Skin::makeLinkObj';
1520 # Fail gracefully
1521 if ( ! isset($nt) ) {
1522 # wfDebugDieBacktrace();
1523 return "<!-- ERROR -->{$prefix}{$text}{$trail}";
1526 if ( $nt->isExternal() ) {
1527 $u = $nt->getFullURL();
1528 $link = $nt->getPrefixedURL();
1529 if ( '' == $text ) { $text = $nt->getPrefixedText(); }
1530 $style = $this->getExternalLinkAttributes( $link, $text, 'extiw' );
1532 $inside = '';
1533 if ( '' != $trail ) {
1534 if ( preg_match( '/^([a-z]+)(.*)$$/sD', $trail, $m ) ) {
1535 $inside = $m[1];
1536 $trail = $m[2];
1539 # Assume $this->postParseLinkColour(). This prevents
1540 # interwiki links from being parsed as external links.
1541 global $wgInterwikiLinkHolders;
1542 $t = "<a href=\"{$u}\"{$style}>{$text}{$inside}</a>";
1543 $nr = array_push($wgInterwikiLinkHolders, $t);
1544 $retVal = '<!--IWLINK '. ($nr-1) ."-->{$trail}";
1545 } elseif ( 0 == $nt->getNamespace() && "" == $nt->getText() ) {
1546 $retVal = $this->makeKnownLinkObj( $nt, $text, $query, $trail, $prefix );
1547 } elseif ( ( -1 == $nt->getNamespace() ) ||
1548 ( Namespace::getImage() == $nt->getNamespace() ) ) {
1549 $retVal = $this->makeKnownLinkObj( $nt, $text, $query, $trail, $prefix );
1550 } else {
1551 if ( $this->postParseLinkColour() ) {
1552 $inside = '';
1553 if ( '' != $trail ) {
1554 if ( preg_match( $this->linktrail, $trail, $m ) ) {
1555 $inside = $m[1];
1556 $trail = $m[2];
1560 # Allows wiki to bypass using linkcache, see OutputPage::parseLinkHolders()
1561 $nr = array_push( $wgLinkHolders['namespaces'], $nt->getNamespace() );
1562 $wgLinkHolders['dbkeys'][] = $nt->getDBkey();
1563 $wgLinkHolders['queries'][] = $query;
1564 $wgLinkHolders['texts'][] = $prefix.$text.$inside;
1565 $wgLinkHolders['titles'][] = $nt;
1567 $retVal = '<!--LINK '. ($nr-1) ."-->{$trail}";
1568 } else {
1569 # Work out link colour immediately
1570 $aid = $nt->getArticleID() ;
1571 if ( 0 == $aid ) {
1572 $retVal = $this->makeBrokenLinkObj( $nt, $text, $query, $trail, $prefix );
1573 } else {
1574 $threshold = $wgUser->getOption('stubthreshold') ;
1575 if ( $threshold > 0 ) {
1576 $dbr =& wfGetDB( DB_SLAVE );
1577 $s = $dbr->selectRow( 'cur', array( 'LENGTH(cur_text) AS x', 'cur_namespace',
1578 'cur_is_redirect' ), array( 'cur_id' => $aid ), $fname ) ;
1579 if ( $s !== false ) {
1580 $size = $s->x;
1581 if ( $s->cur_is_redirect OR $s->cur_namespace != 0 ) {
1582 $size = $threshold*2 ; # Really big
1584 $dbr->freeResult( $res );
1585 } else {
1586 $size = $threshold*2 ; # Really big
1588 } else {
1589 $size = 1 ;
1591 if ( $size < $threshold ) {
1592 $retVal = $this->makeStubLinkObj( $nt, $text, $query, $trail, $prefix );
1593 } else {
1594 $retVal = $this->makeKnownLinkObj( $nt, $text, $query, $trail, $prefix );
1599 return $retVal;
1603 * Pass a title object, not a title string
1605 function makeKnownLinkObj( &$nt, $text = '', $query = '', $trail = '', $prefix = '' , $aprops = '' ) {
1606 global $wgOut, $wgTitle, $wgInputEncoding;
1608 $fname = 'Skin::makeKnownLinkObj';
1609 wfProfileIn( $fname );
1611 if ( !is_object( $nt ) ) {
1612 return $text;
1614 $link = $nt->getPrefixedURL();
1615 # if ( '' != $section && substr($section,0,1) != "#" ) {
1616 # $section = ''
1618 if ( '' == $link ) {
1619 $u = '';
1620 if ( '' == $text ) {
1621 $text = htmlspecialchars( $nt->getFragment() );
1623 } else {
1624 $u = $nt->escapeLocalURL( $query );
1626 if ( '' != $nt->getFragment() ) {
1627 $anchor = urlencode( do_html_entity_decode( str_replace(' ', '_', $nt->getFragment()), ENT_COMPAT, $wgInputEncoding ) );
1628 $replacearray = array(
1629 '%3A' => ':',
1630 '%' => '.'
1632 $u .= '#' . str_replace(array_keys($replacearray),array_values($replacearray),$anchor);
1634 if ( '' == $text ) {
1635 $text = htmlspecialchars( $nt->getPrefixedText() );
1637 $style = $this->getInternalLinkAttributesObj( $nt, $text );
1639 $inside = '';
1640 if ( '' != $trail ) {
1641 if ( preg_match( $this->linktrail, $trail, $m ) ) {
1642 $inside = $m[1];
1643 $trail = $m[2];
1646 $r = "<a href=\"{$u}\"{$style}{$aprops}>{$prefix}{$text}{$inside}</a>{$trail}";
1647 wfProfileOut( $fname );
1648 return $r;
1652 * Pass a title object, not a title string
1654 function makeBrokenLinkObj( &$nt, $text = '', $query = '', $trail = '', $prefix = '' ) {
1655 global $wgOut, $wgUser;
1657 # Fail gracefully
1658 if ( ! isset($nt) ) {
1659 # wfDebugDieBacktrace();
1660 return "<!-- ERROR -->{$prefix}{$text}{$trail}";
1663 $fname = 'Skin::makeBrokenLinkObj';
1664 wfProfileIn( $fname );
1666 if ( '' == $query ) {
1667 $q = 'action=edit';
1668 } else {
1669 $q = 'action=edit&'.$query;
1671 $u = $nt->escapeLocalURL( $q );
1673 if ( '' == $text ) {
1674 $text = htmlspecialchars( $nt->getPrefixedText() );
1676 $style = $this->getInternalLinkAttributesObj( $nt, $text, "yes" );
1678 $inside = '';
1679 if ( '' != $trail ) {
1680 if ( preg_match( $this->linktrail, $trail, $m ) ) {
1681 $inside = $m[1];
1682 $trail = $m[2];
1685 if ( $wgUser->getOption( 'highlightbroken' ) ) {
1686 $s = "<a href=\"{$u}\"{$style}>{$prefix}{$text}{$inside}</a>{$trail}";
1687 } else {
1688 $s = "{$prefix}{$text}{$inside}<a href=\"{$u}\"{$style}>?</a>{$trail}";
1691 wfProfileOut( $fname );
1692 return $s;
1696 * Pass a title object, not a title string
1698 function makeStubLinkObj( &$nt, $text = '', $query = '', $trail = '', $prefix = '' ) {
1699 global $wgOut, $wgUser;
1701 $link = $nt->getPrefixedURL();
1703 $u = $nt->escapeLocalURL( $query );
1705 if ( '' == $text ) {
1706 $text = htmlspecialchars( $nt->getPrefixedText() );
1708 $style = $this->getInternalLinkAttributesObj( $nt, $text, 'stub' );
1710 $inside = '';
1711 if ( '' != $trail ) {
1712 if ( preg_match( $this->linktrail, $trail, $m ) ) {
1713 $inside = $m[1];
1714 $trail = $m[2];
1717 if ( $wgUser->getOption( 'highlightbroken' ) ) {
1718 $s = "<a href=\"{$u}\"{$style}>{$prefix}{$text}{$inside}</a>{$trail}";
1719 } else {
1720 $s = "{$prefix}{$text}{$inside}<a href=\"{$u}\"{$style}>!</a>{$trail}";
1722 return $s;
1725 function makeSelfLinkObj( &$nt, $text = '', $query = '', $trail = '', $prefix = '' ) {
1726 $u = $nt->escapeLocalURL( $query );
1727 if ( '' == $text ) {
1728 $text = htmlspecialchars( $nt->getPrefixedText() );
1730 $inside = '';
1731 if ( '' != $trail ) {
1732 if ( preg_match( $this->linktrail, $trail, $m ) ) {
1733 $inside = $m[1];
1734 $trail = $m[2];
1737 return "<strong>{$prefix}{$text}{$inside}</strong>{$trail}";
1740 /* these are used extensively in SkinPHPTal, but also some other places */
1741 /*static*/ function makeSpecialUrl( $name, $urlaction='' ) {
1742 $title = Title::makeTitle( NS_SPECIAL, $name );
1743 $this->checkTitle($title, $name);
1744 return $title->getLocalURL( $urlaction );
1746 /*static*/ function makeTalkUrl ( $name, $urlaction='' ) {
1747 $title = Title::newFromText( $name );
1748 $title = $title->getTalkPage();
1749 $this->checkTitle($title, $name);
1750 return $title->getLocalURL( $urlaction );
1752 /*static*/ function makeArticleUrl ( $name, $urlaction='' ) {
1753 $title = Title::newFromText( $name );
1754 $title= $title->getSubjectPage();
1755 $this->checkTitle($title, $name);
1756 return $title->getLocalURL( $urlaction );
1758 /*static*/ function makeI18nUrl ( $name, $urlaction='' ) {
1759 $title = Title::newFromText( wfMsgForContent($name) );
1760 $this->checkTitle($title, $name);
1761 return $title->getLocalURL( $urlaction );
1763 /*static*/ function makeUrl ( $name, $urlaction='' ) {
1764 $title = Title::newFromText( $name );
1765 $this->checkTitle($title, $name);
1766 return $title->getLocalURL( $urlaction );
1769 # If url string starts with http, consider as external URL, else
1770 # internal
1771 /*static*/ function makeInternalOrExternalUrl( $name ) {
1772 if ( strncmp( $name, 'http', 4 ) == 0 ) {
1773 return $name;
1774 } else {
1775 return $this->makeUrl( $name );
1779 # this can be passed the NS number as defined in Language.php
1780 /*static*/ function makeNSUrl( $name, $urlaction='', $namespace=0 ) {
1781 $title = Title::makeTitleSafe( $namespace, $name );
1782 $this->checkTitle($title, $name);
1783 return $title->getLocalURL( $urlaction );
1786 /* these return an array with the 'href' and boolean 'exists' */
1787 /*static*/ function makeUrlDetails ( $name, $urlaction='' ) {
1788 $title = Title::newFromText( $name );
1789 $this->checkTitle($title, $name);
1790 return array(
1791 'href' => $title->getLocalURL( $urlaction ),
1792 'exists' => $title->getArticleID() != 0?true:false
1795 /*static*/ function makeTalkUrlDetails ( $name, $urlaction='' ) {
1796 $title = Title::newFromText( $name );
1797 $title = $title->getTalkPage();
1798 $this->checkTitle($title, $name);
1799 return array(
1800 'href' => $title->getLocalURL( $urlaction ),
1801 'exists' => $title->getArticleID() != 0?true:false
1804 /*static*/ function makeArticleUrlDetails ( $name, $urlaction='' ) {
1805 $title = Title::newFromText( $name );
1806 $title= $title->getSubjectPage();
1807 $this->checkTitle($title, $name);
1808 return array(
1809 'href' => $title->getLocalURL( $urlaction ),
1810 'exists' => $title->getArticleID() != 0?true:false
1813 /*static*/ function makeI18nUrlDetails ( $name, $urlaction='' ) {
1814 $title = Title::newFromText( wfMsgForContent($name) );
1815 $this->checkTitle($title, $name);
1816 return array(
1817 'href' => $title->getLocalURL( $urlaction ),
1818 'exists' => $title->getArticleID() != 0?true:false
1822 # make sure we have some title to operate on
1823 /*static*/ function checkTitle ( &$title, &$name ) {
1824 if(!is_object($title)) {
1825 $title = Title::newFromText( $name );
1826 if(!is_object($title)) {
1827 $title = Title::newFromText( '--error: link target missing--' );
1832 function fnamePart( $url ) {
1833 $basename = strrchr( $url, '/' );
1834 if ( false === $basename ) {
1835 $basename = $url;
1836 } else {
1837 $basename = substr( $basename, 1 );
1839 return htmlspecialchars( $basename );
1842 function makeImage( $url, $alt = '' ) {
1843 global $wgOut;
1845 if ( '' == $alt ) {
1846 $alt = $this->fnamePart( $url );
1848 $s = '<img src="'.$url.'" alt="'.$alt.'" />';
1849 return $s;
1852 function makeImageLink( $name, $url, $alt = '' ) {
1853 $nt = Title::makeTitleSafe( NS_IMAGE, $name );
1854 return $this->makeImageLinkObj( $nt, $alt );
1857 function makeImageLinkObj( $nt, $alt = '' ) {
1858 global $wgContLang, $wgUseImageResize;
1859 $img = Image::newFromTitle( $nt );
1860 $url = $img->getURL();
1862 $align = '';
1863 $prefix = $postfix = '';
1865 if ( $wgUseImageResize ) {
1866 # Check if the alt text is of the form "options|alt text"
1867 # Options are:
1868 # * thumbnail make a thumbnail with enlarge-icon and caption, alignment depends on lang
1869 # * left no resizing, just left align. label is used for alt= only
1870 # * right same, but right aligned
1871 # * none same, but not aligned
1872 # * ___px scale to ___ pixels width, no aligning. e.g. use in taxobox
1873 # * center center the image
1874 # * framed Keep original image size, no magnify-button.
1876 $part = explode( '|', $alt);
1878 $mwThumb =& MagicWord::get( MAG_IMG_THUMBNAIL );
1879 $mwLeft =& MagicWord::get( MAG_IMG_LEFT );
1880 $mwRight =& MagicWord::get( MAG_IMG_RIGHT );
1881 $mwNone =& MagicWord::get( MAG_IMG_NONE );
1882 $mwWidth =& MagicWord::get( MAG_IMG_WIDTH );
1883 $mwCenter =& MagicWord::get( MAG_IMG_CENTER );
1884 $mwFramed =& MagicWord::get( MAG_IMG_FRAMED );
1885 $alt = $part[count($part)-1];
1887 $height = $framed = $thumb = false;
1888 $manual_thumb = "" ;
1890 foreach( $part as $key => $val ) {
1891 $val_parts = explode ( "=" , $val , 2 ) ;
1892 $left_part = array_shift ( $val_parts ) ;
1893 if ( ! is_null( $mwThumb->matchVariableStartToEnd($val) ) ) {
1894 $thumb=true;
1895 } elseif ( count ( $val_parts ) == 1 && ! is_null( $mwThumb->matchVariableStartToEnd($left_part) ) ) {
1896 # use manually specified thumbnail
1897 $thumb=true;
1898 $manual_thumb = array_shift ( $val_parts ) ;
1899 } elseif ( ! is_null( $mwRight->matchVariableStartToEnd($val) ) ) {
1900 # remember to set an alignment, don't render immediately
1901 $align = 'right';
1902 } elseif ( ! is_null( $mwLeft->matchVariableStartToEnd($val) ) ) {
1903 # remember to set an alignment, don't render immediately
1904 $align = 'left';
1905 } elseif ( ! is_null( $mwCenter->matchVariableStartToEnd($val) ) ) {
1906 # remember to set an alignment, don't render immediately
1907 $align = 'center';
1908 } elseif ( ! is_null( $mwNone->matchVariableStartToEnd($val) ) ) {
1909 # remember to set an alignment, don't render immediately
1910 $align = 'none';
1911 } elseif ( ! is_null( $match = $mwWidth->matchVariableStartToEnd($val) ) ) {
1912 # $match is the image width in pixels
1913 if ( preg_match( '/^([0-9]*)x([0-9]*)$/', $match, $m ) ) {
1914 $width = intval( $m[1] );
1915 $height = intval( $m[2] );
1916 } else {
1917 $width = intval($match);
1919 } elseif ( ! is_null( $mwFramed->matchVariableStartToEnd($val) ) ) {
1920 $framed=true;
1923 if ( 'center' == $align )
1925 $prefix = '<span style="text-align: center">';
1926 $postfix = '</span>';
1927 $align = 'none';
1930 if ( $thumb || $framed ) {
1932 # Create a thumbnail. Alignment depends on language
1933 # writing direction, # right aligned for left-to-right-
1934 # languages ("Western languages"), left-aligned
1935 # for right-to-left-languages ("Semitic languages")
1937 # If thumbnail width has not been provided, it is set
1938 # here to 180 pixels
1939 if ( $align == '' ) {
1940 $align = $wgContLang->isRTL() ? 'left' : 'right';
1942 if ( ! isset($width) ) {
1943 $width = 180;
1945 return $prefix.$this->makeThumbLinkObj( $img, $alt, $align, $width, $height, $framed, $manual_thumb ).$postfix;
1947 } elseif ( isset($width) ) {
1949 # Create a resized image, without the additional thumbnail
1950 # features
1952 if ( ( ! $height === false )
1953 && ( $img->getHeight() * $width / $img->getWidth() > $height ) ) {
1954 print "height=$height<br>\nimg->getHeight() = ".$img->getHeight()."<br>\n";
1955 print 'rescaling by factor '. $height / $img->getHeight() . "<br>\n";
1956 $width = $img->getWidth() * $height / $img->getHeight();
1958 if ( '' == $manual_thumb ) $url = $img->createThumb( $width );
1960 } # endif $wgUseImageResize
1962 if ( empty( $alt ) ) {
1963 $alt = preg_replace( '/\.(.+?)^/', '', $img->getName() );
1965 $alt = htmlspecialchars( $alt );
1967 $u = $nt->escapeLocalURL();
1968 if ( $url == '' )
1970 $s = wfMsg( 'missingimage', $img->getName() );
1971 $s .= "<br>{$alt}<br>{$url}<br>\n";
1972 } else {
1973 $s = '<a href="'.$u.'" class="image" title="'.$alt.'">' .
1974 '<img src="'.$url.'" alt="'.$alt.'" /></a>';
1976 if ( '' != $align ) {
1977 $s = "<div class=\"float{$align}\"><span>{$s}</span></div>";
1979 return str_replace("\n", ' ',$prefix.$s.$postfix);
1983 * Make HTML for a thumbnail including image, border and caption
1984 * $img is an Image object
1986 function makeThumbLinkObj( $img, $label = '', $align = 'right', $boxwidth = 180, $boxheight=false, $framed=false , $manual_thumb = "" ) {
1987 global $wgStylePath, $wgContLang;
1988 # $image = Title::makeTitleSafe( NS_IMAGE, $name );
1989 $url = $img->getURL();
1991 #$label = htmlspecialchars( $label );
1992 $alt = preg_replace( '/<[^>]*>/', '', $label);
1993 $alt = htmlspecialchars( $alt );
1995 $width = $height = 0;
1996 if ( $img->exists() )
1998 $width = $img->getWidth();
1999 $height = $img->getHeight();
2001 if ( 0 == $width || 0 == $height )
2003 $width = $height = 200;
2005 if ( $boxwidth == 0 )
2007 $boxwidth = 200;
2009 if ( $framed )
2011 // Use image dimensions, don't scale
2012 $boxwidth = $width;
2013 $oboxwidth = $boxwidth + 2;
2014 $boxheight = $height;
2015 $thumbUrl = $url;
2016 } else {
2017 $h = intval( $height/($width/$boxwidth) );
2018 $oboxwidth = $boxwidth + 2;
2019 if ( ( ! $boxheight === false ) && ( $h > $boxheight ) )
2021 $boxwidth *= $boxheight/$h;
2022 } else {
2023 $boxheight = $h;
2025 if ( '' == $manual_thumb ) $thumbUrl = $img->createThumb( $boxwidth );
2028 if ( $manual_thumb != '' ) # Use manually specified thumbnail
2030 $manual_title = Title::makeTitleSafe( NS_IMAGE, $manual_thumb ); #new Title ( $manual_thumb ) ;
2031 $manual_img = Image::newFromTitle( $manual_title );
2032 $thumbUrl = $manual_img->getURL();
2033 if ( $manual_img->exists() )
2035 $width = $manual_img->getWidth();
2036 $height = $manual_img->getHeight();
2037 $boxwidth = $width ;
2038 $boxheight = $height ;
2039 $oboxwidth = $boxwidth + 2 ;
2043 $u = $img->getEscapeLocalURL();
2045 $more = htmlspecialchars( wfMsg( 'thumbnail-more' ) );
2046 $magnifyalign = $wgContLang->isRTL() ? 'left' : 'right';
2047 $textalign = $wgContLang->isRTL() ? ' style="text-align:right"' : '';
2049 $s = "<div class=\"thumb t{$align}\"><div style=\"width:{$oboxwidth}px;\">";
2050 if ( $thumbUrl == '' ) {
2051 $s .= wfMsg( 'missingimage', $img->getName() );
2052 $zoomicon = '';
2053 } else {
2054 $s .= '<a href="'.$u.'" class="internal" title="'.$alt.'">'.
2055 '<img src="'.$thumbUrl.'" alt="'.$alt.'" ' .
2056 'width="'.$boxwidth.'" height="'.$boxheight.'" /></a>';
2057 if ( $framed ) {
2058 $zoomicon="";
2059 } else {
2060 $zoomicon = '<div class="magnify" style="float:'.$magnifyalign.'">'.
2061 '<a href="'.$u.'" class="internal" title="'.$more.'">'.
2062 '<img src="'.$wgStylePath.'/common/images/magnify-clip.png" ' .
2063 'width="15" height="11" alt="'.$more.'" /></a></div>';
2066 $s .= ' <div class="thumbcaption" '.$textalign.'>'.$zoomicon.$label."</div></div></div>";
2067 return str_replace("\n", ' ', $s);
2070 function makeMediaLink( $name, $url, $alt = '' ) {
2071 $nt = Title::makeTitleSafe( Namespace::getMedia(), $name );
2072 return $this->makeMediaLinkObj( $nt, $alt );
2075 function makeMediaLinkObj( $nt, $alt = '' ) {
2076 if ( ! isset( $nt ) )
2078 ### HOTFIX. Instead of breaking, return empty string.
2079 $s = $alt;
2080 } else {
2081 $name = $nt->getDBKey();
2082 $url = Image::wfImageUrl( $name );
2083 if ( empty( $alt ) ) {
2084 $alt = preg_replace( '/\.(.+?)^/', '', $name );
2087 $u = htmlspecialchars( $url );
2088 $s = "<a href=\"{$u}\" class='internal' title=\"{$alt}\">{$alt}</a>";
2090 return $s;
2093 function specialLink( $name, $key = '' ) {
2094 global $wgContLang;
2096 if ( '' == $key ) { $key = strtolower( $name ); }
2097 $pn = $wgContLang->ucfirst( $name );
2098 return $this->makeKnownLink( $wgContLang->specialPage( $pn ),
2099 wfMsg( $key ) );
2102 function makeExternalLink( $url, $text, $escape = true ) {
2103 $style = $this->getExternalLinkAttributes( $url, $text );
2104 $url = htmlspecialchars( $url );
2105 if( $escape ) {
2106 $text = htmlspecialchars( $text );
2108 return '<a href="'.$url.'"'.$style.'>'.$text.'</a>';
2111 # Called by history lists and recent changes
2114 # Returns text for the start of the tabular part of RC
2115 function beginRecentChangesList() {
2116 $this->rc_cache = array() ;
2117 $this->rcMoveIndex = 0;
2118 $this->rcCacheIndex = 0 ;
2119 $this->lastdate = '';
2120 $this->rclistOpen = false;
2121 return '';
2124 function beginImageHistoryList() {
2125 $s = "\n<h2>" . wfMsg( 'imghistory' ) . "</h2>\n" .
2126 "<p>" . wfMsg( 'imghistlegend' ) . "</p>\n".'<ul class="special">';
2127 return $s;
2131 * Returns text for the end of RC
2132 * If enhanced RC is in use, returns pretty much all the text
2134 function endRecentChangesList() {
2135 $s = $this->recentChangesBlock() ;
2136 if( $this->rclistOpen ) {
2137 $s .= "</ul>\n";
2139 return $s;
2143 * Enhanced RC ungrouped line
2145 function recentChangesBlockLine ( $rcObj ) {
2146 global $wgStylePath, $wgContLang ;
2148 # Get rc_xxxx variables
2149 extract( $rcObj->mAttribs ) ;
2150 $curIdEq = 'curid='.$rc_cur_id;
2152 # Spacer image
2153 $r = '' ;
2155 $r .= '<img src="'.$wgStylePath.'/common/images/Arr_.png" width="12" height="12" border="0" />' ;
2156 $r .= '<tt>' ;
2158 if ( $rc_type == RC_MOVE || $rc_type == RC_MOVE_OVER_REDIRECT ) {
2159 $r .= '&nbsp;&nbsp;';
2160 } else {
2161 # M & N (minor & new)
2162 $M = wfMsg( 'minoreditletter' );
2163 $N = wfMsg( 'newpageletter' );
2165 if ( $rc_type == RC_NEW ) {
2166 $r .= $N ;
2167 } else {
2168 $r .= '&nbsp;' ;
2170 if ( $rc_minor ) {
2171 $r .= $M ;
2172 } else {
2173 $r .= '&nbsp;' ;
2177 # Timestamp
2178 $r .= ' '.$rcObj->timestamp.' ' ;
2179 $r .= '</tt>' ;
2181 # Article link
2182 $link = $rcObj->link ;
2183 if ( $rcObj->watched ) $link = '<strong>'.$link.'</strong>' ;
2184 $r .= $link ;
2186 # Diff
2187 $r .= ' (' ;
2188 $r .= $rcObj->difflink ;
2189 $r .= '; ' ;
2191 # Hist
2192 $r .= $this->makeKnownLinkObj( $rcObj->getTitle(), wfMsg( 'hist' ), $curIdEq.'&action=history' );
2194 # User/talk
2195 $r .= ') . . '.$rcObj->userlink ;
2196 $r .= $rcObj->usertalklink ;
2198 # Comment
2199 if ( $rc_comment != '' && $rc_type != RC_MOVE && $rc_type != RC_MOVE_OVER_REDIRECT ) {
2200 $rc_comment=$this->formatComment($rc_comment, $rcObj->getTitle());
2201 $r .= $wgContLang->emphasize( ' ('.$rc_comment.')' );
2204 $r .= "<br />\n" ;
2205 return $r ;
2209 * Enhanced RC group
2211 function recentChangesBlockGroup ( $block ) {
2212 global $wgStylePath, $wgContLang ;
2214 $r = '' ;
2215 $M = wfMsg( 'minoreditletter' );
2216 $N = wfMsg( 'newpageletter' );
2218 # Collate list of users
2219 $isnew = false ;
2220 $userlinks = array () ;
2221 foreach ( $block AS $rcObj ) {
2222 $oldid = $rcObj->mAttribs['rc_last_oldid'];
2223 if ( $rcObj->mAttribs['rc_new'] ) $isnew = true ;
2224 $u = $rcObj->userlink ;
2225 if ( !isset ( $userlinks[$u] ) ) $userlinks[$u] = 0 ;
2226 $userlinks[$u]++ ;
2229 # Sort the list and convert to text
2230 krsort ( $userlinks ) ;
2231 asort ( $userlinks ) ;
2232 $users = array () ;
2233 foreach ( $userlinks as $userlink => $count) {
2234 $text = $userlink ;
2235 if ( $count > 1 ) $text .= " ({$count}&times;)" ;
2236 array_push ( $users , $text ) ;
2238 $users = ' <font size="-1">['.implode('; ',$users).']</font>' ;
2240 # Arrow
2241 $rci = 'RCI'.$this->rcCacheIndex ;
2242 $rcl = 'RCL'.$this->rcCacheIndex ;
2243 $rcm = 'RCM'.$this->rcCacheIndex ;
2244 $toggleLink = "javascript:toggleVisibility('$rci','$rcm','$rcl')" ;
2245 $arrowdir = $wgContLang->isRTL() ? 'l' : 'r';
2246 $tl = '<span id="'.$rcm.'"><a href="'.$toggleLink.'"><img src="'.$wgStylePath.'/common/images/Arr_'.$arrowdir.'.png" width="12" height="12" /></a></span>' ;
2247 $tl .= '<span id="'.$rcl.'" style="display:none"><a href="'.$toggleLink.'"><img src="'.$wgStylePath.'/common/images/Arr_d.png" width="12" height="12" /></a></span>' ;
2248 $r .= $tl ;
2250 # Main line
2251 # M/N
2252 $r .= '<tt>' ;
2253 if ( $isnew ) $r .= $N ;
2254 else $r .= '&nbsp;' ;
2255 $r .= '&nbsp;' ; # Minor
2257 # Timestamp
2258 $r .= ' '.$block[0]->timestamp.' ' ;
2259 $r .= '</tt>' ;
2261 # Article link
2262 $link = $block[0]->link ;
2263 if ( $block[0]->watched ) $link = '<strong>'.$link.'</strong>' ;
2264 $r .= $link ;
2266 $curIdEq = 'curid=' . $block[0]->mAttribs['rc_cur_id'];
2267 if ( $block[0]->mAttribs['rc_type'] != RC_LOG ) {
2268 # Changes
2269 $r .= ' ('.count($block).' ' ;
2270 if ( $isnew ) $r .= wfMsg('changes');
2271 else $r .= $this->makeKnownLinkObj( $block[0]->getTitle() , wfMsg('changes') ,
2272 $curIdEq.'&diff=0&oldid='.$oldid ) ;
2273 $r .= '; ' ;
2275 # History
2276 $r .= $this->makeKnownLinkObj( $block[0]->getTitle(), wfMsg( 'history' ), $curIdEq.'&action=history' );
2277 $r .= ')' ;
2280 $r .= $users ;
2281 $r .= "<br />\n" ;
2283 # Sub-entries
2284 $r .= '<div id="'.$rci.'" style="display:none">' ;
2285 foreach ( $block AS $rcObj ) {
2286 # Get rc_xxxx variables
2287 extract( $rcObj->mAttribs );
2289 $r .= '<img src="'.$wgStylePath.'/common/images/Arr_.png" width="12" height="12" />';
2290 $r .= '<tt>&nbsp; &nbsp; &nbsp; &nbsp;' ;
2291 if ( $rc_new ) $r .= $N ;
2292 else $r .= '&nbsp;' ;
2293 if ( $rc_minor ) $r .= $M ;
2294 else $r .= '&nbsp;' ;
2295 $r .= '</tt>' ;
2297 $o = '' ;
2298 if ( $rc_last_oldid != 0 ) {
2299 $o = 'oldid='.$rc_last_oldid ;
2301 if ( $rc_type == RC_LOG ) {
2302 $link = $rcObj->timestamp ;
2303 } else {
2304 $link = $this->makeKnownLinkObj( $rcObj->getTitle(), $rcObj->timestamp , "{$curIdEq}&$o" ) ;
2306 $link = '<tt>'.$link.'</tt>' ;
2308 $r .= $link ;
2309 $r .= ' (' ;
2310 $r .= $rcObj->curlink ;
2311 $r .= '; ' ;
2312 $r .= $rcObj->lastlink ;
2313 $r .= ') . . '.$rcObj->userlink ;
2314 $r .= $rcObj->usertalklink ;
2315 if ( $rc_comment != '' ) {
2316 $rc_comment=$this->formatComment($rc_comment, $rcObj->getTitle());
2317 $r .= $wgContLang->emphasize( ' ('.$rc_comment.')' ) ;
2319 $r .= "<br />\n" ;
2321 $r .= "</div>\n" ;
2323 $this->rcCacheIndex++ ;
2324 return $r ;
2328 * If enhanced RC is in use, this function takes the previously cached
2329 * RC lines, arranges them, and outputs the HTML
2331 function recentChangesBlock () {
2332 global $wgStylePath ;
2333 if ( count ( $this->rc_cache ) == 0 ) return '' ;
2334 $blockOut = '';
2335 foreach ( $this->rc_cache AS $secureName => $block ) {
2336 if ( count ( $block ) < 2 ) {
2337 $blockOut .= $this->recentChangesBlockLine ( array_shift ( $block ) ) ;
2338 } else {
2339 $blockOut .= $this->recentChangesBlockGroup ( $block ) ;
2343 return '<div>'.$blockOut.'</div>' ;
2347 * Called in a loop over all displayed RC entries
2348 * Either returns the line, or caches it for later use
2350 function recentChangesLine( &$rc, $watched = false ) {
2351 global $wgUser ;
2352 $usenew = $wgUser->getOption( 'usenewrc' );
2353 if ( $usenew )
2354 $line = $this->recentChangesLineNew ( $rc, $watched ) ;
2355 else
2356 $line = $this->recentChangesLineOld ( $rc, $watched ) ;
2357 return $line ;
2360 function recentChangesLineOld( &$rc, $watched = false ) {
2361 global $wgTitle, $wgLang, $wgContLang, $wgUser, $wgRCSeconds, $wgUseRCPatrol, $wgOnlySysopsCanPatrol;
2363 # Extract DB fields into local scope
2364 extract( $rc->mAttribs );
2365 $curIdEq = 'curid=' . $rc_cur_id;
2367 # Make date header if necessary
2368 $date = $wgContLang->date( $rc_timestamp, true);
2369 $uidate = $wgLang->date( $rc_timestamp, true);
2370 $s = '';
2371 if ( $date != $this->lastdate ) {
2372 if ( '' != $this->lastdate ) { $s .= "</ul>\n"; }
2373 $s .= "<h4>{$uidate}</h4>\n<ul class='special'>";
2374 $this->lastdate = $date;
2375 $this->rclistOpen = true;
2378 # If this edit has not yet been patrolled, make it stick out
2379 $s .= ( ! $wgUseRCPatrol || $rc_patrolled ) ? '<li> ' : '<li class="not_patrolled"> ';
2381 if ( $rc_type == RC_MOVE || $rc_type == RC_MOVE_OVER_REDIRECT ) {
2382 # Diff
2383 $s .= '(' . wfMsg( 'diff' ) . ') (';
2384 # Hist
2385 $s .= $this->makeKnownLinkObj( $rc->getMovedToTitle(), wfMsg( 'hist' ), 'action=history' ) .
2386 ') . . ';
2388 # "[[x]] moved to [[y]]"
2389 $msg = ( $rc_type == RC_MOVE ) ? '1movedto2' : '1movedto2_redir';
2390 $s .= wfMsg( $msg, $this->makeKnownLinkObj( $rc->getTitle(), '', 'redirect=no' ),
2391 $this->makeKnownLinkObj( $rc->getMovedToTitle(), '' ) );
2392 } elseif( $rc_namespace == NS_SPECIAL && preg_match( '!^Log/(.*)$!', $rc_title, $matches ) ) {
2393 # Log updates, etc
2394 $logtype = $matches[1];
2395 $logname = LogPage::logName( $logtype );
2396 $s .= '(' . $this->makeKnownLinkObj( $rc->getTitle(), $logname ) . ')';
2397 } else {
2398 # Diff link
2399 if ( $rc_type == RC_NEW || $rc_type == RC_LOG ) {
2400 $diffLink = wfMsg( 'diff' );
2401 } else {
2402 if ( $wgUseRCPatrol && $rc_patrolled == 0 && $wgUser->getID() != 0 &&
2403 ( $wgUser->isSysop() || !$wgOnlySysopsCanPatrol ) )
2404 $rcidparam = "&rcid={$rc_id}";
2405 else
2406 $rcidparam = "";
2407 $diffLink = $this->makeKnownLinkObj( $rc->getTitle(), wfMsg( 'diff' ),
2408 "{$curIdEq}&diff={$rc_this_oldid}&oldid={$rc_last_oldid}{$rcidparam}",
2409 '', '', ' tabindex="'.$rc->counter.'"');
2411 $s .= '('.$diffLink.') (';
2413 # History link
2414 $s .= $this->makeKnownLinkObj( $rc->getTitle(), wfMsg( 'hist' ), $curIdEq.'&action=history' );
2415 $s .= ') . . ';
2417 # M and N (minor and new)
2418 if ( $rc_minor ) { $s .= ' <span class="minor">'.wfMsg( "minoreditletter" ).'</span>'; }
2419 if ( $rc_type == RC_NEW ) { $s .= '<span class="newpage">'.wfMsg( "newpageletter" ).'</span>'; }
2421 # Article link
2422 # If it's a new article, there is no diff link, but if it hasn't been
2423 # patrolled yet, we need to give users a way to do so
2424 if ( $wgUseRCPatrol && $rc_type == RC_NEW && $rc_patrolled == 0 &&
2425 $wgUser->getID() != 0 && ( $wgUser->isSysop() || !$wgOnlySysopsCanPatrol ) )
2426 $articleLink = $this->makeKnownLinkObj( $rc->getTitle(), '', "rcid={$rc_id}" );
2427 else
2428 $articleLink = $this->makeKnownLinkObj( $rc->getTitle(), '' );
2430 if ( $watched ) {
2431 $articleLink = '<strong>'.$articleLink.'</strong>';
2433 $s .= ' '.$articleLink;
2437 # Timestamp
2438 $s .= '; ' . $wgLang->time( $rc_timestamp, true, $wgRCSeconds ) . ' . . ';
2440 # User link (or contributions for unregistered users)
2441 if ( 0 == $rc_user ) {
2442 $userLink = $this->makeKnownLink( $wgContLang->specialPage( 'Contributions' ),
2443 $rc_user_text, 'target=' . $rc_user_text );
2444 } else {
2445 $userLink = $this->makeLink( $wgContLang->getNsText( NS_USER ) . ':'.$rc_user_text, $rc_user_text );
2447 $s .= $userLink;
2449 # User talk link
2450 $talkname=$wgContLang->getNsText(NS_TALK); # use the shorter name
2451 global $wgDisableAnonTalk;
2452 if( 0 == $rc_user && $wgDisableAnonTalk ) {
2453 $userTalkLink = '';
2454 } else {
2455 $utns=$wgContLang->getNsText(NS_USER_TALK);
2456 $userTalkLink= $this->makeLink($utns . ':'.$rc_user_text, $talkname );
2458 # Block link
2459 $blockLink='';
2460 if ( ( 0 == $rc_user ) && $wgUser->isSysop() ) {
2461 $blockLink = $this->makeKnownLink( $wgContLang->specialPage(
2462 'Blockip' ), wfMsg( 'blocklink' ), 'ip='.$rc_user_text );
2465 if($blockLink) {
2466 if($userTalkLink) $userTalkLink .= ' | ';
2467 $userTalkLink .= $blockLink;
2469 if($userTalkLink) $s.=' ('.$userTalkLink.')';
2471 # Add comment
2472 if ( '' != $rc_comment && '*' != $rc_comment && $rc_type != RC_MOVE && $rc_type != RC_MOVE_OVER_REDIRECT ) {
2473 $rc_comment=$this->formatComment($rc_comment,$rc->getTitle());
2474 $s .= $wgContLang->emphasize(' (' . $rc_comment . ')');
2476 $s .= "</li>\n";
2478 return $s;
2481 function recentChangesLineNew( &$baseRC, $watched = false ) {
2482 global $wgTitle, $wgLang, $wgContLang, $wgUser, $wgRCSeconds;
2484 # Create a specialised object
2485 $rc = RCCacheEntry::newFromParent( $baseRC ) ;
2487 # Extract fields from DB into the function scope (rc_xxxx variables)
2488 extract( $rc->mAttribs );
2489 $curIdEq = 'curid=' . $rc_cur_id;
2491 # If it's a new day, add the headline and flush the cache
2492 $date = $wgContLang->date( $rc_timestamp, true);
2493 $uidate = $wgLang->date( $rc_timestamp, true);
2494 $ret = '';
2495 if ( $date != $this->lastdate ) {
2496 # Process current cache
2497 $ret = $this->recentChangesBlock () ;
2498 $this->rc_cache = array() ;
2499 $ret .= "<h4>{$uidate}</h4>\n";
2500 $this->lastdate = $date;
2503 # Make article link
2504 if ( $rc_type == RC_MOVE || $rc_type == RC_MOVE_OVER_REDIRECT ) {
2505 $msg = ( $rc_type == RC_MOVE ) ? "1movedto2" : "1movedto2_redir";
2506 $clink = wfMsg( $msg, $this->makeKnownLinkObj( $rc->getTitle(), '', 'redirect=no' ),
2507 $this->makeKnownLinkObj( $rc->getMovedToTitle(), '' ) );
2508 } elseif( $rc_namespace == NS_SPECIAL && preg_match( '!^Log/(.*)$!', $rc_title, $matches ) ) {
2509 # Log updates, etc
2510 $logtype = $matches[1];
2511 $logname = LogPage::logName( $logtype );
2512 $clink = '(' . $this->makeKnownLinkObj( $rc->getTitle(), $logname ) . ')';
2513 } else {
2514 $clink = $this->makeKnownLinkObj( $rc->getTitle(), '' ) ;
2517 $time = $wgContLang->time( $rc_timestamp, true, $wgRCSeconds );
2518 $rc->watched = $watched ;
2519 $rc->link = $clink ;
2520 $rc->timestamp = $time;
2522 # Make "cur" and "diff" links
2523 if ( ( $rc_type == RC_NEW && $rc_this_oldid == 0 ) || $rc_type == RC_LOG || $rc_type == RC_MOVE || $rc_type == RC_MOVE_OVER_REDIRECT ) {
2524 $curLink = wfMsg( 'cur' );
2525 $diffLink = wfMsg( 'diff' );
2526 } else {
2527 $query = $curIdEq.'&diff=0&oldid='.$rc_this_oldid;
2528 $aprops = ' tabindex="'.$baseRC->counter.'"';
2529 $curLink = $this->makeKnownLinkObj( $rc->getTitle(), wfMsg( 'cur' ), $query, '' ,'' , $aprops );
2530 $diffLink = $this->makeKnownLinkObj( $rc->getTitle(), wfMsg( 'diff'), $query, '' ,'' , $aprops );
2533 # Make "last" link
2534 $titleObj = $rc->getTitle();
2535 if ( $rc_last_oldid == 0 || $rc_type == RC_LOG || $rc_type == RC_MOVE || $rc_type == RC_MOVE_OVER_REDIRECT ) {
2536 $lastLink = wfMsg( 'last' );
2537 } else {
2538 $lastLink = $this->makeKnownLinkObj( $rc->getTitle(), wfMsg( 'last' ),
2539 $curIdEq.'&diff='.$rc_this_oldid.'&oldid='.$rc_last_oldid );
2542 # Make user link (or user contributions for unregistered users)
2543 if ( $rc_user == 0 ) {
2544 $userLink = $this->makeKnownLink( $wgContLang->specialPage( 'Contributions' ),
2545 $rc_user_text, 'target=' . $rc_user_text );
2546 } else {
2547 $userLink = $this->makeLink( $wgContLang->getNsText(
2548 Namespace::getUser() ) . ':'.$rc_user_text, $rc_user_text );
2551 $rc->userlink = $userLink;
2552 $rc->lastlink = $lastLink;
2553 $rc->curlink = $curLink;
2554 $rc->difflink = $diffLink;
2556 # Make user talk link
2557 $utns=$wgContLang->getNsText(NS_USER_TALK);
2558 $talkname=$wgContLang->getNsText(NS_TALK); # use the shorter name
2559 $userTalkLink= $this->makeLink($utns . ':'.$rc_user_text, $talkname );
2561 global $wgDisableAnonTalk;
2562 if ( ( 0 == $rc_user ) && $wgUser->isSysop() ) {
2563 $blockLink = $this->makeKnownLink( $wgContLang->specialPage(
2564 'Blockip' ), wfMsg( 'blocklink' ), 'ip='.$rc_user_text );
2565 if( $wgDisableAnonTalk )
2566 $rc->usertalklink = ' ('.$blockLink.')';
2567 else
2568 $rc->usertalklink = ' ('.$userTalkLink.' | '.$blockLink.')';
2569 } else {
2570 if( $wgDisableAnonTalk && ($rc_user == 0) )
2571 $rc->usertalklink = '';
2572 else
2573 $rc->usertalklink = ' ('.$userTalkLink.')';
2576 # Put accumulated information into the cache, for later display
2577 # Page moves go on their own line
2578 $title = $rc->getTitle();
2579 $secureName = $title->getPrefixedDBkey();
2580 if ( $rc_type == RC_MOVE || $rc_type == RC_MOVE_OVER_REDIRECT ) {
2581 # Use an @ character to prevent collision with page names
2582 $this->rc_cache['@@' . ($this->rcMoveIndex++)] = array($rc);
2583 } else {
2584 if ( !isset ( $this->rc_cache[$secureName] ) ) $this->rc_cache[$secureName] = array() ;
2585 array_push ( $this->rc_cache[$secureName] , $rc ) ;
2587 return $ret;
2590 function endImageHistoryList() {
2591 $s = "</ul>\n";
2592 return $s;
2596 * This function is called by all recent changes variants, by the page history,
2597 * and by the user contributions list. It is responsible for formatting edit
2598 * comments. It escapes any HTML in the comment, but adds some CSS to format
2599 * auto-generated comments (from section editing) and formats [[wikilinks]].
2601 * The &$title parameter must be a title OBJECT. It is used to generate a
2602 * direct link to the section in the autocomment.
2603 * @author Erik Moeller <moeller@scireview.de>
2605 * Note: there's not always a title to pass to this function.
2606 * Since you can't set a default parameter for a reference, I've turned it
2607 * temporarily to a value pass. Should be adjusted further. --brion
2609 function formatComment($comment, $title = NULL) {
2610 global $wgContLang;
2611 $comment = htmlspecialchars( $comment );
2613 # The pattern for autogen comments is / * foo * /, which makes for
2614 # some nasty regex.
2615 # We look for all comments, match any text before and after the comment,
2616 # add a separator where needed and format the comment itself with CSS
2617 while (preg_match('/(.*)\/\*\s*(.*?)\s*\*\/(.*)/', $comment,$match)) {
2618 $pre=$match[1];
2619 $auto=$match[2];
2620 $post=$match[3];
2621 $link='';
2622 if($title) {
2623 $section=$auto;
2625 # This is hackish but should work in most cases.
2626 $section=str_replace('[[','',$section);
2627 $section=str_replace(']]','',$section);
2628 $title->mFragment=$section;
2629 $link=$this->makeKnownLinkObj($title,wfMsg('sectionlink'));
2631 $sep='-';
2632 $auto=$link.$auto;
2633 if($pre) { $auto = $sep.' '.$auto; }
2634 if($post) { $auto .= ' '.$sep; }
2635 $auto='<span class="autocomment">'.$auto.'</span>';
2636 $comment=$pre.$auto.$post;
2639 # format regular and media links - all other wiki formatting
2640 # is ignored
2641 $medians = $wgContLang->getNsText(Namespace::getMedia()).':';
2642 while(preg_match('/\[\[(.*?)(\|(.*?))*\]\](.*)$/',$comment,$match)) {
2643 # Handle link renaming [[foo|text]] will show link as "text"
2644 if( "" != $match[3] ) {
2645 $text = $match[3];
2646 } else {
2647 $text = $match[1];
2649 if( preg_match( '/^' . $medians . '(.*)$/i', $match[1], $submatch ) ) {
2650 # Media link; trail not supported.
2651 $linkRegexp = '/\[\[(.*?)\]\]/';
2652 $thelink = $this->makeMediaLink( $submatch[1], "", $text );
2653 } else {
2654 # Other kind of link
2655 if( preg_match( wfMsgForContent( "linktrail" ), $match[4], $submatch ) ) {
2656 $trail = $submatch[1];
2657 } else {
2658 $trail = "";
2660 $linkRegexp = '/\[\[(.*?)\]\]' . preg_quote( $trail, '/' ) . '/';
2661 if ($match[1][0] == ':')
2662 $match[1] = substr($match[1], 1);
2663 $thelink = $this->makeLink( $match[1], $text, "", $trail );
2665 $comment = preg_replace( $linkRegexp, $thelink, $comment, 1 );
2667 return $comment;
2670 function imageHistoryLine( $iscur, $timestamp, $img, $user, $usertext, $size, $description ) {
2671 global $wgUser, $wgLang, $wgContLang, $wgTitle;
2673 $datetime = $wgLang->timeanddate( $timestamp, true );
2674 $del = wfMsg( 'deleteimg' );
2675 $delall = wfMsg( 'deleteimgcompletely' );
2676 $cur = wfMsg( 'cur' );
2678 if ( $iscur ) {
2679 $url = Image::wfImageUrl( $img );
2680 $rlink = $cur;
2681 if ( $wgUser->isSysop() ) {
2682 $link = $wgTitle->escapeLocalURL( 'image=' . $wgTitle->getPartialURL() .
2683 '&action=delete' );
2684 $style = $this->getInternalLinkAttributes( $link, $delall );
2686 $dlink = '<a href="'.$link.'"'.$style.'>'.$delall.'</a>';
2687 } else {
2688 $dlink = $del;
2690 } else {
2691 $url = htmlspecialchars( wfImageArchiveUrl( $img ) );
2692 if( $wgUser->getID() != 0 && $wgTitle->userCanEdit() ) {
2693 $rlink = $this->makeKnownLink( $wgTitle->getPrefixedText(),
2694 wfMsg( 'revertimg' ), 'action=revert&oldimage=' .
2695 urlencode( $img ) );
2696 $dlink = $this->makeKnownLink( $wgTitle->getPrefixedText(),
2697 $del, 'action=delete&oldimage=' . urlencode( $img ) );
2698 } else {
2699 # Having live active links for non-logged in users
2700 # means that bots and spiders crawling our site can
2701 # inadvertently change content. Baaaad idea.
2702 $rlink = wfMsg( 'revertimg' );
2703 $dlink = $del;
2706 if ( 0 == $user ) {
2707 $userlink = $usertext;
2708 } else {
2709 $userlink = $this->makeLink( $wgContLang->getNsText( Namespace::getUser() ) .
2710 ':'.$usertext, $usertext );
2712 $nbytes = wfMsg( 'nbytes', $size );
2713 $style = $this->getInternalLinkAttributes( $url, $datetime );
2715 $s = "<li> ({$dlink}) ({$rlink}) <a href=\"{$url}\"{$style}>{$datetime}</a>"
2716 . " . . {$userlink} ({$nbytes})";
2718 if ( '' != $description && '*' != $description ) {
2719 $sk=$wgUser->getSkin();
2720 $s .= $wgContLang->emphasize(' (' . $sk->formatComment($description,$wgTitle) . ')');
2722 $s .= "</li>\n";
2723 return $s;
2726 function tocIndent($level) {
2727 return str_repeat( '<div class="tocindent">'."\n", $level>0 ? $level : 0 );
2730 function tocUnindent($level) {
2731 return str_repeat( "</div>\n", $level>0 ? $level : 0 );
2735 * parameter level defines if we are on an indentation level
2737 function tocLine( $anchor, $tocline, $level ) {
2738 $link = '<a href="#'.$anchor.'">'.$tocline.'</a><br />';
2739 if($level) {
2740 return $link."\n";
2741 } else {
2742 return '<div class="tocline">'.$link."</div>\n";
2747 function tocTable($toc) {
2748 # note to CSS fanatics: putting this in a div does not work -- div won't auto-expand
2749 # try min-width & co when somebody gets a chance
2750 $hideline = ' <script type="text/javascript">showTocToggle("' . addslashes( wfMsg('showtoc') ) . '","' . addslashes( wfMsg('hidetoc') ) . '")</script>';
2751 return
2752 '<table border="0" id="toc"><tr id="toctitle"><td align="center">'."\n".
2753 '<b>'.wfMsg('toc').'</b>' .
2754 $hideline .
2755 '</td></tr><tr id="tocinside"><td>'."\n".
2756 $toc."</td></tr></table>\n";
2760 * These two do not check for permissions: check $wgTitle->userCanEdit
2761 * before calling them
2763 function editSectionScriptForOther( $title, $section, $head ) {
2764 $ttl = Title::newFromText( $title );
2765 $url = $ttl->escapeLocalURL( 'action=edit&section='.$section );
2766 return '<span oncontextmenu=\'document.location="'.$url.'";return false;\'>'.$head.'</span>';
2769 function editSectionScript( $section, $head ) {
2770 global $wgTitle, $wgRequest;
2771 if( $wgRequest->getInt( 'oldid' ) && ( $wgRequest->getVal( 'diff' ) != '0' ) ) {
2772 return $head;
2774 $url = $wgTitle->escapeLocalURL( 'action=edit&section='.$section );
2775 return '<span oncontextmenu=\'document.location="'.$url.'";return false;\'>'.$head.'</span>';
2778 function editSectionLinkForOther( $title, $section ) {
2779 global $wgRequest;
2780 global $wgUser, $wgContLang;
2782 $title = Title::newFromText($title);
2783 $editurl = '&section='.$section;
2784 $url = $this->makeKnownLink($title->getPrefixedText(),wfMsg('editsection'),'action=edit'.$editurl);
2786 if( $wgContLang->isRTL() ) {
2787 $farside = 'left';
2788 $nearside = 'right';
2789 } else {
2790 $farside = 'right';
2791 $nearside = 'left';
2793 return "<div class=\"editsection\" style=\"float:$farside;margin-$nearside:5px;\">[".$url."]</div>";
2797 function editSectionLink( $section ) {
2798 global $wgRequest;
2799 global $wgTitle, $wgUser, $wgContLang;
2801 if( $wgRequest->getInt( 'oldid' ) && ( $wgRequest->getVal( 'diff' ) != '0' ) ) {
2802 # Section edit links would be out of sync on an old page.
2803 # But, if we're diffing to the current page, they'll be
2804 # correct.
2805 return '';
2808 $editurl = '&section='.$section;
2809 $url = $this->makeKnownLink($wgTitle->getPrefixedText(),wfMsg('editsection'),'action=edit'.$editurl);
2811 if( $wgContLang->isRTL() ) {
2812 $farside = 'left';
2813 $nearside = 'right';
2814 } else {
2815 $farside = 'right';
2816 $nearside = 'left';
2818 return "<div class=\"editsection\" style=\"float:$farside;margin-$nearside:5px;\">[".$url."]</div>";
2823 * This function is called by EditPage.php and shows a bulletin board style
2824 * toolbar for common editing functions. It can be disabled in the user
2825 * preferences.
2826 * The necessary JavaScript code can be found in style/wikibits.js.
2828 function getEditToolbar() {
2829 global $wgStylePath, $wgLang, $wgMimeType;
2832 * toolarray an array of arrays which each include the filename of
2833 * the button image (without path), the opening tag, the closing tag,
2834 * and optionally a sample text that is inserted between the two when no
2835 * selection is highlighted.
2836 * The tip text is shown when the user moves the mouse over the button.
2838 * Already here are accesskeys (key), which are not used yet until someone
2839 * can figure out a way to make them work in IE. However, we should make
2840 * sure these keys are not defined on the edit page.
2842 $toolarray=array(
2843 array( 'image'=>'button_bold.png',
2844 'open' => "\'\'\'",
2845 'close' => "\'\'\'",
2846 'sample'=> wfMsg('bold_sample'),
2847 'tip' => wfMsg('bold_tip'),
2848 'key' => 'B'
2850 array( 'image'=>'button_italic.png',
2851 'open' => "\'\'",
2852 'close' => "\'\'",
2853 'sample'=> wfMsg('italic_sample'),
2854 'tip' => wfMsg('italic_tip'),
2855 'key' => 'I'
2857 array( 'image'=>'button_link.png',
2858 'open' => '[[',
2859 'close' => ']]',
2860 'sample'=> wfMsg('link_sample'),
2861 'tip' => wfMsg('link_tip'),
2862 'key' => 'L'
2864 array( 'image'=>'button_extlink.png',
2865 'open' => '[',
2866 'close' => ']',
2867 'sample'=> wfMsg('extlink_sample'),
2868 'tip' => wfMsg('extlink_tip'),
2869 'key' => 'X'
2871 array( 'image'=>'button_headline.png',
2872 'open' => "\\n== ",
2873 'close' => " ==\\n",
2874 'sample'=> wfMsg('headline_sample'),
2875 'tip' => wfMsg('headline_tip'),
2876 'key' => 'H'
2878 array( 'image'=>'button_image.png',
2879 'open' => '[['.$wgLang->getNsText(NS_IMAGE).":",
2880 'close' => ']]',
2881 'sample'=> wfMsg('image_sample'),
2882 'tip' => wfMsg('image_tip'),
2883 'key' => 'D'
2885 array( 'image' => 'button_media.png',
2886 'open' => '[['.$wgLang->getNsText(NS_MEDIA).':',
2887 'close' => ']]',
2888 'sample'=> wfMsg('media_sample'),
2889 'tip' => wfMsg('media_tip'),
2890 'key' => 'M'
2892 array( 'image' => 'button_math.png',
2893 'open' => "\\<math\\>",
2894 'close' => "\\</math\\>",
2895 'sample'=> wfMsg('math_sample'),
2896 'tip' => wfMsg('math_tip'),
2897 'key' => 'C'
2899 array( 'image' => 'button_nowiki.png',
2900 'open' => "\\<nowiki\\>",
2901 'close' => "\\</nowiki\\>",
2902 'sample'=> wfMsg('nowiki_sample'),
2903 'tip' => wfMsg('nowiki_tip'),
2904 'key' => 'N'
2906 array( 'image' => 'button_sig.png',
2907 'open' => '--~~~~',
2908 'close' => '',
2909 'sample'=> '',
2910 'tip' => wfMsg('sig_tip'),
2911 'key' => 'Y'
2913 array( 'image' => 'button_hr.png',
2914 'open' => "\\n----\\n",
2915 'close' => '',
2916 'sample'=> '',
2917 'tip' => wfMsg('hr_tip'),
2918 'key' => 'R'
2921 $toolbar ="<script type='text/javascript'>\n/*<![CDATA[*/\n";
2923 $toolbar.="document.writeln(\"<div id='toolbar'>\");\n";
2924 foreach($toolarray as $tool) {
2926 $image=$wgStylePath.'/common/images/'.$tool['image'];
2927 $open=$tool['open'];
2928 $close=$tool['close'];
2929 $sample = addslashes( $tool['sample'] );
2931 // Note that we use the tip both for the ALT tag and the TITLE tag of the image.
2932 // Older browsers show a "speedtip" type message only for ALT.
2933 // Ideally these should be different, realistically they
2934 // probably don't need to be.
2935 $tip = addslashes( $tool['tip'] );
2937 #$key = $tool["key"];
2939 $toolbar.="addButton('$image','$tip','$open','$close','$sample');\n";
2942 $toolbar.="addInfobox('" . addslashes( wfMsg( "infobox" ) ) . "','" . addslashes(wfMsg("infobox_alert")) . "');\n";
2943 $toolbar.="document.writeln(\"</div>\");\n";
2945 $toolbar.="/*]]>*/\n</script>";
2946 return $toolbar;
2950 * @access public
2952 function suppressUrlExpansion() {
2953 return false;