Fix http://bugzilla.wikipedia.org/show_bug.cgi?id=459 Sorting tabindex.
[mediawiki.git] / includes / Skin.php
blob46a9c9563c60775173ea132f46fa2b2dd68cb6b4
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()
65 /**
66 * @todo document
67 * @package MediaWiki
69 class RCCacheEntry extends RecentChange
71 var $secureName, $link;
72 var $curlink , $difflink, $lastlink , $usertalklink , $versionlink ;
73 var $userlink, $timestamp, $watched;
75 function newFromParent( $rc )
77 $rc2 = new RCCacheEntry;
78 $rc2->mAttribs = $rc->mAttribs;
79 $rc2->mExtra = $rc->mExtra;
80 return $rc2;
82 } ;
85 /**
86 * The main skin class that provide methods and properties for all other skins
87 * including PHPTal skins.
88 * This base class is also the "Standard" skin.
89 * @package MediaWiki
91 class Skin {
92 /**#@+
93 * @access private
95 var $lastdate, $lastline;
96 var $linktrail ; # linktrail regexp
97 var $rc_cache ; # Cache for Enhanced Recent Changes
98 var $rcCacheIndex ; # Recent Changes Cache Counter for visibility toggle
99 var $rcMoveIndex;
100 var $postParseLinkColour = true;
101 /**#@-*/
103 function Skin() {
104 global $wgUseOldExistenceCheck;
105 $postParseLinkColour = !$wgUseOldExistenceCheck;
106 $this->linktrail = wfMsg('linktrail');
109 function getSkinNames() {
110 global $wgValidSkinNames;
111 return $wgValidSkinNames;
114 function getStylesheet() {
115 return 'common/wikistandard.css';
118 function getSkinName() {
119 return 'standard';
123 * Get/set accessor for delayed link colouring
125 function postParseLinkColour( $setting = NULL ) {
126 return wfSetVar( $this->postParseLinkColour, $setting );
129 function qbSetting() {
130 global $wgOut, $wgUser;
132 if ( $wgOut->isQuickbarSuppressed() ) { return 0; }
133 $q = $wgUser->getOption( 'quickbar' );
134 if ( '' == $q ) { $q = 0; }
135 return $q;
138 function initPage( &$out ) {
139 $fname = 'Skin::initPage';
140 wfProfileIn( $fname );
142 $out->addLink( array( 'rel' => 'shortcut icon', 'href' => '/favicon.ico' ) );
144 $this->addMetadataLinks($out);
146 wfProfileOut( $fname );
149 function addMetadataLinks( &$out ) {
150 global $wgTitle, $wgEnableDublinCoreRdf, $wgEnableCreativeCommonsRdf, $wgRdfMimeType, $action;
151 global $wgRightsPage, $wgRightsUrl;
153 if( $out->isArticleRelated() ) {
154 # note: buggy CC software only reads first "meta" link
155 if( $wgEnableCreativeCommonsRdf ) {
156 $out->addMetadataLink( array(
157 'title' => 'Creative Commons',
158 'type' => 'application/rdf+xml',
159 'href' => $wgTitle->getLocalURL( 'action=creativecommons') ) );
161 if( $wgEnableDublinCoreRdf ) {
162 $out->addMetadataLink( array(
163 'title' => 'Dublin Core',
164 'type' => 'application/rdf+xml',
165 'href' => $wgTitle->getLocalURL( 'action=dublincore' ) ) );
168 $copyright = '';
169 if( $wgRightsPage ) {
170 $copy = Title::newFromText( $wgRightsPage );
171 if( $copy ) {
172 $copyright = $copy->getLocalURL();
175 if( !$copyright && $wgRightsUrl ) {
176 $copyright = $wgRightsUrl;
178 if( $copyright ) {
179 $out->addLink( array(
180 'rel' => 'copyright',
181 'href' => $copyright ) );
185 function outputPage( &$out ) {
186 global $wgDebugComments;
188 wfProfileIn( 'Skin::outputPage' );
189 $this->initPage( $out );
190 $out->out( $out->headElement() );
192 $out->out( "\n<body" );
193 $ops = $this->getBodyOptions();
194 foreach ( $ops as $name => $val ) {
195 $out->out( " $name='$val'" );
197 $out->out( ">\n" );
198 if ( $wgDebugComments ) {
199 $out->out( "<!-- Wiki debugging output:\n" .
200 $out->mDebugtext . "-->\n" );
202 $out->out( $this->beforeContent() );
204 $out->out( $out->mBodytext . "\n" );
206 $out->out( $this->afterContent() );
208 wfProfileClose();
209 $out->out( $out->reportTime() );
211 $out->out( "\n</body></html>" );
214 function getHeadScripts() {
215 global $wgStylePath, $wgUser, $wgLang, $wgAllowUserJs;
216 $r = "<script type=\"text/javascript\" src=\"{$wgStylePath}/common/wikibits.js\"></script>\n";
217 if( $wgAllowUserJs && $wgUser->getID() != 0 ) { # logged in
218 $userpage = $wgLang->getNsText( Namespace::getUser() ) . ":" . $wgUser->getName();
219 $userjs = htmlspecialchars($this->makeUrl($userpage.'/'.$this->getSkinName().'.js', 'action=raw&ctype=text/javascript'));
220 $r .= '<script type="text/javascript" src="'.$userjs."\"></script>\n";
222 return $r;
225 # get the user/site-specific stylesheet, SkinPHPTal called from RawPage.php (settings are cached that way)
226 function getUserStylesheet() {
227 global $wgOut, $wgStylePath, $wgLang, $wgUser, $wgRequest, $wgTitle, $wgAllowUserCss;
228 $sheet = $this->getStylesheet();
229 $action = $wgRequest->getText('action');
230 $s = "@import \"$wgStylePath/$sheet\";\n";
231 if($wgLang->isRTL()) $s .= "@import \"$wgStylePath/common/common_rtl.css\";\n";
232 if( $wgAllowUserCss && $wgUser->getID() != 0 ) { # logged in
233 if($wgTitle->isCssSubpage() and $action == 'submit' and $wgTitle->userCanEditCssJsSubpage()) {
234 $s .= $wgRequest->getText('wpTextbox1');
235 } else {
236 $userpage = $wgLang->getNsText( Namespace::getUser() ) . ":" . $wgUser->getName();
237 $s.= '@import "'.$this->makeUrl($userpage.'/'.$this->getSkinName().'.css', 'action=raw&ctype=text/css').'";'."\n";
240 $s .= $this->doGetUserStyles();
241 return $s."\n";
245 * placeholder, returns generated js in monobook
247 function getUserJs() { return; }
250 * Return html code that include User stylesheets
252 function getUserStyles() {
253 global $wgOut, $wgStylePath, $wgLang;
254 $s = "<style type='text/css'>\n";
255 $s .= "/*/*/ /*<![CDATA[*/\n"; # <-- Hide the styles from Netscape 4 without hiding them from IE/Mac
256 $s .= $this->getUserStylesheet();
257 $s .= "/*]]>*/ /* */\n";
258 $s .= "</style>\n";
259 return $s;
263 * Some styles that are set by user through the user settings interface.
265 function doGetUserStyles() {
266 global $wgUser, $wgLang;
268 $csspage = $wgLang->getNsText( NS_MEDIAWIKI ) . ':' . $this->getSkinName() . '.css';
269 $s = '@import "'.$this->makeUrl($csspage, 'action=raw&ctype=text/css')."\";\n";
271 if ( 1 == $wgUser->getOption( 'underline' ) ) {
272 # Don't override browser settings
273 } else {
274 # CHECK MERGE @@@
275 # Force no underline
276 $s .= "a { text-decoration: none; }\n";
278 if ( 1 == $wgUser->getOption( 'highlightbroken' ) ) {
279 $s .= "a.new, #quickbar a.new { color: #CC2200; }\n";
281 if ( 1 == $wgUser->getOption( 'justify' ) ) {
282 $s .= "#article { text-align: justify; }\n";
284 return $s;
287 function getBodyOptions() {
288 global $wgUser, $wgTitle, $wgNamespaceBackgrounds, $wgOut, $wgRequest;
290 extract( $wgRequest->getValues( 'oldid', 'redirect', 'diff' ) );
292 if ( 0 != $wgTitle->getNamespace() ) {
293 $a = array( 'bgcolor' => '#ffffec' );
295 else $a = array( 'bgcolor' => '#FFFFFF' );
296 if($wgOut->isArticle() && $wgUser->getOption('editondblclick') &&
297 (!$wgTitle->isProtected() || $wgUser->isSysop()) ) {
298 $t = wfMsg( 'editthispage' );
299 $oid = $red = '';
300 if ( !empty($redirect) ) {
301 $red = "&redirect={$redirect}";
303 if ( !empty($oldid) && ! isset( $diff ) ) {
304 $oid = "&oldid={$oldid}";
306 $s = $wgTitle->getFullURL( "action=edit{$oid}{$red}" );
307 $s = 'document.location = "' .$s .'";';
308 $a += array ('ondblclick' => $s);
311 $a['onload'] = $wgOut->getOnloadHandler();
312 return $a;
315 function getExternalLinkAttributes( $link, $text, $class='' ) {
316 global $wgUser, $wgOut, $wgLang;
318 $link = urldecode( $link );
319 $link = $wgLang->checkTitleEncoding( $link );
320 $link = str_replace( '_', ' ', $link );
321 $link = htmlspecialchars( $link );
323 $r = ($class != '') ? " class='$class'" : " class='external'";
325 if ( 1 == $wgUser->getOption( 'hover' ) ) {
326 $r .= " title=\"{$link}\"";
328 return $r;
331 function getInternalLinkAttributes( $link, $text, $broken = false ) {
332 global $wgUser, $wgOut;
334 $link = urldecode( $link );
335 $link = str_replace( '_', ' ', $link );
336 $link = htmlspecialchars( $link );
338 if ( $broken == 'stub' ) {
339 $r = ' class="stub"';
340 } else if ( $broken == 'yes' ) {
341 $r = ' class="new"';
342 } else {
343 $r = '';
346 if ( 1 == $wgUser->getOption( 'hover' ) ) {
347 $r .= " title=\"{$link}\"";
349 return $r;
353 * @param bool $broken
355 function getInternalLinkAttributesObj( &$nt, $text, $broken = false ) {
356 global $wgUser, $wgOut;
358 if ( $broken == 'stub' ) {
359 $r = ' class="stub"';
360 } else if ( $broken == 'yes' ) {
361 $r = ' class="new"';
362 } else {
363 $r = '';
366 if ( 1 == $wgUser->getOption( 'hover' ) ) {
367 $r .= ' title ="' . $nt->getEscapedText() . '"';
369 return $r;
373 * URL to the logo
375 function getLogo() {
376 global $wgLogo;
377 return $wgLogo;
381 * This will be called immediately after the <body> tag. Split into
382 * two functions to make it easier to subclass.
384 function beforeContent() {
385 global $wgUser, $wgOut;
387 return $this->doBeforeContent();
390 function doBeforeContent() {
391 global $wgUser, $wgOut, $wgTitle, $wgLang, $wgSiteNotice;
392 $fname = 'Skin::doBeforeContent';
393 wfProfileIn( $fname );
395 $s = '';
396 $qb = $this->qbSetting();
398 if( $langlinks = $this->otherLanguages() ) {
399 $rows = 2;
400 $borderhack = '';
401 } else {
402 $rows = 1;
403 $langlinks = false;
404 $borderhack = 'class="top"';
407 $s .= "\n<div id='content'>\n<div id='topbar'>\n" .
408 "<table border='0' cellspacing='0' width='98%'>\n<tr>\n";
410 $shove = ($qb != 0);
411 $left = ($qb == 1 || $qb == 3);
412 if($wgLang->isRTL()) $left = !$left;
414 if ( !$shove ) {
415 $s .= "<td class='top' align='left' valign='top' rowspan='{$rows}'>\n" .
416 $this->logoText() . '</td>';
417 } elseif( $left ) {
418 $s .= $this->getQuickbarCompensator( $rows );
420 $l = $wgLang->isRTL() ? 'right' : 'left';
421 $s .= "<td {$borderhack} align='$l' valign='top'>\n";
423 $s .= $this->topLinks() ;
424 $s .= "<p class='subtitle'>" . $this->pageTitleLinks() . "</p>\n";
426 $r = $wgLang->isRTL() ? "left" : "right";
427 $s .= "</td>\n<td {$borderhack} valign='top' align='$r' nowrap='nowrap'>";
428 $s .= $this->nameAndLogin();
429 $s .= "\n<br />" . $this->searchForm() . "</td>";
431 if ( $langlinks ) {
432 $s .= "</tr>\n<tr>\n<td class='top' colspan=\"2\">$langlinks</td>\n";
435 if ( $shove && !$left ) { # Right
436 $s .= $this->getQuickbarCompensator( $rows );
438 $s .= "</tr>\n</table>\n</div>\n";
439 $s .= "\n<div id='article'>\n";
441 if( $wgSiteNotice ) {
442 $s .= "\n<div id='siteNotice'>$wgSiteNotice</div>\n";
444 $s .= $this->pageTitle();
445 $s .= $this->pageSubtitle() ;
446 $s .= $this->getCategories();
447 wfProfileOut( $fname );
448 return $s;
451 function getCategoryLinks () {
452 global $wgOut, $wgTitle, $wgUser, $wgParser;
453 global $wgUseCategoryMagic, $wgUseCategoryBrowser, $wgLang;
455 if( !$wgUseCategoryMagic ) return '' ;
456 if( count( $wgOut->mCategoryLinks ) == 0 ) return '';
458 # Taken out so that they will be displayed in previews -- TS
459 #if( !$wgOut->isArticle() ) return '';
461 $t = implode ( ' | ' , $wgOut->mCategoryLinks ) ;
462 $s = $this->makeKnownLink( 'Special:Categories',
463 wfMsg( 'categories' ), 'article=' . urlencode( $wgTitle->getPrefixedDBkey() ) )
464 . ': ' . $t;
466 # optional 'dmoz-like' category browser. Will be shown under the list
467 # of categories an article belong to
468 if($wgUseCategoryBrowser) {
469 $s .= '<br/><hr/>';
471 # get a big array of the parents tree
472 $parenttree = $wgTitle->getCategorieBrowser();
474 # Render the array as a serie of links
475 function walkThrough ($tree) {
476 global $wgUser;
477 $sk = $wgUser->getSkin();
478 $return = '';
479 foreach($tree as $element => $parent) {
480 if(empty($parent)) {
481 # element start a new list
482 $return .= '<br />';
483 } else {
484 # grab the others elements
485 $return .= walkThrough($parent);
487 # add our current element to the list
488 $eltitle = Title::NewFromText($element);
489 # FIXME : should be makeLink() [AV]
490 $return .= $sk->makeKnownLink($element, $eltitle->getText()).' &gt; ';
492 return $return;
495 $s .= walkThrough($parenttree);
498 return $s;
501 function getCategories() {
502 $catlinks=$this->getCategoryLinks();
503 if(!empty($catlinks)) {
504 return "<p class='catlinks'>{$catlinks}</p>";
508 function getQuickbarCompensator( $rows = 1 ) {
509 return "<td width='152' rowspan='{$rows}'>&nbsp;</td>";
512 # This gets called immediately before the </body> tag.
514 function afterContent() {
515 global $wgUser, $wgOut, $wgServer;
516 global $wgTitle, $wgLang;
518 $printfooter = "<div class=\"printfooter\">\n" . $this->printFooter() . "</div>\n";
519 return $printfooter . $this->doAfterContent();
522 function printSource() {
523 global $wgTitle;
524 $url = htmlspecialchars( $wgTitle->getFullURL() );
525 return wfMsg( "retrievedfrom", "<a href=\"$url\">$url</a>" );
528 function printFooter() {
529 return "<p>" . $this->printSource() .
530 "</p>\n\n<p>" . $this->pageStats() . "</p>\n";
533 function doAfterContent() {
534 global $wgUser, $wgOut, $wgLang;
535 $fname = 'Skin::doAfterContent';
536 wfProfileIn( $fname );
537 wfProfileIn( $fname.'-1' );
539 $s = "\n</div><br style=\"clear:both\" />\n";
540 $s .= "\n<div id='footer'>";
541 $s .= '<table border="0" cellspacing="0"><tr>';
543 wfProfileOut( $fname.'-1' );
544 wfProfileIn( $fname.'-2' );
546 $qb = $this->qbSetting();
547 $shove = ($qb != 0);
548 $left = ($qb == 1 || $qb == 3);
549 if($wgLang->isRTL()) $left = !$left;
551 if ( $shove && $left ) { # Left
552 $s .= $this->getQuickbarCompensator();
554 wfProfileOut( $fname.'-2' );
555 wfProfileIn( $fname.'-3' );
556 $l = $wgLang->isRTL() ? 'right' : 'left';
557 $s .= "<td class='bottom' align='$l' valign='top'>";
559 $s .= $this->bottomLinks();
560 $s .= "\n<br />" . $this->mainPageLink()
561 . ' | ' . $this->aboutLink()
562 . ' | ' . $this->specialLink( 'recentchanges' )
563 . ' | ' . $this->searchForm()
564 . '<br /><span id="pagestats">' . $this->pageStats() . '</span>';
566 $s .= "</td>";
567 if ( $shove && !$left ) { # Right
568 $s .= $this->getQuickbarCompensator();
570 $s .= "</tr></table>\n</div>\n</div>\n";
572 wfProfileOut( $fname.'-3' );
573 wfProfileIn( $fname.'-4' );
574 if ( 0 != $qb ) { $s .= $this->quickBar(); }
575 wfProfileOut( $fname.'-4' );
576 wfProfileOut( $fname );
577 return $s;
580 function pageTitleLinks() {
581 global $wgOut, $wgTitle, $wgUser, $wgLang, $wgUseApproval, $wgRequest;
583 extract( $wgRequest->getValues( 'oldid', 'diff' ) );
584 $action = $wgRequest->getText( 'action' );
586 $s = $this->printableLink();
587 if ( wfMsg ( 'disclaimers' ) != '-' ) $s .= ' | ' . $this->makeKnownLink( wfMsg( 'disclaimerpage' ), wfMsg( 'disclaimers' ) ) ;
589 if ( $wgOut->isArticleRelated() ) {
590 if ( $wgTitle->getNamespace() == Namespace::getImage() ) {
591 $name = $wgTitle->getDBkey();
592 $link = htmlspecialchars( Image::wfImageUrl( $name ) );
593 $style = $this->getInternalLinkAttributes( $link, $name );
594 $s .= " | <a href=\"{$link}\"{$style}>{$name}</a>";
596 # This will show the "Approve" link if $wgUseApproval=true;
597 if ( isset ( $wgUseApproval ) && $wgUseApproval )
599 $t = $wgTitle->getDBkey();
600 $name = 'Approve this article' ;
601 $link = "http://test.wikipedia.org/w/magnus/wiki.phtml?title={$t}&action=submit&doit=1" ;
602 #htmlspecialchars( wfImageUrl( $name ) );
603 $style = $this->getExternalLinkAttributes( $link, $name );
604 $s .= " | <a href=\"{$link}\"{$style}>{$name}</a>" ;
607 if ( 'history' == $action || isset( $diff ) || isset( $oldid ) ) {
608 $s .= ' | ' . $this->makeKnownLink( $wgTitle->getPrefixedText(),
609 wfMsg( 'currentrev' ) );
612 if ( $wgUser->getNewtalk() ) {
613 # do not show "You have new messages" text when we are viewing our
614 # own talk page
616 if(!(strcmp($wgTitle->getText(),$wgUser->getName()) == 0 &&
617 $wgTitle->getNamespace()==Namespace::getTalk(Namespace::getUser()))) {
618 $n =$wgUser->getName();
619 $tl = $this->makeKnownLink( $wgLang->getNsText(
620 Namespace::getTalk( Namespace::getUser() ) ) . ":{$n}",
621 wfMsg('newmessageslink') );
622 $s.= ' | <strong>'. wfMsg( 'newmessages', $tl ) . '</strong>';
623 # disable caching
624 $wgOut->setSquidMaxage(0);
628 $undelete = $this->getUndeleteLink();
629 if( !empty( $undelete ) ) {
630 $s .= ' | '.$undelete;
632 return $s;
635 function getUndeleteLink() {
636 global $wgUser, $wgTitle, $wgLang, $action;
637 if( $wgUser->isSysop() &&
638 (($wgTitle->getArticleId() == 0) || ($action == "history")) &&
639 ($n = $wgTitle->isDeleted() ) ) {
640 return wfMsg( 'thisisdeleted',
641 $this->makeKnownLink(
642 $wgLang->SpecialPage( 'Undelete/' . $wgTitle->getPrefixedDBkey() ),
643 wfMsg( 'restorelink', $n ) ) );
645 return '';
648 function printableLink() {
649 global $wgOut, $wgFeedClasses, $wgRequest;
651 $baseurl = $_SERVER['REQUEST_URI'];
652 if( strpos( '?', $baseurl ) == false ) {
653 $baseurl .= '?';
654 } else {
655 $baseurl .= '&';
657 $baseurl = htmlspecialchars( $baseurl );
658 $printurl = $wgRequest->escapeAppendQuery( 'printable=yes' );
660 $s = "<a href=\"$printurl\">" . wfMsg( 'printableversion' ) . '</a>';
661 if( $wgOut->isSyndicated() ) {
662 foreach( $wgFeedClasses as $format => $class ) {
663 $feedurl = $wgRequest->escapeAppendQuery( "feed=$format" );
664 $s .= " | <a href=\"$feedurl\">{$format}</a>";
667 return $s;
670 function pageTitle() {
671 global $wgOut, $wgTitle, $wgUser;
673 $s = '<h1 class="pagetitle">' . htmlspecialchars( $wgOut->getPageTitle() ) . '</h1>';
674 if($wgUser->getOption( 'editsectiononrightclick' ) && $wgTitle->userCanEdit()) { $s=$this->editSectionScript(0,$s);}
675 return $s;
678 function pageSubtitle() {
679 global $wgOut;
681 $sub = $wgOut->getSubtitle();
682 if ( '' == $sub ) {
683 global $wgExtraSubtitle;
684 $sub = wfMsg( 'tagline' ) . $wgExtraSubtitle;
686 $subpages = $this->subPageSubtitle();
687 $sub .= !empty($subpages)?"</p><p class='subpages'>$subpages":'';
688 $s = "<p class='subtitle'>{$sub}</p>\n";
689 return $s;
692 function subPageSubtitle() {
693 global $wgOut,$wgTitle,$wgNamespacesWithSubpages;
694 $subpages = '';
695 if($wgOut->isArticle() && !empty($wgNamespacesWithSubpages[$wgTitle->getNamespace()])) {
696 $ptext=$wgTitle->getPrefixedText();
697 if(preg_match('/\//',$ptext)) {
698 $links = explode('/',$ptext);
699 $c = 0;
700 $growinglink = '';
701 foreach($links as $link) {
702 $c++;
703 if ($c<count($links)) {
704 $growinglink .= $link;
705 $getlink = $this->makeLink( $growinglink, $link );
706 if(preg_match('/class="new"/i',$getlink)) { break; } # this is a hack, but it saves time
707 if ($c>1) {
708 $subpages .= ' | ';
709 } else {
710 $subpages .= '&lt; ';
712 $subpages .= $getlink;
713 $growinglink .= '/';
718 return $subpages;
721 function nameAndLogin() {
722 global $wgUser, $wgTitle, $wgLang, $wgShowIPinHeader, $wgIP;
724 $li = $wgLang->specialPage( 'Userlogin' );
725 $lo = $wgLang->specialPage( 'Userlogout' );
727 $s = '';
728 if ( 0 == $wgUser->getID() ) {
729 if( $wgShowIPinHeader && isset( $_COOKIE[ini_get('session.name')] ) ) {
730 $n = $wgIP;
732 $tl = $this->makeKnownLink( $wgLang->getNsText(
733 Namespace::getTalk( Namespace::getUser() ) ) . ":{$n}",
734 $wgLang->getNsText( Namespace::getTalk( 0 ) ) );
736 $s .= $n . ' ('.$tl.')';
737 } else {
738 $s .= wfMsg('notloggedin');
741 $rt = $wgTitle->getPrefixedURL();
742 if ( 0 == strcasecmp( urlencode( $lo ), $rt ) ) {
743 $q = '';
744 } else { $q = "returnto={$rt}"; }
746 $s .= "\n<br />" . $this->makeKnownLink( $li,
747 wfMsg( 'login' ), $q );
748 } else {
749 $n = $wgUser->getName();
750 $rt = $wgTitle->getPrefixedURL();
751 $tl = $this->makeKnownLink( $wgLang->getNsText(
752 Namespace::getTalk( Namespace::getUser() ) ) . ":{$n}",
753 $wgLang->getNsText( Namespace::getTalk( 0 ) ) );
755 $tl = " ({$tl})";
757 $s .= $this->makeKnownLink( $wgLang->getNsText(
758 Namespace::getUser() ) . ":{$n}", $n ) . "{$tl}<br />" .
759 $this->makeKnownLink( $lo, wfMsg( 'logout' ),
760 "returnto={$rt}" ) . ' | ' .
761 $this->specialLink( 'preferences' );
763 $s .= ' | ' . $this->makeKnownLink( wfMsg( 'helppage' ),
764 wfMsg( 'help' ) );
766 return $s;
769 function getSearchLink() {
770 $searchPage =& Title::makeTitle( NS_SPECIAL, 'Search' );
771 return $searchPage->getLocalURL();
774 function escapeSearchLink() {
775 return htmlspecialchars( $this->getSearchLink() );
778 function searchForm() {
779 global $wgRequest;
780 $search = $wgRequest->getText( 'search' );
782 $s = '<form name="search" class="inline" method="post" action="'
783 . $this->escapeSearchLink() . "\">\n"
784 . '<input type="text" name="search" size="19" value="'
785 . htmlspecialchars(substr($search,0,256)) . "\" />\n"
786 . '<input type="submit" name="go" value="' . wfMsg ('go') . '" />&nbsp;'
787 . '<input type="submit" name="fulltext" value="' . wfMsg ('search') . "\" />\n</form>";
789 return $s;
792 function topLinks() {
793 global $wgOut;
794 $sep = " |\n";
796 $s = $this->mainPageLink() . $sep
797 . $this->specialLink( 'recentchanges' );
799 if ( $wgOut->isArticleRelated() ) {
800 $s .= $sep . $this->editThisPage()
801 . $sep . $this->historyLink();
803 # Many people don't like this dropdown box
804 #$s .= $sep . $this->specialPagesList();
806 return $s;
809 function bottomLinks() {
810 global $wgOut, $wgUser, $wgTitle;
811 $sep = " |\n";
813 $s = '';
814 if ( $wgOut->isArticleRelated() ) {
815 $s .= '<strong>' . $this->editThisPage() . '</strong>';
816 if ( 0 != $wgUser->getID() ) {
817 $s .= $sep . $this->watchThisPage();
819 $s .= $sep . $this->talkLink()
820 . $sep . $this->historyLink()
821 . $sep . $this->whatLinksHere()
822 . $sep . $this->watchPageLinksLink();
824 if ( $wgTitle->getNamespace() == Namespace::getUser()
825 || $wgTitle->getNamespace() == Namespace::getTalk(Namespace::getUser()) )
828 $id=User::idFromName($wgTitle->getText());
829 $ip=User::isIP($wgTitle->getText());
831 if($id || $ip) { # both anons and non-anons have contri list
832 $s .= $sep . $this->userContribsLink();
834 if ( 0 != $wgUser->getID() ) { # show only to signed in users
835 if($id) { # can only email non-anons
836 $s .= $sep . $this->emailUserLink();
840 if ( $wgUser->isSysop() && $wgTitle->getArticleId() ) {
841 $s .= "\n<br />" . $this->deleteThisPage() .
842 $sep . $this->protectThisPage() .
843 $sep . $this->moveThisPage();
845 $s .= "<br />\n" . $this->otherLanguages();
847 return $s;
850 function pageStats() {
851 global $wgOut, $wgLang, $wgArticle, $wgRequest;
852 global $wgDisableCounters, $wgMaxCredits, $wgShowCreditsIfMax;
854 extract( $wgRequest->getValues( 'oldid', 'diff' ) );
855 if ( ! $wgOut->isArticle() ) { return ''; }
856 if ( isset( $oldid ) || isset( $diff ) ) { return ''; }
857 if ( 0 == $wgArticle->getID() ) { return ''; }
859 $s = '';
860 if ( !$wgDisableCounters ) {
861 $count = $wgLang->formatNum( $wgArticle->getCount() );
862 if ( $count ) {
863 $s = wfMsg( 'viewcount', $count );
867 if (isset($wgMaxCredits) && $wgMaxCredits != 0) {
868 require_once("Credits.php");
869 $s .= ' ' . getCredits($wgArticle, $wgMaxCredits, $wgShowCreditsIfMax);
870 } else {
871 $s .= $this->lastModified();
874 return $s . ' ' . $this->getCopyright();
877 function getCopyright() {
878 global $wgRightsPage, $wgRightsUrl, $wgRightsText, $wgRequest;
881 $oldid = $wgRequest->getVal( 'oldid' );
882 $diff = $wgRequest->getVal( 'diff' );
884 if ( !is_null( $oldid ) && is_null( $diff ) && wfMsg( 'history_copyright' ) !== '-' ) {
885 $msg = 'history_copyright';
886 } else {
887 $msg = 'copyright';
890 $out = '';
891 if( $wgRightsPage ) {
892 $link = $this->makeKnownLink( $wgRightsPage, $wgRightsText );
893 } elseif( $wgRightsUrl ) {
894 $link = $this->makeExternalLink( $wgRightsUrl, $wgRightsText );
895 } else {
896 # Give up now
897 return $out;
899 $out .= wfMsg( $msg, $link );
900 return $out;
903 function getCopyrightIcon() {
904 global $wgRightsPage, $wgRightsUrl, $wgRightsText, $wgRightsIcon;
905 $out = '';
906 if( $wgRightsIcon ) {
907 $icon = htmlspecialchars( $wgRightsIcon );
908 if( $wgRightsUrl ) {
909 $url = htmlspecialchars( $wgRightsUrl );
910 $out .= '<a href="'.$url.'">';
912 $text = htmlspecialchars( $wgRightsText );
913 $out .= "<img src=\"$icon\" alt='$text' />";
914 if( $wgRightsUrl ) {
915 $out .= '</a>';
918 return $out;
921 function getPoweredBy() {
922 global $wgStylePath;
923 $url = htmlspecialchars( "$wgStylePath/common/images/poweredby_mediawiki_88x31.png" );
924 $img = '<a href="http://www.mediawiki.org/"><img src="'.$url.'" alt="MediaWiki" /></a>';
925 return $img;
928 function lastModified() {
929 global $wgLang, $wgArticle;
931 $timestamp = $wgArticle->getTimestamp();
932 if ( $timestamp ) {
933 $d = $wgLang->timeanddate( $wgArticle->getTimestamp(), true );
934 $s = ' ' . wfMsg( 'lastmodified', $d );
935 } else {
936 $s = '';
938 return $s;
941 function logoText( $align = '' ) {
942 if ( '' != $align ) { $a = " align='{$align}'"; }
943 else { $a = ''; }
945 $mp = wfMsg( 'mainpage' );
946 $titleObj = Title::newFromText( $mp );
947 if ( is_object( $titleObj ) ) {
948 $url = $titleObj->escapeLocalURL();
949 } else {
950 $url = '';
953 $logourl = $this->getLogo();
954 $s = "<a href='{$url}'><img{$a} src='{$logourl}' alt='[{$mp}]' /></a>";
955 return $s;
958 function quickBar() {
959 global $wgOut, $wgTitle, $wgUser, $wgRequest, $wgLang;
960 global $wgDisableUploads, $wgRemoteUploads;
962 $fname = 'Skin::quickBar';
963 wfProfileIn( $fname );
965 $action = $wgRequest->getText( 'action' );
966 $wpPreview = $wgRequest->getBool( 'wpPreview' );
967 $tns=$wgTitle->getNamespace();
969 $s = "\n<div id='quickbar'>";
970 $s .= "\n" . $this->logoText() . "\n<hr class='sep' />";
972 $sep = "\n<br />";
973 $s .= $this->mainPageLink()
974 . $sep . $this->specialLink( 'recentchanges' )
975 . $sep . $this->specialLink( 'randompage' );
976 if ($wgUser->getID()) {
977 $s.= $sep . $this->specialLink( 'watchlist' ) ;
978 $s .= $sep .$this->makeKnownLink( $wgLang->specialPage( 'Contributions' ),
979 wfMsg( 'mycontris' ), 'target=' . wfUrlencode($wgUser->getName() ) );
982 // only show watchlist link if logged in
983 if ( wfMsg ( 'currentevents' ) != '-' ) $s .= $sep . $this->makeKnownLink( wfMsg( 'currentevents' ), '' ) ;
984 $s .= "\n<br /><hr class='sep' />";
985 $articleExists = $wgTitle->getArticleId();
986 if ( $wgOut->isArticle() || $action =='edit' || $action =='history' || $wpPreview) {
987 if($wgOut->isArticle()) {
988 $s .= '<strong>' . $this->editThisPage() . '</strong>';
989 } else { # backlink to the article in edit or history mode
990 if($articleExists){ # no backlink if no article
991 switch($tns) {
992 case 0:
993 $text = wfMsg('articlepage');
994 break;
995 case 1:
996 $text = wfMsg('viewtalkpage');
997 break;
998 case 2:
999 $text = wfMsg('userpage');
1000 break;
1001 case 3:
1002 $text = wfMsg('viewtalkpage');
1003 break;
1004 case 4:
1005 $text = wfMsg('wikipediapage');
1006 break;
1007 case 5:
1008 $text = wfMsg('viewtalkpage');
1009 break;
1010 case 6:
1011 $text = wfMsg('imagepage');
1012 break;
1013 case 7:
1014 $text = wfMsg('viewtalkpage');
1015 break;
1016 default:
1017 $text= wfMsg('articlepage');
1020 $link = $wgTitle->getText();
1021 if ($nstext = $wgLang->getNsText($tns) ) { # add namespace if necessary
1022 $link = $nstext . ':' . $link ;
1025 $s .= $this->makeLink( $link, $text );
1026 } elseif( $wgTitle->getNamespace() != Namespace::getSpecial() ) {
1027 # we just throw in a "New page" text to tell the user that he's in edit mode,
1028 # and to avoid messing with the separator that is prepended to the next item
1029 $s .= '<strong>' . wfMsg('newpage') . '</strong>';
1035 if( $tns%2 && $action!='edit' && !$wpPreview) {
1036 $s.= '<br />'.$this->makeKnownLink($wgTitle->getPrefixedText(),wfMsg('postcomment'),'action=edit&section=new');
1040 watching could cause problems in edit mode:
1041 if user edits article, then loads "watch this article" in background and then saves
1042 article with "Watch this article" checkbox disabled, the article is transparently
1043 unwatched. Therefore we do not show the "Watch this page" link in edit mode
1045 if ( 0 != $wgUser->getID() && $articleExists) {
1046 if($action!='edit' && $action != 'submit' )
1048 $s .= $sep . $this->watchThisPage();
1050 if ( $wgTitle->userCanEdit() )
1051 $s .= $sep . $this->moveThisPage();
1053 if ( $wgUser->isSysop() and $articleExists ) {
1054 $s .= $sep . $this->deleteThisPage() .
1055 $sep . $this->protectThisPage();
1057 $s .= $sep . $this->talkLink();
1058 if ($articleExists && $action !='history') {
1059 $s .= $sep . $this->historyLink();
1061 $s.=$sep . $this->whatLinksHere();
1063 if($wgOut->isArticleRelated()) {
1064 $s .= $sep . $this->watchPageLinksLink();
1067 if ( Namespace::getUser() == $wgTitle->getNamespace()
1068 || $wgTitle->getNamespace() == Namespace::getTalk(Namespace::getUser())
1071 $id=User::idFromName($wgTitle->getText());
1072 $ip=User::isIP($wgTitle->getText());
1074 if($id||$ip) {
1075 $s .= $sep . $this->userContribsLink();
1077 if ( 0 != $wgUser->getID() ) {
1078 if($id) { # can only email real users
1079 $s .= $sep . $this->emailUserLink();
1083 $s .= "\n<br /><hr class='sep' />";
1086 if ( 0 != $wgUser->getID() && ( !$wgDisableUploads || $wgRemoteUploads ) ) {
1087 $s .= $this->specialLink( 'upload' ) . $sep;
1089 $s .= $this->specialLink( 'specialpages' )
1090 . $sep . $this->bugReportsLink();
1092 global $wgSiteSupportPage;
1093 if( $wgSiteSupportPage ) {
1094 $s .= "\n<br /><a href=\"" . htmlspecialchars( $wgSiteSupportPage ) .
1095 '" class="internal">' . wfMsg( 'sitesupport' ) . '</a>';
1098 $s .= "\n<br /></div>\n";
1099 wfProfileOut( $fname );
1100 return $s;
1103 function specialPagesList() {
1104 global $wgUser, $wgOut, $wgLang, $wgServer, $wgRedirectScript;
1105 require_once('SpecialPage.php');
1106 $a = array();
1107 $pages = SpecialPage::getPages();
1109 foreach ( $pages[''] as $name => $page ) {
1110 $a[$name] = $page->getDescription();
1112 if ( $wgUser->isSysop() )
1114 foreach ( $pages['sysop'] as $name => $page ) {
1115 $a[$name] = $page->getDescription();
1118 if ( $wgUser->isDeveloper() )
1120 foreach ( $pages['developer'] as $name => $page ) {
1121 $a[$name] = $page->getDescription() ;
1124 $go = wfMsg( 'go' );
1125 $sp = wfMsg( 'specialpages' );
1126 $spp = $wgLang->specialPage( 'Specialpages' );
1128 $s = '<form id="specialpages" method="get" class="inline" ' .
1129 'action="' . htmlspecialchars( "{$wgServer}{$wgRedirectScript}" ) . "\">\n";
1130 $s .= "<select name=\"wpDropdown\">\n";
1131 $s .= "<option value=\"{$spp}\">{$sp}</option>\n";
1133 foreach ( $a as $name => $desc ) {
1134 $p = $wgLang->specialPage( $name );
1135 $s .= "<option value=\"{$p}\">{$desc}</option>\n";
1137 $s .= "</select>\n";
1138 $s .= "<input type='submit' value=\"{$go}\" name='redirect' />\n";
1139 $s .= "</form>\n";
1140 return $s;
1143 function mainPageLink() {
1144 $mp = wfMsg( 'mainpage' );
1145 $s = $this->makeKnownLink( $mp, $mp );
1146 return $s;
1149 function copyrightLink() {
1150 $s = $this->makeKnownLink( wfMsg( 'copyrightpage' ),
1151 wfMsg( 'copyrightpagename' ) );
1152 return $s;
1155 function aboutLink() {
1156 $s = $this->makeKnownLink( wfMsg( 'aboutpage' ),
1157 wfMsg( 'aboutsite' ) );
1158 return $s;
1162 function disclaimerLink() {
1163 $s = $this->makeKnownLink( wfMsg( 'disclaimerpage' ),
1164 wfMsg( 'disclaimers' ) );
1165 return $s;
1168 function editThisPage() {
1169 global $wgOut, $wgTitle, $wgRequest;
1171 $oldid = $wgRequest->getVal( 'oldid' );
1172 $diff = $wgRequest->getVal( 'diff' );
1173 $redirect = $wgRequest->getVal( 'redirect' );
1175 if ( ! $wgOut->isArticleRelated() ) {
1176 $s = wfMsg( 'protectedpage' );
1177 } else {
1178 $n = $wgTitle->getPrefixedText();
1179 if ( $wgTitle->userCanEdit() ) {
1180 $t = wfMsg( 'editthispage' );
1181 } else {
1182 #$t = wfMsg( "protectedpage" );
1183 $t = wfMsg( 'viewsource' );
1185 $oid = $red = '';
1187 if ( !is_null( $redirect ) ) { $red = "&redirect={$redirect}"; }
1188 if ( $oldid && ! isset( $diff ) ) {
1189 $oid = '&oldid='.$oldid;
1191 $s = $this->makeKnownLink( $n, $t, "action=edit{$oid}{$red}" );
1193 return $s;
1196 function deleteThisPage() {
1197 global $wgUser, $wgOut, $wgTitle, $wgRequest;
1199 $diff = $wgRequest->getVal( 'diff' );
1200 if ( $wgTitle->getArticleId() && ( ! $diff ) && $wgUser->isSysop() ) {
1201 $n = $wgTitle->getPrefixedText();
1202 $t = wfMsg( 'deletethispage' );
1204 $s = $this->makeKnownLink( $n, $t, 'action=delete' );
1205 } else {
1206 $s = '';
1208 return $s;
1211 function protectThisPage() {
1212 global $wgUser, $wgOut, $wgTitle, $wgRequest;
1214 $diff = $wgRequest->getVal( 'diff' );
1215 if ( $wgTitle->getArticleId() && ( ! $diff ) && $wgUser->isSysop() ) {
1216 $n = $wgTitle->getPrefixedText();
1218 if ( $wgTitle->isProtected() ) {
1219 $t = wfMsg( 'unprotectthispage' );
1220 $q = 'action=unprotect';
1221 } else {
1222 $t = wfMsg( 'protectthispage' );
1223 $q = 'action=protect';
1225 $s = $this->makeKnownLink( $n, $t, $q );
1226 } else {
1227 $s = '';
1229 return $s;
1232 function watchThisPage() {
1233 global $wgUser, $wgOut, $wgTitle;
1235 if ( $wgOut->isArticleRelated() ) {
1236 $n = $wgTitle->getPrefixedText();
1238 if ( $wgTitle->userIsWatching() ) {
1239 $t = wfMsg( 'unwatchthispage' );
1240 $q = 'action=unwatch';
1241 } else {
1242 $t = wfMsg( 'watchthispage' );
1243 $q = 'action=watch';
1245 $s = $this->makeKnownLink( $n, $t, $q );
1246 } else {
1247 $s = wfMsg( 'notanarticle' );
1249 return $s;
1252 function moveThisPage() {
1253 global $wgTitle, $wgLang;
1255 if ( $wgTitle->userCanEdit() ) {
1256 $s = $this->makeKnownLink( $wgLang->specialPage( 'Movepage' ),
1257 wfMsg( 'movethispage' ), 'target=' . $wgTitle->getPrefixedURL() );
1258 } // no message if page is protected - would be redundant
1259 return $s;
1262 function historyLink() {
1263 global $wgTitle;
1265 $s = $this->makeKnownLink( $wgTitle->getPrefixedText(),
1266 wfMsg( 'history' ), 'action=history' );
1267 return $s;
1270 function whatLinksHere() {
1271 global $wgTitle, $wgLang;
1273 $s = $this->makeKnownLink( $wgLang->specialPage( 'Whatlinkshere' ),
1274 wfMsg( 'whatlinkshere' ), 'target=' . $wgTitle->getPrefixedURL() );
1275 return $s;
1278 function userContribsLink() {
1279 global $wgTitle, $wgLang;
1281 $s = $this->makeKnownLink( $wgLang->specialPage( 'Contributions' ),
1282 wfMsg( 'contributions' ), 'target=' . $wgTitle->getPartialURL() );
1283 return $s;
1286 function emailUserLink() {
1287 global $wgTitle, $wgLang;
1289 $s = $this->makeKnownLink( $wgLang->specialPage( 'Emailuser' ),
1290 wfMsg( 'emailuser' ), 'target=' . $wgTitle->getPartialURL() );
1291 return $s;
1294 function watchPageLinksLink() {
1295 global $wgOut, $wgTitle, $wgLang;
1297 if ( ! $wgOut->isArticleRelated() ) {
1298 $s = '(' . wfMsg( 'notanarticle' ) . ')';
1299 } else {
1300 $s = $this->makeKnownLink( $wgLang->specialPage(
1301 'Recentchangeslinked' ), wfMsg( 'recentchangeslinked' ),
1302 'target=' . $wgTitle->getPrefixedURL() );
1304 return $s;
1307 function otherLanguages() {
1308 global $wgOut, $wgLang, $wgTitle, $wgUseNewInterlanguage;
1310 $a = $wgOut->getLanguageLinks();
1311 if ( 0 == count( $a ) ) {
1312 if ( !$wgUseNewInterlanguage ) return '';
1313 $ns = $wgLang->getNsIndex ( $wgTitle->getNamespace () ) ;
1314 if ( $ns != 0 AND $ns != 1 ) return '' ;
1315 $pn = 'Intl' ;
1316 $x = 'mode=addlink&xt='.$wgTitle->getDBkey() ;
1317 return $this->makeKnownLink( $wgLang->specialPage( $pn ),
1318 wfMsg( 'intl' ) , $x );
1321 if ( !$wgUseNewInterlanguage ) {
1322 $s = wfMsg( 'otherlanguages' ) . ': ';
1323 } else {
1324 global $wgLanguageCode ;
1325 $x = 'mode=zoom&xt='.$wgTitle->getDBkey() ;
1326 $x .= '&xl='.$wgLanguageCode ;
1327 $s = $this->makeKnownLink( $wgLang->specialPage( 'Intl' ),
1328 wfMsg( 'otherlanguages' ) , $x ) . ': ' ;
1331 $s = wfMsg( 'otherlanguages' ) . ': ';
1332 $first = true;
1333 if($wgLang->isRTL()) $s .= '<span dir="LTR">';
1334 foreach( $a as $l ) {
1335 if ( ! $first ) { $s .= ' | '; }
1336 $first = false;
1338 $nt = Title::newFromText( $l );
1339 $url = $nt->getFullURL();
1340 $text = $wgLang->getLanguageName( $nt->getInterwiki() );
1342 if ( '' == $text ) { $text = $l; }
1343 $style = $this->getExternalLinkAttributes( $l, $text );
1344 $s .= "<a href=\"{$url}\"{$style}>{$text}</a>";
1346 if($wgLang->isRTL()) $s .= '</span>';
1347 return $s;
1350 function bugReportsLink() {
1351 $s = $this->makeKnownLink( wfMsg( 'bugreportspage' ),
1352 wfMsg( 'bugreports' ) );
1353 return $s;
1356 function dateLink() {
1357 global $wgLinkCache;
1358 $t1 = Title::newFromText( gmdate( 'F j' ) );
1359 $t2 = Title::newFromText( gmdate( 'Y' ) );
1361 $wgLinkCache->suspend();
1362 $id = $t1->getArticleID();
1363 $wgLinkCache->resume();
1365 if ( 0 == $id ) {
1366 $s = $this->makeBrokenLink( $t1->getText() );
1367 } else {
1368 $s = $this->makeKnownLink( $t1->getText() );
1370 $s .= ', ';
1372 $wgLinkCache->suspend();
1373 $id = $t2->getArticleID();
1374 $wgLinkCache->resume();
1376 if ( 0 == $id ) {
1377 $s .= $this->makeBrokenLink( $t2->getText() );
1378 } else {
1379 $s .= $this->makeKnownLink( $t2->getText() );
1381 return $s;
1384 function talkLink() {
1385 global $wgLang, $wgTitle, $wgLinkCache;
1387 $tns = $wgTitle->getNamespace();
1388 if ( -1 == $tns ) { return ''; }
1390 $pn = $wgTitle->getText();
1391 $tp = wfMsg( 'talkpage' );
1392 if ( Namespace::isTalk( $tns ) ) {
1393 $lns = Namespace::getSubject( $tns );
1394 switch($tns) {
1395 case 1:
1396 $text = wfMsg('articlepage');
1397 break;
1398 case 3:
1399 $text = wfMsg('userpage');
1400 break;
1401 case 5:
1402 $text = wfMsg('wikipediapage');
1403 break;
1404 case 7:
1405 $text = wfMsg('imagepage');
1406 break;
1407 default:
1408 $text= wfMsg('articlepage');
1410 } else {
1412 $lns = Namespace::getTalk( $tns );
1413 $text=$tp;
1415 $n = $wgLang->getNsText( $lns );
1416 if ( '' == $n ) { $link = $pn; }
1417 else { $link = $n.':'.$pn; }
1419 $wgLinkCache->suspend();
1420 $s = $this->makeLink( $link, $text );
1421 $wgLinkCache->resume();
1423 return $s;
1426 function commentLink() {
1427 global $wgLang, $wgTitle, $wgLinkCache;
1429 $tns = $wgTitle->getNamespace();
1430 if ( -1 == $tns ) { return ''; }
1432 $lns = ( Namespace::isTalk( $tns ) ) ? $tns : Namespace::getTalk( $tns );
1434 # assert Namespace::isTalk( $lns )
1436 $n = $wgLang->getNsText( $lns );
1437 $pn = $wgTitle->getText();
1439 $link = $n.':'.$pn;
1441 $wgLinkCache->suspend();
1442 $s = $this->makeKnownLink($link, wfMsg('postcomment'), 'action=edit&section=new');
1443 $wgLinkCache->resume();
1445 return $s;
1449 * After all the page content is transformed into HTML, it makes
1450 * a final pass through here for things like table backgrounds.
1451 * @todo probably deprecated [AV]
1453 function transformContent( $text ) {
1454 return $text;
1458 * Note: This function MUST call getArticleID() on the link,
1459 * otherwise the cache won't get updated properly. See LINKCACHE.DOC.
1461 function makeLink( $title, $text = '', $query = '', $trail = '' ) {
1462 wfProfileIn( 'Skin::makeLink' );
1463 $nt = Title::newFromText( $title );
1464 if ($nt) {
1465 $result = $this->makeLinkObj( Title::newFromText( $title ), $text, $query, $trail );
1466 } else {
1467 wfDebug( 'Invalid title passed to Skin::makeLink(): "'.$title."\"\n" );
1468 $result = $text == "" ? $title : $text;
1471 wfProfileOut( 'Skin::makeLink' );
1472 return $result;
1475 function makeKnownLink( $title, $text = '', $query = '', $trail = '', $prefix = '',$aprops = '') {
1476 $nt = Title::newFromText( $title );
1477 if ($nt) {
1478 return $this->makeKnownLinkObj( Title::newFromText( $title ), $text, $query, $trail, $prefix , $aprops );
1479 } else {
1480 wfDebug( 'Invalid title passed to Skin::makeKnownLink(): "'.$title."\"\n" );
1481 return $text == '' ? $title : $text;
1485 function makeBrokenLink( $title, $text = '', $query = '', $trail = '' ) {
1486 $nt = Title::newFromText( $title );
1487 if ($nt) {
1488 return $this->makeBrokenLinkObj( Title::newFromText( $title ), $text, $query, $trail );
1489 } else {
1490 wfDebug( 'Invalid title passed to Skin::makeBrokenLink(): "'.$title."\"\n" );
1491 return $text == '' ? $title : $text;
1495 function makeStubLink( $title, $text = '', $query = '', $trail = '' ) {
1496 $nt = Title::newFromText( $title );
1497 if ($nt) {
1498 return $this->makeStubLinkObj( Title::newFromText( $title ), $text, $query, $trail );
1499 } else {
1500 wfDebug( 'Invalid title passed to Skin::makeStubLink(): "'.$title."\"\n" );
1501 return $text == '' ? $title : $text;
1506 * Pass a title object, not a title string
1508 function makeLinkObj( &$nt, $text= '', $query = '', $trail = '', $prefix = '' ) {
1509 global $wgOut, $wgUser, $wgLinkHolders;
1510 $fname = 'Skin::makeLinkObj';
1512 # Fail gracefully
1513 if ( ! isset($nt) )
1514 return "<!-- ERROR -->{$prefix}{$text}{$trail}";
1516 if ( $nt->isExternal() ) {
1517 $u = $nt->getFullURL();
1518 $link = $nt->getPrefixedURL();
1519 if ( '' == $text ) { $text = $nt->getPrefixedText(); }
1520 $style = $this->getExternalLinkAttributes( $link, $text, 'extiw' );
1522 $inside = '';
1523 if ( '' != $trail ) {
1524 if ( preg_match( '/^([a-z]+)(.*)$$/sD', $trail, $m ) ) {
1525 $inside = $m[1];
1526 $trail = $m[2];
1529 $retVal = "<a href=\"{$u}\"{$style}>{$text}{$inside}</a>{$trail}";
1530 } elseif ( 0 == $nt->getNamespace() && "" == $nt->getText() ) {
1531 $retVal = $this->makeKnownLinkObj( $nt, $text, $query, $trail, $prefix );
1532 } elseif ( ( -1 == $nt->getNamespace() ) ||
1533 ( Namespace::getImage() == $nt->getNamespace() ) ) {
1534 $retVal = $this->makeKnownLinkObj( $nt, $text, $query, $trail, $prefix );
1535 } else {
1536 if ( $this->postParseLinkColour() ) {
1537 $inside = '';
1538 if ( '' != $trail ) {
1539 if ( preg_match( $this->linktrail, $trail, $m ) ) {
1540 $inside = $m[1];
1541 $trail = $m[2];
1545 # Allows wiki to bypass using linkcache, see OutputPage::parseLinkHolders()
1546 $nr = array_push( $wgLinkHolders['namespaces'], $nt->getNamespace() );
1547 $wgLinkHolders['dbkeys'][] = $nt->getDBkey();
1548 $wgLinkHolders['queries'][] = $query;
1549 $wgLinkHolders['texts'][] = $prefix.$text.$inside;
1550 $wgLinkHolders['titles'][] = $nt;
1552 $retVal = '<!--LINK '. ($nr-1) ."-->{$trail}";
1553 } else {
1554 # Work out link colour immediately
1555 $aid = $nt->getArticleID() ;
1556 if ( 0 == $aid ) {
1557 $retVal = $this->makeBrokenLinkObj( $nt, $text, $query, $trail, $prefix );
1558 } else {
1559 $threshold = $wgUser->getOption('stubthreshold') ;
1560 if ( $threshold > 0 ) {
1561 $dbr =& wfGetDB( DB_SLAVE );
1562 $s = $dbr->selectRow( 'cur', array( 'LENGTH(cur_text) AS x', 'cur_namespace',
1563 'cur_is_redirect' ), array( 'cur_id' => $aid ), $fname ) ;
1564 if ( $s !== false ) {
1565 $size = $s->x;
1566 if ( $s->cur_is_redirect OR $s->cur_namespace != 0 ) {
1567 $size = $threshold*2 ; # Really big
1569 $dbr->freeResult( $res );
1570 } else {
1571 $size = $threshold*2 ; # Really big
1573 } else {
1574 $size = 1 ;
1576 if ( $size < $threshold ) {
1577 $retVal = $this->makeStubLinkObj( $nt, $text, $query, $trail, $prefix );
1578 } else {
1579 $retVal = $this->makeKnownLinkObj( $nt, $text, $query, $trail, $prefix );
1584 return $retVal;
1588 * Pass a title object, not a title string
1590 function makeKnownLinkObj( &$nt, $text = '', $query = '', $trail = '', $prefix = '' , $aprops = '' ) {
1591 global $wgOut, $wgTitle, $wgInputEncoding;
1593 $fname = 'Skin::makeKnownLinkObj';
1594 wfProfileIn( $fname );
1596 if ( !is_object( $nt ) ) {
1597 return $text;
1599 $link = $nt->getPrefixedURL();
1600 # if ( '' != $section && substr($section,0,1) != "#" ) {
1601 # $section = ''
1603 if ( '' == $link ) {
1604 $u = '';
1605 if ( '' == $text ) {
1606 $text = htmlspecialchars( $nt->getFragment() );
1608 } else {
1609 $u = $nt->escapeLocalURL( $query );
1611 if ( '' != $nt->getFragment() ) {
1612 $anchor = urlencode( do_html_entity_decode( str_replace(' ', '_', $nt->getFragment()), ENT_COMPAT, $wgInputEncoding ) );
1613 $replacearray = array(
1614 '%3A' => ':',
1615 '%' => '.'
1617 $u .= '#' . str_replace(array_keys($replacearray),array_values($replacearray),$anchor);
1619 if ( '' == $text ) {
1620 $text = htmlspecialchars( $nt->getPrefixedText() );
1622 $style = $this->getInternalLinkAttributesObj( $nt, $text );
1624 $inside = '';
1625 if ( '' != $trail ) {
1626 if ( preg_match( $this->linktrail, $trail, $m ) ) {
1627 $inside = $m[1];
1628 $trail = $m[2];
1631 $r = "<a href=\"{$u}\"{$style}{$aprops}>{$prefix}{$text}{$inside}</a>{$trail}";
1632 wfProfileOut( $fname );
1633 return $r;
1637 * Pass a title object, not a title string
1639 function makeBrokenLinkObj( &$nt, $text = '', $query = '', $trail = '', $prefix = '' ) {
1640 global $wgOut, $wgUser;
1642 # Fail gracefully
1643 if ( ! isset($nt) )
1644 return "<!-- ERROR -->{$prefix}{$text}{$trail}";
1646 $fname = 'Skin::makeBrokenLinkObj';
1647 wfProfileIn( $fname );
1649 if ( '' == $query ) {
1650 $q = 'action=edit';
1651 } else {
1652 $q = 'action=edit&'.$query;
1654 $u = $nt->escapeLocalURL( $q );
1656 if ( '' == $text ) {
1657 $text = htmlspecialchars( $nt->getPrefixedText() );
1659 $style = $this->getInternalLinkAttributesObj( $nt, $text, "yes" );
1661 $inside = '';
1662 if ( '' != $trail ) {
1663 if ( preg_match( $this->linktrail, $trail, $m ) ) {
1664 $inside = $m[1];
1665 $trail = $m[2];
1668 if ( $wgUser->getOption( 'highlightbroken' ) ) {
1669 $s = "<a href=\"{$u}\"{$style}>{$prefix}{$text}{$inside}</a>{$trail}";
1670 } else {
1671 $s = "{$prefix}{$text}{$inside}<a href=\"{$u}\"{$style}>?</a>{$trail}";
1674 wfProfileOut( $fname );
1675 return $s;
1679 * Pass a title object, not a title string
1681 function makeStubLinkObj( &$nt, $text = '', $query = '', $trail = '', $prefix = '' ) {
1682 global $wgOut, $wgUser;
1684 $link = $nt->getPrefixedURL();
1686 $u = $nt->escapeLocalURL( $query );
1688 if ( '' == $text ) {
1689 $text = htmlspecialchars( $nt->getPrefixedText() );
1691 $style = $this->getInternalLinkAttributesObj( $nt, $text, 'stub' );
1693 $inside = '';
1694 if ( '' != $trail ) {
1695 if ( preg_match( $this->linktrail, $trail, $m ) ) {
1696 $inside = $m[1];
1697 $trail = $m[2];
1700 if ( $wgUser->getOption( 'highlightbroken' ) ) {
1701 $s = "<a href=\"{$u}\"{$style}>{$prefix}{$text}{$inside}</a>{$trail}";
1702 } else {
1703 $s = "{$prefix}{$text}{$inside}<a href=\"{$u}\"{$style}>!</a>{$trail}";
1705 return $s;
1708 function makeSelfLinkObj( &$nt, $text = '', $query = '', $trail = '', $prefix = '' ) {
1709 $u = $nt->escapeLocalURL( $query );
1710 if ( '' == $text ) {
1711 $text = htmlspecialchars( $nt->getPrefixedText() );
1713 $inside = '';
1714 if ( '' != $trail ) {
1715 if ( preg_match( $this->linktrail, $trail, $m ) ) {
1716 $inside = $m[1];
1717 $trail = $m[2];
1720 return "<strong>{$prefix}{$text}{$inside}</strong>{$trail}";
1723 /* these are used extensively in SkinPHPTal, but also some other places */
1724 /*static*/ function makeSpecialUrl( $name, $urlaction='' ) {
1725 $title = Title::makeTitle( NS_SPECIAL, $name );
1726 $this->checkTitle($title, $name);
1727 return $title->getLocalURL( $urlaction );
1729 /*static*/ function makeTalkUrl ( $name, $urlaction='' ) {
1730 $title = Title::newFromText( $name );
1731 $title = $title->getTalkPage();
1732 $this->checkTitle($title, $name);
1733 return $title->getLocalURL( $urlaction );
1735 /*static*/ function makeArticleUrl ( $name, $urlaction='' ) {
1736 $title = Title::newFromText( $name );
1737 $title= $title->getSubjectPage();
1738 $this->checkTitle($title, $name);
1739 return $title->getLocalURL( $urlaction );
1741 /*static*/ function makeI18nUrl ( $name, $urlaction='' ) {
1742 $title = Title::newFromText( wfMsg($name) );
1743 $this->checkTitle($title, $name);
1744 return $title->getLocalURL( $urlaction );
1746 /*static*/ function makeUrl ( $name, $urlaction='' ) {
1747 $title = Title::newFromText( $name );
1748 $this->checkTitle($title, $name);
1749 return $title->getLocalURL( $urlaction );
1751 # this can be passed the NS number as defined in Language.php
1752 /*static*/ function makeNSUrl( $name, $urlaction='', $namespace=0 ) {
1753 $title = Title::makeTitleSafe( $namespace, $name );
1754 $this->checkTitle($title, $name);
1755 return $title->getLocalURL( $urlaction );
1758 /* these return an array with the 'href' and boolean 'exists' */
1759 /*static*/ function makeUrlDetails ( $name, $urlaction='' ) {
1760 $title = Title::newFromText( $name );
1761 $this->checkTitle($title, $name);
1762 return array(
1763 'href' => $title->getLocalURL( $urlaction ),
1764 'exists' => $title->getArticleID() != 0?true:false
1767 /*static*/ function makeTalkUrlDetails ( $name, $urlaction='' ) {
1768 $title = Title::newFromText( $name );
1769 $title = $title->getTalkPage();
1770 $this->checkTitle($title, $name);
1771 return array(
1772 'href' => $title->getLocalURL( $urlaction ),
1773 'exists' => $title->getArticleID() != 0?true:false
1776 /*static*/ function makeArticleUrlDetails ( $name, $urlaction='' ) {
1777 $title = Title::newFromText( $name );
1778 $title= $title->getSubjectPage();
1779 $this->checkTitle($title, $name);
1780 return array(
1781 'href' => $title->getLocalURL( $urlaction ),
1782 'exists' => $title->getArticleID() != 0?true:false
1785 /*static*/ function makeI18nUrlDetails ( $name, $urlaction='' ) {
1786 $title = Title::newFromText( wfMsg($name) );
1787 $this->checkTitle($title, $name);
1788 return array(
1789 'href' => $title->getLocalURL( $urlaction ),
1790 'exists' => $title->getArticleID() != 0?true:false
1794 # make sure we have some title to operate on
1795 /*static*/ function checkTitle ( &$title, &$name ) {
1796 if(!is_object($title)) {
1797 $title = Title::newFromText( $name );
1798 if(!is_object($title)) {
1799 $title = Title::newFromText( '--error: link target missing--' );
1804 function fnamePart( $url ) {
1805 $basename = strrchr( $url, '/' );
1806 if ( false === $basename ) {
1807 $basename = $url;
1808 } else {
1809 $basename = substr( $basename, 1 );
1811 return htmlspecialchars( $basename );
1814 function makeImage( $url, $alt = '' ) {
1815 global $wgOut;
1817 if ( '' == $alt ) {
1818 $alt = $this->fnamePart( $url );
1820 $s = '<img src="'.$url.'" alt="'.$alt.'" />';
1821 return $s;
1824 function makeImageLink( $name, $url, $alt = '' ) {
1825 $nt = Title::makeTitleSafe( NS_IMAGE, $name );
1826 return $this->makeImageLinkObj( $nt, $alt );
1829 function makeImageLinkObj( $nt, $alt = '' ) {
1830 global $wgLang, $wgUseImageResize;
1831 $img = Image::newFromTitle( $nt );
1832 $url = $img->getURL();
1834 $align = '';
1835 $prefix = $postfix = '';
1837 if ( $wgUseImageResize ) {
1838 # Check if the alt text is of the form "options|alt text"
1839 # Options are:
1840 # * thumbnail make a thumbnail with enlarge-icon and caption, alignment depends on lang
1841 # * left no resizing, just left align. label is used for alt= only
1842 # * right same, but right aligned
1843 # * none same, but not aligned
1844 # * ___px scale to ___ pixels width, no aligning. e.g. use in taxobox
1845 # * center center the image
1846 # * framed Keep original image size, no magnify-button.
1848 $part = explode( '|', $alt);
1850 $mwThumb =& MagicWord::get( MAG_IMG_THUMBNAIL );
1851 $mwLeft =& MagicWord::get( MAG_IMG_LEFT );
1852 $mwRight =& MagicWord::get( MAG_IMG_RIGHT );
1853 $mwNone =& MagicWord::get( MAG_IMG_NONE );
1854 $mwWidth =& MagicWord::get( MAG_IMG_WIDTH );
1855 $mwCenter =& MagicWord::get( MAG_IMG_CENTER );
1856 $mwFramed =& MagicWord::get( MAG_IMG_FRAMED );
1857 $alt = $part[count($part)-1];
1859 $height = $framed = $thumb = false;
1860 $manual_thumb = "" ;
1862 foreach( $part as $key => $val ) {
1863 $val_parts = explode ( "=" , $val , 2 ) ;
1864 $left_part = array_shift ( $val_parts ) ;
1865 if ( ! is_null( $mwThumb->matchVariableStartToEnd($val) ) ) {
1866 $thumb=true;
1867 } elseif ( count ( $val_parts ) == 1 && ! is_null( $mwThumb->matchVariableStartToEnd($left_part) ) ) {
1868 # use manually specified thumbnail
1869 $thumb=true;
1870 $manual_thumb = array_shift ( $val_parts ) ;
1871 } elseif ( ! is_null( $mwRight->matchVariableStartToEnd($val) ) ) {
1872 # remember to set an alignment, don't render immediately
1873 $align = 'right';
1874 } elseif ( ! is_null( $mwLeft->matchVariableStartToEnd($val) ) ) {
1875 # remember to set an alignment, don't render immediately
1876 $align = 'left';
1877 } elseif ( ! is_null( $mwCenter->matchVariableStartToEnd($val) ) ) {
1878 # remember to set an alignment, don't render immediately
1879 $align = 'center';
1880 } elseif ( ! is_null( $mwNone->matchVariableStartToEnd($val) ) ) {
1881 # remember to set an alignment, don't render immediately
1882 $align = 'none';
1883 } elseif ( ! is_null( $match = $mwWidth->matchVariableStartToEnd($val) ) ) {
1884 # $match is the image width in pixels
1885 if ( preg_match( '/^([0-9]*)x([0-9]*)$/', $match, $m ) ) {
1886 $width = intval( $m[1] );
1887 $height = intval( $m[2] );
1888 } else {
1889 $width = intval($match);
1891 } elseif ( ! is_null( $mwFramed->matchVariableStartToEnd($val) ) ) {
1892 $framed=true;
1895 if ( 'center' == $align )
1897 $prefix = '<span style="text-align: center">';
1898 $postfix = '</span>';
1899 $align = 'none';
1902 if ( $thumb || $framed ) {
1904 # Create a thumbnail. Alignment depends on language
1905 # writing direction, # right aligned for left-to-right-
1906 # languages ("Western languages"), left-aligned
1907 # for right-to-left-languages ("Semitic languages")
1909 # If thumbnail width has not been provided, it is set
1910 # here to 180 pixels
1911 if ( $align == '' ) {
1912 $align = $wgLang->isRTL() ? 'left' : 'right';
1914 if ( ! isset($width) ) {
1915 $width = 180;
1917 return $prefix.$this->makeThumbLinkObj( $img, $alt, $align, $width, $height, $framed, $manual_thumb ).$postfix;
1919 } elseif ( isset($width) ) {
1921 # Create a resized image, without the additional thumbnail
1922 # features
1924 if ( ( ! $height === false )
1925 && ( $img->getHeight() * $width / $img->getWidth() > $height ) ) {
1926 print "height=$height<br>\nimg->getHeight() = ".$img->getHeight()."<br>\n";
1927 print 'rescaling by factor '. $height / $img->getHeight() . "<br>\n";
1928 $width = $img->getWidth() * $height / $img->getHeight();
1930 if ( '' == $manual_thumb ) $url = $img->createThumb( $width );
1932 } # endif $wgUseImageResize
1934 if ( empty( $alt ) ) {
1935 $alt = preg_replace( '/\.(.+?)^/', '', $img->getName() );
1937 $alt = htmlspecialchars( $alt );
1939 $u = $nt->escapeLocalURL();
1940 if ( $url == '' )
1942 $s = wfMsg( 'missingimage', $img->getName() );
1943 $s .= "<br>{$alt}<br>{$url}<br>\n";
1944 } else {
1945 $s = '<a href="'.$u.'" class="image" title="'.$alt.'">' .
1946 '<img src="'.$url.'" alt="'.$alt.'" /></a>';
1948 if ( '' != $align ) {
1949 $s = "<div class=\"float{$align}\"><span>{$s}</span></div>";
1951 return str_replace("\n", ' ',$prefix.$s.$postfix);
1955 * Make HTML for a thumbnail including image, border and caption
1956 * $img is an Image object
1958 function makeThumbLinkObj( $img, $label = '', $align = 'right', $boxwidth = 180, $boxheight=false, $framed=false , $manual_thumb = "" ) {
1959 global $wgStylePath, $wgLang;
1960 # $image = Title::makeTitleSafe( NS_IMAGE, $name );
1961 $url = $img->getURL();
1963 #$label = htmlspecialchars( $label );
1964 $alt = preg_replace( '/<[^>]*>/', '', $label);
1965 $alt = htmlspecialchars( $alt );
1967 $width = $height = 0;
1968 if ( $img->exists() )
1970 $width = $img->getWidth();
1971 $height = $img->getHeight();
1973 if ( 0 == $width || 0 == $height )
1975 $width = $height = 200;
1977 if ( $boxwidth == 0 )
1979 $boxwidth = 200;
1981 if ( $framed )
1983 // Use image dimensions, don't scale
1984 $boxwidth = $width;
1985 $oboxwidth = $boxwidth + 2;
1986 $boxheight = $height;
1987 $thumbUrl = $url;
1988 } else {
1989 $h = intval( $height/($width/$boxwidth) );
1990 $oboxwidth = $boxwidth + 2;
1991 if ( ( ! $boxheight === false ) && ( $h > $boxheight ) )
1993 $boxwidth *= $boxheight/$h;
1994 } else {
1995 $boxheight = $h;
1997 if ( '' == $manual_thumb ) $thumbUrl = $img->createThumb( $boxwidth );
2000 if ( $manual_thumb != '' ) # Use manually specified thumbnail
2002 $manual_title = Title::makeTitleSafe( NS_IMAGE, $manual_thumb ); #new Title ( $manual_thumb ) ;
2003 $manual_img = Image::newFromTitle( $manual_title );
2004 $thumbUrl = $manual_img->getURL();
2005 if ( $manual_img->exists() )
2007 $width = $manual_img->getWidth();
2008 $height = $manual_img->getHeight();
2009 $boxwidth = $width ;
2010 $boxheight = $height ;
2011 $oboxwidth = $boxwidth + 2 ;
2015 $u = $img->getEscapeLocalURL();
2017 $more = htmlspecialchars( wfMsg( 'thumbnail-more' ) );
2018 $magnifyalign = $wgLang->isRTL() ? 'left' : 'right';
2019 $textalign = $wgLang->isRTL() ? ' style="text-align:right"' : '';
2021 $s = "<div class=\"thumb t{$align}\"><div style=\"width:{$oboxwidth}px;\">";
2022 if ( $thumbUrl == '' ) {
2023 $s .= wfMsg( 'missingimage', $img->getName() );
2024 $zoomicon = '';
2025 } else {
2026 $s .= '<a href="'.$u.'" class="internal" title="'.$alt.'">'.
2027 '<img src="'.$thumbUrl.'" alt="'.$alt.'" ' .
2028 'width="'.$boxwidth.'" height="'.$boxheight.'" /></a>';
2029 if ( $framed ) {
2030 $zoomicon="";
2031 } else {
2032 $zoomicon = '<div class="magnify" style="float:'.$magnifyalign.'">'.
2033 '<a href="'.$u.'" class="internal" title="'.$more.'">'.
2034 '<img src="'.$wgStylePath.'/common/images/magnify-clip.png" ' .
2035 'width="15" height="11" alt="'.$more.'" /></a></div>';
2038 $s .= ' <div class="thumbcaption" '.$textalign.'>'.$zoomicon.$label."</div></div></div>";
2039 return str_replace("\n", ' ', $s);
2042 function makeMediaLink( $name, $url, $alt = '' ) {
2043 $nt = Title::makeTitleSafe( Namespace::getMedia(), $name );
2044 return $this->makeMediaLinkObj( $nt, $alt );
2047 function makeMediaLinkObj( $nt, $alt = '' ) {
2048 if ( ! isset( $nt ) )
2050 ### HOTFIX. Instead of breaking, return empty string.
2051 $s = $alt;
2052 } else {
2053 $name = $nt->getDBKey();
2054 $url = Image::wfImageUrl( $name );
2055 if ( empty( $alt ) ) {
2056 $alt = preg_replace( '/\.(.+?)^/', '', $name );
2059 $u = htmlspecialchars( $url );
2060 $s = "<a href=\"{$u}\" class='internal' title=\"{$alt}\">{$alt}</a>";
2062 return $s;
2065 function specialLink( $name, $key = '' ) {
2066 global $wgLang;
2068 if ( '' == $key ) { $key = strtolower( $name ); }
2069 $pn = $wgLang->ucfirst( $name );
2070 return $this->makeKnownLink( $wgLang->specialPage( $pn ),
2071 wfMsg( $key ) );
2074 function makeExternalLink( $url, $text, $escape = true ) {
2075 $style = $this->getExternalLinkAttributes( $url, $text );
2076 $url = htmlspecialchars( $url );
2077 if( $escape ) {
2078 $text = htmlspecialchars( $text );
2080 return '<a href="'.$url.'"'.$style.'>'.$text.'</a>';
2083 # Called by history lists and recent changes
2086 # Returns text for the start of the tabular part of RC
2087 function beginRecentChangesList() {
2088 $this->rc_cache = array() ;
2089 $this->rcMoveIndex = 0;
2090 $this->rcCacheIndex = 0 ;
2091 $this->lastdate = '';
2092 $this->rclistOpen = false;
2093 return '';
2096 function beginImageHistoryList() {
2097 $s = "\n<h2>" . wfMsg( 'imghistory' ) . "</h2>\n" .
2098 "<p>" . wfMsg( 'imghistlegend' ) . "</p>\n".'<ul class="special">';
2099 return $s;
2103 * Returns text for the end of RC
2104 * If enhanced RC is in use, returns pretty much all the text
2106 function endRecentChangesList() {
2107 $s = $this->recentChangesBlock() ;
2108 if( $this->rclistOpen ) {
2109 $s .= "</ul>\n";
2111 return $s;
2115 * Enhanced RC ungrouped line
2117 function recentChangesBlockLine ( $rcObj ) {
2118 global $wgStylePath, $wgLang ;
2120 # Get rc_xxxx variables
2121 extract( $rcObj->mAttribs ) ;
2122 $curIdEq = 'curid='.$rc_cur_id;
2124 # Spacer image
2125 $r = '' ;
2127 $r .= '<img src="'.$wgStylePath.'/common/images/Arr_.png" width="12" height="12" border="0" />' ;
2128 $r .= '<tt>' ;
2130 if ( $rc_type == RC_MOVE || $rc_type == RC_MOVE_OVER_REDIRECT ) {
2131 $r .= '&nbsp;&nbsp;';
2132 } else {
2133 # M & N (minor & new)
2134 $M = wfMsg( 'minoreditletter' );
2135 $N = wfMsg( 'newpageletter' );
2137 if ( $rc_type == RC_NEW ) {
2138 $r .= $N ;
2139 } else {
2140 $r .= '&nbsp;' ;
2142 if ( $rc_minor ) {
2143 $r .= $M ;
2144 } else {
2145 $r .= '&nbsp;' ;
2149 # Timestamp
2150 $r .= ' '.$rcObj->timestamp.' ' ;
2151 $r .= '</tt>' ;
2153 # Article link
2154 $link = $rcObj->link ;
2155 if ( $rcObj->watched ) $link = '<strong>'.$link.'</strong>' ;
2156 $r .= $link ;
2158 # Diff
2159 $r .= ' (' ;
2160 $r .= $rcObj->difflink ;
2161 $r .= '; ' ;
2163 # Hist
2164 $r .= $this->makeKnownLinkObj( $rcObj->getTitle(), wfMsg( 'hist' ), $curIdEq.'&action=history' );
2166 # User/talk
2167 $r .= ') . . '.$rcObj->userlink ;
2168 $r .= $rcObj->usertalklink ;
2170 # Comment
2171 if ( $rc_comment != '' && $rc_type != RC_MOVE && $rc_type != RC_MOVE_OVER_REDIRECT ) {
2172 $rc_comment=$this->formatComment($rc_comment, $rcObj->getTitle());
2173 $r .= $wgLang->emphasize( ' ('.$rc_comment.')' );
2176 $r .= "<br />\n" ;
2177 return $r ;
2181 * Enhanced RC group
2183 function recentChangesBlockGroup ( $block ) {
2184 global $wgStylePath, $wgLang ;
2186 $r = '' ;
2187 $M = wfMsg( 'minoreditletter' );
2188 $N = wfMsg( 'newpageletter' );
2190 # Collate list of users
2191 $isnew = false ;
2192 $userlinks = array () ;
2193 foreach ( $block AS $rcObj ) {
2194 $oldid = $rcObj->mAttribs['rc_last_oldid'];
2195 if ( $rcObj->mAttribs['rc_new'] ) $isnew = true ;
2196 $u = $rcObj->userlink ;
2197 if ( !isset ( $userlinks[$u] ) ) $userlinks[$u] = 0 ;
2198 $userlinks[$u]++ ;
2201 # Sort the list and convert to text
2202 krsort ( $userlinks ) ;
2203 asort ( $userlinks ) ;
2204 $users = array () ;
2205 foreach ( $userlinks as $userlink => $count) {
2206 $text = $userlink ;
2207 if ( $count > 1 ) $text .= " ({$count}&times;)" ;
2208 array_push ( $users , $text ) ;
2210 $users = ' <font size="-1">['.implode('; ',$users).']</font>' ;
2212 # Arrow
2213 $rci = 'RCI'.$this->rcCacheIndex ;
2214 $rcl = 'RCL'.$this->rcCacheIndex ;
2215 $rcm = 'RCM'.$this->rcCacheIndex ;
2216 $toggleLink = "javascript:toggleVisibility('$rci','$rcm','$rcl')" ;
2217 $arrowdir = $wgLang->isRTL() ? 'l' : 'r';
2218 $tl = '<span id="'.$rcm.'"><a href="'.$toggleLink.'"><img src="'.$wgStylePath.'/common/images/Arr_'.$arrowdir.'.png" width="12" height="12" /></a></span>' ;
2219 $tl .= '<span id="'.$rcl.'" style="display:none"><a href="'.$toggleLink.'"><img src="'.$wgStylePath.'/common/images/Arr_d.png" width="12" height="12" /></a></span>' ;
2220 $r .= $tl ;
2222 # Main line
2223 # M/N
2224 $r .= '<tt>' ;
2225 if ( $isnew ) $r .= $N ;
2226 else $r .= '&nbsp;' ;
2227 $r .= '&nbsp;' ; # Minor
2229 # Timestamp
2230 $r .= ' '.$block[0]->timestamp.' ' ;
2231 $r .= '</tt>' ;
2233 # Article link
2234 $link = $block[0]->link ;
2235 if ( $block[0]->watched ) $link = '<strong>'.$link.'</strong>' ;
2236 $r .= $link ;
2238 $curIdEq = 'curid=' . $block[0]->mAttribs['rc_cur_id'];
2239 if ( $block[0]->mAttribs['rc_type'] != RC_LOG ) {
2240 # Changes
2241 $r .= ' ('.count($block).' ' ;
2242 if ( $isnew ) $r .= wfMsg('changes');
2243 else $r .= $this->makeKnownLinkObj( $block[0]->getTitle() , wfMsg('changes') ,
2244 $curIdEq.'&diff=0&oldid='.$oldid ) ;
2245 $r .= '; ' ;
2247 # History
2248 $r .= $this->makeKnownLinkObj( $block[0]->getTitle(), wfMsg( 'history' ), $curIdEq.'&action=history' );
2249 $r .= ')' ;
2252 $r .= $users ;
2253 $r .= "<br />\n" ;
2255 # Sub-entries
2256 $r .= '<div id="'.$rci.'" style="display:none">' ;
2257 foreach ( $block AS $rcObj ) {
2258 # Get rc_xxxx variables
2259 extract( $rcObj->mAttribs );
2261 $r .= '<img src="'.$wgStylePath.'/common/images/Arr_.png" width="12" height="12" />';
2262 $r .= '<tt>&nbsp; &nbsp; &nbsp; &nbsp;' ;
2263 if ( $rc_new ) $r .= $N ;
2264 else $r .= '&nbsp;' ;
2265 if ( $rc_minor ) $r .= $M ;
2266 else $r .= '&nbsp;' ;
2267 $r .= '</tt>' ;
2269 $o = '' ;
2270 if ( $rc_last_oldid != 0 ) {
2271 $o = 'oldid='.$rc_last_oldid ;
2273 if ( $rc_type == RC_LOG ) {
2274 $link = $rcObj->timestamp ;
2275 } else {
2276 $link = $this->makeKnownLinkObj( $rcObj->getTitle(), $rcObj->timestamp , "{$curIdEq}&$o" ) ;
2278 $link = '<tt>'.$link.'</tt>' ;
2280 $r .= $link ;
2281 $r .= ' (' ;
2282 $r .= $rcObj->curlink ;
2283 $r .= '; ' ;
2284 $r .= $rcObj->lastlink ;
2285 $r .= ') . . '.$rcObj->userlink ;
2286 $r .= $rcObj->usertalklink ;
2287 if ( $rc_comment != '' ) {
2288 $rc_comment=$this->formatComment($rc_comment, $rcObj->getTitle());
2289 $r .= $wgLang->emphasize( ' ('.$rc_comment.')' ) ;
2291 $r .= "<br />\n" ;
2293 $r .= "</div>\n" ;
2295 $this->rcCacheIndex++ ;
2296 return $r ;
2300 * If enhanced RC is in use, this function takes the previously cached
2301 * RC lines, arranges them, and outputs the HTML
2303 function recentChangesBlock () {
2304 global $wgStylePath ;
2305 if ( count ( $this->rc_cache ) == 0 ) return '' ;
2306 $blockOut = '';
2307 foreach ( $this->rc_cache AS $secureName => $block ) {
2308 if ( count ( $block ) < 2 ) {
2309 $blockOut .= $this->recentChangesBlockLine ( array_shift ( $block ) ) ;
2310 } else {
2311 $blockOut .= $this->recentChangesBlockGroup ( $block ) ;
2315 return '<div>'.$blockOut.'</div>' ;
2319 * Called in a loop over all displayed RC entries
2320 * Either returns the line, or caches it for later use
2322 function recentChangesLine( &$rc, $watched = false ) {
2323 global $wgUser ;
2324 $usenew = $wgUser->getOption( 'usenewrc' );
2325 if ( $usenew )
2326 $line = $this->recentChangesLineNew ( $rc, $watched ) ;
2327 else
2328 $line = $this->recentChangesLineOld ( $rc, $watched ) ;
2329 return $line ;
2332 function recentChangesLineOld( &$rc, $watched = false ) {
2333 global $wgTitle, $wgLang, $wgUser, $wgRCSeconds, $wgUseRCPatrol, $wgOnlySysopsCanPatrol;
2335 # Extract DB fields into local scope
2336 extract( $rc->mAttribs );
2337 $curIdEq = 'curid=' . $rc_cur_id;
2339 # Make date header if necessary
2340 $date = $wgLang->date( $rc_timestamp, true);
2341 $s = '';
2342 if ( $date != $this->lastdate ) {
2343 if ( '' != $this->lastdate ) { $s .= "</ul>\n"; }
2344 $s .= "<h4>{$date}</h4>\n<ul class='special'>";
2345 $this->lastdate = $date;
2346 $this->rclistOpen = true;
2349 # If this edit has not yet been patrolled, make it stick out
2350 $s .= ( ! $wgUseRCPatrol || $rc_patrolled ) ? '<li> ' : '<li class="not_patrolled"> ';
2352 if ( $rc_type == RC_MOVE || $rc_type == RC_MOVE_OVER_REDIRECT ) {
2353 # Diff
2354 $s .= '(' . wfMsg( 'diff' ) . ') (';
2355 # Hist
2356 $s .= $this->makeKnownLinkObj( $rc->getMovedToTitle(), wfMsg( 'hist' ), 'action=history' ) .
2357 ') . . ';
2359 # "[[x]] moved to [[y]]"
2360 $msg = ( $rc_type == RC_MOVE ) ? '1movedto2' : '1movedto2_redir';
2361 $s .= wfMsg( $msg, $this->makeKnownLinkObj( $rc->getTitle(), '', 'redirect=no' ),
2362 $this->makeKnownLinkObj( $rc->getMovedToTitle(), '' ) );
2363 } elseif( $rc_namespace == NS_SPECIAL && preg_match( '!^Log/(.*)$!', $rc_title, $matches ) ) {
2364 # Log updates, etc
2365 $logtype = $matches[1];
2366 $logname = LogPage::logName( $logtype );
2367 $s .= '(' . $this->makeKnownLinkObj( $rc->getTitle(), $logname ) . ')';
2368 } else {
2369 # Diff link
2370 if ( $rc_type == RC_NEW || $rc_type == RC_LOG ) {
2371 $diffLink = wfMsg( 'diff' );
2372 } else {
2373 if ( $wgUseRCPatrol && $rc_patrolled == 0 && $wgUser->getID() != 0 &&
2374 ( $wgUser->isSysop() || !$wgOnlySysopsCanPatrol ) )
2375 $rcidparam = "&rcid={$rc_id}";
2376 else
2377 $rcidparam = "";
2378 $diffLink = $this->makeKnownLinkObj( $rc->getTitle(), wfMsg( 'diff' ),
2379 "{$curIdEq}&diff={$rc_this_oldid}&oldid={$rc_last_oldid}{$rcidparam}",
2380 '', '', ' tabindex="'.$rc->counter.'"');
2382 $s .= '('.$diffLink.') (';
2384 # History link
2385 $s .= $this->makeKnownLinkObj( $rc->getTitle(), wfMsg( 'hist' ), $curIdEq.'&action=history' );
2386 $s .= ') . . ';
2388 # M and N (minor and new)
2389 if ( $rc_minor ) { $s .= ' <span class="minor">'.wfMsg( "minoreditletter" ).'</span>'; }
2390 if ( $rc_type == RC_NEW ) { $s .= '<span class="newpage">'.wfMsg( "newpageletter" ).'</span>'; }
2392 # Article link
2393 # If it's a new article, there is no diff link, but if it hasn't been
2394 # patrolled yet, we need to give users a way to do so
2395 if ( $wgUseRCPatrol && $rc_type == RC_NEW && $rc_patrolled == 0 &&
2396 $wgUser->getID() != 0 && ( $wgUser->isSysop() || !$wgOnlySysopsCanPatrol ) )
2397 $articleLink = $this->makeKnownLinkObj( $rc->getTitle(), '', "rcid={$rc_id}" );
2398 else
2399 $articleLink = $this->makeKnownLinkObj( $rc->getTitle(), '' );
2401 if ( $watched ) {
2402 $articleLink = '<strong>'.$articleLink.'</strong>';
2404 $s .= ' '.$articleLink;
2408 # Timestamp
2409 $s .= '; ' . $wgLang->time( $rc_timestamp, true, $wgRCSeconds ) . ' . . ';
2411 # User link (or contributions for unregistered users)
2412 if ( 0 == $rc_user ) {
2413 $userLink = $this->makeKnownLink( $wgLang->specialPage( 'Contributions' ),
2414 $rc_user_text, 'target=' . $rc_user_text );
2415 } else {
2416 $userLink = $this->makeLink( $wgLang->getNsText( NS_USER ) . ':'.$rc_user_text, $rc_user_text );
2418 $s .= $userLink;
2420 # User talk link
2421 $talkname=$wgLang->getNsText(NS_TALK); # use the shorter name
2422 global $wgDisableAnonTalk;
2423 if( 0 == $rc_user && $wgDisableAnonTalk ) {
2424 $userTalkLink = '';
2425 } else {
2426 $utns=$wgLang->getNsText(NS_USER_TALK);
2427 $userTalkLink= $this->makeLink($utns . ':'.$rc_user_text, $talkname );
2429 # Block link
2430 $blockLink='';
2431 if ( ( 0 == $rc_user ) && $wgUser->isSysop() ) {
2432 $blockLink = $this->makeKnownLink( $wgLang->specialPage(
2433 'Blockip' ), wfMsg( 'blocklink' ), 'ip='.$rc_user_text );
2436 if($blockLink) {
2437 if($userTalkLink) $userTalkLink .= ' | ';
2438 $userTalkLink .= $blockLink;
2440 if($userTalkLink) $s.=' ('.$userTalkLink.')';
2442 # Add comment
2443 if ( '' != $rc_comment && '*' != $rc_comment && $rc_type != RC_MOVE && $rc_type != RC_MOVE_OVER_REDIRECT ) {
2444 $rc_comment=$this->formatComment($rc_comment,$rc->getTitle());
2445 $s .= $wgLang->emphasize(' (' . $rc_comment . ')');
2447 $s .= "</li>\n";
2449 return $s;
2452 function recentChangesLineNew( &$baseRC, $watched = false ) {
2453 global $wgTitle, $wgLang, $wgUser, $wgRCSeconds;
2455 # Create a specialised object
2456 $rc = RCCacheEntry::newFromParent( $baseRC ) ;
2458 # Extract fields from DB into the function scope (rc_xxxx variables)
2459 extract( $rc->mAttribs );
2460 $curIdEq = 'curid=' . $rc_cur_id;
2462 # If it's a new day, add the headline and flush the cache
2463 $date = $wgLang->date( $rc_timestamp, true);
2464 $ret = '';
2465 if ( $date != $this->lastdate ) {
2466 # Process current cache
2467 $ret = $this->recentChangesBlock () ;
2468 $this->rc_cache = array() ;
2469 $ret .= "<h4>{$date}</h4>\n";
2470 $this->lastdate = $date;
2473 # Make article link
2474 if ( $rc_type == RC_MOVE || $rc_type == RC_MOVE_OVER_REDIRECT ) {
2475 $msg = ( $rc_type == RC_MOVE ) ? "1movedto2" : "1movedto2_redir";
2476 $clink = wfMsg( $msg, $this->makeKnownLinkObj( $rc->getTitle(), '', 'redirect=no' ),
2477 $this->makeKnownLinkObj( $rc->getMovedToTitle(), '' ) );
2478 } elseif( $rc_namespace == NS_SPECIAL && preg_match( '!^Log/(.*)$!', $rc_title, $matches ) ) {
2479 # Log updates, etc
2480 $logtype = $matches[1];
2481 $logname = LogPage::logName( $logtype );
2482 $clink = '(' . $this->makeKnownLinkObj( $rc->getTitle(), $logname ) . ')';
2483 } else {
2484 $clink = $this->makeKnownLinkObj( $rc->getTitle(), '' ) ;
2487 $time = $wgLang->time( $rc_timestamp, true, $wgRCSeconds );
2488 $rc->watched = $watched ;
2489 $rc->link = $clink ;
2490 $rc->timestamp = $time;
2492 # Make "cur" and "diff" links
2493 if ( ( $rc_type == RC_NEW && $rc_this_oldid == 0 ) || $rc_type == RC_LOG || $rc_type == RC_MOVE || $rc_type == RC_MOVE_OVER_REDIRECT ) {
2494 $curLink = wfMsg( 'cur' );
2495 $diffLink = wfMsg( 'diff' );
2496 } else {
2497 $query = $curIdEq.'&diff=0&oldid='.$rc_this_oldid;
2498 $aprops = ' tabindex="'.$baseRC->counter.'"';
2499 $curLink = $this->makeKnownLinkObj( $rc->getTitle(), wfMsg( 'cur' ), $query, '' ,'' , $aprops );
2500 $diffLink = $this->makeKnownLinkObj( $rc->getTitle(), wfMsg( 'diff'), $query, '' ,'' , $aprops );
2503 # Make "last" link
2504 $titleObj = $rc->getTitle();
2505 if ( $rc_last_oldid == 0 || $rc_type == RC_LOG || $rc_type == RC_MOVE || $rc_type == RC_MOVE_OVER_REDIRECT ) {
2506 $lastLink = wfMsg( 'last' );
2507 } else {
2508 $lastLink = $this->makeKnownLinkObj( $rc->getTitle(), wfMsg( 'last' ),
2509 $curIdEq.'&diff='.$rc_this_oldid.'&oldid='.$rc_last_oldid );
2512 # Make user link (or user contributions for unregistered users)
2513 if ( $rc_user == 0 ) {
2514 $userLink = $this->makeKnownLink( $wgLang->specialPage( 'Contributions' ),
2515 $rc_user_text, 'target=' . $rc_user_text );
2516 } else {
2517 $userLink = $this->makeLink( $wgLang->getNsText(
2518 Namespace::getUser() ) . ':'.$rc_user_text, $rc_user_text );
2521 $rc->userlink = $userLink;
2522 $rc->lastlink = $lastLink;
2523 $rc->curlink = $curLink;
2524 $rc->difflink = $diffLink;
2526 # Make user talk link
2527 $utns=$wgLang->getNsText(NS_USER_TALK);
2528 $talkname=$wgLang->getNsText(NS_TALK); # use the shorter name
2529 $userTalkLink= $this->makeLink($utns . ':'.$rc_user_text, $talkname );
2531 global $wgDisableAnonTalk;
2532 if ( ( 0 == $rc_user ) && $wgUser->isSysop() ) {
2533 $blockLink = $this->makeKnownLink( $wgLang->specialPage(
2534 'Blockip' ), wfMsg( 'blocklink' ), 'ip='.$rc_user_text );
2535 if( $wgDisableAnonTalk )
2536 $rc->usertalklink = ' ('.$blockLink.')';
2537 else
2538 $rc->usertalklink = ' ('.$userTalkLink.' | '.$blockLink.')';
2539 } else {
2540 if( $wgDisableAnonTalk && ($rc_user == 0) )
2541 $rc->usertalklink = '';
2542 else
2543 $rc->usertalklink = ' ('.$userTalkLink.')';
2546 # Put accumulated information into the cache, for later display
2547 # Page moves go on their own line
2548 $title = $rc->getTitle();
2549 $secureName = $title->getPrefixedDBkey();
2550 if ( $rc_type == RC_MOVE || $rc_type == RC_MOVE_OVER_REDIRECT ) {
2551 # Use an @ character to prevent collision with page names
2552 $this->rc_cache['@@' . ($this->rcMoveIndex++)] = array($rc);
2553 } else {
2554 if ( !isset ( $this->rc_cache[$secureName] ) ) $this->rc_cache[$secureName] = array() ;
2555 array_push ( $this->rc_cache[$secureName] , $rc ) ;
2557 return $ret;
2560 function endImageHistoryList() {
2561 $s = "</ul>\n";
2562 return $s;
2566 * This function is called by all recent changes variants, by the page history,
2567 * and by the user contributions list. It is responsible for formatting edit
2568 * comments. It escapes any HTML in the comment, but adds some CSS to format
2569 * auto-generated comments (from section editing) and formats [[wikilinks]].
2571 * The &$title parameter must be a title OBJECT. It is used to generate a
2572 * direct link to the section in the autocomment.
2573 * @author Erik Moeller <moeller@scireview.de>
2575 * Note: there's not always a title to pass to this function.
2576 * Since you can't set a default parameter for a reference, I've turned it
2577 * temporarily to a value pass. Should be adjusted further. --brion
2579 function formatComment($comment, $title = NULL) {
2580 global $wgLang;
2581 $comment = htmlspecialchars( $comment );
2583 # The pattern for autogen comments is / * foo * /, which makes for
2584 # some nasty regex.
2585 # We look for all comments, match any text before and after the comment,
2586 # add a separator where needed and format the comment itself with CSS
2587 while (preg_match('/(.*)\/\*\s*(.*?)\s*\*\/(.*)/', $comment,$match)) {
2588 $pre=$match[1];
2589 $auto=$match[2];
2590 $post=$match[3];
2591 $link='';
2592 if($title) {
2593 $section=$auto;
2595 # This is hackish but should work in most cases.
2596 $section=str_replace('[[','',$section);
2597 $section=str_replace(']]','',$section);
2598 $title->mFragment=$section;
2599 $link=$this->makeKnownLinkObj($title,wfMsg('sectionlink'));
2601 $sep='-';
2602 $auto=$link.$auto;
2603 if($pre) { $auto = $sep.' '.$auto; }
2604 if($post) { $auto .= ' '.$sep; }
2605 $auto='<span class="autocomment">'.$auto.'</span>';
2606 $comment=$pre.$auto.$post;
2609 # format regular and media links - all other wiki formatting
2610 # is ignored
2611 $medians = $wgLang->getNsText(Namespace::getMedia()).':';
2612 while(preg_match('/\[\[(.*?)(\|(.*?))*\]\](.*)$/',$comment,$match)) {
2613 # Handle link renaming [[foo|text]] will show link as "text"
2614 if( "" != $match[3] ) {
2615 $text = $match[3];
2616 } else {
2617 $text = $match[1];
2619 if( preg_match( '/^' . $medians . '(.*)$/i', $match[1], $submatch ) ) {
2620 # Media link; trail not supported.
2621 $linkRegexp = '/\[\[(.*?)\]\]/';
2622 $thelink = $this->makeMediaLink( $submatch[1], "", $text );
2623 } else {
2624 # Other kind of link
2625 if( preg_match( wfMsg( "linktrail" ), $match[4], $submatch ) ) {
2626 $trail = $submatch[1];
2627 } else {
2628 $trail = "";
2630 $linkRegexp = '/\[\[(.*?)\]\]' . preg_quote( $trail, '/' ) . '/';
2631 if ($match[1][0] == ':')
2632 $match[1] = substr($match[1], 1);
2633 $thelink = $this->makeLink( $match[1], $text, "", $trail );
2635 $comment = preg_replace( $linkRegexp, $thelink, $comment, 1 );
2637 return $comment;
2640 function imageHistoryLine( $iscur, $timestamp, $img, $user, $usertext, $size, $description ) {
2641 global $wgUser, $wgLang, $wgTitle;
2643 $datetime = $wgLang->timeanddate( $timestamp, true );
2644 $del = wfMsg( 'deleteimg' );
2645 $delall = wfMsg( 'deleteimgcompletely' );
2646 $cur = wfMsg( 'cur' );
2648 if ( $iscur ) {
2649 $url = Image::wfImageUrl( $img );
2650 $rlink = $cur;
2651 if ( $wgUser->isSysop() ) {
2652 $link = $wgTitle->escapeLocalURL( 'image=' . $wgTitle->getPartialURL() .
2653 '&action=delete' );
2654 $style = $this->getInternalLinkAttributes( $link, $delall );
2656 $dlink = '<a href="'.$link.'"'.$style.'>'.$delall.'</a>';
2657 } else {
2658 $dlink = $del;
2660 } else {
2661 $url = htmlspecialchars( wfImageArchiveUrl( $img ) );
2662 if( $wgUser->getID() != 0 && $wgTitle->userCanEdit() ) {
2663 $rlink = $this->makeKnownLink( $wgTitle->getPrefixedText(),
2664 wfMsg( 'revertimg' ), 'action=revert&oldimage=' .
2665 urlencode( $img ) );
2666 $dlink = $this->makeKnownLink( $wgTitle->getPrefixedText(),
2667 $del, 'action=delete&oldimage=' . urlencode( $img ) );
2668 } else {
2669 # Having live active links for non-logged in users
2670 # means that bots and spiders crawling our site can
2671 # inadvertently change content. Baaaad idea.
2672 $rlink = wfMsg( 'revertimg' );
2673 $dlink = $del;
2676 if ( 0 == $user ) {
2677 $userlink = $usertext;
2678 } else {
2679 $userlink = $this->makeLink( $wgLang->getNsText( Namespace::getUser() ) .
2680 ':'.$usertext, $usertext );
2682 $nbytes = wfMsg( 'nbytes', $size );
2683 $style = $this->getInternalLinkAttributes( $url, $datetime );
2685 $s = "<li> ({$dlink}) ({$rlink}) <a href=\"{$url}\"{$style}>{$datetime}</a>"
2686 . " . . {$userlink} ({$nbytes})";
2688 if ( '' != $description && '*' != $description ) {
2689 $sk=$wgUser->getSkin();
2690 $s .= $wgLang->emphasize(' (' . $sk->formatComment($description,$wgTitle) . ')');
2692 $s .= "</li>\n";
2693 return $s;
2696 function tocIndent($level) {
2697 return str_repeat( '<div class="tocindent">'."\n", $level>0 ? $level : 0 );
2700 function tocUnindent($level) {
2701 return str_repeat( "</div>\n", $level>0 ? $level : 0 );
2705 * parameter level defines if we are on an indentation level
2707 function tocLine( $anchor, $tocline, $level ) {
2708 $link = '<a href="#'.$anchor.'">'.$tocline.'</a><br />';
2709 if($level) {
2710 return $link."\n";
2711 } else {
2712 return '<div class="tocline">'.$link."</div>\n";
2717 function tocTable($toc) {
2718 # note to CSS fanatics: putting this in a div does not work -- div won't auto-expand
2719 # try min-width & co when somebody gets a chance
2720 $hideline = ' <script type="text/javascript">showTocToggle("' . addslashes( wfMsg('showtoc') ) . '","' . addslashes( wfMsg('hidetoc') ) . '")</script>';
2721 return
2722 '<table border="0" id="toc"><tr id="toctitle"><td align="center">'."\n".
2723 '<b>'.wfMsg('toc').'</b>' .
2724 $hideline .
2725 '</td></tr><tr id="tocinside"><td>'."\n".
2726 $toc."</td></tr></table>\n";
2730 * These two do not check for permissions: check $wgTitle->userCanEdit
2731 * before calling them
2733 function editSectionScriptForOther( $title, $section, $head ) {
2734 $ttl = Title::newFromText( $title );
2735 $url = $ttl->escapeLocalURL( 'action=edit&section='.$section );
2736 return '<span oncontextmenu=\'document.location="'.$url.'";return false;\'>'.$head.'</span>';
2739 function editSectionScript( $section, $head ) {
2740 global $wgTitle, $wgRequest;
2741 if( $wgRequest->getInt( 'oldid' ) && ( $wgRequest->getVal( 'diff' ) != '0' ) ) {
2742 return $head;
2744 $url = $wgTitle->escapeLocalURL( 'action=edit&section='.$section );
2745 return '<span oncontextmenu=\'document.location="'.$url.'";return false;\'>'.$head.'</span>';
2748 function editSectionLinkForOther( $title, $section ) {
2749 global $wgRequest;
2750 global $wgUser, $wgLang;
2752 $title = Title::newFromText($title);
2753 $editurl = '&section='.$section;
2754 $url = $this->makeKnownLink($title->getPrefixedText(),wfMsg('editsection'),'action=edit'.$editurl);
2756 if( $wgLang->isRTL() ) {
2757 $farside = 'left';
2758 $nearside = 'right';
2759 } else {
2760 $farside = 'right';
2761 $nearside = 'left';
2763 return "<div class=\"editsection\" style=\"float:$farside;margin-$nearside:5px;\">[".$url."]</div>";
2767 function editSectionLink( $section ) {
2768 global $wgRequest;
2769 global $wgTitle, $wgUser, $wgLang;
2771 if( $wgRequest->getInt( 'oldid' ) && ( $wgRequest->getVal( 'diff' ) != '0' ) ) {
2772 # Section edit links would be out of sync on an old page.
2773 # But, if we're diffing to the current page, they'll be
2774 # correct.
2775 return '';
2778 $editurl = '&section='.$section;
2779 $url = $this->makeKnownLink($wgTitle->getPrefixedText(),wfMsg('editsection'),'action=edit'.$editurl);
2781 if( $wgLang->isRTL() ) {
2782 $farside = 'left';
2783 $nearside = 'right';
2784 } else {
2785 $farside = 'right';
2786 $nearside = 'left';
2788 return "<div class=\"editsection\" style=\"float:$farside;margin-$nearside:5px;\">[".$url."]</div>";
2793 * This function is called by EditPage.php and shows a bulletin board style
2794 * toolbar for common editing functions. It can be disabled in the user
2795 * preferences.
2796 * The necessary JavaScript code can be found in style/wikibits.js.
2798 function getEditToolbar() {
2799 global $wgStylePath, $wgLang, $wgMimeType;
2802 * toolarray an array of arrays which each include the filename of
2803 * the button image (without path), the opening tag, the closing tag,
2804 * and optionally a sample text that is inserted between the two when no
2805 * selection is highlighted.
2806 * The tip text is shown when the user moves the mouse over the button.
2808 * Already here are accesskeys (key), which are not used yet until someone
2809 * can figure out a way to make them work in IE. However, we should make
2810 * sure these keys are not defined on the edit page.
2812 $toolarray=array(
2813 array( 'image'=>'button_bold.png',
2814 'open' => "\'\'\'",
2815 'close' => "\'\'\'",
2816 'sample'=> wfMsg('bold_sample'),
2817 'tip' => wfMsg('bold_tip'),
2818 'key' => 'B'
2820 array( 'image'=>'button_italic.png',
2821 'open' => "\'\'",
2822 'close' => "\'\'",
2823 'sample'=> wfMsg('italic_sample'),
2824 'tip' => wfMsg('italic_tip'),
2825 'key' => 'I'
2827 array( 'image'=>'button_link.png',
2828 'open' => '[[',
2829 'close' => ']]',
2830 'sample'=> wfMsg('link_sample'),
2831 'tip' => wfMsg('link_tip'),
2832 'key' => 'L'
2834 array( 'image'=>'button_extlink.png',
2835 'open' => '[',
2836 'close' => ']',
2837 'sample'=> wfMsg('extlink_sample'),
2838 'tip' => wfMsg('extlink_tip'),
2839 'key' => 'X'
2841 array( 'image'=>'button_headline.png',
2842 'open' => "\\n== ",
2843 'close' => " ==\\n",
2844 'sample'=> wfMsg('headline_sample'),
2845 'tip' => wfMsg('headline_tip'),
2846 'key' => 'H'
2848 array( 'image'=>'button_image.png',
2849 'open' => '[['.$wgLang->getNsText(NS_IMAGE).":",
2850 'close' => ']]',
2851 'sample'=> wfMsg('image_sample'),
2852 'tip' => wfMsg('image_tip'),
2853 'key' => 'D'
2855 array( 'image' => 'button_media.png',
2856 'open' => '[['.$wgLang->getNsText(NS_MEDIA).':',
2857 'close' => ']]',
2858 'sample'=> wfMsg('media_sample'),
2859 'tip' => wfMsg('media_tip'),
2860 'key' => 'M'
2862 array( 'image' => 'button_math.png',
2863 'open' => "\\<math\\>",
2864 'close' => "\\</math\\>",
2865 'sample'=> wfMsg('math_sample'),
2866 'tip' => wfMsg('math_tip'),
2867 'key' => 'C'
2869 array( 'image' => 'button_nowiki.png',
2870 'open' => "\\<nowiki\\>",
2871 'close' => "\\</nowiki\\>",
2872 'sample'=> wfMsg('nowiki_sample'),
2873 'tip' => wfMsg('nowiki_tip'),
2874 'key' => 'N'
2876 array( 'image' => 'button_sig.png',
2877 'open' => '--~~~~',
2878 'close' => '',
2879 'sample'=> '',
2880 'tip' => wfMsg('sig_tip'),
2881 'key' => 'Y'
2883 array( 'image' => 'button_hr.png',
2884 'open' => "\\n----\\n",
2885 'close' => '',
2886 'sample'=> '',
2887 'tip' => wfMsg('hr_tip'),
2888 'key' => 'R'
2891 $toolbar ="<script type='text/javascript'>\n/*<![CDATA[*/\n";
2893 $toolbar.="document.writeln(\"<div id='toolbar'>\");\n";
2894 foreach($toolarray as $tool) {
2896 $image=$wgStylePath.'/common/images/'.$tool['image'];
2897 $open=$tool['open'];
2898 $close=$tool['close'];
2899 $sample = addslashes( $tool['sample'] );
2901 // Note that we use the tip both for the ALT tag and the TITLE tag of the image.
2902 // Older browsers show a "speedtip" type message only for ALT.
2903 // Ideally these should be different, realistically they
2904 // probably don't need to be.
2905 $tip = addslashes( $tool['tip'] );
2907 #$key = $tool["key"];
2909 $toolbar.="addButton('$image','$tip','$open','$close','$sample');\n";
2912 $toolbar.="addInfobox('" . addslashes( wfMsg( "infobox" ) ) . "','" . addslashes(wfMsg("infobox_alert")) . "');\n";
2913 $toolbar.="document.writeln(\"</div>\");\n";
2915 $toolbar.="/*]]>*/\n</script>";
2916 return $toolbar;
2920 * @access public
2922 function suppressUrlExpansion() {
2923 return false;