jenkins-bot has submitted this change and it was merged. ( https://gerrit.wikimedia.org/r/383304 )
Change subject: Local overrides for global prefs ...................................................................... Local overrides for global prefs This allows individual local overrides for globalized preferences, by adding a checkbox to the "this is a global pref" notice. Bug: T178044 Change-Id: I8e15f1570f314cae63a38325589f3d4811919bc6 --- M extension.json M i18n/en.json M i18n/qqq.json M includes/GlobalPreferencesFactory.php M includes/GlobalPreferencesForm.php M includes/Hooks.php M includes/SpecialGlobalPreferences.php R resources/ext.GlobalPreferences.global-nojs.css R resources/ext.GlobalPreferences.global.css R resources/ext.GlobalPreferences.global.js A resources/ext.GlobalPreferences.local-nojs.css A resources/ext.GlobalPreferences.local.css A resources/ext.GlobalPreferences.local.js 13 files changed, 170 insertions(+), 35 deletions(-) Approvals: MaxSem: Looks good to me, approved jenkins-bot: Verified diff --git a/extension.json b/extension.json index 4824a25..c28c5e8 100644 --- a/extension.json +++ b/extension.json @@ -44,6 +44,9 @@ ], "MediaWikiServices": [ "GlobalPreferences\\Hooks::onMediaWikiServices" + ], + "BeforePageDisplay": [ + "GlobalPreferences\\Hooks::onBeforePageDisplay" ] }, "ResourceFileModulePaths": { @@ -51,13 +54,20 @@ "remoteExtPath": "GlobalPreferences/resources" }, "ResourceModules": { - "ext.GlobalPreferences.special": { - "styles": "ext.GlobalPreferences.special.css", - "scripts": "ext.GlobalPreferences.special.js", + "ext.GlobalPreferences.global": { + "styles": "ext.GlobalPreferences.global.css", + "scripts": "ext.GlobalPreferences.global.js", "messages": [ "globalprefs-select-all" ] }, - "ext.GlobalPreferences.special.nojs": { - "styles": "ext.GlobalPreferences.special.nojs.css" + "ext.GlobalPreferences.global-nojs": { + "styles": "ext.GlobalPreferences.global-nojs.css" + }, + "ext.GlobalPreferences.local": { + "styles": "ext.GlobalPreferences.local.css", + "scripts": "ext.GlobalPreferences.local.js" + }, + "ext.GlobalPreferences.local-nojs": { + "styles": "ext.GlobalPreferences.local-nojs.css" } }, "manifest_version": 1 diff --git a/i18n/en.json b/i18n/en.json index 119902e..03c9156 100644 --- a/i18n/en.json +++ b/i18n/en.json @@ -5,7 +5,8 @@ ] }, "globalprefs-desc": "Allows users to set global preferences", - "globalprefs-set-globally": "This preference has been set globally and must be modified through [[Special:GlobalPreferences#$1|your global preferences]].", + "globalprefs-set-local-exception": "Set a local exception for this [[Special:GlobalPreferences#$1|global preference]].", + "globalprefs-has-local-exception": "This global preference has a [[Special:Preferences#$1|local exception on this wiki]].", "tooltip-globalprefs-check-label": "Make this setting global", "globalprefs-error-header": "Error", "globalprefs-notglobal": "Your account is not a global account and cannot set global preferences.", diff --git a/i18n/qqq.json b/i18n/qqq.json index d2c1323..38c7f30 100644 --- a/i18n/qqq.json +++ b/i18n/qqq.json @@ -6,7 +6,8 @@ ] }, "globalprefs-desc": "{{desc|name=Global Preferences|url=https://www.mediawiki.org/wiki/Extension:GlobalPreferences}}", - "globalprefs-set-globally": "Help message below a disabled preference option instructing the user to change it at their global preferences page.", + "globalprefs-set-local-exception": "Label for the checkbox below a globally-set preference, inviting user to set a local exception for it. $1 is the fragment identifier for the current preferences section, with which to link to the correct section on Special:GlobalPreferences.", + "globalprefs-has-local-exception": "Help text on a global preference that has a local exception. $1 is the fragment identifier for the current preferences section, with which to link to the correct section on Special:Preferences.", "tooltip-globalprefs-check-label": "The tooltip and the label text for the checkbox to enable a preference globally.", "globalprefs-error-header": "Page title for error message.\n{{Identical|Error}}", "globalprefs-notglobal": "Error message a user sees if they do not have a global account.", diff --git a/includes/GlobalPreferencesFactory.php b/includes/GlobalPreferencesFactory.php index b161269..3d29e59 100644 --- a/includes/GlobalPreferencesFactory.php +++ b/includes/GlobalPreferencesFactory.php @@ -27,6 +27,17 @@ */ class GlobalPreferencesFactory extends DefaultPreferencesFactory { + /** + * The suffix appended to preference names + * for the associated preference that tracks whether they have a local override. + */ + const LOCAL_EXCEPTION_SUFFIX = '-local-exception'; + + /** + * The suffix appended to preference names for their global counterparts. + */ + const GLOBAL_EXCEPTION_SUFFIX = '-global'; + /** @var User */ protected $user; @@ -106,30 +117,33 @@ * @return mixed[][] */ protected function getPreferencesLocal( $preferences, $globalPrefNames ) { + $modifiedPrefs = []; foreach ( $preferences as $name => $def ) { + $modifiedPrefs[$name] = $def; + // If this has been set globally. if ( in_array( $name, $globalPrefNames ) ) { - // Disable this preference. - $preferences[$name]['disabled'] = true; + // Disable this preference unless it has a local exception. + $localException = $this->user->getOption( $name . static::LOCAL_EXCEPTION_SUFFIX ); + $modifiedPrefs[$name]['disabled'] = is_null( $localException ); - // Append a help message. - $help = ''; - if ( isset( $preferences[$name]['help-message'] ) ) { - $help .= wfMessage( $preferences[$name]['help-message'] )->parse() . '<br />'; - } elseif ( isset( $preferences[$name]['help'] ) ) { - $help .= $preferences[$name]['help'] . '<br />'; - } - - // Create a link to the relevant section of GlobalPreferences. - $section = substr( $def['section'], 0, strpos( $def['section'], '/' ) ); - $secFragment = 'mw-prefsection-' . $section; - - // Set the new full help text. - $help .= wfMessage( 'globalprefs-set-globally', [ $secFragment ] )->parse(); - $preferences[$name]['help'] = $help; - unset( $preferences[$name]['help-message'] ); + // Add a new local exception preference after this one. + $cssClasses = [ + 'mw-globalprefs-local-exception', + 'mw-globalprefs-local-exception-for-' . $name, + ]; + $secFragment = static::getSectionFragmentId( $def['section'] ); + $labelMsg = wfMessage( 'globalprefs-set-local-exception', [ $secFragment ] ); + $modifiedPrefs[ $name . static::LOCAL_EXCEPTION_SUFFIX ] = [ + 'type' => 'toggle', + 'label-raw' => $labelMsg->parse(), + 'default' => $this->user->getOption( $name . static::LOCAL_EXCEPTION_SUFFIX ), + 'section' => $def['section'], + 'cssclass' => join( ' ', $cssClasses ), + ]; } } + $preferences = $modifiedPrefs; // Add a link to GlobalPreferences to the local preferences form. $linkRenderer = MediaWikiServices::getInstance()->getLinkRenderer(); @@ -162,19 +176,48 @@ continue; } // Create the new preference. - $allPrefs[$pref.'-global'] = [ + $isGlobal = in_array( $pref, $globalPrefNames ); + $allPrefs[$pref . static::GLOBAL_EXCEPTION_SUFFIX] = [ 'type' => 'toggle', // Make the tooltip and the label the same, because the label is normally hidden. 'tooltip' => 'globalprefs-check-label', 'label-message' => 'tooltip-globalprefs-check-label', - 'default' => in_array( $pref, $globalPrefNames ), + 'default' => $isGlobal, 'section' => $def['section'], 'cssclass' => 'mw-globalprefs-global-check mw-globalprefs-checkbox-for-' . $pref, ]; + // If this has a local exception, append a help message to say so. + if ( $isGlobal + && $this->user->getOption( $pref . static::LOCAL_EXCEPTION_SUFFIX ) + ) { + $help = ''; + if ( isset( $def['help-message'] ) ) { + $help .= wfMessage( $def['help-message'] )->parse() . '<br />'; + } elseif ( isset( $def['help'] ) ) { + $help .= $def['help'] . '<br />'; + } + // Create a link to the relevant section of GlobalPreferences. + $secFragment = static::getSectionFragmentId( $def['section'] ); + // Merge the help texts. + $helpMsg = wfMessage( 'globalprefs-has-local-exception', [ $secFragment ] ); + unset( $def['help-message'] ); + $def['help'] = $help . $helpMsg->parse(); + } $allPrefs[$pref] = $def; } return $allPrefs; + } + + /** + * Get the HTML fragment identifier for a given preferences section. This is the leading part + * of the provided section name, up to a slash (if there is one). + * @param string $section A section name, as used in a preference definition. + * @return string + */ + public static function getSectionFragmentId( $section ) { + $sectionId = preg_replace( '#/.*$#', '', $section ); + return 'mw-prefsection-' . $sectionId; } /** @@ -191,7 +234,7 @@ } // Ignore "is global" checkboxes - if ( substr( $name, -strlen( '-global' ) ) === '-global' ) { + if ( static::isGlobalPrefName( $name ) ) { return false; } @@ -211,6 +254,36 @@ } /** + * A convenience function to check if a preference name is for a global one. + * @param string $name The name to check. + * @return bool + */ + public static function isGlobalPrefName( $name ) { + return static::strEndsWith( $name, static::GLOBAL_EXCEPTION_SUFFIX ); + } + + /** + * A convenience function to check if a preference name is for a local-exception preference. + * @param string $name The name to check. + * @return bool + */ + public static function isLocalPrefName( $name ) { + return static::strEndsWith( $name, static::LOCAL_EXCEPTION_SUFFIX ); + } + + /** + * A convenience function to check a string to see if it ends in a given suffix. + * @todo This could probably exist somewhere like StringUtils. + * @param string $name The name to check. + * @param string $suffix The suffix to check for. + * @return bool + */ + protected static function strEndsWith( $name, $suffix ) { + $nameSuffix = substr( $name, -strlen( $suffix ) ); + return ( $nameSuffix === $suffix ); + } + + /** * Checks if the user is globalized. * @return bool */ diff --git a/includes/GlobalPreferencesForm.php b/includes/GlobalPreferencesForm.php index 5c36867..b872421 100644 --- a/includes/GlobalPreferencesForm.php +++ b/includes/GlobalPreferencesForm.php @@ -4,6 +4,7 @@ use Html; use IContextSource; +use MediaWiki\MediaWikiServices; use PreferencesForm; /** @@ -33,6 +34,28 @@ * @return string */ function getBody() { + // Load global values for any preferences with local exceptions. + /** @var GlobalPreferencesFactory $globalPreferences */ + $globalPreferences = MediaWikiServices::getInstance()->getPreferencesFactory(); + $globalPreferences->setUser( $this->getUser() ); + $globalPrefValues = $globalPreferences->getGlobalPreferencesValues(); + foreach ( $this->mFlatFields as $fieldName => $field ) { + // Ignore this if it's a global or a local-exception preference. + $isGlobal = GlobalPreferencesFactory::isGlobalPrefName( $fieldName ); + $isLocalException = GlobalPreferencesFactory::isLocalPrefName( $fieldName ); + if ( $isGlobal || $isLocalException ) { + continue; + } + // See if it's got a local exception. It should also always then have a global value, + // but we check anyway just to be sure. + $localExceptionName = $fieldName . GlobalPreferencesFactory::LOCAL_EXCEPTION_SUFFIX; + $hasGlobalValue = isset( $globalPrefValues[ $fieldName ] ); + if ( $this->getUser()->getOption( $localExceptionName ) && $hasGlobalValue ) { + // And if it does, use the global value. + $this->mFieldData[ $fieldName ] = $globalPrefValues[ $fieldName ]; + } + } + // Add help text to the top of every section. foreach ( $this->getPreferenceSections() as $section ) { $colHeaderText = Html::element( @@ -47,6 +70,7 @@ ); $this->addHeaderText( $secHeader, $section ); } + return parent::getBody(); } } diff --git a/includes/Hooks.php b/includes/Hooks.php index bd2dd72..83e9e1b 100644 --- a/includes/Hooks.php +++ b/includes/Hooks.php @@ -6,10 +6,27 @@ use Language; use MediaWiki\Auth\AuthManager; use MediaWiki\MediaWikiServices; +use OutputPage; use PreferencesForm; +use Skin; use User; class Hooks { + + /** + * Allows last minute changes to the output page, e.g. adding of CSS or JavaScript by extensions. + * @link https://www.mediawiki.org/wiki/Manual:Hooks/BeforePageDisplay + * @param OutputPage &$out The output page. + * @param Skin &$skin The skin. Not used. + */ + public static function onBeforePageDisplay( OutputPage &$out, Skin &$skin ) { + if ( $out->getTitle()->isSpecial( 'Preferences' ) ) { + // Add module styles and scripts separately + // so non-JS users get the styles quicker and to avoid a FOUC. + $out->addModuleStyles( 'ext.GlobalPreferences.local-nojs' ); + $out->addModules( 'ext.GlobalPreferences.local' ); + } + } /** * Load global preferences. @@ -28,6 +45,10 @@ // Overwrite all options that have a global counterpart. foreach ( $globalPreferences->getGlobalPreferencesValues() as $optName => $globalValue ) { + // But not if it has a local exception. + if ( $user->getOption( $optName . GlobalPreferencesFactory::LOCAL_EXCEPTION_SUFFIX ) ) { + continue; + } $options[ $optName ] = $globalValue; } } @@ -51,11 +72,10 @@ foreach ( $options as $optName => $optVal ) { // Ignore if ends in "-global". - if ( substr( $optName, -strlen( '-global' ) ) === '-global' ) { + if ( GlobalPreferencesFactory::isGlobalPrefName( $optName ) ) { unset( $options[ $optName ] ); } } - return true; } @@ -82,10 +102,11 @@ $prefs = []; foreach ( $formData as $name => $value ) { - // If this is the '-global' counterpart of a preference. - if ( substr( $name, -strlen( 'global' ) ) === 'global' && $value === true ) { + // If this is the '-global' counterpart to a preference. + if ( GlobalPreferencesFactory::isGlobalPrefName( $name ) && $value === true ) { // Determine the real name of the preference. - $realName = substr( $name, 0, -strlen( '-global' ) ); + $suffixLen = strlen( GlobalPreferencesFactory::GLOBAL_EXCEPTION_SUFFIX ); + $realName = substr( $name, 0, -$suffixLen ); if ( isset( $formData[$realName] ) ) { // Store normal preference values. $prefs[$realName] = $formData[$realName]; diff --git a/includes/SpecialGlobalPreferences.php b/includes/SpecialGlobalPreferences.php index fc0d235..204623c 100644 --- a/includes/SpecialGlobalPreferences.php +++ b/includes/SpecialGlobalPreferences.php @@ -57,8 +57,8 @@ // Add module styles and scripts separately // so non-JS users get the styles quicker and to avoid a FOUC. - $this->getOutput()->addModuleStyles( 'ext.GlobalPreferences.special.nojs' ); - $this->getOutput()->addModules( 'ext.GlobalPreferences.special' ); + $this->getOutput()->addModuleStyles( 'ext.GlobalPreferences.global-nojs' ); + $this->getOutput()->addModules( 'ext.GlobalPreferences.global' ); parent::execute( $par ); } diff --git a/resources/ext.GlobalPreferences.special.nojs.css b/resources/ext.GlobalPreferences.global-nojs.css similarity index 100% rename from resources/ext.GlobalPreferences.special.nojs.css rename to resources/ext.GlobalPreferences.global-nojs.css diff --git a/resources/ext.GlobalPreferences.special.css b/resources/ext.GlobalPreferences.global.css similarity index 100% rename from resources/ext.GlobalPreferences.special.css rename to resources/ext.GlobalPreferences.global.css diff --git a/resources/ext.GlobalPreferences.special.js b/resources/ext.GlobalPreferences.global.js similarity index 100% rename from resources/ext.GlobalPreferences.special.js rename to resources/ext.GlobalPreferences.global.js diff --git a/resources/ext.GlobalPreferences.local-nojs.css b/resources/ext.GlobalPreferences.local-nojs.css new file mode 100644 index 0000000..7ac2e44 --- /dev/null +++ b/resources/ext.GlobalPreferences.local-nojs.css @@ -0,0 +1,3 @@ +.mw-globalprefs-local-exception label { + font-size: smaller; +} diff --git a/resources/ext.GlobalPreferences.local.css b/resources/ext.GlobalPreferences.local.css new file mode 100644 index 0000000..3bd33cf --- /dev/null +++ b/resources/ext.GlobalPreferences.local.css @@ -0,0 +1 @@ +/* @TODO hover styles etc. */ diff --git a/resources/ext.GlobalPreferences.local.js b/resources/ext.GlobalPreferences.local.js new file mode 100644 index 0000000..5f68fbe --- /dev/null +++ b/resources/ext.GlobalPreferences.local.js @@ -0,0 +1 @@ +// @TODO re-enable global preferences. T178267 -- To view, visit https://gerrit.wikimedia.org/r/383304 To unsubscribe, visit https://gerrit.wikimedia.org/r/settings Gerrit-MessageType: merged Gerrit-Change-Id: I8e15f1570f314cae63a38325589f3d4811919bc6 Gerrit-PatchSet: 12 Gerrit-Project: mediawiki/extensions/GlobalPreferences Gerrit-Branch: master Gerrit-Owner: Samwilson <s...@samwilson.id.au> Gerrit-Reviewer: Legoktm <lego...@member.fsf.org> Gerrit-Reviewer: MaxSem <maxsem.w...@gmail.com> Gerrit-Reviewer: Samwilson <s...@samwilson.id.au> Gerrit-Reviewer: jenkins-bot <> _______________________________________________ MediaWiki-commits mailing list MediaWiki-commits@lists.wikimedia.org https://lists.wikimedia.org/mailman/listinfo/mediawiki-commits