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