2007-12-01 13:37:02 +00:00
|
|
|
<?php
|
2010-02-23 18:05:46 +00:00
|
|
|
/**
|
2012-07-15 20:13:02 +00:00
|
|
|
* Copyright © 2007 Yuri Astrakhan "<Firstname><Lastname>@gmail.com"
|
2007-12-01 13:37:02 +00:00
|
|
|
*
|
|
|
|
|
* 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.,
|
2010-06-21 13:13:32 +00:00
|
|
|
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
2007-12-01 13:37:02 +00:00
|
|
|
* http://www.gnu.org/copyleft/gpl.html
|
2010-08-07 19:59:42 +00:00
|
|
|
*
|
|
|
|
|
* @file
|
2007-12-01 13:37:02 +00:00
|
|
|
*/
|
|
|
|
|
|
2021-06-30 10:28:47 +00:00
|
|
|
use MediaWiki\Cache\LinkBatchFactory;
|
Introduce CommentFormatter
CommentParser:
* Move comment formatting backend from Linker to a CommentParser service.
Allow link existence and file existence to be batched.
* Rename $local to $samePage since I think that is clearer.
* Rename $title to $selfLinkTarget since it was unclear what the title
was used for.
* Rename the "autocomment" concept to "section link" in public
interfaces, although the old term remains in CSS classes.
* Keep unsafe HTML pass-through in separate "unsafe" methods, for easier
static analysis and code review.
CommentFormatter:
* Add CommentFormatter and RowCommentFormatter services as a usable
frontend for comment batches, and to replace the Linker static methods.
* Provide fluent and parametric interfaces.
Linker:
* Remove Linker::makeCommentLink() without deprecation -- nothing calls
it and it is obviously an internal helper.
* Soft-deprecate Linker methods formatComment(), formatLinksInComment(),
commentBlock() and revComment().
Caller migration:
* CommentFormatter single: Linker, RollbackAction, ApiComparePages,
ApiParse
* CommentFormatter parametric batch: ImageHistoryPseudoPager
* CommentFormatter fluent batch: ApiQueryFilearchive
* RowCommentFormatter sequential: History feed, BlocklistPager,
ProtectedPagesPager, ApiQueryProtectedTitles
* RowCommentFormatter with index: ChangesFeed, ChangesList,
ApiQueryDeletedrevs, ApiQueryLogEvents, ApiQueryRecentChanges
* RevisionCommentBatch: HistoryPager, ContribsPager
Bug: T285917
Change-Id: Ia3fd50a4a13138ba5003d884962da24746d562d0
2021-07-01 06:55:03 +00:00
|
|
|
use MediaWiki\CommentFormatter\CommentFormatter;
|
2020-01-18 20:25:04 +00:00
|
|
|
use MediaWiki\Content\IContentHandlerFactory;
|
2021-10-14 14:01:58 +00:00
|
|
|
use MediaWiki\Content\Renderer\ContentRenderer;
|
2021-08-19 08:59:37 +00:00
|
|
|
use MediaWiki\Content\Transform\ContentTransformer;
|
2021-06-30 10:28:47 +00:00
|
|
|
use MediaWiki\Languages\LanguageNameUtils;
|
2021-10-14 14:01:58 +00:00
|
|
|
use MediaWiki\Page\PageReference;
|
2021-06-30 18:53:31 +00:00
|
|
|
use MediaWiki\Page\WikiPageFactory;
|
2021-06-30 10:28:47 +00:00
|
|
|
use MediaWiki\Revision\RevisionLookup;
|
2019-09-12 19:40:57 +00:00
|
|
|
use MediaWiki\Revision\RevisionRecord;
|
2020-03-04 07:28:19 +00:00
|
|
|
use MediaWiki\Revision\SlotRecord;
|
2017-04-25 03:53:50 +00:00
|
|
|
|
2007-12-01 13:37:02 +00:00
|
|
|
/**
|
WARNING: HUGE COMMIT
Doxygen documentation update:
* Changed alls @addtogroup to @ingroup. @addtogroup adds the comment to the group description, but doesn't add the file, class, function, ... to the group like @ingroup does. See for example http://svn.wikimedia.org/doc/group__SpecialPage.html where it's impossible to see related files, classes, ... that should belong to that group.
* Added @file to file description, it seems that it should be explicitely decalred for file descriptions, otherwise doxygen will think that the comment document the first class, variabled, function, ... that is in that file.
* Removed some empty comments
* Removed some ?>
Added following groups:
* ExternalStorage
* JobQueue
* MaintenanceLanguage
One more thing: there are still a lot of warnings when generating the doc.
2008-05-20 17:13:28 +00:00
|
|
|
* @ingroup API
|
2007-12-01 13:37:02 +00:00
|
|
|
*/
|
|
|
|
|
class ApiParse extends ApiBase {
|
2012-08-21 14:15:12 +00:00
|
|
|
|
2019-09-15 15:12:06 +00:00
|
|
|
/** @var string|false|null */
|
2012-08-21 14:15:12 +00:00
|
|
|
private $section = null;
|
|
|
|
|
|
2021-08-19 08:59:37 +00:00
|
|
|
/** @var Content|null */
|
2012-08-21 14:15:12 +00:00
|
|
|
private $content = null;
|
|
|
|
|
|
2021-08-19 08:59:37 +00:00
|
|
|
/** @var Content|null */
|
2012-08-21 14:15:12 +00:00
|
|
|
private $pstContent = null;
|
2010-10-20 18:50:33 +00:00
|
|
|
|
2017-06-12 15:02:58 +00:00
|
|
|
/** @var bool */
|
|
|
|
|
private $contentIsDeleted = false, $contentIsSuppressed = false;
|
|
|
|
|
|
2021-06-30 10:28:47 +00:00
|
|
|
/** @var RevisionLookup */
|
|
|
|
|
private $revisionLookup;
|
|
|
|
|
|
|
|
|
|
/** @var SkinFactory */
|
|
|
|
|
private $skinFactory;
|
|
|
|
|
|
|
|
|
|
/** @var LanguageNameUtils */
|
|
|
|
|
private $languageNameUtils;
|
|
|
|
|
|
|
|
|
|
/** @var LinkBatchFactory */
|
|
|
|
|
private $linkBatchFactory;
|
|
|
|
|
|
|
|
|
|
/** @var LinkCache */
|
|
|
|
|
private $linkCache;
|
|
|
|
|
|
|
|
|
|
/** @var IContentHandlerFactory */
|
|
|
|
|
private $contentHandlerFactory;
|
|
|
|
|
|
|
|
|
|
/** @var Parser */
|
|
|
|
|
private $parser;
|
|
|
|
|
|
2021-06-30 18:53:31 +00:00
|
|
|
/** @var WikiPageFactory */
|
|
|
|
|
private $wikiPageFactory;
|
|
|
|
|
|
2021-08-19 08:59:37 +00:00
|
|
|
/** @var ContentTransformer */
|
|
|
|
|
private $contentTransformer;
|
|
|
|
|
|
Introduce CommentFormatter
CommentParser:
* Move comment formatting backend from Linker to a CommentParser service.
Allow link existence and file existence to be batched.
* Rename $local to $samePage since I think that is clearer.
* Rename $title to $selfLinkTarget since it was unclear what the title
was used for.
* Rename the "autocomment" concept to "section link" in public
interfaces, although the old term remains in CSS classes.
* Keep unsafe HTML pass-through in separate "unsafe" methods, for easier
static analysis and code review.
CommentFormatter:
* Add CommentFormatter and RowCommentFormatter services as a usable
frontend for comment batches, and to replace the Linker static methods.
* Provide fluent and parametric interfaces.
Linker:
* Remove Linker::makeCommentLink() without deprecation -- nothing calls
it and it is obviously an internal helper.
* Soft-deprecate Linker methods formatComment(), formatLinksInComment(),
commentBlock() and revComment().
Caller migration:
* CommentFormatter single: Linker, RollbackAction, ApiComparePages,
ApiParse
* CommentFormatter parametric batch: ImageHistoryPseudoPager
* CommentFormatter fluent batch: ApiQueryFilearchive
* RowCommentFormatter sequential: History feed, BlocklistPager,
ProtectedPagesPager, ApiQueryProtectedTitles
* RowCommentFormatter with index: ChangesFeed, ChangesList,
ApiQueryDeletedrevs, ApiQueryLogEvents, ApiQueryRecentChanges
* RevisionCommentBatch: HistoryPager, ContribsPager
Bug: T285917
Change-Id: Ia3fd50a4a13138ba5003d884962da24746d562d0
2021-07-01 06:55:03 +00:00
|
|
|
/** @var CommentFormatter */
|
|
|
|
|
private $commentFormatter;
|
|
|
|
|
|
2021-10-14 14:01:58 +00:00
|
|
|
/** @var ContentRenderer */
|
|
|
|
|
private $contentRenderer;
|
|
|
|
|
|
2021-06-30 10:28:47 +00:00
|
|
|
/**
|
|
|
|
|
* @param ApiMain $main
|
|
|
|
|
* @param string $action
|
|
|
|
|
* @param RevisionLookup $revisionLookup
|
|
|
|
|
* @param SkinFactory $skinFactory
|
|
|
|
|
* @param LanguageNameUtils $languageNameUtils
|
|
|
|
|
* @param LinkBatchFactory $linkBatchFactory
|
|
|
|
|
* @param LinkCache $linkCache
|
|
|
|
|
* @param IContentHandlerFactory $contentHandlerFactory
|
|
|
|
|
* @param Parser $parser
|
2021-06-30 18:53:31 +00:00
|
|
|
* @param WikiPageFactory $wikiPageFactory
|
2021-10-14 14:01:58 +00:00
|
|
|
* @param ContentRenderer $contentRenderer
|
2021-08-19 08:59:37 +00:00
|
|
|
* @param ContentTransformer $contentTransformer
|
Introduce CommentFormatter
CommentParser:
* Move comment formatting backend from Linker to a CommentParser service.
Allow link existence and file existence to be batched.
* Rename $local to $samePage since I think that is clearer.
* Rename $title to $selfLinkTarget since it was unclear what the title
was used for.
* Rename the "autocomment" concept to "section link" in public
interfaces, although the old term remains in CSS classes.
* Keep unsafe HTML pass-through in separate "unsafe" methods, for easier
static analysis and code review.
CommentFormatter:
* Add CommentFormatter and RowCommentFormatter services as a usable
frontend for comment batches, and to replace the Linker static methods.
* Provide fluent and parametric interfaces.
Linker:
* Remove Linker::makeCommentLink() without deprecation -- nothing calls
it and it is obviously an internal helper.
* Soft-deprecate Linker methods formatComment(), formatLinksInComment(),
commentBlock() and revComment().
Caller migration:
* CommentFormatter single: Linker, RollbackAction, ApiComparePages,
ApiParse
* CommentFormatter parametric batch: ImageHistoryPseudoPager
* CommentFormatter fluent batch: ApiQueryFilearchive
* RowCommentFormatter sequential: History feed, BlocklistPager,
ProtectedPagesPager, ApiQueryProtectedTitles
* RowCommentFormatter with index: ChangesFeed, ChangesList,
ApiQueryDeletedrevs, ApiQueryLogEvents, ApiQueryRecentChanges
* RevisionCommentBatch: HistoryPager, ContribsPager
Bug: T285917
Change-Id: Ia3fd50a4a13138ba5003d884962da24746d562d0
2021-07-01 06:55:03 +00:00
|
|
|
* @param CommentFormatter $commentFormatter
|
2021-06-30 10:28:47 +00:00
|
|
|
*/
|
|
|
|
|
public function __construct(
|
|
|
|
|
ApiMain $main,
|
|
|
|
|
$action,
|
|
|
|
|
RevisionLookup $revisionLookup,
|
|
|
|
|
SkinFactory $skinFactory,
|
|
|
|
|
LanguageNameUtils $languageNameUtils,
|
|
|
|
|
LinkBatchFactory $linkBatchFactory,
|
|
|
|
|
LinkCache $linkCache,
|
|
|
|
|
IContentHandlerFactory $contentHandlerFactory,
|
2021-06-30 18:53:31 +00:00
|
|
|
Parser $parser,
|
2021-08-19 08:59:37 +00:00
|
|
|
WikiPageFactory $wikiPageFactory,
|
2021-10-14 14:01:58 +00:00
|
|
|
ContentRenderer $contentRenderer,
|
Introduce CommentFormatter
CommentParser:
* Move comment formatting backend from Linker to a CommentParser service.
Allow link existence and file existence to be batched.
* Rename $local to $samePage since I think that is clearer.
* Rename $title to $selfLinkTarget since it was unclear what the title
was used for.
* Rename the "autocomment" concept to "section link" in public
interfaces, although the old term remains in CSS classes.
* Keep unsafe HTML pass-through in separate "unsafe" methods, for easier
static analysis and code review.
CommentFormatter:
* Add CommentFormatter and RowCommentFormatter services as a usable
frontend for comment batches, and to replace the Linker static methods.
* Provide fluent and parametric interfaces.
Linker:
* Remove Linker::makeCommentLink() without deprecation -- nothing calls
it and it is obviously an internal helper.
* Soft-deprecate Linker methods formatComment(), formatLinksInComment(),
commentBlock() and revComment().
Caller migration:
* CommentFormatter single: Linker, RollbackAction, ApiComparePages,
ApiParse
* CommentFormatter parametric batch: ImageHistoryPseudoPager
* CommentFormatter fluent batch: ApiQueryFilearchive
* RowCommentFormatter sequential: History feed, BlocklistPager,
ProtectedPagesPager, ApiQueryProtectedTitles
* RowCommentFormatter with index: ChangesFeed, ChangesList,
ApiQueryDeletedrevs, ApiQueryLogEvents, ApiQueryRecentChanges
* RevisionCommentBatch: HistoryPager, ContribsPager
Bug: T285917
Change-Id: Ia3fd50a4a13138ba5003d884962da24746d562d0
2021-07-01 06:55:03 +00:00
|
|
|
ContentTransformer $contentTransformer,
|
|
|
|
|
CommentFormatter $commentFormatter
|
2021-06-30 10:28:47 +00:00
|
|
|
) {
|
|
|
|
|
parent::__construct( $main, $action );
|
|
|
|
|
$this->revisionLookup = $revisionLookup;
|
|
|
|
|
$this->skinFactory = $skinFactory;
|
|
|
|
|
$this->languageNameUtils = $languageNameUtils;
|
|
|
|
|
$this->linkBatchFactory = $linkBatchFactory;
|
|
|
|
|
$this->linkCache = $linkCache;
|
|
|
|
|
$this->contentHandlerFactory = $contentHandlerFactory;
|
|
|
|
|
$this->parser = $parser;
|
2021-06-30 18:53:31 +00:00
|
|
|
$this->wikiPageFactory = $wikiPageFactory;
|
2021-10-14 14:01:58 +00:00
|
|
|
$this->contentRenderer = $contentRenderer;
|
2021-08-19 08:59:37 +00:00
|
|
|
$this->contentTransformer = $contentTransformer;
|
Introduce CommentFormatter
CommentParser:
* Move comment formatting backend from Linker to a CommentParser service.
Allow link existence and file existence to be batched.
* Rename $local to $samePage since I think that is clearer.
* Rename $title to $selfLinkTarget since it was unclear what the title
was used for.
* Rename the "autocomment" concept to "section link" in public
interfaces, although the old term remains in CSS classes.
* Keep unsafe HTML pass-through in separate "unsafe" methods, for easier
static analysis and code review.
CommentFormatter:
* Add CommentFormatter and RowCommentFormatter services as a usable
frontend for comment batches, and to replace the Linker static methods.
* Provide fluent and parametric interfaces.
Linker:
* Remove Linker::makeCommentLink() without deprecation -- nothing calls
it and it is obviously an internal helper.
* Soft-deprecate Linker methods formatComment(), formatLinksInComment(),
commentBlock() and revComment().
Caller migration:
* CommentFormatter single: Linker, RollbackAction, ApiComparePages,
ApiParse
* CommentFormatter parametric batch: ImageHistoryPseudoPager
* CommentFormatter fluent batch: ApiQueryFilearchive
* RowCommentFormatter sequential: History feed, BlocklistPager,
ProtectedPagesPager, ApiQueryProtectedTitles
* RowCommentFormatter with index: ChangesFeed, ChangesList,
ApiQueryDeletedrevs, ApiQueryLogEvents, ApiQueryRecentChanges
* RevisionCommentBatch: HistoryPager, ContribsPager
Bug: T285917
Change-Id: Ia3fd50a4a13138ba5003d884962da24746d562d0
2021-07-01 06:55:03 +00:00
|
|
|
$this->commentFormatter = $commentFormatter;
|
2021-06-30 10:28:47 +00:00
|
|
|
}
|
|
|
|
|
|
2020-04-07 17:05:12 +00:00
|
|
|
private function getPoolKey(): string {
|
|
|
|
|
$poolKey = WikiMap::getCurrentWikiDbDomain() . ':ApiParse:';
|
2021-06-28 19:04:55 +00:00
|
|
|
if ( !$this->getUser()->isRegistered() ) {
|
2020-04-07 17:05:12 +00:00
|
|
|
$poolKey .= 'a:' . $this->getUser()->getName();
|
|
|
|
|
} else {
|
|
|
|
|
$poolKey .= 'u:' . $this->getUser()->getId();
|
|
|
|
|
}
|
|
|
|
|
return $poolKey;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private function getContentParserOutput(
|
|
|
|
|
Content $content,
|
2021-10-14 14:01:58 +00:00
|
|
|
PageReference $page,
|
2020-04-07 17:05:12 +00:00
|
|
|
$revId,
|
|
|
|
|
ParserOptions $popts
|
|
|
|
|
) {
|
|
|
|
|
$worker = new PoolCounterWorkViaCallback( 'ApiParser', $this->getPoolKey(),
|
|
|
|
|
[
|
2021-10-14 14:01:58 +00:00
|
|
|
'doWork' => function () use ( $content, $page, $revId, $popts ) {
|
|
|
|
|
return $this->contentRenderer->getParserOutput( $content, $page, $revId, $popts );
|
2020-04-07 17:05:12 +00:00
|
|
|
},
|
|
|
|
|
'error' => function () {
|
|
|
|
|
$this->dieWithError( 'apierror-concurrency-limit' );
|
|
|
|
|
},
|
|
|
|
|
]
|
|
|
|
|
);
|
|
|
|
|
return $worker->execute();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private function getPageParserOutput(
|
|
|
|
|
WikiPage $page,
|
|
|
|
|
$revId,
|
|
|
|
|
ParserOptions $popts,
|
|
|
|
|
bool $suppressCache
|
|
|
|
|
) {
|
|
|
|
|
$worker = new PoolCounterWorkViaCallback( 'ApiParser', $this->getPoolKey(),
|
|
|
|
|
[
|
2021-02-10 22:31:02 +00:00
|
|
|
'doWork' => static function () use ( $page, $revId, $popts, $suppressCache ) {
|
2020-04-07 17:05:12 +00:00
|
|
|
return $page->getParserOutput( $popts, $revId, $suppressCache );
|
|
|
|
|
},
|
|
|
|
|
'error' => function () {
|
|
|
|
|
$this->dieWithError( 'apierror-concurrency-limit' );
|
|
|
|
|
},
|
|
|
|
|
]
|
|
|
|
|
);
|
|
|
|
|
return $worker->execute();
|
|
|
|
|
}
|
|
|
|
|
|
2007-12-01 13:37:02 +00:00
|
|
|
public function execute() {
|
2010-07-23 07:17:56 +00:00
|
|
|
// The data is hot but user-dependent, like page views, so we set vary cookies
|
|
|
|
|
$this->getMain()->setCacheMode( 'anon-public-user-private' );
|
|
|
|
|
|
2007-12-01 13:37:02 +00:00
|
|
|
// Get parameters
|
|
|
|
|
$params = $this->extractRequestParams();
|
2016-10-19 16:54:25 +00:00
|
|
|
|
2017-09-14 01:13:15 +00:00
|
|
|
// No easy way to say that text and title or revid are allowed together
|
|
|
|
|
// while the rest aren't, so just do it in three calls.
|
2016-10-19 16:54:25 +00:00
|
|
|
$this->requireMaxOneParameter( $params, 'page', 'pageid', 'oldid', 'text' );
|
|
|
|
|
$this->requireMaxOneParameter( $params, 'page', 'pageid', 'oldid', 'title' );
|
2017-09-14 01:13:15 +00:00
|
|
|
$this->requireMaxOneParameter( $params, 'page', 'pageid', 'oldid', 'revid' );
|
2016-10-19 16:54:25 +00:00
|
|
|
|
2007-12-01 13:37:02 +00:00
|
|
|
$text = $params['text'];
|
|
|
|
|
$title = $params['title'];
|
2013-06-19 14:53:57 +00:00
|
|
|
if ( $title === null ) {
|
2013-06-19 10:21:19 +00:00
|
|
|
$titleProvided = false;
|
2013-06-19 14:53:57 +00:00
|
|
|
// A title is needed for parsing, so arbitrarily choose one
|
2013-06-19 10:21:19 +00:00
|
|
|
$title = 'API';
|
|
|
|
|
} else {
|
|
|
|
|
$titleProvided = true;
|
|
|
|
|
}
|
|
|
|
|
|
2008-01-29 14:47:27 +00:00
|
|
|
$page = $params['page'];
|
2010-05-10 14:17:21 +00:00
|
|
|
$pageid = $params['pageid'];
|
2008-04-10 10:51:40 +00:00
|
|
|
$oldid = $params['oldid'];
|
2010-05-10 18:27:58 +00:00
|
|
|
|
2012-08-21 14:15:12 +00:00
|
|
|
$model = $params['contentmodel'];
|
|
|
|
|
$format = $params['contentformat'];
|
|
|
|
|
|
2021-06-11 02:52:06 +00:00
|
|
|
$prop = array_fill_keys( $params['prop'], true );
|
2010-05-25 13:47:22 +00:00
|
|
|
|
2010-05-10 18:27:58 +00:00
|
|
|
if ( isset( $params['section'] ) ) {
|
|
|
|
|
$this->section = $params['section'];
|
2015-03-10 21:27:01 +00:00
|
|
|
if ( !preg_match( '/^((T-)?\d+|new)$/', $this->section ) ) {
|
2016-10-19 16:54:25 +00:00
|
|
|
$this->dieWithError( 'apierror-invalidsection' );
|
2015-03-10 21:27:01 +00:00
|
|
|
}
|
2010-05-10 18:27:58 +00:00
|
|
|
} else {
|
|
|
|
|
$this->section = false;
|
|
|
|
|
}
|
2008-04-14 07:45:50 +00:00
|
|
|
|
2008-12-20 20:00:07 +00:00
|
|
|
// The parser needs $wgTitle to be set, apparently the
|
|
|
|
|
// $title parameter in Parser::parse isn't enough *sigh*
|
2011-10-26 23:27:01 +00:00
|
|
|
// TODO: Does this still need $wgTitle?
|
2019-04-11 13:36:15 +00:00
|
|
|
global $wgTitle;
|
2010-05-10 14:17:21 +00:00
|
|
|
|
2008-10-24 12:28:14 +00:00
|
|
|
$redirValues = null;
|
2011-01-06 23:35:59 +00:00
|
|
|
|
2017-06-13 19:42:21 +00:00
|
|
|
$needContent = isset( $prop['wikitext'] ) ||
|
|
|
|
|
isset( $prop['parsetree'] ) || $params['generatexml'];
|
|
|
|
|
|
2011-06-30 01:06:17 +00:00
|
|
|
// Return result
|
|
|
|
|
$result = $this->getResult();
|
|
|
|
|
|
2020-01-09 23:48:34 +00:00
|
|
|
if ( $oldid !== null || $pageid !== null || $page !== null ) {
|
2015-03-25 23:55:16 +00:00
|
|
|
if ( $this->section === 'new' ) {
|
2016-10-19 16:54:25 +00:00
|
|
|
$this->dieWithError( 'apierror-invalidparammix-parse-new-section', 'invalidparammix' );
|
2015-03-25 23:55:16 +00:00
|
|
|
}
|
2020-01-09 23:48:34 +00:00
|
|
|
if ( $oldid !== null ) {
|
2010-01-23 22:52:40 +00:00
|
|
|
// Don't use the parser cache
|
2021-06-30 10:28:47 +00:00
|
|
|
$rev = $this->revisionLookup->getRevisionById( $oldid );
|
2010-02-23 18:05:46 +00:00
|
|
|
if ( !$rev ) {
|
2016-10-19 16:54:25 +00:00
|
|
|
$this->dieWithError( [ 'apierror-nosuchrevid', $oldid ] );
|
2010-02-23 18:05:46 +00:00
|
|
|
}
|
2016-06-13 08:01:43 +00:00
|
|
|
|
2021-01-11 15:26:02 +00:00
|
|
|
$this->checkTitleUserPermissions( $rev->getPage(), 'read' );
|
2020-03-04 07:28:19 +00:00
|
|
|
|
2021-02-24 15:46:13 +00:00
|
|
|
if ( !$rev->userCan( RevisionRecord::DELETED_TEXT, $this->getAuthority() ) ) {
|
2016-10-19 16:54:25 +00:00
|
|
|
$this->dieWithError(
|
|
|
|
|
[ 'apierror-permissiondenied', $this->msg( 'action-deletedtext' ) ]
|
|
|
|
|
);
|
2010-02-23 18:05:46 +00:00
|
|
|
}
|
2010-01-23 22:47:49 +00:00
|
|
|
|
2021-01-11 15:26:02 +00:00
|
|
|
$revLinkTarget = $rev->getPageAsLinkTarget();
|
2020-03-04 07:28:19 +00:00
|
|
|
$titleObj = Title::newFromLinkTarget( $revLinkTarget );
|
2008-12-20 20:00:07 +00:00
|
|
|
$wgTitle = $titleObj;
|
2021-06-30 18:53:31 +00:00
|
|
|
$pageObj = $this->wikiPageFactory->newFromTitle( $titleObj );
|
2016-06-20 15:58:53 +00:00
|
|
|
list( $popts, $reset, $suppressCache ) = $this->makeParserOptions( $pageObj, $params );
|
2017-06-12 15:02:58 +00:00
|
|
|
$p_result = $this->getParsedContent(
|
2017-06-13 19:42:21 +00:00
|
|
|
$pageObj, $popts, $suppressCache, $pageid, $rev, $needContent
|
2017-06-12 15:02:58 +00:00
|
|
|
);
|
2011-08-05 13:07:09 +00:00
|
|
|
} else { // Not $oldid, but $pageid or $page
|
2011-06-17 15:57:00 +00:00
|
|
|
if ( $params['redirects'] ) {
|
2016-02-17 09:09:32 +00:00
|
|
|
$reqParams = [
|
2011-06-17 15:57:00 +00:00
|
|
|
'redirects' => '',
|
2016-02-17 09:09:32 +00:00
|
|
|
];
|
2019-12-23 14:24:17 +00:00
|
|
|
$pageParams = [];
|
2020-01-09 23:48:34 +00:00
|
|
|
if ( $pageid !== null ) {
|
2011-06-17 15:57:00 +00:00
|
|
|
$reqParams['pageids'] = $pageid;
|
2019-12-23 14:24:17 +00:00
|
|
|
$pageParams['pageid'] = $pageid;
|
2011-06-17 15:57:00 +00:00
|
|
|
} else { // $page
|
|
|
|
|
$reqParams['titles'] = $page;
|
2019-12-23 14:24:17 +00:00
|
|
|
$pageParams['title'] = $page;
|
2010-02-23 18:05:46 +00:00
|
|
|
}
|
2011-06-17 15:57:00 +00:00
|
|
|
$req = new FauxRequest( $reqParams );
|
|
|
|
|
$main = new ApiMain( $req );
|
API: Overhaul ApiResult, make format=xml not throw, and add json formatversion
ApiResult was a mess: some methods could only be used with an array
reference instead of manipulating the stored data, methods that had both
array-ref and internal-data versions had names that didn't at all
correspond, some methods that worked on an array reference were
annoyingly non-static, and then the whole mess with setIndexedTagName.
ApiFormatXml is also entirely annoying to deal with, as it liked to
throw exceptions if certain metadata wasn't provided that no other
formatter required. Its legacy also means we have this silly convention
of using empty-string rather than boolean true, annoying restrictions on
keys (leading to things that should be hashes being arrays of key-value
object instead), '*' used as a key all over the place, and so on.
So, changes here:
* ApiResult is no longer an ApiBase or a ContextSource.
* Wherever sensible, ApiResult provides a static method working on an
arrayref and a non-static method working on internal data.
* Metadata is now always added to ApiResult's internal data structure.
Formatters are responsible for stripping it if necessary. "raw mode"
is deprecated.
* New metadata to replace the '*' key, solve the array() => '[]' vs '{}'
question, and so on.
* New class for formatting warnings and errors using i18n messages, and
support for multiple errors and a more machine-readable format for
warnings. For the moment, though, the actual output will not be changing
yet (see T47843 for future plans).
* New formatversion parameter for format=json and format=php, to select
between BC mode and the modern output.
* In BC mode, booleans will be converted to empty-string presence style;
modules currently returning booleans will need to use
ApiResult::META_BC_BOOLS to preserve their current output.
Actual changes to the API modules' output (e.g. actually returning
booleans for the new formatversion) beyond the use of
ApiResult::setContentValue() are left for a future change.
Bug: T76728
Bug: T57371
Bug: T33629
Change-Id: I7b37295e8862b188d1f3b0cd07f66ac34629678f
2014-12-03 22:14:22 +00:00
|
|
|
$pageSet = new ApiPageSet( $main );
|
|
|
|
|
$pageSet->execute();
|
2015-05-01 19:50:25 +00:00
|
|
|
$redirValues = $pageSet->getRedirectTitlesAsResult( $this->getResult() );
|
API: Overhaul ApiResult, make format=xml not throw, and add json formatversion
ApiResult was a mess: some methods could only be used with an array
reference instead of manipulating the stored data, methods that had both
array-ref and internal-data versions had names that didn't at all
correspond, some methods that worked on an array reference were
annoyingly non-static, and then the whole mess with setIndexedTagName.
ApiFormatXml is also entirely annoying to deal with, as it liked to
throw exceptions if certain metadata wasn't provided that no other
formatter required. Its legacy also means we have this silly convention
of using empty-string rather than boolean true, annoying restrictions on
keys (leading to things that should be hashes being arrays of key-value
object instead), '*' used as a key all over the place, and so on.
So, changes here:
* ApiResult is no longer an ApiBase or a ContextSource.
* Wherever sensible, ApiResult provides a static method working on an
arrayref and a non-static method working on internal data.
* Metadata is now always added to ApiResult's internal data structure.
Formatters are responsible for stripping it if necessary. "raw mode"
is deprecated.
* New metadata to replace the '*' key, solve the array() => '[]' vs '{}'
question, and so on.
* New class for formatting warnings and errors using i18n messages, and
support for multiple errors and a more machine-readable format for
warnings. For the moment, though, the actual output will not be changing
yet (see T47843 for future plans).
* New formatversion parameter for format=json and format=php, to select
between BC mode and the modern output.
* In BC mode, booleans will be converted to empty-string presence style;
modules currently returning booleans will need to use
ApiResult::META_BC_BOOLS to preserve their current output.
Actual changes to the API modules' output (e.g. actually returning
booleans for the new formatversion) beyond the use of
ApiResult::setContentValue() are left for a future change.
Bug: T76728
Bug: T57371
Bug: T33629
Change-Id: I7b37295e8862b188d1f3b0cd07f66ac34629678f
2014-12-03 22:14:22 +00:00
|
|
|
|
|
|
|
|
foreach ( $pageSet->getRedirectTitles() as $title ) {
|
2019-12-23 14:24:17 +00:00
|
|
|
$pageParams = [ 'title' => $title->getFullText() ];
|
2010-05-10 14:17:21 +00:00
|
|
|
}
|
2020-01-09 23:48:34 +00:00
|
|
|
} elseif ( $pageid !== null ) {
|
2016-02-17 09:09:32 +00:00
|
|
|
$pageParams = [ 'pageid' => $pageid ];
|
2012-08-11 19:44:12 +00:00
|
|
|
} else { // $page
|
2016-02-17 09:09:32 +00:00
|
|
|
$pageParams = [ 'title' => $page ];
|
2010-02-23 18:05:46 +00:00
|
|
|
}
|
2012-08-11 19:44:12 +00:00
|
|
|
|
|
|
|
|
$pageObj = $this->getTitleOrPageId( $pageParams, 'fromdb' );
|
|
|
|
|
$titleObj = $pageObj->getTitle();
|
2021-08-30 00:00:34 +00:00
|
|
|
if ( !$titleObj->exists() ) {
|
2016-10-19 16:54:25 +00:00
|
|
|
$this->dieWithError( 'apierror-missingtitle' );
|
2012-10-16 15:42:54 +00:00
|
|
|
}
|
2016-06-13 08:01:43 +00:00
|
|
|
|
2016-10-19 16:54:25 +00:00
|
|
|
$this->checkTitleUserPermissions( $titleObj, 'read' );
|
2010-05-10 14:17:21 +00:00
|
|
|
$wgTitle = $titleObj;
|
2007-12-01 13:37:02 +00:00
|
|
|
|
2010-02-23 18:05:46 +00:00
|
|
|
if ( isset( $prop['revid'] ) ) {
|
2012-08-11 19:44:12 +00:00
|
|
|
$oldid = $pageObj->getLatest();
|
2010-02-23 18:05:46 +00:00
|
|
|
}
|
|
|
|
|
|
2016-06-20 15:58:53 +00:00
|
|
|
list( $popts, $reset, $suppressCache ) = $this->makeParserOptions( $pageObj, $params );
|
2017-06-12 15:02:58 +00:00
|
|
|
$p_result = $this->getParsedContent(
|
2017-06-13 19:42:21 +00:00
|
|
|
$pageObj, $popts, $suppressCache, $pageid, null, $needContent
|
2017-06-12 15:02:58 +00:00
|
|
|
);
|
2008-01-29 14:47:27 +00:00
|
|
|
}
|
2011-01-06 23:35:59 +00:00
|
|
|
} else { // Not $oldid, $pageid, $page. Hence based on $text
|
2010-01-11 15:55:52 +00:00
|
|
|
$titleObj = Title::newFromText( $title );
|
2013-03-01 15:01:26 +00:00
|
|
|
if ( !$titleObj || $titleObj->isExternal() ) {
|
2016-10-19 16:54:25 +00:00
|
|
|
$this->dieWithError( [ 'apierror-invalidtitle', wfEscapeWikiText( $title ) ] );
|
2010-02-23 18:05:46 +00:00
|
|
|
}
|
2017-09-14 01:13:15 +00:00
|
|
|
$revid = $params['revid'];
|
|
|
|
|
if ( $revid !== null ) {
|
2021-06-30 10:28:47 +00:00
|
|
|
$rev = $this->revisionLookup->getRevisionById( $revid );
|
2017-09-14 01:13:15 +00:00
|
|
|
if ( !$rev ) {
|
|
|
|
|
$this->dieWithError( [ 'apierror-nosuchrevid', $revid ] );
|
|
|
|
|
}
|
|
|
|
|
$pTitleObj = $titleObj;
|
2020-03-04 07:28:19 +00:00
|
|
|
$titleObj = Title::newFromLinkTarget( $rev->getPageAsLinkTarget() );
|
2017-09-14 01:13:15 +00:00
|
|
|
if ( $titleProvided ) {
|
|
|
|
|
if ( !$titleObj->equals( $pTitleObj ) ) {
|
|
|
|
|
$this->addWarning( [ 'apierror-revwrongpage', $rev->getId(),
|
|
|
|
|
wfEscapeWikiText( $pTitleObj->getPrefixedText() ) ] );
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
// Consider the title derived from the revid as having
|
|
|
|
|
// been provided.
|
|
|
|
|
$titleProvided = true;
|
|
|
|
|
}
|
|
|
|
|
}
|
2008-12-20 20:00:07 +00:00
|
|
|
$wgTitle = $titleObj;
|
2014-01-09 16:53:08 +00:00
|
|
|
if ( $titleObj->canExist() ) {
|
2021-06-30 18:53:31 +00:00
|
|
|
$pageObj = $this->wikiPageFactory->newFromTitle( $titleObj );
|
2021-01-19 19:57:24 +00:00
|
|
|
list( $popts, $reset ) = $this->makeParserOptions( $pageObj, $params );
|
|
|
|
|
} else { // A special page, presumably
|
|
|
|
|
// XXX: Why is this needed at all? Can't we just fail?
|
|
|
|
|
$pageObj = null;
|
|
|
|
|
$popts = ParserOptions::newCanonical( $this->getContext() );
|
|
|
|
|
list( $popts, $reset ) = $this->tweakParserOptions( $popts, $titleObj, $params );
|
2014-01-09 16:53:08 +00:00
|
|
|
}
|
2012-08-11 19:44:12 +00:00
|
|
|
|
2020-01-09 23:48:34 +00:00
|
|
|
$textProvided = $text !== null;
|
2010-05-10 18:27:58 +00:00
|
|
|
|
2014-01-19 05:58:45 +00:00
|
|
|
if ( !$textProvided ) {
|
2013-06-19 10:21:19 +00:00
|
|
|
if ( $titleProvided && ( $prop || $params['generatexml'] ) ) {
|
2017-09-14 01:13:15 +00:00
|
|
|
if ( $revid !== null ) {
|
|
|
|
|
$this->addWarning( 'apiwarn-parse-revidwithouttext' );
|
|
|
|
|
} else {
|
|
|
|
|
$this->addWarning( 'apiwarn-parse-titlewithouttext' );
|
|
|
|
|
}
|
2013-05-10 15:59:11 +00:00
|
|
|
}
|
|
|
|
|
// Prevent warning from ContentHandler::makeContent()
|
|
|
|
|
$text = '';
|
2012-08-21 14:15:12 +00:00
|
|
|
}
|
|
|
|
|
|
2013-06-19 10:21:19 +00:00
|
|
|
// If we are parsing text, do not use the content model of the default
|
|
|
|
|
// API title, but default to wikitext to keep BC.
|
2020-01-09 23:48:34 +00:00
|
|
|
if ( $textProvided && !$titleProvided && $model === null ) {
|
2013-06-19 10:21:19 +00:00
|
|
|
$model = CONTENT_MODEL_WIKITEXT;
|
2016-10-19 16:54:25 +00:00
|
|
|
$this->addWarning( [ 'apiwarn-parse-nocontentmodel', $model ] );
|
2013-06-19 10:21:19 +00:00
|
|
|
}
|
|
|
|
|
|
2012-08-21 14:15:12 +00:00
|
|
|
try {
|
|
|
|
|
$this->content = ContentHandler::makeContent( $text, $titleObj, $model, $format );
|
|
|
|
|
} catch ( MWContentSerializationException $ex ) {
|
2016-12-08 18:38:45 +00:00
|
|
|
$this->dieWithException( $ex, [
|
|
|
|
|
'wrap' => ApiMessage::create( 'apierror-contentserializationexception', 'parseerror' )
|
|
|
|
|
] );
|
2012-08-21 14:15:12 +00:00
|
|
|
}
|
|
|
|
|
|
2010-05-10 18:27:58 +00:00
|
|
|
if ( $this->section !== false ) {
|
2015-03-10 21:27:01 +00:00
|
|
|
if ( $this->section === 'new' ) {
|
|
|
|
|
// Insert the section title above the content.
|
2020-01-09 23:48:34 +00:00
|
|
|
if ( $params['sectiontitle'] !== null && $params['sectiontitle'] !== '' ) {
|
2015-03-10 21:27:01 +00:00
|
|
|
$this->content = $this->content->addSectionHeader( $params['sectiontitle'] );
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
$this->content = $this->getSectionContent( $this->content, $titleObj->getPrefixedText() );
|
|
|
|
|
}
|
2010-05-10 18:27:58 +00:00
|
|
|
}
|
|
|
|
|
|
2010-02-23 18:05:46 +00:00
|
|
|
if ( $params['pst'] || $params['onlypst'] ) {
|
2021-08-19 08:59:37 +00:00
|
|
|
$this->pstContent = $this->contentTransformer->preSaveTransform(
|
|
|
|
|
$this->content,
|
|
|
|
|
$titleObj,
|
|
|
|
|
$this->getUser(),
|
|
|
|
|
$popts
|
|
|
|
|
);
|
2010-02-23 18:05:46 +00:00
|
|
|
}
|
|
|
|
|
if ( $params['onlypst'] ) {
|
2008-12-04 15:51:39 +00:00
|
|
|
// Build a result and bail out
|
2016-02-17 09:09:32 +00:00
|
|
|
$result_array = [];
|
2015-01-16 19:00:07 +00:00
|
|
|
$result_array['text'] = $this->pstContent->serialize( $format );
|
|
|
|
|
$result_array[ApiResult::META_BC_SUBELEMENTS][] = 'text';
|
2011-01-28 01:47:08 +00:00
|
|
|
if ( isset( $prop['wikitext'] ) ) {
|
2015-01-16 19:00:07 +00:00
|
|
|
$result_array['wikitext'] = $this->content->serialize( $format );
|
|
|
|
|
$result_array[ApiResult::META_BC_SUBELEMENTS][] = 'wikitext';
|
2011-01-28 01:47:08 +00:00
|
|
|
}
|
2020-01-09 23:48:34 +00:00
|
|
|
if ( $params['summary'] !== null ||
|
|
|
|
|
( $params['sectiontitle'] !== null && $this->section === 'new' )
|
2015-03-19 21:20:53 +00:00
|
|
|
) {
|
2015-01-16 19:00:07 +00:00
|
|
|
$result_array['parsedsummary'] = $this->formatSummary( $titleObj, $params );
|
|
|
|
|
$result_array[ApiResult::META_BC_SUBELEMENTS][] = 'parsedsummary';
|
2014-12-18 13:14:54 +00:00
|
|
|
}
|
|
|
|
|
|
2011-06-30 01:06:17 +00:00
|
|
|
$result->addValue( null, $this->getModuleName(), $result_array );
|
2013-11-14 12:47:20 +00:00
|
|
|
|
2008-12-04 15:51:39 +00:00
|
|
|
return;
|
|
|
|
|
}
|
2012-08-21 14:15:12 +00:00
|
|
|
|
2011-08-05 13:07:09 +00:00
|
|
|
// Not cached (save or load)
|
2012-08-21 14:15:12 +00:00
|
|
|
if ( $params['pst'] ) {
|
2020-04-07 17:05:12 +00:00
|
|
|
$p_result = $this->getContentParserOutput( $this->pstContent, $titleObj, $revid, $popts );
|
2012-08-21 14:15:12 +00:00
|
|
|
} else {
|
2020-04-07 17:05:12 +00:00
|
|
|
$p_result = $this->getContentParserOutput( $this->content, $titleObj, $revid, $popts );
|
2012-08-21 14:15:12 +00:00
|
|
|
}
|
2008-01-29 14:47:27 +00:00
|
|
|
}
|
2007-12-01 13:37:02 +00:00
|
|
|
|
2016-02-17 09:09:32 +00:00
|
|
|
$result_array = [];
|
2011-01-04 21:37:18 +00:00
|
|
|
|
|
|
|
|
$result_array['title'] = $titleObj->getPrefixedText();
|
2021-01-19 19:57:24 +00:00
|
|
|
$result_array['pageid'] = $pageid ?: $titleObj->getArticleID();
|
2017-06-12 15:02:58 +00:00
|
|
|
if ( $this->contentIsDeleted ) {
|
|
|
|
|
$result_array['textdeleted'] = true;
|
|
|
|
|
}
|
|
|
|
|
if ( $this->contentIsSuppressed ) {
|
|
|
|
|
$result_array['textsuppressed'] = true;
|
|
|
|
|
}
|
2011-01-04 21:37:18 +00:00
|
|
|
|
2017-04-25 03:53:50 +00:00
|
|
|
if ( isset( $params['useskin'] ) ) {
|
2021-06-30 10:28:47 +00:00
|
|
|
$skin = $this->skinFactory->makeSkin( Skin::normalizeKey( $params['useskin'] ) );
|
2017-04-25 03:53:50 +00:00
|
|
|
} else {
|
|
|
|
|
$skin = null;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
$outputPage = null;
|
2019-10-08 18:23:54 +00:00
|
|
|
$context = null;
|
2020-10-28 21:09:27 +00:00
|
|
|
if ( $skin || isset( $prop['subtitle'] ) || isset( $prop['headhtml'] ) || isset( $prop['categorieshtml'] ) ) {
|
|
|
|
|
// Enabling the skin via 'useskin', 'subtitle', 'headhtml', or 'categorieshtml'
|
2017-05-25 15:18:48 +00:00
|
|
|
// gets OutputPage and Skin involved, which (among others) applies
|
|
|
|
|
// these hooks:
|
2017-04-25 03:53:50 +00:00
|
|
|
// - ParserOutputHooks
|
|
|
|
|
// - Hook: LanguageLinks
|
2020-10-28 21:09:27 +00:00
|
|
|
// - Hook: SkinSubPageSubtitle
|
2017-04-25 03:53:50 +00:00
|
|
|
// - Hook: OutputPageParserOutput
|
2017-05-25 15:18:48 +00:00
|
|
|
// - Hook: OutputPageMakeCategoryLinks
|
2020-10-22 13:01:16 +00:00
|
|
|
// - Hook: OutputPageBeforeHTML
|
2017-04-25 03:53:50 +00:00
|
|
|
$context = new DerivativeContext( $this->getContext() );
|
|
|
|
|
$context->setTitle( $titleObj );
|
2021-01-19 19:57:24 +00:00
|
|
|
|
|
|
|
|
if ( $pageObj ) {
|
|
|
|
|
$context->setWikiPage( $pageObj );
|
|
|
|
|
}
|
2020-10-22 13:01:16 +00:00
|
|
|
// Some hooks only apply to pages when action=view, which this API
|
|
|
|
|
// call is simulating.
|
|
|
|
|
$context->setRequest( new FauxRequest( [ 'action' => 'view' ] ) );
|
2017-04-25 03:53:50 +00:00
|
|
|
|
|
|
|
|
if ( $skin ) {
|
|
|
|
|
// Use the skin specified by 'useskin'
|
|
|
|
|
$context->setSkin( $skin );
|
|
|
|
|
// Context clones the skin, refetch to stay in sync. (T166022)
|
|
|
|
|
$skin = $context->getSkin();
|
2017-05-25 15:18:48 +00:00
|
|
|
} else {
|
|
|
|
|
// Make sure the context's skin refers to the context. Without this,
|
|
|
|
|
// $outputPage->getSkin()->getOutput() !== $outputPage which
|
|
|
|
|
// confuses some of the output.
|
|
|
|
|
$context->setSkin( $context->getSkin() );
|
2017-04-25 03:53:50 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
$outputPage = new OutputPage( $context );
|
2020-10-28 21:09:27 +00:00
|
|
|
// Required for subtitle to appear
|
|
|
|
|
$outputPage->setArticleFlag( true );
|
|
|
|
|
|
2017-04-25 03:53:50 +00:00
|
|
|
$outputPage->addParserOutputMetadata( $p_result );
|
2017-02-28 20:52:17 +00:00
|
|
|
if ( $this->content ) {
|
|
|
|
|
$outputPage->addContentOverride( $titleObj, $this->content );
|
|
|
|
|
}
|
2017-04-25 03:53:50 +00:00
|
|
|
$context->setOutput( $outputPage );
|
2017-04-21 00:25:21 +00:00
|
|
|
|
|
|
|
|
if ( $skin ) {
|
|
|
|
|
// Based on OutputPage::output()
|
2018-04-10 01:22:13 +00:00
|
|
|
$outputPage->loadSkinModules( $skin );
|
2017-04-21 00:25:21 +00:00
|
|
|
}
|
2017-02-28 20:52:17 +00:00
|
|
|
|
Hooks::run() call site migration
Migrate all callers of Hooks::run() to use the new
HookContainer/HookRunner system.
General principles:
* Use DI if it is already used. We're not changing the way state is
managed in this patch.
* HookContainer is always injected, not HookRunner. HookContainer
is a service, it's a more generic interface, it is the only
thing that provides isRegistered() which is needed in some cases,
and a HookRunner can be efficiently constructed from it
(confirmed by benchmark). Because HookContainer is needed
for object construction, it is also needed by all factories.
* "Ask your friendly local base class". Big hierarchies like
SpecialPage and ApiBase have getHookContainer() and getHookRunner()
methods in the base class, and classes that extend that base class
are not expected to know or care where the base class gets its
HookContainer from.
* ProtectedHookAccessorTrait provides protected getHookContainer() and
getHookRunner() methods, getting them from the global service
container. The point of this is to ease migration to DI by ensuring
that call sites ask their local friendly base class rather than
getting a HookRunner from the service container directly.
* Private $this->hookRunner. In some smaller classes where accessor
methods did not seem warranted, there is a private HookRunner property
which is accessed directly. Very rarely (two cases), there is a
protected property, for consistency with code that conventionally
assumes protected=private, but in cases where the class might actually
be overridden, a protected accessor is preferred over a protected
property.
* The last resort: Hooks::runner(). Mostly for static, file-scope and
global code. In a few cases it was used for objects with broken
construction schemes, out of horror or laziness.
Constructors with new required arguments:
* AuthManager
* BadFileLookup
* BlockManager
* ClassicInterwikiLookup
* ContentHandlerFactory
* ContentSecurityPolicy
* DefaultOptionsManager
* DerivedPageDataUpdater
* FullSearchResultWidget
* HtmlCacheUpdater
* LanguageFactory
* LanguageNameUtils
* LinkRenderer
* LinkRendererFactory
* LocalisationCache
* MagicWordFactory
* MessageCache
* NamespaceInfo
* PageEditStash
* PageHandlerFactory
* PageUpdater
* ParserFactory
* PermissionManager
* RevisionStore
* RevisionStoreFactory
* SearchEngineConfig
* SearchEngineFactory
* SearchFormWidget
* SearchNearMatcher
* SessionBackend
* SpecialPageFactory
* UserNameUtils
* UserOptionsManager
* WatchedItemQueryService
* WatchedItemStore
Constructors with new optional arguments:
* DefaultPreferencesFactory
* Language
* LinkHolderArray
* MovePage
* Parser
* ParserCache
* PasswordReset
* Router
setHookContainer() now required after construction:
* AuthenticationProvider
* ResourceLoaderModule
* SearchEngine
Change-Id: Id442b0dbe43aba84bd5cf801d86dedc768b082c7
2020-03-19 02:42:09 +00:00
|
|
|
$this->getHookRunner()->onApiParseMakeOutputPage( $this, $outputPage );
|
2017-04-25 03:53:50 +00:00
|
|
|
}
|
|
|
|
|
|
2020-01-09 23:48:34 +00:00
|
|
|
if ( $oldid !== null ) {
|
2019-02-25 00:38:33 +00:00
|
|
|
$result_array['revid'] = (int)$oldid;
|
2011-01-04 21:37:18 +00:00
|
|
|
}
|
|
|
|
|
|
2020-01-09 23:48:34 +00:00
|
|
|
if ( $params['redirects'] && $redirValues !== null ) {
|
2008-10-24 12:28:14 +00:00
|
|
|
$result_array['redirects'] = $redirValues;
|
2010-02-23 18:05:46 +00:00
|
|
|
}
|
|
|
|
|
|
2010-01-11 15:55:52 +00:00
|
|
|
if ( isset( $prop['text'] ) ) {
|
2021-09-15 01:00:06 +00:00
|
|
|
$skin = $context ? $context->getSkin() : null;
|
2021-10-27 22:26:16 +00:00
|
|
|
$skinOptions = $skin ? $skin->getOptions() : [
|
2021-09-15 01:00:06 +00:00
|
|
|
'toc' => true,
|
|
|
|
|
];
|
2017-11-22 20:07:51 +00:00
|
|
|
$result_array['text'] = $p_result->getText( [
|
|
|
|
|
'allowTOC' => !$params['disabletoc'],
|
2021-10-27 22:26:16 +00:00
|
|
|
'injectTOC' => $skinOptions['toc'],
|
2017-11-22 20:07:51 +00:00
|
|
|
'enableSectionEditLinks' => !$params['disableeditsection'],
|
2018-08-28 16:48:10 +00:00
|
|
|
'wrapperDivClass' => $params['wrapoutputclass'],
|
2017-11-24 19:22:25 +00:00
|
|
|
'deduplicateStyles' => !$params['disablestylededuplication'],
|
2021-09-15 01:00:06 +00:00
|
|
|
'skin' => $skin,
|
2021-11-09 16:31:27 +00:00
|
|
|
'includeDebugInfo' => !$params['disablepp'] && !$params['disablelimitreport']
|
2017-11-22 20:07:51 +00:00
|
|
|
] );
|
2015-01-16 19:00:07 +00:00
|
|
|
$result_array[ApiResult::META_BC_SUBELEMENTS][] = 'text';
|
2020-10-22 13:01:16 +00:00
|
|
|
if ( $context ) {
|
2021-06-30 19:05:11 +00:00
|
|
|
$this->getHookRunner()->onOutputPageBeforeHTML( $context->getOutput(), $result_array['text'] );
|
2020-10-22 13:01:16 +00:00
|
|
|
}
|
2008-01-15 21:33:08 +00:00
|
|
|
}
|
2010-02-23 18:05:46 +00:00
|
|
|
|
2020-01-09 23:48:34 +00:00
|
|
|
if ( $params['summary'] !== null ||
|
|
|
|
|
( $params['sectiontitle'] !== null && $this->section === 'new' )
|
2015-03-19 21:20:53 +00:00
|
|
|
) {
|
2015-01-16 19:00:07 +00:00
|
|
|
$result_array['parsedsummary'] = $this->formatSummary( $titleObj, $params );
|
|
|
|
|
$result_array[ApiResult::META_BC_SUBELEMENTS][] = 'parsedsummary';
|
2010-01-31 17:45:51 +00:00
|
|
|
}
|
2010-02-23 18:05:46 +00:00
|
|
|
|
2014-07-01 13:34:33 +00:00
|
|
|
if ( isset( $prop['langlinks'] ) ) {
|
2017-04-25 03:53:50 +00:00
|
|
|
if ( $skin ) {
|
|
|
|
|
$langlinks = $outputPage->getLanguageLinks();
|
|
|
|
|
} else {
|
|
|
|
|
$langlinks = $p_result->getLanguageLinks();
|
|
|
|
|
// The deprecated 'effectivelanglinks' option depredates OutputPage
|
|
|
|
|
// support via 'useskin'. If not already applied, then run just this
|
|
|
|
|
// one hook of OutputPage::addParserOutputMetadata here.
|
|
|
|
|
if ( $params['effectivelanglinks'] ) {
|
|
|
|
|
$linkFlags = [];
|
Hooks::run() call site migration
Migrate all callers of Hooks::run() to use the new
HookContainer/HookRunner system.
General principles:
* Use DI if it is already used. We're not changing the way state is
managed in this patch.
* HookContainer is always injected, not HookRunner. HookContainer
is a service, it's a more generic interface, it is the only
thing that provides isRegistered() which is needed in some cases,
and a HookRunner can be efficiently constructed from it
(confirmed by benchmark). Because HookContainer is needed
for object construction, it is also needed by all factories.
* "Ask your friendly local base class". Big hierarchies like
SpecialPage and ApiBase have getHookContainer() and getHookRunner()
methods in the base class, and classes that extend that base class
are not expected to know or care where the base class gets its
HookContainer from.
* ProtectedHookAccessorTrait provides protected getHookContainer() and
getHookRunner() methods, getting them from the global service
container. The point of this is to ease migration to DI by ensuring
that call sites ask their local friendly base class rather than
getting a HookRunner from the service container directly.
* Private $this->hookRunner. In some smaller classes where accessor
methods did not seem warranted, there is a private HookRunner property
which is accessed directly. Very rarely (two cases), there is a
protected property, for consistency with code that conventionally
assumes protected=private, but in cases where the class might actually
be overridden, a protected accessor is preferred over a protected
property.
* The last resort: Hooks::runner(). Mostly for static, file-scope and
global code. In a few cases it was used for objects with broken
construction schemes, out of horror or laziness.
Constructors with new required arguments:
* AuthManager
* BadFileLookup
* BlockManager
* ClassicInterwikiLookup
* ContentHandlerFactory
* ContentSecurityPolicy
* DefaultOptionsManager
* DerivedPageDataUpdater
* FullSearchResultWidget
* HtmlCacheUpdater
* LanguageFactory
* LanguageNameUtils
* LinkRenderer
* LinkRendererFactory
* LocalisationCache
* MagicWordFactory
* MessageCache
* NamespaceInfo
* PageEditStash
* PageHandlerFactory
* PageUpdater
* ParserFactory
* PermissionManager
* RevisionStore
* RevisionStoreFactory
* SearchEngineConfig
* SearchEngineFactory
* SearchFormWidget
* SearchNearMatcher
* SessionBackend
* SpecialPageFactory
* UserNameUtils
* UserOptionsManager
* WatchedItemQueryService
* WatchedItemStore
Constructors with new optional arguments:
* DefaultPreferencesFactory
* Language
* LinkHolderArray
* MovePage
* Parser
* ParserCache
* PasswordReset
* Router
setHookContainer() now required after construction:
* AuthenticationProvider
* ResourceLoaderModule
* SearchEngine
Change-Id: Id442b0dbe43aba84bd5cf801d86dedc768b082c7
2020-03-19 02:42:09 +00:00
|
|
|
$this->getHookRunner()->onLanguageLinks( $titleObj, $langlinks, $linkFlags );
|
2017-04-25 03:53:50 +00:00
|
|
|
}
|
2013-04-19 11:19:06 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
$result_array['langlinks'] = $this->formatLangLinks( $langlinks );
|
2010-02-23 18:05:46 +00:00
|
|
|
}
|
|
|
|
|
if ( isset( $prop['categories'] ) ) {
|
2010-01-11 15:55:52 +00:00
|
|
|
$result_array['categories'] = $this->formatCategoryLinks( $p_result->getCategories() );
|
2010-02-23 18:05:46 +00:00
|
|
|
}
|
2010-12-06 18:31:09 +00:00
|
|
|
if ( isset( $prop['categorieshtml'] ) ) {
|
2017-05-25 15:18:48 +00:00
|
|
|
$result_array['categorieshtml'] = $outputPage->getSkin()->getCategories();
|
2015-01-16 19:00:07 +00:00
|
|
|
$result_array[ApiResult::META_BC_SUBELEMENTS][] = 'categorieshtml';
|
2010-12-06 18:31:09 +00:00
|
|
|
}
|
2010-02-23 18:05:46 +00:00
|
|
|
if ( isset( $prop['links'] ) ) {
|
2010-01-11 15:55:52 +00:00
|
|
|
$result_array['links'] = $this->formatLinks( $p_result->getLinks() );
|
2010-02-23 18:05:46 +00:00
|
|
|
}
|
|
|
|
|
if ( isset( $prop['templates'] ) ) {
|
2010-01-11 15:55:52 +00:00
|
|
|
$result_array['templates'] = $this->formatLinks( $p_result->getTemplates() );
|
2010-02-23 18:05:46 +00:00
|
|
|
}
|
|
|
|
|
if ( isset( $prop['images'] ) ) {
|
2010-01-11 15:55:52 +00:00
|
|
|
$result_array['images'] = array_keys( $p_result->getImages() );
|
2010-02-23 18:05:46 +00:00
|
|
|
}
|
|
|
|
|
if ( isset( $prop['externallinks'] ) ) {
|
2010-01-11 15:55:52 +00:00
|
|
|
$result_array['externallinks'] = array_keys( $p_result->getExternalLinks() );
|
2010-02-23 18:05:46 +00:00
|
|
|
}
|
|
|
|
|
if ( isset( $prop['sections'] ) ) {
|
2008-01-15 21:33:08 +00:00
|
|
|
$result_array['sections'] = $p_result->getSections();
|
2010-02-23 18:05:46 +00:00
|
|
|
}
|
2017-03-31 18:59:35 +00:00
|
|
|
if ( isset( $prop['parsewarnings'] ) ) {
|
|
|
|
|
$result_array['parsewarnings'] = $p_result->getWarnings();
|
|
|
|
|
}
|
2021-02-16 21:30:27 +00:00
|
|
|
if ( isset( $prop['parsewarningshtml'] ) ) {
|
|
|
|
|
$warnings = $p_result->getWarnings();
|
|
|
|
|
$warningsHtml = array_map( static function ( $warning ) {
|
|
|
|
|
return ( new RawMessage( '$1', [ $warning ] ) )->parse();
|
|
|
|
|
}, $warnings );
|
|
|
|
|
$result_array['parsewarningshtml'] = $warningsHtml;
|
|
|
|
|
}
|
2010-05-25 13:47:22 +00:00
|
|
|
|
2010-02-23 18:05:46 +00:00
|
|
|
if ( isset( $prop['displaytitle'] ) ) {
|
2018-03-27 17:12:48 +00:00
|
|
|
$result_array['displaytitle'] = $p_result->getDisplayTitle() !== false
|
2021-09-28 18:47:20 +00:00
|
|
|
? $p_result->getDisplayTitle()
|
|
|
|
|
: htmlspecialchars( $titleObj->getPrefixedText(), ENT_NOQUOTES );
|
2010-02-23 18:05:46 +00:00
|
|
|
}
|
|
|
|
|
|
2020-10-28 21:09:27 +00:00
|
|
|
if ( isset( $prop['subtitle'] ) ) {
|
|
|
|
|
$result_array['subtitle'] = $context->getSkin()->prepareSubtitle();
|
|
|
|
|
}
|
|
|
|
|
|
2016-07-21 22:52:29 +00:00
|
|
|
if ( isset( $prop['headitems'] ) ) {
|
2017-04-25 03:53:50 +00:00
|
|
|
if ( $skin ) {
|
|
|
|
|
$result_array['headitems'] = $this->formatHeadItems( $outputPage->getHeadItemsArray() );
|
|
|
|
|
} else {
|
|
|
|
|
$result_array['headitems'] = $this->formatHeadItems( $p_result->getHeadItems() );
|
|
|
|
|
}
|
2016-07-21 22:52:29 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if ( isset( $prop['headhtml'] ) ) {
|
2017-04-25 03:53:50 +00:00
|
|
|
$result_array['headhtml'] = $outputPage->headElement( $context->getSkin() );
|
2016-07-21 22:52:29 +00:00
|
|
|
$result_array[ApiResult::META_BC_SUBELEMENTS][] = 'headhtml';
|
2010-02-09 20:47:35 +00:00
|
|
|
}
|
2010-07-23 07:33:40 +00:00
|
|
|
|
2014-04-16 21:07:54 +00:00
|
|
|
if ( isset( $prop['modules'] ) ) {
|
2017-04-25 03:53:50 +00:00
|
|
|
if ( $skin ) {
|
|
|
|
|
$result_array['modules'] = $outputPage->getModules();
|
2019-03-03 19:19:51 +00:00
|
|
|
// Deprecated since 1.32 (T188689)
|
|
|
|
|
$result_array['modulescripts'] = [];
|
2017-04-25 03:53:50 +00:00
|
|
|
$result_array['modulestyles'] = $outputPage->getModuleStyles();
|
|
|
|
|
} else {
|
|
|
|
|
$result_array['modules'] = array_values( array_unique( $p_result->getModules() ) );
|
2019-03-03 19:19:51 +00:00
|
|
|
// Deprecated since 1.32 (T188689)
|
|
|
|
|
$result_array['modulescripts'] = [];
|
2017-04-25 03:53:50 +00:00
|
|
|
$result_array['modulestyles'] = array_values( array_unique( $p_result->getModuleStyles() ) );
|
|
|
|
|
}
|
2014-04-16 21:07:54 +00:00
|
|
|
}
|
|
|
|
|
|
2015-01-23 23:27:11 +00:00
|
|
|
if ( isset( $prop['jsconfigvars'] ) ) {
|
2017-04-25 03:53:50 +00:00
|
|
|
$jsconfigvars = $skin ? $outputPage->getJsConfigVars() : $p_result->getJsConfigVars();
|
|
|
|
|
$result_array['jsconfigvars'] = ApiResult::addMetadataToResultVars( $jsconfigvars );
|
2015-01-23 23:27:11 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if ( isset( $prop['encodedjsconfigvars'] ) ) {
|
2017-04-25 03:53:50 +00:00
|
|
|
$jsconfigvars = $skin ? $outputPage->getJsConfigVars() : $p_result->getJsConfigVars();
|
2015-01-23 23:27:11 +00:00
|
|
|
$result_array['encodedjsconfigvars'] = FormatJson::encode(
|
2017-04-25 03:53:50 +00:00
|
|
|
$jsconfigvars,
|
|
|
|
|
false,
|
|
|
|
|
FormatJson::ALL_OK
|
2015-01-23 23:27:11 +00:00
|
|
|
);
|
|
|
|
|
$result_array[ApiResult::META_SUBELEMENTS][] = 'encodedjsconfigvars';
|
|
|
|
|
}
|
|
|
|
|
|
2015-06-04 10:32:23 +00:00
|
|
|
if ( isset( $prop['modules'] ) &&
|
|
|
|
|
!isset( $prop['jsconfigvars'] ) && !isset( $prop['encodedjsconfigvars'] ) ) {
|
2016-10-19 16:54:25 +00:00
|
|
|
$this->addWarning( 'apiwarn-moduleswithoutvars' );
|
2015-06-04 10:32:23 +00:00
|
|
|
}
|
|
|
|
|
|
Implement page status indicators
Page status indicators are icons (or short text snippets) usually
displayed in the top-right corner of the page, outside of the main
content. Basically, <indicator name="foo">[[File:Foo.svg|20px]]</indicator>
may be used on a page to place the icon in the indicator area. They
are also known as top icons, page icons, heading icons or title icons.
I found the discussion on bug 23796 highly illuminating. I suggest
that everyone read it before suggesting different design choices.
I spent some time with a thesaurus pondering the name. "Emblems" and
"badges" were also considered, but the former has a much more limited
meaning and the latter is already taken by Wikidata, with a similar
but subtly different feature set. I am not aware of any naming
conflicts ;) besides new talk page message "indicator" (used by core
and Echo in some documents) and OOjs UI indicators (tiny icons like
the arrow on a dropdown form element), which shouldn't be confusing.
Potential use cases include:
* "Lock" indicators for page protection levels
* Featured/good article indicators
* Redirect shortcuts display ("WP:VPT")
* Links to help/manual for special pages
* Coordinates?… or globe icon for inline pop-up maps
Design features:
* Skin-customizable. Skins can fully control where and how indicators
are shown, or may just do <?php echo $this->getIndicators(); ?> to
output the default structure. By default they are not shown at all.
* Extension-customizable. Extensions can call ParserOutput::addIndicator()
to insert an indicator from one of the numerous parser hooks.
* Wiki-customizable. In addition to just using the parser functions,
on-wiki styles and scripts can use the provided classes and ids
(.mw-indicator, #mw-indicator-<name>) to customize their display.
Design limitations:
* Every indicator must have a unique identifier (name). It's not
possible to create arrays, or to have several indicators with the
same name. In case of duplicates, the latest occurrence of the
parser function wins.
* Indicators are displayed ordered by their names (and not occurrence
order). This ensures consistency across pages and provides a simple
means of ordering or grouping them.
* Indicators are not stored, tracked or accessible outside of
ParserOutput (in particular they're not in the page_props table).
They are intended to merely reflect the content or metadata that is
already present on the page, and not be data themselves. If you ever
think you need to list pages with a given status indicator, instead
figure out what it means and use the appropriate tracking category,
special page report, already existing page_prop, or other means.
Corresponding patch in Vector: I90a8ae15ac8275d084ea5f47b6b2684d5e6c7412.
I'll implement support in the other three skins included in the tarball
and document it on mediawiki.org after this is merged.
Bug: 23796
Change-Id: I2389ff9a5332a2b1d033eb75f0946e5241cfaaf4
2014-09-24 10:44:16 +00:00
|
|
|
if ( isset( $prop['indicators'] ) ) {
|
2017-04-25 03:53:50 +00:00
|
|
|
if ( $skin ) {
|
|
|
|
|
$result_array['indicators'] = (array)$outputPage->getIndicators();
|
|
|
|
|
} else {
|
|
|
|
|
$result_array['indicators'] = (array)$p_result->getIndicators();
|
|
|
|
|
}
|
2015-01-16 19:00:07 +00:00
|
|
|
ApiResult::setArrayType( $result_array['indicators'], 'BCkvp', 'name' );
|
Implement page status indicators
Page status indicators are icons (or short text snippets) usually
displayed in the top-right corner of the page, outside of the main
content. Basically, <indicator name="foo">[[File:Foo.svg|20px]]</indicator>
may be used on a page to place the icon in the indicator area. They
are also known as top icons, page icons, heading icons or title icons.
I found the discussion on bug 23796 highly illuminating. I suggest
that everyone read it before suggesting different design choices.
I spent some time with a thesaurus pondering the name. "Emblems" and
"badges" were also considered, but the former has a much more limited
meaning and the latter is already taken by Wikidata, with a similar
but subtly different feature set. I am not aware of any naming
conflicts ;) besides new talk page message "indicator" (used by core
and Echo in some documents) and OOjs UI indicators (tiny icons like
the arrow on a dropdown form element), which shouldn't be confusing.
Potential use cases include:
* "Lock" indicators for page protection levels
* Featured/good article indicators
* Redirect shortcuts display ("WP:VPT")
* Links to help/manual for special pages
* Coordinates?… or globe icon for inline pop-up maps
Design features:
* Skin-customizable. Skins can fully control where and how indicators
are shown, or may just do <?php echo $this->getIndicators(); ?> to
output the default structure. By default they are not shown at all.
* Extension-customizable. Extensions can call ParserOutput::addIndicator()
to insert an indicator from one of the numerous parser hooks.
* Wiki-customizable. In addition to just using the parser functions,
on-wiki styles and scripts can use the provided classes and ids
(.mw-indicator, #mw-indicator-<name>) to customize their display.
Design limitations:
* Every indicator must have a unique identifier (name). It's not
possible to create arrays, or to have several indicators with the
same name. In case of duplicates, the latest occurrence of the
parser function wins.
* Indicators are displayed ordered by their names (and not occurrence
order). This ensures consistency across pages and provides a simple
means of ordering or grouping them.
* Indicators are not stored, tracked or accessible outside of
ParserOutput (in particular they're not in the page_props table).
They are intended to merely reflect the content or metadata that is
already present on the page, and not be data themselves. If you ever
think you need to list pages with a given status indicator, instead
figure out what it means and use the appropriate tracking category,
special page report, already existing page_prop, or other means.
Corresponding patch in Vector: I90a8ae15ac8275d084ea5f47b6b2684d5e6c7412.
I'll implement support in the other three skins included in the tarball
and document it on mediawiki.org after this is merged.
Bug: 23796
Change-Id: I2389ff9a5332a2b1d033eb75f0946e5241cfaaf4
2014-09-24 10:44:16 +00:00
|
|
|
}
|
|
|
|
|
|
2010-05-25 13:47:22 +00:00
|
|
|
if ( isset( $prop['iwlinks'] ) ) {
|
|
|
|
|
$result_array['iwlinks'] = $this->formatIWLinks( $p_result->getInterwikiLinks() );
|
|
|
|
|
}
|
2011-05-17 08:32:10 +00:00
|
|
|
|
2011-01-28 01:47:08 +00:00
|
|
|
if ( isset( $prop['wikitext'] ) ) {
|
2015-01-16 19:00:07 +00:00
|
|
|
$result_array['wikitext'] = $this->content->serialize( $format );
|
|
|
|
|
$result_array[ApiResult::META_BC_SUBELEMENTS][] = 'wikitext';
|
2021-08-19 08:59:37 +00:00
|
|
|
// @phan-suppress-next-line PhanImpossibleTypeComparison
|
2020-01-09 23:48:34 +00:00
|
|
|
if ( $this->pstContent !== null ) {
|
2015-01-16 19:00:07 +00:00
|
|
|
$result_array['psttext'] = $this->pstContent->serialize( $format );
|
|
|
|
|
$result_array[ApiResult::META_BC_SUBELEMENTS][] = 'psttext';
|
2011-01-28 01:47:08 +00:00
|
|
|
}
|
|
|
|
|
}
|
2012-05-05 18:08:58 +00:00
|
|
|
if ( isset( $prop['properties'] ) ) {
|
2021-10-07 16:13:46 +00:00
|
|
|
$result_array['properties'] = $p_result->getPageProperties();
|
2015-01-16 19:00:07 +00:00
|
|
|
ApiResult::setArrayType( $result_array['properties'], 'BCkvp', 'name' );
|
2012-05-05 18:08:58 +00:00
|
|
|
}
|
2010-02-23 18:05:46 +00:00
|
|
|
|
2014-02-04 19:16:59 +00:00
|
|
|
if ( isset( $prop['limitreportdata'] ) ) {
|
2014-04-24 19:50:01 +00:00
|
|
|
$result_array['limitreportdata'] =
|
|
|
|
|
$this->formatLimitReportData( $p_result->getLimitReportData() );
|
2014-02-04 19:16:59 +00:00
|
|
|
}
|
|
|
|
|
if ( isset( $prop['limitreporthtml'] ) ) {
|
2015-01-16 19:00:07 +00:00
|
|
|
$result_array['limitreporthtml'] = EditPage::getPreviewLimitReport( $p_result );
|
|
|
|
|
$result_array[ApiResult::META_BC_SUBELEMENTS][] = 'limitreporthtml';
|
2014-02-04 19:16:59 +00:00
|
|
|
}
|
|
|
|
|
|
2015-06-05 09:22:17 +00:00
|
|
|
if ( isset( $prop['parsetree'] ) || $params['generatexml'] ) {
|
2012-08-21 14:15:12 +00:00
|
|
|
if ( $this->content->getModel() != CONTENT_MODEL_WIKITEXT ) {
|
2016-10-19 16:54:25 +00:00
|
|
|
$this->dieWithError( 'apierror-parsetree-notwikitext', 'notwikitext' );
|
2012-08-21 14:15:12 +00:00
|
|
|
}
|
|
|
|
|
|
2021-06-30 10:28:47 +00:00
|
|
|
$this->parser->startExternalParse( $titleObj, $popts, Parser::OT_PREPROCESS );
|
2019-08-31 16:14:38 +00:00
|
|
|
// @phan-suppress-next-line PhanUndeclaredMethod
|
2021-06-30 10:28:47 +00:00
|
|
|
$xml = $this->parser->preprocessToDom( $this->content->getText() )->__toString();
|
2015-01-16 19:00:07 +00:00
|
|
|
$result_array['parsetree'] = $xml;
|
|
|
|
|
$result_array[ApiResult::META_BC_SUBELEMENTS][] = 'parsetree';
|
2012-08-20 14:55:28 +00:00
|
|
|
}
|
|
|
|
|
|
2016-02-17 09:09:32 +00:00
|
|
|
$result_mapping = [
|
2008-10-24 12:28:14 +00:00
|
|
|
'redirects' => 'r',
|
2007-12-01 13:37:02 +00:00
|
|
|
'langlinks' => 'll',
|
|
|
|
|
'categories' => 'cl',
|
|
|
|
|
'links' => 'pl',
|
|
|
|
|
'templates' => 'tl',
|
|
|
|
|
'images' => 'img',
|
|
|
|
|
'externallinks' => 'el',
|
2010-05-25 13:47:22 +00:00
|
|
|
'iwlinks' => 'iw',
|
2007-12-27 20:14:07 +00:00
|
|
|
'sections' => 's',
|
2010-05-24 16:35:23 +00:00
|
|
|
'headitems' => 'hi',
|
2014-04-16 21:07:54 +00:00
|
|
|
'modules' => 'm',
|
Implement page status indicators
Page status indicators are icons (or short text snippets) usually
displayed in the top-right corner of the page, outside of the main
content. Basically, <indicator name="foo">[[File:Foo.svg|20px]]</indicator>
may be used on a page to place the icon in the indicator area. They
are also known as top icons, page icons, heading icons or title icons.
I found the discussion on bug 23796 highly illuminating. I suggest
that everyone read it before suggesting different design choices.
I spent some time with a thesaurus pondering the name. "Emblems" and
"badges" were also considered, but the former has a much more limited
meaning and the latter is already taken by Wikidata, with a similar
but subtly different feature set. I am not aware of any naming
conflicts ;) besides new talk page message "indicator" (used by core
and Echo in some documents) and OOjs UI indicators (tiny icons like
the arrow on a dropdown form element), which shouldn't be confusing.
Potential use cases include:
* "Lock" indicators for page protection levels
* Featured/good article indicators
* Redirect shortcuts display ("WP:VPT")
* Links to help/manual for special pages
* Coordinates?… or globe icon for inline pop-up maps
Design features:
* Skin-customizable. Skins can fully control where and how indicators
are shown, or may just do <?php echo $this->getIndicators(); ?> to
output the default structure. By default they are not shown at all.
* Extension-customizable. Extensions can call ParserOutput::addIndicator()
to insert an indicator from one of the numerous parser hooks.
* Wiki-customizable. In addition to just using the parser functions,
on-wiki styles and scripts can use the provided classes and ids
(.mw-indicator, #mw-indicator-<name>) to customize their display.
Design limitations:
* Every indicator must have a unique identifier (name). It's not
possible to create arrays, or to have several indicators with the
same name. In case of duplicates, the latest occurrence of the
parser function wins.
* Indicators are displayed ordered by their names (and not occurrence
order). This ensures consistency across pages and provides a simple
means of ordering or grouping them.
* Indicators are not stored, tracked or accessible outside of
ParserOutput (in particular they're not in the page_props table).
They are intended to merely reflect the content or metadata that is
already present on the page, and not be data themselves. If you ever
think you need to list pages with a given status indicator, instead
figure out what it means and use the appropriate tracking category,
special page report, already existing page_prop, or other means.
Corresponding patch in Vector: I90a8ae15ac8275d084ea5f47b6b2684d5e6c7412.
I'll implement support in the other three skins included in the tarball
and document it on mediawiki.org after this is merged.
Bug: 23796
Change-Id: I2389ff9a5332a2b1d033eb75f0946e5241cfaaf4
2014-09-24 10:44:16 +00:00
|
|
|
'indicators' => 'ind',
|
2014-04-16 21:07:54 +00:00
|
|
|
'modulescripts' => 'm',
|
|
|
|
|
'modulestyles' => 'm',
|
2012-05-05 18:08:58 +00:00
|
|
|
'properties' => 'pp',
|
2014-02-04 19:16:59 +00:00
|
|
|
'limitreportdata' => 'lr',
|
2021-02-16 21:30:27 +00:00
|
|
|
'parsewarnings' => 'pw',
|
|
|
|
|
'parsewarningshtml' => 'pw',
|
2016-02-17 09:09:32 +00:00
|
|
|
];
|
2007-12-01 13:37:02 +00:00
|
|
|
$this->setIndexedTagNames( $result_array, $result_mapping );
|
|
|
|
|
$result->addValue( null, $this->getModuleName(), $result_array );
|
|
|
|
|
}
|
2008-04-14 07:45:50 +00:00
|
|
|
|
2013-06-06 16:04:40 +00:00
|
|
|
/**
|
|
|
|
|
* Constructs a ParserOptions object
|
|
|
|
|
*
|
|
|
|
|
* @param WikiPage $pageObj
|
|
|
|
|
* @param array $params
|
|
|
|
|
*
|
2016-06-20 15:58:53 +00:00
|
|
|
* @return array [ ParserOptions, ScopedCallback, bool $suppressCache ]
|
2013-06-06 16:04:40 +00:00
|
|
|
*/
|
2021-01-19 19:57:24 +00:00
|
|
|
private function makeParserOptions( WikiPage $pageObj, array $params ) {
|
2013-06-06 16:04:40 +00:00
|
|
|
$popts = $pageObj->makeParserOptions( $this->getContext() );
|
2021-01-19 19:57:24 +00:00
|
|
|
return $this->tweakParserOptions( $popts, $pageObj->getTitle(), $params );
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Tweaks a ParserOptions object
|
|
|
|
|
*
|
|
|
|
|
* @param ParserOptions $popts
|
|
|
|
|
* @param Title $title
|
|
|
|
|
* @param array $params
|
|
|
|
|
*
|
|
|
|
|
* @return array [ ParserOptions, ScopedCallback, bool $suppressCache ]
|
|
|
|
|
*/
|
|
|
|
|
private function tweakParserOptions( ParserOptions $popts, Title $title, array $params ) {
|
2013-06-12 22:46:04 +00:00
|
|
|
$popts->setIsPreview( $params['preview'] || $params['sectionpreview'] );
|
|
|
|
|
$popts->setIsSectionPreview( $params['sectionpreview'] );
|
2020-04-01 21:24:13 +00:00
|
|
|
|
2017-12-22 18:32:49 +00:00
|
|
|
if ( $params['wrapoutputclass'] !== '' ) {
|
|
|
|
|
$popts->setWrapOutputClass( $params['wrapoutputclass'] );
|
|
|
|
|
}
|
2013-06-06 16:04:40 +00:00
|
|
|
|
2016-06-20 15:58:53 +00:00
|
|
|
$reset = null;
|
|
|
|
|
$suppressCache = false;
|
2021-01-19 19:57:24 +00:00
|
|
|
$this->getHookRunner()->onApiMakeParserOptions( $popts, $title,
|
Hooks::run() call site migration
Migrate all callers of Hooks::run() to use the new
HookContainer/HookRunner system.
General principles:
* Use DI if it is already used. We're not changing the way state is
managed in this patch.
* HookContainer is always injected, not HookRunner. HookContainer
is a service, it's a more generic interface, it is the only
thing that provides isRegistered() which is needed in some cases,
and a HookRunner can be efficiently constructed from it
(confirmed by benchmark). Because HookContainer is needed
for object construction, it is also needed by all factories.
* "Ask your friendly local base class". Big hierarchies like
SpecialPage and ApiBase have getHookContainer() and getHookRunner()
methods in the base class, and classes that extend that base class
are not expected to know or care where the base class gets its
HookContainer from.
* ProtectedHookAccessorTrait provides protected getHookContainer() and
getHookRunner() methods, getting them from the global service
container. The point of this is to ease migration to DI by ensuring
that call sites ask their local friendly base class rather than
getting a HookRunner from the service container directly.
* Private $this->hookRunner. In some smaller classes where accessor
methods did not seem warranted, there is a private HookRunner property
which is accessed directly. Very rarely (two cases), there is a
protected property, for consistency with code that conventionally
assumes protected=private, but in cases where the class might actually
be overridden, a protected accessor is preferred over a protected
property.
* The last resort: Hooks::runner(). Mostly for static, file-scope and
global code. In a few cases it was used for objects with broken
construction schemes, out of horror or laziness.
Constructors with new required arguments:
* AuthManager
* BadFileLookup
* BlockManager
* ClassicInterwikiLookup
* ContentHandlerFactory
* ContentSecurityPolicy
* DefaultOptionsManager
* DerivedPageDataUpdater
* FullSearchResultWidget
* HtmlCacheUpdater
* LanguageFactory
* LanguageNameUtils
* LinkRenderer
* LinkRendererFactory
* LocalisationCache
* MagicWordFactory
* MessageCache
* NamespaceInfo
* PageEditStash
* PageHandlerFactory
* PageUpdater
* ParserFactory
* PermissionManager
* RevisionStore
* RevisionStoreFactory
* SearchEngineConfig
* SearchEngineFactory
* SearchFormWidget
* SearchNearMatcher
* SessionBackend
* SpecialPageFactory
* UserNameUtils
* UserOptionsManager
* WatchedItemQueryService
* WatchedItemStore
Constructors with new optional arguments:
* DefaultPreferencesFactory
* Language
* LinkHolderArray
* MovePage
* Parser
* ParserCache
* PasswordReset
* Router
setHookContainer() now required after construction:
* AuthenticationProvider
* ResourceLoaderModule
* SearchEngine
Change-Id: Id442b0dbe43aba84bd5cf801d86dedc768b082c7
2020-03-19 02:42:09 +00:00
|
|
|
$params, $this, $reset, $suppressCache );
|
2016-06-20 15:58:53 +00:00
|
|
|
|
|
|
|
|
return [ $popts, $reset, $suppressCache ];
|
2013-06-06 16:04:40 +00:00
|
|
|
}
|
|
|
|
|
|
2011-01-01 23:01:24 +00:00
|
|
|
/**
|
2014-04-15 18:12:09 +00:00
|
|
|
* @param WikiPage $page
|
|
|
|
|
* @param ParserOptions $popts
|
2017-06-12 15:02:58 +00:00
|
|
|
* @param bool $suppressCache
|
2014-04-15 18:12:09 +00:00
|
|
|
* @param int $pageId
|
2020-03-04 07:28:19 +00:00
|
|
|
* @param RevisionRecord|null $rev
|
2017-06-12 15:02:58 +00:00
|
|
|
* @param bool $getContent
|
2011-01-01 23:01:24 +00:00
|
|
|
* @return ParserOutput
|
|
|
|
|
*/
|
2017-06-12 15:02:58 +00:00
|
|
|
private function getParsedContent(
|
|
|
|
|
WikiPage $page, $popts, $suppressCache, $pageId, $rev, $getContent
|
|
|
|
|
) {
|
|
|
|
|
$revId = $rev ? $rev->getId() : null;
|
2019-07-21 13:18:14 +00:00
|
|
|
$isDeleted = $rev && $rev->isDeleted( RevisionRecord::DELETED_TEXT );
|
2017-06-12 15:02:58 +00:00
|
|
|
|
|
|
|
|
if ( $getContent || $this->section !== false || $isDeleted ) {
|
|
|
|
|
if ( $rev ) {
|
2020-03-04 07:28:19 +00:00
|
|
|
$this->content = $rev->getContent(
|
|
|
|
|
SlotRecord::MAIN, RevisionRecord::FOR_THIS_USER, $this->getUser()
|
|
|
|
|
);
|
2017-06-12 15:02:58 +00:00
|
|
|
if ( !$this->content ) {
|
|
|
|
|
$this->dieWithError( [ 'apierror-missingcontent-revid', $revId ] );
|
|
|
|
|
}
|
|
|
|
|
} else {
|
2019-07-21 13:18:14 +00:00
|
|
|
$this->content = $page->getContent( RevisionRecord::FOR_THIS_USER, $this->getUser() );
|
2017-06-12 15:02:58 +00:00
|
|
|
if ( !$this->content ) {
|
2018-03-27 17:12:48 +00:00
|
|
|
$this->dieWithError( [ 'apierror-missingcontent-pageid', $page->getId() ] );
|
2017-06-12 15:02:58 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
$this->contentIsDeleted = $isDeleted;
|
|
|
|
|
$this->contentIsSuppressed = $rev &&
|
2019-07-21 13:18:14 +00:00
|
|
|
$rev->isDeleted( RevisionRecord::DELETED_TEXT | RevisionRecord::DELETED_RESTRICTED );
|
2017-06-12 15:02:58 +00:00
|
|
|
}
|
2011-11-18 21:36:57 +00:00
|
|
|
|
2017-06-12 15:02:58 +00:00
|
|
|
if ( $this->section !== false ) {
|
|
|
|
|
$this->content = $this->getSectionContent(
|
|
|
|
|
$this->content,
|
|
|
|
|
$pageId === null ? $page->getTitle()->getPrefixedText() : $this->msg( 'pageid', $pageId )
|
|
|
|
|
);
|
2020-04-07 17:05:12 +00:00
|
|
|
return $this->getContentParserOutput( $this->content, $page->getTitle(), $revId, $popts );
|
2013-11-17 19:54:11 +00:00
|
|
|
}
|
2013-11-14 12:47:20 +00:00
|
|
|
|
2017-06-12 15:02:58 +00:00
|
|
|
if ( $isDeleted ) {
|
|
|
|
|
// getParserOutput can't do revdeled revisions
|
2020-04-07 17:05:12 +00:00
|
|
|
|
|
|
|
|
$pout = $this->getContentParserOutput( $this->content, $page->getTitle(), $revId, $popts );
|
2017-06-12 15:02:58 +00:00
|
|
|
} else {
|
|
|
|
|
// getParserOutput will save to Parser cache if able
|
2020-04-07 17:05:12 +00:00
|
|
|
$pout = $this->getPageParserOutput( $page, $revId, $popts, $suppressCache );
|
2013-11-17 19:54:11 +00:00
|
|
|
}
|
2017-06-12 15:02:58 +00:00
|
|
|
if ( !$pout ) {
|
2019-10-11 16:30:40 +00:00
|
|
|
// @codeCoverageIgnoreStart
|
|
|
|
|
$this->dieWithError( [ 'apierror-nosuchrevid', $revId ?: $page->getLatest() ] );
|
|
|
|
|
// @codeCoverageIgnoreEnd
|
2011-01-01 23:01:24 +00:00
|
|
|
}
|
2013-11-17 19:54:11 +00:00
|
|
|
|
|
|
|
|
return $pout;
|
2011-01-01 23:01:24 +00:00
|
|
|
}
|
|
|
|
|
|
2015-08-24 05:05:09 +00:00
|
|
|
/**
|
|
|
|
|
* Extract the requested section from the given Content
|
|
|
|
|
*
|
2014-07-23 01:26:53 +00:00
|
|
|
* @param Content $content
|
2016-10-19 16:54:25 +00:00
|
|
|
* @param string|Message $what Identifies the content in error messages, e.g. page title.
|
2017-06-12 15:02:58 +00:00
|
|
|
* @return Content
|
2014-07-23 01:26:53 +00:00
|
|
|
*/
|
2012-08-21 14:15:12 +00:00
|
|
|
private function getSectionContent( Content $content, $what ) {
|
2011-08-05 13:07:09 +00:00
|
|
|
// Not cached (save or load)
|
2012-08-21 14:15:12 +00:00
|
|
|
$section = $content->getSection( $this->section );
|
|
|
|
|
if ( $section === false ) {
|
2016-10-19 16:54:25 +00:00
|
|
|
$this->dieWithError( [ 'apierror-nosuchsection-what', $this->section, $what ], 'nosuchsection' );
|
2010-05-10 18:27:58 +00:00
|
|
|
}
|
2012-08-21 14:15:12 +00:00
|
|
|
if ( $section === null ) {
|
2016-10-19 16:54:25 +00:00
|
|
|
$this->dieWithError( [ 'apierror-sectionsnotsupported-what', $what ], 'nosuchsection' );
|
2012-08-21 14:15:12 +00:00
|
|
|
}
|
2013-11-14 12:47:20 +00:00
|
|
|
|
2012-08-21 14:15:12 +00:00
|
|
|
return $section;
|
2010-05-10 18:27:58 +00:00
|
|
|
}
|
|
|
|
|
|
2015-03-19 21:20:53 +00:00
|
|
|
/**
|
Introduce CommentFormatter
CommentParser:
* Move comment formatting backend from Linker to a CommentParser service.
Allow link existence and file existence to be batched.
* Rename $local to $samePage since I think that is clearer.
* Rename $title to $selfLinkTarget since it was unclear what the title
was used for.
* Rename the "autocomment" concept to "section link" in public
interfaces, although the old term remains in CSS classes.
* Keep unsafe HTML pass-through in separate "unsafe" methods, for easier
static analysis and code review.
CommentFormatter:
* Add CommentFormatter and RowCommentFormatter services as a usable
frontend for comment batches, and to replace the Linker static methods.
* Provide fluent and parametric interfaces.
Linker:
* Remove Linker::makeCommentLink() without deprecation -- nothing calls
it and it is obviously an internal helper.
* Soft-deprecate Linker methods formatComment(), formatLinksInComment(),
commentBlock() and revComment().
Caller migration:
* CommentFormatter single: Linker, RollbackAction, ApiComparePages,
ApiParse
* CommentFormatter parametric batch: ImageHistoryPseudoPager
* CommentFormatter fluent batch: ApiQueryFilearchive
* RowCommentFormatter sequential: History feed, BlocklistPager,
ProtectedPagesPager, ApiQueryProtectedTitles
* RowCommentFormatter with index: ChangesFeed, ChangesList,
ApiQueryDeletedrevs, ApiQueryLogEvents, ApiQueryRecentChanges
* RevisionCommentBatch: HistoryPager, ContribsPager
Bug: T285917
Change-Id: Ia3fd50a4a13138ba5003d884962da24746d562d0
2021-07-01 06:55:03 +00:00
|
|
|
* This mimics the behavior of EditPage in formatting a summary
|
2015-03-19 21:20:53 +00:00
|
|
|
*
|
|
|
|
|
* @param Title $title of the page being parsed
|
2018-10-21 11:38:39 +00:00
|
|
|
* @param array $params The API parameters of the request
|
2019-09-15 15:12:06 +00:00
|
|
|
* @return string HTML
|
2015-03-19 21:20:53 +00:00
|
|
|
*/
|
|
|
|
|
private function formatSummary( $title, $params ) {
|
2019-03-11 09:29:20 +00:00
|
|
|
$summary = $params['summary'] ?? '';
|
|
|
|
|
$sectionTitle = $params['sectiontitle'] ?? '';
|
2015-03-19 21:20:53 +00:00
|
|
|
|
|
|
|
|
if ( $this->section === 'new' && ( $sectionTitle === '' || $summary === '' ) ) {
|
2015-06-04 10:32:23 +00:00
|
|
|
if ( $sectionTitle !== '' ) {
|
2015-03-19 21:20:53 +00:00
|
|
|
$summary = $params['sectiontitle'];
|
|
|
|
|
}
|
|
|
|
|
if ( $summary !== '' ) {
|
2015-06-04 10:32:23 +00:00
|
|
|
$summary = wfMessage( 'newsectionsummary' )
|
2021-06-30 10:28:47 +00:00
|
|
|
->rawParams( $this->parser->stripSectionName( $summary ) )
|
2019-04-11 13:36:15 +00:00
|
|
|
->inContentLanguage()->text();
|
2015-03-19 21:20:53 +00:00
|
|
|
}
|
|
|
|
|
}
|
Introduce CommentFormatter
CommentParser:
* Move comment formatting backend from Linker to a CommentParser service.
Allow link existence and file existence to be batched.
* Rename $local to $samePage since I think that is clearer.
* Rename $title to $selfLinkTarget since it was unclear what the title
was used for.
* Rename the "autocomment" concept to "section link" in public
interfaces, although the old term remains in CSS classes.
* Keep unsafe HTML pass-through in separate "unsafe" methods, for easier
static analysis and code review.
CommentFormatter:
* Add CommentFormatter and RowCommentFormatter services as a usable
frontend for comment batches, and to replace the Linker static methods.
* Provide fluent and parametric interfaces.
Linker:
* Remove Linker::makeCommentLink() without deprecation -- nothing calls
it and it is obviously an internal helper.
* Soft-deprecate Linker methods formatComment(), formatLinksInComment(),
commentBlock() and revComment().
Caller migration:
* CommentFormatter single: Linker, RollbackAction, ApiComparePages,
ApiParse
* CommentFormatter parametric batch: ImageHistoryPseudoPager
* CommentFormatter fluent batch: ApiQueryFilearchive
* RowCommentFormatter sequential: History feed, BlocklistPager,
ProtectedPagesPager, ApiQueryProtectedTitles
* RowCommentFormatter with index: ChangesFeed, ChangesList,
ApiQueryDeletedrevs, ApiQueryLogEvents, ApiQueryRecentChanges
* RevisionCommentBatch: HistoryPager, ContribsPager
Bug: T285917
Change-Id: Ia3fd50a4a13138ba5003d884962da24746d562d0
2021-07-01 06:55:03 +00:00
|
|
|
return $this->commentFormatter->format( $summary, $title, $this->section === 'new' );
|
2015-03-19 21:20:53 +00:00
|
|
|
}
|
|
|
|
|
|
2007-12-01 13:37:02 +00:00
|
|
|
private function formatLangLinks( $links ) {
|
2016-02-17 09:09:32 +00:00
|
|
|
$result = [];
|
2010-01-11 15:55:52 +00:00
|
|
|
foreach ( $links as $link ) {
|
2016-02-17 09:09:32 +00:00
|
|
|
$entry = [];
|
2009-09-28 18:36:15 +00:00
|
|
|
$bits = explode( ':', $link, 2 );
|
2011-01-28 01:09:47 +00:00
|
|
|
$title = Title::newFromText( $link );
|
2011-05-17 08:32:10 +00:00
|
|
|
|
2007-12-01 13:37:02 +00:00
|
|
|
$entry['lang'] = $bits[0];
|
2011-01-28 01:09:47 +00:00
|
|
|
if ( $title ) {
|
2011-08-19 15:46:08 +00:00
|
|
|
$entry['url'] = wfExpandUrl( $title->getFullURL(), PROTO_CURRENT );
|
API: HTMLize and internationalize the help, add Special:ApiHelp
The existing API help, formatted as basically a plain-text document
embedded in XML and with a little bolding and a few links
syntax-highlighted in after the fact, works ok for experienced programmers
but isn't at all newbie-friendly. Further, all the help is hard-coded in
English, which isn't very friendly to non-English speakers.
So let's rewrite it. The help text is now obtained from i18n messages
and output in HTML, with the default display consisting of help for a
single module with links to help for other modules. This, of course,
necessitates deprecating many of the existing help-related methods and
hooks and replacing them with new ones, but backwards compatibility is
maintained for almost everything.
At the same time, action=paraminfo also needs to support the
'description' and other help-related fields being output in wikitext or
HTML, and I11cb063d (to access all modules via the 'modules' parameter
instead of having 'modules', 'formatmodules', 'querymodules', and so on)
is folded in.
And we also add Special:ApiHelp. When directly accessed, it simply
redirects to api.php with appropriate parameters. But it's also
transcludable to allow up-to-date API help text to be included within
the on-wiki documentation.
Note this patch doesn't actually add i18n messages for any API modules
besides ApiMain and ApiHelp. That will come in a followup patch, but for
the moment the backwards-compatibility code handles them nicely.
While we're messing with the documentation, we may as well add the
"internal" flag requested in bug 62905 (although the 'includeinternal'
parameter it also requests doesn't make much sense anymore) and a
"deprecated" flag that's needed by several modules now.
Bug: 30936
Bug: 38126
Bug: 42343
Bug: 45641
Bug: 62905
Bug: 63211
Change-Id: Ib14c00df06d85c2f6364d83b2b10ce34c7f513cc
2014-09-16 17:54:01 +00:00
|
|
|
// localised language name in 'uselang' language
|
2021-06-30 10:28:47 +00:00
|
|
|
$entry['langname'] = $this->languageNameUtils->getLanguageName(
|
2014-04-24 19:50:01 +00:00
|
|
|
$title->getInterwiki(),
|
|
|
|
|
$this->getLanguage()->getCode()
|
|
|
|
|
);
|
|
|
|
|
|
2014-02-09 12:31:15 +00:00
|
|
|
// native language name
|
2021-06-30 10:28:47 +00:00
|
|
|
$entry['autonym'] = $this->languageNameUtils->getLanguageName( $title->getInterwiki() );
|
2011-01-28 01:09:47 +00:00
|
|
|
}
|
API: Overhaul ApiResult, make format=xml not throw, and add json formatversion
ApiResult was a mess: some methods could only be used with an array
reference instead of manipulating the stored data, methods that had both
array-ref and internal-data versions had names that didn't at all
correspond, some methods that worked on an array reference were
annoyingly non-static, and then the whole mess with setIndexedTagName.
ApiFormatXml is also entirely annoying to deal with, as it liked to
throw exceptions if certain metadata wasn't provided that no other
formatter required. Its legacy also means we have this silly convention
of using empty-string rather than boolean true, annoying restrictions on
keys (leading to things that should be hashes being arrays of key-value
object instead), '*' used as a key all over the place, and so on.
So, changes here:
* ApiResult is no longer an ApiBase or a ContextSource.
* Wherever sensible, ApiResult provides a static method working on an
arrayref and a non-static method working on internal data.
* Metadata is now always added to ApiResult's internal data structure.
Formatters are responsible for stripping it if necessary. "raw mode"
is deprecated.
* New metadata to replace the '*' key, solve the array() => '[]' vs '{}'
question, and so on.
* New class for formatting warnings and errors using i18n messages, and
support for multiple errors and a more machine-readable format for
warnings. For the moment, though, the actual output will not be changing
yet (see T47843 for future plans).
* New formatversion parameter for format=json and format=php, to select
between BC mode and the modern output.
* In BC mode, booleans will be converted to empty-string presence style;
modules currently returning booleans will need to use
ApiResult::META_BC_BOOLS to preserve their current output.
Actual changes to the API modules' output (e.g. actually returning
booleans for the new formatversion) beyond the use of
ApiResult::setContentValue() are left for a future change.
Bug: T76728
Bug: T57371
Bug: T33629
Change-Id: I7b37295e8862b188d1f3b0cd07f66ac34629678f
2014-12-03 22:14:22 +00:00
|
|
|
ApiResult::setContentValue( $entry, 'title', $bits[1] );
|
2007-12-01 13:37:02 +00:00
|
|
|
$result[] = $entry;
|
|
|
|
|
}
|
2013-11-14 12:47:20 +00:00
|
|
|
|
2007-12-01 13:37:02 +00:00
|
|
|
return $result;
|
|
|
|
|
}
|
2008-04-14 07:45:50 +00:00
|
|
|
|
2007-12-01 13:37:02 +00:00
|
|
|
private function formatCategoryLinks( $links ) {
|
2016-02-17 09:09:32 +00:00
|
|
|
$result = [];
|
2013-10-02 18:58:54 +00:00
|
|
|
|
|
|
|
|
if ( !$links ) {
|
|
|
|
|
return $result;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Fetch hiddencat property
|
2021-06-30 10:28:47 +00:00
|
|
|
$lb = $this->linkBatchFactory->newLinkBatch();
|
2016-02-17 09:09:32 +00:00
|
|
|
$lb->setArray( [ NS_CATEGORY => $links ] );
|
2013-10-02 18:58:54 +00:00
|
|
|
$db = $this->getDB();
|
2016-02-17 09:09:32 +00:00
|
|
|
$res = $db->select( [ 'page', 'page_props' ],
|
|
|
|
|
[ 'page_title', 'pp_propname' ],
|
2013-10-02 18:58:54 +00:00
|
|
|
$lb->constructSet( 'page', $db ),
|
|
|
|
|
__METHOD__,
|
2016-02-17 09:09:32 +00:00
|
|
|
[],
|
|
|
|
|
[ 'page_props' => [
|
|
|
|
|
'LEFT JOIN', [ 'pp_propname' => 'hiddencat', 'pp_page = page_id' ]
|
|
|
|
|
] ]
|
2013-10-02 18:58:54 +00:00
|
|
|
);
|
2016-02-17 09:09:32 +00:00
|
|
|
$hiddencats = [];
|
2013-10-02 18:58:54 +00:00
|
|
|
foreach ( $res as $row ) {
|
|
|
|
|
$hiddencats[$row->page_title] = isset( $row->pp_propname );
|
|
|
|
|
}
|
|
|
|
|
|
2010-01-11 15:55:52 +00:00
|
|
|
foreach ( $links as $link => $sortkey ) {
|
2016-02-17 09:09:32 +00:00
|
|
|
$entry = [];
|
2007-12-01 13:37:02 +00:00
|
|
|
$entry['sortkey'] = $sortkey;
|
2015-12-03 14:15:59 +00:00
|
|
|
// array keys will cast numeric category names to ints, so cast back to string
|
|
|
|
|
ApiResult::setContentValue( $entry, 'category', (string)$link );
|
2013-10-02 18:58:54 +00:00
|
|
|
if ( !isset( $hiddencats[$link] ) ) {
|
2015-01-16 19:00:07 +00:00
|
|
|
$entry['missing'] = true;
|
2016-08-15 18:27:40 +00:00
|
|
|
|
|
|
|
|
// We already know the link doesn't exist in the database, so
|
|
|
|
|
// tell LinkCache that before calling $title->isKnown().
|
|
|
|
|
$title = Title::makeTitle( NS_CATEGORY, $link );
|
2021-06-30 10:28:47 +00:00
|
|
|
$this->linkCache->addBadLinkObj( $title );
|
2016-08-15 18:27:40 +00:00
|
|
|
if ( $title->isKnown() ) {
|
|
|
|
|
$entry['known'] = true;
|
|
|
|
|
}
|
2013-10-02 18:58:54 +00:00
|
|
|
} elseif ( $hiddencats[$link] ) {
|
2015-01-16 19:00:07 +00:00
|
|
|
$entry['hidden'] = true;
|
2013-10-02 18:58:54 +00:00
|
|
|
}
|
2007-12-01 13:37:02 +00:00
|
|
|
$result[] = $entry;
|
|
|
|
|
}
|
2013-10-02 18:58:54 +00:00
|
|
|
|
2007-12-01 13:37:02 +00:00
|
|
|
return $result;
|
|
|
|
|
}
|
2008-04-14 07:45:50 +00:00
|
|
|
|
2007-12-01 13:37:02 +00:00
|
|
|
private function formatLinks( $links ) {
|
2016-02-17 09:09:32 +00:00
|
|
|
$result = [];
|
2010-01-11 15:55:52 +00:00
|
|
|
foreach ( $links as $ns => $nslinks ) {
|
|
|
|
|
foreach ( $nslinks as $title => $id ) {
|
2016-02-17 09:09:32 +00:00
|
|
|
$entry = [];
|
2007-12-01 13:37:02 +00:00
|
|
|
$entry['ns'] = $ns;
|
API: Overhaul ApiResult, make format=xml not throw, and add json formatversion
ApiResult was a mess: some methods could only be used with an array
reference instead of manipulating the stored data, methods that had both
array-ref and internal-data versions had names that didn't at all
correspond, some methods that worked on an array reference were
annoyingly non-static, and then the whole mess with setIndexedTagName.
ApiFormatXml is also entirely annoying to deal with, as it liked to
throw exceptions if certain metadata wasn't provided that no other
formatter required. Its legacy also means we have this silly convention
of using empty-string rather than boolean true, annoying restrictions on
keys (leading to things that should be hashes being arrays of key-value
object instead), '*' used as a key all over the place, and so on.
So, changes here:
* ApiResult is no longer an ApiBase or a ContextSource.
* Wherever sensible, ApiResult provides a static method working on an
arrayref and a non-static method working on internal data.
* Metadata is now always added to ApiResult's internal data structure.
Formatters are responsible for stripping it if necessary. "raw mode"
is deprecated.
* New metadata to replace the '*' key, solve the array() => '[]' vs '{}'
question, and so on.
* New class for formatting warnings and errors using i18n messages, and
support for multiple errors and a more machine-readable format for
warnings. For the moment, though, the actual output will not be changing
yet (see T47843 for future plans).
* New formatversion parameter for format=json and format=php, to select
between BC mode and the modern output.
* In BC mode, booleans will be converted to empty-string presence style;
modules currently returning booleans will need to use
ApiResult::META_BC_BOOLS to preserve their current output.
Actual changes to the API modules' output (e.g. actually returning
booleans for the new formatversion) beyond the use of
ApiResult::setContentValue() are left for a future change.
Bug: T76728
Bug: T57371
Bug: T33629
Change-Id: I7b37295e8862b188d1f3b0cd07f66ac34629678f
2014-12-03 22:14:22 +00:00
|
|
|
ApiResult::setContentValue( $entry, 'title', Title::makeTitle( $ns, $title )->getFullText() );
|
2015-01-16 19:00:07 +00:00
|
|
|
$entry['exists'] = $id != 0;
|
2007-12-01 13:37:02 +00:00
|
|
|
$result[] = $entry;
|
|
|
|
|
}
|
|
|
|
|
}
|
2013-11-14 12:47:20 +00:00
|
|
|
|
2007-12-01 13:37:02 +00:00
|
|
|
return $result;
|
|
|
|
|
}
|
2008-04-14 07:45:50 +00:00
|
|
|
|
2010-05-25 13:47:22 +00:00
|
|
|
private function formatIWLinks( $iw ) {
|
2016-02-17 09:09:32 +00:00
|
|
|
$result = [];
|
2010-05-25 13:47:22 +00:00
|
|
|
foreach ( $iw as $prefix => $titles ) {
|
2010-11-06 16:11:19 +00:00
|
|
|
foreach ( array_keys( $titles ) as $title ) {
|
2016-02-17 09:09:32 +00:00
|
|
|
$entry = [];
|
2010-05-25 13:47:22 +00:00
|
|
|
$entry['prefix'] = $prefix;
|
2010-07-23 07:33:40 +00:00
|
|
|
|
2010-05-25 18:37:55 +00:00
|
|
|
$title = Title::newFromText( "{$prefix}:{$title}" );
|
|
|
|
|
if ( $title ) {
|
2011-08-19 15:46:08 +00:00
|
|
|
$entry['url'] = wfExpandUrl( $title->getFullURL(), PROTO_CURRENT );
|
2010-05-25 18:37:55 +00:00
|
|
|
}
|
2010-07-23 07:33:40 +00:00
|
|
|
|
API: Overhaul ApiResult, make format=xml not throw, and add json formatversion
ApiResult was a mess: some methods could only be used with an array
reference instead of manipulating the stored data, methods that had both
array-ref and internal-data versions had names that didn't at all
correspond, some methods that worked on an array reference were
annoyingly non-static, and then the whole mess with setIndexedTagName.
ApiFormatXml is also entirely annoying to deal with, as it liked to
throw exceptions if certain metadata wasn't provided that no other
formatter required. Its legacy also means we have this silly convention
of using empty-string rather than boolean true, annoying restrictions on
keys (leading to things that should be hashes being arrays of key-value
object instead), '*' used as a key all over the place, and so on.
So, changes here:
* ApiResult is no longer an ApiBase or a ContextSource.
* Wherever sensible, ApiResult provides a static method working on an
arrayref and a non-static method working on internal data.
* Metadata is now always added to ApiResult's internal data structure.
Formatters are responsible for stripping it if necessary. "raw mode"
is deprecated.
* New metadata to replace the '*' key, solve the array() => '[]' vs '{}'
question, and so on.
* New class for formatting warnings and errors using i18n messages, and
support for multiple errors and a more machine-readable format for
warnings. For the moment, though, the actual output will not be changing
yet (see T47843 for future plans).
* New formatversion parameter for format=json and format=php, to select
between BC mode and the modern output.
* In BC mode, booleans will be converted to empty-string presence style;
modules currently returning booleans will need to use
ApiResult::META_BC_BOOLS to preserve their current output.
Actual changes to the API modules' output (e.g. actually returning
booleans for the new formatversion) beyond the use of
ApiResult::setContentValue() are left for a future change.
Bug: T76728
Bug: T57371
Bug: T33629
Change-Id: I7b37295e8862b188d1f3b0cd07f66ac34629678f
2014-12-03 22:14:22 +00:00
|
|
|
ApiResult::setContentValue( $entry, 'title', $title->getFullText() );
|
2010-05-25 13:47:22 +00:00
|
|
|
$result[] = $entry;
|
|
|
|
|
}
|
|
|
|
|
}
|
2013-11-14 12:47:20 +00:00
|
|
|
|
2010-05-25 13:47:22 +00:00
|
|
|
return $result;
|
|
|
|
|
}
|
|
|
|
|
|
2010-01-16 13:07:58 +00:00
|
|
|
private function formatHeadItems( $headItems ) {
|
2016-02-17 09:09:32 +00:00
|
|
|
$result = [];
|
2010-01-23 15:25:14 +00:00
|
|
|
foreach ( $headItems as $tag => $content ) {
|
2016-02-17 09:09:32 +00:00
|
|
|
$entry = [];
|
2010-01-16 13:07:58 +00:00
|
|
|
$entry['tag'] = $tag;
|
API: Overhaul ApiResult, make format=xml not throw, and add json formatversion
ApiResult was a mess: some methods could only be used with an array
reference instead of manipulating the stored data, methods that had both
array-ref and internal-data versions had names that didn't at all
correspond, some methods that worked on an array reference were
annoyingly non-static, and then the whole mess with setIndexedTagName.
ApiFormatXml is also entirely annoying to deal with, as it liked to
throw exceptions if certain metadata wasn't provided that no other
formatter required. Its legacy also means we have this silly convention
of using empty-string rather than boolean true, annoying restrictions on
keys (leading to things that should be hashes being arrays of key-value
object instead), '*' used as a key all over the place, and so on.
So, changes here:
* ApiResult is no longer an ApiBase or a ContextSource.
* Wherever sensible, ApiResult provides a static method working on an
arrayref and a non-static method working on internal data.
* Metadata is now always added to ApiResult's internal data structure.
Formatters are responsible for stripping it if necessary. "raw mode"
is deprecated.
* New metadata to replace the '*' key, solve the array() => '[]' vs '{}'
question, and so on.
* New class for formatting warnings and errors using i18n messages, and
support for multiple errors and a more machine-readable format for
warnings. For the moment, though, the actual output will not be changing
yet (see T47843 for future plans).
* New formatversion parameter for format=json and format=php, to select
between BC mode and the modern output.
* In BC mode, booleans will be converted to empty-string presence style;
modules currently returning booleans will need to use
ApiResult::META_BC_BOOLS to preserve their current output.
Actual changes to the API modules' output (e.g. actually returning
booleans for the new formatversion) beyond the use of
ApiResult::setContentValue() are left for a future change.
Bug: T76728
Bug: T57371
Bug: T33629
Change-Id: I7b37295e8862b188d1f3b0cd07f66ac34629678f
2014-12-03 22:14:22 +00:00
|
|
|
ApiResult::setContentValue( $entry, 'content', $content );
|
2010-01-16 13:07:58 +00:00
|
|
|
$result[] = $entry;
|
|
|
|
|
}
|
2013-11-14 12:47:20 +00:00
|
|
|
|
2010-01-16 13:07:58 +00:00
|
|
|
return $result;
|
|
|
|
|
}
|
|
|
|
|
|
2014-02-04 19:16:59 +00:00
|
|
|
private function formatLimitReportData( $limitReportData ) {
|
2016-02-17 09:09:32 +00:00
|
|
|
$result = [];
|
2014-02-04 19:16:59 +00:00
|
|
|
|
|
|
|
|
foreach ( $limitReportData as $name => $value ) {
|
2016-02-17 09:09:32 +00:00
|
|
|
$entry = [];
|
2014-02-04 19:16:59 +00:00
|
|
|
$entry['name'] = $name;
|
|
|
|
|
if ( !is_array( $value ) ) {
|
2016-02-17 09:09:32 +00:00
|
|
|
$value = [ $value ];
|
2014-02-04 19:16:59 +00:00
|
|
|
}
|
2015-01-16 19:00:07 +00:00
|
|
|
ApiResult::setIndexedTagNameRecursive( $value, 'param' );
|
2014-02-04 19:16:59 +00:00
|
|
|
$entry = array_merge( $entry, $value );
|
|
|
|
|
$result[] = $entry;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return $result;
|
|
|
|
|
}
|
|
|
|
|
|
2007-12-01 13:37:02 +00:00
|
|
|
private function setIndexedTagNames( &$array, $mapping ) {
|
2010-01-11 15:55:52 +00:00
|
|
|
foreach ( $mapping as $key => $name ) {
|
2010-02-23 18:05:46 +00:00
|
|
|
if ( isset( $array[$key] ) ) {
|
API: Overhaul ApiResult, make format=xml not throw, and add json formatversion
ApiResult was a mess: some methods could only be used with an array
reference instead of manipulating the stored data, methods that had both
array-ref and internal-data versions had names that didn't at all
correspond, some methods that worked on an array reference were
annoyingly non-static, and then the whole mess with setIndexedTagName.
ApiFormatXml is also entirely annoying to deal with, as it liked to
throw exceptions if certain metadata wasn't provided that no other
formatter required. Its legacy also means we have this silly convention
of using empty-string rather than boolean true, annoying restrictions on
keys (leading to things that should be hashes being arrays of key-value
object instead), '*' used as a key all over the place, and so on.
So, changes here:
* ApiResult is no longer an ApiBase or a ContextSource.
* Wherever sensible, ApiResult provides a static method working on an
arrayref and a non-static method working on internal data.
* Metadata is now always added to ApiResult's internal data structure.
Formatters are responsible for stripping it if necessary. "raw mode"
is deprecated.
* New metadata to replace the '*' key, solve the array() => '[]' vs '{}'
question, and so on.
* New class for formatting warnings and errors using i18n messages, and
support for multiple errors and a more machine-readable format for
warnings. For the moment, though, the actual output will not be changing
yet (see T47843 for future plans).
* New formatversion parameter for format=json and format=php, to select
between BC mode and the modern output.
* In BC mode, booleans will be converted to empty-string presence style;
modules currently returning booleans will need to use
ApiResult::META_BC_BOOLS to preserve their current output.
Actual changes to the API modules' output (e.g. actually returning
booleans for the new formatversion) beyond the use of
ApiResult::setContentValue() are left for a future change.
Bug: T76728
Bug: T57371
Bug: T33629
Change-Id: I7b37295e8862b188d1f3b0cd07f66ac34629678f
2014-12-03 22:14:22 +00:00
|
|
|
ApiResult::setIndexedTagName( $array[$key], $name );
|
2010-02-23 18:05:46 +00:00
|
|
|
}
|
2007-12-01 13:37:02 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2008-01-28 19:05:26 +00:00
|
|
|
public function getAllowedParams() {
|
2016-02-17 09:09:32 +00:00
|
|
|
return [
|
2013-06-19 14:53:57 +00:00
|
|
|
'title' => null,
|
2016-02-17 09:09:32 +00:00
|
|
|
'text' => [
|
2015-05-07 16:39:55 +00:00
|
|
|
ApiBase::PARAM_TYPE => 'text',
|
2016-02-17 09:09:32 +00:00
|
|
|
],
|
2017-09-14 01:13:15 +00:00
|
|
|
'revid' => [
|
|
|
|
|
ApiBase::PARAM_TYPE => 'integer',
|
|
|
|
|
],
|
2010-01-31 17:45:51 +00:00
|
|
|
'summary' => null,
|
2008-01-29 14:47:27 +00:00
|
|
|
'page' => null,
|
2016-02-17 09:09:32 +00:00
|
|
|
'pageid' => [
|
2011-04-04 20:51:41 +00:00
|
|
|
ApiBase::PARAM_TYPE => 'integer',
|
2016-02-17 09:09:32 +00:00
|
|
|
],
|
2008-10-24 12:28:14 +00:00
|
|
|
'redirects' => false,
|
2016-02-17 09:09:32 +00:00
|
|
|
'oldid' => [
|
2011-04-04 20:51:41 +00:00
|
|
|
ApiBase::PARAM_TYPE => 'integer',
|
2016-02-17 09:09:32 +00:00
|
|
|
],
|
|
|
|
|
'prop' => [
|
2013-11-14 18:03:09 +00:00
|
|
|
ApiBase::PARAM_DFLT => 'text|langlinks|categories|links|templates|' .
|
2017-03-31 18:59:35 +00:00
|
|
|
'images|externallinks|sections|revid|displaytitle|iwlinks|' .
|
|
|
|
|
'properties|parsewarnings',
|
2010-02-23 18:05:46 +00:00
|
|
|
ApiBase::PARAM_ISMULTI => true,
|
2016-02-17 09:09:32 +00:00
|
|
|
ApiBase::PARAM_TYPE => [
|
2008-01-15 21:33:08 +00:00
|
|
|
'text',
|
|
|
|
|
'langlinks',
|
|
|
|
|
'categories',
|
2010-12-06 18:31:09 +00:00
|
|
|
'categorieshtml',
|
2008-01-15 21:33:08 +00:00
|
|
|
'links',
|
|
|
|
|
'templates',
|
|
|
|
|
'images',
|
|
|
|
|
'externallinks',
|
2008-03-28 13:27:44 +00:00
|
|
|
'sections',
|
2009-01-31 16:29:15 +00:00
|
|
|
'revid',
|
|
|
|
|
'displaytitle',
|
2020-10-28 21:09:27 +00:00
|
|
|
'subtitle',
|
2010-05-25 13:47:22 +00:00
|
|
|
'headhtml',
|
2014-04-16 21:07:54 +00:00
|
|
|
'modules',
|
2015-01-23 23:27:11 +00:00
|
|
|
'jsconfigvars',
|
|
|
|
|
'encodedjsconfigvars',
|
Implement page status indicators
Page status indicators are icons (or short text snippets) usually
displayed in the top-right corner of the page, outside of the main
content. Basically, <indicator name="foo">[[File:Foo.svg|20px]]</indicator>
may be used on a page to place the icon in the indicator area. They
are also known as top icons, page icons, heading icons or title icons.
I found the discussion on bug 23796 highly illuminating. I suggest
that everyone read it before suggesting different design choices.
I spent some time with a thesaurus pondering the name. "Emblems" and
"badges" were also considered, but the former has a much more limited
meaning and the latter is already taken by Wikidata, with a similar
but subtly different feature set. I am not aware of any naming
conflicts ;) besides new talk page message "indicator" (used by core
and Echo in some documents) and OOjs UI indicators (tiny icons like
the arrow on a dropdown form element), which shouldn't be confusing.
Potential use cases include:
* "Lock" indicators for page protection levels
* Featured/good article indicators
* Redirect shortcuts display ("WP:VPT")
* Links to help/manual for special pages
* Coordinates?… or globe icon for inline pop-up maps
Design features:
* Skin-customizable. Skins can fully control where and how indicators
are shown, or may just do <?php echo $this->getIndicators(); ?> to
output the default structure. By default they are not shown at all.
* Extension-customizable. Extensions can call ParserOutput::addIndicator()
to insert an indicator from one of the numerous parser hooks.
* Wiki-customizable. In addition to just using the parser functions,
on-wiki styles and scripts can use the provided classes and ids
(.mw-indicator, #mw-indicator-<name>) to customize their display.
Design limitations:
* Every indicator must have a unique identifier (name). It's not
possible to create arrays, or to have several indicators with the
same name. In case of duplicates, the latest occurrence of the
parser function wins.
* Indicators are displayed ordered by their names (and not occurrence
order). This ensures consistency across pages and provides a simple
means of ordering or grouping them.
* Indicators are not stored, tracked or accessible outside of
ParserOutput (in particular they're not in the page_props table).
They are intended to merely reflect the content or metadata that is
already present on the page, and not be data themselves. If you ever
think you need to list pages with a given status indicator, instead
figure out what it means and use the appropriate tracking category,
special page report, already existing page_prop, or other means.
Corresponding patch in Vector: I90a8ae15ac8275d084ea5f47b6b2684d5e6c7412.
I'll implement support in the other three skins included in the tarball
and document it on mediawiki.org after this is merged.
Bug: 23796
Change-Id: I2389ff9a5332a2b1d033eb75f0946e5241cfaaf4
2014-09-24 10:44:16 +00:00
|
|
|
'indicators',
|
2010-05-25 13:47:22 +00:00
|
|
|
'iwlinks',
|
2011-01-28 01:47:08 +00:00
|
|
|
'wikitext',
|
2012-05-05 18:08:58 +00:00
|
|
|
'properties',
|
2014-02-04 19:16:59 +00:00
|
|
|
'limitreportdata',
|
|
|
|
|
'limitreporthtml',
|
2015-06-05 09:22:17 +00:00
|
|
|
'parsetree',
|
2017-05-25 20:07:25 +00:00
|
|
|
'parsewarnings',
|
2021-02-16 21:30:27 +00:00
|
|
|
'parsewarningshtml',
|
2017-05-25 20:07:25 +00:00
|
|
|
'headitems',
|
2016-02-17 09:09:32 +00:00
|
|
|
],
|
|
|
|
|
ApiBase::PARAM_HELP_MSG_PER_VALUE => [
|
|
|
|
|
'parsetree' => [ 'apihelp-parse-paramvalue-prop-parsetree', CONTENT_MODEL_WIKITEXT ],
|
|
|
|
|
],
|
2017-05-25 20:07:25 +00:00
|
|
|
ApiBase::PARAM_DEPRECATED_VALUES => [
|
|
|
|
|
'headitems' => 'apiwarn-deprecation-parse-headitems',
|
|
|
|
|
],
|
2016-02-17 09:09:32 +00:00
|
|
|
],
|
2017-04-27 16:58:17 +00:00
|
|
|
'wrapoutputclass' => 'mw-parser-output',
|
2008-12-04 15:51:39 +00:00
|
|
|
'pst' => false,
|
|
|
|
|
'onlypst' => false,
|
2017-04-25 03:53:50 +00:00
|
|
|
'effectivelanglinks' => [
|
|
|
|
|
ApiBase::PARAM_DFLT => false,
|
|
|
|
|
ApiBase::PARAM_DEPRECATED => true,
|
|
|
|
|
],
|
2010-05-10 18:27:58 +00:00
|
|
|
'section' => null,
|
2016-02-17 09:09:32 +00:00
|
|
|
'sectiontitle' => [
|
2015-03-10 21:27:01 +00:00
|
|
|
ApiBase::PARAM_TYPE => 'string',
|
2016-02-17 09:09:32 +00:00
|
|
|
],
|
|
|
|
|
'disablepp' => [
|
2015-08-24 05:05:09 +00:00
|
|
|
ApiBase::PARAM_DFLT => false,
|
|
|
|
|
ApiBase::PARAM_DEPRECATED => true,
|
2016-02-17 09:09:32 +00:00
|
|
|
],
|
2015-08-24 05:05:09 +00:00
|
|
|
'disablelimitreport' => false,
|
2014-06-21 06:09:18 +00:00
|
|
|
'disableeditsection' => false,
|
2017-11-24 19:22:25 +00:00
|
|
|
'disablestylededuplication' => false,
|
2016-02-17 09:09:32 +00:00
|
|
|
'generatexml' => [
|
2014-09-18 17:38:23 +00:00
|
|
|
ApiBase::PARAM_DFLT => false,
|
2016-02-17 09:09:32 +00:00
|
|
|
ApiBase::PARAM_HELP_MSG => [
|
2014-09-18 17:38:23 +00:00
|
|
|
'apihelp-parse-param-generatexml', CONTENT_MODEL_WIKITEXT
|
2016-02-17 09:09:32 +00:00
|
|
|
],
|
2015-06-05 09:22:17 +00:00
|
|
|
ApiBase::PARAM_DEPRECATED => true,
|
2016-02-17 09:09:32 +00:00
|
|
|
],
|
2013-06-06 16:04:40 +00:00
|
|
|
'preview' => false,
|
2013-06-12 22:46:04 +00:00
|
|
|
'sectionpreview' => false,
|
2013-12-17 22:31:17 +00:00
|
|
|
'disabletoc' => false,
|
2017-04-25 03:53:50 +00:00
|
|
|
'useskin' => [
|
2021-08-08 13:30:16 +00:00
|
|
|
// T237856; We use all installed skins here to allow hidden (but usable) skins
|
|
|
|
|
// to continue working correctly with some features such as Live Preview
|
|
|
|
|
ApiBase::PARAM_TYPE => array_keys( $this->skinFactory->getInstalledSkins() ),
|
2017-04-25 03:53:50 +00:00
|
|
|
],
|
2016-02-17 09:09:32 +00:00
|
|
|
'contentformat' => [
|
2021-06-30 10:28:47 +00:00
|
|
|
ApiBase::PARAM_TYPE => $this->contentHandlerFactory->getAllContentFormats(),
|
2016-02-17 09:09:32 +00:00
|
|
|
],
|
|
|
|
|
'contentmodel' => [
|
2021-06-30 10:28:47 +00:00
|
|
|
ApiBase::PARAM_TYPE => $this->contentHandlerFactory->getContentModels(),
|
2020-01-18 20:25:04 +00:00
|
|
|
],
|
2016-02-17 09:09:32 +00:00
|
|
|
];
|
2007-12-01 13:37:02 +00:00
|
|
|
}
|
|
|
|
|
|
2014-10-28 17:17:02 +00:00
|
|
|
protected function getExamplesMessages() {
|
2016-02-17 09:09:32 +00:00
|
|
|
return [
|
2014-09-18 17:38:23 +00:00
|
|
|
'action=parse&page=Project:Sandbox'
|
|
|
|
|
=> 'apihelp-parse-example-page',
|
|
|
|
|
'action=parse&text={{Project:Sandbox}}&contentmodel=wikitext'
|
|
|
|
|
=> 'apihelp-parse-example-text',
|
|
|
|
|
'action=parse&text={{PAGENAME}}&title=Test'
|
|
|
|
|
=> 'apihelp-parse-example-texttitle',
|
|
|
|
|
'action=parse&summary=Some+[[link]]&prop='
|
|
|
|
|
=> 'apihelp-parse-example-summary',
|
2016-02-17 09:09:32 +00:00
|
|
|
];
|
2007-12-01 13:37:02 +00:00
|
|
|
}
|
|
|
|
|
|
2011-07-17 16:38:24 +00:00
|
|
|
public function getHelpUrls() {
|
2017-04-04 22:52:57 +00:00
|
|
|
return 'https://www.mediawiki.org/wiki/Special:MyLanguage/API:Parsing_wikitext#parse';
|
2011-07-17 16:38:24 +00:00
|
|
|
}
|
2010-07-23 07:17:56 +00:00
|
|
|
}
|