MediaWiki master
SpecialExpandTemplates.php
Go to the documentation of this file.
1<?php
21namespace MediaWiki\Specials;
22
37
46
48 private const MAX_INCLUDE_SIZE = 50_000_000;
49
50 private ParserFactory $parserFactory;
51 private UserOptionsLookup $userOptionsLookup;
52 private TidyDriverBase $tidy;
53
54 public function __construct(
55 ParserFactory $parserFactory,
56 UserOptionsLookup $userOptionsLookup,
57 TidyDriverBase $tidy
58 ) {
59 parent::__construct( 'ExpandTemplates' );
60 $this->parserFactory = $parserFactory;
61 $this->userOptionsLookup = $userOptionsLookup;
62 $this->tidy = $tidy;
63 }
64
69 public function execute( $subpage ) {
70 $this->setHeaders();
71 $this->addHelpLink( 'Help:ExpandTemplates' );
72
73 $request = $this->getRequest();
74 $input = $request->getText( 'wpInput' );
75
76 if ( $input !== '' ) {
77 $removeComments = $request->getBool( 'wpRemoveComments', false );
78 $removeNowiki = $request->getBool( 'wpRemoveNowiki', false );
79 $generateXML = $request->getBool( 'wpGenerateXml' );
80 $generateRawHtml = $request->getBool( 'wpGenerateRawHtml' );
81
82 $options = ParserOptions::newFromContext( $this->getContext() );
83 $options->setRemoveComments( $removeComments );
84 $options->setMaxIncludeSize( self::MAX_INCLUDE_SIZE );
85
86 $titleStr = $request->getText( 'wpContextTitle' );
87 $title = Title::newFromText( $titleStr );
88 if ( !$title ) {
89 $title = $this->getPageTitle();
90 $options->setTargetLanguage( $this->getContentLanguage() );
91 }
92
93 $parser = $this->parserFactory->getInstance();
94 if ( $generateXML ) {
95 $parser->startExternalParse( $title, $options, Parser::OT_PREPROCESS );
96 $dom = $parser->preprocessToDom( $input );
97
98 if ( method_exists( $dom, 'saveXML' ) ) {
99 // @phan-suppress-next-line PhanUndeclaredMethod
100 $xml = $dom->saveXML();
101 } else {
102 // @phan-suppress-next-line PhanUndeclaredMethod
103 $xml = $dom->__toString();
104 }
105 }
106
107 $output = $parser->preprocess( $input, $title, $options );
108 $this->makeForm();
109
110 $out = $this->getOutput();
111 if ( $generateXML ) {
112 // @phan-suppress-next-line PhanPossiblyUndeclaredVariable xml is set when used
113 $out->addHTML( $this->makeOutput( $xml, 'expand_templates_xml_output' ) );
114 }
115
116 $tmp = $this->makeOutput( $output );
117
118 if ( $removeNowiki ) {
119 $tmp = preg_replace(
120 [ '_&lt;nowiki&gt;_', '_&lt;/nowiki&gt;_', '_&lt;nowiki */&gt;_' ],
121 '',
122 $tmp
123 );
124 }
125
126 $tmp = $this->tidy->tidy( $tmp );
127
128 $out->addHTML( $tmp );
129
130 $pout = $parser->parse( $output, $title, $options );
131 // TODO T371008 consider if using the Content framework makes sense instead of creating the pipeline
132 $rawhtml = MediaWikiServices::getInstance()->getDefaultOutputPipeline()
133 ->run( $pout, $options, [ 'enableSectionEditLinks' => false ] )->getContentHolderText();
134 if ( $generateRawHtml && $rawhtml !== '' ) {
135 $out->addHTML( $this->makeOutput( $rawhtml, 'expand_templates_html_output' ) );
136 }
137
138 $this->showHtmlPreview( $title, $pout, $options, $out );
139 } else {
140 $this->makeForm();
141 }
142 }
143
152 private function onSubmitInput( array $values ) {
153 $status = Status::newGood();
154 if ( $values['Input'] === '' ) {
155 $status = Status::newFatal( 'expand_templates_input_missing' );
156 }
157 return $status;
158 }
159
163 private function makeForm() {
164 $fields = [
165 'Input' => [
166 'type' => 'textarea',
167 'label' => $this->msg( 'expand_templates_input' )->text(),
168 'rows' => 10,
169 'id' => 'input',
170 'useeditfont' => true,
171 'required' => true,
172 'autofocus' => true,
173 ],
174 'ContextTitle' => [
175 'type' => 'text',
176 'label' => $this->msg( 'expand_templates_title' )->plain(),
177 'id' => 'contexttitle',
178 'size' => 60,
179 ],
180 'RemoveComments' => [
181 'type' => 'check',
182 'label' => $this->msg( 'expand_templates_remove_comments' )->text(),
183 'id' => 'removecomments',
184 'default' => true,
185 ],
186 'RemoveNowiki' => [
187 'type' => 'check',
188 'label' => $this->msg( 'expand_templates_remove_nowiki' )->text(),
189 'id' => 'removenowiki',
190 ],
191 'GenerateXml' => [
192 'type' => 'check',
193 'label' => $this->msg( 'expand_templates_generate_xml' )->text(),
194 'id' => 'generate_xml',
195 ],
196 'GenerateRawHtml' => [
197 'type' => 'check',
198 'label' => $this->msg( 'expand_templates_generate_rawhtml' )->text(),
199 'id' => 'generate_rawhtml',
200 ],
201 ];
202
203 $form = HTMLForm::factory( 'ooui', $fields, $this->getContext() );
204 $form
205 ->setSubmitTextMsg( 'expand_templates_ok' )
206 ->setWrapperLegendMsg( 'expandtemplates' )
207 ->setHeaderHtml( $this->msg( 'expand_templates_intro' )->parse() )
208 ->setSubmitCallback( $this->onSubmitInput( ... ) )
209 ->showAlways();
210 }
211
219 private function makeOutput( $output, $heading = 'expand_templates_output' ) {
220 $out = "<h2>" . $this->msg( $heading )->escaped() . "</h2>\n";
221 $out .= Html::textarea(
222 'output',
223 $output,
224 [
225 // #output is used by CodeMirror (T384148)
226 'id' => $heading === 'expand_templates_output' ? 'output' : $heading,
227 'cols' => 10,
228 'rows' => 10,
229 'readonly' => 'readonly',
230 'class' => 'mw-editfont-' . $this->userOptionsLookup->getOption( $this->getUser(), 'editfont' )
231 ]
232 );
233
234 return $out;
235 }
236
245 private function showHtmlPreview( Title $title, ParserOutput $pout, ParserOptions $popts, OutputPage $out ) {
246 $out->addHTML( "<h2>" . $this->msg( 'expand_templates_preview' )->escaped() . "</h2>\n" );
247
248 if ( $this->getConfig()->get( MainConfigNames::RawHtml ) ) {
249 $request = $this->getRequest();
250 $user = $this->getUser();
251
252 // To prevent cross-site scripting attacks, don't show the preview if raw HTML is
253 // allowed and a valid edit token is not provided (T73111). However, MediaWiki
254 // does not currently provide logged-out users with CSRF protection; in that case,
255 // do not show the preview unless anonymous editing is allowed.
256 if ( $user->isAnon() && !$this->getAuthority()->isAllowed( 'edit' ) ) {
257 $error = [ 'expand_templates_preview_fail_html_anon' ];
258 } elseif ( !$user->matchEditToken( $request->getVal( 'wpEditToken' ), '', $request ) ) {
259 $error = [ 'expand_templates_preview_fail_html' ];
260 } else {
261 $error = false;
262 }
263
264 if ( $error ) {
265 $out->addHTML(
266 Html::errorBox(
267 $out->msg( $error )->parse(),
268 '',
269 'previewnote'
270 )
271 );
272 return;
273 }
274 }
275
276 $out->addParserOutputContent( $pout, $popts, [ 'enableSectionEditLinks' => false ] );
277 $out->addCategoryLinks( $pout->getCategoryMap() );
278 }
279
280 protected function getGroupName() {
281 return 'wiki';
282 }
283}
284
286class_alias( SpecialExpandTemplates::class, 'SpecialExpandTemplates' );
Object handling generic submission, CSRF protection, layout and other logic for UI forms in a reusabl...
Definition HTMLForm.php:209
This class is a collection of static functions that serve two purposes:
Definition Html.php:57
A class containing constants representing the names of configuration variables.
const RawHtml
Name constant for the RawHtml setting, for use with Config::get()
Service locator for MediaWiki core services.
static getInstance()
Returns the global default instance of the top level service locator.
This is one of the Core classes and should be read at least once by any new developers.
Set options of the Parser.
ParserOutput is a rendering of a Content object or a message.
PHP Parser - Processes wiki markup (which uses a more user-friendly syntax, such as "[[link]]" for ma...
Definition Parser.php:147
Parent class for all special pages.
setHeaders()
Sets headers - this should be called from the execute() method of all derived classes!
getUser()
Shortcut to get the User executing this instance.
getPageTitle( $subpage=false)
Get a self-referential title object.
getConfig()
Shortcut to get main config object.
getContext()
Gets the context this SpecialPage is executed in.
getRequest()
Get the WebRequest being used for this instance.
msg( $key,... $params)
Wrapper around wfMessage that sets the current context.
getOutput()
Get the OutputPage being used for this instance.
getContentLanguage()
Shortcut to get content language.
addHelpLink( $to, $overrideBaseUrl=false)
Adds help link with an icon via page indicators.
A special page to enter wikitext and expands its templates, parser functions, and variables,...
__construct(ParserFactory $parserFactory, UserOptionsLookup $userOptionsLookup, TidyDriverBase $tidy)
getGroupName()
Under which header this special page is listed in Special:SpecialPages See messages 'specialpages-gro...
Generic operation result class Has warning/error list, boolean status and arbitrary value.
Definition Status.php:54
Base class for HTML cleanup utilities.
Represents a title within MediaWiki.
Definition Title.php:78
Provides access to user options.