PortableInfobox/includes/services/PortableInfoboxRenderService.php

352 lines
8.8 KiB
PHP
Raw Permalink Normal View History

<?php
use PortableInfobox\Helpers\PortableInfoboxTemplateEngine;
class PortableInfoboxRenderService {
// keep synced with css variables (--pi-width)
2021-09-10 02:52:19 +00:00
public const DEFAULT_DESKTOP_INFOBOX_WIDTH = 270;
public const DEFAULT_DESKTOP_THUMBNAIL_WIDTH = 350;
2016-12-29 10:28:26 +00:00
protected $templateEngine;
2016-12-28 12:10:57 +00:00
protected $inlineStyles;
public function __construct() {
2018-08-08 09:31:33 +00:00
$this->templateEngine = new PortableInfoboxTemplateEngine();
}
/**
* renders infobox
*
* @param array $infoboxdata
2015-07-02 11:55:39 +00:00
*
2018-08-16 09:25:53 +00:00
* @param string $theme
* @param string $layout
* @param string $accentColor
* @param string $accentColorText
2018-12-23 00:04:00 +00:00
* @param string $type
2019-02-02 22:34:48 +00:00
* @param string $itemName
* @return string - infobox HTML
*/
2018-10-02 07:41:19 +00:00
public function renderInfobox(
2019-02-02 22:34:48 +00:00
array $infoboxdata, $theme, $layout, $accentColor, $accentColorText, $type, $itemName
2018-10-02 07:41:19 +00:00
) {
2016-12-28 12:10:57 +00:00
$this->inlineStyles = $this->getInlineStyles( $accentColor, $accentColorText );
2016-12-29 10:28:26 +00:00
$infoboxHtmlContent = $this->renderChildren( $infoboxdata );
2015-07-02 11:55:39 +00:00
if ( !empty( $infoboxHtmlContent ) ) {
$output = $this->renderItem( 'wrapper', [
'content' => $infoboxHtmlContent,
'theme' => $theme,
2018-12-23 00:04:00 +00:00
'layout' => $layout,
2019-02-02 22:34:48 +00:00
'type' => $type,
'item-name' => $itemName
] );
} else {
$output = '';
}
return $output;
}
/**
* Produces HTML output for item type and data
*
2018-08-16 09:25:53 +00:00
* @param string $type
* @param array $data
* @return string
*/
protected function render( $type, array $data ) {
return $this->templateEngine->render( $type, $data );
}
/**
* renders part of infobox
*
* @param string $type
* @param array $data
*
* @return string - HTML
*/
protected function renderItem( $type, array $data ) {
2016-12-29 10:28:26 +00:00
switch ( $type ) {
case 'group':
$result = $this->renderGroup( $data );
break;
case 'header':
$result = $this->renderHeader( $data );
break;
2018-08-12 09:45:29 +00:00
case 'media':
$result = $this->renderMedia( $data );
2016-12-29 10:28:26 +00:00
break;
case 'title':
$result = $this->renderTitle( $data );
break;
2019-02-24 22:05:18 +00:00
case 'panel':
$result = $this->renderPanel( $data );
break;
case 'section':
$result = '';
break;
2016-12-29 10:28:26 +00:00
default:
$result = $this->render( $type, $data );
break;
}
2016-12-29 10:28:26 +00:00
return $result;
}
/**
* renders group infobox component
*
* @param array $groupData
2015-07-02 11:55:39 +00:00
*
* @return string - group HTML markup
*/
2018-10-02 07:41:19 +00:00
protected function renderGroup( array $groupData ) {
2018-08-12 09:45:29 +00:00
$cssClasses = [];
$groupHTMLContent = '';
2017-01-11 10:27:23 +00:00
$children = $groupData['value'];
2016-12-29 10:28:26 +00:00
$layout = $groupData['layout'];
$collapse = $groupData['collapse'];
2017-01-10 14:24:39 +00:00
$rowItems = $groupData['row-items'];
2017-01-10 14:24:39 +00:00
if ( $rowItems > 0 ) {
2017-01-11 10:27:23 +00:00
$items = $this->createSmartGroups( $children, $rowItems );
2017-01-10 14:24:39 +00:00
$groupHTMLContent .= $this->renderChildren( $items );
} elseif ( $layout === 'horizontal' ) {
$groupHTMLContent .= $this->renderItem(
'horizontal-group-content',
2017-01-11 10:27:23 +00:00
$this->createHorizontalGroupData( $children )
);
} else {
2017-01-11 10:27:23 +00:00
$groupHTMLContent .= $this->renderChildren( $children );
}
2017-01-11 10:27:23 +00:00
if ( $collapse !== null && count( $children ) > 0 && $children[0]['type'] === 'header' ) {
$cssClasses[] = 'pi-collapse';
$cssClasses[] = 'pi-collapse-' . $collapse;
}
return $this->render( 'group', [
'content' => $groupHTMLContent,
2019-02-02 22:34:48 +00:00
'cssClasses' => implode( ' ', $cssClasses ),
'item-name' => $groupData['item-name']
] );
}
/**
* If image element has invalid thumbnail, doesn't render this element at all.
2015-07-02 11:55:39 +00:00
*
2018-08-16 09:25:53 +00:00
* @param array $data
* @return string
*/
2018-10-02 07:41:19 +00:00
protected function renderMedia( array $data ) {
2018-08-22 14:20:49 +00:00
if ( count( $data ) === 0 || !$data[0] ) {
return '';
}
2018-08-22 14:20:49 +00:00
if ( count( $data ) === 1 ) {
$data = $data[0];
2018-08-12 09:45:29 +00:00
$templateName = 'media';
} else {
// More than one image means image collection
$data = [
'images' => $data,
2019-02-03 16:49:06 +00:00
'source' => $data[0]['source'],
'item-name' => $data[0]['item-name']
];
2018-08-12 09:45:29 +00:00
$templateName = 'media-collection';
}
return $this->render( $templateName, $data );
}
2016-12-28 12:10:57 +00:00
2018-10-02 07:41:19 +00:00
protected function renderTitle( array $data ) {
2016-12-29 10:28:26 +00:00
$data['inlineStyles'] = $this->inlineStyles;
return $this->render( 'title', $data );
}
2018-10-02 07:41:19 +00:00
protected function renderHeader( array $data ) {
2016-12-29 10:28:26 +00:00
$data['inlineStyles'] = $this->inlineStyles;
return $this->render( 'header', $data );
}
2018-10-02 07:41:19 +00:00
protected function renderChildren( array $children ) {
2016-12-29 10:28:26 +00:00
$result = '';
foreach ( $children as $child ) {
$type = $child['type'];
if ( $this->templateEngine->isSupportedType( $type ) ) {
$result .= $this->renderItem( $type, $child['data'] );
}
}
return $result;
}
2019-02-24 22:05:18 +00:00
protected function renderPanel( $data, $type = 'panel' ) {
$cssClasses = [];
$sections = [];
$collapse = $data['collapse'];
$header = '';
$shouldShowToggles = false;
foreach ( $data['value'] as $index => $child ) {
switch ( $child['type'] ) {
case 'header':
if ( empty( $header ) ) {
$header = $this->renderHeader( $child['data'] );
}
break;
case 'section':
$sectionData = $this->getSectionData( $child, $index );
// section needs to have content in order to render it
if ( !empty( $sectionData['content'] ) ) {
$sections[] = $sectionData;
if ( !empty( $sectionData['label'] ) ) {
$shouldShowToggles = true;
}
}
break;
default:
// we do not support any other tags than section and header inside panel
break;
}
}
2020-09-29 16:56:06 +00:00
if ( $collapse !== null && count( $sections ) > 0 && !empty( $header ) ) {
2019-02-24 22:05:18 +00:00
$cssClasses[] = 'pi-collapse';
$cssClasses[] = 'pi-collapse-' . $collapse;
}
if ( count( $sections ) > 0 ) {
$sections[0]['active'] = true;
} else {
// do not render empty panel
return '';
}
if ( !$shouldShowToggles ) {
2021-09-10 02:52:19 +00:00
$sections = array_map( static function ( $content ) {
2019-02-24 22:05:18 +00:00
$content['active'] = true;
return $content;
}, $sections );
}
return $this->render( $type, [
'item-name' => $data['item-name'],
'cssClasses' => implode( ' ', $cssClasses ),
'header' => $header,
'sections' => $sections,
'shouldShowToggles' => $shouldShowToggles,
] );
}
private function getSectionData( $section, $index ) {
$content = $this->renderChildren( $section['data']['value'] );
return [
'index' => $index,
'item-name' => $section['data']['item-name'],
'label' => $section['data']['label'],
'content' => !empty( $content ) ? $content : null
];
}
2016-12-28 12:10:57 +00:00
private function getInlineStyles( $accentColor, $accentColorText ) {
$backgroundColor = empty( $accentColor ) ? '' : "background-color:{$accentColor};";
$color = empty( $accentColorText ) ? '' : "color:{$accentColorText};";
2016-12-28 12:36:57 +00:00
return "{$backgroundColor}{$color}";
2016-12-28 12:10:57 +00:00
}
2016-12-29 10:28:26 +00:00
2018-10-02 07:41:19 +00:00
private function createHorizontalGroupData( array $groupData ) {
2016-12-29 10:28:26 +00:00
$horizontalGroupData = [
'data' => [],
2016-12-29 10:28:26 +00:00
'renderLabels' => false
];
foreach ( $groupData as $item ) {
$data = $item['data'];
if ( $item['type'] === 'data' ) {
$horizontalGroupData['data'][] = [
'label' => $data['label'],
'value' => $data['value'],
2019-02-02 22:34:48 +00:00
'source' => $item['data']['source'] ?? "",
'item-name' => $item['data']['item-name']
];
2016-12-29 10:28:26 +00:00
if ( !empty( $data['label'] ) ) {
$horizontalGroupData['renderLabels'] = true;
}
} elseif ( $item['type'] === 'header' ) {
$horizontalGroupData['header'] = $data['value'];
$horizontalGroupData['inlineStyles'] = $this->inlineStyles;
2016-12-29 10:28:26 +00:00
}
}
return $horizontalGroupData;
}
2016-12-29 10:58:27 +00:00
2018-10-02 07:41:19 +00:00
private function createSmartGroups( array $groupData, $rowCapacity ) {
2018-08-12 09:45:29 +00:00
$result = [];
2017-01-11 10:27:23 +00:00
$rowSpan = 0;
2018-08-12 09:45:29 +00:00
$rowItems = [];
2017-01-10 14:24:39 +00:00
foreach ( $groupData as $item ) {
$data = $item['data'];
2018-10-02 07:41:19 +00:00
if ( $item['type'] === 'data' && $data['layout'] !== 'default' ) {
2017-01-10 14:24:39 +00:00
2017-01-12 13:11:46 +00:00
if ( !empty( $rowItems ) && $rowSpan + $data['span'] > $rowCapacity ) {
2017-01-12 11:40:56 +00:00
$result[] = $this->createSmartGroupItem( $rowItems, $rowSpan );
2017-01-11 10:27:23 +00:00
$rowSpan = 0;
2018-08-12 09:45:29 +00:00
$rowItems = [];
2017-01-10 14:24:39 +00:00
}
2017-01-11 10:27:23 +00:00
$rowSpan += $data['span'];
$rowItems[] = $item;
2017-01-10 14:24:39 +00:00
} else {
// smart wrapping works only for data tags
2017-01-11 10:27:23 +00:00
if ( !empty( $rowItems ) ) {
2017-01-12 11:40:56 +00:00
$result[] = $this->createSmartGroupItem( $rowItems, $rowSpan );
2017-01-11 10:27:23 +00:00
$rowSpan = 0;
2018-08-16 09:25:53 +00:00
$rowItems = [];
2017-01-10 14:24:39 +00:00
}
$result[] = $item;
}
}
2017-01-12 11:40:56 +00:00
if ( !empty( $rowItems ) ) {
$result[] = $this->createSmartGroupItem( $rowItems, $rowSpan );
}
2017-01-10 14:24:39 +00:00
2017-01-12 11:40:56 +00:00
return $result;
2017-01-10 14:24:39 +00:00
}
2018-10-02 07:41:19 +00:00
private function createSmartGroupItem( array $rowItems, $rowSpan ) {
2017-01-12 11:40:56 +00:00
return [
'type' => 'smart-group',
2017-01-12 13:11:46 +00:00
'data' => $this->createSmartGroupSections( $rowItems, $rowSpan )
2017-01-12 11:40:56 +00:00
];
}
2018-10-02 07:41:19 +00:00
private function createSmartGroupSections( array $rowItems, $capacity ) {
2021-09-10 02:52:19 +00:00
return array_reduce( $rowItems, static function ( $result, $item ) use ( $capacity ) {
$width = $item['data']['span'] / $capacity * 100;
$styles = "width: {$width}%";
2017-01-12 13:11:46 +00:00
$label = $item['data']['label'] ?? "";
if ( !empty( $label ) ) {
$result['renderLabels'] = true;
2017-01-11 14:04:09 +00:00
}
$result['data'][] = [
'label' => $label,
'value' => $item['data']['value'],
'inlineStyles' => $styles,
2019-02-02 22:34:48 +00:00
'source' => $item['data']['source'] ?? "",
'item-name' => $item['data']['item-name']
];
2017-01-12 13:11:46 +00:00
return $result;
}, [ 'data' => [], 'renderLabels' => false ] );
2017-01-10 14:24:39 +00:00
}
}