Support for enabling skins in the installer

Let the user choose the skins to install (like extensions)
and decide which one will be the default for the new wiki.

Right now core skins are always enabled regardless of user
choices there, but I'm working on that.

Bug: 66440
Change-Id: I2e10720a6ac327e66c415bb91dc897885f952738
This commit is contained in:
Bartosz Dziewoński 2014-06-10 13:41:29 +02:00
parent e7361de181
commit a957836f4a
8 changed files with 199 additions and 32 deletions

View file

@ -120,6 +120,9 @@ production.
suppressed content but not suppress it ("suppressrevision" right).
* Added a new hook, "OutputPageScriptsForBottomQueue", to add modules to the
bottom queue that should be requested in a dedicated <script> request.
* (bug 66440) The MediaWiki web installer will now allow you to choose the skins
to enable (from the ones included in download tarball) and decide which one
should be the default.
=== Bug fixes in 1.24 ===
* (bug 49116) Footer copyright notice is now always displayed in user language

View file

@ -218,6 +218,7 @@ abstract class Installer {
'_LicenseCode' => 'none',
'_CCDone' => false,
'_Extensions' => array(),
'_Skins' => array(),
'_MemCachedServers' => '',
'_UpgradeKeySupplied' => false,
'_ExistingDBSettings' => false,
@ -1426,17 +1427,20 @@ abstract class Installer {
}
/**
* Finds extensions that follow the format /extensions/Name/Name.php,
* Finds extensions that follow the format /$directory/Name/Name.php,
* and returns an array containing the value for 'Name' for each found extension.
*
* Reasonable values for $directory include 'extensions' (the default) and 'skins'.
*
* @param string $directory Directory to search in
* @return array
*/
public function findExtensions() {
public function findExtensions( $directory = 'extensions' ) {
if ( $this->getVar( 'IP' ) === null ) {
return array();
}
$extDir = $this->getVar( 'IP' ) . '/extensions';
$extDir = $this->getVar( 'IP' ) . '/' . $directory;
if ( !is_readable( $extDir ) || !is_dir( $extDir ) ) {
return array();
}

View file

@ -49,6 +49,7 @@ class LocalSettingsGenerator {
$this->installer = $installer;
$this->extensions = $installer->getVar( '_Extensions' );
$this->skins = $installer->getVar( '_Skins' );
$db = $installer->getDBInstaller( $installer->getVar( 'wgDBtype' ) );
@ -129,13 +130,26 @@ class LocalSettingsGenerator {
/**
* Return the full text of the generated LocalSettings.php file,
* including the extensions
* including the extensions and skins.
*
* @return string
*/
public function getText() {
$localSettings = $this->getDefaultText();
if ( count( $this->skins ) ) {
$localSettings .= "
# Enabled skins.
# The following skins were automatically enabled:\n";
foreach ( $this->skins as $skinName ) {
$encSkinName = self::escapePhpString( $skinName );
$localSettings .= "require_once \"\$IP/skins/$encSkinName/$encSkinName.php\";\n";
}
$localSettings .= "\n";
}
if ( count( $this->extensions ) ) {
$localSettings .= "
# Enabled Extensions. Most extensions are enabled by including the base extension file here
@ -146,9 +160,12 @@ class LocalSettingsGenerator {
$encExtName = self::escapePhpString( $extName );
$localSettings .= "require_once \"\$IP/extensions/$encExtName/$encExtName.php\";\n";
}
$localSettings .= "\n";
}
$localSettings .= "\n\n# End of automatically generated settings.
$localSettings .= "
# End of automatically generated settings.
# Add more configuration options below.\n\n";
return $localSettings;
@ -220,6 +237,8 @@ class LocalSettingsGenerator {
wfBoolToStr( $perm ) . ";\n";
}
}
$groupRights .= "\n";
if ( ( isset( $this->groupPermissions['*']['edit'] ) &&
$this->groupPermissions['*']['edit'] === false )
&& ( isset( $this->groupPermissions['*']['createaccount'] ) &&
@ -227,12 +246,12 @@ class LocalSettingsGenerator {
&& ( isset( $this->groupPermissions['*']['read'] ) &&
$this->groupPermissions['*']['read'] !== false )
) {
$noFollow = "\n# Set \$wgNoFollowLinks to true if you open up your wiki to editing by\n"
$noFollow = "# Set \$wgNoFollowLinks to true if you open up your wiki to editing by\n"
. "# the general public and wish to apply nofollow to external links as a\n"
. "# deterrent to spammers. Nofollow is not a comprehensive anti-spam solution\n"
. "# and open wikis will generally require other anti-spam measures; for more\n"
. "# information, see https://www.mediawiki.org/wiki/Manual:Combating_spam\n"
. "\$wgNoFollowLinks = false;";
. "\$wgNoFollowLinks = false;\n\n";
}
}
@ -352,10 +371,6 @@ ${serverSetting}
# web installer while LocalSettings.php is in place
\$wgUpgradeKey = \"{$this->values['wgUpgradeKey']}\";
## Default skin: you can change the default skin. Use the internal symbolic
## names, ie 'vector', 'monobook':
\$wgDefaultSkin = \"{$this->values['wgDefaultSkin']}\";
## For attaching licensing metadata to pages, and displaying an
## appropriate copyright notice / icon. GNU Free Documentation
## License and Creative Commons licenses are supported so far.
@ -367,6 +382,9 @@ ${serverSetting}
# Path to the GNU diff3 utility. Used for conflict resolution.
\$wgDiff3 = \"{$this->values['wgDiff3']}\";
{$groupRights}{$noFollow}";
{$groupRights}{$noFollow}## Default skin: you can change the default skin. Use the internal symbolic
## names, ie 'vector', 'monobook':
\$wgDefaultSkin = \"{$this->values['wgDefaultSkin']}\";
";
}
}

View file

@ -950,6 +950,7 @@ class WebInstaller extends Installer {
* var: The variable to be configured (required)
* label: The message name for the label (required)
* itemLabelPrefix: The message name prefix for the item labels (required)
* itemLabels: List of message names to use for the item labels instead of itemLabelPrefix, keyed by values
* values: List of allowed values (required)
* itemAttribs: Array of attribute arrays, outer key is the value name (optional)
* commonAttribs: Attribute array applied to all items
@ -960,6 +961,39 @@ class WebInstaller extends Installer {
* @return string
*/
public function getRadioSet( $params ) {
$items = $this->getRadioElements( $params );
if ( !isset( $params['label'] ) ) {
$label = '';
} else {
$label = $params['label'];
}
if ( !isset( $params['controlName'] ) ) {
$params['controlName'] = 'config_' . $params['var'];
}
if ( !isset( $params['help'] ) ) {
$params['help'] = "";
}
$s = "<ul>\n";
foreach ( $items as $value => $item ) {
$s .= "<li>$item</li>\n";
}
$s .= "</ul>\n";
return $this->label( $label, $params['controlName'], $s, $params['help'] );
}
/**
* Get a set of labelled radio buttons. You probably want to use getRadioSet(), not this.
*
* @see getRadioSet
*
* @return array
*/
public function getRadioElements( $params ) {
if ( !isset( $params['controlName'] ) ) {
$params['controlName'] = 'config_' . $params['var'];
}
@ -968,15 +1002,8 @@ class WebInstaller extends Installer {
$params['value'] = $this->getVar( $params['var'] );
}
if ( !isset( $params['label'] ) ) {
$label = '';
} else {
$label = $params['label'];
}
if ( !isset( $params['help'] ) ) {
$params['help'] = "";
}
$s = "<ul>\n";
$items = array();
foreach ( $params['values'] as $value ) {
$itemAttribs = array();
@ -993,19 +1020,17 @@ class WebInstaller extends Installer {
$itemAttribs['id'] = $id;
$itemAttribs['tabindex'] = $this->nextTabIndex();
$s .=
'<li>' .
$items[$value] =
Xml::radio( $params['controlName'], $value, $checked, $itemAttribs ) .
'&#160;' .
Xml::tags( 'label', array( 'for' => $id ), $this->parse(
wfMessage( $params['itemLabelPrefix'] . strtolower( $value ) )->plain()
) ) .
"</li>\n";
isset( $params['itemLabels'] ) ?
wfMessage( $params['itemLabels'][$value] )->plain() :
wfMessage( $params['itemLabelPrefix'] . strtolower( $value ) )->plain()
) );
}
$s .= "</ul>\n";
return $this->label( $label, $params['controlName'], $s, $params['help'] );
return $items;
}
/**

View file

@ -145,11 +145,12 @@ abstract class WebInstallerPage {
/**
* @param string $var
* @param mixed $default
*
* @return mixed
*/
public function getVar( $var ) {
return $this->parent->getVar( $var );
public function getVar( $var, $default = null ) {
return $this->parent->getVar( $var, $default );
}
/**
@ -948,6 +949,7 @@ class WebInstallerOptions extends WebInstallerPage {
*/
public function execute() {
if ( $this->getVar( '_SkipOptional' ) == 'skip' ) {
$this->submitSkins();
return 'skip';
}
if ( $this->parent->request->wasPosted() ) {
@ -1025,6 +1027,38 @@ class WebInstallerOptions extends WebInstallerPage {
$this->getFieldSetEnd()
);
$skins = $this->parent->findExtensions( 'skins' );
$skinHtml = $this->getFieldSetStart( 'config-skins' );
if ( $skins ) {
$skinNames = array_map( 'strtolower', $skins );
$radioButtons = $this->parent->getRadioElements( array(
'var' => 'wgDefaultSkin',
'itemLabels' => array_fill_keys( $skinNames, 'config-skins-use-as-default' ),
'values' => $skinNames,
'value' => $this->getVar( 'wgDefaultSkin', $this->getDefaultSkin( $skinNames ) ),
) );
foreach ( $skins as $skin ) {
$skinHtml .=
'<div class="config-skins-item">' .
$this->parent->getCheckBox( array(
'var' => "skin-$skin",
'rawtext' => $skin,
'value' => $this->getVar( "skin-$skin", true ), // all found skins enabled by default
) ) .
'<div class="config-skins-use-as-default">' . $radioButtons[ strtolower( $skin ) ] . '</div>' .
'</div>';
}
} else {
$skinHtml .= $this->parent->getWarningBox( wfMessage( 'config-skins-missing' )->plain() );
}
$skinHtml .= $this->parent->getHelpBox( 'config-skins-help' ) .
$this->getFieldSetEnd();
$this->addHTML( $skinHtml );
$extensions = $this->parent->findExtensions();
if ( $extensions ) {
@ -1220,6 +1254,40 @@ class WebInstallerOptions extends WebInstallerPage {
$this->addHTML( $this->getCCDoneBox() );
}
/**
* Returns a default value to be used for $wgDefaultSkin: the preferred skin, if available among
* the installed skins, or any other one otherwise.
*
* @param string[] $skinNames Names of installed skins.
* @return string
*/
public function getDefaultSkin( array $skinNames ) {
$defaultSkin = $GLOBALS['wgDefaultSkin'];
if ( in_array( $defaultSkin, $skinNames ) ) {
return $defaultSkin;
} else {
return $skinNames[0];
}
}
/**
* If the user skips this installer page, we still need to set up the default skins, but ignore
* everything else.
*
* @return bool
*/
public function submitSkins() {
$skins = $this->parent->findExtensions( 'skins' );
$this->parent->setVar( '_Skins', $skins );
if ( $skins ) {
$skinNames = array_map( 'strtolower', $skins );
$this->parent->setVar( 'wgDefaultSkin', $this->getDefaultSkin( $skinNames ) );
}
return true;
}
/**
* @return bool
*/
@ -1228,7 +1296,7 @@ class WebInstallerOptions extends WebInstallerPage {
'wgEnableEmail', 'wgPasswordSender', 'wgEnableUploads', 'wgLogo',
'wgEnableUserEmail', 'wgEnotifUserTalk', 'wgEnotifWatchlist',
'wgEmailAuthentication', 'wgMainCacheType', '_MemCachedServers',
'wgUseInstantCommons' ) );
'wgUseInstantCommons', 'wgDefaultSkin' ) );
$retVal = true;
@ -1263,6 +1331,27 @@ class WebInstallerOptions extends WebInstallerPage {
$this->setVar( 'wgRightsIcon', '' );
}
$skinsAvailable = $this->parent->findExtensions( 'skins' );
$skinsToInstall = array();
foreach ( $skinsAvailable as $skin ) {
$this->parent->setVarsFromRequest( array( "skin-$skin" ) );
if ( $this->getVar( "skin-$skin" ) ) {
$skinsToInstall[] = $skin;
}
}
$this->parent->setVar( '_Skins', $skinsToInstall );
if ( !$skinsToInstall && $skinsAvailable ) {
$this->parent->showError( 'config-skins-must-enable-some' );
$retVal = false;
}
$defaultSkin = $this->getVar( 'wgDefaultSkin' );
$skinsToInstallLowercase = array_map( 'strtolower', $skinsToInstall );
if ( $skinsToInstall && array_search( $defaultSkin, $skinsToInstallLowercase ) === false ) {
$this->parent->showError( 'config-skins-must-enable-default' );
$retVal = false;
}
$extsAvailable = $this->parent->findExtensions();
$extsToInstall = array();
foreach ( $extsAvailable as $ext ) {

View file

@ -269,6 +269,12 @@
"config-memcache-badport": "Memcached port numbers should be between $1 and $2.",
"config-extensions": "Extensions",
"config-extensions-help": "The extensions listed above were detected in your <code>./extensions</code> directory.\n\nThey may require additional configuration, but you can enable them now.",
"config-skins": "Skins",
"config-skins-help": "The skins listed above were detected in your <code>./skins</code> directory. You must enable at least one, and choose the default.",
"config-skins-use-as-default": "Use this skin as default",
"config-skins-missing": "No skins were found; MediaWiki will use a fallback skin until you install some proper ones.",
"config-skins-must-enable-some": "You must choose at least one skin to enable.",
"config-skins-must-enable-default": "The skin chosen as default must be enabled.",
"config-install-alreadydone": "<strong>Warning:</strong> You seem to have already installed MediaWiki and are trying to install it again.\nPlease proceed to the next page.",
"config-install-begin": "By pressing \"{{int:config-continue}}\", you will begin the installation of MediaWiki.\nIf you still want to make changes, press \"{{int:config-back}}\".",
"config-install-step-done": "done",

View file

@ -287,6 +287,12 @@
"config-memcache-badport": "Used as error message. Parameters:\n* $1 - 1 (hard-coded)\n* $2 - 65535 (hard-coded)\nSee also:\n* {{msg-mw|Config-memcache-badip}}\n* {{msg-mw|Config-memcache-noport}}",
"config-extensions": "{{Identical|Extension}}",
"config-extensions-help": "{{doc-important|Do not translate <code>./extensions</code>.}}\nUsed in help box.",
"config-skins": "{{Identical|Skin}}",
"config-skins-help": "{{doc-important|Do not translate <code>./skins</code>.}}\nUsed in help box.",
"config-skins-use-as-default": "Label shown next to skin names.",
"config-skins-missing": "Warning message shown when there are no skins to install.",
"config-skins-must-enable-some": "Error message shown when the user does silly things.",
"config-skins-must-enable-default": "Error message shown when the user does silly things.",
"config-install-alreadydone": "Error message shown to users visiting the installer when the wiki appears to already be set up.",
"config-install-begin": "Prompt at the end of the initial configuration options screen before the wiki software is installed.",
"config-install-step-done": "{{Identical|Done}}",

View file

@ -97,6 +97,22 @@
margin-left: 10em;
}
.config-skins-item {
/* Clearfix */
clear: left;
overflow: hidden;
}
.config-skins-item .config-input-check {
margin-left: 10em;
width: 20em;
float: left;
}
.config-skins-item .config-skins-use-as-default {
float: left;
}
.error {
color: red;
background-color: #fff;