MediaWiki 1.41.2
WebInstallerOptions.php
Go to the documentation of this file.
1<?php
24use Wikimedia\IPUtils;
25
27
31 public function execute() {
32 if ( $this->getVar( '_SkipOptional' ) == 'skip' ) {
33 $this->submitSkins();
34 return 'skip';
35 }
36 if ( $this->parent->request->wasPosted() && $this->submit() ) {
37 return 'continue';
38 }
39
40 $this->startForm();
41 $this->addModeOptions();
42 $this->addEmailOptions();
43 $this->addSkinOptions();
44 $this->addExtensionOptions();
45 $this->addFileOptions();
46 $this->addPersonalizationOptions();
47 $this->addAdvancedOptions();
48 $this->endForm();
49
50 return null;
51 }
52
53 private function addPersonalizationOptions() {
55 $this->addHTML(
56 $this->getFieldsetStart( 'config-personalization-settings' ) .
57 Html::rawElement( 'div', [
58 'class' => 'config-drag-drop'
59 ], wfMessage( 'config-logo-summary' )->parse() ) .
60 Html::openElement( 'div', [
61 'class' => 'config-personalization-options'
62 ] ) .
63 Html::hidden( 'config_LogoSiteName', $this->getVar( 'wgSitename' ) ) .
65 'var' => '_LogoIcon',
66 // Single quotes are intentional, LocalSettingsGenerator must output this unescaped.
67 'value' => '$wgResourceBasePath/resources/assets/change-your-logo.svg',
68 'label' => 'config-logo-icon',
69 'attribs' => [ 'dir' => 'ltr' ],
70 'help' => $parent->getHelpBox( 'config-logo-icon-help' )
71 ] ) .
73 'var' => '_LogoWordmark',
74 'label' => 'config-logo-wordmark',
75 'attribs' => [ 'dir' => 'ltr' ],
76 'help' => $parent->getHelpBox( 'config-logo-wordmark-help' )
77 ] ) .
79 'var' => '_LogoTagline',
80 'label' => 'config-logo-tagline',
81 'attribs' => [ 'dir' => 'ltr' ],
82 'help' => $parent->getHelpBox( 'config-logo-tagline-help' )
83 ] ) .
85 'var' => '_Logo1x',
86 'label' => 'config-logo-sidebar',
87 'attribs' => [ 'dir' => 'ltr' ],
88 'help' => $parent->getHelpBox( 'config-logo-sidebar-help' )
89 ] ) .
90 Html::openElement( 'div', [
91 'class' => 'logo-preview-area',
92 'data-main-page' => wfMessage( 'config-logo-preview-main' ),
93 'data-filedrop' => wfMessage( 'config-logo-filedrop' )
94 ] ) .
95 Html::closeElement( 'div' ) .
96 Html::closeElement( 'div' ) .
97 $this->getFieldsetEnd()
98 );
99 }
100
105 private function addModeOptions(): void {
106 $this->addHTML(
107 # User Rights
108 // getRadioSet() builds a set of labeled radio buttons.
109 // For grep: The following messages are used as the item labels:
110 // config-profile-wiki, config-profile-no-anon, config-profile-fishbowl, config-profile-private
111 $this->parent->getRadioSet( [
112 'var' => '_RightsProfile',
113 'label' => 'config-profile',
114 'itemLabelPrefix' => 'config-profile-',
115 'values' => array_keys( $this->parent->rightsProfiles ),
116 ] ) .
117 $this->parent->getInfoBox( wfMessage( 'config-profile-help' )->plain() ) .
118
119 # Licensing
120 // getRadioSet() builds a set of labeled radio buttons.
121 // For grep: The following messages are used as the item labels:
122 // config-license-cc-by, config-license-cc-by-sa, config-license-cc-by-nc-sa,
123 // config-license-cc-0, config-license-pd, config-license-gfdl,
124 // config-license-none, config-license-cc-choose
125 $this->parent->getRadioSet( [
126 'var' => '_LicenseCode',
127 'label' => 'config-license',
128 'itemLabelPrefix' => 'config-license-',
129 'values' => array_keys( $this->parent->licenses ),
130 'commonAttribs' => [ 'class' => 'licenseRadio' ],
131 ] ) .
132 $this->getCCChooser() .
133 $this->parent->getHelpBox( 'config-license-help' )
134 );
135 }
136
141 private function addEmailOptions(): void {
142 $emailwrapperStyle = $this->getVar( 'wgEnableEmail' ) ? '' : 'display: none';
143 $this->addHTML(
144 $this->getFieldsetStart( 'config-email-settings' ) .
145 $this->parent->getCheckBox( [
146 'var' => 'wgEnableEmail',
147 'label' => 'config-enable-email',
148 'attribs' => [ 'class' => 'showHideRadio', 'rel' => 'emailwrapper' ],
149 ] ) .
150 $this->parent->getHelpBox( 'config-enable-email-help' ) .
151 "<div id=\"emailwrapper\" style=\"$emailwrapperStyle\">" .
152 $this->parent->getTextBox( [
153 'var' => 'wgPasswordSender',
154 'label' => 'config-email-sender'
155 ] ) .
156 $this->parent->getHelpBox( 'config-email-sender-help' ) .
157 $this->parent->getCheckBox( [
158 'var' => 'wgEnableUserEmail',
159 'label' => 'config-email-user',
160 ] ) .
161 $this->parent->getHelpBox( 'config-email-user-help' ) .
162 $this->parent->getCheckBox( [
163 'var' => 'wgEnotifUserTalk',
164 'label' => 'config-email-usertalk',
165 ] ) .
166 $this->parent->getHelpBox( 'config-email-usertalk-help' ) .
167 $this->parent->getCheckBox( [
168 'var' => 'wgEnotifWatchlist',
169 'label' => 'config-email-watchlist',
170 ] ) .
171 $this->parent->getHelpBox( 'config-email-watchlist-help' ) .
172 $this->parent->getCheckBox( [
173 'var' => 'wgEmailAuthentication',
174 'label' => 'config-email-auth',
175 ] ) .
176 $this->parent->getHelpBox( 'config-email-auth-help' ) .
177 "</div>" .
178 $this->getFieldsetEnd()
179 );
180 }
181
186 private function addSkinOptions(): void {
187 $skins = $this->parent->findExtensions( 'skins' )->value;
188 '@phan-var array[] $skins';
189 $skinHtml = $this->getFieldsetStart( 'config-skins' );
190
191 $skinNames = array_map( 'strtolower', array_keys( $skins ) );
192 $chosenSkinName = $this->getVar( 'wgDefaultSkin', $this->parent->getDefaultSkin( $skinNames ) );
193
194 if ( $skins ) {
195 $radioButtons = $this->parent->getRadioElements( [
196 'var' => 'wgDefaultSkin',
197 'itemLabels' => array_fill_keys( $skinNames, 'config-skins-use-as-default' ),
198 'values' => $skinNames,
199 'value' => $chosenSkinName,
200 ] );
201
202 foreach ( $skins as $skin => $info ) {
203 if ( isset( $info['screenshots'] ) ) {
204 $screenshotText = $this->makeScreenshotsLink( $skin, $info['screenshots'] );
205 } else {
206 $screenshotText = htmlspecialchars( $skin );
207 }
208 $skinHtml .=
209 '<div class="config-skins-item">' .
210 $this->parent->getCheckBox( [
211 'var' => "skin-$skin",
212 'rawtext' => $screenshotText . $this->makeMoreInfoLink( $info ),
213 'value' => $this->getVar( "skin-$skin", true ), // all found skins enabled by default
214 ] ) .
215 '<div class="config-skins-use-as-default">' . $radioButtons[strtolower( $skin )] . '</div>' .
216 '</div>';
217 }
218 } else {
219 $skinHtml .=
220 Html::warningBox( wfMessage( 'config-skins-missing' )->plain(), 'config-warning-box' ) .
221 Html::hidden( 'config_wgDefaultSkin', $chosenSkinName );
222 }
223
224 $skinHtml .= $this->parent->getHelpBox( 'config-skins-help' ) .
225 $this->getFieldsetEnd();
226 $this->addHTML( $skinHtml );
227 }
228
233 private function addExtensionOptions(): void {
234 global $wgLang;
235
236 $extensions = $this->parent->findExtensions()->value;
237 '@phan-var array[] $extensions';
238 $dependencyMap = [];
239
240 if ( $extensions ) {
241 $extHtml = $this->getFieldsetStart( 'config-extensions' );
242
243 $extByType = [];
244 $types = SpecialVersion::getExtensionTypes();
245 // Sort by type first
246 foreach ( $extensions as $ext => $info ) {
247 if ( !isset( $info['type'] ) || !isset( $types[$info['type']] ) ) {
248 // We let extensions normally define custom types, but
249 // since we aren't loading extensions, we'll have to
250 // categorize them under other
251 $info['type'] = 'other';
252 }
253 $extByType[$info['type']][$ext] = $info;
254 }
255
256 foreach ( $types as $type => $message ) {
257 if ( !isset( $extByType[$type] ) ) {
258 continue;
259 }
260 $extHtml .= Html::element( 'h2', [], $message );
261 foreach ( $extByType[$type] as $ext => $info ) {
262 $attribs = [
263 'data-name' => $ext,
264 'class' => 'config-ext-input'
265 ];
266 $labelAttribs = [];
267 if ( isset( $info['requires']['extensions'] ) ) {
268 $dependencyMap[$ext]['extensions'] = $info['requires']['extensions'];
269 $labelAttribs['class'] = 'mw-ext-with-dependencies';
270 }
271 if ( isset( $info['requires']['skins'] ) ) {
272 $dependencyMap[$ext]['skins'] = $info['requires']['skins'];
273 $labelAttribs['class'] = 'mw-ext-with-dependencies';
274 }
275 if ( isset( $dependencyMap[$ext] ) ) {
276 $links = [];
277 // For each dependency, link to the checkbox for each
278 // extension/skin that is required
279 if ( isset( $dependencyMap[$ext]['extensions'] ) ) {
280 foreach ( $dependencyMap[$ext]['extensions'] as $name ) {
281 $links[] = Html::element(
282 'a',
283 [ 'href' => "#config_ext-$name" ],
284 $name
285 );
286 }
287 }
288 if ( isset( $dependencyMap[$ext]['skins'] ) ) {
289 // @phan-suppress-next-line PhanTypeMismatchForeach Phan internal bug
290 foreach ( $dependencyMap[$ext]['skins'] as $name ) {
291 $links[] = Html::element(
292 'a',
293 [ 'href' => "#config_skin-$name" ],
294 $name
295 );
296 }
297 }
298
299 $text = wfMessage( 'config-extensions-requires' )
300 ->rawParams( $ext, $wgLang->commaList( $links ) )
301 ->escaped();
302 } else {
303 $text = $ext;
304 }
305 $extHtml .= $this->parent->getCheckBox( [
306 'var' => "ext-$ext",
307 'rawtext' => $text . $this->makeMoreInfoLink( $info ),
308 'attribs' => $attribs,
309 'labelAttribs' => $labelAttribs,
310 ] );
311 }
312 }
313
314 $extHtml .= $this->parent->getHelpBox( 'config-extensions-help' ) .
315 $this->getFieldsetEnd();
316 $this->addHTML( $extHtml );
317 // Push the dependency map to the client side
318 $this->addHTML( Html::inlineScript(
319 'var extDependencyMap = ' . Html::encodeJsVar( $dependencyMap )
320 ) );
321 }
322 }
323
328 private function addFileOptions(): void {
329 // Having / in paths in Windows looks funny :)
330 $this->setVar( 'wgDeletedDirectory',
331 str_replace(
332 '/', DIRECTORY_SEPARATOR,
333 $this->getVar( 'wgDeletedDirectory' )
334 )
335 );
336
337 $uploadwrapperStyle = $this->getVar( 'wgEnableUploads' ) ? '' : 'display: none';
338 $this->addHTML(
339 # Uploading
340 $this->getFieldsetStart( 'config-upload-settings' ) .
341 $this->parent->getCheckBox( [
342 'var' => 'wgEnableUploads',
343 'label' => 'config-upload-enable',
344 'attribs' => [ 'class' => 'showHideRadio', 'rel' => 'uploadwrapper' ],
345 'help' => $this->parent->getHelpBox( 'config-upload-help' )
346 ] ) .
347 '<div id="uploadwrapper" style="' . $uploadwrapperStyle . '">' .
348 $this->parent->getTextBox( [
349 'var' => 'wgDeletedDirectory',
350 'label' => 'config-upload-deleted',
351 'attribs' => [ 'dir' => 'ltr' ],
352 'help' => $this->parent->getHelpBox( 'config-upload-deleted-help' )
353 ] ) .
354 '</div>'
355 );
356 $this->addHTML(
357 $this->parent->getCheckBox( [
358 'var' => 'wgUseInstantCommons',
359 'label' => 'config-instantcommons',
360 'help' => $this->parent->getHelpBox( 'config-instantcommons-help' )
361 ] ) .
362 $this->getFieldsetEnd()
363 );
364 }
365
370 private function addAdvancedOptions(): void {
371 $caches = [ 'none' ];
372 $cachevalDefault = 'none';
373
374 if ( count( $this->getVar( '_Caches' ) ) ) {
375 // A CACHE_ACCEL implementation is available
376 $caches[] = 'accel';
377 $cachevalDefault = 'accel';
378 }
379 $caches[] = 'memcached';
380
381 // We'll hide/show this on demand when the value changes, see config.js.
382 $cacheval = $this->getVar( '_MainCacheType' );
383 if ( !$cacheval ) {
384 // We need to set a default here; but don't hardcode it
385 // or we lose it every time we reload the page for validation
386 // or going back!
387 $cacheval = $cachevalDefault;
388 }
389 $hidden = ( $cacheval == 'memcached' ) ? '' : 'display: none';
390 $this->addHTML(
391 # Advanced settings
392 $this->getFieldsetStart( 'config-advanced-settings' ) .
393 # Object cache settings
394 // getRadioSet() builds a set of labeled radio buttons.
395 // For grep: The following messages are used as the item labels:
396 // config-cache-none, config-cache-accel, config-cache-memcached
397 $this->parent->getRadioSet( [
398 'var' => '_MainCacheType',
399 'label' => 'config-cache-options',
400 'itemLabelPrefix' => 'config-cache-',
401 'values' => $caches,
402 'value' => $cacheval,
403 ] ) .
404 $this->parent->getHelpBox( 'config-cache-help' ) .
405 "<div id=\"config-memcachewrapper\" style=\"$hidden\">" .
406 $this->parent->getTextArea( [
407 'var' => '_MemCachedServers',
408 'label' => 'config-memcached-servers',
409 'help' => $this->parent->getHelpBox( 'config-memcached-help' )
410 ] ) .
411 '</div>' .
412 $this->getFieldsetEnd()
413 );
414 }
415
421 private function makeScreenshotsLink( $name, $screenshots ) {
422 global $wgLang;
423 if ( count( $screenshots ) > 1 ) {
424 $links = [];
425 $counter = 1;
426
427 foreach ( $screenshots as $shot ) {
428 $links[] = Html::element(
429 'a',
430 [ 'href' => $shot, 'target' => '_blank' ],
431 $wgLang->formatNum( $counter++ )
432 );
433 }
434 return wfMessage( 'config-skins-screenshots' )
435 ->rawParams( $name, $wgLang->commaList( $links ) )
436 ->escaped();
437 } else {
438 $link = Html::element(
439 'a',
440 [ 'href' => $screenshots[0], 'target' => '_blank' ],
441 wfMessage( 'config-screenshot' )->text()
442 );
443 return wfMessage( 'config-skins-screenshot', $name )->rawParams( $link )->escaped();
444 }
445 }
446
451 private function makeMoreInfoLink( $info ) {
452 if ( !isset( $info['url'] ) ) {
453 return '';
454 }
455 return ' ' . wfMessage( 'parentheses' )->rawParams(
456 Html::element(
457 'a',
458 [ 'href' => $info['url'] ],
459 wfMessage( 'config-ext-skins-more-info' )->text()
460 )
461 )->escaped();
462 }
463
467 public function getCCPartnerUrl() {
468 $server = $this->getVar( 'wgServer' );
469 $exitUrl = $server . $this->parent->getUrl( [
470 'page' => 'Options',
471 'SubmitCC' => 'indeed',
472 'config__LicenseCode' => 'cc',
473 'config_wgRightsUrl' => '[license_url]',
474 'config_wgRightsText' => '[license_name]',
475 'config_wgRightsIcon' => '[license_button]',
476 ] );
477 $styleUrl = $server . dirname( dirname( $this->parent->getUrl() ) ) .
478 '/mw-config/config-cc.css';
479 $iframeUrl = 'https://creativecommons.org/license/?' .
480 wfArrayToCgi( [
481 'partner' => 'MediaWiki',
482 'exit_url' => $exitUrl,
483 'lang' => $this->getVar( '_UserLang' ),
484 'stylesheet' => $styleUrl,
485 ] );
486
487 return $iframeUrl;
488 }
489
493 public function getCCChooser() {
494 $iframeAttribs = [
495 'class' => 'config-cc-iframe',
496 'name' => 'config-cc-iframe',
497 'id' => 'config-cc-iframe',
498 'frameborder' => 0,
499 'width' => '100%',
500 'height' => '100%',
501 ];
502 if ( $this->getVar( '_CCDone' ) ) {
503 $iframeAttribs['src'] = $this->parent->getUrl( [ 'ShowCC' => 'yes' ] );
504 } else {
505 $iframeAttribs['src'] = $this->getCCPartnerUrl();
506 }
507 $wrapperStyle = ( $this->getVar( '_LicenseCode' ) == 'cc-choose' ) ? '' : 'display: none';
508
509 return "<div class=\"config-cc-wrapper\" id=\"config-cc-wrapper\" style=\"$wrapperStyle\">\n" .
510 Html::element( 'iframe', $iframeAttribs ) .
511 "</div>\n";
512 }
513
517 public function getCCDoneBox() {
518 $js = "parent.document.getElementById('config-cc-wrapper').style.height = '$1';";
519 // If you change this height, also change it in config.css
520 $expandJs = str_replace( '$1', '54em', $js );
521 $reduceJs = str_replace( '$1', '70px', $js );
522
523 return '<p>' .
524 Html::element( 'img', [ 'src' => $this->getVar( 'wgRightsIcon' ) ] ) .
525 "\u{00A0}\u{00A0}" .
526 htmlspecialchars( $this->getVar( 'wgRightsText' ) ) .
527 "</p>\n" .
528 "<p style=\"text-align: center;\">" .
529 Html::element( 'a',
530 [
531 'href' => $this->getCCPartnerUrl(),
532 'onclick' => $expandJs,
533 ],
534 wfMessage( 'config-cc-again' )->text()
535 ) .
536 "</p>\n" .
537 "<script>\n" .
538 # Reduce the wrapper div height
539 htmlspecialchars( $reduceJs ) .
540 "\n" .
541 "</script>\n";
542 }
543
544 public function submitCC() {
545 $newValues = $this->parent->setVarsFromRequest(
546 [ 'wgRightsUrl', 'wgRightsText', 'wgRightsIcon' ] );
547 if ( count( $newValues ) != 3 ) {
548 $this->parent->showError( 'config-cc-error' );
549
550 return;
551 }
552 $this->setVar( '_CCDone', true );
553 $this->addHTML( $this->getCCDoneBox() );
554 }
555
562 public function submitSkins() {
563 $skins = array_keys( $this->parent->findExtensions( 'skins' )->value );
564 $this->parent->setVar( '_Skins', $skins );
565
566 if ( $skins ) {
567 $skinNames = array_map( 'strtolower', $skins );
568 $this->parent->setVar( 'wgDefaultSkin', $this->parent->getDefaultSkin( $skinNames ) );
569 }
570
571 return true;
572 }
573
577 public function submit() {
578 $this->parent->setVarsFromRequest( [ '_RightsProfile', '_LicenseCode',
579 'wgEnableEmail', 'wgPasswordSender', 'wgEnableUploads',
580 '_Logo1x', '_LogoWordmark', '_LogoTagline', '_LogoIcon',
581 'wgEnableUserEmail', 'wgEnotifUserTalk', 'wgEnotifWatchlist',
582 'wgEmailAuthentication', '_MainCacheType', '_MemCachedServers',
583 'wgUseInstantCommons', 'wgDefaultSkin' ] );
584
585 $retVal = true;
586
587 if ( !array_key_exists( $this->getVar( '_RightsProfile' ), $this->parent->rightsProfiles ) ) {
588 $this->setVar( '_RightsProfile', array_key_first( $this->parent->rightsProfiles ) );
589 }
590
591 $code = $this->getVar( '_LicenseCode' );
592 if ( $code == 'cc-choose' ) {
593 if ( !$this->getVar( '_CCDone' ) ) {
594 $this->parent->showError( 'config-cc-not-chosen' );
595 $retVal = false;
596 }
597 } elseif ( array_key_exists( $code, $this->parent->licenses ) ) {
598 // Messages:
599 // config-license-cc-by, config-license-cc-by-sa, config-license-cc-by-nc-sa,
600 // config-license-cc-0, config-license-pd, config-license-gfdl, config-license-none,
601 // config-license-cc-choose
602 $entry = $this->parent->licenses[$code];
603 $this->setVar( 'wgRightsText',
604 $entry['text'] ?? wfMessage( 'config-license-' . $code )->text() );
605 $this->setVar( 'wgRightsUrl', $entry['url'] );
606 $this->setVar( 'wgRightsIcon', $entry['icon'] );
607 } else {
608 $this->setVar( 'wgRightsText', '' );
609 $this->setVar( 'wgRightsUrl', '' );
610 $this->setVar( 'wgRightsIcon', '' );
611 }
612
613 $skinsAvailable = array_keys( $this->parent->findExtensions( 'skins' )->value );
614 $skinsToInstall = [];
615 foreach ( $skinsAvailable as $skin ) {
616 $this->parent->setVarsFromRequest( [ "skin-$skin" ] );
617 if ( $this->getVar( "skin-$skin" ) ) {
618 $skinsToInstall[] = $skin;
619 }
620 }
621 $this->parent->setVar( '_Skins', $skinsToInstall );
622
623 if ( !$skinsToInstall && $skinsAvailable ) {
624 $this->parent->showError( 'config-skins-must-enable-some' );
625 $retVal = false;
626 }
627 $defaultSkin = $this->getVar( 'wgDefaultSkin' );
628 $skinsToInstallLowercase = array_map( 'strtolower', $skinsToInstall );
629 if ( $skinsToInstall && !in_array( $defaultSkin, $skinsToInstallLowercase ) ) {
630 $this->parent->showError( 'config-skins-must-enable-default' );
631 $retVal = false;
632 }
633
634 $extsAvailable = array_keys( $this->parent->findExtensions()->value );
635 $extsToInstall = [];
636 foreach ( $extsAvailable as $ext ) {
637 $this->parent->setVarsFromRequest( [ "ext-$ext" ] );
638 if ( $this->getVar( "ext-$ext" ) ) {
639 $extsToInstall[] = $ext;
640 }
641 }
642 $this->parent->setVar( '_Extensions', $extsToInstall );
643
644 if ( $this->getVar( '_MainCacheType' ) == 'memcached' ) {
645 $memcServers = explode( "\n", $this->getVar( '_MemCachedServers' ) );
646 // FIXME: explode() will always result in an array of at least one string, even on null (when
647 // the string will be empty and you'll get a PHP warning), so this has never worked?
648 // @phan-suppress-next-line PhanImpossibleCondition
649 if ( !$memcServers ) {
650 $this->parent->showError( 'config-memcache-needservers' );
651 $retVal = false;
652 }
653
654 foreach ( $memcServers as $server ) {
655 $memcParts = explode( ":", $server, 2 );
656 if ( !isset( $memcParts[0] )
657 || ( !IPUtils::isValid( $memcParts[0] )
658 && ( gethostbyname( $memcParts[0] ) == $memcParts[0] ) )
659 ) {
660 $this->parent->showError( 'config-memcache-badip', $memcParts[0] );
661 $retVal = false;
662 } elseif ( !isset( $memcParts[1] ) ) {
663 $this->parent->showError( 'config-memcache-noport', $memcParts[0] );
664 $retVal = false;
665 } elseif ( $memcParts[1] < 1 || $memcParts[1] > 65535 ) {
666 $this->parent->showError( 'config-memcache-badport', 1, 65535 );
667 $retVal = false;
668 }
669 }
670 }
671
672 return $retVal;
673 }
674
675}
wfArrayToCgi( $array1, $array2=null, $prefix='')
This function takes one or two arrays as input, and returns a CGI-style string, e....
wfMessage( $key,... $params)
This is the function for getting translated interface messages.
if(!defined( 'MW_NO_SESSION') &&! $wgCommandLineMode $wgLang
Definition Setup.php:535
This class is a collection of static functions that serve two purposes:
Definition Html.php:57
Give information about the version of MediaWiki, PHP, the DB and extensions.
submitSkins()
If the user skips this installer page, we still need to set up the default skins, but ignore everythi...
Abstract class to define pages for the web installer.
WebInstaller $parent
The WebInstaller object this WebInstallerPage belongs to.
getFieldsetEnd()
Get the end tag of a fieldset.
endForm( $continue='continue', $back='back')
getVar( $var, $default=null)
getFieldsetStart( $legend)
Get the starting tags of a fieldset.
getTextBox( $params)
Get a labelled text box to configure a variable.
getHelpBox( $msg,... $args)
Get small text indented help for a preceding form field.
if(!is_readable( $file)) $ext
Definition router.php:48