Skip to content

Commit 055adf3

Browse files
authored
Merge pull request #84 from magento-trigger/MAGETWO-87081-video
[Team 3] Video Enhancements and Make frontend rendering extensible
2 parents a8a307f + e7a308b commit 055adf3

File tree

46 files changed

+1359
-407
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

46 files changed

+1359
-407
lines changed
Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
<?php
2+
/**
3+
* Copyright © Magento, Inc. All rights reserved.
4+
* See COPYING.txt for license details.
5+
*/
6+
7+
declare(strict_types=1);
8+
9+
namespace Magento\PageBuilder\Block;
10+
11+
use Magento\Framework\View\Element\Template;
12+
13+
/**
14+
* Class WidgetInitializer provides configuration for content types widgets need to be loaded on frontend
15+
* @api
16+
*/
17+
class WidgetInitializer extends Template
18+
{
19+
/**
20+
* @var \Magento\Framework\Serialize\Serializer\Json
21+
*/
22+
private $jsonSerializer;
23+
24+
/**
25+
* WidgetInitializer constructor.
26+
* @param Template\Context $context
27+
* @param \Magento\Framework\Serialize\Serializer\Json $jsonEncoder
28+
* @param array $data
29+
*/
30+
public function __construct(
31+
\Magento\Framework\View\Element\Template\Context $context,
32+
\Magento\Framework\Serialize\Serializer\Json $jsonEncoder,
33+
array $data = []
34+
) {
35+
$this->jsonSerializer = $jsonEncoder;
36+
parent::__construct($context, $data);
37+
}
38+
39+
/**
40+
* Returns config for widgets initializer component.
41+
* @return string
42+
* @api
43+
*/
44+
public function getConfig() : string
45+
{
46+
$widgetsConfig = $this->getData('config');
47+
$resultConfig = [];
48+
foreach ($widgetsConfig as $contentTypeName => $config) {
49+
$selector = sprintf('div[data-role="%s"]', $contentTypeName);
50+
foreach ($config as $item) {
51+
if (!isset($item['component'])) {
52+
continue;
53+
}
54+
if (isset($item['appearance'])) {
55+
$selector .= sprintf('[data-appearance="%s"]', $item['appearance']);
56+
}
57+
$componentConfig = isset($item['config']) ? $item['config'] : '{}';
58+
$resultConfig[$selector] = [$item['component'] => $componentConfig];
59+
}
60+
}
61+
return $this->jsonSerializer->serialize($resultConfig);
62+
}
63+
}

app/code/Magento/PageBuilder/Setup/DataConverter/Renderer/Video.php

Lines changed: 80 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,9 @@
33
* Copyright © Magento, Inc. All rights reserved.
44
* See COPYING.txt for license details.
55
*/
6+
7+
declare(strict_types=1);
8+
69
namespace Magento\PageBuilder\Setup\DataConverter\Renderer;
710

811
use Magento\PageBuilder\Setup\DataConverter\RendererInterface;
@@ -41,65 +44,111 @@ public function render(array $itemData, array $additionalData = [])
4144
throw new \InvalidArgumentException('entityId is missing.');
4245
}
4346
$eavData = $this->eavAttributeLoader->load($itemData['entityId']);
47+
$formData = $itemData['formData'] ?? [];
48+
49+
$rootAttributes = $this->getRootElementAttributes($eavData, $formData);
50+
$wrapperAttributes = $this->getWrapperElementAttributes($eavData, $formData);
51+
$iframeAttributes = $this->getIframeAttributes($eavData);
52+
53+
$rootElementOpenTag = $this->createOpenTagWithAttributes('div', $rootAttributes);
54+
$wrapperElementOpenTag = $this->createOpenTagWithAttributes('div', $wrapperAttributes);
55+
$iframeContainer = $this->createOpenTagWithAttributes('div', ['class' => 'pagebuilder-video-container']);
56+
$iframeOpenTag = $this->createOpenTagWithAttributes('iframe', $iframeAttributes);
57+
58+
return $rootElementOpenTag . $wrapperElementOpenTag . $iframeContainer . $iframeOpenTag
59+
. '</iframe></div></div></div>';
60+
}
4461

