Skip to content

Commit 7264ba4

Browse files
authored
Merge pull request #158 from magento-l3/L3-PR-2022-04-19
L3-PR-2022-04-19
2 parents 295c76d + dceef21 commit 7264ba4

File tree

6 files changed

+319
-15
lines changed

6 files changed

+319
-15
lines changed
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="StorefrontClickProductAddToCartValidateAsyncActionGroup">
11+
<arguments>
12+
<argument name="product" type="string"/>
13+
</arguments>
14+
<waitForElementVisible selector="{{ProductsOnStorefront.productImageByProductName(product)}}" stepKey="waitForProductImage"/>
15+
<moveMouseOver selector="{{ProductsOnStorefront.productImageByProductName(product)}}" stepKey="moveMouseOverProduct"/>
16+
<click selector="{{ProductsOnStorefront.productAddToCartByProductName(product)}}" stepKey="clickProductAddToCart"/>
17+
<seeElement selector="{{StorefrontProductActionSection.addToCartButtonTitleIsAdding}}" stepKey="seeAddingButtonLabel"/>
18+
<waitForElementVisible selector="{{StorefrontProductActionSection.addToCartButtonTitleIsAdded}}" stepKey="waitForAddedButtonLabel"/>
19+
<seeElement selector="{{StorefrontProductActionSection.addToCartButtonTitleIsAdded}}" stepKey="seeAddedButtonLabel"/>
20+
<waitForPageLoad stepKey="waitForProductPageToLoad"/>
21+
<see userInput="You added {{product}} to your shopping cart." stepKey="seeAddToCartSuccessMessage"/>
22+
</actionGroup>
23+
</actionGroups>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
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+
<tests xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
9+
xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/testSchema.xsd">
10+
<test name="StorefrontProductCarouselAddToCartShouldNotReloadPage">
11+
<annotations>
12+
<features value="PageBuilder"/>
13+
<stories value="Add to cart from Carousel"/>
14+
<title value="Adding to cart from product widget carousel should not reload page"/>
15+
<description value="Clicking on Add to Cart on product in carousel widget should not reload page, the request should be submitted asynchronously."/>
16+
<severity value="AVERAGE"/>
17+
<useCaseId value="ACP2E-703"/>
18+
<testCaseId value="AC-2853"/>
19+
<group value="pagebuilder"/>
20+
<group value="pagebuilder-cms-page"/>
21+
<group value="pagebuilder-products"/>
22+
<group value="pagebuilder-productsCarousel"/>
23+
</annotations>
24+
<before>
25+
<createData entity="_defaultCategory" stepKey="createCategory"/>
26+
<createData entity="_defaultProduct" stepKey="createProduct">
27+
<requiredEntity createDataKey="createCategory"/>
28+
</createData>
29+
<createData entity="_emptyCmsPage" stepKey="createCMSPage"/>
30+
<actionGroup ref="AdminLoginActionGroup" stepKey="loginAsAdmin"/>
31+
</before>
32+
<after>
33+
<deleteData createDataKey="createCategory" stepKey="deleteCreatedCategory"/>
34+
<deleteData createDataKey="createProduct" stepKey="deleteCreatedProduct"/>
35+
<deleteData createDataKey="createCMSPage" stepKey="deleteCMSPage"/>
36+
<actionGroup ref="AdminLogoutActionGroup" stepKey="logout"/>
37+
</after>
38+
39+
<!-- Open the newly created CMS Page for editing -->
40+
<actionGroup ref="NavigateToCreatedCMSPageActionGroup" stepKey="navigateToCreatedCMSPage">
41+
<argument name="CMSPage" value="$$createCMSPage$$"/>
42+
</actionGroup>
43+
44+
<!-- Add the product widget with Page Builder, set it to carousel mode and assign the product category -->
45+
<actionGroup ref="AdminOpenPageBuilderFromContentPreviewOverlayActionGroup" stepKey="openPageBuilderFullScreen"/>
46+
<actionGroup ref="dragContentTypeToStage" stepKey="dragRowToRootContainer">
47+
<argument name="contentType" value="PageBuilderRowContentType"/>
48+
<argument name="containerTargetType" value="PageBuilderRootContainerContentType"/>
49+
</actionGroup>
50+
<actionGroup ref="expandPageBuilderPanelMenuSection" stepKey="expandMenuSectionAddContent">
51+
<argument name="contentType" value="PageBuilderProductsContentType"/>
52+
</actionGroup>
53+
<actionGroup ref="dragContentTypeToStage" stepKey="dragOntoStage">
54+
<argument name="contentType" value="PageBuilderProductsContentType"/>
55+
</actionGroup>
56+
<actionGroup ref="openPageBuilderEditPanel" stepKey="openEditAfterDrop">
57+
<argument name="contentType" value="PageBuilderProductsContentType"/>
58+
</actionGroup>
59+
<actionGroup ref="chooseVisualSelectOption" stepKey="selectAppearance">
60+
<argument name="property" value="PageBuilderProductsProductCarouselAppearance"/>
61+
</actionGroup>
62+
<actionGroup ref="chooseVisualSelectOption" stepKey="chooseSelectProductsBy">
63+
<argument name="property" value="PageBuilderProductsSelectProductsByCategory"/>
64+
</actionGroup>
65+
<actionGroup ref="selectCategoryFromCategoryDropDown" stepKey="selectCategory">
66+
<argument name="category" value="$$createCategory.name$$"/>
67+
</actionGroup>
68+
<actionGroup ref="saveEditPanelSettings" stepKey="saveEditPanelSettings"/>
69+
<actionGroup ref="exitPageBuilderFullScreen" stepKey="exitPageBuilderFullScreenBeforeSave"/>
70+
71+
<!-- Save the CMS Page -->
72+
<actionGroup ref="SaveCmsPageActionGroup" stepKey="saveCMSPage"/>
73+
74+
<!-- Validate Add to Cart on the storefront -->
75+
<actionGroup ref="NavigateToStorefrontForCreatedPageActionGroup" stepKey="navigateToCMSPageStorefront">
76+
<argument name="page" value="$$createCMSPage.identifier$$"/>
77+
</actionGroup>
78+
<actionGroup ref="StorefrontClickProductAddToCartValidateAsyncActionGroup" stepKey="clickProductAddToCartInProductsCMSPageStorefront">
79+
<argument name="product" value="$$createProduct.name$$"/>
80+
</actionGroup>
81+
</test>
82+
</tests>

