MediaWiki master
SpecialExpandTemplates.php
Go to the documentation of this file.
1<?php
21namespace MediaWiki\Specials;
22
38
47
49 private const MAX_INCLUDE_SIZE = 50_000_000;
50
51 private ParserFactory $parserFactory;
52 private UserOptionsLookup $userOptionsLookup;
53 private TidyDriverBase $tidy;
54
60 public function __construct(
61 ParserFactory $parserFactory,
62 UserOptionsLookup $userOptionsLookup,
63 TidyDriverBase $tidy
64 ) {
65 parent::__construct( 'ExpandTemplates' );
66 $this->parserFactory = $parserFactory;
67 $this->userOptionsLookup = $userOptionsLookup;
68 $this->tidy = $tidy;
69 }
70
75 public function execute( $subpage ) {
76 $this->setHeaders();
77 $this->addHelpLink( 'Help:ExpandTemplates' );
78
79 $request = $this->getRequest();
80 $input = $request->getText( 'wpInput' );
81
82 if ( strlen( $input ) ) {
83 $removeComments = $request->getBool( 'wpRemoveComments', false );
84 $removeNowiki = $request->getBool( 'wpRemoveNowiki', false );
85 $generateXML = $request->getBool( 'wpGenerateXml' );
86 $generateRawHtml = $request->getBool( 'wpGenerateRawHtml' );
87
88 $options = ParserOptions::newFromContext( $this->getContext() );
89 $options->setRemoveComments( $removeComments );
90 $options->setMaxIncludeSize( self::MAX_INCLUDE_SIZE );
91
92 $titleStr = $request->getText( 'wpContextTitle' );
93 $title = Title::newFromText( $titleStr );
94 if ( !$title ) {
95 $title = $this->getPageTitle();
96 $options->setTargetLanguage( $this->getContentLanguage() );
97 }
98
99 $parser = $this->parserFactory->getInstance();
100 if ( $generateXML ) {
101 $parser->startExternalParse( $title, $options, Parser::OT_PREPROCESS );
102 $dom = $parser->preprocessToDom( $input );
103
104 if ( method_exists( $dom, 'saveXML' ) ) {
105 // @phan-suppress-next-line PhanUndeclaredMethod
106 $xml = $dom->saveXML();
107 } else {
108 // @phan-suppress-next-line PhanUndeclaredMethod
109 $xml = $dom->__toString();
110 }
111 }
112
113 $output = $parser->preprocess( $input, $title, $options );
114 $this->makeForm();
115
116 $out = $this->getOutput();
117 if ( $generateXML ) {
118 // @phan-suppress-next-line PhanPossiblyUndeclaredVariable xml is set when used
119 $out->addHTML( $this->makeOutput( $xml, 'expand_templates_xml_output' ) );
120 }
121
122 $tmp = $this->makeOutput( $output );
123
124 if ( $removeNowiki ) {
125 $tmp = preg_replace(
126 [ '_&lt;nowiki&gt;_', '_&lt;/nowiki&gt;_', '_&lt;nowiki */&gt;_' ],
127 '',
128 $tmp
129 );
130 }
131
132 $tmp = $this->tidy->tidy( $tmp );
133
134 $out->addHTML( $tmp );
135
136 $pout = $parser->parse( $output, $title, $options );
137 // TODO T371008 consider if using the Content framework makes sense instead of creating the pipeline
138 $rawhtml = MediaWikiServices::getInstance()->getDefaultOutputPipeline()
139 ->run( $pout, $options, [ 'enableSectionEditLinks' => false ] )->getContentHolderText();
140 if ( $generateRawHtml && strlen( $rawhtml ) > 0 ) {
141 // @phan-suppress-next-line SecurityCheck-DoubleEscaped Wanted here to display the html
142 $out->addHTML( $this->makeOutput( $rawhtml, 'expand_templates_html_output' ) );
143 }
144
145 $this->showHtmlPreview( $title, $pout, $out );
146 } else {
147 $this->makeForm();
148 }
149 }
150
159 public function onSubmitInput( array $values ) {
160 $status = Status::newGood();
161 if ( !strlen( $values['Input'] ) ) {
162 $status = Status::newFatal( 'expand_templates_input_missing' );
163 }
164 return $status;
165 }
166
170 private function makeForm() {
171 $fields = [
172 'Input' => [
173 'type' => 'textarea',
174 'label' => $this->msg( 'expand_templates_input' )->text(),
175 'rows' => 10,
176 'id' => 'input',
177 'useeditfont' => true,
178 'required' => true,
179 'autofocus' => true,
180 ],
181 'ContextTitle' => [
182 'type' => 'text',
183 'label' => $this->msg( 'expand_templates_title' )->plain(),
184 'id' => 'contexttitle',
185 'size' => 60,
186 ],
187 'RemoveComments' => [
188 'type' => 'check',
189 'label' => $this->msg( 'expand_templates_remove_comments' )->text(),
190 'id' => 'removecomments',
191 'default' => true,
192 ],
193 'RemoveNowiki' => [
194 'type' => 'check',
195 'label' => $this->msg( 'expand_templates_remove_nowiki' )->text(),
196 'id' => 'removenowiki',
197 ],
198 'GenerateXml' => [
199 'type' => 'check',
200 'label' => $this->msg( 'expand_templates_generate_xml' )->text(),
201 'id' => 'generate_xml',
202 ],
203 'GenerateRawHtml' => [
204 'type' => 'check',
205 'label' => $this->msg( 'expand_templates_generate_rawhtml' )->text(),
206 'id' => 'generate_rawhtml',
207 ],
208 ];
209
210 $form = HTMLForm::factory( 'ooui', $fields, $this->getContext() );
211 $form
212 ->setSubmitTextMsg( 'expand_templates_ok' )
213 ->setWrapperLegendMsg( 'expandtemplates' )
214 ->setHeaderHtml( $this->msg( 'expand_templates_intro' )->parse() )
215 ->setSubmitCallback( [ $this, 'onSubmitInput' ] )
216 ->showAlways();
217 }
218
226 private function makeOutput( $output, $heading = 'expand_templates_output' ) {
227 $out = "<h2>" . $this->msg( $heading )->escaped() . "</h2>\n";
228 $out .= Xml::textarea(
229 'output',
230 $output,
231 10,
232 10,
233 [
234 'id' => 'output',
235 'readonly' => 'readonly',
236 'class' => 'mw-editfont-' . $this->userOptionsLookup->getOption( $this->getUser(), 'editfont' )
237 ]
238 );
239
240 return $out;
241 }
242
250 private function showHtmlPreview( Title $title, ParserOutput $pout, OutputPage $out ) {
251 $out->addHTML( "<h2>" . $this->msg( 'expand_templates_preview' )->escaped() . "</h2>\n" );
252
253 if ( $this->getConfig()->get( MainConfigNames::RawHtml ) ) {
254 $request = $this->getRequest();
255 $user = $this->getUser();
256
257 // To prevent cross-site scripting attacks, don't show the preview if raw HTML is
258 // allowed and a valid edit token is not provided (T73111). However, MediaWiki
259 // does not currently provide logged-out users with CSRF protection; in that case,
260 // do not show the preview unless anonymous editing is allowed.
261 if ( $user->isAnon() && !$this->getAuthority()->isAllowed( 'edit' ) ) {
262 $error = [ 'expand_templates_preview_fail_html_anon' ];
263 } elseif ( !$user->matchEditToken( $request->getVal( 'wpEditToken' ), '', $request ) ) {
264 $error = [ 'expand_templates_preview_fail_html' ];
265 } else {
266 $error = false;
267 }
268
269 if ( $error ) {
270 $out->addHTML(
271 Html::errorBox(
272 $out->msg( $error )->parse(),
273 '',
274 'previewnote'
275 )
276 );
277 return;
278 }
279 }
280
281 $out->addParserOutputContent( $pout, [ 'enableSectionEditLinks' => false ] );
282 $out->addCategoryLinks( $pout->getCategoryMap() );
283 }
284
285 protected function getGroupName() {
286 return 'wiki';
287 }
288}
289
291class_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:56
static textarea( $name, $value='', array $attribs=[])
Convenience function to produce a <textarea> element.
Definition Html.php:867
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:145
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...
onSubmitInput(array $values)
Callback for the HTMLForm used in self::makeForm.
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.
Module of static functions for generating XML.
Definition Xml.php:37