MediaWiki  1.34.0
SkinTemplate.php
Go to the documentation of this file.
1 <?php
23 
38 class SkinTemplate extends Skin {
43  public $skinname = 'monobook';
44 
49  public $template = QuickTemplate::class;
50 
51  public $thispage;
52  public $titletxt;
53  public $userpage;
54  public $thisquery;
55  public $loggedin;
56  public $username;
58 
68  function setupTemplate( $classname ) {
69  return new $classname( $this->getConfig() );
70  }
71 
77  public function getLanguages() {
80  return [];
81  }
82 
83  $userLang = $this->getLanguage();
84  $languageLinks = [];
85 
86  foreach ( $this->getOutput()->getLanguageLinks() as $languageLinkText ) {
87  $class = 'interlanguage-link interwiki-' . explode( ':', $languageLinkText, 2 )[0];
88 
89  $languageLinkTitle = Title::newFromText( $languageLinkText );
90  if ( $languageLinkTitle ) {
91  $ilInterwikiCode = $languageLinkTitle->getInterwiki();
92  $ilLangName = Language::fetchLanguageName( $ilInterwikiCode );
93 
94  if ( strval( $ilLangName ) === '' ) {
95  $ilDisplayTextMsg = wfMessage( "interlanguage-link-$ilInterwikiCode" );
96  if ( !$ilDisplayTextMsg->isDisabled() ) {
97  // Use custom MW message for the display text
98  $ilLangName = $ilDisplayTextMsg->text();
99  } else {
100  // Last resort: fallback to the language link target
101  $ilLangName = $languageLinkText;
102  }
103  } else {
104  // Use the language autonym as display text
105  $ilLangName = $this->formatLanguageName( $ilLangName );
106  }
107 
108  // CLDR extension or similar is required to localize the language name;
109  // otherwise we'll end up with the autonym again.
110  $ilLangLocalName = Language::fetchLanguageName(
111  $ilInterwikiCode,
112  $userLang->getCode()
113  );
114 
115  $languageLinkTitleText = $languageLinkTitle->getText();
116  if ( $ilLangLocalName === '' ) {
117  $ilFriendlySiteName = wfMessage( "interlanguage-link-sitename-$ilInterwikiCode" );
118  if ( !$ilFriendlySiteName->isDisabled() ) {
119  if ( $languageLinkTitleText === '' ) {
120  $ilTitle = wfMessage(
121  'interlanguage-link-title-nonlangonly',
122  $ilFriendlySiteName->text()
123  )->text();
124  } else {
125  $ilTitle = wfMessage(
126  'interlanguage-link-title-nonlang',
127  $languageLinkTitleText,
128  $ilFriendlySiteName->text()
129  )->text();
130  }
131  } else {
132  // we have nothing friendly to put in the title, so fall back to
133  // displaying the interlanguage link itself in the title text
134  // (similar to what is done in page content)
135  $ilTitle = $languageLinkTitle->getInterwiki() .
136  ":$languageLinkTitleText";
137  }
138  } elseif ( $languageLinkTitleText === '' ) {
139  $ilTitle = wfMessage(
140  'interlanguage-link-title-langonly',
141  $ilLangLocalName
142  )->text();
143  } else {
144  $ilTitle = wfMessage(
145  'interlanguage-link-title',
146  $languageLinkTitleText,
147  $ilLangLocalName
148  )->text();
149  }
150 
151  $ilInterwikiCodeBCP47 = LanguageCode::bcp47( $ilInterwikiCode );
152  $languageLink = [
153  'href' => $languageLinkTitle->getFullURL(),
154  'text' => $ilLangName,
155  'title' => $ilTitle,
156  'class' => $class,
157  'link-class' => 'interlanguage-link-target',
158  'lang' => $ilInterwikiCodeBCP47,
159  'hreflang' => $ilInterwikiCodeBCP47,
160  ];
161  Hooks::run(
162  'SkinTemplateGetLanguageLink',
163  [ &$languageLink, $languageLinkTitle, $this->getTitle(), $this->getOutput() ]
164  );
165  $languageLinks[] = $languageLink;
166  }
167  }
168 
169  return $languageLinks;
170  }
171 
175  protected function setupTemplateForOutput() {
176  $request = $this->getRequest();
177  $user = $this->getUser();
178  $title = $this->getTitle();
179 
180  $tpl = $this->setupTemplate( $this->template );
181 
182  $this->thispage = $title->getPrefixedDBkey();
183  $this->titletxt = $title->getPrefixedText();
184  $this->userpage = $user->getUserPage()->getPrefixedText();
185  $query = [];
186  if ( !$request->wasPosted() ) {
187  $query = $request->getValues();
188  unset( $query['title'] );
189  unset( $query['returnto'] );
190  unset( $query['returntoquery'] );
191  }
192  $this->thisquery = wfArrayToCgi( $query );
193  $this->loggedin = $user->isLoggedIn();
194  $this->username = $user->getName();
195 
196  if ( $this->loggedin ) {
197  $this->userpageUrlDetails = self::makeUrlDetails( $this->userpage );
198  } else {
199  # This won't be used in the standard skins, but we define it to preserve the interface
200  # To save time, we check for existence
201  $this->userpageUrlDetails = self::makeKnownUrlDetails( $this->userpage );
202  }
203 
204  return $tpl;
205  }
206 
210  function outputPage() {
211  Profiler::instance()->setAllowOutput();
212  $out = $this->getOutput();
213 
214  $this->initPage( $out );
215  $tpl = $this->prepareQuickTemplate();
216  // execute template
217  $res = $tpl->execute();
218 
219  // result may be an error
220  $this->printOrError( $res );
221  }
222 
230  protected function wrapHTML( $title, $html ) {
231  # An ID that includes the actual body text; without categories, contentSub, ...
232  $realBodyAttribs = [ 'id' => 'mw-content-text' ];
233 
234  # Add a mw-content-ltr/rtl class to be able to style based on text
235  # direction when the content is different from the UI language (only
236  # when viewing)
237  # Most information on special pages and file pages is in user language,
238  # rather than content language, so those will not get this
239  if ( Action::getActionName( $this ) === 'view' &&
240  ( !$title->inNamespaces( NS_SPECIAL, NS_FILE ) || $title->isRedirect() ) ) {
241  $pageLang = $title->getPageViewLanguage();
242  $realBodyAttribs['lang'] = $pageLang->getHtmlCode();
243  $realBodyAttribs['dir'] = $pageLang->getDir();
244  $realBodyAttribs['class'] = 'mw-content-' . $pageLang->getDir();
245  }
246 
247  return Html::rawElement( 'div', $realBodyAttribs, $html );
248  }
249 
256  protected function prepareQuickTemplate() {
261 
262  $title = $this->getTitle();
263  $request = $this->getRequest();
264  $out = $this->getOutput();
265  $tpl = $this->setupTemplateForOutput();
266 
267  $tpl->set( 'title', $out->getPageTitle() );
268  $tpl->set( 'pagetitle', $out->getHTMLTitle() );
269  $tpl->set( 'displaytitle', $out->mPageLinkTitle );
270 
271  $tpl->set( 'thispage', $this->thispage );
272  $tpl->set( 'titleprefixeddbkey', $this->thispage );
273  $tpl->set( 'titletext', $title->getText() );
274  $tpl->set( 'articleid', $title->getArticleID() );
275 
276  $tpl->set( 'isarticle', $out->isArticle() );
277 
278  $subpagestr = $this->subPageSubtitle();
279  if ( $subpagestr !== '' ) {
280  $subpagestr = '<span class="subpages">' . $subpagestr . '</span>';
281  }
282  $tpl->set( 'subtitle', $subpagestr . $out->getSubtitle() );
283 
284  $undelete = $this->getUndeleteLink();
285  if ( $undelete === '' ) {
286  $tpl->set( 'undelete', '' );
287  } else {
288  $tpl->set( 'undelete', '<span class="subpages">' . $undelete . '</span>' );
289  }
290 
291  $tpl->set( 'catlinks', $this->getCategories() );
292  if ( $out->isSyndicated() ) {
293  $feeds = [];
294  foreach ( $out->getSyndicationLinks() as $format => $link ) {
295  $feeds[$format] = [
296  // Messages: feed-atom, feed-rss
297  'text' => $this->msg( "feed-$format" )->text(),
298  'href' => $link
299  ];
300  }
301  $tpl->set( 'feeds', $feeds );
302  } else {
303  $tpl->set( 'feeds', false );
304  }
305 
306  $tpl->set( 'mimetype', $wgMimeType );
307  $tpl->set( 'charset', 'UTF-8' );
308  $tpl->set( 'wgScript', $wgScript );
309  $tpl->set( 'skinname', $this->skinname );
310  $tpl->set( 'skinclass', static::class );
311  $tpl->set( 'skin', $this );
312  $tpl->set( 'stylename', $this->stylename );
313  $tpl->set( 'printable', $out->isPrintable() );
314  $tpl->set( 'handheld', $request->getBool( 'handheld' ) );
315  $tpl->set( 'loggedin', $this->loggedin );
316  $tpl->set( 'notspecialpage', !$title->isSpecialPage() );
317  $tpl->set( 'searchaction', $this->getSearchLink() );
318  $tpl->set( 'searchtitle', SpecialPage::getTitleFor( 'Search' )->getPrefixedDBkey() );
319  $tpl->set( 'search', trim( $request->getVal( 'search' ) ) );
320  $tpl->set( 'stylepath', $wgStylePath );
321  $tpl->set( 'articlepath', $wgArticlePath );
322  $tpl->set( 'scriptpath', $wgScriptPath );
323  $tpl->set( 'serverurl', $wgServer );
324  $tpl->set( 'logopath', $wgLogo );
325  $tpl->set( 'sitename', $wgSitename );
326 
327  $userLang = $this->getLanguage();
328  $userLangCode = $userLang->getHtmlCode();
329  $userLangDir = $userLang->getDir();
330 
331  $tpl->set( 'lang', $userLangCode );
332  $tpl->set( 'dir', $userLangDir );
333  $tpl->set( 'rtl', $userLang->isRTL() );
334 
335  $tpl->set( 'capitalizeallnouns', $userLang->capitalizeAllNouns() ? ' capitalize-all-nouns' : '' );
336  $tpl->set( 'showjumplinks', true ); // showjumplinks preference has been removed
337  $tpl->set( 'username', $this->loggedin ? $this->username : null );
338  $tpl->set( 'userpage', $this->userpage );
339  $tpl->set( 'userpageurl', $this->userpageUrlDetails['href'] );
340  $tpl->set( 'userlang', $userLangCode );
341 
342  // Users can have their language set differently than the
343  // content of the wiki. For these users, tell the web browser
344  // that interface elements are in a different language.
345  $tpl->set( 'userlangattributes', '' );
346  $tpl->set( 'specialpageattributes', '' ); # obsolete
347  // Used by VectorBeta to insert HTML before content but after the
348  // heading for the page title. Defaults to empty string.
349  $tpl->set( 'prebodyhtml', '' );
350 
351  $contLang = MediaWikiServices::getInstance()->getContentLanguage();
352  if (
353  $userLangCode !== $contLang->getHtmlCode() ||
354  $userLangDir !== $contLang->getDir()
355  ) {
356  $escUserlang = htmlspecialchars( $userLangCode );
357  $escUserdir = htmlspecialchars( $userLangDir );
358  // Attributes must be in double quotes because htmlspecialchars() doesn't
359  // escape single quotes
360  $attrs = " lang=\"$escUserlang\" dir=\"$escUserdir\"";
361  $tpl->set( 'userlangattributes', $attrs );
362  }
363 
364  $tpl->set( 'newtalk', $this->getNewtalks() );
365  $tpl->set( 'logo', $this->logoText() );
366 
367  $tpl->set( 'copyright', false );
368  // No longer used
369  $tpl->set( 'viewcount', false );
370  $tpl->set( 'lastmod', false );
371  $tpl->set( 'credits', false );
372  $tpl->set( 'numberofwatchingusers', false );
373  if ( $title->exists() ) {
374  if ( $out->isArticle() && $out->isRevisionCurrent() ) {
375  if ( $wgMaxCredits != 0 ) {
377  $action = Action::factory(
378  'credits', $this->getWikiPage(), $this->getContext() );
379  '@phan-var CreditsAction $action';
380  $tpl->set( 'credits',
381  $action->getCredits( $wgMaxCredits, $wgShowCreditsIfMax ) );
382  } else {
383  $tpl->set( 'lastmod', $this->lastModified() );
384  }
385  }
386  if ( $out->showsCopyright() ) {
387  $tpl->set( 'copyright', $this->getCopyright() );
388  }
389  }
390 
391  $tpl->set( 'copyrightico', $this->getCopyrightIcon() );
392  $tpl->set( 'poweredbyico', $this->getPoweredBy() );
393  $tpl->set( 'disclaimer', $this->disclaimerLink() );
394  $tpl->set( 'privacy', $this->privacyLink() );
395  $tpl->set( 'about', $this->aboutLink() );
396 
397  $tpl->set( 'footerlinks', [
398  'info' => [
399  'lastmod',
400  'numberofwatchingusers',
401  'credits',
402  'copyright',
403  ],
404  'places' => [
405  'privacy',
406  'about',
407  'disclaimer',
408  ],
409  ] );
410 
411  global $wgFooterIcons;
412  $tpl->set( 'footericons', $wgFooterIcons );
413  foreach ( $tpl->data['footericons'] as $footerIconsKey => &$footerIconsBlock ) {
414  if ( count( $footerIconsBlock ) > 0 ) {
415  foreach ( $footerIconsBlock as &$footerIcon ) {
416  if ( isset( $footerIcon['src'] ) ) {
417  if ( !isset( $footerIcon['width'] ) ) {
418  $footerIcon['width'] = 88;
419  }
420  if ( !isset( $footerIcon['height'] ) ) {
421  $footerIcon['height'] = 31;
422  }
423  }
424  }
425  } else {
426  unset( $tpl->data['footericons'][$footerIconsKey] );
427  }
428  }
429 
430  $tpl->set( 'indicators', $out->getIndicators() );
431 
432  $tpl->set( 'sitenotice', $this->getSiteNotice() );
433  $tpl->set( 'printfooter', $this->printSource() );
434  // Wrap the bodyText with #mw-content-text element
435  $out->mBodytext = $this->wrapHTML( $title, $out->mBodytext );
436  $tpl->set( 'bodytext', $out->mBodytext );
437 
438  $language_urls = $this->getLanguages();
439  if ( count( $language_urls ) ) {
440  $tpl->set( 'language_urls', $language_urls );
441  } else {
442  $tpl->set( 'language_urls', false );
443  }
444 
445  # Personal toolbar
446  $tpl->set( 'personal_urls', $this->buildPersonalUrls() );
447  $content_navigation = $this->buildContentNavigationUrls();
448  $content_actions = $this->buildContentActionUrls( $content_navigation );
449  $tpl->set( 'content_navigation', $content_navigation );
450  $tpl->set( 'content_actions', $content_actions );
451 
452  $tpl->set( 'sidebar', $this->buildSidebar() );
453  $tpl->set( 'nav_urls', $this->buildNavUrls() );
454 
455  // Do this last in case hooks above add bottom scripts
456  $tpl->set( 'bottomscripts', $this->bottomScripts() );
457 
458  // Set the head scripts near the end, in case the above actions resulted in added scripts
459  $tpl->set( 'headelement', $out->headElement( $this ) );
460 
461  $tpl->set( 'debug', '' );
462  $tpl->set( 'debughtml', $this->generateDebugHTML() );
463  $tpl->set( 'reporttime', wfReportTime( $out->getCSPNonce() ) );
464 
465  // Avoid PHP 7.1 warning of passing $this by reference
466  $skinTemplate = $this;
467  // original version by hansm
468  if ( !Hooks::run( 'SkinTemplateOutputPageBeforeExec', [ &$skinTemplate, &$tpl ] ) ) {
469  wfDebug( __METHOD__ . ": Hook SkinTemplateOutputPageBeforeExec broke outputPage execution!\n" );
470  }
471 
472  // Set the bodytext to another key so that skins can just output it on its own
473  // and output printfooter and debughtml separately
474  $tpl->set( 'bodycontent', $tpl->data['bodytext'] );
475 
476  // Append printfooter and debughtml onto bodytext so that skins that
477  // were already using bodytext before they were split out don't suddenly
478  // start not outputting information.
479  $tpl->data['bodytext'] .= Html::rawElement(
480  'div',
481  [ 'class' => 'printfooter' ],
482  "\n{$tpl->data['printfooter']}"
483  ) . "\n";
484  $tpl->data['bodytext'] .= $tpl->data['debughtml'];
485 
486  // allow extensions adding stuff after the page content.
487  // See Skin::afterContentHook() for further documentation.
488  $tpl->set( 'dataAfterContent', $this->afterContentHook() );
489 
490  return $tpl;
491  }
492 
497  public function getPersonalToolsList() {
498  return $this->makePersonalToolsList();
499  }
500 
510  public function makePersonalToolsList( $personalTools = null, $options = [] ) {
511  $tpl = $this->setupTemplateForOutput();
512  $tpl->set( 'personal_urls', $this->buildPersonalUrls() );
513  $html = '';
514 
515  if ( $personalTools === null ) {
516  $personalTools = ( $tpl instanceof BaseTemplate )
517  ? $tpl->getPersonalTools()
518  : [];
519  }
520 
521  foreach ( $personalTools as $key => $item ) {
522  $html .= $tpl->makeListItem( $key, $item, $options );
523  }
524 
525  return $html;
526  }
527 
535  public function getStructuredPersonalTools() {
536  $tpl = $this->setupTemplateForOutput();
537  $tpl->set( 'personal_urls', $this->buildPersonalUrls() );
538 
539  return ( $tpl instanceof BaseTemplate ) ? $tpl->getPersonalTools() : [];
540  }
541 
550  function formatLanguageName( $name ) {
551  return $this->getLanguage()->ucfirst( $name );
552  }
553 
562  function printOrError( $str ) {
563  echo $str;
564  }
565 
575  function useCombinedLoginLink() {
578  }
579 
584  protected function buildPersonalUrls() {
585  $title = $this->getTitle();
586  $request = $this->getRequest();
587  $pageurl = $title->getLocalURL();
588  $authManager = AuthManager::singleton();
589  $permissionManager = MediaWikiServices::getInstance()->getPermissionManager();
590 
591  /* set up the default links for the personal toolbar */
592  $personal_urls = [];
593 
594  # Due to T34276, if a user does not have read permissions,
595  # $this->getTitle() will just give Special:Badtitle, which is
596  # not especially useful as a returnto parameter. Use the title
597  # from the request instead, if there was one.
598  if ( $permissionManager->userHasRight( $this->getUser(), 'read' ) ) {
599  $page = $this->getTitle();
600  } else {
601  $page = Title::newFromText( $request->getVal( 'title', '' ) );
602  }
603  $page = $request->getVal( 'returnto', $page );
604  $returnto = [];
605  if ( strval( $page ) !== '' ) {
606  $returnto['returnto'] = $page;
607  $query = $request->getVal( 'returntoquery', $this->thisquery );
608  $paramsArray = wfCgiToArray( $query );
609  $query = wfArrayToCgi( $paramsArray );
610  if ( $query != '' ) {
611  $returnto['returntoquery'] = $query;
612  }
613  }
614 
615  if ( $this->loggedin ) {
616  $personal_urls['userpage'] = [
617  'text' => $this->username,
618  'href' => &$this->userpageUrlDetails['href'],
619  'class' => $this->userpageUrlDetails['exists'] ? false : 'new',
620  'exists' => $this->userpageUrlDetails['exists'],
621  'active' => ( $this->userpageUrlDetails['href'] == $pageurl ),
622  'dir' => 'auto'
623  ];
624  $usertalkUrlDetails = $this->makeTalkUrlDetails( $this->userpage );
625  $personal_urls['mytalk'] = [
626  'text' => $this->msg( 'mytalk' )->text(),
627  'href' => &$usertalkUrlDetails['href'],
628  'class' => $usertalkUrlDetails['exists'] ? false : 'new',
629  'exists' => $usertalkUrlDetails['exists'],
630  'active' => ( $usertalkUrlDetails['href'] == $pageurl )
631  ];
632  $href = self::makeSpecialUrl( 'Preferences' );
633  $personal_urls['preferences'] = [
634  'text' => $this->msg( 'mypreferences' )->text(),
635  'href' => $href,
636  'active' => ( $href == $pageurl )
637  ];
638 
639  if ( $permissionManager->userHasRight( $this->getUser(), 'viewmywatchlist' ) ) {
640  $href = self::makeSpecialUrl( 'Watchlist' );
641  $personal_urls['watchlist'] = [
642  'text' => $this->msg( 'mywatchlist' )->text(),
643  'href' => $href,
644  'active' => ( $href == $pageurl )
645  ];
646  }
647 
648  # We need to do an explicit check for Special:Contributions, as we
649  # have to match both the title, and the target, which could come
650  # from request values (Special:Contributions?target=Jimbo_Wales)
651  # or be specified in "sub page" form
652  # (Special:Contributions/Jimbo_Wales). The plot
653  # thickens, because the Title object is altered for special pages,
654  # so it doesn't contain the original alias-with-subpage.
655  $origTitle = Title::newFromText( $request->getText( 'title' ) );
656  if ( $origTitle instanceof Title && $origTitle->isSpecialPage() ) {
657  list( $spName, $spPar ) =
658  MediaWikiServices::getInstance()->getSpecialPageFactory()->
659  resolveAlias( $origTitle->getText() );
660  $active = $spName == 'Contributions'
661  && ( ( $spPar && $spPar == $this->username )
662  || $request->getText( 'target' ) == $this->username );
663  } else {
664  $active = false;
665  }
666 
667  $href = self::makeSpecialUrlSubpage( 'Contributions', $this->username );
668  $personal_urls['mycontris'] = [
669  'text' => $this->msg( 'mycontris' )->text(),
670  'href' => $href,
671  'active' => $active
672  ];
673 
674  // if we can't set the user, we can't unset it either
675  if ( $request->getSession()->canSetUser() ) {
676  $personal_urls['logout'] = [
677  'text' => $this->msg( 'pt-userlogout' )->text(),
678  'href' => self::makeSpecialUrl( 'Userlogout',
679  // Note: userlogout link must always contain an & character, otherwise we might not be able
680  // to detect a buggy precaching proxy (T19790)
681  ( $title->isSpecial( 'Preferences' ) ? [] : $returnto ) ),
682  'active' => false
683  ];
684  }
685  } else {
686  $useCombinedLoginLink = $this->useCombinedLoginLink();
687  if ( !$authManager->canCreateAccounts() || !$authManager->canAuthenticateNow() ) {
688  // don't show combined login/signup link if one of those is actually not available
689  $useCombinedLoginLink = false;
690  }
691 
692  $loginlink = $permissionManager->userHasRight( $this->getUser(), 'createaccount' )
693  && $useCombinedLoginLink ? 'nav-login-createaccount' : 'pt-login';
694 
695  $login_url = [
696  'text' => $this->msg( $loginlink )->text(),
697  'href' => self::makeSpecialUrl( 'Userlogin', $returnto ),
698  'active' => $title->isSpecial( 'Userlogin' )
699  || $title->isSpecial( 'CreateAccount' ) && $useCombinedLoginLink,
700  ];
701  $createaccount_url = [
702  'text' => $this->msg( 'pt-createaccount' )->text(),
703  'href' => self::makeSpecialUrl( 'CreateAccount', $returnto ),
704  'active' => $title->isSpecial( 'CreateAccount' ),
705  ];
706 
707  // No need to show Talk and Contributions to anons if they can't contribute!
708  if ( $permissionManager->groupHasPermission( '*', 'edit' ) ) {
709  // Because of caching, we can't link directly to the IP talk and
710  // contributions pages. Instead we use the special page shortcuts
711  // (which work correctly regardless of caching). This means we can't
712  // determine whether these links are active or not, but since major
713  // skins (MonoBook, Vector) don't use this information, it's not a
714  // huge loss.
715  $personal_urls['anontalk'] = [
716  'text' => $this->msg( 'anontalk' )->text(),
717  'href' => self::makeSpecialUrlSubpage( 'Mytalk', false ),
718  'active' => false
719  ];
720  $personal_urls['anoncontribs'] = [
721  'text' => $this->msg( 'anoncontribs' )->text(),
722  'href' => self::makeSpecialUrlSubpage( 'Mycontributions', false ),
723  'active' => false
724  ];
725  }
726 
727  if (
728  $authManager->canCreateAccounts()
729  && $permissionManager->userHasRight( $this->getUser(), 'createaccount' )
730  && !$useCombinedLoginLink
731  ) {
732  $personal_urls['createaccount'] = $createaccount_url;
733  }
734 
735  if ( $authManager->canAuthenticateNow() ) {
736  $key = $permissionManager->groupHasPermission( '*', 'read' )
737  ? 'login'
738  : 'login-private';
739  $personal_urls[$key] = $login_url;
740  }
741  }
742 
743  Hooks::runWithoutAbort( 'PersonalUrls', [ &$personal_urls, &$title, $this ] );
744  return $personal_urls;
745  }
746 
758  function tabAction( $title, $message, $selected, $query = '', $checkEdit = false ) {
759  $classes = [];
760  if ( $selected ) {
761  $classes[] = 'selected';
762  }
763  $exists = true;
764  if ( $checkEdit && !$title->isKnown() ) {
765  $classes[] = 'new';
766  $exists = false;
767  if ( $query !== '' ) {
768  $query = 'action=edit&redlink=1&' . $query;
769  } else {
770  $query = 'action=edit&redlink=1';
771  }
772  }
773 
774  $services = MediaWikiServices::getInstance();
775  $linkClass = $services->getLinkRenderer()->getLinkClasses( $title );
776 
777  // wfMessageFallback will nicely accept $message as an array of fallbacks
778  // or just a single key
779  $msg = wfMessageFallback( $message )->setContext( $this->getContext() );
780  if ( is_array( $message ) ) {
781  // for hook compatibility just keep the last message name
782  $message = end( $message );
783  }
784  if ( $msg->exists() ) {
785  $text = $msg->text();
786  } else {
787  $text = $services->getContentLanguage()->getConverter()->
788  convertNamespace( $services->getNamespaceInfo()->
789  getSubject( $title->getNamespace() ) );
790  }
791 
792  // Avoid PHP 7.1 warning of passing $this by reference
793  $skinTemplate = $this;
794  $result = [];
795  if ( !Hooks::run( 'SkinTemplateTabAction', [ &$skinTemplate,
796  $title, $message, $selected, $checkEdit,
797  &$classes, &$query, &$text, &$result ] ) ) {
798  return $result;
799  }
800 
801  $result = [
802  'class' => implode( ' ', $classes ),
803  'text' => $text,
804  'href' => $title->getLocalURL( $query ),
805  'exists' => $exists,
806  'primary' => true ];
807  if ( $linkClass !== '' ) {
808  $result['link-class'] = $linkClass;
809  }
810 
811  return $result;
812  }
813 
814  function makeTalkUrlDetails( $name, $urlaction = '' ) {
815  $title = Title::newFromText( $name );
816  if ( !is_object( $title ) ) {
817  throw new MWException( __METHOD__ . " given invalid pagename $name" );
818  }
819  $title = $title->getTalkPage();
820  self::checkTitle( $title, $name );
821  return [
822  'href' => $title->getLocalURL( $urlaction ),
823  'exists' => $title->isKnown(),
824  ];
825  }
826 
833  function makeArticleUrlDetails( $name, $urlaction = '' ) {
834  $title = Title::newFromText( $name );
835  $title = $title->getSubjectPage();
836  self::checkTitle( $title, $name );
837  return [
838  'href' => $title->getLocalURL( $urlaction ),
839  'exists' => $title->exists(),
840  ];
841  }
842 
877  protected function buildContentNavigationUrls() {
879 
880  // Display tabs for the relevant title rather than always the title itself
881  $title = $this->getRelevantTitle();
882  $onPage = $title->equals( $this->getTitle() );
883 
884  $out = $this->getOutput();
885  $request = $this->getRequest();
886  $user = $this->getUser();
887  $permissionManager = MediaWikiServices::getInstance()->getPermissionManager();
888 
889  $content_navigation = [
890  'namespaces' => [],
891  'views' => [],
892  'actions' => [],
893  'variants' => []
894  ];
895 
896  // parameters
897  $action = $request->getVal( 'action', 'view' );
898 
899  $userCanRead = $permissionManager->quickUserCan( 'read', $user, $title );
900 
901  // Avoid PHP 7.1 warning of passing $this by reference
902  $skinTemplate = $this;
903  $preventActiveTabs = false;
904  Hooks::run( 'SkinTemplatePreventOtherActiveTabs', [ &$skinTemplate, &$preventActiveTabs ] );
905 
906  // Checks if page is some kind of content
907  if ( $title->canExist() ) {
908  // Gets page objects for the related namespaces
909  $subjectPage = $title->getSubjectPage();
910  $talkPage = $title->getTalkPage();
911 
912  // Determines if this is a talk page
913  $isTalk = $title->isTalkPage();
914 
915  // Generates XML IDs from namespace names
916  $subjectId = $title->getNamespaceKey( '' );
917 
918  if ( $subjectId == 'main' ) {
919  $talkId = 'talk';
920  } else {
921  $talkId = "{$subjectId}_talk";
922  }
923 
924  $skname = $this->skinname;
925 
926  // Adds namespace links
927  $subjectMsg = [ "nstab-$subjectId" ];
928  if ( $subjectPage->isMainPage() ) {
929  array_unshift( $subjectMsg, 'mainpage-nstab' );
930  }
931  $content_navigation['namespaces'][$subjectId] = $this->tabAction(
932  $subjectPage, $subjectMsg, !$isTalk && !$preventActiveTabs, '', $userCanRead
933  );
934  $content_navigation['namespaces'][$subjectId]['context'] = 'subject';
935  $content_navigation['namespaces'][$talkId] = $this->tabAction(
936  $talkPage, [ "nstab-$talkId", 'talk' ], $isTalk && !$preventActiveTabs, '', $userCanRead
937  );
938  $content_navigation['namespaces'][$talkId]['context'] = 'talk';
939 
940  if ( $userCanRead ) {
941  // Adds "view" view link
942  if ( $title->isKnown() ) {
943  $content_navigation['views']['view'] = $this->tabAction(
944  $isTalk ? $talkPage : $subjectPage,
945  [ "$skname-view-view", 'view' ],
946  ( $onPage && ( $action == 'view' || $action == 'purge' ) ), '', true
947  );
948  // signal to hide this from simple content_actions
949  $content_navigation['views']['view']['redundant'] = true;
950  }
951 
952  $page = $this->canUseWikiPage() ? $this->getWikiPage() : false;
953  $isRemoteContent = $page && !$page->isLocal();
954 
955  // If it is a non-local file, show a link to the file in its own repository
956  // @todo abstract this for remote content that isn't a file
957  if ( $isRemoteContent ) {
958  $content_navigation['views']['view-foreign'] = [
959  'class' => '',
960  'text' => wfMessageFallback( "$skname-view-foreign", 'view-foreign' )->
961  setContext( $this->getContext() )->
962  params( $page->getWikiDisplayName() )->text(),
963  'href' => $page->getSourceURL(),
964  'primary' => false,
965  ];
966  }
967 
968  // Checks if user can edit the current page if it exists or create it otherwise
969  if ( $permissionManager->quickUserCan( 'edit', $user, $title ) &&
970  ( $title->exists() ||
971  $permissionManager->quickUserCan( 'create', $user, $title ) )
972  ) {
973  // Builds CSS class for talk page links
974  $isTalkClass = $isTalk ? ' istalk' : '';
975  // Whether the user is editing the page
976  $isEditing = $onPage && ( $action == 'edit' || $action == 'submit' );
977  // Whether to show the "Add a new section" tab
978  // Checks if this is a current rev of talk page and is not forced to be hidden
979  $showNewSection = !$out->forceHideNewSectionLink()
980  && ( ( $isTalk && $out->isRevisionCurrent() ) || $out->showNewSectionLink() );
981  $section = $request->getVal( 'section' );
982 
983  if ( $title->exists()
984  || ( $title->getNamespace() == NS_MEDIAWIKI
985  && $title->getDefaultMessageText() !== false
986  )
987  ) {
988  $msgKey = $isRemoteContent ? 'edit-local' : 'edit';
989  } else {
990  $msgKey = $isRemoteContent ? 'create-local' : 'create';
991  }
992  $content_navigation['views']['edit'] = [
993  'class' => ( $isEditing && ( $section !== 'new' || !$showNewSection )
994  ? 'selected'
995  : ''
996  ) . $isTalkClass,
997  'text' => wfMessageFallback( "$skname-view-$msgKey", $msgKey )
998  ->setContext( $this->getContext() )->text(),
999  'href' => $title->getLocalURL( $this->editUrlOptions() ),
1000  'primary' => !$isRemoteContent, // don't collapse this in vector
1001  ];
1002 
1003  // section link
1004  if ( $showNewSection ) {
1005  // Adds new section link
1006  // $content_navigation['actions']['addsection']
1007  $content_navigation['views']['addsection'] = [
1008  'class' => ( $isEditing && $section == 'new' ) ? 'selected' : false,
1009  'text' => wfMessageFallback( "$skname-action-addsection", 'addsection' )
1010  ->setContext( $this->getContext() )->text(),
1011  'href' => $title->getLocalURL( 'action=edit&section=new' )
1012  ];
1013  }
1014  // Checks if the page has some kind of viewable source content
1015  } elseif ( $title->hasSourceText() ) {
1016  // Adds view source view link
1017  $content_navigation['views']['viewsource'] = [
1018  'class' => ( $onPage && $action == 'edit' ) ? 'selected' : false,
1019  'text' => wfMessageFallback( "$skname-action-viewsource", 'viewsource' )
1020  ->setContext( $this->getContext() )->text(),
1021  'href' => $title->getLocalURL( $this->editUrlOptions() ),
1022  'primary' => true, // don't collapse this in vector
1023  ];
1024  }
1025 
1026  // Checks if the page exists
1027  if ( $title->exists() ) {
1028  // Adds history view link
1029  $content_navigation['views']['history'] = [
1030  'class' => ( $onPage && $action == 'history' ) ? 'selected' : false,
1031  'text' => wfMessageFallback( "$skname-view-history", 'history_short' )
1032  ->setContext( $this->getContext() )->text(),
1033  'href' => $title->getLocalURL( 'action=history' ),
1034  ];
1035 
1036  if ( $permissionManager->quickUserCan( 'delete', $user, $title ) ) {
1037  $content_navigation['actions']['delete'] = [
1038  'class' => ( $onPage && $action == 'delete' ) ? 'selected' : false,
1039  'text' => wfMessageFallback( "$skname-action-delete", 'delete' )
1040  ->setContext( $this->getContext() )->text(),
1041  'href' => $title->getLocalURL( 'action=delete' )
1042  ];
1043  }
1044 
1045  if ( $permissionManager->quickUserCan( 'move', $user, $title ) ) {
1046  $moveTitle = SpecialPage::getTitleFor( 'Movepage', $title->getPrefixedDBkey() );
1047  $content_navigation['actions']['move'] = [
1048  'class' => $this->getTitle()->isSpecial( 'Movepage' ) ? 'selected' : false,
1049  'text' => wfMessageFallback( "$skname-action-move", 'move' )
1050  ->setContext( $this->getContext() )->text(),
1051  'href' => $moveTitle->getLocalURL()
1052  ];
1053  }
1054  } else {
1055  // article doesn't exist or is deleted
1056  if ( $permissionManager->quickUserCan( 'deletedhistory', $user, $title ) ) {
1057  $n = $title->isDeleted();
1058  if ( $n ) {
1059  $undelTitle = SpecialPage::getTitleFor( 'Undelete', $title->getPrefixedDBkey() );
1060  // If the user can't undelete but can view deleted
1061  // history show them a "View .. deleted" tab instead.
1062  $msgKey = $permissionManager->quickUserCan( 'undelete',
1063  $user, $title ) ? 'undelete' : 'viewdeleted';
1064  $content_navigation['actions']['undelete'] = [
1065  'class' => $this->getTitle()->isSpecial( 'Undelete' ) ? 'selected' : false,
1066  'text' => wfMessageFallback( "$skname-action-$msgKey", "{$msgKey}_short" )
1067  ->setContext( $this->getContext() )->numParams( $n )->text(),
1068  'href' => $undelTitle->getLocalURL()
1069  ];
1070  }
1071  }
1072  }
1073 
1074  if ( $permissionManager->quickUserCan( 'protect', $user, $title ) &&
1075  $title->getRestrictionTypes() &&
1076  $permissionManager->getNamespaceRestrictionLevels( $title->getNamespace(), $user ) !== [ '' ]
1077  ) {
1078  $mode = $title->isProtected() ? 'unprotect' : 'protect';
1079  $content_navigation['actions'][$mode] = [
1080  'class' => ( $onPage && $action == $mode ) ? 'selected' : false,
1081  'text' => wfMessageFallback( "$skname-action-$mode", $mode )
1082  ->setContext( $this->getContext() )->text(),
1083  'href' => $title->getLocalURL( "action=$mode" )
1084  ];
1085  }
1086 
1087  // Checks if the user is logged in
1088  if ( $this->loggedin && $permissionManager->userHasAllRights( $user,
1089  'viewmywatchlist', 'editmywatchlist' )
1090  ) {
1100  $mode = $user->isWatched( $title ) ? 'unwatch' : 'watch';
1101  $content_navigation['actions'][$mode] = [
1102  'class' => 'mw-watchlink ' . (
1103  $onPage && ( $action == 'watch' || $action == 'unwatch' ) ? 'selected' : ''
1104  ),
1105  // uses 'watch' or 'unwatch' message
1106  'text' => $this->msg( $mode )->text(),
1107  'href' => $title->getLocalURL( [ 'action' => $mode ] ),
1108  // Set a data-mw=interface attribute, which the mediawiki.page.ajax
1109  // module will look for to make sure it's a trusted link
1110  'data' => [
1111  'mw' => 'interface',
1112  ],
1113  ];
1114  }
1115  }
1116 
1117  // Avoid PHP 7.1 warning of passing $this by reference
1118  $skinTemplate = $this;
1120  'SkinTemplateNavigation',
1121  [ &$skinTemplate, &$content_navigation ]
1122  );
1123 
1124  if ( $userCanRead && !$wgDisableLangConversion ) {
1125  $pageLang = $title->getPageLanguage();
1126  // Checks that language conversion is enabled and variants exist
1127  // And if it is not in the special namespace
1128  if ( $pageLang->hasVariants() ) {
1129  // Gets list of language variants
1130  $variants = $pageLang->getVariants();
1131  // Gets preferred variant (note that user preference is
1132  // only possible for wiki content language variant)
1133  $preferred = $pageLang->getPreferredVariant();
1134  if ( Action::getActionName( $this ) === 'view' ) {
1135  $params = $request->getQueryValues();
1136  unset( $params['title'] );
1137  } else {
1138  $params = [];
1139  }
1140  // Loops over each variant
1141  foreach ( $variants as $code ) {
1142  // Gets variant name from language code
1143  $varname = $pageLang->getVariantname( $code );
1144  // Appends variant link
1145  $content_navigation['variants'][] = [
1146  'class' => ( $code == $preferred ) ? 'selected' : false,
1147  'text' => $varname,
1148  'href' => $title->getLocalURL( [ 'variant' => $code ] + $params ),
1149  'lang' => LanguageCode::bcp47( $code ),
1150  'hreflang' => LanguageCode::bcp47( $code ),
1151  ];
1152  }
1153  }
1154  }
1155  } else {
1156  // If it's not content, it's got to be a special page
1157  $content_navigation['namespaces']['special'] = [
1158  'class' => 'selected',
1159  'text' => $this->msg( 'nstab-special' )->text(),
1160  'href' => $request->getRequestURL(), // @see: T4457, T4510
1161  'context' => 'subject'
1162  ];
1163 
1164  // Avoid PHP 7.1 warning of passing $this by reference
1165  $skinTemplate = $this;
1166  Hooks::runWithoutAbort( 'SkinTemplateNavigation::SpecialPage',
1167  [ &$skinTemplate, &$content_navigation ] );
1168  }
1169 
1170  // Avoid PHP 7.1 warning of passing $this by reference
1171  $skinTemplate = $this;
1172  // Equiv to SkinTemplateContentActions
1173  Hooks::runWithoutAbort( 'SkinTemplateNavigation::Universal',
1174  [ &$skinTemplate, &$content_navigation ] );
1175 
1176  // Setup xml ids and tooltip info
1177  foreach ( $content_navigation as $section => &$links ) {
1178  foreach ( $links as $key => &$link ) {
1179  $xmlID = $key;
1180  if ( isset( $link['context'] ) && $link['context'] == 'subject' ) {
1181  $xmlID = 'ca-nstab-' . $xmlID;
1182  } elseif ( isset( $link['context'] ) && $link['context'] == 'talk' ) {
1183  $xmlID = 'ca-talk';
1184  $link['rel'] = 'discussion';
1185  } elseif ( $section == 'variants' ) {
1186  $xmlID = 'ca-varlang-' . $xmlID;
1187  } else {
1188  $xmlID = 'ca-' . $xmlID;
1189  }
1190  $link['id'] = $xmlID;
1191  }
1192  }
1193 
1194  # We don't want to give the watch tab an accesskey if the
1195  # page is being edited, because that conflicts with the
1196  # accesskey on the watch checkbox. We also don't want to
1197  # give the edit tab an accesskey, because that's fairly
1198  # superfluous and conflicts with an accesskey (Ctrl-E) often
1199  # used for editing in Safari.
1200  if ( in_array( $action, [ 'edit', 'submit' ] ) ) {
1201  if ( isset( $content_navigation['views']['edit'] ) ) {
1202  $content_navigation['views']['edit']['tooltiponly'] = true;
1203  }
1204  if ( isset( $content_navigation['actions']['watch'] ) ) {
1205  $content_navigation['actions']['watch']['tooltiponly'] = true;
1206  }
1207  if ( isset( $content_navigation['actions']['unwatch'] ) ) {
1208  $content_navigation['actions']['unwatch']['tooltiponly'] = true;
1209  }
1210  }
1211 
1212  return $content_navigation;
1213  }
1214 
1220  private function buildContentActionUrls( $content_navigation ) {
1221  // content_actions has been replaced with content_navigation for backwards
1222  // compatibility and also for skins that just want simple tabs content_actions
1223  // is now built by flattening the content_navigation arrays into one
1224 
1225  $content_actions = [];
1226 
1227  foreach ( $content_navigation as $links ) {
1228  foreach ( $links as $key => $value ) {
1229  if ( isset( $value['redundant'] ) && $value['redundant'] ) {
1230  // Redundant tabs are dropped from content_actions
1231  continue;
1232  }
1233 
1234  // content_actions used to have ids built using the "ca-$key" pattern
1235  // so the xmlID based id is much closer to the actual $key that we want
1236  // for that reason we'll just strip out the ca- if present and use
1237  // the latter potion of the "id" as the $key
1238  if ( isset( $value['id'] ) && substr( $value['id'], 0, 3 ) == 'ca-' ) {
1239  $key = substr( $value['id'], 3 );
1240  }
1241 
1242  if ( isset( $content_actions[$key] ) ) {
1243  wfDebug( __METHOD__ . ": Found a duplicate key for $key while flattening " .
1244  "content_navigation into content_actions.\n" );
1245  continue;
1246  }
1247 
1248  $content_actions[$key] = $value;
1249  }
1250  }
1251 
1252  return $content_actions;
1253  }
1254 
1259  protected function buildNavUrls() {
1260  global $wgUploadNavigationUrl;
1261 
1262  $out = $this->getOutput();
1263  $request = $this->getRequest();
1264 
1265  $nav_urls = [];
1266  $nav_urls['mainpage'] = [ 'href' => self::makeMainPageUrl() ];
1267  if ( $wgUploadNavigationUrl ) {
1268  $nav_urls['upload'] = [ 'href' => $wgUploadNavigationUrl ];
1269  } elseif ( UploadBase::isEnabled() && UploadBase::isAllowed( $this->getUser() ) === true ) {
1270  $nav_urls['upload'] = [ 'href' => self::makeSpecialUrl( 'Upload' ) ];
1271  } else {
1272  $nav_urls['upload'] = false;
1273  }
1274  $nav_urls['specialpages'] = [ 'href' => self::makeSpecialUrl( 'Specialpages' ) ];
1275 
1276  $nav_urls['print'] = false;
1277  $nav_urls['permalink'] = false;
1278  $nav_urls['info'] = false;
1279  $nav_urls['whatlinkshere'] = false;
1280  $nav_urls['recentchangeslinked'] = false;
1281  $nav_urls['contributions'] = false;
1282  $nav_urls['log'] = false;
1283  $nav_urls['blockip'] = false;
1284  $nav_urls['mute'] = false;
1285  $nav_urls['emailuser'] = false;
1286  $nav_urls['userrights'] = false;
1287 
1288  // A print stylesheet is attached to all pages, but nobody ever
1289  // figures that out. :) Add a link...
1290  if ( !$out->isPrintable() && ( $out->isArticle() || $this->getTitle()->isSpecialPage() ) ) {
1291  $nav_urls['print'] = [
1292  'text' => $this->msg( 'printableversion' )->text(),
1293  'href' => $this->getTitle()->getLocalURL(
1294  $request->appendQueryValue( 'printable', 'yes' ) )
1295  ];
1296  }
1297 
1298  if ( $out->isArticle() ) {
1299  // Also add a "permalink" while we're at it
1300  $revid = $this->getOutput()->getRevisionId();
1301  if ( $revid ) {
1302  $nav_urls['permalink'] = [
1303  'text' => $this->msg( 'permalink' )->text(),
1304  'href' => $this->getTitle()->getLocalURL( "oldid=$revid" )
1305  ];
1306  }
1307 
1308  // Avoid PHP 7.1 warning of passing $this by reference
1309  $skinTemplate = $this;
1310  // Use the copy of revision ID in case this undocumented, shady hook tries to mess with internals
1311  Hooks::run( 'SkinTemplateBuildNavUrlsNav_urlsAfterPermalink',
1312  [ &$skinTemplate, &$nav_urls, &$revid, &$revid ] );
1313  }
1314 
1315  if ( $out->isArticleRelated() ) {
1316  $nav_urls['whatlinkshere'] = [
1317  'href' => SpecialPage::getTitleFor( 'Whatlinkshere', $this->thispage )->getLocalURL()
1318  ];
1319 
1320  $nav_urls['info'] = [
1321  'text' => $this->msg( 'pageinfo-toolboxlink' )->text(),
1322  'href' => $this->getTitle()->getLocalURL( "action=info" )
1323  ];
1324 
1325  if ( $this->getTitle()->exists() || $this->getTitle()->inNamespace( NS_CATEGORY ) ) {
1326  $nav_urls['recentchangeslinked'] = [
1327  'href' => SpecialPage::getTitleFor( 'Recentchangeslinked', $this->thispage )->getLocalURL()
1328  ];
1329  }
1330  }
1331 
1332  $user = $this->getRelevantUser();
1333  if ( $user ) {
1334  $rootUser = $user->getName();
1335 
1336  $nav_urls['contributions'] = [
1337  'text' => $this->msg( 'contributions', $rootUser )->text(),
1338  'href' => self::makeSpecialUrlSubpage( 'Contributions', $rootUser ),
1339  'tooltip-params' => [ $rootUser ],
1340  ];
1341 
1342  $nav_urls['log'] = [
1343  'href' => self::makeSpecialUrlSubpage( 'Log', $rootUser )
1344  ];
1345 
1346  if ( MediawikiServices::getInstance()
1348  ->userHasRight( $this->getUser(), 'block' )
1349  ) {
1350  $nav_urls['blockip'] = [
1351  'text' => $this->msg( 'blockip', $rootUser )->text(),
1352  'href' => self::makeSpecialUrlSubpage( 'Block', $rootUser )
1353  ];
1354  }
1355 
1356  if ( $this->showEmailUser( $user ) ) {
1357  $nav_urls['emailuser'] = [
1358  'text' => $this->msg( 'tool-link-emailuser', $rootUser )->text(),
1359  'href' => self::makeSpecialUrlSubpage( 'Emailuser', $rootUser ),
1360  'tooltip-params' => [ $rootUser ],
1361  ];
1362  }
1363 
1364  if ( !$user->isAnon() ) {
1365  if ( $this->getUser()->isRegistered() && $this->getConfig()->get( 'EnableSpecialMute' ) ) {
1366  $nav_urls['mute'] = [
1367  'text' => $this->msg( 'mute-preferences' )->text(),
1368  'href' => self::makeSpecialUrlSubpage( 'Mute', $rootUser )
1369  ];
1370  }
1371 
1372  $sur = new UserrightsPage;
1373  $sur->setContext( $this->getContext() );
1374  $canChange = $sur->userCanChangeRights( $user );
1375  $nav_urls['userrights'] = [
1376  'text' => $this->msg(
1377  $canChange ? 'tool-link-userrights' : 'tool-link-userrights-readonly',
1378  $rootUser
1379  )->text(),
1380  'href' => self::makeSpecialUrlSubpage( 'Userrights', $rootUser )
1381  ];
1382  }
1383  }
1384 
1385  return $nav_urls;
1386  }
1387 
1392  protected function getNameSpaceKey() {
1393  return $this->getTitle()->getNamespaceKey();
1394  }
1395 }
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:123
SkinTemplate\makePersonalToolsList
makePersonalToolsList( $personalTools=null, $options=[])
Get the HTML for the personal tools list.
Definition: SkinTemplate.php:510
Language\fetchLanguageName
static fetchLanguageName( $code, $inLanguage=self::AS_AUTONYMS, $include=self::ALL)
Definition: Language.php:832
ContextSource\getConfig
getConfig()
Definition: ContextSource.php:63
SkinTemplate\useCombinedLoginLink
useCombinedLoginLink()
Output a boolean indicating if buildPersonalUrls should output separate login and create account link...
Definition: SkinTemplate.php:575
Skin\editUrlOptions
editUrlOptions()
Return URL options for the 'edit page' link.
Definition: Skin.php:1110
Skin\showEmailUser
showEmailUser( $id)
Definition: Skin.php:1124
SkinTemplate\setupTemplateForOutput
setupTemplateForOutput()
Definition: SkinTemplate.php:175
$wgMaxCredits
$wgMaxCredits
Set this to the number of authors that you want to be credited below an article text.
Definition: DefaultSettings.php:7183
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:316
Skin\makeUrlDetails
static makeUrlDetails( $name, $urlaction='')
these return an array with the 'href' and boolean 'exists'
Definition: Skin.php:1258
ContextSource\getContext
getContext()
Get the base IContextSource object.
Definition: ContextSource.php:40
Skin\getSiteNotice
getSiteNotice()
Get the site notice.
Definition: Skin.php:1616
wfMessageFallback
wfMessageFallback(... $keys)
This function accepts multiple message keys and returns a message instance for the first message whic...
Definition: GlobalFunctions.php:1287
$wgMimeType
$wgMimeType
The default Content-Type header.
Definition: DefaultSettings.php:3251
SkinTemplate\setupTemplate
setupTemplate( $classname)
Create the template engine object; we feed it a bunch of data and eventually it spits out some HTML.
Definition: SkinTemplate.php:68
SkinTemplate\buildContentNavigationUrls
buildContentNavigationUrls()
a structured array of links usually used for the tabs in a skin
Definition: SkinTemplate.php:877
Skin\getPoweredBy
getPoweredBy()
Gets the powered by MediaWiki icon.
Definition: Skin.php:930
Profiler\instance
static instance()
Singleton.
Definition: Profiler.php:63
MediaWiki\MediaWikiServices
MediaWikiServices is the service locator for the application scope of MediaWiki.
Definition: MediaWikiServices.php:117
$wgScript
$wgScript
The URL path to index.php.
Definition: DefaultSettings.php:185
true
return true
Definition: router.php:92
$wgHideInterlanguageLinks
$wgHideInterlanguageLinks
Hide interlanguage links from the sidebar.
Definition: DefaultSettings.php:2975
Skin\lastModified
lastModified()
Get the timestamp of the latest revision, formatted in user language.
Definition: Skin.php:953
$wgShowCreditsIfMax
$wgShowCreditsIfMax
If there are more than $wgMaxCredits authors, show $wgMaxCredits of them.
Definition: DefaultSettings.php:7189
Skin\checkTitle
static checkTitle(&$title, $name)
make sure we have some title to operate on
Definition: Skin.php:1290
SkinTemplate\$userpageUrlDetails
$userpageUrlDetails
Definition: SkinTemplate.php:57
Skin\makeSpecialUrl
static makeSpecialUrl( $name, $urlaction='', $proto=null)
Make a URL for a Special Page using the given query and protocol.
Definition: Skin.php:1181
Skin\aboutLink
aboutLink()
Gets the link to the wiki's about page.
Definition: Skin.php:1091
NS_FILE
const NS_FILE
Definition: Defines.php:66
SkinTemplate\$titletxt
$titletxt
Definition: SkinTemplate.php:52
Skin\makeSpecialUrlSubpage
static makeSpecialUrlSubpage( $name, $subpage, $urlaction='')
Definition: Skin.php:1196
wfMessage
wfMessage( $key,... $params)
This is the function for getting translated interface messages.
Definition: GlobalFunctions.php:1264
SkinTemplate\$thispage
$thispage
Definition: SkinTemplate.php:51
SpecialPage\getTitleFor
static getTitleFor( $name, $subpage=false, $fragment='')
Get a localised Title object for a specified special page name If you don't need a full Title object,...
Definition: SpecialPage.php:83
ContextSource\canUseWikiPage
canUseWikiPage()
Check whether a WikiPage object can be get with getWikiPage().
Definition: ContextSource.php:91
ContextSource\getRequest
getRequest()
Definition: ContextSource.php:71
SkinTemplate\wrapHTML
wrapHTML( $title, $html)
Wrap the body text with language information and identifiable element.
Definition: SkinTemplate.php:230
$res
$res
Definition: testCompression.php:52
ContextSource\getUser
getUser()
Definition: ContextSource.php:120
ContextSource\getTitle
getTitle()
Definition: ContextSource.php:79
$wgLogo
$wgLogo
The URL path of the wiki logo.
Definition: DefaultSettings.php:268
$wgStylePath
$wgStylePath
The URL path of the skins directory.
Definition: DefaultSettings.php:207
Skin\bottomScripts
bottomScripts()
This gets called shortly before the "</body>" tag.
Definition: Skin.php:686
SkinTemplate\$userpage
$userpage
Definition: SkinTemplate.php:53
Skin\afterContentHook
afterContentHook()
This runs a hook to allow extensions placing their stuff after content and article metadata (e....
Definition: Skin.php:651
ContextSource\getLanguage
getLanguage()
Definition: ContextSource.php:128
NS_SPECIAL
const NS_SPECIAL
Definition: Defines.php:49
UserrightsPage
Special page to allow managing user group membership.
Definition: SpecialUserrights.php:31
SkinTemplate\getPersonalToolsList
getPersonalToolsList()
Get the HTML for the p-personal list.
Definition: SkinTemplate.php:497
wfReportTime
wfReportTime( $nonce=null)
Returns a script tag that stores the amount of time it took MediaWiki to handle the request in millis...
Definition: GlobalFunctions.php:1366
MWException
MediaWiki exception.
Definition: MWException.php:26
SkinTemplate\$skinname
string $skinname
Name of our skin, it probably needs to be all lower case.
Definition: SkinTemplate.php:43
Skin\buildSidebar
buildSidebar()
Build an array that represents the sidebar(s), the navigation bar among them.
Definition: Skin.php:1320
Skin\privacyLink
privacyLink()
Gets the link to the wiki's privacy policy page.
Definition: Skin.php:1083
SkinTemplate\buildNavUrls
buildNavUrls()
build array of common navigation links
Definition: SkinTemplate.php:1259
$wgFooterIcons
$wgFooterIcons
Abstract list of footer icons for skins in place of old copyrightico and poweredbyico code You can ad...
Definition: DefaultSettings.php:3485
Skin\generateDebugHTML
generateDebugHTML()
Generate debug data HTML for displaying at the bottom of the main content area.
Definition: Skin.php:677
SkinTemplate\tabAction
tabAction( $title, $message, $selected, $query='', $checkEdit=false)
Builds an array with tab definition.
Definition: SkinTemplate.php:758
SkinTemplate\formatLanguageName
formatLanguageName( $name)
Format language name for use in sidebar interlanguage links list.
Definition: SkinTemplate.php:550
getPermissionManager
getPermissionManager()
Skin\getCategories
getCategories()
Definition: Skin.php:616
SkinTemplate\buildContentActionUrls
buildContentActionUrls( $content_navigation)
an array of edit links by default used for the tabs
Definition: SkinTemplate.php:1220
ContextSource\getOutput
getOutput()
Definition: ContextSource.php:112
ContextSource\getWikiPage
getWikiPage()
Get the WikiPage object.
Definition: ContextSource.php:104
SkinTemplate\$username
$username
Definition: SkinTemplate.php:56
wfCgiToArray
wfCgiToArray( $query)
This is the logical opposite of wfArrayToCgi(): it accepts a query string as its argument and returns...
Definition: GlobalFunctions.php:392
SkinTemplate\$loggedin
$loggedin
Definition: SkinTemplate.php:55
$title
$title
Definition: testCompression.php:34
$wgUseCombinedLoginLink
$wgUseCombinedLoginLink
Login / create account link behavior when it's possible for anonymous users to create an account.
Definition: DefaultSettings.php:3507
NS_CATEGORY
const NS_CATEGORY
Definition: Defines.php:74
Skin\disclaimerLink
disclaimerLink()
Gets the link to the wiki's general disclaimers page.
Definition: Skin.php:1099
wfDebug
wfDebug( $text, $dest='all', array $context=[])
Sends a line to the debug log if enabled or, optionally, to a comment in output.
Definition: GlobalFunctions.php:913
$wgDisableLangConversion
$wgDisableLangConversion
Whether to enable language variant conversion.
Definition: DefaultSettings.php:3116
ContextSource\setContext
setContext(IContextSource $context)
Definition: ContextSource.php:55
SkinTemplate\getStructuredPersonalTools
getStructuredPersonalTools()
Get personal tools for the user.
Definition: SkinTemplate.php:535
SkinTemplate\$thisquery
$thisquery
Definition: SkinTemplate.php:54
ContextSource\msg
msg( $key,... $params)
Get a Message object with context set Parameters are the same as wfMessage()
Definition: ContextSource.php:168
SkinTemplate\prepareQuickTemplate
prepareQuickTemplate()
initialize various variables and generate the template
Definition: SkinTemplate.php:256
Skin\getRelevantTitle
getRelevantTitle()
Return the "relevant" title.
Definition: Skin.php:349
Hooks\runWithoutAbort
static runWithoutAbort( $event, array $args=[], $deprecatedVersion=null)
Call hook functions defined in Hooks::register and $wgHooks.
Definition: Hooks.php:231
SkinTemplate\$template
string $template
For QuickTemplate, the name of the subclass which will actually fill the template.
Definition: SkinTemplate.php:49
Skin\getSearchLink
getSearchLink()
Definition: Skin.php:833
$wgServer
$wgServer
URL of the server.
Definition: DefaultSettings.php:105
$wgSitename
$wgSitename
Name of the site.
Definition: DefaultSettings.php:80
Skin\printSource
printSource()
Text with the permalink to the source page, usually shown on the footer of a printed page.
Definition: Skin.php:708
SkinTemplate\makeArticleUrlDetails
makeArticleUrlDetails( $name, $urlaction='')
Definition: SkinTemplate.php:833
SkinTemplate\outputPage
outputPage()
Initialize various variables and generate the template.
Definition: SkinTemplate.php:210
SkinTemplate\makeTalkUrlDetails
makeTalkUrlDetails( $name, $urlaction='')
Definition: SkinTemplate.php:814
$wgUploadNavigationUrl
$wgUploadNavigationUrl
Point the upload navigation link to an external URL Useful if you want to use a shared repository by ...
Definition: DefaultSettings.php:888
MediaWiki\Auth\AuthManager
This serves as the entry point to the authentication system.
Definition: AuthManager.php:85
Skin\logoText
logoText( $align='')
Definition: Skin.php:981
SkinTemplate\getLanguages
getLanguages()
Generates array of language links for the current page.
Definition: SkinTemplate.php:77
Skin\getNewtalks
getNewtalks()
Gets new talk page messages for the current user and returns an appropriate alert message (or an empt...
Definition: Skin.php:1473
$wgArticlePath
$wgArticlePath
Definition: img_auth.php:47
SkinTemplate\getNameSpaceKey
getNameSpaceKey()
Generate strings used for xml 'id' names.
Definition: SkinTemplate.php:1392
Title
Represents a title within MediaWiki.
Definition: Title.php:42
Title\isSpecialPage
isSpecialPage()
Returns true if this is a special page.
Definition: Title.php:1209
LanguageCode\bcp47
static bcp47( $code)
Get the normalised IETF language tag See unit test for examples.
Definition: LanguageCode.php:178
Skin\getCopyright
getCopyright( $type='detect')
Definition: Skin.php:851
SpecialPage\setContext
setContext( $context)
Sets the context this SpecialPage is executed in.
Definition: SpecialPage.php:682
Skin\getRelevantUser
getRelevantUser()
Return the "relevant" user.
Definition: Skin.php:370
Skin\subPageSubtitle
subPageSubtitle( $out=null)
Definition: Skin.php:774
Skin\getUndeleteLink
getUndeleteLink()
Definition: Skin.php:726
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:1274
Skin\makeMainPageUrl
static makeMainPageUrl( $urlaction='')
Definition: Skin.php:1163
NS_MEDIAWIKI
const NS_MEDIAWIKI
Definition: Defines.php:68
Skin\getCopyrightIcon
getCopyrightIcon()
Definition: Skin.php:900
Skin
The main skin class which provides methods and properties for all other skins.
Definition: Skin.php:38
Skin\initPage
initPage(OutputPage $out)
Definition: Skin.php:165
$wgScriptPath
$wgScriptPath
The path we should point to.
Definition: DefaultSettings.php:137
Hooks\run
static run( $event, array $args=[], $deprecatedVersion=null)
Call hook functions defined in Hooks::register and $wgHooks.
Definition: Hooks.php:200
BaseTemplate
New base template for a skin's template extended from QuickTemplate this class features helper method...
Definition: BaseTemplate.php:29
SkinTemplate
Base class for template-based skins.
Definition: SkinTemplate.php:38
Action\factory
static factory( $action, Page $page, IContextSource $context=null)
Get an appropriate Action subclass for the given action.
Definition: Action.php:97
SkinTemplate\printOrError
printOrError( $str)
Output the string, or print error message if it's an error object of the appropriate type.
Definition: SkinTemplate.php:562
wfArrayToCgi
wfArrayToCgi( $array1, $array2=null, $prefix='')
This function takes one or two arrays as input, and returns a CGI-style string, e....
Definition: GlobalFunctions.php:347
SkinTemplate\buildPersonalUrls
buildPersonalUrls()
build array of urls for personal toolbar
Definition: SkinTemplate.php:584