MediaWiki REL1_32
Linker.php
Go to the documentation of this file.
1<?php
24
34class Linker {
40
84 public static function link(
85 $target, $html = null, $customAttribs = [], $query = [], $options = []
86 ) {
87 if ( !$target instanceof LinkTarget ) {
88 wfWarn( __METHOD__ . ': Requires $target to be a LinkTarget object.', 2 );
89 return "<!-- ERROR -->$html";
90 }
91
92 if ( is_string( $query ) ) {
93 // some functions withing core using this still hand over query strings
94 wfDeprecated( __METHOD__ . ' with parameter $query as string (should be array)', '1.20' );
96 }
97
98 $services = MediaWikiServices::getInstance();
100 if ( $options ) {
101 // Custom options, create new LinkRenderer
102 if ( !isset( $options['stubThreshold'] ) ) {
103 $defaultLinkRenderer = $services->getLinkRenderer();
104 $options['stubThreshold'] = $defaultLinkRenderer->getStubThreshold();
105 }
106 $linkRenderer = $services->getLinkRendererFactory()
107 ->createFromLegacyOptions( $options );
108 } else {
109 $linkRenderer = $services->getLinkRenderer();
110 }
111
112 if ( $html !== null ) {
113 $text = new HtmlArmor( $html );
114 } else {
115 $text = $html; // null
116 }
117 if ( in_array( 'known', $options, true ) ) {
118 return $linkRenderer->makeKnownLink( $target, $text, $customAttribs, $query );
119 } elseif ( in_array( 'broken', $options, true ) ) {
120 return $linkRenderer->makeBrokenLink( $target, $text, $customAttribs, $query );
121 } elseif ( in_array( 'noclasses', $options, true ) ) {
122 return $linkRenderer->makePreloadedLink( $target, $text, '', $customAttribs, $query );
123 } else {
124 return $linkRenderer->makeLink( $target, $text, $customAttribs, $query );
125 }
126 }
127
141 public static function linkKnown(
142 $target, $html = null, $customAttribs = [],
143 $query = [], $options = [ 'known' ]
144 ) {
145 return self::link( $target, $html, $customAttribs, $query, $options );
146 }
147
163 public static function makeSelfLinkObj( $nt, $html = '', $query = '', $trail = '', $prefix = '' ) {
164 $ret = "<a class=\"mw-selflink selflink\">{$prefix}{$html}</a>{$trail}";
165 if ( !Hooks::run( 'SelfLinkBegin', [ $nt, &$html, &$trail, &$prefix, &$ret ] ) ) {
166 return $ret;
167 }
168
169 if ( $html == '' ) {
170 $html = htmlspecialchars( $nt->getPrefixedText() );
171 }
172 list( $inside, $trail ) = self::splitTrail( $trail );
173 return "<a class=\"mw-selflink selflink\">{$prefix}{$html}{$inside}</a>{$trail}";
174 }
175
186 public static function getInvalidTitleDescription( IContextSource $context, $namespace, $title ) {
187 // First we check whether the namespace exists or not.
188 if ( MWNamespace::exists( $namespace ) ) {
189 if ( $namespace == NS_MAIN ) {
190 $name = $context->msg( 'blanknamespace' )->text();
191 } else {
192 $name = MediaWikiServices::getInstance()->getContentLanguage()->
193 getFormattedNsText( $namespace );
194 }
195 return $context->msg( 'invalidtitle-knownnamespace', $namespace, $name, $title )->text();
196 } else {
197 return $context->msg( 'invalidtitle-unknownnamespace', $namespace, $title )->text();
198 }
199 }
200
206 public static function normaliseSpecialPage( LinkTarget $target ) {
207 if ( $target->getNamespace() == NS_SPECIAL && !$target->isExternal() ) {
208 list( $name, $subpage ) = MediaWikiServices::getInstance()->getSpecialPageFactory()->
209 resolveAlias( $target->getDBkey() );
210 if ( !$name ) {
211 return $target;
212 }
213 $ret = SpecialPage::getTitleValueFor( $name, $subpage, $target->getFragment() );
214 return $ret;
215 } else {
216 return $target;
217 }
218 }
219
228 private static function fnamePart( $url ) {
229 $basename = strrchr( $url, '/' );
230 if ( false === $basename ) {
231 $basename = $url;
232 } else {
233 $basename = substr( $basename, 1 );
234 }
235 return $basename;
236 }
237
248 public static function makeExternalImage( $url, $alt = '' ) {
249 if ( $alt == '' ) {
250 $alt = self::fnamePart( $url );
251 }
252 $img = '';
253 $success = Hooks::run( 'LinkerMakeExternalImage', [ &$url, &$alt, &$img ] );
254 if ( !$success ) {
255 wfDebug( "Hook LinkerMakeExternalImage changed the output of external image "
256 . "with url {$url} and alt text {$alt} to {$img}\n", true );
257 return $img;
258 }
259 return Html::element( 'img',
260 [
261 'src' => $url,
262 'alt' => $alt ] );
263 }
264
301 public static function makeImageLink( Parser $parser, Title $title,
302 $file, $frameParams = [], $handlerParams = [], $time = false,
303 $query = "", $widthOption = null
304 ) {
305 $res = null;
306 $dummy = new DummyLinker;
307 if ( !Hooks::run( 'ImageBeforeProduceHTML', [ &$dummy, &$title,
308 &$file, &$frameParams, &$handlerParams, &$time, &$res,
309 $parser, &$query, &$widthOption
310 ] ) ) {
311 return $res;
312 }
313
314 if ( $file && !$file->allowInlineDisplay() ) {
315 wfDebug( __METHOD__ . ': ' . $title->getPrefixedDBkey() . " does not allow inline display\n" );
316 return self::link( $title );
317 }
318
319 // Clean up parameters
320 $page = $handlerParams['page'] ?? false;
321 if ( !isset( $frameParams['align'] ) ) {
322 $frameParams['align'] = '';
323 }
324 if ( !isset( $frameParams['alt'] ) ) {
325 $frameParams['alt'] = '';
326 }
327 if ( !isset( $frameParams['title'] ) ) {
328 $frameParams['title'] = '';
329 }
330 if ( !isset( $frameParams['class'] ) ) {
331 $frameParams['class'] = '';
332 }
333
334 $prefix = $postfix = '';
335
336 if ( 'center' == $frameParams['align'] ) {
337 $prefix = '<div class="center">';
338 $postfix = '</div>';
339 $frameParams['align'] = 'none';
340 }
341 if ( $file && !isset( $handlerParams['width'] ) ) {
342 if ( isset( $handlerParams['height'] ) && $file->isVectorized() ) {
343 // If its a vector image, and user only specifies height
344 // we don't want it to be limited by its "normal" width.
345 global $wgSVGMaxSize;
346 $handlerParams['width'] = $wgSVGMaxSize;
347 } else {
348 $handlerParams['width'] = $file->getWidth( $page );
349 }
350
351 if ( isset( $frameParams['thumbnail'] )
352 || isset( $frameParams['manualthumb'] )
353 || isset( $frameParams['framed'] )
354 || isset( $frameParams['frameless'] )
355 || !$handlerParams['width']
356 ) {
358
359 if ( $widthOption === null || !isset( $wgThumbLimits[$widthOption] ) ) {
360 $widthOption = User::getDefaultOption( 'thumbsize' );
361 }
362
363 // Reduce width for upright images when parameter 'upright' is used
364 if ( isset( $frameParams['upright'] ) && $frameParams['upright'] == 0 ) {
365 $frameParams['upright'] = $wgThumbUpright;
366 }
367
368 // For caching health: If width scaled down due to upright
369 // parameter, round to full __0 pixel to avoid the creation of a
370 // lot of odd thumbs.
371 $prefWidth = isset( $frameParams['upright'] ) ?
372 round( $wgThumbLimits[$widthOption] * $frameParams['upright'], -1 ) :
373 $wgThumbLimits[$widthOption];
374
375 // Use width which is smaller: real image width or user preference width
376 // Unless image is scalable vector.
377 if ( !isset( $handlerParams['height'] ) && ( $handlerParams['width'] <= 0 ||
378 $prefWidth < $handlerParams['width'] || $file->isVectorized() ) ) {
379 $handlerParams['width'] = $prefWidth;
380 }
381 }
382 }
383
384 if ( isset( $frameParams['thumbnail'] ) || isset( $frameParams['manualthumb'] )
385 || isset( $frameParams['framed'] )
386 ) {
387 # Create a thumbnail. Alignment depends on the writing direction of
388 # the page content language (right-aligned for LTR languages,
389 # left-aligned for RTL languages)
390 # If a thumbnail width has not been provided, it is set
391 # to the default user option as specified in Language*.php
392 if ( $frameParams['align'] == '' ) {
393 $frameParams['align'] = $parser->getTargetLanguage()->alignEnd();
394 }
395 return $prefix .
396 self::makeThumbLink2( $title, $file, $frameParams, $handlerParams, $time, $query ) .
397 $postfix;
398 }
399
400 if ( $file && isset( $frameParams['frameless'] ) ) {
401 $srcWidth = $file->getWidth( $page );
402 # For "frameless" option: do not present an image bigger than the
403 # source (for bitmap-style images). This is the same behavior as the
404 # "thumb" option does it already.
405 if ( $srcWidth && !$file->mustRender() && $handlerParams['width'] > $srcWidth ) {
406 $handlerParams['width'] = $srcWidth;
407 }
408 }
409
410 if ( $file && isset( $handlerParams['width'] ) ) {
411 # Create a resized image, without the additional thumbnail features
412 $thumb = $file->transform( $handlerParams );
413 } else {
414 $thumb = false;
415 }
416
417 if ( !$thumb ) {
418 $s = self::makeBrokenImageLinkObj( $title, $frameParams['title'], '', '', '', $time == true );
419 } else {
421 $params = [
422 'alt' => $frameParams['alt'],
423 'title' => $frameParams['title'],
424 'valign' => $frameParams['valign'] ?? false,
425 'img-class' => $frameParams['class'] ];
426 if ( isset( $frameParams['border'] ) ) {
427 $params['img-class'] .= ( $params['img-class'] !== '' ? ' ' : '' ) . 'thumbborder';
428 }
430
431 $s = $thumb->toHtml( $params );
432 }
433 if ( $frameParams['align'] != '' ) {
434 $s = Html::rawElement(
435 'div',
436 [ 'class' => 'float' . $frameParams['align'] ],
437 $s
438 );
439 }
440 return str_replace( "\n", ' ', $prefix . $s . $postfix );
441 }
442
451 private static function getImageLinkMTOParams( $frameParams, $query = '', $parser = null ) {
452 $mtoParams = [];
453 if ( isset( $frameParams['link-url'] ) && $frameParams['link-url'] !== '' ) {
454 $mtoParams['custom-url-link'] = $frameParams['link-url'];
455 if ( isset( $frameParams['link-target'] ) ) {
456 $mtoParams['custom-target-link'] = $frameParams['link-target'];
457 }
458 if ( $parser ) {
459 $extLinkAttrs = $parser->getExternalLinkAttribs( $frameParams['link-url'] );
460 foreach ( $extLinkAttrs as $name => $val ) {
461 // Currently could include 'rel' and 'target'
462 $mtoParams['parser-extlink-' . $name] = $val;
463 }
464 }
465 } elseif ( isset( $frameParams['link-title'] ) && $frameParams['link-title'] !== '' ) {
466 $mtoParams['custom-title-link'] = Title::newFromLinkTarget(
467 self::normaliseSpecialPage( $frameParams['link-title'] )
468 );
469 } elseif ( !empty( $frameParams['no-link'] ) ) {
470 // No link
471 } else {
472 $mtoParams['desc-link'] = true;
473 $mtoParams['desc-query'] = $query;
474 }
475 return $mtoParams;
476 }
477
490 public static function makeThumbLinkObj( Title $title, $file, $label = '', $alt = '',
491 $align = 'right', $params = [], $framed = false, $manualthumb = ""
492 ) {
493 $frameParams = [
494 'alt' => $alt,
495 'caption' => $label,
496 'align' => $align
497 ];
498 if ( $framed ) {
499 $frameParams['framed'] = true;
500 }
501 if ( $manualthumb ) {
502 $frameParams['manualthumb'] = $manualthumb;
503 }
504 return self::makeThumbLink2( $title, $file, $frameParams, $params );
505 }
506
516 public static function makeThumbLink2( Title $title, $file, $frameParams = [],
517 $handlerParams = [], $time = false, $query = ""
518 ) {
519 $exists = $file && $file->exists();
520
521 $page = $handlerParams['page'] ?? false;
522 if ( !isset( $frameParams['align'] ) ) {
523 $frameParams['align'] = 'right';
524 }
525 if ( !isset( $frameParams['alt'] ) ) {
526 $frameParams['alt'] = '';
527 }
528 if ( !isset( $frameParams['title'] ) ) {
529 $frameParams['title'] = '';
530 }
531 if ( !isset( $frameParams['caption'] ) ) {
532 $frameParams['caption'] = '';
533 }
534
535 if ( empty( $handlerParams['width'] ) ) {
536 // Reduce width for upright images when parameter 'upright' is used
537 $handlerParams['width'] = isset( $frameParams['upright'] ) ? 130 : 180;
538 }
539 $thumb = false;
540 $noscale = false;
541 $manualthumb = false;
542
543 if ( !$exists ) {
544 $outerWidth = $handlerParams['width'] + 2;
545 } else {
546 if ( isset( $frameParams['manualthumb'] ) ) {
547 # Use manually specified thumbnail
548 $manual_title = Title::makeTitleSafe( NS_FILE, $frameParams['manualthumb'] );
549 if ( $manual_title ) {
550 $manual_img = wfFindFile( $manual_title );
551 if ( $manual_img ) {
552 $thumb = $manual_img->getUnscaledThumb( $handlerParams );
553 $manualthumb = true;
554 } else {
555 $exists = false;
556 }
557 }
558 } elseif ( isset( $frameParams['framed'] ) ) {
559 // Use image dimensions, don't scale
560 $thumb = $file->getUnscaledThumb( $handlerParams );
561 $noscale = true;
562 } else {
563 # Do not present an image bigger than the source, for bitmap-style images
564 # This is a hack to maintain compatibility with arbitrary pre-1.10 behavior
565 $srcWidth = $file->getWidth( $page );
566 if ( $srcWidth && !$file->mustRender() && $handlerParams['width'] > $srcWidth ) {
567 $handlerParams['width'] = $srcWidth;
568 }
569 $thumb = $file->transform( $handlerParams );
570 }
571
572 if ( $thumb ) {
573 $outerWidth = $thumb->getWidth() + 2;
574 } else {
575 $outerWidth = $handlerParams['width'] + 2;
576 }
577 }
578
579 # ThumbnailImage::toHtml() already adds page= onto the end of DjVu URLs
580 # So we don't need to pass it here in $query. However, the URL for the
581 # zoom icon still needs it, so we make a unique query for it. See T16771
582 $url = $title->getLocalURL( $query );
583 if ( $page ) {
584 $url = wfAppendQuery( $url, [ 'page' => $page ] );
585 }
586 if ( $manualthumb
587 && !isset( $frameParams['link-title'] )
588 && !isset( $frameParams['link-url'] )
589 && !isset( $frameParams['no-link'] ) ) {
590 $frameParams['link-url'] = $url;
591 }
592
593 $s = "<div class=\"thumb t{$frameParams['align']}\">"
594 . "<div class=\"thumbinner\" style=\"width:{$outerWidth}px;\">";
595
596 if ( !$exists ) {
597 $s .= self::makeBrokenImageLinkObj( $title, $frameParams['title'], '', '', '', $time == true );
598 $zoomIcon = '';
599 } elseif ( !$thumb ) {
600 $s .= wfMessage( 'thumbnail_error', '' )->escaped();
601 $zoomIcon = '';
602 } else {
603 if ( !$noscale && !$manualthumb ) {
605 }
606 $params = [
607 'alt' => $frameParams['alt'],
608 'title' => $frameParams['title'],
609 'img-class' => ( isset( $frameParams['class'] ) && $frameParams['class'] !== ''
610 ? $frameParams['class'] . ' '
611 : '' ) . 'thumbimage'
612 ];
614 $s .= $thumb->toHtml( $params );
615 if ( isset( $frameParams['framed'] ) ) {
616 $zoomIcon = "";
617 } else {
618 $zoomIcon = Html::rawElement( 'div', [ 'class' => 'magnify' ],
619 Html::rawElement( 'a', [
620 'href' => $url,
621 'class' => 'internal',
622 'title' => wfMessage( 'thumbnail-more' )->text() ],
623 "" ) );
624 }
625 }
626 $s .= ' <div class="thumbcaption">' . $zoomIcon . $frameParams['caption'] . "</div></div></div>";
627 return str_replace( "\n", ' ', $s );
628 }
629
638 public static function processResponsiveImages( $file, $thumb, $hp ) {
639 global $wgResponsiveImages;
640 if ( $wgResponsiveImages && $thumb && !$thumb->isError() ) {
641 $hp15 = $hp;
642 $hp15['width'] = round( $hp['width'] * 1.5 );
643 $hp20 = $hp;
644 $hp20['width'] = $hp['width'] * 2;
645 if ( isset( $hp['height'] ) ) {
646 $hp15['height'] = round( $hp['height'] * 1.5 );
647 $hp20['height'] = $hp['height'] * 2;
648 }
649
650 $thumb15 = $file->transform( $hp15 );
651 $thumb20 = $file->transform( $hp20 );
652 if ( $thumb15 && !$thumb15->isError() && $thumb15->getUrl() !== $thumb->getUrl() ) {
653 $thumb->responsiveUrls['1.5'] = $thumb15->getUrl();
654 }
655 if ( $thumb20 && !$thumb20->isError() && $thumb20->getUrl() !== $thumb->getUrl() ) {
656 $thumb->responsiveUrls['2'] = $thumb20->getUrl();
657 }
658 }
659 }
660
673 public static function makeBrokenImageLinkObj( $title, $label = '',
674 $query = '', $unused1 = '', $unused2 = '', $time = false
675 ) {
676 if ( !$title instanceof Title ) {
677 wfWarn( __METHOD__ . ': Requires $title to be a Title object.' );
678 return "<!-- ERROR -->" . htmlspecialchars( $label );
679 }
680
682 if ( $label == '' ) {
683 $label = $title->getPrefixedText();
684 }
685 $encLabel = htmlspecialchars( $label );
686 $currentExists = $time ? ( wfFindFile( $title ) != false ) : false;
687
689 && !$currentExists
690 ) {
691 $redir = RepoGroup::singleton()->getLocalRepo()->checkRedirect( $title );
692
693 if ( $redir ) {
694 // We already know it's a redirect, so mark it
695 // accordingly
696 return self::link(
697 $title,
698 $encLabel,
699 [ 'class' => 'mw-redirect' ],
701 [ 'known', 'noclasses' ]
702 );
703 }
704
705 $href = self::getUploadUrl( $title, $query );
706
707 return '<a href="' . htmlspecialchars( $href ) . '" class="new" title="' .
708 htmlspecialchars( $title->getPrefixedText(), ENT_QUOTES ) . '">' .
709 $encLabel . '</a>';
710 }
711
712 return self::link( $title, $encLabel, [], wfCgiToArray( $query ), [ 'known', 'noclasses' ] );
713 }
714
723 protected static function getUploadUrl( $destFile, $query = '' ) {
725 $q = 'wpDestFile=' . $destFile->getPartialURL();
726 if ( $query != '' ) {
727 $q .= '&' . $query;
728 }
729
732 } elseif ( $wgUploadNavigationUrl ) {
734 } else {
735 $upload = SpecialPage::getTitleFor( 'Upload' );
736 return $upload->getLocalURL( $q );
737 }
738 }
739
749 public static function makeMediaLinkObj( $title, $html = '', $time = false ) {
750 $img = wfFindFile( $title, [ 'time' => $time ] );
751 return self::makeMediaLinkFile( $title, $img, $html );
752 }
753
766 public static function makeMediaLinkFile( Title $title, $file, $html = '' ) {
767 if ( $file && $file->exists() ) {
768 $url = $file->getUrl();
769 $class = 'internal';
770 } else {
771 $url = self::getUploadUrl( $title );
772 $class = 'new';
773 }
774
775 $alt = $title->getText();
776 if ( $html == '' ) {
777 $html = $alt;
778 }
779
780 $ret = '';
781 $attribs = [
782 'href' => $url,
783 'class' => $class,
784 'title' => $alt
785 ];
786
787 if ( !Hooks::run( 'LinkerMakeMediaLinkFile',
788 [ $title, $file, &$html, &$attribs, &$ret ] ) ) {
789 wfDebug( "Hook LinkerMakeMediaLinkFile changed the output of link "
790 . "with url {$url} and text {$html} to {$ret}\n", true );
791 return $ret;
792 }
793
794 return Html::rawElement( 'a', $attribs, $html );
795 }
796
807 public static function specialLink( $name, $key = '' ) {
808 if ( $key == '' ) {
809 $key = strtolower( $name );
810 }
811
812 return self::linkKnown( SpecialPage::getTitleFor( $name ), wfMessage( $key )->escaped() );
813 }
814
826 public static function makeExternalLink( $url, $text, $escape = true,
827 $linktype = '', $attribs = [], $title = null
828 ) {
829 global $wgTitle;
830 $class = "external";
831 if ( $linktype ) {
832 $class .= " $linktype";
833 }
834 if ( isset( $attribs['class'] ) && $attribs['class'] ) {
835 $class .= " {$attribs['class']}";
836 }
837 $attribs['class'] = $class;
838
839 if ( $escape ) {
840 $text = htmlspecialchars( $text );
841 }
842
843 if ( !$title ) {
844 $title = $wgTitle;
845 }
846 $newRel = Parser::getExternalLinkRel( $url, $title );
847 if ( !isset( $attribs['rel'] ) || $attribs['rel'] === '' ) {
848 $attribs['rel'] = $newRel;
849 } elseif ( $newRel !== '' ) {
850 // Merge the rel attributes.
851 $newRels = explode( ' ', $newRel );
852 $oldRels = explode( ' ', $attribs['rel'] );
853 $combined = array_unique( array_merge( $newRels, $oldRels ) );
854 $attribs['rel'] = implode( ' ', $combined );
855 }
856 $link = '';
857 $success = Hooks::run( 'LinkerMakeExternalLink',
858 [ &$url, &$text, &$link, &$attribs, $linktype ] );
859 if ( !$success ) {
860 wfDebug( "Hook LinkerMakeExternalLink changed the output of link "
861 . "with url {$url} and text {$text} to {$link}\n", true );
862 return $link;
863 }
864 $attribs['href'] = $url;
865 return Html::rawElement( 'a', $attribs, $text );
866 }
867
876 public static function userLink( $userId, $userName, $altUserName = false ) {
877 $classes = 'mw-userlink';
878 $page = null;
879 if ( $userId == 0 ) {
880 $page = ExternalUserNames::getUserLinkTitle( $userName );
881
882 if ( ExternalUserNames::isExternal( $userName ) ) {
883 $classes .= ' mw-extuserlink';
884 } elseif ( $altUserName === false ) {
885 $altUserName = IP::prettifyIP( $userName );
886 }
887 $classes .= ' mw-anonuserlink'; // Separate link class for anons (T45179)
888 } else {
889 $page = Title::makeTitle( NS_USER, $userName );
890 }
891
892 // Wrap the output with <bdi> tags for directionality isolation
893 $linkText =
894 '<bdi>' . htmlspecialchars( $altUserName !== false ? $altUserName : $userName ) . '</bdi>';
895
896 return $page
897 ? self::link( $page, $linkText, [ 'class' => $classes ] )
898 : Html::rawElement( 'span', [ 'class' => $classes ], $linkText );
899 }
900
914 public static function userToolLinks(
915 $userId, $userText, $redContribsWhenNoEdits = false, $flags = 0, $edits = null
916 ) {
917 global $wgUser, $wgDisableAnonTalk, $wgLang;
918 $talkable = !( $wgDisableAnonTalk && 0 == $userId );
919 $blockable = !( $flags & self::TOOL_LINKS_NOBLOCK );
920 $addEmailLink = $flags & self::TOOL_LINKS_EMAIL && $userId;
921
922 if ( $userId == 0 && ExternalUserNames::isExternal( $userText ) ) {
923 // No tools for an external user
924 return '';
925 }
926
927 $items = [];
928 if ( $talkable ) {
929 $items[] = self::userTalkLink( $userId, $userText );
930 }
931 if ( $userId ) {
932 // check if the user has an edit
933 $attribs = [];
934 $attribs['class'] = 'mw-usertoollinks-contribs';
935 if ( $redContribsWhenNoEdits ) {
936 if ( intval( $edits ) === 0 && $edits !== 0 ) {
937 $user = User::newFromId( $userId );
938 $edits = $user->getEditCount();
939 }
940 if ( $edits === 0 ) {
941 $attribs['class'] .= ' new';
942 }
943 }
944 $contribsPage = SpecialPage::getTitleFor( 'Contributions', $userText );
945
946 $items[] = self::link( $contribsPage, wfMessage( 'contribslink' )->escaped(), $attribs );
947 }
948 if ( $blockable && $wgUser->isAllowed( 'block' ) ) {
949 $items[] = self::blockLink( $userId, $userText );
950 }
951
952 if ( $addEmailLink && $wgUser->canSendEmail() ) {
953 $items[] = self::emailLink( $userId, $userText );
954 }
955
956 Hooks::run( 'UserToolLinksEdit', [ $userId, $userText, &$items ] );
957
958 if ( $items ) {
959 return wfMessage( 'word-separator' )->escaped()
960 . '<span class="mw-usertoollinks">'
961 . wfMessage( 'parentheses' )->rawParams( $wgLang->pipeList( $items ) )->escaped()
962 . '</span>';
963 } else {
964 return '';
965 }
966 }
967
976 public static function userToolLinksRedContribs( $userId, $userText, $edits = null ) {
977 return self::userToolLinks( $userId, $userText, true, 0, $edits );
978 }
979
986 public static function userTalkLink( $userId, $userText ) {
987 $userTalkPage = Title::makeTitle( NS_USER_TALK, $userText );
988 $moreLinkAttribs['class'] = 'mw-usertoollinks-talk';
989 $userTalkLink = self::link( $userTalkPage,
990 wfMessage( 'talkpagelinktext' )->escaped(),
991 $moreLinkAttribs );
992 return $userTalkLink;
993 }
994
1001 public static function blockLink( $userId, $userText ) {
1002 $blockPage = SpecialPage::getTitleFor( 'Block', $userText );
1003 $moreLinkAttribs['class'] = 'mw-usertoollinks-block';
1004 $blockLink = self::link( $blockPage,
1005 wfMessage( 'blocklink' )->escaped(),
1006 $moreLinkAttribs );
1007 return $blockLink;
1008 }
1009
1015 public static function emailLink( $userId, $userText ) {
1016 $emailPage = SpecialPage::getTitleFor( 'Emailuser', $userText );
1017 $moreLinkAttribs['class'] = 'mw-usertoollinks-mail';
1018 $emailLink = self::link( $emailPage,
1019 wfMessage( 'emaillink' )->escaped(),
1020 $moreLinkAttribs );
1021 return $emailLink;
1022 }
1023
1031 public static function revUserLink( $rev, $isPublic = false ) {
1032 if ( $rev->isDeleted( Revision::DELETED_USER ) && $isPublic ) {
1033 $link = wfMessage( 'rev-deleted-user' )->escaped();
1034 } elseif ( $rev->userCan( Revision::DELETED_USER ) ) {
1036 $rev->getUserText( Revision::FOR_THIS_USER ) );
1037 } else {
1038 $link = wfMessage( 'rev-deleted-user' )->escaped();
1039 }
1040 if ( $rev->isDeleted( Revision::DELETED_USER ) ) {
1041 return '<span class="history-deleted">' . $link . '</span>';
1042 }
1043 return $link;
1044 }
1045
1053 public static function revUserTools( $rev, $isPublic = false ) {
1054 if ( $rev->isDeleted( Revision::DELETED_USER ) && $isPublic ) {
1055 $link = wfMessage( 'rev-deleted-user' )->escaped();
1056 } elseif ( $rev->userCan( Revision::DELETED_USER ) ) {
1057 $userId = $rev->getUser( Revision::FOR_THIS_USER );
1058 $userText = $rev->getUserText( Revision::FOR_THIS_USER );
1059 $link = self::userLink( $userId, $userText )
1060 . self::userToolLinks( $userId, $userText );
1061 } else {
1062 $link = wfMessage( 'rev-deleted-user' )->escaped();
1063 }
1064 if ( $rev->isDeleted( Revision::DELETED_USER ) ) {
1065 return ' <span class="history-deleted">' . $link . '</span>';
1066 }
1067 return $link;
1068 }
1069
1088 public static function formatComment(
1089 $comment, $title = null, $local = false, $wikiId = null
1090 ) {
1091 # Sanitize text a bit:
1092 $comment = str_replace( "\n", " ", $comment );
1093 # Allow HTML entities (for T15815)
1094 $comment = Sanitizer::escapeHtmlAllowEntities( $comment );
1095
1096 # Render autocomments and make links:
1097 $comment = self::formatAutocomments( $comment, $title, $local, $wikiId );
1098 $comment = self::formatLinksInComment( $comment, $title, $local, $wikiId );
1099
1100 return $comment;
1101 }
1102
1120 private static function formatAutocomments(
1121 $comment, $title = null, $local = false, $wikiId = null
1122 ) {
1123 // @todo $append here is something of a hack to preserve the status
1124 // quo. Someone who knows more about bidi and such should decide
1125 // (1) what sane rendering even *is* for an LTR edit summary on an RTL
1126 // wiki, both when autocomments exist and when they don't, and
1127 // (2) what markup will make that actually happen.
1128 $append = '';
1129 $comment = preg_replace_callback(
1130 // To detect the presence of content before or after the
1131 // auto-comment, we use capturing groups inside optional zero-width
1132 // assertions. But older versions of PCRE can't directly make
1133 // zero-width assertions optional, so wrap them in a non-capturing
1134 // group.
1135 '!(?:(?<=(.)))?/\*\s*(.*?)\s*\*/(?:(?=(.)))?!',
1136 function ( $match ) use ( $title, $local, $wikiId, &$append ) {
1137 global $wgLang;
1138
1139 // Ensure all match positions are defined
1140 $match += [ '', '', '', '' ];
1141
1142 $pre = $match[1] !== '';
1143 $auto = $match[2];
1144 $post = $match[3] !== '';
1145 $comment = null;
1146
1147 Hooks::run(
1148 'FormatAutocomments',
1149 [ &$comment, $pre, $auto, $post, $title, $local, $wikiId ]
1150 );
1151
1152 if ( $comment === null ) {
1153 $link = '';
1154 if ( $title ) {
1155 $section = $auto;
1156 # Remove links that a user may have manually put in the autosummary
1157 # This could be improved by copying as much of Parser::stripSectionName as desired.
1158 $section = str_replace( '[[:', '', $section );
1159 $section = str_replace( '[[', '', $section );
1160 $section = str_replace( ']]', '', $section );
1161
1162 $section = substr( Parser::guessSectionNameFromStrippedText( $section ), 1 );
1163 if ( $local ) {
1164 $sectionTitle = Title::makeTitleSafe( NS_MAIN, '', $section );
1165 } else {
1166 $sectionTitle = Title::makeTitleSafe( $title->getNamespace(),
1167 $title->getDBkey(), $section );
1168 }
1169 if ( $sectionTitle ) {
1170 $link = Linker::makeCommentLink( $sectionTitle, $wgLang->getArrow(), $wikiId, 'noclasses' );
1171 } else {
1172 $link = '';
1173 }
1174 }
1175 if ( $pre ) {
1176 # written summary $presep autocomment (summary /* section */)
1177 $pre = wfMessage( 'autocomment-prefix' )->inContentLanguage()->escaped();
1178 }
1179 if ( $post ) {
1180 # autocomment $postsep written summary (/* section */ summary)
1181 $auto .= wfMessage( 'colon-separator' )->inContentLanguage()->escaped();
1182 }
1183 $auto = '<span class="autocomment">' . $auto . '</span>';
1184 $comment = $pre . $link . $wgLang->getDirMark()
1185 . '<span dir="auto">' . $auto;
1186 $append .= '</span>';
1187 }
1188 return $comment;
1189 },
1190 $comment
1191 );
1192 return $comment . $append;
1193 }
1194
1214 public static function formatLinksInComment(
1215 $comment, $title = null, $local = false, $wikiId = null
1216 ) {
1217 return preg_replace_callback(
1218 '/
1219 \[\[
1220 \s*+ # ignore leading whitespace, the *+ quantifier disallows backtracking
1221 :? # ignore optional leading colon
1222 ([^\]|]+) # 1. link target; page names cannot include ] or |
1223 (?:\|
1224 # 2. link text
1225 # Stop matching at ]] without relying on backtracking.
1226 ((?:]?[^\]])*+)
1227 )?
1228 \]\]
1229 ([^[]*) # 3. link trail (the text up until the next link)
1230 /x',
1231 function ( $match ) use ( $title, $local, $wikiId ) {
1232 $medians = '(?:' . preg_quote( MWNamespace::getCanonicalName( NS_MEDIA ), '/' ) . '|';
1233 $medians .= preg_quote(
1234 MediaWikiServices::getInstance()->getContentLanguage()->getNsText( NS_MEDIA ),
1235 '/'
1236 ) . '):';
1237
1238 $comment = $match[0];
1239
1240 # fix up urlencoded title texts (copied from Parser::replaceInternalLinks)
1241 if ( strpos( $match[1], '%' ) !== false ) {
1242 $match[1] = strtr(
1243 rawurldecode( $match[1] ),
1244 [ '<' => '&lt;', '>' => '&gt;' ]
1245 );
1246 }
1247
1248 # Handle link renaming [[foo|text]] will show link as "text"
1249 if ( $match[2] != "" ) {
1250 $text = $match[2];
1251 } else {
1252 $text = $match[1];
1253 }
1254 $submatch = [];
1255 $thelink = null;
1256 if ( preg_match( '/^' . $medians . '(.*)$/i', $match[1], $submatch ) ) {
1257 # Media link; trail not supported.
1258 $linkRegexp = '/\[\[(.*?)\]\]/';
1259 $title = Title::makeTitleSafe( NS_FILE, $submatch[1] );
1260 if ( $title ) {
1261 $thelink = Linker::makeMediaLinkObj( $title, $text );
1262 }
1263 } else {
1264 # Other kind of link
1265 # Make sure its target is non-empty
1266 if ( isset( $match[1][0] ) && $match[1][0] == ':' ) {
1267 $match[1] = substr( $match[1], 1 );
1268 }
1269 if ( $match[1] !== false && $match[1] !== '' ) {
1270 if ( preg_match(
1271 MediaWikiServices::getInstance()->getContentLanguage()->linkTrail(),
1272 $match[3],
1273 $submatch
1274 ) ) {
1275 $trail = $submatch[1];
1276 } else {
1277 $trail = "";
1278 }
1279 $linkRegexp = '/\[\[(.*?)\]\]' . preg_quote( $trail, '/' ) . '/';
1280 list( $inside, $trail ) = Linker::splitTrail( $trail );
1281
1282 $linkText = $text;
1283 $linkTarget = Linker::normalizeSubpageLink( $title, $match[1], $linkText );
1284
1285 $target = Title::newFromText( $linkTarget );
1286 if ( $target ) {
1287 if ( $target->getText() == '' && !$target->isExternal()
1288 && !$local && $title
1289 ) {
1290 $target = $title->createFragmentTarget( $target->getFragment() );
1291 }
1292
1293 $thelink = Linker::makeCommentLink( $target, $linkText . $inside, $wikiId ) . $trail;
1294 }
1295 }
1296 }
1297 if ( $thelink ) {
1298 // If the link is still valid, go ahead and replace it in!
1299 $comment = preg_replace(
1300 $linkRegexp,
1302 $comment,
1303 1
1304 );
1305 }
1306
1307 return $comment;
1308 },
1309 $comment
1310 );
1311 }
1312
1326 public static function makeCommentLink(
1327 LinkTarget $linkTarget, $text, $wikiId = null, $options = []
1328 ) {
1329 if ( $wikiId !== null && !$linkTarget->isExternal() ) {
1332 $wikiId,
1333 $linkTarget->getNamespace() === 0
1334 ? $linkTarget->getDBkey()
1335 : MWNamespace::getCanonicalName( $linkTarget->getNamespace() ) . ':'
1336 . $linkTarget->getDBkey(),
1337 $linkTarget->getFragment()
1338 ),
1339 $text,
1340 /* escape = */ false // Already escaped
1341 );
1342 } else {
1343 $link = self::link( $linkTarget, $text, [], [], $options );
1344 }
1345
1346 return $link;
1347 }
1348
1355 public static function normalizeSubpageLink( $contextTitle, $target, &$text ) {
1356 # Valid link forms:
1357 # Foobar -- normal
1358 # :Foobar -- override special treatment of prefix (images, language links)
1359 # /Foobar -- convert to CurrentPage/Foobar
1360 # /Foobar/ -- convert to CurrentPage/Foobar, strip the initial and final / from text
1361 # ../ -- convert to CurrentPage, from CurrentPage/CurrentSubPage
1362 # ../Foobar -- convert to CurrentPage/Foobar,
1363 # (from CurrentPage/CurrentSubPage)
1364 # ../Foobar/ -- convert to CurrentPage/Foobar, use 'Foobar' as text
1365 # (from CurrentPage/CurrentSubPage)
1366
1367 $ret = $target; # default return value is no change
1368
1369 # Some namespaces don't allow subpages,
1370 # so only perform processing if subpages are allowed
1371 if ( $contextTitle && MWNamespace::hasSubpages( $contextTitle->getNamespace() ) ) {
1372 $hash = strpos( $target, '#' );
1373 if ( $hash !== false ) {
1374 $suffix = substr( $target, $hash );
1375 $target = substr( $target, 0, $hash );
1376 } else {
1377 $suffix = '';
1378 }
1379 # T9425
1380 $target = trim( $target );
1381 # Look at the first character
1382 if ( $target != '' && $target[0] === '/' ) {
1383 # / at end means we don't want the slash to be shown
1384 $m = [];
1385 $trailingSlashes = preg_match_all( '%(/+)$%', $target, $m );
1386 if ( $trailingSlashes ) {
1387 $noslash = $target = substr( $target, 1, -strlen( $m[0][0] ) );
1388 } else {
1389 $noslash = substr( $target, 1 );
1390 }
1391
1392 $ret = $contextTitle->getPrefixedText() . '/' . trim( $noslash ) . $suffix;
1393 if ( $text === '' ) {
1394 $text = $target . $suffix;
1395 } # this might be changed for ugliness reasons
1396 } else {
1397 # check for .. subpage backlinks
1398 $dotdotcount = 0;
1399 $nodotdot = $target;
1400 while ( strncmp( $nodotdot, "../", 3 ) == 0 ) {
1401 ++$dotdotcount;
1402 $nodotdot = substr( $nodotdot, 3 );
1403 }
1404 if ( $dotdotcount > 0 ) {
1405 $exploded = explode( '/', $contextTitle->getPrefixedText() );
1406 if ( count( $exploded ) > $dotdotcount ) { # not allowed to go below top level page
1407 $ret = implode( '/', array_slice( $exploded, 0, -$dotdotcount ) );
1408 # / at the end means don't show full path
1409 if ( substr( $nodotdot, -1, 1 ) === '/' ) {
1410 $nodotdot = rtrim( $nodotdot, '/' );
1411 if ( $text === '' ) {
1412 $text = $nodotdot . $suffix;
1413 }
1414 }
1415 $nodotdot = trim( $nodotdot );
1416 if ( $nodotdot != '' ) {
1417 $ret .= '/' . $nodotdot;
1418 }
1419 $ret .= $suffix;
1420 }
1421 }
1422 }
1423 }
1424
1425 return $ret;
1426 }
1427
1441 public static function commentBlock(
1442 $comment, $title = null, $local = false, $wikiId = null
1443 ) {
1444 // '*' used to be the comment inserted by the software way back
1445 // in antiquity in case none was provided, here for backwards
1446 // compatibility, acc. to brion -ævar
1447 if ( $comment == '' || $comment == '*' ) {
1448 return '';
1449 } else {
1450 $formatted = self::formatComment( $comment, $title, $local, $wikiId );
1451 $formatted = wfMessage( 'parentheses' )->rawParams( $formatted )->escaped();
1452 return " <span class=\"comment\">$formatted</span>";
1453 }
1454 }
1455
1466 public static function revComment( Revision $rev, $local = false, $isPublic = false ) {
1467 if ( $rev->getComment( Revision::RAW ) == "" ) {
1468 return "";
1469 }
1470 if ( $rev->isDeleted( Revision::DELETED_COMMENT ) && $isPublic ) {
1471 $block = " <span class=\"comment\">" . wfMessage( 'rev-deleted-comment' )->escaped() . "</span>";
1472 } elseif ( $rev->userCan( Revision::DELETED_COMMENT ) ) {
1473 $block = self::commentBlock( $rev->getComment( Revision::FOR_THIS_USER ),
1474 $rev->getTitle(), $local );
1475 } else {
1476 $block = " <span class=\"comment\">" . wfMessage( 'rev-deleted-comment' )->escaped() . "</span>";
1477 }
1478 if ( $rev->isDeleted( Revision::DELETED_COMMENT ) ) {
1479 return " <span class=\"history-deleted\">$block</span>";
1480 }
1481 return $block;
1482 }
1483
1489 public static function formatRevisionSize( $size ) {
1490 if ( $size == 0 ) {
1491 $stxt = wfMessage( 'historyempty' )->escaped();
1492 } else {
1493 $stxt = wfMessage( 'nbytes' )->numParams( $size )->escaped();
1494 $stxt = wfMessage( 'parentheses' )->rawParams( $stxt )->escaped();
1495 }
1496 return "<span class=\"history-size\">$stxt</span>";
1497 }
1498
1505 public static function tocIndent() {
1506 return "\n<ul>\n";
1507 }
1508
1516 public static function tocUnindent( $level ) {
1517 return "</li>\n" . str_repeat( "</ul>\n</li>\n", $level > 0 ? $level : 0 );
1518 }
1519
1531 public static function tocLine( $anchor, $tocline, $tocnumber, $level, $sectionIndex = false ) {
1532 $classes = "toclevel-$level";
1533 if ( $sectionIndex !== false ) {
1534 $classes .= " tocsection-$sectionIndex";
1535 }
1536
1537 // <li class="$classes"><a href="#$anchor"><span class="tocnumber">
1538 // $tocnumber</span> <span class="toctext">$tocline</span></a>
1539 return Html::openElement( 'li', [ 'class' => $classes ] )
1540 . Html::rawElement( 'a',
1541 [ 'href' => "#$anchor" ],
1542 Html::element( 'span', [ 'class' => 'tocnumber' ], $tocnumber )
1543 . ' '
1544 . Html::rawElement( 'span', [ 'class' => 'toctext' ], $tocline )
1545 );
1546 }
1547
1555 public static function tocLineEnd() {
1556 return "</li>\n";
1557 }
1558
1567 public static function tocList( $toc, $lang = false ) {
1569 $title = wfMessage( 'toc' )->inLanguage( $lang )->escaped();
1570
1571 return '<div id="toc" class="toc">'
1572 . Html::element( 'input', [
1573 'type' => 'checkbox',
1574 'role' => 'button',
1575 'id' => 'toctogglecheckbox',
1576 'class' => 'toctogglecheckbox',
1577 'style' => 'display:none',
1578 ] )
1579 . Html::openElement( 'div', [
1580 'class' => 'toctitle',
1581 'lang' => $lang->getHtmlCode(),
1582 'dir' => $lang->getDir(),
1583 ] )
1584 . "<h2>$title</h2>"
1585 . '<span class="toctogglespan">'
1586 . Html::label( '', 'toctogglecheckbox', [
1587 'class' => 'toctogglelabel',
1588 ] )
1589 . '</span>'
1590 . "</div>\n"
1591 . $toc
1592 . "</ul>\n</div>\n";
1593 }
1594
1603 public static function generateTOC( $tree, $lang = false ) {
1604 $toc = '';
1605 $lastLevel = 0;
1606 foreach ( $tree as $section ) {
1607 if ( $section['toclevel'] > $lastLevel ) {
1608 $toc .= self::tocIndent();
1609 } elseif ( $section['toclevel'] < $lastLevel ) {
1610 $toc .= self::tocUnindent(
1611 $lastLevel - $section['toclevel'] );
1612 } else {
1613 $toc .= self::tocLineEnd();
1614 }
1615
1616 $toc .= self::tocLine( $section['anchor'],
1617 $section['line'], $section['number'],
1618 $section['toclevel'], $section['index'] );
1619 $lastLevel = $section['toclevel'];
1620 }
1621 $toc .= self::tocLineEnd();
1622 return self::tocList( $toc, $lang );
1623 }
1624
1641 public static function makeHeadline( $level, $attribs, $anchor, $html,
1642 $link, $fallbackAnchor = false
1643 ) {
1644 $anchorEscaped = htmlspecialchars( $anchor );
1645 $fallback = '';
1646 if ( $fallbackAnchor !== false && $fallbackAnchor !== $anchor ) {
1647 $fallbackAnchor = htmlspecialchars( $fallbackAnchor );
1648 $fallback = "<span id=\"$fallbackAnchor\"></span>";
1649 }
1650 $ret = "<h$level$attribs"
1651 . "$fallback<span class=\"mw-headline\" id=\"$anchorEscaped\">$html</span>"
1652 . $link
1653 . "</h$level>";
1654
1655 return $ret;
1656 }
1657
1664 static function splitTrail( $trail ) {
1665 $regex = MediaWikiServices::getInstance()->getContentLanguage()->linkTrail();
1666 $inside = '';
1667 if ( $trail !== '' ) {
1668 $m = [];
1669 if ( preg_match( $regex, $trail, $m ) ) {
1670 $inside = $m[1];
1671 $trail = $m[2];
1672 }
1673 }
1674 return [ $inside, $trail ];
1675 }
1676
1704 public static function generateRollback( $rev, IContextSource $context = null,
1705 $options = [ 'verify' ]
1706 ) {
1707 if ( $context === null ) {
1708 $context = RequestContext::getMain();
1709 }
1710
1711 $editCount = false;
1712 if ( in_array( 'verify', $options, true ) ) {
1713 $editCount = self::getRollbackEditCount( $rev, true );
1714 if ( $editCount === false ) {
1715 return '';
1716 }
1717 }
1718
1719 $inner = self::buildRollbackLink( $rev, $context, $editCount );
1720
1721 if ( !in_array( 'noBrackets', $options, true ) ) {
1722 $inner = $context->msg( 'brackets' )->rawParams( $inner )->escaped();
1723 }
1724
1725 return '<span class="mw-rollback-link">' . $inner . '</span>';
1726 }
1727
1743 public static function getRollbackEditCount( $rev, $verify ) {
1745 if ( !is_int( $wgShowRollbackEditCount ) || !$wgShowRollbackEditCount > 0 ) {
1746 // Nothing has happened, indicate this by returning 'null'
1747 return null;
1748 }
1749
1750 $dbr = wfGetDB( DB_REPLICA );
1751
1752 // Up to the value of $wgShowRollbackEditCount revisions are counted
1754 $res = $dbr->select(
1755 $revQuery['tables'],
1756 [ 'rev_user_text' => $revQuery['fields']['rev_user_text'], 'rev_deleted' ],
1757 // $rev->getPage() returns null sometimes
1758 [ 'rev_page' => $rev->getTitle()->getArticleID() ],
1759 __METHOD__,
1760 [
1761 'USE INDEX' => [ 'revision' => 'page_timestamp' ],
1762 'ORDER BY' => 'rev_timestamp DESC',
1763 'LIMIT' => $wgShowRollbackEditCount + 1
1764 ],
1765 $revQuery['joins']
1766 );
1767
1768 $editCount = 0;
1769 $moreRevs = false;
1770 foreach ( $res as $row ) {
1771 if ( $rev->getUserText( Revision::RAW ) != $row->rev_user_text ) {
1772 if ( $verify &&
1773 ( $row->rev_deleted & Revision::DELETED_TEXT
1774 || $row->rev_deleted & Revision::DELETED_USER
1775 ) ) {
1776 // If the user or the text of the revision we might rollback
1777 // to is deleted in some way we can't rollback. Similar to
1778 // the sanity checks in WikiPage::commitRollback.
1779 return false;
1780 }
1781 $moreRevs = true;
1782 break;
1783 }
1784 $editCount++;
1785 }
1786
1787 if ( $verify && $editCount <= $wgShowRollbackEditCount && !$moreRevs ) {
1788 // We didn't find at least $wgShowRollbackEditCount revisions made by the current user
1789 // and there weren't any other revisions. That means that the current user is the only
1790 // editor, so we can't rollback
1791 return false;
1792 }
1793 return $editCount;
1794 }
1795
1805 public static function buildRollbackLink( $rev, IContextSource $context = null,
1806 $editCount = false
1807 ) {
1809
1810 // To config which pages are affected by miser mode
1811 $disableRollbackEditCountSpecialPage = [ 'Recentchanges', 'Watchlist' ];
1812
1813 if ( $context === null ) {
1814 $context = RequestContext::getMain();
1815 }
1816
1817 $title = $rev->getTitle();
1818 $query = [
1819 'action' => 'rollback',
1820 'from' => $rev->getUserText(),
1821 'token' => $context->getUser()->getEditToken( 'rollback' ),
1822 ];
1823 $attrs = [
1824 'data-mw' => 'interface',
1825 'title' => $context->msg( 'tooltip-rollback' )->text(),
1826 ];
1827 $options = [ 'known', 'noclasses' ];
1828
1829 if ( $context->getRequest()->getBool( 'bot' ) ) {
1830 $query['bot'] = '1';
1831 $query['hidediff'] = '1'; // T17999
1832 }
1833
1834 $disableRollbackEditCount = false;
1835 if ( $wgMiserMode ) {
1836 foreach ( $disableRollbackEditCountSpecialPage as $specialPage ) {
1837 if ( $context->getTitle()->isSpecial( $specialPage ) ) {
1838 $disableRollbackEditCount = true;
1839 break;
1840 }
1841 }
1842 }
1843
1844 if ( !$disableRollbackEditCount
1845 && is_int( $wgShowRollbackEditCount )
1847 ) {
1848 if ( !is_numeric( $editCount ) ) {
1849 $editCount = self::getRollbackEditCount( $rev, false );
1850 }
1851
1852 if ( $editCount > $wgShowRollbackEditCount ) {
1853 $html = $context->msg( 'rollbacklinkcount-morethan' )
1854 ->numParams( $wgShowRollbackEditCount )->parse();
1855 } else {
1856 $html = $context->msg( 'rollbacklinkcount' )->numParams( $editCount )->parse();
1857 }
1858
1859 return self::link( $title, $html, $attrs, $query, $options );
1860 } else {
1861 $html = $context->msg( 'rollbacklink' )->escaped();
1862 return self::link( $title, $html, $attrs, $query, $options );
1863 }
1864 }
1865
1884 public static function formatTemplates( $templates, $preview = false,
1885 $section = false, $more = null
1886 ) {
1887 wfDeprecated( __METHOD__, '1.28' );
1888
1889 $type = false;
1890 if ( $preview ) {
1891 $type = 'preview';
1892 } elseif ( $section ) {
1893 $type = 'section';
1894 }
1895
1896 if ( $more instanceof Message ) {
1897 $more = $more->toString();
1898 }
1899
1900 $formatter = new TemplatesOnThisPageFormatter(
1901 RequestContext::getMain(),
1902 MediaWikiServices::getInstance()->getLinkRenderer()
1903 );
1904 return $formatter->format( $templates, $type, $more );
1905 }
1906
1915 public static function formatHiddenCategories( $hiddencats ) {
1916 $outText = '';
1917 if ( count( $hiddencats ) > 0 ) {
1918 # Construct the HTML
1919 $outText = '<div class="mw-hiddenCategoriesExplanation">';
1920 $outText .= wfMessage( 'hiddencategories' )->numParams( count( $hiddencats ) )->parseAsBlock();
1921 $outText .= "</div><ul>\n";
1922
1923 foreach ( $hiddencats as $titleObj ) {
1924 # If it's hidden, it must exist - no need to check with a LinkBatch
1925 $outText .= '<li>'
1926 . self::link( $titleObj, null, [], [], 'known' )
1927 . "</li>\n";
1928 }
1929 $outText .= '</ul>';
1930 }
1931 return $outText;
1932 }
1933
1944 public static function formatSize( $size ) {
1945 wfDeprecated( __METHOD__, '1.28' );
1946
1947 global $wgLang;
1948 return htmlspecialchars( $wgLang->formatSize( $size ) );
1949 }
1950
1967 public static function titleAttrib( $name, $options = null, array $msgParams = [] ) {
1968 $message = wfMessage( "tooltip-$name", $msgParams );
1969 if ( !$message->exists() ) {
1970 $tooltip = false;
1971 } else {
1972 $tooltip = $message->text();
1973 # Compatibility: formerly some tooltips had [alt-.] hardcoded
1974 $tooltip = preg_replace( "/ ?\[alt-.\]$/", '', $tooltip );
1975 # Message equal to '-' means suppress it.
1976 if ( $tooltip == '-' ) {
1977 $tooltip = false;
1978 }
1979 }
1980
1982
1983 if ( in_array( 'nonexisting', $options ) ) {
1984 $tooltip = wfMessage( 'red-link-title', $tooltip ?: '' )->text();
1985 }
1986 if ( in_array( 'withaccess', $options ) ) {
1987 $accesskey = self::accesskey( $name );
1988 if ( $accesskey !== false ) {
1989 // Should be build the same as in jquery.accessKeyLabel.js
1990 if ( $tooltip === false || $tooltip === '' ) {
1991 $tooltip = wfMessage( 'brackets', $accesskey )->text();
1992 } else {
1993 $tooltip .= wfMessage( 'word-separator' )->text();
1994 $tooltip .= wfMessage( 'brackets', $accesskey )->text();
1995 }
1996 }
1997 }
1998
1999 return $tooltip;
2000 }
2001
2002 public static $accesskeycache;
2003
2015 public static function accesskey( $name ) {
2016 if ( isset( self::$accesskeycache[$name] ) ) {
2017 return self::$accesskeycache[$name];
2018 }
2019
2020 $message = wfMessage( "accesskey-$name" );
2021
2022 if ( !$message->exists() ) {
2023 $accesskey = false;
2024 } else {
2025 $accesskey = $message->plain();
2026 if ( $accesskey === '' || $accesskey === '-' ) {
2027 # @todo FIXME: Per standard MW behavior, a value of '-' means to suppress the
2028 # attribute, but this is broken for accesskey: that might be a useful
2029 # value.
2030 $accesskey = false;
2031 }
2032 }
2033
2034 self::$accesskeycache[$name] = $accesskey;
2035 return self::$accesskeycache[$name];
2036 }
2037
2051 public static function getRevDeleteLink( User $user, Revision $rev, Title $title ) {
2052 $canHide = $user->isAllowed( 'deleterevision' );
2053 if ( !$canHide && !( $rev->getVisibility() && $user->isAllowed( 'deletedhistory' ) ) ) {
2054 return '';
2055 }
2056
2057 if ( !$rev->userCan( Revision::DELETED_RESTRICTED, $user ) ) {
2058 return self::revDeleteLinkDisabled( $canHide ); // revision was hidden from sysops
2059 } else {
2060 if ( $rev->getId() ) {
2061 // RevDelete links using revision ID are stable across
2062 // page deletion and undeletion; use when possible.
2063 $query = [
2064 'type' => 'revision',
2065 'target' => $title->getPrefixedDBkey(),
2066 'ids' => $rev->getId()
2067 ];
2068 } else {
2069 // Older deleted entries didn't save a revision ID.
2070 // We have to refer to these by timestamp, ick!
2071 $query = [
2072 'type' => 'archive',
2073 'target' => $title->getPrefixedDBkey(),
2074 'ids' => $rev->getTimestamp()
2075 ];
2076 }
2078 $rev->isDeleted( Revision::DELETED_RESTRICTED ), $canHide );
2079 }
2080 }
2081
2092 public static function revDeleteLink( $query = [], $restricted = false, $delete = true ) {
2093 $sp = SpecialPage::getTitleFor( 'Revisiondelete' );
2094 $msgKey = $delete ? 'rev-delundel' : 'rev-showdeleted';
2095 $html = wfMessage( $msgKey )->escaped();
2096 $tag = $restricted ? 'strong' : 'span';
2097 $link = self::link( $sp, $html, [], $query, [ 'known', 'noclasses' ] );
2098 return Xml::tags(
2099 $tag,
2100 [ 'class' => 'mw-revdelundel-link' ],
2101 wfMessage( 'parentheses' )->rawParams( $link )->escaped()
2102 );
2103 }
2104
2114 public static function revDeleteLinkDisabled( $delete = true ) {
2115 $msgKey = $delete ? 'rev-delundel' : 'rev-showdeleted';
2116 $html = wfMessage( $msgKey )->escaped();
2117 $htmlParentheses = wfMessage( 'parentheses' )->rawParams( $html )->escaped();
2118 return Xml::tags( 'span', [ 'class' => 'mw-revdelundel-link' ], $htmlParentheses );
2119 }
2120
2133 public static function tooltipAndAccesskeyAttribs(
2134 $name,
2135 array $msgParams = [],
2136 $options = null
2137 ) {
2139 $options[] = 'withaccess';
2140
2141 $attribs = [
2142 'title' => self::titleAttrib( $name, $options, $msgParams ),
2143 'accesskey' => self::accesskey( $name )
2144 ];
2145 if ( $attribs['title'] === false ) {
2146 unset( $attribs['title'] );
2147 }
2148 if ( $attribs['accesskey'] === false ) {
2149 unset( $attribs['accesskey'] );
2150 }
2151 return $attribs;
2152 }
2153
2161 public static function tooltip( $name, $options = null ) {
2162 $tooltip = self::titleAttrib( $name, $options );
2163 if ( $tooltip === false ) {
2164 return '';
2165 }
2166 return Xml::expandAttributes( [
2167 'title' => $tooltip
2168 ] );
2169 }
2170
2171}
This list may contain false positives That usually means there is additional text with links below the first Each row contains links to the first and second as well as the first line of the second redirect text
$wgThumbUpright
Adjust width of upright images when parameter 'upright' is used This allows a nicer look for upright ...
$wgThumbLimits
Adjust thumbnails on image pages according to a user setting.
$wgDisableAnonTalk
Disable links to talk pages of anonymous users (IPs) in listings on special pages like page history,...
$wgSVGMaxSize
Don't scale a SVG larger than this.
$wgShowRollbackEditCount
The $wgShowRollbackEditCount variable is used to show how many edits can be rolled back.
$wgUploadMissingFileUrl
Point the upload link for missing files to an external URL, as with $wgUploadNavigationUrl.
$wgUploadNavigationUrl
Point the upload navigation link to an external URL Useful if you want to use a shared repository by ...
$wgResponsiveImages
Generate and use thumbnails suitable for screens with 1.5 and 2.0 pixel densities.
$wgEnableUploads
Allow users to upload files.
$wgMiserMode
Disable database-intensive features.
wfGetLangObj( $langcode=false)
Return a Language object from $langcode.
wfDebug( $text, $dest='all', array $context=[])
Sends a line to the debug log if enabled or, optionally, to a comment in output.
wfWarn( $msg, $callerOffset=1, $level=E_USER_NOTICE)
Send a warning either to the debug log or in a PHP error depending on $wgDevelopmentWarnings.
wfGetDB( $db, $groups=[], $wiki=false)
Get a Database object.
wfFindFile( $title, $options=[])
Find a file.
wfAppendQuery( $url, $query)
Append a query string to an existing URL, which may or may not already have query string parameters a...
wfCgiToArray( $query)
This is the logical opposite of wfArrayToCgi(): it accepts a query string as its argument and returns...
wfDeprecated( $function, $version=false, $component=false, $callerOffset=2)
Throws a warning that $function is deprecated.
$fallback
$wgLang
Definition Setup.php:910
if(! $wgRequest->checkUrlExtension()) if(isset( $_SERVER['PATH_INFO']) && $_SERVER['PATH_INFO'] !='') $wgTitle
Definition api.php:57
static getUserLinkTitle( $userName)
Get a target Title to link a username.
static isExternal( $username)
Tells whether the username is external or not.
Marks HTML that shouldn't be escaped.
Definition HtmlArmor.php:28
Some internal bits split of from Skin.php.
Definition Linker.php:34
static tocList( $toc, $lang=false)
Wraps the TOC in a table and provides the hide/collapse javascript.
Definition Linker.php:1567
static generateRollback( $rev, IContextSource $context=null, $options=[ 'verify'])
Generate a rollback link for a given revision.
Definition Linker.php:1704
static makeMediaLinkFile(Title $title, $file, $html='')
Create a direct link to a given uploaded file.
Definition Linker.php:766
static link( $target, $html=null, $customAttribs=[], $query=[], $options=[])
This function returns an HTML link to the given target.
Definition Linker.php:84
static fnamePart( $url)
Returns the filename part of an url.
Definition Linker.php:228
static tocLine( $anchor, $tocline, $tocnumber, $level, $sectionIndex=false)
parameter level defines if we are on an indentation level
Definition Linker.php:1531
static userLink( $userId, $userName, $altUserName=false)
Make user link (or user contributions for unregistered users)
Definition Linker.php:876
static $accesskeycache
Definition Linker.php:2002
static titleAttrib( $name, $options=null, array $msgParams=[])
Given the id of an interface element, constructs the appropriate title attribute from the system mess...
Definition Linker.php:1967
static makeThumbLink2(Title $title, $file, $frameParams=[], $handlerParams=[], $time=false, $query="")
Definition Linker.php:516
static formatSize( $size)
Definition Linker.php:1944
static accesskey( $name)
Given the id of an interface element, constructs the appropriate accesskey attribute from the system ...
Definition Linker.php:2015
static formatAutocomments( $comment, $title=null, $local=false, $wikiId=null)
Converts autogenerated comments in edit summaries into section links.
Definition Linker.php:1120
static specialLink( $name, $key='')
Make a link to a special page given its name and, optionally, a message key from the link text.
Definition Linker.php:807
static makeImageLink(Parser $parser, Title $title, $file, $frameParams=[], $handlerParams=[], $time=false, $query="", $widthOption=null)
Given parameters derived from [[Image:Foo|options...]], generate the HTML that that syntax inserts in...
Definition Linker.php:301
static linkKnown( $target, $html=null, $customAttribs=[], $query=[], $options=[ 'known'])
Identical to link(), except $options defaults to 'known'.
Definition Linker.php:141
static generateTOC( $tree, $lang=false)
Generate a table of contents from a section tree.
Definition Linker.php:1603
static makeExternalImage( $url, $alt='')
Return the code for images which were added via external links, via Parser::maybeMakeExternalImage().
Definition Linker.php:248
static userToolLinksRedContribs( $userId, $userText, $edits=null)
Alias for userToolLinks( $userId, $userText, true );.
Definition Linker.php:976
static buildRollbackLink( $rev, IContextSource $context=null, $editCount=false)
Build a raw rollback link, useful for collections of "tool" links.
Definition Linker.php:1805
static makeCommentLink(LinkTarget $linkTarget, $text, $wikiId=null, $options=[])
Generates a link to the given Title.
Definition Linker.php:1326
static processResponsiveImages( $file, $thumb, $hp)
Process responsive images: add 1.5x and 2x subimages to the thumbnail, where applicable.
Definition Linker.php:638
static blockLink( $userId, $userText)
Definition Linker.php:1001
static revDeleteLinkDisabled( $delete=true)
Creates a dead (show/hide) link for deleting revisions/log entries.
Definition Linker.php:2114
static getRollbackEditCount( $rev, $verify)
This function will return the number of revisions which a rollback would revert and,...
Definition Linker.php:1743
static normalizeSubpageLink( $contextTitle, $target, &$text)
Definition Linker.php:1355
static revComment(Revision $rev, $local=false, $isPublic=false)
Wrap and format the given revision's comment block, if the current user is allowed to view it.
Definition Linker.php:1466
const TOOL_LINKS_NOBLOCK
Flags for userToolLinks()
Definition Linker.php:38
static makeSelfLinkObj( $nt, $html='', $query='', $trail='', $prefix='')
Make appropriate markup for a link to the current article.
Definition Linker.php:163
static getUploadUrl( $destFile, $query='')
Get the URL to upload a certain file.
Definition Linker.php:723
static tocIndent()
Add another level to the Table of Contents.
Definition Linker.php:1505
static revUserLink( $rev, $isPublic=false)
Generate a user link if the current user is allowed to view it.
Definition Linker.php:1031
static commentBlock( $comment, $title=null, $local=false, $wikiId=null)
Wrap a comment in standard punctuation and formatting if it's non-empty, otherwise return empty strin...
Definition Linker.php:1441
static getInvalidTitleDescription(IContextSource $context, $namespace, $title)
Get a message saying that an invalid title was encountered.
Definition Linker.php:186
static revUserTools( $rev, $isPublic=false)
Generate a user tool link cluster if the current user is allowed to view it.
Definition Linker.php:1053
static emailLink( $userId, $userText)
Definition Linker.php:1015
static formatHiddenCategories( $hiddencats)
Returns HTML for the "hidden categories on this page" list.
Definition Linker.php:1915
static splitTrail( $trail)
Split a link trail, return the "inside" portion and the remainder of the trail as a two-element array...
Definition Linker.php:1664
static makeThumbLinkObj(Title $title, $file, $label='', $alt='', $align='right', $params=[], $framed=false, $manualthumb="")
Make HTML for a thumbnail including image, border and caption.
Definition Linker.php:490
const TOOL_LINKS_EMAIL
Definition Linker.php:39
static userToolLinks( $userId, $userText, $redContribsWhenNoEdits=false, $flags=0, $edits=null)
Generate standard user tool links (talk, contributions, block link, etc.)
Definition Linker.php:914
static formatRevisionSize( $size)
Definition Linker.php:1489
static tooltip( $name, $options=null)
Returns raw bits of HTML, use titleAttrib()
Definition Linker.php:2161
static userTalkLink( $userId, $userText)
Definition Linker.php:986
static formatLinksInComment( $comment, $title=null, $local=false, $wikiId=null)
Formats wiki links and media links in text; all other wiki formatting is ignored.
Definition Linker.php:1214
static makeMediaLinkObj( $title, $html='', $time=false)
Create a direct link to a given uploaded file.
Definition Linker.php:749
static makeExternalLink( $url, $text, $escape=true, $linktype='', $attribs=[], $title=null)
Make an external link.
Definition Linker.php:826
static normaliseSpecialPage(LinkTarget $target)
Definition Linker.php:206
static makeHeadline( $level, $attribs, $anchor, $html, $link, $fallbackAnchor=false)
Create a headline for content.
Definition Linker.php:1641
static formatTemplates( $templates, $preview=false, $section=false, $more=null)
Definition Linker.php:1884
static tocUnindent( $level)
Finish one or more sublevels on the Table of Contents.
Definition Linker.php:1516
static tooltipAndAccesskeyAttribs( $name, array $msgParams=[], $options=null)
Returns the attributes for the tooltip and access key.
Definition Linker.php:2133
static getImageLinkMTOParams( $frameParams, $query='', $parser=null)
Get the link parameters for MediaTransformOutput::toHtml() from given frame parameters supplied by th...
Definition Linker.php:451
static revDeleteLink( $query=[], $restricted=false, $delete=true)
Creates a (show/hide) link for deleting revisions/log entries.
Definition Linker.php:2092
static tocLineEnd()
End a Table Of Contents line.
Definition Linker.php:1555
static formatComment( $comment, $title=null, $local=false, $wikiId=null)
This function is called by all recent changes variants, by the page history, and by the user contribu...
Definition Linker.php:1088
static makeBrokenImageLinkObj( $title, $label='', $query='', $unused1='', $unused2='', $time=false)
Make a "broken" link to an image.
Definition Linker.php:673
static getRevDeleteLink(User $user, Revision $rev, Title $title)
Get a revision-deletion link, or disabled link, or nothing, depending on user permissions & the setti...
Definition Linker.php:2051
MediaWikiServices is the service locator for the application scope of MediaWiki.
The Message class provides methods which fulfil two basic services:
Definition Message.php:160
PHP Parser - Processes wiki markup (which uses a more user-friendly syntax, such as "[[link]]" for ma...
Definition Parser.php:68
static singleton()
Get a RepoGroup instance.
Definition RepoGroup.php:59
const DELETED_USER
Definition Revision.php:49
static getQueryInfo( $options=[])
Return the tables, fields, and join conditions to be selected to create a new revision object.
Definition Revision.php:521
const DELETED_TEXT
Definition Revision.php:47
const DELETED_RESTRICTED
Definition Revision.php:50
const RAW
Definition Revision.php:57
const DELETED_COMMENT
Definition Revision.php:48
const FOR_THIS_USER
Definition Revision.php:56
static escapeRegexReplacement( $string)
Escape a string to make it suitable for inclusion in a preg_replace() replacement parameter.
Handles formatting for the "templates used on this page" lists.
Represents a title within MediaWiki.
Definition Title.php:39
The User object encapsulates all of the user-specific settings (user_id, name, rights,...
Definition User.php:47
static newFromId( $id)
Static factory method for creation from a given user ID.
Definition User.php:615
static getDefaultOption( $opt)
Get a given default option value.
Definition User.php:1818
static getForeignURL( $wikiID, $page, $fragmentId=null)
Convenience to get a url to a page on a foreign wiki.
Definition WikiMap.php:171
$res
Definition database.txt:21
deferred txt A few of the database updates required by various functions here can be deferred until after the result page is displayed to the user For updating the view updating the linked to tables after a etc PHP does not yet have any way to tell the server to actually return and disconnect while still running these but it might have such a feature in the future We handle these by creating a deferred update object and putting those objects on a global list
Definition deferred.txt:11
see documentation in includes Linker php for Linker::makeImageLink or false for current used if you return false $parser
Definition hooks.txt:1873
see documentation in includes Linker php for Linker::makeImageLink & $time
Definition hooks.txt:1841
return true to allow those checks to and false if checking is done remove or add to the links of a group of changes in EnhancedChangesList Hook subscribers can return false to omit this line from recentchanges use this to change the tables headers change it to an object instance and return false override the list derivative used the name of the old file when set the default code will be skipped $pre
Definition hooks.txt:1621
return true to allow those checks to and false if checking is done remove or add to the links of a group of changes in EnhancedChangesList Hook subscribers can return false to omit this line from recentchanges use this to change the tables headers change it to an object instance and return false override the list derivative used the name of the old file when set the default code will be skipped true if there is text before this autocomment $auto
Definition hooks.txt:1623
null means default in associative array with keys and values unescaped Should be merged with default with a value of false meaning to suppress the attribute in associative array with keys and values unescaped & $options
Definition hooks.txt:2050
usually copyright or history_copyright This message must be in HTML not wikitext if the section is included from a template to be included in the link
Definition hooks.txt:3108
do that in ParserLimitReportFormat instead use this to modify the parameters of the image all existing parser cache entries will be invalid To avoid you ll need to handle that somehow(e.g. with the RejectParserCacheValue hook) because MediaWiki won 't do it for you. & $defaults also a ContextSource after deleting those rows but within the same transaction you ll probably need to make sure the header is varied on and they can depend only on the ResourceLoaderContext $context
Definition hooks.txt:2885
null means default & $customAttribs
Definition hooks.txt:2044
static configuration should be added through ResourceLoaderGetConfigVars instead can be used to get the real title e g db for database replication lag or jobqueue for job queue size converted to pseudo seconds It is possible to add more fields and they will be returned to the user in the API response after the basic globals have been set but before ordinary actions take place or wrap services the preferred way to define a new service is the $wgServiceWiringFiles array $services
Definition hooks.txt:2335
null means default in associative array with keys and values unescaped Should be merged with default with a value of false meaning to suppress the attribute in associative array with keys and values unescaped noclasses & $ret
Definition hooks.txt:2054
either a unescaped string or a HtmlArmor object after in associative array form externallinks including delete and has completed for all link tables whether this was an auto creation use $formDescriptor instead default is conds Array Extra conditions for the No matching items in log is displayed if loglist is empty msgKey Array If you want a nice box with a set this to the key of the message First element is the message additional optional elements are parameters for the key that are processed with wfMessage() -> params() ->parseAsBlock() - offset Set to overwrite offset parameter in $wgRequest set to '' to unset offset - wrap String Wrap the message in html(usually something like "&lt;div ...>$1&lt;/div>"). - flags Integer display flags(NO_ACTION_LINK, NO_EXTRA_USER_LINKS) 'LogException':Called before an exception(or PHP error) is logged. This is meant for integration with external error aggregation services
null means default in associative array with keys and values unescaped Should be merged with default with a value of false meaning to suppress the attribute in associative array with keys and values unescaped noclasses just before the function returns a value If you return an< a > element with HTML attributes $attribs and contents $html will be returned If you return $ret will be returned and may include noclasses & $html
Definition hooks.txt:2062
usually copyright or history_copyright This message must be in HTML not wikitext & $link
Definition hooks.txt:3106
Allows to change the fields on the form that will be generated $name
Definition hooks.txt:302
null means default in associative array with keys and values unescaped Should be merged with default with a value of false meaning to suppress the attribute in associative array with keys and values unescaped noclasses just before the function returns a value If you return an< a > element with HTML attributes $attribs and contents $html will be returned If you return $ret will be returned and may include noclasses after processing & $attribs
Definition hooks.txt:2063
null for the local wiki Added should default to null in handler for backwards compatibility add a value to it if you want to add a cookie that have to vary cache options can modify $query
Definition hooks.txt:1656
null means default in associative array with keys and values unescaped Should be merged with default with a value of false meaning to suppress the attribute in associative array with keys and values unescaped noclasses just before the function returns a value If you return an< a > element with HTML attributes $attribs and contents $html will be returned If you return $ret will be returned and may include noclasses after processing after in associative array form before processing starts Return false to skip default processing and return $ret $linkRenderer
Definition hooks.txt:2105
see documentation in includes Linker php for Linker::makeImageLink & $handlerParams
Definition hooks.txt:1839
usually copyright or history_copyright This message must be in HTML not wikitext if the section is included from a template $section
Definition hooks.txt:3107
presenting them properly to the user as errors is done by the caller return true use this to change the list i e etc $rev
Definition hooks.txt:1818
processing should stop and the error should be shown to the user * false
Definition hooks.txt:187
const NS_FILE
Definition Defines.php:70
const NS_MAIN
Definition Defines.php:64
const NS_SPECIAL
Definition Defines.php:53
const NS_MEDIA
Definition Defines.php:52
const NS_USER_TALK
Definition Defines.php:67
Interface for objects which can provide a MediaWiki context on request.
getFragment()
Get the link fragment (i.e.
getNamespace()
Get the namespace index.
getDBkey()
Get the main part with underscores.
isExternal()
Whether this LinkTarget has an interwiki component.
The wiki should then use memcached to cache various data To use multiple just add more items to the array To increase the weight of a make its entry a array("192.168.0.1:11211", 2))
const DB_REPLICA
Definition defines.php:25
$params
if(!isset( $args[0])) $lang