From 795dc7d0cf1f3f69501752d998d00b367ec9e3f6 Mon Sep 17 00:00:00 2001 From: Stanislav Idolov Date: Fri, 7 Jun 2019 13:21:11 -0500 Subject: [PATCH] magento/adobe-stock-integration#4: Introduce image listing UI component --- AdobeStockAsset/Model/Asset.php | 34 +++ AdobeStockAsset/Model/Client.php | 6 +- .../Api/Data/AssetInterface.php | 22 ++ AdobeStockImage/Model/GetImageList.php | 2 +- AdobeStockImage/etc/adobe_stock_requests.xml | 4 +- .../adobe_stock_images_listing.xml | 9 +- .../adminhtml/web/css/source/_module.less | 30 ++- .../adminhtml/web/js/components/masonry.js | 214 ++++++++++++++++++ .../web/template/grid/cells/image.html | 9 - .../adminhtml/web/template/grid/listing.html | 15 +- .../view/adminhtml/web/template/masonry.html | 15 ++ 11 files changed, 323 insertions(+), 37 deletions(-) create mode 100644 AdobeStockImageAdminUi/view/adminhtml/web/js/components/masonry.js delete mode 100644 AdobeStockImageAdminUi/view/adminhtml/web/template/grid/cells/image.html create mode 100644 AdobeStockImageAdminUi/view/adminhtml/web/template/masonry.html diff --git a/AdobeStockAsset/Model/Asset.php b/AdobeStockAsset/Model/Asset.php index c34ab8242e6b..7e43d3235105 100644 --- a/AdobeStockAsset/Model/Asset.php +++ b/AdobeStockAsset/Model/Asset.php @@ -69,6 +69,40 @@ public function getExtensionAttributes() return $this->_getExtensionAttributes(); } + /** + * @param int $value + * @return Asset|AssetInterface + */ + public function setHeight(int $value) + { + return $this->setData('height', $value); + } + + /** + * @return int + */ + public function getHeight() : int + { + return $this->_get('height'); + } + + /** + * @param int $value + * @return Asset|AssetInterface + */ + public function setWidth(int $value) + { + return $this->setData('width', $value); + } + + /** + * @return int + */ + public function getWidth() : int + { + return $this->_get('width'); + } + /** * @param \Magento\AdobeStockImageApi\Api\Data\AssetExtensionInterface $extensionAttributes * @return $this diff --git a/AdobeStockAsset/Model/Client.php b/AdobeStockAsset/Model/Client.php index 552cd4a6419d..8c3831e76abe 100644 --- a/AdobeStockAsset/Model/Client.php +++ b/AdobeStockAsset/Model/Client.php @@ -62,7 +62,7 @@ public function search(SearchRequestInterface $request) : Result { $searchParams = new SearchParameters(); $searchParams->setLimit($request->getSize()); - $searchParams->setOffset($request->getOffset() * $request->getSize()); + $searchParams->setOffset($request->getOffset()); $this->setUpFilters($request->getFilters(), $searchParams); $resultsColumns = Constants::getResultColumns(); @@ -84,7 +84,9 @@ public function search(SearchRequestInterface $request) : Result /** @var AssetInterface $asset */ $asset = $this->assetFactory->create(); $asset->setId($file->id); - $asset->setUrl($file->thumbnail_220_url); + $asset->setUrl($file->thumbnail_500_url); + $asset->setHeight($file->height); + $asset->setWidth($file->width); $items[] = $asset; } diff --git a/AdobeStockAssetApi/Api/Data/AssetInterface.php b/AdobeStockAssetApi/Api/Data/AssetInterface.php index 2c944687b623..0e91ab99c897 100644 --- a/AdobeStockAssetApi/Api/Data/AssetInterface.php +++ b/AdobeStockAssetApi/Api/Data/AssetInterface.php @@ -84,6 +84,28 @@ public function getUrl(); */ public function setUrl($value); + /** + * @param int $value + * @return $this + */ + public function setHeight(int $value); + + /** + * @return int + */ + public function getHeight() : int; + + /** + * @param int $value + * @return $this + */ + public function setWidth(int $value); + + /** + * @return int + */ + public function getWidth() : int; + /** * Retrieve existing extension attributes object or create a new one. * diff --git a/AdobeStockImage/Model/GetImageList.php b/AdobeStockImage/Model/GetImageList.php index ff5cba22ddb0..3d2e3882ffc7 100644 --- a/AdobeStockImage/Model/GetImageList.php +++ b/AdobeStockImage/Model/GetImageList.php @@ -65,7 +65,7 @@ public function execute(SearchCriteriaInterface $searchCriteria): SearchResultsI { $this->requestBuilder->setName('adobe_stock_image_search'); $this->requestBuilder->setSize($searchCriteria->getPageSize()); - $this->requestBuilder->setOffset($searchCriteria->getCurrentPage()); + $this->requestBuilder->setOffset(($searchCriteria->getCurrentPage() - 1) * $searchCriteria->getPageSize()); $this->requestBuilder->setLocale($this->localeResolver->getLocale()); $this->applyFilters($searchCriteria); diff --git a/AdobeStockImage/etc/adobe_stock_requests.xml b/AdobeStockImage/etc/adobe_stock_requests.xml index 20c222ddaa12..59d957e1f974 100644 --- a/AdobeStockImage/etc/adobe_stock_requests.xml +++ b/AdobeStockImage/etc/adobe_stock_requests.xml @@ -21,7 +21,9 @@ - + + + 0 32 diff --git a/AdobeStockImageAdminUi/view/adminhtml/ui_component/adobe_stock_images_listing.xml b/AdobeStockImageAdminUi/view/adminhtml/ui_component/adobe_stock_images_listing.xml index 9fcee3f6b83a..4163ba70dea6 100644 --- a/AdobeStockImageAdminUi/view/adminhtml/ui_component/adobe_stock_images_listing.xml +++ b/AdobeStockImageAdminUi/view/adminhtml/ui_component/adobe_stock_images_listing.xml @@ -55,10 +55,15 @@ - + + + + adobe_stock_images_listing.adobe_stock_images_listing_data_source + adobe-stock-images-masonry-grid + + - Magento_AdobeStockImageAdminUi/grid/cells/image diff --git a/AdobeStockImageAdminUi/view/adminhtml/web/css/source/_module.less b/AdobeStockImageAdminUi/view/adminhtml/web/css/source/_module.less index 8ed88ec8f126..36d1f9730b50 100644 --- a/AdobeStockImageAdminUi/view/adminhtml/web/css/source/_module.less +++ b/AdobeStockImageAdminUi/view/adminhtml/web/css/source/_module.less @@ -4,15 +4,23 @@ // */ & when (@media-common = true) { - .adobe-stock-image-column > div { - display: inline-block; - - .adobe-stock-image-cell { - margin: 10px; - - img { - max-height: 200px; - } + .masonry-image-column { + position: relative; + margin: 20px 0 20px 0; + } + .masonry-image-block { + background-color: #D5D5D5; + overflow: hidden; + left: 0; + position: absolute; + top: 0; + margin: 0; + } + .masonry-image-block img { + left: 0; + position: absolute; + top: 0; + height: 100%; + width: 100%; } - } -} \ No newline at end of file +} diff --git a/AdobeStockImageAdminUi/view/adminhtml/web/js/components/masonry.js b/AdobeStockImageAdminUi/view/adminhtml/web/js/components/masonry.js new file mode 100644 index 000000000000..671385e14f9b --- /dev/null +++ b/AdobeStockImageAdminUi/view/adminhtml/web/js/components/masonry.js @@ -0,0 +1,214 @@ +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +define([ + 'uiElement', + 'jquery' +], function (Element, $) { + 'use strict'; + + return Element.extend({ + defaults: { + template: 'Magento_AdobeStockImageAdminUi/masonry', + imports: { + rows: '${ $.provider }:data.items' + }, + listens: { + 'rows': 'initComponent' + }, + + /** + * Images array + * @param array + */ + images: [], + + /** + * Images container id + * @param string + */ + containerId: null, + + /** + * Minimum aspect ratio for each image + * @param int + */ + minRatio: null, + + /** + * Container width + * @param int + */ + containerWidth: window.innerWidth, + + /** + * Margin between images + * @param int + */ + imageMargin: 20, + + /** + * Container styles + * @param {Object} + */ + containerStyles: {}, + }, + + /** + * Init observable variables + * @return {Object} + */ + initObservable: function () { + this._super() + .observe([ + 'rows', + 'images', + 'containerStyles' + ]); + + return this; + }, + + /** + * Init component handler + * @param rows + * @return {Object} + */ + initComponent: function (rows) { + if (!rows.length) { + return; + } + + this.imageMargin = parseInt(this.imageMargin); + this.container = $('[data-id="' + this.containerId + '"]')[0]; + + this.prepareImages(rows); + this.setLayoutStyles(); + this.setContainerHeight(); + this.setEventListener(); + return this; + }, + + /** + * Prepare and assign images to observable var + * @param rows + */ + prepareImages: function (rows) { + this.images(rows.map( (asset) => { + return { + src: asset.url, + ratio: (asset.width / asset.height).toFixed(2), + id: asset.id + }; + })); + }, + + /** + * Set event listener to track resize event + */ + setEventListener: function () { + var running = false, + handler = function() { + this.containerWidth = window.innerWidth; + this.setLayoutStyles(); + this.setContainerHeight(); + }.bind(this); + + window.addEventListener('resize', function () { + if (!running) { + running = true; + if (window.requestAnimationFrame) { + window.requestAnimationFrame(function () { + handler(); + running = false; + }); + } else { + setTimeout(function () { + handler(); + running = false; + }, 66); + } + } + }); + }, + + /** + * Set optimal container height + */ + setContainerHeight: function() { + var styles = this.containerStyles(); + + styles['height'] = this.totalHeight + 'px'; + this.containerStyles(styles); + }, + + /** + * Set layout styles inside the container + */ + setLayoutStyles: function() { + var containerWidth = parseInt(this.container.clientWidth), + row = [], + translateX = 0, + translateY = 0, + ratio = 0, + imageWidth = 0, + rowHeight = 0; + + this.setMinRatio(); + + this.images().forEach(function(image, index) { + ratio += parseFloat(image.ratio); + row.push(image); + + if (ratio >= this.minRatio || index + 1 === this.images().length) { + ratio = Math.max(ratio, this.minRatio); + rowHeight = (containerWidth - this.imageMargin * (row.length - 1)) / ratio; + + row.forEach(function(img) { + imageWidth = rowHeight * img.ratio; + this.setImageStyles(img.id, imageWidth, rowHeight, translateX, translateY); + translateX += imageWidth + this.imageMargin; + }.bind(this)); + + row = []; + ratio = 0; + translateY += parseInt(rowHeight) + this.imageMargin; + translateX = 0; + } + }.bind(this)); + this.totalHeight = translateY - this.imageMargin; + }, + + /** + * Set styles for every image in layout + * + * @param {Number} imageId + * @param {Number} imageWidth + * @param {Number} rowHeight + * @param {Number} translateX + * @param {Number} translateY + */ + setImageStyles: function (imageId, imageWidth, rowHeight, translateX, translateY) { + $('[data-id="' + imageId + '"]') + .css('width', parseInt(imageWidth) + 'px') + .css('height', parseInt(rowHeight) + 'px') + .css('transform', ('translate3d(' + translateX + 'px,' + translateY + 'px, 0)')); + }, + + /** + * Set min ratio for images in layout + */ + setMinRatio: function() { + if (this.containerWidth <= 640) { + this.minRatio = 2; + } else if (this.containerWidth <= 1280) { + this.minRatio = 4; + } else if (this.containerWidth <= 1920) { + this.minRatio = 5; + } else { + this.minRatio = 6; + } + } + }); +}); diff --git a/AdobeStockImageAdminUi/view/adminhtml/web/template/grid/cells/image.html b/AdobeStockImageAdminUi/view/adminhtml/web/template/grid/cells/image.html deleted file mode 100644 index 2ce0d091e1f3..000000000000 --- a/AdobeStockImageAdminUi/view/adminhtml/web/template/grid/cells/image.html +++ /dev/null @@ -1,9 +0,0 @@ - -
- -
\ No newline at end of file diff --git a/AdobeStockImageAdminUi/view/adminhtml/web/template/grid/listing.html b/AdobeStockImageAdminUi/view/adminhtml/web/template/grid/listing.html index ca7c44f73228..5699b1063584 100644 --- a/AdobeStockImageAdminUi/view/adminhtml/web/template/grid/listing.html +++ b/AdobeStockImageAdminUi/view/adminhtml/web/template/grid/listing.html @@ -4,14 +4,7 @@ * See COPYING.txt for license details. */ --> -
-
-
-
-
-
- -
-
-
+ + + + diff --git a/AdobeStockImageAdminUi/view/adminhtml/web/template/masonry.html b/AdobeStockImageAdminUi/view/adminhtml/web/template/masonry.html new file mode 100644 index 000000000000..18c83770e269 --- /dev/null +++ b/AdobeStockImageAdminUi/view/adminhtml/web/template/masonry.html @@ -0,0 +1,15 @@ + +
+
+ +
+ +
+ +
+