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'; public const INLINE_SWITCHER_KEY = '60_mw-diff-inline-switch'; /** @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, Title $newTitle ): array { $legend = null; $inlineSwitcher = null; $showDiffToggleSwitch = $context->getConfig()->get( MainConfigNames::ShowDiffToggleSwitch ); // wikidiff2 inline type gets a legend to explain the highlighting colours and show an inline toggle if ( $this->engine === self::ENGINE_WIKIDIFF2 || $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() ); $hideDiffClass = $this->engine === self::ENGINE_WIKIDIFF2 ? 'oo-ui-element-hidden' : ''; $legend = Html::rawElement( 'div', [ 'class' => 'mw-diff-inline-legend ' . $hideDiffClass ], "$ins $del" ); if ( $showDiffToggleSwitch ) { $values = $context->getRequest()->getValues(); $isInlineDiffType = isset( $values['diff-type'] ) && $values['diff-type'] === 'inline'; unset( $values[ 'diff-type' ] ); unset( $values[ 'title' ] ); $inlineSwitcher = Html::rawElement( 'div', [ 'class' => 'mw-diffPage-inlineToggle-container' ], // Will be replaced by a ButtonSelectWidget in JS new ButtonGroupWidget( [ 'items' => [ new ButtonWidget( [ 'active' => $isInlineDiffType, 'label' => $context->msg( 'diff-inline-format-label' )->plain(), 'href' => $newTitle->getLocalURL( $values ) . '&diff-type=inline' ] ), new ButtonWidget( [ 'active' => !$isInlineDiffType, 'label' => $context->msg( 'diff-table-format-label' )->plain(), 'href' => $newTitle->getLocalURL( $values ) ] ) ] ] ) ); } } // 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, self::INLINE_SWITCHER_KEY => $inlineSwitcher ]; $this->hookRunner->onTextSlotDiffRendererTablePrefix( $this, $context, $parts ); if ( count( $parts ) > 1 && $parts[self::INLINE_LEGEND_KEY] === null ) { $parts[self::INLINE_LEGEND_KEY] = Html::element( 'div' ); } return $parts; } /** * 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