MediaWiki  1.23.6
SkinTemplate.php
Go to the documentation of this file.
1 <?php
31  var $_context = array();
32 
33  function set( $varName, $value ) {
34  $this->_context[$varName] = $value;
35  }
36 
37  function translate( $value ) {
38  wfProfileIn( __METHOD__ );
39 
40  // Hack for i18n:attributes in PHPTAL 1.0.0 dev version as of 2004-10-23
41  $value = preg_replace( '/^string:/', '', $value );
42 
43  $value = wfMessage( $value )->text();
44  // interpolate variables
45  $m = array();
46  while ( preg_match( '/\$([0-9]*?)/sm', $value, $m ) ) {
47  list( $src, $var ) = $m;
49  $varValue = $this->_context[$var];
51  $value = str_replace( $src, $varValue, $value );
52  }
53  wfProfileOut( __METHOD__ );
54  return $value;
55  }
56 }
57 
70 class SkinTemplate extends Skin {
79  var $skinname = 'monobook';
80 
85  var $stylename = 'monobook';
86 
91  var $template = 'QuickTemplate';
92 
97  var $useHeadElement = false;
98 
107  $out->addModuleStyles( array(
108  'mediawiki.legacy.shared',
109  'mediawiki.legacy.commonPrint',
110  'mediawiki.ui.button'
111  ) );
112  }
113 
125  function setupTemplate( $classname, $repository = false, $cache_dir = false ) {
126  return new $classname();
127  }
128 
135  public function getLanguages() {
136  global $wgHideInterlanguageLinks;
137  if ( $wgHideInterlanguageLinks ) {
138  return array();
139  }
140 
141  $userLang = $this->getLanguage();
142  $languageLinks = array();
143 
144  foreach ( $this->getOutput()->getLanguageLinks() as $languageLinkText ) {
145  $languageLinkParts = explode( ':', $languageLinkText, 2 );
146  $class = 'interlanguage-link interwiki-' . $languageLinkParts[0];
147  unset( $languageLinkParts );
148 
149  $languageLinkTitle = Title::newFromText( $languageLinkText );
150  if ( $languageLinkTitle ) {
151  $ilInterwikiCode = $languageLinkTitle->getInterwiki();
152  $ilLangName = Language::fetchLanguageName( $ilInterwikiCode );
153 
154  if ( strval( $ilLangName ) === '' ) {
155  $ilLangName = $languageLinkText;
156  } else {
157  $ilLangName = $this->formatLanguageName( $ilLangName );
158  }
159 
160  // CLDR extension or similar is required to localize the language name;
161  // otherwise we'll end up with the autonym again.
162  $ilLangLocalName = Language::fetchLanguageName(
163  $ilInterwikiCode,
164  $userLang->getCode()
165  );
166 
167  $languageLinkTitleText = $languageLinkTitle->getText();
168  if ( $languageLinkTitleText === '' ) {
169  $ilTitle = wfMessage(
170  'interlanguage-link-title-langonly',
171  $ilLangLocalName
172  )->text();
173  } else {
174  $ilTitle = wfMessage(
175  'interlanguage-link-title',
176  $languageLinkTitleText,
177  $ilLangLocalName
178  )->text();
179  }
180 
181  $ilInterwikiCodeBCP47 = wfBCP47( $ilInterwikiCode );
182  $languageLink = array(
183  'href' => $languageLinkTitle->getFullURL(),
184  'text' => $ilLangName,
185  'title' => $ilTitle,
186  'class' => $class,
187  'lang' => $ilInterwikiCodeBCP47,
188  'hreflang' => $ilInterwikiCodeBCP47,
189  );
190  wfRunHooks( 'SkinTemplateGetLanguageLink', array( &$languageLink, $languageLinkTitle, $this->getTitle() ) );
191  $languageLinks[] = $languageLink;
192  }
193  }
194 
195  return $languageLinks;
196  }
197 
198  protected function setupTemplateForOutput() {
199  wfProfileIn( __METHOD__ );
200 
201  $request = $this->getRequest();
202  $user = $this->getUser();
203  $title = $this->getTitle();
204 
205  wfProfileIn( __METHOD__ . '-init' );
206  $tpl = $this->setupTemplate( $this->template, 'skins' );
207  wfProfileOut( __METHOD__ . '-init' );
208 
209  wfProfileIn( __METHOD__ . '-stuff' );
210  $this->thispage = $title->getPrefixedDBkey();
211  $this->titletxt = $title->getPrefixedText();
212  $this->userpage = $user->getUserPage()->getPrefixedText();
213  $query = array();
214  if ( !$request->wasPosted() ) {
215  $query = $request->getValues();
216  unset( $query['title'] );
217  unset( $query['returnto'] );
218  unset( $query['returntoquery'] );
219  }
220  $this->thisquery = wfArrayToCgi( $query );
221  $this->loggedin = $user->isLoggedIn();
222  $this->username = $user->getName();
223 
224  if ( $this->loggedin || $this->showIPinHeader() ) {
225  $this->userpageUrlDetails = self::makeUrlDetails( $this->userpage );
226  } else {
227  # This won't be used in the standard skins, but we define it to preserve the interface
228  # To save time, we check for existence
229  $this->userpageUrlDetails = self::makeKnownUrlDetails( $this->userpage );
230  }
231 
232  wfProfileOut( __METHOD__ . '-stuff' );
233 
234  wfProfileOut( __METHOD__ );
235 
236  return $tpl;
237  }
238 
244  function outputPage( OutputPage $out = null ) {
245  wfProfileIn( __METHOD__ );
246  Profiler::instance()->setTemplated( true );
247 
248  $oldContext = null;
249  if ( $out !== null ) {
250  // @todo Add wfDeprecated in 1.20
251  $oldContext = $this->getContext();
252  $this->setContext( $out->getContext() );
253  }
254 
255  $out = $this->getOutput();
256 
257  wfProfileIn( __METHOD__ . '-init' );
258  $this->initPage( $out );
259  wfProfileOut( __METHOD__ . '-init' );
260  $tpl = $this->prepareQuickTemplate( $out );
261  // execute template
262  wfProfileIn( __METHOD__ . '-execute' );
263  $res = $tpl->execute();
264  wfProfileOut( __METHOD__ . '-execute' );
265 
266  // result may be an error
267  $this->printOrError( $res );
268 
269  if ( $oldContext ) {
270  $this->setContext( $oldContext );
271  }
272 
273  wfProfileOut( __METHOD__ );
274  }
275 
282  protected function prepareQuickTemplate() {
283  global $wgContLang, $wgScript, $wgStylePath,
284  $wgMimeType, $wgJsMimeType, $wgXhtmlNamespaces, $wgHtml5Version,
285  $wgDisableCounters, $wgSitename, $wgLogo, $wgMaxCredits,
286  $wgShowCreditsIfMax, $wgPageShowWatchingUsers, $wgArticlePath,
287  $wgScriptPath, $wgServer;
288 
289  wfProfileIn( __METHOD__ );
290 
291  $title = $this->getTitle();
292  $request = $this->getRequest();
293  $out = $this->getOutput();
294  $tpl = $this->setupTemplateForOutput();
295 
296  wfProfileIn( __METHOD__ . '-stuff-head' );
297  if ( !$this->useHeadElement ) {
298  $tpl->set( 'pagecss', false );
299  $tpl->set( 'usercss', false );
300 
301  $tpl->set( 'userjs', false );
302  $tpl->set( 'userjsprev', false );
303 
304  $tpl->set( 'jsvarurl', false );
305 
306  $tpl->set( 'xhtmldefaultnamespace', 'http://www.w3.org/1999/xhtml' );
307  $tpl->set( 'xhtmlnamespaces', $wgXhtmlNamespaces );
308  $tpl->set( 'html5version', $wgHtml5Version );
309  $tpl->set( 'headlinks', $out->getHeadLinks() );
310  $tpl->set( 'csslinks', $out->buildCssLinks() );
311  $tpl->set( 'pageclass', $this->getPageClasses( $title ) );
312  $tpl->set( 'skinnameclass', ( 'skin-' . Sanitizer::escapeClass( $this->getSkinName() ) ) );
313  }
314  wfProfileOut( __METHOD__ . '-stuff-head' );
315 
316  wfProfileIn( __METHOD__ . '-stuff2' );
317  $tpl->set( 'title', $out->getPageTitle() );
318  $tpl->set( 'pagetitle', $out->getHTMLTitle() );
319  $tpl->set( 'displaytitle', $out->mPageLinkTitle );
320 
321  $tpl->setRef( 'thispage', $this->thispage );
322  $tpl->setRef( 'titleprefixeddbkey', $this->thispage );
323  $tpl->set( 'titletext', $title->getText() );
324  $tpl->set( 'articleid', $title->getArticleID() );
325 
326  $tpl->set( 'isarticle', $out->isArticle() );
327 
328  $subpagestr = $this->subPageSubtitle();
329  if ( $subpagestr !== '' ) {
330  $subpagestr = '<span class="subpages">' . $subpagestr . '</span>';
331  }
332  $tpl->set( 'subtitle', $subpagestr . $out->getSubtitle() );
333 
334  $undelete = $this->getUndeleteLink();
335  if ( $undelete === '' ) {
336  $tpl->set( 'undelete', '' );
337  } else {
338  $tpl->set( 'undelete', '<span class="subpages">' . $undelete . '</span>' );
339  }
340 
341  $tpl->set( 'catlinks', $this->getCategories() );
342  if ( $out->isSyndicated() ) {
343  $feeds = array();
344  foreach ( $out->getSyndicationLinks() as $format => $link ) {
345  $feeds[$format] = array(
346  // Messages: feed-atom, feed-rss
347  'text' => $this->msg( "feed-$format" )->text(),
348  'href' => $link
349  );
350  }
351  $tpl->setRef( 'feeds', $feeds );
352  } else {
353  $tpl->set( 'feeds', false );
354  }
355 
356  $tpl->setRef( 'mimetype', $wgMimeType );
357  $tpl->setRef( 'jsmimetype', $wgJsMimeType );
358  $tpl->set( 'charset', 'UTF-8' );
359  $tpl->setRef( 'wgScript', $wgScript );
360  $tpl->setRef( 'skinname', $this->skinname );
361  $tpl->set( 'skinclass', get_class( $this ) );
362  $tpl->setRef( 'skin', $this );
363  $tpl->setRef( 'stylename', $this->stylename );
364  $tpl->set( 'printable', $out->isPrintable() );
365  $tpl->set( 'handheld', $request->getBool( 'handheld' ) );
366  $tpl->setRef( 'loggedin', $this->loggedin );
367  $tpl->set( 'notspecialpage', !$title->isSpecialPage() );
368  /* XXX currently unused, might get useful later
369  $tpl->set( 'editable', ( !$title->isSpecialPage() ) );
370  $tpl->set( 'exists', $title->getArticleID() != 0 );
371  $tpl->set( 'watch', $user->isWatched( $title ) ? 'unwatch' : 'watch' );
372  $tpl->set( 'protect', count( $title->isProtected() ) ? 'unprotect' : 'protect' );
373  $tpl->set( 'helppage', $this->msg( 'helppage' )->text() );
374  */
375  $tpl->set( 'searchaction', $this->escapeSearchLink() );
376  $tpl->set( 'searchtitle', SpecialPage::getTitleFor( 'Search' )->getPrefixedDBkey() );
377  $tpl->set( 'search', trim( $request->getVal( 'search' ) ) );
378  $tpl->setRef( 'stylepath', $wgStylePath );
379  $tpl->setRef( 'articlepath', $wgArticlePath );
380  $tpl->setRef( 'scriptpath', $wgScriptPath );
381  $tpl->setRef( 'serverurl', $wgServer );
382  $tpl->setRef( 'logopath', $wgLogo );
383  $tpl->setRef( 'sitename', $wgSitename );
384 
385  $userLang = $this->getLanguage();
386  $userLangCode = $userLang->getHtmlCode();
387  $userLangDir = $userLang->getDir();
388 
389  $tpl->set( 'lang', $userLangCode );
390  $tpl->set( 'dir', $userLangDir );
391  $tpl->set( 'rtl', $userLang->isRTL() );
392 
393  $tpl->set( 'capitalizeallnouns', $userLang->capitalizeAllNouns() ? ' capitalize-all-nouns' : '' );
394  $tpl->set( 'showjumplinks', true ); // showjumplinks preference has been removed
395  $tpl->set( 'username', $this->loggedin ? $this->username : null );
396  $tpl->setRef( 'userpage', $this->userpage );
397  $tpl->setRef( 'userpageurl', $this->userpageUrlDetails['href'] );
398  $tpl->set( 'userlang', $userLangCode );
399 
400  // Users can have their language set differently than the
401  // content of the wiki. For these users, tell the web browser
402  // that interface elements are in a different language.
403  $tpl->set( 'userlangattributes', '' );
404  $tpl->set( 'specialpageattributes', '' ); # obsolete
405  // Used by VectorBeta to insert HTML before content but after the heading for the page title. Defaults to empty string.
406  $tpl->set( 'prebodyhtml', '' );
407 
408  if ( $userLangCode !== $wgContLang->getHtmlCode() || $userLangDir !== $wgContLang->getDir() ) {
409  $escUserlang = htmlspecialchars( $userLangCode );
410  $escUserdir = htmlspecialchars( $userLangDir );
411  // Attributes must be in double quotes because htmlspecialchars() doesn't
412  // escape single quotes
413  $attrs = " lang=\"$escUserlang\" dir=\"$escUserdir\"";
414  $tpl->set( 'userlangattributes', $attrs );
415  }
416 
417  wfProfileOut( __METHOD__ . '-stuff2' );
418 
419  wfProfileIn( __METHOD__ . '-stuff3' );
420  $tpl->set( 'newtalk', $this->getNewtalks() );
421  $tpl->set( 'logo', $this->logoText() );
422 
423  $tpl->set( 'copyright', false );
424  $tpl->set( 'viewcount', false );
425  $tpl->set( 'lastmod', false );
426  $tpl->set( 'credits', false );
427  $tpl->set( 'numberofwatchingusers', false );
428  if ( $out->isArticle() && $title->exists() ) {
429  if ( $this->isRevisionCurrent() ) {
430  if ( !$wgDisableCounters ) {
431  $viewcount = $this->getWikiPage()->getCount();
432  if ( $viewcount ) {
433  $tpl->set( 'viewcount', $this->msg( 'viewcount' )->numParams( $viewcount )->parse() );
434  }
435  }
436 
437  if ( $wgPageShowWatchingUsers ) {
438  $dbr = wfGetDB( DB_SLAVE );
439  $num = $dbr->selectField( 'watchlist', 'COUNT(*)',
440  array( 'wl_title' => $title->getDBkey(), 'wl_namespace' => $title->getNamespace() ),
441  __METHOD__
442  );
443  if ( $num > 0 ) {
444  $tpl->set( 'numberofwatchingusers',
445  $this->msg( 'number_of_watching_users_pageview' )->numParams( $num )->parse()
446  );
447  }
448  }
449 
450  if ( $wgMaxCredits != 0 ) {
451  $tpl->set( 'credits', Action::factory( 'credits', $this->getWikiPage(),
452  $this->getContext() )->getCredits( $wgMaxCredits, $wgShowCreditsIfMax ) );
453  } else {
454  $tpl->set( 'lastmod', $this->lastModified() );
455  }
456  }
457  $tpl->set( 'copyright', $this->getCopyright() );
458  }
459  wfProfileOut( __METHOD__ . '-stuff3' );
460 
461  wfProfileIn( __METHOD__ . '-stuff4' );
462  $tpl->set( 'copyrightico', $this->getCopyrightIcon() );
463  $tpl->set( 'poweredbyico', $this->getPoweredBy() );
464  $tpl->set( 'disclaimer', $this->disclaimerLink() );
465  $tpl->set( 'privacy', $this->privacyLink() );
466  $tpl->set( 'about', $this->aboutLink() );
467 
468  $tpl->set( 'footerlinks', array(
469  'info' => array(
470  'lastmod',
471  'viewcount',
472  'numberofwatchingusers',
473  'credits',
474  'copyright',
475  ),
476  'places' => array(
477  'privacy',
478  'about',
479  'disclaimer',
480  ),
481  ) );
482 
483  global $wgFooterIcons;
484  $tpl->set( 'footericons', $wgFooterIcons );
485  foreach ( $tpl->data['footericons'] as $footerIconsKey => &$footerIconsBlock ) {
486  if ( count( $footerIconsBlock ) > 0 ) {
487  foreach ( $footerIconsBlock as &$footerIcon ) {
488  if ( isset( $footerIcon['src'] ) ) {
489  if ( !isset( $footerIcon['width'] ) ) {
490  $footerIcon['width'] = 88;
491  }
492  if ( !isset( $footerIcon['height'] ) ) {
493  $footerIcon['height'] = 31;
494  }
495  }
496  }
497  } else {
498  unset( $tpl->data['footericons'][$footerIconsKey] );
499  }
500  }
501 
502  $tpl->set( 'sitenotice', $this->getSiteNotice() );
503  $tpl->set( 'bottomscripts', $this->bottomScripts() );
504  $tpl->set( 'printfooter', $this->printSource() );
505 
506  # An ID that includes the actual body text; without categories, contentSub, ...
507  $realBodyAttribs = array( 'id' => 'mw-content-text' );
508 
509  # Add a mw-content-ltr/rtl class to be able to style based on text direction
510  # when the content is different from the UI language, i.e.:
511  # not for special pages or file pages AND only when viewing AND if the page exists
512  # (or is in MW namespace, because that has default content)
513  if ( !in_array( $title->getNamespace(), array( NS_SPECIAL, NS_FILE ) ) &&
514  Action::getActionName( $this ) === 'view' &&
515  ( $title->exists() || $title->getNamespace() == NS_MEDIAWIKI ) ) {
516  $pageLang = $title->getPageViewLanguage();
517  $realBodyAttribs['lang'] = $pageLang->getHtmlCode();
518  $realBodyAttribs['dir'] = $pageLang->getDir();
519  $realBodyAttribs['class'] = 'mw-content-' . $pageLang->getDir();
520  }
521 
522  $out->mBodytext = Html::rawElement( 'div', $realBodyAttribs, $out->mBodytext );
523  $tpl->setRef( 'bodytext', $out->mBodytext );
524 
525  $language_urls = $this->getLanguages();
526  if ( count( $language_urls ) ) {
527  $tpl->setRef( 'language_urls', $language_urls );
528  } else {
529  $tpl->set( 'language_urls', false );
530  }
531  wfProfileOut( __METHOD__ . '-stuff4' );
532 
533  wfProfileIn( __METHOD__ . '-stuff5' );
534  # Personal toolbar
535  $tpl->set( 'personal_urls', $this->buildPersonalUrls() );
536  $content_navigation = $this->buildContentNavigationUrls();
537  $content_actions = $this->buildContentActionUrls( $content_navigation );
538  $tpl->setRef( 'content_navigation', $content_navigation );
539  $tpl->setRef( 'content_actions', $content_actions );
540 
541  $tpl->set( 'sidebar', $this->buildSidebar() );
542  $tpl->set( 'nav_urls', $this->buildNavUrls() );
543 
544  // Set the head scripts near the end, in case the above actions resulted in added scripts
545  if ( $this->useHeadElement ) {
546  $tpl->set( 'headelement', $out->headElement( $this ) );
547  } else {
548  $tpl->set( 'headscripts', $out->getHeadScripts() . $out->getHeadItems() );
549  }
550 
551  $tpl->set( 'debug', '' );
552  $tpl->set( 'debughtml', $this->generateDebugHTML() );
553  $tpl->set( 'reporttime', wfReportTime() );
554 
555  // original version by hansm
556  if ( !wfRunHooks( 'SkinTemplateOutputPageBeforeExec', array( &$this, &$tpl ) ) ) {
557  wfDebug( __METHOD__ . ": Hook SkinTemplateOutputPageBeforeExec broke outputPage execution!\n" );
558  }
559 
560  // Set the bodytext to another key so that skins can just output it on it's own
561  // and output printfooter and debughtml separately
562  $tpl->set( 'bodycontent', $tpl->data['bodytext'] );
563 
564  // Append printfooter and debughtml onto bodytext so that skins that were already
565  // using bodytext before they were split out don't suddenly start not outputting information
566  $tpl->data['bodytext'] .= Html::rawElement( 'div', array( 'class' => 'printfooter' ), "\n{$tpl->data['printfooter']}" ) . "\n";
567  $tpl->data['bodytext'] .= $tpl->data['debughtml'];
568 
569  // allow extensions adding stuff after the page content.
570  // See Skin::afterContentHook() for further documentation.
571  $tpl->set( 'dataAfterContent', $this->afterContentHook() );
572  wfProfileOut( __METHOD__ . '-stuff5' );
573 
574  wfProfileOut( __METHOD__ );
575  return $tpl;
576  }
577 
582  public function getPersonalToolsList() {
583  $tpl = $this->setupTemplateForOutput();
584  $tpl->set( 'personal_urls', $this->buildPersonalUrls() );
585  $html = '';
586  foreach ( $tpl->getPersonalTools() as $key => $item ) {
587  $html .= $tpl->makeListItem( $key, $item );
588  }
589  return $html;
590  }
591 
600  function formatLanguageName( $name ) {
601  return $this->getLanguage()->ucfirst( $name );
602  }
603 
612  function printOrError( $str ) {
613  echo $str;
614  }
615 
625  function useCombinedLoginLink() {
626  global $wgUseCombinedLoginLink;
627  return $wgUseCombinedLoginLink;
628  }
629 
634  protected function buildPersonalUrls() {
635  $title = $this->getTitle();
636  $request = $this->getRequest();
637  $pageurl = $title->getLocalURL();
638  wfProfileIn( __METHOD__ );
639 
640  /* set up the default links for the personal toolbar */
641  $personal_urls = array();
642 
643  # Due to bug 32276, if a user does not have read permissions,
644  # $this->getTitle() will just give Special:Badtitle, which is
645  # not especially useful as a returnto parameter. Use the title
646  # from the request instead, if there was one.
647  if ( $this->getUser()->isAllowed( 'read' ) ) {
648  $page = $this->getTitle();
649  } else {
650  $page = Title::newFromText( $request->getVal( 'title', '' ) );
651  }
652  $page = $request->getVal( 'returnto', $page );
653  $a = array();
654  if ( strval( $page ) !== '' ) {
655  $a['returnto'] = $page;
656  $query = $request->getVal( 'returntoquery', $this->thisquery );
657  if ( $query != '' ) {
658  $a['returntoquery'] = $query;
659  }
660  }
661 
662  $returnto = wfArrayToCgi( $a );
663  if ( $this->loggedin ) {
664  $personal_urls['userpage'] = array(
665  'text' => $this->username,
666  'href' => &$this->userpageUrlDetails['href'],
667  'class' => $this->userpageUrlDetails['exists'] ? false : 'new',
668  'active' => ( $this->userpageUrlDetails['href'] == $pageurl ),
669  'dir' => 'auto'
670  );
671  $usertalkUrlDetails = $this->makeTalkUrlDetails( $this->userpage );
672  $personal_urls['mytalk'] = array(
673  'text' => $this->msg( 'mytalk' )->text(),
674  'href' => &$usertalkUrlDetails['href'],
675  'class' => $usertalkUrlDetails['exists'] ? false : 'new',
676  'active' => ( $usertalkUrlDetails['href'] == $pageurl )
677  );
678  $href = self::makeSpecialUrl( 'Preferences' );
679  $personal_urls['preferences'] = array(
680  'text' => $this->msg( 'mypreferences' )->text(),
681  'href' => $href,
682  'active' => ( $href == $pageurl )
683  );
684 
685  if ( $this->getUser()->isAllowed( 'viewmywatchlist' ) ) {
686  $href = self::makeSpecialUrl( 'Watchlist' );
687  $personal_urls['watchlist'] = array(
688  'text' => $this->msg( 'mywatchlist' )->text(),
689  'href' => $href,
690  'active' => ( $href == $pageurl )
691  );
692  }
693 
694  # We need to do an explicit check for Special:Contributions, as we
695  # have to match both the title, and the target, which could come
696  # from request values (Special:Contributions?target=Jimbo_Wales)
697  # or be specified in "sub page" form
698  # (Special:Contributions/Jimbo_Wales). The plot
699  # thickens, because the Title object is altered for special pages,
700  # so it doesn't contain the original alias-with-subpage.
701  $origTitle = Title::newFromText( $request->getText( 'title' ) );
702  if ( $origTitle instanceof Title && $origTitle->isSpecialPage() ) {
703  list( $spName, $spPar ) = SpecialPageFactory::resolveAlias( $origTitle->getText() );
704  $active = $spName == 'Contributions'
705  && ( ( $spPar && $spPar == $this->username )
706  || $request->getText( 'target' ) == $this->username );
707  } else {
708  $active = false;
709  }
710 
711  $href = self::makeSpecialUrlSubpage( 'Contributions', $this->username );
712  $personal_urls['mycontris'] = array(
713  'text' => $this->msg( 'mycontris' )->text(),
714  'href' => $href,
715  'active' => $active
716  );
717  $personal_urls['logout'] = array(
718  'text' => $this->msg( 'pt-userlogout' )->text(),
719  'href' => self::makeSpecialUrl( 'Userlogout',
720  // userlogout link must always contain an & character, otherwise we might not be able
721  // to detect a buggy precaching proxy (bug 17790)
722  $title->isSpecial( 'Preferences' ) ? 'noreturnto' : $returnto
723  ),
724  'active' => false
725  );
726  } else {
727  $useCombinedLoginLink = $this->useCombinedLoginLink();
728  $loginlink = $this->getUser()->isAllowed( 'createaccount' ) && $useCombinedLoginLink
729  ? 'nav-login-createaccount'
730  : 'pt-login';
731  $is_signup = $request->getText( 'type' ) == 'signup';
732 
733  $login_url = array(
734  'text' => $this->msg( $loginlink )->text(),
735  'href' => self::makeSpecialUrl( 'Userlogin', $returnto ),
736  'active' => $title->isSpecial( 'Userlogin' ) && ( $loginlink == 'nav-login-createaccount' || !$is_signup ),
737  );
738  $createaccount_url = array(
739  'text' => $this->msg( 'pt-createaccount' )->text(),
740  'href' => self::makeSpecialUrl( 'Userlogin', "$returnto&type=signup" ),
741  'active' => $title->isSpecial( 'Userlogin' ) && $is_signup,
742  );
743 
744  if ( $this->showIPinHeader() ) {
745  $href = &$this->userpageUrlDetails['href'];
746  $personal_urls['anonuserpage'] = array(
747  'text' => $this->username,
748  'href' => $href,
749  'class' => $this->userpageUrlDetails['exists'] ? false : 'new',
750  'active' => ( $pageurl == $href )
751  );
752  $usertalkUrlDetails = $this->makeTalkUrlDetails( $this->userpage );
753  $href = &$usertalkUrlDetails['href'];
754  $personal_urls['anontalk'] = array(
755  'text' => $this->msg( 'anontalk' )->text(),
756  'href' => $href,
757  'class' => $usertalkUrlDetails['exists'] ? false : 'new',
758  'active' => ( $pageurl == $href )
759  );
760  }
761 
762  if ( $this->getUser()->isAllowed( 'createaccount' ) && !$useCombinedLoginLink ) {
763  $personal_urls['createaccount'] = $createaccount_url;
764  }
765 
766  $personal_urls['login'] = $login_url;
767  }
768 
769  wfRunHooks( 'PersonalUrls', array( &$personal_urls, &$title, $this ) );
770  wfProfileOut( __METHOD__ );
771  return $personal_urls;
772  }
773 
785  function tabAction( $title, $message, $selected, $query = '', $checkEdit = false ) {
786  $classes = array();
787  if ( $selected ) {
788  $classes[] = 'selected';
789  }
790  if ( $checkEdit && !$title->isKnown() ) {
791  $classes[] = 'new';
792  if ( $query !== '' ) {
793  $query = 'action=edit&redlink=1&' . $query;
794  } else {
795  $query = 'action=edit&redlink=1';
796  }
797  }
798 
799  // wfMessageFallback will nicely accept $message as an array of fallbacks
800  // or just a single key
801  $msg = wfMessageFallback( $message )->setContext( $this->getContext() );
802  if ( is_array( $message ) ) {
803  // for hook compatibility just keep the last message name
804  $message = end( $message );
805  }
806  if ( $msg->exists() ) {
807  $text = $msg->text();
808  } else {
810  $text = $wgContLang->getFormattedNsText(
811  MWNamespace::getSubject( $title->getNamespace() ) );
812  }
813 
814  $result = array();
815  if ( !wfRunHooks( 'SkinTemplateTabAction', array( &$this,
816  $title, $message, $selected, $checkEdit,
817  &$classes, &$query, &$text, &$result ) ) ) {
818  return $result;
819  }
820 
821  return array(
822  'class' => implode( ' ', $classes ),
823  'text' => $text,
824  'href' => $title->getLocalURL( $query ),
825  'primary' => true );
826  }
827 
828  function makeTalkUrlDetails( $name, $urlaction = '' ) {
830  if ( !is_object( $title ) ) {
831  throw new MWException( __METHOD__ . " given invalid pagename $name" );
832  }
833  $title = $title->getTalkPage();
835  return array(
836  'href' => $title->getLocalURL( $urlaction ),
837  'exists' => $title->getArticleID() != 0,
838  );
839  }
840 
841  function makeArticleUrlDetails( $name, $urlaction = '' ) {
843  $title = $title->getSubjectPage();
845  return array(
846  'href' => $title->getLocalURL( $urlaction ),
847  'exists' => $title->getArticleID() != 0,
848  );
849  }
850 
884  protected function buildContentNavigationUrls() {
885  global $wgDisableLangConversion;
886 
887  wfProfileIn( __METHOD__ );
888 
889  // Display tabs for the relevant title rather than always the title itself
890  $title = $this->getRelevantTitle();
891  $onPage = $title->equals( $this->getTitle() );
892 
893  $out = $this->getOutput();
894  $request = $this->getRequest();
895  $user = $this->getUser();
896 
897  $content_navigation = array(
898  'namespaces' => array(),
899  'views' => array(),
900  'actions' => array(),
901  'variants' => array()
902  );
903 
904  // parameters
905  $action = $request->getVal( 'action', 'view' );
906 
907  $userCanRead = $title->quickUserCan( 'read', $user );
908 
909  $preventActiveTabs = false;
910  wfRunHooks( 'SkinTemplatePreventOtherActiveTabs', array( &$this, &$preventActiveTabs ) );
911 
912  // Checks if page is some kind of content
913  if ( $title->canExist() ) {
914  // Gets page objects for the related namespaces
915  $subjectPage = $title->getSubjectPage();
916  $talkPage = $title->getTalkPage();
917 
918  // Determines if this is a talk page
919  $isTalk = $title->isTalkPage();
920 
921  // Generates XML IDs from namespace names
922  $subjectId = $title->getNamespaceKey( '' );
923 
924  if ( $subjectId == 'main' ) {
925  $talkId = 'talk';
926  } else {
927  $talkId = "{$subjectId}_talk";
928  }
929 
930  $skname = $this->skinname;
931 
932  // Adds namespace links
933  $subjectMsg = array( "nstab-$subjectId" );
934  if ( $subjectPage->isMainPage() ) {
935  array_unshift( $subjectMsg, 'mainpage-nstab' );
936  }
937  $content_navigation['namespaces'][$subjectId] = $this->tabAction(
938  $subjectPage, $subjectMsg, !$isTalk && !$preventActiveTabs, '', $userCanRead
939  );
940  $content_navigation['namespaces'][$subjectId]['context'] = 'subject';
941  $content_navigation['namespaces'][$talkId] = $this->tabAction(
942  $talkPage, array( "nstab-$talkId", 'talk' ), $isTalk && !$preventActiveTabs, '', $userCanRead
943  );
944  $content_navigation['namespaces'][$talkId]['context'] = 'talk';
945 
946  if ( $userCanRead ) {
947  $isForeignFile = $title->inNamespace( NS_FILE ) && $this->canUseWikiPage() &&
948  $this->getWikiPage() instanceof WikiFilePage && !$this->getWikiPage()->isLocal();
949 
950  // Adds view view link
951  if ( $title->exists() || $isForeignFile ) {
952  $content_navigation['views']['view'] = $this->tabAction(
953  $isTalk ? $talkPage : $subjectPage,
954  array( "$skname-view-view", 'view' ),
955  ( $onPage && ( $action == 'view' || $action == 'purge' ) ), '', true
956  );
957  // signal to hide this from simple content_actions
958  $content_navigation['views']['view']['redundant'] = true;
959  }
960 
961  // If it is a non-local file, show a link to the file in its own repository
962  if ( $isForeignFile ) {
963  $file = $this->getWikiPage()->getFile();
964  $content_navigation['views']['view-foreign'] = array(
965  'class' => '',
966  'text' => wfMessageFallback( "$skname-view-foreign", 'view-foreign' )->
967  setContext( $this->getContext() )->
968  params( $file->getRepo()->getDisplayName() )->text(),
969  'href' => $file->getDescriptionUrl(),
970  'primary' => false,
971  );
972  }
973 
974  wfProfileIn( __METHOD__ . '-edit' );
975 
976  // Checks if user can edit the current page if it exists or create it otherwise
977  if ( $title->quickUserCan( 'edit', $user ) && ( $title->exists() || $title->quickUserCan( 'create', $user ) ) ) {
978  // Builds CSS class for talk page links
979  $isTalkClass = $isTalk ? ' istalk' : '';
980  // Whether the user is editing the page
981  $isEditing = $onPage && ( $action == 'edit' || $action == 'submit' );
982  // Whether to show the "Add a new section" tab
983  // Checks if this is a current rev of talk page and is not forced to be hidden
984  $showNewSection = !$out->forceHideNewSectionLink()
985  && ( ( $isTalk && $this->isRevisionCurrent() ) || $out->showNewSectionLink() );
986  $section = $request->getVal( 'section' );
987 
988  if ( $title->exists() || ( $title->getNamespace() == NS_MEDIAWIKI && $title->getDefaultMessageText() !== false ) ) {
989  $msgKey = $isForeignFile ? 'edit-local' : 'edit';
990  } else {
991  $msgKey = $isForeignFile ? 'create-local' : 'create';
992  }
993  $content_navigation['views']['edit'] = array(
994  'class' => ( $isEditing && ( $section !== 'new' || !$showNewSection ) ? 'selected' : '' ) . $isTalkClass,
995  'text' => wfMessageFallback( "$skname-view-$msgKey", $msgKey )->setContext( $this->getContext() )->text(),
996  'href' => $title->getLocalURL( $this->editUrlOptions() ),
997  'primary' => !$isForeignFile, // don't collapse this in vector
998  );
999 
1000  // section link
1001  if ( $showNewSection ) {
1002  // Adds new section link
1003  //$content_navigation['actions']['addsection']
1004  $content_navigation['views']['addsection'] = array(
1005  'class' => ( $isEditing && $section == 'new' ) ? 'selected' : false,
1006  'text' => wfMessageFallback( "$skname-action-addsection", 'addsection' )->setContext( $this->getContext() )->text(),
1007  'href' => $title->getLocalURL( 'action=edit&section=new' )
1008  );
1009  }
1010  // Checks if the page has some kind of viewable content
1011  } elseif ( $title->hasSourceText() ) {
1012  // Adds view source view link
1013  $content_navigation['views']['viewsource'] = array(
1014  'class' => ( $onPage && $action == 'edit' ) ? 'selected' : false,
1015  'text' => wfMessageFallback( "$skname-action-viewsource", 'viewsource' )->setContext( $this->getContext() )->text(),
1016  'href' => $title->getLocalURL( $this->editUrlOptions() ),
1017  'primary' => true, // don't collapse this in vector
1018  );
1019  }
1020  wfProfileOut( __METHOD__ . '-edit' );
1021 
1022  wfProfileIn( __METHOD__ . '-live' );
1023  // Checks if the page exists
1024  if ( $title->exists() ) {
1025  // Adds history view link
1026  $content_navigation['views']['history'] = array(
1027  'class' => ( $onPage && $action == 'history' ) ? 'selected' : false,
1028  'text' => wfMessageFallback( "$skname-view-history", 'history_short' )->setContext( $this->getContext() )->text(),
1029  'href' => $title->getLocalURL( 'action=history' ),
1030  'rel' => 'archives',
1031  );
1032 
1033  if ( $title->quickUserCan( 'delete', $user ) ) {
1034  $content_navigation['actions']['delete'] = array(
1035  'class' => ( $onPage && $action == 'delete' ) ? 'selected' : false,
1036  'text' => wfMessageFallback( "$skname-action-delete", 'delete' )->setContext( $this->getContext() )->text(),
1037  'href' => $title->getLocalURL( 'action=delete' )
1038  );
1039  }
1040 
1041  if ( $title->quickUserCan( 'move', $user ) ) {
1042  $moveTitle = SpecialPage::getTitleFor( 'Movepage', $title->getPrefixedDBkey() );
1043  $content_navigation['actions']['move'] = array(
1044  'class' => $this->getTitle()->isSpecial( 'Movepage' ) ? 'selected' : false,
1045  'text' => wfMessageFallback( "$skname-action-move", 'move' )->setContext( $this->getContext() )->text(),
1046  'href' => $moveTitle->getLocalURL()
1047  );
1048  }
1049  } else {
1050  // article doesn't exist or is deleted
1051  if ( $user->isAllowed( 'deletedhistory' ) ) {
1052  $n = $title->isDeleted();
1053  if ( $n ) {
1054  $undelTitle = SpecialPage::getTitleFor( 'Undelete' );
1055  // If the user can't undelete but can view deleted history show them a "View .. deleted" tab instead
1056  $msgKey = $user->isAllowed( 'undelete' ) ? 'undelete' : 'viewdeleted';
1057  $content_navigation['actions']['undelete'] = array(
1058  'class' => $this->getTitle()->isSpecial( 'Undelete' ) ? 'selected' : false,
1059  'text' => wfMessageFallback( "$skname-action-$msgKey", "{$msgKey}_short" )
1060  ->setContext( $this->getContext() )->numParams( $n )->text(),
1061  'href' => $undelTitle->getLocalURL( array( 'target' => $title->getPrefixedDBkey() ) )
1062  );
1063  }
1064  }
1065  }
1066 
1067  if ( $title->quickUserCan( 'protect', $user ) && $title->getRestrictionTypes() &&
1068  MWNamespace::getRestrictionLevels( $title->getNamespace(), $user ) !== array( '' )
1069  ) {
1070  $mode = $title->isProtected() ? 'unprotect' : 'protect';
1071  $content_navigation['actions'][$mode] = array(
1072  'class' => ( $onPage && $action == $mode ) ? 'selected' : false,
1073  'text' => wfMessageFallback( "$skname-action-$mode", $mode )->setContext( $this->getContext() )->text(),
1074  'href' => $title->getLocalURL( "action=$mode" )
1075  );
1076  }
1077 
1078  wfProfileOut( __METHOD__ . '-live' );
1079 
1080  // Checks if the user is logged in
1081  if ( $this->loggedin && $user->isAllowedAll( 'viewmywatchlist', 'editmywatchlist' ) ) {
1091  $mode = $user->isWatched( $title ) ? 'unwatch' : 'watch';
1092  $token = WatchAction::getWatchToken( $title, $user, $mode );
1093  $content_navigation['actions'][$mode] = array(
1094  'class' => $onPage && ( $action == 'watch' || $action == 'unwatch' ) ? 'selected' : false,
1095  // uses 'watch' or 'unwatch' message
1096  'text' => $this->msg( $mode )->text(),
1097  'href' => $title->getLocalURL( array( 'action' => $mode, 'token' => $token ) )
1098  );
1099  }
1100  }
1101 
1102  wfRunHooks( 'SkinTemplateNavigation', array( &$this, &$content_navigation ) );
1103 
1104  if ( $userCanRead && !$wgDisableLangConversion ) {
1105  $pageLang = $title->getPageLanguage();
1106  // Gets list of language variants
1107  $variants = $pageLang->getVariants();
1108  // Checks that language conversion is enabled and variants exist
1109  // And if it is not in the special namespace
1110  if ( count( $variants ) > 1 ) {
1111  // Gets preferred variant (note that user preference is
1112  // only possible for wiki content language variant)
1113  $preferred = $pageLang->getPreferredVariant();
1114  if ( Action::getActionName( $this ) === 'view' ) {
1115  $params = $request->getQueryValues();
1116  unset( $params['title'] );
1117  } else {
1118  $params = array();
1119  }
1120  // Loops over each variant
1121  foreach ( $variants as $code ) {
1122  // Gets variant name from language code
1123  $varname = $pageLang->getVariantname( $code );
1124  // Appends variant link
1125  $content_navigation['variants'][] = array(
1126  'class' => ( $code == $preferred ) ? 'selected' : false,
1127  'text' => $varname,
1128  'href' => $title->getLocalURL( array( 'variant' => $code ) + $params ),
1129  'lang' => wfBCP47( $code ),
1130  'hreflang' => wfBCP47( $code ),
1131  );
1132  }
1133  }
1134  }
1135  } else {
1136  // If it's not content, it's got to be a special page
1137  $content_navigation['namespaces']['special'] = array(
1138  'class' => 'selected',
1139  'text' => $this->msg( 'nstab-special' )->text(),
1140  'href' => $request->getRequestURL(), // @see: bug 2457, bug 2510
1141  'context' => 'subject'
1142  );
1143 
1144  wfRunHooks( 'SkinTemplateNavigation::SpecialPage',
1145  array( &$this, &$content_navigation ) );
1146  }
1147 
1148  // Equiv to SkinTemplateContentActions
1149  wfRunHooks( 'SkinTemplateNavigation::Universal', array( &$this, &$content_navigation ) );
1150 
1151  // Setup xml ids and tooltip info
1152  foreach ( $content_navigation as $section => &$links ) {
1153  foreach ( $links as $key => &$link ) {
1154  $xmlID = $key;
1155  if ( isset( $link['context'] ) && $link['context'] == 'subject' ) {
1156  $xmlID = 'ca-nstab-' . $xmlID;
1157  } elseif ( isset( $link['context'] ) && $link['context'] == 'talk' ) {
1158  $xmlID = 'ca-talk';
1159  } elseif ( $section == 'variants' ) {
1160  $xmlID = 'ca-varlang-' . $xmlID;
1161  } else {
1162  $xmlID = 'ca-' . $xmlID;
1163  }
1164  $link['id'] = $xmlID;
1165  }
1166  }
1167 
1168  # We don't want to give the watch tab an accesskey if the
1169  # page is being edited, because that conflicts with the
1170  # accesskey on the watch checkbox. We also don't want to
1171  # give the edit tab an accesskey, because that's fairly
1172  # superfluous and conflicts with an accesskey (Ctrl-E) often
1173  # used for editing in Safari.
1174  if ( in_array( $action, array( 'edit', 'submit' ) ) ) {
1175  if ( isset( $content_navigation['views']['edit'] ) ) {
1176  $content_navigation['views']['edit']['tooltiponly'] = true;
1177  }
1178  if ( isset( $content_navigation['actions']['watch'] ) ) {
1179  $content_navigation['actions']['watch']['tooltiponly'] = true;
1180  }
1181  if ( isset( $content_navigation['actions']['unwatch'] ) ) {
1182  $content_navigation['actions']['unwatch']['tooltiponly'] = true;
1183  }
1184  }
1185 
1186  wfProfileOut( __METHOD__ );
1187 
1188  return $content_navigation;
1189  }
1190 
1196  function buildContentActionUrls( $content_navigation ) {
1197 
1198  wfProfileIn( __METHOD__ );
1199 
1200  // content_actions has been replaced with content_navigation for backwards
1201  // compatibility and also for skins that just want simple tabs content_actions
1202  // is now built by flattening the content_navigation arrays into one
1203 
1204  $content_actions = array();
1205 
1206  foreach ( $content_navigation as $links ) {
1207 
1208  foreach ( $links as $key => $value ) {
1209 
1210  if ( isset( $value['redundant'] ) && $value['redundant'] ) {
1211  // Redundant tabs are dropped from content_actions
1212  continue;
1213  }
1214 
1215  // content_actions used to have ids built using the "ca-$key" pattern
1216  // so the xmlID based id is much closer to the actual $key that we want
1217  // for that reason we'll just strip out the ca- if present and use
1218  // the latter potion of the "id" as the $key
1219  if ( isset( $value['id'] ) && substr( $value['id'], 0, 3 ) == 'ca-' ) {
1220  $key = substr( $value['id'], 3 );
1221  }
1222 
1223  if ( isset( $content_actions[$key] ) ) {
1224  wfDebug( __METHOD__ . ": Found a duplicate key for $key while flattening " .
1225  "content_navigation into content_actions.\n" );
1226  continue;
1227  }
1228 
1229  $content_actions[$key] = $value;
1230 
1231  }
1232 
1233  }
1234 
1235  wfProfileOut( __METHOD__ );
1236 
1237  return $content_actions;
1238  }
1239 
1245  protected function buildNavUrls() {
1246  global $wgUploadNavigationUrl;
1247 
1248  wfProfileIn( __METHOD__ );
1249 
1250  $out = $this->getOutput();
1251  $request = $this->getRequest();
1252 
1253  $nav_urls = array();
1254  $nav_urls['mainpage'] = array( 'href' => self::makeMainPageUrl() );
1255  if ( $wgUploadNavigationUrl ) {
1256  $nav_urls['upload'] = array( 'href' => $wgUploadNavigationUrl );
1257  } elseif ( UploadBase::isEnabled() && UploadBase::isAllowed( $this->getUser() ) === true ) {
1258  $nav_urls['upload'] = array( 'href' => self::makeSpecialUrl( 'Upload' ) );
1259  } else {
1260  $nav_urls['upload'] = false;
1261  }
1262  $nav_urls['specialpages'] = array( 'href' => self::makeSpecialUrl( 'Specialpages' ) );
1263 
1264  $nav_urls['print'] = false;
1265  $nav_urls['permalink'] = false;
1266  $nav_urls['info'] = false;
1267  $nav_urls['whatlinkshere'] = false;
1268  $nav_urls['recentchangeslinked'] = false;
1269  $nav_urls['contributions'] = false;
1270  $nav_urls['log'] = false;
1271  $nav_urls['blockip'] = false;
1272  $nav_urls['emailuser'] = false;
1273  $nav_urls['userrights'] = false;
1274 
1275  // A print stylesheet is attached to all pages, but nobody ever
1276  // figures that out. :) Add a link...
1277  if ( !$out->isPrintable() && ( $out->isArticle() || $this->getTitle()->isSpecialPage() ) ) {
1278  $nav_urls['print'] = array(
1279  'text' => $this->msg( 'printableversion' )->text(),
1280  'href' => $this->getTitle()->getLocalURL(
1281  $request->appendQueryValue( 'printable', 'yes', true ) )
1282  );
1283  }
1284 
1285  if ( $out->isArticle() ) {
1286  // Also add a "permalink" while we're at it
1287  $revid = $this->getRevisionId();
1288  if ( $revid ) {
1289  $nav_urls['permalink'] = array(
1290  'text' => $this->msg( 'permalink' )->text(),
1291  'href' => $this->getTitle()->getLocalURL( "oldid=$revid" )
1292  );
1293  }
1294 
1295  // Use the copy of revision ID in case this undocumented, shady hook tries to mess with internals
1296  wfRunHooks( 'SkinTemplateBuildNavUrlsNav_urlsAfterPermalink',
1297  array( &$this, &$nav_urls, &$revid, &$revid ) );
1298  }
1299 
1300  if ( $out->isArticleRelated() ) {
1301  $nav_urls['whatlinkshere'] = array(
1302  'href' => SpecialPage::getTitleFor( 'Whatlinkshere', $this->thispage )->getLocalURL()
1303  );
1304 
1305  $nav_urls['info'] = array(
1306  'text' => $this->msg( 'pageinfo-toolboxlink' )->text(),
1307  'href' => $this->getTitle()->getLocalURL( "action=info" )
1308  );
1309 
1310  if ( $this->getTitle()->getArticleID() ) {
1311  $nav_urls['recentchangeslinked'] = array(
1312  'href' => SpecialPage::getTitleFor( 'Recentchangeslinked', $this->thispage )->getLocalURL()
1313  );
1314  }
1315  }
1316 
1317  $user = $this->getRelevantUser();
1318  if ( $user ) {
1319  $rootUser = $user->getName();
1320 
1321  $nav_urls['contributions'] = array(
1322  'text' => $this->msg( 'contributions', $rootUser )->text(),
1323  'href' => self::makeSpecialUrlSubpage( 'Contributions', $rootUser )
1324  );
1325 
1326  $nav_urls['log'] = array(
1327  'href' => self::makeSpecialUrlSubpage( 'Log', $rootUser )
1328  );
1329 
1330  if ( $this->getUser()->isAllowed( 'block' ) ) {
1331  $nav_urls['blockip'] = array(
1332  'href' => self::makeSpecialUrlSubpage( 'Block', $rootUser )
1333  );
1334  }
1335 
1336  if ( $this->showEmailUser( $user ) ) {
1337  $nav_urls['emailuser'] = array(
1338  'href' => self::makeSpecialUrlSubpage( 'Emailuser', $rootUser )
1339  );
1340  }
1341 
1342  if ( !$user->isAnon() ) {
1343  $sur = new UserrightsPage;
1344  $sur->setContext( $this->getContext() );
1345  if ( $sur->userCanExecute( $this->getUser() ) ) {
1346  $nav_urls['userrights'] = array(
1347  'href' => self::makeSpecialUrlSubpage( 'Userrights', $rootUser )
1348  );
1349  }
1350  }
1351  }
1352 
1353  wfProfileOut( __METHOD__ );
1354  return $nav_urls;
1355  }
1356 
1362  function getNameSpaceKey() {
1363  return $this->getTitle()->getNamespaceKey();
1364  }
1365 }
1366 
1372 abstract class QuickTemplate {
1376  function __construct() {
1377  $this->data = array();
1378  $this->translator = new MediaWiki_I18N();
1379  }
1380 
1386  public function set( $name, $value ) {
1387  $this->data[$name] = $value;
1388  }
1389 
1397  public function get( $name, $default = null ) {
1398  if ( isset( $this->data[$name] ) ) {
1399  return $this->data[$name];
1400  } else {
1401  return $default;
1402  }
1403  }
1404 
1409  public function setRef( $name, &$value ) {
1410  $this->data[$name] =& $value;
1411  }
1412 
1416  public function setTranslator( &$t ) {
1417  $this->translator = &$t;
1418  }
1419 
1424  abstract public function execute();
1425 
1429  function text( $str ) {
1430  echo htmlspecialchars( $this->data[$str] );
1431  }
1432 
1436  function html( $str ) {
1437  echo $this->data[$str];
1438  }
1439 
1443  function msg( $str ) {
1444  echo htmlspecialchars( $this->translator->translate( $str ) );
1445  }
1446 
1450  function msgHtml( $str ) {
1451  echo $this->translator->translate( $str );
1452  }
1453 
1458  function msgWiki( $str ) {
1459  global $wgOut;
1460 
1461  $text = $this->translator->translate( $str );
1462  echo $wgOut->parse( $text );
1463  }
1464 
1469  function haveData( $str ) {
1470  return isset( $this->data[$str] );
1471  }
1472 
1478  function haveMsg( $str ) {
1479  $msg = $this->translator->translate( $str );
1480  return ( $msg != '-' ) && ( $msg != '' ); # ????
1481  }
1482 
1488  public function getSkin() {
1489  return $this->data['skin'];
1490  }
1491 
1498  public function getHTML() {
1499  ob_start();
1500  $this->execute();
1501  $html = ob_get_contents();
1502  ob_end_clean();
1503  return $html;
1504  }
1505 }
1506 
1512 abstract class BaseTemplate extends QuickTemplate {
1513 
1520  public function getMsg( $name ) {
1521  return $this->getSkin()->msg( $name );
1522  }
1523 
1524  function msg( $str ) {
1525  echo $this->getMsg( $str )->escaped();
1526  }
1527 
1528  function msgHtml( $str ) {
1529  echo $this->getMsg( $str )->text();
1530  }
1531 
1532  function msgWiki( $str ) {
1533  echo $this->getMsg( $str )->parseAsBlock();
1534  }
1535 
1543  function getToolbox() {
1544  wfProfileIn( __METHOD__ );
1545 
1546  $toolbox = array();
1547  if ( isset( $this->data['nav_urls']['whatlinkshere'] ) && $this->data['nav_urls']['whatlinkshere'] ) {
1548  $toolbox['whatlinkshere'] = $this->data['nav_urls']['whatlinkshere'];
1549  $toolbox['whatlinkshere']['id'] = 't-whatlinkshere';
1550  }
1551  if ( isset( $this->data['nav_urls']['recentchangeslinked'] ) && $this->data['nav_urls']['recentchangeslinked'] ) {
1552  $toolbox['recentchangeslinked'] = $this->data['nav_urls']['recentchangeslinked'];
1553  $toolbox['recentchangeslinked']['msg'] = 'recentchangeslinked-toolbox';
1554  $toolbox['recentchangeslinked']['id'] = 't-recentchangeslinked';
1555  }
1556  if ( isset( $this->data['feeds'] ) && $this->data['feeds'] ) {
1557  $toolbox['feeds']['id'] = 'feedlinks';
1558  $toolbox['feeds']['links'] = array();
1559  foreach ( $this->data['feeds'] as $key => $feed ) {
1560  $toolbox['feeds']['links'][$key] = $feed;
1561  $toolbox['feeds']['links'][$key]['id'] = "feed-$key";
1562  $toolbox['feeds']['links'][$key]['rel'] = 'alternate';
1563  $toolbox['feeds']['links'][$key]['type'] = "application/{$key}+xml";
1564  $toolbox['feeds']['links'][$key]['class'] = 'feedlink';
1565  }
1566  }
1567  foreach ( array( 'contributions', 'log', 'blockip', 'emailuser', 'userrights', 'upload', 'specialpages' ) as $special ) {
1568  if ( isset( $this->data['nav_urls'][$special] ) && $this->data['nav_urls'][$special] ) {
1569  $toolbox[$special] = $this->data['nav_urls'][$special];
1570  $toolbox[$special]['id'] = "t-$special";
1571  }
1572  }
1573  if ( isset( $this->data['nav_urls']['print'] ) && $this->data['nav_urls']['print'] ) {
1574  $toolbox['print'] = $this->data['nav_urls']['print'];
1575  $toolbox['print']['id'] = 't-print';
1576  $toolbox['print']['rel'] = 'alternate';
1577  $toolbox['print']['msg'] = 'printableversion';
1578  }
1579  if ( isset( $this->data['nav_urls']['permalink'] ) && $this->data['nav_urls']['permalink'] ) {
1580  $toolbox['permalink'] = $this->data['nav_urls']['permalink'];
1581  if ( $toolbox['permalink']['href'] === '' ) {
1582  unset( $toolbox['permalink']['href'] );
1583  $toolbox['ispermalink']['tooltiponly'] = true;
1584  $toolbox['ispermalink']['id'] = 't-ispermalink';
1585  $toolbox['ispermalink']['msg'] = 'permalink';
1586  } else {
1587  $toolbox['permalink']['id'] = 't-permalink';
1588  }
1589  }
1590  if ( isset( $this->data['nav_urls']['info'] ) && $this->data['nav_urls']['info'] ) {
1591  $toolbox['info'] = $this->data['nav_urls']['info'];
1592  $toolbox['info']['id'] = 't-info';
1593  }
1594 
1595  wfRunHooks( 'BaseTemplateToolbox', array( &$this, &$toolbox ) );
1596  wfProfileOut( __METHOD__ );
1597  return $toolbox;
1598  }
1599 
1610  function getPersonalTools() {
1611  $personal_tools = array();
1612  foreach ( $this->get( 'personal_urls' ) as $key => $plink ) {
1613  # The class on a personal_urls item is meant to go on the <a> instead
1614  # of the <li> so we have to use a single item "links" array instead
1615  # of using most of the personal_url's keys directly.
1616  $ptool = array(
1617  'links' => array(
1618  array( 'single-id' => "pt-$key" ),
1619  ),
1620  'id' => "pt-$key",
1621  );
1622  if ( isset( $plink['active'] ) ) {
1623  $ptool['active'] = $plink['active'];
1624  }
1625  foreach ( array( 'href', 'class', 'text', 'dir' ) as $k ) {
1626  if ( isset( $plink[$k] ) ) {
1627  $ptool['links'][0][$k] = $plink[$k];
1628  }
1629  }
1630  $personal_tools[$key] = $ptool;
1631  }
1632  return $personal_tools;
1633  }
1634 
1635  function getSidebar( $options = array() ) {
1636  // Force the rendering of the following portals
1637  $sidebar = $this->data['sidebar'];
1638  if ( !isset( $sidebar['SEARCH'] ) ) {
1639  $sidebar['SEARCH'] = true;
1640  }
1641  if ( !isset( $sidebar['TOOLBOX'] ) ) {
1642  $sidebar['TOOLBOX'] = true;
1643  }
1644  if ( !isset( $sidebar['LANGUAGES'] ) ) {
1645  $sidebar['LANGUAGES'] = true;
1646  }
1647 
1648  if ( !isset( $options['search'] ) || $options['search'] !== true ) {
1649  unset( $sidebar['SEARCH'] );
1650  }
1651  if ( isset( $options['toolbox'] ) && $options['toolbox'] === false ) {
1652  unset( $sidebar['TOOLBOX'] );
1653  }
1654  if ( isset( $options['languages'] ) && $options['languages'] === false ) {
1655  unset( $sidebar['LANGUAGES'] );
1656  }
1657 
1658  $boxes = array();
1659  foreach ( $sidebar as $boxName => $content ) {
1660  if ( $content === false ) {
1661  continue;
1662  }
1663  switch ( $boxName ) {
1664  case 'SEARCH':
1665  // Search is a special case, skins should custom implement this
1666  $boxes[$boxName] = array(
1667  'id' => 'p-search',
1668  'header' => $this->getMsg( 'search' )->text(),
1669  'generated' => false,
1670  'content' => true,
1671  );
1672  break;
1673  case 'TOOLBOX':
1674  $msgObj = $this->getMsg( 'toolbox' );
1675  $boxes[$boxName] = array(
1676  'id' => 'p-tb',
1677  'header' => $msgObj->exists() ? $msgObj->text() : 'toolbox',
1678  'generated' => false,
1679  'content' => $this->getToolbox(),
1680  );
1681  break;
1682  case 'LANGUAGES':
1683  if ( $this->data['language_urls'] ) {
1684  $msgObj = $this->getMsg( 'otherlanguages' );
1685  $boxes[$boxName] = array(
1686  'id' => 'p-lang',
1687  'header' => $msgObj->exists() ? $msgObj->text() : 'otherlanguages',
1688  'generated' => false,
1689  'content' => $this->data['language_urls'],
1690  );
1691  }
1692  break;
1693  default:
1694  $msgObj = $this->getMsg( $boxName );
1695  $boxes[$boxName] = array(
1696  'id' => "p-$boxName",
1697  'header' => $msgObj->exists() ? $msgObj->text() : $boxName,
1698  'generated' => true,
1699  'content' => $content,
1700  );
1701  break;
1702  }
1703  }
1704 
1705  // HACK: Compatibility with extensions still using SkinTemplateToolboxEnd
1706  $hookContents = null;
1707  if ( isset( $boxes['TOOLBOX'] ) ) {
1708  ob_start();
1709  // We pass an extra 'true' at the end so extensions using BaseTemplateToolbox
1710  // can abort and avoid outputting double toolbox links
1711  wfRunHooks( 'SkinTemplateToolboxEnd', array( &$this, true ) );
1712  $hookContents = ob_get_contents();
1713  ob_end_clean();
1714  if ( !trim( $hookContents ) ) {
1715  $hookContents = null;
1716  }
1717  }
1718  // END hack
1719 
1720  if ( isset( $options['htmlOnly'] ) && $options['htmlOnly'] === true ) {
1721  foreach ( $boxes as $boxName => $box ) {
1722  if ( is_array( $box['content'] ) ) {
1723  $content = '<ul>';
1724  foreach ( $box['content'] as $key => $val ) {
1725  $content .= "\n " . $this->makeListItem( $key, $val );
1726  }
1727  // HACK, shove the toolbox end onto the toolbox if we're rendering itself
1728  if ( $hookContents ) {
1729  $content .= "\n $hookContents";
1730  }
1731  // END hack
1732  $content .= "\n</ul>\n";
1733  $boxes[$boxName]['content'] = $content;
1734  }
1735  }
1736  } else {
1737  if ( $hookContents ) {
1738  $boxes['TOOLBOXEND'] = array(
1739  'id' => 'p-toolboxend',
1740  'header' => $boxes['TOOLBOX']['header'],
1741  'generated' => false,
1742  'content' => "<ul>{$hookContents}</ul>",
1743  );
1744  // HACK: Make sure that TOOLBOXEND is sorted next to TOOLBOX
1745  $boxes2 = array();
1746  foreach ( $boxes as $key => $box ) {
1747  if ( $key === 'TOOLBOXEND' ) {
1748  continue;
1749  }
1750  $boxes2[$key] = $box;
1751  if ( $key === 'TOOLBOX' ) {
1752  $boxes2['TOOLBOXEND'] = $boxes['TOOLBOXEND'];
1753  }
1754  }
1755  $boxes = $boxes2;
1756  // END hack
1757  }
1758  }
1759 
1760  return $boxes;
1761  }
1762 
1766  protected function renderAfterPortlet( $name ) {
1767  $content = '';
1768  wfRunHooks( 'BaseTemplateAfterPortlet', array( $this, $name, &$content ) );
1769 
1770  if ( $content !== '' ) {
1771  echo "<div class='after-portlet after-portlet-$name'>$content</div>";
1772  }
1773 
1774  }
1775 
1819  function makeLink( $key, $item, $options = array() ) {
1820  if ( isset( $item['text'] ) ) {
1821  $text = $item['text'];
1822  } else {
1823  $text = $this->translator->translate( isset( $item['msg'] ) ? $item['msg'] : $key );
1824  }
1825 
1826  $html = htmlspecialchars( $text );
1827 
1828  if ( isset( $options['text-wrapper'] ) ) {
1829  $wrapper = $options['text-wrapper'];
1830  if ( isset( $wrapper['tag'] ) ) {
1831  $wrapper = array( $wrapper );
1832  }
1833  while ( count( $wrapper ) > 0 ) {
1834  $element = array_pop( $wrapper );
1835  $html = Html::rawElement( $element['tag'], isset( $element['attributes'] ) ? $element['attributes'] : null, $html );
1836  }
1837  }
1838 
1839  if ( isset( $item['href'] ) || isset( $options['link-fallback'] ) ) {
1840  $attrs = $item;
1841  foreach ( array( 'single-id', 'text', 'msg', 'tooltiponly', 'context', 'primary' ) as $k ) {
1842  unset( $attrs[$k] );
1843  }
1844 
1845  if ( isset( $item['id'] ) && !isset( $item['single-id'] ) ) {
1846  $item['single-id'] = $item['id'];
1847  }
1848  if ( isset( $item['single-id'] ) ) {
1849  if ( isset( $item['tooltiponly'] ) && $item['tooltiponly'] ) {
1850  $title = Linker::titleAttrib( $item['single-id'] );
1851  if ( $title !== false ) {
1852  $attrs['title'] = $title;
1853  }
1854  } else {
1855  $tip = Linker::tooltipAndAccesskeyAttribs( $item['single-id'] );
1856  if ( isset( $tip['title'] ) && $tip['title'] !== false ) {
1857  $attrs['title'] = $tip['title'];
1858  }
1859  if ( isset( $tip['accesskey'] ) && $tip['accesskey'] !== false ) {
1860  $attrs['accesskey'] = $tip['accesskey'];
1861  }
1862  }
1863  }
1864  if ( isset( $options['link-class'] ) ) {
1865  if ( isset( $attrs['class'] ) ) {
1866  $attrs['class'] .= " {$options['link-class']}";
1867  } else {
1868  $attrs['class'] = $options['link-class'];
1869  }
1870  }
1871  $html = Html::rawElement( isset( $attrs['href'] ) ? 'a' : $options['link-fallback'], $attrs, $html );
1872  }
1873 
1874  return $html;
1875  }
1876 
1905  function makeListItem( $key, $item, $options = array() ) {
1906  if ( isset( $item['links'] ) ) {
1907  $links = array();
1908  foreach ( $item['links'] as $linkKey => $link ) {
1909  $links[] = $this->makeLink( $linkKey, $link, $options );
1910  }
1911  $html = implode( ' ', $links );
1912  } else {
1913  $link = $item;
1914  // These keys are used by makeListItem and shouldn't be passed on to the link
1915  foreach ( array( 'id', 'class', 'active', 'tag', 'itemtitle' ) as $k ) {
1916  unset( $link[$k] );
1917  }
1918  if ( isset( $item['id'] ) && !isset( $item['single-id'] ) ) {
1919  // The id goes on the <li> not on the <a> for single links
1920  // but makeSidebarLink still needs to know what id to use when
1921  // generating tooltips and accesskeys.
1922  $link['single-id'] = $item['id'];
1923  }
1924  $html = $this->makeLink( $key, $link, $options );
1925  }
1926 
1927  $attrs = array();
1928  foreach ( array( 'id', 'class' ) as $attr ) {
1929  if ( isset( $item[$attr] ) ) {
1930  $attrs[$attr] = $item[$attr];
1931  }
1932  }
1933  if ( isset( $item['active'] ) && $item['active'] ) {
1934  if ( !isset( $attrs['class'] ) ) {
1935  $attrs['class'] = '';
1936  }
1937  $attrs['class'] .= ' active';
1938  $attrs['class'] = trim( $attrs['class'] );
1939  }
1940  if ( isset( $item['itemtitle'] ) ) {
1941  $attrs['title'] = $item['itemtitle'];
1942  }
1943  return Html::rawElement( isset( $options['tag'] ) ? $options['tag'] : 'li', $attrs, $html );
1944  }
1945 
1946  function makeSearchInput( $attrs = array() ) {
1947  $realAttrs = array(
1948  'type' => 'search',
1949  'name' => 'search',
1950  'placeholder' => wfMessage( 'searchsuggest-search' )->text(),
1951  'value' => $this->get( 'search', '' ),
1952  );
1953  $realAttrs = array_merge( $realAttrs, Linker::tooltipAndAccesskeyAttribs( 'search' ), $attrs );
1954  return Html::element( 'input', $realAttrs );
1955  }
1956 
1957  function makeSearchButton( $mode, $attrs = array() ) {
1958  switch ( $mode ) {
1959  case 'go':
1960  case 'fulltext':
1961  $realAttrs = array(
1962  'type' => 'submit',
1963  'name' => $mode,
1964  'value' => $this->translator->translate(
1965  $mode == 'go' ? 'searcharticle' : 'searchbutton' ),
1966  );
1967  $realAttrs = array_merge(
1968  $realAttrs,
1969  Linker::tooltipAndAccesskeyAttribs( "search-$mode" ),
1970  $attrs
1971  );
1972  return Html::element( 'input', $realAttrs );
1973  case 'image':
1974  $buttonAttrs = array(
1975  'type' => 'submit',
1976  'name' => 'button',
1977  );
1978  $buttonAttrs = array_merge(
1979  $buttonAttrs,
1980  Linker::tooltipAndAccesskeyAttribs( 'search-fulltext' ),
1981  $attrs
1982  );
1983  unset( $buttonAttrs['src'] );
1984  unset( $buttonAttrs['alt'] );
1985  unset( $buttonAttrs['width'] );
1986  unset( $buttonAttrs['height'] );
1987  $imgAttrs = array(
1988  'src' => $attrs['src'],
1989  'alt' => isset( $attrs['alt'] )
1990  ? $attrs['alt']
1991  : $this->translator->translate( 'searchbutton' ),
1992  'width' => isset( $attrs['width'] ) ? $attrs['width'] : null,
1993  'height' => isset( $attrs['height'] ) ? $attrs['height'] : null,
1994  );
1995  return Html::rawElement( 'button', $buttonAttrs, Html::element( 'img', $imgAttrs ) );
1996  default:
1997  throw new MWException( 'Unknown mode passed to BaseTemplate::makeSearchButton' );
1998  }
1999  }
2000 
2009  function getFooterLinks( $option = null ) {
2010  $footerlinks = $this->get( 'footerlinks' );
2011 
2012  // Reduce footer links down to only those which are being used
2013  $validFooterLinks = array();
2014  foreach ( $footerlinks as $category => $links ) {
2015  $validFooterLinks[$category] = array();
2016  foreach ( $links as $link ) {
2017  if ( isset( $this->data[$link] ) && $this->data[$link] ) {
2018  $validFooterLinks[$category][] = $link;
2019  }
2020  }
2021  if ( count( $validFooterLinks[$category] ) <= 0 ) {
2022  unset( $validFooterLinks[$category] );
2023  }
2024  }
2025 
2026  if ( $option == 'flat' ) {
2027  // fold footerlinks into a single array using a bit of trickery
2028  $validFooterLinks = call_user_func_array(
2029  'array_merge',
2030  array_values( $validFooterLinks )
2031  );
2032  }
2033 
2034  return $validFooterLinks;
2035  }
2036 
2048  function getFooterIcons( $option = null ) {
2049  // Generate additional footer icons
2050  $footericons = $this->get( 'footericons' );
2051 
2052  if ( $option == 'icononly' ) {
2053  // Unset any icons which don't have an image
2054  foreach ( $footericons as &$footerIconsBlock ) {
2055  foreach ( $footerIconsBlock as $footerIconKey => $footerIcon ) {
2056  if ( !is_string( $footerIcon ) && !isset( $footerIcon['src'] ) ) {
2057  unset( $footerIconsBlock[$footerIconKey] );
2058  }
2059  }
2060  }
2061  // Redo removal of any empty blocks
2062  foreach ( $footericons as $footerIconsKey => &$footerIconsBlock ) {
2063  if ( count( $footerIconsBlock ) <= 0 ) {
2064  unset( $footericons[$footerIconsKey] );
2065  }
2066  }
2067  } elseif ( $option == 'nocopyright' ) {
2068  unset( $footericons['copyright']['copyright'] );
2069  if ( count( $footericons['copyright'] ) <= 0 ) {
2070  unset( $footericons['copyright'] );
2071  }
2072  }
2073 
2074  return $footericons;
2075  }
2076 
2082  function printTrail() { ?>
2083 <?php echo MWDebug::getDebugHTML( $this->getSkin()->getContext() ); ?>
2084 <?php $this->html( 'bottomscripts' ); /* JS call to runBodyOnloadHook */ ?>
2085 <?php $this->html( 'reporttime' ) ?>
2086 <?php
2087  }
2088 
2089 }
Action\getActionName
static getActionName(IContextSource $context)
Get the action that will be executed, not necessarily the one passed passed through the "action" requ...
Definition: Action.php:112
BaseTemplate\getPersonalTools
getPersonalTools()
Create an array of personal tools items from the data in the quicktemplate stored by SkinTemplate.
Definition: SkinTemplate.php:1610
BaseTemplate\getFooterLinks
getFooterLinks( $option=null)
Returns an array of footerlinks trimmed down to only those footer links that are valid.
Definition: SkinTemplate.php:2009
BaseTemplate\makeSearchInput
makeSearchInput( $attrs=array())
Definition: SkinTemplate.php:1946
BaseTemplate\msg
msg( $str)
Definition: SkinTemplate.php:1524
BaseTemplate\msgWiki
msgWiki( $str)
An ugly, ugly hack.
Definition: SkinTemplate.php:1532
SkinTemplate\useCombinedLoginLink
useCombinedLoginLink()
Output a boolean indicating if buildPersonalUrls should output separate login and create account link...
Definition: SkinTemplate.php:625
$result
The index of the header message $result[1]=The index of the body text message $result[2 through n]=Parameters passed to body text message. Please note the header message cannot receive/use parameters. 'ImportHandleLogItemXMLTag':When parsing a XML tag in a log item. $reader:XMLReader object $logInfo:Array of information Return false to stop further processing of the tag 'ImportHandlePageXMLTag':When parsing a XML tag in a page. $reader:XMLReader object $pageInfo:Array of information Return false to stop further processing of the tag 'ImportHandleRevisionXMLTag':When parsing a XML tag in a page revision. $reader:XMLReader object $pageInfo:Array of page information $revisionInfo:Array of revision information Return false to stop further processing of the tag 'ImportHandleToplevelXMLTag':When parsing a top level XML tag. $reader:XMLReader object Return false to stop further processing of the tag 'ImportHandleUploadXMLTag':When parsing a XML tag in a file upload. $reader:XMLReader object $revisionInfo:Array of information Return false to stop further processing of the tag 'InfoAction':When building information to display on the action=info page. $context:IContextSource object & $pageInfo:Array of information 'InitializeArticleMaybeRedirect':MediaWiki check to see if title is a redirect. $title:Title object for the current page $request:WebRequest $ignoreRedirect:boolean to skip redirect check $target:Title/string of redirect target $article:Article object 'InterwikiLoadPrefix':When resolving if a given prefix is an interwiki or not. Return true without providing an interwiki to continue interwiki search. $prefix:interwiki prefix we are looking for. & $iwData:output array describing the interwiki with keys iw_url, iw_local, iw_trans and optionally iw_api and iw_wikiid. 'InternalParseBeforeSanitize':during Parser 's internalParse method just before the parser removes unwanted/dangerous HTML tags and after nowiki/noinclude/includeonly/onlyinclude and other processings. Ideal for syntax-extensions after template/parser function execution which respect nowiki and HTML-comments. & $parser:Parser object & $text:string containing partially parsed text & $stripState:Parser 's internal StripState object 'InternalParseBeforeLinks':during Parser 's internalParse method before links but after nowiki/noinclude/includeonly/onlyinclude and other processings. & $parser:Parser object & $text:string containing partially parsed text & $stripState:Parser 's internal StripState object 'InvalidateEmailComplete':Called after a user 's email has been invalidated successfully. $user:user(object) whose email is being invalidated 'IRCLineURL':When constructing the URL to use in an IRC notification. Callee may modify $url and $query, URL will be constructed as $url . $query & $url:URL to index.php & $query:Query string $rc:RecentChange object that triggered url generation 'IsFileCacheable':Override the result of Article::isFileCacheable()(if true) $article:article(object) being checked 'IsTrustedProxy':Override the result of wfIsTrustedProxy() $ip:IP being check $result:Change this value to override the result of wfIsTrustedProxy() 'IsUploadAllowedFromUrl':Override the result of UploadFromUrl::isAllowedUrl() $url:URL used to upload from & $allowed:Boolean indicating if uploading is allowed for given URL 'isValidEmailAddr':Override the result of User::isValidEmailAddr(), for instance to return false if the domain name doesn 't match your organization. $addr:The e-mail address entered by the user & $result:Set this and return false to override the internal checks 'isValidPassword':Override the result of User::isValidPassword() $password:The password entered by the user & $result:Set this and return false to override the internal checks $user:User the password is being validated for 'Language::getMessagesFileName':$code:The language code or the language we 're looking for a messages file for & $file:The messages file path, you can override this to change the location. 'LanguageGetNamespaces':Provide custom ordering for namespaces or remove namespaces. Do not use this hook to add namespaces. Use CanonicalNamespaces for that. & $namespaces:Array of namespaces indexed by their numbers 'LanguageGetMagic':DEPRECATED, use $magicWords in a file listed in $wgExtensionMessagesFiles instead. Use this to define synonyms of magic words depending of the language $magicExtensions:associative array of magic words synonyms $lang:language code(string) 'LanguageGetSpecialPageAliases':DEPRECATED, use $specialPageAliases in a file listed in $wgExtensionMessagesFiles instead. Use to define aliases of special pages names depending of the language $specialPageAliases:associative array of magic words synonyms $lang:language code(string) 'LanguageGetTranslatedLanguageNames':Provide translated language names. & $names:array of language code=> language name $code language of the preferred translations 'LanguageLinks':Manipulate a page 's language links. This is called in various places to allow extensions to define the effective language links for a page. $title:The page 's Title. & $links:Associative array mapping language codes to prefixed links of the form "language:title". & $linkFlags:Associative array mapping prefixed links to arrays of flags. Currently unused, but planned to provide support for marking individual language links in the UI, e.g. for featured articles. 'LinkBegin':Used when generating internal and interwiki links in Linker::link(), before processing starts. Return false to skip default processing and return $ret. See documentation for Linker::link() for details on the expected meanings of parameters. $skin:the Skin object $target:the Title that the link is pointing to & $html:the contents that the< a > tag should have(raw HTML) $result
Definition: hooks.txt:1528
Skin\showEmailUser
showEmailUser( $id)
Definition: Skin.php:1051
SkinTemplate\setupTemplateForOutput
setupTemplateForOutput()
Definition: SkinTemplate.php:198
Title\newFromText
static newFromText( $text, $defaultNamespace=NS_MAIN)
Create a new Title from text, such as what one would find in a link.
Definition: Title.php:189
Skin\makeUrlDetails
static makeUrlDetails( $name, $urlaction='')
these return an array with the 'href' and boolean 'exists'
Definition: Skin.php:1186
ContextSource\getContext
getContext()
Get the RequestContext object.
Definition: ContextSource.php:40
Skin\getSiteNotice
getSiteNotice()
Get the site notice.
Definition: Skin.php:1567
MWDebug\getDebugHTML
static getDebugHTML(IContextSource $context)
Returns the HTML to add to the page for the toolbar.
Definition: Debug.php:392
data
and how to run hooks for an and one after Each event has a preferably in CamelCase For ArticleDelete hook A clump of code and data that should be run when an event happens This can be either a function and a chunk of data
Definition: hooks.txt:6
wfBCP47
wfBCP47( $code)
Get the normalised IETF language tag See unit test for examples.
Definition: GlobalFunctions.php:3929
php
skin txt MediaWiki includes four core it has been set as the default in MediaWiki since the replacing Monobook it had been been the default skin since before being replaced by Vector largely rewritten in while keeping its appearance Several legacy skins were removed in the as the burden of supporting them became too heavy to bear Those in etc for skin dependent CSS etc for skin dependent JavaScript These can also be customised on a per user by etc This feature has led to a wide variety of user styles becoming that gallery is a good place to ending in php
Definition: skin.txt:62
BaseTemplate\makeListItem
makeListItem( $key, $item, $options=array())
Generates a list item for a navigation, portlet, portal, sidebar...
Definition: SkinTemplate.php:1905
$html
null means default in associative array with keys and values unescaped Should be merged with default with a value of false meaning to suppress the attribute in associative array with keys and values unescaped noclasses just before the function returns a value If you return an< a > element with HTML attributes $attribs and contents $html will be returned If you return $ret will be returned and may include noclasses & $html
Definition: hooks.txt:1530
ContextSource\msg
msg()
Get a Message object with context set Parameters are the same as wfMessage()
Definition: ContextSource.php:175
QuickTemplate\msgHtml
msgHtml( $str)
Definition: SkinTemplate.php:1450
SkinTemplate\buildContentNavigationUrls
buildContentNavigationUrls()
a structured array of links usually used for the tabs in a skin
Definition: SkinTemplate.php:884
Skin\getPoweredBy
getPoweredBy()
Gets the powered by MediaWiki icon.
Definition: Skin.php:887
Profiler\instance
static instance()
Singleton.
Definition: Profiler.php:127
SkinTemplate\$stylename
$stylename
Stylesheets set to use.
Definition: SkinTemplate.php:85
SkinTemplate\$template
$template
For QuickTemplate, the name of the subclass which will actually fill the template.
Definition: SkinTemplate.php:91
MediaWiki_I18N\translate
translate( $value)
Definition: SkinTemplate.php:37
wfGetDB
& wfGetDB( $db, $groups=array(), $wiki=false)
Get a Database object.
Definition: GlobalFunctions.php:3659
text
design txt This is a brief overview of the new design More thorough and up to date information is available on the documentation wiki at etc Handles the details of getting and saving to the user table of the and dealing with sessions and cookies OutputPage Encapsulates the entire HTML page that will be sent in response to any server request It is used by calling its functions to add text
Definition: design.txt:12
Skin\lastModified
lastModified()
Get the timestamp of the latest revision, formatted in user language.
Definition: Skin.php:901
UploadBase\isEnabled
static isEnabled()
Returns true if uploads are enabled.
Definition: UploadBase.php:98
MediaWiki_I18N\$_context
$_context
Definition: SkinTemplate.php:31
wfProfileIn
wfProfileIn( $functionname)
Begin profiling of a function.
Definition: Profiler.php:33
Skin\checkTitle
static checkTitle(&$title, $name)
make sure we have some title to operate on
Definition: Skin.php:1218
$n
$n
Definition: RandomTest.php:76
BaseTemplate\makeLink
makeLink( $key, $item, $options=array())
Makes a link, usually used by makeListItem to generate a link for an item in a list used in navigatio...
Definition: SkinTemplate.php:1819
wfSuppressWarnings
wfSuppressWarnings( $end=false)
Reference-counted warning suppression.
Definition: GlobalFunctions.php:2387
Skin\subPageSubtitle
subPageSubtitle()
Definition: Skin.php:730
$personal_urls
do that in ParserLimitReportFormat instead use this to modify the parameters of the image and a DIV can begin in one section and end in another Make sure your code can handle that case gracefully See the EditSectionClearerLink extension for an example zero but section is usually empty its values are the globals values my talk my contributions etc & $personal_urls
Definition: hooks.txt:1956
Skin\makeSpecialUrl
static makeSpecialUrl( $name, $urlaction='', $proto=null)
Make a URL for a Special Page using the given query and protocol.
Definition: Skin.php:1109
Skin\aboutLink
aboutLink()
Gets the link to the wiki's about page.
Definition: Skin.php:1018
NS_FILE
const NS_FILE
Definition: Defines.php:85
$params
$params
Definition: styleTest.css.php:40
Skin\makeSpecialUrlSubpage
static makeSpecialUrlSubpage( $name, $subpage, $urlaction='')
Definition: Skin.php:1124
SpecialPage\getTitleFor
static getTitleFor( $name, $subpage=false, $fragment='')
Get a localised Title object for a specified special page name.
Definition: SpecialPage.php:74
Sanitizer\escapeClass
static escapeClass( $class)
Given a value, escape it so that it can be used as a CSS class and return it.
Definition: Sanitizer.php:1143
ContextSource\canUseWikiPage
canUseWikiPage()
Check whether a WikiPage object can be get with getWikiPage().
Definition: ContextSource.php:99
ContextSource\getRequest
getRequest()
Get the WebRequest object.
Definition: ContextSource.php:77
$wgContLang
this class mediates it Skin Encapsulates a look and feel for the wiki All of the functions that render HTML and make choices about how to render it are here and are called from various other places when and is meant to be subclassed with other skins that may override some of its functions The User object contains a reference to a and so rather than having a global skin object we just rely on the global User and get the skin with $wgUser and also has some character encoding functions and other locale stuff The current user interface language is instantiated as and the content language as $wgContLang
Definition: design.txt:56
SkinTemplate\setupSkinUserCss
setupSkinUserCss(OutputPage $out)
#-
Definition: SkinTemplate.php:106
ContextSource\getUser
getUser()
Get the User object.
Definition: ContextSource.php:132
$link
set to $title object and return false for a match for latest after cache objects are set use the ContentHandler facility to handle CSS and JavaScript for highlighting & $link
Definition: hooks.txt:2149
ContextSource\getTitle
getTitle()
Get the Title object.
Definition: ContextSource.php:87
wfMessageFallback
wfMessageFallback()
This function accepts multiple message keys and returns a message instance for the first message whic...
Definition: GlobalFunctions.php:1422
QuickTemplate\setRef
setRef( $name, &$value)
Definition: SkinTemplate.php:1409
QuickTemplate\getSkin
getSkin()
Get the Skin object related to this object.
Definition: SkinTemplate.php:1488
true
null means default in associative array with keys and values unescaped Should be merged with default with a value of false meaning to suppress the attribute in associative array with keys and values unescaped noclasses just before the function returns a value If you return true
Definition: hooks.txt:1530
Skin\bottomScripts
bottomScripts()
This gets called shortly before the "</body>" tag.
Definition: Skin.php:672
QuickTemplate\setTranslator
setTranslator(&$t)
Definition: SkinTemplate.php:1416
Skin\afterContentHook
afterContentHook()
This runs a hook to allow extensions placing their stuff after content and article metadata (e....
Definition: Skin.php:637
$dbr
$dbr
Definition: testCompression.php:48
ContextSource\getLanguage
getLanguage()
Get the Language object.
Definition: ContextSource.php:154
QuickTemplate\getHTML
getHTML()
Fetch the output of a QuickTemplate and return it.
Definition: SkinTemplate.php:1498
Linker\tooltipAndAccesskeyAttribs
static tooltipAndAccesskeyAttribs( $name)
Returns the attributes for the tooltip and access key.
Definition: Linker.php:2298
NS_SPECIAL
const NS_SPECIAL
Definition: Defines.php:68
UserrightsPage
Special page to allow managing user group membership.
Definition: SpecialUserrights.php:29
SkinTemplate\$skinname
$skinname
#+
Definition: SkinTemplate.php:79
SkinTemplate\getPersonalToolsList
getPersonalToolsList()
Get the HTML for the p-personal list.
Definition: SkinTemplate.php:582
QuickTemplate\msg
msg( $str)
Definition: SkinTemplate.php:1443
MWException
MediaWiki exception.
Definition: MWException.php:26
$out
$out
Definition: UtfNormalGenerate.php:167
Skin\buildSidebar
buildSidebar()
Build an array that represents the sidebar(s), the navigation bar among them.
Definition: Skin.php:1248
QuickTemplate\msgWiki
msgWiki( $str)
An ugly, ugly hack.
Definition: SkinTemplate.php:1458
Skin\privacyLink
privacyLink()
Gets the link to the wiki's privacy policy page.
Definition: Skin.php:1010
SkinTemplate\buildNavUrls
buildNavUrls()
build array of common navigation links
Definition: SkinTemplate.php:1245
wfRestoreWarnings
wfRestoreWarnings()
Restore error level to previous value.
Definition: GlobalFunctions.php:2417
Skin\generateDebugHTML
generateDebugHTML()
Generate debug data HTML for displaying at the bottom of the main content area.
Definition: Skin.php:663
SkinTemplate\tabAction
tabAction( $title, $message, $selected, $query='', $checkEdit=false)
Builds an array with tab definition.
Definition: SkinTemplate.php:785
SkinTemplate\formatLanguageName
formatLanguageName( $name)
Format language name for use in sidebar interlanguage links list.
Definition: SkinTemplate.php:600
Html\element
static element( $element, $attribs=array(), $contents='')
Identical to rawElement(), but HTML-escapes $contents (like Xml::element()).
Definition: Html.php:148
Skin\getCategories
getCategories()
Definition: Skin.php:604
SkinTemplate\buildContentActionUrls
buildContentActionUrls( $content_navigation)
an array of edit links by default used for the tabs
Definition: SkinTemplate.php:1196
ContextSource\getOutput
getOutput()
Get the OutputPage object.
Definition: ContextSource.php:122
ContextSource\getWikiPage
getWikiPage()
Get the WikiPage object.
Definition: ContextSource.php:112
wfProfileOut
wfProfileOut( $functionname='missing')
Stop profiling of a function.
Definition: Profiler.php:46
$wgOut
$wgOut
Definition: Setup.php:562
wfMessage
null means default in associative array with keys and values unescaped Should be merged with default with a value of false meaning to suppress the attribute in associative array with keys and values unescaped noclasses just before the function returns a value If you return an< a > element with HTML attributes $attribs and contents $html will be returned If you return $ret will be returned and may include noclasses after processing after in associative array form externallinks including delete and has completed for all link tables default is conds Array Extra conditions for the No matching items in log is displayed if loglist is empty msgKey Array If you want a nice box with a set this to the key of the message First element is the message additional optional elements are parameters for the key that are processed with wfMessage() -> params() ->parseAsBlock() - offset Set to overwrite offset parameter in $wgRequest set to '' to unset offset - wrap String Wrap the message in html(usually something like "&lt
BaseTemplate\printTrail
printTrail()
Output the basic end-page trail including bottomscripts, reporttime, and debug stuff.
Definition: SkinTemplate.php:2082
wfRunHooks
wfRunHooks( $event, array $args=array(), $deprecatedVersion=null)
Call hook functions defined in $wgHooks.
Definition: GlobalFunctions.php:4010
Skin\isRevisionCurrent
isRevisionCurrent()
Whether the revision displayed is the latest revision of the page.
Definition: Skin.php:320
array
the array() calling protocol came about after MediaWiki 1.4rc1.
List of Api Query prop modules.
global
when a variable name is used in a it is silently declared as a new masking the global
Definition: design.txt:93
Skin\disclaimerLink
disclaimerLink()
Gets the link to the wiki's general disclaimers page.
Definition: Skin.php:1026
MWNamespace\getRestrictionLevels
static getRestrictionLevels( $index, User $user=null)
Determine which restriction levels it makes sense to use in a namespace, optionally filtered by a use...
Definition: Namespace.php:446
ContextSource\setContext
setContext(IContextSource $context)
Set the IContextSource object.
Definition: ContextSource.php:57
OutputPage
This class should be covered by a general architecture document which does not exist as of January 20...
Definition: OutputPage.php:38
list
deferred txt A few of the database updates required by various functions here can be deferred until after the result page is displayed to the user For updating the view updating the linked to tables after a etc PHP does not yet have any way to tell the server to actually return and disconnect while still running these but it might have such a feature in the future We handle these by creating a deferred update object and putting those objects on a global list
Definition: deferred.txt:11
false
processing should stop and the error should be shown to the user * false
Definition: hooks.txt:188
BaseTemplate\msgHtml
msgHtml( $str)
Definition: SkinTemplate.php:1528
$options
null means default in associative array with keys and values unescaped Should be merged with default with a value of false meaning to suppress the attribute in associative array with keys and values unescaped & $options
Definition: hooks.txt:1530
$section
$section
Definition: Utf8Test.php:88
QuickTemplate\execute
execute()
Main function, used by classes that subclass QuickTemplate to show the actual HTML output.
SkinTemplate\prepareQuickTemplate
prepareQuickTemplate()
initialize various variables and generate the template
Definition: SkinTemplate.php:282
wfDebug
wfDebug( $text, $dest='all')
Sends a line to the debug log if enabled or, optionally, to a comment in output.
Definition: GlobalFunctions.php:933
Skin\getRelevantTitle
getRelevantTitle()
Return the "relevant" title.
Definition: Skin.php:344
QuickTemplate\text
text( $str)
Definition: SkinTemplate.php:1429
$title
presenting them properly to the user as errors is done by the caller $title
Definition: hooks.txt:1324
Skin\getPageClasses
getPageClasses( $title)
TODO: document.
Definition: Skin.php:455
BaseTemplate\renderAfterPortlet
renderAfterPortlet( $name)
Definition: SkinTemplate.php:1766
Skin\showIPinHeader
showIPinHeader()
Returns true if the IP should be shown in the header.
Definition: Skin.php:784
$name
Allows to change the fields on the form that will be generated $name
Definition: hooks.txt:336
BaseTemplate\getMsg
getMsg( $name)
Get a Message object with its context set.
Definition: SkinTemplate.php:1520
$value
$value
Definition: styleTest.css.php:45
UploadBase\isAllowed
static isAllowed( $user)
Returns true if the user can use this upload module or else a string identifying the missing permissi...
Definition: UploadBase.php:117
QuickTemplate\__construct
__construct()
Constructor.
Definition: SkinTemplate.php:1376
Skin\printSource
printSource()
Text with the permalink to the source page, usually shown on the footer of a printed page.
Definition: Skin.php:688
SkinTemplate\makeArticleUrlDetails
makeArticleUrlDetails( $name, $urlaction='')
Definition: SkinTemplate.php:841
$wgJsMimeType
$wgJsMimeType
Definition: Setup.php:350
SpecialPageFactory\resolveAlias
static resolveAlias( $alias)
Given a special page name with a possible subpage, return an array where the first element is the spe...
Definition: SpecialPageFactory.php:271
BaseTemplate\makeSearchButton
makeSearchButton( $mode, $attrs=array())
Definition: SkinTemplate.php:1957
Language\fetchLanguageName
static fetchLanguageName( $code, $inLanguage=null, $include='all')
Definition: Language.php:941
SkinTemplate\makeTalkUrlDetails
makeTalkUrlDetails( $name, $urlaction='')
Definition: SkinTemplate.php:828
$user
please add to it if you re going to add events to the MediaWiki code where normally authentication against an external auth plugin would be creating a account $user
Definition: hooks.txt:237
QuickTemplate\haveMsg
haveMsg( $str)
Definition: SkinTemplate.php:1478
wfReportTime
wfReportTime()
Returns a script tag that stores the amount of time it took MediaWiki to handle the request in millis...
Definition: GlobalFunctions.php:1826
Skin\logoText
logoText( $align='')
Definition: Skin.php:928
QuickTemplate
Generic wrapper for template functions, with interface compatible with what we use of PHPTAL 0....
Definition: SkinTemplate.php:1372
$file
if(PHP_SAPI !='cli') $file
Definition: UtfNormalTest2.php:30
SkinTemplate\getLanguages
getLanguages()
Generates array of language links for the current page.
Definition: SkinTemplate.php:135
QuickTemplate\haveData
haveData( $str)
Definition: SkinTemplate.php:1469
Skin\getNewtalks
getNewtalks()
Gets new talk page messages for the current user and returns an appropriate alert message (or an empt...
Definition: Skin.php:1400
$wgArticlePath
$wgArticlePath
Definition: img_auth.php:48
SkinTemplate\getNameSpaceKey
getNameSpaceKey()
Generate strings used for xml 'id' names.
Definition: SkinTemplate.php:1362
DB_SLAVE
const DB_SLAVE
Definition: Defines.php:55
Title
Represents a title within MediaWiki.
Definition: Title.php:35
BaseTemplate\getToolbox
getToolbox()
Create an array of common toolbox items from the data in the quicktemplate stored by SkinTemplate.
Definition: SkinTemplate.php:1543
QuickTemplate\html
html( $str)
Definition: SkinTemplate.php:1436
Skin\escapeSearchLink
escapeSearchLink()
Definition: Skin.php:800
SkinTemplate\$useHeadElement
$useHeadElement
Whether this skin use OutputPage::headElement() to generate the "<head>" tag.
Definition: SkinTemplate.php:97
Title\isSpecialPage
isSpecialPage()
Returns true if this is a special page.
Definition: Title.php:997
Linker\titleAttrib
static titleAttrib( $name, $options=null)
Given the id of an interface element, constructs the appropriate title attribute from the system mess...
Definition: Linker.php:2072
as
This document is intended to provide useful advice for parties seeking to redistribute MediaWiki to end users It s targeted particularly at maintainers for Linux since it s been observed that distribution packages of MediaWiki often break We ve consistently had to recommend that users seeking support use official tarballs instead of their distribution s and this often solves whatever problem the user is having It would be nice if this could such as
Definition: distributors.txt:9
Skin\getCopyright
getCopyright( $type='detect')
Definition: Skin.php:808
SkinTemplate\outputPage
outputPage(OutputPage $out=null)
initialize various variables and generate the template
Definition: SkinTemplate.php:244
SpecialPage\setContext
setContext( $context)
Sets the context this SpecialPage is executed in.
Definition: SpecialPage.php:498
Skin\getRelevantUser
getRelevantUser()
Return the "relevant" user.
Definition: Skin.php:368
Skin\getUndeleteLink
getUndeleteLink()
Definition: Skin.php:702
Skin\makeKnownUrlDetails
static makeKnownUrlDetails( $name, $urlaction='')
Make URL details where the article exists (or at least it's convenient to think so)
Definition: Skin.php:1202
WatchAction\getWatchToken
static getWatchToken(Title $title, User $user, $action='watch')
Get token to watch (or unwatch) a page for a user.
Definition: WatchAction.php:184
WikiFilePage
Special handling for file pages.
Definition: WikiFilePage.php:28
MediaWiki_I18N
Wrapper object for MediaWiki's localization functions, to be passed to the template engine.
Definition: SkinTemplate.php:30
NS_MEDIAWIKI
const NS_MEDIAWIKI
Definition: Defines.php:87
$t
$t
Definition: testCompression.php:65
Skin\getCopyrightIcon
getCopyrightIcon()
Definition: Skin.php:857
BaseTemplate\getSidebar
getSidebar( $options=array())
Definition: SkinTemplate.php:1635
Skin\getSkinName
getSkinName()
Definition: Skin.php:208
Skin
The main skin class which provides methods and properties for all other skins.
Definition: Skin.php:35
Html\rawElement
static rawElement( $element, $attribs=array(), $contents='')
Returns an HTML element in a string.
Definition: Html.php:124
$query
return true to allow those checks to and false if checking is done use this to change the tables headers temp or archived zone change it to an object instance and return false override the list derivative used the name of the old file when set the default code will be skipped add a value to it if you want to add a cookie that have to vary cache options can modify $query
Definition: hooks.txt:1105
MWNamespace\getSubject
static getSubject( $index)
Get the subject namespace index for a given namespace Special namespaces (NS_MEDIA,...
Definition: Namespace.php:132
BaseTemplate\getFooterIcons
getFooterIcons( $option=null)
Returns an array of footer icons filtered down by options relevant to how the skin wishes to display ...
Definition: SkinTemplate.php:2048
Skin\initPage
initPage(OutputPage $out)
Definition: Skin.php:215
$res
$res
Definition: database.txt:21
Skin\getRevisionId
getRevisionId()
Get the current revision ID.
Definition: Skin.php:311
BaseTemplate
New base template for a skin's template extended from QuickTemplate this class features helper method...
Definition: SkinTemplate.php:1512
SkinTemplate
Template-filler skin base class Formerly generic PHPTal (http://phptal.sourceforge....
Definition: SkinTemplate.php:70
Action\factory
static factory( $action, Page $page, IContextSource $context=null)
Get an appropriate Action subclass for the given action.
Definition: Action.php:88
$special
namespace and then decline to actually register it RecentChangesLinked and Watchlist $special
Definition: hooks.txt:815
SkinTemplate\printOrError
printOrError( $str)
Output the string, or print error message if it's an error object of the appropriate type.
Definition: SkinTemplate.php:612
SkinTemplate\setupTemplate
setupTemplate( $classname, $repository=false, $cache_dir=false)
Create the template engine object; we feed it a bunch of data and eventually it spits out some HTML.
Definition: SkinTemplate.php:125
wfArrayToCgi
wfArrayToCgi( $array1, $array2=null, $prefix='')
This function takes two arrays as input, and returns a CGI-style string, e.g.
Definition: GlobalFunctions.php:367
SkinTemplate\buildPersonalUrls
buildPersonalUrls()
build array of urls for personal toolbar
Definition: SkinTemplate.php:634