MediaWiki  master
Skin.php
Go to the documentation of this file.
1 <?php
26 
38 abstract class Skin extends ContextSource {
42  protected $skinname = null;
43 
44  protected $mRelevantTitle = null;
45  protected $mRelevantUser = null;
46 
51  public $stylename = null;
52 
57  static function getSkinNames() {
58  $skinFactory = MediaWikiServices::getInstance()->getSkinFactory();
59  return $skinFactory->getSkinNames();
60  }
61 
67  static function getSkinNameMessages() {
68  wfDeprecated( __METHOD__, '1.34' );
69  $messages = [];
70  foreach ( self::getSkinNames() as $skinKey => $skinName ) {
71  $messages[] = "skinname-$skinKey";
72  }
73  return $messages;
74  }
75 
83  public static function getAllowedSkins() {
84  global $wgSkipSkins;
85 
86  $allowedSkins = self::getSkinNames();
87 
88  foreach ( $wgSkipSkins as $skip ) {
89  unset( $allowedSkins[$skip] );
90  }
91 
92  return $allowedSkins;
93  }
94 
104  static function normalizeKey( $key ) {
106 
107  $skinNames = self::getSkinNames();
108 
109  // Make keys lowercase for case-insensitive matching.
110  $skinNames = array_change_key_case( $skinNames, CASE_LOWER );
111  $key = strtolower( $key );
112  $defaultSkin = strtolower( $wgDefaultSkin );
113  $fallbackSkin = strtolower( $wgFallbackSkin );
114 
115  if ( $key == '' || $key == 'default' ) {
116  // Don't return the default immediately;
117  // in a misconfiguration we need to fall back.
118  $key = $defaultSkin;
119  }
120 
121  if ( isset( $skinNames[$key] ) ) {
122  return $key;
123  }
124 
125  // Older versions of the software used a numeric setting
126  // in the user preferences.
127  $fallback = [
128  0 => $defaultSkin,
129  2 => 'cologneblue'
130  ];
131 
132  if ( isset( $fallback[$key] ) ) {
133  $key = $fallback[$key];
134  }
135 
136  if ( isset( $skinNames[$key] ) ) {
137  return $key;
138  } elseif ( isset( $skinNames[$defaultSkin] ) ) {
139  return $defaultSkin;
140  } else {
141  return $fallbackSkin;
142  }
143  }
144 
149  public function __construct( $skinname = null ) {
150  if ( is_string( $skinname ) ) {
151  $this->skinname = $skinname;
152  }
153  }
154 
158  public function getSkinName() {
159  return $this->skinname;
160  }
161 
165  public function initPage( OutputPage $out ) {
166  $this->preloadExistence();
167  }
168 
179  public function getDefaultModules() {
180  $out = $this->getOutput();
181  $user = $this->getUser();
182 
183  // Modules declared in the $modules literal are loaded
184  // for ALL users, on ALL pages, in ALL skins.
185  // Keep this list as small as possible!
186  $modules = [
187  'styles' => [
188  // The 'styles' key sets render-blocking style modules
189  // Unlike other keys in $modules, this is an associative array
190  // where each key is its own group pointing to a list of modules
191  'core' => [
192  'mediawiki.legacy.shared',
193  'mediawiki.legacy.commonPrint',
194  ],
195  'content' => [],
196  'syndicate' => [],
197  ],
198  'core' => [
199  'site',
200  'mediawiki.page.startup',
201  ],
202  // modules that enhance the content in some way
203  'content' => [
204  'mediawiki.page.ready',
205  ],
206  // modules relating to search functionality
207  'search' => [
208  'mediawiki.searchSuggest',
209  ],
210  // modules relating to functionality relating to watching an article
211  'watch' => [],
212  // modules which relate to the current users preferences
213  'user' => [],
214  // modules relating to RSS/Atom Feeds
215  'syndicate' => [],
216  ];
217 
218  // Preload jquery.tablesorter for mediawiki.page.ready
219  if ( strpos( $out->getHTML(), 'sortable' ) !== false ) {
220  $modules['content'][] = 'jquery.tablesorter';
221  $modules['styles']['content'][] = 'jquery.tablesorter.styles';
222  }
223 
224  // Preload jquery.makeCollapsible for mediawiki.page.ready
225  if ( strpos( $out->getHTML(), 'mw-collapsible' ) !== false ) {
226  $modules['content'][] = 'jquery.makeCollapsible';
227  $modules['styles']['content'][] = 'jquery.makeCollapsible.styles';
228  }
229 
230  // Deprecated since 1.26: Unconditional loading of mediawiki.ui.button
231  // on every page is deprecated. Express a dependency instead.
232  if ( strpos( $out->getHTML(), 'mw-ui-button' ) !== false ) {
233  $modules['styles']['content'][] = 'mediawiki.ui.button';
234  }
235 
236  if ( $out->isTOCEnabled() ) {
237  $modules['content'][] = 'mediawiki.toc';
238  $modules['styles']['content'][] = 'mediawiki.toc.styles';
239  }
240 
241  // Add various resources if required
242  if ( $user->isLoggedIn()
243  && MediaWikiServices::getInstance()
244  ->getPermissionManager()
245  ->userHasAllRights( $user, 'writeapi', 'viewmywatchlist', 'editmywatchlist' )
246  && $this->getRelevantTitle()->canExist()
247  ) {
248  $modules['watch'][] = 'mediawiki.page.watch.ajax';
249  }
250 
251  if ( $user->getBoolOption( 'editsectiononrightclick' ) ) {
252  $modules['user'][] = 'mediawiki.action.view.rightClickEdit';
253  }
254 
255  // Crazy edit-on-double-click stuff
256  if ( $out->isArticle() && $user->getOption( 'editondblclick' ) ) {
257  $modules['user'][] = 'mediawiki.action.view.dblClickEdit';
258  }
259 
260  if ( $out->isSyndicated() ) {
261  $modules['styles']['syndicate'][] = 'mediawiki.feedlink';
262  }
263 
264  return $modules;
265  }
266 
270  protected function preloadExistence() {
271  $titles = [];
272 
273  // User/talk link
274  $user = $this->getUser();
275  if ( $user->isLoggedIn() ) {
276  $titles[] = $user->getUserPage();
277  $titles[] = $user->getTalkPage();
278  }
279 
280  // Check, if the page can hold some kind of content, otherwise do nothing
281  $title = $this->getRelevantTitle();
282  if ( $title->canExist() && $title->canHaveTalkPage() ) {
283  if ( $title->isTalkPage() ) {
284  $titles[] = $title->getSubjectPage();
285  } else {
286  $titles[] = $title->getTalkPage();
287  }
288  }
289 
290  // Footer links (used by SkinTemplate::prepareQuickTemplate)
291  foreach ( [
292  $this->footerLinkTitle( 'privacy', 'privacypage' ),
293  $this->footerLinkTitle( 'aboutsite', 'aboutpage' ),
294  $this->footerLinkTitle( 'disclaimers', 'disclaimerpage' ),
295  ] as $title ) {
296  if ( $title ) {
297  $titles[] = $title;
298  }
299  }
300 
301  Hooks::run( 'SkinPreloadExistence', [ &$titles, $this ] );
302 
303  if ( $titles ) {
304  $lb = new LinkBatch( $titles );
305  $lb->setCaller( __METHOD__ );
306  $lb->execute();
307  }
308  }
309 
316  public function getRevisionId() {
317  return $this->getOutput()->getRevisionId();
318  }
319 
326  public function isRevisionCurrent() {
327  return $this->getOutput()->isRevisionCurrent();
328  }
329 
335  public function setRelevantTitle( $t ) {
336  $this->mRelevantTitle = $t;
337  }
338 
349  public function getRelevantTitle() {
350  return $this->mRelevantTitle ?? $this->getTitle();
351  }
352 
358  public function setRelevantUser( $u ) {
359  $this->mRelevantUser = $u;
360  }
361 
370  public function getRelevantUser() {
371  if ( isset( $this->mRelevantUser ) ) {
372  return $this->mRelevantUser;
373  }
374  $title = $this->getRelevantTitle();
375  if ( $title->hasSubjectNamespace( NS_USER ) ) {
376  $rootUser = $title->getRootText();
377  if ( User::isIP( $rootUser ) ) {
378  $this->mRelevantUser = User::newFromName( $rootUser, false );
379  } else {
380  $user = User::newFromName( $rootUser, false );
381 
382  if ( $user ) {
383  $user->load( User::READ_NORMAL );
384 
385  if ( $user->isLoggedIn() ) {
386  $this->mRelevantUser = $user;
387  }
388  }
389  }
390  return $this->mRelevantUser;
391  }
392  return null;
393  }
394 
398  abstract function outputPage();
399 
405  public static function makeVariablesScript( $data, $nonce = null ) {
406  if ( $data ) {
409  $nonce
410  );
411  }
412  return '';
413  }
414 
421  public static function getDynamicStylesheetQuery() {
422  return [
423  'action' => 'raw',
424  'ctype' => 'text/css',
425  ];
426  }
427 
434  public function setupSkinUserCss( OutputPage $out ) {
435  // Stub.
436  }
437 
443  function getPageClasses( $title ) {
444  $numeric = 'ns-' . $title->getNamespace();
445  $user = $this->getUser();
446 
447  if ( $title->isSpecialPage() ) {
448  $type = 'ns-special';
449  // T25315: provide a class based on the canonical special page name without subpages
450  list( $canonicalName ) = MediaWikiServices::getInstance()->getSpecialPageFactory()->
451  resolveAlias( $title->getDBkey() );
452  if ( $canonicalName ) {
453  $type .= ' ' . Sanitizer::escapeClass( "mw-special-$canonicalName" );
454  } else {
455  $type .= ' mw-invalidspecialpage';
456  }
457  } else {
458  if ( $title->isTalkPage() ) {
459  $type = 'ns-talk';
460  } else {
461  $type = 'ns-subject';
462  }
463  // T208315: add HTML class when the user can edit the page
464  if ( MediaWikiServices::getInstance()->getPermissionManager()
465  ->quickUserCan( 'edit', $user, $title )
466  ) {
467  $type .= ' mw-editable';
468  }
469  }
470 
471  $name = Sanitizer::escapeClass( 'page-' . $title->getPrefixedText() );
472  $root = Sanitizer::escapeClass( 'rootpage-' . $title->getRootTitle()->getPrefixedText() );
473 
474  return "$numeric $type $name $root";
475  }
476 
481  public function getHtmlElementAttributes() {
482  $lang = $this->getLanguage();
483  return [
484  'lang' => $lang->getHtmlCode(),
485  'dir' => $lang->getDir(),
486  'class' => 'client-nojs',
487  ];
488  }
489 
497  function addToBodyAttributes( $out, &$bodyAttrs ) {
498  // does nothing by default
499  }
500 
505  function getLogo() {
506  return $this->getConfig()->get( 'Logo' );
507  }
508 
518  public function shouldPreloadLogo() {
519  return false;
520  }
521 
525  function getCategoryLinks() {
526  $out = $this->getOutput();
527  $allCats = $out->getCategoryLinks();
528  $linkRenderer = MediaWikiServices::getInstance()->getLinkRenderer();
529 
530  if ( $allCats === [] ) {
531  return '';
532  }
533 
534  $embed = "<li>";
535  $pop = "</li>";
536 
537  $s = '';
538  $colon = $this->msg( 'colon-separator' )->escaped();
539 
540  if ( !empty( $allCats['normal'] ) ) {
541  $t = $embed . implode( $pop . $embed, $allCats['normal'] ) . $pop;
542 
543  $msg = $this->msg( 'pagecategories' )->numParams( count( $allCats['normal'] ) );
544  $linkPage = $this->msg( 'pagecategorieslink' )->inContentLanguage()->text();
545  $title = Title::newFromText( $linkPage );
546  $link = $title ? $linkRenderer->makeLink( $title, $msg->text() ) : $msg->escaped();
547  $s .= '<div id="mw-normal-catlinks" class="mw-normal-catlinks">' .
548  $link . $colon . '<ul>' . $t . '</ul></div>';
549  }
550 
551  # Hidden categories
552  if ( isset( $allCats['hidden'] ) ) {
553  if ( $this->getUser()->getBoolOption( 'showhiddencats' ) ) {
554  $class = ' mw-hidden-cats-user-shown';
555  } elseif ( $this->getTitle()->getNamespace() == NS_CATEGORY ) {
556  $class = ' mw-hidden-cats-ns-shown';
557  } else {
558  $class = ' mw-hidden-cats-hidden';
559  }
560 
561  $s .= "<div id=\"mw-hidden-catlinks\" class=\"mw-hidden-catlinks$class\">" .
562  $this->msg( 'hidden-categories' )->numParams( count( $allCats['hidden'] ) )->escaped() .
563  $colon . '<ul>' . $embed . implode( $pop . $embed, $allCats['hidden'] ) . $pop . '</ul>' .
564  '</div>';
565  }
566 
567  # optional 'dmoz-like' category browser. Will be shown under the list
568  # of categories an article belong to
569  if ( $this->getConfig()->get( 'UseCategoryBrowser' ) ) {
570  $s .= '<br /><hr />';
571 
572  # get a big array of the parents tree
573  $parenttree = $this->getTitle()->getParentCategoryTree();
574  # Skin object passed by reference cause it can not be
575  # accessed under the method subfunction drawCategoryBrowser
576  $tempout = explode( "\n", $this->drawCategoryBrowser( $parenttree ) );
577  # Clean out bogus first entry and sort them
578  unset( $tempout[0] );
579  asort( $tempout );
580  # Output one per line
581  $s .= implode( "<br />\n", $tempout );
582  }
583 
584  return $s;
585  }
586 
592  function drawCategoryBrowser( $tree ) {
593  $return = '';
594  $linkRenderer = MediaWikiServices::getInstance()->getLinkRenderer();
595 
596  foreach ( $tree as $element => $parent ) {
597  if ( empty( $parent ) ) {
598  # element start a new list
599  $return .= "\n";
600  } else {
601  # grab the others elements
602  $return .= $this->drawCategoryBrowser( $parent ) . ' &gt; ';
603  }
604 
605  # add our current element to the list
606  $eltitle = Title::newFromText( $element );
607  $return .= $linkRenderer->makeLink( $eltitle, $eltitle->getText() );
608  }
609 
610  return $return;
611  }
612 
616  function getCategories() {
617  $out = $this->getOutput();
618  $catlinks = $this->getCategoryLinks();
619 
620  // Check what we're showing
621  $allCats = $out->getCategoryLinks();
622  $showHidden = $this->getUser()->getBoolOption( 'showhiddencats' ) ||
623  $this->getTitle()->getNamespace() == NS_CATEGORY;
624 
625  $classes = [ 'catlinks' ];
626  if ( empty( $allCats['normal'] ) && !( !empty( $allCats['hidden'] ) && $showHidden ) ) {
627  $classes[] = 'catlinks-allhidden';
628  }
629 
630  return Html::rawElement(
631  'div',
632  [ 'id' => 'catlinks', 'class' => $classes, 'data-mw' => 'interface' ],
633  $catlinks
634  );
635  }
636 
651  protected function afterContentHook() {
652  $data = '';
653 
654  if ( Hooks::run( 'SkinAfterContent', [ &$data, $this ] ) ) {
655  // adding just some spaces shouldn't toggle the output
656  // of the whole <div/>, so we use trim() here
657  if ( trim( $data ) != '' ) {
658  // Doing this here instead of in the skins to
659  // ensure that the div has the same ID in all
660  // skins
661  $data = "<div id='mw-data-after-content'>\n" .
662  "\t$data\n" .
663  "</div>\n";
664  }
665  } else {
666  wfDebug( "Hook SkinAfterContent changed output processing.\n" );
667  }
668 
669  return $data;
670  }
671 
677  protected function generateDebugHTML() {
678  return MWDebug::getHTMLDebugLog();
679  }
680 
686  function bottomScripts() {
687  // TODO and the suckage continues. This function is really just a wrapper around
688  // OutputPage::getBottomScripts() which takes a Skin param. This should be cleaned
689  // up at some point
690  $chunks = [ $this->getOutput()->getBottomScripts() ];
691 
692  // Keep the hook appendage separate to preserve WrappedString objects.
693  // This enables BaseTemplate::getTrail() to merge them where possible.
694  $extraHtml = '';
695  Hooks::run( 'SkinAfterBottomScripts', [ $this, &$extraHtml ] );
696  if ( $extraHtml !== '' ) {
697  $chunks[] = $extraHtml;
698  }
699  return WrappedString::join( "\n", $chunks );
700  }
701 
708  function printSource() {
709  $oldid = $this->getOutput()->getRevisionId();
710  if ( $oldid ) {
711  $canonicalUrl = $this->getTitle()->getCanonicalURL( 'oldid=' . $oldid );
712  $url = htmlspecialchars( wfExpandIRI( $canonicalUrl ) );
713  } else {
714  // oldid not available for non existing pages
715  $url = htmlspecialchars( wfExpandIRI( $this->getTitle()->getCanonicalURL() ) );
716  }
717 
718  return $this->msg( 'retrievedfrom' )
719  ->rawParams( '<a dir="ltr" href="' . $url . '">' . $url . '</a>' )
720  ->parse();
721  }
722 
726  function getUndeleteLink() {
727  $action = $this->getRequest()->getVal( 'action', 'view' );
728  $title = $this->getTitle();
729  $linkRenderer = MediaWikiServices::getInstance()->getLinkRenderer();
730  $permissionManager = MediaWikiServices::getInstance()->getPermissionManager();
731 
732  if ( ( !$title->exists() || $action == 'history' ) &&
733  $permissionManager->quickUserCan( 'deletedhistory', $this->getUser(), $title )
734  ) {
735  $n = $title->isDeleted();
736 
737  if ( $n ) {
738  if ( $permissionManager->quickUserCan( 'undelete',
739  $this->getUser(), $this->getTitle() )
740  ) {
741  $msg = 'thisisdeleted';
742  } else {
743  $msg = 'viewdeleted';
744  }
745 
746  $subtitle = $this->msg( $msg )->rawParams(
747  $linkRenderer->makeKnownLink(
748  SpecialPage::getTitleFor( 'Undelete', $this->getTitle()->getPrefixedDBkey() ),
749  $this->msg( 'restorelink' )->numParams( $n )->text() )
750  )->escaped();
751 
752  // Allow extensions to add more links
753  $links = [];
754  Hooks::run( 'UndeletePageToolLinks', [ $this->getContext(), $linkRenderer, &$links ] );
755 
756  if ( $links ) {
757  $subtitle .= ''
758  . $this->msg( 'word-separator' )->escaped()
759  . $this->msg( 'parentheses' )
760  ->rawParams( $this->getLanguage()->pipeList( $links ) )
761  ->escaped();
762  }
763  return Html::rawElement( 'div', [ 'class' => 'mw-undelete-subtitle' ], $subtitle );
764  }
765  }
766 
767  return '';
768  }
769 
774  function subPageSubtitle( $out = null ) {
775  $linkRenderer = MediaWikiServices::getInstance()->getLinkRenderer();
776  if ( $out === null ) {
777  $out = $this->getOutput();
778  }
779  $title = $out->getTitle();
780  $subpages = '';
781 
782  if ( !Hooks::run( 'SkinSubPageSubtitle', [ &$subpages, $this, $out ] ) ) {
783  return $subpages;
784  }
785 
786  if (
787  $out->isArticle() && MediaWikiServices::getInstance()->getNamespaceInfo()->
788  hasSubpages( $title->getNamespace() )
789  ) {
790  $ptext = $title->getPrefixedText();
791  if ( strpos( $ptext, '/' ) !== false ) {
792  $links = explode( '/', $ptext );
793  array_pop( $links );
794  $c = 0;
795  $growinglink = '';
796  $display = '';
797  $lang = $this->getLanguage();
798 
799  foreach ( $links as $link ) {
800  $growinglink .= $link;
801  $display .= $link;
802  $linkObj = Title::newFromText( $growinglink );
803 
804  if ( is_object( $linkObj ) && $linkObj->isKnown() ) {
805  $getlink = $linkRenderer->makeKnownLink(
806  $linkObj, $display
807  );
808 
809  $c++;
810 
811  if ( $c > 1 ) {
812  $subpages .= $lang->getDirMarkEntity() . $this->msg( 'pipe-separator' )->escaped();
813  } else {
814  $subpages .= '&lt; ';
815  }
816 
817  $subpages .= $getlink;
818  $display = '';
819  } else {
820  $display .= '/';
821  }
822  $growinglink .= '/';
823  }
824  }
825  }
826 
827  return $subpages;
828  }
829 
833  function getSearchLink() {
835  return $searchPage->getLocalURL();
836  }
837 
842  function escapeSearchLink() {
843  wfDeprecated( __METHOD__, '1.34' );
844  return htmlspecialchars( $this->getSearchLink() );
845  }
846 
851  function getCopyright( $type = 'detect' ) {
852  $linkRenderer = MediaWikiServices::getInstance()->getLinkRenderer();
853  if ( $type == 'detect' ) {
854  if ( !$this->getOutput()->isRevisionCurrent()
855  && !$this->msg( 'history_copyright' )->inContentLanguage()->isDisabled()
856  ) {
857  $type = 'history';
858  } else {
859  $type = 'normal';
860  }
861  }
862 
863  if ( $type == 'history' ) {
864  $msg = 'history_copyright';
865  } else {
866  $msg = 'copyright';
867  }
868 
869  $config = $this->getConfig();
870 
871  if ( $config->get( 'RightsPage' ) ) {
872  $title = Title::newFromText( $config->get( 'RightsPage' ) );
873  $link = $linkRenderer->makeKnownLink(
874  $title, new HtmlArmor( $config->get( 'RightsText' ) )
875  );
876  } elseif ( $config->get( 'RightsUrl' ) ) {
877  $link = Linker::makeExternalLink( $config->get( 'RightsUrl' ), $config->get( 'RightsText' ) );
878  } elseif ( $config->get( 'RightsText' ) ) {
879  $link = $config->get( 'RightsText' );
880  } else {
881  # Give up now
882  return '';
883  }
884 
885  // Allow for site and per-namespace customization of copyright notice.
886  // @todo Remove deprecated $forContent param from hook handlers and then remove here.
887  $forContent = true;
888 
889  Hooks::run(
890  'SkinCopyrightFooter',
891  [ $this->getTitle(), $type, &$msg, &$link, &$forContent ]
892  );
893 
894  return $this->msg( $msg )->rawParams( $link )->text();
895  }
896 
900  function getCopyrightIcon() {
901  $out = '';
902  $config = $this->getConfig();
903 
904  $footerIcons = $config->get( 'FooterIcons' );
905  if ( $footerIcons['copyright']['copyright'] ) {
906  $out = $footerIcons['copyright']['copyright'];
907  } elseif ( $config->get( 'RightsIcon' ) ) {
908  $icon = htmlspecialchars( $config->get( 'RightsIcon' ) );
909  $url = $config->get( 'RightsUrl' );
910 
911  if ( $url ) {
912  $out .= '<a href="' . htmlspecialchars( $url ) . '">';
913  }
914 
915  $text = htmlspecialchars( $config->get( 'RightsText' ) );
916  $out .= "<img src=\"$icon\" alt=\"$text\" width=\"88\" height=\"31\" />";
917 
918  if ( $url ) {
919  $out .= '</a>';
920  }
921  }
922 
923  return $out;
924  }
925 
930  function getPoweredBy() {
931  $resourceBasePath = $this->getConfig()->get( 'ResourceBasePath' );
932  $url1 = htmlspecialchars(
933  "$resourceBasePath/resources/assets/poweredby_mediawiki_88x31.png"
934  );
935  $url1_5 = htmlspecialchars(
936  "$resourceBasePath/resources/assets/poweredby_mediawiki_132x47.png"
937  );
938  $url2 = htmlspecialchars(
939  "$resourceBasePath/resources/assets/poweredby_mediawiki_176x62.png"
940  );
941  $text = '<a href="https://www.mediawiki.org/"><img src="' . $url1
942  . '" srcset="' . $url1_5 . ' 1.5x, ' . $url2 . ' 2x" '
943  . 'height="31" width="88" alt="Powered by MediaWiki" /></a>';
944  Hooks::run( 'SkinGetPoweredBy', [ &$text, $this ] );
945  return $text;
946  }
947 
953  protected function lastModified() {
954  $timestamp = $this->getOutput()->getRevisionTimestamp();
955 
956  # No cached timestamp, load it from the database
957  if ( $timestamp === null ) {
958  $timestamp = Revision::getTimestampFromId( $this->getTitle(),
959  $this->getOutput()->getRevisionId() );
960  }
961 
962  if ( $timestamp ) {
963  $d = $this->getLanguage()->userDate( $timestamp, $this->getUser() );
964  $t = $this->getLanguage()->userTime( $timestamp, $this->getUser() );
965  $s = ' ' . $this->msg( 'lastmodifiedat', $d, $t )->parse();
966  } else {
967  $s = '';
968  }
969 
970  if ( MediaWikiServices::getInstance()->getDBLoadBalancer()->getLaggedReplicaMode() ) {
971  $s .= ' <strong>' . $this->msg( 'laggedslavemode' )->parse() . '</strong>';
972  }
973 
974  return $s;
975  }
976 
981  function logoText( $align = '' ) {
982  if ( $align != '' ) {
983  $a = " style='float: {$align};'";
984  } else {
985  $a = '';
986  }
987 
988  $mp = $this->msg( 'mainpage' )->escaped();
989  $mptitle = Title::newMainPage();
990  $url = ( is_object( $mptitle ) ? htmlspecialchars( $mptitle->getLocalURL() ) : '' );
991 
992  $logourl = $this->getLogo();
993  $s = "<a href='{$url}'><img{$a} src='{$logourl}' alt='[{$mp}]' /></a>";
994 
995  return $s;
996  }
997 
1006  function makeFooterIcon( $icon, $withImage = 'withImage' ) {
1007  if ( is_string( $icon ) ) {
1008  $html = $icon;
1009  } else { // Assuming array
1010  $url = $icon["url"] ?? null;
1011  unset( $icon["url"] );
1012  if ( isset( $icon["src"] ) && $withImage === 'withImage' ) {
1013  // do this the lazy way, just pass icon data as an attribute array
1014  $html = Html::element( 'img', $icon );
1015  } else {
1016  $html = htmlspecialchars( $icon["alt"] );
1017  }
1018  if ( $url ) {
1019  $html = Html::rawElement( 'a',
1020  [ "href" => $url, "target" => $this->getConfig()->get( 'ExternalLinkTarget' ) ],
1021  $html );
1022  }
1023  }
1024  return $html;
1025  }
1026 
1031  function mainPageLink() {
1032  $linkRenderer = MediaWikiServices::getInstance()->getLinkRenderer();
1033  $s = $linkRenderer->makeKnownLink(
1035  $this->msg( 'mainpage' )->text()
1036  );
1037 
1038  return $s;
1039  }
1040 
1047  public function footerLink( $desc, $page ) {
1048  $title = $this->footerLinkTitle( $desc, $page );
1049  $linkRenderer = MediaWikiServices::getInstance()->getLinkRenderer();
1050  if ( !$title ) {
1051  return '';
1052  }
1053 
1054  return $linkRenderer->makeKnownLink(
1055  $title,
1056  $this->msg( $desc )->text()
1057  );
1058  }
1059 
1065  private function footerLinkTitle( $desc, $page ) {
1066  // If the link description has been set to "-" in the default language,
1067  if ( $this->msg( $desc )->inContentLanguage()->isDisabled() ) {
1068  // then it is disabled, for all languages.
1069  return null;
1070  }
1071  // Otherwise, we display the link for the user, described in their
1072  // language (which may or may not be the same as the default language),
1073  // but we make the link target be the one site-wide page.
1074  $title = Title::newFromText( $this->msg( $page )->inContentLanguage()->text() );
1075 
1076  return $title ?: null;
1077  }
1078 
1083  function privacyLink() {
1084  return $this->footerLink( 'privacy', 'privacypage' );
1085  }
1086 
1091  function aboutLink() {
1092  return $this->footerLink( 'aboutsite', 'aboutpage' );
1093  }
1094 
1099  function disclaimerLink() {
1100  return $this->footerLink( 'disclaimers', 'disclaimerpage' );
1101  }
1102 
1110  function editUrlOptions() {
1111  $options = [ 'action' => 'edit' ];
1112 
1113  if ( !$this->getOutput()->isRevisionCurrent() ) {
1114  $options['oldid'] = intval( $this->getOutput()->getRevisionId() );
1115  }
1116 
1117  return $options;
1118  }
1119 
1124  function showEmailUser( $id ) {
1125  if ( $id instanceof User ) {
1126  $targetUser = $id;
1127  } else {
1128  $targetUser = User::newFromId( $id );
1129  }
1130 
1131  # The sending user must have a confirmed email address and the receiving
1132  # user must accept emails from the sender.
1133  return $this->getUser()->canSendEmail()
1134  && SpecialEmailUser::validateTarget( $targetUser, $this->getUser() ) === '';
1135  }
1136 
1148  function getSkinStylePath( $name ) {
1149  if ( $this->stylename === null ) {
1150  $class = static::class;
1151  throw new MWException( "$class::\$stylename must be set to use getSkinStylePath()" );
1152  }
1153 
1154  return $this->getConfig()->get( 'StylePath' ) . "/{$this->stylename}/$name";
1155  }
1156 
1157  /* these are used extensively in SkinTemplate, but also some other places */
1158 
1163  static function makeMainPageUrl( $urlaction = '' ) {
1165  self::checkTitle( $title, '' );
1166 
1167  return $title->getLinkURL( $urlaction );
1168  }
1169 
1181  static function makeSpecialUrl( $name, $urlaction = '', $proto = null ) {
1183  if ( is_null( $proto ) ) {
1184  return $title->getLocalURL( $urlaction );
1185  } else {
1186  return $title->getFullURL( $urlaction, false, $proto );
1187  }
1188  }
1189 
1196  static function makeSpecialUrlSubpage( $name, $subpage, $urlaction = '' ) {
1197  $title = SpecialPage::getSafeTitleFor( $name, $subpage );
1198  return $title->getLocalURL( $urlaction );
1199  }
1200 
1206  static function makeI18nUrl( $name, $urlaction = '' ) {
1207  $title = Title::newFromText( wfMessage( $name )->inContentLanguage()->text() );
1208  self::checkTitle( $title, $name );
1209  return $title->getLocalURL( $urlaction );
1210  }
1211 
1217  static function makeUrl( $name, $urlaction = '' ) {
1218  $title = Title::newFromText( $name );
1219  self::checkTitle( $title, $name );
1220 
1221  return $title->getLocalURL( $urlaction );
1222  }
1223 
1230  static function makeInternalOrExternalUrl( $name ) {
1231  if ( preg_match( '/^(?i:' . wfUrlProtocols() . ')/', $name ) ) {
1232  return $name;
1233  } else {
1234  return self::makeUrl( $name );
1235  }
1236  }
1237 
1245  static function makeNSUrl( $name, $urlaction = '', $namespace = NS_MAIN ) {
1246  $title = Title::makeTitleSafe( $namespace, $name );
1247  self::checkTitle( $title, $name );
1248 
1249  return $title->getLocalURL( $urlaction );
1250  }
1251 
1258  static function makeUrlDetails( $name, $urlaction = '' ) {
1259  $title = Title::newFromText( $name );
1260  self::checkTitle( $title, $name );
1261 
1262  return [
1263  'href' => $title->getLocalURL( $urlaction ),
1264  'exists' => $title->isKnown(),
1265  ];
1266  }
1267 
1274  static function makeKnownUrlDetails( $name, $urlaction = '' ) {
1275  $title = Title::newFromText( $name );
1276  self::checkTitle( $title, $name );
1277 
1278  return [
1279  'href' => $title->getLocalURL( $urlaction ),
1280  'exists' => true
1281  ];
1282  }
1283 
1290  static function checkTitle( &$title, $name ) {
1291  if ( !is_object( $title ) ) {
1292  $title = Title::newFromText( $name );
1293  if ( !is_object( $title ) ) {
1294  $title = Title::newFromText( '--error: link target missing--' );
1295  }
1296  }
1297  }
1298 
1320  public function buildSidebar() {
1321  $services = MediaWikiServices::getInstance();
1322  $callback = function ( $old = null, &$ttl = null ) {
1323  $bar = [];
1324  $this->addToSidebar( $bar, 'sidebar' );
1325  Hooks::run( 'SkinBuildSidebar', [ $this, &$bar ] );
1326  $msgCache = MediaWikiServices::getInstance()->getMessageCache();
1327  if ( $msgCache->isDisabled() ) {
1328  $ttl = WANObjectCache::TTL_UNCACHEABLE; // bug T133069
1329  }
1330 
1331  return $bar;
1332  };
1333 
1334  $msgCache = $services->getMessageCache();
1335  $wanCache = $services->getMainWANObjectCache();
1336  $config = $this->getConfig();
1337 
1338  $sidebar = $config->get( 'EnableSidebarCache' )
1339  ? $wanCache->getWithSetCallback(
1340  $wanCache->makeKey( 'sidebar', $this->getLanguage()->getCode() ),
1341  $config->get( 'SidebarCacheExpiry' ),
1342  $callback,
1343  [
1344  'checkKeys' => [
1345  // Unless there is both no exact $code override nor an i18n definition
1346  // in the software, the only MediaWiki page to check is for $code.
1347  $msgCache->getCheckKey( $this->getLanguage()->getCode() )
1348  ],
1349  'lockTSE' => 30
1350  ]
1351  )
1352  : $callback();
1353 
1354  // Apply post-processing to the cached value
1355  Hooks::run( 'SidebarBeforeOutput', [ $this, &$sidebar ] );
1356 
1357  return $sidebar;
1358  }
1359 
1369  public function addToSidebar( &$bar, $message ) {
1370  $this->addToSidebarPlain( $bar, $this->msg( $message )->inContentLanguage()->plain() );
1371  }
1372 
1380  function addToSidebarPlain( &$bar, $text ) {
1381  $lines = explode( "\n", $text );
1382 
1383  $heading = '';
1384  $config = $this->getConfig();
1385  $messageTitle = $config->get( 'EnableSidebarCache' )
1386  ? Title::newMainPage() : $this->getTitle();
1387 
1388  foreach ( $lines as $line ) {
1389  if ( strpos( $line, '*' ) !== 0 ) {
1390  continue;
1391  }
1392  $line = rtrim( $line, "\r" ); // for Windows compat
1393 
1394  if ( strpos( $line, '**' ) !== 0 ) {
1395  $heading = trim( $line, '* ' );
1396  if ( !array_key_exists( $heading, $bar ) ) {
1397  $bar[$heading] = [];
1398  }
1399  } else {
1400  $line = trim( $line, '* ' );
1401 
1402  if ( strpos( $line, '|' ) !== false ) { // sanity check
1403  $line = MessageCache::singleton()->transform( $line, false, null, $messageTitle );
1404  $line = array_map( 'trim', explode( '|', $line, 2 ) );
1405  if ( count( $line ) !== 2 ) {
1406  // Second sanity check, could be hit by people doing
1407  // funky stuff with parserfuncs... (T35321)
1408  continue;
1409  }
1410 
1411  $extraAttribs = [];
1412 
1413  $msgLink = $this->msg( $line[0] )->title( $messageTitle )->inContentLanguage();
1414  if ( $msgLink->exists() ) {
1415  $link = $msgLink->text();
1416  if ( $link == '-' ) {
1417  continue;
1418  }
1419  } else {
1420  $link = $line[0];
1421  }
1422  $msgText = $this->msg( $line[1] )->title( $messageTitle );
1423  if ( $msgText->exists() ) {
1424  $text = $msgText->text();
1425  } else {
1426  $text = $line[1];
1427  }
1428 
1429  if ( preg_match( '/^(?i:' . wfUrlProtocols() . ')/', $link ) ) {
1430  $href = $link;
1431 
1432  // Parser::getExternalLinkAttribs won't work here because of the Namespace things
1433  if ( $config->get( 'NoFollowLinks' ) &&
1434  !wfMatchesDomainList( $href, $config->get( 'NoFollowDomainExceptions' ) )
1435  ) {
1436  $extraAttribs['rel'] = 'nofollow';
1437  }
1438 
1439  if ( $config->get( 'ExternalLinkTarget' ) ) {
1440  $extraAttribs['target'] = $config->get( 'ExternalLinkTarget' );
1441  }
1442  } else {
1443  $title = Title::newFromText( $link );
1444 
1445  if ( $title ) {
1446  $title = $title->fixSpecialName();
1447  $href = $title->getLinkURL();
1448  } else {
1449  $href = 'INVALID-TITLE';
1450  }
1451  }
1452 
1453  $bar[$heading][] = array_merge( [
1454  'text' => $text,
1455  'href' => $href,
1456  'id' => Sanitizer::escapeIdForAttribute( 'n-' . strtr( $line[1], ' ', '-' ) ),
1457  'active' => false,
1458  ], $extraAttribs );
1459  } else {
1460  continue;
1461  }
1462  }
1463  }
1464 
1465  return $bar;
1466  }
1467 
1473  function getNewtalks() {
1474  $newMessagesAlert = '';
1475  $user = $this->getUser();
1476  $newtalks = $user->getNewMessageLinks();
1477  $out = $this->getOutput();
1478  $linkRenderer = MediaWikiServices::getInstance()->getLinkRenderer();
1479 
1480  // Allow extensions to disable or modify the new messages alert
1481  if ( !Hooks::run( 'GetNewMessagesAlert', [ &$newMessagesAlert, $newtalks, $user, $out ] ) ) {
1482  return '';
1483  }
1484  if ( $newMessagesAlert ) {
1485  return $newMessagesAlert;
1486  }
1487 
1488  if ( count( $newtalks ) == 1 && WikiMap::isCurrentWikiId( $newtalks[0]['wiki'] ) ) {
1489  $uTalkTitle = $user->getTalkPage();
1490  $lastSeenRev = $newtalks[0]['rev'] ?? null;
1491  $nofAuthors = 0;
1492  if ( $lastSeenRev !== null ) {
1493  $plural = true; // Default if we have a last seen revision: if unknown, use plural
1494  $latestRev = Revision::newFromTitle( $uTalkTitle, false, Revision::READ_NORMAL );
1495  if ( $latestRev !== null ) {
1496  // Singular if only 1 unseen revision, plural if several unseen revisions.
1497  $plural = $latestRev->getParentId() !== $lastSeenRev->getId();
1498  $nofAuthors = $uTalkTitle->countAuthorsBetween(
1499  $lastSeenRev, $latestRev, 10, 'include_new' );
1500  }
1501  } else {
1502  // Singular if no revision -> diff link will show latest change only in any case
1503  $plural = false;
1504  }
1505  $plural = $plural ? 999 : 1;
1506  // 999 signifies "more than one revision". We don't know how many, and even if we did,
1507  // the number of revisions or authors is not necessarily the same as the number of
1508  // "messages".
1509  $newMessagesLink = $linkRenderer->makeKnownLink(
1510  $uTalkTitle,
1511  $this->msg( 'newmessageslinkplural' )->params( $plural )->text(),
1512  [],
1513  $uTalkTitle->isRedirect() ? [ 'redirect' => 'no' ] : []
1514  );
1515 
1516  $newMessagesDiffLink = $linkRenderer->makeKnownLink(
1517  $uTalkTitle,
1518  $this->msg( 'newmessagesdifflinkplural' )->params( $plural )->text(),
1519  [],
1520  $lastSeenRev !== null
1521  ? [ 'oldid' => $lastSeenRev->getId(), 'diff' => 'cur' ]
1522  : [ 'diff' => 'cur' ]
1523  );
1524 
1525  if ( $nofAuthors >= 1 && $nofAuthors <= 10 ) {
1526  $newMessagesAlert = $this->msg(
1527  'youhavenewmessagesfromusers',
1528  $newMessagesLink,
1529  $newMessagesDiffLink
1530  )->numParams( $nofAuthors, $plural );
1531  } else {
1532  // $nofAuthors === 11 signifies "11 or more" ("more than 10")
1533  $newMessagesAlert = $this->msg(
1534  $nofAuthors > 10 ? 'youhavenewmessagesmanyusers' : 'youhavenewmessages',
1535  $newMessagesLink,
1536  $newMessagesDiffLink
1537  )->numParams( $plural );
1538  }
1539  $newMessagesAlert = $newMessagesAlert->text();
1540  # Disable CDN cache
1541  $out->setCdnMaxage( 0 );
1542  } elseif ( count( $newtalks ) ) {
1543  $sep = $this->msg( 'newtalkseparator' )->escaped();
1544  $msgs = [];
1545 
1546  foreach ( $newtalks as $newtalk ) {
1547  $msgs[] = Xml::element(
1548  'a',
1549  [ 'href' => $newtalk['link'] ], $newtalk['wiki']
1550  );
1551  }
1552  $parts = implode( $sep, $msgs );
1553  $newMessagesAlert = $this->msg( 'youhavenewmessagesmulti' )->rawParams( $parts )->escaped();
1554  $out->setCdnMaxage( 0 );
1555  }
1556 
1557  return $newMessagesAlert;
1558  }
1559 
1567  private function getCachedNotice( $name ) {
1568  $config = $this->getConfig();
1569 
1570  if ( $name === 'default' ) {
1571  // special case
1572  $notice = $config->get( 'SiteNotice' );
1573  if ( empty( $notice ) ) {
1574  return false;
1575  }
1576  } else {
1577  $msg = $this->msg( $name )->inContentLanguage();
1578  if ( $msg->isBlank() ) {
1579  return '';
1580  } elseif ( $msg->isDisabled() ) {
1581  return false;
1582  }
1583  $notice = $msg->plain();
1584  }
1585 
1586  $services = MediaWikiServices::getInstance();
1587  $cache = $services->getMainWANObjectCache();
1588  $parsed = $cache->getWithSetCallback(
1589  // Use the extra hash appender to let eg SSL variants separately cache
1590  // Key is verified with md5 hash of unparsed wikitext
1591  $cache->makeKey( $name, $config->get( 'RenderHashAppend' ), md5( $notice ) ),
1592  // TTL in seconds
1593  600,
1594  function () use ( $notice ) {
1595  return $this->getOutput()->parseAsInterface( $notice );
1596  }
1597  );
1598 
1599  $contLang = $services->getContentLanguage();
1600  return Html::rawElement(
1601  'div',
1602  [
1603  'id' => 'localNotice',
1604  'lang' => $contLang->getHtmlCode(),
1605  'dir' => $contLang->getDir()
1606  ],
1607  $parsed
1608  );
1609  }
1610 
1616  function getSiteNotice() {
1617  $siteNotice = '';
1618 
1619  if ( Hooks::run( 'SiteNoticeBefore', [ &$siteNotice, $this ] ) ) {
1620  if ( is_object( $this->getUser() ) && $this->getUser()->isLoggedIn() ) {
1621  $siteNotice = $this->getCachedNotice( 'sitenotice' );
1622  } else {
1623  $anonNotice = $this->getCachedNotice( 'anonnotice' );
1624  if ( $anonNotice === false ) {
1625  $siteNotice = $this->getCachedNotice( 'sitenotice' );
1626  } else {
1627  $siteNotice = $anonNotice;
1628  }
1629  }
1630  if ( $siteNotice === false ) {
1631  $siteNotice = $this->getCachedNotice( 'default' );
1632  }
1633  }
1634 
1635  Hooks::run( 'SiteNoticeAfter', [ &$siteNotice, $this ] );
1636  return $siteNotice;
1637  }
1638 
1652  public function doEditSectionLink( Title $nt, $section, $tooltip, Language $lang ) {
1653  // HTML generated here should probably have userlangattributes
1654  // added to it for LTR text on RTL pages
1655 
1656  $attribs = [];
1657  if ( !is_null( $tooltip ) ) {
1658  $attribs['title'] = $this->msg( 'editsectionhint' )->rawParams( $tooltip )
1659  ->inLanguage( $lang )->text();
1660  }
1661 
1662  $links = [
1663  'editsection' => [
1664  'text' => $this->msg( 'editsection' )->inLanguage( $lang )->text(),
1665  'targetTitle' => $nt,
1666  'attribs' => $attribs,
1667  'query' => [ 'action' => 'edit', 'section' => $section ]
1668  ]
1669  ];
1670 
1671  Hooks::run( 'SkinEditSectionLinks', [ $this, $nt, $section, $tooltip, &$links, $lang ] );
1672 
1673  $result = '<span class="mw-editsection"><span class="mw-editsection-bracket">[</span>';
1674 
1675  $linkRenderer = MediaWikiServices::getInstance()->getLinkRenderer();
1676  $linksHtml = [];
1677  foreach ( $links as $k => $linkDetails ) {
1678  $linksHtml[] = $linkRenderer->makeKnownLink(
1679  $linkDetails['targetTitle'],
1680  $linkDetails['text'],
1681  $linkDetails['attribs'],
1682  $linkDetails['query']
1683  );
1684  }
1685 
1686  $result .= implode(
1687  '<span class="mw-editsection-divider">'
1688  . $this->msg( 'pipe-separator' )->inLanguage( $lang )->escaped()
1689  . '</span>',
1690  $linksHtml
1691  );
1692 
1693  $result .= '<span class="mw-editsection-bracket">]</span></span>';
1694  return $result;
1695  }
1696 
1697 }
showEmailUser( $id)
Definition: Skin.php:1124
static makeUrlDetails( $name, $urlaction='')
these return an array with the &#39;href&#39; and boolean &#39;exists&#39;
Definition: Skin.php:1258
static makeI18nUrl( $name, $urlaction='')
Definition: Skin.php:1206
makeFooterIcon( $icon, $withImage='withImage')
Renders a $wgFooterIcons icon according to the method&#39;s arguments.
Definition: Skin.php:1006
wfUrlProtocols( $includeProtocolRelative=true)
Returns a regular expression of url protocols.
lastModified()
Get the timestamp of the latest revision, formatted in user language.
Definition: Skin.php:953
footerLinkTitle( $desc, $page)
Definition: Skin.php:1065
static element( $element, $attribs=[], $contents='')
Identical to rawElement(), but HTML-escapes $contents (like Xml::element()).
Definition: Html.php:231
static normalizeKey( $key)
Normalize a skin preference value to a form that can be loaded.
Definition: Skin.php:104
static getTimestampFromId( $title, $id, $flags=0)
Get rev_timestamp from rev_id, without loading the rest of the row.
Definition: Revision.php:1060
afterContentHook()
This runs a hook to allow extensions placing their stuff after content and article metadata (e...
Definition: Skin.php:651
setRelevantUser( $u)
Set the "relevant" user.
Definition: Skin.php:358
getPoweredBy()
Gets the powered by MediaWiki icon.
Definition: Skin.php:930
getNewtalks()
Gets new talk page messages for the current user and returns an appropriate alert message (or an empt...
Definition: Skin.php:1473
const NS_MAIN
Definition: Defines.php:60
static makeSpecialUrl( $name, $urlaction='', $proto=null)
Make a URL for a Special Page using the given query and protocol.
Definition: Skin.php:1181
static newMainPage(MessageLocalizer $localizer=null)
Create a new Title for the Main Page.
Definition: Title.php:648
static isIP( $name)
Does the string match an anonymous IP address?
Definition: User.php:891
buildSidebar()
Build an array that represents the sidebar(s), the navigation bar among them.
Definition: Skin.php:1320
The simplest way of implementing IContextSource is to hold a RequestContext as a member variable and ...
privacyLink()
Gets the link to the wiki&#39;s privacy policy page.
Definition: Skin.php:1083
if(!isset( $args[0])) $lang
static rawElement( $element, $attribs=[], $contents='')
Returns an HTML element in a string.
Definition: Html.php:209
doEditSectionLink(Title $nt, $section, $tooltip, Language $lang)
Create a section edit link.
Definition: Skin.php:1652
initPage(OutputPage $out)
Definition: Skin.php:165
editUrlOptions()
Return URL options for the &#39;edit page&#39; link.
Definition: Skin.php:1110
getLogo()
URL to the logo.
Definition: Skin.php:505
static getSkinNames()
Fetch the set of available skins.
Definition: Skin.php:57
getCopyrightIcon()
Definition: Skin.php:900
static makeConfigSetScript(array $configuration)
Returns JS code which will set the MediaWiki configuration array to the given value.
getCachedNotice( $name)
Get a cached notice.
Definition: Skin.php:1567
static newFromTitle(LinkTarget $linkTarget, $id=0, $flags=0)
Load either the current, or a specified, revision that&#39;s attached to a given link target...
Definition: Revision.php:138
shouldPreloadLogo()
Whether the logo should be preloaded with an HTTP link header or not.
Definition: Skin.php:518
getCategories()
Definition: Skin.php:616
getSiteNotice()
Get the site notice.
Definition: Skin.php:1616
static getHTMLDebugLog()
Generate debug log in HTML for displaying at the bottom of the main content area. ...
Definition: MWDebug.php:478
getPageClasses( $title)
TODO: document.
Definition: Skin.php:443
addToBodyAttributes( $out, &$bodyAttrs)
This will be called by OutputPage::headElement when it is creating the "<body>" tag, skins can override it if they have a need to add in any body attributes or classes of their own.
Definition: Skin.php:497
The User object encapsulates all of the user-specific settings (user_id, name, rights, email address, options, last login time).
Definition: User.php:51
Class representing a list of titles The execute() method checks them all for existence and adds them ...
Definition: LinkBatch.php:34
preloadExistence()
Preload the existence of three commonly-requested pages in a single query.
Definition: Skin.php:270
footerLink( $desc, $page)
Returns an HTML link for use in the footer.
Definition: Skin.php:1047
$modules
wfMatchesDomainList( $url, $domains)
Check whether a given URL has a domain that occurs in a given set of domains.
$mRelevantTitle
Definition: Skin.php:44
static checkTitle(&$title, $name)
make sure we have some title to operate on
Definition: Skin.php:1290
mainPageLink()
Gets the link to the wiki&#39;s main page.
Definition: Skin.php:1031
static escapeIdForAttribute( $id, $mode=self::ID_PRIMARY)
Given a section name or other user-generated or otherwise unsafe string, escapes it to be a valid HTM...
Definition: Sanitizer.php:1295
drawCategoryBrowser( $tree)
Render the array as a series of links.
Definition: Skin.php:592
getRelevantTitle()
Return the "relevant" title.
Definition: Skin.php:349
wfDebug( $text, $dest='all', array $context=[])
Sends a line to the debug log if enabled or, optionally, to a comment in output.
subPageSubtitle( $out=null)
Definition: Skin.php:774
getCategoryLinks()
Definition: Skin.php:525
disclaimerLink()
Gets the link to the wiki&#39;s general disclaimers page.
Definition: Skin.php:1099
getContext()
Get the base IContextSource object.
$cache
Definition: mcc.php:33
getSearchLink()
Definition: Skin.php:833
$mRelevantUser
Definition: Skin.php:45
const NS_CATEGORY
Definition: Defines.php:74
static makeVariablesScript( $data, $nonce=null)
Definition: Skin.php:405
static makeExternalLink( $url, $text, $escape=true, $linktype='', $attribs=[], $title=null)
Make an external link.
Definition: Linker.php:848
generateDebugHTML()
Generate debug data HTML for displaying at the bottom of the main content area.
Definition: Skin.php:677
setRelevantTitle( $t)
Set the "relevant" title.
Definition: Skin.php:335
getHtmlElementAttributes()
Return values for <html> element.
Definition: Skin.php:481
static escapeClass( $class)
Given a value, escape it so that it can be used as a CSS class and return it.
Definition: Sanitizer.php:1418
getRelevantUser()
Return the "relevant" user.
Definition: Skin.php:370
aboutLink()
Gets the link to the wiki&#39;s about page.
Definition: Skin.php:1091
addToSidebarPlain(&$bar, $text)
Add content from plain text.
Definition: Skin.php:1380
addToSidebar(&$bar, $message)
Add content from a sidebar system message Currently only used for MediaWiki:Sidebar (but may be used ...
Definition: Skin.php:1369
static getTitleFor( $name, $subpage=false, $fragment='')
Get a localised Title object for a specified special page name If you don&#39;t need a full Title object...
Definition: SpecialPage.php:83
logoText( $align='')
Definition: Skin.php:981
static makeKnownUrlDetails( $name, $urlaction='')
Make URL details where the article exists (or at least it&#39;s convenient to think so) ...
Definition: Skin.php:1274
static makeInlineScript( $script, $nonce=null)
Returns an HTML script tag that runs given JS code after startup and base modules.
static makeUrl( $name, $urlaction='')
Definition: Skin.php:1217
getDefaultModules()
Defines the ResourceLoader modules that should be added to the skin It is recommended that skins wish...
Definition: Skin.php:179
static makeTitleSafe( $ns, $title, $fragment='', $interwiki='')
Create a new Title from a namespace index and a DB key.
Definition: Title.php:612
printSource()
Text with the permalink to the source page, usually shown on the footer of a printed page...
Definition: Skin.php:708
static newFromId( $id)
Static factory method for creation from a given user ID.
Definition: User.php:539
string $stylename
Stylesheets set to use.
Definition: Skin.php:51
$fallback
Definition: MessagesAb.php:11
$lines
Definition: router.php:61
static isCurrentWikiId( $wikiId)
Definition: WikiMap.php:313
msg( $key,... $params)
Get a Message object with context set Parameters are the same as wfMessage()
wfExpandIRI( $url)
Take a URL, make sure it&#39;s expanded to fully qualified, and replace any encoded non-ASCII Unicode cha...
isRevisionCurrent()
Whether the revision displayed is the latest revision of the page.
Definition: Skin.php:326
$wgDefaultSkin
Default skin, for new users and anonymous visitors.
static makeNSUrl( $name, $urlaction='', $namespace=NS_MAIN)
this can be passed the NS number as defined in Language.php
Definition: Skin.php:1245
$wgSkipSkins
Specify the names of skins that should not be presented in the list of available skins in user prefer...
wfDeprecated( $function, $version=false, $component=false, $callerOffset=2)
Throws a warning that $function is deprecated.
$line
Definition: cdb.php:59
static getSkinNameMessages()
Fetch the skinname messages for available skins.
Definition: Skin.php:67
getCopyright( $type='detect')
Definition: Skin.php:851
static element( $element, $attribs=null, $contents='', $allowShortTag=true)
Format an XML element with given attributes and, optionally, text content.
Definition: Xml.php:41
$wgFallbackSkin
Fallback skin used when the skin defined by $wgDefaultSkin can&#39;t be found.
static validateTarget( $target, User $sender)
Validate target User.
getUndeleteLink()
Definition: Skin.php:726
static makeInternalOrExternalUrl( $name)
If url string starts with http, consider as external URL, else internal.
Definition: Skin.php:1230
getSkinStylePath( $name)
Return a fully resolved style path URL to images or styles stored in the current skin&#39;s folder...
Definition: Skin.php:1148
static getSafeTitleFor( $name, $subpage=false)
Get a localised Title object for a page name with a possibly unvalidated subpage. ...
static getDynamicStylesheetQuery()
Get the query to generate a dynamic stylesheet.
Definition: Skin.php:421
wfMessage( $key,... $params)
This is the function for getting translated interface messages.
static newFromName( $name, $validate='valid')
Static factory method for creation from username.
Definition: User.php:515
setupSkinUserCss(OutputPage $out)
Hook point for adding style modules to OutputPage.
Definition: Skin.php:434
static makeMainPageUrl( $urlaction='')
Definition: Skin.php:1163
$searchPage
getRevisionId()
Get the current revision ID.
Definition: Skin.php:316
outputPage()
Outputs the HTML generated by other functions.
escapeSearchLink()
Definition: Skin.php:842
getSkinName()
Definition: Skin.php:158
static getAllowedSkins()
Fetch the list of user-selectable skins in regards to $wgSkipSkins.
Definition: Skin.php:83
__construct( $skinname=null)
Definition: Skin.php:149
bottomScripts()
This gets called shortly before the "</body>" tag.
Definition: Skin.php:686
return true
Definition: router.php:92
static singleton()
Get the singleton instance of this class.
static makeSpecialUrlSubpage( $name, $subpage, $urlaction='')
Definition: Skin.php:1196
static run( $event, array $args=[], $deprecatedVersion=null)
Call hook functions defined in Hooks::register and $wgHooks.
Definition: Hooks.php:200
string null $skinname
Definition: Skin.php:42
static newFromText( $text, $defaultNamespace=NS_MAIN)
Create a new Title from text, such as what one would find in a link.
Definition: Title.php:319