app/code/Magento/PageBuilder/view/adminhtml/web/js/content-type/video/converter/attribute/videosrc.js

+53-2
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

app/code/Magento/PageBuilder/view/adminhtml/web/ts/js/content-type/video/converter/attribute/videosrc.ts

+64-1
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,68 @@ import {DataObject} from "../../../../data-store";
88
import {get} from "../../../../utils/object";
99

1010
export default class VideoSrc implements ConverterInterface {
11+
12+
/**
13+
* Parse YouTube parameters from given URL and Autoplay setting from UI
14+
*
15+
* @param url string
16+
* @param data DataObject
17+
* @returns string
18+
* @private
19+
*/
20+
private static parseYoutubeGetParams(url: string, data: DataObject): string {
21+
const acceptableYouTubeParams = [
22+
"rel",
23+
"controls",
24+
"autoplay",
25+
"mute",
26+
"loop",
27+
"playlist",
28+
"cc_lang_pref",
29+
"cc_load_policy",
30+
"color",
31+
"disablekb",
32+
"end",
33+
"fs",
34+
"hl",
35+
"iv_load_policy",
36+
"modestbranding",
37+
"start",
38+
];
39+
40+
const a = document.createElement("a");
41+
a.href = url;
42+
const urlGetParams: {[key: string]: string} = {};
43+
a.search.slice(a.search.indexOf("?") + 1).split("&").map((hash) => {
44+
const [key, val] = hash.split("=");
45+
urlGetParams[key] = decodeURIComponent(val);
46+
});
47+
48+
const filteredGetParams: {[key: string]: string} = {};
49+
for (const param of acceptableYouTubeParams) {
50+
if (urlGetParams.hasOwnProperty(param)) {
51+
filteredGetParams[param] = urlGetParams[param];
52+
}
53+
}
54+
55+
if (data.autoplay === "true") {
56+
filteredGetParams.autoplay = "1";
57+
filteredGetParams.mute = "1";
58+
} else {
59+
delete filteredGetParams.autoplay;
60+
delete filteredGetParams.mute;
61+
}
62+
63+
const processedGetParams = [];
64+
for (const param in filteredGetParams) {
65+
if (filteredGetParams.hasOwnProperty(param)) {
66+
processedGetParams.push(encodeURI(param + "=" + filteredGetParams[param]));
67+
}
68+
}
69+
70+
return processedGetParams.length > 0 ? "?" + processedGetParams.join("&") : "";
71+
}
72+
1173
/**
1274
* Convert value to internal format
1375
*
@@ -16,6 +78,7 @@ export default class VideoSrc implements ConverterInterface {
1678
*/
1779
public fromDom(value: string): string | object {
1880
value = value.replace(/\?autoplay=1&mute=1/g, "");
81+
value = value.replace(/&autoplay=1&mute=1/g, "");
1982
value = value.replace(/\?title=0&byline=0&portrait=0/g, "");
2083
value = value.replace(/&autoplay=1&autopause=0&muted=1/g, "");
2184
return value;
@@ -41,7 +104,7 @@ export default class VideoSrc implements ConverterInterface {
41104

42105
if (youtubeRegExp.test(value)) {
43106
return "https://www.youtube.com/embed/" + youtubeRegExp.exec(value)[1] +
44-
(data.autoplay === "true" ? "?autoplay=1&mute=1" : "");
107+
VideoSrc.parseYoutubeGetParams(value, data);
45108
} else if (vimeoRegExp.test(value)) {
46109
return "https://player.vimeo.com/video/" + vimeoRegExp.exec(value)[3] +
47110
"?title=0&byline=0&portrait=0" + (data.autoplay === "true" ? "&autoplay=1&autopause=0&muted=1" : "");

app/code/Magento/PageBuilder/view/frontend/templates/catalog/product/widget/content/carousel.phtml

+29-12
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,18 @@
66
use Magento\Framework\App\Action\Action;
77

88
// phpcs:disable Magento2.Templates.ThisInTemplate
9+
// phpcs:disable Generic.Files.LineLength.TooLong
910

1011
/** @var \Magento\CatalogWidget\Block\Product\ProductsList $block */
1112
?>
12-
<?php if ($exist = ($block->getProductCollection() && $block->getProductCollection()->getSize())) : ?>
13+
<?php
14+
/**
15+
* Product carousel widget template
16+
*
17+
* @var \Magento\Framework\Escaper $escaper
18+
*/
19+
?>
20+
<?php if ($exist = ($block->getProductCollection() && $block->getProductCollection()->getSize())): ?>
1321
<?php
1422
$type = 'widget-product-carousel';
1523

@@ -23,7 +31,7 @@ use Magento\Framework\App\Action\Action;
2331
?>
2432
<ol class="product-items <?= /* @noEscape */ $type ?>">
2533
<?php $iterator = 1; ?>
26-
<?php foreach ($items as $_item) : ?>
34+
<?php foreach ($items as $_item): ?>
2735
<?= /* @noEscape */ ($iterator++ == 1) ? '<li class="product-item">' : '</li><li class="product-item">' ?>
2836
<div class="product-item-info">
2937
<a href="<?= $block->escapeUrl($block->getProductUrl($_item)) ?>" class="product-item-photo">
@@ -37,20 +45,20 @@ use Magento\Framework\App\Action\Action;
3745
<?= $block->escapeHtml($_item->getName()) ?>
3846
</a>
3947
</strong>
40-
<?php if ($templateType) : ?>
48+
<?php if ($templateType): ?>
4149
<?= $block->getReviewsSummaryHtml($_item, $templateType) ?>
4250
<?php endif; ?>
4351

4452
<?= $block->getProductPriceHtml($_item, $type) ?>
4553

4654
<?= $block->getProductDetailsHtml($_item) ?>
4755

48-
<?php if ($showWishlist || $showCompare || $showCart) : ?>
56+
<?php if ($showWishlist || $showCompare || $showCart): ?>
4957
<div class="product-item-inner">
5058
<div class="product-item-actions">
51-
<?php if ($showCart) : ?>
59+
<?php if ($showCart): ?>
5260
<div class="actions-primary">
53-
<?php if ($_item->isSaleable()) : ?>
61+
<?php if ($_item->isSaleable()): ?>
5462
<?php $postParams = $block->getAddToCartPostParams($_item); ?>
5563
<form data-role="tocart-form" data-product-sku="<?= $block->escapeHtml($_item->getSku()) ?>" action="<?= $block->escapeUrl($postParams['action']) ?>" method="post">
5664
<input type="hidden" name="product" value="<?= $block->escapeHtmlAttr($postParams['data']['product']) ?>">
@@ -62,24 +70,33 @@ use Magento\Framework\App\Action\Action;
6270
<span><?= $block->escapeHtml(__('Add to Cart')) ?></span>
6371
</button>
6472
</form>
65-
<?php else : ?>
66-
<?php if ($_item->getIsSalable()) : ?>
73+
<script type="text/x-magento-init">
74+
{
75+
"[data-role=tocart-form], .form.map.checkout": {
76+
"catalogAddToCart": {
77+
"product_sku": "<?= $escaper->escapeJs($_item->getSku()); ?>"
78+
}
79+
}
80+
}
81+
</script>
82+
<?php else: ?>
83+
<?php if ($_item->getIsSalable()): ?>
6784
<div class="stock available"><span><?= $block->escapeHtml(__('In stock')) ?></span></div>
68-
<?php else : ?>
85+
<?php else: ?>
6986
<div class="stock unavailable"><span><?= $block->escapeHtml(__('Out of stock')) ?></span></div>
7087
<?php endif; ?>
7188
<?php endif; ?>
7289
</div>
7390
<?php endif; ?>
74-
<?php if ($showWishlist || $showCompare) : ?>
91+
<?php if ($showWishlist || $showCompare): ?>
7592
<div class="actions-secondary" data-role="add-to-links">
76-
<?php if ($this->helper(\Magento\Wishlist\Helper\Data::class)->isAllow() && $showWishlist) : ?>
93+
<?php if ($this->helper(\Magento\Wishlist\Helper\Data::class)->isAllow() && $showWishlist): ?>
7794
<a href="#"
7895
data-post='<?= /* @noEscape */ $block->getAddToWishlistParams($_item) ?>' class="action towishlist" data-action="add-to-wishlist" title="<?= $block->escapeHtmlAttr(__('Add to Wish List')) ?>">
7996
<span><?= $block->escapeHtml(__('Add to Wish List')) ?></span>
8097
</a>
8198
<?php endif; ?>
82-
<?php if ($block->getAddToCompareUrl() && $showCompare) : ?>
99+
<?php if ($block->getAddToCompareUrl() && $showCompare): ?>
83100
<?php $compareHelper = $this->helper(\Magento\Catalog\Helper\Product\Compare::class);?>
84101
<a href="#" class="action tocompare" data-post='<?= /* @noEscape */ $compareHelper->getPostDataParams($_item) ?>' title="<?= $block->escapeHtmlAttr(__('Add to Compare')) ?>">
85102
<span><?= $block->escapeHtml(__('Add to Compare')) ?></span>

0 commit comments

Comments
 (0)