MediaWiki 1.43.1
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 && strlen( $output ) > 0 ) {
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 $out->addHTML( $this->makeOutput( $rawhtml, 'expand_templates_html_output' ) );
142 }
143
144 $this->showHtmlPreview( $title, $pout, $out );
145 } else {
146 $this->makeForm();
147 }
148 }
149
158 public function onSubmitInput( array $values ) {
159 $status = Status::newGood();
160 if ( !strlen( $values['Input'] ) ) {
161 $status = Status::newFatal( 'expand_templates_input_missing' );
162 }
163 return $status;
164 }
165
169 private function makeForm() {
170 $fields = [
171 'Input' => [
172 'type' => 'textarea',
173 'label' => $this->msg( 'expand_templates_input' )->text(),
174 'rows' => 10,
175 'id' => 'input',
176 'useeditfont' => true,
177 'required' => true,
178 'autofocus' => true,
179 ],
180 'ContextTitle' => [
181 'type' => 'text',
182 'label' => $this->msg( 'expand_templates_title' )->plain(),
183 'id' => 'contexttitle',
184 'size' => 60,
185 ],
186 'RemoveComments' => [
187 'type' => 'check',
188 'label' => $this->msg( 'expand_templates_remove_comments' )->text(),
189 'id' => 'removecomments',
190 'default' => true,
191 ],
192 'RemoveNowiki' => [
193 'type' => 'check',
194 'label' => $this->msg( 'expand_templates_remove_nowiki' )->text(),
195 'id' => 'removenowiki',
196 ],
197 'GenerateXml' => [
198 'type' => 'check',
199 'label' => $this->msg( 'expand_templates_generate_xml' )->text(),
200 'id' => 'generate_xml',
201 ],
202 'GenerateRawHtml' => [
203 'type' => 'check',
204 'label' => $this->msg( 'expand_templates_generate_rawhtml' )->text(),
205 'id' => 'generate_rawhtml',
206 ],
207 ];
208
209 $form = HTMLForm::factory( 'ooui', $fields, $this->getContext() );
210 $form
211 ->setSubmitTextMsg( 'expand_templates_ok' )
212 ->setWrapperLegendMsg( 'expandtemplates' )
213 ->setHeaderHtml( $this->msg( 'expand_templates_intro' )->parse() )
214 ->setSubmitCallback( [ $this, 'onSubmitInput' ] )
215 ->showAlways();
216 }
217
225 private function makeOutput( $output, $heading = 'expand_templates_output' ) {
226 $out = "<h2>" . $this->msg( $heading )->escaped() . "</h2>\n";
227 $out .= Xml::textarea(
228 'output',
229 $output,
230 10,
231 10,
232 [
233 'id' => 'output',
234 'readonly' => 'readonly',
235 'class' => 'mw-editfont-' . $this->userOptionsLookup->getOption( $this->getUser(), 'editfont' )
236 ]
237 );
238
239 return $out;
240 }
241
249 private function showHtmlPreview( Title $title, ParserOutput $pout, OutputPage $out ) {
250 $out->addHTML( "<h2>" . $this->msg( 'expand_templates_preview' )->escaped() . "</h2>\n" );
251
252 if ( $this->getConfig()->get( MainConfigNames::RawHtml ) ) {
253 $request = $this->getRequest();
254 $user = $this->getUser();
255
256 // To prevent cross-site scripting attacks, don't show the preview if raw HTML is
257 // allowed and a valid edit token is not provided (T73111). However, MediaWiki
258 // does not currently provide logged-out users with CSRF protection; in that case,
259 // do not show the preview unless anonymous editing is allowed.
260 if ( $user->isAnon() && !$this->getAuthority()->isAllowed( 'edit' ) ) {
261 $error = [ 'expand_templates_preview_fail_html_anon' ];
262 } elseif ( !$user->matchEditToken( $request->getVal( 'wpEditToken' ), '', $request ) ) {
263 $error = [ 'expand_templates_preview_fail_html' ];
264 } else {
265 $error = false;
266 }
267
268 if ( $error ) {
269 $out->addHTML(
270 Html::errorBox(
271 $out->msg( $error )->parse(),
272 '',
273 'previewnote'
274 )
275 );
276 return;
277 }
278 }
279
280 $out->addParserOutputContent( $pout, [ 'enableSectionEditLinks' => false ] );
281 $out->addCategoryLinks( $pout->getCategoryMap() );
282 }
283
284 protected function getGroupName() {
285 return 'wiki';
286 }
287}
288
290class_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
static textarea( $name, $value='', array $attribs=[])
Convenience function to produce a <textarea> element.
Definition Html.php:849
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:143
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