Add audio support; NodeImage -> NodeMedia (#11)

This commit is contained in:
Luqgreg 2018-08-13 12:15:22 +02:00
commit 626710caf9
18 changed files with 550 additions and 601 deletions

View file

@ -6,7 +6,7 @@
],
"url": "https://github.com/Luqgreg/mediawiki-PortableInfobox",
"descriptionmsg": "portable-infobox-desc",
"version": "0.2.1",
"version": "0.2.1-audio_support",
"type": "parserhook",
"license-name": "GPL-3.0-or-later",
"config": {
@ -51,13 +51,16 @@
"PortableInfobox\\Parser\\MediaWikiParserService": "includes/services/Parser/MediaWikiParserService.php",
"PortableInfobox\\Parser\\Nodes\\NodeFactory": "includes/services/Parser/Nodes/NodeFactory.class.php",
"PortableInfobox\\Parser\\Nodes\\Node": "includes/services/Parser/Nodes/Node.php",
"PortableInfobox\\Parser\\Nodes\\NodeNavigation": "includes/services/Parser/Nodes/NodeNavigation.php",
"PortableInfobox\\Parser\\Nodes\\NodeAudio": "includes/services/Parser/Nodes/NodeAudio.php",
"PortableInfobox\\Parser\\Nodes\\NodeData": "includes/services/Parser/Nodes/NodeData.php",
"PortableInfobox\\Parser\\Nodes\\NodeInfobox": "includes/services/Parser/Nodes/NodeInfobox.php",
"PortableInfobox\\Parser\\Nodes\\NodeGroup": "includes/services/Parser/Nodes/NodeGroup.php",
"PortableInfobox\\Parser\\Nodes\\NodeHeader": "includes/services/Parser/Nodes/NodeHeader.php",
"PortableInfobox\\Parser\\Nodes\\NodeImage": "includes/services/Parser/Nodes/NodeImage.php",
"PortableInfobox\\Parser\\Nodes\\NodeInfobox": "includes/services/Parser/Nodes/NodeInfobox.php",
"PortableInfobox\\Parser\\Nodes\\NodeData": "includes/services/Parser/Nodes/NodeData.php",
"PortableInfobox\\Parser\\Nodes\\NodeMedia": "includes/services/Parser/Nodes/NodeMedia.php",
"PortableInfobox\\Parser\\Nodes\\NodeNavigation": "includes/services/Parser/Nodes/NodeNavigation.php",
"PortableInfobox\\Parser\\Nodes\\NodeTitle": "includes/services/Parser/Nodes/NodeTitle.php",
"PortableInfobox\\Parser\\Nodes\\NodeVideo": "includes/services/Parser/Nodes/NodeVideo.php",
"PortableInfobox\\Parser\\Nodes\\NodeUnimplemented": "includes/services/Parser/Nodes/NodeUnimplemented.php",
"PortableInfobox\\Helpers\\FileNamespaceSanitizeHelper": "includes/services/Helpers/FileNamespaceSanitizeHelper.php",
"PortableInfobox\\Helpers\\HtmlHelper": "includes/services/Helpers/HtmlHelper.class.php",

View file

@ -21,18 +21,20 @@ class PortableInfoboxImagesHelper {
$title = $data['name'];
$file = $this->getFileFromTitle( $title );
if (
!$file || !$file->exists() ||
!in_array( $file->getMediaType(), [ MEDIATYPE_BITMAP, MEDIATYPE_DRAWING, MEDIATYPE_VIDEO ] )
) {
if ( !$file || !$file->exists() ) {
return false;
}
// we don't need failing thumbnail creation for videos
if( $file->getMediaType() == MEDIATYPE_VIDEO ) {
return array_merge( $data, [
'ref' => ++self::$count
] );
$mediatype = $file->getMediaType();
$data['isImage'] = in_array( $mediatype, [ MEDIATYPE_BITMAP, MEDIATYPE_DRAWING ] );
$data['isVideo'] = $mediatype === MEDIATYPE_VIDEO;
$data['isAudio'] = $mediatype === MEDIATYPE_AUDIO;
$data['ref'] = ++self::$count;
// we don't need failing thumbnail creation for videos and audio files
if( !$data['isImage'] ) {
return $data;
}
// get dimensions
@ -65,7 +67,6 @@ class PortableInfoboxImagesHelper {
}
return array_merge( $data, [
'ref' => ++self::$count,
'height' => intval( $imgTagDimensions['height'] ),
'width' => intval( $imgTagDimensions['width'] ),
'thumbnail' => $thumbnail->getUrl(),

View file

@ -13,13 +13,16 @@ class PortableInfoboxTemplateEngine {
'wrapper' => 'PortableInfoboxWrapper.hbs',
'title' => 'PortableInfoboxItemTitle.hbs',
'header' => 'PortableInfoboxItemHeader.hbs',
'image' => 'PortableInfoboxItemImage.hbs',
'media' => 'PortableInfoboxItemMedia.hbs',
'audio' => 'PortableInfoboxItemMedia.hbs',
'image' => 'PortableInfoboxItemMedia.hbs',
'video' => 'PortableInfoboxItemMedia.hbs',
'data' => 'PortableInfoboxItemData.hbs',
'group' => 'PortableInfoboxItemGroup.hbs',
'smart-group' => 'PortableInfoboxItemSmartGroup.hbs',
'horizontal-group-content' => 'PortableInfoboxHorizontalGroupContent.hbs',
'navigation' => 'PortableInfoboxItemNavigation.hbs',
'image-collection' => 'PortableInfoboxItemImageCollection.hbs',
'media-collection' => 'PortableInfoboxItemMediaCollection.hbs',
'xml-parse-error' => 'PortableInfoboxMarkupDebug.hbs'
];
@ -48,7 +51,7 @@ class PortableInfoboxTemplateEngine {
if ( !empty( self::$cache[ $type ] ) ) {
return self::$cache[ $type ];
}
$path = self::getTemplatesDir() . DIRECTORY_SEPARATOR . self::$templates[ $type ];
// @see https://github.com/wikimedia/mediawiki-vendor/tree/master/zordius/lightncandy

View file

@ -0,0 +1,25 @@
<?php
namespace PortableInfobox\Parser\Nodes;
class NodeAudio extends NodeMedia {
/*
* @return bool
*/
protected function allowImage() {
return false;
}
/*
* @return bool
*/
protected function allowVideo() {
return false;
}
/*
* @return bool
*/
protected function allowAudio() {
return true;
}
}

View file

@ -1,209 +1,18 @@
<?php
namespace PortableInfobox\Parser\Nodes;
use PortableInfobox\Helpers\FileNamespaceSanitizeHelper;
use PortableInfobox\Helpers\HtmlHelper;
use PortableInfobox\Helpers\PortableInfoboxDataBag;
use PortableInfobox\Sanitizers\SanitizerBuilder;
class NodeImage extends Node {
const GALLERY = 'GALLERY';
const TABBER = 'TABBER';
const ALT_TAG_NAME = 'alt';
const CAPTION_TAG_NAME = 'caption';
public static function getMarkers( $value, $ext ) {
if ( preg_match_all('/' . \Parser::MARKER_PREFIX . '-' . $ext . '-[A-F0-9]{8}' . \Parser::MARKER_SUFFIX . '/is', $value, $out ) ) {
return $out[0];
} else {
return [];
}
}
public static function getGalleryData( $marker ) {
$gallery = PortableInfoboxDataBag::getInstance()->getGallery( $marker );
return isset( $gallery ) ? array_map( function ( $image ) {
return [
'label' => $image[1] ?: $image[0]->getText(),
'title' => $image[0]
];
}, $gallery->getimages() ) : [];
}
public static function getTabberData( $html ) {
$data = [];
$doc = HtmlHelper::createDOMDocumentFromText( $html );
$sxml = simplexml_import_dom( $doc );
$divs = $sxml->xpath( '//div[@class=\'tabbertab\']' );
foreach ( $divs as $div ) {
if ( preg_match( '/ src="(?:[^"]*\/)?([^"]*?)"/', $div->asXML(), $out ) ) {
$data[] = [
'label' => (string) $div['title'],
'title' => $out[1]
];
}
}
return $data;
}
public function getData() {
if ( !isset( $this->data ) ) {
$this->data = [];
// value passed to source parameter (or default)
$value = $this->getRawValueWithDefault( $this->xmlNode );
if ( $this->containsTabberOrGallery( $value ) ) {
$this->data = $this->getImagesData( $value );
} else {
$this->data = [ $this->getImageData(
$value,
$this->getValueWithDefault( $this->xmlNode->{self::ALT_TAG_NAME} ),
$this->getValueWithDefault( $this->xmlNode->{self::CAPTION_TAG_NAME} )
) ];
}
}
return $this->data;
}
/**
* @desc Checks if parser preprocessed string containg Tabber or Gallery extension
* @param string $str String to check
class NodeImage extends NodeMedia {
/*
* @return bool
*/
private function containsTabberOrGallery( $str ) {
return !empty( self::getMarkers( $str, self::TABBER ) ) || !empty( self::getMarkers( $str, self::GALLERY ) );
}
private function getImagesData( $value ) {
$data = [];
$items = array_merge( $this->getGalleryItems( $value ), $this->getTabberItems( $value ) );
foreach( $items as $item ) {
$data[] = $this->getImageData( $item['title'], $item['label'], $item['label'] );
}
return $data;
}
private function getGalleryItems( $value ) {
$galleryItems = [];
$galleryMarkers = self::getMarkers( $value, self::GALLERY );
foreach ( $galleryMarkers as $marker ) {
$galleryItems = array_merge( $galleryItems, self::getGalleryData( $marker ) );
}
return $galleryItems;
}
private function getTabberItems( $value ) {
$tabberItems = [];
$tabberMarkers = self::getMarkers( $value, self::TABBER );
foreach ( $tabberMarkers as $marker ) {
$tabberHtml = $this->getExternalParser()->parseRecursive( $marker );
$tabberItems = array_merge( $tabberItems, self::getTabberData( $tabberHtml ) );
}
return $tabberItems;
}
/**
* @desc prepare infobox image node data.
*
* @param $title
* @param $alt
* @param $caption
* @return array
*/
private function getImageData( $title, $alt, $caption ) {
$titleObj = $title instanceof \Title ? $title : $this->getImageAsTitleObject( $title );
$fileObj = $this->getFileFromTitle( $titleObj );
if ( $titleObj instanceof \Title ) {
$this->getExternalParser()->addImage( $titleObj->getDBkey() );
}
$image = [
'url' => $this->resolveImageUrl( $fileObj ),
'name' => $titleObj ? $titleObj->getText() : '',
'key' => $titleObj ? $titleObj->getDBKey() : '',
'alt' => $alt ?? ( $titleObj ? $titleObj->getText() : null ),
'caption' => SanitizerBuilder::createFromType( 'image' )
->sanitize( [ 'caption' => $caption ] )['caption'] ?: null,
'isVideo' => $this->isVideo( $fileObj )
];
return $image;
}
public function isEmpty() {
$data = $this->getData();
foreach ( $data as $dataItem ) {
if ( !empty( $dataItem[ 'url' ] ) ) {
return false;
}
}
protected function allowImage() {
return true;
}
public function getSources() {
$sources = $this->extractSourcesFromNode( $this->xmlNode );
if ( $this->xmlNode->{self::ALT_TAG_NAME} ) {
$sources = array_merge( $sources,
$this->extractSourcesFromNode( $this->xmlNode->{self::ALT_TAG_NAME} ) );
}
if ( $this->xmlNode->{self::CAPTION_TAG_NAME} ) {
$sources = array_merge( $sources,
$this->extractSourcesFromNode( $this->xmlNode->{self::CAPTION_TAG_NAME} ) );
}
return array_unique( $sources );
}
private function getImageAsTitleObject( $imageName ) {
global $wgContLang;
$title = \Title::makeTitleSafe(
NS_FILE,
FileNamespaceSanitizeHelper::getInstance()->sanitizeImageFileName( $imageName, $wgContLang )
);
return $title;
}
/**
* NOTE: Protected to override in unit tests
*
* @desc get file object from title object
* @param Title|null $title
* @return File|null
*/
protected function getFileFromTitle( $title ) {
if( is_string( $title ) ) {
$title = \Title::newFromText( $title, NS_FILE );
}
if( $title instanceof \Title ) {
$file = wfFindFile( $title );
if( $file instanceof \File && $file->exists() ) {
return $file;
}
}
return null;
}
/**
* @desc returns image url for given image title
* @param File|null $file
* @return string url or '' if image doesn't exist
*/
public function resolveImageUrl( $file ) {
return $file ? $file->getUrl() : '';
}
/**
* @desc checks if file media type is VIDEO
* @param File|null $file
/*
* @return bool
*/
private function isVideo( $file ) {
return $file ? $file->getMediaType() === MEDIATYPE_VIDEO : false;
protected function allowAudio() {
return false;
}
}
}

View file

@ -0,0 +1,252 @@
<?php
namespace PortableInfobox\Parser\Nodes;
use PortableInfobox\Helpers\FileNamespaceSanitizeHelper;
use PortableInfobox\Helpers\HtmlHelper;
use PortableInfobox\Helpers\PortableInfoboxDataBag;
use PortableInfobox\Sanitizers\SanitizerBuilder;
class NodeMedia extends Node {
const GALLERY = 'GALLERY';
const TABBER = 'TABBER';
const ALLOWIMAGE_ATTR_NAME = 'image';
const ALLOWVIDEO_ATTR_NAME = 'video';
const ALLOWAUDIO_ATTR_NAME = 'audio';
const ALT_TAG_NAME = 'alt';
const CAPTION_TAG_NAME = 'caption';
public static function getMarkers( $value, $ext ) {
if ( preg_match_all('/' . \Parser::MARKER_PREFIX . '-' . $ext . '-[A-F0-9]{8}' . \Parser::MARKER_SUFFIX . '/is', $value, $out ) ) {
return $out[0];
} else {
return [];
}
}
public static function getGalleryData( $marker ) {
$gallery = PortableInfoboxDataBag::getInstance()->getGallery( $marker );
return isset( $gallery ) ? array_map( function ( $image ) {
return [
'label' => $image[1] ?: $image[0]->getText(),
'title' => $image[0]
];
}, $gallery->getimages() ) : [];
}
public static function getTabberData( $html ) {
$data = [];
$doc = HtmlHelper::createDOMDocumentFromText( $html );
$sxml = simplexml_import_dom( $doc );
$divs = $sxml->xpath( '//div[@class=\'tabbertab\']' );
foreach ( $divs as $div ) {
if ( preg_match( '/ src="(?:[^"]*\/)?([^"]*?)"/', $div->asXML(), $out ) ) {
$data[] = [
'label' => (string) $div['title'],
'title' => $out[1]
];
}
}
return $data;
}
public function getData() {
if ( !isset( $this->data ) ) {
$this->data = [];
// value passed to source parameter (or default)
$value = $this->getRawValueWithDefault( $this->xmlNode );
if ( $this->containsTabberOrGallery( $value ) ) {
$this->data = $this->getImagesData( $value );
} else {
$this->data = [ $this->getImageData(
$value,
$this->getValueWithDefault( $this->xmlNode->{self::ALT_TAG_NAME} ),
$this->getValueWithDefault( $this->xmlNode->{self::CAPTION_TAG_NAME} )
) ];
}
}
return $this->data;
}
/**
* @desc Checks if parser preprocessed string containg Tabber or Gallery extension
* @param string $str String to check
* @return bool
*/
private function containsTabberOrGallery( $str ) {
return !empty( self::getMarkers( $str, self::TABBER ) ) || !empty( self::getMarkers( $str, self::GALLERY ) );
}
private function getImagesData( $value ) {
$data = [];
$items = array_merge( $this->getGalleryItems( $value ), $this->getTabberItems( $value ) );
foreach( $items as $item ) {
$data[] = $this->getImageData( $item['title'], $item['label'], $item['label'] );
}
return $data;
}
private function getGalleryItems( $value ) {
$galleryItems = [];
$galleryMarkers = self::getMarkers( $value, self::GALLERY );
foreach ( $galleryMarkers as $marker ) {
$galleryItems = array_merge( $galleryItems, self::getGalleryData( $marker ) );
}
return $galleryItems;
}
private function getTabberItems( $value ) {
$tabberItems = [];
$tabberMarkers = self::getMarkers( $value, self::TABBER );
foreach ( $tabberMarkers as $marker ) {
$tabberHtml = $this->getExternalParser()->parseRecursive( $marker );
$tabberItems = array_merge( $tabberItems, self::getTabberData( $tabberHtml ) );
}
return $tabberItems;
}
/**
* @desc prepare infobox image node data.
*
* @param $title
* @param $alt
* @param $caption
* @return array
*/
private function getImageData( $title, $alt, $caption ) {
$titleObj = $title instanceof \Title ? $title : $this->getImageAsTitleObject( $title );
$fileObj = $this->getFileFromTitle( $titleObj );
if( !isset( $fileObj ) || !$this->isTypeAllowed( $fileObj->getMediaType() ) ) {
return [];
}
if ( $titleObj instanceof \Title ) {
$this->getExternalParser()->addImage( $titleObj->getDBkey() );
}
$image = [
'url' => $this->resolveImageUrl( $fileObj ),
'name' => $titleObj ? $titleObj->getText() : '',
'alt' => $alt ?? ( $titleObj ? $titleObj->getText() : null ),
'caption' => SanitizerBuilder::createFromType( 'image' )
->sanitize( [ 'caption' => $caption ] )['caption'] ?: null
];
return $image;
}
public function isEmpty() {
$data = $this->getData();
foreach ( $data as $dataItem ) {
if ( !empty( $dataItem[ 'url' ] ) ) {
return false;
}
}
return true;
}
public function getSources() {
$sources = $this->extractSourcesFromNode( $this->xmlNode );
if ( $this->xmlNode->{self::ALT_TAG_NAME} ) {
$sources = array_merge( $sources,
$this->extractSourcesFromNode( $this->xmlNode->{self::ALT_TAG_NAME} ) );
}
if ( $this->xmlNode->{self::CAPTION_TAG_NAME} ) {
$sources = array_merge( $sources,
$this->extractSourcesFromNode( $this->xmlNode->{self::CAPTION_TAG_NAME} ) );
}
return array_unique( $sources );
}
private function getImageAsTitleObject( $imageName ) {
global $wgContLang;
$title = \Title::makeTitleSafe(
NS_FILE,
FileNamespaceSanitizeHelper::getInstance()->sanitizeImageFileName( $imageName, $wgContLang )
);
return $title;
}
/**
* NOTE: Protected to override in unit tests
*
* @desc get file object from title object
* @param Title|null $title
* @return File|null
*/
protected function getFileFromTitle( $title ) {
if( is_string( $title ) ) {
$title = \Title::newFromText( $title, NS_FILE );
}
if( $title instanceof \Title ) {
$file = wfFindFile( $title );
if( $file instanceof \File && $file->exists() ) {
return $file;
}
}
return null;
}
/**
* @desc returns image url for given image title
* @param File|null $file
* @return string url or '' if image doesn't exist
*/
public function resolveImageUrl( $file ) {
return $file ? $file->getUrl() : '';
}
/**
* @desc checks if file media type is allowed
* @param string $type
* @return bool
*/
private function isTypeAllowed( $type ) {
switch( $type ) {
case MEDIATYPE_BITMAP:
case MEDIATYPE_DRAWING:
return $this->allowImage();
case MEDIATYPE_VIDEO:
return $this->allowVideo();
case MEDIATYPE_AUDIO:
return $this->allowAudio();
default:
return false;
}
}
/**
* @return bool
*/
protected function allowImage() {
$attr = $this->getXmlAttribute( $this->xmlNode, self::ALLOWIMAGE_ATTR_NAME );
return !( isset( $attr ) && strtolower( $attr ) === 'false' );
}
/**
* @return bool
*/
protected function allowVideo() {
$attr = $this->getXmlAttribute( $this->xmlNode, self::ALLOWVIDEO_ATTR_NAME );
return !( isset( $attr ) && strtolower( $attr ) === 'false' );
}
/*
* @return bool
*/
protected function allowAudio() {
$attr = $this->getXmlAttribute( $this->xmlNode, self::ALLOWAUDIO_ATTR_NAME );
return !( isset( $attr ) && strtolower( $attr ) === 'false' );
}
}

View file

@ -0,0 +1,25 @@
<?php
namespace PortableInfobox\Parser\Nodes;
class NodeVideo extends NodeMedia {
/*
* @return bool
*/
protected function allowImage() {
return false;
}
/*
* @return bool
*/
protected function allowVideo() {
return true;
}
/*
* @return bool
*/
protected function allowAudio() {
return false;
}
}

View file

@ -82,8 +82,11 @@ class PortableInfoboxRenderService {
case 'header':
$result = $this->renderHeader( $data );
break;
case 'media':
case 'audio':
case 'image':
$result = $this->renderImage( $data );
case 'video':
$result = $this->renderMedia( $data );
break;
case 'title':
$result = $this->renderTitle( $data );
@ -104,7 +107,7 @@ class PortableInfoboxRenderService {
* @return string - group HTML markup
*/
protected function renderGroup( $groupData ) {
$cssClasses = [ ];
$cssClasses = [];
$groupHTMLContent = '';
$children = $groupData['value'];
$layout = $groupData['layout'];
@ -140,15 +143,13 @@ class PortableInfoboxRenderService {
* @param $data
* @return string
*/
protected function renderImage( $data ) {
protected function renderMedia( $data ) {
$helper = $this->getImageHelper();
$data = $this->filterImageData( $data );
$images = [ ];
$images = [];
foreach ( $data as $dataItem ) {
$extendedItem = $dataItem;
$extendedItem['context'] = null;
$extendedItem = $helper->extendImageData( $extendedItem, $this->imagesWidth, $this->infoboxWidth );
if ( !!$extendedItem ) {
@ -162,11 +163,11 @@ class PortableInfoboxRenderService {
if ( count( $images ) === 1 ) {
$data = $images[0];
$templateName = 'image';
$templateName = 'media';
} else {
// More than one image means image collection
$data = $helper->extendImageCollectionData( $images );
$templateName = 'image-collection';
$templateName = 'media-collection';
}
return $this->render( $templateName, $data );
@ -196,22 +197,6 @@ class PortableInfoboxRenderService {
return $result;
}
private function filterImageData( $data ) {
$dataWithCaption = array_filter($data, function( $item ) {
return !empty( $item['caption'] );
});
$result = [];
if ( !empty( $dataWithCaption ) ) {
$result = $dataWithCaption;
} elseif ( !empty( $data ) ) {
$result = [ $data[0] ];
}
return $result;
}
private function getInlineStyles( $accentColor, $accentColorText ) {
$backgroundColor = empty( $accentColor ) ? '' : "background-color:{$accentColor};";
$color = empty( $accentColorText ) ? '' : "color:{$accentColorText};";
@ -221,8 +206,8 @@ class PortableInfoboxRenderService {
private function createHorizontalGroupData( $groupData ) {
$horizontalGroupData = [
'labels' => [ ],
'values' => [ ],
'labels' => [],
'values' => [],
'renderLabels' => false
];
@ -246,9 +231,9 @@ class PortableInfoboxRenderService {
}
private function createSmartGroups( $groupData, $rowCapacity ) {
$result = [ ];
$result = [];
$rowSpan = 0;
$rowItems = [ ];
$rowItems = [];
foreach ( $groupData as $item ) {
$data = $item['data'];
@ -258,7 +243,7 @@ class PortableInfoboxRenderService {
if ( !empty( $rowItems ) && $rowSpan + $data['span'] > $rowCapacity ) {
$result[] = $this->createSmartGroupItem( $rowItems, $rowSpan );
$rowSpan = 0;
$rowItems = [ ];
$rowItems = [];
}
$rowSpan += $data['span'];
$rowItems[] = $item;
@ -298,6 +283,6 @@ class PortableInfoboxRenderService {
$result['values'][] = [ 'value' => $item['data']['value'], 'inlineStyles' => $styles ];
return $result;
}, [ 'labels' => [ ], 'values' => [ ], 'renderLabels' => false ] );
}, [ 'labels' => [], 'values' => [], 'renderLabels' => false ] );
}
}

View file

@ -1,14 +1,14 @@
(function (window, $) {
'use strict';
var ImageCollection = {
var MediaCollection = {
init: function($content) {
var $imageCollections = $content.find('.pi-image-collection');
var $mediaCollections = $content.find('.pi-media-collection');
$imageCollections.each( function( index ) {
var $collection = $imageCollections.eq(index),
$tabs = $collection.find('ul.pi-image-collection-tabs li'),
$tabContent = $collection.find('.pi-image-collection-tab-content');
$mediaCollections.each( function( index ) {
var $collection = $mediaCollections.eq(index),
$tabs = $collection.find('ul.pi-media-collection-tabs li'),
$tabContent = $collection.find('.pi-media-collection-tab-content');
$tabs.click( function() {
var $target = $(this),
@ -43,7 +43,7 @@
};
mw.hook('wikipage.content').add(function($content) {
ImageCollection.init($content);
MediaCollection.init($content);
CollapsibleGroup.init($content);
});
})(window, jQuery);

View file

@ -44,7 +44,7 @@
font-weight: bold;
line-height: 1.3;
}
.pi-image {
.pi-media {
margin: 0;
max-width: 100%;
text-align: center;
@ -71,54 +71,55 @@
}
}
.pi {
&-image {
&-thumbnail {
max-width: var(--pi-width);
height: auto;
&-media-collection {
overflow: hidden;
margin: 0;
padding-top: 1px;
& &-tabs {
list-style: none;
margin: 0 -1px;
padding: 1px 0;
text-align: center;
}
&-collection {
overflow: hidden;
margin: 0;
padding-top: 1px;
& &-tabs {
list-style: none;
margin: 0 -1px;
padding: 1px 0;
text-align: center;
&-tabs {
li {
border: 1px solid var(--pi-secondary-background);
box-sizing: border-box;
cursor: pointer;
display: inline-block;
margin: -1px -1px 0 0;
max-width: 50%;
overflow: hidden;
text-overflow: ellipsis;
vertical-align: bottom;
white-space: nowrap;
}
&-tabs {
li {
border: 1px solid var(--pi-secondary-background);
box-sizing: border-box;
cursor: pointer;
display: inline-block;
margin: -1px -1px 0 0;
max-width: 50%;
overflow: hidden;
text-overflow: ellipsis;
vertical-align: bottom;
white-space: nowrap;
}
li.current {
background: var(--pi-secondary-background);
font-weight: bold;
}
}
&-tab-content {
display: none;
.video-thumbnail {
display: block;
}
&.current {
display: inherit;
}
li.current {
background: var(--pi-secondary-background);
font-weight: bold;
}
}
&-tab-content {
display: none;
&.current {
display: inherit;
}
}
}
&-image-thumbnail {
max-width: var(--pi-width);
height: auto;
}
&-video-player {
width: var(--pi-width);
height: auto;
}
&-audio-player {
width: var(--pi-width);
&::-webkit-media-controls-enclosure {
border-radius: 0;
}
}
&-caption {
-webkit-hyphens: auto;
-moz-hyphens: auto;

View file

@ -1,52 +0,0 @@
/* global beforeEach, describe, it, expect, jasmine, mw, $ */
describe('Portable Infobox', function () {
describe('collapsible sections', function () {
var portableInfoboxHtml = `
<section class="pi-item pi-group pi-border-color pi-collapse">
<h2 class="pi-item pi-header pi-secondary-font pi-item-spacing pi-secondary-background">Bugged</h2>
<div class="pi-item pi-data pi-item-spacing pi-border-color">
<div class="pi-data-value pi-font">
<figure class="article-thumb tleft show-info-icon" style="width: 250px">
<a href="/wiki/User:PanSola" class="image image-thumbnail link-internal" title="User:PanSola">
<img src="data:image/gif;base64,R0lGODlhAQABAIABAAAAAP///yH5BAEAAAEALAAAAAABAAEAQAICTAEAOw%3D%3D" alt="Wookieepedia" class="thumbimage lzy lzyPlcHld " data-image-key="Wookieepedia.png" data-image-name="Wookieepedia.png" data-src="https://vignette.wikia.nocookie.net/infobox/images/b/b1/Wookieepedia.png/revision/latest?cb=20160107195313" width="250" height="65" onload="if(typeof ImgLzy==='object'){ImgLzy.load(this)}">
<noscript>&lt;img src="https://vignette.wikia.nocookie.net/infobox/images/b/b1/Wookieepedia.png/revision/latest?cb=20160107195313" alt="Wookieepedia" class="thumbimage " data-image-key="Wookieepedia.png" data-image-name="Wookieepedia.png" width="250" height="65" &gt;</noscript></a>
<figcaption><a href="/wiki/File:Wookieepedia.png" class="sprite info-icon"></a></figcaption>
</figure>
</div>
</div>
</section>
`,
div = document.createElement('div');
beforeEach(function () {
div.innerHTML = portableInfoboxHtml;
mw.hook('wikipage.content').fire($(div));
});
it('collapsed state is toggled on collapsible header click', function () {
var portableInfoboxHeader = div.querySelector('.pi-header');
portableInfoboxHeader.click();
expect(div.querySelector('.pi-collapse').className).toContain('pi-collapse-closed');
portableInfoboxHeader.click();
expect(div.querySelector('.pi-collapse').className).not.toContain('pi-collapse-closed');
});
it('emit global scroll event on collapsible header click', function () {
var portableInfoboxHeader = div.querySelector('.pi-header'),
scrollSpy = jasmine.createSpy('scrollSpy');
$(window).on('scroll', scrollSpy);
portableInfoboxHeader.click();
portableInfoboxHeader.click();
expect(scrollSpy).toHaveBeenCalledTimes(2);
});
});
});

View file

@ -1,7 +0,0 @@
<figure class="pi-item pi-image{{#if isVideo}} pi-video{{/if}}">
<a href="{{url}}" class="image image-thumbnail{{#isVideo}} video video-thumbnail{{/isVideo}}" title="{{alt}}">
{{#unless isVideo}}<img src="{{thumbnail}}" srcset="{{thumbnail}} 1x, {{thumbnail2x}} 2x" class="pi-image-thumbnail" alt="{{alt}}" width="{{{width}}}" height="{{{height}}}"/>
{{else}}<video src="{{url}}" class="pi-video-player" controls="true" controlsList="nodownload" preload="metadata">{{alt}}</video>{{/unless}}
</a>
{{#if caption}}<figcaption class="pi-item-spacing pi-caption">{{{caption}}}</figcaption>{{/if}}
</figure>

View file

@ -1,15 +0,0 @@
<div class="pi-image-collection">
<ul class="pi-image-collection-tabs">
{{#each images}}<li class="pi-tab-link pi-item-spacing{{#if isFirst}} current{{/if}}" data-pi-tab="pi-tab-{{ref}}">{{{caption}}}</li>{{/each}}
</ul>
{{#each images}}
<div class="pi-image-collection-tab-content{{#if isFirst}} current{{/if}}" id="pi-tab-{{ref}}">
<figure class="pi-item pi-image{{#if isVideo}} pi-video{{/if}}">
<a href="{{url}}" class="image image-thumbnail{{#isVideo}} video video-thumbnail{{/isVideo}}" title="{{alt}}">
{{#unless isVideo}}<img src="{{thumbnail}}" srcset="{{thumbnail}} 1x, {{thumbnail2x}} 2x" class="pi-image-thumbnail" alt="{{alt}}" width="{{{width}}}" height="{{{height}}}"/>
{{else}}<video src="{{url}}" class="pi-video-player" controls="true" controlsList="nodownload" preload="metadata">{{alt}}</video>{{/unless}}
</a>
</figure>
</div>
{{/each}}
</div>

View file

@ -0,0 +1,9 @@
<figure class="pi-item pi-media{{#if isImage}} pi-image{{/if}}{{#if isVideo}} pi-video{{/if}}{{#if isAudio}} pi-audio{{/if}}">
<a href="{{url}}" class="{{#if isImage}}image image-thumbnail{{/if}}{{#if isVideo}}video{{/if}}{{#if isAudio}}audio{{/if}}" title="{{alt}}">
{{#if isImage}}<img src="{{thumbnail}}" srcset="{{thumbnail}} 1x, {{thumbnail2x}} 2x" class="pi-image-thumbnail" alt="{{alt}}" width="{{{width}}}" height="{{{height}}}"/>
{{else}}{{#if isVideo}}<video src="{{url}}" class="pi-video-player" controls="true" controlsList="nodownload" preload="metadata">{{alt}}</video>
{{else}}{{#if isAudio}}<audio src="{{url}}" class="pi-audio-player" controls="true" controlsList="nodownload">{{alt}}</audio>
{{else}}{{alt}}{{/if}}{{/if}}{{/if}}
</a>
{{#if caption}}<figcaption class="pi-item-spacing pi-caption">{{{caption}}}</figcaption>{{/if}}
</figure>

View file

@ -0,0 +1,17 @@
<div class="pi-media-collection">
<ul class="pi-media-collection-tabs">
{{#each images}}<li class="pi-tab-link pi-item-spacing{{#if isFirst}} current{{/if}}" data-pi-tab="pi-tab-{{ref}}">{{{caption}}}</li>{{/each}}
</ul>
{{#each images}}
<div class="pi-media-collection-tab-content{{#if isFirst}} current{{/if}}" id="pi-tab-{{ref}}">
<figure class="pi-item pi-media{{#if isImage}} pi-image{{/if}}{{#if isVideo}} pi-video{{/if}}{{#if isAudio}} pi-audio{{/if}}">
<a href="{{url}}" class="{{#if isImage}}image image-thumbnail{{/if}}{{#if isVideo}}video{{/if}}{{#if isAudio}}audio{{/if}}" title="{{alt}}">
{{#if isImage}}<img src="{{thumbnail}}" srcset="{{thumbnail}} 1x, {{thumbnail2x}} 2x" class="pi-image-thumbnail" alt="{{alt}}" width="{{{width}}}" height="{{{height}}}"/>
{{else}}{{#if isVideo}}<video src="{{url}}" class="pi-video-player" controls="true" controlsList="nodownload" preload="metadata">{{alt}}</video>
{{else}}{{#if isAudio}}<audio src="{{url}}" class="pi-audio-player" controls="true" controlsList="nodownload">{{alt}}</audio>
{{else}}{{alt}}{{/if}}{{/if}}{{/if}}
</a>
</figure>
</div>
{{/each}}
</div>

View file

@ -22,170 +22,6 @@ class PortableInfoboxRenderServiceTest extends MediaWikiTestCase {
return $DOM->saveXML();
}
/**
* @param $data
* @param $expected
*
* @dataProvider filterImagesDataProvider
*/
public function testFilterImages( $data, $expected ) {
$method = ( new ReflectionClass( 'PortableInfoboxRenderService' ) )->getMethod( 'filterImageData' );
$method->setAccessible( true );
$renderService = new PortableInfoboxRenderService();
$this->assertEquals( $expected, $method->invokeArgs( $renderService, [ $data ] ) );
}
public function filterImagesDataProvider() {
return [
[
'data' => [
[
'url' => 'some.url.com',
'name' => 'name1',
'key' => 'key1',
'alt' => 'alt1',
'caption' => 'caption1',
'isVideo' => false,
],
[
'url' => 'some.url.com',
'name' => 'name2',
'key' => 'key2',
'alt' => 'alt2',
'caption' => 'caption2',
'isVideo' => false,
],
],
'expected' => [
[
'url' => 'some.url.com',
'name' => 'name1',
'key' => 'key1',
'alt' => 'alt1',
'caption' => 'caption1',
'isVideo' => false,
],
[
'url' => 'some.url.com',
'name' => 'name2',
'key' => 'key2',
'alt' => 'alt2',
'caption' => 'caption2',
'isVideo' => false,
],
]
],
[
'data' => [
[
'url' => 'some.url.com',
'name' => 'name1',
'key' => 'key1',
'alt' => 'alt1',
'caption' => '',
'isVideo' => false,
],
[
'url' => 'some.url.com',
'name' => 'name2',
'key' => 'key2',
'alt' => 'alt2',
'caption' => 'caption2',
'isVideo' => false,
],
[
'url' => 'some.url.com',
'name' => 'name3',
'key' => 'key3',
'alt' => 'alt3',
'caption' => 'caption3',
'isVideo' => false,
],
],
'expected' => [
1 => [
'url' => 'some.url.com',
'name' => 'name2',
'key' => 'key2',
'alt' => 'alt2',
'caption' => 'caption2',
'isVideo' => false,
],
2 => [
'url' => 'some.url.com',
'name' => 'name3',
'key' => 'key3',
'alt' => 'alt3',
'caption' => 'caption3',
'isVideo' => false,
]
]
],
[
'data' => [
[
'url' => 'some.url.com',
'name' => 'name1',
'key' => 'key1',
'alt' => 'alt1',
'caption' => 'caption1',
'isVideo' => false,
],
[
'url' => 'some.url.com',
'name' => 'name2',
'key' => 'key2',
'alt' => 'alt2',
'caption' => '',
'isVideo' => false,
],
],
'expected' => [
[
'url' => 'some.url.com',
'name' => 'name1',
'key' => 'key1',
'alt' => 'alt1',
'caption' => 'caption1',
'isVideo' => false,
],
],
],
[
'data' => [
[
'url' => 'some.url.com',
'name' => 'name1',
'key' => 'key1',
'alt' => 'alt1',
'caption' => '',
'isVideo' => false,
],
[
'url' => 'some.url.com',
'name' => 'name2',
'key' => 'key2',
'alt' => 'alt2',
'caption' => '',
'isVideo' => false,
],
],
'expected' => [
[
'url' => 'some.url.com',
'name' => 'name1',
'key' => 'key1',
'alt' => 'alt1',
'caption' => '',
'isVideo' => false,
],
]
],
];
}
/**
* @param $input
* @param $expectedOutput
@ -263,16 +99,13 @@ class PortableInfoboxRenderServiceTest extends MediaWikiTestCase {
[
'alt' => 'image alt',
'url' => 'http://image.jpg',
'name' => 'image',
'key' => 'image',
'caption' => 'Lorem ipsum dolor',
'isVideo' => false
'caption' => 'Lorem ipsum dolor'
]
]
]
],
'output' => '<aside class="portable-infobox pi-background">
<figure class="pi-item pi-image">
<figure class="pi-item pi-media pi-image">
<a href="http://image.jpg" class="image image-thumbnail" title="image alt">
<img src="http://thumbnail.jpg" srcset="http://thumbnail.jpg 1x, http://thumbnail2x.jpg 2x" class="pi-image-thumbnail" alt="image alt"
width="400" height="200"/>
@ -286,14 +119,11 @@ class PortableInfoboxRenderServiceTest extends MediaWikiTestCase {
'alt' => 'image alt',
'url' => 'http://image.jpg',
'caption' => 'Lorem ipsum dolor',
'name' => 'image',
'key' => 'image',
'width' => '400',
'height' => '200',
'thumbnail' => 'http://thumbnail.jpg',
'thumbnail2x' => 'http://thumbnail2x.jpg',
'media-type' => 'image',
'isVideo' => false
'isImage' => true
]
],
'accentColor' => '',
@ -307,19 +137,15 @@ class PortableInfoboxRenderServiceTest extends MediaWikiTestCase {
[
'alt' => 'image alt',
'url' => 'http://image.jpg',
'caption' => 'Lorem ipsum dolor',
'isVideo' => true,
'duration' => '1:20',
'name' => 'test',
'key' => 'test'
'caption' => 'Lorem ipsum dolor'
]
]
]
],
'output' => '<aside class="portable-infobox pi-background">
<figure class="pi-item pi-image pi-video">
<figure class="pi-item pi-media pi-video">
<a href="http://image.jpg"
class="image image-thumbnail video video-thumbnail"
class="video"
title="image alt">
<video src="http://image.jpg" class="pi-video-player" controls="true" controlsList="nodownload" preload="metadata">image alt</video>
</a>
@ -389,10 +215,7 @@ class PortableInfoboxRenderServiceTest extends MediaWikiTestCase {
'data' => [
[
'alt' => 'image alt',
'url' => 'http://image.jpg',
'name' => 'image',
'key' => 'image',
'isVideo' => false
'url' => 'http://image.jpg'
]
]
],
@ -406,7 +229,7 @@ class PortableInfoboxRenderServiceTest extends MediaWikiTestCase {
],
'output' => '<aside class="portable-infobox pi-background">
<h2 class="pi-item pi-item-spacing pi-title">Test Title</h2>
<figure class="pi-item pi-image">
<figure class="pi-item pi-media pi-image">
<a href="http://image.jpg" class="image image-thumbnail" title="image alt">
<img src="http://thumbnail.jpg" srcset="http://thumbnail.jpg 1x, http://thumbnail2x.jpg 2x" class="pi-image-thumbnail" alt="image alt"
width="400" height="200"/>
@ -422,14 +245,11 @@ class PortableInfoboxRenderServiceTest extends MediaWikiTestCase {
'extendImageData' => [
'alt' => 'image alt',
'url' => 'http://image.jpg',
'name' => 'image',
'key' => 'image',
'width' => '400',
'height' => '200',
'thumbnail' => 'http://thumbnail.jpg',
'thumbnail2x' => 'http://thumbnail2x.jpg',
'media-type' => 'image',
'isVideo' => false
'isImage' => true
]
],
'accentColor' => '',

View file

@ -100,7 +100,10 @@ class PortableInfoboxImagesHelperTest extends MediaWikiTestCase {
'thumbnail' => null,
'thumbnail2x' => null,
'width' => $resultDimensions[ 'width' ],
'height' => $resultDimensions[ 'height' ]
'height' => $resultDimensions[ 'height' ],
'isImage' => true,
'isVideo' => false,
'isAudio' => false
];
$thumb = $this->getMockBuilder( 'ThumbnailImage' )
->disableOriginalConstructor()

View file

@ -1,13 +1,13 @@
<?php
use PortableInfobox\Helpers\PortableInfoboxDataBag;
use PortableInfobox\Parser\Nodes\NodeImage;
use PortableInfobox\Parser\Nodes\NodeMedia;
/**
* @group PortableInfobox
* @covers PortableInfobox\Parser\Nodes\NodeImage
* @covers PortableInfobox\Parser\Nodes\NodeMedia
*/
class NodeImageTest extends MediaWikiTestCase {
class NodeMediaTest extends MediaWikiTestCase {
protected function setUp() {
parent::setUp();
@ -17,13 +17,13 @@ class NodeImageTest extends MediaWikiTestCase {
}
/**
* @covers PortableInfobox\Parser\Nodes\NodeImage::getGalleryData
* @covers PortableInfobox\Parser\Nodes\NodeMedia::getGalleryData
* @dataProvider galleryDataProvider
* @param $marker
* @param $expected
*/
public function testGalleryData( $marker, $expected ) {
$this->assertEquals( $expected, NodeImage::getGalleryData( $marker ) );
$this->assertEquals( $expected, NodeMedia::getGalleryData( $marker ) );
}
public function galleryDataProvider() {
@ -83,7 +83,7 @@ class NodeImageTest extends MediaWikiTestCase {
}
/**
* @covers PortableInfobox\Parser\Nodes\NodeImage::getTabberData
* @covers PortableInfobox\Parser\Nodes\NodeMedia::getTabberData
*/
public function testTabberData() {
$input = '<div class="tabber"><div class="tabbertab" title="_title_"><p><a><img src="_src_"></a></p></div></div>';
@ -93,18 +93,18 @@ class NodeImageTest extends MediaWikiTestCase {
'title' => '_src_',
]
];
$this->assertEquals( $expected, NodeImage::getTabberData( $input ) );
$this->assertEquals( $expected, NodeMedia::getTabberData( $input ) );
}
/**
* @covers PortableInfobox\Parser\Nodes\NodeImage::getMarkers
* @covers PortableInfobox\Parser\Nodes\NodeMedia::getMarkers
* @dataProvider markersProvider
* @param $ext
* @param $value
* @param $expected
*/
public function testMarkers( $ext, $value, $expected ) {
$this->assertEquals( $expected, PortableInfobox\Parser\Nodes\NodeImage::getMarkers( $value, $ext ) );
$this->assertEquals( $expected, PortableInfobox\Parser\Nodes\NodeMedia::getMarkers( $value, $ext ) );
}
public function markersProvider() {
@ -129,7 +129,7 @@ class NodeImageTest extends MediaWikiTestCase {
/**
* @covers PortableInfobox\Parser\Nodes\NodeImage::getData
* @covers PortableInfobox\Parser\Nodes\NodeMedia::getData
* @dataProvider dataProvider
*
* @param $markup
@ -137,44 +137,50 @@ class NodeImageTest extends MediaWikiTestCase {
* @param $expected
*/
public function testData( $markup, $params, $expected ) {
$node = PortableInfobox\Parser\Nodes\NodeFactory::newFromXML( $markup, $params );
$imageMock = empty( $params ) ? NULL : new ImageMock();
$xmlObj = PortableInfobox\Parser\XmlParser::parseXmlString( $markup );
$this->assertEquals( $expected, $node->getData() );
$mock = $this->getMock(NodeMedia::class, [ 'getFilefromTitle' ], [ $xmlObj, $params ]);
$mock->expects( $this->any( ))
->method( 'getFilefromTitle' )
->willReturn( $imageMock );
$this->assertEquals( $expected, $mock->getData() );
}
public function dataProvider() {
// markup, params, expected
return [
[
'<image source="img"></image>',
'<media source="img"></media>',
[ ],
[ [ 'url' => '', 'name' => '', 'key' => '', 'alt' => null, 'caption' => null, 'isVideo' => false ] ]
[ [ ] ]
],
[
'<image source="img"></image>',
'<media source="img"></media>',
[ 'img' => 'test.jpg' ],
[ [ 'url' => '', 'name' => 'Test.jpg', 'key' => 'Test.jpg', 'alt' => 'Test.jpg', 'caption' => null, 'isVideo' => false ] ]
[ [ 'url' => '', 'name' => 'Test.jpg', 'alt' => 'Test.jpg', 'caption' => null ] ]
],
[
'<image source="img"><alt><default>test alt</default></alt></image>',
'<media source="img"><alt><default>test alt</default></alt></media>',
[ 'img' => 'test.jpg' ],
[ [ 'url' => '', 'name' => 'Test.jpg', 'key' => 'Test.jpg', 'alt' => 'test alt', 'caption' => null, 'isVideo' => false ] ]
[ [ 'url' => '', 'name' => 'Test.jpg', 'alt' => 'test alt', 'caption' => null ] ]
],
[
'<image source="img"><alt source="alt source"><default>test alt</default></alt></image>',
'<media source="img"><alt source="alt source"><default>test alt</default></alt></media>',
[ 'img' => 'test.jpg', 'alt source' => 2 ],
[ [ 'url' => '', 'name' => 'Test.jpg', 'key' => 'Test.jpg', 'alt' => 2, 'caption' => null, 'isVideo' => false ] ]
[ [ 'url' => '', 'name' => 'Test.jpg', 'alt' => 2, 'caption' => null ] ]
],
[
'<image source="img"><alt><default>test alt</default></alt><caption source="img"/></image>',
'<media source="img"><alt><default>test alt</default></alt><caption source="img"/></media>',
[ 'img' => 'test.jpg' ],
[ [ 'url' => '', 'name' => 'Test.jpg', 'key' => 'Test.jpg', 'alt' => 'test alt', 'caption' => 'test.jpg', 'isVideo' => false ] ]
[ [ 'url' => '', 'name' => 'Test.jpg', 'alt' => 'test alt', 'caption' => 'test.jpg' ] ]
],
];
}
/**
* @covers PortableInfobox\Parser\Nodes\NodeImage::isEmpty
* @covers PortableInfobox\Parser\Nodes\NodeMedia::isEmpty
* @dataProvider isEmptyProvider
*
* @param $markup
@ -189,12 +195,12 @@ class NodeImageTest extends MediaWikiTestCase {
public function isEmptyProvider() {
return [
[ '<image></image>', [ ], true ],
[ '<media></media>', [ ], true ],
];
}
/**
* @covers PortableInfobox\Parser\Nodes\NodeImage::getSources
* @covers PortableInfobox\Parser\Nodes\NodeMedia::getSources
* @dataProvider sourcesProvider
*
* @param $markup
@ -209,22 +215,22 @@ class NodeImageTest extends MediaWikiTestCase {
public function sourcesProvider() {
return [
[
'<image source="img"/>',
'<media source="img"/>',
[ 'img' ]
],
[
'<image source="img"><default>{{{img}}}</default><alt source="img" /></image>',
'<media source="img"><default>{{{img}}}</default><alt source="img" /></media>',
[ 'img' ]
],
[
'<image source="img"><alt source="alt"/><caption source="cap"/></image>',
'<media source="img"><alt source="alt"/><caption source="cap"/></media>',
[ 'img', 'alt', 'cap' ]
],
[
'<image source="img"><alt source="alt"><default>{{{def}}}</default></alt><caption source="cap"/></image>',
'<media source="img"><alt source="alt"><default>{{{def}}}</default></alt><caption source="cap"/></media>',
[ 'img', 'alt', 'def', 'cap' ] ],
[
'<image/>',
'<media/>',
[ ]
],
[
@ -244,8 +250,8 @@ class NodeImageTest extends MediaWikiTestCase {
public function metadataProvider() {
return [
[
'<image source="img"><caption source="cap"><format>Test {{{cap}}} and {{{fcap}}}</format></caption></image>',
[ 'type' => 'image', 'sources' => [
'<media source="img"><caption source="cap"><format>Test {{{cap}}} and {{{fcap}}}</format></caption></media>',
[ 'type' => 'media', 'sources' => [
'img' => [ 'label' => '', 'primary' => true ],
'cap' => [ 'label' => '' ],
'fcap' => [ 'label' => '' ]
@ -262,13 +268,13 @@ class NodeImageTest extends MediaWikiTestCase {
* @throws PortableInfobox\Parser\XmlMarkupParseErrorException
*/
public function testVideo( $markup, $params, $expected ) {
$fileMock = new FileMock();
$videoMock = new VideoMock();
$xmlObj = PortableInfobox\Parser\XmlParser::parseXmlString( $markup );
$mock = $this->getMock(NodeImage::class, [ 'getFilefromTitle' ], [ $xmlObj, $params ]);
$mock = $this->getMock(NodeMedia::class, [ 'getFilefromTitle' ], [ $xmlObj, $params ]);
$mock->expects( $this->any( ))
->method( 'getFilefromTitle' )
->willReturn( $fileMock );
->willReturn( $videoMock );
$this->assertEquals( $expected, $mock->getData() );
}
@ -276,26 +282,90 @@ class NodeImageTest extends MediaWikiTestCase {
public function videoProvider() {
return [
[
'<image source="img" />',
[ 'img' => 'test.jpg' ],
'<media source="media" />',
[ 'media' => 'test.webm' ],
[
[
'url' => 'http://test.url',
'name' => 'Test.jpg',
'key' => 'Test.jpg',
'alt' => 'Test.jpg',
'caption' => null,
'isVideo' => true
'name' => 'Test.webm',
'alt' => 'Test.webm',
'caption' => null
]
]
],
[
'<media source="media" video="false" />',
[ 'media' => 'test.webm' ],
[ [ ] ]
]
];
}
/**
* @dataProvider audioProvider
* @param $markup
* @param $params
* @param $expected
* @throws PortableInfobox\Parser\XmlMarkupParseErrorException
*/
public function testAudio( $markup, $params, $expected ) {
$audioMock = new AudioMock();
$xmlObj = PortableInfobox\Parser\XmlParser::parseXmlString( $markup );
$mock = $this->getMock(NodeMedia::class, [ 'getFilefromTitle' ], [ $xmlObj, $params ]);
$mock->expects( $this->any( ))
->method( 'getFilefromTitle' )
->willReturn( $audioMock );
$this->assertEquals( $expected, $mock->getData() );
}
public function audioProvider() {
return [
[
'<media source="media" />',
[ 'media' => 'test.ogg' ],
[
[
'url' => 'http://test.url',
'name' => 'Test.ogg',
'alt' => 'Test.ogg',
'caption' => null
]
]
],
[
'<media source="media" audio="false" />',
[ 'media' => 'test.ogg' ],
[ [ ] ]
]
];
}
}
class FileMock {
class ImageMock {
public function getMediaType() {
return "VIDEO";
return MEDIATYPE_BITMAP;
}
public function getUrl() {
return '';
}
}
class VideoMock {
public function getMediaType() {
return MEDIATYPE_VIDEO;
}
public function getUrl() {
return 'http://test.url';
}
}
class AudioMock {
public function getMediaType() {
return MEDIATYPE_AUDIO;
}
public function getUrl() {
@ -305,7 +375,7 @@ class FileMock {
class GalleryMock {
private $images;
public function __construct( Array $images = [] ) {
public function __construct( array $images = [] ) {
$this->images = $images;
}