mirror of
https://github.com/Universal-Omega/PortableInfobox.git
synced 2024-11-15 11:59:56 +00:00
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:
commit
cae634dfb1
|
@ -5,6 +5,7 @@ $wgExtensionCredits[ 'parserhook' ][] = [
|
|||
'name' => 'Portable Infobox',
|
||||
'author' => [
|
||||
'Adam Robak',
|
||||
'Diana Falkowska',
|
||||
'Jacek Jursza',
|
||||
'Mateusz Rybarski',
|
||||
'Rafał Leszczyński',
|
||||
|
|
|
@ -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 );
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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) ],
|
||||
];
|
||||
}
|
||||
|
||||
|
|
|
@ -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] );
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -1 +1 @@
|
|||
<aside class="portable-infobox{{#theme}} {{theme}}{{/theme}}">{{{content}}}</aside>
|
||||
<aside class="portable-infobox{{#theme}} {{theme}}{{/theme}}{{#layout}} {{layout}}{{/layout}}">{{{content}}}</aside>
|
||||
|
|
|
@ -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 ]
|
||||
];
|
||||
}
|
||||
}
|
|
@ -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'
|
||||
]
|
||||
];
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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' => [
|
||||
[
|
||||
|
|
7
tests/nodes/NodeGroupTest.php
Normal file
7
tests/nodes/NodeGroupTest.php
Normal file
|
@ -0,0 +1,7 @@
|
|||
<?php
|
||||
/**
|
||||
* Created by IntelliJ IDEA.
|
||||
* User: adamr
|
||||
* Date: 15/06/15
|
||||
* Time: 14:38
|
||||
*/
|
Loading…
Reference in a new issue