mirror of
https://github.com/Universal-Omega/PortableInfobox.git
synced 2024-11-15 11:59:56 +00:00
Add audio support; NodeImage -> NodeMedia (#11)
This commit is contained in:
commit
626710caf9
|
@ -6,7 +6,7 @@
|
||||||
],
|
],
|
||||||
"url": "https://github.com/Luqgreg/mediawiki-PortableInfobox",
|
"url": "https://github.com/Luqgreg/mediawiki-PortableInfobox",
|
||||||
"descriptionmsg": "portable-infobox-desc",
|
"descriptionmsg": "portable-infobox-desc",
|
||||||
"version": "0.2.1",
|
"version": "0.2.1-audio_support",
|
||||||
"type": "parserhook",
|
"type": "parserhook",
|
||||||
"license-name": "GPL-3.0-or-later",
|
"license-name": "GPL-3.0-or-later",
|
||||||
"config": {
|
"config": {
|
||||||
|
@ -51,13 +51,16 @@
|
||||||
"PortableInfobox\\Parser\\MediaWikiParserService": "includes/services/Parser/MediaWikiParserService.php",
|
"PortableInfobox\\Parser\\MediaWikiParserService": "includes/services/Parser/MediaWikiParserService.php",
|
||||||
"PortableInfobox\\Parser\\Nodes\\NodeFactory": "includes/services/Parser/Nodes/NodeFactory.class.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\\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\\NodeGroup": "includes/services/Parser/Nodes/NodeGroup.php",
|
||||||
"PortableInfobox\\Parser\\Nodes\\NodeHeader": "includes/services/Parser/Nodes/NodeHeader.php",
|
"PortableInfobox\\Parser\\Nodes\\NodeHeader": "includes/services/Parser/Nodes/NodeHeader.php",
|
||||||
"PortableInfobox\\Parser\\Nodes\\NodeImage": "includes/services/Parser/Nodes/NodeImage.php",
|
"PortableInfobox\\Parser\\Nodes\\NodeImage": "includes/services/Parser/Nodes/NodeImage.php",
|
||||||
"PortableInfobox\\Parser\\Nodes\\NodeInfobox": "includes/services/Parser/Nodes/NodeInfobox.php",
|
"PortableInfobox\\Parser\\Nodes\\NodeMedia": "includes/services/Parser/Nodes/NodeMedia.php",
|
||||||
"PortableInfobox\\Parser\\Nodes\\NodeData": "includes/services/Parser/Nodes/NodeData.php",
|
"PortableInfobox\\Parser\\Nodes\\NodeNavigation": "includes/services/Parser/Nodes/NodeNavigation.php",
|
||||||
"PortableInfobox\\Parser\\Nodes\\NodeTitle": "includes/services/Parser/Nodes/NodeTitle.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\\Parser\\Nodes\\NodeUnimplemented": "includes/services/Parser/Nodes/NodeUnimplemented.php",
|
||||||
"PortableInfobox\\Helpers\\FileNamespaceSanitizeHelper": "includes/services/Helpers/FileNamespaceSanitizeHelper.php",
|
"PortableInfobox\\Helpers\\FileNamespaceSanitizeHelper": "includes/services/Helpers/FileNamespaceSanitizeHelper.php",
|
||||||
"PortableInfobox\\Helpers\\HtmlHelper": "includes/services/Helpers/HtmlHelper.class.php",
|
"PortableInfobox\\Helpers\\HtmlHelper": "includes/services/Helpers/HtmlHelper.class.php",
|
||||||
|
|
|
@ -21,18 +21,20 @@ class PortableInfoboxImagesHelper {
|
||||||
$title = $data['name'];
|
$title = $data['name'];
|
||||||
$file = $this->getFileFromTitle( $title );
|
$file = $this->getFileFromTitle( $title );
|
||||||
|
|
||||||
if (
|
if ( !$file || !$file->exists() ) {
|
||||||
!$file || !$file->exists() ||
|
|
||||||
!in_array( $file->getMediaType(), [ MEDIATYPE_BITMAP, MEDIATYPE_DRAWING, MEDIATYPE_VIDEO ] )
|
|
||||||
) {
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// we don't need failing thumbnail creation for videos
|
$mediatype = $file->getMediaType();
|
||||||
if( $file->getMediaType() == MEDIATYPE_VIDEO ) {
|
$data['isImage'] = in_array( $mediatype, [ MEDIATYPE_BITMAP, MEDIATYPE_DRAWING ] );
|
||||||
return array_merge( $data, [
|
$data['isVideo'] = $mediatype === MEDIATYPE_VIDEO;
|
||||||
'ref' => ++self::$count
|
$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
|
// get dimensions
|
||||||
|
@ -65,7 +67,6 @@ class PortableInfoboxImagesHelper {
|
||||||
}
|
}
|
||||||
|
|
||||||
return array_merge( $data, [
|
return array_merge( $data, [
|
||||||
'ref' => ++self::$count,
|
|
||||||
'height' => intval( $imgTagDimensions['height'] ),
|
'height' => intval( $imgTagDimensions['height'] ),
|
||||||
'width' => intval( $imgTagDimensions['width'] ),
|
'width' => intval( $imgTagDimensions['width'] ),
|
||||||
'thumbnail' => $thumbnail->getUrl(),
|
'thumbnail' => $thumbnail->getUrl(),
|
||||||
|
|
|
@ -13,13 +13,16 @@ class PortableInfoboxTemplateEngine {
|
||||||
'wrapper' => 'PortableInfoboxWrapper.hbs',
|
'wrapper' => 'PortableInfoboxWrapper.hbs',
|
||||||
'title' => 'PortableInfoboxItemTitle.hbs',
|
'title' => 'PortableInfoboxItemTitle.hbs',
|
||||||
'header' => 'PortableInfoboxItemHeader.hbs',
|
'header' => 'PortableInfoboxItemHeader.hbs',
|
||||||
'image' => 'PortableInfoboxItemImage.hbs',
|
'media' => 'PortableInfoboxItemMedia.hbs',
|
||||||
|
'audio' => 'PortableInfoboxItemMedia.hbs',
|
||||||
|
'image' => 'PortableInfoboxItemMedia.hbs',
|
||||||
|
'video' => 'PortableInfoboxItemMedia.hbs',
|
||||||
'data' => 'PortableInfoboxItemData.hbs',
|
'data' => 'PortableInfoboxItemData.hbs',
|
||||||
'group' => 'PortableInfoboxItemGroup.hbs',
|
'group' => 'PortableInfoboxItemGroup.hbs',
|
||||||
'smart-group' => 'PortableInfoboxItemSmartGroup.hbs',
|
'smart-group' => 'PortableInfoboxItemSmartGroup.hbs',
|
||||||
'horizontal-group-content' => 'PortableInfoboxHorizontalGroupContent.hbs',
|
'horizontal-group-content' => 'PortableInfoboxHorizontalGroupContent.hbs',
|
||||||
'navigation' => 'PortableInfoboxItemNavigation.hbs',
|
'navigation' => 'PortableInfoboxItemNavigation.hbs',
|
||||||
'image-collection' => 'PortableInfoboxItemImageCollection.hbs',
|
'media-collection' => 'PortableInfoboxItemMediaCollection.hbs',
|
||||||
'xml-parse-error' => 'PortableInfoboxMarkupDebug.hbs'
|
'xml-parse-error' => 'PortableInfoboxMarkupDebug.hbs'
|
||||||
];
|
];
|
||||||
|
|
||||||
|
|
25
includes/services/Parser/Nodes/NodeAudio.php
Normal file
25
includes/services/Parser/Nodes/NodeAudio.php
Normal 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;
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,209 +1,18 @@
|
||||||
<?php
|
<?php
|
||||||
namespace PortableInfobox\Parser\Nodes;
|
namespace PortableInfobox\Parser\Nodes;
|
||||||
|
|
||||||
use PortableInfobox\Helpers\FileNamespaceSanitizeHelper;
|
class NodeImage extends NodeMedia {
|
||||||
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
|
|
||||||
* @return bool
|
* @return bool
|
||||||
*/
|
*/
|
||||||
private function containsTabberOrGallery( $str ) {
|
protected function allowImage() {
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return true;
|
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
|
* @return bool
|
||||||
*/
|
*/
|
||||||
private function isVideo( $file ) {
|
protected function allowAudio() {
|
||||||
return $file ? $file->getMediaType() === MEDIATYPE_VIDEO : false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
252
includes/services/Parser/Nodes/NodeMedia.php
Normal file
252
includes/services/Parser/Nodes/NodeMedia.php
Normal 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' );
|
||||||
|
}
|
||||||
|
}
|
25
includes/services/Parser/Nodes/NodeVideo.php
Normal file
25
includes/services/Parser/Nodes/NodeVideo.php
Normal 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;
|
||||||
|
}
|
||||||
|
}
|
|
@ -82,8 +82,11 @@ class PortableInfoboxRenderService {
|
||||||
case 'header':
|
case 'header':
|
||||||
$result = $this->renderHeader( $data );
|
$result = $this->renderHeader( $data );
|
||||||
break;
|
break;
|
||||||
|
case 'media':
|
||||||
|
case 'audio':
|
||||||
case 'image':
|
case 'image':
|
||||||
$result = $this->renderImage( $data );
|
case 'video':
|
||||||
|
$result = $this->renderMedia( $data );
|
||||||
break;
|
break;
|
||||||
case 'title':
|
case 'title':
|
||||||
$result = $this->renderTitle( $data );
|
$result = $this->renderTitle( $data );
|
||||||
|
@ -104,7 +107,7 @@ class PortableInfoboxRenderService {
|
||||||
* @return string - group HTML markup
|
* @return string - group HTML markup
|
||||||
*/
|
*/
|
||||||
protected function renderGroup( $groupData ) {
|
protected function renderGroup( $groupData ) {
|
||||||
$cssClasses = [ ];
|
$cssClasses = [];
|
||||||
$groupHTMLContent = '';
|
$groupHTMLContent = '';
|
||||||
$children = $groupData['value'];
|
$children = $groupData['value'];
|
||||||
$layout = $groupData['layout'];
|
$layout = $groupData['layout'];
|
||||||
|
@ -140,15 +143,13 @@ class PortableInfoboxRenderService {
|
||||||
* @param $data
|
* @param $data
|
||||||
* @return string
|
* @return string
|
||||||
*/
|
*/
|
||||||
protected function renderImage( $data ) {
|
protected function renderMedia( $data ) {
|
||||||
$helper = $this->getImageHelper();
|
$helper = $this->getImageHelper();
|
||||||
|
|
||||||
$data = $this->filterImageData( $data );
|
$images = [];
|
||||||
$images = [ ];
|
|
||||||
|
|
||||||
foreach ( $data as $dataItem ) {
|
foreach ( $data as $dataItem ) {
|
||||||
$extendedItem = $dataItem;
|
$extendedItem = $dataItem;
|
||||||
$extendedItem['context'] = null;
|
|
||||||
$extendedItem = $helper->extendImageData( $extendedItem, $this->imagesWidth, $this->infoboxWidth );
|
$extendedItem = $helper->extendImageData( $extendedItem, $this->imagesWidth, $this->infoboxWidth );
|
||||||
|
|
||||||
if ( !!$extendedItem ) {
|
if ( !!$extendedItem ) {
|
||||||
|
@ -162,11 +163,11 @@ class PortableInfoboxRenderService {
|
||||||
|
|
||||||
if ( count( $images ) === 1 ) {
|
if ( count( $images ) === 1 ) {
|
||||||
$data = $images[0];
|
$data = $images[0];
|
||||||
$templateName = 'image';
|
$templateName = 'media';
|
||||||
} else {
|
} else {
|
||||||
// More than one image means image collection
|
// More than one image means image collection
|
||||||
$data = $helper->extendImageCollectionData( $images );
|
$data = $helper->extendImageCollectionData( $images );
|
||||||
$templateName = 'image-collection';
|
$templateName = 'media-collection';
|
||||||
}
|
}
|
||||||
|
|
||||||
return $this->render( $templateName, $data );
|
return $this->render( $templateName, $data );
|
||||||
|
@ -196,22 +197,6 @@ class PortableInfoboxRenderService {
|
||||||
return $result;
|
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 ) {
|
private function getInlineStyles( $accentColor, $accentColorText ) {
|
||||||
$backgroundColor = empty( $accentColor ) ? '' : "background-color:{$accentColor};";
|
$backgroundColor = empty( $accentColor ) ? '' : "background-color:{$accentColor};";
|
||||||
$color = empty( $accentColorText ) ? '' : "color:{$accentColorText};";
|
$color = empty( $accentColorText ) ? '' : "color:{$accentColorText};";
|
||||||
|
@ -221,8 +206,8 @@ class PortableInfoboxRenderService {
|
||||||
|
|
||||||
private function createHorizontalGroupData( $groupData ) {
|
private function createHorizontalGroupData( $groupData ) {
|
||||||
$horizontalGroupData = [
|
$horizontalGroupData = [
|
||||||
'labels' => [ ],
|
'labels' => [],
|
||||||
'values' => [ ],
|
'values' => [],
|
||||||
'renderLabels' => false
|
'renderLabels' => false
|
||||||
];
|
];
|
||||||
|
|
||||||
|
@ -246,9 +231,9 @@ class PortableInfoboxRenderService {
|
||||||
}
|
}
|
||||||
|
|
||||||
private function createSmartGroups( $groupData, $rowCapacity ) {
|
private function createSmartGroups( $groupData, $rowCapacity ) {
|
||||||
$result = [ ];
|
$result = [];
|
||||||
$rowSpan = 0;
|
$rowSpan = 0;
|
||||||
$rowItems = [ ];
|
$rowItems = [];
|
||||||
|
|
||||||
foreach ( $groupData as $item ) {
|
foreach ( $groupData as $item ) {
|
||||||
$data = $item['data'];
|
$data = $item['data'];
|
||||||
|
@ -258,7 +243,7 @@ class PortableInfoboxRenderService {
|
||||||
if ( !empty( $rowItems ) && $rowSpan + $data['span'] > $rowCapacity ) {
|
if ( !empty( $rowItems ) && $rowSpan + $data['span'] > $rowCapacity ) {
|
||||||
$result[] = $this->createSmartGroupItem( $rowItems, $rowSpan );
|
$result[] = $this->createSmartGroupItem( $rowItems, $rowSpan );
|
||||||
$rowSpan = 0;
|
$rowSpan = 0;
|
||||||
$rowItems = [ ];
|
$rowItems = [];
|
||||||
}
|
}
|
||||||
$rowSpan += $data['span'];
|
$rowSpan += $data['span'];
|
||||||
$rowItems[] = $item;
|
$rowItems[] = $item;
|
||||||
|
@ -298,6 +283,6 @@ class PortableInfoboxRenderService {
|
||||||
$result['values'][] = [ 'value' => $item['data']['value'], 'inlineStyles' => $styles ];
|
$result['values'][] = [ 'value' => $item['data']['value'], 'inlineStyles' => $styles ];
|
||||||
|
|
||||||
return $result;
|
return $result;
|
||||||
}, [ 'labels' => [ ], 'values' => [ ], 'renderLabels' => false ] );
|
}, [ 'labels' => [], 'values' => [], 'renderLabels' => false ] );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,14 +1,14 @@
|
||||||
(function (window, $) {
|
(function (window, $) {
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
var ImageCollection = {
|
var MediaCollection = {
|
||||||
init: function($content) {
|
init: function($content) {
|
||||||
var $imageCollections = $content.find('.pi-image-collection');
|
var $mediaCollections = $content.find('.pi-media-collection');
|
||||||
|
|
||||||
$imageCollections.each( function( index ) {
|
$mediaCollections.each( function( index ) {
|
||||||
var $collection = $imageCollections.eq(index),
|
var $collection = $mediaCollections.eq(index),
|
||||||
$tabs = $collection.find('ul.pi-image-collection-tabs li'),
|
$tabs = $collection.find('ul.pi-media-collection-tabs li'),
|
||||||
$tabContent = $collection.find('.pi-image-collection-tab-content');
|
$tabContent = $collection.find('.pi-media-collection-tab-content');
|
||||||
|
|
||||||
$tabs.click( function() {
|
$tabs.click( function() {
|
||||||
var $target = $(this),
|
var $target = $(this),
|
||||||
|
@ -43,7 +43,7 @@
|
||||||
};
|
};
|
||||||
|
|
||||||
mw.hook('wikipage.content').add(function($content) {
|
mw.hook('wikipage.content').add(function($content) {
|
||||||
ImageCollection.init($content);
|
MediaCollection.init($content);
|
||||||
CollapsibleGroup.init($content);
|
CollapsibleGroup.init($content);
|
||||||
});
|
});
|
||||||
})(window, jQuery);
|
})(window, jQuery);
|
||||||
|
|
|
@ -44,7 +44,7 @@
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
line-height: 1.3;
|
line-height: 1.3;
|
||||||
}
|
}
|
||||||
.pi-image {
|
.pi-media {
|
||||||
margin: 0;
|
margin: 0;
|
||||||
max-width: 100%;
|
max-width: 100%;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
|
@ -71,12 +71,7 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.pi {
|
.pi {
|
||||||
&-image {
|
&-media-collection {
|
||||||
&-thumbnail {
|
|
||||||
max-width: var(--pi-width);
|
|
||||||
height: auto;
|
|
||||||
}
|
|
||||||
&-collection {
|
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
margin: 0;
|
margin: 0;
|
||||||
padding-top: 1px;
|
padding-top: 1px;
|
||||||
|
@ -106,19 +101,25 @@
|
||||||
}
|
}
|
||||||
&-tab-content {
|
&-tab-content {
|
||||||
display: none;
|
display: none;
|
||||||
.video-thumbnail {
|
|
||||||
display: block;
|
|
||||||
}
|
|
||||||
&.current {
|
&.current {
|
||||||
display: inherit;
|
display: inherit;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
&-image-thumbnail {
|
||||||
|
max-width: var(--pi-width);
|
||||||
|
height: auto;
|
||||||
}
|
}
|
||||||
&-video-player {
|
&-video-player {
|
||||||
width: var(--pi-width);
|
width: var(--pi-width);
|
||||||
height: auto;
|
height: auto;
|
||||||
}
|
}
|
||||||
|
&-audio-player {
|
||||||
|
width: var(--pi-width);
|
||||||
|
&::-webkit-media-controls-enclosure {
|
||||||
|
border-radius: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
&-caption {
|
&-caption {
|
||||||
-webkit-hyphens: auto;
|
-webkit-hyphens: auto;
|
||||||
-moz-hyphens: auto;
|
-moz-hyphens: auto;
|
||||||
|
|
|
@ -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><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" ></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);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
|
@ -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>
|
|
|
@ -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>
|
|
9
templates/PortableInfoboxItemMedia.hbs
Normal file
9
templates/PortableInfoboxItemMedia.hbs
Normal 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>
|
17
templates/PortableInfoboxItemMediaCollection.hbs
Normal file
17
templates/PortableInfoboxItemMediaCollection.hbs
Normal 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>
|
|
@ -22,170 +22,6 @@ class PortableInfoboxRenderServiceTest extends MediaWikiTestCase {
|
||||||
return $DOM->saveXML();
|
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 $input
|
||||||
* @param $expectedOutput
|
* @param $expectedOutput
|
||||||
|
@ -263,16 +99,13 @@ class PortableInfoboxRenderServiceTest extends MediaWikiTestCase {
|
||||||
[
|
[
|
||||||
'alt' => 'image alt',
|
'alt' => 'image alt',
|
||||||
'url' => 'http://image.jpg',
|
'url' => 'http://image.jpg',
|
||||||
'name' => 'image',
|
'caption' => 'Lorem ipsum dolor'
|
||||||
'key' => 'image',
|
|
||||||
'caption' => 'Lorem ipsum dolor',
|
|
||||||
'isVideo' => false
|
|
||||||
]
|
]
|
||||||
]
|
]
|
||||||
]
|
]
|
||||||
],
|
],
|
||||||
'output' => '<aside class="portable-infobox pi-background">
|
'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">
|
<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"
|
<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"/>
|
width="400" height="200"/>
|
||||||
|
@ -286,14 +119,11 @@ class PortableInfoboxRenderServiceTest extends MediaWikiTestCase {
|
||||||
'alt' => 'image alt',
|
'alt' => 'image alt',
|
||||||
'url' => 'http://image.jpg',
|
'url' => 'http://image.jpg',
|
||||||
'caption' => 'Lorem ipsum dolor',
|
'caption' => 'Lorem ipsum dolor',
|
||||||
'name' => 'image',
|
|
||||||
'key' => 'image',
|
|
||||||
'width' => '400',
|
'width' => '400',
|
||||||
'height' => '200',
|
'height' => '200',
|
||||||
'thumbnail' => 'http://thumbnail.jpg',
|
'thumbnail' => 'http://thumbnail.jpg',
|
||||||
'thumbnail2x' => 'http://thumbnail2x.jpg',
|
'thumbnail2x' => 'http://thumbnail2x.jpg',
|
||||||
'media-type' => 'image',
|
'isImage' => true
|
||||||
'isVideo' => false
|
|
||||||
]
|
]
|
||||||
],
|
],
|
||||||
'accentColor' => '',
|
'accentColor' => '',
|
||||||
|
@ -307,19 +137,15 @@ class PortableInfoboxRenderServiceTest extends MediaWikiTestCase {
|
||||||
[
|
[
|
||||||
'alt' => 'image alt',
|
'alt' => 'image alt',
|
||||||
'url' => 'http://image.jpg',
|
'url' => 'http://image.jpg',
|
||||||
'caption' => 'Lorem ipsum dolor',
|
'caption' => 'Lorem ipsum dolor'
|
||||||
'isVideo' => true,
|
|
||||||
'duration' => '1:20',
|
|
||||||
'name' => 'test',
|
|
||||||
'key' => 'test'
|
|
||||||
]
|
]
|
||||||
]
|
]
|
||||||
]
|
]
|
||||||
],
|
],
|
||||||
'output' => '<aside class="portable-infobox pi-background">
|
'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"
|
<a href="http://image.jpg"
|
||||||
class="image image-thumbnail video video-thumbnail"
|
class="video"
|
||||||
title="image alt">
|
title="image alt">
|
||||||
<video src="http://image.jpg" class="pi-video-player" controls="true" controlsList="nodownload" preload="metadata">image alt</video>
|
<video src="http://image.jpg" class="pi-video-player" controls="true" controlsList="nodownload" preload="metadata">image alt</video>
|
||||||
</a>
|
</a>
|
||||||
|
@ -389,10 +215,7 @@ class PortableInfoboxRenderServiceTest extends MediaWikiTestCase {
|
||||||
'data' => [
|
'data' => [
|
||||||
[
|
[
|
||||||
'alt' => 'image alt',
|
'alt' => 'image alt',
|
||||||
'url' => 'http://image.jpg',
|
'url' => 'http://image.jpg'
|
||||||
'name' => 'image',
|
|
||||||
'key' => 'image',
|
|
||||||
'isVideo' => false
|
|
||||||
]
|
]
|
||||||
]
|
]
|
||||||
],
|
],
|
||||||
|
@ -406,7 +229,7 @@ class PortableInfoboxRenderServiceTest extends MediaWikiTestCase {
|
||||||
],
|
],
|
||||||
'output' => '<aside class="portable-infobox pi-background">
|
'output' => '<aside class="portable-infobox pi-background">
|
||||||
<h2 class="pi-item pi-item-spacing pi-title">Test Title</h2>
|
<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">
|
<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"
|
<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"/>
|
width="400" height="200"/>
|
||||||
|
@ -422,14 +245,11 @@ class PortableInfoboxRenderServiceTest extends MediaWikiTestCase {
|
||||||
'extendImageData' => [
|
'extendImageData' => [
|
||||||
'alt' => 'image alt',
|
'alt' => 'image alt',
|
||||||
'url' => 'http://image.jpg',
|
'url' => 'http://image.jpg',
|
||||||
'name' => 'image',
|
|
||||||
'key' => 'image',
|
|
||||||
'width' => '400',
|
'width' => '400',
|
||||||
'height' => '200',
|
'height' => '200',
|
||||||
'thumbnail' => 'http://thumbnail.jpg',
|
'thumbnail' => 'http://thumbnail.jpg',
|
||||||
'thumbnail2x' => 'http://thumbnail2x.jpg',
|
'thumbnail2x' => 'http://thumbnail2x.jpg',
|
||||||
'media-type' => 'image',
|
'isImage' => true
|
||||||
'isVideo' => false
|
|
||||||
]
|
]
|
||||||
],
|
],
|
||||||
'accentColor' => '',
|
'accentColor' => '',
|
||||||
|
|
|
@ -100,7 +100,10 @@ class PortableInfoboxImagesHelperTest extends MediaWikiTestCase {
|
||||||
'thumbnail' => null,
|
'thumbnail' => null,
|
||||||
'thumbnail2x' => null,
|
'thumbnail2x' => null,
|
||||||
'width' => $resultDimensions[ 'width' ],
|
'width' => $resultDimensions[ 'width' ],
|
||||||
'height' => $resultDimensions[ 'height' ]
|
'height' => $resultDimensions[ 'height' ],
|
||||||
|
'isImage' => true,
|
||||||
|
'isVideo' => false,
|
||||||
|
'isAudio' => false
|
||||||
];
|
];
|
||||||
$thumb = $this->getMockBuilder( 'ThumbnailImage' )
|
$thumb = $this->getMockBuilder( 'ThumbnailImage' )
|
||||||
->disableOriginalConstructor()
|
->disableOriginalConstructor()
|
||||||
|
|
|
@ -1,13 +1,13 @@
|
||||||
<?php
|
<?php
|
||||||
|
|
||||||
use PortableInfobox\Helpers\PortableInfoboxDataBag;
|
use PortableInfobox\Helpers\PortableInfoboxDataBag;
|
||||||
use PortableInfobox\Parser\Nodes\NodeImage;
|
use PortableInfobox\Parser\Nodes\NodeMedia;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @group PortableInfobox
|
* @group PortableInfobox
|
||||||
* @covers PortableInfobox\Parser\Nodes\NodeImage
|
* @covers PortableInfobox\Parser\Nodes\NodeMedia
|
||||||
*/
|
*/
|
||||||
class NodeImageTest extends MediaWikiTestCase {
|
class NodeMediaTest extends MediaWikiTestCase {
|
||||||
|
|
||||||
protected function setUp() {
|
protected function setUp() {
|
||||||
parent::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
|
* @dataProvider galleryDataProvider
|
||||||
* @param $marker
|
* @param $marker
|
||||||
* @param $expected
|
* @param $expected
|
||||||
*/
|
*/
|
||||||
public function testGalleryData( $marker, $expected ) {
|
public function testGalleryData( $marker, $expected ) {
|
||||||
$this->assertEquals( $expected, NodeImage::getGalleryData( $marker ) );
|
$this->assertEquals( $expected, NodeMedia::getGalleryData( $marker ) );
|
||||||
}
|
}
|
||||||
|
|
||||||
public function galleryDataProvider() {
|
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() {
|
public function testTabberData() {
|
||||||
$input = '<div class="tabber"><div class="tabbertab" title="_title_"><p><a><img src="_src_"></a></p></div></div>';
|
$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_',
|
'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
|
* @dataProvider markersProvider
|
||||||
* @param $ext
|
* @param $ext
|
||||||
* @param $value
|
* @param $value
|
||||||
* @param $expected
|
* @param $expected
|
||||||
*/
|
*/
|
||||||
public function testMarkers( $ext, $value, $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() {
|
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
|
* @dataProvider dataProvider
|
||||||
*
|
*
|
||||||
* @param $markup
|
* @param $markup
|
||||||
|
@ -137,44 +137,50 @@ class NodeImageTest extends MediaWikiTestCase {
|
||||||
* @param $expected
|
* @param $expected
|
||||||
*/
|
*/
|
||||||
public function testData( $markup, $params, $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() {
|
public function dataProvider() {
|
||||||
// markup, params, expected
|
// markup, params, expected
|
||||||
return [
|
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' ],
|
[ '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' ],
|
[ '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 ],
|
[ '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' ],
|
[ '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
|
* @dataProvider isEmptyProvider
|
||||||
*
|
*
|
||||||
* @param $markup
|
* @param $markup
|
||||||
|
@ -189,12 +195,12 @@ class NodeImageTest extends MediaWikiTestCase {
|
||||||
|
|
||||||
public function isEmptyProvider() {
|
public function isEmptyProvider() {
|
||||||
return [
|
return [
|
||||||
[ '<image></image>', [ ], true ],
|
[ '<media></media>', [ ], true ],
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @covers PortableInfobox\Parser\Nodes\NodeImage::getSources
|
* @covers PortableInfobox\Parser\Nodes\NodeMedia::getSources
|
||||||
* @dataProvider sourcesProvider
|
* @dataProvider sourcesProvider
|
||||||
*
|
*
|
||||||
* @param $markup
|
* @param $markup
|
||||||
|
@ -209,22 +215,22 @@ class NodeImageTest extends MediaWikiTestCase {
|
||||||
public function sourcesProvider() {
|
public function sourcesProvider() {
|
||||||
return [
|
return [
|
||||||
[
|
[
|
||||||
'<image source="img"/>',
|
'<media source="img"/>',
|
||||||
[ 'img' ]
|
[ 'img' ]
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
'<image source="img"><default>{{{img}}}</default><alt source="img" /></image>',
|
'<media source="img"><default>{{{img}}}</default><alt source="img" /></media>',
|
||||||
[ 'img' ]
|
[ 'img' ]
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
'<image source="img"><alt source="alt"/><caption source="cap"/></image>',
|
'<media source="img"><alt source="alt"/><caption source="cap"/></media>',
|
||||||
[ 'img', 'alt', 'cap' ]
|
[ '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' ] ],
|
[ 'img', 'alt', 'def', 'cap' ] ],
|
||||||
[
|
[
|
||||||
'<image/>',
|
'<media/>',
|
||||||
[ ]
|
[ ]
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
|
@ -244,8 +250,8 @@ class NodeImageTest extends MediaWikiTestCase {
|
||||||
public function metadataProvider() {
|
public function metadataProvider() {
|
||||||
return [
|
return [
|
||||||
[
|
[
|
||||||
'<image source="img"><caption source="cap"><format>Test {{{cap}}} and {{{fcap}}}</format></caption></image>',
|
'<media source="img"><caption source="cap"><format>Test {{{cap}}} and {{{fcap}}}</format></caption></media>',
|
||||||
[ 'type' => 'image', 'sources' => [
|
[ 'type' => 'media', 'sources' => [
|
||||||
'img' => [ 'label' => '', 'primary' => true ],
|
'img' => [ 'label' => '', 'primary' => true ],
|
||||||
'cap' => [ 'label' => '' ],
|
'cap' => [ 'label' => '' ],
|
||||||
'fcap' => [ 'label' => '' ]
|
'fcap' => [ 'label' => '' ]
|
||||||
|
@ -262,13 +268,13 @@ class NodeImageTest extends MediaWikiTestCase {
|
||||||
* @throws PortableInfobox\Parser\XmlMarkupParseErrorException
|
* @throws PortableInfobox\Parser\XmlMarkupParseErrorException
|
||||||
*/
|
*/
|
||||||
public function testVideo( $markup, $params, $expected ) {
|
public function testVideo( $markup, $params, $expected ) {
|
||||||
$fileMock = new FileMock();
|
$videoMock = new VideoMock();
|
||||||
$xmlObj = PortableInfobox\Parser\XmlParser::parseXmlString( $markup );
|
$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( ))
|
$mock->expects( $this->any( ))
|
||||||
->method( 'getFilefromTitle' )
|
->method( 'getFilefromTitle' )
|
||||||
->willReturn( $fileMock );
|
->willReturn( $videoMock );
|
||||||
|
|
||||||
$this->assertEquals( $expected, $mock->getData() );
|
$this->assertEquals( $expected, $mock->getData() );
|
||||||
}
|
}
|
||||||
|
@ -276,26 +282,90 @@ class NodeImageTest extends MediaWikiTestCase {
|
||||||
public function videoProvider() {
|
public function videoProvider() {
|
||||||
return [
|
return [
|
||||||
[
|
[
|
||||||
'<image source="img" />',
|
'<media source="media" />',
|
||||||
[ 'img' => 'test.jpg' ],
|
[ 'media' => 'test.webm' ],
|
||||||
[
|
[
|
||||||
[
|
[
|
||||||
'url' => 'http://test.url',
|
'url' => 'http://test.url',
|
||||||
'name' => 'Test.jpg',
|
'name' => 'Test.webm',
|
||||||
'key' => 'Test.jpg',
|
'alt' => 'Test.webm',
|
||||||
'alt' => 'Test.jpg',
|
'caption' => null
|
||||||
'caption' => null,
|
|
||||||
'isVideo' => true
|
|
||||||
]
|
]
|
||||||
]
|
]
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'<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() {
|
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() {
|
public function getUrl() {
|
||||||
|
@ -305,7 +375,7 @@ class FileMock {
|
||||||
|
|
||||||
class GalleryMock {
|
class GalleryMock {
|
||||||
private $images;
|
private $images;
|
||||||
public function __construct( Array $images = [] ) {
|
public function __construct( array $images = [] ) {
|
||||||
$this->images = $images;
|
$this->images = $images;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue