. * * @file * @ingroup Skins */ declare( strict_types=1 ); namespace MediaWiki\Skins\Citizen\Partials; use DOMDocument; use DOMElement; use DOMNode; use DOMXpath; use HtmlFormatter\HtmlFormatter; use MediaWiki\MediaWikiServices; use MediaWiki\Title\Title; use Wikimedia\Parsoid\Utils\DOMCompat; use Wikimedia\Services\NoSuchServiceException; final class BodyContent extends Partial { /** * The code below is largely based on the extension MobileFrontend * All credits go to the author and contributors of the project */ /** * Class name for section wrappers */ public const SECTION_CLASS = 'citizen-section'; /** * List of tags that could be considered as section headers. * @var array */ private $topHeadingTags = [ "h1", "h2", "h3", "h4", "h5", "h6" ]; /** * Helper function to decide if the page should be formatted * * @param Title $title * @return bool */ private function shouldFormatPage( $title ) { try { $mfCxt = MediaWikiServices::getInstance()->getService( 'MobileFrontend.Context' ); // Check if page is in mobile view and let MF do the formatting return !$mfCxt->shouldDisplayMobileView(); } catch ( NoSuchServiceException $ex ) { // MobileFrontend not installed. Don't do anything } $enableSections = ( $this->getConfigValue( 'CitizenEnableCollapsibleSections' ) === true && $title->canExist() && $title->getContentModel() == CONTENT_MODEL_WIKITEXT && !$title->isMainPage() && $title->isContentPage() ); return $enableSections; } /** * Rebuild the body content * * @param string $bodyContent HTML of the body content from core * @return string html */ public function decorateBodyContent( $bodyContent ) { $title = $this->title; // Return the page if title is null if ( $title === null ) { return $bodyContent; } // Make section and sanitize the output if ( $this->shouldFormatPage( $title ) ) { $formatter = new HtmlFormatter( $bodyContent ); $doc = $formatter->getDoc(); // Make top level sections $this->makeSections( $doc, $this->getTopHeadings( $doc ) ); $formatter->filterContent(); $bodyContent = $formatter->getText(); } return $bodyContent; } /** * @param DOMNode|null $node * @return string|false Heading tag name if the node is a heading */ private function getHeadingName( $node ) { if ( !( $node instanceof DOMElement ) ) { return false; } // We accept both kinds of nodes that can be returned by getTopHeadings(): // a `