Page Menu
Home
WickedGov Phorge
Search
Configure Global Search
Log In
Files
F1430116
TextSlotDiffRenderer.php
No One
Temporary
Actions
Download File
Edit File
Delete File
View Transforms
Subscribe
Flag For Later
Award Token
Size
10 KB
Referenced Files
None
Subscribers
None
TextSlotDiffRenderer.php
View Options
<?php
/**
* Renders a slot diff by doing a text diff on the native representation.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
* http://www.gnu.org/copyleft/gpl.html
*
* @file
* @ingroup DifferenceEngine
*/
use
MediaWiki\Content\Content
;
use
MediaWiki\Content\TextContent
;
use
MediaWiki\Context\IContextSource
;
use
MediaWiki\Context\RequestContext
;
use
MediaWiki\Diff\TextDiffer\ManifoldTextDiffer
;
use
MediaWiki\Diff\TextDiffer\TextDiffer
;
use
MediaWiki\HookContainer\HookContainer
;
use
MediaWiki\HookContainer\HookRunner
;
use
MediaWiki\Html\Html
;
use
MediaWiki\Language\Language
;
use
MediaWiki\MediaWikiServices
;
use
MediaWiki\PoolCounter\PoolCounterWorkViaCallback
;
use
MediaWiki\Status\Status
;
use
MediaWiki\Title\Title
;
use
OOUI\ToggleSwitchWidget
;
use
Wikimedia\Stats\IBufferingStatsdDataFactory
;
use
Wikimedia\Stats\StatsFactory
;
/**
* Renders a slot diff by doing a text diff on the native representation.
*
* If you want to use this without content objects (to call getTextDiff() on some
* non-content-related texts), obtain an instance with
* ContentHandler::getForModelID( CONTENT_MODEL_TEXT )
* ->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 StatsFactory|null */
private
$statsFactory
;
/** @var HookRunner|null */
private
$hookRunner
;
/** @var string|null */
private
$format
;
/** @var string */
private
$contentModel
;
/** @var TextDiffer|null */
private
$textDiffer
;
/** @var bool */
private
$inlineToggleEnabled
=
false
;
/** @inheritDoc */
public
function
getExtraCacheKeys
()
{
return
$this
->
textDiffer
->
getCacheKeys
(
[
$this
->
format
]
);
}
/**
* Convenience helper to use getTextDiff without an instance.
* @param string $oldText
* @param string $newText
* @param array $options
* @return string
*/
public
static
function
diff
(
$oldText
,
$newText
,
$options
=
[]
)
{
/** @var TextSlotDiffRenderer $slotDiffRenderer */
$slotDiffRenderer
=
MediaWikiServices
::
getInstance
()
->
getContentHandlerFactory
()
->
getContentHandler
(
CONTENT_MODEL_TEXT
)
->
getSlotDiffRenderer
(
RequestContext
::
getMain
(),
$options
);
'@phan-var TextSlotDiffRenderer $slotDiffRenderer'
;
return
$slotDiffRenderer
->
getTextDiff
(
$oldText
,
$newText
);
}
/**
* This has no effect since MW 1.43.
*
* @internal Use ContentHandler::createTextSlotDiffRenderer instead
* @param IBufferingStatsdDataFactory $statsdDataFactory
*/
public
function
setStatsdDataFactory
(
IBufferingStatsdDataFactory
$statsdDataFactory
)
{
wfDeprecated
(
__METHOD__
,
'1.43'
);
}
/**
* @internal Use ContentHandler::createTextSlotDiffRenderer instead
* @param StatsFactory $statsFactory
*/
public
function
setStatsFactory
(
StatsFactory
$statsFactory
)
{
$this
->
statsFactory
=
$statsFactory
;
}
/**
* This has no effect since MW 1.41. The language is now injected via setTextDiffer().
*
* @param Language $language
* @deprecated since 1.41
*/
public
function
setLanguage
(
Language
$language
)
{
wfDeprecated
(
__METHOD__
,
'1.41'
);
}
/**
* @internal Use ContentHandler::createTextSlotDiffRenderer instead
* @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 null $executable Must be null since 1.41. Previously a path to execute.
*/
public
function
setEngine
(
$type
,
$executable
=
null
)
{
if
(
$executable
!==
null
)
{
throw
new
\InvalidArgumentException
(
'The $executable parameter is no longer supported and must be null'
);
}
switch
(
$type
)
{
case
self
::
ENGINE_PHP
:
$engine
=
'php'
;
$format
=
'table'
;
break
;
case
self
::
ENGINE_WIKIDIFF2
:
$engine
=
'wikidiff2'
;
$format
=
'table'
;
break
;
case
self
::
ENGINE_EXTERNAL
:
$engine
=
'external'
;
$format
=
'external'
;
break
;
case
self
::
ENGINE_WIKIDIFF2_INLINE
:
$engine
=
'wikidiff2'
;
$format
=
'inline'
;
break
;
default
:
throw
new
\InvalidArgumentException
(
'$type '
.
'must be one of the TextSlotDiffRenderer::ENGINE_* constants'
);
}
if
(
$this
->
textDiffer
instanceof
ManifoldTextDiffer
)
{
$this
->
textDiffer
->
setEngine
(
$engine
);
}
$this
->
setFormat
(
$format
);
}
/**
* Set the TextDiffer format
*
* @since 1.41
* @param string $format
*/
public
function
setFormat
(
$format
)
{
$this
->
format
=
$format
;
}
/**
* @param TextDiffer $textDiffer
*/
public
function
setTextDiffer
(
TextDiffer
$textDiffer
)
{
$this
->
textDiffer
=
$textDiffer
;
}
/**
* Get the current TextDiffer, or throw an exception if setTextDiffer() has
* not been called.
*
* @return TextDiffer
*/
private
function
getTextDiffer
():
TextDiffer
{
return
$this
->
textDiffer
;
}
/**
* Set a flag indicating whether the inline toggle switch is shown.
*
* @since 1.41
* @param bool $enabled
*/
public
function
setInlineToggleEnabled
(
$enabled
=
true
)
{
$this
->
inlineToggleEnabled
=
$enabled
;
}
/**
* 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
);
}
public
function
localizeDiff
(
$diff
,
$options
=
[]
)
{
return
$this
->
textDiffer
->
localize
(
$this
->
format
,
$diff
,
$options
);
}
/**
* @inheritDoc
*/
public
function
getTablePrefix
(
IContextSource
$context
,
Title
$newTitle
):
array
{
$parts
=
$this
->
getTextDiffer
()->
getTablePrefixes
(
$this
->
format
);
$showDiffToggleSwitch
=
$this
->
inlineToggleEnabled
&&
$this
->
getTextDiffer
()->
hasFormat
(
'inline'
);
// If we support the inline type, add a toggle switch
if
(
$showDiffToggleSwitch
)
{
$values
=
$context
->
getRequest
()->
getValues
();
$isInlineDiffType
=
$this
->
format
===
'inline'
;
$values
[
'diff-type'
]
=
$isInlineDiffType
?
'table'
:
'inline'
;
unset
(
$values
[
'title'
]
);
$parts
[
self
::
INLINE_SWITCHER_KEY
]
=
Html
::
rawElement
(
'div'
,
[
'class'
=>
'mw-diffPage-inlineToggle-container'
],
new
OOUI\FieldLayout
(
new
ToggleSwitchWidget
(
[
'id'
=>
'mw-diffPage-inline-toggle-switch'
,
'href'
=>
$newTitle
->
getLocalURL
(
$values
),
'value'
=>
$isInlineDiffType
,
'title'
=>
$context
->
msg
(
'diff-inline-switch-desc'
)->
plain
()
]
),
[
'id'
=>
'mw-diffPage-inline-toggle-switch-layout'
,
'label'
=>
$context
->
msg
(
'diff-inline-format-label'
)->
plain
(),
'infusable'
=>
true
,
'title'
=>
$context
->
msg
(
'diff-inline-switch-desc'
)->
plain
()
]
),
);
}
// Add 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
=>
null
,
self
::
INLINE_SWITCHER_KEY
=>
null
];
// Allow extensions to add other parts to this area (or modify the 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'
);
}
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 <tr> tags, or an empty string if the inputs are identical.
*/
public
function
getTextDiff
(
string
$oldText
,
string
$newText
)
{
$diff
=
function
()
use
(
$oldText
,
$newText
)
{
$time
=
microtime
(
true
);
$result
=
$this
->
getTextDiffInternal
(
$oldText
,
$newText
);
$time
=
intval
(
(
microtime
(
true
)
-
$time
)
*
1000
);
if
(
$this
->
statsFactory
)
{
$this
->
statsFactory
->
getTiming
(
'diff_text_seconds'
)
->
copyToStatsdAt
(
'diff_time'
)
->
observe
(
$time
);
}
return
$result
;
};
/**
* @param Status $status
* @throws FatalError
* @return never
*/
$error
=
static
function
(
$status
)
{
throw
new
FatalError
(
$status
->
getWikiText
()
);
};
// Use PoolCounter if the diff looks like it can be expensive
if
(
strlen
(
$oldText
)
+
strlen
(
$newText
)
>
20000
)
{
$work
=
new
PoolCounterWorkViaCallback
(
'diff'
,
md5
(
$oldText
)
.
md5
(
$newText
),
[
'doWork'
=>
$diff
,
'error'
=>
$error
]
);
return
$work
->
execute
();
}
return
$diff
();
}
/**
* Diff the text representations of two content objects (or just two pieces of text in general).
* This does the actual diffing, getTextDiff() wraps it with logging and resource limiting.
* @param string $oldText
* @param string $newText
* @return string
* @throws Exception
*/
protected
function
getTextDiffInternal
(
$oldText
,
$newText
)
{
$oldText
=
str_replace
(
"
\r\n
"
,
"
\n
"
,
$oldText
);
$newText
=
str_replace
(
"
\r\n
"
,
"
\n
"
,
$newText
);
if
(
$oldText
===
$newText
)
{
return
''
;
}
$textDiffer
=
$this
->
getTextDiffer
();
$diffText
=
$textDiffer
->
render
(
$oldText
,
$newText
,
$this
->
format
);
return
$textDiffer
->
addRowWrapper
(
$this
->
format
,
$diffText
);
}
}
File Metadata
Details
Attached
Mime Type
text/x-php
Expires
Sat, May 16, 18:24 (7 h, 5 m)
Storage Engine
local-disk
Storage Format
Raw Data
Storage Handle
97/ce/544c0e0e504b51e425ddb8694a21
Default Alt Text
TextSlotDiffRenderer.php (10 KB)
Attached To
Mode
rMWPROD MediaWiki Production
Attached
Detach File
Event Timeline
Log In to Comment