Werdna has uploaded a new change for review.

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

Change subject: Add template syntax for OOUI in wikitext.
......................................................................

Add template syntax for OOUI in wikitext.

Warning: Currently has no XSS protection. If you do not want to be XSS'd,
then you should not allow untrusted users to edit any pages.

Bug: T88026
Change-Id: I69d7059f10eda73696b6257d9243f7785c0f783b
---
M autoload.php
D generateLibAutoload.php
A includes/ContainerAccess.php
M includes/DeferredWidget.php
A includes/OOUILightNCandy.php
M includes/ParserHooks.php
M includes/WidgetFactory.php
M includes/WidgetInfo.php
A includes/argument-filters/DeferredGroupElementFilter.php
A includes/argument-filters/FlagsFilter.php
M includes/argument-filters/GroupElementFilter.php
M includes/container.php
M resources/Resources.php
M resources/defer.js
14 files changed, 523 insertions(+), 60 deletions(-)


  git pull ssh://gerrit.wikimedia.org:29418/mediawiki/extensions/OOUIPlayground 
refs/changes/83/192783/1

diff --git a/autoload.php b/autoload.php
index 6ee40ca..9725d95 100644
--- a/autoload.php
+++ b/autoload.php
@@ -7,6 +7,9 @@
        'OOUIPlayground\\ArgumentFilterGroup' => __DIR__ . 
'/includes/argument-filters/ArgumentFilter.php',
        'OOUIPlayground\\ArgumentFilterInterface' => __DIR__ . 
'/includes/argument-filters/ArgumentFilter.php',
        'OOUIPlayground\\ConfiguredCodeRenderer' => __DIR__ . 
'/includes/CodeRenderer.php',
+       'OOUIPlayground\\Container' => __DIR__ . 
'/includes/ContainerAccess.php',
+       'OOUIPlayground\\DeferredGroupElementFilter' => __DIR__ . 
'/includes/argument-filters/DeferredGroupElementFilter.php',
+       'OOUIPlayground\\FlagsFilter' => __DIR__ . 
'/includes/argument-filters/FlagsFilter.php',
        'OOUIPlayground\\GeSHICodeRenderer' => __DIR__ . 
'/includes/CodeRenderer.php',
        'OOUIPlayground\\GroupElementFilter' => __DIR__ . 
'/includes/argument-filters/GroupElementFilter.php',
        'OOUIPlayground\\ICodeRenderer' => __DIR__ . 
'/includes/CodeRenderer.php',
@@ -18,6 +21,8 @@
        'OOUIPlayground\\NoSuchWidgetException' => __DIR__ . 
'/includes/WidgetInfo.php',
        'OOUIPlayground\\NoTypeGiven' => __DIR__ . 
'/includes/WidgetFactory.php',
        'OOUIPlayground\\NullCodeRenderer' => __DIR__ . 
'/includes/CodeRenderer.php',
+       'OOUIPlayground\\OOUILightNCandy' => __DIR__ . 
'/includes/OOUILightNCandy.php',
+       'OOUIPlayground\\OOUIStatic' => __DIR__ . 
'/includes/OOUILightNCandy.php',
        'OOUIPlayground\\ParserHooks' => __DIR__ . '/includes/ParserHooks.php',
        'OOUIPlayground\\PreCodeRenderer' => __DIR__ . 
'/includes/CodeRenderer.php',
        'OOUIPlayground\\WidgetDocumenter' => __DIR__ . 
