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
59 public function __construct(
60 ParserFactory $parserFactory,
61 UserOptionsLookup $userOptionsLookup,
62 TidyDriverBase $tidy
63 ) {
64 parent::__construct( 'ExpandTemplates' );
65 $this->parserFactory = $parserFactory;
66 $this->userOptionsLookup = $userOptionsLookup;
67 $this->tidy = $tidy;
68 }
69
74 public function execute( $subpage ) {
75 $this->setHeaders();
76 $this->addHelpLink( 'Help:ExpandTemplates' );
77
78 $request = $this->getRequest();
79 $input = $request->getText( 'wpInput' );
80
81 if ( strlen( $input ) ) {
82 $removeComments = $request->getBool( 'wpRemoveComments', false );
83 $removeNowiki = $request->getBool( 'wpRemoveNowiki', false );
84 $generateXML = $request->getBool( 'wpGenerateXml' );
85 $generateRawHtml = $request->getBool( 'wpGenerateRawHtml' );
86
87 $options = ParserOptions::newFromContext( $this->getContext() );
88 $options->setRemoveComments( $removeComments );
89 $options->setMaxIncludeSize( self::MAX_INCLUDE_SIZE );
90
91 $titleStr = $request->getText( 'wpContextTitle' );
92 $title = Title::newFromText( $titleStr );
93 if ( !$title ) {
94 $title = $this->getPageTitle();
95 $options->setTargetLanguage( $this->getContentLanguage() );
96 }
97
98 $parser = $this->parserFactory->getInstance();
99 if ( $generateXML ) {
100 $parser->startExternalParse( $title, $options, Parser::OT_PREPROCESS );
101 $dom = $parser->preprocessToDom( $input );
102
103 if ( method_exists( $dom, 'saveXML' ) ) {
104 // @phan-suppress-next-line PhanUndeclaredMethod
105 $xml = $dom->saveXML();
106 } else {
107 // @phan-suppress-next-line PhanUndeclaredMethod
108 $xml = $dom->__toString();
109 }
110 }
111
112 $output = $parser->preprocess( $input, $title, $options );
113 $this->makeForm();
114
115 $out = $this->getOutput();
116 if ( $generateXML && strlen( $output ) > 0 ) {
117 // @phan-suppress-next-line PhanPossiblyUndeclaredVariable xml is set when used
118 $out->addHTML( $this->makeOutput( $xml, 'expand_templates_xml_output' ) );
119 }
120
121 $tmp = $this->makeOutput( $output );
122
123 if ( $removeNowiki ) {
124 $tmp = preg_replace(
125 [ '_&lt;nowiki&gt;_', '_&lt;/nowiki&gt;_', '_&lt;nowiki */&gt;_' ],
126 '',
127 $tmp
128 );
129 }
130
131 $tmp = $this->tidy->tidy( $tmp );
132
133 $out->addHTML( $tmp );
134
135 $pout = $parser->parse( $output, $title, $options );
136 $rawhtml = $pout->getText( [ 'enableSectionEditLinks' => false ] );
137 if ( $generateRawHtml && strlen( $rawhtml ) > 0 ) {
138 // @phan-suppress-next-line SecurityCheck-DoubleEscaped Wanted here to display the html
139 $out->addHTML( $this->makeOutput( $rawhtml, 'expand_templates_html_output' ) );
140 }
141
142 $this->showHtmlPreview( $title, $pout, $out );
143 } else {
144 $this->makeForm();
145 }
146 }
147
156 public function onSubmitInput( array $values ) {
157 $status = Status::newGood();
158 if ( !strlen( $values['Input'] ) ) {
159 $status = Status::newFatal( 'expand_templates_input_missing' );
160 }
161 return $status;
162 }
163
167 private function makeForm() {
168 $fields = [
169 'ContextTitle' => [
170 'type' => 'text',
171 'label' => $this->msg( 'expand_templates_title' )->plain(),
172 'id' => 'contexttitle',
173 'size' => 60,
174 'autofocus' => true,
175 ],
176 'Input' => [
177 'type' => 'textarea',
178 'label' => $this->msg( 'expand_templates_input' )->text(),
179 'rows' => 10,
180 'id' => 'input',
181 'useeditfont' => true,
182 ],
183 'RemoveComments' => [
184 'type' => 'check',
185 'label' => $this->msg( 'expand_templates_remove_comments' )->text(),
186 'id' => 'removecomments',
187 'default' => true,
188 ],
189 'RemoveNowiki' => [
190 'type' => 'check',
191 'label' => $this->msg( 'expand_templates_remove_nowiki' )->text(),
192 'id' => 'removenowiki',
193 ],
194 'GenerateXml' => [
195 'type' => 'check',
196 'label' => $this->msg( 'expand_templates_generate_xml' )->text(),
197 'id' => 'generate_xml',
198 ],
199 'GenerateRawHtml' => [
200 'type' => 'check',
201 'label' => $this->msg( 'expand_templates_generate_rawhtml' )->text(),
202 'id' => 'generate_rawhtml',
203 ],
204 ];
205
206 $form = HTMLForm::factory( 'ooui', $fields, $this->getContext() );
207 $form
208 ->setSubmitTextMsg( 'expand_templates_ok' )
209 ->setWrapperLegendMsg( 'expandtemplates' )
210 ->setHeaderHtml( $this->msg( 'expand_templates_intro' )->parse() )
211 ->setSubmitCallback( [ $this, 'onSubmitInput' ] )
212 ->showAlways();
213 }
214
222 private function makeOutput( $output, $heading = 'expand_templates_output' ) {
223 $out = "<h2>" . $this->msg( $heading )->escaped() . "</h2>\n";
224 $out .= Xml::textarea(
225 'output',
226 $output,
227 10,
228 10,
229 [
230 'id' => 'output',
231 'readonly' => 'readonly',
232 'class' => 'mw-editfont-' . $this->userOptionsLookup->getOption( $this->getUser(), 'editfont' )
233 ]
234 );
235
236 return $out;
237 }
238
246 private function showHtmlPreview( Title $title, ParserOutput $pout, OutputPage $out ) {
247 $out->addHTML( "<h2>" . $this->msg( 'expand_templates_preview' )->escaped() . "</h2>\n" );
248
249 if ( $this->getConfig()->get( MainConfigNames::RawHtml ) ) {
250 $request = $this->getRequest();
251 $user = $this->getUser();
252
253 // To prevent cross-site scripting attacks, don't show the preview if raw HTML is
254 // allowed and a valid edit token is not provided (T73111). However, MediaWiki
255 // does not currently provide logged-out users with CSRF protection; in that case,
256 // do not show the preview unless anonymous editing is allowed.
257 if ( $user->isAnon() && !$this->getAuthority()->isAllowed( 'edit' ) ) {
258 $error = [ 'expand_templates_preview_fail_html_anon' ];
259 } elseif ( !$user->matchEditToken( $request->getVal( 'wpEditToken' ), '', $request ) ) {
260 $error = [ 'expand_templates_preview_fail_html' ];
261 } else {
262 $error = false;
263 }
264
265 if ( $error ) {
266 $out->addHTML(
267 Html::errorBox(
268 $out->msg( $error )->parse(),
269 '',
270 'previewnote'
271 )
272 );
273 return;
274 }
275 }
276
277 $out->addParserOutputContent( $pout, [ 'enableSectionEditLinks' => false ] );
278 $out->setCategoryLinks( $pout->getCategoryMap() );
279 }
280
281 protected function getGroupName() {
282 return 'wiki';
283 }
284}
285
287class_alias( SpecialExpandTemplates::class, 'SpecialExpandTemplates' );
Object handling generic submission, CSRF protection, layout and other logic for UI forms in a reusabl...
Definition HTMLForm.php:206
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:854
A class containing constants representing the names of configuration variables.
const RawHtml
Name constant for the RawHtml setting, for use with Config::get()
This is one of the Core classes and should be read at least once by any new developers.
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:156
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
Set options of the Parser.