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