Skip to content

Commit ae2cdeb

Browse files
Merge pull request #369 from adobe-commerce-tier-4/PR-10-01-2024
[Support Tier-4 chittima] 10-01-2024 Regular delivery of bugfixes and improvements
2 parents 975aee1 + 9a0d50a commit ae2cdeb

File tree

4 files changed

+207
-7
lines changed

4 files changed

+207
-7
lines changed

app/code/Magento/PageBuilder/Model/Stage/HtmlFilter.php

Lines changed: 31 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -78,17 +78,43 @@ public function filterHtml(string $content): string
7878
);
7979
foreach ($htmlContentTypes as $htmlContentType) {
8080
/* @var \DOMElement $htmlContentType */
81-
$innerHTML = '';
82-
$children = $htmlContentType->childNodes;
83-
foreach ($children as $child) {
84-
$innerHTML .= $child->ownerDocument->saveXML($child);
85-
}
8681
$htmlContentType->setAttribute(
8782
"class",
8883
$htmlContentType->getAttribute("class") . " placeholder-html-code"
8984
);
85+
86+
$innerHTML = $this->getChildrenInnerHtml($htmlContentType);
87+
9088
$htmlContentType->nodeValue = htmlentities($innerHTML);
9189
}
9290
return substr(trim($dom->saveHTML()), 5, -6);
9391
}
92+
93+
/**
94+
* Get inner HTML of element's children
95+
*
96+
* @param \DOMElement $element
97+
* @return string
98+
*/
99+
private function getChildrenInnerHtml(\DOMElement $element): string
100+
{
101+
$innerHTML = '';
102+
$childrenIterator = $element->childNodes->getIterator();
103+
while ($childrenIterator->valid()) {
104+
$child = $childrenIterator->current();
105+
try {
106+
$ownerDocument = $child->ownerDocument;
107+
} catch (\Error $error) {
108+
$ownerDocument = null;
109+
$this->loggerInterface->critical($error->getMessage());
110+
}
111+
if ($ownerDocument === null) {
112+
$childrenIterator->next();
113+
continue;
114+
}
115+
$innerHTML .= $ownerDocument->saveXML($child);
116+
$childrenIterator->next();
117+
}
118+
return $innerHTML;
119+
}
94120
}
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
<?php
2+
/**
3+
* Copyright 2024 Adobe
4+
* All Rights Reserved.
5+
*/
6+
declare(strict_types=1);
7+
8+
namespace Magento\PageBuilder\Test\Unit\Model\Stage;
9+
10+
use Magento\PageBuilder\Model\Stage\HtmlFilter;
11+
use PHPUnit\Framework\MockObject\MockObject;
12+
use PHPUnit\Framework\TestCase;
13+
use Psr\Log\LoggerInterface;
14+
15+
class HtmlFilterTest extends TestCase
16+
{
17+
/**
18+
* @var LoggerInterface|MockObject
19+
*/
20+
private $loggerMock;
21+
22+
/**
23+
* @var HtmlFilter
24+
*/
25+
private $htmlFilter;
26+
27+
protected function setUp(): void
28+
{
29+
$this->loggerMock = $this->createMock(LoggerInterface::class);
30+
$this->htmlFilter = new HtmlFilter($this->loggerMock);
31+
}
32+
33+
public function testFilterHtml()
34+
{
35+
//test for script tag
36+
$inputHtml = '<div><script type="text/x-magento-init">alert("test")</script><p>Content</p></div>';
37+
$expectedOutput = '<div><p>Content</p></div>';
38+
39+
$result = $this->htmlFilter->filterHtml($inputHtml);
40+
$this->assertEquals($expectedOutput, $result);
41+
42+
//test for PB placeholder
43+
$inputHtml = '
44+
<div data-content-type="html" data-appearance="default" data-element="main" class="test">
45+
<div class="block-123">Test</div>
46+
</div>';
47+
$expectedOutput = '
48+
<div data-content-type="html" data-appearance="default" data-element="main" class="test placeholder-html-code">
49+
&lt;div class="block-123"&gt;Test&lt;/div&gt;
50+
</div>';
51+
52+
$result = $this->htmlFilter->filterHtml($inputHtml);
53+
$this->assertEquals($expectedOutput, $result);
54+
}
55+
}

app/code/Magento/PageBuilder/view/adminhtml/web/js/form/provider.js

Lines changed: 37 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,9 @@
55

