Don't produce a title attribute for external links when the link text is
[lhc/web/wiklou.git] / includes / Skin.php
1 <?php
2
3 /**
4 *
5 * @package MediaWiki
6 */
7
8 /**
9 * This is not a valid entry point, perform no further processing unless MEDIAWIKI is defined
10 */
11 if( defined( "MEDIAWIKI" ) ) {
12
13 # See skin.doc
14 require_once( 'Image.php' );
15
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
19 #
20 /*
21 $wgValidSkinNames = array(
22 'standard' => 'Standard',
23 'nostalgia' => 'Nostalgia',
24 'cologneblue' => 'CologneBlue'
25 );
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';
34 }
35 */
36
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
40 #
41
42 $skinDir = dir($IP.'/skins');
43
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;
49 }
50 }
51 $skinDir->close();
52 unset($matches);
53
54 require_once( 'RecentChange.php' );
55
56 global $wgLinkHolders;
57 $wgLinkHolders = array(
58 'namespaces' => array(),
59 'dbkeys' => array(),
60 'queries' => array(),
61 'texts' => array(),
62 'titles' => array()
63 );
64
65 /**
66 * @todo document
67 * @package MediaWiki
68 */
69 class RCCacheEntry extends RecentChange
70 {
71 var $secureName, $link;
72 var $curlink , $difflink, $lastlink , $usertalklink , $versionlink ;
73 var $userlink, $timestamp, $watched;
74
75 function newFromParent( $rc )
76 {
77 $rc2 = new RCCacheEntry;
78 $rc2->mAttribs = $rc->mAttribs;
79 $rc2->mExtra = $rc->mExtra;
80 return $rc2;
81 }
82 } ;
83
84
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
90 */
91 class Skin {
92 /**#@+
93 * @access private
94 */
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 /**#@-*/
102
103 function Skin() {
104 global $wgUseOldExistenceCheck;
105 $postParseLinkColour = !$wgUseOldExistenceCheck;
106 $this->linktrail = wfMsg('linktrail');
107 }
108
109 function getSkinNames() {
110 global $wgValidSkinNames;
111 return $wgValidSkinNames;
112 }
113
114 function getStylesheet() {
115 return 'common/wikistandard.css';
116 }
117
118 function getSkinName() {
119 return 'standard';
120 }
121
122 /**
123 * Get/set accessor for delayed link colouring
124 */
125 function postParseLinkColour( $setting = NULL ) {
126 return wfSetVar( $this->postParseLinkColour, $setting );
127 }
128
129 function qbSetting() {
130 global $wgOut, $wgUser;
131
132 if ( $wgOut->isQuickbarSuppressed() ) { return 0; }
133 $q = $wgUser->getOption( 'quickbar' );
134 if ( '' == $q ) { $q = 0; }
135 return $q;
136 }
137
138 function initPage( &$out ) {
139 $fname = 'Skin::initPage';
140 wfProfileIn( $fname );
141
142 $out->addLink( array( 'rel' => 'shortcut icon', 'href' => '/favicon.ico' ) );
143
144 $this->addMetadataLinks($out);
145
146 wfProfileOut( $fname );
147 }
148
149 function addMetadataLinks( &$out ) {
150 global $wgTitle, $wgEnableDublinCoreRdf, $wgEnableCreativeCommonsRdf, $wgRdfMimeType, $action;
151 global $wgRightsPage, $wgRightsUrl;
152
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') ) );
160 }
161 if( $wgEnableDublinCoreRdf ) {
162 $out->addMetadataLink( array(
163 'title' => 'Dublin Core',
164 'type' => 'application/rdf+xml',
165 'href' => $wgTitle->getLocalURL( 'action=dublincore' ) ) );
166 }
167 }
168 $copyright = '';
169 if( $wgRightsPage ) {
170 $copy = Title::newFromText( $wgRightsPage );
171 if( $copy ) {
172 $copyright = $copy->getLocalURL();
173 }
174 }
175 if( !$copyright && $wgRightsUrl ) {
176 $copyright = $wgRightsUrl;
177 }
178 if( $copyright ) {
179 $out->addLink( array(
180 'rel' => 'copyright',
181 'href' => $copyright ) );
182 }
183 }
184
185 function outputPage( &$out ) {
186 global $wgDebugComments;
187
188 wfProfileIn( 'Skin::outputPage' );
189 $this->initPage( $out );
190 $out->out( $out->headElement() );
191
192 $out->out( "\n<body" );
193 $ops = $this->getBodyOptions();
194 foreach ( $ops as $name => $val ) {
195 $out->out( " $name='$val'" );
196 }
197 $out->out( ">\n" );
198 if ( $wgDebugComments ) {
199 $out->out( "<!-- Wiki debugging output:\n" .
200 $out->mDebugtext . "-->\n" );
201 }
202 $out->out( $this->beforeContent() );
203
204 $out->out( $out->mBodytext . "\n" );
205
206 $out->out( $this->afterContent() );
207
208 wfProfileClose();
209 $out->out( $out->reportTime() );
210
211 $out->out( "\n</body></html>" );
212 }
213
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";
221 }
222 return $r;
223 }
224
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";
238 }
239 }
240 $s .= $this->doGetUserStyles();
241 return $s."\n";
242 }
243
244 /**
245 * placeholder, returns generated js in monobook
246 */
247 function getUserJs() { return; }
248
249 /**
250 * Return html code that include User stylesheets
251 */
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;
260 }
261
262 /**
263 * Some styles that are set by user through the user settings interface.
264 */
265 function doGetUserStyles() {
266 global $wgUser, $wgLang;
267
268 $csspage = $wgLang->getNsText( NS_MEDIAWIKI ) . ':' . $this->getSkinName() . '.css';
269 $s = '@import "'.$this->makeUrl($csspage, 'action=raw&ctype=text/css')."\";\n";
270
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";
277 }
278 if ( 1 == $wgUser->getOption( 'highlightbroken' ) ) {
279 $s .= "a.new, #quickbar a.new { color: #CC2200; }\n";
280 }
281 if ( 1 == $wgUser->getOption( 'justify' ) ) {
282 $s .= "#article { text-align: justify; }\n";
283 }
284 return $s;
285 }
286
287 function getBodyOptions() {
288 global $wgUser, $wgTitle, $wgNamespaceBackgrounds, $wgOut, $wgRequest;
289
290 extract( $wgRequest->getValues( 'oldid', 'redirect', 'diff' ) );
291
292 if ( 0 != $wgTitle->getNamespace() ) {
293 $a = array( 'bgcolor' => '#ffffec' );
294 }
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}";
302 }
303 if ( !empty($oldid) && ! isset( $diff ) ) {
304 $oid = "&oldid={$oldid}";
305 }
306 $s = $wgTitle->getFullURL( "action=edit{$oid}{$red}" );
307 $s = 'document.location = "' .$s .'";';
308 $a += array ('ondblclick' => $s);
309
310 }
311 $a['onload'] = $wgOut->getOnloadHandler();
312 return $a;
313 }
314
315 function getExternalLinkAttributes( $link, $text, $class='' ) {
316 global $wgUser, $wgOut, $wgLang;
317
318 $same = ($link == $text);
319 $link = urldecode( $link );
320 $link = $wgLang->checkTitleEncoding( $link );
321 $link = str_replace( '_', ' ', $link );
322 $link = htmlspecialchars( $link );
323
324 $r = ($class != '') ? " class='$class'" : " class='external'";
325
326 if ( !$same && $wgUser->getOption( 'hover' ) ) {
327 $r .= " title=\"{$link}\"";
328 }
329 return $r;
330 }
331
332 function getInternalLinkAttributes( $link, $text, $broken = false ) {
333 global $wgUser, $wgOut;
334
335 $link = urldecode( $link );
336 $link = str_replace( '_', ' ', $link );
337 $link = htmlspecialchars( $link );
338
339 if ( $broken == 'stub' ) {
340 $r = ' class="stub"';
341 } else if ( $broken == 'yes' ) {
342 $r = ' class="new"';
343 } else {
344 $r = '';
345 }
346
347 if ( 1 == $wgUser->getOption( 'hover' ) ) {
348 $r .= " title=\"{$link}\"";
349 }
350 return $r;
351 }
352
353 /**
354 * @param bool $broken
355 */
356 function getInternalLinkAttributesObj( &$nt, $text, $broken = false ) {
357 global $wgUser, $wgOut;
358
359 if ( $broken == 'stub' ) {
360 $r = ' class="stub"';
361 } else if ( $broken == 'yes' ) {
362 $r = ' class="new"';
363 } else {
364 $r = '';
365 }
366
367 if ( 1 == $wgUser->getOption( 'hover' ) ) {
368 $r .= ' title="' . $nt->getEscapedText() . '"';
369 }
370 return $r;
371 }
372
373 /**
374 * URL to the logo
375 */
376 function getLogo() {
377 global $wgLogo;
378 return $wgLogo;
379 }
380
381 /**
382 * This will be called immediately after the <body> tag. Split into
383 * two functions to make it easier to subclass.
384 */
385 function beforeContent() {
386 global $wgUser, $wgOut;
387
388 return $this->doBeforeContent();
389 }
390
391 function doBeforeContent() {
392 global $wgUser, $wgOut, $wgTitle, $wgLang, $wgSiteNotice;
393 $fname = 'Skin::doBeforeContent';
394 wfProfileIn( $fname );
395
396 $s = '';
397 $qb = $this->qbSetting();
398
399 if( $langlinks = $this->otherLanguages() ) {
400 $rows = 2;
401 $borderhack = '';
402 } else {
403 $rows = 1;
404 $langlinks = false;
405 $borderhack = 'class="top"';
406 }
407
408 $s .= "\n<div id='content'>\n<div id='topbar'>\n" .
409 "<table border='0' cellspacing='0' width='98%'>\n<tr>\n";
410
411 $shove = ($qb != 0);
412 $left = ($qb == 1 || $qb == 3);
413 if($wgLang->isRTL()) $left = !$left;
414
415 if ( !$shove ) {
416 $s .= "<td class='top' align='left' valign='top' rowspan='{$rows}'>\n" .
417 $this->logoText() . '</td>';
418 } elseif( $left ) {
419 $s .= $this->getQuickbarCompensator( $rows );
420 }
421 $l = $wgLang->isRTL() ? 'right' : 'left';
422 $s .= "<td {$borderhack} align='$l' valign='top'>\n";
423
424 $s .= $this->topLinks() ;
425 $s .= "<p class='subtitle'>" . $this->pageTitleLinks() . "</p>\n";
426
427 $r = $wgLang->isRTL() ? "left" : "right";
428 $s .= "</td>\n<td {$borderhack} valign='top' align='$r' nowrap='nowrap'>";
429 $s .= $this->nameAndLogin();
430 $s .= "\n<br />" . $this->searchForm() . "</td>";
431
432 if ( $langlinks ) {
433 $s .= "</tr>\n<tr>\n<td class='top' colspan=\"2\">$langlinks</td>\n";
434 }
435
436 if ( $shove && !$left ) { # Right
437 $s .= $this->getQuickbarCompensator( $rows );
438 }
439 $s .= "</tr>\n</table>\n</div>\n";
440 $s .= "\n<div id='article'>\n";
441
442 if( $wgSiteNotice ) {
443 $s .= "\n<div id='siteNotice'>$wgSiteNotice</div>\n";
444 }
445 $s .= $this->pageTitle();
446 $s .= $this->pageSubtitle() ;
447 $s .= $this->getCategories();
448 wfProfileOut( $fname );
449 return $s;
450 }
451
452 function getCategoryLinks () {
453 global $wgOut, $wgTitle, $wgUser, $wgParser;
454 global $wgUseCategoryMagic, $wgUseCategoryBrowser, $wgLang;
455
456 if( !$wgUseCategoryMagic ) return '' ;
457 if( count( $wgOut->mCategoryLinks ) == 0 ) return '';
458
459 # Taken out so that they will be displayed in previews -- TS
460 #if( !$wgOut->isArticle() ) return '';
461
462 $t = implode ( ' | ' , $wgOut->mCategoryLinks ) ;
463 $s = $this->makeKnownLink( 'Special:Categories',
464 wfMsg( 'categories' ), 'article=' . urlencode( $wgTitle->getPrefixedDBkey() ) )
465 . ': ' . $t;
466
467 # optional 'dmoz-like' category browser. Will be shown under the list
468 # of categories an article belong to
469 if($wgUseCategoryBrowser) {
470 $s .= '<br/><hr/>';
471
472 # get a big array of the parents tree
473 $parenttree = $wgTitle->getCategorieBrowser();
474
475 # Render the array as a serie of links
476 function walkThrough ($tree) {
477 global $wgUser;
478 $sk = $wgUser->getSkin();
479 $return = '';
480 foreach($tree as $element => $parent) {
481 if(empty($parent)) {
482 # element start a new list
483 $return .= '<br />';
484 } else {
485 # grab the others elements
486 $return .= walkThrough($parent);
487 }
488 # add our current element to the list
489 $eltitle = Title::NewFromText($element);
490 # FIXME : should be makeLink() [AV]
491 $return .= $sk->makeKnownLink($element, $eltitle->getText()).' &gt; ';
492 }
493 return $return;
494 }
495
496 $s .= walkThrough($parenttree);
497 }
498
499 return $s;
500 }
501
502 function getCategories() {
503 $catlinks=$this->getCategoryLinks();
504 if(!empty($catlinks)) {
505 return "<p class='catlinks'>{$catlinks}</p>";
506 }
507 }
508
509 function getQuickbarCompensator( $rows = 1 ) {
510 return "<td width='152' rowspan='{$rows}'>&nbsp;</td>";
511 }
512
513 # This gets called immediately before the </body> tag.
514 #
515 function afterContent() {
516 global $wgUser, $wgOut, $wgServer;
517 global $wgTitle, $wgLang;
518
519 $printfooter = "<div class=\"printfooter\">\n" . $this->printFooter() . "</div>\n";
520 return $printfooter . $this->doAfterContent();
521 }
522
523 function printSource() {
524 global $wgTitle;
525 $url = htmlspecialchars( $wgTitle->getFullURL() );
526 return wfMsg( "retrievedfrom", "<a href=\"$url\">$url</a>" );
527 }
528
529 function printFooter() {
530 return "<p>" . $this->printSource() .
531 "</p>\n\n<p>" . $this->pageStats() . "</p>\n";
532 }
533
534 function doAfterContent() {
535 global $wgUser, $wgOut, $wgLang;
536 $fname = 'Skin::doAfterContent';
537 wfProfileIn( $fname );
538 wfProfileIn( $fname.'-1' );
539
540 $s = "\n</div><br style=\"clear:both\" />\n";
541 $s .= "\n<div id='footer'>";
542 $s .= '<table border="0" cellspacing="0"><tr>';
543
544 wfProfileOut( $fname.'-1' );
545 wfProfileIn( $fname.'-2' );
546
547 $qb = $this->qbSetting();
548 $shove = ($qb != 0);
549 $left = ($qb == 1 || $qb == 3);
550 if($wgLang->isRTL()) $left = !$left;
551
552 if ( $shove && $left ) { # Left
553 $s .= $this->getQuickbarCompensator();
554 }
555 wfProfileOut( $fname.'-2' );
556 wfProfileIn( $fname.'-3' );
557 $l = $wgLang->isRTL() ? 'right' : 'left';
558 $s .= "<td class='bottom' align='$l' valign='top'>";
559
560 $s .= $this->bottomLinks();
561 $s .= "\n<br />" . $this->mainPageLink()
562 . ' | ' . $this->aboutLink()
563 . ' | ' . $this->specialLink( 'recentchanges' )
564 . ' | ' . $this->searchForm()
565 . '<br /><span id="pagestats">' . $this->pageStats() . '</span>';
566
567 $s .= "</td>";
568 if ( $shove && !$left ) { # Right
569 $s .= $this->getQuickbarCompensator();
570 }
571 $s .= "</tr></table>\n</div>\n</div>\n";
572
573 wfProfileOut( $fname.'-3' );
574 wfProfileIn( $fname.'-4' );
575 if ( 0 != $qb ) { $s .= $this->quickBar(); }
576 wfProfileOut( $fname.'-4' );
577 wfProfileOut( $fname );
578 return $s;
579 }
580
581 function pageTitleLinks() {
582 global $wgOut, $wgTitle, $wgUser, $wgLang, $wgUseApproval, $wgRequest;
583
584 extract( $wgRequest->getValues( 'oldid', 'diff' ) );
585 $action = $wgRequest->getText( 'action' );
586
587 $s = $this->printableLink();
588 if ( wfMsg ( 'disclaimers' ) != '-' ) $s .= ' | ' . $this->makeKnownLink( wfMsg( 'disclaimerpage' ), wfMsg( 'disclaimers' ) ) ;
589
590 if ( $wgOut->isArticleRelated() ) {
591 if ( $wgTitle->getNamespace() == Namespace::getImage() ) {
592 $name = $wgTitle->getDBkey();
593 $link = htmlspecialchars( Image::wfImageUrl( $name ) );
594 $style = $this->getInternalLinkAttributes( $link, $name );
595 $s .= " | <a href=\"{$link}\"{$style}>{$name}</a>";
596 }
597 # This will show the "Approve" link if $wgUseApproval=true;
598 if ( isset ( $wgUseApproval ) && $wgUseApproval )
599 {
600 $t = $wgTitle->getDBkey();
601 $name = 'Approve this article' ;
602 $link = "http://test.wikipedia.org/w/magnus/wiki.phtml?title={$t}&action=submit&doit=1" ;
603 #htmlspecialchars( wfImageUrl( $name ) );
604 $style = $this->getExternalLinkAttributes( $link, $name );
605 $s .= " | <a href=\"{$link}\"{$style}>{$name}</a>" ;
606 }
607 }
608 if ( 'history' == $action || isset( $diff ) || isset( $oldid ) ) {
609 $s .= ' | ' . $this->makeKnownLink( $wgTitle->getPrefixedText(),
610 wfMsg( 'currentrev' ) );
611 }
612
613 if ( $wgUser->getNewtalk() ) {
614 # do not show "You have new messages" text when we are viewing our
615 # own talk page
616
617 if(!(strcmp($wgTitle->getText(),$wgUser->getName()) == 0 &&
618 $wgTitle->getNamespace()==Namespace::getTalk(Namespace::getUser()))) {
619 $n =$wgUser->getName();
620 $tl = $this->makeKnownLink( $wgLang->getNsText(
621 Namespace::getTalk( Namespace::getUser() ) ) . ":{$n}",
622 wfMsg('newmessageslink') );
623 $s.= ' | <strong>'. wfMsg( 'newmessages', $tl ) . '</strong>';
624 # disable caching
625 $wgOut->setSquidMaxage(0);
626 }
627 }
628
629 $undelete = $this->getUndeleteLink();
630 if( !empty( $undelete ) ) {
631 $s .= ' | '.$undelete;
632 }
633 return $s;
634 }
635
636 function getUndeleteLink() {
637 global $wgUser, $wgTitle, $wgLang, $action;
638 if( $wgUser->isSysop() &&
639 (($wgTitle->getArticleId() == 0) || ($action == "history")) &&
640 ($n = $wgTitle->isDeleted() ) ) {
641 return wfMsg( 'thisisdeleted',
642 $this->makeKnownLink(
643 $wgLang->SpecialPage( 'Undelete/' . $wgTitle->getPrefixedDBkey() ),
644 wfMsg( 'restorelink', $n ) ) );
645 }
646 return '';
647 }
648
649 function printableLink() {
650 global $wgOut, $wgFeedClasses, $wgRequest;
651
652 $baseurl = $_SERVER['REQUEST_URI'];
653 if( strpos( '?', $baseurl ) == false ) {
654 $baseurl .= '?';
655 } else {
656 $baseurl .= '&';
657 }
658 $baseurl = htmlspecialchars( $baseurl );
659 $printurl = $wgRequest->escapeAppendQuery( 'printable=yes' );
660
661 $s = "<a href=\"$printurl\">" . wfMsg( 'printableversion' ) . '</a>';
662 if( $wgOut->isSyndicated() ) {
663 foreach( $wgFeedClasses as $format => $class ) {
664 $feedurl = $wgRequest->escapeAppendQuery( "feed=$format" );
665 $s .= " | <a href=\"$feedurl\">{$format}</a>";
666 }
667 }
668 return $s;
669 }
670
671 function pageTitle() {
672 global $wgOut, $wgTitle, $wgUser;
673
674 $s = '<h1 class="pagetitle">' . htmlspecialchars( $wgOut->getPageTitle() ) . '</h1>';
675 if($wgUser->getOption( 'editsectiononrightclick' ) && $wgTitle->userCanEdit()) { $s=$this->editSectionScript(0,$s);}
676 return $s;
677 }
678
679 function pageSubtitle() {
680 global $wgOut;
681
682 $sub = $wgOut->getSubtitle();
683 if ( '' == $sub ) {
684 global $wgExtraSubtitle;
685 $sub = wfMsg( 'tagline' ) . $wgExtraSubtitle;
686 }
687 $subpages = $this->subPageSubtitle();
688 $sub .= !empty($subpages)?"</p><p class='subpages'>$subpages":'';
689 $s = "<p class='subtitle'>{$sub}</p>\n";
690 return $s;
691 }
692
693 function subPageSubtitle() {
694 global $wgOut,$wgTitle,$wgNamespacesWithSubpages;
695 $subpages = '';
696 if($wgOut->isArticle() && !empty($wgNamespacesWithSubpages[$wgTitle->getNamespace()])) {
697 $ptext=$wgTitle->getPrefixedText();
698 if(preg_match('/\//',$ptext)) {
699 $links = explode('/',$ptext);
700 $c = 0;
701 $growinglink = '';
702 foreach($links as $link) {
703 $c++;
704 if ($c<count($links)) {
705 $growinglink .= $link;
706 $getlink = $this->makeLink( $growinglink, $link );
707 if(preg_match('/class="new"/i',$getlink)) { break; } # this is a hack, but it saves time
708 if ($c>1) {
709 $subpages .= ' | ';
710 } else {
711 $subpages .= '&lt; ';
712 }
713 $subpages .= $getlink;
714 $growinglink .= '/';
715 }
716 }
717 }
718 }
719 return $subpages;
720 }
721
722 function nameAndLogin() {
723 global $wgUser, $wgTitle, $wgLang, $wgShowIPinHeader, $wgIP;
724
725 $li = $wgLang->specialPage( 'Userlogin' );
726 $lo = $wgLang->specialPage( 'Userlogout' );
727
728 $s = '';
729 if ( 0 == $wgUser->getID() ) {
730 if( $wgShowIPinHeader && isset( $_COOKIE[ini_get('session.name')] ) ) {
731 $n = $wgIP;
732
733 $tl = $this->makeKnownLink( $wgLang->getNsText(
734 Namespace::getTalk( Namespace::getUser() ) ) . ":{$n}",
735 $wgLang->getNsText( Namespace::getTalk( 0 ) ) );
736
737 $s .= $n . ' ('.$tl.')';
738 } else {
739 $s .= wfMsg('notloggedin');
740 }
741
742 $rt = $wgTitle->getPrefixedURL();
743 if ( 0 == strcasecmp( urlencode( $lo ), $rt ) ) {
744 $q = '';
745 } else { $q = "returnto={$rt}"; }
746
747 $s .= "\n<br />" . $this->makeKnownLink( $li,
748 wfMsg( 'login' ), $q );
749 } else {
750 $n = $wgUser->getName();
751 $rt = $wgTitle->getPrefixedURL();
752 $tl = $this->makeKnownLink( $wgLang->getNsText(
753 Namespace::getTalk( Namespace::getUser() ) ) . ":{$n}",
754 $wgLang->getNsText( Namespace::getTalk( 0 ) ) );
755
756 $tl = " ({$tl})";
757
758 $s .= $this->makeKnownLink( $wgLang->getNsText(
759 Namespace::getUser() ) . ":{$n}", $n ) . "{$tl}<br />" .
760 $this->makeKnownLink( $lo, wfMsg( 'logout' ),
761 "returnto={$rt}" ) . ' | ' .
762 $this->specialLink( 'preferences' );
763 }
764 $s .= ' | ' . $this->makeKnownLink( wfMsg( 'helppage' ),
765 wfMsg( 'help' ) );
766
767 return $s;
768 }
769
770 function getSearchLink() {
771 $searchPage =& Title::makeTitle( NS_SPECIAL, 'Search' );
772 return $searchPage->getLocalURL();
773 }
774
775 function escapeSearchLink() {
776 return htmlspecialchars( $this->getSearchLink() );
777 }
778
779 function searchForm() {
780 global $wgRequest;
781 $search = $wgRequest->getText( 'search' );
782
783 $s = '<form name="search" class="inline" method="post" action="'
784 . $this->escapeSearchLink() . "\">\n"
785 . '<input type="text" name="search" size="19" value="'
786 . htmlspecialchars(substr($search,0,256)) . "\" />\n"
787 . '<input type="submit" name="go" value="' . wfMsg ('go') . '" />&nbsp;'
788 . '<input type="submit" name="fulltext" value="' . wfMsg ('search') . "\" />\n</form>";
789
790 return $s;
791 }
792
793 function topLinks() {
794 global $wgOut;
795 $sep = " |\n";
796
797 $s = $this->mainPageLink() . $sep
798 . $this->specialLink( 'recentchanges' );
799
800 if ( $wgOut->isArticleRelated() ) {
801 $s .= $sep . $this->editThisPage()
802 . $sep . $this->historyLink();
803 }
804 # Many people don't like this dropdown box
805 #$s .= $sep . $this->specialPagesList();
806
807 return $s;
808 }
809
810 function bottomLinks() {
811 global $wgOut, $wgUser, $wgTitle;
812 $sep = " |\n";
813
814 $s = '';
815 if ( $wgOut->isArticleRelated() ) {
816 $s .= '<strong>' . $this->editThisPage() . '</strong>';
817 if ( 0 != $wgUser->getID() ) {
818 $s .= $sep . $this->watchThisPage();
819 }
820 $s .= $sep . $this->talkLink()
821 . $sep . $this->historyLink()
822 . $sep . $this->whatLinksHere()
823 . $sep . $this->watchPageLinksLink();
824
825 if ( $wgTitle->getNamespace() == Namespace::getUser()
826 || $wgTitle->getNamespace() == Namespace::getTalk(Namespace::getUser()) )
827
828 {
829 $id=User::idFromName($wgTitle->getText());
830 $ip=User::isIP($wgTitle->getText());
831
832 if($id || $ip) { # both anons and non-anons have contri list
833 $s .= $sep . $this->userContribsLink();
834 }
835 if ( 0 != $wgUser->getID() ) { # show only to signed in users
836 if($id) { # can only email non-anons
837 $s .= $sep . $this->emailUserLink();
838 }
839 }
840 }
841 if ( $wgUser->isSysop() && $wgTitle->getArticleId() ) {
842 $s .= "\n<br />" . $this->deleteThisPage() .
843 $sep . $this->protectThisPage() .
844 $sep . $this->moveThisPage();
845 }
846 $s .= "<br />\n" . $this->otherLanguages();
847 }
848 return $s;
849 }
850
851 function pageStats() {
852 global $wgOut, $wgLang, $wgArticle, $wgRequest;
853 global $wgDisableCounters, $wgMaxCredits, $wgShowCreditsIfMax;
854
855 extract( $wgRequest->getValues( 'oldid', 'diff' ) );
856 if ( ! $wgOut->isArticle() ) { return ''; }
857 if ( isset( $oldid ) || isset( $diff ) ) { return ''; }
858 if ( 0 == $wgArticle->getID() ) { return ''; }
859
860 $s = '';
861 if ( !$wgDisableCounters ) {
862 $count = $wgLang->formatNum( $wgArticle->getCount() );
863 if ( $count ) {
864 $s = wfMsg( 'viewcount', $count );
865 }
866 }
867
868 if (isset($wgMaxCredits) && $wgMaxCredits != 0) {
869 require_once("Credits.php");
870 $s .= ' ' . getCredits($wgArticle, $wgMaxCredits, $wgShowCreditsIfMax);
871 } else {
872 $s .= $this->lastModified();
873 }
874
875 return $s . ' ' . $this->getCopyright();
876 }
877
878 function getCopyright() {
879 global $wgRightsPage, $wgRightsUrl, $wgRightsText, $wgRequest;
880
881
882 $oldid = $wgRequest->getVal( 'oldid' );
883 $diff = $wgRequest->getVal( 'diff' );
884
885 if ( !is_null( $oldid ) && is_null( $diff ) && wfMsg( 'history_copyright' ) !== '-' ) {
886 $msg = 'history_copyright';
887 } else {
888 $msg = 'copyright';
889 }
890
891 $out = '';
892 if( $wgRightsPage ) {
893 $link = $this->makeKnownLink( $wgRightsPage, $wgRightsText );
894 } elseif( $wgRightsUrl ) {
895 $link = $this->makeExternalLink( $wgRightsUrl, $wgRightsText );
896 } else {
897 # Give up now
898 return $out;
899 }
900 $out .= wfMsg( $msg, $link );
901 return $out;
902 }
903
904 function getCopyrightIcon() {
905 global $wgRightsPage, $wgRightsUrl, $wgRightsText, $wgRightsIcon;
906 $out = '';
907 if( $wgRightsIcon ) {
908 $icon = htmlspecialchars( $wgRightsIcon );
909 if( $wgRightsUrl ) {
910 $url = htmlspecialchars( $wgRightsUrl );
911 $out .= '<a href="'.$url.'">';
912 }
913 $text = htmlspecialchars( $wgRightsText );
914 $out .= "<img src=\"$icon\" alt='$text' />";
915 if( $wgRightsUrl ) {
916 $out .= '</a>';
917 }
918 }
919 return $out;
920 }
921
922 function getPoweredBy() {
923 global $wgStylePath;
924 $url = htmlspecialchars( "$wgStylePath/common/images/poweredby_mediawiki_88x31.png" );
925 $img = '<a href="http://www.mediawiki.org/"><img src="'.$url.'" alt="MediaWiki" /></a>';
926 return $img;
927 }
928
929 function lastModified() {
930 global $wgLang, $wgArticle;
931
932 $timestamp = $wgArticle->getTimestamp();
933 if ( $timestamp ) {
934 $d = $wgLang->timeanddate( $wgArticle->getTimestamp(), true );
935 $s = ' ' . wfMsg( 'lastmodified', $d );
936 } else {
937 $s = '';
938 }
939 return $s;
940 }
941
942 function logoText( $align = '' ) {
943 if ( '' != $align ) { $a = " align='{$align}'"; }
944 else { $a = ''; }
945
946 $mp = wfMsg( 'mainpage' );
947 $titleObj = Title::newFromText( $mp );
948 if ( is_object( $titleObj ) ) {
949 $url = $titleObj->escapeLocalURL();
950 } else {
951 $url = '';
952 }
953
954 $logourl = $this->getLogo();
955 $s = "<a href='{$url}'><img{$a} src='{$logourl}' alt='[{$mp}]' /></a>";
956 return $s;
957 }
958
959 function quickBar() {
960 global $wgOut, $wgTitle, $wgUser, $wgRequest, $wgLang;
961 global $wgDisableUploads, $wgRemoteUploads;
962
963 $fname = 'Skin::quickBar';
964 wfProfileIn( $fname );
965
966 $action = $wgRequest->getText( 'action' );
967 $wpPreview = $wgRequest->getBool( 'wpPreview' );
968 $tns=$wgTitle->getNamespace();
969
970 $s = "\n<div id='quickbar'>";
971 $s .= "\n" . $this->logoText() . "\n<hr class='sep' />";
972
973 $sep = "\n<br />";
974 $s .= $this->mainPageLink()
975 . $sep . $this->specialLink( 'recentchanges' )
976 . $sep . $this->specialLink( 'randompage' );
977 if ($wgUser->getID()) {
978 $s.= $sep . $this->specialLink( 'watchlist' ) ;
979 $s .= $sep .$this->makeKnownLink( $wgLang->specialPage( 'Contributions' ),
980 wfMsg( 'mycontris' ), 'target=' . wfUrlencode($wgUser->getName() ) );
981
982 }
983 // only show watchlist link if logged in
984 if ( wfMsg ( 'currentevents' ) != '-' ) $s .= $sep . $this->makeKnownLink( wfMsg( 'currentevents' ), '' ) ;
985 $s .= "\n<br /><hr class='sep' />";
986 $articleExists = $wgTitle->getArticleId();
987 if ( $wgOut->isArticle() || $action =='edit' || $action =='history' || $wpPreview) {
988 if($wgOut->isArticle()) {
989 $s .= '<strong>' . $this->editThisPage() . '</strong>';
990 } else { # backlink to the article in edit or history mode
991 if($articleExists){ # no backlink if no article
992 switch($tns) {
993 case 0:
994 $text = wfMsg('articlepage');
995 break;
996 case 1:
997 $text = wfMsg('viewtalkpage');
998 break;
999 case 2:
1000 $text = wfMsg('userpage');
1001 break;
1002 case 3:
1003 $text = wfMsg('viewtalkpage');
1004 break;
1005 case 4:
1006 $text = wfMsg('wikipediapage');
1007 break;
1008 case 5:
1009 $text = wfMsg('viewtalkpage');
1010 break;
1011 case 6:
1012 $text = wfMsg('imagepage');
1013 break;
1014 case 7:
1015 $text = wfMsg('viewtalkpage');
1016 break;
1017 default:
1018 $text= wfMsg('articlepage');
1019 }
1020
1021 $link = $wgTitle->getText();
1022 if ($nstext = $wgLang->getNsText($tns) ) { # add namespace if necessary
1023 $link = $nstext . ':' . $link ;
1024 }
1025
1026 $s .= $this->makeLink( $link, $text );
1027 } elseif( $wgTitle->getNamespace() != Namespace::getSpecial() ) {
1028 # we just throw in a "New page" text to tell the user that he's in edit mode,
1029 # and to avoid messing with the separator that is prepended to the next item
1030 $s .= '<strong>' . wfMsg('newpage') . '</strong>';
1031 }
1032
1033 }
1034
1035
1036 if( $tns%2 && $action!='edit' && !$wpPreview) {
1037 $s.= '<br />'.$this->makeKnownLink($wgTitle->getPrefixedText(),wfMsg('postcomment'),'action=edit&section=new');
1038 }
1039
1040 /*
1041 watching could cause problems in edit mode:
1042 if user edits article, then loads "watch this article" in background and then saves
1043 article with "Watch this article" checkbox disabled, the article is transparently
1044 unwatched. Therefore we do not show the "Watch this page" link in edit mode
1045 */
1046 if ( 0 != $wgUser->getID() && $articleExists) {
1047 if($action!='edit' && $action != 'submit' )
1048 {
1049 $s .= $sep . $this->watchThisPage();
1050 }
1051 if ( $wgTitle->userCanEdit() )
1052 $s .= $sep . $this->moveThisPage();
1053 }
1054 if ( $wgUser->isSysop() and $articleExists ) {
1055 $s .= $sep . $this->deleteThisPage() .
1056 $sep . $this->protectThisPage();
1057 }
1058 $s .= $sep . $this->talkLink();
1059 if ($articleExists && $action !='history') {
1060 $s .= $sep . $this->historyLink();
1061 }
1062 $s.=$sep . $this->whatLinksHere();
1063
1064 if($wgOut->isArticleRelated()) {
1065 $s .= $sep . $this->watchPageLinksLink();
1066 }
1067
1068 if ( Namespace::getUser() == $wgTitle->getNamespace()
1069 || $wgTitle->getNamespace() == Namespace::getTalk(Namespace::getUser())
1070 ) {
1071
1072 $id=User::idFromName($wgTitle->getText());
1073 $ip=User::isIP($wgTitle->getText());
1074
1075 if($id||$ip) {
1076 $s .= $sep . $this->userContribsLink();
1077 }
1078 if ( 0 != $wgUser->getID() ) {
1079 if($id) { # can only email real users
1080 $s .= $sep . $this->emailUserLink();
1081 }
1082 }
1083 }
1084 $s .= "\n<br /><hr class='sep' />";
1085 }
1086
1087 if ( 0 != $wgUser->getID() && ( !$wgDisableUploads || $wgRemoteUploads ) ) {
1088 $s .= $this->specialLink( 'upload' ) . $sep;
1089 }
1090 $s .= $this->specialLink( 'specialpages' )
1091 . $sep . $this->bugReportsLink();
1092
1093 global $wgSiteSupportPage;
1094 if( $wgSiteSupportPage ) {
1095 $s .= "\n<br /><a href=\"" . htmlspecialchars( $wgSiteSupportPage ) .
1096 '" class="internal">' . wfMsg( 'sitesupport' ) . '</a>';
1097 }
1098
1099 $s .= "\n<br /></div>\n";
1100 wfProfileOut( $fname );
1101 return $s;
1102 }
1103
1104 function specialPagesList() {
1105 global $wgUser, $wgOut, $wgLang, $wgServer, $wgRedirectScript;
1106 require_once('SpecialPage.php');
1107 $a = array();
1108 $pages = SpecialPage::getPages();
1109
1110 foreach ( $pages[''] as $name => $page ) {
1111 $a[$name] = $page->getDescription();
1112 }
1113 if ( $wgUser->isSysop() )
1114 {
1115 foreach ( $pages['sysop'] as $name => $page ) {
1116 $a[$name] = $page->getDescription();
1117 }
1118 }
1119 if ( $wgUser->isDeveloper() )
1120 {
1121 foreach ( $pages['developer'] as $name => $page ) {
1122 $a[$name] = $page->getDescription() ;
1123 }
1124 }
1125 $go = wfMsg( 'go' );
1126 $sp = wfMsg( 'specialpages' );
1127 $spp = $wgLang->specialPage( 'Specialpages' );
1128
1129 $s = '<form id="specialpages" method="get" class="inline" ' .
1130 'action="' . htmlspecialchars( "{$wgServer}{$wgRedirectScript}" ) . "\">\n";
1131 $s .= "<select name=\"wpDropdown\">\n";
1132 $s .= "<option value=\"{$spp}\">{$sp}</option>\n";
1133
1134 foreach ( $a as $name => $desc ) {
1135 $p = $wgLang->specialPage( $name );
1136 $s .= "<option value=\"{$p}\">{$desc}</option>\n";
1137 }
1138 $s .= "</select>\n";
1139 $s .= "<input type='submit' value=\"{$go}\" name='redirect' />\n";
1140 $s .= "</form>\n";
1141 return $s;
1142 }
1143
1144 function mainPageLink() {
1145 $mp = wfMsg( 'mainpage' );
1146 $s = $this->makeKnownLink( $mp, $mp );
1147 return $s;
1148 }
1149
1150 function copyrightLink() {
1151 $s = $this->makeKnownLink( wfMsg( 'copyrightpage' ),
1152 wfMsg( 'copyrightpagename' ) );
1153 return $s;
1154 }
1155
1156 function aboutLink() {
1157 $s = $this->makeKnownLink( wfMsg( 'aboutpage' ),
1158 wfMsg( 'aboutsite' ) );
1159 return $s;
1160 }
1161
1162
1163 function disclaimerLink() {
1164 $s = $this->makeKnownLink( wfMsg( 'disclaimerpage' ),
1165 wfMsg( 'disclaimers' ) );
1166 return $s;
1167 }
1168
1169 function editThisPage() {
1170 global $wgOut, $wgTitle, $wgRequest;
1171
1172 $oldid = $wgRequest->getVal( 'oldid' );
1173 $diff = $wgRequest->getVal( 'diff' );
1174 $redirect = $wgRequest->getVal( 'redirect' );
1175
1176 if ( ! $wgOut->isArticleRelated() ) {
1177 $s = wfMsg( 'protectedpage' );
1178 } else {
1179 $n = $wgTitle->getPrefixedText();
1180 if ( $wgTitle->userCanEdit() ) {
1181 $t = wfMsg( 'editthispage' );
1182 } else {
1183 #$t = wfMsg( "protectedpage" );
1184 $t = wfMsg( 'viewsource' );
1185 }
1186 $oid = $red = '';
1187
1188 if ( !is_null( $redirect ) ) { $red = "&redirect={$redirect}"; }
1189 if ( $oldid && ! isset( $diff ) ) {
1190 $oid = '&oldid='.$oldid;
1191 }
1192 $s = $this->makeKnownLink( $n, $t, "action=edit{$oid}{$red}" );
1193 }
1194 return $s;
1195 }
1196
1197 function deleteThisPage() {
1198 global $wgUser, $wgOut, $wgTitle, $wgRequest;
1199
1200 $diff = $wgRequest->getVal( 'diff' );
1201 if ( $wgTitle->getArticleId() && ( ! $diff ) && $wgUser->isSysop() ) {
1202 $n = $wgTitle->getPrefixedText();
1203 $t = wfMsg( 'deletethispage' );
1204
1205 $s = $this->makeKnownLink( $n, $t, 'action=delete' );
1206 } else {
1207 $s = '';
1208 }
1209 return $s;
1210 }
1211
1212 function protectThisPage() {
1213 global $wgUser, $wgOut, $wgTitle, $wgRequest;
1214
1215 $diff = $wgRequest->getVal( 'diff' );
1216 if ( $wgTitle->getArticleId() && ( ! $diff ) && $wgUser->isSysop() ) {
1217 $n = $wgTitle->getPrefixedText();
1218
1219 if ( $wgTitle->isProtected() ) {
1220 $t = wfMsg( 'unprotectthispage' );
1221 $q = 'action=unprotect';
1222 } else {
1223 $t = wfMsg( 'protectthispage' );
1224 $q = 'action=protect';
1225 }
1226 $s = $this->makeKnownLink( $n, $t, $q );
1227 } else {
1228 $s = '';
1229 }
1230 return $s;
1231 }
1232
1233 function watchThisPage() {
1234 global $wgUser, $wgOut, $wgTitle;
1235
1236 if ( $wgOut->isArticleRelated() ) {
1237 $n = $wgTitle->getPrefixedText();
1238
1239 if ( $wgTitle->userIsWatching() ) {
1240 $t = wfMsg( 'unwatchthispage' );
1241 $q = 'action=unwatch';
1242 } else {
1243 $t = wfMsg( 'watchthispage' );
1244 $q = 'action=watch';
1245 }
1246 $s = $this->makeKnownLink( $n, $t, $q );
1247 } else {
1248 $s = wfMsg( 'notanarticle' );
1249 }
1250 return $s;
1251 }
1252
1253 function moveThisPage() {
1254 global $wgTitle, $wgLang;
1255
1256 if ( $wgTitle->userCanEdit() ) {
1257 $s = $this->makeKnownLink( $wgLang->specialPage( 'Movepage' ),
1258 wfMsg( 'movethispage' ), 'target=' . $wgTitle->getPrefixedURL() );
1259 } // no message if page is protected - would be redundant
1260 return $s;
1261 }
1262
1263 function historyLink() {
1264 global $wgTitle;
1265
1266 $s = $this->makeKnownLink( $wgTitle->getPrefixedText(),
1267 wfMsg( 'history' ), 'action=history' );
1268 return $s;
1269 }
1270
1271 function whatLinksHere() {
1272 global $wgTitle, $wgLang;
1273
1274 $s = $this->makeKnownLink( $wgLang->specialPage( 'Whatlinkshere' ),
1275 wfMsg( 'whatlinkshere' ), 'target=' . $wgTitle->getPrefixedURL() );
1276 return $s;
1277 }
1278
1279 function userContribsLink() {
1280 global $wgTitle, $wgLang;
1281
1282 $s = $this->makeKnownLink( $wgLang->specialPage( 'Contributions' ),
1283 wfMsg( 'contributions' ), 'target=' . $wgTitle->getPartialURL() );
1284 return $s;
1285 }
1286
1287 function emailUserLink() {
1288 global $wgTitle, $wgLang;
1289
1290 $s = $this->makeKnownLink( $wgLang->specialPage( 'Emailuser' ),
1291 wfMsg( 'emailuser' ), 'target=' . $wgTitle->getPartialURL() );
1292 return $s;
1293 }
1294
1295 function watchPageLinksLink() {
1296 global $wgOut, $wgTitle, $wgLang;
1297
1298 if ( ! $wgOut->isArticleRelated() ) {
1299 $s = '(' . wfMsg( 'notanarticle' ) . ')';
1300 } else {
1301 $s = $this->makeKnownLink( $wgLang->specialPage(
1302 'Recentchangeslinked' ), wfMsg( 'recentchangeslinked' ),
1303 'target=' . $wgTitle->getPrefixedURL() );
1304 }
1305 return $s;
1306 }
1307
1308 function otherLanguages() {
1309 global $wgOut, $wgLang, $wgTitle, $wgUseNewInterlanguage;
1310
1311 $a = $wgOut->getLanguageLinks();
1312 if ( 0 == count( $a ) ) {
1313 if ( !$wgUseNewInterlanguage ) return '';
1314 $ns = $wgLang->getNsIndex ( $wgTitle->getNamespace () ) ;
1315 if ( $ns != 0 AND $ns != 1 ) return '' ;
1316 $pn = 'Intl' ;
1317 $x = 'mode=addlink&xt='.$wgTitle->getDBkey() ;
1318 return $this->makeKnownLink( $wgLang->specialPage( $pn ),
1319 wfMsg( 'intl' ) , $x );
1320 }
1321
1322 if ( !$wgUseNewInterlanguage ) {
1323 $s = wfMsg( 'otherlanguages' ) . ': ';
1324 } else {
1325 global $wgLanguageCode ;
1326 $x = 'mode=zoom&xt='.$wgTitle->getDBkey() ;
1327 $x .= '&xl='.$wgLanguageCode ;
1328 $s = $this->makeKnownLink( $wgLang->specialPage( 'Intl' ),
1329 wfMsg( 'otherlanguages' ) , $x ) . ': ' ;
1330 }
1331
1332 $s = wfMsg( 'otherlanguages' ) . ': ';
1333 $first = true;
1334 if($wgLang->isRTL()) $s .= '<span dir="LTR">';
1335 foreach( $a as $l ) {
1336 if ( ! $first ) { $s .= ' | '; }
1337 $first = false;
1338
1339 $nt = Title::newFromText( $l );
1340 $url = $nt->getFullURL();
1341 $text = $wgLang->getLanguageName( $nt->getInterwiki() );
1342
1343 if ( '' == $text ) { $text = $l; }
1344 $style = $this->getExternalLinkAttributes( $l, $text );
1345 $s .= "<a href=\"{$url}\"{$style}>{$text}</a>";
1346 }
1347 if($wgLang->isRTL()) $s .= '</span>';
1348 return $s;
1349 }
1350
1351 function bugReportsLink() {
1352 $s = $this->makeKnownLink( wfMsg( 'bugreportspage' ),
1353 wfMsg( 'bugreports' ) );
1354 return $s;
1355 }
1356
1357 function dateLink() {
1358 global $wgLinkCache;
1359 $t1 = Title::newFromText( gmdate( 'F j' ) );
1360 $t2 = Title::newFromText( gmdate( 'Y' ) );
1361
1362 $wgLinkCache->suspend();
1363 $id = $t1->getArticleID();
1364 $wgLinkCache->resume();
1365
1366 if ( 0 == $id ) {
1367 $s = $this->makeBrokenLink( $t1->getText() );
1368 } else {
1369 $s = $this->makeKnownLink( $t1->getText() );
1370 }
1371 $s .= ', ';
1372
1373 $wgLinkCache->suspend();
1374 $id = $t2->getArticleID();
1375 $wgLinkCache->resume();
1376
1377 if ( 0 == $id ) {
1378 $s .= $this->makeBrokenLink( $t2->getText() );
1379 } else {
1380 $s .= $this->makeKnownLink( $t2->getText() );
1381 }
1382 return $s;
1383 }
1384
1385 function talkLink() {
1386 global $wgLang, $wgTitle, $wgLinkCache;
1387
1388 $tns = $wgTitle->getNamespace();
1389 if ( -1 == $tns ) { return ''; }
1390
1391 $pn = $wgTitle->getText();
1392 $tp = wfMsg( 'talkpage' );
1393 if ( Namespace::isTalk( $tns ) ) {
1394 $lns = Namespace::getSubject( $tns );
1395 switch($tns) {
1396 case 1:
1397 $text = wfMsg('articlepage');
1398 break;
1399 case 3:
1400 $text = wfMsg('userpage');
1401 break;
1402 case 5:
1403 $text = wfMsg('wikipediapage');
1404 break;
1405 case 7:
1406 $text = wfMsg('imagepage');
1407 break;
1408 default:
1409 $text= wfMsg('articlepage');
1410 }
1411 } else {
1412
1413 $lns = Namespace::getTalk( $tns );
1414 $text=$tp;
1415 }
1416 $n = $wgLang->getNsText( $lns );
1417 if ( '' == $n ) { $link = $pn; }
1418 else { $link = $n.':'.$pn; }
1419
1420 $wgLinkCache->suspend();
1421 $s = $this->makeLink( $link, $text );
1422 $wgLinkCache->resume();
1423
1424 return $s;
1425 }
1426
1427 function commentLink() {
1428 global $wgLang, $wgTitle, $wgLinkCache;
1429
1430 $tns = $wgTitle->getNamespace();
1431 if ( -1 == $tns ) { return ''; }
1432
1433 $lns = ( Namespace::isTalk( $tns ) ) ? $tns : Namespace::getTalk( $tns );
1434
1435 # assert Namespace::isTalk( $lns )
1436
1437 $n = $wgLang->getNsText( $lns );
1438 $pn = $wgTitle->getText();
1439
1440 $link = $n.':'.$pn;
1441
1442 $wgLinkCache->suspend();
1443 $s = $this->makeKnownLink($link, wfMsg('postcomment'), 'action=edit&section=new');
1444 $wgLinkCache->resume();
1445
1446 return $s;
1447 }
1448
1449 /**
1450 * After all the page content is transformed into HTML, it makes
1451 * a final pass through here for things like table backgrounds.
1452 * @todo probably deprecated [AV]
1453 */
1454 function transformContent( $text ) {
1455 return $text;
1456 }
1457
1458 /**
1459 * Note: This function MUST call getArticleID() on the link,
1460 * otherwise the cache won't get updated properly. See LINKCACHE.DOC.
1461 */
1462 function makeLink( $title, $text = '', $query = '', $trail = '' ) {
1463 wfProfileIn( 'Skin::makeLink' );
1464 $nt = Title::newFromText( $title );
1465 if ($nt) {
1466 $result = $this->makeLinkObj( Title::newFromText( $title ), $text, $query, $trail );
1467 } else {
1468 wfDebug( 'Invalid title passed to Skin::makeLink(): "'.$title."\"\n" );
1469 $result = $text == "" ? $title : $text;
1470 }
1471
1472 wfProfileOut( 'Skin::makeLink' );
1473 return $result;
1474 }
1475
1476 function makeKnownLink( $title, $text = '', $query = '', $trail = '', $prefix = '',$aprops = '') {
1477 $nt = Title::newFromText( $title );
1478 if ($nt) {
1479 return $this->makeKnownLinkObj( Title::newFromText( $title ), $text, $query, $trail, $prefix , $aprops );
1480 } else {
1481 wfDebug( 'Invalid title passed to Skin::makeKnownLink(): "'.$title."\"\n" );
1482 return $text == '' ? $title : $text;
1483 }
1484 }
1485
1486 function makeBrokenLink( $title, $text = '', $query = '', $trail = '' ) {
1487 $nt = Title::newFromText( $title );
1488 if ($nt) {
1489 return $this->makeBrokenLinkObj( Title::newFromText( $title ), $text, $query, $trail );
1490 } else {
1491 wfDebug( 'Invalid title passed to Skin::makeBrokenLink(): "'.$title."\"\n" );
1492 return $text == '' ? $title : $text;
1493 }
1494 }
1495
1496 function makeStubLink( $title, $text = '', $query = '', $trail = '' ) {
1497 $nt = Title::newFromText( $title );
1498 if ($nt) {
1499 return $this->makeStubLinkObj( Title::newFromText( $title ), $text, $query, $trail );
1500 } else {
1501 wfDebug( 'Invalid title passed to Skin::makeStubLink(): "'.$title."\"\n" );
1502 return $text == '' ? $title : $text;
1503 }
1504 }
1505
1506 /**
1507 * Pass a title object, not a title string
1508 */
1509 function makeLinkObj( &$nt, $text= '', $query = '', $trail = '', $prefix = '' ) {
1510 global $wgOut, $wgUser, $wgLinkHolders;
1511 $fname = 'Skin::makeLinkObj';
1512
1513 # Fail gracefully
1514 if ( ! isset($nt) ) {
1515 # wfDebugDieBacktrace();
1516 return "<!-- ERROR -->{$prefix}{$text}{$trail}";
1517 }
1518
1519 if ( $nt->isExternal() ) {
1520 $u = $nt->getFullURL();
1521 $link = $nt->getPrefixedURL();
1522 if ( '' == $text ) { $text = $nt->getPrefixedText(); }
1523 $style = $this->getExternalLinkAttributes( $link, $text, 'extiw' );
1524
1525 $inside = '';
1526 if ( '' != $trail ) {
1527 if ( preg_match( '/^([a-z]+)(.*)$$/sD', $trail, $m ) ) {
1528 $inside = $m[1];
1529 $trail = $m[2];
1530 }
1531 }
1532 $retVal = "<a href=\"{$u}\"{$style}>{$text}{$inside}</a>{$trail}";
1533 } elseif ( 0 == $nt->getNamespace() && "" == $nt->getText() ) {
1534 $retVal = $this->makeKnownLinkObj( $nt, $text, $query, $trail, $prefix );
1535 } elseif ( ( -1 == $nt->getNamespace() ) ||
1536 ( Namespace::getImage() == $nt->getNamespace() ) ) {
1537 $retVal = $this->makeKnownLinkObj( $nt, $text, $query, $trail, $prefix );
1538 } else {
1539 if ( $this->postParseLinkColour() ) {
1540 $inside = '';
1541 if ( '' != $trail ) {
1542 if ( preg_match( $this->linktrail, $trail, $m ) ) {
1543 $inside = $m[1];
1544 $trail = $m[2];
1545 }
1546 }
1547
1548 # Allows wiki to bypass using linkcache, see OutputPage::parseLinkHolders()
1549 $nr = array_push( $wgLinkHolders['namespaces'], $nt->getNamespace() );
1550 $wgLinkHolders['dbkeys'][] = $nt->getDBkey();
1551 $wgLinkHolders['queries'][] = $query;
1552 $wgLinkHolders['texts'][] = $prefix.$text.$inside;
1553 $wgLinkHolders['titles'][] = $nt;
1554
1555 $retVal = '<!--LINK '. ($nr-1) ."-->{$trail}";
1556 } else {
1557 # Work out link colour immediately
1558 $aid = $nt->getArticleID() ;
1559 if ( 0 == $aid ) {
1560 $retVal = $this->makeBrokenLinkObj( $nt, $text, $query, $trail, $prefix );
1561 } else {
1562 $threshold = $wgUser->getOption('stubthreshold') ;
1563 if ( $threshold > 0 ) {
1564 $dbr =& wfGetDB( DB_SLAVE );
1565 $s = $dbr->selectRow( 'cur', array( 'LENGTH(cur_text) AS x', 'cur_namespace',
1566 'cur_is_redirect' ), array( 'cur_id' => $aid ), $fname ) ;
1567 if ( $s !== false ) {
1568 $size = $s->x;
1569 if ( $s->cur_is_redirect OR $s->cur_namespace != 0 ) {
1570 $size = $threshold*2 ; # Really big
1571 }
1572 $dbr->freeResult( $res );
1573 } else {
1574 $size = $threshold*2 ; # Really big
1575 }
1576 } else {
1577 $size = 1 ;
1578 }
1579 if ( $size < $threshold ) {
1580 $retVal = $this->makeStubLinkObj( $nt, $text, $query, $trail, $prefix );
1581 } else {
1582 $retVal = $this->makeKnownLinkObj( $nt, $text, $query, $trail, $prefix );
1583 }
1584 }
1585 }
1586 }
1587 return $retVal;
1588 }
1589
1590 /**
1591 * Pass a title object, not a title string
1592 */
1593 function makeKnownLinkObj( &$nt, $text = '', $query = '', $trail = '', $prefix = '' , $aprops = '' ) {
1594 global $wgOut, $wgTitle, $wgInputEncoding;
1595
1596 $fname = 'Skin::makeKnownLinkObj';
1597 wfProfileIn( $fname );
1598
1599 if ( !is_object( $nt ) ) {
1600 return $text;
1601 }
1602 $link = $nt->getPrefixedURL();
1603 # if ( '' != $section && substr($section,0,1) != "#" ) {
1604 # $section = ''
1605
1606 if ( '' == $link ) {
1607 $u = '';
1608 if ( '' == $text ) {
1609 $text = htmlspecialchars( $nt->getFragment() );
1610 }
1611 } else {
1612 $u = $nt->escapeLocalURL( $query );
1613 }
1614 if ( '' != $nt->getFragment() ) {
1615 $anchor = urlencode( do_html_entity_decode( str_replace(' ', '_', $nt->getFragment()), ENT_COMPAT, $wgInputEncoding ) );
1616 $replacearray = array(
1617 '%3A' => ':',
1618 '%' => '.'
1619 );
1620 $u .= '#' . str_replace(array_keys($replacearray),array_values($replacearray),$anchor);
1621 }
1622 if ( '' == $text ) {
1623 $text = htmlspecialchars( $nt->getPrefixedText() );
1624 }
1625 $style = $this->getInternalLinkAttributesObj( $nt, $text );
1626
1627 $inside = '';
1628 if ( '' != $trail ) {
1629 if ( preg_match( $this->linktrail, $trail, $m ) ) {
1630 $inside = $m[1];
1631 $trail = $m[2];
1632 }
1633 }
1634 $r = "<a href=\"{$u}\"{$style}{$aprops}>{$prefix}{$text}{$inside}</a>{$trail}";
1635 wfProfileOut( $fname );
1636 return $r;
1637 }
1638
1639 /**
1640 * Pass a title object, not a title string
1641 */
1642 function makeBrokenLinkObj( &$nt, $text = '', $query = '', $trail = '', $prefix = '' ) {
1643 global $wgOut, $wgUser;
1644
1645 # Fail gracefully
1646 if ( ! isset($nt) ) {
1647 # wfDebugDieBacktrace();
1648 return "<!-- ERROR -->{$prefix}{$text}{$trail}";
1649 }
1650
1651 $fname = 'Skin::makeBrokenLinkObj';
1652 wfProfileIn( $fname );
1653
1654 if ( '' == $query ) {
1655 $q = 'action=edit';
1656 } else {
1657 $q = 'action=edit&'.$query;
1658 }
1659 $u = $nt->escapeLocalURL( $q );
1660
1661 if ( '' == $text ) {
1662 $text = htmlspecialchars( $nt->getPrefixedText() );
1663 }
1664 $style = $this->getInternalLinkAttributesObj( $nt, $text, "yes" );
1665
1666 $inside = '';
1667 if ( '' != $trail ) {
1668 if ( preg_match( $this->linktrail, $trail, $m ) ) {
1669 $inside = $m[1];
1670 $trail = $m[2];
1671 }
1672 }
1673 if ( $wgUser->getOption( 'highlightbroken' ) ) {
1674 $s = "<a href=\"{$u}\"{$style}>{$prefix}{$text}{$inside}</a>{$trail}";
1675 } else {
1676 $s = "{$prefix}{$text}{$inside}<a href=\"{$u}\"{$style}>?</a>{$trail}";
1677 }
1678
1679 wfProfileOut( $fname );
1680 return $s;
1681 }
1682
1683 /**
1684 * Pass a title object, not a title string
1685 */
1686 function makeStubLinkObj( &$nt, $text = '', $query = '', $trail = '', $prefix = '' ) {
1687 global $wgOut, $wgUser;
1688
1689 $link = $nt->getPrefixedURL();
1690
1691 $u = $nt->escapeLocalURL( $query );
1692
1693 if ( '' == $text ) {
1694 $text = htmlspecialchars( $nt->getPrefixedText() );
1695 }
1696 $style = $this->getInternalLinkAttributesObj( $nt, $text, 'stub' );
1697
1698 $inside = '';
1699 if ( '' != $trail ) {
1700 if ( preg_match( $this->linktrail, $trail, $m ) ) {
1701 $inside = $m[1];
1702 $trail = $m[2];
1703 }
1704 }
1705 if ( $wgUser->getOption( 'highlightbroken' ) ) {
1706 $s = "<a href=\"{$u}\"{$style}>{$prefix}{$text}{$inside}</a>{$trail}";
1707 } else {
1708 $s = "{$prefix}{$text}{$inside}<a href=\"{$u}\"{$style}>!</a>{$trail}";
1709 }
1710 return $s;
1711 }
1712
1713 function makeSelfLinkObj( &$nt, $text = '', $query = '', $trail = '', $prefix = '' ) {
1714 $u = $nt->escapeLocalURL( $query );
1715 if ( '' == $text ) {
1716 $text = htmlspecialchars( $nt->getPrefixedText() );
1717 }
1718 $inside = '';
1719 if ( '' != $trail ) {
1720 if ( preg_match( $this->linktrail, $trail, $m ) ) {
1721 $inside = $m[1];
1722 $trail = $m[2];
1723 }
1724 }
1725 return "<strong>{$prefix}{$text}{$inside}</strong>{$trail}";
1726 }
1727
1728 /* these are used extensively in SkinPHPTal, but also some other places */
1729 /*static*/ function makeSpecialUrl( $name, $urlaction='' ) {
1730 $title = Title::makeTitle( NS_SPECIAL, $name );
1731 $this->checkTitle($title, $name);
1732 return $title->getLocalURL( $urlaction );
1733 }
1734 /*static*/ function makeTalkUrl ( $name, $urlaction='' ) {
1735 $title = Title::newFromText( $name );
1736 $title = $title->getTalkPage();
1737 $this->checkTitle($title, $name);
1738 return $title->getLocalURL( $urlaction );
1739 }
1740 /*static*/ function makeArticleUrl ( $name, $urlaction='' ) {
1741 $title = Title::newFromText( $name );
1742 $title= $title->getSubjectPage();
1743 $this->checkTitle($title, $name);
1744 return $title->getLocalURL( $urlaction );
1745 }
1746 /*static*/ function makeI18nUrl ( $name, $urlaction='' ) {
1747 $title = Title::newFromText( wfMsgForContent($name) );
1748 $this->checkTitle($title, $name);
1749 return $title->getLocalURL( $urlaction );
1750 }
1751 /*static*/ function makeUrl ( $name, $urlaction='' ) {
1752 $title = Title::newFromText( $name );
1753 $this->checkTitle($title, $name);
1754 return $title->getLocalURL( $urlaction );
1755 }
1756 # this can be passed the NS number as defined in Language.php
1757 /*static*/ function makeNSUrl( $name, $urlaction='', $namespace=0 ) {
1758 $title = Title::makeTitleSafe( $namespace, $name );
1759 $this->checkTitle($title, $name);
1760 return $title->getLocalURL( $urlaction );
1761 }
1762
1763 /* these return an array with the 'href' and boolean 'exists' */
1764 /*static*/ function makeUrlDetails ( $name, $urlaction='' ) {
1765 $title = Title::newFromText( $name );
1766 $this->checkTitle($title, $name);
1767 return array(
1768 'href' => $title->getLocalURL( $urlaction ),
1769 'exists' => $title->getArticleID() != 0?true:false
1770 );
1771 }
1772 /*static*/ function makeTalkUrlDetails ( $name, $urlaction='' ) {
1773 $title = Title::newFromText( $name );
1774 $title = $title->getTalkPage();
1775 $this->checkTitle($title, $name);
1776 return array(
1777 'href' => $title->getLocalURL( $urlaction ),
1778 'exists' => $title->getArticleID() != 0?true:false
1779 );
1780 }
1781 /*static*/ function makeArticleUrlDetails ( $name, $urlaction='' ) {
1782 $title = Title::newFromText( $name );
1783 $title= $title->getSubjectPage();
1784 $this->checkTitle($title, $name);
1785 return array(
1786 'href' => $title->getLocalURL( $urlaction ),
1787 'exists' => $title->getArticleID() != 0?true:false
1788 );
1789 }
1790 /*static*/ function makeI18nUrlDetails ( $name, $urlaction='' ) {
1791 $title = Title::newFromText( wfMsgForContent($name) );
1792 $this->checkTitle($title, $name);
1793 return array(
1794 'href' => $title->getLocalURL( $urlaction ),
1795 'exists' => $title->getArticleID() != 0?true:false
1796 );
1797 }
1798
1799 # make sure we have some title to operate on
1800 /*static*/ function checkTitle ( &$title, &$name ) {
1801 if(!is_object($title)) {
1802 $title = Title::newFromText( $name );
1803 if(!is_object($title)) {
1804 $title = Title::newFromText( '--error: link target missing--' );
1805 }
1806 }
1807 }
1808
1809 function fnamePart( $url ) {
1810 $basename = strrchr( $url, '/' );
1811 if ( false === $basename ) {
1812 $basename = $url;
1813 } else {
1814 $basename = substr( $basename, 1 );
1815 }
1816 return htmlspecialchars( $basename );
1817 }
1818
1819 function makeImage( $url, $alt = '' ) {
1820 global $wgOut;
1821
1822 if ( '' == $alt ) {
1823 $alt = $this->fnamePart( $url );
1824 }
1825 $s = '<img src="'.$url.'" alt="'.$alt.'" />';
1826 return $s;
1827 }
1828
1829 function makeImageLink( $name, $url, $alt = '' ) {
1830 $nt = Title::makeTitleSafe( NS_IMAGE, $name );
1831 return $this->makeImageLinkObj( $nt, $alt );
1832 }
1833
1834 function makeImageLinkObj( $nt, $alt = '' ) {
1835 global $wgLang, $wgUseImageResize;
1836 $img = Image::newFromTitle( $nt );
1837 $url = $img->getURL();
1838
1839 $align = '';
1840 $prefix = $postfix = '';
1841
1842 if ( $wgUseImageResize ) {
1843 # Check if the alt text is of the form "options|alt text"
1844 # Options are:
1845 # * thumbnail make a thumbnail with enlarge-icon and caption, alignment depends on lang
1846 # * left no resizing, just left align. label is used for alt= only
1847 # * right same, but right aligned
1848 # * none same, but not aligned
1849 # * ___px scale to ___ pixels width, no aligning. e.g. use in taxobox
1850 # * center center the image
1851 # * framed Keep original image size, no magnify-button.
1852
1853 $part = explode( '|', $alt);
1854
1855 $mwThumb =& MagicWord::get( MAG_IMG_THUMBNAIL );
1856 $mwLeft =& MagicWord::get( MAG_IMG_LEFT );
1857 $mwRight =& MagicWord::get( MAG_IMG_RIGHT );
1858 $mwNone =& MagicWord::get( MAG_IMG_NONE );
1859 $mwWidth =& MagicWord::get( MAG_IMG_WIDTH );
1860 $mwCenter =& MagicWord::get( MAG_IMG_CENTER );
1861 $mwFramed =& MagicWord::get( MAG_IMG_FRAMED );
1862 $alt = $part[count($part)-1];
1863
1864 $height = $framed = $thumb = false;
1865 $manual_thumb = "" ;
1866
1867 foreach( $part as $key => $val ) {
1868 $val_parts = explode ( "=" , $val , 2 ) ;
1869 $left_part = array_shift ( $val_parts ) ;
1870 if ( ! is_null( $mwThumb->matchVariableStartToEnd($val) ) ) {
1871 $thumb=true;
1872 } elseif ( count ( $val_parts ) == 1 && ! is_null( $mwThumb->matchVariableStartToEnd($left_part) ) ) {
1873 # use manually specified thumbnail
1874 $thumb=true;
1875 $manual_thumb = array_shift ( $val_parts ) ;
1876 } elseif ( ! is_null( $mwRight->matchVariableStartToEnd($val) ) ) {
1877 # remember to set an alignment, don't render immediately
1878 $align = 'right';
1879 } elseif ( ! is_null( $mwLeft->matchVariableStartToEnd($val) ) ) {
1880 # remember to set an alignment, don't render immediately
1881 $align = 'left';
1882 } elseif ( ! is_null( $mwCenter->matchVariableStartToEnd($val) ) ) {
1883 # remember to set an alignment, don't render immediately
1884 $align = 'center';
1885 } elseif ( ! is_null( $mwNone->matchVariableStartToEnd($val) ) ) {
1886 # remember to set an alignment, don't render immediately
1887 $align = 'none';
1888 } elseif ( ! is_null( $match = $mwWidth->matchVariableStartToEnd($val) ) ) {
1889 # $match is the image width in pixels
1890 if ( preg_match( '/^([0-9]*)x([0-9]*)$/', $match, $m ) ) {
1891 $width = intval( $m[1] );
1892 $height = intval( $m[2] );
1893 } else {
1894 $width = intval($match);
1895 }
1896 } elseif ( ! is_null( $mwFramed->matchVariableStartToEnd($val) ) ) {
1897 $framed=true;
1898 }
1899 }
1900 if ( 'center' == $align )
1901 {
1902 $prefix = '<span style="text-align: center">';
1903 $postfix = '</span>';
1904 $align = 'none';
1905 }
1906
1907 if ( $thumb || $framed ) {
1908
1909 # Create a thumbnail. Alignment depends on language
1910 # writing direction, # right aligned for left-to-right-
1911 # languages ("Western languages"), left-aligned
1912 # for right-to-left-languages ("Semitic languages")
1913 #
1914 # If thumbnail width has not been provided, it is set
1915 # here to 180 pixels
1916 if ( $align == '' ) {
1917 $align = $wgLang->isRTL() ? 'left' : 'right';
1918 }
1919 if ( ! isset($width) ) {
1920 $width = 180;
1921 }
1922 return $prefix.$this->makeThumbLinkObj( $img, $alt, $align, $width, $height, $framed, $manual_thumb ).$postfix;
1923
1924 } elseif ( isset($width) ) {
1925
1926 # Create a resized image, without the additional thumbnail
1927 # features
1928
1929 if ( ( ! $height === false )
1930 && ( $img->getHeight() * $width / $img->getWidth() > $height ) ) {
1931 print "height=$height<br>\nimg->getHeight() = ".$img->getHeight()."<br>\n";
1932 print 'rescaling by factor '. $height / $img->getHeight() . "<br>\n";
1933 $width = $img->getWidth() * $height / $img->getHeight();
1934 }
1935 if ( '' == $manual_thumb ) $url = $img->createThumb( $width );
1936 }
1937 } # endif $wgUseImageResize
1938
1939 if ( empty( $alt ) ) {
1940 $alt = preg_replace( '/\.(.+?)^/', '', $img->getName() );
1941 }
1942 $alt = htmlspecialchars( $alt );
1943
1944 $u = $nt->escapeLocalURL();
1945 if ( $url == '' )
1946 {
1947 $s = wfMsg( 'missingimage', $img->getName() );
1948 $s .= "<br>{$alt}<br>{$url}<br>\n";
1949 } else {
1950 $s = '<a href="'.$u.'" class="image" title="'.$alt.'">' .
1951 '<img src="'.$url.'" alt="'.$alt.'" /></a>';
1952 }
1953 if ( '' != $align ) {
1954 $s = "<div class=\"float{$align}\"><span>{$s}</span></div>";
1955 }
1956 return str_replace("\n", ' ',$prefix.$s.$postfix);
1957 }
1958
1959 /**
1960 * Make HTML for a thumbnail including image, border and caption
1961 * $img is an Image object
1962 */
1963 function makeThumbLinkObj( $img, $label = '', $align = 'right', $boxwidth = 180, $boxheight=false, $framed=false , $manual_thumb = "" ) {
1964 global $wgStylePath, $wgLang;
1965 # $image = Title::makeTitleSafe( NS_IMAGE, $name );
1966 $url = $img->getURL();
1967
1968 #$label = htmlspecialchars( $label );
1969 $alt = preg_replace( '/<[^>]*>/', '', $label);
1970 $alt = htmlspecialchars( $alt );
1971
1972 $width = $height = 0;
1973 if ( $img->exists() )
1974 {
1975 $width = $img->getWidth();
1976 $height = $img->getHeight();
1977 }
1978 if ( 0 == $width || 0 == $height )
1979 {
1980 $width = $height = 200;
1981 }
1982 if ( $boxwidth == 0 )
1983 {
1984 $boxwidth = 200;
1985 }
1986 if ( $framed )
1987 {
1988 // Use image dimensions, don't scale
1989 $boxwidth = $width;
1990 $oboxwidth = $boxwidth + 2;
1991 $boxheight = $height;
1992 $thumbUrl = $url;
1993 } else {
1994 $h = intval( $height/($width/$boxwidth) );
1995 $oboxwidth = $boxwidth + 2;
1996 if ( ( ! $boxheight === false ) && ( $h > $boxheight ) )
1997 {
1998 $boxwidth *= $boxheight/$h;
1999 } else {
2000 $boxheight = $h;
2001 }
2002 if ( '' == $manual_thumb ) $thumbUrl = $img->createThumb( $boxwidth );
2003 }
2004
2005 if ( $manual_thumb != '' ) # Use manually specified thumbnail
2006 {
2007 $manual_title = Title::makeTitleSafe( NS_IMAGE, $manual_thumb ); #new Title ( $manual_thumb ) ;
2008 $manual_img = Image::newFromTitle( $manual_title );
2009 $thumbUrl = $manual_img->getURL();
2010 if ( $manual_img->exists() )
2011 {
2012 $width = $manual_img->getWidth();
2013 $height = $manual_img->getHeight();
2014 $boxwidth = $width ;
2015 $boxheight = $height ;
2016 $oboxwidth = $boxwidth + 2 ;
2017 }
2018 }
2019
2020 $u = $img->getEscapeLocalURL();
2021
2022 $more = htmlspecialchars( wfMsg( 'thumbnail-more' ) );
2023 $magnifyalign = $wgLang->isRTL() ? 'left' : 'right';
2024 $textalign = $wgLang->isRTL() ? ' style="text-align:right"' : '';
2025
2026 $s = "<div class=\"thumb t{$align}\"><div style=\"width:{$oboxwidth}px;\">";
2027 if ( $thumbUrl == '' ) {
2028 $s .= wfMsg( 'missingimage', $img->getName() );
2029 $zoomicon = '';
2030 } else {
2031 $s .= '<a href="'.$u.'" class="internal" title="'.$alt.'">'.
2032 '<img src="'.$thumbUrl.'" alt="'.$alt.'" ' .
2033 'width="'.$boxwidth.'" height="'.$boxheight.'" /></a>';
2034 if ( $framed ) {
2035 $zoomicon="";
2036 } else {
2037 $zoomicon = '<div class="magnify" style="float:'.$magnifyalign.'">'.
2038 '<a href="'.$u.'" class="internal" title="'.$more.'">'.
2039 '<img src="'.$wgStylePath.'/common/images/magnify-clip.png" ' .
2040 'width="15" height="11" alt="'.$more.'" /></a></div>';
2041 }
2042 }
2043 $s .= ' <div class="thumbcaption" '.$textalign.'>'.$zoomicon.$label."</div></div></div>";
2044 return str_replace("\n", ' ', $s);
2045 }
2046
2047 function makeMediaLink( $name, $url, $alt = '' ) {
2048 $nt = Title::makeTitleSafe( Namespace::getMedia(), $name );
2049 return $this->makeMediaLinkObj( $nt, $alt );
2050 }
2051
2052 function makeMediaLinkObj( $nt, $alt = '' ) {
2053 if ( ! isset( $nt ) )
2054 {
2055 ### HOTFIX. Instead of breaking, return empty string.
2056 $s = $alt;
2057 } else {
2058 $name = $nt->getDBKey();
2059 $url = Image::wfImageUrl( $name );
2060 if ( empty( $alt ) ) {
2061 $alt = preg_replace( '/\.(.+?)^/', '', $name );
2062 }
2063
2064 $u = htmlspecialchars( $url );
2065 $s = "<a href=\"{$u}\" class='internal' title=\"{$alt}\">{$alt}</a>";
2066 }
2067 return $s;
2068 }
2069
2070 function specialLink( $name, $key = '' ) {
2071 global $wgLang;
2072
2073 if ( '' == $key ) { $key = strtolower( $name ); }
2074 $pn = $wgLang->ucfirst( $name );
2075 return $this->makeKnownLink( $wgLang->specialPage( $pn ),
2076 wfMsg( $key ) );
2077 }
2078
2079 function makeExternalLink( $url, $text, $escape = true ) {
2080 $style = $this->getExternalLinkAttributes( $url, $text );
2081 $url = htmlspecialchars( $url );
2082 if( $escape ) {
2083 $text = htmlspecialchars( $text );
2084 }
2085 return '<a href="'.$url.'"'.$style.'>'.$text.'</a>';
2086 }
2087
2088 # Called by history lists and recent changes
2089 #
2090
2091 # Returns text for the start of the tabular part of RC
2092 function beginRecentChangesList() {
2093 $this->rc_cache = array() ;
2094 $this->rcMoveIndex = 0;
2095 $this->rcCacheIndex = 0 ;
2096 $this->lastdate = '';
2097 $this->rclistOpen = false;
2098 return '';
2099 }
2100
2101 function beginImageHistoryList() {
2102 $s = "\n<h2>" . wfMsg( 'imghistory' ) . "</h2>\n" .
2103 "<p>" . wfMsg( 'imghistlegend' ) . "</p>\n".'<ul class="special">';
2104 return $s;
2105 }
2106
2107 /**
2108 * Returns text for the end of RC
2109 * If enhanced RC is in use, returns pretty much all the text
2110 */
2111 function endRecentChangesList() {
2112 $s = $this->recentChangesBlock() ;
2113 if( $this->rclistOpen ) {
2114 $s .= "</ul>\n";
2115 }
2116 return $s;
2117 }
2118
2119 /**
2120 * Enhanced RC ungrouped line
2121 */
2122 function recentChangesBlockLine ( $rcObj ) {
2123 global $wgStylePath, $wgLang ;
2124
2125 # Get rc_xxxx variables
2126 extract( $rcObj->mAttribs ) ;
2127 $curIdEq = 'curid='.$rc_cur_id;
2128
2129 # Spacer image
2130 $r = '' ;
2131
2132 $r .= '<img src="'.$wgStylePath.'/common/images/Arr_.png" width="12" height="12" border="0" />' ;
2133 $r .= '<tt>' ;
2134
2135 if ( $rc_type == RC_MOVE || $rc_type == RC_MOVE_OVER_REDIRECT ) {
2136 $r .= '&nbsp;&nbsp;';
2137 } else {
2138 # M & N (minor & new)
2139 $M = wfMsg( 'minoreditletter' );
2140 $N = wfMsg( 'newpageletter' );
2141
2142 if ( $rc_type == RC_NEW ) {
2143 $r .= $N ;
2144 } else {
2145 $r .= '&nbsp;' ;
2146 }
2147 if ( $rc_minor ) {
2148 $r .= $M ;
2149 } else {
2150 $r .= '&nbsp;' ;
2151 }
2152 }
2153
2154 # Timestamp
2155 $r .= ' '.$rcObj->timestamp.' ' ;
2156 $r .= '</tt>' ;
2157
2158 # Article link
2159 $link = $rcObj->link ;
2160 if ( $rcObj->watched ) $link = '<strong>'.$link.'</strong>' ;
2161 $r .= $link ;
2162
2163 # Diff
2164 $r .= ' (' ;
2165 $r .= $rcObj->difflink ;
2166 $r .= '; ' ;
2167
2168 # Hist
2169 $r .= $this->makeKnownLinkObj( $rcObj->getTitle(), wfMsg( 'hist' ), $curIdEq.'&action=history' );
2170
2171 # User/talk
2172 $r .= ') . . '.$rcObj->userlink ;
2173 $r .= $rcObj->usertalklink ;
2174
2175 # Comment
2176 if ( $rc_comment != '' && $rc_type != RC_MOVE && $rc_type != RC_MOVE_OVER_REDIRECT ) {
2177 $rc_comment=$this->formatComment($rc_comment, $rcObj->getTitle());
2178 $r .= $wgLang->emphasize( ' ('.$rc_comment.')' );
2179 }
2180
2181 $r .= "<br />\n" ;
2182 return $r ;
2183 }
2184
2185 /**
2186 * Enhanced RC group
2187 */
2188 function recentChangesBlockGroup ( $block ) {
2189 global $wgStylePath, $wgLang ;
2190
2191 $r = '' ;
2192 $M = wfMsg( 'minoreditletter' );
2193 $N = wfMsg( 'newpageletter' );
2194
2195 # Collate list of users
2196 $isnew = false ;
2197 $userlinks = array () ;
2198 foreach ( $block AS $rcObj ) {
2199 $oldid = $rcObj->mAttribs['rc_last_oldid'];
2200 if ( $rcObj->mAttribs['rc_new'] ) $isnew = true ;
2201 $u = $rcObj->userlink ;
2202 if ( !isset ( $userlinks[$u] ) ) $userlinks[$u] = 0 ;
2203 $userlinks[$u]++ ;
2204 }
2205
2206 # Sort the list and convert to text
2207 krsort ( $userlinks ) ;
2208 asort ( $userlinks ) ;
2209 $users = array () ;
2210 foreach ( $userlinks as $userlink => $count) {
2211 $text = $userlink ;
2212 if ( $count > 1 ) $text .= " ({$count}&times;)" ;
2213 array_push ( $users , $text ) ;
2214 }
2215 $users = ' <font size="-1">['.implode('; ',$users).']</font>' ;
2216
2217 # Arrow
2218 $rci = 'RCI'.$this->rcCacheIndex ;
2219 $rcl = 'RCL'.$this->rcCacheIndex ;
2220 $rcm = 'RCM'.$this->rcCacheIndex ;
2221 $toggleLink = "javascript:toggleVisibility('$rci','$rcm','$rcl')" ;
2222 $arrowdir = $wgLang->isRTL() ? 'l' : 'r';
2223 $tl = '<span id="'.$rcm.'"><a href="'.$toggleLink.'"><img src="'.$wgStylePath.'/common/images/Arr_'.$arrowdir.'.png" width="12" height="12" /></a></span>' ;
2224 $tl .= '<span id="'.$rcl.'" style="display:none"><a href="'.$toggleLink.'"><img src="'.$wgStylePath.'/common/images/Arr_d.png" width="12" height="12" /></a></span>' ;
2225 $r .= $tl ;
2226
2227 # Main line
2228 # M/N
2229 $r .= '<tt>' ;
2230 if ( $isnew ) $r .= $N ;
2231 else $r .= '&nbsp;' ;
2232 $r .= '&nbsp;' ; # Minor
2233
2234 # Timestamp
2235 $r .= ' '.$block[0]->timestamp.' ' ;
2236 $r .= '</tt>' ;
2237
2238 # Article link
2239 $link = $block[0]->link ;
2240 if ( $block[0]->watched ) $link = '<strong>'.$link.'</strong>' ;
2241 $r .= $link ;
2242
2243 $curIdEq = 'curid=' . $block[0]->mAttribs['rc_cur_id'];
2244 if ( $block[0]->mAttribs['rc_type'] != RC_LOG ) {
2245 # Changes
2246 $r .= ' ('.count($block).' ' ;
2247 if ( $isnew ) $r .= wfMsg('changes');
2248 else $r .= $this->makeKnownLinkObj( $block[0]->getTitle() , wfMsg('changes') ,
2249 $curIdEq.'&diff=0&oldid='.$oldid ) ;
2250 $r .= '; ' ;
2251
2252 # History
2253 $r .= $this->makeKnownLinkObj( $block[0]->getTitle(), wfMsg( 'history' ), $curIdEq.'&action=history' );
2254 $r .= ')' ;
2255 }
2256
2257 $r .= $users ;
2258 $r .= "<br />\n" ;
2259
2260 # Sub-entries
2261 $r .= '<div id="'.$rci.'" style="display:none">' ;
2262 foreach ( $block AS $rcObj ) {
2263 # Get rc_xxxx variables
2264 extract( $rcObj->mAttribs );
2265
2266 $r .= '<img src="'.$wgStylePath.'/common/images/Arr_.png" width="12" height="12" />';
2267 $r .= '<tt>&nbsp; &nbsp; &nbsp; &nbsp;' ;
2268 if ( $rc_new ) $r .= $N ;
2269 else $r .= '&nbsp;' ;
2270 if ( $rc_minor ) $r .= $M ;
2271 else $r .= '&nbsp;' ;
2272 $r .= '</tt>' ;
2273
2274 $o = '' ;
2275 if ( $rc_last_oldid != 0 ) {
2276 $o = 'oldid='.$rc_last_oldid ;
2277 }
2278 if ( $rc_type == RC_LOG ) {
2279 $link = $rcObj->timestamp ;
2280 } else {
2281 $link = $this->makeKnownLinkObj( $rcObj->getTitle(), $rcObj->timestamp , "{$curIdEq}&$o" ) ;
2282 }
2283 $link = '<tt>'.$link.'</tt>' ;
2284
2285 $r .= $link ;
2286 $r .= ' (' ;
2287 $r .= $rcObj->curlink ;
2288 $r .= '; ' ;
2289 $r .= $rcObj->lastlink ;
2290 $r .= ') . . '.$rcObj->userlink ;
2291 $r .= $rcObj->usertalklink ;
2292 if ( $rc_comment != '' ) {
2293 $rc_comment=$this->formatComment($rc_comment, $rcObj->getTitle());
2294 $r .= $wgLang->emphasize( ' ('.$rc_comment.')' ) ;
2295 }
2296 $r .= "<br />\n" ;
2297 }
2298 $r .= "</div>\n" ;
2299
2300 $this->rcCacheIndex++ ;
2301 return $r ;
2302 }
2303
2304 /**
2305 * If enhanced RC is in use, this function takes the previously cached
2306 * RC lines, arranges them, and outputs the HTML
2307 */
2308 function recentChangesBlock () {
2309 global $wgStylePath ;
2310 if ( count ( $this->rc_cache ) == 0 ) return '' ;
2311 $blockOut = '';
2312 foreach ( $this->rc_cache AS $secureName => $block ) {
2313 if ( count ( $block ) < 2 ) {
2314 $blockOut .= $this->recentChangesBlockLine ( array_shift ( $block ) ) ;
2315 } else {
2316 $blockOut .= $this->recentChangesBlockGroup ( $block ) ;
2317 }
2318 }
2319
2320 return '<div>'.$blockOut.'</div>' ;
2321 }
2322
2323 /**
2324 * Called in a loop over all displayed RC entries
2325 * Either returns the line, or caches it for later use
2326 */
2327 function recentChangesLine( &$rc, $watched = false ) {
2328 global $wgUser ;
2329 $usenew = $wgUser->getOption( 'usenewrc' );
2330 if ( $usenew )
2331 $line = $this->recentChangesLineNew ( $rc, $watched ) ;
2332 else
2333 $line = $this->recentChangesLineOld ( $rc, $watched ) ;
2334 return $line ;
2335 }
2336
2337 function recentChangesLineOld( &$rc, $watched = false ) {
2338 global $wgTitle, $wgLang, $wgUser, $wgRCSeconds, $wgUseRCPatrol, $wgOnlySysopsCanPatrol;
2339
2340 # Extract DB fields into local scope
2341 extract( $rc->mAttribs );
2342 $curIdEq = 'curid=' . $rc_cur_id;
2343
2344 # Make date header if necessary
2345 $date = $wgLang->date( $rc_timestamp, true);
2346 $s = '';
2347 if ( $date != $this->lastdate ) {
2348 if ( '' != $this->lastdate ) { $s .= "</ul>\n"; }
2349 $s .= "<h4>{$date}</h4>\n<ul class='special'>";
2350 $this->lastdate = $date;
2351 $this->rclistOpen = true;
2352 }
2353
2354 # If this edit has not yet been patrolled, make it stick out
2355 $s .= ( ! $wgUseRCPatrol || $rc_patrolled ) ? '<li> ' : '<li class="not_patrolled"> ';
2356
2357 if ( $rc_type == RC_MOVE || $rc_type == RC_MOVE_OVER_REDIRECT ) {
2358 # Diff
2359 $s .= '(' . wfMsg( 'diff' ) . ') (';
2360 # Hist
2361 $s .= $this->makeKnownLinkObj( $rc->getMovedToTitle(), wfMsg( 'hist' ), 'action=history' ) .
2362 ') . . ';
2363
2364 # "[[x]] moved to [[y]]"
2365 $msg = ( $rc_type == RC_MOVE ) ? '1movedto2' : '1movedto2_redir';
2366 $s .= wfMsg( $msg, $this->makeKnownLinkObj( $rc->getTitle(), '', 'redirect=no' ),
2367 $this->makeKnownLinkObj( $rc->getMovedToTitle(), '' ) );
2368 } elseif( $rc_namespace == NS_SPECIAL && preg_match( '!^Log/(.*)$!', $rc_title, $matches ) ) {
2369 # Log updates, etc
2370 $logtype = $matches[1];
2371 $logname = LogPage::logName( $logtype );
2372 $s .= '(' . $this->makeKnownLinkObj( $rc->getTitle(), $logname ) . ')';
2373 } else {
2374 # Diff link
2375 if ( $rc_type == RC_NEW || $rc_type == RC_LOG ) {
2376 $diffLink = wfMsg( 'diff' );
2377 } else {
2378 if ( $wgUseRCPatrol && $rc_patrolled == 0 && $wgUser->getID() != 0 &&
2379 ( $wgUser->isSysop() || !$wgOnlySysopsCanPatrol ) )
2380 $rcidparam = "&rcid={$rc_id}";
2381 else
2382 $rcidparam = "";
2383 $diffLink = $this->makeKnownLinkObj( $rc->getTitle(), wfMsg( 'diff' ),
2384 "{$curIdEq}&diff={$rc_this_oldid}&oldid={$rc_last_oldid}{$rcidparam}",
2385 '', '', ' tabindex="'.$rc->counter.'"');
2386 }
2387 $s .= '('.$diffLink.') (';
2388
2389 # History link
2390 $s .= $this->makeKnownLinkObj( $rc->getTitle(), wfMsg( 'hist' ), $curIdEq.'&action=history' );
2391 $s .= ') . . ';
2392
2393 # M and N (minor and new)
2394 if ( $rc_minor ) { $s .= ' <span class="minor">'.wfMsg( "minoreditletter" ).'</span>'; }
2395 if ( $rc_type == RC_NEW ) { $s .= '<span class="newpage">'.wfMsg( "newpageletter" ).'</span>'; }
2396
2397 # Article link
2398 # If it's a new article, there is no diff link, but if it hasn't been
2399 # patrolled yet, we need to give users a way to do so
2400 if ( $wgUseRCPatrol && $rc_type == RC_NEW && $rc_patrolled == 0 &&
2401 $wgUser->getID() != 0 && ( $wgUser->isSysop() || !$wgOnlySysopsCanPatrol ) )
2402 $articleLink = $this->makeKnownLinkObj( $rc->getTitle(), '', "rcid={$rc_id}" );
2403 else
2404 $articleLink = $this->makeKnownLinkObj( $rc->getTitle(), '' );
2405
2406 if ( $watched ) {
2407 $articleLink = '<strong>'.$articleLink.'</strong>';
2408 }
2409 $s .= ' '.$articleLink;
2410
2411 }
2412
2413 # Timestamp
2414 $s .= '; ' . $wgLang->time( $rc_timestamp, true, $wgRCSeconds ) . ' . . ';
2415
2416 # User link (or contributions for unregistered users)
2417 if ( 0 == $rc_user ) {
2418 $userLink = $this->makeKnownLink( $wgLang->specialPage( 'Contributions' ),
2419 $rc_user_text, 'target=' . $rc_user_text );
2420 } else {
2421 $userLink = $this->makeLink( $wgLang->getNsText( NS_USER ) . ':'.$rc_user_text, $rc_user_text );
2422 }
2423 $s .= $userLink;
2424
2425 # User talk link
2426 $talkname=$wgLang->getNsText(NS_TALK); # use the shorter name
2427 global $wgDisableAnonTalk;
2428 if( 0 == $rc_user && $wgDisableAnonTalk ) {
2429 $userTalkLink = '';
2430 } else {
2431 $utns=$wgLang->getNsText(NS_USER_TALK);
2432 $userTalkLink= $this->makeLink($utns . ':'.$rc_user_text, $talkname );
2433 }
2434 # Block link
2435 $blockLink='';
2436 if ( ( 0 == $rc_user ) && $wgUser->isSysop() ) {
2437 $blockLink = $this->makeKnownLink( $wgLang->specialPage(
2438 'Blockip' ), wfMsg( 'blocklink' ), 'ip='.$rc_user_text );
2439
2440 }
2441 if($blockLink) {
2442 if($userTalkLink) $userTalkLink .= ' | ';
2443 $userTalkLink .= $blockLink;
2444 }
2445 if($userTalkLink) $s.=' ('.$userTalkLink.')';
2446
2447 # Add comment
2448 if ( '' != $rc_comment && '*' != $rc_comment && $rc_type != RC_MOVE && $rc_type != RC_MOVE_OVER_REDIRECT ) {
2449 $rc_comment=$this->formatComment($rc_comment,$rc->getTitle());
2450 $s .= $wgLang->emphasize(' (' . $rc_comment . ')');
2451 }
2452 $s .= "</li>\n";
2453
2454 return $s;
2455 }
2456
2457 function recentChangesLineNew( &$baseRC, $watched = false ) {
2458 global $wgTitle, $wgLang, $wgUser, $wgRCSeconds;
2459
2460 # Create a specialised object
2461 $rc = RCCacheEntry::newFromParent( $baseRC ) ;
2462
2463 # Extract fields from DB into the function scope (rc_xxxx variables)
2464 extract( $rc->mAttribs );
2465 $curIdEq = 'curid=' . $rc_cur_id;
2466
2467 # If it's a new day, add the headline and flush the cache
2468 $date = $wgLang->date( $rc_timestamp, true);
2469 $ret = '';
2470 if ( $date != $this->lastdate ) {
2471 # Process current cache
2472 $ret = $this->recentChangesBlock () ;
2473 $this->rc_cache = array() ;
2474 $ret .= "<h4>{$date}</h4>\n";
2475 $this->lastdate = $date;
2476 }
2477
2478 # Make article link
2479 if ( $rc_type == RC_MOVE || $rc_type == RC_MOVE_OVER_REDIRECT ) {
2480 $msg = ( $rc_type == RC_MOVE ) ? "1movedto2" : "1movedto2_redir";
2481 $clink = wfMsg( $msg, $this->makeKnownLinkObj( $rc->getTitle(), '', 'redirect=no' ),
2482 $this->makeKnownLinkObj( $rc->getMovedToTitle(), '' ) );
2483 } elseif( $rc_namespace == NS_SPECIAL && preg_match( '!^Log/(.*)$!', $rc_title, $matches ) ) {
2484 # Log updates, etc
2485 $logtype = $matches[1];
2486 $logname = LogPage::logName( $logtype );
2487 $clink = '(' . $this->makeKnownLinkObj( $rc->getTitle(), $logname ) . ')';
2488 } else {
2489 $clink = $this->makeKnownLinkObj( $rc->getTitle(), '' ) ;
2490 }
2491
2492 $time = $wgLang->time( $rc_timestamp, true, $wgRCSeconds );
2493 $rc->watched = $watched ;
2494 $rc->link = $clink ;
2495 $rc->timestamp = $time;
2496
2497 # Make "cur" and "diff" links
2498 if ( ( $rc_type == RC_NEW && $rc_this_oldid == 0 ) || $rc_type == RC_LOG || $rc_type == RC_MOVE || $rc_type == RC_MOVE_OVER_REDIRECT ) {
2499 $curLink = wfMsg( 'cur' );
2500 $diffLink = wfMsg( 'diff' );
2501 } else {
2502 $query = $curIdEq.'&diff=0&oldid='.$rc_this_oldid;
2503 $aprops = ' tabindex="'.$baseRC->counter.'"';
2504 $curLink = $this->makeKnownLinkObj( $rc->getTitle(), wfMsg( 'cur' ), $query, '' ,'' , $aprops );
2505 $diffLink = $this->makeKnownLinkObj( $rc->getTitle(), wfMsg( 'diff'), $query, '' ,'' , $aprops );
2506 }
2507
2508 # Make "last" link
2509 $titleObj = $rc->getTitle();
2510 if ( $rc_last_oldid == 0 || $rc_type == RC_LOG || $rc_type == RC_MOVE || $rc_type == RC_MOVE_OVER_REDIRECT ) {
2511 $lastLink = wfMsg( 'last' );
2512 } else {
2513 $lastLink = $this->makeKnownLinkObj( $rc->getTitle(), wfMsg( 'last' ),
2514 $curIdEq.'&diff='.$rc_this_oldid.'&oldid='.$rc_last_oldid );
2515 }
2516
2517 # Make user link (or user contributions for unregistered users)
2518 if ( $rc_user == 0 ) {
2519 $userLink = $this->makeKnownLink( $wgLang->specialPage( 'Contributions' ),
2520 $rc_user_text, 'target=' . $rc_user_text );
2521 } else {
2522 $userLink = $this->makeLink( $wgLang->getNsText(
2523 Namespace::getUser() ) . ':'.$rc_user_text, $rc_user_text );
2524 }
2525
2526 $rc->userlink = $userLink;
2527 $rc->lastlink = $lastLink;
2528 $rc->curlink = $curLink;
2529 $rc->difflink = $diffLink;
2530
2531 # Make user talk link
2532 $utns=$wgLang->getNsText(NS_USER_TALK);
2533 $talkname=$wgLang->getNsText(NS_TALK); # use the shorter name
2534 $userTalkLink= $this->makeLink($utns . ':'.$rc_user_text, $talkname );
2535
2536 global $wgDisableAnonTalk;
2537 if ( ( 0 == $rc_user ) && $wgUser->isSysop() ) {
2538 $blockLink = $this->makeKnownLink( $wgLang->specialPage(
2539 'Blockip' ), wfMsg( 'blocklink' ), 'ip='.$rc_user_text );
2540 if( $wgDisableAnonTalk )
2541 $rc->usertalklink = ' ('.$blockLink.')';
2542 else
2543 $rc->usertalklink = ' ('.$userTalkLink.' | '.$blockLink.')';
2544 } else {
2545 if( $wgDisableAnonTalk && ($rc_user == 0) )
2546 $rc->usertalklink = '';
2547 else
2548 $rc->usertalklink = ' ('.$userTalkLink.')';
2549 }
2550
2551 # Put accumulated information into the cache, for later display
2552 # Page moves go on their own line
2553 $title = $rc->getTitle();
2554 $secureName = $title->getPrefixedDBkey();
2555 if ( $rc_type == RC_MOVE || $rc_type == RC_MOVE_OVER_REDIRECT ) {
2556 # Use an @ character to prevent collision with page names
2557 $this->rc_cache['@@' . ($this->rcMoveIndex++)] = array($rc);
2558 } else {
2559 if ( !isset ( $this->rc_cache[$secureName] ) ) $this->rc_cache[$secureName] = array() ;
2560 array_push ( $this->rc_cache[$secureName] , $rc ) ;
2561 }
2562 return $ret;
2563 }
2564
2565 function endImageHistoryList() {
2566 $s = "</ul>\n";
2567 return $s;
2568 }
2569
2570 /**
2571 * This function is called by all recent changes variants, by the page history,
2572 * and by the user contributions list. It is responsible for formatting edit
2573 * comments. It escapes any HTML in the comment, but adds some CSS to format
2574 * auto-generated comments (from section editing) and formats [[wikilinks]].
2575 *
2576 * The &$title parameter must be a title OBJECT. It is used to generate a
2577 * direct link to the section in the autocomment.
2578 * @author Erik Moeller <moeller@scireview.de>
2579 *
2580 * Note: there's not always a title to pass to this function.
2581 * Since you can't set a default parameter for a reference, I've turned it
2582 * temporarily to a value pass. Should be adjusted further. --brion
2583 */
2584 function formatComment($comment, $title = NULL) {
2585 global $wgLang;
2586 $comment = htmlspecialchars( $comment );
2587
2588 # The pattern for autogen comments is / * foo * /, which makes for
2589 # some nasty regex.
2590 # We look for all comments, match any text before and after the comment,
2591 # add a separator where needed and format the comment itself with CSS
2592 while (preg_match('/(.*)\/\*\s*(.*?)\s*\*\/(.*)/', $comment,$match)) {
2593 $pre=$match[1];
2594 $auto=$match[2];
2595 $post=$match[3];
2596 $link='';
2597 if($title) {
2598 $section=$auto;
2599
2600 # This is hackish but should work in most cases.
2601 $section=str_replace('[[','',$section);
2602 $section=str_replace(']]','',$section);
2603 $title->mFragment=$section;
2604 $link=$this->makeKnownLinkObj($title,wfMsg('sectionlink'));
2605 }
2606 $sep='-';
2607 $auto=$link.$auto;
2608 if($pre) { $auto = $sep.' '.$auto; }
2609 if($post) { $auto .= ' '.$sep; }
2610 $auto='<span class="autocomment">'.$auto.'</span>';
2611 $comment=$pre.$auto.$post;
2612 }
2613
2614 # format regular and media links - all other wiki formatting
2615 # is ignored
2616 $medians = $wgLang->getNsText(Namespace::getMedia()).':';
2617 while(preg_match('/\[\[(.*?)(\|(.*?))*\]\](.*)$/',$comment,$match)) {
2618 # Handle link renaming [[foo|text]] will show link as "text"
2619 if( "" != $match[3] ) {
2620 $text = $match[3];
2621 } else {
2622 $text = $match[1];
2623 }
2624 if( preg_match( '/^' . $medians . '(.*)$/i', $match[1], $submatch ) ) {
2625 # Media link; trail not supported.
2626 $linkRegexp = '/\[\[(.*?)\]\]/';
2627 $thelink = $this->makeMediaLink( $submatch[1], "", $text );
2628 } else {
2629 # Other kind of link
2630 if( preg_match( wfMsg( "linktrail" ), $match[4], $submatch ) ) {
2631 $trail = $submatch[1];
2632 } else {
2633 $trail = "";
2634 }
2635 $linkRegexp = '/\[\[(.*?)\]\]' . preg_quote( $trail, '/' ) . '/';
2636 if ($match[1][0] == ':')
2637 $match[1] = substr($match[1], 1);
2638 $thelink = $this->makeLink( $match[1], $text, "", $trail );
2639 }
2640 $comment = preg_replace( $linkRegexp, $thelink, $comment, 1 );
2641 }
2642 return $comment;
2643 }
2644
2645 function imageHistoryLine( $iscur, $timestamp, $img, $user, $usertext, $size, $description ) {
2646 global $wgUser, $wgLang, $wgTitle;
2647
2648 $datetime = $wgLang->timeanddate( $timestamp, true );
2649 $del = wfMsg( 'deleteimg' );
2650 $delall = wfMsg( 'deleteimgcompletely' );
2651 $cur = wfMsg( 'cur' );
2652
2653 if ( $iscur ) {
2654 $url = Image::wfImageUrl( $img );
2655 $rlink = $cur;
2656 if ( $wgUser->isSysop() ) {
2657 $link = $wgTitle->escapeLocalURL( 'image=' . $wgTitle->getPartialURL() .
2658 '&action=delete' );
2659 $style = $this->getInternalLinkAttributes( $link, $delall );
2660
2661 $dlink = '<a href="'.$link.'"'.$style.'>'.$delall.'</a>';
2662 } else {
2663 $dlink = $del;
2664 }
2665 } else {
2666 $url = htmlspecialchars( wfImageArchiveUrl( $img ) );
2667 if( $wgUser->getID() != 0 && $wgTitle->userCanEdit() ) {
2668 $rlink = $this->makeKnownLink( $wgTitle->getPrefixedText(),
2669 wfMsg( 'revertimg' ), 'action=revert&oldimage=' .
2670 urlencode( $img ) );
2671 $dlink = $this->makeKnownLink( $wgTitle->getPrefixedText(),
2672 $del, 'action=delete&oldimage=' . urlencode( $img ) );
2673 } else {
2674 # Having live active links for non-logged in users
2675 # means that bots and spiders crawling our site can
2676 # inadvertently change content. Baaaad idea.
2677 $rlink = wfMsg( 'revertimg' );
2678 $dlink = $del;
2679 }
2680 }
2681 if ( 0 == $user ) {
2682 $userlink = $usertext;
2683 } else {
2684 $userlink = $this->makeLink( $wgLang->getNsText( Namespace::getUser() ) .
2685 ':'.$usertext, $usertext );
2686 }
2687 $nbytes = wfMsg( 'nbytes', $size );
2688 $style = $this->getInternalLinkAttributes( $url, $datetime );
2689
2690 $s = "<li> ({$dlink}) ({$rlink}) <a href=\"{$url}\"{$style}>{$datetime}</a>"
2691 . " . . {$userlink} ({$nbytes})";
2692
2693 if ( '' != $description && '*' != $description ) {
2694 $sk=$wgUser->getSkin();
2695 $s .= $wgLang->emphasize(' (' . $sk->formatComment($description,$wgTitle) . ')');
2696 }
2697 $s .= "</li>\n";
2698 return $s;
2699 }
2700
2701 function tocIndent($level) {
2702 return str_repeat( '<div class="tocindent">'."\n", $level>0 ? $level : 0 );
2703 }
2704
2705 function tocUnindent($level) {
2706 return str_repeat( "</div>\n", $level>0 ? $level : 0 );
2707 }
2708
2709 /**
2710 * parameter level defines if we are on an indentation level
2711 */
2712 function tocLine( $anchor, $tocline, $level ) {
2713 $link = '<a href="#'.$anchor.'">'.$tocline.'</a><br />';
2714 if($level) {
2715 return $link."\n";
2716 } else {
2717 return '<div class="tocline">'.$link."</div>\n";
2718 }
2719
2720 }
2721
2722 function tocTable($toc) {
2723 # note to CSS fanatics: putting this in a div does not work -- div won't auto-expand
2724 # try min-width & co when somebody gets a chance
2725 $hideline = ' <script type="text/javascript">showTocToggle("' . addslashes( wfMsg('showtoc') ) . '","' . addslashes( wfMsg('hidetoc') ) . '")</script>';
2726 return
2727 '<table border="0" id="toc"><tr id="toctitle"><td align="center">'."\n".
2728 '<b>'.wfMsg('toc').'</b>' .
2729 $hideline .
2730 '</td></tr><tr id="tocinside"><td>'."\n".
2731 $toc."</td></tr></table>\n";
2732 }
2733
2734 /**
2735 * These two do not check for permissions: check $wgTitle->userCanEdit
2736 * before calling them
2737 */
2738 function editSectionScriptForOther( $title, $section, $head ) {
2739 $ttl = Title::newFromText( $title );
2740 $url = $ttl->escapeLocalURL( 'action=edit&section='.$section );
2741 return '<span oncontextmenu=\'document.location="'.$url.'";return false;\'>'.$head.'</span>';
2742 }
2743
2744 function editSectionScript( $section, $head ) {
2745 global $wgTitle, $wgRequest;
2746 if( $wgRequest->getInt( 'oldid' ) && ( $wgRequest->getVal( 'diff' ) != '0' ) ) {
2747 return $head;
2748 }
2749 $url = $wgTitle->escapeLocalURL( 'action=edit&section='.$section );
2750 return '<span oncontextmenu=\'document.location="'.$url.'";return false;\'>'.$head.'</span>';
2751 }
2752
2753 function editSectionLinkForOther( $title, $section ) {
2754 global $wgRequest;
2755 global $wgUser, $wgLang;
2756
2757 $title = Title::newFromText($title);
2758 $editurl = '&section='.$section;
2759 $url = $this->makeKnownLink($title->getPrefixedText(),wfMsg('editsection'),'action=edit'.$editurl);
2760
2761 if( $wgLang->isRTL() ) {
2762 $farside = 'left';
2763 $nearside = 'right';
2764 } else {
2765 $farside = 'right';
2766 $nearside = 'left';
2767 }
2768 return "<div class=\"editsection\" style=\"float:$farside;margin-$nearside:5px;\">[".$url."]</div>";
2769
2770 }
2771
2772 function editSectionLink( $section ) {
2773 global $wgRequest;
2774 global $wgTitle, $wgUser, $wgLang;
2775
2776 if( $wgRequest->getInt( 'oldid' ) && ( $wgRequest->getVal( 'diff' ) != '0' ) ) {
2777 # Section edit links would be out of sync on an old page.
2778 # But, if we're diffing to the current page, they'll be
2779 # correct.
2780 return '';
2781 }
2782
2783 $editurl = '&section='.$section;
2784 $url = $this->makeKnownLink($wgTitle->getPrefixedText(),wfMsg('editsection'),'action=edit'.$editurl);
2785
2786 if( $wgLang->isRTL() ) {
2787 $farside = 'left';
2788 $nearside = 'right';
2789 } else {
2790 $farside = 'right';
2791 $nearside = 'left';
2792 }
2793 return "<div class=\"editsection\" style=\"float:$farside;margin-$nearside:5px;\">[".$url."]</div>";
2794
2795 }
2796
2797 /**
2798 * This function is called by EditPage.php and shows a bulletin board style
2799 * toolbar for common editing functions. It can be disabled in the user
2800 * preferences.
2801 * The necessary JavaScript code can be found in style/wikibits.js.
2802 */
2803 function getEditToolbar() {
2804 global $wgStylePath, $wgLang, $wgMimeType;
2805
2806 /**
2807 * toolarray an array of arrays which each include the filename of
2808 * the button image (without path), the opening tag, the closing tag,
2809 * and optionally a sample text that is inserted between the two when no
2810 * selection is highlighted.
2811 * The tip text is shown when the user moves the mouse over the button.
2812 *
2813 * Already here are accesskeys (key), which are not used yet until someone
2814 * can figure out a way to make them work in IE. However, we should make
2815 * sure these keys are not defined on the edit page.
2816 */
2817 $toolarray=array(
2818 array( 'image'=>'button_bold.png',
2819 'open' => "\'\'\'",
2820 'close' => "\'\'\'",
2821 'sample'=> wfMsg('bold_sample'),
2822 'tip' => wfMsg('bold_tip'),
2823 'key' => 'B'
2824 ),
2825 array( 'image'=>'button_italic.png',
2826 'open' => "\'\'",
2827 'close' => "\'\'",
2828 'sample'=> wfMsg('italic_sample'),
2829 'tip' => wfMsg('italic_tip'),
2830 'key' => 'I'
2831 ),
2832 array( 'image'=>'button_link.png',
2833 'open' => '[[',
2834 'close' => ']]',
2835 'sample'=> wfMsg('link_sample'),
2836 'tip' => wfMsg('link_tip'),
2837 'key' => 'L'
2838 ),
2839 array( 'image'=>'button_extlink.png',
2840 'open' => '[',
2841 'close' => ']',
2842 'sample'=> wfMsg('extlink_sample'),
2843 'tip' => wfMsg('extlink_tip'),
2844 'key' => 'X'
2845 ),
2846 array( 'image'=>'button_headline.png',
2847 'open' => "\\n== ",
2848 'close' => " ==\\n",
2849 'sample'=> wfMsg('headline_sample'),
2850 'tip' => wfMsg('headline_tip'),
2851 'key' => 'H'
2852 ),
2853 array( 'image'=>'button_image.png',
2854 'open' => '[['.$wgLang->getNsText(NS_IMAGE).":",
2855 'close' => ']]',
2856 'sample'=> wfMsg('image_sample'),
2857 'tip' => wfMsg('image_tip'),
2858 'key' => 'D'
2859 ),
2860 array( 'image' => 'button_media.png',
2861 'open' => '[['.$wgLang->getNsText(NS_MEDIA).':',
2862 'close' => ']]',
2863 'sample'=> wfMsg('media_sample'),
2864 'tip' => wfMsg('media_tip'),
2865 'key' => 'M'
2866 ),
2867 array( 'image' => 'button_math.png',
2868 'open' => "\\<math\\>",
2869 'close' => "\\</math\\>",
2870 'sample'=> wfMsg('math_sample'),
2871 'tip' => wfMsg('math_tip'),
2872 'key' => 'C'
2873 ),
2874 array( 'image' => 'button_nowiki.png',
2875 'open' => "\\<nowiki\\>",
2876 'close' => "\\</nowiki\\>",
2877 'sample'=> wfMsg('nowiki_sample'),
2878 'tip' => wfMsg('nowiki_tip'),
2879 'key' => 'N'
2880 ),
2881 array( 'image' => 'button_sig.png',
2882 'open' => '--~~~~',
2883 'close' => '',
2884 'sample'=> '',
2885 'tip' => wfMsg('sig_tip'),
2886 'key' => 'Y'
2887 ),
2888 array( 'image' => 'button_hr.png',
2889 'open' => "\\n----\\n",
2890 'close' => '',
2891 'sample'=> '',
2892 'tip' => wfMsg('hr_tip'),
2893 'key' => 'R'
2894 )
2895 );
2896 $toolbar ="<script type='text/javascript'>\n/*<![CDATA[*/\n";
2897
2898 $toolbar.="document.writeln(\"<div id='toolbar'>\");\n";
2899 foreach($toolarray as $tool) {
2900
2901 $image=$wgStylePath.'/common/images/'.$tool['image'];
2902 $open=$tool['open'];
2903 $close=$tool['close'];
2904 $sample = addslashes( $tool['sample'] );
2905
2906 // Note that we use the tip both for the ALT tag and the TITLE tag of the image.
2907 // Older browsers show a "speedtip" type message only for ALT.
2908 // Ideally these should be different, realistically they
2909 // probably don't need to be.
2910 $tip = addslashes( $tool['tip'] );
2911
2912 #$key = $tool["key"];
2913
2914 $toolbar.="addButton('$image','$tip','$open','$close','$sample');\n";
2915 }
2916
2917 $toolbar.="addInfobox('" . addslashes( wfMsg( "infobox" ) ) . "','" . addslashes(wfMsg("infobox_alert")) . "');\n";
2918 $toolbar.="document.writeln(\"</div>\");\n";
2919
2920 $toolbar.="/*]]>*/\n</script>";
2921 return $toolbar;
2922 }
2923
2924 /**
2925 * @access public
2926 */
2927 function suppressUrlExpansion() {
2928 return false;
2929 }
2930 }
2931
2932 }
2933 ?>