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