66
define([
77
'Magento_Ui/js/form/provider',
8-
'Magento_PageBuilder/js/events'
9-
], function (Provider, events) {
8+
'Magento_PageBuilder/js/events',
9+
'jquery'
10+
], function (Provider, events, $) {
1011
'use strict';
1112

1213
return Provider.extend({
@@ -18,8 +19,42 @@ define([
1819
/** @inheritdoc **/
1920
save: function () {
2021
events.trigger('form:' + this.id + ':saveAfter', this.get('data'));
22+
this._refreshSlickOnSave();
2123

2224
return this;
25+
},
26+
27+
/**
28+
* Refresh slick slide of parent window
29+
*
30+
* @private
31+
*/
32+
_refreshSlickOnSave: function () {
33+
let slickObj = $('.slick-list.draggable'),
34+
parentSlick,
35+
currentSettings;
36+
37+
if (slickObj.length === 0) {
38+
return;
39+
}
40+
41+
parentSlick = slickObj.parent();
42+
43+
if (typeof parentSlick.slick !== 'function') {
44+
return;
45+
}
46+
47+
currentSettings = parentSlick.slick('getSlick').options;
48+
49+
if (!currentSettings.infinite) {
50+
return;
51+
}
52+
53+
if (currentSettings.rows > 0) {
54+
parentSlick.slick('slickSetOption', 'rows', 0);
55+
}
56+
57+
parentSlick.slick('refresh');
2358
}
2459
});
2560
});
Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
/**
2+
* Copyright 2024 Adobe
3+
* All Rights Reserved.
4+
*/
5+
6+
define([
7+
'Magento_PageBuilder/js/form/provider',
8+
'Magento_PageBuilder/js/events',
9+
'jquery'
10+
], function (Provider, events, $) {
11+
'use strict';
12+
13+
describe('Magento_PageBuilder/js/form/provider', function () {
14+
let instance;
15+
16+
beforeEach(function () {
17+
instance = new Provider({
18+
id: 'test-form'
19+
});
20+
spyOn(events, 'trigger');
21+
22+
instance.set('data', { key: 'value' });
23+
});
24+
25+
it('should trigger save event after save is called', function () {
26+
instance.save();
27+
expect(events.trigger).toHaveBeenCalledWith('form:' + instance.id + ':saveAfter', instance.get('data'));
28+
});
29+
30+
it('should trigger form saveAfter event and refresh slick if infinite is true', function () {
31+
const slickMock = {
32+
options: { infinite: true, rows: 1},
33+
getSlick: function () {
34+
return { options: this.options };
35+
}
36+
};
37+
38+
const slickListMock = {
39+
length: 1,
40+
parent: jasmine.createSpy('parent').and.returnValue({
41+
slick: jasmine.createSpy('slick').and.returnValue(slickMock)
42+
})
43+
};
44+
45+
spyOn($.fn, 'find').and.returnValue(slickListMock);
46+
47+
const result = instance.save();
48+
49+
expect(events.trigger).toHaveBeenCalledWith('form:' + instance.id + ':saveAfter', instance.get('data'));
50+
expect($.fn.find).toHaveBeenCalledWith('.slick-list.draggable');
51+
expect($.fn.find().parent).toHaveBeenCalled();
52+
expect($.fn.find().parent().slick).toHaveBeenCalledWith('refresh');
53+
expect(result).toBe(instance);
54+
});
55+
56+
it('should not refresh slick if infinite is false', function () {
57+
const slickMockFalse = {
58+
options: { infinite: false },
59+
getSlick: function () {
60+
return { options: this.options };
61+
}
62+
};
63+
64+
spyOn($.fn, 'find').and.returnValue(slickMockFalse);
65+
66+
$.fn.find.and.returnValue({
67+
length: 1,
68+
parent: jasmine.createSpy('parent').and.returnValue({
69+
slick: jasmine.createSpy('slick').and.returnValue(slickMockFalse)
70+
})
71+
});
72+
73+
const result = instance.save();
74+
75+
expect(events.trigger).toHaveBeenCalledWith('form:' + instance.id + ':saveAfter', instance.get('data'));
76+
expect($('.slick-list.draggable').parent().slick.calls.count()).toBe(1);
77+
expect($.fn.find).toHaveBeenCalledWith('.slick-list.draggable');
78+
expect($.fn.find().parent).toHaveBeenCalled();
79+
expect($.fn.find().parent().slick).toHaveBeenCalled();
80+
expect($.fn.find().parent().slick).not.toHaveBeenCalledWith('refresh');
81+
expect(result).toBe(instance);
82+
});
83+
});
84+
});

0 commit comments

Comments
 (0)