diff --git a/app/code/Magento/Catalog/Block/Adminhtml/Product/Helper/Form/Gallery/Content.php b/app/code/Magento/Catalog/Block/Adminhtml/Product/Helper/Form/Gallery/Content.php
index 9fb672b07b8d1..f61f9071155aa 100644
--- a/app/code/Magento/Catalog/Block/Adminhtml/Product/Helper/Form/Gallery/Content.php
+++ b/app/code/Magento/Catalog/Block/Adminhtml/Product/Helper/Form/Gallery/Content.php
@@ -122,21 +122,40 @@ public function getAddImagesButton()
*/
public function getImagesJson()
{
- if (is_array($this->getElement()->getImages())) {
- $value = $this->getElement()->getImages();
+ $value = $this->getElement()->getImages();
+ if (is_array($value) &&
+ array_key_exists('images', $value) &&
+ is_array($value['images']) &&
+ count($value['images'])
+ ) {
$directory = $this->_filesystem->getDirectoryRead(DirectoryList::MEDIA);
- if (is_array($value['images']) && count($value['images']) > 0) {
- foreach ($value['images'] as &$image) {
- $image['url'] = $this->_mediaConfig->getMediaUrl($image['file']);
- $fileHandler = $directory->stat($this->_mediaConfig->getMediaPath($image['file']));
- $image['size'] = $fileHandler['size'];
- }
- return $this->_jsonEncoder->encode($value['images']);
+ $images = $this->sortImagesByPosition($value['images']);
+ foreach ($images as &$image) {
+ $image['url'] = $this->_mediaConfig->getMediaUrl($image['file']);
+ $fileHandler = $directory->stat($this->_mediaConfig->getMediaPath($image['file']));
+ $image['size'] = $fileHandler['size'];
}
+ return $this->_jsonEncoder->encode($images);
}
return '[]';
}
+ /**
+ * Sort images array by position key
+ *
+ * @param array $images
+ * @return array
+ */
+ private function sortImagesByPosition($images)
+ {
+ if (is_array($images)) {
+ usort($images, function ($imageA, $imageB) {
+ return ($imageA['position'] < $imageB['position']) ? -1 : 1;
+ });
+ }
+ return $images;
+ }
+
/**
* @return string
*/
diff --git a/app/code/Magento/Catalog/Test/Unit/Block/Adminhtml/Product/Helper/Form/Gallery/ContentTest.php b/app/code/Magento/Catalog/Test/Unit/Block/Adminhtml/Product/Helper/Form/Gallery/ContentTest.php
index f7d1137407ff3..72a25933efa0b 100644
--- a/app/code/Magento/Catalog/Test/Unit/Block/Adminhtml/Product/Helper/Form/Gallery/ContentTest.php
+++ b/app/code/Magento/Catalog/Test/Unit/Block/Adminhtml/Product/Helper/Form/Gallery/ContentTest.php
@@ -82,37 +82,59 @@ public function testGetImagesJson()
['file_1.jpg', 'catalog/product/image_1.jpg'],
['file_2.jpg', 'catalog/product/image_2.jpg']
];
- // @codingStandardsIgnoreStart
- $encodedString = '[{"value_id":"1","file":"image_1.jpg","media_type":"image","url":"http:\/\/magento2.dev\/pub\/media\/catalog\/product\/image_1.jpg","size":879394},{"value_id":"2","file":"image_2.jpg","media_type":"image","url":"http:\/\/magento2.dev\/pub\/media\/catalog\/product\/image`_2.jpg","size":399659}]';
- // @codingStandardsIgnoreEnd
+
+ $sizeMap = [
+ ['catalog/product/image_1.jpg', ['size' => 399659]],
+ ['catalog/product/image_2.jpg', ['size' => 879394]]
+ ];
+
+ $imagesResult = [
+ [
+ 'value_id' => '2',
+ 'file' => 'file_2.jpg',
+ 'media_type' => 'image',
+ 'position' => '0',
+ 'url' => 'url_to_the_image/image_2.jpg',
+ 'size' => 879394
+ ],
+ [
+ 'value_id' => '1',
+ 'file' => 'file_1.jpg',
+ 'media_type' => 'image',
+ 'position' => '1',
+ 'url' => 'url_to_the_image/image_1.jpg',
+ 'size' => 399659
+ ]
+ ];
+
$images = [
'images' => [
[
'value_id' => '1',
'file' => 'file_1.jpg',
'media_type' => 'image',
+ 'position' => '1'
] ,
[
'value_id' => '2',
'file' => 'file_2.jpg',
'media_type' => 'image',
+ 'position' => '0'
]
]
];
- $firstStat = ['size' => 879394];
- $secondStat = ['size' => 399659];
+
$this->content->setElement($this->galleryMock);
- $this->galleryMock->expects($this->any())->method('getImages')->willReturn($images);
+ $this->galleryMock->expects($this->once())->method('getImages')->willReturn($images);
$this->fileSystemMock->expects($this->once())->method('getDirectoryRead')->willReturn($this->readMock);
$this->mediaConfigMock->expects($this->any())->method('getMediaUrl')->willReturnMap($url);
- $this->mediaConfigMock->expects($this->any())->method('getMediaPath')->willReturn($mediaPath);
+ $this->mediaConfigMock->expects($this->any())->method('getMediaPath')->willReturnMap($mediaPath);
- $this->readMock->expects($this->at(0))->method('stat')->willReturn($firstStat);
- $this->readMock->expects($this->at(1))->method('stat')->willReturn($secondStat);
- $this->jsonEncoderMock->expects($this->once())->method('encode')->willReturn($encodedString);
+ $this->readMock->expects($this->any())->method('stat')->willReturnMap($sizeMap);
+ $this->jsonEncoderMock->expects($this->once())->method('encode')->willReturnCallback('json_encode');
- $this->assertSame($encodedString, $this->content->getImagesJson());
+ $this->assertSame(json_encode($imagesResult), $this->content->getImagesJson());
}
public function testGetImagesJsonWithoutImages()
diff --git a/app/code/Magento/CatalogImportExport/Model/Import/Product.php b/app/code/Magento/CatalogImportExport/Model/Import/Product.php
index b56a03da0f3b5..03c2f3f4f511a 100644
--- a/app/code/Magento/CatalogImportExport/Model/Import/Product.php
+++ b/app/code/Magento/CatalogImportExport/Model/Import/Product.php
@@ -1270,7 +1270,7 @@ protected function _saveProductCategories(array $categoriesData)
);
}
if ($categoriesIn) {
- $this->_connection->insertOnDuplicate($tableName, $categoriesIn, ['position']);
+ $this->_connection->insertOnDuplicate($tableName, $categoriesIn, ['product_id', 'category_id']);
}
}
return $this;
diff --git a/app/code/Magento/Newsletter/Block/Adminhtml/Queue/Edit.php b/app/code/Magento/Newsletter/Block/Adminhtml/Queue/Edit.php
index dff671f15f0c4..f71b1f76d7ff4 100644
--- a/app/code/Magento/Newsletter/Block/Adminhtml/Queue/Edit.php
+++ b/app/code/Magento/Newsletter/Block/Adminhtml/Queue/Edit.php
@@ -161,7 +161,12 @@ protected function _prepareLayout()
*/
public function getPreviewUrl()
{
- return $this->getUrl('*/*/preview');
+ if ($this->getTemplateId()) {
+ $params = ['template_id' => $this->getTemplateId()];
+ } else {
+ $params = ['id' => $this->getRequest()->getParam('id')];
+ }
+ return $this->getUrl('*/*/preview', $params);
}
/**
diff --git a/app/code/Magento/Newsletter/Block/Adminhtml/Queue/Preview/Form.php b/app/code/Magento/Newsletter/Block/Adminhtml/Queue/Preview/Form.php
index bf237fb9787de..0e4a69d1050f8 100644
--- a/app/code/Magento/Newsletter/Block/Adminhtml/Queue/Preview/Form.php
+++ b/app/code/Magento/Newsletter/Block/Adminhtml/Queue/Preview/Form.php
@@ -35,6 +35,10 @@ protected function _prepareForm()
if ($data = $this->getFormData()) {
$mapper = ['preview_store_id' => 'store_id'];
+ if (empty($data['id']) && !empty($data['text'])) {
+ $this->_backendSession->setPreviewData($data);
+ }
+
foreach ($data as $key => $value) {
if (array_key_exists($key, $mapper)) {
$name = $mapper[$key];
diff --git a/app/code/Magento/Newsletter/Block/Adminhtml/Template/Edit.php b/app/code/Magento/Newsletter/Block/Adminhtml/Template/Edit.php
index 2bbd61bf47bd0..03297c9c45181 100644
--- a/app/code/Magento/Newsletter/Block/Adminhtml/Template/Edit.php
+++ b/app/code/Magento/Newsletter/Block/Adminhtml/Template/Edit.php
@@ -238,7 +238,7 @@ public function getSaveUrl()
*/
public function getPreviewUrl()
{
- return $this->getUrl('*/*/preview');
+ return $this->getUrl('*/*/preview', ['id' => $this->getRequest()->getParam('id')]);
}
/**
diff --git a/app/code/Magento/Newsletter/Block/Adminhtml/Template/Preview.php b/app/code/Magento/Newsletter/Block/Adminhtml/Template/Preview.php
index 4bce98adb6ebb..0a415fe7c2024 100644
--- a/app/code/Magento/Newsletter/Block/Adminhtml/Template/Preview.php
+++ b/app/code/Magento/Newsletter/Block/Adminhtml/Template/Preview.php
@@ -58,9 +58,11 @@ protected function _toHtml()
if ($id = (int)$this->getRequest()->getParam('id')) {
$this->loadTemplate($template, $id);
} else {
- $template->setTemplateType($this->getRequest()->getParam('type'));
- $template->setTemplateText($this->getRequest()->getParam('text'));
- $template->setTemplateStyles($this->getRequest()->getParam('styles'));
+ $previewData = $this->getPreviewData();
+
+ $template->setTemplateType($previewData['type']);
+ $template->setTemplateText($previewData['text']);
+ $template->setTemplateStyles($previewData['styles']);
}
\Magento\Framework\Profiler::start($this->profilerName);
@@ -88,6 +90,32 @@ protected function _toHtml()
return $templateProcessed;
}
+ /**
+ * Return template preview data
+ *
+ * @return array
+ */
+ private function getPreviewData()
+ {
+ $previewData = [];
+ $previewParams = ['type', 'text', 'styles'];
+
+ $sessionData = [];
+ if ($this->_backendSession->hasPreviewData()) {
+ $sessionData = $this->_backendSession->getPreviewData();
+ }
+
+ foreach ($previewParams as $param) {
+ if (isset($sessionData[$param])) {
+ $previewData[$param] = $sessionData[$param];
+ } else {
+ $previewData[$param] = $this->getRequest()->getParam($param);
+ }
+ }
+
+ return $previewData;
+ }
+
/**
* Get Store Id from request or default
*
diff --git a/app/code/Magento/Newsletter/Block/Adminhtml/Template/Preview/Form.php b/app/code/Magento/Newsletter/Block/Adminhtml/Template/Preview/Form.php
index efc15663d462b..ac6d569d69a88 100644
--- a/app/code/Magento/Newsletter/Block/Adminhtml/Template/Preview/Form.php
+++ b/app/code/Magento/Newsletter/Block/Adminhtml/Template/Preview/Form.php
@@ -35,6 +35,10 @@ protected function _prepareForm()
if ($data = $this->getFormData()) {
$mapper = ['preview_store_id' => 'store_id'];
+ if (empty($data['id']) && !empty($data['text'])) {
+ $this->_backendSession->setPreviewData($data);
+ }
+
foreach ($data as $key => $value) {
if (array_key_exists($key, $mapper)) {
$name = $mapper[$key];
diff --git a/app/code/Magento/Newsletter/Controller/Adminhtml/Queue/Preview.php b/app/code/Magento/Newsletter/Controller/Adminhtml/Queue/Preview.php
index 64d33a0fda3a9..a11d1abc82b9b 100644
--- a/app/code/Magento/Newsletter/Controller/Adminhtml/Queue/Preview.php
+++ b/app/code/Magento/Newsletter/Controller/Adminhtml/Queue/Preview.php
@@ -17,7 +17,11 @@ public function execute()
{
$this->_view->loadLayout();
$data = $this->getRequest()->getParams();
- if (empty($data) || !isset($data['id'])) {
+
+ $isEmptyRequestData = empty($data) || !isset($data['id']);
+ $isEmptyPreviewData = !$this->_getSession()->hasPreviewData() || empty($this->_getSession()->getPreviewData());
+
+ if ($isEmptyRequestData && $isEmptyPreviewData) {
$this->_forward('noroute');
return;
}
diff --git a/app/code/Magento/Newsletter/Controller/Adminhtml/Queue/Save.php b/app/code/Magento/Newsletter/Controller/Adminhtml/Queue/Save.php
index a96cd34edb85d..4acef96088aff 100644
--- a/app/code/Magento/Newsletter/Controller/Adminhtml/Queue/Save.php
+++ b/app/code/Magento/Newsletter/Controller/Adminhtml/Queue/Save.php
@@ -82,6 +82,7 @@ public function execute()
$this->messageManager->addSuccess(__('You saved the newsletter queue.'));
$this->_getSession()->setFormData(false);
+ $this->_getSession()->unsPreviewData();
$this->_redirect('*/*');
} catch (\Magento\Framework\Exception\LocalizedException $e) {
diff --git a/app/code/Magento/Newsletter/Controller/Adminhtml/Template/Preview.php b/app/code/Magento/Newsletter/Controller/Adminhtml/Template/Preview.php
index e01897d71d197..80579ddb49395 100644
--- a/app/code/Magento/Newsletter/Controller/Adminhtml/Template/Preview.php
+++ b/app/code/Magento/Newsletter/Controller/Adminhtml/Template/Preview.php
@@ -18,7 +18,10 @@ public function execute()
$this->_view->loadLayout();
$data = $this->getRequest()->getParams();
- if (empty($data) || !isset($data['id'])) {
+ $isEmptyRequestData = empty($data) || !isset($data['id']);
+ $isEmptyPreviewData = !$this->_getSession()->hasPreviewData() || empty($this->_getSession()->getPreviewData());
+
+ if ($isEmptyRequestData && $isEmptyPreviewData) {
$this->_forward('noroute');
return $this;
}
diff --git a/app/code/Magento/Newsletter/Controller/Adminhtml/Template/Save.php b/app/code/Magento/Newsletter/Controller/Adminhtml/Template/Save.php
index 9aeb187e99019..ee09d6da776bc 100644
--- a/app/code/Magento/Newsletter/Controller/Adminhtml/Template/Save.php
+++ b/app/code/Magento/Newsletter/Controller/Adminhtml/Template/Save.php
@@ -63,7 +63,7 @@ public function execute()
$this->messageManager->addSuccess(__('The newsletter template has been saved.'));
$this->_getSession()->setFormData(false);
-
+ $this->_getSession()->unsPreviewData();
$this->_redirect('*/template');
return;
} catch (LocalizedException $e) {
diff --git a/app/code/Magento/Newsletter/Test/Unit/Block/Adminhtml/Queue/PreviewTest.php b/app/code/Magento/Newsletter/Test/Unit/Block/Adminhtml/Queue/PreviewTest.php
index dae38205e1d72..ad90c5a6d9159 100644
--- a/app/code/Magento/Newsletter/Test/Unit/Block/Adminhtml/Queue/PreviewTest.php
+++ b/app/code/Magento/Newsletter/Test/Unit/Block/Adminhtml/Queue/PreviewTest.php
@@ -62,6 +62,12 @@ protected function setUp()
$appState = $this->getMock('Magento\Framework\App\State', [], [], '', false);
$context->expects($this->once())->method('getAppState')->will($this->returnValue($appState));
+ $backendSession = $this->getMockBuilder('Magento\Backend\Model\Session')
+ ->disableOriginalConstructor()
+ ->getMock();
+
+ $context->expects($this->once())->method('getBackendSession')->willReturn($backendSession);
+
$templateFactory = $this->getMock('Magento\Newsletter\Model\TemplateFactory', ['create'], [], '', false);
$this->template = $this->getMock('Magento\Newsletter\Model\Template', [], [], '', false);
$templateFactory->expects($this->once())->method('create')->will($this->returnValue($this->template));
diff --git a/app/code/Magento/Newsletter/view/adminhtml/layout/newsletter_queue_preview.xml b/app/code/Magento/Newsletter/view/adminhtml/layout/newsletter_queue_preview.xml
index 9081bbd72b2d6..13c329b2f022c 100644
--- a/app/code/Magento/Newsletter/view/adminhtml/layout/newsletter_queue_preview.xml
+++ b/app/code/Magento/Newsletter/view/adminhtml/layout/newsletter_queue_preview.xml
@@ -10,6 +10,7 @@
+
diff --git a/app/code/Magento/Newsletter/view/adminhtml/layout/newsletter_template_preview.xml b/app/code/Magento/Newsletter/view/adminhtml/layout/newsletter_template_preview.xml
index fb7088093ae52..81898079f46e6 100644
--- a/app/code/Magento/Newsletter/view/adminhtml/layout/newsletter_template_preview.xml
+++ b/app/code/Magento/Newsletter/view/adminhtml/layout/newsletter_template_preview.xml
@@ -10,6 +10,7 @@
+
diff --git a/app/code/Magento/Newsletter/view/adminhtml/templates/preview/iframeswitcher.phtml b/app/code/Magento/Newsletter/view/adminhtml/templates/preview/iframeswitcher.phtml
index ef1d0593a1a6b..aa5679047a593 100644
--- a/app/code/Magento/Newsletter/view/adminhtml/templates/preview/iframeswitcher.phtml
+++ b/app/code/Magento/Newsletter/view/adminhtml/templates/preview/iframeswitcher.phtml
@@ -42,8 +42,8 @@ function unBlockPreview() {
jQuery('body').trigger('hideLoadingPopup');
}
-Event.observe(window, 'load', preview);
-Event.observe(previewIframe, 'load', unBlockPreview);
+jQuery(document).ready(preview);
+jQuery(previewIframe).ready(unBlockPreview);
jQuery("#preview_iframe").load(function() {
jQuery(this).height(jQuery(this).contents().find("html").height() );
diff --git a/app/code/Magento/ProductVideo/view/frontend/web/js/fotorama-add-video-events.js b/app/code/Magento/ProductVideo/view/frontend/web/js/fotorama-add-video-events.js
index 7975efc95180b..0b149e37a0716 100644
--- a/app/code/Magento/ProductVideo/view/frontend/web/js/fotorama-add-video-events.js
+++ b/app/code/Magento/ProductVideo/view/frontend/web/js/fotorama-add-video-events.js
@@ -249,11 +249,7 @@ define([
tmpVideoData.videoUrl = tmpInputData.videoUrl;
}
- if (tmpVideoData.isBase) {
- videoData.unshift(tmpVideoData);
- } else {
- videoData.push(tmpVideoData);
- }
+ videoData.push(tmpVideoData);
}
return videoData;
diff --git a/app/code/Magento/Swatches/view/frontend/web/js/swatch-renderer.js b/app/code/Magento/Swatches/view/frontend/web/js/swatch-renderer.js
index 326cbd7e43c5d..5135493c06494 100644
--- a/app/code/Magento/Swatches/view/frontend/web/js/swatch-renderer.js
+++ b/app/code/Magento/Swatches/view/frontend/web/js/swatch-renderer.js
@@ -184,6 +184,9 @@ define([
// Callback url for media
mediaCallback: '',
+ // Local media cache
+ mediaCache: {},
+
// Cache for BaseProduct images. Needed when option unset
mediaGalleryInitial: [{}],
@@ -718,7 +721,22 @@ define([
$this = $widget.element,
attributes = {},
productId = 0,
- additional;
+ mediaCallData,
+ mediaCacheKey,
+
+ /**
+ * Processes product media data
+ *
+ * @param {Object} data
+ * @returns void
+ */
+ mediaSuccessCallback = function (data) {
+ if (!(mediaCacheKey in $widget.options.mediaCache)) {
+ $widget.options.mediaCache[mediaCacheKey] = data;
+ }
+ $widget._ProductMediaCallback($this, data);
+ $widget._DisableProductMediaLoader($this);
+ };
if (!$widget.options.mediaCallback) {
return;
@@ -739,24 +757,28 @@ define([
.find('.price-box.price-final_price').attr('data-product-id');
}
- additional = $.parseQuery();
-
- $widget._XhrKiller();
- $widget._EnableProductMediaLoader($this);
- $widget.xhr = $.post(
- $widget.options.mediaCallback, {
- 'product_id': productId,
- attributes: attributes,
- isAjax: true,
- additional: additional
- }, function (data) {
- $widget._ProductMediaCallback($this, data);
- $widget._DisableProductMediaLoader($this);
- },
- 'json'
- ).done(function () {
+ mediaCallData = {
+ 'product_id': productId,
+ 'attributes': attributes,
+ 'additional': $.parseQuery()
+ };
+ mediaCacheKey = JSON.stringify(mediaCallData);
+
+ if (mediaCacheKey in $widget.options.mediaCache) {
+ mediaSuccessCallback($widget.options.mediaCache[mediaCacheKey]);
+ } else {
+ mediaCallData.isAjax = true;
+ $widget._XhrKiller();
+ $widget._EnableProductMediaLoader($this);
+ $widget.xhr = $.post(
+ $widget.options.mediaCallback,
+ mediaCallData,
+ mediaSuccessCallback,
+ 'json'
+ ).done(function () {
$widget._XhrKiller();
});
+ }
},
/**
@@ -820,32 +842,30 @@ define([
return e.hasOwnProperty('large') && e.hasOwnProperty('medium') && e.hasOwnProperty('small');
};
- if (_.size($widget) < 1) {
+ if (_.size($widget) < 1 || !support(response)) {
this.updateBaseImage(this.options.mediaGalleryInitial, $main, isProductViewExist);
return;
}
- if (support(response)) {
- images.push({
- full: response.large,
- img: response.medium,
- thumb: response.small,
- isMain: true
- });
+ images.push({
+ full: response.large,
+ img: response.medium,
+ thumb: response.small,
+ isMain: true
+ });
- if (response.hasOwnProperty('gallery')) {
- $.each(response.gallery, function () {
- if (!support(this) || response.large === this.large) {
- return;
- }
- images.push({
- full: this.large,
- img: this.medium,
- thumb: this.small
- });
+ if (response.hasOwnProperty('gallery')) {
+ $.each(response.gallery, function () {
+ if (!support(this) || response.large === this.large) {
+ return;
+ }
+ images.push({
+ full: this.large,
+ img: this.medium,
+ thumb: this.small
});
- }
+ });
}
this.updateBaseImage(images, $main, isProductViewExist);
@@ -882,11 +902,9 @@ define([
gallery = context.find(this.options.mediaGallerySelector).data('gallery'),
item;
- if (images) {
- imagesToUpdate = this._setImageType($.extend(true, [], images));
- }
-
if (isProductViewExist) {
+ imagesToUpdate = images.length ? this._setImageType($.extend(true, [], images)) : [];
+
if (this.options.onlyMainImg) {
updateImg = imagesToUpdate.filter(function (img) {
return img.isMain;
diff --git a/app/code/Magento/Wishlist/view/frontend/web/js/add-to-wishlist.js b/app/code/Magento/Wishlist/view/frontend/web/js/add-to-wishlist.js
index 600c38ace28c4..d442c7e878a24 100644
--- a/app/code/Magento/Wishlist/view/frontend/web/js/add-to-wishlist.js
+++ b/app/code/Magento/Wishlist/view/frontend/web/js/add-to-wishlist.js
@@ -23,6 +23,7 @@ define([
},
_bind: function() {
var options = this.options,
+ dataUpdateFunc = '_updateWishlistData',
changeCustomOption = 'change ' + options.customOptionsInfo,
changeQty = 'change ' + options.qtyInfo,
events = {};
@@ -35,12 +36,14 @@ define([
options.productType = [];
}
- events[changeCustomOption] = '_updateWishlistData';
- events[changeQty] = '_updateWishlistData';
- options.productType.forEach(function (type) {
- events['change ' + options[type + 'Info']] = '_updateWishlistData';
- });
+ events[changeCustomOption] = dataUpdateFunc;
+ events[changeQty] = dataUpdateFunc;
+ for (var key in options.productType) {
+ if (options.productType.hasOwnProperty(key) && options.productType[key] + 'Info' in options) {
+ events['change ' + options[options.productType[key] + 'Info']] = dataUpdateFunc;
+ }
+ }
this._on(events);
},
_updateWishlistData: function(event) {
diff --git a/dev/tests/functional/tests/app/Magento/Newsletter/Test/Block/Adminhtml/Template/FormPageActions.php b/dev/tests/functional/tests/app/Magento/Newsletter/Test/Block/Adminhtml/Template/FormPageActions.php
index c544a86f454ad..ff8214f9034b8 100644
--- a/dev/tests/functional/tests/app/Magento/Newsletter/Test/Block/Adminhtml/Template/FormPageActions.php
+++ b/dev/tests/functional/tests/app/Magento/Newsletter/Test/Block/Adminhtml/Template/FormPageActions.php
@@ -17,9 +17,26 @@
class FormPageActions extends AbstractFormPageActions
{
/**
- * "Save" button
+ * "Save Template" button
*
* @var string
*/
protected $saveButton = "[data-ui-id='page-actions-toolbar-save-button']";
+
+ /**
+ * "Preview Template" button
+ *
+ * @var string
+ */
+ private $previewButton = "[data-role='template-preview']";
+
+ /**
+ * Click preview button on form page
+ *
+ * @return void
+ */
+ public function clickPreview()
+ {
+ $this->_rootElement->find($this->previewButton)->click();
+ }
}
diff --git a/dev/tests/functional/tests/app/Magento/Newsletter/Test/TestCase/PreviewNewsletterTemplateEntityTest.php b/dev/tests/functional/tests/app/Magento/Newsletter/Test/TestCase/PreviewNewsletterTemplateEntityTest.php
new file mode 100644
index 0000000000000..bd30c443ca0c1
--- /dev/null
+++ b/dev/tests/functional/tests/app/Magento/Newsletter/Test/TestCase/PreviewNewsletterTemplateEntityTest.php
@@ -0,0 +1,87 @@
+ "Newsletter Template"
+ * 3. Find created template in grid and open it
+ * 4. Click "Preview Template" button at the top of the page
+ * 5. Perform all assertions
+ *
+ * @group Newsletters_(MX)
+ * @ZephyrId MAGETWO-51979
+ */
+class PreviewNewsletterTemplateEntityTest extends Injectable
+{
+ /* tags */
+ const MVP = 'yes';
+ const DOMAIN = 'MX';
+ /* end tags */
+
+ /**
+ * Page with newsletter template grid
+ *
+ * @var TemplateIndex
+ */
+ protected $templateIndex;
+
+ /**
+ * Page for create newsletter template
+ *
+ * @var TemplateNewIndex
+ */
+ protected $templateNewIndex;
+
+ /**
+ * Inject newsletter page
+ *
+ * @param TemplateIndex $templateIndex
+ * @param TemplateNewIndex $templateNewIndex
+ * @return void
+ */
+ public function __inject(
+ TemplateIndex $templateIndex,
+ TemplateNewIndex $templateNewIndex
+ ) {
+ $this->templateIndex = $templateIndex;
+ $this->templateNewIndex = $templateNewIndex;
+ }
+
+ /**
+ * Action for Newsletter Template
+ *
+ * @param Template $newsletter
+ * @return void
+ */
+ public function test(Template $newsletter)
+ {
+ // Preconditions
+ $newsletter->persist();
+
+ // Steps
+ // 1. Open Backend
+ // 2. Go to "Marketing" -> "Newsletter Template"
+ $this->templateIndex->open();
+ // 3. Find created template in grid and open it
+ $this->templateIndex->getNewsletterTemplateGrid()->searchAndOpen(['code' => $newsletter->getCode()]);
+ // 4. Click "Preview Template" button at the top of the page
+ $this->templateNewIndex->getFormPageActions()->clickPreview();
+ }
+}
diff --git a/dev/tests/functional/tests/app/Magento/Newsletter/Test/TestCase/PreviewNewsletterTemplateEntityTest.xml b/dev/tests/functional/tests/app/Magento/Newsletter/Test/TestCase/PreviewNewsletterTemplateEntityTest.xml
new file mode 100644
index 0000000000000..13b499fca5e3c
--- /dev/null
+++ b/dev/tests/functional/tests/app/Magento/Newsletter/Test/TestCase/PreviewNewsletterTemplateEntityTest.xml
@@ -0,0 +1,15 @@
+
+
+
+
+
+ default
+
+
+
+
diff --git a/dev/tests/integration/testsuite/Magento/CatalogImportExport/Model/Import/ProductTest.php b/dev/tests/integration/testsuite/Magento/CatalogImportExport/Model/Import/ProductTest.php
index 499fdf32045b0..3be0fa114309c 100644
--- a/dev/tests/integration/testsuite/Magento/CatalogImportExport/Model/Import/ProductTest.php
+++ b/dev/tests/integration/testsuite/Magento/CatalogImportExport/Model/Import/ProductTest.php
@@ -14,6 +14,8 @@
*/
namespace Magento\CatalogImportExport\Model\Import;
+use Magento\Catalog\Api\ProductRepositoryInterface;
+use Magento\Catalog\Model\Category;
use Magento\Framework\App\Bootstrap;
use Magento\Framework\App\Filesystem\DirectoryList;
use Magento\ImportExport\Model\Import;
@@ -887,6 +889,70 @@ public function testProductCategories($fixture, $separator)
$this->assertTrue(count($categories) == 2);
}
+ /**
+ * @magentoAppArea adminhtml
+ * @magentoDbIsolation enabled
+ * @magentoAppIsolation enabled
+ * @magentoDataFixture Magento/Catalog/_files/multiple_products.php
+ * @magentoDataFixture Magento/Catalog/_files/category.php
+ */
+ public function testProductPositionInCategory()
+ {
+ /* @var \Magento\Catalog\Model\ResourceModel\Category\Collection $collection */
+ $collection = $this->objectManager->create(\Magento\Catalog\Model\ResourceModel\Category\Collection::class);
+ $collection->addNameToResult()->load();
+ /** @var Category $category */
+ $category = $collection->getItemByColumnValue('name', 'Category 1');
+
+ /** @var ProductRepositoryInterface $productRepository */
+ $productRepository = $this->objectManager->create(ProductRepositoryInterface::class);
+
+ $categoryProducts = [];
+ $i = 51;
+ foreach (['simple1', 'simple2', 'simple3'] as $sku) {
+ $categoryProducts[$productRepository->get($sku)->getId()] = $i++;
+ }
+ $category->setPostedProducts($categoryProducts);
+ $category->save();
+
+ $filesystem = \Magento\TestFramework\Helper\Bootstrap::getObjectManager()->create(
+ \Magento\Framework\Filesystem::class
+ );
+
+ $directory = $filesystem->getDirectoryWrite(DirectoryList::ROOT);
+ $source = $this->objectManager->create(
+ \Magento\ImportExport\Model\Import\Source\Csv::class,
+ [
+ 'file' => __DIR__ . '/_files/products_to_import.csv',
+ 'directory' => $directory
+ ]
+ );
+ $errors = $this->_model->setSource(
+ $source
+ )->setParameters(
+ [
+ 'behavior' => \Magento\ImportExport\Model\Import::BEHAVIOR_APPEND,
+ 'entity' => 'catalog_product'
+ ]
+ )->validateData();
+
+ $this->assertTrue($errors->getErrorsCount() == 0);
+ $this->_model->importData();
+
+ /** @var \Magento\Framework\App\ResourceConnection $resourceConnection */
+ $resourceConnection = \Magento\TestFramework\Helper\Bootstrap::getObjectManager()->get(
+ \Magento\Framework\App\ResourceConnection::class
+ );
+ $tableName = $resourceConnection->getTableName('catalog_category_product');
+ $select = $resourceConnection->getConnection()->select()->from($tableName)
+ ->where('category_id = ?', $category->getId());
+ $items = $resourceConnection->getConnection()->fetchAll($select);
+ $this->assertCount(3, $items);
+ foreach ($items as $item) {
+ $this->assertGreaterThan(50, $item['position']);
+ }
+ }
+
/**
* @return array
*/
diff --git a/dev/tests/integration/testsuite/Magento/CatalogImportExport/Model/Import/_files/products_to_import.csv b/dev/tests/integration/testsuite/Magento/CatalogImportExport/Model/Import/_files/products_to_import.csv
index a107fdff250ec..383a9414c9e22 100644
--- a/dev/tests/integration/testsuite/Magento/CatalogImportExport/Model/Import/_files/products_to_import.csv
+++ b/dev/tests/integration/testsuite/Magento/CatalogImportExport/Model/Import/_files/products_to_import.csv
@@ -1,4 +1,4 @@
-sku,product_type,store_view_code,name,price,attribute_set_code
-simple1,simple,,"simple 1",25,Default
-simple2,simple,,"simple 2",34,Default
-simple3,simple,,"simple 3",58,Default
+sku,product_type,store_view_code,name,price,attribute_set_code,categories
+simple1,simple,,"simple 1",25,Default,"Default Category/Category 1"
+simple2,simple,,"simple 2",34,Default,"Default Category/Category 1"
+simple3,simple,,"simple 3",58,Default,"Default Category/Category 1"
diff --git a/lib/web/mage/gallery/gallery.js b/lib/web/mage/gallery/gallery.js
index d2f13455992a2..11ee24f6816dc 100644
--- a/lib/web/mage/gallery/gallery.js
+++ b/lib/web/mage/gallery/gallery.js
@@ -15,28 +15,20 @@ define([
'use strict';
/**
- * Set main item first in order.
- * @param {Array.