Foxtrott has uploaded a new change for review.

  https://gerrit.wikimedia.org/r/89480


Change subject: Reworking the extension
......................................................................

Reworking the extension

* adding a singleton to manage Bootstrap
* adding a resource loader module capable of compiling several LESS files in 
one single context
* removing the unused fixes.less

Change-Id: Ib69e0a7764dafe7346b73e1eae630ca141819df6
---
A Bootstrap.class.php
M Bootstrap.php
A ResourceLoaderBootstrapModule.php
D fixes.less
4 files changed, 345 insertions(+), 89 deletions(-)


  git pull ssh://gerrit.wikimedia.org:29418/mediawiki/extensions/Bootstrap 
refs/changes/80/89480/1

diff --git a/Bootstrap.class.php b/Bootstrap.class.php
new file mode 100644
index 0000000..09277bd
--- /dev/null
+++ b/Bootstrap.class.php
@@ -0,0 +1,213 @@
+<?php
+/**
+ * File holding the Bootstrap class
+ *
+ * @copyright (C) 2013, Stephan Gambke
+ * @license   http://www.gnu.org/licenses/gpl-3.0.html GNU General Public 
License, version 3 (or later)
+ *
+ * This file is part of the MediaWiki extension Bootstrap.
+ * The Bootstrap extension is free software: you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * The Bootstrap extension is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ * @file
+ * @ingroup   Bootstrap
+ */
+
+class Bootstrap {
+
+
+       static private $bootstrap = null;
+       static private $moduleDescriptions = array(
+               'variables'            => array( 'styles' => 'variables' ),
+               'mixins'               => array( 'styles' => 'mixins' ),
+               'normalize'            => array( 'styles' => 'normalize' ),
+               'print'                => array( 'styles' => 'print' ),
+               'scaffolding'          => array( 'styles' => 'scaffolding' ),
+               'type'                 => array( 'styles' => 'type' ),
+               'code'                 => array( 'styles' => 'code' ),
+               'grid'                 => array( 'styles' => 'grid' ),
+               'tables'               => array( 'styles' => 'tables' ),
+               'forms'                => array( 'styles' => 'forms' ),
+               'buttons'              => array( 'styles' => 'buttons' ),
+               'component-animations' => array( 'styles' => 
'component-animations' ),
+               'glyphicons'           => array( 'styles' => 'glyphicons' ),
+               'dropdowns'            => array( 'styles' => 'dropdowns' ),
+               'button-groups'        => array( 'styles' => 'button-groups' ),
+               'input-groups'         => array( 'styles' => 'input-groups' ),
+               'navs'                 => array( 'styles' => 'navs' ),
+               'navbar'               => array( 'styles' => 'navbar' ),
+               'breadcrumbs'          => array( 'styles' => 'breadcrumbs' ),
+               'pagination'           => array( 'styles' => 'pagination' ),
+               'pager'                => array( 'styles' => 'pager' ),
+               'labels'               => array( 'styles' => 'labels' ),
+               'badges'               => array( 'styles' => 'badges' ),
+               'jumbotron'            => array( 'styles' => 'jumbotron' ),
+               'thumbnails'           => array( 'styles' => 'thumbnails' ),
+               'alerts'               => array( 'styles' => 'alerts' ),
+               'progress-bars'        => array( 'styles' => 'progress-bars' ),
+               'media'                => array( 'styles' => 'media' ),
+               'list-group'           => array( 'styles' => 'list-group' ),
+               'panels'               => array( 'styles' => 'panels' ),
+               'wells'                => array( 'styles' => 'wells' ),
+               'close'                => array( 'styles' => 'close' ),
+
+               // Components w/ JavaScript
+               'modals'               => array( 'styles' => 'modals', 
'scripts' => 'bootstrap/js/modal.js' ),
+               'tooltip'              => array( 'styles' => 'tooltip', 
'scripts' => 'bootstrap/js/tooltip.js' ),
+               'popovers'             => array( 'styles' => 'popovers', 
'scripts' => 'bootstrap/js/popover.js', 'dependencies' => 
'ext.bootstrap.tooltip' ),
+               'carousel'             => array( 'styles' => 'carousel', 
'scripts' => 'bootstrap/js/carousel.js' ),
+
+               // Utility classes
+               'utilities'            => array( 'styles' => 'utilities' ),
+               'responsive-utilities' => array( 'styles' => 
'responsive-utilities' ),
+
+               // JS-only components
+               'affix'                => array( 'scripts' => 
'bootstrap/js/affix.js' ),
+               'alert'                => array( 'scripts' => 
'bootstrap/js/alert.js' ),
+               'button'               => array( 'scripts' => 
'bootstrap/js/button.js' ),
+               'collapse'             => array( 'scripts' => 
'bootstrap/js/collapse.js' ),
+               'dropdown'             => array( 'scripts' => 
'bootstrap/js/dropdown.js' ),
+               'scrollspy'            => array( 'scripts' => 
'bootstrap/js/scrollspy.js' ),
+               'tab'                  => array( 'scripts' => 
'bootstrap/js/tab.js' ),
+               'transition'           => array( 'scripts' => 
'bootstrap/js/transition.js' ),
+
+       );
+       static private $coreModules = array( 'variables', 'mixins', 
'normalize', 'print', 'scaffolding', 'type', 'code',
+                                                                               
 'grid', 'tables', 'forms', 'buttons' );
+       static private $optionalModules = array( 'component-animations', 
'glyphicons', 'dropdowns', 'button-groups',
+                                                                               
         'input-groups', 'navs', 'navbar', 'breadcrumbs', 'pagination', 'pager',
+                                                                               
         'labels', 'badges', 'jumbotron', 'thumbnails', 'alerts', 
'progress-bars',
+                                                                               
         'media', 'list-group', 'panels', 'wells', 'close', 'modals', 'tooltip',
+                                                                               
         'popovers', 'carousel', 'utilities', 'responsive-utilities', 'affix',
+                                                                               
         'alert', 'button', 'collapse', 'dropdown', 'scrollspy', 'tab', 
'transition' );
+
+       /**
+        * Returns the Bootstrap singleton.
+        *
+        * @return Bootstrap
+        */
+       public static function getBootstrap() {
+
+               // if singleton was not yet created
+               if ( self::$bootstrap === null ) {
+                       self::initializeBootstrap();
+               }
+
+               return self::$bootstrap;
+       }
+
+       /**
+        * sets up the Bootstrap singleton and does some initialization
+        */
+       protected static function initializeBootstrap() {
+
+               global $wgResourceModules;
+
+               // register resource loader modules for JS components
+               foreach ( self::$moduleDescriptions as $module => $description 
) {
+                       if ( isset( $description[ 'scripts' ] ) ) {
+
+                               $wgResourceModules[ 'ext.bootstrap.' . $module 
] = array(
+                                       'localBasePath' => $wgResourceModules[ 
'ext.bootstrap' ][ 'localBasePath' ],
+                                       'remoteExtPath' => 'Bootstrap',
+                                       'scripts'       => $description[ 
'scripts' ],
+                               );
+
+                               if ( isset( $description[ 'dependencies' ] ) ) {
+                                       $wgResourceModules[ 'ext.bootstrap.' . 
$module ][ 'dependencies' ] = $description[ 'dependencies' ];
+                               }
+                       }
+               }
+
+               self::$bootstrap = new Bootstrap();
+
+               // add core Bootstrap modules
+               self::$bootstrap->addBootstrapModule( self::$coreModules );
+       }
+
+       /**
+        * Adds the given Bootstrap module or modules.
+        *
+        * @param string|array(string) $modules
+        */
+       public function addBootstrapModule( $modules ) {
+
+               $modules = (array)$modules;
+
+               foreach ( $modules as $module ) {
+
+                       // if the module is known
+                       if ( array_key_exists( $module, 
self::$moduleDescriptions ) ) {
+
+                               global $wgResourceModules;
+
+                               // add less files to $wgResourceModules
+                               if ( isset( self::$moduleDescriptions[ $module 
][ 'styles' ] ) ) {
+                                       $wgResourceModules[ 'ext.bootstrap' ][ 
'styles' ] = array_merge( $wgResourceModules[ 'ext.bootstrap' ][ 'styles' ], 
(array)self::$moduleDescriptions[ $module ][ 'styles' ] );
+                               }
+
+                               // ensure loading of js files using dependencies
+                               if ( isset( self::$moduleDescriptions[ $module 
][ 'scripts' ] ) ) {
+                                       $wgResourceModules[ 'ext.bootstrap' ][ 
'dependencies' ][ ] = 'ext.bootstrap.' . $module;
+
+                               }
+
+                               // prevent adding this module again
+                               unset( self::$moduleDescriptions[ $module ] );
+                       }
+               }
+
+       }
+
+       /**
+        * Adds all bootstrap modules
+        */
+       public function addAllBootstrapModules() {
+
+               $this->addBootstrapModule( self::$optionalModules );
+       }
+
+       /**
+        * @param string $path
+        * @param string $file
+        */
+       public function addExternalModule( $path, $file ) {
+
+               global $wgResourceModules;
+
+               if ( !in_array( $path, $wgResourceModules[ 'ext.bootstrap' ][ 
'paths' ] ) ) {
+                       $wgResourceModules[ 'ext.bootstrap' ][ 'paths' ][ ] = 
$path;
+               }
+
+               $wgResourceModules[ 'ext.bootstrap' ][ 'styles' ][ ] = $file;
+       }
+
+       /**
+        * @param string $key   the LESS variable name
+        * @param string $value the value to assign to the variable
+        */
+       public function setLessVariable( $key, $value ) {
+
+               $this->setLessVariables( array( $key => $value ) );
+       }
+
+       /**
+        * @param $variables
+        */
+       public function setLessVariables( $variables ) {
+
+               global $wgResourceModules;
+               $wgResourceModules[ 'ext.bootstrap' ][ 'variables' ] = 
array_merge( $wgResourceModules[ 'ext.bootstrap' ][ 'variables' ], $variables );
+       }
+
+}
diff --git a/Bootstrap.php b/Bootstrap.php
index 461e506..b0140b9 100644
--- a/Bootstrap.php
+++ b/Bootstrap.php
@@ -35,7 +35,11 @@
  * @ingroup Bootstrap
  */
 if ( !defined( 'MEDIAWIKI' ) ) {
-       die( 'This file is part of a MediaWiki extension, it is not a valid 
entry point.' );
+       die( 'This file is part of the MediaWiki extension Bootstrap, it is not 
a valid entry point.' );
+}
+
+if ( version_compare( $wgVersion, '1.22', 'lt' ) ) {
+       die( '<b>Error:</b> This version of <a 
href="https://www.mediawiki.org/wiki/Extension:Bootstrap";>Bootstrap</a> is only 
compatible with MediaWiki 1.22 or above. You need to upgrade MediaWiki first.' 
);
 }
 
 /**
@@ -59,62 +63,18 @@
 // register message files
 $wgExtensionMessagesFiles['Bootstrap'] = $dir . '/Bootstrap.i18n.php';
 
-// register resource modules with the Resource Loader
+$wgAutoloadClasses['bootstrap\ResourceLoaderBootstrapModule'] = $dir . 
'/ResourceLoaderBootstrapModule.php';
+$wgAutoloadClasses['Bootstrap'] = $dir . '/Bootstrap.class.php';
 
-// module loading all styles
-// It is enough to include fixes.less. Everything else is included through 
this file.
-$wgResourceModules['ext.bootstrap.styles'] = array(
-       'localBasePath' => $dir,
-       'remoteExtPath' => 'Bootstrap',
-       'styles' => array( 'fixes.less' ),
-);
-
-// module loading all scripts
-$wgResourceModules['ext.bootstrap.scripts'] = array(
-       'localBasePath' => $dir,
-       'remoteExtPath' => 'Bootstrap',
-       'dependencies' => array(  ),
-);
-
-$moduleNames = array(
-       'affix',
-       'alert',
-       'button',
-       'carousel',
-       'collapse',
-       'dropdown',
-       'modal',
-       'popover',
-       'scrollspy',
-       'tab',
-       'tooltip',
-       'transition',
-);
-
-$moduleTemplate = array(
-       'localBasePath' => $dir,
-       'remoteExtPath' => 'Bootstrap',
-       'dependencies' => array( 'jquery' ),
-);
-
-// register bootstrap modules with the ResourceLoader
-foreach ( $moduleNames as $modName ) {
-
-       $wgResourceModules[ "ext.bootstrap.scripts.$modName" ] = array_merge( 
$moduleTemplate, array(
-               'scripts' => array( "bootstrap/js/$modName.js" ),
-       ) );
-
-       $wgResourceModules['ext.bootstrap.scripts']['dependencies'][] = 
"ext.bootstrap.scripts.$modName";
-}
-
-// Fix dependencies between modules explicitely
-$wgResourceModules['ext.bootstrap.scripts.popover']['dependencies'][] = 
"ext.bootstrap.scripts.tooltip";
-
-// all-including module
+// register skeleton resource module with the Resource Loader
 $wgResourceModules['ext.bootstrap'] = array(
        'localBasePath' => $dir,
        'remoteExtPath' => 'Bootstrap',
-       'dependencies' => array( 'ext.bootstrap.styles', 
'ext.bootstrap.scripts' ),
+       'class' => 'bootstrap\ResourceLoaderBootstrapModule',
+       'styles' => array(),
+       'variables' => array(),
+       'paths' => array( $dir . '/bootstrap/less' ),
+       'dependencies' => array(),
 );
 
 unset( $dir );
diff --git a/ResourceLoaderBootstrapModule.php 
b/ResourceLoaderBootstrapModule.php
new file mode 100644
index 0000000..3f323ee
--- /dev/null
+++ b/ResourceLoaderBootstrapModule.php
@@ -0,0 +1,119 @@
+<?php
+/**
+ * File holding the Bootstrap class
+ *
+ * @copyright (C) 2013, Stephan Gambke
+ * @license   http://www.gnu.org/licenses/gpl-3.0.html GNU General Public 
License, version 3 (or later)
+ *
+ * This file is part of the MediaWiki extension Bootstrap.
+ * The Bootstrap extension is free software: you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * The Bootstrap extension is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ * @file
+ * @ingroup   Bootstrap
+ */
+
+namespace Bootstrap;
+
+use ResourceLoader;
+use ResourceLoaderContext;
+use ResourceLoaderFileModule;
+
+/**
+ * ResourceLoader module based on local JavaScript/LESS files.
+ *
+ * Different to the behaviour of ResourceLoaderFileModule this module compiles 
all LESS files in one compile context.
+ *
+ * It recognizes the following additional fields in $wgResourceModules:
+ * * styles: array of LESS file names (with or without extension .less)
+ * * variables: array of key value pairs representing LESS variables, that 
will be added to the LESS script after all
+ *              files imports, i.e. that may override any variable set in 
style files
+ * * paths: array of paths to search for style files; all these paths together 
represent one virtual file base and will
+ *             be searched for a style file; this means it is not possible to 
include two LESS files with the same name
+ *          even if in different paths
+ *
+ * @package Bootstrap
+ */
+class ResourceLoaderBootstrapModule extends ResourceLoaderFileModule {
+
+       protected $variables = array();
+       protected $paths = array();
+
+       public function __construct( $options = array(), $localBasePath = null, 
$remoteBasePath = null
+       ) {
+
+               parent::__construct( $options, $localBasePath, $remoteBasePath 
);
+
+               if ( isset( $options[ 'variables' ] ) ) {
+                       $this->variables = $options[ 'variables' ];
+               }
+
+               if ( isset( $options[ 'paths' ] ) ) {
+                       $this->paths = $options[ 'paths' ];
+               }
+
+       }
+
+       /**
+        * Get the compiled Bootstrap styles
+        *
+        * @param ResourceLoaderContext $context
+        *
+        * @return array
+        */
+       public function getStyles( ResourceLoaderContext $context ) {
+
+               $compiler = ResourceLoader::getLessCompiler();
+
+               // prepare a temp file containing all the variables to load
+               // have to use a temp file for variables because inline 
variables do not overwrite @import'ed variables even if
+               // set after the @import (see 
https://github.com/leafo/lessphp/issues/302 )
+               $tmpFile = null;
+
+               if ( !empty( $this->variables ) ) {
+
+                       $tmpFile = tempnam( sys_get_temp_dir(), 'php' );
+
+                       $handle = fopen( $tmpFile, 'w' );
+
+                       foreach ( $this->variables as $key => $value ) {
+                               fwrite( $handle, "@$key: $value;\n" );
+                       }
+
+                       fclose( $handle );
+
+                       $this->styles[ ] = basename( $tmpFile );
+                       $this->paths[ ]  = dirname( $tmpFile );
+
+               }
+
+               // add all
+               $lessCode = implode( array_map( function ( $module ) { return 
"@import \"$module\";\n"; }, $this->styles ) );
+
+               // add additional paths for external files
+               foreach ( $this->paths as $path ) {
+                       $compiler->addImportDir( $path );
+               }
+
+               $styles = $compiler->compile( $lessCode );
+
+               unlink( $tmpFile );
+
+               return array( 'all' => $styles );
+       }
+
+       public function supportsURLLoading() {
+
+               return false;
+       }
+}
diff --git a/fixes.less b/fixes.less
deleted file mode 100644
index 32c78ca..0000000
--- a/fixes.less
+++ /dev/null
@@ -1,36 +0,0 @@
-/*!
- * LESS style file importing the regular Bootstrap file and then attaching 
fixes.
- *
- * @copyright (C) 2013, Stephan Gambke
- * @license http://www.gnu.org/licenses/gpl-3.0.html GNU General Public 
License, version 3 (or later)
- *
- * This file is part of the MediaWiki extension Bootstrap.
- * The Bootstrap extension is free software: you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * The Bootstrap extension is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program.  If not, see <http://www.gnu.org/licenses/>.
- *
- * @file
- * @ingroup Bootstrap
- */
-
-/*
- * first import regular Bootstrap
- *********************/
-
-@import "bootstrap/less/bootstrap.less";
-
-
-/*
- * then apply fixes
- *********************/
-
-/* None yet */

-- 
To view, visit https://gerrit.wikimedia.org/r/89480
To unsubscribe, visit https://gerrit.wikimedia.org/r/settings

Gerrit-MessageType: newchange
Gerrit-Change-Id: Ib69e0a7764dafe7346b73e1eae630ca141819df6
Gerrit-PatchSet: 1
Gerrit-Project: mediawiki/extensions/Bootstrap
Gerrit-Branch: master
Gerrit-Owner: Foxtrott <[email protected]>

_______________________________________________
MediaWiki-commits mailing list
[email protected]
https://lists.wikimedia.org/mailman/listinfo/mediawiki-commits

Reply via email to