'/includes/WidgetDocumenter.php',
diff --git a/generateLibAutoload.php b/generateLibAutoload.php
deleted file mode 100644
index 108d90e..0000000
--- a/generateLibAutoload.php
+++ /dev/null
@@ -1,17 +0,0 @@
-<?php
-
-require_once __DIR__ . '/../../includes/utils/AutoloadGenerator.php';
-
-function main() {
-       $base = __DIR__ . '/lib';
-       $generator = new AutoloadGenerator( $base );
-       foreach ( array( 'oojs-ui/php' ) as $dir ) {
-               $generator->readDir( $base . '/' . $dir );
-       }
-
-       $generator->generateAutoload( $base );
-
-       echo "Done.\n\n";
-}
-
-main();
diff --git a/includes/ContainerAccess.php b/includes/ContainerAccess.php
new file mode 100644
index 0000000..24fd8d8
--- /dev/null
+++ b/includes/ContainerAccess.php
@@ -0,0 +1,20 @@
+<?php
+
+namespace OOUIPlayground;
+
+class Container {
+       protected static $container;
+
+       /**
+        * Gets an object from the container.
+        * @param  string $obj The object to get
+        * @return mixed|null   That section in config.php, or null if it does 
not exist.
+        */
+       public static function get( $obj ) {
+               if ( self::$container === null ) {
+                       self::$container = require __DIR__ . '/container.php';
+               }
+
+               return self::$container[$obj];
+       }
+}
\ No newline at end of file
diff --git a/includes/DeferredWidget.php b/includes/DeferredWidget.php
index e2495b9..725212c 100644
--- a/includes/DeferredWidget.php
+++ b/includes/DeferredWidget.php
@@ -3,14 +3,26 @@
 namespace OOUI;
 
 use FormatJson;
