Fix IE freezing rendering whilst waiting for CSS with MonoBook (bug 624) (take 2)
[lhc/web/wiklou.git] / includes / SkinTemplate.php
1 <?php
2 # This program is free software; you can redistribute it and/or modify
3 # it under the terms of the GNU General Public License as published by
4 # the Free Software Foundation; either version 2 of the License, or
5 # (at your option) any later version.
6 #
7 # This program is distributed in the hope that it will be useful,
8 # but WITHOUT ANY WARRANTY; without even the implied warranty of
9 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 # GNU General Public License for more details.
11 #
12 # You should have received a copy of the GNU General Public License along
13 # with this program; if not, write to the Free Software Foundation, Inc.,
14 # 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
15 # http://www.gnu.org/copyleft/gpl.html
16
17 /**
18 * Template-filler skin base class
19 * Formerly generic PHPTal (http://phptal.sourceforge.net/) skin
20 * Based on Brion's smarty skin
21 * Copyright (C) Gabriel Wicke -- http://www.aulinx.de/
22 *
23 * Todo: Needs some serious refactoring into functions that correspond
24 * to the computations individual esi snippets need. Most importantly no body
25 * parsing for most of those of course.
26 *
27 * PHPTAL support has been moved to a subclass in SkinPHPTal.php,
28 * and is optional. You'll need to install PHPTAL manually to use
29 * skins that depend on it.
30 *
31 * @package MediaWiki
32 * @subpackage Skins
33 */
34
35 /**
36 * This is not a valid entry point, perform no further processing unless
37 * MEDIAWIKI is defined
38 */
39 if( defined( 'MEDIAWIKI' ) ) {
40
41 require_once 'GlobalFunctions.php';
42
43 /**
44 * Wrapper object for MediaWiki's localization functions,
45 * to be passed to the template engine.
46 *
47 * @access private
48 * @package MediaWiki
49 */
50 class MediaWiki_I18N {
51 var $_context = array();
52
53 function set($varName, $value) {
54 $this->_context[$varName] = $value;
55 }
56
57 function translate($value) {
58 $fname = 'SkinTemplate-translate';
59 wfProfileIn( $fname );
60
61 // Hack for i18n:attributes in PHPTAL 1.0.0 dev version as of 2004-10-23
62 $value = preg_replace( '/^string:/', '', $value );
63
64 $value = wfMsg( $value );
65 // interpolate variables
66 while (preg_match('/\$([0-9]*?)/sm', $value, $m)) {
67 list($src, $var) = $m;
68 wfSuppressWarnings();
69 $varValue = $this->_context[$var];
70 wfRestoreWarnings();
71 $value = str_replace($src, $varValue, $value);
72 }
73 wfProfileOut( $fname );
74 return $value;
75 }
76 }
77
78 /**
79 *
80 * @package MediaWiki
81 */
82 class SkinTemplate extends Skin {
83 /**#@+
84 * @access private
85 */
86
87 /**
88 * Name of our skin, set in initPage()
89 * It probably need to be all lower case.
90 */
91 var $skinname;
92
93 /**
94 * Stylesheets set to use
95 * Sub directory in ./skins/ where various stylesheets are located
96 */
97 var $stylename;
98
99 /**
100 * For QuickTemplate, the name of the subclass which
101 * will actually fill the template.
102 *
103 * In PHPTal mode, name of PHPTal template to be used.
104 * '.pt' will be automaticly added to it on PHPTAL object creation
105 */
106 var $template;
107
108 /**#@-*/
109
110 /**
111 * Setup the base parameters...
112 * Child classes should override this to set the name,
113 * style subdirectory, and template filler callback.
114 *
115 * @param OutputPage $out
116 */
117 function initPage( &$out ) {
118 parent::initPage( $out );
119 $this->skinname = 'monobook';
120 $this->stylename = 'monobook';
121 $this->template = 'QuickTemplate';
122 }
123
124 /**
125 * Create the template engine object; we feed it a bunch of data
126 * and eventually it spits out some HTML. Should have interface
127 * roughly equivalent to PHPTAL 0.7.
128 *
129 * @param string $callback (or file)
130 * @param string $repository subdirectory where we keep template files
131 * @param string $cache_dir
132 * @return object
133 * @access private
134 */
135 function &setupTemplate( $classname, $repository=false, $cache_dir=false ) {
136 return new $classname();
137 }
138
139 /**
140 * initialize various variables and generate the template
141 *
142 * @param OutputPage $out
143 * @access public
144 */
145 function outputPage( &$out ) {
146 global $wgTitle, $wgArticle, $wgUser, $wgLang, $wgContLang, $wgOut;
147 global $wgScript, $wgStylePath, $wgLanguageCode, $wgContLanguageCode, $wgUseNewInterlanguage;
148 global $wgMimeType, $wgOutputEncoding, $wgUseDatabaseMessages, $wgRequest;
149 global $wgDisableCounters, $wgLogo, $action, $wgFeedClasses, $wgSiteNotice;
150 global $wgMaxCredits, $wgShowCreditsIfMax;
151 global $wgPageShowWatchingUsers;
152
153 $fname = 'SkinTemplate::outputPage';
154 wfProfileIn( $fname );
155
156 extract( $wgRequest->getValues( 'oldid', 'diff' ) );
157
158 wfProfileIn( "$fname-init" );
159 $this->initPage( $out );
160 $tpl =& $this->setupTemplate( $this->template, 'skins' );
161
162 #if ( $wgUseDatabaseMessages ) { // uncomment this to fall back to GetText
163 $tpl->setTranslator(new MediaWiki_I18N());
164 #}
165 wfProfileOut( "$fname-init" );
166
167 wfProfileIn( "$fname-stuff" );
168 $this->thispage = $wgTitle->getPrefixedDbKey();
169 $this->thisurl = $wgTitle->getPrefixedURL();
170 $this->loggedin = $wgUser->getID() != 0;
171 $this->iscontent = ($wgTitle->getNamespace() != Namespace::getSpecial() );
172 $this->iseditable = ($this->iscontent and !($action == 'edit' or $action == 'submit'));
173 $this->username = $wgUser->getName();
174 $this->userpage = $wgContLang->getNsText( Namespace::getUser() ) . ":" . $wgUser->getName();
175 $this->userpageUrlDetails = $this->makeUrlDetails($this->userpage);
176
177 $this->usercss = $this->userjs = $this->userjsprev = false;
178 $this->setupUserCss();
179 $this->setupUserJs();
180 $this->titletxt = $wgTitle->getPrefixedText();
181 wfProfileOut( "$fname-stuff" );
182
183 wfProfileIn( "$fname-stuff2" );
184 $tpl->set( 'title', $wgOut->getPageTitle() );
185 $tpl->set( 'pagetitle', $wgOut->getHTMLTitle() );
186
187 $tpl->setRef( "thispage", $this->thispage );
188 $subpagestr = $this->subPageSubtitle();
189 $tpl->set(
190 'subtitle', !empty($subpagestr)?
191 '<span class="subpages">'.$subpagestr.'</span>'.$out->getSubtitle():
192 $out->getSubtitle()
193 );
194 $undelete = $this->getUndeleteLink();
195 $tpl->set(
196 "undelete", !empty($undelete)?
197 '<span class="subpages">'.$undelete.'</span>':
198 ''
199 );
200
201 $tpl->set( 'catlinks', $this->getCategories());
202 if( $wgOut->isSyndicated() ) {
203 $feeds = array();
204 foreach( $wgFeedClasses as $format => $class ) {
205 $feeds[$format] = array(
206 'text' => $format,
207 'href' => $wgRequest->appendQuery( "feed=$format" ),
208 'ttip' => wfMsg('tooltip-'.$format)
209 );
210 }
211 $tpl->setRef( 'feeds', $feeds );
212 } else {
213 $tpl->set( 'feeds', false );
214 }
215 $tpl->setRef( 'mimetype', $wgMimeType );
216 $tpl->setRef( 'charset', $wgOutputEncoding );
217 $tpl->set( 'headlinks', $out->getHeadLinks() );
218 $tpl->setRef( 'wgScript', $wgScript );
219 $tpl->setRef( 'skinname', $this->skinname );
220 $tpl->setRef( 'stylename', $this->stylename );
221 $tpl->setRef( 'loggedin', $this->loggedin );
222 $tpl->set('nsclass', 'ns-'.$wgTitle->getNamespace());
223 $tpl->set('notspecialpage', $wgTitle->getNamespace() != NS_SPECIAL);
224 /* XXX currently unused, might get useful later
225 $tpl->set( "editable", ($wgTitle->getNamespace() != NS_SPECIAL ) );
226 $tpl->set( "exists", $wgTitle->getArticleID() != 0 );
227 $tpl->set( "watch", $wgTitle->userIsWatching() ? "unwatch" : "watch" );
228 $tpl->set( "protect", count($wgTitle->isProtected()) ? "unprotect" : "protect" );
229 $tpl->set( "helppage", wfMsg('helppage'));
230 */
231 $tpl->set( 'searchaction', $this->escapeSearchLink() );
232 $tpl->set( 'search', trim( $wgRequest->getVal( 'search' ) ) );
233 $tpl->setRef( 'stylepath', $wgStylePath );
234 $tpl->setRef( 'logopath', $wgLogo );
235 $tpl->setRef( "lang", $wgContLanguageCode );
236 $tpl->set( 'dir', $wgContLang->isRTL() ? "rtl" : "ltr" );
237 $tpl->set( 'rtl', $wgContLang->isRTL() );
238 $tpl->set( 'langname', $wgContLang->getLanguageName( $wgContLanguageCode ) );
239 $tpl->setRef( 'username', $this->username );
240 $tpl->setRef( 'userpage', $this->userpage);
241 $tpl->setRef( 'userpageurl', $this->userpageUrlDetails['href']);
242 $tpl->setRef( 'usercss', $this->usercss);
243 $tpl->setRef( 'userjs', $this->userjs);
244 $tpl->setRef( 'userjsprev', $this->userjsprev);
245 global $wgUseSiteJs;
246 if ($wgUseSiteJs) {
247 if($this->loggedin) {
248 $tpl->set( 'jsvarurl', $this->makeUrl('-','action=raw&smaxage=0&gen=js') );
249 } else {
250 $tpl->set( 'jsvarurl', $this->makeUrl('-','action=raw&gen=js') );
251 }
252 } else {
253 $tpl->set('jsvarurl', false);
254 }
255 if( $wgUser->getNewtalk() ) {
256 $usertitle = Title::newFromText( $this->userpage );
257 $usertalktitle = $usertitle->getTalkPage();
258 if($usertalktitle->getPrefixedDbKey() != $this->thispage){
259
260 $ntl = wfMsg( 'newmessages',
261 $this->makeKnownLink(
262 $wgContLang->getNsText( Namespace::getTalk( Namespace::getUser() ) )
263 . ':' . $this->username,
264 wfMsg('newmessageslink') )
265 );
266 # Disable Cache
267 $wgOut->setSquidMaxage(0);
268 }
269 } else {
270 $ntl = '';
271 }
272 wfProfileOut( "$fname-stuff2" );
273
274 wfProfileIn( "$fname-stuff3" );
275 $tpl->setRef( 'newtalk', $ntl );
276 $tpl->setRef( 'skin', $this);
277 $tpl->set( 'logo', $this->logoText() );
278 if ( $wgOut->isArticle() and (!isset( $oldid ) or isset( $diff )) and 0 != $wgArticle->getID() ) {
279 if ( !$wgDisableCounters ) {
280 $viewcount = $wgLang->formatNum( $wgArticle->getCount() );
281 if ( $viewcount ) {
282 $tpl->set('viewcount', wfMsg( "viewcount", $viewcount ));
283 } else {
284 $tpl->set('viewcount', false);
285 }
286 }
287
288 if ($wgPageShowWatchingUsers) {
289 $dbr =& wfGetDB( DB_SLAVE );
290 extract( $dbr->tableNames( 'watchlist' ) );
291 $sql = "SELECT COUNT(*) AS n FROM $watchlist
292 WHERE wl_title='" . $dbr->strencode($wgTitle->getDBKey()) .
293 "' AND wl_namespace=" . $wgTitle->getNamespace() ;
294 $res = $dbr->query( $sql, 'SkinPHPTal::outputPage');
295 $x = $dbr->fetchObject( $res );
296 $numberofwatchingusers = $x->n;
297 if ($numberofwatchingusers > 0) {
298 $tpl->set('numberofwatchingusers', wfMsg('number_of_watching_users_pageview', $numberofwatchingusers));
299 } else {
300 $tpl->set('numberofwatchingusers', false);
301 }
302 } else {
303 $tpl->set('numberofwatchingusers', false);
304 }
305
306 $tpl->set('lastmod', $this->lastModified());
307 $tpl->set('copyright',$this->getCopyright());
308
309 $this->credits = false;
310
311 if (isset($wgMaxCredits) && $wgMaxCredits != 0) {
312 require_once("Credits.php");
313 $this->credits = getCredits($wgArticle, $wgMaxCredits, $wgShowCreditsIfMax);
314 }
315
316 $tpl->setRef( 'credits', $this->credits );
317
318 } elseif ( isset( $oldid ) && !isset( $diff ) ) {
319 $tpl->set('copyright', $this->getCopyright());
320 $tpl->set('viewcount', false);
321 $tpl->set('lastmod', false);
322 $tpl->set('credits', false);
323 $tpl->set('numberofwatchingusers', false);
324 } else {
325 $tpl->set('copyright', false);
326 $tpl->set('viewcount', false);
327 $tpl->set('lastmod', false);
328 $tpl->set('credits', false);
329 $tpl->set('numberofwatchingusers', false);
330 }
331 wfProfileOut( "$fname-stuff3" );
332
333 wfProfileIn( "$fname-stuff4" );
334 $tpl->set( 'copyrightico', $this->getCopyrightIcon() );
335 $tpl->set( 'poweredbyico', $this->getPoweredBy() );
336 $tpl->set( 'disclaimer', $this->disclaimerLink() );
337 $tpl->set( 'about', $this->aboutLink() );
338
339 $tpl->setRef( 'debug', $out->mDebugtext );
340 $tpl->set( 'reporttime', $out->reportTime() );
341 $tpl->set( 'sitenotice', $wgSiteNotice );
342 $tpl->set( 'tagline', wfMsg('tagline') );
343
344 $printfooter = "<div class=\"printfooter\">\n" . $this->printSource() . "</div>\n";
345 $out->mBodytext .= $printfooter ;
346 $tpl->setRef( 'bodytext', $out->mBodytext );
347
348 # Language links
349 $language_urls = array();
350 foreach( $wgOut->getLanguageLinks() as $l ) {
351 $nt = Title::newFromText( $l );
352 $language_urls[] = array('href' => $nt->getFullURL(),
353 'text' => ($wgContLang->getLanguageName( $nt->getInterwiki()) != ''?$wgContLang->getLanguageName( $nt->getInterwiki()) : $l),
354 'class' => $wgContLang->isRTL() ? 'rtl' : 'ltr');
355 }
356 if(count($language_urls)) {
357 $tpl->setRef( 'language_urls', $language_urls);
358 } else {
359 $tpl->set('language_urls', false);
360 }
361 wfProfileOut( "$fname-stuff4" );
362
363 # Personal toolbar
364 $tpl->set('personal_urls', $this->buildPersonalUrls());
365 $content_actions = $this->buildContentActionUrls();
366 $tpl->setRef('content_actions', $content_actions);
367
368 // XXX: attach this from javascript, same with section editing
369 if($this->iseditable && $wgUser->getOption("editondblclick") )
370 {
371 $tpl->set('body_ondblclick', 'document.location = "' .$content_actions['edit']['href'] .'";');
372 } else {
373 $tpl->set('body_ondblclick', false);
374 }
375 $tpl->set( 'navigation_urls', $this->buildNavigationUrls() );
376 $tpl->set( 'nav_urls', $this->buildNavUrls() );
377
378 // execute template
379 wfProfileIn( "$fname-execute" );
380 $res = $tpl->execute();
381 wfProfileOut( "$fname-execute" );
382
383 // result may be an error
384 $this->printOrError( $res );
385 wfProfileOut( $fname );
386 }
387
388 /**
389 * Output the string, or print error message if it's
390 * an error object of the appropriate type.
391 * For the base class, assume strings all around.
392 *
393 * @param mixed $str
394 * @access private
395 */
396 function printOrError( &$str ) {
397 echo $str;
398 }
399
400 /**
401 * build array of urls for personal toolbar
402 * @return array
403 * @access private
404 */
405 function buildPersonalUrls() {
406 $fname = 'SkinTemplate::buildPersonalUrls';
407 wfProfileIn( $fname );
408
409 /* set up the default links for the personal toolbar */
410 global $wgShowIPinHeader;
411 $personal_urls = array();
412 if ($this->loggedin) {
413 $personal_urls['userpage'] = array(
414 'text' => $this->username,
415 'href' => &$this->userpageUrlDetails['href'],
416 'class' => $this->userpageUrlDetails['exists']?false:'new'
417 );
418 $usertalkUrlDetails = $this->makeTalkUrlDetails($this->userpage);
419 $personal_urls['mytalk'] = array(
420 'text' => wfMsg('mytalk'),
421 'href' => &$usertalkUrlDetails['href'],
422 'class' => $usertalkUrlDetails['exists']?false:'new'
423 );
424 $personal_urls['preferences'] = array(
425 'text' => wfMsg('preferences'),
426 'href' => $this->makeSpecialUrl('Preferences')
427 );
428 $personal_urls['watchlist'] = array(
429 'text' => wfMsg('watchlist'),
430 'href' => $this->makeSpecialUrl('Watchlist')
431 );
432 $personal_urls['mycontris'] = array(
433 'text' => wfMsg('mycontris'),
434 'href' => $this->makeSpecialUrl('Contributions','target=' . urlencode( $this->username ) )
435 );
436 $personal_urls['logout'] = array(
437 'text' => wfMsg('userlogout'),
438 'href' => $this->makeSpecialUrl('Userlogout','returnto=' . $this->thisurl )
439 );
440 } else {
441 if( $wgShowIPinHeader && isset( $_COOKIE[ini_get("session.name")] ) ) {
442 $personal_urls['anonuserpage'] = array(
443 'text' => $this->username,
444 'href' => &$this->userpageUrlDetails['href'],
445 'class' => $this->userpageUrlDetails['exists']?false:'new'
446 );
447 $usertalkUrlDetails = $this->makeTalkUrlDetails($this->userpage);
448 $personal_urls['anontalk'] = array(
449 'text' => wfMsg('anontalk'),
450 'href' => &$usertalkUrlDetails['href'],
451 'class' => $usertalkUrlDetails['exists']?false:'new'
452 );
453 $personal_urls['anonlogin'] = array(
454 'text' => wfMsg('userlogin'),
455 'href' => $this->makeSpecialUrl('Userlogin', 'returnto=' . $this->thisurl )
456 );
457 } else {
458
459 $personal_urls['login'] = array(
460 'text' => wfMsg('userlogin'),
461 'href' => $this->makeSpecialUrl('Userlogin', 'returnto=' . $this->thisurl )
462 );
463 }
464 }
465 wfProfileOut( $fname );
466 return $personal_urls;
467 }
468
469 /**
470 * an array of edit links by default used for the tabs
471 * @return array
472 * @access private
473 */
474 function buildContentActionUrls () {
475 global $wgContLang;
476 $fname = 'SkinTemplate::buildContentActionUrls';
477 wfProfileIn( $fname );
478
479 global $wgTitle, $wgUser, $wgRequest, $wgUseValidation;
480 $action = $wgRequest->getText( 'action' );
481 $section = $wgRequest->getText( 'section' );
482 $oldid = $wgRequest->getVal( 'oldid' );
483 $diff = $wgRequest->getVal( 'diff' );
484 $content_actions = array();
485
486 if( $this->iscontent ) {
487
488 $nskey = $this->getNameSpaceKey();
489 $is_active = !Namespace::isTalk( $wgTitle->getNamespace()) ;
490 if ( $action == 'validate' ) $is_active = false ; # Show article tab deselected when validating
491 $content_actions[$nskey] = array('class' => ($is_active) ? 'selected' : false,
492 'text' => wfMsg($nskey),
493 'href' => $this->makeArticleUrl($this->thispage));
494
495 /* set up the classes for the talk link */
496 wfProfileIn( "$fname-talk" );
497 $talk_class = (Namespace::isTalk( $wgTitle->getNamespace()) ? 'selected' : false);
498 $talktitle = $wgTitle->getTalkPage();
499 if( $talktitle->getArticleId() != 0 ) {
500 $content_actions['talk'] = array(
501 'class' => $talk_class,
502 'text' => wfMsg('talk'),
503 'href' => $talktitle->getLocalUrl()
504 );
505 } else {
506 $content_actions['talk'] = array(
507 'class' => $talk_class ? $talk_class.' new' : 'new',
508 'text' => wfMsg('talk'),
509 'href' => $talktitle->getLocalUrl( 'action=edit' )
510 );
511 }
512 wfProfileOut( "$fname-talk" );
513
514 wfProfileIn( "$fname-edit" );
515 if ( $wgTitle->userCanEdit() ) {
516 $oid = ( $oldid && ! isset( $diff ) ) ? '&oldid='.IntVal( $oldid ) : false;
517 $istalk = ( Namespace::isTalk( $wgTitle->getNamespace()) );
518 $istalkclass = $istalk?' istalk':'';
519 $content_actions['edit'] = array(
520 'class' => ((($action == 'edit' or $action == 'submit') and $section != 'new') ? 'selected' : '').$istalkclass,
521 'text' => wfMsg('edit'),
522 'href' => $wgTitle->getLocalUrl( 'action=edit'.$oid )
523 );
524 if ( $istalk ) {
525 $content_actions['addsection'] = array(
526 'class' => $section == 'new'?'selected':false,
527 'text' => wfMsg('addsection'),
528 'href' => $wgTitle->getLocalUrl( 'action=edit&section=new' )
529 );
530 }
531 } else {
532 $oid = ( $oldid && ! isset( $diff ) ) ? '&oldid='.IntVal( $oldid ) : '';
533 $content_actions['viewsource'] = array(
534 'class' => ($action == 'edit') ? 'selected' : false,
535 'text' => wfMsg('viewsource'),
536 'href' => $wgTitle->getLocalUrl( 'action=edit'.$oid )
537 );
538 }
539 wfProfileOut( "$fname-edit" );
540
541 wfProfileIn( "$fname-live" );
542 if ( $wgTitle->getArticleId() ) {
543
544 $content_actions['history'] = array(
545 'class' => ($action == 'history') ? 'selected' : false,
546 'text' => wfMsg('history_short'),
547 'href' => $wgTitle->getLocalUrl( 'action=history')
548 );
549
550 # XXX: is there a rollback action anywhere or is it planned?
551 # Don't recall where i got this from...
552 /*if( $wgUser->getNewtalk() ) {
553 $content_actions['rollback'] = array('class' => ($action == 'rollback') ? 'selected' : false,
554 'text' => wfMsg('rollback_short'),
555 'href' => $this->makeUrl($this->thispage, 'action=rollback'),
556 'ttip' => wfMsg('tooltip-rollback'),
557 'akey' => wfMsg('accesskey-rollback'));
558 }
559 */
560
561 if($wgUser->isAllowed('protect')){
562 if(!$wgTitle->isProtected()){
563 $content_actions['protect'] = array(
564 'class' => ($action == 'protect') ? 'selected' : false,
565 'text' => wfMsg('protect'),
566 'href' => $wgTitle->getLocalUrl( 'action=protect' )
567 );
568
569 } else {
570 $content_actions['unprotect'] = array(
571 'class' => ($action == 'unprotect') ? 'selected' : false,
572 'text' => wfMsg('unprotect'),
573 'href' => $wgTitle->getLocalUrl( 'action=unprotect' )
574 );
575 }
576 }
577 if($wgUser->isAllowed('delete')){
578 $content_actions['delete'] = array(
579 'class' => ($action == 'delete') ? 'selected' : false,
580 'text' => wfMsg('delete'),
581 'href' => $wgTitle->getLocalUrl( 'action=delete' )
582 );
583 }
584 if ( $wgUser->getID() != 0 ) {
585 if ( $wgTitle->userCanMove()) {
586 $content_actions['move'] = array(
587 'class' => ($wgTitle->getDbKey() == 'Movepage' and $wgTitle->getNamespace == Namespace::getSpecial()) ? 'selected' : false,
588 'text' => wfMsg('move'),
589 'href' => $this->makeSpecialUrl('Movepage', 'target='. urlencode( $this->thispage ) )
590 );
591 }
592 }
593 } else {
594 //article doesn't exist or is deleted
595 if($wgUser->isAllowed('delete')){
596 if( $n = $wgTitle->isDeleted() ) {
597 $content_actions['undelete'] = array(
598 'class' => false,
599 'text' => wfMsg( "undelete_short", $n ),
600 'href' => $this->makeSpecialUrl('Undelete/'.$this->thispage)
601 );
602 }
603 }
604 }
605 wfProfileOut( "$fname-live" );
606
607 if ( $wgUser->getID() != 0 and $action != 'submit' ) {
608 if( !$wgTitle->userIsWatching()) {
609 $content_actions['watch'] = array(
610 'class' => ($action == 'watch' or $action == 'unwatch') ? 'selected' : false,
611 'text' => wfMsg('watch'),
612 'href' => $wgTitle->getLocalUrl( 'action=watch' )
613 );
614 } else {
615 $content_actions['unwatch'] = array(
616 'class' => ($action == 'unwatch' or $action == 'watch') ? 'selected' : false,
617 'text' => wfMsg('unwatch'),
618 'href' => $wgTitle->getLocalUrl( 'action=unwatch' )
619 );
620 }
621 }
622
623 # Show validate tab
624 if ( $wgUseValidation && $wgTitle->getArticleId() && $wgTitle->getNamespace() == 0 ) {
625 global $wgArticle ;
626 $article_time = "&timestamp=" . $wgArticle->mTimestamp ;
627 $content_actions['validate'] = array(
628 'class' => ($action == 'validate') ? 'selected' : false ,
629 'text' => wfMsg('val_tab'),
630 'href' => $wgTitle->getLocalUrl( 'action=validate'.$article_time)
631 );
632 }
633
634 } else {
635 /* show special page tab */
636
637 $content_actions['article'] = array(
638 'class' => 'selected',
639 'text' => wfMsg('specialpage'),
640 'href' => false
641 );
642 }
643
644 /* show links to different language variants */
645 global $wgDisableLangConversion;
646 $variants = $wgContLang->getVariants();
647 if( !$wgDisableLangConversion && sizeof( $variants ) > 1 ) {
648 $preferred = $wgContLang->getPreferredVariant();
649 $actstr = '';
650 if( $action )
651 $actstr = 'action=' . $action . '&';
652 $vcount=0;
653 foreach( $variants as $code ) {
654 $varname = $wgContLang->getVariantname( $code );
655 if( $varname == 'disable' )
656 continue;
657 $selected = ( $code == $preferred )? 'selected' : false;
658 $content_actions['varlang-' . $vcount] = array(
659 'class' => $selected,
660 'text' => $varname,
661 'href' => $wgTitle->getLocalUrl( $actstr . 'variant=' . $code )
662 );
663 $vcount ++;
664 }
665 }
666
667 wfProfileOut( $fname );
668 return $content_actions;
669 }
670
671 /**
672 * build array of global navigation links
673 * @return array
674 * @access private
675 */
676 function buildNavigationUrls () {
677 $fname = 'SkinTemplate::buildNavigationUrls';
678 wfProfileIn( $fname );
679
680 global $wgNavigationLinks;
681 $result = array();
682 foreach ( $wgNavigationLinks as $link ) {
683 $text = wfMsg( $link['text'] );
684 wfProfileIn( "$fname-{$link['text']}" );
685 if ($text != '-') {
686 $dest = wfMsgForContent( $link['href'] );
687 wfProfileIn( "$fname-{$link['text']}2" );
688 $result[] = array(
689 'text' => $text,
690 'href' => $this->makeInternalOrExternalUrl( $dest ),
691 'id' => 'n-'.$link['text']
692 );
693 wfProfileOut( "$fname-{$link['text']}2" );
694 }
695 wfProfileOut( "$fname-{$link['text']}" );
696 }
697 wfProfileOut( $fname );
698 return $result;
699 }
700
701 /**
702 * build array of common navigation links
703 * @return array
704 * @access private
705 */
706 function buildNavUrls () {
707 $fname = 'SkinTemplate::buildNavUrls';
708 wfProfileIn( $fname );
709
710 global $wgTitle, $wgUser, $wgRequest;
711 global $wgSiteSupportPage, $wgDisableUploads;
712
713 $action = $wgRequest->getText( 'action' );
714 $oldid = $wgRequest->getVal( 'oldid' );
715 $diff = $wgRequest->getVal( 'diff' );
716
717 $nav_urls = array();
718 $nav_urls['mainpage'] = array('href' => $this->makeI18nUrl('mainpage'));
719 $nav_urls['randompage'] = array('href' => $this->makeSpecialUrl('Randompage'));
720 $nav_urls['recentchanges'] = array('href' => $this->makeSpecialUrl('Recentchanges'));
721 $nav_urls['currentevents'] = (wfMsgForContent('currentevents') != '-') ? array('href' => $this->makeI18nUrl('currentevents')) : false;
722 $nav_urls['portal'] = (wfMsgForContent('portal') != '-') ? array('href' => $this->makeI18nUrl('portal-url')) : false;
723 $nav_urls['bugreports'] = array('href' => $this->makeI18nUrl('bugreportspage'));
724 // $nav_urls['sitesupport'] = array('href' => $this->makeI18nUrl('sitesupportpage'));
725 $nav_urls['sitesupport'] = array('href' => $wgSiteSupportPage);
726 $nav_urls['help'] = array('href' => $this->makeI18nUrl('helppage'));
727 if( $this->loggedin && !$wgDisableUploads ) {
728 $nav_urls['upload'] = array('href' => $this->makeSpecialUrl('Upload'));
729 } else {
730 $nav_urls['upload'] = false;
731 }
732 $nav_urls['specialpages'] = array('href' => $this->makeSpecialUrl('Specialpages'));
733
734 if( $wgTitle->getNamespace() != NS_SPECIAL) {
735 $nav_urls['whatlinkshere'] = array('href' => $this->makeSpecialUrl('Whatlinkshere', 'target='.urlencode( $this->thispage)));
736 $nav_urls['recentchangeslinked'] = array('href' => $this->makeSpecialUrl('Recentchangeslinked', 'target='.urlencode( $this->thispage)));
737 }
738
739 if( $wgTitle->getNamespace() == NS_USER || $wgTitle->getNamespace() == NS_USER_TALK ) {
740 $id = User::idFromName($wgTitle->getText());
741 $ip = User::isIP($wgTitle->getText());
742 } else {
743 $id = 0;
744 $ip = false;
745 }
746
747 if($id || $ip) { # both anons and non-anons have contri list
748 $nav_urls['contributions'] = array(
749 'href' => $this->makeSpecialUrl('Contributions', "target=" . $wgTitle->getPartialURL() )
750 );
751 } else {
752 $nav_urls['contributions'] = false;
753 }
754 $nav_urls['emailuser'] = false;
755 if( $this->showEmailUser( $id ) ) {
756 $nav_urls['emailuser'] = array(
757 'href' => $this->makeSpecialUrl('Emailuser', "target=" . $wgTitle->getPartialURL() )
758 );
759 }
760 wfProfileOut( $fname );
761 return $nav_urls;
762 }
763
764 /**
765 * Generate strings used for xml 'id' names
766 * @return string
767 * @private
768 */
769 function getNameSpaceKey () {
770 global $wgTitle;
771 switch ($wgTitle->getNamespace()) {
772 case NS_MAIN:
773 case NS_TALK:
774 return 'nstab-main';
775 case NS_USER:
776 case NS_USER_TALK:
777 return 'nstab-user';
778 case NS_MEDIA:
779 return 'nstab-media';
780 case NS_SPECIAL:
781 return 'nstab-special';
782 case NS_PROJECT:
783 case NS_PROJECT_TALK:
784 return 'nstab-wp';
785 case NS_IMAGE:
786 case NS_IMAGE_TALK:
787 return 'nstab-image';
788 case NS_MEDIAWIKI:
789 case NS_MEDIAWIKI_TALK:
790 return 'nstab-mediawiki';
791 case NS_TEMPLATE:
792 case NS_TEMPLATE_TALK:
793 return 'nstab-template';
794 case NS_HELP:
795 case NS_HELP_TALK:
796 return 'nstab-help';
797 case NS_CATEGORY:
798 case NS_CATEGORY_TALK:
799 return 'nstab-category';
800 default:
801 return 'nstab-main';
802 }
803 }
804
805 /**
806 * @access private
807 */
808 function setupUserCss() {
809 $fname = 'SkinTemplate::setupUserCss';
810 wfProfileIn( $fname );
811
812 global $wgRequest, $wgTitle, $wgAllowUserCss, $wgUseSiteCss, $wgContLang;
813
814 $sitecss = '';
815 $usercss = '';
816 $siteargs = '';
817
818 # Add user-specific code if this is a user and we allow that kind of thing
819
820 if ( $wgAllowUserCss && $this->loggedin ) {
821 $action = $wgRequest->getText('action');
822
823 # if we're previewing the CSS page, use it
824 if($wgTitle->isCssSubpage() and $action == 'submit' and $wgTitle->userCanEditCssJsSubpage()) {
825 $siteargs .= "&smaxage=0&maxage=0";
826 $usercss = $wgRequest->getText('wpTextbox1');
827 } else {
828 $siteargs .= "&maxage=0";
829 $usercss = '@import "' .
830 $this->makeUrl($this->userpage . '/'.$this->skinname.'.css',
831 'action=raw&ctype=text/css') . '";' ."\n";
832 }
833 }
834
835 # If we use the site's dynamic CSS, throw that in, too
836
837 if ( $wgUseSiteCss ) {
838 if ($wgContLang->isRTL()) $s .= '@import "' . $wgStylePath . '/' . $this->stylename . '/rtl.css";' . "\n";
839 $sitecss .= '@import "' . $this->makeNSUrl(ucfirst($this->skinname) . '.css', 'action=raw&ctype=text/css&smaxage=' . $wgSquidMaxage, NS_MEDIAWIKI) . '";' . "\n";
840 $sitecss .= '@import "' . $this->makeUrl('-','action=raw&gen=css' . $siteargs) . '";' . "\n";
841 }
842
843 # If we use any dynamic CSS, make a little CDATA block out of it.
844
845 if ( !empty($sitecss) || !empty($usercss) ) {
846 $this->usercss = "/*<![CDATA[*/\n" . $sitecss . $usercss . '/*]]>*/';
847 }
848 wfProfileOut( $fname );
849 }
850
851 /**
852 * @access private
853 */
854 function setupUserJs() {
855 $fname = 'SkinTemplate::setupUserJs';
856 wfProfileIn( $fname );
857
858 global $wgRequest, $wgTitle, $wgAllowUserJs;
859 $action = $wgRequest->getText('action');
860
861 if( $wgAllowUserJs && $this->loggedin ) {
862 if($wgTitle->isJsSubpage() and $action == 'submit' and $wgTitle->userCanEditCssJsSubpage()) {
863 # XXX: additional security check/prompt?
864 $this->userjsprev = '/*<![CDATA[*/ ' . $wgRequest->getText('wpTextbox1') . ' /*]]>*/';
865 } else {
866 $this->userjs = $this->makeUrl($this->userpage.'/'.$this->skinname.'.js', 'action=raw&ctype=text/javascript&dontcountme=s');
867 }
868 }
869 wfProfileOut( $fname );
870 }
871
872 /**
873 * returns css with user-specific options
874 * @access public
875 */
876 function getUserStylesheet() {
877 $fname = 'SkinTemplate::getUserStylesheet';
878 wfProfileIn( $fname );
879
880 global $wgUser, $wgRequest, $wgTitle, $wgContLang, $wgSquidMaxage, $wgStylePath;
881 $action = $wgRequest->getText('action');
882 $maxage = $wgRequest->getText('maxage');
883 $s = "/* generated user stylesheet */\n";
884
885 if($wgUser->getID() != 0) {
886 if ( 1 == $wgUser->getOption( "underline" ) ) {
887 $s .= "a { text-decoration: underline; }\n";
888 } else {
889 $s .= "a { text-decoration: none; }\n";
890 }
891 }
892 if ( 1 != $wgUser->getOption( "highlightbroken" ) ) {
893 $s .= "a.new, #quickbar a.new { color: #CC2200; }\n";
894 }
895 if ( 1 == $wgUser->getOption( "justify" ) ) {
896 $s .= "#bodyContent { text-align: justify; }\n";
897 }
898 wfProfileOut( $fname );
899 return $s;
900 }
901
902 /**
903 * @access public
904 */
905 function getUserJs() {
906 $fname = 'SkinTemplate::getUserJs';
907 wfProfileIn( $fname );
908
909 global $wgUser, $wgStylePath;
910 $s = '/* generated javascript */';
911 $s .= "var skin = '{$this->skinname}';\nvar stylepath = '{$wgStylePath}';";
912 $s .= '/* MediaWiki:'.ucfirst($this->skinname)." */\n";
913 $s .= wfMsg(ucfirst($this->skinname).'.js');
914
915 wfProfileOut( $fname );
916 return $s;
917 }
918 }
919
920 /**
921 * Generic wrapper for template functions, with interface
922 * compatible with what we use of PHPTAL 0.7.
923 */
924 class QuickTemplate {
925 /**
926 * @access public
927 */
928 function QuickTemplate() {
929 $this->data = array();
930 $this->translator = new MediaWiki_I18N();
931 }
932
933 /**
934 * @access public
935 */
936 function set( $name, $value ) {
937 $this->data[$name] = $value;
938 }
939
940 /**
941 * @access public
942 */
943 function setRef($name, &$value) {
944 $this->data[$name] =& $value;
945 }
946
947 /**
948 * @access public
949 */
950 function setTranslator( &$t ) {
951 $this->translator = &$t;
952 }
953
954 /**
955 * @access public
956 */
957 function execute() {
958 echo "Override this function.";
959 }
960
961
962 /**
963 * @access private
964 */
965 function text( $str ) {
966 echo htmlspecialchars( $this->data[$str] );
967 }
968
969 /**
970 * @access private
971 */
972 function html( $str ) {
973 echo $this->data[$str];
974 }
975
976 /**
977 * @access private
978 */
979 function msg( $str ) {
980 echo htmlspecialchars( $this->translator->translate( $str ) );
981 }
982
983 /**
984 * @access private
985 */
986 function msgHtml( $str ) {
987 echo $this->translator->translate( $str );
988 }
989
990 /**
991 * An ugly, ugly hack.
992 * @access private
993 */
994 function msgWiki( $str ) {
995 global $wgParser, $wgTitle, $wgOut, $wgUseTidy;
996
997 $text = $this->translator->translate( $str );
998 $parserOutput = $wgParser->parse( $text, $wgTitle,
999 $wgOut->mParserOptions, true );
1000 echo $parserOutput->getText();
1001 }
1002
1003 /**
1004 * @access private
1005 */
1006 function haveData( $str ) {
1007 return $this->data[$str];
1008 }
1009
1010 /**
1011 * @access private
1012 */
1013 function haveMsg( $str ) {
1014 $msg = $this->translator->translate( $str );
1015 return ($msg != '-') && ($msg != ''); # ????
1016 }
1017 }
1018
1019 } // end of if( defined( 'MEDIAWIKI' ) )
1020 ?>