MediaWiki  master
SkinTemplate.php
Go to the documentation of this file.
1 <?php
22 
39 class SkinTemplate extends Skin {
44  public $template;
45 
46  public $thispage;
47  public $titletxt;
48  public $userpage;
49  public $thisquery;
50  // TODO: Rename this to $isRegistered (but that's a breaking change)
51  public $loggedin;
52  public $username;
54 
63  protected function setupTemplate( $classname ) {
64  return new $classname( $this->getConfig() );
65  }
66 
70  protected function setupTemplateForOutput() {
71  $this->setupTemplateContext();
72  $template = $this->options['template'] ?? $this->template;
73  if ( !$template ) {
74  throw new RuntimeException(
75  'SkinTemplate skins must define a `template` either as a public'
76  . ' property of by passing in a`template` option to the constructor.'
77  );
78  }
79  $tpl = $this->setupTemplate( $template );
80  return $tpl;
81  }
82 
92  final protected function setupTemplateContext() {
93  $request = $this->getRequest();
94  $user = $this->getUser();
95  $title = $this->getTitle();
96 
97  $this->thispage = $title->getPrefixedDBkey();
98  $this->titletxt = $title->getPrefixedText();
99  $this->userpage = $user->getUserPage()->getPrefixedText();
100  $query = [];
101  if ( !$request->wasPosted() ) {
102  $query = $request->getValues();
103  unset( $query['title'] );
104  unset( $query['returnto'] );
105  unset( $query['returntoquery'] );
106  }
107  $this->thisquery = wfArrayToCgi( $query );
108  $this->loggedin = $user->isRegistered();
109  $this->username = $user->getName();
110 
111  if ( $this->loggedin ) {
112  $this->userpageUrlDetails = self::makeUrlDetails( $this->userpage );
113  } else {
114  # This won't be used in the standard skins, but we define it to preserve the interface
115  # To save time, we check for existence
116  $this->userpageUrlDetails = self::makeKnownUrlDetails( $this->userpage );
117  }
118  }
119 
128  public function generateHTML() {
129  $tpl = $this->prepareQuickTemplate();
130  // execute template
131  return $tpl->execute();
132  }
133 
138  public function outputPage() {
139  Profiler::instance()->setAllowOutput();
140  $out = $this->getOutput();
141 
142  $this->initPage( $out );
143  $out->addJsConfigVars( $this->getJsConfigVars() );
144 
145  // result may be an error
146  echo $this->generateHTML();
147  }
148 
156  protected function getJsConfigVars() : array {
157  return [];
158  }
159 
167  protected function wrapHTML( $title, $html ) {
168  # An ID that includes the actual body text; without categories, contentSub, ...
169  $realBodyAttribs = [ 'id' => 'mw-content-text' ];
170 
171  # Add a mw-content-ltr/rtl class to be able to style based on text
172  # direction when the content is different from the UI language (only
173  # when viewing)
174  # Most information on special pages and file pages is in user language,
175  # rather than content language, so those will not get this
176  if ( Action::getActionName( $this ) === 'view' &&
177  ( !$title->inNamespaces( NS_SPECIAL, NS_FILE ) || $title->isRedirect() ) ) {
178  $pageLang = $title->getPageViewLanguage();
179  $realBodyAttribs['lang'] = $pageLang->getHtmlCode();
180  $realBodyAttribs['dir'] = $pageLang->getDir();
181  $realBodyAttribs['class'] = 'mw-content-' . $pageLang->getDir();
182  }
183 
184  return Html::rawElement( 'div', $realBodyAttribs, $html );
185  }
186 
192  final protected function prepareUserLanguageAttributes() {
193  $userLang = $this->getLanguage();
194  $userLangCode = $userLang->getHtmlCode();
195  $userLangDir = $userLang->getDir();
196  $contLang = MediaWikiServices::getInstance()->getContentLanguage();
197  if (
198  $userLangCode !== $contLang->getHtmlCode() ||
199  $userLangDir !== $contLang->getDir()
200  ) {
201  $escUserlang = htmlspecialchars( $userLangCode );
202  $escUserdir = htmlspecialchars( $userLangDir );
203  // Attributes must be in double quotes because htmlspecialchars() doesn't
204  // escape single quotes
205  return " lang=\"$escUserlang\" dir=\"$escUserdir\"";
206  }
207  return '';
208  }
209 
215  protected function getFooterIcons() {
216  $config = $this->getConfig();
217 
218  $footericons = [];
219  foreach ( $config->get( 'FooterIcons' ) as $footerIconsKey => &$footerIconsBlock ) {
220  if ( count( $footerIconsBlock ) > 0 ) {
221  $footericons[$footerIconsKey] = [];
222  foreach ( $footerIconsBlock as &$footerIcon ) {
223  if ( isset( $footerIcon['src'] ) ) {
224  if ( !isset( $footerIcon['width'] ) ) {
225  $footerIcon['width'] = 88;
226  }
227  if ( !isset( $footerIcon['height'] ) ) {
228  $footerIcon['height'] = 31;
229  }
230  }
231 
232  // Only output icons which have an image.
233  // For historic reasons this mimics the `icononly` option
234  // for BaseTemplate::getFooterIcons.
235  // In some cases the icon may be an empty array.
236  // Filter these out. (See T269776)
237  if ( is_string( $footerIcon ) || isset( $footerIcon['src'] ) ) {
238  $footericons[$footerIconsKey][] = $footerIcon;
239  }
240  }
241  }
242  }
243  return $footericons;
244  }
245 
251  final protected function prepareUndeleteLink() {
252  $undelete = $this->getUndeleteLink();
253  return $undelete === '' ? null : '<span class="subpages">' . $undelete . '</span>';
254  }
255 
262  protected function prepareQuickTemplate() {
263  $title = $this->getTitle();
264  $request = $this->getRequest();
265  $out = $this->getOutput();
266  $config = $this->getConfig();
267  $tpl = $this->setupTemplateForOutput();
268 
269  $tpl->set( 'title', $out->getPageTitle() );
270  $tpl->set( 'pagetitle', $out->getHTMLTitle() );
271  $tpl->set( 'displaytitle', $out->mPageLinkTitle );
272 
273  $tpl->set( 'thispage', $this->thispage );
274  $tpl->set( 'titleprefixeddbkey', $this->thispage );
275  $tpl->set( 'titletext', $title->getText() );
276  $tpl->set( 'articleid', $title->getArticleID() );
277 
278  $tpl->set( 'isarticle', $out->isArticle() );
279 
280  $tpl->set( 'subtitle', $this->prepareSubtitle() );
281  $tpl->set( 'undelete', $this->prepareUndeleteLink() );
282 
283  $tpl->set( 'catlinks', $this->getCategories() );
284  $feeds = $this->buildFeedUrls();
285  $tpl->set( 'feeds', count( $feeds ) ? $feeds : false );
286 
287  $tpl->set( 'mimetype', $config->get( 'MimeType' ) );
288  $tpl->set( 'charset', 'UTF-8' );
289  $tpl->set( 'wgScript', $config->get( 'Script' ) );
290  $tpl->set( 'skinname', $this->skinname );
291  $tpl->set( 'skinclass', static::class );
292  $tpl->set( 'skin', $this );
293  $tpl->set( 'stylename', $this->stylename );
294  $tpl->set( 'printable', $out->isPrintable() );
295  $tpl->set( 'handheld', $request->getBool( 'handheld' ) );
296  $tpl->set( 'loggedin', $this->loggedin );
297  $tpl->set( 'notspecialpage', !$title->isSpecialPage() );
298 
299  // Deprecated since 1.36
300  $searchLink = SpecialPage::getTitleFor( 'Search' )->getLocalURL();
301  $tpl->set( 'searchaction', $searchLink );
302 
303  $tpl->set( 'searchtitle', SpecialPage::getTitleFor( 'Search' )->getPrefixedDBkey() );
304  $tpl->set( 'search', trim( $request->getVal( 'search' ) ) );
305  $tpl->set( 'stylepath', $config->get( 'StylePath' ) );
306  $tpl->set( 'articlepath', $config->get( 'ArticlePath' ) );
307  $tpl->set( 'scriptpath', $config->get( 'ScriptPath' ) );
308  $tpl->set( 'serverurl', $config->get( 'Server' ) );
310  $tpl->set( 'logopath', $logos['1x'] );
311  $tpl->set( 'sitename', $config->get( 'Sitename' ) );
312 
313  $userLang = $this->getLanguage();
314  $userLangCode = $userLang->getHtmlCode();
315  $userLangDir = $userLang->getDir();
316 
317  $tpl->set( 'lang', $userLangCode );
318  $tpl->set( 'dir', $userLangDir );
319  $tpl->set( 'rtl', $userLang->isRTL() );
320 
321  $tpl->set( 'capitalizeallnouns', $userLang->capitalizeAllNouns() ? ' capitalize-all-nouns' : '' );
322  $tpl->set( 'showjumplinks', true ); // showjumplinks preference has been removed
323  $tpl->set( 'username', $this->loggedin ? $this->username : null );
324  $tpl->set( 'userpage', $this->userpage );
325  $tpl->set( 'userpageurl', $this->userpageUrlDetails['href'] );
326  $tpl->set( 'userlang', $userLangCode );
327 
328  // Users can have their language set differently than the
329  // content of the wiki. For these users, tell the web browser
330  // that interface elements are in a different language.
331  $tpl->set( 'userlangattributes', $this->prepareUserLanguageAttributes() );
332  $tpl->set( 'specialpageattributes', '' ); # obsolete
333  // Used by VectorBeta to insert HTML before content but after the
334  // heading for the page title. Defaults to empty string.
335  $tpl->set( 'prebodyhtml', '' );
336 
337  $tpl->set( 'newtalk', $this->getNewtalks() );
338  $tpl->set( 'logo', $this->logoText() );
339 
340  $footerData = $this->getFooterLinks();
341  $tpl->set( 'copyright', $footerData['info']['copyright'] ?? false );
342  // No longer used
343  $tpl->set( 'viewcount', false );
344  $tpl->set( 'lastmod', $footerData['info']['lastmod'] ?? false );
345  $tpl->set( 'credits', $footerData['info']['credits'] ?? false );
346  $tpl->set( 'numberofwatchingusers', false );
347 
348  $tpl->set( 'copyrightico', $this->getCopyrightIcon() );
349  $tpl->set( 'poweredbyico', $this->getPoweredBy() );
350 
351  $tpl->set( 'disclaimer', $footerData['places']['disclaimer'] ?? false );
352  $tpl->set( 'privacy', $footerData['places']['privacy'] ?? false );
353  $tpl->set( 'about', $footerData['places']['about'] ?? false );
354 
355  // Flatten for compat with the 'footerlinks' key in QuickTemplate-based skins.
356  $flattenedfooterlinks = [];
357  foreach ( $footerData as $category => $links ) {
358  $flattenedfooterlinks[$category] = array_keys( $links );
359  foreach ( $links as $key => $value ) {
360  // For full support with BaseTemplate we also need to
361  // copy over the keys.
362  $tpl->set( $key, $value );
363  }
364  }
365  $tpl->set( 'footerlinks', $flattenedfooterlinks );
366  $tpl->set( 'footericons', $this->getFooterIcons() );
367 
368  $tpl->set( 'indicators', $out->getIndicators() );
369 
370  $tpl->set( 'sitenotice', $this->getSiteNotice() );
371  $tpl->set( 'printfooter', $this->printSource() );
372  // Wrap the bodyText with #mw-content-text element
373  $tpl->set( 'bodytext', $this->wrapHTML( $title, $out->getHTML() ) );
374 
375  $tpl->set( 'language_urls', $this->getLanguages() ?: false );
376 
377  $content_navigation = $this->buildContentNavigationUrls();
378  # Personal toolbar
379  $tpl->set( 'personal_urls', $this->insertNotificationsIntoPersonalTools( $content_navigation ) );
380  // user-menu and notifications are new content navigation entries and aren't expected
381  // to be part of content_navigation or content_actions. Adding them in there breaks skins
382  // that do not expect it.
383  unset( $content_navigation['user-menu'], $content_navigation['notifications'] );
384  $content_actions = $this->buildContentActionUrls( $content_navigation );
385  $tpl->set( 'content_navigation', $content_navigation );
386  $tpl->set( 'content_actions', $content_actions );
387 
388  $tpl->set( 'sidebar', $this->buildSidebar() );
389  $tpl->set( 'nav_urls', $this->buildNavUrls() );
390 
391  // Do this last in case hooks above add bottom scripts
392  $tpl->set( 'bottomscripts', $this->bottomScripts() );
393 
394  // Set the head scripts near the end, in case the above actions resulted in added scripts
395  $tpl->set( 'headelement', $out->headElement( $this ) );
396 
397  $tpl->set( 'debug', '' );
398  $tpl->set( 'debughtml', MWDebug::getHTMLDebugLog() );
399  $tpl->set( 'reporttime', wfReportTime( $out->getCSP()->getNonce() ) );
400 
401  // original version by hansm
402  // See T60137 for information on deprecation.
403  if ( !$this->getHookRunner()->onSkinTemplateOutputPageBeforeExec( $this, $tpl ) ) {
404  wfDebug( __METHOD__ . ": Hook SkinTemplateOutputPageBeforeExec broke outputPage execution!" );
405  }
406 
407  // Set the bodytext to another key so that skins can just output it on its own
408  // and output printfooter and debughtml separately
409  $tpl->set( 'bodycontent', $tpl->data['bodytext'] );
410 
411  // Append printfooter and debughtml onto bodytext so that skins that
412  // were already using bodytext before they were split out don't suddenly
413  // start not outputting information.
414  $tpl->data['bodytext'] .= Html::rawElement(
415  'div',
416  [ 'class' => 'printfooter' ],
417  "\n{$tpl->data['printfooter']}"
418  ) . "\n";
419  $tpl->data['bodytext'] .= $tpl->data['debughtml'];
420 
421  // allow extensions adding stuff after the page content.
422  // See Skin::afterContentHook() for further documentation.
423  $tpl->set( 'dataAfterContent', $this->afterContentHook() );
424 
425  return $tpl;
426  }
427 
433  public function getPersonalToolsList() {
434  return $this->makePersonalToolsList();
435  }
436 
447  public function makePersonalToolsList( $personalTools = null, $options = [] ) {
448  $this->setupTemplateContext();
449  $html = '';
450 
451  if ( $personalTools === null ) {
452  $personalTools = $this->getPersonalToolsForMakeListItem(
453  $this->buildPersonalUrls()
454  );
455  }
456 
457  foreach ( $personalTools as $key => $item ) {
458  $html .= $this->makeListItem( $key, $item, $options );
459  }
460 
461  return $html;
462  }
463 
471  public function getStructuredPersonalTools() {
472  // buildPersonalUrls requires the template context.
473  $this->setupTemplateContext();
474  return $this->getPersonalToolsForMakeListItem(
475  $this->buildPersonalUrls()
476  );
477  }
478 
486  protected function buildPersonalUrls( bool $includeNotifications = true ) {
487  $title = $this->getTitle();
488  $request = $this->getRequest();
489  $pageurl = $title->getLocalURL();
490  $services = MediaWikiServices::getInstance();
491  $authManager = $services->getAuthManager();
492  $permissionManager = $services->getPermissionManager();
493 
494  /* set up the default links for the personal toolbar */
495  $personal_urls = [];
496 
497  # Due to T34276, if a user does not have read permissions,
498  # $this->getTitle() will just give Special:Badtitle, which is
499  # not especially useful as a returnto parameter. Use the title
500  # from the request instead, if there was one.
501  if ( $this->getAuthority()->isAllowed( 'read' ) ) {
502  $page = $title;
503  } else {
504  $page = Title::newFromText( $request->getVal( 'title', '' ) );
505  }
506  $page = $request->getVal( 'returnto', $page );
507  $returnto = [];
508  if ( strval( $page ) !== '' ) {
509  $returnto['returnto'] = $page;
510  $query = $request->getVal( 'returntoquery', $this->thisquery );
511  $paramsArray = wfCgiToArray( $query );
512  $query = wfArrayToCgi( $paramsArray );
513  if ( $query != '' ) {
514  $returnto['returntoquery'] = $query;
515  }
516  }
517 
518  if ( $this->loggedin ) {
519  $personal_urls['userpage'] = [
520  'text' => $this->username,
521  'href' => &$this->userpageUrlDetails['href'],
522  'class' => $this->userpageUrlDetails['exists'] ? false : 'new',
523  'exists' => $this->userpageUrlDetails['exists'],
524  'active' => ( $this->userpageUrlDetails['href'] == $pageurl ),
525  'dir' => 'auto'
526  ];
527 
528  // Merge notifications into the personal menu for older skins.
529  if ( $includeNotifications ) {
530  $contentNavigation = $this->buildContentNavigationUrls();
531 
532  $personal_urls += $contentNavigation['notifications'];
533  }
534 
535  $usertalkUrlDetails = $this->makeTalkUrlDetails( $this->userpage );
536  $personal_urls['mytalk'] = [
537  'text' => $this->msg( 'mytalk' )->text(),
538  'href' => &$usertalkUrlDetails['href'],
539  'class' => $usertalkUrlDetails['exists'] ? false : 'new',
540  'exists' => $usertalkUrlDetails['exists'],
541  'active' => ( $usertalkUrlDetails['href'] == $pageurl )
542  ];
543  $href = self::makeSpecialUrl( 'Preferences' );
544  $personal_urls['preferences'] = [
545  'text' => $this->msg( 'mypreferences' )->text(),
546  'href' => $href,
547  'active' => ( $href == $pageurl )
548  ];
549 
550  if ( $this->getAuthority()->isAllowed( 'viewmywatchlist' ) ) {
551  $href = self::makeSpecialUrl( 'Watchlist' );
552  $personal_urls['watchlist'] = [
553  'text' => $this->msg( 'mywatchlist' )->text(),
554  'href' => $href,
555  'active' => ( $href == $pageurl )
556  ];
557  }
558 
559  # We need to do an explicit check for Special:Contributions, as we
560  # have to match both the title, and the target, which could come
561  # from request values (Special:Contributions?target=Jimbo_Wales)
562  # or be specified in "sub page" form
563  # (Special:Contributions/Jimbo_Wales). The plot
564  # thickens, because the Title object is altered for special pages,
565  # so it doesn't contain the original alias-with-subpage.
566  $origTitle = Title::newFromText( $request->getText( 'title' ) );
567  if ( $origTitle instanceof Title && $origTitle->isSpecialPage() ) {
568  list( $spName, $spPar ) =
569  MediaWikiServices::getInstance()->getSpecialPageFactory()->
570  resolveAlias( $origTitle->getText() );
571  $active = $spName == 'Contributions'
572  && ( ( $spPar && $spPar == $this->username )
573  || $request->getText( 'target' ) == $this->username );
574  } else {
575  $active = false;
576  }
577 
578  $href = self::makeSpecialUrlSubpage( 'Contributions', $this->username );
579  $personal_urls['mycontris'] = [
580  'text' => $this->msg( 'mycontris' )->text(),
581  'href' => $href,
582  'active' => $active
583  ];
584 
585  // if we can't set the user, we can't unset it either
586  if ( $request->getSession()->canSetUser() ) {
587  $personal_urls['logout'] = [
588  'text' => $this->msg( 'pt-userlogout' )->text(),
589  'data-mw' => 'interface',
590  'href' => self::makeSpecialUrl( 'Userlogout',
591  // Note: userlogout link must always contain an & character, otherwise we might not be able
592  // to detect a buggy precaching proxy (T19790)
593  ( $title->isSpecial( 'Preferences' ) ? [] : $returnto ) ),
594  'active' => false
595  ];
596  }
597  } else {
598  $useCombinedLoginLink = $this->getConfig()->get( 'UseCombinedLoginLink' );
599  if ( !$authManager->canCreateAccounts() || !$authManager->canAuthenticateNow() ) {
600  // don't show combined login/signup link if one of those is actually not available
601  $useCombinedLoginLink = false;
602  }
603 
604  $loginlink = $this->getAuthority()->isAllowed( 'createaccount' )
605  && $useCombinedLoginLink ? 'nav-login-createaccount' : 'pt-login';
606 
607  $login_url = [
608  'text' => $this->msg( $loginlink )->text(),
609  'href' => self::makeSpecialUrl( 'Userlogin', $returnto ),
610  'active' => $title->isSpecial( 'Userlogin' )
611  || $title->isSpecial( 'CreateAccount' ) && $useCombinedLoginLink,
612  ];
613  $createaccount_url = [
614  'text' => $this->msg( 'pt-createaccount' )->text(),
615  'href' => self::makeSpecialUrl( 'CreateAccount', $returnto ),
616  'active' => $title->isSpecial( 'CreateAccount' ),
617  ];
618 
619  // No need to show Talk and Contributions to anons if they can't contribute!
620  // TODO: easy way to get anon authority!
621  if ( $permissionManager->groupHasPermission( '*', 'edit' ) ) {
622  // Non interactive placeholder for anonymous users.
623  // It's unstyled by default (black color). Skin that
624  // needs it, can style it using the 'pt-anonuserpage' id.
625  // Skin that does not need it should unset it.
626  $personal_urls['anonuserpage'] = [
627  'text' => $this->msg( 'notloggedin' )->text(),
628  ];
629 
630  // Because of caching, we can't link directly to the IP talk and
631  // contributions pages. Instead we use the special page shortcuts
632  // (which work correctly regardless of caching). This means we can't
633  // determine whether these links are active or not, but since major
634  // skins (MonoBook, Vector) don't use this information, it's not a
635  // huge loss.
636  $personal_urls['anontalk'] = [
637  'text' => $this->msg( 'anontalk' )->text(),
638  'href' => self::makeSpecialUrlSubpage( 'Mytalk', false ),
639  'active' => false
640  ];
641  $personal_urls['anoncontribs'] = [
642  'text' => $this->msg( 'anoncontribs' )->text(),
643  'href' => self::makeSpecialUrlSubpage( 'Mycontributions', false ),
644  'active' => false
645  ];
646  }
647 
648  if (
649  $authManager->canCreateAccounts()
650  && $this->getAuthority()->isAllowed( 'createaccount' )
651  && !$useCombinedLoginLink
652  ) {
653  $personal_urls['createaccount'] = $createaccount_url;
654  }
655 
656  if ( $authManager->canAuthenticateNow() ) {
657  // TODO: easy way to get anon authority
658  $key = $permissionManager->groupHasPermission( '*', 'read' )
659  ? 'login'
660  : 'login-private';
661  $personal_urls[$key] = $login_url;
662  }
663  }
664 
665  $this->getHookRunner()->onPersonalUrls( $personal_urls, $title, $this );
666 
667  return $personal_urls;
668  }
669 
683  public function tabAction( $title, $message, $selected, $query = '', $checkEdit = false ) {
684  $classes = [];
685  if ( $selected ) {
686  $classes[] = 'selected';
687  }
688  $exists = true;
689  if ( $checkEdit && !$title->isKnown() ) {
690  $classes[] = 'new';
691  $exists = false;
692  if ( $query !== '' ) {
693  $query = 'action=edit&redlink=1&' . $query;
694  } else {
695  $query = 'action=edit&redlink=1';
696  }
697  }
698 
699  $services = MediaWikiServices::getInstance();
700  $linkClass = $services->getLinkRenderer()->getLinkClasses( $title );
701 
702  if ( $message instanceof MessageSpecifier ) {
703  $msg = new Message( $message );
704  $message = $message->getKey();
705  } else {
706  // wfMessageFallback will nicely accept $message as an array of fallbacks
707  // or just a single key
708  $msg = wfMessageFallback( $message );
709  if ( is_array( $message ) ) {
710  // for hook compatibility just keep the last message name
711  $message = end( $message );
712  }
713  }
714  $msg->setContext( $this->getContext() );
715  if ( $msg->exists() ) {
716  $text = $msg->text();
717  } else {
718  $text = $services->getLanguageConverterFactory()
719  ->getLanguageConverter( $services->getContentLanguage() )
720  ->convertNamespace(
721  $services->getNamespaceInfo()
722  ->getSubject( $title->getNamespace() )
723  );
724  }
725 
726  $result = [];
727  if ( !$this->getHookRunner()->onSkinTemplateTabAction( $this, $title, $message,
728  $selected, $checkEdit, $classes, $query, $text, $result )
729  ) {
730  return $result;
731  }
732 
733  $result = [
734  'class' => implode( ' ', $classes ),
735  'text' => $text,
736  'href' => $title->getLocalURL( $query ),
737  'exists' => $exists,
738  'primary' => true ];
739  if ( $linkClass !== '' ) {
740  $result['link-class'] = $linkClass;
741  }
742 
743  return $result;
744  }
745 
751  private function makeTalkUrlDetails( $name, $urlaction = '' ) {
752  $title = Title::newFromText( $name );
753  if ( !is_object( $title ) ) {
754  throw new MWException( __METHOD__ . " given invalid pagename $name" );
755  }
756  $title = $title->getTalkPage();
757  self::checkTitle( $title, $name );
758  return [
759  'href' => $title->getLocalURL( $urlaction ),
760  'exists' => $title->isKnown(),
761  ];
762  }
763 
770  public function makeArticleUrlDetails( $name, $urlaction = '' ) {
771  wfDeprecated( __METHOD__, '1.35' );
772  $title = Title::newFromText( $name );
773  $title = $title->getSubjectPage();
774  self::checkTitle( $title, $name );
775  return [
776  'href' => $title->getLocalURL( $urlaction ),
777  'exists' => $title->exists(),
778  ];
779  }
780 
790  private function getWatchLinkAttrs(
791  string $mode, User $user, Title $title, ?string $action, bool $onPage
792  ): array {
793  $class = 'mw-watchlink ' . (
794  $onPage && ( $action == 'watch' || $action == 'unwatch' ) ? 'selected' : ''
795  );
796 
797  // Add class identifying the page is temporarily watched, if applicable.
798  if ( $this->getConfig()->get( 'WatchlistExpiry' ) &&
799  $user->isTempWatched( $title )
800  ) {
801  $class .= ' mw-watchlink-temp';
802  }
803 
804  return [
805  'class' => $class,
806  // uses 'watch' or 'unwatch' message
807  'text' => $this->msg( $mode )->text(),
808  'href' => $title->getLocalURL( [ 'action' => $mode ] ),
809  // Set a data-mw=interface attribute, which the mediawiki.page.ajax
810  // module will look for to make sure it's a trusted link
811  'data' => [
812  'mw' => 'interface',
813  ],
814  ];
815  }
816 
851  protected function buildContentNavigationUrls() {
852  // Display tabs for the relevant title rather than always the title itself
853  $title = $this->getRelevantTitle();
854  $onPage = $title->equals( $this->getTitle() );
855 
856  $out = $this->getOutput();
857  $request = $this->getRequest();
858  $user = $this->getUser();
859  $permissionManager = MediaWikiServices::getInstance()->getPermissionManager();
860 
861  $content_navigation = [
862  'user-menu' => $this->buildPersonalUrls( false ),
863  'notifications' => [],
864  'namespaces' => [],
865  'views' => [],
866  'actions' => [],
867  'variants' => []
868  ];
869 
870  // parameters
871  $action = $request->getVal( 'action', 'view' );
872 
873  $userCanRead = $this->getAuthority()->probablyCan( 'read', $title );
874 
875  $preventActiveTabs = false;
876  $this->getHookRunner()->onSkinTemplatePreventOtherActiveTabs( $this, $preventActiveTabs );
877 
878  // Checks if page is some kind of content
879  if ( $title->canExist() ) {
880  // Gets page objects for the related namespaces
881  $subjectPage = $title->getSubjectPage();
882  $talkPage = $title->getTalkPage();
883 
884  // Determines if this is a talk page
885  $isTalk = $title->isTalkPage();
886 
887  // Generates XML IDs from namespace names
888  $subjectId = $title->getNamespaceKey( '' );
889 
890  if ( $subjectId == 'main' ) {
891  $talkId = 'talk';
892  } else {
893  $talkId = "{$subjectId}_talk";
894  }
895 
896  $skname = $this->skinname;
897 
898  // Adds namespace links
899  if ( $subjectId === 'user' ) {
900  $subjectMsg = wfMessage( 'nstab-user', $subjectPage->getRootText() );
901  } else {
902  $subjectMsg = [ "nstab-$subjectId" ];
903  }
904  if ( $subjectPage->isMainPage() ) {
905  array_unshift( $subjectMsg, 'mainpage-nstab' );
906  }
907 
908  $content_navigation['namespaces'][$subjectId] = $this->tabAction(
909  $subjectPage, $subjectMsg, !$isTalk && !$preventActiveTabs, '', $userCanRead
910  );
911  $content_navigation['namespaces'][$subjectId]['context'] = 'subject';
912  $content_navigation['namespaces'][$talkId] = $this->tabAction(
913  $talkPage, [ "nstab-$talkId", 'talk' ], $isTalk && !$preventActiveTabs, '', $userCanRead
914  );
915  $content_navigation['namespaces'][$talkId]['context'] = 'talk';
916 
917  if ( $userCanRead ) {
918  // Adds "view" view link
919  if ( $title->isKnown() ) {
920  $content_navigation['views']['view'] = $this->tabAction(
921  $isTalk ? $talkPage : $subjectPage,
922  [ "$skname-view-view", 'view' ],
923  ( $onPage && ( $action == 'view' || $action == 'purge' ) ), '', true
924  );
925  // signal to hide this from simple content_actions
926  $content_navigation['views']['view']['redundant'] = true;
927  }
928 
929  $page = $this->canUseWikiPage() ? $this->getWikiPage() : false;
930  $isRemoteContent = $page && !$page->isLocal();
931 
932  // If it is a non-local file, show a link to the file in its own repository
933  // @todo abstract this for remote content that isn't a file
934  if ( $isRemoteContent ) {
935  $content_navigation['views']['view-foreign'] = [
936  'class' => '',
937  'text' => wfMessageFallback( "$skname-view-foreign", 'view-foreign' )->
938  setContext( $this->getContext() )->
939  params( $page->getWikiDisplayName() )->text(),
940  'href' => $page->getSourceURL(),
941  'primary' => false,
942  ];
943  }
944 
945  // Checks if user can edit the current page if it exists or create it otherwise
946  if ( $this->getAuthority()->probablyCan( 'edit', $title ) &&
947  ( $title->exists() ||
948  $this->getAuthority()->probablyCan( 'create', $title ) )
949  ) {
950  // Builds CSS class for talk page links
951  $isTalkClass = $isTalk ? ' istalk' : '';
952  // Whether the user is editing the page
953  $isEditing = $onPage && ( $action == 'edit' || $action == 'submit' );
954  // Whether to show the "Add a new section" tab
955  // Checks if this is a current rev of talk page and is not forced to be hidden
956  $showNewSection = !$out->forceHideNewSectionLink()
957  && ( ( $isTalk && $out->isRevisionCurrent() ) || $out->showNewSectionLink() );
958  $section = $request->getVal( 'section' );
959 
960  if ( $title->exists()
961  || ( $title->inNamespace( NS_MEDIAWIKI )
962  && $title->getDefaultMessageText() !== false
963  )
964  ) {
965  $msgKey = $isRemoteContent ? 'edit-local' : 'edit';
966  } else {
967  $msgKey = $isRemoteContent ? 'create-local' : 'create';
968  }
969  $content_navigation['views']['edit'] = [
970  'class' => ( $isEditing && ( $section !== 'new' || !$showNewSection )
971  ? 'selected'
972  : ''
973  ) . $isTalkClass,
974  'text' => wfMessageFallback( "$skname-view-$msgKey", $msgKey )
975  ->setContext( $this->getContext() )->text(),
976  'href' => $title->getLocalURL( $this->editUrlOptions() ),
977  'primary' => !$isRemoteContent, // don't collapse this in vector
978  ];
979 
980  // section link
981  if ( $showNewSection ) {
982  // Adds new section link
983  // $content_navigation['actions']['addsection']
984  $content_navigation['views']['addsection'] = [
985  'class' => ( $isEditing && $section == 'new' ) ? 'selected' : false,
986  'text' => wfMessageFallback( "$skname-action-addsection", 'addsection' )
987  ->setContext( $this->getContext() )->text(),
988  'href' => $title->getLocalURL( 'action=edit&section=new' )
989  ];
990  }
991  // Checks if the page has some kind of viewable source content
992  } elseif ( $title->hasSourceText() ) {
993  // Adds view source view link
994  $content_navigation['views']['viewsource'] = [
995  'class' => ( $onPage && $action == 'edit' ) ? 'selected' : false,
996  'text' => wfMessageFallback( "$skname-action-viewsource", 'viewsource' )
997  ->setContext( $this->getContext() )->text(),
998  'href' => $title->getLocalURL( $this->editUrlOptions() ),
999  'primary' => true, // don't collapse this in vector
1000  ];
1001  }
1002 
1003  // Checks if the page exists
1004  if ( $title->exists() ) {
1005  // Adds history view link
1006  $content_navigation['views']['history'] = [
1007  'class' => ( $onPage && $action == 'history' ) ? 'selected' : false,
1008  'text' => wfMessageFallback( "$skname-view-history", 'history_short' )
1009  ->setContext( $this->getContext() )->text(),
1010  'href' => $title->getLocalURL( 'action=history' ),
1011  ];
1012 
1013  if ( $this->getAuthority()->probablyCan( 'delete', $title ) ) {
1014  $content_navigation['actions']['delete'] = [
1015  'class' => ( $onPage && $action == 'delete' ) ? 'selected' : false,
1016  'text' => wfMessageFallback( "$skname-action-delete", 'delete' )
1017  ->setContext( $this->getContext() )->text(),
1018  'href' => $title->getLocalURL( 'action=delete' )
1019  ];
1020  }
1021 
1022  if ( $this->getAuthority()->probablyCan( 'move', $title ) ) {
1023  $moveTitle = SpecialPage::getTitleFor( 'Movepage', $title->getPrefixedDBkey() );
1024  $content_navigation['actions']['move'] = [
1025  'class' => $this->getTitle()->isSpecial( 'Movepage' ) ? 'selected' : false,
1026  'text' => wfMessageFallback( "$skname-action-move", 'move' )
1027  ->setContext( $this->getContext() )->text(),
1028  'href' => $moveTitle->getLocalURL()
1029  ];
1030  }
1031  } else {
1032  // article doesn't exist or is deleted
1033  if ( $this->getAuthority()->probablyCan( 'deletedhistory', $title ) ) {
1034  $n = $title->getDeletedEditsCount();
1035  if ( $n ) {
1036  $undelTitle = SpecialPage::getTitleFor( 'Undelete', $title->getPrefixedDBkey() );
1037  // If the user can't undelete but can view deleted
1038  // history show them a "View .. deleted" tab instead.
1039  $msgKey = $this->getAuthority()->probablyCan( 'undelete', $title ) ?
1040  'undelete' : 'viewdeleted';
1041  $content_navigation['actions']['undelete'] = [
1042  'class' => $this->getTitle()->isSpecial( 'Undelete' ) ? 'selected' : false,
1043  'text' => wfMessageFallback( "$skname-action-$msgKey", "{$msgKey}_short" )
1044  ->setContext( $this->getContext() )->numParams( $n )->text(),
1045  'href' => $undelTitle->getLocalURL()
1046  ];
1047  }
1048  }
1049  }
1050 
1051  if ( $this->getAuthority()->probablyCan( 'protect', $title ) &&
1052  $title->getRestrictionTypes() &&
1053  $permissionManager->getNamespaceRestrictionLevels( $title->getNamespace(), $user ) !== [ '' ]
1054  ) {
1055  $mode = $title->isProtected() ? 'unprotect' : 'protect';
1056  $content_navigation['actions'][$mode] = [
1057  'class' => ( $onPage && $action == $mode ) ? 'selected' : false,
1058  'text' => wfMessageFallback( "$skname-action-$mode", $mode )
1059  ->setContext( $this->getContext() )->text(),
1060  'href' => $title->getLocalURL( "action=$mode" )
1061  ];
1062  }
1063 
1064  // Checks if the user is logged in
1065  if ( $this->loggedin && $this->getAuthority()
1066  ->isAllowedAll( 'viewmywatchlist', 'editmywatchlist' )
1067  ) {
1077  $mode = $user->isWatched( $title ) ? 'unwatch' : 'watch';
1078 
1079  // Add the watch/unwatch link.
1080  $content_navigation['actions'][$mode] = $this->getWatchLinkAttrs(
1081  $mode,
1082  $user,
1083  $title,
1084  $action,
1085  $onPage
1086  );
1087  }
1088  }
1089 
1090  $this->getHookRunner()->onSkinTemplateNavigation( $this, $content_navigation );
1091 
1092  $languageConverterFactory = MediaWikiServices::getInstance()->getLanguageConverterFactory();
1093 
1094  if ( $userCanRead && !$languageConverterFactory->isConversionDisabled() ) {
1095  $pageLang = $title->getPageLanguage();
1096  $converter = $languageConverterFactory
1097  ->getLanguageConverter( $pageLang );
1098  // Checks that language conversion is enabled and variants exist
1099  // And if it is not in the special namespace
1100  if ( $converter->hasVariants() ) {
1101  // Gets list of language variants
1102  $variants = $converter->getVariants();
1103  // Gets preferred variant (note that user preference is
1104  // only possible for wiki content language variant)
1105  $preferred = $converter->getPreferredVariant();
1106  if ( Action::getActionName( $this ) === 'view' ) {
1107  $params = $request->getQueryValues();
1108  unset( $params['title'] );
1109  } else {
1110  $params = [];
1111  }
1112  // Loops over each variant
1113  foreach ( $variants as $code ) {
1114  // Gets variant name from language code
1115  $varname = $pageLang->getVariantname( $code );
1116  // Appends variant link
1117  $content_navigation['variants'][] = [
1118  'class' => ( $code == $preferred ) ? 'selected' : false,
1119  'text' => $varname,
1120  'href' => $title->getLocalURL( [ 'variant' => $code ] + $params ),
1121  'lang' => LanguageCode::bcp47( $code ),
1122  'hreflang' => LanguageCode::bcp47( $code ),
1123  ];
1124  }
1125  }
1126  }
1127  } else {
1128  // If it's not content, and a request URL is set it's got to be a special page
1129  try {
1130  $url = $request->getRequestURL();
1131  } catch ( MWException $e ) {
1132  $url = false;
1133  }
1134  $content_navigation['namespaces']['special'] = [
1135  'class' => 'selected',
1136  'text' => $this->msg( 'nstab-special' )->text(),
1137  'href' => $url, // @see: T4457, T4510
1138  'context' => 'subject'
1139  ];
1140  $this->getHookRunner()->onSkinTemplateNavigation__SpecialPage(
1141  $this, $content_navigation );
1142  }
1143 
1144  // Equiv to SkinTemplateContentActions
1145  $this->getHookRunner()->onSkinTemplateNavigation__Universal(
1146  $this, $content_navigation );
1147 
1148  // Setup xml ids and tooltip info
1149  foreach ( $content_navigation as $section => &$links ) {
1150  foreach ( $links as $key => &$link ) {
1151  // Allow links to set their own id for backwards compatibility reasons.
1152  if ( isset( $link['id'] ) ) {
1153  continue;
1154  }
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 $navigation => $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 
1276  final protected function insertNotificationsIntoPersonalTools(
1277  array $contentNavigation
1278  ) : array {
1279  // userpage is only defined for logged-in users, and wfArrayInsertAfter requires the
1280  // $after parameter to be a known key in the array.
1281  if ( isset( $contentNavigation['user-menu']['userpage'] ) ) {
1282  return wfArrayInsertAfter(
1283  $contentNavigation['user-menu'],
1284  $contentNavigation['notifications'],
1285  'userpage'
1286  );
1287  } else {
1288  return $contentNavigation['user-menu'];
1289  }
1290  }
1291 }
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:2604
SkinTemplate\makePersonalToolsList
makePersonalToolsList( $personalTools=null, $options=[])
Get the HTML for the personal tools list Please ensure setupTemplateContext is called before calling ...
Definition: SkinTemplate.php:447
Skin\$skinname
string null $skinname
Definition: Skin.php:48
wfArrayInsertAfter
wfArrayInsertAfter(array $array, array $insert, $after)
Insert array into another array after the specified KEY
Definition: GlobalFunctions.php:210
ContextSource\getConfig
getConfig()
Definition: ContextSource.php:71
Skin\editUrlOptions
editUrlOptions()
Return URL options for the 'edit page' link.
Definition: Skin.php:1237
SkinTemplate\setupTemplateForOutput
setupTemplateForOutput()
Definition: SkinTemplate.php:70
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:363
Skin\makeUrlDetails
static makeUrlDetails( $name, $urlaction='')
these return an array with the 'href' and boolean 'exists'
Definition: Skin.php:1383
ContextSource\getContext
getContext()
Get the base IContextSource object.
Definition: ContextSource.php:46
Skin\getSiteNotice
getSiteNotice()
Definition: Skin.php:2040
wfMessageFallback
wfMessageFallback(... $keys)
This function accepts multiple message keys and returns a message instance for the first message whic...
Definition: GlobalFunctions.php:1254
NS_MEDIAWIKI
const NS_MEDIAWIKI
Definition: Defines.php:72
Skin\buildFeedUrls
buildFeedUrls()
Build data structure representing syndication links.
Definition: Skin.php:1687
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:63
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:851
Skin\getPoweredBy
getPoweredBy()
Gets the powered by MediaWiki icon.
Definition: Skin.php:989
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:172
true
return true
Definition: router.php:90
MessageSpecifier
Stable for implementing.
Definition: MessageSpecifier.php:24
Skin\checkTitle
static checkTitle(&$title, $name)
make sure we have some title to operate on
Definition: Skin.php:1415
SkinTemplate\$userpageUrlDetails
$userpageUrlDetails
Definition: SkinTemplate.php:53
MWDebug\getHTMLDebugLog
static getHTMLDebugLog()
Generate debug log in HTML for displaying at the bottom of the main content area.
Definition: MWDebug.php:644
Skin\makeSpecialUrl
static makeSpecialUrl( $name, $urlaction='', $proto=null)
Make a URL for a Special Page using the given query and protocol.
Definition: Skin.php:1311
SkinTemplate\$titletxt
$titletxt
Definition: SkinTemplate.php:47
Skin\makeSpecialUrlSubpage
static makeSpecialUrlSubpage( $name, $subpage, $urlaction='')
Definition: Skin.php:1326
wfMessage
wfMessage( $key,... $params)
This is the function for getting translated interface messages.
Definition: GlobalFunctions.php:1231
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:107
ContextSource\canUseWikiPage
canUseWikiPage()
Check whether a WikiPage object can be get with getWikiPage().
Definition: ContextSource.php:102
ContextSource\getRequest
getRequest()
Definition: ContextSource.php:80
SkinTemplate\wrapHTML
wrapHTML( $title, $html)
Wrap the body text with language information and identifiable element.
Definition: SkinTemplate.php:167
ContextSource\getUser
getUser()
Stable to override.
Definition: ContextSource.php:135
ContextSource\getTitle
getTitle()
Definition: ContextSource.php:89
SkinTemplate\getWatchLinkAttrs
getWatchLinkAttrs(string $mode, User $user, Title $title, ?string $action, bool $onPage)
Get the attributes for the watch link.
Definition: SkinTemplate.php:790
Skin\makeListItem
makeListItem( $key, $item, $options=[])
Generates a list item for a navigation, portlet, portal, sidebar...
Definition: Skin.php:2455
Skin\bottomScripts
bottomScripts()
This gets called shortly before the "</body>" tag.
Definition: Skin.php:739
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:701
ContextSource\getLanguage
getLanguage()
Definition: ContextSource.php:151
NS_SPECIAL
const NS_SPECIAL
Definition: Defines.php:53
SkinTemplate\getPersonalToolsList
getPersonalToolsList()
Get the HTML for the p-personal list.
Definition: SkinTemplate.php:433
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:1314
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:1726
wfDeprecated
wfDeprecated( $function, $version=false, $component=false, $callerOffset=2)
Logs a warning that $function is deprecated.
Definition: GlobalFunctions.php:1034
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:215
SkinTemplate\tabAction
tabAction( $title, $message, $selected, $query='', $checkEdit=false)
Builds an array with tab definition.
Definition: SkinTemplate.php:683
Skin\getCategories
getCategories()
Definition: Skin.php:666
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:125
User\isTempWatched
isTempWatched( $title, $checkRights=self::CHECK_USER_RIGHTS)
Check if the article is temporarily watched.
Definition: User.php:3194
ContextSource\getWikiPage
getWikiPage()
Get the WikiPage object.
Definition: ContextSource.php:116
SkinTemplate\$username
$username
Definition: SkinTemplate.php:52
wfCgiToArray
wfCgiToArray( $query)
This is the logical opposite of wfArrayToCgi(): it accepts a query string as its argument and returns...
Definition: GlobalFunctions.php:396
Skin\getLanguages
getLanguages()
Generates array of language links for the current page.
Definition: Skin.php:1445
SkinTemplate\$loggedin
$loggedin
Definition: SkinTemplate.php:51
$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:915
ContextSource\setContext
setContext(IContextSource $context)
Definition: ContextSource.php:62
ResourceLoaderSkinModule\getAvailableLogos
static getAvailableLogos( $conf)
Return an array of all available logos that a skin may use.
Definition: ResourceLoaderSkinModule.php:432
SkinTemplate\buildPersonalUrls
buildPersonalUrls(bool $includeNotifications=true)
build array of urls for personal toolbar Please ensure setupTemplateContext is called before calling ...
Definition: SkinTemplate.php:486
SkinTemplate\getStructuredPersonalTools
getStructuredPersonalTools()
Get personal tools for the user.
Definition: SkinTemplate.php:471
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:195
SkinTemplate\prepareQuickTemplate
prepareQuickTemplate()
initialize various variables and generate the template
Definition: SkinTemplate.php:262
SkinTemplate\setupTemplateContext
setupTemplateContext()
Setup class properties that are necessary prior to calling setupTemplateForOutput.
Definition: SkinTemplate.php:92
Skin\getRelevantTitle
getRelevantTitle()
Return the "relevant" title.
Definition: Skin.php:410
ContextSource\getAuthority
getAuthority()
Definition: ContextSource.php:142
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:2243
Skin\printSource
printSource()
Text with the permalink to the source page, usually shown on the footer of a printed page.
Definition: Skin.php:762
SkinTemplate\makeArticleUrlDetails
makeArticleUrlDetails( $name, $urlaction='')
Definition: SkinTemplate.php:770
SkinTemplate\outputPage
outputPage()
Initialize various variables and generate the template @stable to override.
Definition: SkinTemplate.php:138
SkinTemplate\makeTalkUrlDetails
makeTalkUrlDetails( $name, $urlaction='')
Definition: SkinTemplate.php:751
Skin\logoText
logoText( $align='')
Definition: Skin.php:1046
Skin\getNewtalks
getNewtalks()
Gets new talk page messages for the current user and returns an appropriate alert message (or an empt...
Definition: Skin.php:1886
SkinTemplate\getNameSpaceKey
getNameSpaceKey()
Generate strings used for xml 'id' names.
Definition: SkinTemplate.php:1263
Title
Represents a title within MediaWiki.
Definition: Title.php:46
SkinTemplate\prepareUserLanguageAttributes
prepareUserLanguageAttributes()
Prepare user language attribute links.
Definition: SkinTemplate.php:192
SkinTemplate\getJsConfigVars
getJsConfigVars()
Returns array of config variables that should be added only to this skin for use in JavaScript.
Definition: SkinTemplate.php:156
Title\isSpecialPage
isSpecialPage()
Returns true if this is a special page.
Definition: Title.php:1277
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
Message
The Message class deals with fetching and processing of interface message into a variety of formats.
Definition: Message.php:161
SkinTemplate\insertNotificationsIntoPersonalTools
insertNotificationsIntoPersonalTools(array $contentNavigation)
Insert the notifications content navigation into the personal tools, in their old position,...
Definition: SkinTemplate.php:1276
Skin\getUndeleteLink
getUndeleteLink()
Definition: Skin.php:781
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:1399
Skin\getFooterLinks
getFooterLinks()
Get template representation of the footer containing site footer links as well as standard footer lin...
Definition: Skin.php:2624
Skin\getCopyrightIcon
getCopyrightIcon()
Definition: Skin.php:959
SkinTemplate\prepareUndeleteLink
prepareUndeleteLink()
Prepare undelete link for output in page.
Definition: SkinTemplate.php:251
NS_FILE
const NS_FILE
Definition: Defines.php:70
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:206
User
The User object encapsulates all of the user-specific settings (user_id, name, rights,...
Definition: User.php:66
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:128
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:351