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