+use MWException;
 
 class DeferredWidget extends Widget {
+       protected $config;
+
        /**
         * @param string[]|bool $config['testparam'] A test parameter
         */
        function __construct( array $config ) {
+               if ( ! isset( $config['class'] ) ) {
+                       throw new MWException( "No class specified for 
DeferredWidget" );
+               }
+
+               $this->config = $config;
                $this->setAttributes( array( 'data-params' => 
FormatJson::encode( $config ) ) );
                $this->addClasses( array( 'ooui-deferred' ) );
                $this->tag = 'span';
        }
+
+       public function getConfig() {
+               return $this->config;
+       }
 }
diff --git a/includes/OOUILightNCandy.php b/includes/OOUILightNCandy.php
new file mode 100644
index 0000000..21bdb55
--- /dev/null
+++ b/includes/OOUILightNCandy.php
@@ -0,0 +1,165 @@
+<?php
+
+namespace OOUIPlayground;
+
+use FormatJson;
+use LightnCandy;
+use OOUI\DeferredWidget;
+use OOUI\MediaWikiTheme;
+use OOUI\Theme;
+use SimpleLightNCandy;
+
+class OOUILightNCandy extends SimpleLightNCandy {
+       protected $widgetRepo;
+       protected $widgetFactory;
+
+       function __construct( WidgetRepository $repo = null, WidgetFactory 
$factory = null, $dir ) {
+               parent::__construct( $dir );
+               $this->widgetRepo = $repo;
+               $this->widgetFactory = $factory;
+
+               $this->setupHelpers();
+       }
+
+       public function setupRendering() {
+               Theme::setSingleton( new MediaWikiTheme );
+
+               OOUIStatic::overrideFactory( $this->widgetFactory );
+               OOUIStatic::overrideRepository( $this->widgetRepo );
+       }
+
+       public function teardownRendering() {
+               OOUIStatic::clearOverrides();
+       }
+
+       public function renderTemplate( $templateName, array $input ) {
+               $this->setupRendering();
+               $output = parent::renderTemplate( $templateName, $input );
+               $this->teardownRendering();
+               return $output;
+       }
+
+       public function renderString( $templateStr, array $input ) {
+               $this->setupRendering();
+               $output = parent::renderString( $templateStr, $input );
+               $this->teardownRendering();
+               return $output;
+       }
+
+       protected function setupHelpers() {
+               $this->addHBHelper( 'ooui',
+                       function( $context, array $options ) {
+                               return OOUIPlayground\OOUIStatic::oouiHelper( 
$context, $options );
+                       }
+               );
+       }
+
+       protected function getCompileOptions() {
+               $options = parent::getCompileOptions();
+
+               $options['flags'] ^= LightnCandy::FLAG_MUSTACHE;
+               $options['flags'] |= LightnCandy::FLAG_HANDLEBARSJS;
+
+               return $options;
+       }
+}
+
+/**
+ * It's not possible to pass the WidgetRepo or WidgetFactory into a 
LightNCandy template,
+ * by design. So this is a hack we're using to get things working. It's 
probably the wrong
+ * way to approach the problem but it works for now.
+ */
+abstract class OOUIStatic {
+       protected static $overrideRepo = null;
+       protected static $overrideFactory = null;
+
+       public static function oouiHelper( $context, array $options ) {
+               $widgetName = $context;
+
+               set_error_handler( function( $errno, $errstr, $errfile, 
$errline ) {
+                       die( "$errstr at $errfile:$errline\n" . wfBacktrace() );
+               } );
+
+               $widgetInfo = self::getRepo()->getInfo( $widgetName );
+               $params = self::getParams( $widgetInfo, $options );
+               if ( isset( $options['old_ctx']['_ooui_mode'] ) ) {
+                       $params['type'] = $widgetInfo->getType();
+                       $ret = array( FormatJson::encode( $params ) . ',', 
'raw' );
+               } else {
+                       $widget = self::getFactory()->getWidget( $widgetInfo, 
$params );
+                       if ( ! $widget instanceof DeferredWidget ) {
+                               $widget->setAttributes(
+                                       array( 'data-params' => 
FormatJson::encode( $params ) )
+                               );
+                       }
+
+                       $ret = array( $widget->__toString(), 'raw' );
+               }
+
+               restore_error_handler();
+               return $ret;
+       }
+
+       public static function getParams( WidgetInfo $widgetInfo, array 
$options ) {
+               $params = array();
+
+               foreach( $options['hash'] as $key => $value ) {
+                       if ( substr( $key, -strlen( '_json' ) ) === '_json' ) {
+                               $params[substr( $key, 0, -strlen( '_json' ) )] 
= FormatJson::encode( $value );
+                       } elseif ( substr( $key, -strlen( '_list' ) ) === 
'_list' ) {
+                               $params[substr( $key, 0, -strlen( '_list' ) )] 
= explode( ' ', $value );
+                       } else {
+                               $params[$key] = $value;
+                       }
+               }
+
+               // Handle contents if relevant
+               if ( isset( $options['fn'] ) ) {
+                       $contentMode = $widgetInfo->getContentMode();
+                       $contentVar = $widgetInfo->getContentVar();
+
+                       if ( $contentMode === 'var' ) {
+                               $params[$contentVar] = $options['fn']( array() 
);
+                       } elseif ( $contentMode === 'group' ) {
+                               $input = $options['fn']( array( '_ooui_mode' => 
'groupelement' ) );
+                               $input = trim( $input );
+                               $input = rtrim( $input, ',' );
+                               $input = "[$input]";
+                               $input = FormatJson::decode( $input, true );
+
+                               $params[$contentVar] = $input;
+                       }
+               }
+
+               return $params;
+       }
+
+       public static function overrideRepository( WidgetRepository $repo = 
null ) {
+               self::$overrideRepo = $repo;
+       }
+
+       public static function overrideFactory( WidgetFactory $factory = null ) 
{
+               self::$overrideFactory = $factory;
+       }
+
+       public static function clearOverrides() {
+               self::overrideRepository( null );
+               self::overrideFactory( null );
+       }
+
+       protected static function getRepo() {
+               if ( self::$overrideRepo !== null ) {
+                       return self::$overrideRepo;
+               } else {
+                       return Container::get( 'widgetRepository' );
+               }
+       }
+
+       protected static function getFactory() {
+               if ( self::$overrideFactory !== null ) {
+                       return self::$overrideFactory;
+               } else {
+                       return Container::get( 'widgetFactory' );
+               }
+       }
+}
diff --git a/includes/ParserHooks.php b/includes/ParserHooks.php
index 8bf03d9..c698e26 100755
--- a/includes/ParserHooks.php
+++ b/includes/ParserHooks.php
@@ -13,8 +13,6 @@
 use Status;
 
 class ParserHooks {
-       protected static $container = null;
-
        /**
         * Handler for ParserFirstCallInit hook
         * @param  Parser $parser Parser to initialise
@@ -23,21 +21,9 @@
        public static function setupParser( Parser $parser ) {
                $parser->setHook( 'ooui-demo', array( __CLASS__, 'renderDemo' ) 
);
                $parser->setHook( 'ooui-doc', array( __CLASS__, 'renderDoc' ) );
+               $parser->setHook( 'ooui-template', array( __CLASS__, 
'renderTemplate' ) );
 
                return true;
-       }
-
-       /**
-        * Gets an object from the container.
-        * @param  string $obj The object to get
-        * @return mixed|null   That section in config.php, or null if it does 
not exist.
-        */
-       protected static function getContainer( $obj ) {
-               if ( self::$container === null ) {
-                       self::$container = require __DIR__ . '/container.php';
-               }
-
-               return self::$container[$obj];
        }
 
        /**
@@ -51,6 +37,15 @@
                }
        }
 
+       /**
+        * Gets an object from the container.
+        * @param  string $obj The object to get
+        * @return mixed|null   That section in config.php, or null if it does 
not exist.
+        */
+       protected static function getContainer( $obj ) {
+               return Container::get( $obj );
+       }
+
        public static function renderDoc( $input, array $args, Parser $parser, 
PPFrame $frame ) {
                $classStatus = self::getWidgetFromAttributes( $args );
 
@@ -62,6 +57,19 @@
                $params = $doc->getOptions( $classStatus->getValue() );
 
                return self::getContainer( 'templating' )->renderTemplate( 
'widget_doc', $params );
+       }
+
+       public static function renderTemplate( $input, array $args, Parser 
$parser, PPFrame $frame ) {
+               $parser->getOutput()->addModules( 
'ext.ooui-playground.deferred-widgets' );
+               $parser->getOutput()->addModuleStyles( array( 'oojs-ui.styles' 
) );
+
+               $templating = new OOUILightNCandy(
+                       null /* default repo */,
+                       null /* default factory */,
+                       __DIR__ . "/../templates"
+               );
+
+               return $templating->renderString( $input, array() );
        }
 
        /**
@@ -113,7 +121,7 @@
        }
 
        /**
-        * Reads the attributes of a tag call to get info about the requested 
class 
+        * Reads the attributes of a tag call to get info about the requested 
class
         * @param  array  $attributes Attributes of a tag call.
         * @todo Merge with WidgetRepository::create
         * @return WidgetInfo
diff --git a/includes/WidgetFactory.php b/includes/WidgetFactory.php
index 5bff766..ed9bb7a 100644
--- a/includes/WidgetFactory.php
+++ b/includes/WidgetFactory.php
@@ -2,50 +2,75 @@
 
 namespace OOUIPlayground;
 
+use OOUI\DeferredWidget;
 use MWException;
 
 class WidgetFactory {
        /** @var ArgumentFilterGroup */
        protected $filter;
+       /** @var ArgumentFilterGroup */
+       protected $deferredFilters;
        /** @var WidgetRepository */
        protected $repo;
 
        /**
         * @param WidgetRepository                               $repo
         * @param array[ArgumentFilterInterface] $filters
+        * * @param array[ArgumentFilterInterface] $deferredFilters
         */
-       function __construct( WidgetRepository $repo, array $filters = array() 
) {
+       function __construct( WidgetRepository $repo, array $filters = array(), 
array $deferredFilters = array() ) {
                $this->repo = $repo;
                $this->filter = new ArgumentFilterGroup( $filters );
+               $this->deferredFilter = new ArgumentFilterGroup( 
$deferredFilters );
        }
 
-       function getWidget( WidgetInfo $info, array $args ) {
-               $this->filter->filter( $info, $args );
-               $className = $info->getFullClassName();
-               return new $className( $args );
+       /**
+        * [getWidget description]
+        * @param  WidgetInfo $info  Widget description retrieved from a 
WidgetRepository
+        * @param  array      $args  Parameters to pass to the widget 
constructor.
+        * @param boolean $defer Set to true if this widget should 
unconditionally
+        * be rendered by OOUI-JS instead of OOUI-PHP
+        * @return \OOUI\Widget
+        */
+       function getWidget( WidgetInfo $info, array $args, $defer = false ) {
+               if ( $defer || $info->isDeferred() ) {
+                       $this->deferredFilter->filter( $info, $args );
+                       $args['class'] = $info->getClassName();
+                       $args['passthru'][] = __METHOD__;
+                       return new DeferredWidget( $args );
+               } else {
+                       $this->filter->filter( $info, $args );
+                       $className = $info->getFullClassName();
+
+                       return $info->instantiate( $args );
+               }
        }
 
        /**
         * Creates a widget from an array configuration
         * @param  array  $args Array of parameters for the widget.
         * The 'type' parameter is required
+        * @param boolean $defer Set to true if this widget should 
unconditionally
+        * be rendered by OOUI-JS instead of OOUI-PHP
         * @throws NoSuchWidgetException
         * @throws NoTypeGivenException
-        * @return Widget
+        * @return \OOUI\Widget
         */
-       public function create( array $args ) {
+       public function create( array $args, $defer = false ) {
                if ( ! isset( $args['type'] ) ) {
                        throw new NoTypeGivenException();
                }
 
                $widgetClass = $this->repo->getInfo( $args['type'] );
                unset( $args['type'] );
+               $args['passthru'][] = __METHOD__;
 
-               return $this->getWidget( $widgetClass, $args );
+               return $this->getWidget( $widgetClass, $args, $defer );
        }
 
-       public function addFilter( ArgumentFilterInterface $filter ) {
-               $this->filter->addFilter( $filter );
+       public function addFilter( ArgumentFilterInterface $filter, $deferred = 
false ) {
+               $modifyFilter = $deferred ? $this->deferredFilter : 
$this->filter;
+               $modifyFilter->addFilter( $filter );
        }
 }
 
diff --git a/includes/WidgetInfo.php b/includes/WidgetInfo.php
index efc1f15..c9cc058 100644
--- a/includes/WidgetInfo.php
+++ b/includes/WidgetInfo.php
@@ -21,13 +21,7 @@
         * (cannot be used with new because it's in the wrong namespace)
         */
        public function getClassName( $type ) {
-               $type = strtolower( $type );
-
-               if ( ! isset( $this->classMap[$type] ) ) {
-                       throw new NoSuchWidgetException( $type );
-               } else {
-                       return $this->classMap[$type]['class'];
-               }
+               return $this->getInfo( $type )['className'];
        }
 
        /**
@@ -37,10 +31,12 @@
         * @return WidgetInfo
         */
        public function getInfo( $type ) {
-               $className = $this->getClassName( $type );
+               $type = strtolower( $type );
 
-               if ( $className ) {
+               if ( isset( $this->classMap[$type] ) ) {
                        return new WidgetInfo( $type, $this->classMap[$type] );
+               } else {
+                       throw new NoSuchWidgetException( $type );
                }
        }
 }
@@ -118,6 +114,10 @@
         * @return ReflectionClass
         */
        public function getReflection() {
+               if ( $this->isDeferred() ) {
+                       throw new MWException( "Getting reflection is not 
supported on deferred widgets" );
+               }
+
                return new ReflectionClass( $this->getFullClassName() );
        }
 
@@ -128,16 +128,45 @@
                return 'OOUI\\' . $this->className;
        }
 
+       public function getContentMode() {
+               return $this->getAttribute( 'contentMode' ) ?: 'var';
+       }
+
+       public function getContentVar() {
+               return $this->getAttribute( 'contentVar' ) ?: 'content';
+       }
+
+       public function isDeferred() {
+               return $this->getAttribute( 'deferred' ) != null;
+       }
+
+       public function hasSpecialInstantiator() {
+               return is_callable( $this->getSpecialInstantiator() );
+       }
+
+       public function getSpecialInstantiator() {
+               return $this->getAttribute( 'instantiator' );
+       }
+
+       protected function getAttribute( $name ) {
+               return isset( $this->classInfo[$name] ) ? 
$this->classInfo[$name] : null;
+       }
+
        /**
         * Get an instance of the OOUI-PHP class
-        * Only for internal use, outside this class
+        * Only for internal use, outside this class and 
WidgetFactory::getWidget
         * you should use a correctly configured WidgetFactory.
         * @param  array  $args Options for instantiation
         * @return OOUI\Widget  The requested class
         */
-       protected function instantiate( array $args = array() ) {
+       public function instantiate( array $args = array() ) {
                $fullClass = $this->getFullClassName();
-               return new $fullClass( $args );
+               if ( $this->hasSpecialInstantiator() ) {
+                       $instantiator = $this->getSpecialInstantiator();
+                       return $instantiator( $fullClass, $args );
+               } else {
+                       return new $fullClass( $args );
+               }
        }
 }
 
diff --git a/includes/argument-filters/DeferredGroupElementFilter.php 
b/includes/argument-filters/DeferredGroupElementFilter.php
new file mode 100644
index 0000000..77974d8
--- /dev/null
+++ b/includes/argument-filters/DeferredGroupElementFilter.php
@@ -0,0 +1,19 @@
+<?php
+
+namespace OOUIPlayground;
+
+use MWException;
+use OOUI\DeferredWidget;
+
+class DeferredGroupElementFilter extends GroupElementFilter {
+       protected function instantiateWidget( array $item ) {
+               $widget = $this->widgetFactory->create( $item, true );
+
+               if ( ! $widget instanceof DeferredWidget ) {
+                       throw new MWException( "Created a non-deferred widget 
of type " . get_class( $widget ) );
+               }
+
+               return $widget->getConfig();
+       }
+}
+
diff --git a/includes/argument-filters/FlagsFilter.php 
b/includes/argument-filters/FlagsFilter.php
new file mode 100644
index 0000000..0773b1c
--- /dev/null
+++ b/includes/argument-filters/FlagsFilter.php
@@ -0,0 +1,11 @@
+<?php
+
+namespace OOUIPlayground;
+
+class FlagsFilter implements ArgumentFilterInterface {
+       function filter( WidgetInfo $widget, array &$args ) {
+               if ( isset( $args['flags'] ) ) {
+                       $args['flags'] = explode( ' ', $args['flags'] );
+               }
+       }
+}
diff --git a/includes/argument-filters/GroupElementFilter.php 
b/includes/argument-filters/GroupElementFilter.php
index 0c907d5..6044bb6 100644
--- a/includes/argument-filters/GroupElementFilter.php
+++ b/includes/argument-filters/GroupElementFilter.php
@@ -13,19 +13,30 @@
        }
 
        public function filter( WidgetInfo $widget, array &$arguments ) {
-               if ( $widget->isA( 'GroupElement' ) && isset( 
$arguments['items'] ) ) {
+               if ( $this->shouldProcess( $widget, $arguments ) ) {
                        $newItems = array();
                        foreach( $arguments['items'] as $item ) {
                                if ( ! is_array( $item ) ) {
                                        throw new 
InvalidGroupElementItemException();
                                } else {
-                                       $newItems[] = 
$this->widgetFactory->create( $item );
+                                       $newItems[] = $this->instantiateWidget( 
$item );
                                }
                        }
 
                        $arguments['items'] = $newItems;
                }
        }
+
+       // @todo This works right now but it's fragile.
+       // We'd like to check for the GroupElement mixin, but some things that
+       // we treat as GroupElements (e.g. FieldLayout) don't mix that in.
+       protected function shouldProcess( WidgetInfo $widget, array $arguments 
) {
+               return isset( $arguments['items'] ) && is_array( reset( 
$arguments['items'] ) );
+       }
+
+       protected function instantiateWidget( array $item ) {
+               return $this->widgetFactory->create( $item );
+       }
 }
 
 class InvalidGroupElementItemException extends MWException {
diff --git a/includes/container.php b/includes/container.php
index 462fec9..02a6858 100644
--- a/includes/container.php
+++ b/includes/container.php
@@ -8,18 +8,42 @@
 
 $container = new Container;
 
+// Options:
+// class: Required, class name
+// deferred: Optional, default false.
+//   If set to true, this element will be rendered in JS instead of PHP.
+// contentVar: Optional, default 'content'.
+//   If this element is called with the block helper, the config variable to be
+//   filled with the processed block content.
+// contentMode: Optional, default 'var'.
+// If the element is called with the block helper, what to do with the 
contents.
+//   Has the following possible values:
+//   * var: Take the raw content and put it unprocessed into the variable.
+//   * group: The parent element is a group element, add all OOUI elements 
inside
+//     it to the parent element.
+// instantiator: Optional.
+//   If this element's constructor has a nonstandard signature
+//   (the standard signature is function __construct( array $config ))
+//   This should be a function with the following signature:
+//   function( string $className, array $config ) :OOUI\Widget
+//   It should be able to cope with empty $config
 $container['classMap'] = array(
        'buttongroup' => array(
                'class' => 'ButtonGroupWidget',
+               'contentMode' => 'group',
+               'contentVar' => 'items',
        ),
        'buttoninput' => array(
                'class' => 'ButtonInputWidget',
+               'contentVar' => 'label',
        ),
        'button' => array(
                'class' => 'ButtonWidget',
+               'contentVar' => 'label',
        ),
        'checkboxinput' => array(
                'class' => 'CheckboxInputWidget',
+               'contentVar' => 'label',
        ),
        'icon' => array(
                'class' => 'IconWidget',
@@ -32,15 +56,153 @@
        ),
        'label' => array(
                'class' => 'LabelWidget',
+               'contentVar' => 'label',
        ),
        'radioinput' => array(
                'class' => 'RadioInputWidget',
        ),
        'textinput' => array(
                'class' => 'TextInputWidget',
+               'contentVar' => 'value',
        ),
        'deferred' => array(
                'class' => 'DeferredWidget',
+       ),
+       'action' => array(
+               'class' => 'ActionWidget',
+               'deferred' => true,
+       ),
+       'buttonoption' => array(
+               'class' => 'ButtonOptionWidget',
+               'deferred' => true,
+               'contentVar' => 'label',
+       ),
+       'buttonselect' => array(
+               'class' => 'ButtonSelectWidget',
+               'deferred' => true,
+               'contentMode' => 'group',
+               'contentVar' => 'items',
+       ),
+       'combobox' => array(
+               'class' => 'ComboBoxWidget',
+               'deferred' => true,
+       ),
+       'decoratedoption' => array(
+               'class' => 'DecoratedOptionWidget',
+               'deferred' => true,
+       ),
+       'dropdown' => array(
+               'class' => 'DropdownWidget',
+               'deferred' => true,
+       ),
+       'menuoption' => array(
+               'class' => 'MenuOptionWidget',
+               'deferred' => true,
+       ),
+       'menusectionoption' => array(
+               'class' => 'MenuSectionOptionWidget',
+               'deferred' => true,
+       ),
+       'menuselect' => array(
+               'class' => 'MenuSelectWidget',
+               'deferred' => true,
+               'contentMode' => 'group',
+               'contentVar' => 'items',
+       ),
+       'option' => array(
+               'class' => 'OptionWidget',
+               'deferred' => true,
+       ),
+       'outlinecontrols' => array(
+               'class' => 'OutlineControlsWidget',
+               'deferred' => true,
+       ),
+       'outlineoption' => array(
+               'class' => 'OutlineOptionWidget',
+               'deferred' => true,
+               'contentVar' => 'label',
+       ),
+       'outlineselect' => array(
+               'class' => 'OutlineSelectWidget',
+               'deferred' => true,
+               'contentMode' => 'group',
+               'contentVar' => 'items',
+       ),
+       'popupbutton' => array(
+               'class' => 'PopupButtonWidget',
+               'deferred' => true,
+       ),
+       'popup' => array(
+               'class' => 'PopupWidget',
+               'deferred' => true,
+       ),
+       'progressbar' => array(
+               'class' => 'ProgressBarWidget',
+               'deferred' => true,
+       ),
+       'radiooption' => array(
+               'class' => 'RadioOptionWidget',
+               'deferred' => true,
+               'contentVar' => 'label',
+       ),
+       'radioselect' => array(
+               'class' => 'RadioSelectWidget',
+               'deferred' => true,
+               'contentMode' => 'group',
+               'contentVar' => 'items',
+       ),
+       'search' => array(
+               'class' => 'SearchWidget',
+               'deferred' => true,
+       ),
+       'select' => array(
+               'class' => 'SelectWidget',
+               'deferred' => true,
+       ),
+       'textinputmenuselect' => array(
+               'class' => 'TextInputMenuSelectWidget',
+               'deferred' => true,
+       ),
+       'togglebutton' => array(
+               'class' => 'ToggleButtonWidget',
+               'deferred' => true,
+       ),
+       'toggleswitch' => array(
+               'class' => 'ToggleSwitchWidget',
+               'deferred' => true,
+       ),
+       'fieldlayout' => array(
+               'class' => 'FieldLayout',
+               'contentMode' => 'group',
+               'contentVar' => 'items',
+               'instantiator' => function( $className, array $config ) {
+                       $element = false;
+                       if (
+                               isset( $config['items'] ) &&
+                               is_array( $config['items'] ) &&
+                               count( $config['items'] )
+                       ) {
+                               $element = reset( $config['items'] );
+                       }
+
+                       // If there's an empty $config, give a dummy element.
+                       if ( ! $element ) {
+                               $element = new \OOUI\LabelWidget;
+                       }
+
+                       if ( is_array( $element ) ) {
+                               var_dump( $element, $config );
+                               die( wfBacktrace() );
+                       }
+
+                       unset( $config['items'] );
+                       return new $className( $element, $config );
+               },
+       ),
+       'fieldsetlayout' => array(
+               'class' => 'FieldsetLayout',
+               'contentMode' => 'group',
+               'contentVar' => 'items',
        ),
 );
 
@@ -74,6 +236,7 @@
 
        // Some filters want a WidgetFactory
        $factory->addFilter( new GroupElementFilter( $factory ) );
+       $factory->addFilter( new DeferredGroupElementFilter( $factory ), true );
 
        return $factory;
 };
diff --git a/resources/Resources.php b/resources/Resources.php
index 25b7327..dcacc38 100644
--- a/resources/Resources.php
+++ b/resources/Resources.php
@@ -7,8 +7,12 @@
 );
 
 $wgResourceModules['ext.ooui-playground'] = array(
-       'scripts' => array( 'display.js', 'defer.js' ),
-       'dependencies' => array( 'oojs-ui' ),
+       'styles' => 'display.less',
+       'scripts' => array( 'display.js' ),
+       'dependencies' => array(
+               'oojs-ui',
+               'ext.ooui-playground.deferred-widgets',
+       ),
        'messages' => array(
                "ooui-playground-language-php",
                "ooui-playground-language-javascript",
@@ -19,3 +23,9 @@
        'styles' => array( 'display.less', 'hidecode.css' ),
        'position' => 'top',
 ) + $oouiPlaygroundResourceTemplate;
+$wgResourceModules['ext.ooui-playground.deferred-widgets'] = array(
+       'scripts' => 'defer.js',
+       'dependencies' => array(
+               'oojs-ui',
+       ),
+) + $oouiPlaygroundResourceTemplate;
diff --git a/resources/defer.js b/resources/defer.js
index a2476ae..b668f60 100644
--- a/resources/defer.js
+++ b/resources/defer.js
@@ -7,6 +7,8 @@
                        newItems;
 
                if ( typeof OO.ui[className] === 'undefined' ) {
+                       console.log( "Unable to load " + className );
+                       console.dir( config );
                        return $( '<span/>' ).addClass( 'error' )
                                .text( 'Unable to load ' + className );
                }
@@ -41,7 +43,7 @@
 
        $( '.ooui-deferred' ).each( function() {
                var config = $( this ).data( 'params' ),
-                       widget = instantiateFromParameters( config );
+                       widget = instantiateFromParameters( $.extend( {}, 
config ) );
 
                if ( widget.$element ) {
                        $( this ).replaceWith( widget.$element );

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

Gerrit-MessageType: newchange
Gerrit-Change-Id: I69d7059f10eda73696b6257d9243f7785c0f783b
Gerrit-PatchSet: 1
Gerrit-Project: mediawiki/extensions/OOUIPlayground
Gerrit-Branch: master
Gerrit-Owner: Werdna <[email protected]>

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

Reply via email to