45-
$rootElementAttributes = [
62+
/**
63+
* Creates an open tag with the given name and attributes
64+
*
65+
* @param string $elementName
66+
* @param array $attributes
67+
* @return string
68+
*/
69+
private function createOpenTagWithAttributes(string $elementName, array $attributes): string
70+
{
71+
$elementHtml = '<' . $elementName;
72+
foreach ($attributes as $attributeName => $attributeValue) {
73+
$elementHtml .= ' ' . $attributeName . (isset($attributeValue) ? '="' . $attributeValue . '"' : '');
74+
}
75+
return $elementHtml . '>';
76+
}
77+
78+
/**
79+
* Get attributes, style, and classes for the root element
80+
*
81+
* @param array $eavData
82+
* @param array $formData
83+
* @return array
84+
*/
85+
private function getRootElementAttributes(array $eavData, array $formData): array
86+
{
87+
$attributes = [
4688
'data-role' => 'video',
4789
'data-appearance' => 'default',
90+
'class' => $eavData['css_classes'] ?? ''
4891
];
4992

50-
$formData = $itemData['formData'] ?? [];
51-
if (isset($formData['align']) && $formData['align'] !== '') {
52-
$rootElementAttributes['style'] = 'text-align: ' . $formData['align'] . ';';
53-
unset($formData['align']);
54-
}
55-
56-
$iframeElementAttributes = $this->getIframeAttributes($eavData, $formData);
93+
$justifyMap = [
94+
'left' => 'flex-start',
95+
'center' => 'center',
96+
'right' => 'flex-end'
97+
];
5798

58-
$rootElementHtml = '<div';
59-
foreach ($rootElementAttributes as $attributeName => $attributeValue) {
60-
$rootElementHtml .= $attributeValue ? " $attributeName=\"$attributeValue\"" : '';
61-
}
62-
$rootElementHtml .= '><iframe frameborder="0" webkitallowfullscreen mozallowfullscreen allowfullscreen';
63-
foreach ($iframeElementAttributes as $attributeName => $attributeValue) {
64-
$rootElementHtml .= $attributeValue ? " $attributeName=\"$attributeValue\"" : '';
99+
if (isset($formData['align']) && isset($justifyMap[$formData['align']])) {
100+
$attributes['style'] = 'justify-content: ' . $justifyMap[$formData['align']] . ';';
101+
unset($formData['align']);
65102
}
66-
$rootElementHtml .= '></iframe></div>';
67103

68-
return $rootElementHtml;
104+
return $attributes;
69105
}
70106

71107
/**
72-
* Get attributes, style, and classes for the iframe
108+
* Get attributes, style, and classes for the wrapper
73109
*
74110
* @param array $eavData
75111
* @param array $formData
76112
* @return array
77113
*/
78-
private function getIframeAttributes($eavData, $formData)
114+
private function getWrapperElementAttributes(array $eavData, array $formData): array
79115
{
80-
$iframeElementAttributes = [
81-
'class' => $eavData['css_classes'] ?? '',
82-
'src' => $eavData['video_url']
116+
$attributes = [
117+
'class' => 'pagebuilder-video-wrapper'
83118
];
84119

85-
if (isset($eavData['video_width'])) {
86-
$iframeElementAttributes['width'] = $this->normalizeSizeDimension($eavData['video_width']);
87-
}
120+
$style = $this->styleExtractor->extractStyle($formData);
88121

89-
if (isset($eavData['video_height'])) {
90-
$iframeElementAttributes['height'] = $this->normalizeSizeDimension($eavData['video_height']);
122+
if (isset($eavData['video_width'])) {
123+
$style .= 'max-width: ' . $this->normalizeSizeDimension($eavData['video_width']) . ';';
91124
}
92125

93-
$style = $this->styleExtractor->extractStyle($formData);
94126
if ($style) {
95-
$iframeElementAttributes['style'] = $style;
127+
$attributes['style'] = $style;
96128
}
97129

98-
return $iframeElementAttributes;
130+
return $attributes;
131+
}
132+
133+
/**
134+
* Get attributes, style, and classes for the iframe
135+
*
136+
* @param array $eavData
137+
* @return array
138+
*/
139+
private function getIframeAttributes(array $eavData): array
140+
{
141+
$attributes = [
142+
'src' => $eavData['video_url'],
143+
'frameborder' => '0',
144+
'allowfullscreen' => null
145+
];
146+
147+
return $attributes;
99148
}
100149

101150
/**
102-
* Normalize value for width/height
151+
* Normalize value for width
103152
*
104153
* @param string $value
105154
* @return string

app/code/Magento/PageBuilder/Test/Mftf/ActionGroup/VideoActionGroup.xml

Lines changed: 19 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -14,30 +14,44 @@
1414
<argument name="index" defaultValue="1" type="string"/>
1515
<argument name="url" defaultValue=""/>
1616
<argument name="width" defaultValue=""/>
17-
<argument name="height" defaultValue=""/>
1817
</arguments>
1918
<waitForElementVisible selector="{{page.base(index)}}" stepKey="waitForElement"/>
2019
<waitForElementVisible selector="{{page.source(index, url.renderedValue)}}" stepKey="waitForUrl"/>
21-
<waitForElementVisible selector="{{page.height(index, height.value)}}" stepKey="waitForHeight"/>
2220
<waitForElementVisible selector="{{page.width(index, width.value)}}" stepKey="waitForWidth"/>
21+
<comment userInput="Validate Aspect Ratio" stepKey="commentValidateAspectRatio"/>
22+
<executeJS function="return window.calculatedHeight = parseInt(getComputedStyle(document.evaluate(&quot;{{page.iframe(index)}}&quot;,document.body).iterateNext()).width) / 16 * 9" stepKey="calculatedHeight"/>
23+
<executeJS function="return window.actualHeight = parseInt(getComputedStyle(document.evaluate(&quot;{{page.iframe(index)}}&quot;,document.body).iterateNext()).height)" stepKey="actualHeight"/>
24+
<executeJS function="return Math.abs(window.calculatedHeight - window.actualHeight)" stepKey="ratioDifference"/>
25+
<assertLessThanOrEqual stepKey="assertRatio">
26+
<!-- This is 2 because the width and the height may both have fractions that could round by a maximum of 1 for each which makes the maximum 2-->
27+
<expectedResult type="int">2</expectedResult>
28+
<actualResult type="variable">ratioDifference</actualResult>
29+
</assertLessThanOrEqual>
2330
</actionGroup>
24-
<actionGroup name="validateVideoEmptyHeightEmptyWidth">
31+
<actionGroup name="validateVideoEmptyWidth">
2532
<arguments>
2633
<argument name="page" defaultValue=""/>
2734
<argument name="index" defaultValue="1" type="string"/>
2835
<argument name="url" defaultValue=""/>
2936
</arguments>
3037
<waitForElementVisible selector="{{page.base(index)}}" stepKey="waitForElement"/>
3138
<waitForElementVisible selector="{{page.source(index, url.renderedValue)}}" stepKey="waitForUrl"/>
32-
<waitForElementVisible selector="{{page.noHeight(index)}}" stepKey="waitForHeight"/>
3339
<waitForElementVisible selector="{{page.noWidth(index)}}" stepKey="waitForWidth"/>
40+
<comment userInput="Validate Aspect Ratio" stepKey="commentValidateAspectRatio"/>
41+
<executeJS function="return window.calculatedHeight = parseInt(getComputedStyle(document.evaluate(&quot;{{page.iframe(index)}}&quot;,document.body).iterateNext()).width) / 16 * 9" stepKey="calculatedHeight"/>
42+
<executeJS function="return window.actualHeight = parseInt(getComputedStyle(document.evaluate(&quot;{{page.iframe(index)}}&quot;,document.body).iterateNext()).height)" stepKey="actualHeight"/>
43+
<executeJS function="return Math.abs(window.calculatedHeight - window.actualHeight)" stepKey="ratioDifference"/>
44+
<assertLessThanOrEqual stepKey="assertRatio">
45+
<!-- This is 2 because the width and the height may both have fractions that could round by a maximum of 1 for each which makes the maximum 2-->
46+
<expectedResult type="int">2</expectedResult>
47+
<actualResult type="variable">ratioDifference</actualResult>
48+
</assertLessThanOrEqual>
3449
</actionGroup>
3550
<actionGroup name="validateEmptyVideoStage">
3651
<arguments>
3752
<argument name="index" defaultValue="1" type="string"/>
3853
</arguments>
3954
<waitForElementVisible selector="{{VideoOnStage.empty(index)}}" stepKey="waitForEmptyVideo"/>
4055
<waitForElementVisible selector="{{VideoOnStage.icon(index)}}" stepKey="waitForIcon"/>
41-
<waitForElementVisible selector="{{VideoOnStage.text(index, PageBuilderVideoUrl_Default.text)}}" stepKey="waitForText"/>
4256
</actionGroup>
4357
</actionGroups>

app/code/Magento/PageBuilder/Test/Mftf/Data/VideoData.xml

Lines changed: 20 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -10,37 +10,44 @@
1010
xsi:noNamespaceSchemaLocation="../../../../../../../dev/tests/acceptance/vendor/magento/magento2-functional-testing-framework/src/Magento/FunctionalTestingFramework/DataGenerator/etc/dataProfileSchema.xsd">
1111
<!-- URL -->
1212
<entity name="PageBuilderVideoUrl_Default" type="pagebuilder_video_url_property">
13-
<data key="name">Video Embed URL</data>
13+
<data key="name">Video URL</data>
1414
<data key="section">general</data>
1515
<data key="fieldName">video_source</data>
1616
<data key="text">Video</data>
1717
</entity>
1818
<entity name="PageBuilderVideoUrl_YouTube" type="pagebuilder_video_url_property">
19-
<data key="name">Video Embed URL</data>
19+
<data key="name">Video URL</data>
2020
<data key="section">general</data>
2121
<data key="fieldName">video_source</data>
2222
<data key="value">https://www.youtube.com/embed/slOtnjsbff0</data>
2323
<data key="renderedValue">https://www.youtube.com/embed/slOtnjsbff0</data>
2424
</entity>
25+
<entity name="PageBuilder_InvalidVideoURL_Text" type="pagebuilder_video_url_property">
26+
<data key="name">Video URL</data>
27+
<data key="section">general</data>
28+
<data key="fieldName">video_source</data>
29+
<data key="value">Test</data>
30+
<data key="errorMessage">Please enter a valid video URL.</data>
31+
</entity>
32+
<entity name="PageBuilder_InvalidVideoURL_HTML" type="pagebuilder_video_url_property">
33+
<data key="name">Video URL</data>
34+
<data key="section">general</data>
35+
<data key="fieldName">video_source</data>
36+
<data key="value">&lt;iframe width=&quot;1280&quot; height=&quot;720&quot; src=&quot;https://www.youtube.com/embed/bLXEUP6vKEk"&gt;&lt;/iframe&gt;</data>
37+
<data key="errorMessage">Please enter a valid video URL.</data>
38+
</entity>
2539
<entity name="PageBuilderVideoUrl_NonEmbedded" type="pagebuilder_video_url_property">
26-
<data key="name">Video Embed URL</data>
40+
<data key="name">Video URL</data>
2741
<data key="section">general</data>
2842
<data key="fieldName">video_source</data>
2943
<data key="value">https://www.youtube.com/watch?v=slOtnjsbff0</data>
3044
<data key="renderedValue">https://www.youtube.com/embed/slOtnjsbff0</data>
3145
</entity>
3246
<!-- Width -->
3347
<entity name="PageBuilderVideoWidth_500" type="pagebuilder_video_width_property">
34-
<data key="name">Width</data>
35-
<data key="section">general</data>
36-
<data key="fieldName">width</data>
37-
<data key="value">500px</data>
38-
</entity>
39-
<!-- Height -->
40-
<entity name="PageBuilderVideoHeight_200" type="pagebuilder_video_height_property">
41-
<data key="name">Height</data>
48+
<data key="name">Maximum Width</data>
4249
<data key="section">general</data>
43-
<data key="fieldName">height</data>
44-
<data key="value">200px</data>
50+
<data key="fieldName">max_width</data>
51+
<data key="value">500</data>
4552
</entity>
4653
</entities>

0 commit comments

Comments
 (0)