Merge remote-tracking branch 'origin/dev' into DAT-2875-refactor

# Conflicts:
#	extensions/wikia/PortableInfobox/controllers/PortableInfoboxParserTagController.class.php
#	extensions/wikia/PortableInfobox/services/Parser/Nodes/NodeGroup.php
#	extensions/wikia/PortableInfobox/tests/ParserNodesTest.php
This commit is contained in:
idradm 2015-06-15 14:57:57 +02:00
commit cae634dfb1
13 changed files with 268 additions and 27 deletions

View file

@ -5,6 +5,7 @@ $wgExtensionCredits[ 'parserhook' ][] = [
'name' => 'Portable Infobox',
'author' => [
'Adam Robak',
'Diana Falkowska',
'Jacek Jursza',
'Mateusz Rybarski',
'Rafał Leszczyński',

View file

@ -6,10 +6,16 @@ class PortableInfoboxParserTagController extends WikiaController {
const PARSER_TAG_NAME = 'infobox';
const INFOBOXES_PROPERTY_NAME = 'infoboxes';
const DEFAULT_THEME_NAME = 'wikia';
const INFOBOX_THEME_PREFIX = "portable-infobox-theme-";
const DEFAULT_LAYOUT_NAME = 'default';
const INFOBOX_THEME_PREFIX = 'portable-infobox-theme-';
const INFOBOX_LAYOUT_PREFIX = 'portable-infobox-layout-';
private $markerNumber = 0;
private $markers = [ ];
private $supportedLayouts = [
'default',
'tabular'
];
protected static $instance;
@ -74,8 +80,8 @@ class PortableInfoboxParserTagController extends WikiaController {
$this->saveToParserOutput( $parser->getOutput(), $infoboxNode );
$theme = $this->getThemeWithDefault( $params, $frame );
return ( new PortableInfoboxRenderService() )->renderInfobox( $data, $theme );
$layout = $this->getLayout( $params );
return ( new PortableInfoboxRenderService() )->renderInfobox( $data, $theme, $layout );
}
/**
@ -144,6 +150,15 @@ class PortableInfoboxParserTagController extends WikiaController {
( isset( $params[ 'theme' ] ) ? $params[ 'theme' ] : self::DEFAULT_THEME_NAME );
}
private function getLayout( $params ) {
$layoutName = isset( $params[ 'layout' ] ) ? $params[ 'layout' ] : false;
if ( $layoutName && in_array( $layoutName, $this->supportedLayouts ) ) {
//make sure no whitespaces, prevents side effects
return self::INFOBOX_LAYOUT_PREFIX . $layoutName;
}
return self::INFOBOX_LAYOUT_PREFIX . self::DEFAULT_LAYOUT_NAME;
}
/**
* Function ensures that arrays are used for merging
*
@ -160,5 +175,4 @@ class PortableInfoboxParserTagController extends WikiaController {
return array_merge( $namedArgs, $args );
}
}

View file

@ -21,11 +21,12 @@ class MediaWikiParserService implements ExternalParser {
*/
public function parse( $wikitext ) {
wfProfileIn( __METHOD__ );
if ( substr( $wikitext, 0, 1 ) == "*" ) {
if ( in_array( substr( $wikitext, 0, 1 ), [ '*', '#' ] ) ) {
//fix for first item list elements
$wikitext = "\n" . $wikitext;
}
$output = $this->parser->internalParse( $wikitext, false, $this->frame );
$parsed = $this->parser->internalParse( $wikitext, false, $this->frame );
$output = $this->parser->doBlockLevels( $parsed, false );
$this->parser->replaceLinkHolders( $output );
wfProfileOut( __METHOD__ );
@ -69,15 +70,4 @@ class MediaWikiParserService implements ExternalParser {
$sha1 = $file ? $file->getSha1() : false;
$this->parser->getOutput()->addImage( $title, $tmstmp, $sha1 );
}
private function getParserTitle() {
return $this->parser->getTitle();
}
private function getParserOptions() {
$options = $this->parser->getOptions();
$options->enableLimitReport( false );
return $options;
}
}

View file

@ -178,6 +178,14 @@ class Node {
: null;
}
protected function getXmlAttributeFromSupported( \SimpleXMLElement $xmlNode, $attribute, $supportedAttributes ) {
$attr = $this->getXmlAttribute( $xmlNode, $attribute );
if ( isset($attr) && in_array( $attr, $supportedAttributes ) ) {
return $attr;
}
return static::DEFAULT_TAG_NAME;
}
protected function getRawInfoboxData( $key ) {
return isset( $this->infoboxData[ $key ] ) ? $this->infoboxData[ $key ]
: null;

View file

@ -2,10 +2,19 @@
namespace Wikia\PortableInfobox\Parser\Nodes;
class NodeGroup extends Node {
const DATA_LAYOUT_ATTR_NAME = 'layout';
const DEFAULT_TAG_NAME = 'default';
private $supportedGroupLayouts = [
'default',
'horizontal'
];
public function getData() {
if ( !isset( $this->data ) ) {
$this->data = [ 'value' => $this->getDataForChildren() ];
$this->data = [ 'value' => $this->getDataForChildren(),
'layout' => $this->getXmlAttributeFromSupported( $this->xmlNode,
self::DATA_LAYOUT_ATTR_NAME, $this->supportedGroupLayouts) ];
}
return $this->data;
@ -14,7 +23,9 @@ class NodeGroup extends Node {
public function getRenderData() {
return [
'type' => $this->getType(),
'data' => [ 'value' => $this->getRenderDataForChildren() ],
'data' => [ 'value' => $this->getRenderDataForChildren(),
'layout' => $this->getXmlAttributeFromSupported( $this->xmlNode,
self::DATA_LAYOUT_ATTR_NAME, $this->supportedGroupLayouts) ],
];
}

View file

@ -39,7 +39,7 @@ class PortableInfoboxRenderService extends WikiaService {
* @param array $infoboxdata
* @return string - infobox HTML
*/
public function renderInfobox( array $infoboxdata, $theme ) {
public function renderInfobox( array $infoboxdata, $theme, $layout ) {
wfProfileIn( __METHOD__ );
$infoboxHtmlContent = '';
@ -52,7 +52,7 @@ class PortableInfoboxRenderService extends WikiaService {
$infoboxHtmlContent .= $this->renderComparisonItem( $data['value'] );
break;
case 'group':
$infoboxHtmlContent .= $this->renderGroup( $data['value'] );
$infoboxHtmlContent .= $this->renderGroup( $data );
break;
case 'footer':
$infoboxHtmlContent .= $this->renderItem( 'footer', $data );
@ -65,7 +65,7 @@ class PortableInfoboxRenderService extends WikiaService {
}
if(!empty($infoboxHtmlContent)) {
$output = $this->renderItem( 'wrapper', [ 'content' => $infoboxHtmlContent, 'theme' => $theme ] );
$output = $this->renderItem( 'wrapper', [ 'content' => $infoboxHtmlContent, 'theme' => $theme, 'layout' => $layout ] );
} else {
$output = '';
}
@ -126,8 +126,10 @@ class PortableInfoboxRenderService extends WikiaService {
*/
private function renderGroup( $groupData ) {
$groupHTMLContent = '';
$dataItems = $groupData['value'];
$layout = $groupData['layout'];
foreach ( $groupData as $item ) {
foreach ( $dataItems as $item ) {
$type = $item['type'];
if ( $this->validateType( $type ) ) {
@ -135,7 +137,7 @@ class PortableInfoboxRenderService extends WikiaService {
}
}
return $this->renderItem( 'group', [ 'content' => $groupHTMLContent ] );
return $this->renderItem( 'group', [ 'content' => $groupHTMLContent, 'layout' => $layout] );
}
/**

View file

@ -1,11 +1,12 @@
@import 'skins/shared/color';
@import 'skins/shared/mixins/columns';
@import 'skins/shared/mixins/flexbox';
$infobox-width: 270px; // temporary value used to mach with Khal Drogo Infobox
$infobox-margin: 15px;
$infobox-item-margin: 5px;
$infobox-background: mix($color-page, $color-links, 92%);
$infobox-section-header-background: transparentize($color-links, 0.9);
$infobox-section-header-background: transparentize($color-links, .9);
.portable-infobox {
background-color: $infobox-background;
@ -125,4 +126,68 @@ $infobox-section-header-background: transparentize($color-links, 0.9);
padding-right: $infobox-item-margin * 2;
}
}
.group-layout-horizontal {
&.item-type-group {
display: table;
table-layout: fixed;
width: 100%;
}
.item-type-header {
display: table-caption;
}
.item-type-key-val {
border-bottom: 0;
display: table-cell;
padding: $infobox-item-margin;
text-align: center;
}
.item-type-key-val:not(:last-of-type) {
border-right: 1px solid $infobox-section-header-background;
}
.portable-infobox-item-label {
font-size: inherit;
overflow: hidden;
vertical-align: top;
white-space: nowrap;
}
.portable-infobox-item-value {
padding-left: 0;
}
}
}
.portable-infobox-layout-tabular {
> .item-type-key-val,
.item-type-group .item-type-key-val {
@include flexbox;
@include flex-direction(row);
box-sizing: border-box;
overflow: hidden;
width: 100%;
.portable-infobox-item-label {
@include flex-basis($infobox-width / 3);
line-height: 18px;
margin-top: inherit;
}
.portable-infobox-item-value {
@include flex-basis($infobox-width * 2 / 3);
font-size: 14px;
line-height: 20px;
}
}
.portable-infobox-item-margins {
padding: $infobox-item-margin * 3 $infobox-item-margin * 2;
}
}

View file

@ -1 +1 @@
<section class="portable-infobox-item item-type-group">{{{content}}}</section>
<section class="portable-infobox-item item-type-group{{#layout}} group-layout-{{layout}}{{/layout}}">{{{content}}}</section>

View file

@ -1 +1 @@
<aside class="portable-infobox{{#theme}} {{theme}}{{/theme}}">{{{content}}}</aside>
<aside class="portable-infobox{{#theme}} {{theme}}{{/theme}}{{#layout}} {{layout}}{{/layout}}">{{{content}}}</aside>

View file

@ -2,10 +2,60 @@
class MediaWikiParserTest extends WikiaBaseTest {
/** @var Parser */
protected $parser;
public function setUp() {
$this->parser = new Parser();
$title = Title::newFromText( 'test' );
$options = new ParserOptions();
$this->parser->startExternalParse( $title, $options, 'text', true );
parent::setUp();
}
protected function parse( $wikitext, $params, $newline = false ) {
$withVars = $this->parser->replaceVariables( $wikitext,
$this->parser->getPreprocessor()->newCustomFrame( $params ) );
$parserOutput = $this->parser->parse( $withVars, $this->parser->getTitle(), $this->parser->getOptions(),
$newline );
return preg_replace( '|{{{.*}}}|Us', '', preg_replace( '|[\n\r]|Us', '', $parserOutput->getText() ) );
}
public function testAsideTagPWrappedDuringParsing() {
$aside = "<aside></aside>";
$result = ( new Parser() )->doBlockLevels( $aside, true );
//parser adds new line at the end of block
$this->assertEquals( $aside . "\n", $result );
}
/**
* @dataProvider mwParserWrapperDataProvider
*
* @param $wikitext
* @param $params
*/
public function testWrapper( $wikitext, $params, $newline ) {
$frame = $this->parser->getPreprocessor()->newCustomFrame( $params );
$wrapper = new \Wikia\PortableInfobox\Parser\MediaWikiParserService( $this->parser, $frame );
$output = $wrapper->parseRecursive( $wikitext );
$this->assertEquals( $this->parse( $wikitext, $params, $newline ), $output );
}
public function mwParserWrapperDataProvider() {
return [
[ "*1\n*2\n*3", [ ], true ],
[ "''d''", [ ], false ],
[ "'''dd'''", [ ], false ],
[ "#1\n#2\n#3 ksajdlk", [ ], true ],
[ "{{{test}}}", [ 'test' => 1 ], false ],
[ " :asdf", [ ], false ],
[ "\n:asdf", [ ], false ],
[ "\n;asdf", [ ], false ],
[ "[[asdf]]", [ ], false ]
];
}
}

View file

@ -135,4 +135,60 @@ class PortableInfoboxParserTagControllerTest extends WikiaBaseTest {
PortableInfoboxParserTagController::INFOBOX_THEME_PREFIX . $expectedName
) );
}
/**
* @dataProvider testGetLayoutDataProvider
*/
public function testGetLayout( $layout, $expectedOutput, $text, $message ) {
$marker = $this->controller->renderInfobox( $text, $layout, $this->parser,
$this->parser->getPreprocessor()->newFrame() )[ 0 ];
$output = $this->controller->replaceMarkers( $marker );
$this->assertTrue( $this->checkClassName(
$output,
$expectedOutput,
$message
) );
}
public function testGetLayoutDataProvider() {
return [
[
'layout' => [ 'layout' => 'tabular' ],
'expectedOutput' => 'portable-infobox-layout-tabular',
'text' => '<data><default>test</default></data>',
'message' => 'set tabular layout'
],
[
'layout' => [ 'layout' => 'looool' ],
'expectedOutput' => 'portable-infobox-layout-default',
'text' => '<data><default>test</default></data>',
'message' => 'invalid layout name'
],
[
'layout' => [ 'layout' => '' ],
'expectedOutput' => 'portable-infobox-layout-default',
'text' => '<data><default>test</default></data>',
'message' => 'layout is empty string'
],
[
'layout' => [ 'layout' => 5 ],
'expectedOutput' => 'portable-infobox-layout-default',
'text' => '<data><default>test</default></data>',
'message' => 'layout is an integer'
],
[
'layout' => [ 'layout' => [] ],
'expectedOutput' => 'portable-infobox-layout-default',
'text' => '<data><default>test</default></data>',
'message' => 'layout an empty table'
],
[
'layout' => [],
'expectedOutput' => 'portable-infobox-layout-default',
'text' => '<data><default>test</default></data>',
'message' => 'layout is not set'
]
];
}
}

View file

@ -271,6 +271,43 @@ class PortableInfoboxRenderServiceTest extends PHPUnit_Framework_TestCase {
</aside>',
'description' => 'Infobox with title, image and group with header two key-value pairs'
],
[
'input' => [
[
'type' => 'group',
'data' => [
'value' => [
[
'type' => 'header',
'data' => [
'value' => 'Test Header'
]
],
[
'type' => 'data',
'data' => [
'label' => 'test label',
'value' => 'test value'
]
]
],
'layout' => 'horizontal'
]
]
],
'output' => '<aside class="portable-infobox">
<section class="portable-infobox-item item-type-group group-layout-horizontal">
<div class="portable-infobox-item item-type-header portable-infobox-item-margins portable-infobox-header-background">
<h2 class="portable-infobox-header portable-infobox-header-font">Test Header</h2>
</div>
<div class="portable-infobox-item item-type-key-val portable-infobox-item-margins">
<h3 class="portable-infobox-item-label portable-infobox-header-font">test label</h3>
<div class="portable-infobox-item-value">test value</div>
</div>
</section>
</aside>',
'description' => 'Infobox with title, image and horizontal group'
],
[
'input' => [
[

View file

@ -0,0 +1,7 @@
<?php
/**
* Created by IntelliJ IDEA.
* User: adamr
* Date: 15/06/15
* Time: 14:38
*/