finally found the reason for the li bug, top a now in skin
[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 $link = $nt->getPrefixedURL();
1309 if ( "" == $text ) { $text = $nt->getPrefixedText(); }
1310 $style = $this->getExternalLinkAttributes( $link, $text );
1311
1312 $inside = "";
1313 if ( "" != $trail ) {
1314 if ( preg_match( "/^([a-z]+)(.*)$$/sD", $trail, $m ) ) {
1315 $inside = $m[1];
1316 $trail = $m[2];
1317 }
1318 }
1319 $retVal = "<a href=\"{$u}\"{$style}>{$text}{$inside}</a>{$trail}";
1320 } elseif ( 0 == $nt->getNamespace() && "" == $nt->getText() ) {
1321 $retVal = $this->makeKnownLinkObj( $nt, $text, $query, $trail, $prefix );
1322 } elseif ( ( -1 == $nt->getNamespace() ) ||
1323 ( Namespace::getImage() == $nt->getNamespace() ) ) {
1324 $retVal = $this->makeKnownLinkObj( $nt, $text, $query, $trail, $prefix );
1325 } else {
1326 $aid = $nt->getArticleID() ;
1327 if ( 0 == $aid ) {
1328 $retVal = $this->makeBrokenLinkObj( $nt, $text, $query, $trail, $prefix );
1329 } else {
1330 $threshold = $wgUser->getOption("stubthreshold") ;
1331 if ( $threshold > 0 ) {
1332 $res = wfQuery ( "SELECT LENGTH(cur_text) AS x, cur_namespace, cur_is_redirect FROM cur WHERE cur_id='{$aid}'", DB_READ ) ;
1333
1334 if ( wfNumRows( $res ) > 0 ) {
1335 $s = wfFetchObject( $res );
1336 $size = $s->x;
1337 if ( $s->cur_is_redirect OR $s->cur_namespace != 0 ) {
1338 $size = $threshold*2 ; # Really big
1339 }
1340 wfFreeResult( $res );
1341 } else {
1342 $size = $threshold*2 ; # Really big
1343 }
1344 } else {
1345 $size = 1 ;
1346 }
1347 if ( $size < $threshold ) {
1348 $retVal = $this->makeStubLinkObj( $nt, $text, $query, $trail, $prefix );
1349 } else {
1350 $retVal = $this->makeKnownLinkObj( $nt, $text, $query, $trail, $prefix );
1351 }
1352 }
1353 }
1354 return $retVal;
1355 }
1356
1357 # Pass a title object, not a title string
1358 function makeKnownLinkObj( &$nt, $text = "", $query = "", $trail = "", $prefix = "" )
1359 {
1360 global $wgOut, $wgTitle;
1361
1362 $fname = "Skin::makeKnownLinkObj";
1363 wfProfileIn( $fname );
1364
1365 $link = $nt->getPrefixedURL();
1366
1367 if ( "" == $link ) {
1368 $u = "";
1369 if ( "" == $text ) { $text = $nt->getFragment(); }
1370 } else {
1371 $u = $nt->escapeLocalURL( $query );
1372 }
1373 if ( "" != $nt->getFragment() ) {
1374 $u .= "#" . wfEscapeHTML( $nt->getFragment() );
1375 }
1376 if ( "" == $text ) { $text = $nt->getPrefixedText(); }
1377 $style = $this->getInternalLinkAttributesObj( $nt, $text );
1378
1379 $inside = "";
1380 if ( "" != $trail ) {
1381 if ( preg_match( $this->linktrail, $trail, $m ) ) {
1382 $inside = $m[1];
1383 $trail = $m[2];
1384 }
1385 }
1386 $r = "<a href=\"{$u}\"{$style}>{$prefix}{$text}{$inside}</a>{$trail}";
1387 wfProfileOut( $fname );
1388 return $r;
1389 }
1390
1391 # Pass a title object, not a title string
1392 function makeBrokenLinkObj( &$nt, $text = "", $query = "", $trail = "", $prefix = "" )
1393 {
1394 global $wgOut, $wgUser;
1395
1396 $fname = "Skin::makeBrokenLinkObj";
1397 wfProfileIn( $fname );
1398
1399 if ( "" == $query ) {
1400 $q = "action=edit";
1401 } else {
1402 $q = "action=edit&{$query}";
1403 }
1404 $u = $nt->escapeLocalURL( $q );
1405
1406 if ( "" == $text ) { $text = $nt->getPrefixedText(); }
1407 $style = $this->getInternalLinkAttributesObj( $nt, $text, "yes" );
1408
1409 $inside = "";
1410 if ( "" != $trail ) {
1411 if ( preg_match( $this->linktrail, $trail, $m ) ) {
1412 $inside = $m[1];
1413 $trail = $m[2];
1414 }
1415 }
1416 if ( $wgUser->getOption( "highlightbroken" ) ) {
1417 $s = "<a href=\"{$u}\"{$style}>{$prefix}{$text}{$inside}</a>{$trail}";
1418 } else {
1419 $s = "{$prefix}{$text}{$inside}<a href=\"{$u}\"{$style}>?</a>{$trail}";
1420 }
1421
1422 wfProfileOut( $fname );
1423 return $s;
1424 }
1425
1426 # Pass a title object, not a title string
1427 function makeStubLinkObj( &$nt, $text = "", $query = "", $trail = "", $prefix = "" )
1428 {
1429 global $wgOut, $wgUser;
1430
1431 $link = $nt->getPrefixedURL();
1432
1433 $u = $nt->escapeLocalURL( $query );
1434
1435 if ( "" == $text ) { $text = $nt->getPrefixedText(); }
1436 $style = $this->getInternalLinkAttributesObj( $nt, $text, "stub" );
1437
1438 $inside = "";
1439 if ( "" != $trail ) {
1440 if ( preg_match( $this->linktrail, $trail, $m ) ) {
1441 $inside = $m[1];
1442 $trail = $m[2];
1443 }
1444 }
1445 if ( $wgUser->getOption( "highlightbroken" ) ) {
1446 $s = "<a href=\"{$u}\"{$style}>{$prefix}{$text}{$inside}</a>{$trail}";
1447 } else {
1448 $s = "{$prefix}{$text}{$inside}<a href=\"{$u}\"{$style}>!</a>{$trail}";
1449 }
1450 return $s;
1451 }
1452
1453 function fnamePart( $url )
1454 {
1455 $basename = strrchr( $url, "/" );
1456 if ( false === $basename ) { $basename = $url; }
1457 else { $basename = substr( $basename, 1 ); }
1458 return wfEscapeHTML( $basename );
1459 }
1460
1461 function makeImage( $url, $alt = "" )
1462 {
1463 global $wgOut;
1464
1465 if ( "" == $alt ) { $alt = $this->fnamePart( $url ); }
1466 $s = "<img src=\"{$url}\" alt=\"{$alt}\" />";
1467 return $s;
1468 }
1469
1470 function makeImageLink( $name, $url, $alt = "" ) {
1471 $nt = Title::makeTitle( Namespace::getImage(), $name );
1472 return $this->makeImageLinkObj( $nt, $alt );
1473 }
1474
1475 function makeImageLinkObj( $nt, $alt = "" ) {
1476 global $wgLang, $wgUseImageResize;
1477 $name = $nt->getDBKey();
1478 $url = wfImageUrl( $name );
1479 $align = "";
1480 $prefix = $postfix = "";
1481
1482 if ( $wgUseImageResize ) {
1483 # Check if the alt text is of the form "options|alt text"
1484 # Options are:
1485 # * thumbnail make a thumbnail with enlarge-icon and caption, alignment depends on lang
1486 # * left no resizing, just left align. label is used for alt= only
1487 # * right same, but right aligned
1488 # * none same, but not aligned
1489 # * ___px scale to ___ pixels width, no aligning. e.g. use in taxobox
1490
1491 $part = explode( "|", $alt);
1492
1493 $mwThumb =& MagicWord::get( MAG_IMG_THUMBNAIL );
1494 $mwLeft =& MagicWord::get( MAG_IMG_LEFT );
1495 $mwRight =& MagicWord::get( MAG_IMG_RIGHT );
1496 $mwNone =& MagicWord::get( MAG_IMG_NONE );
1497 $mwWidth =& MagicWord::get( MAG_IMG_WIDTH );
1498 $mwCenter =& MagicWord::get( MAG_IMG_CENTER );
1499 $alt = $part[count($part)-1];
1500
1501 $thumb=false;
1502
1503 foreach( $part as $key => $val ) {
1504 if ( ! is_null( $mwThumb->matchVariableStartToEnd($val) ) ) {
1505 $thumb=true;
1506 } elseif ( ! is_null( $mwRight->matchVariableStartToEnd($val) ) ) {
1507 # remember to set an alignment, don't render immediately
1508 $align = "right";
1509 } elseif ( ! is_null( $mwLeft->matchVariableStartToEnd($val) ) ) {
1510 # remember to set an alignment, don't render immediately
1511 $align = "left";
1512 } elseif ( ! is_null( $mwCenter->matchVariableStartToEnd($val) ) ) {
1513 # remember to set an alignment, don't render immediately
1514 $align = "center";
1515 } elseif ( ! is_null( $mwNone->matchVariableStartToEnd($val) ) ) {
1516 # remember to set an alignment, don't render immediately
1517 $align = "none";
1518 } elseif ( ! is_null( $match = $mwWidth->matchVariableStartToEnd($val) ) ) {
1519 # $match is the image width in pixels
1520 $width = intval($match);
1521 }
1522 }
1523 if ( "center" == $align )
1524 {
1525 $prefix = '<span style="text-align: center">';
1526 $postfix = '</span>';
1527 $align = "none";
1528 }
1529
1530 if ( $thumb ) {
1531
1532 # Create a thumbnail. Alignment depends on language
1533 # writing direction, # right aligned for left-to-right-
1534 # languages ("Western languages"), left-aligned
1535 # for right-to-left-languages ("Semitic languages")
1536 #
1537 # If thumbnail width has not been provided, it is set
1538 # here to 180 pixels
1539 if ( $align == "" ) {
1540 $align = $wgLang->isRTL() ? "left" : "right";
1541 }
1542 if ( ! isset($width) ) {
1543 $width = 180;
1544 }
1545 return $prefix.$this->makeThumbLinkObj( $nt, $alt, $align, $width ).$postfix;
1546
1547 } elseif ( isset($width) ) {
1548
1549 # Create a resized image, without the additional thumbnail
1550 # features
1551 $url = $this->createThumb( $name, $width );
1552 }
1553 } # endif $wgUseImageResize
1554
1555 if ( empty( $alt ) ) {
1556 $alt = preg_replace( '/\.(.+?)^/', '', $name );
1557 }
1558 $alt = htmlspecialchars( $alt );
1559
1560 $u = $nt->escapeLocalURL();
1561 if ( $url == "" )
1562 {
1563 $s = str_replace( "$1", $name, wfMsg("missingimage") );
1564 } else {
1565 $s = "\n <a href=\"{$u}\" class='image' title=\"{$alt}\">\n" .
1566 " <img src=\"{$url}\" alt=\"{$alt}\" />\n </a>";
1567 }
1568 if ( "" != $align ) {
1569 $s = "<div class=\"float{$align}\"><span>{$s}\n</span></div>";
1570 }
1571 return $prefix.$s.$postfix;
1572 }
1573
1574 function createThumb( $name, $width ) {
1575 global $wgUploadDirectory;
1576 global $wgImageMagickConvertCommand;
1577 global $wgUseImageMagick;
1578 global $wgUseSquid, $wgInternalServer;
1579 $imgPath = wfImagePath( $name );
1580 $thumbName = $width."px-".$icon.$name;
1581 $thumbPath = wfImageThumbDir( $thumbName )."/".$thumbName;
1582 $thumbUrl = wfImageThumbUrl( $thumbName );
1583
1584 if ( ! file_exists( $imgPath ) )
1585 {
1586 # If there is no image, there will be no thumbnail
1587 return "";
1588 }
1589
1590 if ( (! file_exists( $thumbPath ) )
1591 || ( filemtime($thumbPath) < filemtime($imgPath) ) ) {
1592 # Squid purging
1593 if ( $wgUseSquid ) {
1594 $urlArr = Array(
1595 $wgInternalServer.$thumbUrl
1596 );
1597 wfPurgeSquidServers($urlArr);
1598 }
1599
1600 if ( $wgUseImageMagick ) {
1601 # use ImageMagick
1602 $cmd = $wgImageMagickConvertCommand .
1603 " -quality 85 -geometry {$width} ".
1604 escapeshellarg($imgPath) . " " .
1605 escapeshellarg($thumbPath);
1606 $conv = shell_exec( $cmd );
1607 } else {
1608 # Use PHP's builtin GD library functions.
1609 #
1610 # First find out what kind of file this is, and select the correct
1611 # input routine for this.
1612 list($src_width, $src_height, $src_type, $src_attr) = getimagesize( $imgPath );
1613 switch( $src_type ) {
1614 case 1: # GIF
1615 $src_image = imagecreatefromgif( $imgPath );
1616 break;
1617 case 2: # JPG
1618 $src_image = imagecreatefromjpeg( $imgPath );
1619 break;
1620 case 3: # PNG
1621 $src_image = imagecreatefrompng( $imgPath );
1622 break;
1623 case 15: # WBMP for WML
1624 $src_image = imagecreatefromwbmp( $imgPath );
1625 break;
1626 case 16: # XBM
1627 $src_image = imagecreatefromxbm( $imgPath );
1628 break;
1629 default:
1630 return "Image type not supported";
1631 break;
1632 }
1633 $height = floor( $src_height * ( $width/$src_width ) );
1634 $dst_image = imagecreatetruecolor( $width, $height );
1635 imagecopyresampled( $dst_image, $src_image,
1636 0,0,0,0,
1637 $width, $height, $src_width, $src_height );
1638 switch( $src_type ) {
1639 case 1: # GIF
1640 case 3: # PNG
1641 case 15: # WBMP
1642 case 16: # XBM
1643 #$thumbUrl .= ".png";
1644 #$thumbPath .= ".png";
1645 imagepng( $dst_image, $thumbPath );
1646 break;
1647 case 2: # JPEG
1648 #$thumbUrl .= ".jpg";
1649 #$thumbPath .= ".jpg";
1650 imageinterlace( $dst_image );
1651 imagejpeg( $dst_image, $thumbPath, 95 );
1652 break;
1653 default:
1654 break;
1655 }
1656 imagedestroy( $dst_image );
1657 imagedestroy( $src_image );
1658
1659
1660 }
1661 #
1662 # Check for zero-sized thumbnails. Those can be generated when
1663 # no disk space is available or some other error occurs
1664 #
1665 $thumbstat = stat( $thumbPath );
1666 $imgstat = stat( $imgPath );
1667 if( $thumbstat["size"] == 0 )
1668 {
1669 unlink( $thumbPath );
1670 }
1671
1672 }
1673 return $thumbUrl;
1674 }
1675
1676 function makeThumbLinkObj( $nt, $label = "", $align = "right", $boxwidth = 180 ) {
1677 global $wgUploadPath, $wgLang;
1678 $name = $nt->getDBKey();
1679 $image = Title::makeTitle( Namespace::getImage(), $name );
1680 $url = wfImageUrl( $name );
1681 $path = wfImagePath( $name );
1682
1683 #$label = htmlspecialchars( $label );
1684 $alt = preg_replace( "/<[^>]*>/", "", $label);
1685 $alt = htmlspecialchars( $alt );
1686
1687 if ( file_exists( $path ) )
1688 {
1689 list($width, $height, $type, $attr) = getimagesize( $path );
1690 } else {
1691 $width = $height = 200;
1692 }
1693 $boxheight = intval( $height/($width/$boxwidth) );
1694 if ( $boxwidth > $width ) {
1695 $boxwidth = $width;
1696 $boxheight = $height;
1697 }
1698
1699 $thumbUrl = $this->createThumb( $name, $boxwidth );
1700
1701 $u = $nt->escapeLocalURL();
1702
1703 $more = htmlspecialchars( wfMsg( "thumbnail-more" ) );
1704 $magnifyalign = $wgLang->isRTL() ? "left" : "right";
1705 $textalign = $wgLang->isRTL() ? " style=\"text-align:right\"" : "";
1706
1707 $s = "<div class=\"thumbnail-{$align}\" style=\"width:{$boxwidth}px;\"><div>";
1708 if ( $thumbUrl == "" ) {
1709 $s .= str_replace( "$1", $name, wfMsg("missingimage") );
1710 } else {
1711 $s .= "\n".' <a href="'.$u.'" class="internal" title="'.$alt.'">'."\n".
1712 ' <img src="'.$thumbUrl.'" alt="'.$alt.'" ' .
1713 ' width="'.$boxwidth.'" height="'.$boxheight.'" /></a>' ."\n".
1714 ' <a href="'.$u.'" class="internal" title="'.$more.'"> ' ."\n".
1715 ' <img src="'.$wgUploadPath.'/magnify-clip.png" ' .
1716 'width="26" height="24" align="'.$magnifyalign.'" alt="'.$more.'" /> </a>'."\n";
1717 }
1718 $s .= ' <p'.$textalign.'>'.$label."</p>\n</div></div>";
1719 return $s;
1720 }
1721
1722 function makeMediaLink( $name, $url, $alt = "" ) {
1723 $nt = Title::makeTitle( Namespace::getMedia(), $name );
1724 return $this->makeMediaLinkObj( $nt, $alt );
1725 }
1726
1727 function makeMediaLinkObj( $nt, $alt = "" )
1728 {
1729 $name = $nt->getDBKey();
1730 $url = wfImageUrl( $name );
1731 if ( empty( $alt ) ) {
1732 $alt = preg_replace( '/\.(.+?)^/', '', $name );
1733 }
1734
1735 $u = htmlspecialchars( $url );
1736 $s = "<a href=\"{$u}\" class='internal' title=\"{$alt}\">{$alt}</a>";
1737 return $s;
1738 }
1739
1740 function specialLink( $name, $key = "" )
1741 {
1742 global $wgLang;
1743
1744 if ( "" == $key ) { $key = strtolower( $name ); }
1745 $pn = $wgLang->ucfirst( $name );
1746 return $this->makeKnownLink( $wgLang->specialPage( $pn ),
1747 wfMsg( $key ) );
1748 }
1749
1750 # Called by history lists and recent changes
1751 #
1752
1753 # Returns text for the start of the tabular part of RC
1754 function beginRecentChangesList()
1755 {
1756 $this->rc_cache = array() ;
1757 $this->rcMoveIndex = 0;
1758 $this->rcCacheIndex = 0 ;
1759 $this->lastdate = "";
1760 return "";
1761 }
1762
1763 function beginImageHistoryList()
1764 {
1765 $s = "\n<h2>" . wfMsg( "imghistory" ) . "</h2>\n" .
1766 "<p>" . wfMsg( "imghistlegend" ) . "\n<ul class='special'>";
1767 return $s;
1768 }
1769
1770 # Returns text for the end of RC
1771 # If enhanced RC is in use, returns pretty much all the text
1772 function endRecentChangesList()
1773 {
1774 $s = $this->recentChangesBlock() ;
1775 $s .= "</ul>\n";
1776 return $s;
1777 }
1778
1779 # Enhanced RC ungrouped line
1780 function recentChangesBlockLine ( $rcObj )
1781 {
1782 global $wgUploadPath, $wgLang ;
1783
1784 # Get rc_xxxx variables
1785 extract( $rcObj->mAttribs ) ;
1786 $curIdEq = "curid=$rc_cur_id";
1787
1788 # Spacer image
1789 $r = "" ;
1790
1791 $r .= "<img src='{$wgUploadPath}/Arr_.png' width='12' height='12' border='0' />" ; $r .= "<tt>" ;
1792
1793 if ( $rc_type == RC_MOVE ) {
1794 $r .= "&nbsp;&nbsp;";
1795 } else {
1796 # M & N (minor & new)
1797 $M = wfMsg( "minoreditletter" );
1798 $N = wfMsg( "newpageletter" );
1799
1800 if ( $rc_type == RC_NEW ) {
1801 $r .= $N ;
1802 } else {
1803 $r .= "&nbsp;" ;
1804 }
1805 if ( $rc_minor ) {
1806 $r .= $M ;
1807 } else {
1808 $r .= "&nbsp;" ;
1809 }
1810 }
1811
1812 # Timestamp
1813 $r .= " ".$rcObj->timestamp." " ;
1814 $r .= "</tt>" ;
1815
1816 # Article link
1817 $link = $rcObj->link ;
1818 if ( $rcObj->watched ) $link = "<strong>{$link}</strong>" ;
1819 $r .= $link ;
1820
1821 # Cur
1822 $r .= " (" ;
1823 $r .= $rcObj->curlink ;
1824 $r .= "; " ;
1825
1826 # Hist
1827 $r .= $this->makeKnownLinkObj( $rcObj->getTitle(), wfMsg( "hist" ), "{$curIdEq}&action=history" );
1828
1829 # User/talk
1830 $r .= ") . . ".$rcObj->userlink ;
1831 $r .= $rcObj->usertalklink ;
1832
1833 # Comment
1834 if ( $rc_comment != "" && $rc_type != RC_MOVE ) {
1835 $rc_comment=$this->formatComment($rc_comment);
1836 $r .= $wgLang->emphasize( " (".$rc_comment.")" );
1837 }
1838
1839 $r .= "<br />\n" ;
1840 return $r ;
1841 }
1842
1843 # Enhanced RC group
1844 function recentChangesBlockGroup ( $block )
1845 {
1846 global $wgUploadPath, $wgLang ;
1847
1848 $r = "" ;
1849 $M = wfMsg( "minoreditletter" );
1850 $N = wfMsg( "newpageletter" );
1851
1852 # Collate list of users
1853 $isnew = false ;
1854 $userlinks = array () ;
1855 foreach ( $block AS $rcObj ) {
1856 $oldid = $rcObj->mAttribs['rc_last_oldid'];
1857 if ( $rcObj->mAttribs['rc_new'] ) $isnew = true ;
1858 $u = $rcObj->userlink ;
1859 if ( !isset ( $userlinks[$u] ) ) $userlinks[$u] = 0 ;
1860 $userlinks[$u]++ ;
1861 }
1862
1863 # Sort the list and convert to text
1864 krsort ( $userlinks ) ;
1865 asort ( $userlinks ) ;
1866 $users = array () ;
1867 foreach ( $userlinks as $userlink => $count) {
1868 $text = $userlink ;
1869 if ( $count > 1 ) $text .= " ({$count}&times;)" ;
1870 array_push ( $users , $text ) ;
1871 }
1872 $users = " <font size='-1'>[".implode("; ",$users)."]</font>" ;
1873
1874 # Arrow
1875 $rci = "RCI{$this->rcCacheIndex}" ;
1876 $rcl = "RCL{$this->rcCacheIndex}" ;
1877 $rcm = "RCM{$this->rcCacheIndex}" ;
1878 $toggleLink = "javascript:toggleVisibility(\"{$rci}\",\"{$rcm}\",\"{$rcl}\")" ;
1879 $arrowdir = $wgLang->isRTL() ? "l" : "r";
1880 $tl = "<span id='{$rcm}'><a href='$toggleLink'><img src='{$wgUploadPath}/Arr_{$arrowdir}.png' width='12' height='12' /></a></span>" ;
1881 $tl .= "<span id='{$rcl}' style='display:none'><a href='$toggleLink'><img src='{$wgUploadPath}/Arr_d.png' width='12' height='12' /></a></span>" ;
1882 $r .= $tl ;
1883
1884 # Main line
1885 # M/N
1886 $r .= "<tt>" ;
1887 if ( $isnew ) $r .= $N ;
1888 else $r .= "&nbsp;" ;
1889 $r .= "&nbsp;" ; # Minor
1890
1891 # Timestamp
1892 $r .= " ".$block[0]->timestamp." " ;
1893 $r .= "</tt>" ;
1894
1895 # Article link
1896 $link = $block[0]->link ;
1897 if ( $block[0]->watched ) $link = "<strong>{$link}</strong>" ;
1898 $r .= $link ;
1899
1900 $curIdEq = "curid=" . $block[0]->mAttribs['rc_cur_id'];
1901 if ( $block[0]->mAttribs['rc_type'] != RC_LOG ) {
1902 # Changes
1903 $r .= " (".count($block)." " ;
1904 if ( $isnew ) $r .= wfMsg("changes");
1905 else $r .= $this->makeKnownLinkObj( $block[0]->getTitle() , wfMsg("changes") ,
1906 "{$curIdEq}&diff=0&oldid=".$oldid ) ;
1907 $r .= "; " ;
1908
1909 # History
1910 $r .= $this->makeKnownLinkObj( $block[0]->getTitle(), wfMsg( "history" ), "{$curIdEq}&action=history" );
1911 $r .= ")" ;
1912 }
1913
1914 $r .= $users ;
1915 $r .= "<br />\n" ;
1916
1917 # Sub-entries
1918 $r .= "<div id='{$rci}' style='display:none'>" ;
1919 foreach ( $block AS $rcObj ) {
1920 # Get rc_xxxx variables
1921 extract( $rcObj->mAttribs );
1922
1923 $r .= "<img src='{$wgUploadPath}/Arr_.png' width=12 height=12 />";
1924 $r .= "<tt>&nbsp; &nbsp; &nbsp; &nbsp;" ;
1925 if ( $rc_new ) $r .= $N ;
1926 else $r .= "&nbsp;" ;
1927 if ( $rc_minor ) $r .= $M ;
1928 else $r .= "&nbsp;" ;
1929 $r .= "</tt>" ;
1930
1931 $o = "" ;
1932 if ( $rc_last_oldid != 0 ) {
1933 $o = "oldid=".$rc_last_oldid ;
1934 }
1935 if ( $rc_type == RC_LOG ) {
1936 $link = $rcObj->timestamp ;
1937 } else {
1938 $link = $this->makeKnownLinkObj( $rcObj->getTitle(), $rcObj->timestamp , "{$curIdEq}&$o" ) ;
1939 }
1940 $link = "<tt>{$link}</tt>" ;
1941
1942 $r .= $link ;
1943 $r .= " (" ;
1944 $r .= $rcObj->curlink ;
1945 $r .= "; " ;
1946 $r .= $rcObj->lastlink ;
1947 $r .= ") . . ".$rcObj->userlink ;
1948 $r .= $rcObj->usertalklink ;
1949 if ( $rc_comment != "" ) {
1950 $rc_comment=$this->formatComment($rc_comment);
1951 $r .= $wgLang->emphasize( " (".$rc_comment.")" ) ;
1952 }
1953 $r .= "<br />\n" ;
1954 }
1955 $r .= "</div>\n" ;
1956
1957 $this->rcCacheIndex++ ;
1958 return $r ;
1959 }
1960
1961 # If enhanced RC is in use, this function takes the previously cached
1962 # RC lines, arranges them, and outputs the HTML
1963 function recentChangesBlock ()
1964 {
1965 global $wgUploadPath ;
1966 if ( count ( $this->rc_cache ) == 0 ) return "" ;
1967 $blockOut = "";
1968 foreach ( $this->rc_cache AS $secureName => $block ) {
1969 if ( count ( $block ) < 2 ) {
1970 $blockOut .= $this->recentChangesBlockLine ( array_shift ( $block ) ) ;
1971 } else {
1972 $blockOut .= $this->recentChangesBlockGroup ( $block ) ;
1973 }
1974 }
1975
1976 return "<div>{$blockOut}</div>" ;
1977 }
1978
1979 # Called in a loop over all displayed RC entries
1980 # Either returns the line, or caches it for later use
1981 function recentChangesLine( &$rc, $watched = false )
1982 {
1983 global $wgUser ;
1984 $usenew = $wgUser->getOption( "usenewrc" );
1985 if ( $usenew )
1986 $line = $this->recentChangesLineNew ( $rc, $watched ) ;
1987 else
1988 $line = $this->recentChangesLineOld ( $rc, $watched ) ;
1989 return $line ;
1990 }
1991
1992 function recentChangesLineOld( &$rc, $watched = false )
1993 {
1994 global $wgTitle, $wgLang, $wgUser, $wgRCSeconds;
1995
1996 # Extract DB fields into local scope
1997 extract( $rc->mAttribs );
1998 $curIdEq = "curid=" . $rc_cur_id;
1999
2000 # Make date header if necessary
2001 $date = $wgLang->date( $rc_timestamp, true);
2002 $s = "";
2003 if ( $date != $this->lastdate ) {
2004 if ( "" != $this->lastdate ) { $s .= "</ul>\n"; }
2005 $s .= "<h4>{$date}</h4>\n<ul class='special'>";
2006 $this->lastdate = $date;
2007 }
2008 $s .= "<li> ";
2009
2010 if ( $rc_type == RC_MOVE ) {
2011 # Diff
2012 $s .= "(" . wfMsg( "diff" ) . ") (";
2013 # Hist
2014 $s .= $this->makeKnownLinkObj( $rc->getMovedToTitle(), wfMsg( "hist" ), "action=history" ) .
2015 ") . . ";
2016
2017 # "[[x]] moved to [[y]]"
2018
2019 $s .= wfMsg( "1movedto2", $this->makeKnownLinkObj( $rc->getTitle(), "", "redirect=no" ),
2020 $this->makeKnownLinkObj( $rc->getMovedToTitle(), "" ) );
2021
2022 } else {
2023 # Diff link
2024 if ( $rc_type == RC_NEW || $rc_type == RC_LOG ) {
2025 $diffLink = wfMsg( "diff" );
2026 } else {
2027 $diffLink = $this->makeKnownLinkObj( $rc->getTitle(), wfMsg( "diff" ),
2028 "{$curIdEq}&diff={$rc_this_oldid}&oldid={$rc_last_oldid}" );
2029 }
2030 $s .= "($diffLink) (";
2031
2032 # History link
2033 $s .= $this->makeKnownLinkObj( $rc->getTitle(), wfMsg( "hist" ), "{$curIdEq}&action=history" );
2034 $s .= ") . . ";
2035
2036 # M and N (minor and new)
2037 $M = wfMsg( "minoreditletter" );
2038 $N = wfMsg( "newpageletter" );
2039 if ( $rc_minor ) { $s .= " <strong>{$M}</strong>"; }
2040 if ( $rc_type == RC_NEW ) { $s .= "<strong>{$N}</strong>"; }
2041
2042 # Article link
2043 $articleLink = $this->makeKnownLinkObj( $rc->getTitle(), "" );
2044
2045 if ( $watched ) {
2046 $articleLink = "<strong>{$articleLink}</strong>";
2047 }
2048 $s .= " $articleLink";
2049
2050 }
2051
2052 # Timestamp
2053 $s .= "; " . $wgLang->time( $rc_timestamp, true, $wgRCSeconds ) . " . . ";
2054
2055 # User link (or contributions for unregistered users)
2056 if ( 0 == $rc_user ) {
2057 $userLink = $this->makeKnownLink( $wgLang->specialPage( "Contributions" ),
2058 $rc_user_text, "target=" . $rc_user_text );
2059 } else {
2060 $userLink = $this->makeLink( $wgLang->getNsText( NS_USER ) . ":{$rc_user_text}", $rc_user_text );
2061 }
2062 $s .= $userLink;
2063
2064 # User talk link
2065 $talkname=$wgLang->getNsText(NS_TALK); # use the shorter name
2066 global $wgDisableAnonTalk;
2067 if( 0 == $rc_user && $wgDisableAnonTalk ) {
2068 $userTalkLink = "";
2069 } else {
2070 $utns=$wgLang->getNsText(NS_USER_TALK);
2071 $userTalkLink= $this->makeLink($utns . ":{$rc_user_text}", $talkname );
2072 }
2073 # Block link
2074 $blockLink="";
2075 if ( ( 0 == $rc_user ) && $wgUser->isSysop() ) {
2076 $blockLink = $this->makeKnownLink( $wgLang->specialPage(
2077 "Blockip" ), wfMsg( "blocklink" ), "ip={$rc_user_text}" );
2078
2079 }
2080 if($blockLink) {
2081 if($userTalkLink) $userTalkLink .= " | ";
2082 $userTalkLink .= $blockLink;
2083 }
2084 if($userTalkLink) $s.=" ({$userTalkLink})";
2085
2086 # Add comment
2087 if ( "" != $rc_comment && "*" != $rc_comment && $rc_type != RC_MOVE ) {
2088 $rc_comment=$this->formatComment($rc_comment);
2089 $s .= $wgLang->emphasize(" (" . $rc_comment . ")");
2090 }
2091 $s .= "</li>\n";
2092
2093 return $s;
2094 }
2095
2096 # function recentChangesLineNew( $ts, $u, $ut, $ns, $ttl, $c, $isminor, $isnew, $watched = false, $oldid = 0 , $diffid = 0 )
2097 function recentChangesLineNew( &$baseRC, $watched = false )
2098 {
2099 global $wgTitle, $wgLang, $wgUser, $wgRCSeconds;
2100
2101 # Create a specialised object
2102 $rc = RCCacheEntry::newFromParent( $baseRC ) ;
2103
2104 # Extract fields from DB into the function scope (rc_xxxx variables)
2105 extract( $rc->mAttribs );
2106 $curIdEq = "curid=" . $rc_cur_id;
2107
2108 # If it's a new day, add the headline and flush the cache
2109 $date = $wgLang->date( $rc_timestamp, true);
2110 $ret = "" ;
2111 if ( $date != $this->lastdate ) {
2112 # Process current cache
2113 $ret = $this->recentChangesBlock () ;
2114 $this->rc_cache = array() ;
2115 $ret .= "<h4>{$date}</h4>\n";
2116 $this->lastdate = $date;
2117 }
2118
2119 # Make article link
2120 if ( $rc_type == RC_MOVE ) {
2121 $clink = $this->makeKnownLinkObj( $rc->getTitle(), "", "redirect=no" );
2122 $clink .= " " . wfMsg("movedto") . " ";
2123 $clink .= $this->makeKnownLinkObj( $rc->getMovedToTitle(), "" );
2124 } else {
2125 $clink = $this->makeKnownLinkObj( $rc->getTitle(), "" ) ;
2126 }
2127
2128 $time = $wgLang->time( $rc_timestamp, true, $wgRCSeconds );
2129 $rc->watched = $watched ;
2130 $rc->link = $clink ;
2131 $rc->timestamp = $time;
2132
2133 # Make "cur" link
2134 if ( ( $rc_type == RC_NEW && $rc_this_oldid == 0 ) || $rc_type == RC_LOG || $rc_type == RC_MOVE) {
2135 $curLink = wfMsg( "cur" );
2136 } else {
2137 $curLink = $this->makeKnownLinkObj( $rc->getTitle(), wfMsg( "cur" ),
2138 "{$curIdEq}&diff=0&oldid={$rc_this_oldid}" );
2139 }
2140
2141 # Make "last" link
2142 $titleObj = $rc->getTitle();
2143 if ( $rc_last_oldid == 0 || $rc_type == RC_LOG || $rc_type == RC_MOVE ) {
2144 $lastLink = wfMsg( "last" );
2145 } else {
2146 $lastLink = $this->makeKnownLinkObj( $rc->getTitle(), wfMsg( "last" ),
2147 "{$curIdEq}&diff={$rc_this_oldid}&oldid={$rc_last_oldid}" );
2148 }
2149
2150 # Make user link (or user contributions for unregistered users)
2151 if ( 0 == $rc_user ) {
2152 $userLink = $this->makeKnownLink( $wgLang->specialPage( "Contributions" ),
2153 $rc_user_text, "target=" . $rc_user_text );
2154 } else {
2155 $userLink = $this->makeLink( $wgLang->getNsText(
2156 Namespace::getUser() ) . ":{$rc_user_text}", $rc_user_text );
2157 }
2158
2159 $rc->userlink = $userLink ;
2160 $rc->lastlink = $lastLink ;
2161 $rc->curlink = $curLink ;
2162
2163 # Make user talk link
2164 $utns=$wgLang->getNsText(NS_USER_TALK);
2165 $talkname=$wgLang->getNsText(NS_TALK); # use the shorter name
2166 $userTalkLink= $this->makeLink($utns . ":{$rc_user_text}", $talkname );
2167
2168 global $wgDisableAnonTalk;
2169 if ( ( 0 == $rc_user ) && $wgUser->isSysop() ) {
2170 $blockLink = $this->makeKnownLink( $wgLang->specialPage(
2171 "Blockip" ), wfMsg( "blocklink" ), "ip={$rc_user_text}" );
2172 if( $wgDisableAnonTalk )
2173 $rc->usertalklink = " ({$blockLink})";
2174 else
2175 $rc->usertalklink = " ({$userTalkLink} | {$blockLink})";
2176 } else {
2177 if( $wgDisableAnonTalk && ($rc_user == 0) )
2178 $rc->usertalklink = "";
2179 else
2180 $rc->usertalklink = " ({$userTalkLink})";
2181 }
2182
2183 # Put accumulated information into the cache, for later display
2184 # Page moves go on their own line
2185 $title = $rc->getTitle();
2186 $secureName = $title->getPrefixedDBkey();
2187 if ( $rc_type == RC_MOVE ) {
2188 # Use an @ character to prevent collision with page names
2189 $this->rc_cache["@@" . ($this->rcMoveIndex++)] = array($rc);
2190 } else {
2191 if ( !isset ( $this->rc_cache[$secureName] ) ) $this->rc_cache[$secureName] = array() ;
2192 array_push ( $this->rc_cache[$secureName] , $rc ) ;
2193 }
2194 return $ret;
2195 }
2196
2197 function endImageHistoryList()
2198 {
2199 $s = "</ul>\n";
2200 return $s;
2201 }
2202
2203 /* This function is called by all recent changes variants, by the page history,
2204 and by the user contributions list. It is responsible for formatting edit
2205 comments. It escapes any HTML in the comment, but adds some CSS to format
2206 auto-generated comments (from section editing) and formats [[wikilinks]].
2207 Main author: Erik Möller (moeller@scireview.de)
2208 */
2209 function formatComment($comment)
2210 {
2211 global $wgLang;
2212 $comment=wfEscapeHTML($comment);
2213
2214 # The pattern for autogen comments is / * foo * /, which makes for
2215 # some nasty regex.
2216 # We look for all comments, match any text before and after the comment,
2217 # add a separator where needed and format the comment itself with CSS
2218 while (preg_match("/(.*)\/\*\s*(.*?)\s*\*\/(.*)/", $comment,$match)) {
2219 $pre=$match[1];
2220 $auto=$match[2];
2221 $post=$match[3];
2222 $sep="-";
2223 if($pre) { $auto="$sep ".$auto; }
2224 if($post) { $auto.=" $sep"; }
2225 $auto="<span class=\"autocomment\">".$auto."</span>";
2226 $comment=$pre.$auto.$post;
2227 }
2228
2229 # format regular and media links - all other wiki formatting
2230 # is ignored
2231 while(preg_match("/\[\[(.*?)(\|(.*?))*\]\]/",$comment,$match)) {
2232
2233 $medians = $wgLang->getNsText(Namespace::getMedia());
2234 $func="makeLink";
2235 if(preg_match("/^".$medians."/i",$match[1])) {
2236 $func="makeMediaLink";
2237 }
2238 if($match[3]) {
2239 $comment=
2240 preg_replace("/\[\[(.*?)\]\]/",
2241 $this->$func($match[1],$match[3]),$comment,1);
2242 } else {
2243 $comment=
2244 preg_replace("/\[\[(.*?)\]\]/",
2245 $this->$func($match[1],$match[1]),$comment,1);
2246 }
2247 }
2248
2249 return $comment;
2250
2251 }
2252
2253 function imageHistoryLine( $iscur, $ts, $img, $u, $ut, $size, $c )
2254 {
2255 global $wgUser, $wgLang, $wgTitle;
2256
2257 $dt = $wgLang->timeanddate( $ts, true );
2258 $del = wfMsg( "deleteimg" );
2259 $cur = wfMsg( "cur" );
2260
2261 if ( $iscur ) {
2262 $url = wfImageUrl( $img );
2263 $rlink = $cur;
2264 if ( $wgUser->isSysop() ) {
2265 $link = $wgTitle->escapeLocalURL( "image=" . $wgTitle->getPartialURL() .
2266 "&action=delete" );
2267 $style = $this->getInternalLinkAttributes( $link, $del );
2268
2269 $dlink = "<a href=\"{$link}\"{$style}>{$del}</a>";
2270 } else {
2271 $dlink = $del;
2272 }
2273 } else {
2274 $url = wfEscapeHTML( wfImageArchiveUrl( $img ) );
2275 if( $wgUser->getID() != 0 ) {
2276 $rlink = $this->makeKnownLink( $wgTitle->getPrefixedText(),
2277 wfMsg( "revertimg" ), "action=revert&oldimage=" .
2278 urlencode( $img ) );
2279 $dlink = $this->makeKnownLink( $wgTitle->getPrefixedText(),
2280 $del, "action=delete&oldimage=" . urlencode( $img ) );
2281 } else {
2282 # Having live active links for non-logged in users
2283 # means that bots and spiders crawling our site can
2284 # inadvertently change content. Baaaad idea.
2285 $rlink = wfMsg( "revertimg" );
2286 $dlink = $del;
2287 }
2288 }
2289 if ( 0 == $u ) { $ul = $ut; }
2290 else { $ul = $this->makeLink( $wgLang->getNsText(
2291 Namespace::getUser() ) . ":{$ut}", $ut ); }
2292
2293 $nb = wfMsg( "nbytes", $size );
2294 $style = $this->getInternalLinkAttributes( $url, $dt );
2295
2296 $s = "<li> ({$dlink}) ({$rlink}) <a href=\"{$url}\"{$style}>{$dt}</a>"
2297 . " . . {$ul} ({$nb})";
2298
2299 if ( "" != $c && "*" != $c ) {
2300 $sk=$wgUser->getSkin();
2301 $s .= $wgLang->emphasize(" (" . $sk->formatComment($c) . ")");
2302 }
2303 $s .= "</li>\n";
2304 return $s;
2305 }
2306
2307 function tocIndent($level) {
2308 return str_repeat( "<div class='tocindent'>\n", $level>0 ? $level : 0 );
2309 }
2310
2311 function tocUnindent($level) {
2312 return str_repeat( "</div>\n", $level>0 ? $level : 0 );
2313 }
2314
2315 # parameter level defines if we are on an indentation level
2316 function tocLine( $anchor, $tocline, $level ) {
2317 $link = "<a href=\"#$anchor\">$tocline</a><br />";
2318 if($level) {
2319 return "$link\n";
2320 } else {
2321 return "<div class='tocline'>$link</div>\n";
2322 }
2323
2324 }
2325
2326 function tocTable($toc) {
2327 # note to CSS fanatics: putting this in a div does not work -- div won't auto-expand
2328 # try min-width & co when somebody gets a chance
2329 $hideline = " <script type='text/javascript'>showTocToggle(\"" . addslashes( wfMsg("showtoc") ) . "\",\"" . addslashes( wfMsg("hidetoc") ) . "\")</script>";
2330 return
2331 "<table border=\"0\" id=\"toc\"><tr><td align=\"center\">\n".
2332 "<b>".wfMsg("toc")."</b>" .
2333 $hideline .
2334 "</td></tr><tr id='tocinside'><td>\n".
2335 $toc."</td></tr></table>\n";
2336 }
2337
2338 # These two do not check for permissions: check $wgTitle->userCanEdit before calling them
2339 function editSectionScript( $section, $head ) {
2340 global $wgTitle, $wgRequest;
2341 if( $wgRequest->getInt( "oldid" ) && ( $wgRequest->getVal( "diff" ) != "0" ) ) {
2342 return $head;
2343 }
2344 $url = $wgTitle->escapeLocalURL( "action=edit&section=$section" );
2345 return "<span oncontextmenu='document.location=\"$url\";return false;'>{$head}</span>";
2346 }
2347
2348 function editSectionLink( $section ) {
2349 global $wgRequest;
2350 global $wgTitle, $wgUser, $wgLang;
2351
2352 if( $wgRequest->getInt( "oldid" ) && ( $wgRequest->getVal( "diff" ) != "0" ) ) {
2353 # Section edit links would be out of sync on an old page.
2354 # But, if we're diffing to the current page, they'll be
2355 # correct.
2356 return "";
2357 }
2358
2359 $editurl = "&section={$section}";
2360 $url = $this->makeKnownLink($wgTitle->getPrefixedText(),wfMsg("editsection"),"action=edit".$editurl);
2361
2362 if( $wgLang->isRTL() ) {
2363 $farside = "left";
2364 $nearside = "right";
2365 } else {
2366 $farside = "right";
2367 $nearside = "left";
2368 }
2369 return "<div class=\"editsection\" style=\"float:$farside;margin-$nearside:5px;\">[".$url."]</div>";
2370
2371 }
2372
2373 // This function is called by EditPage.php and shows a bulletin board style
2374 // toolbar for common editing functions. It can be disabled in the user preferences.
2375 // The necsesary JavaScript code can be found in style/wikibits.js.
2376 function getEditToolbar() {
2377 global $wgUploadPath, $wgLang, $wgMimeType;
2378
2379 // toolarray an array of arrays which each include the filename of
2380 // the button image (without path), the opening tag, the closing tag,
2381 // and optionally a sample text that is inserted between the two when no
2382 // selection is highlighted.
2383 // The tip text is shown when the user moves the mouse over the button.
2384
2385 // Already here are accesskeys (key), which are not used yet until someone
2386 // can figure out a way to make them work in IE. However, we should make
2387 // sure these keys are not defined on the edit page.
2388 $toolarray=array(
2389 array( "image"=>"button_bold.png",
2390 "open"=>"\'\'\'",
2391 "close"=>"\'\'\'",
2392 "sample"=>wfMsg("bold_sample"),
2393 "tip"=>wfMsg("bold_tip"),
2394 "key"=>"B"
2395 ),
2396 array( "image"=>"button_italic.png",
2397 "open"=>"\'\'",
2398 "close"=>"\'\'",
2399 "sample"=>wfMsg("italic_sample"),
2400 "tip"=>wfMsg("italic_tip"),
2401 "key"=>"I"
2402 ),
2403 array( "image"=>"button_link.png",
2404 "open"=>"[[",
2405 "close"=>"]]",
2406 "sample"=>wfMsg("link_sample"),
2407 "tip"=>wfMsg("link_tip"),
2408 "key"=>"L"
2409 ),
2410 array( "image"=>"button_extlink.png",
2411 "open"=>"[",
2412 "close"=>"]",
2413 "sample"=>wfMsg("extlink_sample"),
2414 "tip"=>wfMsg("extlink_tip"),
2415 "key"=>"X"
2416 ),
2417 array( "image"=>"button_headline.png",
2418 "open"=>"\\n== ",
2419 "close"=>" ==\\n",
2420 "sample"=>wfMsg("headline_sample"),
2421 "tip"=>wfMsg("headline_tip"),
2422 "key"=>"H"
2423 ),
2424 array( "image"=>"button_image.png",
2425 "open"=>"[[".$wgLang->getNsText(NS_IMAGE).":",
2426 "close"=>"]]",
2427 "sample"=>wfMsg("image_sample"),
2428 "tip"=>wfMsg("image_tip"),
2429 "key"=>"D"
2430 ),
2431 array( "image"=>"button_media.png",
2432 "open"=>"[[".$wgLang->getNsText(NS_MEDIA).":",
2433 "close"=>"]]",
2434 "sample"=>wfMsg("media_sample"),
2435 "tip"=>wfMsg("media_tip"),
2436 "key"=>"M"
2437 ),
2438 array( "image"=>"button_math.png",
2439 "open"=>"\\<math\\>",
2440 "close"=>"\\</math\\>",
2441 "sample"=>wfMsg("math_sample"),
2442 "tip"=>wfMsg("math_tip"),
2443 "key"=>"C"
2444 ),
2445 array( "image"=>"button_nowiki.png",
2446 "open"=>"\\<nowiki\\>",
2447 "close"=>"\\</nowiki\\>",
2448 "sample"=>wfMsg("nowiki_sample"),
2449 "tip"=>wfMsg("nowiki_tip"),
2450 "key"=>"N"
2451 ),
2452 array( "image"=>"button_sig.png",
2453 "open"=>"--~~~~",
2454 "close"=>"",
2455 "sample"=>"",
2456 "tip"=>wfMsg("sig_tip"),
2457 "key"=>"Y"
2458 ),
2459 array( "image"=>"button_hr.png",
2460 "open"=>"\\n----\\n",
2461 "close"=>"",
2462 "sample"=>"",
2463 "tip"=>wfMsg("hr_tip"),
2464 "key"=>"R"
2465 )
2466 );
2467 $toolbar ="<script type='text/javascript'>\n";
2468
2469 $xml = ($wgMimeType == "text/xml");
2470 if( $xml ) {
2471 $toolbar .= "<![CDATA[";
2472 }
2473
2474 $toolbar.="document.writeln(\"<div id='toolbar'>\");\n";
2475 foreach($toolarray as $tool) {
2476
2477 $image=$wgUploadPath."/".$tool["image"];
2478 $open=$tool["open"];
2479 $close=$tool["close"];
2480 $sample = addslashes( $tool["sample"] );
2481
2482 // Note that we use the tip both for the ALT tag and the TITLE tag of the image.
2483 // Older browsers show a "speedtip" type message only for ALT.
2484 // Ideally these should be different, realistically they
2485 // probably don't need to be.
2486 $tip = addslashes( $tool["tip"] );
2487
2488 #$key = $tool["key"];
2489
2490 $toolbar.="addButton('$image','$tip','$open','$close','$sample');\n";
2491 }
2492
2493 $toolbar.="addInfobox('" . addslashes( wfMsg( "infobox" ) ) . "','" . addslashes(wfMsg("infobox_alert")) . "');\n";
2494 $toolbar.="document.writeln(\"</div>\");\n";
2495
2496 if( $xml ) {
2497 $toolbar .= "]]>";
2498 }
2499 $toolbar.="</script>";
2500 return $toolbar;
2501 }
2502 }
2503
2504 include_once( "SkinStandard.php" );
2505 include_once( "SkinNostalgia.php" );
2506 include_once( "SkinCologneBlue.php" );
2507
2508 if( $wgUseSmarty ) {
2509 include_once( "SkinSmarty.php" );
2510 }
2511 if( $wgUsePHPTal ) {
2512 include_once( "SkinPHPTal.php" );
2513 }
2514
2515
2516 ?>