getSlotDiffRenderer( RequestContext::getMain() ) * * @ingroup DifferenceEngine */ class TextSlotDiffRenderer extends SlotDiffRenderer { /** Use the PHP diff implementation (DiffEngine). */ public const ENGINE_PHP = 'php'; /** Use the wikidiff2 PHP module. */ public const ENGINE_WIKIDIFF2 = 'wikidiff2'; /** Use the wikidiff2 PHP module. */ public const ENGINE_WIKIDIFF2_INLINE = 'wikidiff2inline'; /** Use an external executable. */ public const ENGINE_EXTERNAL = 'external'; public const INLINE_LEGEND_KEY = '10_mw-diff-inline-legend'; /** @var IBufferingStatsdDataFactory|null */ private $statsdDataFactory; /** @var Language|null The language this content is in. */ private $language; /** @var HookRunner|null */ private $hookRunner; /** @var string One of the ENGINE_* constants. */ private $engine = self::ENGINE_PHP; /** @var string|null Path to an executable to be used as the diff engine. */ private $externalEngine; /** @var string */ private $contentModel; /** @inheritDoc */ public function getExtraCacheKeys() { // Tell DifferenceEngine this is a different variant from the standard wikidiff2 variant return $this->engine === self::ENGINE_WIKIDIFF2_INLINE ? [ phpversion( 'wikidiff2' ), 'inline' ] : []; } /** * Convenience helper to use getTextDiff without an instance. * @param string $oldText * @param string $newText * @return string */ public static function diff( $oldText, $newText ) { /** @var TextSlotDiffRenderer $slotDiffRenderer */ $slotDiffRenderer = MediaWikiServices::getInstance() ->getContentHandlerFactory() ->getContentHandler( CONTENT_MODEL_TEXT ) ->getSlotDiffRenderer( RequestContext::getMain() ); '@phan-var TextSlotDiffRenderer $slotDiffRenderer'; return $slotDiffRenderer->getTextDiff( $oldText, $newText ); } /** * @param IBufferingStatsdDataFactory $statsdDataFactory */ public function setStatsdDataFactory( IBufferingStatsdDataFactory $statsdDataFactory ) { $this->statsdDataFactory = $statsdDataFactory; } /** * @param Language $language */ public function setLanguage( Language $language ) { $this->language = $language; } /** * @since 1.41 * @param HookContainer $hookContainer */ public function setHookContainer( HookContainer $hookContainer ): void { $this->hookRunner = new HookRunner( $hookContainer ); } /** * @param string $contentModel * @since 1.41 */ public function setContentModel( string $contentModel ) { $this->contentModel = $contentModel; } /** * Set which diff engine to use. * @param string $type One of the ENGINE_* constants. * @param string|null $executable Path to an external executable, only when type is ENGINE_EXTERNAL. */ public function setEngine( $type, $executable = null ) { $engines = [ self::ENGINE_PHP, self::ENGINE_WIKIDIFF2, self::ENGINE_EXTERNAL, self::ENGINE_WIKIDIFF2_INLINE ]; Assert::parameter( in_array( $type, $engines, true ), '$type', 'must be one of the TextSlotDiffRenderer::ENGINE_* constants' ); if ( $type === self::ENGINE_EXTERNAL ) { Assert::parameter( is_string( $executable ) && is_executable( $executable ), '$executable', 'must be a path to a valid executable' ); } else { Assert::parameter( $executable === null, '$executable', 'must not be set unless $type is ENGINE_EXTERNAL' ); } $this->engine = $type; $this->externalEngine = $executable; } /** * Get the content model ID that this renderer acts on * * @since 1.41 * @return string */ public function getContentModel(): string { return $this->contentModel; } /** @inheritDoc */ public function getDiff( Content $oldContent = null, Content $newContent = null ) { $this->normalizeContents( $oldContent, $newContent, TextContent::class ); $oldText = $oldContent->serialize(); $newText = $newContent->serialize(); return $this->getTextDiff( $oldText, $newText ); } /** * @inheritDoc */ public function getTablePrefix( IContextSource $context ): string { $legend = null; // wikidiff2 inline type gets a legend to explain the highlighting colours. if ( $this->engine === self::ENGINE_WIKIDIFF2_INLINE ) { $ins = Html::element( 'span', [ 'class' => 'mw-diff-inline-legend-ins' ], $context->msg( 'diff-inline-tooltip-ins' )->plain() ); $del = Html::element( 'span', [ 'class' => 'mw-diff-inline-legend-del' ], $context->msg( 'diff-inline-tooltip-del' )->plain() ); $legend = Html::rawElement( 'div', [ 'class' => 'mw-diff-inline-legend' ], "$ins $del" ); } // Allow extensions to add other parts to this area (or modify the legend). // An empty placeholder for the legend is added when it's not in use and other items have been added. $parts = [ self::INLINE_LEGEND_KEY => $legend ]; $this->hookRunner->onTextSlotDiffRendererTablePrefix( $this, $context, $parts ); if ( count( $parts ) > 1 && $parts[self::INLINE_LEGEND_KEY] === null ) { $parts[self::INLINE_LEGEND_KEY] = Html::element( 'div' ); } ksort( $parts ); if ( count( array_filter( $parts ) ) > 0 ) { $attrs = [ 'class' => 'mw-diff-table-prefix', 'dir' => $this->language->getDir(), 'lang' => $this->language->getCode(), ]; return Html::rawElement( 'div', $attrs, implode( '', $parts ) ); } return ''; } /** * Diff the text representations of two content objects (or just two pieces of text in general). * @param string $oldText * @param string $newText * @return string HTML. One or more