Page Menu
Home
WickedGov Phorge
Search
Configure Global Search
Log In
Files
F4127980
ApiVisualEditorEdit.php
No One
Temporary
Actions
Download File
Edit File
Delete File
View Transforms
Subscribe
Flag For Later
Award Token
Size
20 KB
Referenced Files
None
Subscribers
None
ApiVisualEditorEdit.php
View Options
<?php
/**
* Parsoid/RESTBase+MediaWiki API wrapper.
*
* @file
* @ingroup Extensions
* @copyright 2011-2021 VisualEditor Team and others; see AUTHORS.txt
* @license MIT
*/
namespace
MediaWiki\Extension\VisualEditor
;
use
Deflate
;
use
DifferenceEngine
;
use
FlaggablePageView
;
use
MediaWiki\Api\ApiBase
;
use
MediaWiki\Api\ApiMain
;
use
MediaWiki\Content\ContentHandler
;
use
MediaWiki\Context\DerivativeContext
;
use
MediaWiki\Context\RequestContext
;
use
MediaWiki\HookContainer\HookContainer
;
use
MediaWiki\Logger\LoggerFactory
;
use
MediaWiki\MediaWikiServices
;
use
MediaWiki\Page\WikiPageFactory
;
use
MediaWiki\Parser\Sanitizer
;
use
MediaWiki\Registration\ExtensionRegistry
;
use
MediaWiki\Request\DerivativeRequest
;
use
MediaWiki\Revision\SlotRecord
;
use
MediaWiki\Skin\SkinFactory
;
use
MediaWiki\SpecialPage\SpecialPageFactory
;
use
MediaWiki\Storage\PageEditStash
;
use
MediaWiki\Title\Title
;
use
MediaWiki\User\UserIdentity
;
use
Wikimedia\ObjectCache\BagOStuff
;
use
Wikimedia\ParamValidator\ParamValidator
;
use
Wikimedia\Rdbms\IDBAccessObject
;
use
Wikimedia\Stats\StatsFactory
;
class
ApiVisualEditorEdit
extends
ApiBase
{
use
ApiParsoidTrait
;
private
const
MAX_CACHE_RECENT
=
2
;
private
const
MAX_CACHE_TTL
=
900
;
private
readonly
VisualEditorHookRunner
$hookRunner
;
public
function
__construct
(
ApiMain
$main
,
string
$name
,
HookContainer
$hookContainer
,
StatsFactory
$statsFactory
,
private
readonly
PageEditStash
$pageEditStash
,
private
readonly
SkinFactory
$skinFactory
,
private
readonly
WikiPageFactory
$wikiPageFactory
,
private
readonly
SpecialPageFactory
$specialPageFactory
,
private
readonly
VisualEditorParsoidClientFactory
$parsoidClientFactory
)
{
parent
::
__construct
(
$main
,
$name
);
$this
->
setLogger
(
LoggerFactory
::
getInstance
(
'VisualEditor'
)
);
$this
->
setStatsFactory
(
$statsFactory
);
$this
->
hookRunner
=
new
VisualEditorHookRunner
(
$hookContainer
);
}
/**
* @inheritDoc
*/
protected
function
getParsoidClient
():
ParsoidClient
{
return
$this
->
parsoidClientFactory
->
createParsoidClient
(
$this
->
getRequest
()->
getHeader
(
'Cookie'
)
);
}
/**
* Attempt to save a given page's wikitext to MediaWiki's storage layer via its API
*
* @param Title $title The title of the page to write
* @param string $wikitext The wikitext to write
* @param array $params The edit parameters
* @return mixed The result of the save attempt
*/
protected
function
saveWikitext
(
Title
$title
,
$wikitext
,
$params
)
{
$apiParams
=
[
'action'
=>
'edit'
,
'title'
=>
$title
->
getPrefixedDBkey
(),
'text'
=>
$wikitext
,
'summary'
=>
$params
[
'summary'
],
'basetimestamp'
=>
$params
[
'basetimestamp'
],
'starttimestamp'
=>
$params
[
'starttimestamp'
],
'token'
=>
$params
[
'token'
],
'watchlist'
=>
$params
[
'watchlist'
],
// NOTE: Must use getText() to work; PHP array from $params['tags'] is not understood
// by the edit API.
'tags'
=>
$this
->
getRequest
()->
getText
(
'tags'
),
'section'
=>
$params
[
'section'
],
'sectiontitle'
=>
$params
[
'sectiontitle'
],
'captchaid'
=>
$params
[
'captchaid'
],
'captchaword'
=>
$params
[
'captchaword'
],
'returnto'
=>
$params
[
'returnto'
],
'returntoquery'
=>
$params
[
'returntoquery'
],
'returntoanchor'
=>
$params
[
'returntoanchor'
],
'errorformat'
=>
'html'
,
(
$params
[
'minor'
]
!==
null
?
'minor'
:
'notminor'
)
=>
true
,
];
// Pass any unrecognized query parameters to the internal action=edit API request. This is
// necessary to support extensions that add extra stuff to the edit form (e.g. FlaggedRevs)
// and allows passing any other query parameters to be used for edit tagging (e.g. T209132).
// Exclude other known params from here and ApiMain.
// TODO: This doesn't exclude params from the formatter
$allParams
=
$this
->
getRequest
()->
getValues
();
$knownParams
=
array_keys
(
$this
->
getAllowedParams
()
+
$this
->
getMain
()->
getAllowedParams
()
);
foreach
(
$knownParams
as
$knownParam
)
{
unset
(
$allParams
[
$knownParam
]
);
}
$context
=
new
DerivativeContext
(
$this
->
getContext
()
);
$context
->
setRequest
(
new
DerivativeRequest
(
$context
->
getRequest
(),
$apiParams
+
$allParams
,
/* was posted? */
true
)
);
$api
=
new
ApiMain
(
$context
,
/* enable write? */
true
);
$api
->
execute
();
return
$api
->
getResult
()->
getResultData
();
}
/**
* Load into an array the output of MediaWiki's parser for a given revision
*
* @param int $newRevId The revision to load
* @param array $params Original request params
* @return array Some properties haphazardly extracted from an action=parse API response
*/
protected
function
parseWikitext
(
$newRevId
,
array
$params
)
{
$apiParams
=
[
'action'
=>
'parse'
,
'oldid'
=>
$newRevId
,
'prop'
=>
'text|revid|categorieshtml|sections|displaytitle|subtitle|modules|jsconfigvars'
,
'usearticle'
=>
true
,
'useskin'
=>
$params
[
'useskin'
],
];
// Boolean parameters must be omitted completely to be treated as false.
// Param is added by hook in MobileFrontend, so it may be unset.
if
(
isset
(
$params
[
'mobileformat'
]
)
&&
$params
[
'mobileformat'
]
)
{
$apiParams
[
'mobileformat'
]
=
'1'
;
}
$context
=
new
DerivativeContext
(
$this
->
getContext
()
);
$context
->
setRequest
(
new
DerivativeRequest
(
$context
->
getRequest
(),
$apiParams
,
/* was posted? */
true
)
);
$api
=
new
ApiMain
(
$context
,
/* enable write? */
true
);
$api
->
execute
();
$result
=
$api
->
getResult
()->
getResultData
(
null
,
[
/* Transform content nodes to '*' */
'BC'
=>
[],
/* Add back-compat subelements */
'Types'
=>
[],
/* Remove any metadata keys from the links array */
'Strip'
=>
'all'
,
]
);
$content
=
$result
[
'parse'
][
'text'
][
'*'
]
??
false
;
$categorieshtml
=
$result
[
'parse'
][
'categorieshtml'
][
'*'
]
??
false
;
$sections
=
isset
(
$result
[
'parse'
][
'showtoc'
]
)
?
$result
[
'parse'
][
'sections'
]
:
[];
$displaytitle
=
$result
[
'parse'
][
'displaytitle'
]
??
false
;
$subtitle
=
$result
[
'parse'
][
'subtitle'
]
??
false
;
$modules
=
array_merge
(
$result
[
'parse'
][
'modules'
]
??
[],
$result
[
'parse'
][
'modulestyles'
]
??
[]
);
$jsconfigvars
=
$result
[
'parse'
][
'jsconfigvars'
]
??
[];
if
(
$displaytitle
!==
false
)
{
// Escape entities as in OutputPage::setPageTitle()
$displaytitle
=
Sanitizer
::
removeSomeTags
(
$displaytitle
);
}
return
[
'content'
=>
$content
,
'categorieshtml'
=>
$categorieshtml
,
'sections'
=>
$sections
,
'displayTitleHtml'
=>
$displaytitle
,
'contentSub'
=>
$subtitle
,
'modules'
=>
$modules
,
'jsconfigvars'
=>
$jsconfigvars
];
}
/**
* Create and load the parsed wikitext of an edit, or from the serialisation cache if available.
*
* @param Title $title The title of the page
* @param array $params The edit parameters
* @param array $parserParams The parser parameters
* @return string The wikitext of the edit
*/
protected
function
getWikitext
(
Title
$title
,
$params
,
$parserParams
)
{
if
(
$params
[
'cachekey'
]
!==
null
)
{
$wikitext
=
$this
->
trySerializationCache
(
$params
[
'cachekey'
]
);
if
(
!
is_string
(
$wikitext
)
)
{
$this
->
dieWithError
(
'apierror-visualeditor-badcachekey'
,
'badcachekey'
);
}
}
else
{
$wikitext
=
$this
->
getWikitextNoCache
(
$title
,
$params
,
$parserParams
);
}
'@phan-var string $wikitext'
;
return
$wikitext
;
}
/**
* Create and load the parsed wikitext of an edit, ignoring the serialisation cache.
*
* @param Title $title The title of the page
* @param array $params The edit parameters
* @param array $parserParams The parser parameters
* @return string The wikitext of the edit
*/
protected
function
getWikitextNoCache
(
Title
$title
,
$params
,
$parserParams
)
{
$this
->
requireOnlyOneParameter
(
$params
,
'html'
);
if
(
Deflate
::
isDeflated
(
$params
[
'html'
]
)
)
{
$status
=
Deflate
::
inflate
(
$params
[
'html'
]
);
if
(
!
$status
->
isGood
()
)
{
$this
->
dieWithError
(
'deflate-invaliddeflate'
,
'invaliddeflate'
);
}
$html
=
$status
->
getValue
();
}
else
{
$html
=
$params
[
'html'
];
}
$wikitext
=
$this
->
transformHTML
(
$title
,
$html
,
$parserParams
[
'oldid'
]
??
null
,
$params
[
'etag'
]
??
null
)[
'body'
];
return
$wikitext
;
}
/**
* Load the parsed wikitext of an edit into the serialisation cache.
*
* @param Title $title The title of the page
* @param string $wikitext The wikitext of the edit
* @return string|false The key of the wikitext in the serialisation cache
*/
protected
function
storeInSerializationCache
(
Title
$title
,
$wikitext
)
{
if
(
$wikitext
===
false
)
{
return
false
;
}
$cache
=
MediaWikiServices
::
getInstance
()->
getObjectCacheFactory
()->
getLocalClusterInstance
();
// Store the corresponding wikitext, referenceable by a new key
$hash
=
md5
(
$wikitext
);
$key
=
$cache
->
makeKey
(
'visualeditor'
,
'serialization'
,
$hash
);
$ok
=
$cache
->
set
(
$key
,
$wikitext
,
self
::
MAX_CACHE_TTL
);
if
(
$ok
)
{
$this
->
pruneExcessStashedEntries
(
$cache
,
$this
->
getUser
(),
$key
);
}
$status
=
$ok
?
'ok'
:
'failed'
;
$this
->
getStatsFactory
()->
getCounter
(
'VE_editstash_serialization_cache_set_total'
)
->
setLabel
(
'status'
,
$status
)
->
increment
();
// Also parse and prepare the edit in case it might be saved later
$pageUpdater
=
$this
->
wikiPageFactory
->
newFromTitle
(
$title
)->
newPageUpdater
(
$this
->
getUser
()
);
$content
=
ContentHandler
::
makeContent
(
$wikitext
,
$title
,
CONTENT_MODEL_WIKITEXT
);
$status
=
$this
->
pageEditStash
->
parseAndCache
(
$pageUpdater
,
$content
,
$this
->
getUser
(),
''
);
if
(
$status
===
$this
->
pageEditStash
::
ERROR_NONE
)
{
$logger
=
LoggerFactory
::
getInstance
(
'StashEdit'
);
$logger
->
debug
(
"Cached parser output for VE content key '$key'."
);
}
$this
->
getStatsFactory
()->
getCounter
(
'VE_editstash_cache_store_total'
)
->
setLabel
(
'status'
,
$status
)
->
increment
();
return
$hash
;
}
private
function
pruneExcessStashedEntries
(
BagOStuff
$cache
,
UserIdentity
$user
,
string
$newKey
):
void
{
$key
=
$cache
->
makeKey
(
'visualeditor-serialization-recent'
,
$user
->
getName
()
);
$keyList
=
$cache
->
get
(
$key
)
?:
[];
if
(
count
(
$keyList
)
>=
self
::
MAX_CACHE_RECENT
)
{
$oldestKey
=
array_shift
(
$keyList
);
$cache
->
delete
(
$oldestKey
);
}
$keyList
[]
=
$newKey
;
$cache
->
set
(
$key
,
$keyList
,
2
*
self
::
MAX_CACHE_TTL
);
}
/**
* Load some parsed wikitext of an edit from the serialisation cache.
*
* @param string $hash The key of the wikitext in the serialisation cache
* @return string|false The wikitext
*/
protected
function
trySerializationCache
(
$hash
)
{
$cache
=
MediaWikiServices
::
getInstance
()->
getObjectCacheFactory
()->
getLocalClusterInstance
();
$key
=
$cache
->
makeKey
(
'visualeditor'
,
'serialization'
,
$hash
);
$value
=
$cache
->
get
(
$key
);
$status
=
(
$value
!==
false
)
?
'hit'
:
'miss'
;
$this
->
getStatsFactory
()->
getCounter
(
'VE_editstash_serialization_cache_get_total'
)
->
setLabel
(
'status'
,
$status
)
->
increment
();
return
$value
;
}
/**
* Calculate the different between the wikitext of an edit and an existing revision.
*
* @param Title $title The title of the page
* @param int|null $fromId The existing revision of the page to compare with
* @param string $wikitext The wikitext to compare against
* @param int|null $section Whether the wikitext refers to a given section or the whole page
* @return array The comparison, or `[ 'result' => 'nochanges' ]` if there are none
*/
protected
function
diffWikitext
(
Title
$title
,
?
int
$fromId
,
$wikitext
,
$section
=
null
)
{
$apiParams
=
[
'action'
=>
'compare'
,
'prop'
=>
'diff'
,
// Because we're just providing wikitext, we only care about the main slot
'slots'
=>
SlotRecord
::
MAIN
,
'fromtitle'
=>
$title
->
getPrefixedDBkey
(),
'fromrev'
=>
$fromId
,
'fromsection'
=>
$section
,
'toslots'
=>
SlotRecord
::
MAIN
,
'totext-main'
=>
$wikitext
,
'topst'
=>
true
,
];
$context
=
new
DerivativeContext
(
$this
->
getContext
()
);
$context
->
setRequest
(
new
DerivativeRequest
(
$context
->
getRequest
(),
$apiParams
,
/* was posted? */
true
)
);
$api
=
new
ApiMain
(
$context
,
/* enable write? */
false
);
$api
->
execute
();
$result
=
$api
->
getResult
()->
getResultData
();
if
(
!
isset
(
$result
[
'compare'
][
'bodies'
][
SlotRecord
::
MAIN
]
)
)
{
$this
->
dieWithError
(
'apierror-visualeditor-difffailed'
,
'difffailed'
);
}
$diffRows
=
$result
[
'compare'
][
'bodies'
][
SlotRecord
::
MAIN
];
$context
=
new
DerivativeContext
(
$this
->
getContext
()
);
$context
->
setTitle
(
$title
);
$engine
=
new
DifferenceEngine
(
$context
);
return
[
'result'
=>
'success'
,
'diff'
=>
$diffRows
?
$engine
->
addHeader
(
$diffRows
,
$context
->
msg
(
'currentrev'
)->
parse
(),
$context
->
msg
(
'yourtext'
)->
parse
()
)
:
''
];
}
/**
* @inheritDoc
*/
public
function
execute
()
{
$user
=
$this
->
getUser
();
$params
=
$this
->
extractRequestParams
();
$result
=
[];
$title
=
Title
::
newFromText
(
$params
[
'page'
]
);
if
(
$title
&&
$title
->
isSpecialPage
()
)
{
// Convert Special:CollabPad/MyPage to MyPage so we can serialize properly
[
$special
,
$subPage
]
=
$this
->
specialPageFactory
->
resolveAlias
(
$title
->
getDBkey
()
);
if
(
$special
===
'CollabPad'
)
{
$title
=
Title
::
newFromText
(
$subPage
);
}
}
if
(
!
$title
)
{
$this
->
dieWithError
(
[
'apierror-invalidtitle'
,
wfEscapeWikiText
(
$params
[
'page'
]
)
]
);
}
if
(
!
$title
->
canExist
()
)
{
$this
->
dieWithError
(
'apierror-pagecannotexist'
);
}
$this
->
getErrorFormatter
()->
setContextTitle
(
$title
);
$parserParams
=
[];
if
(
isset
(
$params
[
'oldid'
]
)
)
{
$parserParams
[
'oldid'
]
=
$params
[
'oldid'
];
}
if
(
isset
(
$params
[
'wikitext'
]
)
)
{
$wikitext
=
str_replace
(
"
\r\n
"
,
"
\n
"
,
$params
[
'wikitext'
]
);
}
else
{
$wikitext
=
$this
->
getWikitext
(
$title
,
$params
,
$parserParams
);
}
if
(
$params
[
'paction'
]
===
'serialize'
)
{
$result
=
[
'result'
=>
'success'
,
'content'
=>
$wikitext
];
}
elseif
(
$params
[
'paction'
]
===
'serializeforcache'
)
{
$key
=
$this
->
storeInSerializationCache
(
$title
,
$wikitext
);
$result
=
[
'result'
=>
'success'
,
'cachekey'
=>
$key
];
}
elseif
(
$params
[
'paction'
]
===
'diff'
)
{
$section
=
$params
[
'section'
]
??
null
;
$result
=
$this
->
diffWikitext
(
$title
,
$params
[
'oldid'
],
$wikitext
,
$section
);
}
elseif
(
$params
[
'paction'
]
===
'save'
)
{
$pluginData
=
[];
foreach
(
$params
[
'plugins'
]
??
[]
as
$plugin
)
{
$pluginData
[
$plugin
]
=
$params
[
'data-'
.
$plugin
];
}
$presaveHook
=
$this
->
hookRunner
->
onVisualEditorApiVisualEditorEditPreSave
(
$title
->
toPageIdentity
(),
$user
,
$wikitext
,
$params
,
$pluginData
,
$result
);
if
(
$presaveHook
===
false
)
{
$this
->
dieWithError
(
$result
[
'message'
],
'hookaborted'
,
$result
);
}
$saveresult
=
$this
->
saveWikitext
(
$title
,
$wikitext
,
$params
);
$editStatus
=
$saveresult
[
'edit'
][
'result'
];
// Error
if
(
$editStatus
!==
'Success'
)
{
$result
[
'result'
]
=
'error'
;
$result
[
'edit'
]
=
$saveresult
[
'edit'
];
}
else
{
// Success
$result
[
'result'
]
=
'success'
;
if
(
$params
[
'nocontent'
]
)
{
$result
[
'nocontent'
]
=
true
;
}
else
{
if
(
isset
(
$saveresult
[
'edit'
][
'newrevid'
]
)
)
{
$newRevId
=
intval
(
$saveresult
[
'edit'
][
'newrevid'
]
);
}
else
{
$newRevId
=
$title
->
getLatestRevID
();
}
// Return result of parseWikitext instead of saveWikitext so that the
// frontend can update the page rendering without a refresh.
$parseWikitextResult
=
$this
->
parseWikitext
(
$newRevId
,
$params
);
$result
=
array_merge
(
$result
,
$parseWikitextResult
);
}
$result
[
'isRedirect'
]
=
(
string
)
$title
->
isRedirect
();
if
(
ExtensionRegistry
::
getInstance
()->
isLoaded
(
'FlaggedRevs'
)
)
{
$newContext
=
new
DerivativeContext
(
RequestContext
::
getMain
()
);
// Defeat !$this->isPageView( $request ) || $request->getVal( 'oldid' ) check in setPageContent
$newRequest
=
new
DerivativeRequest
(
$this
->
getRequest
(),
[
'diff'
=>
null
,
'oldid'
=>
''
,
'title'
=>
$title
->
getPrefixedText
(),
'action'
=>
'view'
]
+
$this
->
getRequest
()->
getValues
()
);
$newContext
->
setRequest
(
$newRequest
);
$newContext
->
setTitle
(
$title
);
// Must be after $globalContext->setTitle since FlaggedRevs constructor
// inspects global Title
$view
=
FlaggablePageView
::
newFromTitle
(
$title
);
// Most likely identical to $globalState, but not our concern
$originalContext
=
$view
->
getContext
();
$view
->
setContext
(
$newContext
);
// The two parameters here are references but we don't care
// about what FlaggedRevs does with them.
$outputDone
=
null
;
$useParserCache
=
null
;
// @phan-suppress-next-line PhanTypeMismatchArgument
$view
->
setPageContent
(
$outputDone
,
$useParserCache
);
$view
->
displayTag
();
$view
->
setContext
(
$originalContext
);
}
$lang
=
$this
->
getLanguage
();
if
(
isset
(
$saveresult
[
'edit'
][
'newtimestamp'
]
)
)
{
$ts
=
$saveresult
[
'edit'
][
'newtimestamp'
];
$date
=
$lang
->
userDate
(
$ts
,
$user
);
$time
=
$lang
->
userTime
(
$ts
,
$user
);
$result
[
'lastModified'
]
=
[
'date'
=>
$date
,
'time'
=>
$time
,
'message'
=>
$this
->
msg
(
'lastmodifiedat'
,
$date
,
$time
)->
parse
(),
];
}
if
(
isset
(
$saveresult
[
'edit'
][
'newrevid'
]
)
)
{
$result
[
'newrevid'
]
=
intval
(
$saveresult
[
'edit'
][
'newrevid'
]
);
}
if
(
isset
(
$saveresult
[
'edit'
][
'tempusercreated'
]
)
)
{
$result
[
'tempusercreated'
]
=
$saveresult
[
'edit'
][
'tempusercreated'
];
}
if
(
isset
(
$saveresult
[
'edit'
][
'tempusercreatedredirect'
]
)
)
{
$result
[
'tempusercreatedredirect'
]
=
$saveresult
[
'edit'
][
'tempusercreatedredirect'
];
}
$result
[
'watched'
]
=
$saveresult
[
'edit'
][
'watched'
]
??
false
;
$result
[
'watchlistexpiry'
]
=
$saveresult
[
'edit'
][
'watchlistexpiry'
]
??
null
;
}
// Refresh article ID (which is used by toPageIdentity()) in case we just created the page.
// Maybe it's not great to rely on this side-effect…
$title
->
getArticleID
(
IDBAccessObject
::
READ_LATEST
);
$this
->
hookRunner
->
onVisualEditorApiVisualEditorEditPostSave
(
$title
->
toPageIdentity
(),
$user
,
$wikitext
,
$params
,
$pluginData
,
$saveresult
,
$result
);
}
$this
->
getResult
()->
addValue
(
null
,
$this
->
getModuleName
(),
$result
);
}
/**
* @inheritDoc
*/
public
function
getAllowedParams
()
{
return
[
'paction'
=>
[
ParamValidator
::
PARAM_REQUIRED
=>
true
,
ParamValidator
::
PARAM_TYPE
=>
[
'serialize'
,
'serializeforcache'
,
'diff'
,
'save'
,
],
],
'page'
=>
[
ParamValidator
::
PARAM_REQUIRED
=>
true
,
],
'token'
=>
[
ParamValidator
::
PARAM_REQUIRED
=>
true
,
],
'wikitext'
=>
[
ParamValidator
::
PARAM_TYPE
=>
'text'
,
ParamValidator
::
PARAM_DEFAULT
=>
null
,
],
'section'
=>
null
,
'sectiontitle'
=>
null
,
'basetimestamp'
=>
[
ParamValidator
::
PARAM_TYPE
=>
'timestamp'
,
],
'starttimestamp'
=>
[
ParamValidator
::
PARAM_TYPE
=>
'timestamp'
,
],
'oldid'
=>
[
ParamValidator
::
PARAM_TYPE
=>
'integer'
,
],
'minor'
=>
null
,
'watchlist'
=>
null
,
'html'
=>
[
// Use the 'raw' type to avoid Unicode NFC normalization.
// This makes the parameter binary safe, so that (a) if
// we use client-side compression it is not mangled, and/or
// (b) deprecated Unicode sequences explicitly encoded in
// wikitext (ie,  ) are not mangled. Wikitext is
// in Unicode Normal Form C, but because of explicit entities
// the output HTML is not guaranteed to be.
ParamValidator
::
PARAM_TYPE
=>
'raw'
,
ParamValidator
::
PARAM_DEFAULT
=>
null
,
],
'etag'
=>
null
,
'summary'
=>
null
,
'captchaid'
=>
null
,
'captchaword'
=>
null
,
'cachekey'
=>
null
,
'nocontent'
=>
false
,
'returnto'
=>
[
ParamValidator
::
PARAM_TYPE
=>
'title'
,
ApiBase
::
PARAM_HELP_MSG
=>
'apihelp-edit-param-returnto'
,
],
'returntoquery'
=>
[
ParamValidator
::
PARAM_TYPE
=>
'string'
,
ParamValidator
::
PARAM_DEFAULT
=>
''
,
ApiBase
::
PARAM_HELP_MSG
=>
'apihelp-edit-param-returntoquery'
,
],
'returntoanchor'
=>
[
ParamValidator
::
PARAM_TYPE
=>
'string'
,
ParamValidator
::
PARAM_DEFAULT
=>
''
,
ApiBase
::
PARAM_HELP_MSG
=>
'apihelp-edit-param-returntoanchor'
,
],
'useskin'
=>
[
ParamValidator
::
PARAM_TYPE
=>
array_keys
(
$this
->
skinFactory
->
getInstalledSkins
()
),
ApiBase
::
PARAM_HELP_MSG
=>
'apihelp-parse-param-useskin'
,
],
'tags'
=>
[
ParamValidator
::
PARAM_ISMULTI
=>
true
,
],
'plugins'
=>
[
ParamValidator
::
PARAM_ISMULTI
=>
true
,
ParamValidator
::
PARAM_TYPE
=>
'string'
,
],
// Additional data sent by the client. Not used directly in the ApiVisualEditorEdit workflows, but
// is passed alongside the other parameters to implementations of onApiVisualEditorEditPostSave and
// onApiVisualEditorEditPreSave
'data-{plugin}'
=>
[
ApiBase
::
PARAM_TEMPLATE_VARS
=>
[
'plugin'
=>
'plugins'
]
]
];
}
/**
* @inheritDoc
*/
public
function
needsToken
()
{
return
'csrf'
;
}
/**
* @inheritDoc
*/
public
function
isInternal
()
{
return
true
;
}
/**
* @inheritDoc
*/
public
function
isWriteMode
()
{
return
true
;
}
}
File Metadata
Details
Attached
Mime Type
text/x-php
Expires
Wed, Aug 19, 08:59 (2 w, 3 d ago)
Storage Engine
local-disk
Storage Format
Raw Data
Storage Handle
0e/83/e19a5252326c02a59c4a5e17eff2
Default Alt Text
ApiVisualEditorEdit.php (20 KB)
Attached To
Mode
rMWPROD MediaWiki Production
Attached
Detach File
Event Timeline
Log In to Comment