MediaWiki REL1_33
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 = null;
116 }
117
118 if ( in_array( 'known', $options, true ) ) {
119 return $linkRenderer->makeKnownLink( $target, $text, $customAttribs, $query );
120 }
121
122 if ( in_array( 'broken', $options, true ) ) {
123 return $linkRenderer->makeBrokenLink( $target, $text, $customAttribs, $query );
124 }
125
126 if ( in_array( 'noclasses', $options, true ) ) {
127 return $linkRenderer->makePreloadedLink( $target, $text, '', $customAttribs, $query );
128 }
129
130 return $linkRenderer->makeLink( $target, $text, $customAttribs, $query );
131 }
132
146 public static function linkKnown(
147 $target, $html = null, $customAttribs = [],
148 $query = [], $options = [ 'known' ]
149 ) {
150 return self::link( $target, $html, $customAttribs, $query, $options );
151 }
152
168 public static function makeSelfLinkObj( $nt, $html = '', $query = '', $trail = '', $prefix = '' ) {
169 $ret = "<a class=\"mw-selflink selflink\">{$prefix}{$html}</a>{$trail}";
170 if ( !Hooks::run( 'SelfLinkBegin', [ $nt, &$html, &$trail, &$prefix, &$ret ] ) ) {
171 return $ret;
172 }
173
174 if ( $html == '' ) {
175 $html = htmlspecialchars( $nt->getPrefixedText() );
176 }
177 list( $inside, $trail ) = self::splitTrail( $trail );
178 return "<a class=\"mw-selflink selflink\">{$prefix}{$html}{$inside}</a>{$trail}";
179 }
180
191 public static function getInvalidTitleDescription( IContextSource $context, $namespace, $title ) {
192 // First we check whether the namespace exists or not.
193 if ( MWNamespace::exists( $namespace ) ) {
194 if ( $namespace == NS_MAIN ) {
195 $name = $context->msg( 'blanknamespace' )->text();
196 } else {
197 $name = MediaWikiServices::getInstance()->getContentLanguage()->
198 getFormattedNsText( $namespace );
199 }
200 return $context->msg( 'invalidtitle-knownnamespace', $namespace, $name, $title )->text();
201 }
202
203 return $context->msg( 'invalidtitle-unknownnamespace', $namespace, $title )->text();
204 }
205
211 public static function normaliseSpecialPage( LinkTarget $target ) {
212 if ( $target->getNamespace() == NS_SPECIAL && !$target->isExternal() ) {
213 list( $name, $subpage ) = MediaWikiServices::getInstance()->getSpecialPageFactory()->
214 resolveAlias( $target->getDBkey() );
215 if ( $name ) {
216 return SpecialPage::getTitleValueFor( $name, $subpage, $target->getFragment() );
217 }
218 }
219
220 return $target;
221 }
222
231 private static function fnamePart( $url ) {
232 $basename = strrchr( $url, '/' );
233 if ( $basename === false ) {
234 $basename = $url;
235 } else {
236 $basename = substr( $basename, 1 );
237 }
238 return $basename;
239 }
240
251 public static function makeExternalImage( $url, $alt = '' ) {
252 if ( $alt == '' ) {
253 $alt = self::fnamePart( $url );
254 }
255 $img = '';
256 $success = Hooks::run( 'LinkerMakeExternalImage', [ &$url, &$alt, &$img ] );
257 if ( !$success ) {
258 wfDebug( "Hook LinkerMakeExternalImage changed the output of external image "
259 . "with url {$url} and alt text {$alt} to {$img}\n", true );
260 return $img;
261 }
262 return Html::element( 'img',
263 [
264 'src' => $url,
265 'alt' => $alt
266 ]
267 );
268 }
269
307 public static function makeImageLink( Parser $parser, Title $title,
308 $file, $frameParams = [], $handlerParams = [], $time = false,
309 $query = "", $widthOption = null
310 ) {
311 $res = null;
312 $dummy = new DummyLinker;
313 if ( !Hooks::run( 'ImageBeforeProduceHTML', [ &$dummy, &$title,
314 &$file, &$frameParams, &$handlerParams, &$time, &$res,
315 $parser, &$query, &$widthOption
316 ] ) ) {
317 return $res;
318 }
319
320 if ( $file && !$file->allowInlineDisplay() ) {
321 wfDebug( __METHOD__ . ': ' . $title->getPrefixedDBkey() . " does not allow inline display\n" );
322 return self::link( $title );
323 }
324
325 // Clean up parameters
326 $page = $handlerParams['page'] ?? false;
327 if ( !isset( $frameParams['align'] ) ) {
328 $frameParams['align'] = '';
329 }
330 if ( !isset( $frameParams['alt'] ) ) {
331 $frameParams['alt'] = '';
332 }
333 if ( !isset( $frameParams['title'] ) ) {
334 $frameParams['title'] = '';
335 }
336 if ( !isset( $frameParams['class'] ) ) {
337 $frameParams['class'] = '';
338 }
339
340 $prefix = $postfix = '';
341
342 if ( $frameParams['align'] == 'center' ) {
343 $prefix = '<div class="center">';
344 $postfix = '</div>';
345 $frameParams['align'] = 'none';
346 }
347 if ( $file && !isset( $handlerParams['width'] ) ) {
348 if ( isset( $handlerParams['height'] ) && $file->isVectorized() ) {
349 // If its a vector image, and user only specifies height
350 // we don't want it to be limited by its "normal" width.
351 global $wgSVGMaxSize;
352 $handlerParams['width'] = $wgSVGMaxSize;
353 } else {
354 $handlerParams['width'] = $file->getWidth( $page );
355 }
356
357 if ( isset( $frameParams['thumbnail'] )
358 || isset( $frameParams['manualthumb'] )
359 || isset( $frameParams['framed'] )
360 || isset( $frameParams['frameless'] )
361 || !$handlerParams['width']
362 ) {
364
365 if ( $widthOption === null || !isset( $wgThumbLimits[$widthOption] ) ) {
366 $widthOption = User::getDefaultOption( 'thumbsize' );
367 }
368
369 // Reduce width for upright images when parameter 'upright' is used
370 if ( isset( $frameParams['upright'] ) && $frameParams['upright'] == 0 ) {
371 $frameParams['upright'] = $wgThumbUpright;
372 }
373
374 // For caching health: If width scaled down due to upright
375 // parameter, round to full __0 pixel to avoid the creation of a
376 // lot of odd thumbs.
377 $prefWidth = isset( $frameParams['upright'] ) ?
378 round( $wgThumbLimits[$widthOption] * $frameParams['upright'], -1 ) :
379 $wgThumbLimits[$widthOption];
380
381 // Use width which is smaller: real image width or user preference width
382 // Unless image is scalable vector.
383 if ( !isset( $handlerParams['height'] ) && ( $handlerParams['width'] <= 0 ||
384 $prefWidth < $handlerParams['width'] || $file->isVectorized() ) ) {
385 $handlerParams['width'] = $prefWidth;
386 }
387 }
388 }
389
390 if ( isset( $frameParams['thumbnail'] ) || isset( $frameParams['manualthumb'] )
391 || isset( $frameParams['framed'] )
392 ) {
393 # Create a thumbnail. Alignment depends on the writing direction of
394 # the page content language (right-aligned for LTR languages,
395 # left-aligned for RTL languages)
396 # If a thumbnail width has not been provided, it is set
397 # to the default user option as specified in Language*.php
398 if ( $frameParams['align'] == '' ) {
399 $frameParams['align'] = $parser->getTargetLanguage()->alignEnd();
400 }
401 return $prefix .
403 $postfix;
404 }
405
406 if ( $file && isset( $frameParams['frameless'] ) ) {
407 $srcWidth = $file->getWidth( $page );
408 # For "frameless" option: do not present an image bigger than the
409 # source (for bitmap-style images). This is the same behavior as the
410 # "thumb" option does it already.
411 if ( $srcWidth && !$file->mustRender() && $handlerParams['width'] > $srcWidth ) {
412 $handlerParams['width'] = $srcWidth;
413 }
414 }
415
416 if ( $file && isset( $handlerParams['width'] ) ) {
417 # Create a resized image, without the additional thumbnail features
418 $thumb = $file->transform( $handlerParams );
419 } else {
420 $thumb = false;
421 }
422
423 if ( !$thumb ) {
424 $s = self::makeBrokenImageLinkObj( $title, $frameParams['title'], '', '', '', $time == true );
425 } else {
427 $params = [
428 'alt' => $frameParams['alt'],
429 'title' => $frameParams['title'],
430 'valign' => $frameParams['valign'] ?? false,
431 'img-class' => $frameParams['class'] ];
432 if ( isset( $frameParams['border'] ) ) {
433 $params['img-class'] .= ( $params['img-class'] !== '' ? ' ' : '' ) . 'thumbborder';
434 }
436
437 $s = $thumb->toHtml( $params );
438 }
439 if ( $frameParams['align'] != '' ) {
440 $s = Html::rawElement(
441 'div',
442 [ 'class' => 'float' . $frameParams['align'] ],
443 $s
444 );
445 }
446 return str_replace( "\n", ' ', $prefix . $s . $postfix );
447 }
448
457 private static function getImageLinkMTOParams( $frameParams, $query = '', $parser = null ) {
458 $mtoParams = [];
459 if ( isset( $frameParams['link-url'] ) && $frameParams['link-url'] !== '' ) {
460 $mtoParams['custom-url-link'] = $frameParams['link-url'];
461 if ( isset( $frameParams['link-target'] ) ) {
462 $mtoParams['custom-target-link'] = $frameParams['link-target'];
463 }
464 if ( $parser ) {
465 $extLinkAttrs = $parser->getExternalLinkAttribs( $frameParams['link-url'] );
466 foreach ( $extLinkAttrs as $name => $val ) {
467 // Currently could include 'rel' and 'target'
468 $mtoParams['parser-extlink-' . $name] = $val;
469 }
470 }
471 } elseif ( isset( $frameParams['link-title'] ) && $frameParams['link-title'] !== '' ) {
472 $mtoParams['custom-title-link'] = Title::newFromLinkTarget(
473 self::normaliseSpecialPage( $frameParams['link-title'] )
474 );
475 } elseif ( !empty( $frameParams['no-link'] ) ) {
476 // No link
477 } else {
478 $mtoParams['desc-link'] = true;
479 $mtoParams['desc-query'] = $query;
480 }
481 return $mtoParams;
482 }
483
496 public static function makeThumbLinkObj( Title $title, $file, $label = '', $alt = '',
497 $align = 'right', $params = [], $framed = false, $manualthumb = ""
498 ) {
499 $frameParams = [
500 'alt' => $alt,
501 'caption' => $label,
502 'align' => $align
503 ];
504 if ( $framed ) {
505 $frameParams['framed'] = true;
506 }
507 if ( $manualthumb ) {
508 $frameParams['manualthumb'] = $manualthumb;
509 }
510 return self::makeThumbLink2( $title, $file, $frameParams, $params );
511 }
512
522 public static function makeThumbLink2( Title $title, $file, $frameParams = [],
523 $handlerParams = [], $time = false, $query = ""
524 ) {
525 $exists = $file && $file->exists();
526
527 $page = $handlerParams['page'] ?? false;
528 if ( !isset( $frameParams['align'] ) ) {
529 $frameParams['align'] = 'right';
530 }
531 if ( !isset( $frameParams['alt'] ) ) {
532 $frameParams['alt'] = '';
533 }
534 if ( !isset( $frameParams['title'] ) ) {
535 $frameParams['title'] = '';
536 }
537 if ( !isset( $frameParams['caption'] ) ) {
538 $frameParams['caption'] = '';
539 }
540
541 if ( empty( $handlerParams['width'] ) ) {
542 // Reduce width for upright images when parameter 'upright' is used
543 $handlerParams['width'] = isset( $frameParams['upright'] ) ? 130 : 180;
544 }
545 $thumb = false;
546 $noscale = false;
547 $manualthumb = false;
548
549 if ( !$exists ) {
550 $outerWidth = $handlerParams['width'] + 2;
551 } else {
552 if ( isset( $frameParams['manualthumb'] ) ) {
553 # Use manually specified thumbnail
554 $manual_title = Title::makeTitleSafe( NS_FILE, $frameParams['manualthumb'] );
555 if ( $manual_title ) {
556 $manual_img = wfFindFile( $manual_title );
557 if ( $manual_img ) {
558 $thumb = $manual_img->getUnscaledThumb( $handlerParams );
559 $manualthumb = true;
560 } else {
561 $exists = false;
562 }
563 }
564 } elseif ( isset( $frameParams['framed'] ) ) {
565 // Use image dimensions, don't scale
566 $thumb = $file->getUnscaledThumb( $handlerParams );
567 $noscale = true;
568 } else {
569 # Do not present an image bigger than the source, for bitmap-style images
570 # This is a hack to maintain compatibility with arbitrary pre-1.10 behavior
571 $srcWidth = $file->getWidth( $page );
572 if ( $srcWidth && !$file->mustRender() && $handlerParams['width'] > $srcWidth ) {
573 $handlerParams['width'] = $srcWidth;
574 }
575 $thumb = $file->transform( $handlerParams );
576 }
577
578 if ( $thumb ) {
579 $outerWidth = $thumb->getWidth() + 2;
580 } else {
581 $outerWidth = $handlerParams['width'] + 2;
582 }
583 }
584
585 # ThumbnailImage::toHtml() already adds page= onto the end of DjVu URLs
586 # So we don't need to pass it here in $query. However, the URL for the
587 # zoom icon still needs it, so we make a unique query for it. See T16771
588 $url = $title->getLocalURL( $query );
589 if ( $page ) {
590 $url = wfAppendQuery( $url, [ 'page' => $page ] );
591 }
592 if ( $manualthumb
593 && !isset( $frameParams['link-title'] )
594 && !isset( $frameParams['link-url'] )
595 && !isset( $frameParams['no-link'] ) ) {
596 $frameParams['link-url'] = $url;
597 }
598
599 $s = "<div class=\"thumb t{$frameParams['align']}\">"
600 . "<div class=\"thumbinner\" style=\"width:{$outerWidth}px;\">";
601
602 if ( !$exists ) {
603 $s .= self::makeBrokenImageLinkObj( $title, $frameParams['title'], '', '', '', $time == true );
604 $zoomIcon = '';
605 } elseif ( !$thumb ) {
606 $s .= wfMessage( 'thumbnail_error', '' )->escaped();
607 $zoomIcon = '';
608 } else {
609 if ( !$noscale && !$manualthumb ) {
611 }
612 $params = [
613 'alt' => $frameParams['alt'],
614 'title' => $frameParams['title'],
615 'img-class' => ( isset( $frameParams['class'] ) && $frameParams['class'] !== ''
616 ? $frameParams['class'] . ' '
617 : '' ) . 'thumbimage'
618 ];
620 $s .= $thumb->toHtml( $params );
621 if ( isset( $frameParams['framed'] ) ) {
622 $zoomIcon = "";
623 } else {
624 $zoomIcon = Html::rawElement( 'div', [ 'class' => 'magnify' ],
625 Html::rawElement( 'a', [
626 'href' => $url,
627 'class' => 'internal',
628 'title' => wfMessage( 'thumbnail-more' )->text() ],
629 "" ) );
630 }
631 }
632 $s .= ' <div class="thumbcaption">' . $zoomIcon . $frameParams['caption'] . "</div></div></div>";
633 return str_replace( "\n", ' ', $s );
634 }
635
644 public static function processResponsiveImages( $file, $thumb, $hp ) {
645 global $wgResponsiveImages;
646 if ( $wgResponsiveImages && $thumb && !$thumb->isError() ) {
647 $hp15 = $hp;
648 $hp15['width'] = round( $hp['width'] * 1.5 );
649 $hp20 = $hp;
650 $hp20['width'] = $hp['width'] * 2;
651 if ( isset( $hp['height'] ) ) {
652 $hp15['height'] = round( $hp['height'] * 1.5 );
653 $hp20['height'] = $hp['height'] * 2;
654 }
655
656 $thumb15 = $file->transform( $hp15 );
657 $thumb20 = $file->transform( $hp20 );
658 if ( $thumb15 && !$thumb15->isError() && $thumb15->getUrl() !== $thumb->getUrl() ) {
659 $thumb->responsiveUrls['1.5'] = $thumb15->getUrl();
660 }
661 if ( $thumb20 && !$thumb20->isError() && $thumb20->getUrl() !== $thumb->getUrl() ) {
662 $thumb->responsiveUrls['2'] = $thumb20->getUrl();
663 }
664 }
665 }
666
679 public static function makeBrokenImageLinkObj( $title, $label = '',
680 $query = '', $unused1 = '', $unused2 = '', $time = false
681 ) {
682 if ( !$title instanceof Title ) {
683 wfWarn( __METHOD__ . ': Requires $title to be a Title object.' );
684 return "<!-- ERROR -->" . htmlspecialchars( $label );
685 }
686
688 if ( $label == '' ) {
689 $label = $title->getPrefixedText();
690 }
691 $encLabel = htmlspecialchars( $label );
692 $currentExists = $time ? ( wfFindFile( $title ) != false ) : false;
693
695 && !$currentExists
696 ) {
697 $redir = RepoGroup::singleton()->getLocalRepo()->checkRedirect( $title );
698
699 if ( $redir ) {
700 // We already know it's a redirect, so mark it
701 // accordingly
702 return self::link(
703 $title,
704 $encLabel,
705 [ 'class' => 'mw-redirect' ],
707 [ 'known', 'noclasses' ]
708 );
709 }
710
711 $href = self::getUploadUrl( $title, $query );
712
713 return '<a href="' . htmlspecialchars( $href ) . '" class="new" title="' .
714 htmlspecialchars( $title->getPrefixedText(), ENT_QUOTES ) . '">' .
715 $encLabel . '</a>';
716 }
717
718 return self::link( $title, $encLabel, [], wfCgiToArray( $query ), [ 'known', 'noclasses' ] );
719 }
720
729 protected static function getUploadUrl( $destFile, $query = '' ) {
731 $q = 'wpDestFile=' . $destFile->getPartialURL();
732 if ( $query != '' ) {
733 $q .= '&' . $query;
734 }
735
738 }
739
742 }
743
744 $upload = SpecialPage::getTitleFor( 'Upload' );
745
746 return $upload->getLocalURL( $q );
747 }
748
758 public static function makeMediaLinkObj( $title, $html = '', $time = false ) {
759 $img = wfFindFile( $title, [ 'time' => $time ] );
760 return self::makeMediaLinkFile( $title, $img, $html );
761 }
762
775 public static function makeMediaLinkFile( Title $title, $file, $html = '' ) {
776 if ( $file && $file->exists() ) {
777 $url = $file->getUrl();
778 $class = 'internal';
779 } else {
780 $url = self::getUploadUrl( $title );
781 $class = 'new';
782 }
783
784 $alt = $title->getText();
785 if ( $html == '' ) {
786 $html = $alt;
787 }
788
789 $ret = '';
790 $attribs = [
791 'href' => $url,
792 'class' => $class,
793 'title' => $alt
794 ];
795
796 if ( !Hooks::run( 'LinkerMakeMediaLinkFile',
797 [ $title, $file, &$html, &$attribs, &$ret ] ) ) {
798 wfDebug( "Hook LinkerMakeMediaLinkFile changed the output of link "
799 . "with url {$url} and text {$html} to {$ret}\n", true );
800 return $ret;
801 }
802
803 return Html::rawElement( 'a', $attribs, $html );
804 }
805
816 public static function specialLink( $name, $key = '' ) {
817 if ( $key == '' ) {
818 $key = strtolower( $name );
819 }
820
821 return self::linkKnown( SpecialPage::getTitleFor( $name ), wfMessage( $key )->escaped() );
822 }
823
842 public static function makeExternalLink( $url, $text, $escape = true,
843 $linktype = '', $attribs = [], $title = null
844 ) {
845 global $wgTitle;
846 $class = "external";
847 if ( $linktype ) {
848 $class .= " $linktype";
849 }
850 if ( isset( $attribs['class'] ) && $attribs['class'] ) {
851 $class .= " {$attribs['class']}";
852 }
853 $attribs['class'] = $class;
854
855 if ( $escape ) {
856 $text = htmlspecialchars( $text );
857 }
858
859 if ( !$title ) {
861 }
862 $newRel = Parser::getExternalLinkRel( $url, $title );
863 if ( !isset( $attribs['rel'] ) || $attribs['rel'] === '' ) {
864 $attribs['rel'] = $newRel;
865 } elseif ( $newRel !== '' ) {
866 // Merge the rel attributes.
867 $newRels = explode( ' ', $newRel );
868 $oldRels = explode( ' ', $attribs['rel'] );
869 $combined = array_unique( array_merge( $newRels, $oldRels ) );
870 $attribs['rel'] = implode( ' ', $combined );
871 }
872 $link = '';
873 $success = Hooks::run( 'LinkerMakeExternalLink',
874 [ &$url, &$text, &$link, &$attribs, $linktype ] );
875 if ( !$success ) {
876 wfDebug( "Hook LinkerMakeExternalLink changed the output of link "
877 . "with url {$url} and text {$text} to {$link}\n", true );
878 return $link;
879 }
880 $attribs['href'] = $url;
881 return Html::rawElement( 'a', $attribs, $text );
882 }
883
892 public static function userLink( $userId, $userName, $altUserName = false ) {
893 $classes = 'mw-userlink';
894 $page = null;
895 if ( $userId == 0 ) {
896 $page = ExternalUserNames::getUserLinkTitle( $userName );
897
898 if ( ExternalUserNames::isExternal( $userName ) ) {
899 $classes .= ' mw-extuserlink';
900 } elseif ( $altUserName === false ) {
901 $altUserName = IP::prettifyIP( $userName );
902 }
903 $classes .= ' mw-anonuserlink'; // Separate link class for anons (T45179)
904 } else {
905 $page = Title::makeTitle( NS_USER, $userName );
906 }
907
908 // Wrap the output with <bdi> tags for directionality isolation
909 $linkText =
910 '<bdi>' . htmlspecialchars( $altUserName !== false ? $altUserName : $userName ) . '</bdi>';
911
912 return $page
913 ? self::link( $page, $linkText, [ 'class' => $classes ] )
914 : Html::rawElement( 'span', [ 'class' => $classes ], $linkText );
915 }
916
931 public static function userToolLinks(
932 $userId, $userText, $redContribsWhenNoEdits = false, $flags = 0, $edits = null,
933 $useParentheses = true
934 ) {
935 global $wgUser, $wgDisableAnonTalk, $wgLang;
936 $talkable = !( $wgDisableAnonTalk && $userId == 0 );
937 $blockable = !( $flags & self::TOOL_LINKS_NOBLOCK );
938 $addEmailLink = $flags & self::TOOL_LINKS_EMAIL && $userId;
939
940 if ( $userId == 0 && ExternalUserNames::isExternal( $userText ) ) {
941 // No tools for an external user
942 return '';
943 }
944
945 $items = [];
946 if ( $talkable ) {
947 $items[] = self::userTalkLink( $userId, $userText );
948 }
949 if ( $userId ) {
950 // check if the user has an edit
951 $attribs = [];
952 $attribs['class'] = 'mw-usertoollinks-contribs';
953 if ( $redContribsWhenNoEdits ) {
954 if ( intval( $edits ) === 0 && $edits !== 0 ) {
955 $user = User::newFromId( $userId );
956 $edits = $user->getEditCount();
957 }
958 if ( $edits === 0 ) {
959 $attribs['class'] .= ' new';
960 }
961 }
962 $contribsPage = SpecialPage::getTitleFor( 'Contributions', $userText );
963
964 $items[] = self::link( $contribsPage, wfMessage( 'contribslink' )->escaped(), $attribs );
965 }
966 if ( $blockable && $wgUser->isAllowed( 'block' ) ) {
967 $items[] = self::blockLink( $userId, $userText );
968 }
969
970 if ( $addEmailLink && $wgUser->canSendEmail() ) {
971 $items[] = self::emailLink( $userId, $userText );
972 }
973
974 Hooks::run( 'UserToolLinksEdit', [ $userId, $userText, &$items ] );
975
976 if ( !$items ) {
977 return '';
978 }
979
980 if ( $useParentheses ) {
981 return wfMessage( 'word-separator' )->escaped()
982 . '<span class="mw-usertoollinks">'
983 . wfMessage( 'parentheses' )->rawParams( $wgLang->pipeList( $items ) )->escaped()
984 . '</span>';
985 }
986
987 $tools = [];
988 foreach ( $items as $tool ) {
989 $tools[] = Html::rawElement( 'span', [], $tool );
990 }
991 return ' <span class="mw-usertoollinks mw-changeslist-links">' .
992 implode( ' ', $tools ) . '</span>';
993 }
994
1004 public static function userToolLinksRedContribs(
1005 $userId, $userText, $edits = null, $useParentheses = true
1006 ) {
1007 return self::userToolLinks( $userId, $userText, true, 0, $edits, $useParentheses );
1008 }
1009
1016 public static function userTalkLink( $userId, $userText ) {
1017 $userTalkPage = Title::makeTitle( NS_USER_TALK, $userText );
1018 $moreLinkAttribs['class'] = 'mw-usertoollinks-talk';
1019
1020 return self::link( $userTalkPage,
1021 wfMessage( 'talkpagelinktext' )->escaped(),
1022 $moreLinkAttribs
1023 );
1024 }
1025
1032 public static function blockLink( $userId, $userText ) {
1033 $blockPage = SpecialPage::getTitleFor( 'Block', $userText );
1034 $moreLinkAttribs['class'] = 'mw-usertoollinks-block';
1035
1036 return self::link( $blockPage,
1037 wfMessage( 'blocklink' )->escaped(),
1038 $moreLinkAttribs
1039 );
1040 }
1041
1047 public static function emailLink( $userId, $userText ) {
1048 $emailPage = SpecialPage::getTitleFor( 'Emailuser', $userText );
1049 $moreLinkAttribs['class'] = 'mw-usertoollinks-mail';
1050 return self::link( $emailPage,
1051 wfMessage( 'emaillink' )->escaped(),
1052 $moreLinkAttribs
1053 );
1054 }
1055
1063 public static function revUserLink( $rev, $isPublic = false ) {
1064 if ( $rev->isDeleted( Revision::DELETED_USER ) && $isPublic ) {
1065 $link = wfMessage( 'rev-deleted-user' )->escaped();
1066 } elseif ( $rev->userCan( Revision::DELETED_USER ) ) {
1068 $rev->getUserText( Revision::FOR_THIS_USER ) );
1069 } else {
1070 $link = wfMessage( 'rev-deleted-user' )->escaped();
1071 }
1072 if ( $rev->isDeleted( Revision::DELETED_USER ) ) {
1073 return '<span class="history-deleted">' . $link . '</span>';
1074 }
1075 return $link;
1076 }
1077
1086 public static function revUserTools( $rev, $isPublic = false, $useParentheses = true ) {
1087 if ( $rev->isDeleted( Revision::DELETED_USER ) && $isPublic ) {
1088 $link = wfMessage( 'rev-deleted-user' )->escaped();
1089 } elseif ( $rev->userCan( Revision::DELETED_USER ) ) {
1090 $userId = $rev->getUser( Revision::FOR_THIS_USER );
1091 $userText = $rev->getUserText( Revision::FOR_THIS_USER );
1092 $link = self::userLink( $userId, $userText )
1093 . self::userToolLinks( $userId, $userText, false, 0, null,
1094 $useParentheses );
1095 } else {
1096 $link = wfMessage( 'rev-deleted-user' )->escaped();
1097 }
1098 if ( $rev->isDeleted( Revision::DELETED_USER ) ) {
1099 return ' <span class="history-deleted mw-userlink">' . $link . '</span>';
1100 }
1101 return $link;
1102 }
1103
1122 public static function formatComment(
1123 $comment, $title = null, $local = false, $wikiId = null
1124 ) {
1125 # Sanitize text a bit:
1126 $comment = str_replace( "\n", " ", $comment );
1127 # Allow HTML entities (for T15815)
1128 $comment = Sanitizer::escapeHtmlAllowEntities( $comment );
1129
1130 # Render autocomments and make links:
1131 $comment = self::formatAutocomments( $comment, $title, $local, $wikiId );
1132 return self::formatLinksInComment( $comment, $title, $local, $wikiId );
1133 }
1134
1152 private static function formatAutocomments(
1153 $comment, $title = null, $local = false, $wikiId = null
1154 ) {
1155 // @todo $append here is something of a hack to preserve the status
1156 // quo. Someone who knows more about bidi and such should decide
1157 // (1) what sane rendering even *is* for an LTR edit summary on an RTL
1158 // wiki, both when autocomments exist and when they don't, and
1159 // (2) what markup will make that actually happen.
1160 $append = '';
1161 $comment = preg_replace_callback(
1162 // To detect the presence of content before or after the
1163 // auto-comment, we use capturing groups inside optional zero-width
1164 // assertions. But older versions of PCRE can't directly make
1165 // zero-width assertions optional, so wrap them in a non-capturing
1166 // group.
1167 '!(?:(?<=(.)))?/\*\s*(.*?)\s*\*/(?:(?=(.)))?!',
1168 function ( $match ) use ( $title, $local, $wikiId, &$append ) {
1169 global $wgLang;
1170
1171 // Ensure all match positions are defined
1172 $match += [ '', '', '', '' ];
1173
1174 $pre = $match[1] !== '';
1175 $auto = $match[2];
1176 $post = $match[3] !== '';
1177 $comment = null;
1178
1179 Hooks::run(
1180 'FormatAutocomments',
1181 [ &$comment, $pre, $auto, $post, $title, $local, $wikiId ]
1182 );
1183
1184 if ( $comment === null ) {
1185 if ( $title ) {
1186 $section = $auto;
1187 # Remove links that a user may have manually put in the autosummary
1188 # This could be improved by copying as much of Parser::stripSectionName as desired.
1189 $section = str_replace( [
1190 '[[:',
1191 '[[',
1192 ']]'
1193 ], '', $section );
1194
1195 // We don't want any links in the auto text to be linked, but we still
1196 // want to show any [[ ]]
1197 $sectionText = str_replace( '[[', '&#91;[', $auto );
1198
1199 $section = substr( Parser::guessSectionNameFromStrippedText( $section ), 1 );
1200 if ( $local ) {
1201 $sectionTitle = Title::makeTitleSafe( NS_MAIN, '', $section );
1202 } else {
1203 $sectionTitle = Title::makeTitleSafe( $title->getNamespace(),
1204 $title->getDBkey(), $section );
1205 }
1206 if ( $sectionTitle ) {
1208 $sectionTitle, $wgLang->getArrow() . $wgLang->getDirMark() . $sectionText,
1209 $wikiId, 'noclasses'
1210 );
1211 }
1212 }
1213 if ( $pre ) {
1214 # written summary $presep autocomment (summary /* section */)
1215 $pre = wfMessage( 'autocomment-prefix' )->inContentLanguage()->escaped();
1216 }
1217 if ( $post ) {
1218 # autocomment $postsep written summary (/* section */ summary)
1219 $auto .= wfMessage( 'colon-separator' )->inContentLanguage()->escaped();
1220 }
1221 if ( $auto ) {
1222 $auto = '<span dir="auto"><span class="autocomment">' . $auto . '</span>';
1223 $append .= '</span>';
1224 }
1225 $comment = $pre . $auto;
1226 }
1227 return $comment;
1228 },
1229 $comment
1230 );
1231 return $comment . $append;
1232 }
1233
1253 public static function formatLinksInComment(
1254 $comment, $title = null, $local = false, $wikiId = null
1255 ) {
1256 return preg_replace_callback(
1257 '/
1258 \[\[
1259 \s*+ # ignore leading whitespace, the *+ quantifier disallows backtracking
1260 :? # ignore optional leading colon
1261 ([^\]|]+) # 1. link target; page names cannot include ] or |
1262 (?:\|
1263 # 2. link text
1264 # Stop matching at ]] without relying on backtracking.
1265 ((?:]?[^\]])*+)
1266 )?
1267 \]\]
1268 ([^[]*) # 3. link trail (the text up until the next link)
1269 /x',
1270 function ( $match ) use ( $title, $local, $wikiId ) {
1271 $medians = '(?:' . preg_quote( MWNamespace::getCanonicalName( NS_MEDIA ), '/' ) . '|';
1272 $medians .= preg_quote(
1273 MediaWikiServices::getInstance()->getContentLanguage()->getNsText( NS_MEDIA ),
1274 '/'
1275 ) . '):';
1276
1277 $comment = $match[0];
1278
1279 # fix up urlencoded title texts (copied from Parser::replaceInternalLinks)
1280 if ( strpos( $match[1], '%' ) !== false ) {
1281 $match[1] = strtr(
1282 rawurldecode( $match[1] ),
1283 [ '<' => '&lt;', '>' => '&gt;' ]
1284 );
1285 }
1286
1287 # Handle link renaming [[foo|text]] will show link as "text"
1288 if ( $match[2] != "" ) {
1289 $text = $match[2];
1290 } else {
1291 $text = $match[1];
1292 }
1293 $submatch = [];
1294 $thelink = null;
1295 if ( preg_match( '/^' . $medians . '(.*)$/i', $match[1], $submatch ) ) {
1296 # Media link; trail not supported.
1297 $linkRegexp = '/\[\[(.*?)\]\]/';
1298 $title = Title::makeTitleSafe( NS_FILE, $submatch[1] );
1299 if ( $title ) {
1300 $thelink = Linker::makeMediaLinkObj( $title, $text );
1301 }
1302 } else {
1303 # Other kind of link
1304 # Make sure its target is non-empty
1305 if ( isset( $match[1][0] ) && $match[1][0] == ':' ) {
1306 $match[1] = substr( $match[1], 1 );
1307 }
1308 if ( $match[1] !== false && $match[1] !== '' ) {
1309 if ( preg_match(
1310 MediaWikiServices::getInstance()->getContentLanguage()->linkTrail(),
1311 $match[3],
1312 $submatch
1313 ) ) {
1314 $trail = $submatch[1];
1315 } else {
1316 $trail = "";
1317 }
1318 $linkRegexp = '/\[\[(.*?)\]\]' . preg_quote( $trail, '/' ) . '/';
1319 list( $inside, $trail ) = Linker::splitTrail( $trail );
1320
1321 $linkText = $text;
1322 $linkTarget = Linker::normalizeSubpageLink( $title, $match[1], $linkText );
1323
1324 $target = Title::newFromText( $linkTarget );
1325 if ( $target ) {
1326 if ( $target->getText() == '' && !$target->isExternal()
1327 && !$local && $title
1328 ) {
1329 $target = $title->createFragmentTarget( $target->getFragment() );
1330 }
1331
1332 $thelink = Linker::makeCommentLink( $target, $linkText . $inside, $wikiId ) . $trail;
1333 }
1334 }
1335 }
1336 if ( $thelink ) {
1337 // If the link is still valid, go ahead and replace it in!
1338 $comment = preg_replace(
1339 $linkRegexp,
1341 $comment,
1342 1
1343 );
1344 }
1345
1346 return $comment;
1347 },
1348 $comment
1349 );
1350 }
1351
1365 public static function makeCommentLink(
1366 LinkTarget $linkTarget, $text, $wikiId = null, $options = []
1367 ) {
1368 if ( $wikiId !== null && !$linkTarget->isExternal() ) {
1370 WikiMap::getForeignURL(
1371 $wikiId,
1372 $linkTarget->getNamespace() === 0
1373 ? $linkTarget->getDBkey()
1374 : MWNamespace::getCanonicalName( $linkTarget->getNamespace() ) . ':'
1375 . $linkTarget->getDBkey(),
1376 $linkTarget->getFragment()
1377 ),
1378 $text,
1379 /* escape = */ false // Already escaped
1380 );
1381 } else {
1382 $link = self::link( $linkTarget, $text, [], [], $options );
1383 }
1384
1385 return $link;
1386 }
1387
1394 public static function normalizeSubpageLink( $contextTitle, $target, &$text ) {
1395 # Valid link forms:
1396 # Foobar -- normal
1397 # :Foobar -- override special treatment of prefix (images, language links)
1398 # /Foobar -- convert to CurrentPage/Foobar
1399 # /Foobar/ -- convert to CurrentPage/Foobar, strip the initial and final / from text
1400 # ../ -- convert to CurrentPage, from CurrentPage/CurrentSubPage
1401 # ../Foobar -- convert to CurrentPage/Foobar,
1402 # (from CurrentPage/CurrentSubPage)
1403 # ../Foobar/ -- convert to CurrentPage/Foobar, use 'Foobar' as text
1404 # (from CurrentPage/CurrentSubPage)
1405
1406 $ret = $target; # default return value is no change
1407
1408 # Some namespaces don't allow subpages,
1409 # so only perform processing if subpages are allowed
1410 if ( $contextTitle && MWNamespace::hasSubpages( $contextTitle->getNamespace() ) ) {
1411 $hash = strpos( $target, '#' );
1412 if ( $hash !== false ) {
1413 $suffix = substr( $target, $hash );
1414 $target = substr( $target, 0, $hash );
1415 } else {
1416 $suffix = '';
1417 }
1418 # T9425
1419 $target = trim( $target );
1420 # Look at the first character
1421 if ( $target != '' && $target[0] === '/' ) {
1422 # / at end means we don't want the slash to be shown
1423 $m = [];
1424 $trailingSlashes = preg_match_all( '%(/+)$%', $target, $m );
1425 if ( $trailingSlashes ) {
1426 $noslash = $target = substr( $target, 1, -strlen( $m[0][0] ) );
1427 } else {
1428 $noslash = substr( $target, 1 );
1429 }
1430
1431 $ret = $contextTitle->getPrefixedText() . '/' . trim( $noslash ) . $suffix;
1432 if ( $text === '' ) {
1433 $text = $target . $suffix;
1434 } # this might be changed for ugliness reasons
1435 } else {
1436 # check for .. subpage backlinks
1437 $dotdotcount = 0;
1438 $nodotdot = $target;
1439 while ( strncmp( $nodotdot, "../", 3 ) == 0 ) {
1440 ++$dotdotcount;
1441 $nodotdot = substr( $nodotdot, 3 );
1442 }
1443 if ( $dotdotcount > 0 ) {
1444 $exploded = explode( '/', $contextTitle->getPrefixedText() );
1445 if ( count( $exploded ) > $dotdotcount ) { # not allowed to go below top level page
1446 $ret = implode( '/', array_slice( $exploded, 0, -$dotdotcount ) );
1447 # / at the end means don't show full path
1448 if ( substr( $nodotdot, -1, 1 ) === '/' ) {
1449 $nodotdot = rtrim( $nodotdot, '/' );
1450 if ( $text === '' ) {
1451 $text = $nodotdot . $suffix;
1452 }
1453 }
1454 $nodotdot = trim( $nodotdot );
1455 if ( $nodotdot != '' ) {
1456 $ret .= '/' . $nodotdot;
1457 }
1458 $ret .= $suffix;
1459 }
1460 }
1461 }
1462 }
1463
1464 return $ret;
1465 }
1466
1480 public static function commentBlock(
1481 $comment, $title = null, $local = false, $wikiId = null, $useParentheses = true
1482 ) {
1483 // '*' used to be the comment inserted by the software way back
1484 // in antiquity in case none was provided, here for backwards
1485 // compatibility, acc. to brion -ævar
1486 if ( $comment == '' || $comment == '*' ) {
1487 return '';
1488 }
1489 $formatted = self::formatComment( $comment, $title, $local, $wikiId );
1490 if ( $useParentheses ) {
1491 $formatted = wfMessage( 'parentheses' )->rawParams( $formatted )->escaped();
1492 $classNames = 'comment';
1493 } else {
1494 $classNames = 'comment comment--without-parentheses';
1495 }
1496 return " <span class=\"$classNames\">$formatted</span>";
1497 }
1498
1510 public static function revComment( Revision $rev, $local = false, $isPublic = false,
1511 $useParentheses = true
1512 ) {
1513 if ( $rev->getComment( Revision::RAW ) == "" ) {
1514 return "";
1515 }
1516 if ( $rev->isDeleted( Revision::DELETED_COMMENT ) && $isPublic ) {
1517 $block = " <span class=\"comment\">" . wfMessage( 'rev-deleted-comment' )->escaped() . "</span>";
1518 } elseif ( $rev->userCan( Revision::DELETED_COMMENT ) ) {
1519 $block = self::commentBlock( $rev->getComment( Revision::FOR_THIS_USER ),
1520 $rev->getTitle(), $local, null, $useParentheses );
1521 } else {
1522 $block = " <span class=\"comment\">" . wfMessage( 'rev-deleted-comment' )->escaped() . "</span>";
1523 }
1524 if ( $rev->isDeleted( Revision::DELETED_COMMENT ) ) {
1525 return " <span class=\"history-deleted comment\">$block</span>";
1526 }
1527 return $block;
1528 }
1529
1535 public static function formatRevisionSize( $size ) {
1536 if ( $size == 0 ) {
1537 $stxt = wfMessage( 'historyempty' )->escaped();
1538 } else {
1539 $stxt = wfMessage( 'nbytes' )->numParams( $size )->escaped();
1540 }
1541 return "<span class=\"history-size mw-diff-bytes\">$stxt</span>";
1542 }
1543
1550 public static function tocIndent() {
1551 return "\n<ul>\n";
1552 }
1553
1561 public static function tocUnindent( $level ) {
1562 return "</li>\n" . str_repeat( "</ul>\n</li>\n", $level > 0 ? $level : 0 );
1563 }
1564
1576 public static function tocLine( $anchor, $tocline, $tocnumber, $level, $sectionIndex = false ) {
1577 $classes = "toclevel-$level";
1578 if ( $sectionIndex !== false ) {
1579 $classes .= " tocsection-$sectionIndex";
1580 }
1581
1582 // <li class="$classes"><a href="#$anchor"><span class="tocnumber">
1583 // $tocnumber</span> <span class="toctext">$tocline</span></a>
1584 return Html::openElement( 'li', [ 'class' => $classes ] )
1585 . Html::rawElement( 'a',
1586 [ 'href' => "#$anchor" ],
1587 Html::element( 'span', [ 'class' => 'tocnumber' ], $tocnumber )
1588 . ' '
1589 . Html::rawElement( 'span', [ 'class' => 'toctext' ], $tocline )
1590 );
1591 }
1592
1600 public static function tocLineEnd() {
1601 return "</li>\n";
1602 }
1603
1613 public static function tocList( $toc, $lang = null ) {
1614 $lang = $lang ?? RequestContext::getMain()->getLanguage();
1615 if ( !$lang instanceof Language ) {
1616 wfDeprecated( __METHOD__ . ' with type other than Language for $lang', '1.33' );
1618 }
1619
1620 $title = wfMessage( 'toc' )->inLanguage( $lang )->escaped();
1621
1622 return '<div id="toc" class="toc">'
1623 . Html::element( 'input', [
1624 'type' => 'checkbox',
1625 'role' => 'button',
1626 'id' => 'toctogglecheckbox',
1627 'class' => 'toctogglecheckbox',
1628 'style' => 'display:none',
1629 ] )
1630 . Html::openElement( 'div', [
1631 'class' => 'toctitle',
1632 'lang' => $lang->getHtmlCode(),
1633 'dir' => $lang->getDir(),
1634 ] )
1635 . "<h2>$title</h2>"
1636 . '<span class="toctogglespan">'
1637 . Html::label( '', 'toctogglecheckbox', [
1638 'class' => 'toctogglelabel',
1639 ] )
1640 . '</span>'
1641 . "</div>\n"
1642 . $toc
1643 . "</ul>\n</div>\n";
1644 }
1645
1655 public static function generateTOC( $tree, $lang = null ) {
1656 $toc = '';
1657 $lastLevel = 0;
1658 foreach ( $tree as $section ) {
1659 if ( $section['toclevel'] > $lastLevel ) {
1660 $toc .= self::tocIndent();
1661 } elseif ( $section['toclevel'] < $lastLevel ) {
1662 $toc .= self::tocUnindent(
1663 $lastLevel - $section['toclevel'] );
1664 } else {
1665 $toc .= self::tocLineEnd();
1666 }
1667
1668 $toc .= self::tocLine( $section['anchor'],
1669 $section['line'], $section['number'],
1670 $section['toclevel'], $section['index'] );
1671 $lastLevel = $section['toclevel'];
1672 }
1673 $toc .= self::tocLineEnd();
1674 return self::tocList( $toc, $lang );
1675 }
1676
1693 public static function makeHeadline( $level, $attribs, $anchor, $html,
1694 $link, $fallbackAnchor = false
1695 ) {
1696 $anchorEscaped = htmlspecialchars( $anchor );
1697 $fallback = '';
1698 if ( $fallbackAnchor !== false && $fallbackAnchor !== $anchor ) {
1699 $fallbackAnchor = htmlspecialchars( $fallbackAnchor );
1700 $fallback = "<span id=\"$fallbackAnchor\"></span>";
1701 }
1702 return "<h$level$attribs"
1703 . "$fallback<span class=\"mw-headline\" id=\"$anchorEscaped\">$html</span>"
1704 . $link
1705 . "</h$level>";
1706 }
1707
1714 static function splitTrail( $trail ) {
1715 $regex = MediaWikiServices::getInstance()->getContentLanguage()->linkTrail();
1716 $inside = '';
1717 if ( $trail !== '' && preg_match( $regex, $trail, $m ) ) {
1718 list( , $inside, $trail ) = $m;
1719 }
1720 return [ $inside, $trail ];
1721 }
1722
1750 public static function generateRollback( $rev, IContextSource $context = null,
1751 $options = [ 'verify' ]
1752 ) {
1753 if ( $context === null ) {
1754 $context = RequestContext::getMain();
1755 }
1756
1757 $editCount = false;
1758 if ( in_array( 'verify', $options, true ) ) {
1759 $editCount = self::getRollbackEditCount( $rev, true );
1760 if ( $editCount === false ) {
1761 return '';
1762 }
1763 }
1764
1765 $inner = self::buildRollbackLink( $rev, $context, $editCount );
1766
1767 if ( !in_array( 'noBrackets', $options, true ) ) {
1768 $inner = $context->msg( 'brackets' )->rawParams( $inner )->escaped();
1769 }
1770
1771 if ( $context->getUser()->getBoolOption( 'showrollbackconfirmation' ) ) {
1772 $stats = MediaWikiServices::getInstance()->getStatsdDataFactory();
1773 $stats->increment( 'rollbackconfirmation.event.load' );
1774 $context->getOutput()->addModules( 'mediawiki.page.rollback.confirmation' );
1775 }
1776
1777 return '<span class="mw-rollback-link">' . $inner . '</span>';
1778 }
1779
1795 public static function getRollbackEditCount( $rev, $verify ) {
1797 if ( !is_int( $wgShowRollbackEditCount ) || !$wgShowRollbackEditCount > 0 ) {
1798 // Nothing has happened, indicate this by returning 'null'
1799 return null;
1800 }
1801
1802 $dbr = wfGetDB( DB_REPLICA );
1803
1804 // Up to the value of $wgShowRollbackEditCount revisions are counted
1806 $res = $dbr->select(
1807 $revQuery['tables'],
1808 [ 'rev_user_text' => $revQuery['fields']['rev_user_text'], 'rev_deleted' ],
1809 // $rev->getPage() returns null sometimes
1810 [ 'rev_page' => $rev->getTitle()->getArticleID() ],
1811 __METHOD__,
1812 [
1813 'USE INDEX' => [ 'revision' => 'page_timestamp' ],
1814 'ORDER BY' => 'rev_timestamp DESC',
1815 'LIMIT' => $wgShowRollbackEditCount + 1
1816 ],
1817 $revQuery['joins']
1818 );
1819
1820 $editCount = 0;
1821 $moreRevs = false;
1822 foreach ( $res as $row ) {
1823 if ( $rev->getUserText( Revision::RAW ) != $row->rev_user_text ) {
1824 if ( $verify &&
1825 ( $row->rev_deleted & Revision::DELETED_TEXT
1826 || $row->rev_deleted & Revision::DELETED_USER
1827 ) ) {
1828 // If the user or the text of the revision we might rollback
1829 // to is deleted in some way we can't rollback. Similar to
1830 // the sanity checks in WikiPage::commitRollback.
1831 return false;
1832 }
1833 $moreRevs = true;
1834 break;
1835 }
1836 $editCount++;
1837 }
1838
1839 if ( $verify && $editCount <= $wgShowRollbackEditCount && !$moreRevs ) {
1840 // We didn't find at least $wgShowRollbackEditCount revisions made by the current user
1841 // and there weren't any other revisions. That means that the current user is the only
1842 // editor, so we can't rollback
1843 return false;
1844 }
1845 return $editCount;
1846 }
1847
1857 public static function buildRollbackLink( $rev, IContextSource $context = null,
1858 $editCount = false
1859 ) {
1861
1862 // To config which pages are affected by miser mode
1863 $disableRollbackEditCountSpecialPage = [ 'Recentchanges', 'Watchlist' ];
1864
1865 if ( $context === null ) {
1866 $context = RequestContext::getMain();
1867 }
1868
1869 $title = $rev->getTitle();
1870
1871 $query = [
1872 'action' => 'rollback',
1873 'from' => $rev->getUserText(),
1874 'token' => $context->getUser()->getEditToken( 'rollback' ),
1875 ];
1876
1877 $attrs = [
1878 'data-mw' => 'interface',
1879 'title' => $context->msg( 'tooltip-rollback' )->text()
1880 ];
1881
1882 $options = [ 'known', 'noclasses' ];
1883
1884 if ( $context->getRequest()->getBool( 'bot' ) ) {
1885 //T17999
1886 $query['hidediff'] = '1';
1887 $query['bot'] = '1';
1888 }
1889
1890 $disableRollbackEditCount = false;
1891 if ( $wgMiserMode ) {
1892 foreach ( $disableRollbackEditCountSpecialPage as $specialPage ) {
1893 if ( $context->getTitle()->isSpecial( $specialPage ) ) {
1894 $disableRollbackEditCount = true;
1895 break;
1896 }
1897 }
1898 }
1899
1900 if ( !$disableRollbackEditCount
1901 && is_int( $wgShowRollbackEditCount )
1903 ) {
1904 if ( !is_numeric( $editCount ) ) {
1905 $editCount = self::getRollbackEditCount( $rev, false );
1906 }
1907
1908 if ( $editCount > $wgShowRollbackEditCount ) {
1909 $html = $context->msg( 'rollbacklinkcount-morethan' )
1910 ->numParams( $wgShowRollbackEditCount )->parse();
1911 } else {
1912 $html = $context->msg( 'rollbacklinkcount' )->numParams( $editCount )->parse();
1913 }
1914
1915 return self::link( $title, $html, $attrs, $query, $options );
1916 }
1917
1918 $html = $context->msg( 'rollbacklink' )->escaped();
1919 return self::link( $title, $html, $attrs, $query, $options );
1920 }
1921
1930 public static function formatHiddenCategories( $hiddencats ) {
1931 $outText = '';
1932 if ( count( $hiddencats ) > 0 ) {
1933 # Construct the HTML
1934 $outText = '<div class="mw-hiddenCategoriesExplanation">';
1935 $outText .= wfMessage( 'hiddencategories' )->numParams( count( $hiddencats ) )->parseAsBlock();
1936 $outText .= "</div><ul>\n";
1937
1938 foreach ( $hiddencats as $titleObj ) {
1939 # If it's hidden, it must exist - no need to check with a LinkBatch
1940 $outText .= '<li>'
1941 . self::link( $titleObj, null, [], [], 'known' )
1942 . "</li>\n";
1943 }
1944 $outText .= '</ul>';
1945 }
1946 return $outText;
1947 }
1948
1965 public static function titleAttrib( $name, $options = null, array $msgParams = [] ) {
1966 $message = wfMessage( "tooltip-$name", $msgParams );
1967 if ( !$message->exists() ) {
1968 $tooltip = false;
1969 } else {
1970 $tooltip = $message->text();
1971 # Compatibility: formerly some tooltips had [alt-.] hardcoded
1972 $tooltip = preg_replace( "/ ?\[alt-.\]$/", '', $tooltip );
1973 # Message equal to '-' means suppress it.
1974 if ( $tooltip == '-' ) {
1975 $tooltip = false;
1976 }
1977 }
1978
1980
1981 if ( in_array( 'nonexisting', $options ) ) {
1982 $tooltip = wfMessage( 'red-link-title', $tooltip ?: '' )->text();
1983 }
1984 if ( in_array( 'withaccess', $options ) ) {
1985 $accesskey = self::accesskey( $name );
1986 if ( $accesskey !== false ) {
1987 // Should be build the same as in jquery.accessKeyLabel.js
1988 if ( $tooltip === false || $tooltip === '' ) {
1989 $tooltip = wfMessage( 'brackets', $accesskey )->text();
1990 } else {
1991 $tooltip .= wfMessage( 'word-separator' )->text();
1992 $tooltip .= wfMessage( 'brackets', $accesskey )->text();
1993 }
1994 }
1995 }
1996
1997 return $tooltip;
1998 }
1999
2000 public static $accesskeycache;
2001
2013 public static function accesskey( $name ) {
2014 if ( isset( self::$accesskeycache[$name] ) ) {
2015 return self::$accesskeycache[$name];
2016 }
2017
2018 $message = wfMessage( "accesskey-$name" );
2019
2020 if ( !$message->exists() ) {
2021 $accesskey = false;
2022 } else {
2023 $accesskey = $message->plain();
2024 if ( $accesskey === '' || $accesskey === '-' ) {
2025 # @todo FIXME: Per standard MW behavior, a value of '-' means to suppress the
2026 # attribute, but this is broken for accesskey: that might be a useful
2027 # value.
2028 $accesskey = false;
2029 }
2030 }
2031
2032 self::$accesskeycache[$name] = $accesskey;
2033 return self::$accesskeycache[$name];
2034 }
2035
2049 public static function getRevDeleteLink( User $user, Revision $rev, Title $title ) {
2050 $canHide = $user->isAllowed( 'deleterevision' );
2051 if ( !$canHide && !( $rev->getVisibility() && $user->isAllowed( 'deletedhistory' ) ) ) {
2052 return '';
2053 }
2054
2055 if ( !$rev->userCan( Revision::DELETED_RESTRICTED, $user ) ) {
2056 return self::revDeleteLinkDisabled( $canHide ); // revision was hidden from sysops
2057 }
2058 if ( $rev->getId() ) {
2059 // RevDelete links using revision ID are stable across
2060 // page deletion and undeletion; use when possible.
2061 $query = [
2062 'type' => 'revision',
2063 'target' => $title->getPrefixedDBkey(),
2064 'ids' => $rev->getId()
2065 ];
2066 } else {
2067 // Older deleted entries didn't save a revision ID.
2068 // We have to refer to these by timestamp, ick!
2069 $query = [
2070 'type' => 'archive',
2071 'target' => $title->getPrefixedDBkey(),
2072 'ids' => $rev->getTimestamp()
2073 ];
2074 }
2076 $rev->isDeleted( Revision::DELETED_RESTRICTED ), $canHide );
2077 }
2078
2089 public static function revDeleteLink( $query = [], $restricted = false, $delete = true ) {
2090 $sp = SpecialPage::getTitleFor( 'Revisiondelete' );
2091 $msgKey = $delete ? 'rev-delundel' : 'rev-showdeleted';
2092 $html = wfMessage( $msgKey )->escaped();
2093 $tag = $restricted ? 'strong' : 'span';
2094 $link = self::link( $sp, $html, [], $query, [ 'known', 'noclasses' ] );
2095 return Xml::tags(
2096 $tag,
2097 [ 'class' => 'mw-revdelundel-link' ],
2098 wfMessage( 'parentheses' )->rawParams( $link )->escaped()
2099 );
2100 }
2101
2111 public static function revDeleteLinkDisabled( $delete = true ) {
2112 $msgKey = $delete ? 'rev-delundel' : 'rev-showdeleted';
2113 $html = wfMessage( $msgKey )->escaped();
2114 $htmlParentheses = wfMessage( 'parentheses' )->rawParams( $html )->escaped();
2115 return Xml::tags( 'span', [ 'class' => 'mw-revdelundel-link' ], $htmlParentheses );
2116 }
2117
2130 public static function tooltipAndAccesskeyAttribs(
2131 $name,
2132 array $msgParams = [],
2133 $options = null
2134 ) {
2136 $options[] = 'withaccess';
2137
2138 $attribs = [
2139 'title' => self::titleAttrib( $name, $options, $msgParams ),
2140 'accesskey' => self::accesskey( $name )
2141 ];
2142 if ( $attribs['title'] === false ) {
2143 unset( $attribs['title'] );
2144 }
2145 if ( $attribs['accesskey'] === false ) {
2146 unset( $attribs['accesskey'] );
2147 }
2148 return $attribs;
2149 }
2150
2158 public static function tooltip( $name, $options = null ) {
2159 $tooltip = self::titleAttrib( $name, $options );
2160 if ( $tooltip === false ) {
2161 return '';
2162 }
2163 return Xml::expandAttributes( [
2164 'title' => $tooltip
2165 ] );
2166 }
2167
2168}
Apache License January AND DISTRIBUTION Definitions License shall mean the terms and conditions for use
See &</td >< td > &Fill in a specific reason below(for example, citing particular pages that were vandalized).</td >< td >
target page
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:875
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
Internationalisation code.
Definition Language.php:36
Some internal bits split of from Skin.php.
Definition Linker.php:34
static generateRollback( $rev, IContextSource $context=null, $options=[ 'verify'])
Generate a rollback link for a given revision.
Definition Linker.php:1750
static makeMediaLinkFile(Title $title, $file, $html='')
Create a direct link to a given uploaded file.
Definition Linker.php:775
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:231
static tocLine( $anchor, $tocline, $tocnumber, $level, $sectionIndex=false)
parameter level defines if we are on an indentation level
Definition Linker.php:1576
static userLink( $userId, $userName, $altUserName=false)
Make user link (or user contributions for unregistered users)
Definition Linker.php:892
static $accesskeycache
Definition Linker.php:2000
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:1965
static makeThumbLink2(Title $title, $file, $frameParams=[], $handlerParams=[], $time=false, $query="")
Definition Linker.php:522
static accesskey( $name)
Given the id of an interface element, constructs the appropriate accesskey attribute from the system ...
Definition Linker.php:2013
static formatAutocomments( $comment, $title=null, $local=false, $wikiId=null)
Converts autogenerated comments in edit summaries into section links.
Definition Linker.php:1152
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:816
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:307
static linkKnown( $target, $html=null, $customAttribs=[], $query=[], $options=[ 'known'])
Identical to link(), except $options defaults to 'known'.
Definition Linker.php:146
static makeExternalImage( $url, $alt='')
Return the code for images which were added via external links, via Parser::maybeMakeExternalImage().
Definition Linker.php:251
static buildRollbackLink( $rev, IContextSource $context=null, $editCount=false)
Build a raw rollback link, useful for collections of "tool" links.
Definition Linker.php:1857
static makeCommentLink(LinkTarget $linkTarget, $text, $wikiId=null, $options=[])
Generates a link to the given Title.
Definition Linker.php:1365
static revComment(Revision $rev, $local=false, $isPublic=false, $useParentheses=true)
Wrap and format the given revision's comment block, if the current user is allowed to view it.
Definition Linker.php:1510
static processResponsiveImages( $file, $thumb, $hp)
Process responsive images: add 1.5x and 2x subimages to the thumbnail, where applicable.
Definition Linker.php:644
static blockLink( $userId, $userText)
Definition Linker.php:1032
static revDeleteLinkDisabled( $delete=true)
Creates a dead (show/hide) link for deleting revisions/log entries.
Definition Linker.php:2111
static getRollbackEditCount( $rev, $verify)
This function will return the number of revisions which a rollback would revert and,...
Definition Linker.php:1795
static normalizeSubpageLink( $contextTitle, $target, &$text)
Definition Linker.php:1394
const TOOL_LINKS_NOBLOCK
Flags for userToolLinks()
Definition Linker.php:38
static tocList( $toc, $lang=null)
Wraps the TOC in a table and provides the hide/collapse javascript.
Definition Linker.php:1613
static makeSelfLinkObj( $nt, $html='', $query='', $trail='', $prefix='')
Make appropriate markup for a link to the current article.
Definition Linker.php:168
static getUploadUrl( $destFile, $query='')
Get the URL to upload a certain file.
Definition Linker.php:729
static generateTOC( $tree, $lang=null)
Generate a table of contents from a section tree.
Definition Linker.php:1655
static tocIndent()
Add another level to the Table of Contents.
Definition Linker.php:1550
static revUserLink( $rev, $isPublic=false)
Generate a user link if the current user is allowed to view it.
Definition Linker.php:1063
static getInvalidTitleDescription(IContextSource $context, $namespace, $title)
Get a message saying that an invalid title was encountered.
Definition Linker.php:191
static emailLink( $userId, $userText)
Definition Linker.php:1047
static formatHiddenCategories( $hiddencats)
Returns HTML for the "hidden categories on this page" list.
Definition Linker.php:1930
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:1714
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:496
const TOOL_LINKS_EMAIL
Definition Linker.php:39
static formatRevisionSize( $size)
Definition Linker.php:1535
static commentBlock( $comment, $title=null, $local=false, $wikiId=null, $useParentheses=true)
Wrap a comment in standard punctuation and formatting if it's non-empty, otherwise return empty strin...
Definition Linker.php:1480
static tooltip( $name, $options=null)
Returns raw bits of HTML, use titleAttrib()
Definition Linker.php:2158
static revUserTools( $rev, $isPublic=false, $useParentheses=true)
Generate a user tool link cluster if the current user is allowed to view it.
Definition Linker.php:1086
static userTalkLink( $userId, $userText)
Definition Linker.php:1016
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:1253
static makeMediaLinkObj( $title, $html='', $time=false)
Create a direct link to a given uploaded file.
Definition Linker.php:758
static makeExternalLink( $url, $text, $escape=true, $linktype='', $attribs=[], $title=null)
Make an external link.
Definition Linker.php:842
static userToolLinks( $userId, $userText, $redContribsWhenNoEdits=false, $flags=0, $edits=null, $useParentheses=true)
Generate standard user tool links (talk, contributions, block link, etc.)
Definition Linker.php:931
static normaliseSpecialPage(LinkTarget $target)
Definition Linker.php:211
static makeHeadline( $level, $attribs, $anchor, $html, $link, $fallbackAnchor=false)
Create a headline for content.
Definition Linker.php:1693
static tocUnindent( $level)
Finish one or more sublevels on the Table of Contents.
Definition Linker.php:1561
static tooltipAndAccesskeyAttribs( $name, array $msgParams=[], $options=null)
Returns the attributes for the tooltip and access key.
Definition Linker.php:2130
static getImageLinkMTOParams( $frameParams, $query='', $parser=null)
Get the link parameters for MediaTransformOutput::toHtml() from given frame parameters supplied by th...
Definition Linker.php:457
static revDeleteLink( $query=[], $restricted=false, $delete=true)
Creates a (show/hide) link for deleting revisions/log entries.
Definition Linker.php:2089
static tocLineEnd()
End a Table Of Contents line.
Definition Linker.php:1600
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:1122
static userToolLinksRedContribs( $userId, $userText, $edits=null, $useParentheses=true)
Alias for userToolLinks( $userId, $userText, true );.
Definition Linker.php:1004
static makeBrokenImageLinkObj( $title, $label='', $query='', $unused1='', $unused2='', $time=false)
Make a "broken" link to an image.
Definition Linker.php:679
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:2049
MediaWikiServices is the service locator for the application scope of MediaWiki.
getTitle()
Get the Title object that we'll be acting on, as specified in the WebRequest.
PHP Parser - Processes wiki markup (which uses a more user-friendly syntax, such as "[[link]]" for ma...
Definition Parser.php:69
static singleton()
Get a RepoGroup instance.
Definition RepoGroup.php:61
const DELETED_USER
Definition Revision.php:48
static getQueryInfo( $options=[])
Return the tables, fields, and join conditions to be selected to create a new revision object.
Definition Revision.php:511
const DELETED_TEXT
Definition Revision.php:46
const DELETED_RESTRICTED
Definition Revision.php:49
const RAW
Definition Revision.php:56
const DELETED_COMMENT
Definition Revision.php:47
const FOR_THIS_USER
Definition Revision.php:55
static escapeRegexReplacement( $string)
Escape a string to make it suitable for inclusion in a preg_replace() replacement parameter.
Represents a title within MediaWiki.
Definition Title.php:40
The User object encapsulates all of the user-specific settings (user_id, name, rights,...
Definition User.php:48
static newFromId( $id)
Static factory method for creation from a given user ID.
Definition User.php:609
static getDefaultOption( $opt)
Get a given default option value.
Definition User.php:1818
$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
This document is intended to provide useful advice for parties seeking to redistribute MediaWiki to end users It s targeted particularly at maintainers for Linux since it s been observed that distribution packages of MediaWiki often break We ve consistently had to recommend that users seeking support use official tarballs instead of their distribution s and this often solves whatever problem the user is having It would be nice if this could such as
This document is intended to provide useful advice for parties seeking to redistribute MediaWiki to end users It s targeted particularly at maintainers for Linux since it s been observed that distribution packages of MediaWiki often break We ve consistently had to recommend that users seeking support use official tarballs instead of their distribution s and this often solves whatever problem the user is having It would be nice if this could change
const NS_USER
Definition Defines.php:75
const NS_FILE
Definition Defines.php:79
const NS_MAIN
Definition Defines.php:73
const NS_SPECIAL
Definition Defines.php:62
const NS_MEDIA
Definition Defines.php:61
const NS_USER_TALK
Definition Defines.php:76
see documentation in includes Linker php for Linker::makeImageLink & $time
Definition hooks.txt:1802
see documentation in includes Linker php for Linker::makeImageLink or false for current used if you return false $parser
Definition hooks.txt:1834
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:1582
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:1584
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:1999
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:3071
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:2848
null means default & $customAttribs
Definition hooks.txt:1993
namespace and then decline to actually register it file or subcat img or subcat $title
Definition hooks.txt:955
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:2290
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:2003
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:2011
usually copyright or history_copyright This message must be in HTML not wikitext & $link
Definition hooks.txt:3069
Allows to change the fields on the form that will be generated $name
Definition hooks.txt:271
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:2012
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:1617
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:2054
return true to allow those checks to and false if checking is done & $user
Definition hooks.txt:1510
see documentation in includes Linker php for Linker::makeImageLink & $handlerParams
Definition hooks.txt:1800
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:3070
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:1779
processing should stop and the error should be shown to the user * false
Definition hooks.txt:187
injection txt This is an overview of how MediaWiki makes use of dependency injection The design described here grew from the discussion of RFC T384 The term dependency this means that anything an object needs to operate should be injected from the the object itself should only know narrow no concrete implementation of the logic it relies on The requirement to inject everything typically results in an architecture that based on two main types of and essentially stateless service objects that use other service objects to operate on the value objects As of the beginning MediaWiki is only starting to use the DI approach Much of the code still relies on global state or direct resulting in a highly cyclical dependency which acts as the top level factory for services in MediaWiki which can be used to gain access to default instances of various services MediaWikiServices however also allows new services to be defined and default services to be redefined Services are defined or redefined by providing a callback the instantiator that will return a new instance of the service When it will create an instance of MediaWikiServices and populate it with the services defined in the files listed by thereby bootstrapping the DI framework Per $wgServiceWiringFiles lists includes ServiceWiring php
Definition injection.txt:37
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))
This document provides an overview of the usage of PageUpdater and that is
const DB_REPLICA
Definition defines.php:25
if(PHP_SAPI !='cli-server') if(!isset( $_SERVER['SCRIPT_FILENAME'])) $file
Definition router.php:42
$params
if(!isset( $args[0])) $lang