1<?php
2/**
3 * Content handler for wiki text pages.
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License along
16 * with this program; if not, write to the Free Software Foundation, Inc.,
17 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
18 * http://www.gnu.org/copyleft/gpl.html
19 *
20 * @since 1.21
21 *
22 * @file
23 * @ingroup Content
24 */
25
26use MediaWiki\Languages\LanguageNameUtils;
27use MediaWiki\MediaWikiServices;
28
29/**
30 * Content handler for wiki text pages.
31 *
32 * @ingroup Content
33 */
34class WikitextContentHandler extends TextContentHandler {
35
36	public function __construct( $modelId = CONTENT_MODEL_WIKITEXT ) {
37		parent::__construct( $modelId, [ CONTENT_FORMAT_WIKITEXT ] );
38	}
39
40	protected function getContentClass() {
41		return WikitextContent::class;
42	}
43
44	/**
45	 * Returns a WikitextContent object representing a redirect to the given destination page.
46	 *
47	 * @param Title $destination The page to redirect to.
48	 * @param string $text Text to include in the redirect, if possible.
49	 *
50	 * @return Content
51	 *
52	 * @see ContentHandler::makeRedirectContent
53	 */
54	public function makeRedirectContent( Title $destination, $text = '' ) {
55		$optionalColon = '';
56
57		$services = MediaWikiServices::getInstance();
58		if ( $destination->getNamespace() === NS_CATEGORY ) {
59			$optionalColon = ':';
60		} else {
61			$iw = $destination->getInterwiki();
62			if ( $iw && $services
63					->getLanguageNameUtils()
64					->getLanguageName( $iw,
65						LanguageNameUtils::AUTONYMS,
66						LanguageNameUtils::DEFINED )
67			) {
68				$optionalColon = ':';
69			}
70		}
71
72		$mwRedir = $services->getMagicWordFactory()->get( 'redirect' );
73		$redirectText = $mwRedir->getSynonym( 0 ) .
74			' [[' . $optionalColon . $destination->getFullText() . ']]';
75
76		if ( $text != '' ) {
77			$redirectText .= "\n" . $text;
78		}
79
80		$class = $this->getContentClass();
81		return new $class( $redirectText );
82	}
83
84	/**
85	 * Returns true because wikitext supports redirects.
86	 *
87	 * @return bool Always true.
88	 *
89	 * @see ContentHandler::supportsRedirects
90	 */
91	public function supportsRedirects() {
92		return true;
93	}
94
95	/**
96	 * Returns true because wikitext supports sections.
97	 *
98	 * @return bool Always true.
99	 *
100	 * @see ContentHandler::supportsSections
101	 */
102	public function supportsSections() {
103		return true;
104	}
105
106	/**
107	 * Returns true, because wikitext supports caching using the
108	 * ParserCache mechanism.
109	 *
110	 * @since 1.21
111	 *
112	 * @return bool Always true.
113	 *
114	 * @see ContentHandler::isParserCacheSupported
115	 */
116	public function isParserCacheSupported() {
117		return true;
118	}
119
120	/**
121	 * @return FileContentHandler
122	 */
123	protected function getFileHandler() {
124		return new FileContentHandler();
125	}
126
127	public function getFieldsForSearchIndex( SearchEngine $engine ) {
128		$fields = parent::getFieldsForSearchIndex( $engine );
129
130		$fields['heading'] =
131			$engine->makeSearchFieldMapping( 'heading', SearchIndexField::INDEX_TYPE_TEXT );
132		$fields['heading']->setFlag( SearchIndexField::FLAG_SCORING );
133
134		$fields['auxiliary_text'] =
135			$engine->makeSearchFieldMapping( 'auxiliary_text', SearchIndexField::INDEX_TYPE_TEXT );
136
137		$fields['opening_text'] =
138			$engine->makeSearchFieldMapping( 'opening_text', SearchIndexField::INDEX_TYPE_TEXT );
139		$fields['opening_text']->setFlag(
140			SearchIndexField::FLAG_SCORING | SearchIndexField::FLAG_NO_HIGHLIGHT
141		);
142		// Until we have full first-class content handler for files, we invoke it explicitly here
143		$fields = array_merge( $fields, $this->getFileHandler()->getFieldsForSearchIndex( $engine ) );
144
145		return $fields;
146	}
147
148	public function getDataForSearchIndex(
149		WikiPage $page,
150		ParserOutput $parserOutput,
151		SearchEngine $engine
152	) {
153		$fields = parent::getDataForSearchIndex( $page, $parserOutput, $engine );
154
155		$structure = new WikiTextStructure( $parserOutput );
156		$fields['heading'] = $structure->headings();
157		// text fields
158		$fields['opening_text'] = $structure->getOpeningText();
159		$fields['text'] = $structure->getMainText(); // overwrites one from ContentHandler
160		$fields['auxiliary_text'] = $structure->getAuxiliaryText();
161		$fields['defaultsort'] = $structure->getDefaultSort();
162
163		// Until we have full first-class content handler for files, we invoke it explicitly here
164		if ( $page->getTitle()->getNamespace() === NS_FILE ) {
165			$fields = array_merge( $fields,
166					$this->getFileHandler()->getDataForSearchIndex( $page, $parserOutput, $engine ) );
167		}
168		return $fields;
169	}
170
171	/**
172	 * Returns the content's text as-is.
173	 *
174	 * @param Content $content
175	 * @param string|null $format The serialization format to check
176	 *
177	 * @return mixed
178	 */
179	public function serializeContent( Content $content, $format = null ) {
180		$this->checkFormat( $format );
181
182		// NOTE: MessageContent also uses CONTENT_MODEL_WIKITEXT, but it's not a TextContent!
183		// Perhaps MessageContent should use a separate ContentHandler instead.
184		if ( $content instanceof MessageContent ) {
185			return $content->getMessage()->plain();
186		}
187
188		return parent::serializeContent( $content, $format );
189	}
190
191}
192