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