Add ability to load plain CSS files at the bottom
authorGilles Dubuc <gdubuc@wikimedia.org>
Mon, 25 May 2015 14:04:57 +0000 (16:04 +0200)
committerOri.livneh <ori@wikimedia.org>
Mon, 25 May 2015 21:10:14 +0000 (21:10 +0000)
Currently all styles modules added to the page using
addModuleStyles are put into the head, regardless
of their "position" value.

Bug: T97420
Change-Id: Ie4287e17d6f298cc63f42f257b1f67ee36961b77

includes/OutputPage.php
includes/resourceloader/ResourceLoaderFileModule.php
includes/resourceloader/ResourceLoaderImageModule.php
includes/resourceloader/ResourceLoaderModule.php
resources/Resources.php

index 770cf47..a3a5a27 100644 (file)
@@ -591,6 +591,19 @@ class OutputPage extends ContextSource {
         * @return array Array of module names
         */
        public function getModuleStyles( $filter = false, $position = null ) {
+               // T97420
+               $resourceLoader = $this->getResourceLoader();
+
+               foreach ( $this->mModuleStyles as $val ) {
+                       $module = $resourceLoader->getModule( $val );
+
+                       if ( $module instanceof ResourceLoaderModule && $module->isPositionDefault() ) {
+                               $warning = __METHOD__ . ': style module should define its position explicitly: ' . $val . ' ' . get_class( $module );
+                               wfDebugLog( 'resourceloader', $warning );
+                               wfLogWarning( $warning );
+                       }
+               }
+
                return $this->getModules( $filter, $position, 'mModuleStyles' );
        }
 
@@ -3008,11 +3021,17 @@ class OutputPage extends ContextSource {
                // Scripts "only" requests marked for bottom inclusion
                // If we're in the <head>, use load() calls rather than <script src="..."> tags
                $links = array();
+
                $links[] = $this->makeResourceLoaderLink( $this->getModuleScripts( true, 'bottom' ),
                        ResourceLoaderModule::TYPE_SCRIPTS, /* $useESI = */ false, /* $extraQuery = */ array(),
                        /* $loadCall = */ $inHead
                );
 
+               $links[] = $this->makeResourceLoaderLink( $this->getModuleStyles( true, 'bottom' ),
+                       ResourceLoaderModule::TYPE_STYLES, /* $useESI = */ false, /* $extraQuery = */ array(),
+                       /* $loadCall = */ $inHead
+               );
+
                // Modules requests - let the client calculate dependencies and batch requests as it likes
                // Only load modules that have marked themselves for loading at the bottom
                $modules = $this->getModules( true, 'bottom' );
@@ -3070,6 +3089,9 @@ class OutputPage extends ContextSource {
         * @return string
         */
        function getBottomScripts() {
+               // In case the skin wants to add bottom CSS
+               $this->getSkin()->setupSkinUserCss( $this );
+
                // Optimise jQuery ready event cross-browser.
                // This also enforces $.isReady to be true at </body> which fixes the
                // mw.loader bug in Firefox with using document.write between </body>
@@ -3581,7 +3603,7 @@ class OutputPage extends ContextSource {
                $otherTags = ''; // Tags to append after the normal <link> tags
                $resourceLoader = $this->getResourceLoader();
 
-               $moduleStyles = $this->getModuleStyles();
+               $moduleStyles = $this->getModuleStyles( true, 'top' );
 
                // Per-site custom styles
                $moduleStyles[] = 'site';
index 3569bf3..0ee2e7d 100644 (file)
@@ -272,8 +272,9 @@ class ResourceLoaderFileModule extends ResourceLoaderModule {
                                        $this->{$member} = $option;
                                        break;
                                // Single strings
-                               case 'group':
                                case 'position':
+                                       $this->isPositionDefined = true;
+                               case 'group':
                                case 'skipFunction':
                                        $this->{$member} = (string)$option;
                                        break;
index 53940e7..eaff4ab 100644 (file)
@@ -45,6 +45,9 @@ class ResourceLoaderImageModule extends ResourceLoaderModule {
        protected $selectorWithVariant = '.{prefix}-{name}-{variant}';
        protected $targets = array( 'desktop', 'mobile' );
 
+       /** @var string Position on the page to load this module at */
+       protected $position = 'bottom';
+
        /**
         * Constructs a new module from an options array.
         *
@@ -151,6 +154,8 @@ class ResourceLoaderImageModule extends ResourceLoaderModule {
                                        $this->{$member} = $option;
                                        break;
 
+                               case 'position':
+                                       $this->isPositionDefined = true;
                                case 'prefix':
                                case 'selectorWithoutVariant':
                                case 'selectorWithVariant':
@@ -400,4 +405,17 @@ class ResourceLoaderImageModule extends ResourceLoaderModule {
 
                return $localBasePath;
        }
+
+       /**
+        * @return string
+        */
+       public function getPosition() {
+               $this->loadFromDefinition();
+               return $this->position;
+       }
+
+       public function isPositionDefault() {
+               $this->loadFromDefinition();
+               return parent::isPositionDefault();
+       }
 }
index 117dce6..57634ab 100644 (file)
@@ -65,6 +65,10 @@ abstract class ResourceLoaderModule {
        // In-object cache for version hash
        protected $versionHash = array();
 
+       // Whether the position returned by getPosition() is defined in the module configuration
+       // and not a default value
+       protected $isPositionDefined = false;
+
        /**
         * @var Config
         */
@@ -285,6 +289,19 @@ abstract class ResourceLoaderModule {
                return 'bottom';
        }
 
+       /**
+        * Whether the position returned by getPosition() is a default value or comes from the module
+        * definition. This method is meant to be short-lived, and is only useful until classes added via
+        * addModuleStyles with a default value define an explicit position. See getModuleStyles() in
+        * OutputPage for the related migration warning.
+        *
+        * @return bool
+        * @since  1.26
+        */
+       public function isPositionDefault() {
+               return !$this->isPositionDefined;
+       }
+
        /**
         * Whether this module's JS expects to work without the client-side ResourceLoader module.
         * Returning true from this function will prevent mw.loader.state() call from being
index 3943aae..b0cd932 100644 (file)
@@ -104,6 +104,7 @@ return array(
                ),
        ),
        'mediawiki.skinning.interface' => array(
+               'position' => 'top',
                'class' => 'ResourceLoaderSkinModule',
                // Used in the web installer. Test it after modifying this definition!
                'styles' => array(
@@ -114,6 +115,7 @@ return array(
        ),
 
        'mediawiki.skinning.content.parsoid' => array(
+               'position' => 'top',
                // Style Parsoid HTML+RDFa output consistent with wikitext from PHP parser
                // with the interface.css styles; skinStyles should be used if your
                // skin over-rides common content styling.
@@ -124,6 +126,7 @@ return array(
        ),
 
        'mediawiki.skinning.content.externallinks' => array(
+               'position' => 'top',
                'styles' => array(
                        'resources/src/mediawiki.skinning/content.externallinks.css' => array( 'media' => 'screen' ),
                ),
@@ -337,6 +340,13 @@ return array(
 
        'jquery.ui.core' => array(
                'scripts' => 'resources/lib/jquery.ui/jquery.ui.core.js',
+               'dependencies' => array(
+                       'jquery.ui.core.styles',
+               ),
+               'group' => 'jquery.ui',
+       ),
+       'jquery.ui.core.styles' => array(
+               'position' => 'top',
                'skinStyles' => array(
                        'default' => array(
                                'resources/lib/jquery.ui/themes/smoothness/jquery.ui.core.css',
@@ -850,6 +860,7 @@ return array(
                ),
        ),
        'mediawiki.content.json' => array(
+               'position' => 'top',
                'styles' => 'resources/src/mediawiki/mediawiki.content.json.css',
        ),
        'mediawiki.confirmCloseWindow' => array(
@@ -922,6 +933,7 @@ return array(
        ),
 
        'mediawiki.helplink' => array(
+               'position' => 'top',
                'styles' => array(
                        'resources/src/mediawiki/mediawiki.helplink.less',
                ),
@@ -1026,6 +1038,7 @@ return array(
                ),
        ),
        'mediawiki.sectionAnchor' => array(
+               'position' => 'top',
                // Back-compat to hide it on cached pages (T18691; Ie9e334e973; 2015-03-17)
                'styles' => 'resources/src/mediawiki/mediawiki.sectionAnchor.css',
                'targets' => array( 'desktop', 'mobile' ),
@@ -1101,8 +1114,8 @@ return array(
                'position' => 'top',
        ),
        'mediawiki.action.edit.styles' => array(
-               'styles' => 'resources/src/mediawiki.action/mediawiki.action.edit.styles.css',
                'position' => 'top',
+               'styles' => 'resources/src/mediawiki.action/mediawiki.action.edit.styles.css',
        ),
        'mediawiki.action.edit.collapsibleFooter' => array(
                'scripts' => 'resources/src/mediawiki.action/mediawiki.action.edit.collapsibleFooter.js',
@@ -1153,6 +1166,7 @@ return array(
                'group' => 'mediawiki.action.history',
        ),
        'mediawiki.action.history.diff' => array(
+               'position' => 'top',
                'styles' => array(
                        'resources/src/mediawiki.action/mediawiki.action.history.diff.css',
                        'resources/src/mediawiki.action/mediawiki.action.history.diff.print.css' => array(
@@ -1179,6 +1193,7 @@ return array(
                ),
        ),
        'mediawiki.action.view.categoryPage.styles' => array(
+               'position' => 'top',
                'styles' => 'resources/src/mediawiki.action/mediawiki.action.view.categoryPage.less',
                'targets' => array( 'desktop', 'mobile' )
        ),
@@ -1204,8 +1219,8 @@ return array(
                'position' => 'top',
        ),
        'mediawiki.action.view.redirectPage' => array(
-               'styles' => 'resources/src/mediawiki.action/mediawiki.action.view.redirectPage.css',
                'position' => 'top',
+               'styles' => 'resources/src/mediawiki.action/mediawiki.action.view.redirectPage.css',
        ),
        'mediawiki.action.view.rightClickEdit' => array(
                'scripts' => 'resources/src/mediawiki.action/mediawiki.action.view.rightClickEdit.js',
@@ -1384,6 +1399,7 @@ return array(
        /* MediaWiki Special pages */
 
        'mediawiki.special' => array(
+               'position' => 'top',
                'scripts' => 'resources/src/mediawiki.special/mediawiki.special.js',
                'styles' => 'resources/src/mediawiki.special/mediawiki.special.css',
        ),
@@ -1402,9 +1418,11 @@ return array(
                ),
        ),
        'mediawiki.special.changeslist' => array(
+               'position' => 'top',
                'styles' => 'resources/src/mediawiki.special/mediawiki.special.changeslist.css',
        ),
        'mediawiki.special.changeslist.legend' => array(
+               'position' => 'top',
                'styles' => 'resources/src/mediawiki.special/mediawiki.special.changeslist.legend.css',
        ),
        'mediawiki.special.changeslist.legend.js' => array(
@@ -1415,6 +1433,7 @@ return array(
                ),
        ),
        'mediawiki.special.changeslist.enhanced' => array(
+               'position' => 'top',
                'styles' => 'resources/src/mediawiki.special/mediawiki.special.changeslist.enhanced.css',
        ),
        'mediawiki.special.edittags' => array(
@@ -1442,6 +1461,7 @@ return array(
                'scripts' => 'resources/src/mediawiki.special/mediawiki.special.pageLanguage.js',
        ),
        'mediawiki.special.pagesWithProp' => array(
+               'position' => 'top',
                'styles' => 'resources/src/mediawiki.special/mediawiki.special.pagesWithProp.css',
        ),
        'mediawiki.special.preferences' => array(
@@ -1464,6 +1484,7 @@ return array(
                'position' => 'top',
        ),
        'mediawiki.special.search' => array(
+               'position' => 'top',
                'scripts' => 'resources/src/mediawiki.special/mediawiki.special.search.js',
                'styles' => 'resources/src/mediawiki.special/mediawiki.special.search.css',
                'messages' => array(
@@ -1508,16 +1529,16 @@ return array(
                'position' => 'top',
        ),
        'mediawiki.special.userlogin.signup.styles' => array(
+               'position' => 'top',
                'styles' => array(
                        'resources/src/mediawiki.special/mediawiki.special.userlogin.signup.css',
                ),
-               'position' => 'top',
        ),
        'mediawiki.special.userlogin.login.styles' => array(
+               'position' => 'top',
                'styles' => array(
                        'resources/src/mediawiki.special/mediawiki.special.userlogin.login.css',
                ),
-               'position' => 'top',
        ),
        'mediawiki.special.userlogin.common.js' => array(
                'scripts' => array(
@@ -1596,6 +1617,7 @@ return array(
                'position' => 'top',
        ),
        'mediawiki.legacy.commonPrint' => array(
+               'position' => 'top',
                'styles' => array(
                        'resources/src/mediawiki.legacy/commonPrint.css' => array( 'media' => 'print' )
                ),
@@ -1607,11 +1629,13 @@ return array(
        ),
        'mediawiki.legacy.shared' => array(
                // Used in the web installer. Test it after modifying this definition!
+               'position' => 'top',
                'styles' => array(
                        'resources/src/mediawiki.legacy/shared.css' => array( 'media' => 'screen' )
                ),
        ),
        'mediawiki.legacy.oldshared' => array(
+               'position' => 'top',
                'styles' => array(
                        'resources/src/mediawiki.legacy/oldshared.css' => array( 'media' => 'screen' )
                ),
@@ -1625,78 +1649,78 @@ return array(
        /* MediaWiki UI */
 
        'mediawiki.ui' => array(
+               'position' => 'top',
                'skinStyles' => array(
                        'default' => array(
                                'resources/src/mediawiki.ui/default.less',
                        ),
                ),
-               'position' => 'top',
                'targets' => array( 'desktop', 'mobile' ),
        ),
        'mediawiki.ui.checkbox' => array(
+               'position' => 'top',
                'skinStyles' => array(
                        'default' => array(
                                'resources/src/mediawiki.ui/components/checkbox.less',
                        ),
                ),
-               'position' => 'top',
                'targets' => array( 'desktop', 'mobile' ),
        ),
        'mediawiki.ui.radio' => array(
+               'position' => 'top',
                'skinStyles' => array(
                        'default' => array(
                                'resources/src/mediawiki.ui/components/radio.less',
                        ),
                ),
-               'position' => 'top',
                'targets' => array( 'desktop', 'mobile' ),
        ),
        // Lightweight module for anchor styles
        'mediawiki.ui.anchor' => array(
+               'position' => 'top',
                'skinStyles' => array(
                        'default' => array(
                                'resources/src/mediawiki.ui/components/anchors.less',
                        ),
                ),
-               'position' => 'top',
                'targets' => array( 'desktop', 'mobile' ),
        ),
        // Lightweight module for button styles
        'mediawiki.ui.button' => array(
+               'position' => 'top',
                'skinStyles' => array(
                        'default' => array(
                                'resources/src/mediawiki.ui/components/buttons.less',
                        ),
                ),
-               'position' => 'top',
                'targets' => array( 'desktop', 'mobile' ),
        ),
        'mediawiki.ui.input' => array(
+               'position' => 'top',
                'skinStyles' => array(
                        'default' => array(
                                'resources/src/mediawiki.ui/components/inputs.less',
                        ),
                ),
-               'position' => 'top',
                'targets' => array( 'desktop', 'mobile' ),
        ),
        'mediawiki.ui.icon' => array(
+               'position' => 'top',
                'skinStyles' => array(
                        'default' => array(
                                'resources/src/mediawiki.ui/components/icons.less',
                        ),
                ),
-               'position' => 'top',
                'targets' => array( 'desktop', 'mobile' ),
        ),
        // Lightweight module for text styles
        'mediawiki.ui.text' => array(
+               'position' => 'top',
                'skinStyles' => array(
                        'default' => array(
                                'resources/src/mediawiki.ui/components/text.less',
                        ),
                ),
-               'position' => 'top',
                'targets' => array( 'desktop', 'mobile' ),
        ),
 
@@ -1775,6 +1799,7 @@ return array(
        ),
 
        'oojs-ui.styles.icons' => array(
+               'position' => 'top',
                'class' => 'ResourceLoaderImageModule',
                'localBasePath' => "$IP/resources/lib/oojs-ui/themes/mediawiki",
                'data' => 'icons.json',
@@ -1782,16 +1807,19 @@ return array(
                'selectorWithVariant' => '.oo-ui-image-{variant} .oo-ui-icon-{name}, .oo-ui-image-{variant}.oo-ui-icon-{name}, .mw-ui-icon-{name}-{variant}:after, .mw-ui-icon-{name}-{variant}:before, .mw-ui-hovericon:hover .mw-ui-icon-{name}-{variant}-hover:before, .mw-ui-hovericon.mw-ui-icon-{name}-{variant}-hover:hover:before',
        ),
        'oojs-ui.styles.indicators' => array(
+               'position' => 'top',
                'class' => 'ResourceLoaderImageModule',
                'localBasePath' => "$IP/resources/lib/oojs-ui/themes/mediawiki",
                'data' => 'indicators.json',
        ),
        'oojs-ui.styles.textures' => array(
+               'position' => 'top',
                'class' => 'ResourceLoaderImageModule',
                'localBasePath' => "$IP/resources/lib/oojs-ui/themes/mediawiki",
                'data' => 'textures.json',
        ),
        'oojs-ui.styles.icons-alerts' => array(
+               'position' => 'top',
                'class' => 'ResourceLoaderImageModule',
                'localBasePath' => "$IP/resources/lib/oojs-ui/themes/mediawiki",
                'data' => 'icons-alerts.json',
@@ -1799,6 +1827,7 @@ return array(
                'selectorWithVariant' => '.oo-ui-image-{variant} .oo-ui-icon-{name}, .oo-ui-image-{variant}.oo-ui-icon-{name}, .mw-ui-icon-{name}-{variant}:after, .mw-ui-icon-{name}-{variant}:before, .mw-ui-hovericon:hover .mw-ui-icon-{name}-{variant}-hover:before, .mw-ui-hovericon.mw-ui-icon-{name}-{variant}-hover:hover:before',
        ),
        'oojs-ui.styles.icons-content' => array(
+               'position' => 'top',
                'class' => 'ResourceLoaderImageModule',
                'localBasePath' => "$IP/resources/lib/oojs-ui/themes/mediawiki",
                'data' => 'icons-content.json',
@@ -1806,6 +1835,7 @@ return array(
                'selectorWithVariant' => '.oo-ui-image-{variant} .oo-ui-icon-{name}, .oo-ui-image-{variant}.oo-ui-icon-{name}, .mw-ui-icon-{name}-{variant}:after, .mw-ui-icon-{name}-{variant}:before, .mw-ui-hovericon:hover .mw-ui-icon-{name}-{variant}-hover:before, .mw-ui-hovericon.mw-ui-icon-{name}-{variant}-hover:hover:before',
        ),
        'oojs-ui.styles.icons-editing-advanced' => array(
+               'position' => 'top',
                'class' => 'ResourceLoaderImageModule',
                'localBasePath' => "$IP/resources/lib/oojs-ui/themes/mediawiki",
                'data' => 'icons-editing-advanced.json',
@@ -1813,6 +1843,7 @@ return array(
                'selectorWithVariant' => '.oo-ui-image-{variant} .oo-ui-icon-{name}, .oo-ui-image-{variant}.oo-ui-icon-{name}, .mw-ui-icon-{name}-{variant}:after, .mw-ui-icon-{name}-{variant}:before, .mw-ui-hovericon:hover .mw-ui-icon-{name}-{variant}-hover:before, .mw-ui-hovericon.mw-ui-icon-{name}-{variant}-hover:hover:before',
        ),
        'oojs-ui.styles.icons-editing-core' => array(
+               'position' => 'top',
                'class' => 'ResourceLoaderImageModule',
                'localBasePath' => "$IP/resources/lib/oojs-ui/themes/mediawiki",
                'data' => 'icons-editing-core.json',
@@ -1820,6 +1851,7 @@ return array(
                'selectorWithVariant' => '.oo-ui-image-{variant} .oo-ui-icon-{name}, .oo-ui-image-{variant}.oo-ui-icon-{name}, .mw-ui-icon-{name}-{variant}:after, .mw-ui-icon-{name}-{variant}:before, .mw-ui-hovericon:hover .mw-ui-icon-{name}-{variant}-hover:before, .mw-ui-hovericon.mw-ui-icon-{name}-{variant}-hover:hover:before',
        ),
        'oojs-ui.styles.icons-editing-list' => array(
+               'position' => 'top',
                'class' => 'ResourceLoaderImageModule',
                'localBasePath' => "$IP/resources/lib/oojs-ui/themes/mediawiki",
                'data' => 'icons-editing-list.json',
@@ -1827,6 +1859,7 @@ return array(
                'selectorWithVariant' => '.oo-ui-image-{variant} .oo-ui-icon-{name}, .oo-ui-image-{variant}.oo-ui-icon-{name}, .mw-ui-icon-{name}-{variant}:after, .mw-ui-icon-{name}-{variant}:before, .mw-ui-hovericon:hover .mw-ui-icon-{name}-{variant}-hover:before, .mw-ui-hovericon.mw-ui-icon-{name}-{variant}-hover:hover:before',
        ),
        'oojs-ui.styles.icons-editing-styling' => array(
+               'position' => 'top',
                'class' => 'ResourceLoaderImageModule',
                'localBasePath' => "$IP/resources/lib/oojs-ui/themes/mediawiki",
                'data' => 'icons-editing-styling.json',
@@ -1834,6 +1867,7 @@ return array(
                'selectorWithVariant' => '.oo-ui-image-{variant} .oo-ui-icon-{name}, .oo-ui-image-{variant}.oo-ui-icon-{name}, .mw-ui-icon-{name}-{variant}:after, .mw-ui-icon-{name}-{variant}:before, .mw-ui-hovericon:hover .mw-ui-icon-{name}-{variant}-hover:before, .mw-ui-hovericon.mw-ui-icon-{name}-{variant}-hover:hover:before',
        ),
        'oojs-ui.styles.icons-interactions' => array(
+               'position' => 'top',
                'class' => 'ResourceLoaderImageModule',
                'localBasePath' => "$IP/resources/lib/oojs-ui/themes/mediawiki",
                'data' => 'icons-interactions.json',
@@ -1841,6 +1875,7 @@ return array(
                'selectorWithVariant' => '.oo-ui-image-{variant} .oo-ui-icon-{name}, .oo-ui-image-{variant}.oo-ui-icon-{name}, .mw-ui-icon-{name}-{variant}:after, .mw-ui-icon-{name}-{variant}:before, .mw-ui-hovericon:hover .mw-ui-icon-{name}-{variant}-hover:before, .mw-ui-hovericon.mw-ui-icon-{name}-{variant}-hover:hover:before',
        ),
        'oojs-ui.styles.icons-layout' => array(
+               'position' => 'top',
                'class' => 'ResourceLoaderImageModule',
                'localBasePath' => "$IP/resources/lib/oojs-ui/themes/mediawiki",
                'data' => 'icons-layout.json',
@@ -1848,6 +1883,7 @@ return array(
                'selectorWithVariant' => '.oo-ui-image-{variant} .oo-ui-icon-{name}, .oo-ui-image-{variant}.oo-ui-icon-{name}, .mw-ui-icon-{name}-{variant}:after, .mw-ui-icon-{name}-{variant}:before, .mw-ui-hovericon:hover .mw-ui-icon-{name}-{variant}-hover:before, .mw-ui-hovericon.mw-ui-icon-{name}-{variant}-hover:hover:before',
        ),
        'oojs-ui.styles.icons-location' => array(
+               'position' => 'top',
                'class' => 'ResourceLoaderImageModule',
                'localBasePath' => "$IP/resources/lib/oojs-ui/themes/mediawiki",
                'data' => 'icons-location.json',
@@ -1855,6 +1891,7 @@ return array(
                'selectorWithVariant' => '.oo-ui-image-{variant} .oo-ui-icon-{name}, .oo-ui-image-{variant}.oo-ui-icon-{name}, .mw-ui-icon-{name}-{variant}:after, .mw-ui-icon-{name}-{variant}:before, .mw-ui-hovericon:hover .mw-ui-icon-{name}-{variant}-hover:before, .mw-ui-hovericon.mw-ui-icon-{name}-{variant}-hover:hover:before',
        ),
        'oojs-ui.styles.icons-media' => array(
+               'position' => 'top',
                'class' => 'ResourceLoaderImageModule',
                'localBasePath' => "$IP/resources/lib/oojs-ui/themes/mediawiki",
                'data' => 'icons-media.json',
@@ -1862,6 +1899,7 @@ return array(
                'selectorWithVariant' => '.oo-ui-image-{variant} .oo-ui-icon-{name}, .oo-ui-image-{variant}.oo-ui-icon-{name}, .mw-ui-icon-{name}-{variant}:after, .mw-ui-icon-{name}-{variant}:before, .mw-ui-hovericon:hover .mw-ui-icon-{name}-{variant}-hover:before, .mw-ui-hovericon.mw-ui-icon-{name}-{variant}-hover:hover:before',
        ),
        'oojs-ui.styles.icons-moderation' => array(
+               'position' => 'top',
                'class' => 'ResourceLoaderImageModule',
                'localBasePath' => "$IP/resources/lib/oojs-ui/themes/mediawiki",
                'data' => 'icons-moderation.json',
@@ -1869,6 +1907,7 @@ return array(
                'selectorWithVariant' => '.oo-ui-image-{variant} .oo-ui-icon-{name}, .oo-ui-image-{variant}.oo-ui-icon-{name}, .mw-ui-icon-{name}-{variant}:after, .mw-ui-icon-{name}-{variant}:before, .mw-ui-hovericon:hover .mw-ui-icon-{name}-{variant}-hover:before, .mw-ui-hovericon.mw-ui-icon-{name}-{variant}-hover:hover:before',
        ),
        'oojs-ui.styles.icons-movement' => array(
+               'position' => 'top',
                'class' => 'ResourceLoaderImageModule',
                'localBasePath' => "$IP/resources/lib/oojs-ui/themes/mediawiki",
                'data' => 'icons-movement.json',
@@ -1876,6 +1915,7 @@ return array(
                'selectorWithVariant' => '.oo-ui-image-{variant} .oo-ui-icon-{name}, .oo-ui-image-{variant}.oo-ui-icon-{name}, .mw-ui-icon-{name}-{variant}:after, .mw-ui-icon-{name}-{variant}:before, .mw-ui-hovericon:hover .mw-ui-icon-{name}-{variant}-hover:before, .mw-ui-hovericon.mw-ui-icon-{name}-{variant}-hover:hover:before',
        ),
        'oojs-ui.styles.icons-user' => array(
+               'position' => 'top',
                'class' => 'ResourceLoaderImageModule',
                'localBasePath' => "$IP/resources/lib/oojs-ui/themes/mediawiki",
                'data' => 'icons-user.json',
@@ -1883,6 +1923,7 @@ return array(
                'selectorWithVariant' => '.oo-ui-image-{variant} .oo-ui-icon-{name}, .oo-ui-image-{variant}.oo-ui-icon-{name}, .mw-ui-icon-{name}-{variant}:after, .mw-ui-icon-{name}-{variant}:before, .mw-ui-hovericon:hover .mw-ui-icon-{name}-{variant}-hover:before, .mw-ui-hovericon.mw-ui-icon-{name}-{variant}-hover:hover:before',
        ),
        'oojs-ui.styles.icons-wikimedia' => array(
+               'position' => 'top',
                'class' => 'ResourceLoaderImageModule',
                'localBasePath' => "$IP/resources/lib/oojs-ui/themes/mediawiki",
                'data' => 'icons-wikimedia.json',