Add ParserOutputFlags::NO_TOC
Rather than suppress the TOCData in ParserOutput when __NOTOC__ is used, set a new parser output flag, NO_TOC, since some clients want to know whether there are sections present on the page irrespective of whether the UX for the Table Of Contents should be displayed/suppressed. Added OutputPage::getOutputFlag() as an @internal method for the moment; eventually we should use the same object to represent metadata in ParserOutput and OutputPage (T301020). Bug: T332243 Followup-To: Ife2126ace95ac4d9ec44f6374c63d8fc995cf034 Followup-To: Iea6426336f93c053a5977768f0785cdb46daf5bf Change-Id: Ib41e6e4926cb752826ad75d10e8692125fc0b064
This commit is contained in:
parent
0064e43837
commit
0448851e92
6 changed files with 143 additions and 30 deletions
|
|
@ -377,6 +377,11 @@ class OutputPage extends ContextSource {
|
|||
*/
|
||||
private $mEnableTOC = false;
|
||||
|
||||
/**
|
||||
* @var array<string,bool> Flags set in the ParserOutput
|
||||
*/
|
||||
private $mOutputFlags = [];
|
||||
|
||||
/**
|
||||
* @var string|null The URL to send in a <link> element with rel=license
|
||||
*/
|
||||
|
|
@ -2071,6 +2076,16 @@ class OutputPage extends ContextSource {
|
|||
return $this->tocData;
|
||||
}
|
||||
|
||||
/**
|
||||
* @internal Will be replaced by direct access to
|
||||
* ParserOutput::getOutputFlag()
|
||||
* @param string $name A flag name from ParserOutputFlags
|
||||
* @return bool
|
||||
*/
|
||||
public function getOutputFlag( string $name ): bool {
|
||||
return isset( $this->mOutputFlags[$name] );
|
||||
}
|
||||
|
||||
/**
|
||||
* Add all metadata associated with a ParserOutput object, but without the actual HTML. This
|
||||
* includes categories, language links, ResourceLoader modules, effects of certain magic words,
|
||||
|
|
@ -2106,6 +2121,8 @@ class OutputPage extends ContextSource {
|
|||
// addParserOutputMetadata() may be called multiple times, but the
|
||||
// following lines overwrite any previous data. These should
|
||||
// be migrated to an injection pattern. (T301020, T300979)
|
||||
// (Note that OutputPage::getOutputFlag() also contains this
|
||||
// information, with flags from each $parserOutput all OR'ed together.)
|
||||
$this->mNewSectionLink = $parserOutput->getNewSection();
|
||||
$this->mHideNewSectionLink = $parserOutput->getHideNewSection();
|
||||
$this->mNoGallery = $parserOutput->getNoGallery();
|
||||
|
|
@ -2219,6 +2236,16 @@ class OutputPage extends ContextSource {
|
|||
// Eventually we'll emit a deprecation message here (T293513)
|
||||
$this->mEnableTOC = true;
|
||||
}
|
||||
// Uniform handling of all boolean flags: they are OR'ed together
|
||||
// (See ParserOutput::collectMetadata())
|
||||
$flags =
|
||||
array_flip( $parserOutput->getAllFlags() ) +
|
||||
array_flip( ParserOutputFlags::cases() );
|
||||
foreach ( $flags as $name => $ignore ) {
|
||||
if ( $parserOutput->getOutputFlag( $name ) ) {
|
||||
$this->mOutputFlags[$name] = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -4583,7 +4610,8 @@ class OutputPage extends ContextSource {
|
|||
}
|
||||
|
||||
/**
|
||||
* Whether the output has a table of contents
|
||||
* Whether the output has a table of contents when the ToC is
|
||||
* rendered inline.
|
||||
* @return bool
|
||||
* @since 1.22
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -4418,16 +4418,7 @@ class Parser {
|
|||
$enoughToc = false;
|
||||
}
|
||||
|
||||
if ( $enoughToc ) {
|
||||
// Record the fact that the TOC should be shown. T294950
|
||||
// (We shouldn't be looking at ::getTOCHTML() for this because
|
||||
// eventually that will be replaced (T293513) and
|
||||
// $tocData will contain sections even if there aren't
|
||||
// $enoughToc to show.)
|
||||
$this->mOutput->setOutputFlag( ParserOutputFlags::SHOW_TOC );
|
||||
}
|
||||
|
||||
if ( $isMain && !$suppressToc && $this->mShowToc ) {
|
||||
if ( $isMain && !$suppressToc ) {
|
||||
// We generally output the section information via the API
|
||||
// even if there isn't "enough" of a ToC to merit showing
|
||||
// it -- but the "suppress TOC" parser option is set when
|
||||
|
|
@ -4435,10 +4426,26 @@ class Parser {
|
|||
// (ie, JavaScript content that might have spurious === or
|
||||
// <h2>: T307691) so we will *not* set section information
|
||||
// in that case.
|
||||
// The TOCData will also be null/unset if __NOTOC__ is
|
||||
// used on the page (and not overridden by __TOC__ or
|
||||
// __FORCETOC__).
|
||||
$this->mOutput->setTOCData( $tocData );
|
||||
|
||||
// T294950: Record a suggestion that the TOC should be shown.
|
||||
// We shouldn't be looking at ::getTOCHTML() for this because
|
||||
// that was replaced (T293513); and $tocData will contain sections
|
||||
// even if there aren't $enoughToc to show (T332243).
|
||||
// Skins are free to ignore this suggestion and implement their
|
||||
// own criteria for showing/suppressing TOC (T318186).
|
||||
if ( $enoughToc ) {
|
||||
$this->mOutput->setOutputFlag( ParserOutputFlags::SHOW_TOC );
|
||||
}
|
||||
|
||||
// If __NOTOC__ is used on the page (and not overridden by
|
||||
// __TOC__ or __FORCETOC__) set the NO_TOC flag to tell
|
||||
// the skin that although the section information is
|
||||
// valid, it should perhaps not be presented as a Table Of
|
||||
// Contents.
|
||||
if ( !$this->mShowToc ) {
|
||||
$this->mOutput->setOutputFlag( ParserOutputFlags::NO_TOC );
|
||||
}
|
||||
}
|
||||
|
||||
# split up and insert constructed headlines
|
||||
|
|
|
|||
|
|
@ -94,10 +94,22 @@ class ParserOutputFlags {
|
|||
// These flags are stored in the ParserOutput::$mFlags array
|
||||
|
||||
/**
|
||||
* @var string Show the table of contents in the skin?
|
||||
* @var string Show the table of contents in the skin? This is
|
||||
* a /suggestion/ based on whether the TOC is "large enough"
|
||||
* and other factors, and is intended mostly for skins which
|
||||
* want to match the behavior of the traditional inline ToC.
|
||||
*/
|
||||
public const SHOW_TOC = 'show-toc';
|
||||
|
||||
/**
|
||||
* @var string Suppress the table of contents in the skin?
|
||||
* This reflects the use of the __NOTOC__ magic word in the
|
||||
* article (possibly modified by __TOC__ or __FORCETOC__),
|
||||
* and represents an explicit request from the author to
|
||||
* hide the TOC.
|
||||
*/
|
||||
public const NO_TOC = 'no-toc';
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
|
|
@ -161,6 +173,7 @@ class ParserOutputFlags {
|
|||
self::NEW_SECTION,
|
||||
self::HIDE_NEW_SECTION,
|
||||
self::SHOW_TOC,
|
||||
self::NO_TOC,
|
||||
self::PREVENT_CLICKJACKING,
|
||||
self::VARY_REVISION,
|
||||
self::VARY_REVISION_ID,
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@
|
|||
|
||||
namespace MediaWiki\Skin;
|
||||
|
||||
use MediaWiki\Parser\ParserOutputFlags;
|
||||
use OutputPage;
|
||||
|
||||
/**
|
||||
|
|
@ -83,6 +84,10 @@ class SkinComponentTableOfContents implements SkinComponent {
|
|||
if ( $tocData === null ) {
|
||||
return [];
|
||||
}
|
||||
// Respect __NOTOC__
|
||||
if ( $this->output->getOutputFlag( ParserOutputFlags::NO_TOC ) ) {
|
||||
return [];
|
||||
}
|
||||
|
||||
$outputSections = $tocData->getSections();
|
||||
|
||||
|
|
|
|||
|
|
@ -881,7 +881,7 @@ __NOTOC__
|
|||
{{sections}}
|
||||
==Section 4==
|
||||
!! metadata
|
||||
flags=
|
||||
flags=no-toc
|
||||
!! html/php
|
||||
<h2><span class="mw-headline" id="Section_0">Section 0</span><span class="mw-editsection"><span class="mw-editsection-bracket">[</span><a href="/index.php?title=Parser_test&action=edit&section=1" title="Edit section: Section 0">edit</a><span class="mw-editsection-bracket">]</span></span></h2>
|
||||
<h3><span class="mw-headline" id="Section_1">Section 1</span><span class="mw-editsection"><span class="mw-editsection-bracket">[</span><a href="/index.php?title=Template:Sections&action=edit&section=T-1" title="Edit section: Section 1">edit</a><span class="mw-editsection-bracket">]</span></span></h3>
|
||||
|
|
@ -934,7 +934,7 @@ showflags
|
|||
!! wikitext
|
||||
__NOTOC__
|
||||
!! metadata
|
||||
flags=
|
||||
flags=no-toc
|
||||
!! html/php
|
||||
!! html/parsoid
|
||||
<meta property="mw:PageProp/notoc"/>
|
||||
|
|
@ -1005,7 +1005,7 @@ showflags
|
|||
__NOTOC__
|
||||
== One ==
|
||||
!! metadata
|
||||
flags=
|
||||
flags=no-toc
|
||||
!! html/php
|
||||
<h2><span class="mw-headline" id="One">One</span><span class="mw-editsection"><span class="mw-editsection-bracket">[</span><a href="/index.php?title=Parser_test&action=edit&section=1" title="Edit section: One">edit</a><span class="mw-editsection-bracket">]</span></span></h2>
|
||||
!! html/parsoid
|
||||
|
|
@ -1102,7 +1102,7 @@ __NOTOC__
|
|||
== Three ==
|
||||
=== Four ===
|
||||
!! metadata
|
||||
flags=
|
||||
flags=no-toc
|
||||
!! html/php
|
||||
<h2><span class="mw-headline" id="One">One</span><span class="mw-editsection"><span class="mw-editsection-bracket">[</span><a href="/index.php?title=Parser_test&action=edit&section=1" title="Edit section: One">edit</a><span class="mw-editsection-bracket">]</span></span></h2>
|
||||
<h3><span class="mw-headline" id="Two">Two</span><span class="mw-editsection"><span class="mw-editsection-bracket">[</span><a href="/index.php?title=Parser_test&action=edit&section=2" title="Edit section: Two">edit</a><span class="mw-editsection-bracket">]</span></span></h3>
|
||||
|
|
|
|||
|
|
@ -1174,14 +1174,20 @@ class OutputPageTest extends MediaWikiIntegrationTestCase {
|
|||
$op = $this->newInstance();
|
||||
|
||||
$this->assertFalse( $op->showNewSectionLink() );
|
||||
$this->assertFalse( $op->getOutputFlag( ParserOutputFlags::NEW_SECTION ) );
|
||||
|
||||
$pOut1 = $this->createParserOutputStub( 'getNewSection', true );
|
||||
$pOut1 = $this->createParserOutputStubWithFlags(
|
||||
[ 'getNewSection' => true ], [ ParserOutputFlags::NEW_SECTION ]
|
||||
);
|
||||
$op->addParserOutputMetadata( $pOut1 );
|
||||
$this->assertTrue( $op->showNewSectionLink() );
|
||||
$this->assertTrue( $op->getOutputFlag( ParserOutputFlags::NEW_SECTION ) );
|
||||
|
||||
$pOut2 = $this->createParserOutputStub( 'getNewSection', false );
|
||||
$op->addParserOutput( $pOut2 );
|
||||
$this->assertFalse( $op->showNewSectionLink() );
|
||||
// Note that flags are OR'ed together, and not reset.
|
||||
$this->assertTrue( $op->getOutputFlag( ParserOutputFlags::NEW_SECTION ) );
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -1193,14 +1199,20 @@ class OutputPageTest extends MediaWikiIntegrationTestCase {
|
|||
$op = $this->newInstance();
|
||||
|
||||
$this->assertFalse( $op->forceHideNewSectionLink() );
|
||||
$this->assertFalse( $op->getOutputFlag( ParserOutputFlags::HIDE_NEW_SECTION ) );
|
||||
|
||||
$pOut1 = $this->createParserOutputStub( 'getHideNewSection', true );
|
||||
$pOut1 = $this->createParserOutputStubWithFlags(
|
||||
[ 'getHideNewSection' => true ], [ ParserOutputFlags::HIDE_NEW_SECTION ]
|
||||
);
|
||||
$op->addParserOutputMetadata( $pOut1 );
|
||||
$this->assertTrue( $op->forceHideNewSectionLink() );
|
||||
$this->assertTrue( $op->getOutputFlag( ParserOutputFlags::HIDE_NEW_SECTION ) );
|
||||
|
||||
$pOut2 = $this->createParserOutputStub( 'getHideNewSection', false );
|
||||
$op->addParserOutput( $pOut2 );
|
||||
$this->assertFalse( $op->forceHideNewSectionLink() );
|
||||
// Note that flags are OR'ed together, and not reset.
|
||||
$this->assertTrue( $op->getOutputFlag( ParserOutputFlags::HIDE_NEW_SECTION ) );
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -1762,6 +1774,19 @@ class OutputPageTest extends MediaWikiIntegrationTestCase {
|
|||
} elseif ( count( $args ) === 2 ) {
|
||||
$retVals = [ $args[0] => $args[1] ];
|
||||
}
|
||||
return $this->createParserOutputStubWithFlags( $retVals, [] );
|
||||
}
|
||||
|
||||
/**
|
||||
* First argument is an array
|
||||
* [ $methodName => $returnValue, $methodName => $returnValue, ... ]
|
||||
* Second argument is an array of parser flags for which ::getOutputFlag()
|
||||
* should return 'TRUE'.
|
||||
* @param array $retVals
|
||||
* @param array $flags
|
||||
* @return ParserOutput
|
||||
*/
|
||||
private function createParserOutputStubWithFlags( array $retVals, array $flags ): ParserOutput {
|
||||
$pOut = $this->createMock( ParserOutput::class );
|
||||
foreach ( $retVals as $method => $retVal ) {
|
||||
$pOut->method( $method )->willReturn( $retVal );
|
||||
|
|
@ -1786,6 +1811,10 @@ class OutputPageTest extends MediaWikiIntegrationTestCase {
|
|||
$pOut->method( $method )->willReturn( [] );
|
||||
}
|
||||
|
||||
$pOut->method( 'getOutputFlag' )->willReturnCallback( static function ( $name ) use ( $flags ) {
|
||||
return in_array( $name, $flags, true );
|
||||
} );
|
||||
|
||||
return $pOut;
|
||||
}
|
||||
|
||||
|
|
@ -2042,14 +2071,20 @@ class OutputPageTest extends MediaWikiIntegrationTestCase {
|
|||
public function testNoGallery() {
|
||||
$op = $this->newInstance();
|
||||
$this->assertFalse( $op->mNoGallery );
|
||||
$this->assertFalse( $op->getOutputFlag( ParserOutputFlags::NO_GALLERY ) );
|
||||
|
||||
$stubPO1 = $this->createParserOutputStub( 'getNoGallery', true );
|
||||
$stubPO1 = $this->createParserOutputStubWithFlags(
|
||||
[ 'getNoGallery' => true ], [ ParserOutputFlags::NO_GALLERY ]
|
||||
);
|
||||
$op->addParserOutputMetadata( $stubPO1 );
|
||||
$this->assertTrue( $op->mNoGallery );
|
||||
$this->assertTrue( $op->getOutputFlag( ParserOutputFlags::NO_GALLERY ) );
|
||||
|
||||
$stubPO2 = $this->createParserOutputStub( 'getNoGallery', false );
|
||||
$op->addParserOutput( $stubPO2 );
|
||||
$this->assertFalse( $op->mNoGallery );
|
||||
// Note that flags are OR'ed together, and not reset.
|
||||
$this->assertTrue( $op->getOutputFlag( ParserOutputFlags::NO_GALLERY ) );
|
||||
}
|
||||
|
||||
private static $parserOutputHookCalled;
|
||||
|
|
@ -2136,15 +2171,19 @@ class OutputPageTest extends MediaWikiIntegrationTestCase {
|
|||
$op = $this->newInstance();
|
||||
$this->assertSame( '', $op->getHTML() );
|
||||
$this->assertFalse( $op->showNewSectionLink() );
|
||||
$this->assertFalse( $op->getOutputFlag( ParserOutputFlags::NEW_SECTION ) );
|
||||
|
||||
$pOut = $this->createParserOutputStub( [
|
||||
$pOut = $this->createParserOutputStubWithFlags( [
|
||||
'getText' => '<some text>',
|
||||
'getNewSection' => true,
|
||||
], [
|
||||
ParserOutputFlags::NEW_SECTION,
|
||||
] );
|
||||
|
||||
$op->addParserOutput( $pOut );
|
||||
$this->assertSame( '<some text>', $op->getHTML() );
|
||||
$this->assertTrue( $op->showNewSectionLink() );
|
||||
$this->assertTrue( $op->getOutputFlag( ParserOutputFlags::NEW_SECTION ) );
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -3162,24 +3201,24 @@ class OutputPageTest extends MediaWikiIntegrationTestCase {
|
|||
public function testIsTOCEnabled() {
|
||||
$op = $this->newInstance();
|
||||
$this->assertFalse( $op->isTOCEnabled() );
|
||||
$this->assertFalse( $op->getOutputFlag( ParserOutputFlags::SHOW_TOC ) );
|
||||
|
||||
$pOut1 = $this->createParserOutputStub();
|
||||
$pOut1->method( 'getOutputFlag' )->willReturnMap( [
|
||||
[ ParserOutputFlags::SHOW_TOC, false ],
|
||||
] );
|
||||
$op->addParserOutputMetadata( $pOut1 );
|
||||
$this->assertFalse( $op->isTOCEnabled() );
|
||||
$this->assertFalse( $op->getOutputFlag( ParserOutputFlags::SHOW_TOC ) );
|
||||
|
||||
$pOut2 = $this->createParserOutputStub();
|
||||
$pOut2->method( 'getOutputFlag' )->willReturnMap( [
|
||||
[ ParserOutputFlags::SHOW_TOC, true ],
|
||||
] );
|
||||
$pOut2 = $this->createParserOutputStubWithFlags(
|
||||
[], [ ParserOutputFlags::SHOW_TOC ]
|
||||
);
|
||||
$op->addParserOutput( $pOut2 );
|
||||
$this->assertTrue( $op->isTOCEnabled() );
|
||||
$this->assertTrue( $op->getOutputFlag( ParserOutputFlags::SHOW_TOC ) );
|
||||
|
||||
// The parser output doesn't disable the TOC after it was enabled
|
||||
$op->addParserOutputMetadata( $pOut1 );
|
||||
$this->assertTrue( $op->isTOCEnabled() );
|
||||
$this->assertTrue( $op->getOutputFlag( ParserOutputFlags::SHOW_TOC ) );
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -3213,6 +3252,27 @@ class OutputPageTest extends MediaWikiIntegrationTestCase {
|
|||
$this->assertTrue( $op->isTOCEnabled() );
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers OutputPage::addParserOutputMetadata
|
||||
* @covers OutputPage::addParserOutput
|
||||
*/
|
||||
public function testNoTOC() {
|
||||
$op = $this->newInstance();
|
||||
$this->assertFalse( $op->getOutputFlag( ParserOutputFlags::NO_TOC ) );
|
||||
|
||||
$stubPO1 = $this->createParserOutputStubWithFlags(
|
||||
[], [ ParserOutputFlags::NO_TOC ]
|
||||
);
|
||||
$op->addParserOutputMetadata( $stubPO1 );
|
||||
$this->assertTrue( $op->getOutputFlag( ParserOutputFlags::NO_TOC ) );
|
||||
|
||||
$stubPO2 = $this->createParserOutputStub();
|
||||
$this->assertFalse( $stubPO2->getOutputFlag( ParserOutputFlags::NO_TOC ) );
|
||||
$op->addParserOutput( $stubPO2 );
|
||||
// Note that flags are OR'ed together, and not reset.
|
||||
$this->assertTrue( $op->getOutputFlag( ParserOutputFlags::NO_TOC ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider providePreloadLinkHeaders
|
||||
* @covers \MediaWiki\ResourceLoader\SkinModule
|
||||
|
|
|
|||
Loading…
Reference in a new issue