Werdna has uploaded a new change for review. https://gerrit.wikimedia.org/r/190466
Change subject: WIP: "Smoke test" at Special:OOUIDemo ...................................................................... WIP: "Smoke test" at Special:OOUIDemo Includes support for calling OOUIPlayground from templates. Change-Id: Ia4c101567d1adef5c6cdc89b2ec0ed884fed73e7 --- M OOUIPlayground.php M autoload.php M i18n/en.json A includes/ContainerAccess.php A includes/OOUILightNCandy.php M includes/ParserHooks.php A includes/SpecialOOUIDemo.php M includes/WidgetInfo.php M includes/container.php A templates/demo.template A templates/used_widgets.template 11 files changed, 295 insertions(+), 26 deletions(-) git pull ssh://gerrit.wikimedia.org:29418/mediawiki/extensions/OOUIPlayground refs/changes/66/190466/1 diff --git a/OOUIPlayground.php b/OOUIPlayground.php index 13707ce..13aef20 100644 --- a/OOUIPlayground.php +++ b/OOUIPlayground.php @@ -43,6 +43,8 @@ $wgMessagesDirs['OOUIPlayground'] = __DIR__ . '/i18n'; +$wgSpecialPages['OOUIDemo'] = 'SpecialOOUIDemo'; + $dir = dirname( __FILE__ ); require_once __DIR__ . "/autoload.php"; diff --git a/autoload.php b/autoload.php index 6ee40ca..ba471dd 100644 --- a/autoload.php +++ b/autoload.php @@ -1,5 +1,5 @@ <?php -// This file is generated by /Users/andrew/wm-dev/vagrant/mediawiki/extensions/OOUIPlayground, do not adjust manually +// This file is generated by /vagrant/mediawiki/extensions/OOUIPlayground, do not adjust manually global $wgAutoloadClasses; @@ -7,6 +7,7 @@ '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\\GeSHICodeRenderer' => __DIR__ . '/includes/CodeRenderer.php', 'OOUIPlayground\\GroupElementFilter' => __DIR__ . '/includes/argument-filters/GroupElementFilter.php', 'OOUIPlayground\\ICodeRenderer' => __DIR__ . '/includes/CodeRenderer.php', @@ -18,6 +19,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', @@ -27,4 +30,5 @@ 'OOUI\\DeferredWidget' => __DIR__ . '/includes/DeferredWidget.php', 'OOUI\\MockGroupWidget' => __DIR__ . '/tests/phpunit/mocks/MockWidget.php', 'OOUI\\MockWidget' => __DIR__ . '/tests/phpunit/mocks/MockWidget.php', + 'SpecialOOUIDemo' => __DIR__ . '/includes/SpecialOOUIDemo.php', ); diff --git a/i18n/en.json b/i18n/en.json index 86b239f..8c0c34e 100644 --- a/i18n/en.json +++ b/i18n/en.json @@ -5,5 +5,6 @@ "ooui-playground-language-php" : "PHP", "ooui-playground-language-javascript" : "JavaScript", "ooui-playground-error-no-type" : "You must specify a type", - "ooui-playground-error-bad-type" : "There is no type called '$1'" + "ooui-playground-error-bad-type" : "There is no type called '$1'", + "oouidemo" : "OOJS-UI Demo" } \ No newline at end of file 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/OOUILightNCandy.php b/includes/OOUILightNCandy.php new file mode 100644 index 0000000..db30d35 --- /dev/null +++ b/includes/OOUILightNCandy.php @@ -0,0 +1,138 @@ +<?php + +namespace OOUIPlayground; + +use FormatJson; +use LightnCandy; +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 renderTemplate( $templateName, array $input ) { + Theme::setSingleton( new MediaWikiTheme ); + + OOUIStatic::overrideFactory( $this->widgetFactory ); + OOUIStatic::overrideRepository( $this->widgetRepo ); + $output = parent::renderTemplate( $templateName, $input ); + OOUIStatic::clearOverrides(); + 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; + + $widgetInfo = self::getRepo()->getInfo( $widgetName ); + $params = self::getParams( $widgetInfo, $options ); + if ( isset( $params['render'] ) && $params['render'] === 'json' ) { + unset( $params['render'] ); + $params['type'] = $widgetInfo->getType(); + return array( FormatJson::encode( $params ) . ',', 'raw' ); + } else { + $widget = self::getFactory()->getWidget( $widgetInfo, $params ); + + return array( $widget->__toString(), 'raw' ); + } + } + + 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 79d3916..3ef509f 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 @@ -28,19 +26,6 @@ } /** - * 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]; - } - - /** * Does any initialisation necessary to get OOUI to work. */ protected static function setupOOUI() { @@ -51,6 +36,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 ); diff --git a/includes/SpecialOOUIDemo.php b/includes/SpecialOOUIDemo.php new file mode 100644 index 0000000..5fe1350 --- /dev/null +++ b/includes/SpecialOOUIDemo.php @@ -0,0 +1,70 @@ +<?php + +use OOUI\Widget; +use OOUIPlayground\Container; +use OOUIPlayground\GroupElementFilter; +use OOUIPlayground\OOUILightNCandy; +use OOUIPlayground\WidgetFactory; +use OOUIPlayground\WidgetInfo; + +class SpecialOOUIDemo extends SpecialPage { + function __construct() { + parent::__construct( 'OOUIDemo' ); + } + + function execute( $par ) { + $this->setHeaders(); + + $this->getOutput()->addModules( array( 'oojs-ui' ) ); + $this->getOutput()->addModuleStyles( array( 'oojs-ui.styles' ) ); + + $widgetRepository = Container::get( 'widgetRepository' ); + $widgetFactory = new RecordingWidgetFactory( $widgetRepository ); + $widgetFactory->addFilter( new GroupElementFilter( $widgetFactory ) ); + $templating = new OOUILightNCandy( null /* default repo */, $widgetFactory, __DIR__ . "/../templates" ); + + $output = $this->getContext()->getOutput(); + + $output->addHTML( $templating->renderTemplate( 'demo', array('foo' => 'bar') ) ); + $output->addHTML( + $templating->renderTemplate( + 'used_widgets', + array( 'used' => $widgetFactory->getUsedWidgets() ) + ) + ); + } +} + +/** @todo Would be nice to be a Decorator instead of a whole new subclass */ +class RecordingWidgetFactory extends WidgetFactory { + protected $createdWidgets = array(); + + public function getWidget( WidgetInfo $info, array $args ) { + $output = parent::getWidget( $info, $args ); + + $this->recordWidget( $info, $output ); + + return $output; + } + + public function getUsedWidgets() { + return array_keys( array_filter( $this->createdWidgets ) ); + } + + protected function recordWidget( WidgetInfo $info, Widget $widget ) { + $typesCreated = array( $info->getFullClassName() ); + + $reflection = $info->getReflection()->getParentClass(); + while( $reflection ) { + $typesCreated[] = $reflection->getName(); + $reflection = $reflection->getParentClass(); + } + + $typesCreated = array_merge( $typesCreated, $info->getMixins() ); + + $this->createdWidgets = array_merge( + $this->createdWidgets, + array_fill_keys( $typesCreated, true ) + ); + } +} \ No newline at end of file diff --git a/includes/WidgetInfo.php b/includes/WidgetInfo.php index efc1f15..e764aef 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 ); } } } @@ -128,6 +124,18 @@ return 'OOUI\\' . $this->className; } + public function getContentMode() { + return $this->getAttribute( 'contentMode' ) ?: 'var'; + } + + public function getContentVar() { + return $this->getAttribute( 'contentVar' ) ?: 'content'; + } + + 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 diff --git a/includes/container.php b/includes/container.php index 462fec9..be6abcf 100644 --- a/includes/container.php +++ b/includes/container.php @@ -11,12 +11,16 @@ $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', @@ -32,6 +36,7 @@ ), 'label' => array( 'class' => 'LabelWidget', + 'contentVar' => 'label', ), 'radioinput' => array( 'class' => 'RadioInputWidget', diff --git a/templates/demo.template b/templates/demo.template new file mode 100644 index 0000000..ef3408a --- /dev/null +++ b/templates/demo.template @@ -0,0 +1,21 @@ +{{#with "testctx"}} +<h3>Labels</h3> +<p>Normal labels:<br/> +{{#ooui "label"}} +This is my test template. +{{/ooui}} +</p> + +<p>Labels with icons:<br/> +{{ooui "icon" iconTitle="Add" icon="add"}} {{#ooui "label"}}Add{{/ooui}} +</p> + +<h3>Buttons</h3> + +{{#ooui "buttongroup"}} +{{#ooui "button" render="json"}}Test button{{/ooui}} +{{#ooui "button" flags_list="progressive primary" render="json"}}Progressive primary{{/ooui}} +{{#ooui "button" flags_list="destructive primary" render="json"}}Destructive primary{{/ooui}} +{{#ooui "button" flags_list="constructive" render="json"}}Constructive{{/ooui}} +{{/ooui}} +{{/with}} diff --git a/templates/used_widgets.template b/templates/used_widgets.template new file mode 100644 index 0000000..a6b1183 --- /dev/null +++ b/templates/used_widgets.template @@ -0,0 +1,6 @@ +<p>The following widgets were used in generating this demo:</p> +<ul> +{{#each used}} + <li>{{.}}</li> +{{/each}} +</ul> \ No newline at end of file -- To view, visit https://gerrit.wikimedia.org/r/190466 To unsubscribe, visit https://gerrit.wikimedia.org/r/settings Gerrit-MessageType: newchange Gerrit-Change-Id: Ia4c101567d1adef5c6cdc89b2ec0ed884fed73e7 Gerrit-PatchSet: 1 Gerrit-Project: mediawiki/extensions/OOUIPlayground Gerrit-Branch: master Gerrit-Owner: Werdna <agarr...@wikimedia.org> _______________________________________________ MediaWiki-commits mailing list MediaWiki-commits@lists.wikimedia.org https://lists.wikimedia.org/mailman/listinfo/mediawiki-commits