MediaWiki master
SpecialExpandTemplates.php
Go to the documentation of this file.
1<?php
7namespace MediaWiki\Specials;
8
23
32
34 private const MAX_INCLUDE_SIZE = 50_000_000;
35
36 private ParserFactory $parserFactory;
37 private UserOptionsLookup $userOptionsLookup;
38 private TidyDriverBase $tidy;
39
40 public function __construct(
41 ParserFactory $parserFactory,
42 UserOptionsLookup $userOptionsLookup,
43 TidyDriverBase $tidy
44 ) {
45 parent::__construct( 'ExpandTemplates' );
46 $this->parserFactory = $parserFactory;
47 $this->userOptionsLookup = $userOptionsLookup;
48 $this->tidy = $tidy;
49 }
50
55 public function execute( $subpage ) {
56 $this->setHeaders();
57 $this->addHelpLink( 'Help:ExpandTemplates' );
58
59 $request = $this->getRequest();
60 $input = $request->getText( 'wpInput' );
61
62 if ( $input !== '' ) {
63 $removeComments = $request->getBool( 'wpRemoveComments', false );
64 $removeNowiki = $request->getBool( 'wpRemoveNowiki', false );
65 $generateXML = $request->getBool( 'wpGenerateXml' );
66 $generateRawHtml = $request->getBool( 'wpGenerateRawHtml' );
67
68 $options = ParserOptions::newFromContext( $this->getContext() );
69 $options->setRemoveComments( $removeComments );
70 $options->setMaxIncludeSize( self::MAX_INCLUDE_SIZE );
71
72 $titleStr = $request->getText( 'wpContextTitle' );
73 $title = Title::newFromText( $titleStr );
74 if ( !$title ) {
75 $title = $this->getPageTitle();
76 $options->setTargetLanguage( $this->getContentLanguage() );
77 }
78
79 $parser = $this->parserFactory->getInstance();
80 if ( $generateXML ) {
81 $parser->startExternalParse( $title, $options, Parser::OT_PREPROCESS );
82 $dom = $parser->preprocessToDom( $input );
83
84 if ( method_exists( $dom, 'saveXML' ) ) {
85 // @phan-suppress-next-line PhanUndeclaredMethod
86 $xml = $dom->saveXML();
87 } else {
88 // @phan-suppress-next-line PhanUndeclaredMethod
89 $xml = $dom->__toString();
90 }
91 }
92
93 $output = $parser->preprocess( $input, $title, $options );
94 $this->makeForm();
95
96 $out = $this->getOutput();
97 if ( $generateXML ) {
98 // @phan-suppress-next-line PhanPossiblyUndeclaredVariable xml is set when used
99 $out->addHTML( $this->makeOutput( $xml, 'expand_templates_xml_output' ) );
100 }
101
102 $tmp = $this->makeOutput( $output );
103
104 if ( $removeNowiki ) {
105 $tmp = preg_replace(
106 [ '_&lt;nowiki&gt;_', '_&lt;/nowiki&gt;_', '_&lt;nowiki */&gt;_' ],
107 '',
108 $tmp
109 );
110 }
111
112 $tmp = $this->tidy->tidy( $tmp );
113
114 $out->addHTML( $tmp );
115
116 $pout = $parser->parse( $output, $title, $options );
117 // TODO T371008 consider if using the Content framework makes sense instead of creating the pipeline
118 $rawhtml = MediaWikiServices::getInstance()->getDefaultOutputPipeline()
119 ->run( $pout, $options, [ 'enableSectionEditLinks' => false ] )->getContentHolderText();
120 if ( $generateRawHtml && $rawhtml !== '' ) {
121 $out->addHTML( $this->makeOutput( $rawhtml, 'expand_templates_html_output' ) );
122 }
123
124 $this->showHtmlPreview( $title, $pout, $options, $out );
125 } else {
126 $this->makeForm();
127 }
128 }
129
138 private function onSubmitInput( array $values ) {
139 $status = Status::newGood();
140 if ( $values['Input'] === '' ) {
141 $status = Status::newFatal( 'expand_templates_input_missing' );
142 }
143 return $status;
144 }
145
149 private function makeForm() {
150 $fields = [
151 'Input' => [
152 'type' => 'textarea',
153 'label' => $this->msg( 'expand_templates_input' )->text(),
154 'rows' => 10,
155 'id' => 'input',
156 'useeditfont' => true,
157 'required' => true,
158 'autofocus' => true,
159 ],
160 'ContextTitle' => [
161 'type' => 'text',
162 'label' => $this->msg( 'expand_templates_title' )->plain(),
163 'id' => 'contexttitle',
164 'size' => 60,
165 ],
166 'RemoveComments' => [
167 'type' => 'check',
168 'label' => $this->msg( 'expand_templates_remove_comments' )->text(),
169 'id' => 'removecomments',
170 'default' => true,
171 ],
172 'RemoveNowiki' => [
173 'type' => 'check',
174 'label' => $this->msg( 'expand_templates_remove_nowiki' )->text(),
175 'id' => 'removenowiki',
176 ],
177 'GenerateXml' => [
178 'type' => 'check',
179 'label' => $this->msg( 'expand_templates_generate_xml' )->text(),
180 'id' => 'generate_xml',
181 ],
182 'GenerateRawHtml' => [
183 'type' => 'check',
184 'label' => $this->msg( 'expand_templates_generate_rawhtml' )->text(),
185 'id' => 'generate_rawhtml',
186 ],
187 ];
188
189 $form = HTMLForm::factory( 'ooui', $fields, $this->getContext() );
190 $form
191 ->setSubmitTextMsg( 'expand_templates_ok' )
192 ->setWrapperLegendMsg( 'expandtemplates' )
193 ->setHeaderHtml( $this->msg( 'expand_templates_intro' )->parse() )
194 ->setSubmitCallback( $this->onSubmitInput( ... ) )
195 ->showAlways();
196 }
197
205 private function makeOutput( $output, $heading = 'expand_templates_output' ) {
206 $out = "<h2>" . $this->msg( $heading )->escaped() . "</h2>\n";
207 $out .= Html::textarea(
208 'output',
209 $output,
210 [
211 // #output is used by CodeMirror (T384148)
212 'id' => $heading === 'expand_templates_output' ? 'output' : $heading,
213 'cols' => 10,
214 'rows' => 10,
215 'readonly' => 'readonly',
216 'class' => 'mw-editfont-' . $this->userOptionsLookup->getOption( $this->getUser(), 'editfont' )
217 ]
218 );
219
220 return $out;
221 }
222
231 private function showHtmlPreview( Title $title, ParserOutput $pout, ParserOptions $popts, OutputPage $out ) {
232 $out->addHTML( "<h2>" . $this->msg( 'expand_templates_preview' )->escaped() . "</h2>\n" );
233
234 if ( $this->getConfig()->get( MainConfigNames::RawHtml ) ) {
235 $request = $this->getRequest();
236 $user = $this->getUser();
237
238 // To prevent cross-site scripting attacks, don't show the preview if raw HTML is
239 // allowed and a valid edit token is not provided (T73111). However, MediaWiki
240 // does not currently provide logged-out users with CSRF protection; in that case,
241 // do not show the preview unless anonymous editing is allowed.
242 if ( $user->isAnon() && !$this->getAuthority()->isAllowed( 'edit' ) ) {
243 $error = [ 'expand_templates_preview_fail_html_anon' ];
244 } elseif ( !$user->matchEditToken( $request->getVal( 'wpEditToken' ), '', $request ) ) {
245 $error = [ 'expand_templates_preview_fail_html' ];
246 } else {
247 $error = false;
248 }
249
250 if ( $error ) {
251 $out->addHTML(
252 Html::errorBox(
253 $out->msg( $error )->parse(),
254 '',
255 'previewnote'
256 )
257 );
258 return;
259 }
260 }
261
262 $out->addParserOutputContent( $pout, $popts, [ 'enableSectionEditLinks' => false ] );
263 $out->addCategoryLinks( $pout->getCategoryMap() );
264 }
265
267 protected function getGroupName() {
268 return 'wiki';
269 }
270}
271
273class_alias( SpecialExpandTemplates::class, 'SpecialExpandTemplates' );
Object handling generic submission, CSRF protection, layout and other logic for UI forms in a reusabl...
Definition HTMLForm.php:195
This class is a collection of static functions that serve two purposes:
Definition Html.php:43
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:135
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:44
Base class for HTML cleanup utilities.
Represents a title within MediaWiki.
Definition Title.php:69
Provides access to user options.