Skip to content

Commit 494b08f

Browse files
authored
Merge branch 'develop' into 421_empty-border-radius-fix
2 parents ee498be + aa71a04 commit 494b08f

File tree

15 files changed

+311
-57
lines changed

15 files changed

+311
-57
lines changed

app/code/Magento/PageBuilder/Model/Filter/Template.php

Lines changed: 98 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -7,47 +7,65 @@
77

88
namespace Magento\PageBuilder\Model\Filter;
99

10+
use DOMDocument;
11+
use DOMElement;
12+
use DOMException;
13+
use DOMNode;
14+
use DOMXPath;
15+
use Exception;
16+
use Magento\Framework\Exception\LocalizedException;
17+
use Magento\Framework\Math\Random;
18+
use Magento\Framework\Serialize\Serializer\Json;
19+
use Magento\Framework\View\ConfigInterface;
20+
use Magento\PageBuilder\Plugin\Filter\TemplatePlugin;
21+
use Psr\Log\LoggerInterface;
22+
1023
/**
1124
* Specific template filters for Page Builder content
1225
*/
1326
class Template
1427
{
1528
/**
16-
* @var \Magento\Framework\View\ConfigInterface
29+
* @var ConfigInterface
1730
*/
1831
private $viewConfig;
1932

2033
/**
21-
* @var \Psr\Log\LoggerInterface
34+
* @var LoggerInterface
2235
*/
2336
private $logger;
2437

2538
/**
26-
* @var \DOMDocument
39+
* @var DOMDocument
2740
*/
2841
private $domDocument;
2942

3043
/**
31-
* @var \Magento\Framework\Math\Random
44+
* @var Random
3245
*/
3346
private $mathRandom;
3447

3548
/**
36-
* @var \Magento\Framework\Serialize\Serializer\Json
49+
* @var Json
3750
*/
3851
private $json;
3952

4053
/**
41-
* @param \Psr\Log\LoggerInterface $logger
42-
* @param \Magento\Framework\View\ConfigInterface $viewConfig
43-
* @param \Magento\Framework\Math\Random $mathRandom
44-
* @param \Magento\Framework\Serialize\Serializer\Json $json
54+
* @var array
55+
*/
56+
private $scripts;
57+
58+
/**
59+
* @param LoggerInterface $logger
60+
* @param ConfigInterface $viewConfig
61+
* @param Random $mathRandom
62+
* @param Json $json
4563
*/
4664
public function __construct(
47-
\Psr\Log\LoggerInterface $logger,
48-
\Magento\Framework\View\ConfigInterface $viewConfig,
49-
\Magento\Framework\Math\Random $mathRandom,
50-
\Magento\Framework\Serialize\Serializer\Json $json
65+
LoggerInterface $logger,
66+
ConfigInterface $viewConfig,
67+
Random $mathRandom,
68+
Json $json
5169
) {
5270
$this->logger = $logger;
5371
$this->viewConfig = $viewConfig;
@@ -59,22 +77,22 @@ public function __construct(
5977
* After filter of template data apply transformations
6078
*
6179
* @param string $result
62-
*
6380
* @return string
6481
* @SuppressWarnings(PHPMD.UnusedFormalParameter)
6582
*/
6683
public function filter(string $result) : string
6784
{
6885
$this->domDocument = false;
86+
$this->scripts = [];
6987

7088
// Validate if the filtered result requires background image processing
71-
if (preg_match(\Magento\PageBuilder\Plugin\Filter\TemplatePlugin::BACKGROUND_IMAGE_PATTERN, $result)) {
89+
if (preg_match(TemplatePlugin::BACKGROUND_IMAGE_PATTERN, $result)) {
7290
$document = $this->getDomDocument($result);
7391
$this->generateBackgroundImageStyles($document);
7492
}
7593

7694
// Process any HTML content types, they need to be decoded on the front-end
77-
if (preg_match(\Magento\PageBuilder\Plugin\Filter\TemplatePlugin::HTML_CONTENT_TYPE_PATTERN, $result)) {
95+
if (preg_match(TemplatePlugin::HTML_CONTENT_TYPE_PATTERN, $result)) {
7896
$document = $this->getDomDocument($result);
7997
$uniqueNodeNameToDecodedOuterHtmlMap = $this->generateDecodedHtmlPlaceholderMappingInDocument($document);
8098
}
@@ -112,6 +130,8 @@ function ($matches) {
112130

113131
$result = $docHtml;
114132
}
133+
134+
$result = $this->unmaskScriptTags($result);
115135
}
116136

117137
return $result;
@@ -122,9 +142,9 @@ function ($matches) {
122142
*
123143
* @param string $html
124144
*
125-
* @return \DOMDocument
145+
* @return DOMDocument
126146
*/
127-
private function getDomDocument(string $html) : \DOMDocument
147+
private function getDomDocument(string $html) : DOMDocument
128148
{
129149
if (!$this->domDocument) {
130150
$this->domDocument = $this->createDomDocument($html);
@@ -138,14 +158,16 @@ private function getDomDocument(string $html) : \DOMDocument
138158
*
139159
* @param string $html
140160
*
141-
* @return \DOMDocument
161+
* @return DOMDocument
142162
*/
143-
private function createDomDocument(string $html) : \DOMDocument
163+
private function createDomDocument(string $html) : DOMDocument
144164
{
145-
$domDocument = new \DOMDocument('1.0', 'UTF-8');
165+
$html = $this->maskScriptTags($html);
166+
167+
$domDocument = new DOMDocument('1.0', 'UTF-8');
146168
set_error_handler(
147169
function ($errorNumber, $errorString) {
148-
throw new \DOMException($errorString, $errorNumber);
170+
throw new DOMException($errorString, $errorNumber);
149171
}
150172
);
151173
$string = mb_convert_encoding($html, 'HTML-ENTITIES', 'UTF-8');
@@ -155,7 +177,7 @@ function ($errorNumber, $errorString) {
155177
'<html><body>' . $string . '</body></html>'
156178
);
157179
libxml_clear_errors();
158-
} catch (\Exception $e) {
180+
} catch (Exception $e) {
159181
restore_error_handler();
160182
$this->logger->critical($e);
161183
}
@@ -167,16 +189,16 @@ function ($errorNumber, $errorString) {
167189
/**
168190
* Convert encoded HTML content types to placeholders and generate decoded outer html map for future replacement
169191
*
170-
* @param \DOMDocument $document
192+
* @param DOMDocument $document
171193
* @return array
172-
* @throws \Magento\Framework\Exception\LocalizedException
194+
* @throws LocalizedException
173195
*/
174-
private function generateDecodedHtmlPlaceholderMappingInDocument(\DOMDocument $document): array
196+
private function generateDecodedHtmlPlaceholderMappingInDocument(DOMDocument $document): array
175197
{
176-
$xpath = new \DOMXPath($document);
198+
$xpath = new DOMXPath($document);
177199

178200
// construct xpath query to fetch top-level ancestor html content type nodes
179-
/** @var $htmlContentTypeNodes \DOMNode[] */
201+
/** @var $htmlContentTypeNodes DOMNode[] */
180202
$htmlContentTypeNodes = $xpath->query(
181203
'//*[@data-content-type="html" and not(@data-decoded="true")]' .
182204
'[not(ancestor::*[@data-content-type="html"])]'
@@ -221,7 +243,7 @@ private function generateDecodedHtmlPlaceholderMappingInDocument(\DOMDocument $d
221243
// by the dom library
222244
$uniqueNodeName = $this->mathRandom->getRandomString(32, $this->mathRandom::CHARS_LOWERS);
223245

224-
$uniqueNode = new \DOMElement($uniqueNodeName);
246+
$uniqueNode = new DOMElement($uniqueNodeName);
225247
$htmlContentTypeNode->parentNode->replaceChild($uniqueNode, $htmlContentTypeNode);
226248

227249
$uniqueNodeNameToDecodedOuterHtmlMap[$uniqueNodeName] = $decodedOuterHtml;
@@ -233,14 +255,14 @@ private function generateDecodedHtmlPlaceholderMappingInDocument(\DOMDocument $d
233255
/**
234256
* Generate the CSS for any background images on the page
235257
*
236-
* @param \DOMDocument $document
258+
* @param DOMDocument $document
237259
*/
238-
private function generateBackgroundImageStyles(\DOMDocument $document) : void
260+
private function generateBackgroundImageStyles(DOMDocument $document) : void
239261
{
240-
$xpath = new \DOMXPath($document);
262+
$xpath = new DOMXPath($document);
241263
$nodes = $xpath->query('//*[@data-background-images]');
242264
foreach ($nodes as $node) {
243-
/* @var \DOMElement $node */
265+
/* @var DOMElement $node */
244266
$backgroundImages = $node->attributes->getNamedItem('data-background-images');
245267
if ($backgroundImages->nodeValue !== '') {
246268
$elementClass = uniqid('background-image-');
@@ -337,4 +359,47 @@ private function getMediaQuery(string $view) : ?string
337359
}
338360
return null;
339361
}
362+
363+
/**
364+
* Masks "x-magento-template" script tags in html content before loading it into DOM parser
365+
*
366+
* DOMDocument::loadHTML() will remove any closing tag inside script tag and will result in broken html template
367+
*
368+
* @param string $content
369+
* @return string
370+
* @see https://bugs.php.net/bug.php?id=52012
371+
*/
372+
private function maskScriptTags(string $content): string
373+
{
374+
$tag = 'script';
375+
$content = preg_replace_callback(
376+
sprintf('#<%1$s[^>]*type="text/x-magento-template\"[^>]*>.*?</%1$s>#is', $tag),
377+
function ($matches) {
378+
$key = $this->mathRandom->getRandomString(32, $this->mathRandom::CHARS_LOWERS);
379+
$this->scripts[$key] = $matches[0];
380+
return '<' . $key . '>' . '</' . $key . '>';
381+
},
382+
$content
383+
);
384+
return $content;
385+
}
386+
387+
/**
388+
* Replaces masked "x-magento-template" script tags with their corresponding content
389+
*
390+
* @param string $content
391+
* @return string
392+
* @see maskScriptTags()
393+
*/
394+
private function unmaskScriptTags(string $content): string
395+
{
396+
foreach ($this->scripts as $key => $script) {
397+
$content = str_replace(
398+
'<' . $key . '>' . '</' . $key . '>',
399+
$script,
400+
$content
401+
);
402+
}
403+
return $content;
404+
}
340405
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<!--
3+
/**
4+
* Copyright © Magento, Inc. All rights reserved.
5+
* See COPYING.txt for license details.
6+
*/
7+
-->
8+
<actionGroups xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
9+
xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/actionGroupSchema.xsd">
10+
<actionGroup name="AddPageLinkWidgetToTinyMCEWithAnchorAndTitleActionGroup" extends="addPageLinkWidgetToTinyMCE">
11+
<arguments>
12+
<argument name="anchor" defaultValue="" type="string"/>
13+
<argument name="title" defaultValue="" type="string"/>
14+
</arguments>
15+
<comment userInput="Insert anchor and title text" stepKey="commentAddAnchorAndTitleText" after="waitForLoadingMaskToDisappear2"/>
16+
<waitForElementVisible selector="{{WidgetSection.InputAnchorCustomText}}" stepKey="waitForInputAnchorCustomText" after="commentAddAnchorAndTitleText"/>
17+
<fillField selector="{{WidgetSection.InputAnchorCustomText}}" userInput="{{anchor}}" stepKey="insertTextToDisplay" after="waitForInputAnchorCustomText" />
18+
<waitForElementVisible selector="{{WidgetSection.InputAnchorCustomTitle}}" stepKey="waitForInputAnchorCustomTitle" after="insertTextToDisplay"/>
19+
<fillField selector="{{WidgetSection.InputAnchorCustomTitle}}" userInput="{{title}}" stepKey="insertTitle" after="waitForInputAnchorCustomTitle"/>
20+
<waitForElementVisible selector="{{TinyMCESection.InsertWidgetIcon}}" stepKey="waitForInsertWidget1" after="waitForInsertWidgetModalToClose"/>
21+
<click selector="{{TinyMCESection.InsertWidgetIcon}}" stepKey="clickAddWidgetBtn"/>
22+
</actionGroup>
23+
</actionGroups>

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

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,10 @@
3939
<data key="stageValue">{{widget type=&quot;Magento\Cms\Block\Widget\Page\Link&quot; template=&quot;widget/link/link_block.phtml&quot; page_id=</data>
4040
<data key="stageValueEncoded">e3t3aWRnZXQgdHlwZT0iTWFnZW50b1xDbXNcQmxvY2tcV2lkZ2V0XFBhZ2VcTGluayIgdGVtcGxhdGU9IndpZGdldC9saW5rL2xpbmtfYmxvY2sucGh0bWwiIHBhZ2VfaWQ9</data>
4141
</entity>
42+
<entity name="TinyMCEWidgetCMSPageLinkWithAnchorAndTitle" extends="TinyMCEWidgetCMSPageLink" type="pagebuilder_text_widget_property">
43+
<data key="anchorText">Piiramatult kõnesid ja SMSe Eestis ja ELi rändluses</data>
44+
<data key="title">Piiramatult kõnesid ja SMSe Eestis ja ELi rändluses</data>
45+
</entity>
4246
<entity name="PageBuilderTextArea_WidgetCMSPageLink" type="pagebuilder_text_widget_property">
4347
<data key="widgetType">Magento\Cms\Block\Widget\Page\Link</data>
4448
<data key="editPanelValue">{{widget type=&quot;Magento\\Cms\\Block\\Widget\\Page\\Link&quot; template=&quot;widget/link/link_block.phtml&quot; page_id=</data>

app/code/Magento/PageBuilder/Test/Mftf/Test/AdminPageBuilderSlideItemCommonTest/SlideItemMoveSlideItemsToRearrangeTest.xml

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -101,13 +101,9 @@
101101
<seeElement selector="{{SlideOnBackend.messageContent('2', PageBuilderSlideItemContent_Slide2.value)}}" stepKey="seeSlide2ContentAfterSave"/>
102102
<!-- Change Slide Order -->
103103
<comment userInput="Change Slide Order" stepKey="commentSortingSlides"/>
104-
<executeJS function="return document.querySelectorAll('{{SliderOnStage.slideNavigationDragHandle}}')[0].clientWidth / 4" stepKey="xCoordinateToMoveTo"/>
105-
<comment userInput="xCoordinateToMoveTo: $xCoordinateToMoveTo" stepKey="commentXCoordinate"/>
106-
<executeJS function="return document.querySelectorAll('{{SliderOnStage.slideNavigationDragHandle}}')[0].clientHeight / 2" stepKey="yCoordinateToMoveTo"/>
107-
<comment userInput="yCoordinateToMoveTo: $yCoordinateToMoveTo" stepKey="commentYCoordinate"/>
108104
<click selector="{{SliderOnStage.slideNavigationDot('1', '3')}}" stepKey="clickSlideDot"/>
109105
<waitForPageLoad stepKey="waitForPageLoad2"/>
110-
<dragAndDrop selector1="{{SliderOnStage.slideNavigationDragHandleByIndex('1', '3')}}" selector2="{{SliderOnStage.slideNavigationDot('1', '1')}}" x="$xCoordinateToMoveTo" y="$yCoordinateToMoveTo" stepKey="dragAndDropSlide"/>
106+
<dragAndDrop selector1="{{SliderOnStage.slideNavigationDragHandleByIndex('1', '3')}}" selector2="{{SliderOnStage.slideNavigationDot('1', '1')}}" x="-1" stepKey="dragAndDropSlide"/>
111107
<waitForPageLoad stepKey="waitForDragAndDrop"/>
112108
<!-- Validate Stage After Sorting -->
113109
<comment userInput="Validate Stage After Sorting" stepKey="commentValidateStage2"/>

app/code/Magento/PageBuilder/Test/Mftf/Test/AdminPageBuilderTemplateTests/PageBuilderApplyTemplatesPermission.xml

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,9 +19,6 @@
1919
<group value="pagebuilder"/>
2020
<group value="pagebuilder-templates"/>
2121
<group value="pagebuilder-templates-permissions"/>
22-
<skip>
23-
<issueId value="MQE-2160"/>
24-
</skip>
2522
</annotations>
2623
<before>
2724
<createData entity="_emptyCmsPage" stepKey="createCMSPage"/>

app/code/Magento/PageBuilder/Test/Mftf/Test/AdminPageBuilderTemplateTests/PageBuilderDeleteTemplatesPermission.xml

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,9 +19,6 @@
1919
<group value="pagebuilder"/>
2020
<group value="pagebuilder-templates"/>
2121
<group value="pagebuilder-templates-permissions"/>
22-
<skip>
23-
<issueId value="MQE-2160"/>
24-
</skip>
2522
</annotations>
2623
<before>
2724
<createData entity="_emptyCmsPage" stepKey="createCMSPage"/>

app/code/Magento/PageBuilder/Test/Mftf/Test/AdminPageBuilderTemplateTests/PageBuilderSaveTemplatesPermission.xml

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,9 +19,6 @@
1919
<group value="pagebuilder"/>
2020
<group value="pagebuilder-templates"/>
2121
<group value="pagebuilder-templates-permissions"/>
22-
<skip>
23-
<issueId value="MQE-2160"/>
24-
</skip>
2522
</annotations>
2623
<before>
2724
<createData entity="_emptyCmsPage" stepKey="createCMSPage"/>

app/code/Magento/PageBuilder/Test/Mftf/Test/AdminPageBuilderTemplateTests/PageBuilderTemplatesPermission.xml

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,9 +19,6 @@
1919
<group value="pagebuilder"/>
2020
<group value="pagebuilder-templates"/>
2121
<group value="pagebuilder-templates-permissions"/>
22-
<skip>
23-
<issueId value="MQE-2160"/>
24-
</skip>
2522
</annotations>
2623
<before>
2724
<createData entity="rolePageBuilderTemplates" stepKey="role1"/>

app/code/Magento/PageBuilder/Test/Mftf/Test/AdminPageBuilderTextTest/TextInlineWidgetEditingTest.xml

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -40,9 +40,10 @@
4040
<argument name="contentType" value="PageBuilderTextContentType"/>
4141
</actionGroup>
4242
<clickWithLeftButton x="10" y="10" selector="{{TextOnStage.tinymce('1')}}" stepKey="focusOnTextEditorArea"/>
43-
<actionGroup ref="addPageLinkWidgetToTinyMCEInline" stepKey="addPageLinkWidgetToTinyMCE">
44-
<argument name="widget" value="TinyMCEWidgetCMSPageLink"/>
43+
<actionGroup ref="AddPageLinkWidgetToTinyMCEWithAnchorAndTitleActionGroup" stepKey="addPageLinkWidgetToTinyMCE">
4544
<argument name="page" value="$$createCMSPageB.identifier$$"/>
45+
<argument name="anchor" value="{{TinyMCEWidgetCMSPageLinkWithAnchorAndTitle.anchorText}}"/>
46+
<argument name="title" value="{{TinyMCEWidgetCMSPageLinkWithAnchorAndTitle.title}}"/>
4647
</actionGroup>
4748
<waitForElementVisible selector="{{TextOnStage.text('1', TinyMCEWidgetCMSPageLink.editPanelValue)}}" stepKey="waitForWidgetStage1"/>
4849
<!--Verify widget edit page-->
@@ -73,6 +74,19 @@
7374
<actionGroup ref="doubleClickWidgetTinyMCE" stepKey="doubleClickWidget">
7475
<argument name="widget" value="TinyMCEWidgetCMSPageLink.editPanelValue"/>
7576
</actionGroup>
77+
<!-- Grab a value from the link-->
78+
<waitForElementVisible selector="{{WidgetSection.InputAnchorCustomText}}" stepKey="waitForInputAnchorCustomText"/>
79+
<grabValueFrom selector="{{WidgetSection.InputAnchorCustomText}}" stepKey="grabAnchorText"/>
80+
<waitForElementVisible selector="{{WidgetSection.InputAnchorCustomTitle}}" stepKey="waitForInputAnchorCustomTitle"/>
81+
<grabValueFrom selector="{{WidgetSection.InputAnchorCustomTitle}}" stepKey="grabTitleText"/>
82+
<assertEquals stepKey="assertAnchorTextCMSWidgetLink" message="pass">
83+
<expectedResult type="string">{{TinyMCEWidgetCMSPageLinkWithAnchorAndTitle.anchorText}}</expectedResult>
84+
<actualResult type="string">{$grabAnchorText}</actualResult>
85+
</assertEquals>
86+
<assertEquals stepKey="assertTitleCMSWidgetLink" message="pass">
87+
<expectedResult type="string">{{TinyMCEWidgetCMSPageLinkWithAnchorAndTitle.title}}</expectedResult>
88+
<actualResult type="string">{$grabTitleText}</actualResult>
89+
</assertEquals>
7690
<actionGroup ref="closeWidgetPanelTinyMCE" stepKey="closeWidgetPanelTinyMCE"/>
7791
<!-- Validate Storefront -->
7892
<comment userInput="Verify Widget Content Type on storefront" stepKey="commentVerifyWidgetOnStorefront"/>

0 commit comments

Comments
 (0)