Add MobileFrontend support

This commit is contained in:
Luqgreg 2018-08-01 19:15:43 +02:00
commit 817553f60f
21 changed files with 148 additions and 1498 deletions

View file

@ -7,6 +7,12 @@ class PortableInfoboxHooks {
return true;
}
public static function onBeforePageDisplayMobile( OutputPage $out, Skin $skin ) {
$out->addModules( 'ext.PortableInfobox.mobile' );
return true;
}
public static function onImageServingCollectImages( &$imageNamesArray, $articleTitle ) {
if ( $articleTitle ) {
@ -118,13 +124,4 @@ class PortableInfoboxHooks {
return true;
}
public static function onArticleAsJsonBeforeEncode( &$text ) {
$tagController = PortableInfoboxParserTagController::getInstance();
$tagController->moveFirstMarkerToTop( $text );
$text = $tagController->replaceMarkers( $text );
return true;
}
}

View file

@ -54,11 +54,7 @@ class PortableInfoboxParserTagController extends WikiaObject {
* @return string
*/
public static function replaceInfoboxMarkers( Parser $parser, &$text ) {
global $wgArticleAsJson;
// The replacements for ArticleAsJson are handled in PortableInfoboxHooks::onArticleAsJsonBeforeEncode
if ( !$wgArticleAsJson ) {
$text = static::getInstance()->replaceMarkers( $text );
}
$text = static::getInstance()->replaceMarkers( $text );
return true;
}
@ -95,8 +91,7 @@ class PortableInfoboxParserTagController extends WikiaObject {
$accentColor = $this->getColor( self::ACCENT_COLOR, $params, $frame );
$accentColorText = $this->getColor( self::ACCENT_COLOR_TEXT, $params, $frame );
$renderService = \F::app()->checkSkin( 'wikiamobile' ) ?
new PortableInfoboxMobileRenderService() : new PortableInfoboxRenderService();
$renderService = new PortableInfoboxRenderService();
return $renderService->renderInfobox( $data, implode( ' ', $themeList ), $layout, $accentColor, $accentColorText );
}

View file

@ -20,6 +20,11 @@
"ext.PortableInfobox": {
"scripts": "js/PortableInfobox.js",
"styles": "styles/PortableInfobox.less"
},
"ext.PortableInfobox.mobile": {
"scripts": "js/PortableInfobox.js",
"styles": "styles/PortableInfobox.less",
"targets": "mobile"
}
},
"ResourceFileModulePaths": {
@ -40,7 +45,6 @@
"PortableInfoboxDataService": "services/PortableInfoboxDataService.class.php",
"PortableInfoboxQueryService": "services/PortableInfoboxQueryService.class.php",
"PortableInfoboxRenderService": "services/PortableInfoboxRenderService.class.php",
"PortableInfoboxMobileRenderService": "services/PortableInfoboxMobileRenderService.class.php",
"PortableInfoboxErrorRenderService": "services/PortableInfoboxErrorRenderService.class.php",
"Wikia\\PortableInfobox\\Parser\\ExternalParser": "services/Parser/ExternalParser.php",
"Wikia\\PortableInfobox\\Parser\\SimpleParser": "services/Parser/SimpleParser.php",
@ -68,7 +72,6 @@
"PassThroughSanitizer": "services/Sanitizers/PassThroughSanitizer.php",
"NodeTypeSanitizerInterface": "services/Sanitizers/NodeTypeSanitizerInterface.php",
"NodeDataSanitizer": "services/Sanitizers/NodeDataSanitizer.php",
"NodeHeroImageSanitizer": "services/Sanitizers/NodeHeroImageSanitizer.php",
"NodeHorizontalGroupSanitizer": "services/Sanitizers/NodeHorizontalGroupSanitizer.php",
"NodeImageSanitizer": "services/Sanitizers/NodeImageSanitizer.php",
"NodeTitleSanitizer": "services/Sanitizers/NodeTitleSanitizer.php",
@ -83,6 +86,7 @@
"ParserFirstCallInit": "PortableInfoboxParserTagController::parserTagInit",
"AfterParserParseImageGallery": "PortableInfoboxHooks::onAfterParserParseImageGallery",
"BeforePageDisplay": "PortableInfoboxHooks::onBeforePageDisplay",
"BeforePageDisplayMobile": "PortableInfoboxHooks::onBeforePageDisplayMobile",
"ParserAfterTidy": "PortableInfoboxParserTagController::replaceInfoboxMarkers",
"ImageServing::buildAndGetIndex": "PortableInfoboxHooks::onImageServingCollectImages",
"wgQueryPages": "PortableInfoboxHooks::onWgQueryPages",
@ -90,8 +94,7 @@
"ArticlePurge": "PortableInfoboxHooks::onArticlePurge",
"ArticleSave": "PortableInfoboxHooks::onArticleSave",
"BacklinksPurge": "PortableInfoboxHooks::onBacklinksPurge",
"ArticleInsertComplete": "PortableInfoboxHooks::onArticleInsertComplete",
"ArticleAsJsonBeforeEncode": "PortableInfoboxHooks::onArticleAsJsonBeforeEncode"
"ArticleInsertComplete": "PortableInfoboxHooks::onArticleInsertComplete"
},
"SpecialPages": {
"AllInfoboxes": "AllinfoboxesQueryPage"

View file

@ -13,18 +13,12 @@ class PortableInfoboxMustacheEngine {
'title' => 'PortableInfoboxItemTitle.mustache',
'header' => 'PortableInfoboxItemHeader.mustache',
'image' => 'PortableInfoboxItemImage.mustache',
'image-mobile' => 'PortableInfoboxItemImageMobile.mustache',
'image-mobile-wikiamobile' => 'PortableInfoboxItemImageMobileWikiaMobile.mustache',
'data' => 'PortableInfoboxItemData.mustache',
'group' => 'PortableInfoboxItemGroup.mustache',
'smart-group' => 'PortableInfoboxItemSmartGroup.mustache',
'horizontal-group-content' => 'PortableInfoboxHorizontalGroupContent.mustache',
'navigation' => 'PortableInfoboxItemNavigation.mustache',
'hero-mobile' => 'PortableInfoboxItemHeroMobile.mustache',
'hero-mobile-wikiamobile' => 'PortableInfoboxItemHeroMobileWikiaMobile.mustache',
'image-collection' => 'PortableInfoboxItemImageCollection.mustache',
'image-collection-mobile' => 'PortableInfoboxItemImageCollectionMobile.mustache',
'image-collection-mobile-wikiamobile' => 'PortableInfoboxItemImageCollectionMobileWikiaMobile.mustache'
'image-collection' => 'PortableInfoboxItemImageCollection.mustache'
];
protected $templateEngine;

View file

@ -32,20 +32,13 @@ class NodeImage extends Node {
}
public static function getTabberData( $html ) {
global $wgArticleAsJson;
$data = array();
$doc = HtmlHelper::createDOMDocumentFromText( $html );
$sxml = simplexml_import_dom( $doc );
$divs = $sxml->xpath( '//div[@class=\'tabbertab\']' );
foreach ( $divs as $div ) {
if ( $wgArticleAsJson ) {
if ( preg_match( '/data-ref="([^"]+)"/', $div->asXML(), $out ) ) {
$data[] = array( 'label' => (string) $div['title'], 'title' => \ArticleAsJson::$media[$out[1]]['title'] );
}
} else {
if ( preg_match( '/data-(video|image)-key="([^"]+)"/', $div->asXML(), $out ) ) {
$data[] = array( 'label' => (string) $div['title'], 'title' => $out[2] );
}
if ( preg_match( '/data-(video|image)-key="([^"]+)"/', $div->asXML(), $out ) ) {
$data[] = array( 'label' => (string) $div['title'], 'title' => $out[2] );
}
}
return $data;

View file

@ -1,174 +0,0 @@
<?php
class PortableInfoboxMobileRenderService extends PortableInfoboxRenderService {
const MEDIA_CONTEXT_INFOBOX_HERO_IMAGE = 'infobox-hero-image';
const MEDIA_CONTEXT_INFOBOX = 'infobox';
const MOBILE_THUMBNAIL_WIDTH = 360;
/**
* renders infobox
*
* @param array $infoboxdata
*
* @param $theme
* @param $layout
* @param $accentColor
* @param $accentColorText
* @return string - infobox HTML
*/
public function renderInfobox( array $infoboxdata, $theme, $layout, $accentColor, $accentColorText ) {
$items = $this->splitOfHeroData( $infoboxdata, [ 'hero' => [ ], 'infobox' => [ ] ] );
if ( !empty( $items['hero'] ) ) {
$infoboxHtmlContent = $this->renderInfoboxHero( $items['hero'] ) . $this->renderChildren( $items['infobox'] );
} else {
$infoboxHtmlContent = $this->renderChildren( $infoboxdata );
}
if ( !empty( $infoboxHtmlContent ) ) {
$output = $this->renderItem( 'wrapper', [ 'content' => $infoboxHtmlContent, 'isMercury' => $this->isMercury() ] );
} else {
$output = '';
}
// Since portable infoboxes are rendered within ParserAfterTidy Hook, we can not be sure if this method will be
// invoked before or after infobox is rendered. If this method does not process PI html, markers related to
// template type parsing may be included in the result html and this may break our mobile application.
// See XW-4827
TemplateTypesParser::onParserAfterTidy( null, $output );
\Wikia\PortableInfobox\Helpers\PortableInfoboxDataBag::getInstance()->setFirstInfoboxAlredyRendered( true );
return $output;
}
private function splitOfHeroData( $items, $result ) {
foreach ( $items as $item ) {
$data = $item['data'];
$type = $item['type'];
if ( $this->isValidHeroDataItem( $item, $result['hero'] ) ) {
$result['hero'][$type] = $data;
} elseif ( $type === 'group' ) {
// go deeper to find nested hero data items
$groupResult = $this->splitOfHeroData( $data['value'], [ 'hero' => $result['hero'], 'infobox' => [ ] ] );
// make sure other elements structure stays the same
$result['hero'] = $groupResult['hero'];
$item['data']['value'] = $groupResult['infobox'];
$result['infobox'][] = $item;
} else {
$result['infobox'][] = $item;
}
}
return $result;
}
protected function renderImage( $data ) {
$images = [ ];
$count = count( $data );
$helper = $this->getImageHelper();
for ( $i = 0; $i < $count; $i++ ) {
$data[$i]['context'] = self::MEDIA_CONTEXT_INFOBOX;
$data[$i] = $helper->extendImageData( $data[$i], self::MOBILE_THUMBNAIL_WIDTH );
if ( !!$data[$i] ) {
$images[] = $data[$i];
}
}
if ( count( $images ) === 0 ) {
return '';
}
// use different template for wikiamobile
if ( !$this->isMercury() ) {
// always display only the first image on WikiaMobile
$data = $images[0];
$templateName = 'image-mobile-wikiamobile';
} else {
if ( count( $images ) === 1 ) {
$data = $images[0];
$templateName = 'image-mobile';
} else {
// more than one image means image collection
$data = $helper->extendImageCollectionData( $images );
$templateName = 'image-collection-mobile';
}
}
$data = SanitizerBuilder::createFromType( 'image' )->sanitize( $data );
return parent::render( $templateName, $data );
}
protected function renderTitle( $data ) {
return $this->render( 'title', $data );
}
protected function renderHeader( $data ) {
return $this->render( 'header', $data );
}
protected function render( $type, array $data ) {
$data = SanitizerBuilder::createFromType( $type )->sanitize( $data );
return parent::render( $type, $data );
}
/**
* renders infobox hero component
*
* @param array $data - infobox hero component data
*
* @return string
*/
private function renderInfoboxHero( $data ) {
$helper = $this->getImageHelper();
$template = '';
// In mobile-wiki SPA content of the first infobox's hero module has been moved to the article header.
$firstInfoboxAlredyRendered = \Wikia\PortableInfobox\Helpers\PortableInfoboxDataBag::getInstance()
->isFirstInfoboxAlredyRendered();
if ( isset( $data['image'] ) ) {
$image = $data['image'][0];
$image['context'] = self::MEDIA_CONTEXT_INFOBOX_HERO_IMAGE;
$image = $helper->extendImageData( $image, self::MOBILE_THUMBNAIL_WIDTH );
$data['image'] = $image;
if ( !$this->isMercury() ) {
return $this->renderItem( 'hero-mobile-wikiamobile', $data );
} elseif ( $firstInfoboxAlredyRendered ) {
return $this->renderItem( 'hero-mobile', $data );
}
} elseif ( !$this->isMercury() || $firstInfoboxAlredyRendered ) {
return $this->renderItem( 'title', $data['title'] );
}
return !empty( $template ) ? $this->renderItem( $template, $data['title'] ) : '';
}
/**
* checks if infobox data item is valid hero component data.
*
* @param array $item - infobox data item
* @param array $heroData - hero component data
*
* @return bool
*/
private function isValidHeroDataItem( $item, $heroData ) {
$type = $item['type'];
return ( $type === 'title' && !isset( $heroData['title'] ) ) ||
( $type === 'image' && !isset( $heroData['image'] ) &&
count( $item['data'] ) === 1 );
}
private function isMercury() {
global $wgArticleAsJson;
return !empty( $wgArticleAsJson );
}
}

View file

@ -1,24 +0,0 @@
<?php
class NodeHeroImageSanitizer extends NodeSanitizer {
protected $allowedTags = [ 'a' ];
protected $selectorsWrappingTextToPad = [ 'li' ];
protected $selectorsWrappingAllowedFeatures = [ 'sup[@class="reference"]' ];
protected $selectorsForFullRemoval =
[ 'script', 'span[@itemprop="duration"]', '*[contains(@data-component,"article-media")]'];
/**
* @param $data
* @return mixed
*/
public function sanitize( $data ) {
if ( !empty( $data[ 'title' ][ 'value' ] ) ) {
$data[ 'title' ][ 'value' ] = $this->sanitizeElementData( $data[ 'title' ][ 'value' ] );
}
if ( !empty( $data[ 'image' ][ 'caption' ] ) ) {
$data[ 'image' ]['caption'] = $this->sanitizeElementData( $data[ 'image' ]['caption'] );
}
return $data;
}
}

View file

@ -18,9 +18,6 @@ class SanitizerBuilder {
return new NodeTitleSanitizer();
case 'image':
return new NodeImageSanitizer();
case 'hero-mobile':
case 'hero-mobile-wikiamobile':
return new NodeHeroImageSanitizer();
default:
return new PassThroughSanitizer();
}

View file

@ -11,57 +11,62 @@
background: var(--pi-background);
clear: right;
float: right;
font-size: .85em;
margin: 0 0 var(--pi-margin) var(--pi-margin);
width: var(--pi-width);
.pi-border-color {
border-color: var(--pi-border-color);
}
.pi-secondary-background {
background-color: var(--pi-secondary-background);
}
.pi-secondary-font {
margin: 0;
padding: 0;
}
.pi-item-spacing {
padding: var(--pi-item-spacing);
}
.pi-title {
border: 0;
margin: 0;
font-family: inherit;
font-size: 1.75em;
line-height: 1.5;
}
.pi-header {
border: 0;
margin: 0;
font-family: inherit;
font-size: 1.2em;
font-weight: bold;
line-height: 1.3;
}
.pi-title {
border: 0;
.pi-image {
margin: 0;
font-size: 18px;
line-height: 28px;
max-width: 100%;
text-align: center;
}
.pi-data-label {
padding-top: 0;
font-size: inherit;
line-height: inherit;
}
.pi-data-value {
>* {
>:not(ul), li {
margin: 0;
}
li {
margin: 0;
line-height: 19px;
}
ol, ul {
ol {
list-style-position: inside;
}
}
>.pi-item:last-child {
border-bottom: 0;
}
.pi-secondary-font {
font-size: 12px;
font-weight: bold;
line-height: 18px;
margin-top: 0;
}
.pi-item-spacing {
padding: var(--pi-item-spacing);
}
}
.pi {
&-secondary-background {
background-color: var(--pi-secondary-background);
}
&-border-color {
border-color: var(--pi-border-color);
}
&-image {
text-align: center;
margin: 0;
&-thumbnail{
max-width: var(--pi-width);
height: auto;
@ -105,9 +110,8 @@
-ms-hyphens: auto;
hyphens: auto;
color: #808080;
font-size: 12px;
font-size: 1em;
font-style: italic;
text-align: left;
word-wrap: break-word;
}
&-data {
@ -139,19 +143,17 @@
word-wrap: break-word;
}
&-value {
-ms-flex: 1;
-webkit-flex: 1;
-moz-flex: 1;
flex: 1;
-webkit-hyphens: auto;
-moz-hyphens: auto;
-ms-hyphens: auto;
hyphens: auto;
font-size: 12px;
line-height: 18px;
padding-left: 0;
word-break: break-word;
&:not(:first-child) {
-ms-flex-preferred-size: 180px;
-webkit-flex-basis: 180px;
-moz-flex-basis: 180px;
flex-basis: 180px;
padding-left: 10px;
}
}
@ -171,6 +173,9 @@
.pi-header {
text-align: left;
}
thead + tbody .pi-data-value {
padding-top: 0;
}
.pi-horizontal-group-item {
vertical-align: top;
&:not(:first-child) {
@ -184,11 +189,7 @@
}
&-smart {
&-data {
&-label:not(:first-child) {
border-color: var(--pi-border-color);
border-left-style: solid;
border-left-width: 1px;
}
&-label:not(:first-child),
&-value:not(:first-child) {
border-color: var(--pi-border-color);
border-left-style: solid;
@ -204,11 +205,14 @@
&:last-child {
border-bottom: 0;
}
&-body {
display: flex;
}
&-head {
display: flex;
& + .pi-smart-group-body .pi-data-value {
padding-top: 0;
}
}
&-body {
display: flex;
}
.pi-smart-data-label {
padding-bottom: 0;
@ -225,54 +229,94 @@
.pi-data {
display: block;
}
.pi-data-value {
.pi-data-value:not(:only-child) {
padding-left: 10px;
}
}
&-collapse {
.pi-header {
&:first-child {
padding-right: 25px;
position: relative;
&::after {
border-color: currentColor;
border-style: solid;
border-width: 2px 2px 0 0;
content: '';
display: block;
height: 5px;
right: 10px;
position: absolute;
top: 50%;
width: 5px;
-webkit-transform: rotate(-45deg);
transform: rotate(-45deg);
margin-top: -3px;
}
}
}
@media screen and (min-width: 720px) {
.pi-collapse .pi-header:first-child {
padding-right: 25px;
position: relative;
&::after {
border-color: currentColor;
border-style: solid;
border-width: 2px 2px 0 0;
content: '';
display: block;
height: 5px;
right: 10px;
position: absolute;
top: 50%;
width: 5px;
-webkit-transform: rotate(-45deg);
transform: rotate(-45deg);
margin-top: -3px;
}
&-closed {
.pi-header:first-child::after {
transform: rotate(135deg);
-webkit-transform: rotate(135deg);
-moz-transform: rotate(135deg);
-ms-transform: rotate(135deg);
margin-top: -5px;
}
> :nth-child(n+2) {
}
.pi-collapse-closed {
.pi-header:first-child::after {
transform: rotate(135deg);
-webkit-transform: rotate(135deg);
-moz-transform: rotate(135deg);
-ms-transform: rotate(135deg);
margin-top: -5px;
}
> :nth-child(n+2) {
display: none;
}
.pi-horizontal-group {
thead {
display: none;
}
.pi-horizontal-group {
thead {
display: none;
}
tbody {
display: none;
}
tbody {
display: none;
}
}
}
}
@media screen and (max-width: 720px) {
.portable-infobox {
float: none;
width: initial;
font-size: initial;
margin: 0;
.skin-minerva & {
margin: 0 -16px;
}
.pi-title {
text-align: center;
}
}
}
.skin-minerva {
.pi-caption {
margin: var(--pi-item-spacing);
}
.pi-horizontal-group {
display: table;
margin: 0;
width: 100% !important;
.pi-header {
display: table-caption;
}
}
.pi-navigation {
box-sizing: border-box;
width: 100%;
float: none;
}
}
/* PI errors */
p.pi-error-info {
background-color: #f33;
color: #fff;

View file

@ -1,10 +1,6 @@
{{!
This template is linked with of mercury/front/templates/main/components/infobox-builder-item-data.hbs
Changing this template requires modifying the other in mercury repo.
}}
<div class="pi-item pi-data pi-item-spacing pi-border-color{{#cssClasses}} {{{cssClasses}}}{{/cssClasses}}"{{#inlineStyles}} style="{{inlineStyles}}"{{/inlineStyles}}>
{{#label}}
<h3 class="pi-data-label pi-secondary-font">{{{label}}}</h3>
{{/label}}
<div class="pi-data-value pi-font">{{{value}}}</div>
</div>
</div>

View file

@ -1,45 +0,0 @@
<div class="pi-item pi-hero">
{{#title}}
<hgroup class="pi-hero-title-wrapper pi-item-spacing">
<h2 class="pi-hero-title">{{{value}}}</h2>
{{#image.caption}}
<h3 class="pi-hero-caption">{{{image.caption}}}</h3>
{{/image.caption}}
</hgroup>
{{/title}}
{{#image}}
<figure data-attrs="{{dataAttrs}}" data-file="{{fileName}}">
<a href="{{url}}">
<img class="article-media-placeholder lazyload"
src="data:image/svg+xml;charset=utf-8,%3Csvg xmlns%3D'http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg' viewBox%3D'0 0 {{originalWidth}} {{originalHeight}}'%2F%3E"
data-src="{{thumbnail}}"
data-srcset="{{thumbnail}}, {{thumbnail2x}} 2x"
data-sizes="auto"
alt="{{title}}"
{{#originalWidth}} width="{{originalWidth}}"{{/originalWidth}}
{{#originalHeight}} height="{{originalHeight}}"{{/originalHeight}}/>
<noscript>
<img src="{{url}}" alt="{{alt}}"{{#originalWidth}} width="{{originalWidth}}"{{/originalWidth}}{{#originalHeight}} height="{{originalHeight}}"{{/originalHeight}}/>
</noscript>
{{#isVideo}}
<div class="video-icon-container">
<svg class="wds-player-icon-play-medium" viewBox="0 0 180 180">
<g fill="none" fill-rule="evenodd">
<g opacity=".9" transform="rotate(90 75 90)">
<g fill="#000" filter="url(#a)">
<rect id="b" width="150" height="150" rx="75"></rect>
</g>
<g fill="#FFF">
<rect id="b" width="150" height="150" rx="75"></rect>
</g>
</g>
<path fill="#00D6D6" fill-rule="nonzero"
d="M80.87 58.006l34.32 25.523c3.052 2.27 3.722 6.633 1.496 9.746a6.91 6.91 0 0 1-1.497 1.527l-34.32 25.523c-3.053 2.27-7.33 1.586-9.558-1.527A7.07 7.07 0 0 1 70 114.69V63.643c0-3.854 3.063-6.977 6.84-6.977 1.45 0 2.86.47 4.03 1.34z"></path>
</g>
</svg>
</div>
{{/isVideo}}
</a>
</figure>
{{/image}}
</div>

View file

@ -1,16 +0,0 @@
<div class="pi-item pi-hero">
{{#title}}
<hgroup class="pi-hero-title-wrapper pi-item-spacing">
<h2 class="pi-hero-title">{{{value}}}</h2>
{{#image.caption}}
<h3 class="pi-hero-caption">{{{image.caption}}}</h3>
{{/image.caption}}
</hgroup>
{{/title}}
{{#image}}
<img src="data:image/gif;base64,R0lGODlhAQABAIABAAAAAP///yH5BAEAAAEALAAAAAABAAEAQAICTAEAOw%3D%3D"
data-src="{{thumbnail}}" class="pi-image-thumbnail lazy media article-media" alt="{{alt}}"
data-image-key="{{name}}" data-image-name="{{name}}" data-ref="{{ref}}"
data-params='[{"name":"{{name}}", "full":"{{url}}"}]'/>
{{/image}}
</div>

View file

@ -1,7 +1,3 @@
{{!
This template is linked with of mercury/front/templates/main/components/infobox-builder-item-image.hbs
Changing this template requires modifying the other in mercury repo.
}}
<figure class="pi-item pi-image">
<a href="{{url}}" class="image image-thumbnail{{#isVideo}} video video-thumbnail{{/isVideo}}"
title="{{alt}}">
@ -22,4 +18,4 @@
{{/isVideo}}
</a>
{{#caption}}<figcaption class="pi-item-spacing pi-caption">{{{caption}}}</figcaption>{{/caption}}
</figure>
</figure>

View file

@ -1,51 +0,0 @@
<div class="pi-image-collection gallery"
data-attrs="{{dataAttrs}}">
{{#images}}
<figure class="pi-item pi-image" data-ref="{{dataRef}}" data-file="{{fileName}}">
<a href="{{url}}">
<img class="article-media-placeholder lazyload"
src="data:image/svg+xml;charset=utf-8,%3Csvg xmlns%3D'http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg' viewBox%3D'0 0 {{width}} {{height}}'%2F%3E"
alt="{{title}}"
data-srcset="{{thumbnail}}, {{thumbnail2x}} 2x"
data-srcset=""
{{#width}} width="{{width}}"{{/width}}
{{#height}} height="{{height}}"{{/height}} />
<noscript>
<img src="{{url}}" alt="{{alt}}"{{#width}} width="{{width}}"{{/width}}{{#height}} height="{{height}}"{{/height}} />
</noscript>
{{#isVideo}}
<div class="video-icon-container">
<svg class="wds-player-icon-play-medium" viewBox="0 0 180 180">
<g fill="none" fill-rule="evenodd">
<g opacity=".9" transform="rotate(90 75 90)">
<g fill="#000" filter="url(#a)">
<rect id="b" width="150" height="150" rx="75"></rect>
</g>
<g fill="#FFF">
<rect id="b" width="150" height="150" rx="75"></rect>
</g>
</g>
<path fill="#00D6D6" fill-rule="nonzero"
d="M80.87 58.006l34.32 25.523c3.052 2.27 3.722 6.633 1.496 9.746a6.91 6.91 0 0 1-1.497 1.527l-34.32 25.523c-3.053 2.27-7.33 1.586-9.558-1.527A7.07 7.07 0 0 1 70 114.69V63.643c0-3.854 3.063-6.977 6.84-6.977 1.45 0 2.86.47 4.03 1.34z"></path>
</g>
</svg>
</div>
{{/isVideo}}
</a>
{{#caption}}<figcaption class="pi-hero-title-wrapper pi-item-spacing"><h3 class="pi-hero-caption">{{{caption}}}</h3></figcaption>{{/caption}}
<div class="image-collection-actions">
{{^isFirst}}
<button class="action-previous">
{{{menuControlIcon}}}
</button>
{{/isFirst}}
{{^isLast}}
<button class="action-next">
{{{menuControlIcon}}}
</button>
{{/isLast}}
</div>
</figure>
{{/images}}
</div>

View file

@ -1,6 +0,0 @@
<div class="pi-item pi-hero">
<img src="data:image/gif;base64,R0lGODlhAQABAIABAAAAAP///yH5BAEAAAEALAAAAAABAAEAQAICTAEAOw%3D%3D"
data-src="{{thumbnail}}" class="pi-image-thumbnail lazy media article-media" alt="{{alt}}"
data-image-key="{{name}}" data-image-name="{{name}}" data-ref="{{ref}}"
data-params='[{"name":"{{name}}", "full":"{{url}}"}]'/>
</div>

View file

@ -1,39 +0,0 @@
<div class="pi-item pi-image">
<figure class="article-media-thumbnail" data-attrs="{{dataAttrs}}" data-file="{{fileName}}">
<a href="{{url}}">
<img class="article-media-placeholder lazyload"
src="data:image/svg+xml;charset=utf-8,%3Csvg xmlns%3D'http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg' viewBox%3D'0 0 {{originalWidth}} {{originalHeight}}'%2F%3E"
data-src="{{thumbnail}}"
data-srcset="{{thumbnail}}, {{thumbnail2x}} 2x"
data-sizes="auto"
alt="{{title}}"
{{#originalWidth}} width="{{originalWidth}}"{{/originalWidth}}
{{#originalHeight}} height="{{originalHeight}}"{{/originalHeight}} />
<noscript>
<img src="{{url}}" alt="{{alt}}"{{#originalWidth}}
width="{{originalWidth}}"{{/originalWidth}}{{#originalHeight}} height="{{originalHeight}}"{{/originalHeight}} />
</noscript>
{{#caption}}
<figcaption>{{caption}}</figcaption>
{{/caption}}
{{#isVideo}}
<div class="video-icon-container">
<svg class="wds-player-icon-play-medium" viewBox="0 0 180 180">
<g fill="none" fill-rule="evenodd">
<g opacity=".9" transform="rotate(90 75 90)">
<g fill="#000" filter="url(#a)">
<rect id="b" width="150" height="150" rx="75"></rect>
</g>
<g fill="#FFF">
<rect id="b" width="150" height="150" rx="75"></rect>
</g>
</g>
<path fill="#00D6D6" fill-rule="nonzero"
d="M80.87 58.006l34.32 25.523c3.052 2.27 3.722 6.633 1.496 9.746a6.91 6.91 0 0 1-1.497 1.527l-34.32 25.523c-3.053 2.27-7.33 1.586-9.558-1.527A7.07 7.07 0 0 1 70 114.69V63.643c0-3.854 3.063-6.977 6.84-6.977 1.45 0 2.86.47 4.03 1.34z"></path>
</g>
</svg>
</div>
{{/isVideo}}
</a>
</figure>
</div>

View file

@ -1,6 +0,0 @@
<div class="pi-item pi-image">
<img src="data:image/gif;base64,R0lGODlhAQABAIABAAAAAP///yH5BAEAAAEALAAAAAABAAEAQAICTAEAOw%3D%3D"
data-src="{{thumbnail}}" class="pi-image-thumbnail lazy media article-media" alt="{{alt}}"
data-image-key="{{name}}" data-image-name="{{name}}" data-ref="{{ref}}"
data-params='[{"name":"{{name}}", "full":"{{url}}"}]'/>
</div>

View file

@ -1,5 +1 @@
{{!
This template is linked with of mercury/front/templates/main/components/infobox-builder-item-title.hbs
Changing this template requires modifying the other in mercury repo.
}}
<h2 class="pi-item pi-item-spacing pi-title"{{#inlineStyles}} style="{{inlineStyles}}"{{/inlineStyles}}>{{{value}}}</h2>
<h2 class="pi-item pi-item-spacing pi-title"{{#inlineStyles}} style="{{inlineStyles}}"{{/inlineStyles}}>{{{value}}}</h2>

View file

@ -1,5 +1 @@
{{!
This template is linked with of mercury/front/templates/main/components/infobox-builder-item-wrapper.hbs
Changing this template requires modifying the other in mercury repo.
}}
<aside class="portable-infobox pi-background{{#isMercury}} pi{{/isMercury}}{{#theme}} {{theme}}{{/theme}}{{#layout}} {{layout}}{{/layout}}">{{{content}}}</aside>
<aside class="portable-infobox pi-background{{#theme}} {{theme}}{{/theme}}{{#layout}} {{layout}}{{/layout}}">{{{content}}}</aside>

View file

@ -1,853 +0,0 @@
<?php
class PortableInfoboxMobileRenderServiceTest extends WikiaBaseTest {
protected function setUp() {
$this->setupFile = dirname( __FILE__ ) . '/../PortableInfobox.setup.php';
parent::setUp();
if ( !extension_loaded( 'mustache' ) ) {
$this->markTestSkipped( '"mustache" PHP extension needs to be loaded!' );
}
}
private function mockInfoboxImagesHelper( $input ) {
$extendImageData = isset( $input['extendImageData'] ) ? $input['extendImageData'] : null;
$mock = $this->getMockBuilder( 'Wikia\PortableInfobox\Helpers\PortableInfoboxImagesHelper' )
->setMethods( [ 'extendImageData', 'getFileWidth' ] )
->getMock();
$mock->expects( $this->any() )
->method( 'extendImageData' )
->will( $this->returnValue( $extendImageData ) );
$mock->expects( $this->any() )
->method( 'getFileWidth' )
->will( $this->returnValue( $extendImageData['width'] ) );
$this->mockClass( 'Wikia\PortableInfobox\Helpers\PortableInfoboxImagesHelper', $mock );
}
/**
* @param $html
* @return string
*/
private function normalizeHTML( $html ) {
if ( empty( $html ) ) {
return '';
}
$config = [
'indent' => true,
'output-xhtml' => false
];
$tidy = new tidy();
$tidy->parseString($html, $config);
$tidy->cleanRepair();
return preg_replace( '/>\s+/', '>', (string) $tidy );
}
/**
* @dataProvider renderInfoboxDataProvider
*/
public function testRenderInfobox( $input, $expectedOutput, $description, $mockParams ) {
$wrapper = new \Wikia\Util\GlobalStateWrapper( [ 'wgArticleAsJson' => $mockParams['isMercury'] ?? true ] );
$this->mockInfoboxImagesHelper( $mockParams );
$infoboxRenderService = new PortableInfoboxMobileRenderService();
$actualOutput = $wrapper->wrap( function () use ( $infoboxRenderService, $input ) {
return $infoboxRenderService->renderInfobox( $input, '', '', '', '' );
} );
$expectedHtml = $this->normalizeHTML( $expectedOutput );
$actualHtml = $this->normalizeHTML( $actualOutput );
$this->assertEquals( $expectedHtml, $actualHtml, $description );
}
public function renderInfoboxDataProvider() {
return [
[
'input' => [ ],
'output' => '',
'description' => 'Empty data should yield no infobox markup',
'mockParams' => [ ]
],
[
'input' => [
[
'type' => 'title',
'data' => [
'value' => 'Test Title'
]
]
],
'output' => '<aside class="portable-infobox pi-background pi">
<h2 class="pi-item pi-item-spacing pi-title">Test Title</h2>
</aside>',
'description' => 'Only title',
'mockParams' => [ ]
],
[
'input' => [
[
'type' => 'navigation',
'data' => [
'value' => 'navigation value',
]
]
],
'output' => '<aside class="portable-infobox pi-background pi">
<nav class="pi-navigation pi-item-spacing pi-secondary-background pi-secondary-font">navigation value</nav>
</aside>',
'description' => 'navigation only',
'mockParams' => [ ]
],
[
'input' => [
[
'type' => 'data',
'data' => [
'label' => 'test label',
'value' => 'test value'
]
]
],
'output' => '<aside class="portable-infobox pi-background pi">
<div class="pi-item pi-data pi-item-spacing pi-border-color">
<h3 class="pi-data-label pi-secondary-font">test label</h3>
<div class="pi-data-value pi-font">test value</div>
</div>
</aside>',
'description' => 'Only pair',
'mockParams' => [ ]
],
[
'input' => [
[
'type' => 'title',
'data' => [
'value' => 'Test Title'
]
],
[
'type' => 'image',
'data' => [
[
'alt' => 'image alt',
'url' => 'http://image.jpg',
'name' => 'image',
'key' => 'image',
'isVideo' => false
]
]
],
[
'type' => 'data',
'data' => [
'label' => 'test label',
'value' => 'test value'
]
]
],
'output' => '<aside class="portable-infobox pi-background pi">
<div class="pi-item pi-hero">
<hgroup class="pi-hero-title-wrapper pi-item-spacing">
<h2 class="pi-hero-title">Test Title</h2>
</hgroup>
<figure data-attrs="" data-file="">
<a href="http://image.jpg">
<img class="article-media-placeholder lazyload" src="data:image/svg+xml;charset=utf-8,%3Csvg xmlns%3D\'http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg\' viewBox%3D\'0 0 400 200\'%2F%3E" data-src="http://image.jpg" data-srcset="http://image.jpg, http://image2x.jpg 2x" data-sizes="auto" alt="" width="400" height="200"/><noscript>
<img src="http://image.jpg" alt="image alt" width="400" height="200"/>
</noscript>
</a>
</figure>
</div>
<div class="pi-item pi-data pi-item-spacing pi-border-color">
<h3 class="pi-data-label pi-secondary-font">test label</h3>
<div class="pi-data-value pi-font">test value</div>
</div>
</aside>',
'description' => 'Simple infobox with title, image and key-value pair',
'mockParams' => [
'extendImageData' => [
'alt' => 'image alt',
'url' => 'http://image.jpg',
'name' => 'test1',
'key' => 'test1',
'ref' => 1,
'width' => '400',
'height' => '200',
'originalWidth' => '400',
'originalHeight' => '200',
'thumbnail' => 'http://image.jpg',
'thumbnail2x' => 'http://image2x.jpg',
'media-type' => 'image',
'isVideo' => false
]
]
],
[
'input' => [
[
'type' => 'title',
'data' => [
'value' => 'Test Title'
]
],
[
'type' => 'image',
'data' => [ ]
],
[
'type' => 'data',
'data' => [
'label' => 'test label',
'value' => 'test value'
]
]
],
'output' => '<aside class="portable-infobox pi-background pi">
<h2 class="pi-item pi-item-spacing pi-title">Test Title</h2>
<div class="pi-item pi-data pi-item-spacing pi-border-color">
<h3 class="pi-data-label pi-secondary-font">test label</h3>
<div class="pi-data-value pi-font">test value</div>
</div>
</aside>',
'description' => 'Simple infobox with title, INVALID image and key-value pair',
'mockParams' => [ ]
],
[
'input' => [
[
'type' => 'title',
'data' => [
'value' => 'Test Title'
]
],
[
'type' => 'data',
'data' => [
'label' => 'test label',
'value' => 'test value'
]
]
],
'output' => '<aside class="portable-infobox pi-background pi">
<h2 class="pi-item pi-item-spacing pi-title">Test Title</h2>
<div class="pi-item pi-data pi-item-spacing pi-border-color">
<h3 class="pi-data-label pi-secondary-font">test label</h3>
<div class="pi-data-value pi-font">test value</div>
</div>
</aside>',
'description' => 'Simple infobox with title, empty image and key-value pair',
'mockParams' => [ ]
],
[
'input' => [
[
'type' => 'title',
'data' => [
'value' => 'Test Title'
]
],
[
'type' => 'group',
'data' => [
'value' => [
[
'type' => 'header',
'data' => [
'value' => 'Test Header'
]
],
[
'type' => 'data',
'data' => [
'label' => 'test label',
'value' => 'test value'
]
],
[
'type' => 'data',
'data' => [
'label' => 'test label',
'value' => 'test value'
]
]
],
'layout' => 'default',
'collapse' => null,
'row-items' => null
]
]
],
'output' => '<aside class="portable-infobox pi-background pi">
<h2 class="pi-item pi-item-spacing pi-title">Test Title</h2>
<section class="pi-item pi-group pi-border-color">
<h2 class="pi-item pi-header pi-secondary-font pi-item-spacing pi-secondary-background">Test Header</h2>
<div class="pi-item pi-data pi-item-spacing pi-border-color">
<h3 class="pi-data-label pi-secondary-font">test label</h3>
<div class="pi-data-value pi-font">test value</div>
</div>
<div class="pi-item pi-data pi-item-spacing pi-border-color">
<h3 class="pi-data-label pi-secondary-font">test label</h3>
<div class="pi-data-value pi-font">test value</div>
</div>
</section>
</aside>',
'description' => 'Infobox with title, group with header and two key-value pairs',
'mockParams' => [ ]
],
[
'input' => [
[
'type' => 'group',
'data' => [
'value' => [
[
'type' => 'header',
'data' => [
'value' => 'Test header'
]
],
[
'type' => 'data',
'data' => [
'label' => 'test label',
'value' => 'test value'
]
],
[
'type' => 'data',
'data' => [
'label' => 'test label',
'value' => 'test value'
]
]
],
'layout' => 'horizontal',
'collapse' => null,
'row-items' => null
]
]
],
'output' => '<aside class="portable-infobox pi-background pi">
<section class="pi-item pi-group pi-border-color">
<table class="pi-horizontal-group">
<caption
class="pi-header pi-secondary-font pi-secondary-background pi-item-spacing">Test header</caption>
<thead>
<tr>
<th
class="pi-horizontal-group-item pi-data-label pi-secondary-font pi-border-color pi-item-spacing">test label</th>
<th
class="pi-horizontal-group-item pi-data-label pi-secondary-font pi-border-color pi-item-spacing">test label</th>
</tr>
</thead>
<tbody>
<tr>
<td
class="pi-horizontal-group-item pi-data-value pi-font pi-border-color pi-item-spacing">test value</td>
<td
class="pi-horizontal-group-item pi-data-value pi-font pi-border-color pi-item-spacing">test value</td>
</tr>
</tbody>
</table>
</section>
</aside>',
'description' => 'Infobox with horizontal group',
'mockParams' => [
'createHorizontalGroupData' => [
'header' => 'Test header',
'labels' => [ 'test label', 'test label' ],
'values' => [ 'test value', 'test value' ],
'renderLabels' => true
]
]
],
[
'input' => [
[
'type' => 'group',
'data' => [
'value' => [
[
'type' => 'data',
'data' => [
'label' => '',
'value' => 'test value'
]
],
[
'type' => 'data',
'data' => [
'label' => '',
'value' => 'test value'
]
]
],
'layout' => 'horizontal',
'collapse' => null,
'row-items' => null
]
]
],
'output' => '<aside class="portable-infobox pi-background pi">
<section class="pi-item pi-group pi-border-color">
<table class="pi-horizontal-group pi-horizontal-group-no-labels">
<tbody>
<tr>
<td
class="pi-horizontal-group-item pi-data-value pi-font pi-border-color pi-item-spacing">test value</td>
<td
class="pi-horizontal-group-item pi-data-value pi-font pi-border-color pi-item-spacing">test value</td>
</tr>
</tbody>
</table>
</section>
</aside>',
'description' => 'Infobox with horizontal group without header and labels',
'mockParams' => [
'createHorizontalGroupData' => [
'labels' => [ '', '' ],
'values' => [ 'test value', 'test value' ],
'renderLabels' => false
]
]
],
[
'input' => [
[
'type' => 'navigation',
'data' => [
'value' => '<p>Links</p>'
]
]
],
'output' => '<aside class="portable-infobox pi-background pi">
<nav class="pi-navigation pi-item-spacing pi-secondary-background pi-secondary-font">
<p>Links</p>
</nav>
</aside>',
'description' => 'Infobox with navigation',
'mockParams' => [ ]
],
[
'input' => [
[
'type' => 'image',
'data' => [
[
'alt' => 'image alt',
'url' => 'http://image.jpg',
'ref' => 1,
'name' => 'test1',
'key' => 'test1',
'isVideo' => false
]
]
]
],
'output' => '<aside class="portable-infobox pi-background">
<div class="pi-item pi-hero">
<img
src="data:image/gif;base64,R0lGODlhAQABAIABAAAAAP///yH5BAEAAAEALAAAAAABAAEAQAICTAEAOw%3D%3D" data-src="http://image.jpg" class="pi-image-thumbnail lazy media article-media" alt="image alt" data-image-key="test1" data-image-name="test1" data-ref="1" data-params=\'[{"name":"test1", "full":"http://image.jpg"}]\' />
</div>
</aside>',
'description' => 'WikiaMobile: Only image. Image is not small- should render hero.',
'mockParams' => [
'isMercury' => false,
'extendImageData' => [
'alt' => 'image alt',
'url' => 'http://image.jpg',
'name' => 'test1',
'key' => 'test1',
'ref' => 1,
'width' => '400',
'height' => '200',
'originalWidth' => '400',
'originalHeight' => '200',
'thumbnail' => 'http://image.jpg',
'thumbnail2x' => 'http://image2x.jpg',
'media-type' => 'image',
'isVideo' => false
]
]
],
[
'input' => [
[
'type' => 'title',
'data' => [
'value' => 'Test <img /><a href="example.com">Title</a>'
]
],
[
'type' => 'image',
'data' => [
[
'url' => 'http://image.jpg',
'name' => 'test1',
'key' => 'test1',
'ref' => 44,
'isVideo' => false
]
]
]
],
'output' => '<aside class="portable-infobox pi-background">
<div class="pi-item pi-hero">
<hgroup class="pi-hero-title-wrapper pi-item-spacing">
<h2 class="pi-hero-title">Test <a href="example.com">Title</a></h2>
</hgroup>
<img
src="data:image/gif;base64,R0lGODlhAQABAIABAAAAAP///yH5BAEAAAEALAAAAAABAAEAQAICTAEAOw%3D%3D" data-src="thumbnail.jpg" class="pi-image-thumbnail lazy media article-media" alt="" data-image-key="test1" data-image-name="test1" data-ref="44" data-params=\'[{"name":"test1", "full":"http://image.jpg"}]\'/>
</div>
</aside>',
'description' => 'WikiaMobile: Infobox with full hero module with title with HTML tags',
'mockParams' => [
'isMercury' => false,
'extendImageData' => [
'url' => 'http://image.jpg',
'name' => 'test1',
'key' => 'test1',
'ref' => 44,
'width' => '400',
'height' => '200',
'originalWidth' => '400',
'originalHeight' => '200',
'thumbnail' => 'thumbnail.jpg',
'thumbnail2x' => 'thumbnail2x.jpg',
'isVideo' => false,
'media-type' => 'image'
]
]
],
[
'input' => [
[
'type' => 'image',
'data' => [
[
'alt' => 'image alt',
'url' => 'http://image.jpg',
'ref' => 1,
'name' => 'test1',
'key' => 'test1',
'isVideo' => false
]
]
]
],
'output' => '<aside class="portable-infobox pi-background pi">
<div class="pi-item pi-hero">
<figure data-attrs="" data-file="">
<a href="http://image.jpg">
<img class="article-media-placeholder lazyload" src="data:image/svg+xml;charset=utf-8,%3Csvg xmlns%3D\'http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg\' viewBox%3D\'0 0 400 200\'%2F%3E" data-src="http://image.jpg" data-srcset="http://image.jpg, http://image2x.jpg 2x" data-sizes="auto" alt="" width="400" height="200"/><noscript>
<img src="http://image.jpg" alt="image alt" width="400" height="200"/>
</noscript>
</a>
</figure>
</div>
</aside>',
'description' => 'Mercury: Only image. Image is not small- should render hero.',
'mockParams' => [
'extendImageData' => [
'alt' => 'image alt',
'url' => 'http://image.jpg',
'name' => 'test1',
'key' => 'test1',
'ref' => 1,
'width' => '400',
'height' => '200',
'originalWidth' => '400',
'originalHeight' => '200',
'thumbnail' => 'http://image.jpg',
'thumbnail2x' => 'http://image2x.jpg',
'media-type' => 'image',
'isVideo' => false,
'mercuryComponentAttrs' => json_encode( [
'itemContext' => 'portable-infobox',
'ref' => 1
] )
]
]
],
[
'input' => [
[
'type' => 'title',
'data' => [
'value' => 'Test <img /><a href="example.com">Title</a>'
]
],
[
'type' => 'image',
'data' => [
[
'url' => 'http://image.jpg',
'name' => 'test1',
'key' => 'test1',
'ref' => 44,
'isVideo' => false
]
]
]
],
'output' => '<aside class="portable-infobox pi-background pi">
<div class="pi-item pi-hero">
<hgroup class="pi-hero-title-wrapper pi-item-spacing">
<h2 class="pi-hero-title">Test <a href="example.com">Title</a></h2>
</hgroup>
<figure data-attrs="" data-file="">
<a href="http://image.jpg">
<img class="article-media-placeholder lazyload" src="data:image/svg+xml;charset=utf-8,%3Csvg xmlns%3D\'http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg\' viewBox%3D\'0 0 400 200\'%2F%3E" data-src="thumbnail.jpg" data-srcset="thumbnail.jpg, thumbnail2x.jpg 2x" data-sizes="auto" alt="" width="400" height="200"/><noscript>
<img src="http://image.jpg" alt="" width="400" height="200"/>
</noscript>
</a>
</figure>
</div>
</aside>',
'description' => 'Mercury: Infobox with full hero module with title with HTML tags',
'mockParams' => [
'extendImageData' => [
'url' => 'http://image.jpg',
'name' => 'test1',
'key' => 'test1',
'ref' => 44,
'width' => '400',
'height' => '200',
'originalWidth' => '400',
'originalHeight' => '200',
'thumbnail' => 'thumbnail.jpg',
'thumbnail2x' => 'thumbnail2x.jpg',
'isVideo' => false,
'media-type' => 'image',
'mercuryComponentAttrs' => json_encode( [
'itemContext' => 'portable-infobox',
'ref' => 44
] )
]
]
],
[
'input' => [
[
'type' => 'data',
'data' => [
'label' => 'Test 1',
'value' => 'test value 1'
]
],
[
'type' => 'title',
'data' => [
'value' => 'Test <img /><a href="example.com">Title</a>'
]
],
[
'type' => 'group',
'data' => [
'value' => [
[
'type' => 'header',
'data' => [
'value' => 'Test Header'
]
],
[
'type' => 'data',
'data' => [
'label' => 'Test 2',
'value' => 'test value 2'
]
],
[
'type' => 'image',
'data' => [
[
'url' => 'http://image.jpg',
'name' => 'test1',
'key' => 'test1',
'ref' => 44,
'isVideo' => false
]
]
],
[
'type' => 'data',
'data' => [
'label' => 'Test 3',
'value' => 'test value 3'
]
]
],
'layout' => null,
'collapse' => null,
'row-items' => null
]
]
],
'output' => '<aside class="portable-infobox pi-background pi">
<div class="pi-item pi-hero">
<hgroup class="pi-hero-title-wrapper pi-item-spacing">
<h2 class="pi-hero-title">Test <a href="example.com">Title</a></h2>
</hgroup>
<figure data-attrs="" data-file="">
<a href="http://image.jpg">
<img class="article-media-placeholder lazyload" src="data:image/svg+xml;charset=utf-8,%3Csvg xmlns%3D\'http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg\' viewBox%3D\'0 0 400 200\'%2F%3E" data-src="thumbnail.jpg" data-srcset="thumbnail.jpg, thumbnail2x.jpg 2x" data-sizes="auto" alt="" width="400" height="200"/><noscript>
<img src="http://image.jpg" alt="" width="400" height="200"/>
</noscript>
</a>
</figure>
</div>
<div class="pi-item pi-data pi-item-spacing pi-border-color">
<h3 class="pi-data-label pi-secondary-font">Test 1</h3>
<div class="pi-data-value pi-font">test value 1</div>
</div>
<section class="pi-item pi-group pi-border-color">
<h2 class="pi-item pi-header pi-secondary-font pi-item-spacing pi-secondary-background">Test Header</h2>
<div class="pi-item pi-data pi-item-spacing pi-border-color">
<h3 class="pi-data-label pi-secondary-font">Test 2</h3>
<div class="pi-data-value pi-font">test value 2</div>
</div>
<div class="pi-item pi-data pi-item-spacing pi-border-color">
<h3 class="pi-data-label pi-secondary-font">Test 3</h3>
<div class="pi-data-value pi-font">test value 3</div>
</div>
</section>
</aside>',
'description' => 'Mercury: Infobox with valid hero data partially nested in group',
'mockParams' => [
'extendImageData' => [
'url' => 'http://image.jpg',
'name' => 'test1',
'key' => 'test1',
'ref' => 44,
'width' => '400',
'height' => '200',
'originalWidth' => '400',
'originalHeight' => '200',
'thumbnail' => 'thumbnail.jpg',
'thumbnail2x' => 'thumbnail2x.jpg',
'isVideo' => false,
'media-type' => 'image',
'mercuryComponentAttrs' => json_encode( [
'itemContext' => 'portable-infobox',
'ref' => 44
] )
]
]
],
[
'input' => [
[
'type' => 'data',
'data' => [
'label' => 'Test 1',
'value' => 'test value 1'
]
],
[
'type' => 'title',
'data' => [
'value' => 'Test <img /><a href="example.com">Title</a>'
]
],
[
'type' => 'group',
'data' => [
'value' => [
[
'type' => 'header',
'data' => [
'value' => 'Test Header'
]
],
[
'type' => 'data',
'data' => [
'label' => 'Test 2',
'value' => 'test value 2'
]
],
[
'type' => 'image',
'data' => [
[
'url' => 'http://image.jpg',
'name' => 'test1',
'key' => 'test1',
'ref' => 44,
'isVideo' => false
]
]
],
[
'type' => 'data',
'data' => [
'label' => 'Test 3',
'value' => 'test value 3'
]
]
],
'layout' => null,
'collapse' => null,
'row-items' => null
]
]
],
'output' => '<aside class="portable-infobox pi-background pi">
<div class="pi-item pi-hero">
<hgroup class="pi-hero-title-wrapper pi-item-spacing">
<h2 class="pi-hero-title">Test <a href="example.com">Title</a></h2>
</hgroup>
<figure data-attrs="" data-file="">
<a href="http://image.jpg">
<img class="article-media-placeholder lazyload" src="data:image/svg+xml;charset=utf-8,%3Csvg xmlns%3D\'http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg\' viewBox%3D\'0 0 400 200\'%2F%3E" data-src="thumbnail.jpg" data-srcset="thumbnail.jpg, thumbnail2x.jpg 2x" data-sizes="auto" alt="" width="400" height="200"/><noscript>
<img src="http://image.jpg" alt="" width="400" height="200"/>
</noscript>
</a>
</figure>
</div>
<div class="pi-item pi-data pi-item-spacing pi-border-color">
<h3 class="pi-data-label pi-secondary-font">Test 1</h3>
<div class="pi-data-value pi-font">test value 1</div>
</div>
<section class="pi-item pi-group pi-border-color">
<h2 class="pi-item pi-header pi-secondary-font pi-item-spacing pi-secondary-background">Test Header</h2>
<div class="pi-item pi-data pi-item-spacing pi-border-color">
<h3 class="pi-data-label pi-secondary-font">Test 2</h3>
<div class="pi-data-value pi-font">test value 2</div>
</div>
<div class="pi-item pi-data pi-item-spacing pi-border-color">
<h3 class="pi-data-label pi-secondary-font">Test 3</h3>
<div class="pi-data-value pi-font">test value 3</div>
</div>
</section>
</aside>',
'description' => 'Mercury: Infobox with invalid hero data partially nested in group',
'mockParams' => [
'extendImageData' => [
'url' => 'http://image.jpg',
'name' => 'test1',
'key' => 'test1',
'ref' => 44,
'width' => '200',
'height' => '200',
'originalWidth' => '400',
'originalHeight' => '200',
'thumbnail' => 'thumbnail.jpg',
'thumbnail2x' => 'thumbnail2x.jpg',
'isVideo' => false,
'media-type' => 'image',
'mercuryComponentAttrs' => json_encode( [
'itemContext' => 'portable-infobox',
'ref' => 44
] )
]
]
]
];
}
}

View file

@ -1,143 +0,0 @@
<?php
class NodeHeroImageSanitizerTest extends WikiaBaseTest {
/** @var NodeHeroImageSanitizer $sanitizer */
private $sanitizer;
protected function setUp() {
$this->setupFile = dirname( __FILE__ ) . '/../../PortableInfobox.setup.php';
$this->sanitizer = SanitizerBuilder::createFromType('hero-mobile');
parent::setUp();
}
/**
* @param $data
* @param $expected
* @dataProvider sanitizeDataProvider
*/
public function testSanitize( $data, $expected ) {
$this->assertEquals(
$expected,
$this->sanitizer->sanitize( $data )
);
}
public function sanitizeDataProvider() {
return [
[
[ 'title' => [ 'value' => 'Test Title' ] ],
[ 'title' => [ 'value' => 'Test Title' ] ]
],
[
[ 'title' => [ 'value' => 'Real world <a href="http://vignette-poz.wikia-dev.com/mediawiki116/images/b/b6/DBGT_Logo.svg/revision/latest?cb=20150601155347" class="image image-thumbnail" ><img src="http://vignette-poz.wikia-dev.com/mediawiki116/images/b/b6/DBGT_Logo.svg/revision/latest/scale-to-width-down/30?cb=20150601155347" alt="DBGT Logo" class="" data-image-key="DBGT_Logo.svg" data-image-name="DBGT Logo.svg" width="30" height="18" ></a>title example' ] ] ,
[ 'title' => [ 'value' => 'Real world title example' ] ]
],
[
[ 'title' => [ 'value' => 'Test <a>Title with</a> <span><small>small</small></span> tag, span tag and <img src="sfefes"/>tag' ] ],
[ 'title' => [ 'value' => 'Test <a>Title with</a> small tag, span tag and tag' ] ]
],
[
[ 'title' => [ 'value' => '<a href="http://vignette-poz.wikia-dev.com//images/9/95/All_Stats_%2B2.png/revision/latest?cb=20151222111955" class="image image-thumbnail"><img src="abc" alt="All Stats +2" class="thumbimage" /></a>' ] ],
[ 'title' => [ 'value' => '' ] ],
],
[
[ 'title' => [ 'value' => '<figure class="article-thumb tright show-info-icon" style="width: 335px"> <a href="http://mediawiki119.marzjan.wikia-dev.com/wiki/File:AMERICA%27S_TEST_KITCHEN_SEASON_9" class="video video-thumbnail image lightbox medium " itemprop=\'video\' itemscope itemtype="http://schema.org/VideoObject" ><img src="http://vignette-poz.wikia-dev.com//images/6/6e/AMERICA%27S_TEST_KITCHEN_SEASON_9/revision/latest/scale-to-width-down/335?cb=20130904003328" alt="AMERICA&#039;S TEST KITCHEN SEASON 9" class="thumbimage " data-video-key="AMERICA&#039;S_TEST_KITCHEN_SEASON_9" data-video-name="AMERICA&#039;S TEST KITCHEN SEASON 9" width="335" height="187" itemprop="thumbnail" ></span><meta itemprop="duration" content="PT01M00S"></a> <figcaption> <a href="/wiki/File:AMERICA%27S_TEST_KITCHEN_SEASON_9" class="sprite info-icon"></a> <p class="title">AMERICA&#039;S TEST KITCHEN SEASON 9</p> </figcaption> </figure>' ] ],
[ 'title' => [ 'value' => 'AMERICA&#039;S TEST KITCHEN SEASON 9' ] ]
],
[
[ 'title' => [ 'value' => '<sup id="cite_ref-0" class="reference"><a href="#cite_note-0">[1]</a></sup>' ] ],
[ 'title' => [ 'value' => '<sup id="cite_ref-0" class="reference"><a href="#cite_note-0">[1]</a></sup>' ] ]
],
[
[ 'title' => [ 'value' => '<script>JSSnippetsStack.push({dependencies:[{"url":"http://i3.marzjan.wikia-dev.com/__am/1451462348/group/-/wikia_photo_gallery_js","type":"js"},{"url":"http://i2.marzjan.wikia-dev.com/__am/1451462348/sass/background-dynamic%3D1%26background-image%3D%26background-image-height%3D1185%26background-image-width%3D1600%26color-body%3D%2523bacdd8%26color-body-middle%3D%2523bacdd8%26color-buttons%3D%2523006cb0%26color-header%3D%25233a5766%26color-links%3D%2523006cb0%26color-page%3D%2523ffffff%26oasisTypography%3D1%26page-opacity%3D100%26widthType%3D0/extensions/wikia/WikiaPhotoGallery/css/gallery.scss","type":"css"}],callback:function(json){WikiaPhotoGalleryView.init(json)},id:"WikiaPhotoGalleryView.init"})</script>' ] ],
[ 'title' => [ 'value' => '' ] ]
],
[
[ 'title' => [ 'value' => '<ul><li>1
</li><li>2
</li><li>3
</li></ul>' ] ],
[ 'title' => [ 'value' => '1 2 3' ] ]
],
[
[ 'title' => [ 'value' => '<ol><li>1
</li><li>2
<ol><li>2.1
</li></ol>
</li></ol>' ] ],
[ 'title' => [ 'value' => '1 2 2.1' ] ]
],
[
[ 'title' => [ 'value' => 'Próxima' ] ],
[ 'title' => [ 'value' => 'Próxima' ] ]
],
[
[ 'title' => [ 'value' => 'Música de' ] ],
[ 'title' => [ 'value' => 'Música de' ] ]
],
[
[ 'title' => [ 'value' => 'A <b>Kuruma</b> in <i><a href="/wiki/Grand_Theft_Auto_Online" title="Grand Theft Auto Online">Grand Theft Auto Online</a></i>.' ] ],
[ 'title' => [ 'value' => 'A Kuruma in <a href="/wiki/Grand_Theft_Auto_Online" title="Grand Theft Auto Online">Grand Theft Auto Online</a>.' ] ]
],
[
[ 'title' => [ 'value' => '<a href="/wiki/User:Idradm" class="new" title="User:Idradm (page does not exist)">Idradm</a> (<a href="/wiki/User_talk:Idradm" title="User talk:Idradm (page does not exist)">talk</a>) 15:34, January 4, 2016 (UTC)' ] ],
[ 'title' => [ 'value' => '<a href="/wiki/User:Idradm" class="new" title="User:Idradm (page does not exist)">Idradm</a> (<a href="/wiki/User_talk:Idradm" title="User talk:Idradm (page does not exist)">talk</a>) 15:34, January 4, 2016 (UTC)' ] ]
],
[
[ 'image' => [ 'caption' => 'Test Title' ] ],
[ 'image' => [ 'caption' => 'Test Title' ] ]
],
[
[ 'image' => [ 'caption' => 'Real world <a href="http://vignette-poz.wikia-dev.com/mediawiki116/images/b/b6/DBGT_Logo.svg/revision/latest?cb=20150601155347" class="image image-thumbnail" ><img src="http://vignette-poz.wikia-dev.com/mediawiki116/images/b/b6/DBGT_Logo.svg/revision/latest/scale-to-width-down/30?cb=20150601155347" alt="DBGT Logo" class="" data-image-key="DBGT_Logo.svg" data-image-name="DBGT Logo.svg" width="30" height="18" ></a>title example' ] ] ,
[ 'image' => [ 'caption' => 'Real world title example' ] ]
],
[
[ 'image' => [ 'caption' => 'Test <a>Title with</a> <span><small>small</small></span> tag, span tag and <img src="sfefes"/>tag' ] ],
[ 'image' => [ 'caption' => 'Test <a>Title with</a> small tag, span tag and tag' ] ]
],
[
[ 'image' => [ 'caption' => '<a href="http://vignette-poz.wikia-dev.com//images/9/95/All_Stats_%2B2.png/revision/latest?cb=20151222111955" class="image image-thumbnail"><img src="abc" alt="All Stats +2" class="thumbimage" /></a>' ] ],
[ 'image' => [ 'caption' => '' ] ],
],
[
[ 'image' => [ 'caption' => '<figure class="article-thumb tright show-info-icon" style="width: 335px"> <a href="http://mediawiki119.marzjan.wikia-dev.com/wiki/File:AMERICA%27S_TEST_KITCHEN_SEASON_9" class="video video-thumbnail image lightbox medium " itemprop=\'video\' itemscope itemtype="http://schema.org/VideoObject" ><img src="http://vignette-poz.wikia-dev.com//images/6/6e/AMERICA%27S_TEST_KITCHEN_SEASON_9/revision/latest/scale-to-width-down/335?cb=20130904003328" alt="AMERICA&#039;S TEST KITCHEN SEASON 9" class="thumbimage " data-video-key="AMERICA&#039;S_TEST_KITCHEN_SEASON_9" data-video-name="AMERICA&#039;S TEST KITCHEN SEASON 9" width="335" height="187" itemprop="thumbnail" ></span><meta itemprop="duration" content="PT01M00S"></a> <figcaption> <a href="/wiki/File:AMERICA%27S_TEST_KITCHEN_SEASON_9" class="sprite info-icon"></a> <p class="title">AMERICA&#039;S TEST KITCHEN SEASON 9</p> </figcaption> </figure>' ] ],
[ 'image' => [ 'caption' => 'AMERICA&#039;S TEST KITCHEN SEASON 9' ] ]
],
[
[ 'image' => [ 'caption' => '<sup id="cite_ref-0" class="reference"><a href="#cite_note-0">[1]</a></sup>' ] ],
[ 'image' => [ 'caption' => '<sup id="cite_ref-0" class="reference"><a href="#cite_note-0">[1]</a></sup>' ] ]
],
[
[ 'image' => [ 'caption' => '<script>JSSnippetsStack.push({dependencies:[{"url":"http://i3.marzjan.wikia-dev.com/__am/1451462348/group/-/wikia_photo_gallery_js","type":"js"},{"url":"http://i2.marzjan.wikia-dev.com/__am/1451462348/sass/background-dynamic%3D1%26background-image%3D%26background-image-height%3D1185%26background-image-width%3D1600%26color-body%3D%2523bacdd8%26color-body-middle%3D%2523bacdd8%26color-buttons%3D%2523006cb0%26color-header%3D%25233a5766%26color-links%3D%2523006cb0%26color-page%3D%2523ffffff%26oasisTypography%3D1%26page-opacity%3D100%26widthType%3D0/extensions/wikia/WikiaPhotoGallery/css/gallery.scss","type":"css"}],callback:function(json){WikiaPhotoGalleryView.init(json)},id:"WikiaPhotoGalleryView.init"})</script>' ] ],
[ 'image' => [ 'caption' => '' ] ]
],
[
[ 'image' => [ 'caption' => '<ul><li>1</li><li>2</li><li>3</li></ul>' ] ],
[ 'image' => [ 'caption' => '1 2 3' ] ]
],
[
[ 'image' => [ 'caption' => '<ol><li>1</li><li>2<ol><li>2.1</li></ol></li></ol>' ] ],
[ 'image' => [ 'caption' => '1 2 2.1' ] ]
],
[
[ 'image' => [ 'caption' => 'Próxima' ] ],
[ 'image' => [ 'caption' => 'Próxima' ] ]
],
[
[ 'image' => [ 'caption' => 'Música de' ] ],
[ 'image' => [ 'caption' => 'Música de' ] ]
],
[
[ 'image' => [ 'caption' => 'A <b>Kuruma</b> in <i><a href="/wiki/Grand_Theft_Auto_Online" title="Grand Theft Auto Online">Grand Theft Auto Online</a></i>.' ] ],
[ 'image' => [ 'caption' => 'A Kuruma in <a href="/wiki/Grand_Theft_Auto_Online" title="Grand Theft Auto Online">Grand Theft Auto Online</a>.' ] ]
],
[
[ 'image' => [ 'caption' => '<a href="/wiki/User:Idradm" class="new" title="User:Idradm (page does not exist)">Idradm</a> (<a href="/wiki/User_talk:Idradm" title="User talk:Idradm (page does not exist)">talk</a>) 15:34, January 4, 2016 (UTC)' ] ],
[ 'image' => [ 'caption' => '<a href="/wiki/User:Idradm" class="new" title="User:Idradm (page does not exist)">Idradm</a> (<a href="/wiki/User_talk:Idradm" title="User talk:Idradm (page does not exist)">talk</a>) 15:34, January 4, 2016 (UTC)' ] ]
]
];
}
}