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