MediaWiki  master
SkinTemplate.php
Go to the documentation of this file.
1 <?php
22 
37 class SkinTemplate extends Skin {
42  public $skinname = 'monobook';
43 
48  public $template = QuickTemplate::class;
49 
50  public $thispage;
51  public $titletxt;
52  public $userpage;
53  public $thisquery;
54  public $loggedin;
55  public $username;
57 
66  protected function setupTemplate( $classname ) {
67  return new $classname( $this->getConfig() );
68  }
69 
73  protected function setupTemplateForOutput() {
74  $this->setupTemplateContext();
75  $tpl = $this->setupTemplate( $this->template );
76  return $tpl;
77  }
78 
88  final protected function setupTemplateContext() {
89  $request = $this->getRequest();
90  $user = $this->getUser();
91  $title = $this->getTitle();
92 
93  $this->thispage = $title->getPrefixedDBkey();
94  $this->titletxt = $title->getPrefixedText();
95  $this->userpage = $user->getUserPage()->getPrefixedText();
96  $query = [];
97  if ( !$request->wasPosted() ) {
98  $query = $request->getValues();
99  unset( $query['title'] );
100  unset( $query['returnto'] );
101  unset( $query['returntoquery'] );
102  }
103  $this->thisquery = wfArrayToCgi( $query );
104  $this->loggedin = $user->isLoggedIn();
105  $this->username = $user->getName();
106 
107  if ( $this->loggedin ) {
108  $this->userpageUrlDetails = self::makeUrlDetails( $this->userpage );
109  } else {
110  # This won't be used in the standard skins, but we define it to preserve the interface
111  # To save time, we check for existence
112  $this->userpageUrlDetails = self::makeKnownUrlDetails( $this->userpage );
113  }
114  }
115 
124  public function generateHTML() {
125  $tpl = $this->prepareQuickTemplate();
126  // execute template
127  return $tpl->execute();
128  }
129 
133  public function outputPage() {
134  Profiler::instance()->setAllowOutput();
135  $out = $this->getOutput();
136 
137  $this->initPage( $out );
138  $out->addJsConfigVars( $this->getJsConfigVars() );
139 
140  // result may be an error
141  echo $this->generateHTML();
142  }
143 
151  protected function getJsConfigVars() : array {
152  return [];
153  }
154 
162  protected function wrapHTML( $title, $html ) {
163  # An ID that includes the actual body text; without categories, contentSub, ...
164  $realBodyAttribs = [ 'id' => 'mw-content-text' ];
165 
166  # Add a mw-content-ltr/rtl class to be able to style based on text
167  # direction when the content is different from the UI language (only
168  # when viewing)
169  # Most information on special pages and file pages is in user language,
170  # rather than content language, so those will not get this
171  if ( Action::getActionName( $this ) === 'view' &&
172  ( !$title->inNamespaces( NS_SPECIAL, NS_FILE ) || $title->isRedirect() ) ) {
173  $pageLang = $title->getPageViewLanguage();
174  $realBodyAttribs['lang'] = $pageLang->getHtmlCode();
175  $realBodyAttribs['dir'] = $pageLang->getDir();
176  $realBodyAttribs['class'] = 'mw-content-' . $pageLang->getDir();
177  }
178 
179  return Html::rawElement( 'div', $realBodyAttribs, $html );
180  }
181 
187  final protected function prepareSubtitle() {
188  $out = $this->getOutput();
189  $subpagestr = $this->subPageSubtitle();
190  if ( $subpagestr !== '' ) {
191  $subpagestr = '<span class="subpages">' . $subpagestr . '</span>';
192  }
193  return $subpagestr . $out->getSubtitle();
194  }
195 
201  final protected function prepareUserLanguageAttributes() {
202  $userLang = $this->getLanguage();
203  $userLangCode = $userLang->getHtmlCode();
204  $userLangDir = $userLang->getDir();
205  $contLang = MediaWikiServices::getInstance()->getContentLanguage();
206  if (
207  $userLangCode !== $contLang->getHtmlCode() ||
208  $userLangDir !== $contLang->getDir()
209  ) {
210  $escUserlang = htmlspecialchars( $userLangCode );
211  $escUserdir = htmlspecialchars( $userLangDir );
212  // Attributes must be in double quotes because htmlspecialchars() doesn't
213  // escape single quotes
214  return " lang=\"$escUserlang\" dir=\"$escUserdir\"";
215  }
216  return '';
217  }
218 
224  protected function getFooterIcons() {
225  $config = $this->getConfig();
226 
227  $footericons = [];
228  foreach ( $config->get( 'FooterIcons' ) as $footerIconsKey => &$footerIconsBlock ) {
229  if ( count( $footerIconsBlock ) > 0 ) {
230  $footericons[$footerIconsKey] = [];
231  foreach ( $footerIconsBlock as &$footerIcon ) {
232  if ( isset( $footerIcon['src'] ) ) {
233  if ( !isset( $footerIcon['width'] ) ) {
234  $footerIcon['width'] = 88;
235  }
236  if ( !isset( $footerIcon['height'] ) ) {
237  $footerIcon['height'] = 31;
238  }
239  }
240  $footericons[$footerIconsKey][] = $footerIcon;
241  }
242  }
243  }
244  return $footericons;
245  }
246 
256  protected function getFooterLinks() {
257  $out = $this->getOutput();
258  $title = $out->getTitle();
259  $titleExists = $title->exists();
260  $config = $this->getConfig();
261  $wgMaxCredits = $config->get( 'MaxCredits' );
262  $wgShowCreditsIfMax = $config->get( 'ShowCreditsIfMax' );
263  $useCredits = $titleExists && $out->isArticle() &&
264  $out->isRevisionCurrent() && $wgMaxCredits !== 0;
265 
267  if ( $titleExists ) {
268  $action = Action::factory(
269  'credits',
271  $this->getWikiPage(),
272  $this->getContext()
273  ),
274  $this->getContext()
275  );
276  }
277 
278  '@phan-var CreditsAction $action';
279  $data = [
280  'info' => [
281  'lastmod' => !$useCredits ? $this->lastModified() : null,
282  'numberofwatchingusers' => null,
283  'credits' => $useCredits ?
284  $action->getCredits( $wgMaxCredits, $wgShowCreditsIfMax ) : null,
285  'copyright' => $titleExists &&
286  $out->showsCopyright() ? $this->getCopyright() : null,
287  ],
288  'places' => $this->getSiteFooterLinks(),
289  ];
290  foreach ( $data as $key => $existingItems ) {
291  $newItems = [];
292  $this->getHookRunner()->onSkinAddFooterLinks( $this->getSkin(), $key, $newItems );
293  $data[$key] = $existingItems + $newItems;
294  }
295  return $data;
296  }
297 
303  final protected function prepareUndeleteLink() {
304  $undelete = $this->getUndeleteLink();
305  return $undelete === '' ? null : '<span class="subpages">' . $undelete . '</span>';
306  }
307 
314  protected function prepareQuickTemplate() {
315  $title = $this->getTitle();
316  $request = $this->getRequest();
317  $out = $this->getOutput();
318  $config = $this->getConfig();
319  $tpl = $this->setupTemplateForOutput();
320 
321  $tpl->set( 'title', $out->getPageTitle() );
322  $tpl->set( 'pagetitle', $out->getHTMLTitle() );
323  $tpl->set( 'displaytitle', $out->mPageLinkTitle );
324 
325  $tpl->set( 'thispage', $this->thispage );
326  $tpl->set( 'titleprefixeddbkey', $this->thispage );
327  $tpl->set( 'titletext', $title->getText() );
328  $tpl->set( 'articleid', $title->getArticleID() );
329 
330  $tpl->set( 'isarticle', $out->isArticle() );
331 
332  $tpl->set( 'subtitle', $this->prepareSubtitle() );
333  $tpl->set( 'undelete', $this->prepareUndeleteLink() );
334 
335  $tpl->set( 'catlinks', $this->getCategories() );
336  $feeds = $this->buildFeedUrls();
337  $tpl->set( 'feeds', count( $feeds ) ? $feeds : false );
338 
339  $tpl->set( 'mimetype', $config->get( 'MimeType' ) );
340  $tpl->set( 'charset', 'UTF-8' );
341  $tpl->set( 'wgScript', $config->get( 'Script' ) );
342  $tpl->set( 'skinname', $this->skinname );
343  $tpl->set( 'skinclass', static::class );
344  $tpl->set( 'skin', $this );
345  $tpl->set( 'stylename', $this->stylename );
346  $tpl->set( 'printable', $out->isPrintable() );
347  $tpl->set( 'handheld', $request->getBool( 'handheld' ) );
348  $tpl->set( 'loggedin', $this->loggedin );
349  $tpl->set( 'notspecialpage', !$title->isSpecialPage() );
350  $tpl->set( 'searchaction', $this->getSearchLink() );
351  $tpl->set( 'searchtitle', SpecialPage::getTitleFor( 'Search' )->getPrefixedDBkey() );
352  $tpl->set( 'search', trim( $request->getVal( 'search' ) ) );
353  $tpl->set( 'stylepath', $config->get( 'StylePath' ) );
354  $tpl->set( 'articlepath', $config->get( 'ArticlePath' ) );
355  $tpl->set( 'scriptpath', $config->get( 'ScriptPath' ) );
356  $tpl->set( 'serverurl', $config->get( 'Server' ) );
358  $tpl->set( 'logopath', $logos['1x'] );
359  $tpl->set( 'sitename', $config->get( 'Sitename' ) );
360 
361  $userLang = $this->getLanguage();
362  $userLangCode = $userLang->getHtmlCode();
363  $userLangDir = $userLang->getDir();
364 
365  $tpl->set( 'lang', $userLangCode );
366  $tpl->set( 'dir', $userLangDir );
367  $tpl->set( 'rtl', $userLang->isRTL() );
368 
369  $tpl->set( 'capitalizeallnouns', $userLang->capitalizeAllNouns() ? ' capitalize-all-nouns' : '' );
370  $tpl->set( 'showjumplinks', true ); // showjumplinks preference has been removed
371  $tpl->set( 'username', $this->loggedin ? $this->username : null );
372  $tpl->set( 'userpage', $this->userpage );
373  $tpl->set( 'userpageurl', $this->userpageUrlDetails['href'] );
374  $tpl->set( 'userlang', $userLangCode );
375 
376  // Users can have their language set differently than the
377  // content of the wiki. For these users, tell the web browser
378  // that interface elements are in a different language.
379  $tpl->set( 'userlangattributes', $this->prepareUserLanguageAttributes() );
380  $tpl->set( 'specialpageattributes', '' ); # obsolete
381  // Used by VectorBeta to insert HTML before content but after the
382  // heading for the page title. Defaults to empty string.
383  $tpl->set( 'prebodyhtml', '' );
384 
385  $tpl->set( 'newtalk', $this->getNewtalks() );
386  $tpl->set( 'logo', $this->logoText() );
387 
388  $footerData = $this->getFooterLinks();
389  $tpl->set( 'copyright', $footerData['info']['copyright'] ?? false );
390  // No longer used
391  $tpl->set( 'viewcount', false );
392  $tpl->set( 'lastmod', $footerData['info']['lastmod'] ?? false );
393  $tpl->set( 'credits', $footerData['info']['credits'] ?? false );
394  $tpl->set( 'numberofwatchingusers', false );
395 
396  $tpl->set( 'copyrightico', $this->getCopyrightIcon() );
397  $tpl->set( 'poweredbyico', $this->getPoweredBy() );
398 
399  $tpl->set( 'disclaimer', $footerData['places']['disclaimer'] ?? false );
400  $tpl->set( 'privacy', $footerData['places']['privacy'] ?? false );
401  $tpl->set( 'about', $footerData['places']['about'] ?? false );
402 
403  // Flatten for compat with the 'footerlinks' key in QuickTemplate-based skins.
404  $flattenedfooterlinks = [];
405  foreach ( $footerData as $category => $links ) {
406  $flattenedfooterlinks[$category] = array_keys( $links );
407  foreach ( $links as $key => $value ) {
408  // For full support with BaseTemplate we also need to
409  // copy over the keys.
410  $tpl->set( $key, $value );
411  }
412  }
413  $tpl->set( 'footerlinks', $flattenedfooterlinks );
414  $tpl->set( 'footericons', $this->getFooterIcons() );
415 
416  $tpl->set( 'indicators', $out->getIndicators() );
417 
418  $tpl->set( 'sitenotice', $this->getSiteNotice() );
419  $tpl->set( 'printfooter', $this->printSource() );
420  // Wrap the bodyText with #mw-content-text element
421  $tpl->set( 'bodytext', $this->wrapHTML( $title, $out->getHTML() ) );
422 
423  $tpl->set( 'language_urls', $this->getLanguages() ?: false );
424 
425  # Personal toolbar
426  $tpl->set( 'personal_urls', $this->buildPersonalUrls() );
427  $content_navigation = $this->buildContentNavigationUrls();
428  $content_actions = $this->buildContentActionUrls( $content_navigation );
429  $tpl->set( 'content_navigation', $content_navigation );
430  $tpl->set( 'content_actions', $content_actions );
431 
432  $tpl->set( 'sidebar', $this->buildSidebar() );
433  $tpl->set( 'nav_urls', $this->buildNavUrls() );
434 
435  // Do this last in case hooks above add bottom scripts
436  $tpl->set( 'bottomscripts', $this->bottomScripts() );
437 
438  // Set the head scripts near the end, in case the above actions resulted in added scripts
439  $tpl->set( 'headelement', $out->headElement( $this ) );
440 
441  $tpl->set( 'debug', '' );
442  $tpl->set( 'debughtml', $this->generateDebugHTML() );
443  $tpl->set( 'reporttime', wfReportTime( $out->getCSP()->getNonce() ) );
444 
445  // original version by hansm
446  // See T60137 for information on deprecation.
447  if ( !$this->getHookRunner()->onSkinTemplateOutputPageBeforeExec( $this, $tpl ) ) {
448  wfDebug( __METHOD__ . ": Hook SkinTemplateOutputPageBeforeExec broke outputPage execution!" );
449  }
450 
451  // Set the bodytext to another key so that skins can just output it on its own
452  // and output printfooter and debughtml separately
453  $tpl->set( 'bodycontent', $tpl->data['bodytext'] );
454 
455  // Append printfooter and debughtml onto bodytext so that skins that
456  // were already using bodytext before they were split out don't suddenly
457  // start not outputting information.
458  $tpl->data['bodytext'] .= Html::rawElement(
459  'div',
460  [ 'class' => 'printfooter' ],
461  "\n{$tpl->data['printfooter']}"
462  ) . "\n";
463  $tpl->data['bodytext'] .= $tpl->data['debughtml'];
464 
465  // allow extensions adding stuff after the page content.
466  // See Skin::afterContentHook() for further documentation.
467  $tpl->set( 'dataAfterContent', $this->afterContentHook() );
468 
469  return $tpl;
470  }
471 
477  public function getPersonalToolsList() {
478  return $this->makePersonalToolsList();
479  }
480 
491  public function makePersonalToolsList( $personalTools = null, $options = [] ) {
492  $this->setupTemplateContext();
493  $html = '';
494 
495  if ( $personalTools === null ) {
496  $personalTools = $this->getPersonalToolsForMakeListItem(
497  $this->buildPersonalUrls()
498  );
499  }
500 
501  foreach ( $personalTools as $key => $item ) {
502  $html .= $this->makeListItem( $key, $item, $options );
503  }
504 
505  return $html;
506  }
507 
515  public function getStructuredPersonalTools() {
516  // buildPersonalUrls requires the template context.
517  $this->setupTemplateContext();
518  return $this->getPersonalToolsForMakeListItem(
519  $this->buildPersonalUrls()
520  );
521  }
522 
529  protected function buildPersonalUrls() {
530  $title = $this->getTitle();
531  $request = $this->getRequest();
532  $pageurl = $title->getLocalURL();
533  $services = MediaWikiServices::getInstance();
534  $authManager = $services->getAuthManager();
535  $permissionManager = $services->getPermissionManager();
536 
537  /* set up the default links for the personal toolbar */
538  $personal_urls = [];
539 
540  # Due to T34276, if a user does not have read permissions,
541  # $this->getTitle() will just give Special:Badtitle, which is
542  # not especially useful as a returnto parameter. Use the title
543  # from the request instead, if there was one.
544  if ( $permissionManager->userHasRight( $this->getUser(), 'read' ) ) {
545  $page = $title;
546  } else {
547  $page = Title::newFromText( $request->getVal( 'title', '' ) );
548  }
549  $page = $request->getVal( 'returnto', $page );
550  $returnto = [];
551  if ( strval( $page ) !== '' ) {
552  $returnto['returnto'] = $page;
553  $query = $request->getVal( 'returntoquery', $this->thisquery );
554  $paramsArray = wfCgiToArray( $query );
555  $query = wfArrayToCgi( $paramsArray );
556  if ( $query != '' ) {
557  $returnto['returntoquery'] = $query;
558  }
559  }
560 
561  if ( $this->loggedin ) {
562  $personal_urls['userpage'] = [
563  'text' => $this->username,
564  'href' => &$this->userpageUrlDetails['href'],
565  'class' => $this->userpageUrlDetails['exists'] ? false : 'new',
566  'exists' => $this->userpageUrlDetails['exists'],
567  'active' => ( $this->userpageUrlDetails['href'] == $pageurl ),
568  'dir' => 'auto'
569  ];
570  $usertalkUrlDetails = $this->makeTalkUrlDetails( $this->userpage );
571  $personal_urls['mytalk'] = [
572  'text' => $this->msg( 'mytalk' )->text(),
573  'href' => &$usertalkUrlDetails['href'],
574  'class' => $usertalkUrlDetails['exists'] ? false : 'new',
575  'exists' => $usertalkUrlDetails['exists'],
576  'active' => ( $usertalkUrlDetails['href'] == $pageurl )
577  ];
578  $href = self::makeSpecialUrl( 'Preferences' );
579  $personal_urls['preferences'] = [
580  'text' => $this->msg( 'mypreferences' )->text(),
581  'href' => $href,
582  'active' => ( $href == $pageurl )
583  ];
584 
585  if ( $permissionManager->userHasRight( $this->getUser(), 'viewmywatchlist' ) ) {
586  $href = self::makeSpecialUrl( 'Watchlist' );
587  $personal_urls['watchlist'] = [
588  'text' => $this->msg( 'mywatchlist' )->text(),
589  'href' => $href,
590  'active' => ( $href == $pageurl )
591  ];
592  }
593 
594  # We need to do an explicit check for Special:Contributions, as we
595  # have to match both the title, and the target, which could come
596  # from request values (Special:Contributions?target=Jimbo_Wales)
597  # or be specified in "sub page" form
598  # (Special:Contributions/Jimbo_Wales). The plot
599  # thickens, because the Title object is altered for special pages,
600  # so it doesn't contain the original alias-with-subpage.
601  $origTitle = Title::newFromText( $request->getText( 'title' ) );
602  if ( $origTitle instanceof Title && $origTitle->isSpecialPage() ) {
603  list( $spName, $spPar ) =
604  MediaWikiServices::getInstance()->getSpecialPageFactory()->
605  resolveAlias( $origTitle->getText() );
606  $active = $spName == 'Contributions'
607  && ( ( $spPar && $spPar == $this->username )
608  || $request->getText( 'target' ) == $this->username );
609  } else {
610  $active = false;
611  }
612 
613  $href = self::makeSpecialUrlSubpage( 'Contributions', $this->username );
614  $personal_urls['mycontris'] = [
615  'text' => $this->msg( 'mycontris' )->text(),
616  'href' => $href,
617  'active' => $active
618  ];
619 
620  // if we can't set the user, we can't unset it either
621  if ( $request->getSession()->canSetUser() ) {
622  $personal_urls['logout'] = [
623  'text' => $this->msg( 'pt-userlogout' )->text(),
624  'data-mw' => 'interface',
625  'href' => self::makeSpecialUrl( 'Userlogout',
626  // Note: userlogout link must always contain an & character, otherwise we might not be able
627  // to detect a buggy precaching proxy (T19790)
628  ( $title->isSpecial( 'Preferences' ) ? [] : $returnto ) ),
629  'active' => false
630  ];
631  }
632  } else {
633  $useCombinedLoginLink = $this->getConfig()->get( 'UseCombinedLoginLink' );
634  if ( !$authManager->canCreateAccounts() || !$authManager->canAuthenticateNow() ) {
635  // don't show combined login/signup link if one of those is actually not available
636  $useCombinedLoginLink = false;
637  }
638 
639  $loginlink = $permissionManager->userHasRight( $this->getUser(), 'createaccount' )
640  && $useCombinedLoginLink ? 'nav-login-createaccount' : 'pt-login';
641 
642  $login_url = [
643  'text' => $this->msg( $loginlink )->text(),
644  'href' => self::makeSpecialUrl( 'Userlogin', $returnto ),
645  'active' => $title->isSpecial( 'Userlogin' )
646  || $title->isSpecial( 'CreateAccount' ) && $useCombinedLoginLink,
647  ];
648  $createaccount_url = [
649  'text' => $this->msg( 'pt-createaccount' )->text(),
650  'href' => self::makeSpecialUrl( 'CreateAccount', $returnto ),
651  'active' => $title->isSpecial( 'CreateAccount' ),
652  ];
653 
654  // No need to show Talk and Contributions to anons if they can't contribute!
655  if ( $permissionManager->groupHasPermission( '*', 'edit' ) ) {
656  // Because of caching, we can't link directly to the IP talk and
657  // contributions pages. Instead we use the special page shortcuts
658  // (which work correctly regardless of caching). This means we can't
659  // determine whether these links are active or not, but since major
660  // skins (MonoBook, Vector) don't use this information, it's not a
661  // huge loss.
662  $personal_urls['anontalk'] = [
663  'text' => $this->msg( 'anontalk' )->text(),
664  'href' => self::makeSpecialUrlSubpage( 'Mytalk', false ),
665  'active' => false
666  ];
667  $personal_urls['anoncontribs'] = [
668  'text' => $this->msg( 'anoncontribs' )->text(),
669  'href' => self::makeSpecialUrlSubpage( 'Mycontributions', false ),
670  'active' => false
671  ];
672  }
673 
674  if (
675  $authManager->canCreateAccounts()
676  && $permissionManager->userHasRight( $this->getUser(), 'createaccount' )
677  && !$useCombinedLoginLink
678  ) {
679  $personal_urls['createaccount'] = $createaccount_url;
680  }
681 
682  if ( $authManager->canAuthenticateNow() ) {
683  $key = $permissionManager->groupHasPermission( '*', 'read' )
684  ? 'login'
685  : 'login-private';
686  $personal_urls[$key] = $login_url;
687  }
688  }
689 
690  $this->getHookRunner()->onPersonalUrls( $personal_urls, $title, $this );
691  return $personal_urls;
692  }
693 
705  public function tabAction( $title, $message, $selected, $query = '', $checkEdit = false ) {
706  $classes = [];
707  if ( $selected ) {
708  $classes[] = 'selected';
709  }
710  $exists = true;
711  if ( $checkEdit && !$title->isKnown() ) {
712  $classes[] = 'new';
713  $exists = false;
714  if ( $query !== '' ) {
715  $query = 'action=edit&redlink=1&' . $query;
716  } else {
717  $query = 'action=edit&redlink=1';
718  }
719  }
720 
721  $services = MediaWikiServices::getInstance();
722  $linkClass = $services->getLinkRenderer()->getLinkClasses( $title );
723 
724  // wfMessageFallback will nicely accept $message as an array of fallbacks
725  // or just a single key
726  $msg = wfMessageFallback( $message )->setContext( $this->getContext() );
727  if ( is_array( $message ) ) {
728  // for hook compatibility just keep the last message name
729  $message = end( $message );
730  }
731  if ( $msg->exists() ) {
732  $text = $msg->text();
733  } else {
734  $text = $services->getLanguageConverterFactory()
735  ->getLanguageConverter( $services->getContentLanguage() )
736  ->convertNamespace(
737  $services->getNamespaceInfo()
738  ->getSubject( $title->getNamespace() )
739  );
740  }
741 
742  $result = [];
743  if ( !$this->getHookRunner()->onSkinTemplateTabAction( $this, $title, $message,
744  $selected, $checkEdit, $classes, $query, $text, $result )
745  ) {
746  return $result;
747  }
748 
749  $result = [
750  'class' => implode( ' ', $classes ),
751  'text' => $text,
752  'href' => $title->getLocalURL( $query ),
753  'exists' => $exists,
754  'primary' => true ];
755  if ( $linkClass !== '' ) {
756  $result['link-class'] = $linkClass;
757  }
758 
759  return $result;
760  }
761 
767  private function makeTalkUrlDetails( $name, $urlaction = '' ) {
768  $title = Title::newFromText( $name );
769  if ( !is_object( $title ) ) {
770  throw new MWException( __METHOD__ . " given invalid pagename $name" );
771  }
772  $title = $title->getTalkPage();
773  self::checkTitle( $title, $name );
774  return [
775  'href' => $title->getLocalURL( $urlaction ),
776  'exists' => $title->isKnown(),
777  ];
778  }
779 
786  public function makeArticleUrlDetails( $name, $urlaction = '' ) {
787  wfDeprecated( __METHOD__, '1.35' );
788  $title = Title::newFromText( $name );
789  $title = $title->getSubjectPage();
790  self::checkTitle( $title, $name );
791  return [
792  'href' => $title->getLocalURL( $urlaction ),
793  'exists' => $title->exists(),
794  ];
795  }
796 
806  private function getWatchLinkAttrs(
807  string $mode, User $user, Title $title, ?string $action, bool $onPage
808  ): array {
809  $class = 'mw-watchlink ' . (
810  $onPage && ( $action == 'watch' || $action == 'unwatch' ) ? 'selected' : ''
811  );
812 
813  // Add class identifying the page is temporarily watched, if applicable.
814  if ( $this->getConfig()->get( 'WatchlistExpiry' ) &&
815  $user->isTempWatched( $title )
816  ) {
817  $class .= ' mw-watchlink-temp';
818  }
819 
820  return [
821  'class' => $class,
822  // uses 'watch' or 'unwatch' message
823  'text' => $this->msg( $mode )->text(),
824  'href' => $title->getLocalURL( [ 'action' => $mode ] ),
825  // Set a data-mw=interface attribute, which the mediawiki.page.ajax
826  // module will look for to make sure it's a trusted link
827  'data' => [
828  'mw' => 'interface',
829  ],
830  ];
831  }
832 
867  protected function buildContentNavigationUrls() {
868  // Display tabs for the relevant title rather than always the title itself
869  $title = $this->getRelevantTitle();
870  $onPage = $title->equals( $this->getTitle() );
871 
872  $out = $this->getOutput();
873  $request = $this->getRequest();
874  $user = $this->getUser();
875  $permissionManager = MediaWikiServices::getInstance()->getPermissionManager();
876 
877  $content_navigation = [
878  'namespaces' => [],
879  'views' => [],
880  'actions' => [],
881  'variants' => []
882  ];
883 
884  // parameters
885  $action = $request->getVal( 'action', 'view' );
886 
887  $userCanRead = $permissionManager->quickUserCan( 'read', $user, $title );
888 
889  $preventActiveTabs = false;
890  $this->getHookRunner()->onSkinTemplatePreventOtherActiveTabs( $this, $preventActiveTabs );
891 
892  // Checks if page is some kind of content
893  if ( $title->canExist() ) {
894  // Gets page objects for the related namespaces
895  $subjectPage = $title->getSubjectPage();
896  $talkPage = $title->getTalkPage();
897 
898  // Determines if this is a talk page
899  $isTalk = $title->isTalkPage();
900 
901  // Generates XML IDs from namespace names
902  $subjectId = $title->getNamespaceKey( '' );
903 
904  if ( $subjectId == 'main' ) {
905  $talkId = 'talk';
906  } else {
907  $talkId = "{$subjectId}_talk";
908  }
909 
910  $skname = $this->skinname;
911 
912  // Adds namespace links
913  $subjectMsg = [ "nstab-$subjectId" ];
914  if ( $subjectPage->isMainPage() ) {
915  array_unshift( $subjectMsg, 'mainpage-nstab' );
916  }
917  $content_navigation['namespaces'][$subjectId] = $this->tabAction(
918  $subjectPage, $subjectMsg, !$isTalk && !$preventActiveTabs, '', $userCanRead
919  );
920  $content_navigation['namespaces'][$subjectId]['context'] = 'subject';
921  $content_navigation['namespaces'][$talkId] = $this->tabAction(
922  $talkPage, [ "nstab-$talkId", 'talk' ], $isTalk && !$preventActiveTabs, '', $userCanRead
923  );
924  $content_navigation['namespaces'][$talkId]['context'] = 'talk';
925 
926  if ( $userCanRead ) {
927  // Adds "view" view link
928  if ( $title->isKnown() ) {
929  $content_navigation['views']['view'] = $this->tabAction(
930  $isTalk ? $talkPage : $subjectPage,
931  [ "$skname-view-view", 'view' ],
932  ( $onPage && ( $action == 'view' || $action == 'purge' ) ), '', true
933  );
934  // signal to hide this from simple content_actions
935  $content_navigation['views']['view']['redundant'] = true;
936  }
937 
938  $page = $this->canUseWikiPage() ? $this->getWikiPage() : false;
939  $isRemoteContent = $page && !$page->isLocal();
940 
941  // If it is a non-local file, show a link to the file in its own repository
942  // @todo abstract this for remote content that isn't a file
943  if ( $isRemoteContent ) {
944  $content_navigation['views']['view-foreign'] = [
945  'class' => '',
946  'text' => wfMessageFallback( "$skname-view-foreign", 'view-foreign' )->
947  setContext( $this->getContext() )->
948  params( $page->getWikiDisplayName() )->text(),
949  'href' => $page->getSourceURL(),
950  'primary' => false,
951  ];
952  }
953 
954  // Checks if user can edit the current page if it exists or create it otherwise
955  if ( $permissionManager->quickUserCan( 'edit', $user, $title ) &&
956  ( $title->exists() ||
957  $permissionManager->quickUserCan( 'create', $user, $title ) )
958  ) {
959  // Builds CSS class for talk page links
960  $isTalkClass = $isTalk ? ' istalk' : '';
961  // Whether the user is editing the page
962  $isEditing = $onPage && ( $action == 'edit' || $action == 'submit' );
963  // Whether to show the "Add a new section" tab
964  // Checks if this is a current rev of talk page and is not forced to be hidden
965  $showNewSection = !$out->forceHideNewSectionLink()
966  && ( ( $isTalk && $out->isRevisionCurrent() ) || $out->showNewSectionLink() );
967  $section = $request->getVal( 'section' );
968 
969  if ( $title->exists()
970  || ( $title->inNamespace( NS_MEDIAWIKI )
971  && $title->getDefaultMessageText() !== false
972  )
973  ) {
974  $msgKey = $isRemoteContent ? 'edit-local' : 'edit';
975  } else {
976  $msgKey = $isRemoteContent ? 'create-local' : 'create';
977  }
978  $content_navigation['views']['edit'] = [
979  'class' => ( $isEditing && ( $section !== 'new' || !$showNewSection )
980  ? 'selected'
981  : ''
982  ) . $isTalkClass,
983  'text' => wfMessageFallback( "$skname-view-$msgKey", $msgKey )
984  ->setContext( $this->getContext() )->text(),
985  'href' => $title->getLocalURL( $this->editUrlOptions() ),
986  'primary' => !$isRemoteContent, // don't collapse this in vector
987  ];
988 
989  // section link
990  if ( $showNewSection ) {
991  // Adds new section link
992  // $content_navigation['actions']['addsection']
993  $content_navigation['views']['addsection'] = [
994  'class' => ( $isEditing && $section == 'new' ) ? 'selected' : false,
995  'text' => wfMessageFallback( "$skname-action-addsection", 'addsection' )
996  ->setContext( $this->getContext() )->text(),
997  'href' => $title->getLocalURL( 'action=edit&section=new' )
998  ];
999  }
1000  // Checks if the page has some kind of viewable source content
1001  } elseif ( $title->hasSourceText() ) {
1002  // Adds view source view link
1003  $content_navigation['views']['viewsource'] = [
1004  'class' => ( $onPage && $action == 'edit' ) ? 'selected' : false,
1005  'text' => wfMessageFallback( "$skname-action-viewsource", 'viewsource' )
1006  ->setContext( $this->getContext() )->text(),
1007  'href' => $title->getLocalURL( $this->editUrlOptions() ),
1008  'primary' => true, // don't collapse this in vector
1009  ];
1010  }
1011 
1012  // Checks if the page exists
1013  if ( $title->exists() ) {
1014  // Adds history view link
1015  $content_navigation['views']['history'] = [
1016  'class' => ( $onPage && $action == 'history' ) ? 'selected' : false,
1017  'text' => wfMessageFallback( "$skname-view-history", 'history_short' )
1018  ->setContext( $this->getContext() )->text(),
1019  'href' => $title->getLocalURL( 'action=history' ),
1020  ];
1021 
1022  if ( $permissionManager->quickUserCan( 'delete', $user, $title ) ) {
1023  $content_navigation['actions']['delete'] = [
1024  'class' => ( $onPage && $action == 'delete' ) ? 'selected' : false,
1025  'text' => wfMessageFallback( "$skname-action-delete", 'delete' )
1026  ->setContext( $this->getContext() )->text(),
1027  'href' => $title->getLocalURL( 'action=delete' )
1028  ];
1029  }
1030 
1031  if ( $permissionManager->quickUserCan( 'move', $user, $title ) ) {
1032  $moveTitle = SpecialPage::getTitleFor( 'Movepage', $title->getPrefixedDBkey() );
1033  $content_navigation['actions']['move'] = [
1034  'class' => $this->getTitle()->isSpecial( 'Movepage' ) ? 'selected' : false,
1035  'text' => wfMessageFallback( "$skname-action-move", 'move' )
1036  ->setContext( $this->getContext() )->text(),
1037  'href' => $moveTitle->getLocalURL()
1038  ];
1039  }
1040  } else {
1041  // article doesn't exist or is deleted
1042  if ( $permissionManager->quickUserCan( 'deletedhistory', $user, $title ) ) {
1043  $n = $title->isDeleted();
1044  if ( $n ) {
1045  $undelTitle = SpecialPage::getTitleFor( 'Undelete', $title->getPrefixedDBkey() );
1046  // If the user can't undelete but can view deleted
1047  // history show them a "View .. deleted" tab instead.
1048  $msgKey = $permissionManager->quickUserCan( 'undelete',
1049  $user, $title ) ? 'undelete' : 'viewdeleted';
1050  $content_navigation['actions']['undelete'] = [
1051  'class' => $this->getTitle()->isSpecial( 'Undelete' ) ? 'selected' : false,
1052  'text' => wfMessageFallback( "$skname-action-$msgKey", "{$msgKey}_short" )
1053  ->setContext( $this->getContext() )->numParams( $n )->text(),
1054  'href' => $undelTitle->getLocalURL()
1055  ];
1056  }
1057  }
1058  }
1059 
1060  if ( $permissionManager->quickUserCan( 'protect', $user, $title ) &&
1061  $title->getRestrictionTypes() &&
1062  $permissionManager->getNamespaceRestrictionLevels( $title->getNamespace(), $user ) !== [ '' ]
1063  ) {
1064  $mode = $title->isProtected() ? 'unprotect' : 'protect';
1065  $content_navigation['actions'][$mode] = [
1066  'class' => ( $onPage && $action == $mode ) ? 'selected' : false,
1067  'text' => wfMessageFallback( "$skname-action-$mode", $mode )
1068  ->setContext( $this->getContext() )->text(),
1069  'href' => $title->getLocalURL( "action=$mode" )
1070  ];
1071  }
1072 
1073  // Checks if the user is logged in
1074  if ( $this->loggedin && $permissionManager->userHasAllRights( $user,
1075  'viewmywatchlist', 'editmywatchlist' )
1076  ) {
1086  $mode = $user->isWatched( $title ) ? 'unwatch' : 'watch';
1087 
1088  // Add the watch/unwatch link.
1089  $content_navigation['actions'][$mode] = $this->getWatchLinkAttrs(
1090  $mode,
1091  $user,
1092  $title,
1093  $action,
1094  $onPage
1095  );
1096  }
1097  }
1098 
1099  $this->getHookRunner()->onSkinTemplateNavigation( $this, $content_navigation );
1100 
1101  if ( $userCanRead && !$this->getConfig()->get( 'DisableLangConversion' ) ) {
1102  $pageLang = $title->getPageLanguage();
1103  $converter = MediaWikiServices::getInstance()
1104  ->getLanguageConverterFactory()
1105  ->getLanguageConverter( $pageLang );
1106  // Checks that language conversion is enabled and variants exist
1107  // And if it is not in the special namespace
1108  if ( $converter->hasVariants() ) {
1109  // Gets list of language variants
1110  $variants = $converter->getVariants();
1111  // Gets preferred variant (note that user preference is
1112  // only possible for wiki content language variant)
1113  $preferred = $converter->getPreferredVariant();
1114  if ( Action::getActionName( $this ) === 'view' ) {
1115  $params = $request->getQueryValues();
1116  unset( $params['title'] );
1117  } else {
1118  $params = [];
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'][] = [
1126  'class' => ( $code == $preferred ) ? 'selected' : false,
1127  'text' => $varname,
1128  'href' => $title->getLocalURL( [ 'variant' => $code ] + $params ),
1129  'lang' => LanguageCode::bcp47( $code ),
1130  'hreflang' => LanguageCode::bcp47( $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'] = [
1138  'class' => 'selected',
1139  'text' => $this->msg( 'nstab-special' )->text(),
1140  'href' => $request->getRequestURL(), // @see: T4457, T4510
1141  'context' => 'subject'
1142  ];
1143 
1144  $this->getHookRunner()->onSkinTemplateNavigation__SpecialPage(
1145  $this, $content_navigation );
1146  }
1147 
1148  // Equiv to SkinTemplateContentActions
1149  $this->getHookRunner()->onSkinTemplateNavigation__Universal(
1150  $this, $content_navigation );
1151 
1152  // Setup xml ids and tooltip info
1153  foreach ( $content_navigation as $section => &$links ) {
1154  foreach ( $links as $key => &$link ) {
1155  $xmlID = $key;
1156  if ( isset( $link['context'] ) && $link['context'] == 'subject' ) {
1157  $xmlID = 'ca-nstab-' . $xmlID;
1158  } elseif ( isset( $link['context'] ) && $link['context'] == 'talk' ) {
1159  $xmlID = 'ca-talk';
1160  $link['rel'] = 'discussion';
1161  } elseif ( $section == 'variants' ) {
1162  $xmlID = 'ca-varlang-' . $xmlID;
1163  } else {
1164  $xmlID = 'ca-' . $xmlID;
1165  }
1166  $link['id'] = $xmlID;
1167  }
1168  }
1169 
1170  # We don't want to give the watch tab an accesskey if the
1171  # page is being edited, because that conflicts with the
1172  # accesskey on the watch checkbox. We also don't want to
1173  # give the edit tab an accesskey, because that's fairly
1174  # superfluous and conflicts with an accesskey (Ctrl-E) often
1175  # used for editing in Safari.
1176  if ( in_array( $action, [ 'edit', 'submit' ] ) ) {
1177  if ( isset( $content_navigation['views']['edit'] ) ) {
1178  $content_navigation['views']['edit']['tooltiponly'] = true;
1179  }
1180  if ( isset( $content_navigation['actions']['watch'] ) ) {
1181  $content_navigation['actions']['watch']['tooltiponly'] = true;
1182  }
1183  if ( isset( $content_navigation['actions']['unwatch'] ) ) {
1184  $content_navigation['actions']['unwatch']['tooltiponly'] = true;
1185  }
1186  }
1187 
1188  return $content_navigation;
1189  }
1190 
1196  private function buildContentActionUrls( $content_navigation ) {
1197  // content_actions has been replaced with content_navigation for backwards
1198  // compatibility and also for skins that just want simple tabs content_actions
1199  // is now built by flattening the content_navigation arrays into one
1200 
1201  $content_actions = [];
1202 
1203  foreach ( $content_navigation as $links ) {
1204  foreach ( $links as $key => $value ) {
1205  if ( isset( $value['redundant'] ) && $value['redundant'] ) {
1206  // Redundant tabs are dropped from content_actions
1207  continue;
1208  }
1209 
1210  // content_actions used to have ids built using the "ca-$key" pattern
1211  // so the xmlID based id is much closer to the actual $key that we want
1212  // for that reason we'll just strip out the ca- if present and use
1213  // the latter potion of the "id" as the $key
1214  if ( isset( $value['id'] ) && substr( $value['id'], 0, 3 ) == 'ca-' ) {
1215  $key = substr( $value['id'], 3 );
1216  }
1217 
1218  if ( isset( $content_actions[$key] ) ) {
1219  wfDebug( __METHOD__ . ": Found a duplicate key for $key while flattening " .
1220  "content_navigation into content_actions." );
1221  continue;
1222  }
1223 
1224  $content_actions[$key] = $value;
1225  }
1226  }
1227 
1228  return $content_actions;
1229  }
1230 
1237  protected function buildNavUrls() {
1238  $navUrls = parent::buildNavUrls();
1239  $out = $this->getOutput();
1240  if ( !$out->isArticle() ) {
1241  return $navUrls;
1242  }
1243  $modifiedNavUrls = [];
1244  foreach ( $navUrls as $key => $url ) {
1245  $modifiedNavUrls[$key] = $url;
1246  if ( $key === 'permalink' ) {
1247  $revid = $out->getRevisionId();
1248  // Use the copy of revision ID in case this undocumented,
1249  // shady hook tries to mess with internals.
1250  $this->getHookRunner()->onSkinTemplateBuildNavUrlsNav_urlsAfterPermalink(
1251  $this, $modifiedNavUrls, $revid, $revid
1252  );
1253  }
1254  }
1255  return $modifiedNavUrls;
1256  }
1257 
1263  protected function getNameSpaceKey() {
1264  return $this->getTitle()->getNamespaceKey();
1265  }
1266 }
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:152
SkinTemplate\makePersonalToolsList
makePersonalToolsList( $personalTools=null, $options=[])
Get the HTML for the personal tools list Please ensure setupTemplateContext is called before calling ...
Definition: SkinTemplate.php:491
ContextSource\getConfig
getConfig()
Definition: ContextSource.php:63
Skin\editUrlOptions
editUrlOptions()
Return URL options for the 'edit page' link.
Definition: Skin.php:1119
SkinTemplate\setupTemplateForOutput
setupTemplateForOutput()
Definition: SkinTemplate.php:73
$wgMaxCredits
$wgMaxCredits
Set this to the number of authors that you want to be credited below an article text.
Definition: DefaultSettings.php:7585
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:329
Skin\makeUrlDetails
static makeUrlDetails( $name, $urlaction='')
these return an array with the 'href' and boolean 'exists'
Definition: Skin.php:1272
ContextSource\getContext
getContext()
Get the base IContextSource object.
Definition: ContextSource.php:40
Skin\getSiteNotice
getSiteNotice()
Get the site notice.
Definition: Skin.php:1924
wfMessageFallback
wfMessageFallback(... $keys)
This function accepts multiple message keys and returns a message instance for the first message whic...
Definition: GlobalFunctions.php:1245
Skin\buildFeedUrls
buildFeedUrls()
Build data structure representing syndication links.
Definition: Skin.php:1570
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:66
Skin\$options
array $options
Skin options passed into constructor.
Definition: Skin.php:51
SkinTemplate\buildContentNavigationUrls
buildContentNavigationUrls()
a structured array of links usually used for the tabs in a skin
Definition: SkinTemplate.php:867
Skin\getPoweredBy
getPoweredBy()
Gets the powered by MediaWiki icon.
Definition: Skin.php:899
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:152
true
return true
Definition: router.php:90
Skin\lastModified
lastModified()
Get the timestamp of the latest revision, formatted in user language.
Definition: Skin.php:922
Skin\getSiteFooterLinks
getSiteFooterLinks()
Gets the link to the wiki's privacy policy, about page, and disclaimer page.
Definition: Skin.php:1057
$wgShowCreditsIfMax
$wgShowCreditsIfMax
If there are more than $wgMaxCredits authors, show $wgMaxCredits of them.
Definition: DefaultSettings.php:7591
Skin\checkTitle
static checkTitle(&$title, $name)
make sure we have some title to operate on
Definition: Skin.php:1304
SkinTemplate\$userpageUrlDetails
$userpageUrlDetails
Definition: SkinTemplate.php:56
Skin\makeSpecialUrl
static makeSpecialUrl( $name, $urlaction='', $proto=null)
Make a URL for a Special Page using the given query and protocol.
Definition: Skin.php:1191
NS_FILE
const NS_FILE
Definition: Defines.php:75
SkinTemplate\$titletxt
$titletxt
Definition: SkinTemplate.php:51
Skin\makeSpecialUrlSubpage
static makeSpecialUrlSubpage( $name, $subpage, $urlaction='')
Definition: Skin.php:1206
SkinTemplate\$thispage
$thispage
Definition: SkinTemplate.php:50
SkinTemplate\getFooterLinks
getFooterLinks()
Get template representation of the footer containing site footer links as well as standard footer lin...
Definition: SkinTemplate.php:256
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:90
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:162
Action\factory
static factory(?string $action, Page $article, IContextSource $context=null)
Get an appropriate Action subclass for the given action.
Definition: Action.php:113
ContextSource\getUser
getUser()
Definition: ContextSource.php:120
ContextSource\getTitle
getTitle()
Definition: ContextSource.php:79
SkinTemplate\getWatchLinkAttrs
getWatchLinkAttrs(string $mode, User $user, Title $title, ?string $action, bool $onPage)
Get the attributes for the watch link.
Definition: SkinTemplate.php:806
Skin\makeListItem
makeListItem( $key, $item, $options=[])
Generates a list item for a navigation, portlet, portal, sidebar...
Definition: Skin.php:2319
Skin\bottomScripts
bottomScripts()
This gets called shortly before the "</body>" tag.
Definition: Skin.php:671
SkinTemplate\$userpage
$userpage
Definition: SkinTemplate.php:52
Skin\afterContentHook
afterContentHook()
This runs a hook to allow extensions placing their stuff after content and article metadata (e....
Definition: Skin.php:636
ContextSource\getLanguage
getLanguage()
Definition: ContextSource.php:128
NS_SPECIAL
const NS_SPECIAL
Definition: Defines.php:58
SkinTemplate\getPersonalToolsList
getPersonalToolsList()
Get the HTML for the p-personal list.
Definition: SkinTemplate.php:477
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:1305
Article\newFromWikiPage
static newFromWikiPage(WikiPage $page, IContextSource $context)
Create an Article object of the appropriate class for the given page.
Definition: Article.php:226
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:42
Skin\buildSidebar
buildSidebar()
Build an array that represents the sidebar(s), the navigation bar among them.
Definition: Skin.php:1608
wfDeprecated
wfDeprecated( $function, $version=false, $component=false, $callerOffset=2)
Logs a warning that $function is deprecated.
Definition: GlobalFunctions.php:1029
SkinTemplate\buildNavUrls
buildNavUrls()
build array of common navigation links and run the SkinTemplateBuildNavUrlsNav_urlsAfterPermalink hoo...
Definition: SkinTemplate.php:1237
SkinTemplate\getFooterIcons
getFooterIcons()
Get template representation of the footer.
Definition: SkinTemplate.php:224
Skin\generateDebugHTML
generateDebugHTML()
Generate debug data HTML for displaying at the bottom of the main content area.
Definition: Skin.php:662
SkinTemplate\tabAction
tabAction( $title, $message, $selected, $query='', $checkEdit=false)
Builds an array with tab definition.
Definition: SkinTemplate.php:705
Skin\getCategories
getCategories()
Definition: Skin.php:603
SkinTemplate\buildContentActionUrls
buildContentActionUrls( $content_navigation)
an array of edit links by default used for the tabs
Definition: SkinTemplate.php:1196
ContextSource\getOutput
getOutput()
Definition: ContextSource.php:112
User\isTempWatched
isTempWatched( $title, $checkRights=self::CHECK_USER_RIGHTS)
Check if the article is temporarily watched.
Definition: User.php:3246
ContextSource\getWikiPage
getWikiPage()
Get the WikiPage object.
Definition: ContextSource.php:104
ContextSource\getSkin
getSkin()
Definition: ContextSource.php:136
SkinTemplate\$username
$username
Definition: SkinTemplate.php:55
wfCgiToArray
wfCgiToArray( $query)
This is the logical opposite of wfArrayToCgi(): it accepts a query string as its argument and returns...
Definition: GlobalFunctions.php:391
Skin\getLanguages
getLanguages()
Generates array of language links for the current page.
Definition: Skin.php:1334
SkinTemplate\$loggedin
$loggedin
Definition: SkinTemplate.php:54
$title
$title
Definition: testCompression.php:38
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:912
ContextSource\setContext
setContext(IContextSource $context)
Definition: ContextSource.php:55
ResourceLoaderSkinModule\getAvailableLogos
static getAvailableLogos( $conf)
Return an array of all available logos that a skin may use.
Definition: ResourceLoaderSkinModule.php:319
SkinTemplate\getStructuredPersonalTools
getStructuredPersonalTools()
Get personal tools for the user.
Definition: SkinTemplate.php:515
SkinTemplate\$thisquery
$thisquery
Definition: SkinTemplate.php:53
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:314
SkinTemplate\setupTemplateContext
setupTemplateContext()
Setup class properties that are necessary prior to calling setupTemplateForOutput.
Definition: SkinTemplate.php:88
Skin\getRelevantTitle
getRelevantTitle()
Return the "relevant" title.
Definition: Skin.php:353
SkinTemplate\$template
string $template
For QuickTemplate, the name of the subclass which will actually fill the template.
Definition: SkinTemplate.php:48
Skin\getSearchLink
getSearchLink()
Definition: Skin.php:817
Skin\getPersonalToolsForMakeListItem
getPersonalToolsForMakeListItem( $urls)
Create an array of personal tools items from the data in the quicktemplate stored by SkinTemplate.
Definition: Skin.php:2125
Skin\printSource
printSource()
Text with the permalink to the source page, usually shown on the footer of a printed page.
Definition: Skin.php:693
SkinTemplate\makeArticleUrlDetails
makeArticleUrlDetails( $name, $urlaction='')
Definition: SkinTemplate.php:786
SkinTemplate\outputPage
outputPage()
Initialize various variables and generate the template.
Definition: SkinTemplate.php:133
SkinTemplate\makeTalkUrlDetails
makeTalkUrlDetails( $name, $urlaction='')
Definition: SkinTemplate.php:767
Skin\logoText
logoText( $align='')
Definition: Skin.php:953
Skin\getNewtalks
getNewtalks()
Gets new talk page messages for the current user and returns an appropriate alert message (or an empt...
Definition: Skin.php:1768
SkinTemplate\getNameSpaceKey
getNameSpaceKey()
Generate strings used for xml 'id' names.
Definition: SkinTemplate.php:1263
Title
Represents a title within MediaWiki.
Definition: Title.php:42
SkinTemplate\prepareUserLanguageAttributes
prepareUserLanguageAttributes()
Prepare user language attribute links.
Definition: SkinTemplate.php:201
SkinTemplate\getJsConfigVars
getJsConfigVars()
Returns array of config variables that should be added only to this skin for use in JavaScript.
Definition: SkinTemplate.php:151
Title\isSpecialPage
isSpecialPage()
Returns true if this is a special page.
Definition: Title.php:1241
LanguageCode\bcp47
static bcp47( $code)
Get the normalised IETF language tag See unit test for examples.
Definition: LanguageCode.php:175
Skin\getCopyright
getCopyright( $type='detect')
Definition: Skin.php:826
Html\rawElement
static rawElement( $element, $attribs=[], $contents='')
Returns an HTML element in a string.
Definition: Html.php:209
Skin\subPageSubtitle
subPageSubtitle( $out=null)
Definition: Skin.php:760
Skin\getUndeleteLink
getUndeleteLink()
Definition: Skin.php:712
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:1288
CreditsAction
Definition: CreditsAction.php:31
NS_MEDIAWIKI
const NS_MEDIAWIKI
Definition: Defines.php:77
Skin\getCopyrightIcon
getCopyrightIcon()
Definition: Skin.php:869
SkinTemplate\prepareUndeleteLink
prepareUndeleteLink()
Prepare undelete link for output in page.
Definition: SkinTemplate.php:303
Skin
The main skin class which provides methods and properties for all other skins.
Definition: Skin.php:40
Skin\initPage
initPage(OutputPage $out)
Definition: Skin.php:174
User
The User object encapsulates all of the user-specific settings (user_id, name, rights,...
Definition: User.php:54
SkinTemplate\prepareSubtitle
prepareSubtitle()
Prepare the subtitle of the page for output in the skin if one has been set.
Definition: SkinTemplate.php:187
SkinTemplate
Base class for template-based skins.
Definition: SkinTemplate.php:37
SkinTemplate\generateHTML
generateHTML()
Subclasses not wishing to use the QuickTemplate render method can rewrite this method,...
Definition: SkinTemplate.php:124
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:346
SkinTemplate\buildPersonalUrls
buildPersonalUrls()
build array of urls for personal toolbar Please ensure setupTemplateContext is called before calling ...
Definition: SkinTemplate.php:529