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