diff --git a/app/bootstrap.php b/app/bootstrap.php index ba62b296bd49c..70b632537a75b 100644 --- a/app/bootstrap.php +++ b/app/bootstrap.php @@ -54,8 +54,16 @@ && isset($_SERVER['HTTP_ACCEPT']) && strpos($_SERVER['HTTP_ACCEPT'], 'text/html') !== false ) { - \Magento\Framework\Profiler::applyConfig( - (isset($_SERVER['MAGE_PROFILER']) && strlen($_SERVER['MAGE_PROFILER'])) ? $_SERVER['MAGE_PROFILER'] : trim(file_get_contents(BP . '/var/profiler.flag')), + $profilerConfig = isset($_SERVER['MAGE_PROFILER']) && strlen($_SERVER['MAGE_PROFILER']) + ? $_SERVER['MAGE_PROFILER'] + : trim(file_get_contents(BP . '/var/profiler.flag')); + + if ($profilerConfig) { + $profilerConfig = json_decode($profilerConfig, true) ?: $profilerConfig; + } + + Magento\Framework\Profiler::applyConfig( + $profilerConfig, BP, !empty($_SERVER['HTTP_X_REQUESTED_WITH']) && $_SERVER['HTTP_X_REQUESTED_WITH'] == 'XMLHttpRequest' ); diff --git a/app/code/Magento/AdminNotification/Observer/PredispatchAdminActionControllerObserver.php b/app/code/Magento/AdminNotification/Observer/PredispatchAdminActionControllerObserver.php index 3275de2a82fb7..24ef712c0f61f 100644 --- a/app/code/Magento/AdminNotification/Observer/PredispatchAdminActionControllerObserver.php +++ b/app/code/Magento/AdminNotification/Observer/PredispatchAdminActionControllerObserver.php @@ -37,7 +37,7 @@ public function __construct( } /** - * Predispath admin action controller + * Predispatch admin action controller * * @param \Magento\Framework\Event\Observer $observer * @return void diff --git a/app/code/Magento/AdminNotification/Test/Mftf/composer.json b/app/code/Magento/AdminNotification/Test/Mftf/composer.json deleted file mode 100644 index 6dcd053378c1b..0000000000000 --- a/app/code/Magento/AdminNotification/Test/Mftf/composer.json +++ /dev/null @@ -1,20 +0,0 @@ -{ - "name": "magento/functional-test-module-admin-notification", - "description": "N/A", - "config": { - "sort-packages": true - }, - "require": { - "php": "~7.1.3||~7.2.0", - "magento/magento2-functional-testing-framework": "2.2.0", - "magento/functional-test-module-backend": "100.0.0-dev", - "magento/functional-test-module-media-storage": "100.0.0-dev", - "magento/functional-test-module-store": "100.0.0-dev", - "magento/functional-test-module-ui": "100.0.0-dev" - }, - "type": "magento2-test", - "license": [ - "OSL-3.0", - "AFL-3.0" - ] -} diff --git a/app/code/Magento/AdvancedPricingImportExport/Test/Mftf/composer.json b/app/code/Magento/AdvancedPricingImportExport/Test/Mftf/composer.json deleted file mode 100644 index df2817ad6a52f..0000000000000 --- a/app/code/Magento/AdvancedPricingImportExport/Test/Mftf/composer.json +++ /dev/null @@ -1,23 +0,0 @@ -{ - "name": "magento/functional-test-module-advanced-pricing-import-export", - "description": "N/A", - "config": { - "sort-packages": true - }, - "require": { - "php": "~7.1.3||~7.2.0", - "magento/magento2-functional-testing-framework": "2.2.0", - "magento/functional-test-module-catalog": "100.0.0-dev", - "magento/functional-test-module-catalog-import-export": "100.0.0-dev", - "magento/functional-test-module-catalog-inventory": "100.0.0-dev", - "magento/functional-test-module-customer": "100.0.0-dev", - "magento/functional-test-module-eav": "100.0.0-dev", - "magento/functional-test-module-import-export": "100.0.0-dev", - "magento/functional-test-module-store": "100.0.0-dev" - }, - "type": "magento2-test", - "license": [ - "OSL-3.0", - "AFL-3.0" - ] -} diff --git a/app/code/Magento/AdvancedSearch/Model/ResourceModel/Index.php b/app/code/Magento/AdvancedSearch/Model/ResourceModel/Index.php index c2379e9dff062..7751a3b75092d 100644 --- a/app/code/Magento/AdvancedSearch/Model/ResourceModel/Index.php +++ b/app/code/Magento/AdvancedSearch/Model/ResourceModel/Index.php @@ -6,18 +6,22 @@ namespace Magento\AdvancedSearch\Model\ResourceModel; use Magento\Framework\Model\ResourceModel\Db\AbstractDb; +use Magento\Framework\Search\Request\IndexScopeResolverInterface; use Magento\Store\Model\StoreManagerInterface; use Magento\Framework\Model\ResourceModel\Db\Context; use Magento\Framework\EntityManager\MetadataPool; use Magento\Catalog\Api\Data\CategoryInterface; use Magento\Framework\App\ObjectManager; -use Magento\Framework\Indexer\ScopeResolver\IndexScopeResolver as TableResolver; use Magento\Framework\Search\Request\Dimension; use Magento\Catalog\Model\Indexer\Category\Product\AbstractAction; +use Magento\Framework\Search\Request\IndexScopeResolverInterface as TableResolver; +use Magento\Catalog\Model\Indexer\Product\Price\DimensionCollectionFactory; /** * @api * @since 100.1.0 + * + * @SuppressWarnings(PHPMD.CouplingBetweenObjects) */ class Index extends AbstractDb { @@ -38,6 +42,11 @@ class Index extends AbstractDb */ private $tableResolver; + /** + * @var DimensionCollectionFactory|null + */ + private $dimensionCollectionFactory; + /** * Index constructor. * @param Context $context @@ -45,18 +54,22 @@ class Index extends AbstractDb * @param MetadataPool $metadataPool * @param null $connectionName * @param TableResolver|null $tableResolver + * @param DimensionCollectionFactory|null $dimensionCollectionFactory */ public function __construct( Context $context, StoreManagerInterface $storeManager, MetadataPool $metadataPool, $connectionName = null, - TableResolver $tableResolver = null + TableResolver $tableResolver = null, + DimensionCollectionFactory $dimensionCollectionFactory = null ) { parent::__construct($context, $connectionName); $this->storeManager = $storeManager; $this->metadataPool = $metadataPool; - $this->tableResolver = $tableResolver ?: ObjectManager::getInstance()->get(TableResolver::class); + $this->tableResolver = $tableResolver ?: ObjectManager::getInstance()->get(IndexScopeResolverInterface::class); + $this->dimensionCollectionFactory = $dimensionCollectionFactory + ?: ObjectManager::getInstance()->get(DimensionCollectionFactory::class); } /** @@ -78,18 +91,22 @@ protected function _construct() protected function _getCatalogProductPriceData($productIds = null) { $connection = $this->getConnection(); - - $select = $connection->select()->from( - $this->getTable('catalog_product_index_price'), - ['entity_id', 'customer_group_id', 'website_id', 'min_price'] - ); - - if ($productIds) { - $select->where('entity_id IN (?)', $productIds); + $catalogProductIndexPriceSelect = []; + + foreach ($this->dimensionCollectionFactory->create() as $dimensions) { + $catalogProductIndexPriceSelect[] = $connection->select()->from( + $this->tableResolver->resolve('catalog_product_index_price', $dimensions), + ['entity_id', 'customer_group_id', 'website_id', 'min_price'] + ); + if ($productIds) { + current($catalogProductIndexPriceSelect)->where('entity_id IN (?)', $productIds); + } } + $catalogProductIndexPriceUnionSelect = $connection->select()->union($catalogProductIndexPriceSelect); + $result = []; - foreach ($connection->fetchAll($select) as $row) { + foreach ($connection->fetchAll($catalogProductIndexPriceUnionSelect) as $row) { $result[$row['website_id']][$row['entity_id']][$row['customer_group_id']] = round($row['min_price'], 2); } diff --git a/app/code/Magento/AdvancedSearch/Test/Mftf/composer.json b/app/code/Magento/AdvancedSearch/Test/Mftf/composer.json deleted file mode 100644 index b5582c72a039a..0000000000000 --- a/app/code/Magento/AdvancedSearch/Test/Mftf/composer.json +++ /dev/null @@ -1,22 +0,0 @@ -{ - "name": "magento/functional-test-module-advanced-search", - "description": "N/A", - "config": { - "sort-packages": true - }, - "require": { - "magento/magento2-functional-testing-framework": "2.2.0", - "magento/functional-test-module-backend": "100.0.0-dev", - "magento/functional-test-module-catalog": "100.0.0-dev", - "magento/functional-test-module-catalog-search": "100.0.0-dev", - "magento/functional-test-module-config": "100.0.0-dev", - "magento/functional-test-module-customer": "100.0.0-dev", - "magento/functional-test-module-search": "100.0.0-dev", - "magento/functional-test-module-store": "100.0.0-dev", - "php": "~7.1.3||~7.2.0" - }, - "type": "magento2-test", - "license": [ - "proprietary" - ] -} diff --git a/app/code/Magento/AdvancedSearch/Test/Unit/Model/ResourceModel/IndexTest.php b/app/code/Magento/AdvancedSearch/Test/Unit/Model/ResourceModel/IndexTest.php index 185e932406e5b..1f37e40842f54 100644 --- a/app/code/Magento/AdvancedSearch/Test/Unit/Model/ResourceModel/IndexTest.php +++ b/app/code/Magento/AdvancedSearch/Test/Unit/Model/ResourceModel/IndexTest.php @@ -15,6 +15,9 @@ use Magento\Framework\App\ResourceConnection; use Magento\Framework\DB\Select; +/** + * @SuppressWarnings(PHPMD.CouplingBetweenObjects) + */ class IndexTest extends \PHPUnit\Framework\TestCase { /** @@ -59,10 +62,24 @@ protected function setUp() $this->resourceConnectionMock->expects($this->any())->method('getConnection')->willReturn($this->adapterMock); $this->metadataPoolMock = $this->createMock(MetadataPool::class); + $indexScopeResolverMock = $this->createMock( + \Magento\Framework\Indexer\ScopeResolver\IndexScopeResolver::class + ); + $traversableMock = $this->createMock(\Traversable::class); + $dimensionsMock = $this->createMock(\Magento\Framework\Indexer\MultiDimensionProvider::class); + $dimensionsMock->method('getIterator')->willReturn($traversableMock); + $dimensionFactoryMock = $this->createMock( + \Magento\Catalog\Model\Indexer\Product\Price\DimensionCollectionFactory::class + ); + $dimensionFactoryMock->method('create')->willReturn($dimensionsMock); + $this->model = new Index( $this->resourceContextMock, $this->storeManagerMock, - $this->metadataPoolMock + $this->metadataPoolMock, + 'connectionName', + $indexScopeResolverMock, + $dimensionFactoryMock ); } @@ -71,11 +88,13 @@ public function testGetPriceIndexDataUsesFrontendPriceIndexerTable() $storeId = 1; $storeMock = $this->createMock(StoreInterface::class); $storeMock->expects($this->any())->method('getId')->willReturn($storeId); + $storeMock->method('getWebsiteId')->willReturn(1); $this->storeManagerMock->expects($this->once())->method('getStore')->with($storeId)->willReturn($storeMock); $selectMock = $this->createMock(Select::class); $selectMock->expects($this->any())->method('from')->willReturnSelf(); $selectMock->expects($this->any())->method('where')->willReturnSelf(); + $selectMock->expects($this->any())->method('union')->willReturnSelf(); $this->adapterMock->expects($this->once())->method('select')->willReturn($selectMock); $this->adapterMock->expects($this->once())->method('fetchAll')->with($selectMock)->willReturn([]); diff --git a/app/code/Magento/AdvancedSearch/composer.json b/app/code/Magento/AdvancedSearch/composer.json index a224a1001cd01..c6a5af07e60a7 100644 --- a/app/code/Magento/AdvancedSearch/composer.json +++ b/app/code/Magento/AdvancedSearch/composer.json @@ -17,7 +17,8 @@ }, "type": "magento2-module", "license": [ - "proprietary" + "OSL-3.0", + "AFL-3.0" ], "autoload": { "files": [ diff --git a/app/code/Magento/AdvancedSearch/etc/di.xml b/app/code/Magento/AdvancedSearch/etc/di.xml index 9ec75f56bbf7b..21e19fd58825b 100644 --- a/app/code/Magento/AdvancedSearch/etc/di.xml +++ b/app/code/Magento/AdvancedSearch/etc/di.xml @@ -19,6 +19,12 @@ Did you mean + + + Magento\CatalogSearch\Model\ResourceModel\EngineInterface::CONFIG_ENGINE_PATH + \Magento\Store\Model\ScopeInterface::SCOPE_STORE + + @@ -26,5 +32,12 @@ + + + + Magento\Catalog\Model\Indexer\Product\Price\PriceTableResolver + + + diff --git a/app/code/Magento/Amqp/Test/Mftf/composer.json b/app/code/Magento/Amqp/Test/Mftf/composer.json deleted file mode 100644 index 348200c5d1cb4..0000000000000 --- a/app/code/Magento/Amqp/Test/Mftf/composer.json +++ /dev/null @@ -1,17 +0,0 @@ -{ - "name": "magento/functional-test-module-amqp", - "description": "N/A", - "config": { - "sort-packages": true - }, - "require": { - "magento/magento2-functional-testing-framework": "2.2.0", - "magento/framework-amqp": "100.0.0-dev", - "magento/framework-message-queue": "100.0.0-dev", - "php": "~7.1.3||~7.2.0" - }, - "type": "magento2-test", - "license": [ - "proprietary" - ] -} diff --git a/app/code/Magento/Amqp/composer.json b/app/code/Magento/Amqp/composer.json index 23130dfb01a4e..b50e951b46f81 100644 --- a/app/code/Magento/Amqp/composer.json +++ b/app/code/Magento/Amqp/composer.json @@ -12,7 +12,8 @@ }, "type": "magento2-module", "license": [ - "proprietary" + "OSL-3.0", + "AFL-3.0" ], "autoload": { "files": [ diff --git a/app/code/Magento/Analytics/Test/Mftf/Test/AdminConfigurationBlankIndustryTest.xml b/app/code/Magento/Analytics/Test/Mftf/Test/AdminConfigurationBlankIndustryTest.xml index 8649eac484d94..fefb7874ef736 100644 --- a/app/code/Magento/Analytics/Test/Mftf/Test/AdminConfigurationBlankIndustryTest.xml +++ b/app/code/Magento/Analytics/Test/Mftf/Test/AdminConfigurationBlankIndustryTest.xml @@ -22,6 +22,7 @@ + diff --git a/app/code/Magento/Analytics/Test/Mftf/Test/AdminConfigurationEnableDisableAnalyticsTest.xml b/app/code/Magento/Analytics/Test/Mftf/Test/AdminConfigurationEnableDisableAnalyticsTest.xml index 8b0714cd2ef65..15c9727cc8c79 100644 --- a/app/code/Magento/Analytics/Test/Mftf/Test/AdminConfigurationEnableDisableAnalyticsTest.xml +++ b/app/code/Magento/Analytics/Test/Mftf/Test/AdminConfigurationEnableDisableAnalyticsTest.xml @@ -16,8 +16,9 @@ - - + + + diff --git a/app/code/Magento/Analytics/Test/Mftf/Test/AdminConfigurationIndustryTest.xml b/app/code/Magento/Analytics/Test/Mftf/Test/AdminConfigurationIndustryTest.xml index 6b38bccf33dd5..d4f30737bae3e 100644 --- a/app/code/Magento/Analytics/Test/Mftf/Test/AdminConfigurationIndustryTest.xml +++ b/app/code/Magento/Analytics/Test/Mftf/Test/AdminConfigurationIndustryTest.xml @@ -17,8 +17,9 @@ - - + + + diff --git a/app/code/Magento/Analytics/Test/Mftf/Test/AdminConfigurationPermissionTest.xml b/app/code/Magento/Analytics/Test/Mftf/Test/AdminConfigurationPermissionTest.xml index 501dba3dba23b..b3ccd3afd1bf7 100644 --- a/app/code/Magento/Analytics/Test/Mftf/Test/AdminConfigurationPermissionTest.xml +++ b/app/code/Magento/Analytics/Test/Mftf/Test/AdminConfigurationPermissionTest.xml @@ -17,8 +17,9 @@ - - + + + diff --git a/app/code/Magento/Analytics/Test/Mftf/composer.json b/app/code/Magento/Analytics/Test/Mftf/composer.json deleted file mode 100644 index cc288fbbb130d..0000000000000 --- a/app/code/Magento/Analytics/Test/Mftf/composer.json +++ /dev/null @@ -1,20 +0,0 @@ -{ - "name": "magento/functional-test-module-analytics", - "description": "N/A", - "config": { - "sort-packages": true - }, - "require": { - "php": "~7.1.3||~7.2.0", - "magento/functional-test-module-backend": "100.0.0-dev", - "magento/functional-test-module-config": "100.0.0-dev", - "magento/functional-test-module-integration": "100.0.0-dev", - "magento/functional-test-module-store": "100.0.0-dev", - "magento/magento2-functional-testing-framework": "2.2.0" - }, - "type": "magento2-test", - "license": [ - "OSL-3.0", - "AFL-3.0" - ] -} diff --git a/app/code/Magento/AsynchronousOperations/Test/Mftf/composer.json b/app/code/Magento/AsynchronousOperations/Test/Mftf/composer.json deleted file mode 100644 index baadc0d0d914a..0000000000000 --- a/app/code/Magento/AsynchronousOperations/Test/Mftf/composer.json +++ /dev/null @@ -1,24 +0,0 @@ -{ - "name": "magento/functional-test-module-asynchronous-operations", - "description": "N/A", - "config": { - "sort-packages": true - }, - "require": { - "magento/magento2-functional-testing-framework": "2.2.0", - "magento/framework-bulk": "100.0.0-dev", - "magento/functional-test-module-authorization": "100.0.0-dev", - "magento/functional-test-module-backend": "100.0.0-dev", - "magento/functional-test-module-ui": "100.0.0-dev", - "magento/functional-test-module-user": "100.0.0-dev", - "php": "~7.1.3||~7.2.0" - }, - "suggest": { - "magento/functional-test-module-admin-notification": "100.0.0-dev", - "magento/functional-test-module-logging": "100.0.0-dev" - }, - "type": "magento2-test", - "license": [ - "proprietary" - ] -} diff --git a/app/code/Magento/AsynchronousOperations/composer.json b/app/code/Magento/AsynchronousOperations/composer.json index 3acb92710e62b..7d5a097eeea3f 100644 --- a/app/code/Magento/AsynchronousOperations/composer.json +++ b/app/code/Magento/AsynchronousOperations/composer.json @@ -19,7 +19,8 @@ }, "type": "magento2-module", "license": [ - "proprietary" + "OSL-3.0", + "AFL-3.0" ], "autoload": { "files": [ diff --git a/app/code/Magento/Authorization/Test/Mftf/composer.json b/app/code/Magento/Authorization/Test/Mftf/composer.json deleted file mode 100644 index fddc5acb034ed..0000000000000 --- a/app/code/Magento/Authorization/Test/Mftf/composer.json +++ /dev/null @@ -1,17 +0,0 @@ -{ - "name": "magento/functional-test-module-authorization", - "description": "Authorization module provides access to Magento ACL functionality.", - "config": { - "sort-packages": true - }, - "require": { - "php": "~7.1.3||~7.2.0", - "magento/magento2-functional-testing-framework": "2.2.0", - "magento/functional-test-module-backend": "100.0.0-dev" - }, - "type": "magento2-test", - "license": [ - "OSL-3.0", - "AFL-3.0" - ] -} diff --git a/app/code/Magento/Authorizenet/Test/Mftf/composer.json b/app/code/Magento/Authorizenet/Test/Mftf/composer.json deleted file mode 100644 index b02806a0ae3f3..0000000000000 --- a/app/code/Magento/Authorizenet/Test/Mftf/composer.json +++ /dev/null @@ -1,25 +0,0 @@ -{ - "name": "magento/functional-test-module-authorizenet", - "description": "N/A", - "config": { - "sort-packages": true - }, - "require": { - "php": "~7.1.3||~7.2.0", - "magento/magento2-functional-testing-framework": "2.2.0", - "magento/functional-test-module-backend": "100.0.0-dev", - "magento/functional-test-module-catalog": "100.0.0-dev", - "magento/functional-test-module-checkout": "100.0.0-dev", - "magento/functional-test-module-payment": "100.0.0-dev", - "magento/functional-test-module-quote": "100.0.0-dev", - "magento/functional-test-module-sales": "100.0.0-dev", - "magento/functional-test-module-store": "100.0.0-dev" - }, - "suggest": { - "magento/functional-test-module-config": "100.0.0-dev" - }, - "type": "magento2-test", - "license": [ - "proprietary" - ] -} diff --git a/app/code/Magento/Authorizenet/composer.json b/app/code/Magento/Authorizenet/composer.json index 31f2295da4307..4e646004d9a6d 100644 --- a/app/code/Magento/Authorizenet/composer.json +++ b/app/code/Magento/Authorizenet/composer.json @@ -20,7 +20,8 @@ }, "type": "magento2-module", "license": [ - "proprietary" + "OSL-3.0", + "AFL-3.0" ], "autoload": { "files": [ diff --git a/app/code/Magento/Backend/Block/Dashboard/Bar.php b/app/code/Magento/Backend/Block/Dashboard/Bar.php index 29557f12c1093..7ccb2d51ccd1b 100644 --- a/app/code/Magento/Backend/Block/Dashboard/Bar.php +++ b/app/code/Magento/Backend/Block/Dashboard/Bar.php @@ -38,14 +38,6 @@ public function getTotals() */ public function addTotal($label, $value, $isQuantity = false) { - /*if (!$isQuantity) { - $value = $this->format($value); - $decimals = substr($value, -2); - $value = substr($value, 0, -2); - } else { - $value = ($value != '')?$value:0; - $decimals = ''; - }*/ if (!$isQuantity) { $value = $this->format($value); } diff --git a/app/code/Magento/Backend/Block/System/Store/Delete/Group.php b/app/code/Magento/Backend/Block/System/Store/Delete/Group.php index ae80b56066a6d..e95f3bbf9f8c1 100644 --- a/app/code/Magento/Backend/Block/System/Store/Delete/Group.php +++ b/app/code/Magento/Backend/Block/System/Store/Delete/Group.php @@ -19,7 +19,7 @@ protected function _prepareLayout() { $itemId = $this->getRequest()->getParam('group_id'); - $this->setTemplate('system/store/delete_group.phtml'); + $this->setTemplate('Magento_Backend::system/store/delete_group.phtml'); $this->setAction($this->getUrl('adminhtml/*/deleteGroupPost', ['group_id' => $itemId])); $this->addChild( 'confirm_deletion_button', diff --git a/app/code/Magento/Backend/Block/System/Store/Delete/Website.php b/app/code/Magento/Backend/Block/System/Store/Delete/Website.php index da28a471130cc..82cbb780137b8 100644 --- a/app/code/Magento/Backend/Block/System/Store/Delete/Website.php +++ b/app/code/Magento/Backend/Block/System/Store/Delete/Website.php @@ -19,7 +19,7 @@ protected function _prepareLayout() { $itemId = $this->getRequest()->getParam('website_id'); - $this->setTemplate('system/store/delete_website.phtml'); + $this->setTemplate('Magento_Backend::system/store/delete_website.phtml'); $this->setAction($this->getUrl('adminhtml/*/deleteWebsitePost', ['website_id' => $itemId])); $this->addChild( 'confirm_deletion_button', diff --git a/app/code/Magento/Backend/Helper/Dashboard/Order.php b/app/code/Magento/Backend/Helper/Dashboard/Order.php index 9fc2c2cdb4e6f..c19c28b6e33eb 100644 --- a/app/code/Magento/Backend/Helper/Dashboard/Order.php +++ b/app/code/Magento/Backend/Helper/Dashboard/Order.php @@ -13,7 +13,7 @@ * @api * @since 100.0.2 */ -class Order extends \Magento\Backend\Helper\Dashboard\AbstractDashboard +class Order extends AbstractDashboard { /** * @var \Magento\Reports\Model\ResourceModel\Order\Collection @@ -29,32 +29,25 @@ class Order extends \Magento\Backend\Helper\Dashboard\AbstractDashboard /** * @param \Magento\Framework\App\Helper\Context $context * @param \Magento\Reports\Model\ResourceModel\Order\Collection $orderCollection + * @param \Magento\Store\Model\StoreManagerInterface $storeManager */ public function __construct( \Magento\Framework\App\Helper\Context $context, - \Magento\Reports\Model\ResourceModel\Order\Collection $orderCollection + \Magento\Reports\Model\ResourceModel\Order\Collection $orderCollection, + \Magento\Store\Model\StoreManagerInterface $storeManager = null ) { $this->_orderCollection = $orderCollection; - parent::__construct($context); - } + $this->_storeManager = $storeManager ?: ObjectManager::getInstance() + ->get(\Magento\Store\Model\StoreManagerInterface::class); - /** - * The getter function to get the new StoreManager dependency - * - * @return \Magento\Store\Model\StoreManagerInterface - * - * @deprecated 100.1.0 - */ - private function getStoreManager() - { - if ($this->_storeManager === null) { - $this->_storeManager = ObjectManager::getInstance()->get(\Magento\Store\Model\StoreManagerInterface::class); - } - return $this->_storeManager; + parent::__construct($context); } /** * @return void + * + * @throws \Magento\Framework\Exception\LocalizedException + * @throws \Magento\Framework\Exception\NoSuchEntityException */ protected function _initCollection() { @@ -65,15 +58,15 @@ protected function _initCollection() if ($this->getParam('store')) { $this->_collection->addFieldToFilter('store_id', $this->getParam('store')); } elseif ($this->getParam('website')) { - $storeIds = $this->getStoreManager()->getWebsite($this->getParam('website'))->getStoreIds(); + $storeIds = $this->_storeManager->getWebsite($this->getParam('website'))->getStoreIds(); $this->_collection->addFieldToFilter('store_id', ['in' => implode(',', $storeIds)]); } elseif ($this->getParam('group')) { - $storeIds = $this->getStoreManager()->getGroup($this->getParam('group'))->getStoreIds(); + $storeIds = $this->_storeManager->getGroup($this->getParam('group'))->getStoreIds(); $this->_collection->addFieldToFilter('store_id', ['in' => implode(',', $storeIds)]); } elseif (!$this->_collection->isLive()) { $this->_collection->addFieldToFilter( 'store_id', - ['eq' => $this->getStoreManager()->getStore(\Magento\Store\Model\Store::ADMIN_CODE)->getId()] + ['eq' => $this->_storeManager->getStore(\Magento\Store\Model\Store::ADMIN_CODE)->getId()] ); } $this->_collection->load(); diff --git a/app/code/Magento/Backend/Test/Mftf/composer.json b/app/code/Magento/Backend/Test/Mftf/composer.json deleted file mode 100644 index adc3900cfe054..0000000000000 --- a/app/code/Magento/Backend/Test/Mftf/composer.json +++ /dev/null @@ -1,35 +0,0 @@ -{ - "name": "magento/functional-test-module-backend", - "description": "N/A", - "config": { - "sort-packages": true - }, - "require": { - "php": "~7.1.3||~7.2.0", - "magento/magento2-functional-testing-framework": "2.2.0", - "magento/functional-test-module-backup": "100.0.0-dev", - "magento/functional-test-module-catalog": "100.0.0-dev", - "magento/functional-test-module-config": "100.0.0-dev", - "magento/functional-test-module-customer": "100.0.0-dev", - "magento/functional-test-module-developer": "100.0.0-dev", - "magento/functional-test-module-directory": "100.0.0-dev", - "magento/functional-test-module-eav": "100.0.0-dev", - "magento/functional-test-module-quote": "100.0.0-dev", - "magento/functional-test-module-reports": "100.0.0-dev", - "magento/functional-test-module-require-js": "100.0.0-dev", - "magento/functional-test-module-sales": "100.0.0-dev", - "magento/functional-test-module-security": "100.0.0-dev", - "magento/functional-test-module-store": "100.0.0-dev", - "magento/functional-test-module-translation": "100.0.0-dev", - "magento/functional-test-module-ui": "100.0.0-dev", - "magento/functional-test-module-user": "100.0.0-dev" - }, - "suggest": { - "magento/functional-test-module-theme": "100.0.0-dev" - }, - "type": "magento2-test", - "license": [ - "OSL-3.0", - "AFL-3.0" - ] -} diff --git a/app/code/Magento/Backup/Test/Mftf/composer.json b/app/code/Magento/Backup/Test/Mftf/composer.json deleted file mode 100644 index d7a6c804ab5b3..0000000000000 --- a/app/code/Magento/Backup/Test/Mftf/composer.json +++ /dev/null @@ -1,19 +0,0 @@ -{ - "name": "magento/functional-test-module-backup", - "description": "N/A", - "config": { - "sort-packages": true - }, - "require": { - "php": "~7.1.3||~7.2.0", - "magento/magento2-functional-testing-framework": "2.2.0", - "magento/functional-test-module-backend": "100.0.0-dev", - "magento/functional-test-module-cron": "100.0.0-dev", - "magento/functional-test-module-store": "100.0.0-dev" - }, - "type": "magento2-test", - "license": [ - "OSL-3.0", - "AFL-3.0" - ] -} diff --git a/app/code/Magento/Backup/Test/Unit/Model/DbTest.php b/app/code/Magento/Backup/Test/Unit/Model/DbTest.php new file mode 100644 index 0000000000000..0cab5f0ad1e99 --- /dev/null +++ b/app/code/Magento/Backup/Test/Unit/Model/DbTest.php @@ -0,0 +1,243 @@ +dbResourceMock = $this->getMockBuilder(DbResource::class) + ->disableOriginalConstructor() + ->getMock(); + $this->connectionResourceMock = $this->getMockBuilder(ResourceConnection::class) + ->disableOriginalConstructor() + ->getMock(); + + $this->objectManager = new ObjectManager($this); + $this->dbModel = $this->objectManager->getObject( + Db::class, + [ + 'resourceDb' => $this->dbResourceMock, + 'resource' => $this->connectionResourceMock + ] + ); + } + + public function testGetResource() + { + self::assertEquals($this->dbResourceMock, $this->dbModel->getResource()); + } + + public function testGetTables() + { + $tables = []; + $this->dbResourceMock->expects($this->once()) + ->method('getTables') + ->willReturn($tables); + + self::assertEquals($tables, $this->dbModel->getTables()); + } + + public function testGetTableCreateScript() + { + $tableName = 'some_table'; + $script = 'script'; + $this->dbResourceMock->expects($this->once()) + ->method('getTableCreateScript') + ->with($tableName, false) + ->willReturn($script); + + self::assertEquals($script, $this->dbModel->getTableCreateScript($tableName, false)); + } + + public function testGetTableDataDump() + { + $tableName = 'some_table'; + $dump = 'dump'; + $this->dbResourceMock->expects($this->once()) + ->method('getTableDataDump') + ->with($tableName) + ->willReturn($dump); + + self::assertEquals($dump, $this->dbModel->getTableDataDump($tableName)); + } + + public function testGetHeader() + { + $header = 'header'; + $this->dbResourceMock->expects($this->once()) + ->method('getHeader') + ->willReturn($header); + + self::assertEquals($header, $this->dbModel->getHeader()); + } + + public function testGetFooter() + { + $footer = 'footer'; + $this->dbResourceMock->expects($this->once()) + ->method('getFooter') + ->willReturn($footer); + + self::assertEquals($footer, $this->dbModel->getFooter()); + } + + public function testRenderSql() + { + $header = 'header'; + $script = 'script'; + $tableName = 'some_table'; + $tables = [$tableName, $tableName]; + $dump = 'dump'; + $footer = 'footer'; + + $this->dbResourceMock->expects($this->once()) + ->method('getTables') + ->willReturn($tables); + $this->dbResourceMock->expects($this->once()) + ->method('getHeader') + ->willReturn($header); + $this->dbResourceMock->expects($this->exactly(2)) + ->method('getTableCreateScript') + ->with($tableName, true) + ->willReturn($script); + $this->dbResourceMock->expects($this->exactly(2)) + ->method('getTableDataDump') + ->with($tableName) + ->willReturn($dump); + $this->dbResourceMock->expects($this->once()) + ->method('getFooter') + ->willReturn($footer); + + self::assertEquals( + $header . $script . $dump . $script . $dump . $footer, + $this->dbModel->renderSql() + ); + } + + public function testCreateBackup() + { + /** @var BackupInterface|\PHPUnit_Framework_MockObject_MockObject $backupMock */ + $backupMock = $this->getMockBuilder(BackupInterface::class)->getMock(); + /** @var DataObject $tableStatus */ + $tableStatus = new DataObject(); + + $tableName = 'some_table'; + $tables = [$tableName]; + $header = 'header'; + $footer = 'footer'; + $dropSql = 'drop_sql'; + $createSql = 'create_sql'; + $beforeSql = 'before_sql'; + $afterSql = 'after_sql'; + $dataSql = 'data_sql'; + $foreignKeysSql = 'foreign_keys'; + $triggersSql = 'triggers_sql'; + $rowsCount = 2; + $dataLength = 1; + + $this->dbResourceMock->expects($this->once()) + ->method('beginTransaction'); + $this->dbResourceMock->expects($this->once()) + ->method('commitTransaction'); + $this->dbResourceMock->expects($this->once()) + ->method('getTables') + ->willReturn($tables); + $this->dbResourceMock->expects($this->once()) + ->method('getTableDropSql') + ->willReturn($dropSql); + $this->dbResourceMock->expects($this->once()) + ->method('getTableCreateSql') + ->with($tableName, false) + ->willReturn($createSql); + $this->dbResourceMock->expects($this->once()) + ->method('getTableDataBeforeSql') + ->with($tableName) + ->willReturn($beforeSql); + $this->dbResourceMock->expects($this->once()) + ->method('getTableDataAfterSql') + ->with($tableName) + ->willReturn($afterSql); + $this->dbResourceMock->expects($this->once()) + ->method('getTableDataSql') + ->with($tableName, $rowsCount, 0) + ->willReturn($dataSql); + $this->dbResourceMock->expects($this->once()) + ->method('getTableStatus') + ->with($tableName) + ->willReturn($tableStatus); + $this->dbResourceMock->expects($this->once()) + ->method('getTables') + ->willReturn($createSql); + $this->dbResourceMock->expects($this->once()) + ->method('getHeader') + ->willReturn($header); + $this->dbResourceMock->expects($this->once()) + ->method('getTableHeader') + ->willReturn($header); + $this->dbResourceMock->expects($this->once()) + ->method('getFooter') + ->willReturn($footer); + $this->dbResourceMock->expects($this->once()) + ->method('getTableForeignKeysSql') + ->willReturn($foreignKeysSql); + $this->dbResourceMock->expects($this->once()) + ->method('getTableTriggersSql') + ->willReturn($triggersSql); + $backupMock->expects($this->once()) + ->method('open'); + $backupMock->expects($this->once()) + ->method('close'); + + $tableStatus->setRows($rowsCount); + $tableStatus->setDataLength($dataLength); + + $backupMock->expects($this->any()) + ->method('write') + ->withConsecutive( + [$this->equalTo($header)], + [$this->equalTo($header . $dropSql . "\n")], + [$this->equalTo($createSql . "\n")], + [$this->equalTo($beforeSql)], + [$this->equalTo($dataSql)], + [$this->equalTo($afterSql)], + [$this->equalTo($foreignKeysSql)], + [$this->equalTo($triggersSql)], + [$this->equalTo($footer)] + ); + + $this->dbModel->createBackup($backupMock); + } +} diff --git a/app/code/Magento/Braintree/Gateway/Http/Client/TransactionRefund.php b/app/code/Magento/Braintree/Gateway/Http/Client/TransactionRefund.php index 4c3f1e179d378..6d43929db7675 100644 --- a/app/code/Magento/Braintree/Gateway/Http/Client/TransactionRefund.php +++ b/app/code/Magento/Braintree/Gateway/Http/Client/TransactionRefund.php @@ -17,8 +17,6 @@ class TransactionRefund extends AbstractTransaction protected function process(array $data) { $storeId = $data['store_id'] ?? null; - // sending store id and other additional keys are restricted by Braintree API - unset($data['store_id']); return $this->adapterFactory->create($storeId) ->refund($data['transaction_id'], $data[PaymentDataBuilder::AMOUNT]); diff --git a/app/code/Magento/Braintree/Gateway/Http/Client/TransactionSubmitForSettlement.php b/app/code/Magento/Braintree/Gateway/Http/Client/TransactionSubmitForSettlement.php index 16ebd7a7a00c5..6760e724fd3a6 100644 --- a/app/code/Magento/Braintree/Gateway/Http/Client/TransactionSubmitForSettlement.php +++ b/app/code/Magento/Braintree/Gateway/Http/Client/TransactionSubmitForSettlement.php @@ -19,8 +19,6 @@ class TransactionSubmitForSettlement extends AbstractTransaction protected function process(array $data) { $storeId = $data['store_id'] ?? null; - // sending store id and other additional keys are restricted by Braintree API - unset($data['store_id']); return $this->adapterFactory->create($storeId) ->submitForSettlement($data[CaptureDataBuilder::TRANSACTION_ID], $data[PaymentDataBuilder::AMOUNT]); diff --git a/app/code/Magento/Braintree/Gateway/Http/Client/TransactionVoid.php b/app/code/Magento/Braintree/Gateway/Http/Client/TransactionVoid.php index e9a478a8bac23..0a940839fc154 100644 --- a/app/code/Magento/Braintree/Gateway/Http/Client/TransactionVoid.php +++ b/app/code/Magento/Braintree/Gateway/Http/Client/TransactionVoid.php @@ -15,8 +15,6 @@ class TransactionVoid extends AbstractTransaction protected function process(array $data) { $storeId = $data['store_id'] ?? null; - // sending store id and other additional keys are restricted by Braintree API - unset($data['store_id']); return $this->adapterFactory->create($storeId)->void($data['transaction_id']); } diff --git a/app/code/Magento/Braintree/Test/Mftf/ActionGroup/AdminRoleActionGroup.xml b/app/code/Magento/Braintree/Test/Mftf/ActionGroup/AdminRoleActionGroup.xml new file mode 100644 index 0000000000000..e86d5403e11eb --- /dev/null +++ b/app/code/Magento/Braintree/Test/Mftf/ActionGroup/AdminRoleActionGroup.xml @@ -0,0 +1,51 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/code/Magento/Braintree/Test/Mftf/ActionGroup/AdminUserActionGroup.xml b/app/code/Magento/Braintree/Test/Mftf/ActionGroup/AdminUserActionGroup.xml new file mode 100644 index 0000000000000..23c322083773c --- /dev/null +++ b/app/code/Magento/Braintree/Test/Mftf/ActionGroup/AdminUserActionGroup.xml @@ -0,0 +1,56 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/code/Magento/Braintree/Test/Mftf/ActionGroup/ConfigureBraintreeActionGroup.xml b/app/code/Magento/Braintree/Test/Mftf/ActionGroup/ConfigureBraintreeActionGroup.xml new file mode 100644 index 0000000000000..27e2039fe526e --- /dev/null +++ b/app/code/Magento/Braintree/Test/Mftf/ActionGroup/ConfigureBraintreeActionGroup.xml @@ -0,0 +1,49 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/code/Magento/Braintree/Test/Mftf/ActionGroup/CreateCustomerActionGroup.xml b/app/code/Magento/Braintree/Test/Mftf/ActionGroup/CreateCustomerActionGroup.xml new file mode 100644 index 0000000000000..a68042127ec48 --- /dev/null +++ b/app/code/Magento/Braintree/Test/Mftf/ActionGroup/CreateCustomerActionGroup.xml @@ -0,0 +1,44 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/code/Magento/Braintree/Test/Mftf/ActionGroup/CreateNewOrderActionGroup.xml b/app/code/Magento/Braintree/Test/Mftf/ActionGroup/CreateNewOrderActionGroup.xml new file mode 100644 index 0000000000000..ee7158c2b63f7 --- /dev/null +++ b/app/code/Magento/Braintree/Test/Mftf/ActionGroup/CreateNewOrderActionGroup.xml @@ -0,0 +1,66 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/code/Magento/Braintree/Test/Mftf/ActionGroup/CreateNewProductActionGroup.xml b/app/code/Magento/Braintree/Test/Mftf/ActionGroup/CreateNewProductActionGroup.xml new file mode 100644 index 0000000000000..19de3e859ae9a --- /dev/null +++ b/app/code/Magento/Braintree/Test/Mftf/ActionGroup/CreateNewProductActionGroup.xml @@ -0,0 +1,25 @@ + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/code/Magento/Braintree/Test/Mftf/ActionGroup/DeleteCustomerActionGroup.xml b/app/code/Magento/Braintree/Test/Mftf/ActionGroup/DeleteCustomerActionGroup.xml new file mode 100644 index 0000000000000..65eddc0d9e51a --- /dev/null +++ b/app/code/Magento/Braintree/Test/Mftf/ActionGroup/DeleteCustomerActionGroup.xml @@ -0,0 +1,28 @@ + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/code/Magento/Braintree/Test/Mftf/ActionGroup/DeleteProductActionGroup.xml b/app/code/Magento/Braintree/Test/Mftf/ActionGroup/DeleteProductActionGroup.xml new file mode 100644 index 0000000000000..724c6d92846c4 --- /dev/null +++ b/app/code/Magento/Braintree/Test/Mftf/ActionGroup/DeleteProductActionGroup.xml @@ -0,0 +1,26 @@ + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/code/Magento/Braintree/Test/Mftf/ActionGroup/SwitchAccountActionGroup.xml b/app/code/Magento/Braintree/Test/Mftf/ActionGroup/SwitchAccountActionGroup.xml new file mode 100644 index 0000000000000..7c774a634b369 --- /dev/null +++ b/app/code/Magento/Braintree/Test/Mftf/ActionGroup/SwitchAccountActionGroup.xml @@ -0,0 +1,28 @@ + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/code/Magento/Braintree/Test/Mftf/Data/BraintreeData.xml b/app/code/Magento/Braintree/Test/Mftf/Data/BraintreeData.xml index 6e669a1b8bf4b..208c8b25d8d64 100644 --- a/app/code/Magento/Braintree/Test/Mftf/Data/BraintreeData.xml +++ b/app/code/Magento/Braintree/Test/Mftf/Data/BraintreeData.xml @@ -62,4 +62,40 @@ + + + Website + new_website + Store + new_store + Block + + + + Role + + + admin + John + Smith + admin123 + mail@mail.com + + + + 5105105105105100 + 12 + 20 + 113 + + + + Credit Card (Braintree) + d4pdjhxgjfrsmzbf + m7q4wmh43xrgyrst + 67de364080b1b4e2492d7a3de413a572 + Magneto + PayPal (Braintree) + + diff --git a/app/code/Magento/Braintree/Test/Mftf/Data/NewCustomerData.xml b/app/code/Magento/Braintree/Test/Mftf/Data/NewCustomerData.xml new file mode 100644 index 0000000000000..772c1c39a04ca --- /dev/null +++ b/app/code/Magento/Braintree/Test/Mftf/Data/NewCustomerData.xml @@ -0,0 +1,23 @@ + + + + + + Abgar + Abgaryan + m@m.com + Abgar + Abgaryan + Street + Yerevan + 9999 + 9999 + + + diff --git a/app/code/Magento/Braintree/Test/Mftf/Data/NewProductData.xml b/app/code/Magento/Braintree/Test/Mftf/Data/NewProductData.xml new file mode 100644 index 0000000000000..72661ae94076f --- /dev/null +++ b/app/code/Magento/Braintree/Test/Mftf/Data/NewProductData.xml @@ -0,0 +1,17 @@ + + + + + + ProductTest + 100 + 100 + + + diff --git a/app/code/Magento/Braintree/Test/Mftf/Section/AdminCreateRoleSection.xml b/app/code/Magento/Braintree/Test/Mftf/Section/AdminCreateRoleSection.xml new file mode 100644 index 0000000000000..1158f471d51f0 --- /dev/null +++ b/app/code/Magento/Braintree/Test/Mftf/Section/AdminCreateRoleSection.xml @@ -0,0 +1,24 @@ + + + +
+ + + + + + + + + + + + + +
+
\ No newline at end of file diff --git a/app/code/Magento/Braintree/Test/Mftf/Section/AdminCreateUserSection.xml b/app/code/Magento/Braintree/Test/Mftf/Section/AdminCreateUserSection.xml new file mode 100644 index 0000000000000..98d748b5a30ea --- /dev/null +++ b/app/code/Magento/Braintree/Test/Mftf/Section/AdminCreateUserSection.xml @@ -0,0 +1,23 @@ + + + +
+ + + + + + + + + + + + +
+
\ No newline at end of file diff --git a/app/code/Magento/Braintree/Test/Mftf/Section/AdminDeleteRoleSection.xml b/app/code/Magento/Braintree/Test/Mftf/Section/AdminDeleteRoleSection.xml new file mode 100644 index 0000000000000..220c9a444b02f --- /dev/null +++ b/app/code/Magento/Braintree/Test/Mftf/Section/AdminDeleteRoleSection.xml @@ -0,0 +1,15 @@ + + + +
+ + + + +
+
\ No newline at end of file diff --git a/app/code/Magento/Braintree/Test/Mftf/Section/AdminDeleteUserSection.xml b/app/code/Magento/Braintree/Test/Mftf/Section/AdminDeleteUserSection.xml new file mode 100644 index 0000000000000..bf2e2b44eb602 --- /dev/null +++ b/app/code/Magento/Braintree/Test/Mftf/Section/AdminDeleteUserSection.xml @@ -0,0 +1,15 @@ + + + +
+ + + + +
+
\ No newline at end of file diff --git a/app/code/Magento/Braintree/Test/Mftf/Section/AdminEditRoleInfoSection.xml b/app/code/Magento/Braintree/Test/Mftf/Section/AdminEditRoleInfoSection.xml new file mode 100644 index 0000000000000..e37ce8f4738b3 --- /dev/null +++ b/app/code/Magento/Braintree/Test/Mftf/Section/AdminEditRoleInfoSection.xml @@ -0,0 +1,21 @@ + + + +
+ + + + + + + + + + +
+
\ No newline at end of file diff --git a/app/code/Magento/Braintree/Test/Mftf/Section/AdminEditUserRoleSection.xml b/app/code/Magento/Braintree/Test/Mftf/Section/AdminEditUserRoleSection.xml new file mode 100644 index 0000000000000..e999413c96d74 --- /dev/null +++ b/app/code/Magento/Braintree/Test/Mftf/Section/AdminEditUserRoleSection.xml @@ -0,0 +1,17 @@ + + + +
+ + + + + + +
+
\ No newline at end of file diff --git a/app/code/Magento/Braintree/Test/Mftf/Section/AdminEditUserSection.xml b/app/code/Magento/Braintree/Test/Mftf/Section/AdminEditUserSection.xml new file mode 100644 index 0000000000000..2e5fcfb7b5c8d --- /dev/null +++ b/app/code/Magento/Braintree/Test/Mftf/Section/AdminEditUserSection.xml @@ -0,0 +1,28 @@ + + + +
+ + + + + + + + + + + + + + + + + +
+
\ No newline at end of file diff --git a/app/code/Magento/Braintree/Test/Mftf/Section/AdminMenuSection.xml b/app/code/Magento/Braintree/Test/Mftf/Section/AdminMenuSection.xml new file mode 100644 index 0000000000000..660c7393b4061 --- /dev/null +++ b/app/code/Magento/Braintree/Test/Mftf/Section/AdminMenuSection.xml @@ -0,0 +1,23 @@ + + + + +
+ + + + + + + + + + +
+
diff --git a/app/code/Magento/Braintree/Test/Mftf/Section/AdminRoleGridSection.xml b/app/code/Magento/Braintree/Test/Mftf/Section/AdminRoleGridSection.xml new file mode 100644 index 0000000000000..63cbadc71d3d3 --- /dev/null +++ b/app/code/Magento/Braintree/Test/Mftf/Section/AdminRoleGridSection.xml @@ -0,0 +1,17 @@ + + + +
+ + + + + + +
+
\ No newline at end of file diff --git a/app/code/Magento/Braintree/Test/Mftf/Section/AdminUserGridSection.xml b/app/code/Magento/Braintree/Test/Mftf/Section/AdminUserGridSection.xml new file mode 100644 index 0000000000000..9564bc61f799c --- /dev/null +++ b/app/code/Magento/Braintree/Test/Mftf/Section/AdminUserGridSection.xml @@ -0,0 +1,17 @@ + + + +
+ + + + + + +
+
\ No newline at end of file diff --git a/app/code/Magento/Braintree/Test/Mftf/Section/BraintreeConfiguraionSection.xml b/app/code/Magento/Braintree/Test/Mftf/Section/BraintreeConfiguraionSection.xml new file mode 100644 index 0000000000000..016af2e102744 --- /dev/null +++ b/app/code/Magento/Braintree/Test/Mftf/Section/BraintreeConfiguraionSection.xml @@ -0,0 +1,34 @@ + + + +
+ + + + + + + + + + + + + + + + + + + + + + + +
+
\ No newline at end of file diff --git a/app/code/Magento/Braintree/Test/Mftf/Section/CatalogSubmenuSection.xml b/app/code/Magento/Braintree/Test/Mftf/Section/CatalogSubmenuSection.xml new file mode 100644 index 0000000000000..32f02a69f817e --- /dev/null +++ b/app/code/Magento/Braintree/Test/Mftf/Section/CatalogSubmenuSection.xml @@ -0,0 +1,14 @@ + + + + +
+ +
+
diff --git a/app/code/Magento/Braintree/Test/Mftf/Section/ConfigurationListSection.xml b/app/code/Magento/Braintree/Test/Mftf/Section/ConfigurationListSection.xml new file mode 100644 index 0000000000000..100407438eaae --- /dev/null +++ b/app/code/Magento/Braintree/Test/Mftf/Section/ConfigurationListSection.xml @@ -0,0 +1,15 @@ + + + + +
+ + +
+
diff --git a/app/code/Magento/Braintree/Test/Mftf/Section/ConfigurationPaymentSection.xml b/app/code/Magento/Braintree/Test/Mftf/Section/ConfigurationPaymentSection.xml new file mode 100644 index 0000000000000..885a45be721f1 --- /dev/null +++ b/app/code/Magento/Braintree/Test/Mftf/Section/ConfigurationPaymentSection.xml @@ -0,0 +1,14 @@ + + + + +
+ +
+
diff --git a/app/code/Magento/Braintree/Test/Mftf/Section/CustomersPageSection.xml b/app/code/Magento/Braintree/Test/Mftf/Section/CustomersPageSection.xml new file mode 100644 index 0000000000000..e4a75b1b6a842 --- /dev/null +++ b/app/code/Magento/Braintree/Test/Mftf/Section/CustomersPageSection.xml @@ -0,0 +1,19 @@ + + + + +
+ + + + + + +
+
diff --git a/app/code/Magento/Braintree/Test/Mftf/Section/CustomersSubmenuSection.xml b/app/code/Magento/Braintree/Test/Mftf/Section/CustomersSubmenuSection.xml new file mode 100644 index 0000000000000..937afb83da96f --- /dev/null +++ b/app/code/Magento/Braintree/Test/Mftf/Section/CustomersSubmenuSection.xml @@ -0,0 +1,14 @@ + + + + +
+ +
+
diff --git a/app/code/Magento/Braintree/Test/Mftf/Section/NewCustomerPageSection.xml b/app/code/Magento/Braintree/Test/Mftf/Section/NewCustomerPageSection.xml new file mode 100644 index 0000000000000..d302f9c7d0cba --- /dev/null +++ b/app/code/Magento/Braintree/Test/Mftf/Section/NewCustomerPageSection.xml @@ -0,0 +1,33 @@ + + + + +
+ + + + + + + + + + + + + + + + + + + + +
+
diff --git a/app/code/Magento/Braintree/Test/Mftf/Section/NewOrderSection.xml b/app/code/Magento/Braintree/Test/Mftf/Section/NewOrderSection.xml new file mode 100644 index 0000000000000..13f59ad2cf18e --- /dev/null +++ b/app/code/Magento/Braintree/Test/Mftf/Section/NewOrderSection.xml @@ -0,0 +1,35 @@ + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + +
+
\ No newline at end of file diff --git a/app/code/Magento/Braintree/Test/Mftf/Section/NewProductPageSection.xml b/app/code/Magento/Braintree/Test/Mftf/Section/NewProductPageSection.xml new file mode 100644 index 0000000000000..42e451940c91b --- /dev/null +++ b/app/code/Magento/Braintree/Test/Mftf/Section/NewProductPageSection.xml @@ -0,0 +1,19 @@ + + + + +
+ + + + + + +
+
diff --git a/app/code/Magento/Braintree/Test/Mftf/Section/ProductsPageSection.xml b/app/code/Magento/Braintree/Test/Mftf/Section/ProductsPageSection.xml new file mode 100644 index 0000000000000..267efdf3d0e5e --- /dev/null +++ b/app/code/Magento/Braintree/Test/Mftf/Section/ProductsPageSection.xml @@ -0,0 +1,20 @@ + + + + +
+ + + + + + + +
+
diff --git a/app/code/Magento/Braintree/Test/Mftf/Section/StoresSubmenuSection.xml b/app/code/Magento/Braintree/Test/Mftf/Section/StoresSubmenuSection.xml new file mode 100644 index 0000000000000..f094baa9f3446 --- /dev/null +++ b/app/code/Magento/Braintree/Test/Mftf/Section/StoresSubmenuSection.xml @@ -0,0 +1,14 @@ + + + + +
+ +
+
diff --git a/app/code/Magento/Braintree/Test/Mftf/Section/SwitchAccountSection.xml b/app/code/Magento/Braintree/Test/Mftf/Section/SwitchAccountSection.xml new file mode 100644 index 0000000000000..3a07cbc6dd145 --- /dev/null +++ b/app/code/Magento/Braintree/Test/Mftf/Section/SwitchAccountSection.xml @@ -0,0 +1,24 @@ + + + + + +
+ + + +
+ +
+ + +
+ +
+ diff --git a/app/code/Magento/Braintree/Test/Mftf/Test/CreateAnAdminOrderUsingBraintreePaymentTest1.xml b/app/code/Magento/Braintree/Test/Mftf/Test/CreateAnAdminOrderUsingBraintreePaymentTest1.xml new file mode 100644 index 0000000000000..df2e98816f0d3 --- /dev/null +++ b/app/code/Magento/Braintree/Test/Mftf/Test/CreateAnAdminOrderUsingBraintreePaymentTest1.xml @@ -0,0 +1,87 @@ + + + + + + + + + + <description value="Admin should be able to create order using Braintree payment"/> + <severity value="CRITICAL"/> + <testCaseId value="MAGETWO-93677"/> + <group value="braintree"/> + <skip> + <issueId value="MQE-1187" /> + </skip> + </annotations> + + + <before> + <!--Login As Admin--> + <actionGroup ref="LoginAsAdmin" stepKey="loginAsAdmin"/> + + <!--CreateNewProduct--> + <actionGroup ref="CreateNewProductActionGroup" stepKey="CreateNewProduct"/> + + <!--Create New Customer--> + <actionGroup ref="CreateCustomerActionGroup" stepKey="CreateCustomer"/> + + </before> + + + <!--Configure Braintree--> + <actionGroup ref="ConfigureBraintree" stepKey="configureBraintree"/> + + <!--Create New Role--> + <actionGroup ref="GoToUserRoles" stepKey="GoToUserRoles"/> + <actionGroup ref="AdminCreateRole" stepKey="AdminCreateNewRole"/> + + <!--Create New User With Specific Role--> + <actionGroup ref="GoToAllUsers" stepKey="GoToAllUsers"/> + <actionGroup ref="AdminCreateUserAction" stepKey="AdminCreateNewUser"/> + + <!--SignOut--> + <actionGroup ref="SignOut" stepKey="signOutFromAdmin"/> + + <!--SignIn New User--> + <actionGroup ref="LoginNewUser" stepKey="signInNewUser"/> + <waitForPageLoad stepKey="waitForLogin" time="3"/> + + <!--Create New Order--> + <actionGroup ref="CreateNewOrderActionGroup" stepKey="createNewOrder"/> + + + <after> + <!--SignOut--> + <actionGroup ref="SignOut" stepKey="signOutFromNewUser"/> + <actionGroup ref="LoginAsAdmin" stepKey="loginAsAdmin"/> + + <!--Delete Product--> + <actionGroup ref="DeleteProductActionGroup" stepKey="DeleteAllProducts"> + <argument name="productName" value="NewProductData.ProductName"/> + </actionGroup> + + <!--Delete Customer--> + <actionGroup ref="DeleteCustomerActionGroup" stepKey="DeleteCustomer"> + <argument name="lastName" value="NewCustomerData.LastName"/> + </actionGroup> + + <!--Delete User --> + <actionGroup ref="GoToAllUsers" stepKey="GoBackToAllUsers"/> + <actionGroup ref="AdminDeleteUserActionGroup" stepKey="AdminDeleteUserActionGroup"/> + + <!--Delete Role--> + <actionGroup ref="GoToUserRoles" stepKey="GoBackToUserRoles"/> + <actionGroup ref="AdminDeleteRoleActionGroup" stepKey="AdminDeleteRoleActionGroup"/> + + </after> + + </test> +</tests> diff --git a/app/code/Magento/Braintree/Test/Mftf/composer.json b/app/code/Magento/Braintree/Test/Mftf/composer.json deleted file mode 100644 index 2f827424cb7f1..0000000000000 --- a/app/code/Magento/Braintree/Test/Mftf/composer.json +++ /dev/null @@ -1,33 +0,0 @@ -{ - "name": "magento/functional-test-module-braintree", - "description": "N/A", - "config": { - "sort-packages": true - }, - "require": { - "php": "~7.1.3||~7.2.0", - "magento/magento2-functional-testing-framework": "2.2.0", - "magento/magento-composer-installer": "100.0.0-dev", - "magento/functional-test-module-catalog": "100.0.0-dev", - "magento/functional-test-module-backend": "100.0.0-dev", - "magento/functional-test-module-checkout": "100.0.0-dev", - "magento/functional-test-module-config": "100.0.0-dev", - "magento/functional-test-module-customer": "100.0.0-dev", - "magento/functional-test-module-directory": "100.0.0-dev", - "magento/functional-test-module-instant-purchase": "100.0.0-dev", - "magento/functional-test-module-payment": "100.0.0-dev", - "magento/functional-test-module-paypal": "100.0.0-dev", - "magento/functional-test-module-quote": "100.0.0-dev", - "magento/functional-test-module-sales": "100.0.0-dev", - "magento/functional-test-module-ui": "100.0.0-dev", - "magento/functional-test-module-vault": "100.0.0-dev" - }, - "suggest": { - "magento/functional-test-module-checkout-agreements": "100.0.0-dev", - "magento/functional-test-module-theme": "100.0.0-dev" - }, - "type": "magento2-test", - "license": [ - "proprietary" - ] -} diff --git a/app/code/Magento/Braintree/Test/Unit/Model/InstantPurchase/CreditCard/AvailabilityCheckerTest.php b/app/code/Magento/Braintree/Test/Unit/Model/InstantPurchase/CreditCard/AvailabilityCheckerTest.php new file mode 100644 index 0000000000000..2248aab1aad2e --- /dev/null +++ b/app/code/Magento/Braintree/Test/Unit/Model/InstantPurchase/CreditCard/AvailabilityCheckerTest.php @@ -0,0 +1,70 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +declare(strict_types=1); + +namespace Magento\Braintree\Test\Unit\Model\InstantPurchase\CreditCard; + +use Magento\Braintree\Gateway\Config\Config; +use Magento\Braintree\Model\InstantPurchase\CreditCard\AvailabilityChecker; + +/** + * @covers \Magento\Braintree\Model\InstantPurchase\CreditCard\AvailabilityChecker + */ +class AvailabilityCheckerTest extends \PHPUnit\Framework\TestCase +{ + /** + * Testable Object + * + * @var AvailabilityChecker + */ + private $availabilityChecker; + + /** + * @var Config|\PHPUnit_Framework_MockObject_MockObject + */ + private $configMock; + + /** + * Set Up + * + * @return void + */ + protected function setUp() + { + $this->configMock = $this->createMock(Config::class); + $this->availabilityChecker = new AvailabilityChecker($this->configMock); + } + + /** + * Test isAvailable method + * + * @dataProvider isAvailableDataProvider + * + * @param bool $isVerify3DSecure + * @param bool $expected + * + * @return void + */ + public function testIsAvailable(bool $isVerify3DSecure, bool $expected) + { + $this->configMock->expects($this->once())->method('isVerify3DSecure')->willReturn($isVerify3DSecure); + $actual = $this->availabilityChecker->isAvailable(); + self::assertEquals($expected, $actual); + } + + /** + * Data provider for isAvailable method test + * + * @return array + */ + public function isAvailableDataProvider() + { + return [ + [true, false], + [false, true], + ]; + } +} diff --git a/app/code/Magento/Braintree/Test/Unit/Model/InstantPurchase/CreditCard/TokenFormatterTest.php b/app/code/Magento/Braintree/Test/Unit/Model/InstantPurchase/CreditCard/TokenFormatterTest.php new file mode 100644 index 0000000000000..a5c7cd743d85f --- /dev/null +++ b/app/code/Magento/Braintree/Test/Unit/Model/InstantPurchase/CreditCard/TokenFormatterTest.php @@ -0,0 +1,119 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +declare(strict_types=1); + +namespace Magento\Braintree\Test\Unit\Model\InstantPurchase\CreditCard; + +use Magento\Braintree\Model\InstantPurchase\CreditCard\TokenFormatter as CreditCardTokenFormatter; +use Magento\Vault\Api\Data\PaymentTokenInterface; +use PHPUnit\Framework\TestCase; +use PHPUnit_Framework_MockObject_MockObject; + +class TokenFormatterTest extends TestCase +{ + /** + * @var PaymentTokenInterface|PHPUnit_Framework_MockObject_MockObject + */ + private $paymentTokenMock; + + /** + * @var CreditCardTokenFormatter + */ + private $creditCardTokenFormatter; + + /** + * @var array + */ + private $tokenDetails = [ + 'type' => 'visa', + 'maskedCC' => '1111************9999', + 'expirationDate' => '01-01-2020' + ]; + + /** + * Set Up + * + * @return void + */ + protected function setUp() + { + $this->paymentTokenMock = $this->getMockBuilder(PaymentTokenInterface::class) + ->getMockForAbstractClass(); + + $this->creditCardTokenFormatter = new CreditCardTokenFormatter(); + } + + /** + * Testing the payment format with a known credit card type + * + * @return void + */ + public function testFormatPaymentTokenWithKnownCardType() + { + $this->tokenDetails['type'] = key(CreditCardTokenFormatter::$baseCardTypes); + $this->paymentTokenMock->expects($this->once()) + ->method('getTokenDetails') + ->willReturn(json_encode($this->tokenDetails)); + + $formattedString = sprintf( + '%s: %s, %s: %s (%s: %s)', + __('Credit Card'), + reset(CreditCardTokenFormatter::$baseCardTypes), + __('ending'), + $this->tokenDetails['maskedCC'], + __('expires'), + $this->tokenDetails['expirationDate'] + ); + + self::assertEquals( + $formattedString, + $this->creditCardTokenFormatter->formatPaymentToken($this->paymentTokenMock) + ); + } + + /** + * Testing the payment format with a unknown credit card type + * + * @return void + */ + public function testFormatPaymentTokenWithUnknownCardType() + { + $this->paymentTokenMock->expects($this->once()) + ->method('getTokenDetails') + ->willReturn(json_encode($this->tokenDetails)); + + $formattedString = sprintf( + '%s: %s, %s: %s (%s: %s)', + __('Credit Card'), + $this->tokenDetails['type'], + __('ending'), + $this->tokenDetails['maskedCC'], + __('expires'), + $this->tokenDetails['expirationDate'] + ); + + self::assertEquals( + $formattedString, + $this->creditCardTokenFormatter->formatPaymentToken($this->paymentTokenMock) + ); + } + + /** + * Testing the payment format with wrong card data + * + * @return void + */ + public function testFormatPaymentTokenWithWrongData() + { + unset($this->tokenDetails['type']); + $this->paymentTokenMock->expects($this->once()) + ->method('getTokenDetails') + ->willReturn(json_encode($this->tokenDetails)); + self::expectException('\InvalidArgumentException'); + + $this->creditCardTokenFormatter->formatPaymentToken($this->paymentTokenMock); + } +} diff --git a/app/code/Magento/Braintree/Test/Unit/Model/InstantPurchase/PayPal/TokenFormatterTest.php b/app/code/Magento/Braintree/Test/Unit/Model/InstantPurchase/PayPal/TokenFormatterTest.php new file mode 100644 index 0000000000000..e4cd8fd58043b --- /dev/null +++ b/app/code/Magento/Braintree/Test/Unit/Model/InstantPurchase/PayPal/TokenFormatterTest.php @@ -0,0 +1,104 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +declare(strict_types=1); + +namespace Magento\Braintree\Test\Unit\Model\InstantPurchase\PayPal; + +use Magento\Braintree\Model\InstantPurchase\CreditCard\TokenFormatter as PaypalTokenFormatter; +use Magento\Vault\Api\Data\PaymentTokenInterface; + +class TokenFormatterTest extends \PHPUnit\Framework\TestCase +{ + /** + * @var PaymentTokenInterface|\PHPUnit_Framework_MockObject_MockObject + */ + private $paymentTokenMock; + + /** + * @var PaypalTokenFormatter + */ + private $paypalTokenFormatter; + + /** + * @var array + */ + private $tokenDetails = [ + 'type' => 'visa', + 'maskedCC' => '4444************9999', + 'expirationDate' => '07-07-2025' + ]; + + /** + * Test setup + */ + protected function setUp() + { + $this->paymentTokenMock = $this->getMockBuilder(PaymentTokenInterface::class) + ->getMockForAbstractClass(); + + $this->paypalTokenFormatter = new PaypalTokenFormatter(); + } + + /** + * testFormatPaymentTokenWithKnownCardType + */ + public function testFormatPaymentTokenWithKnownCardType() + { + $this->tokenDetails['type'] = key(PaypalTokenFormatter::$baseCardTypes); + $this->paymentTokenMock->expects($this->once()) + ->method('getTokenDetails') + ->willReturn(json_encode($this->tokenDetails)); + + $formattedString = sprintf( + '%s: %s, %s: %s (%s: %s)', + __('Credit Card'), + reset(PaypalTokenFormatter::$baseCardTypes), + __('ending'), + $this->tokenDetails['maskedCC'], + __('expires'), + $this->tokenDetails['expirationDate'] + ); + + self::assertEquals($formattedString, $this->paypalTokenFormatter->formatPaymentToken($this->paymentTokenMock)); + } + + /** + * testFormatPaymentTokenWithUnknownCardType + */ + public function testFormatPaymentTokenWithUnknownCardType() + { + $this->paymentTokenMock->expects($this->once()) + ->method('getTokenDetails') + ->willReturn(json_encode($this->tokenDetails)); + + $formattedString = sprintf( + '%s: %s, %s: %s (%s: %s)', + __('Credit Card'), + $this->tokenDetails['type'], + __('ending'), + $this->tokenDetails['maskedCC'], + __('expires'), + $this->tokenDetails['expirationDate'] + ); + + self::assertEquals($formattedString, $this->paypalTokenFormatter->formatPaymentToken($this->paymentTokenMock)); + } + + /** + * testFormatPaymentTokenWithWrongData + */ + public function testFormatPaymentTokenWithWrongData() + { + unset($this->tokenDetails['type']); + + $this->paymentTokenMock->expects($this->once()) + ->method('getTokenDetails') + ->willReturn(json_encode($this->tokenDetails)); + self::expectException('\InvalidArgumentException'); + + $this->paypalTokenFormatter->formatPaymentToken($this->paymentTokenMock); + } +} diff --git a/app/code/Magento/Braintree/Test/Unit/Model/InstantPurchase/PaymentAdditionalInformationProviderTest.php b/app/code/Magento/Braintree/Test/Unit/Model/InstantPurchase/PaymentAdditionalInformationProviderTest.php new file mode 100644 index 0000000000000..2631fcbe5f5b5 --- /dev/null +++ b/app/code/Magento/Braintree/Test/Unit/Model/InstantPurchase/PaymentAdditionalInformationProviderTest.php @@ -0,0 +1,83 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +declare(strict_types=1); + +namespace Magento\Braintree\Test\Unit\Model\InstantPurchase; + +use Magento\Braintree\Gateway\Command\GetPaymentNonceCommand; +use Magento\Braintree\Model\InstantPurchase\PaymentAdditionalInformationProvider; +use Magento\Payment\Gateway\Command\Result\ArrayResult; +use Magento\Vault\Api\Data\PaymentTokenInterface; + +/** + * @covers \Magento\Braintree\Model\InstantPurchase\PaymentAdditionalInformationProvider + */ +class PaymentAdditionalInformationProviderTest extends \PHPUnit\Framework\TestCase +{ + /** + * Testable Object + * + * @var PaymentAdditionalInformationProvider + */ + private $paymentAdditionalInformationProvider; + + /** + * @var GetPaymentNonceCommand|\PHPUnit_Framework_MockObject_MockObject + */ + private $getPaymentNonceCommandMock; + + /** + * @var PaymentTokenInterface|\PHPUnit_Framework_MockObject_MockObject + */ + private $paymentTokenMock; + + /** + * @var ArrayResult|\PHPUnit_Framework_MockObject_MockObject + */ + private $arrayResultMock; + + /** + * Set Up + * + * @return void + */ + protected function setUp() + { + $this->getPaymentNonceCommandMock = $this->createMock(GetPaymentNonceCommand::class); + $this->paymentTokenMock = $this->createMock(PaymentTokenInterface::class); + $this->arrayResultMock = $this->createMock(ArrayResult::class); + $this->paymentAdditionalInformationProvider = new PaymentAdditionalInformationProvider( + $this->getPaymentNonceCommandMock + ); + } + + /** + * Test getAdditionalInformation method + * + * @return void + */ + public function testGetAdditionalInformation() + { + $customerId = 15; + $publicHash = '3n4b7sn48g'; + $paymentMethodNonce = 'test'; + + $this->paymentTokenMock->expects($this->once())->method('getCustomerId')->willReturn($customerId); + $this->paymentTokenMock->expects($this->once())->method('getPublicHash')->willReturn($publicHash); + $this->getPaymentNonceCommandMock->expects($this->once())->method('execute')->with([ + PaymentTokenInterface::CUSTOMER_ID => $customerId, + PaymentTokenInterface::PUBLIC_HASH => $publicHash, + ])->willReturn($this->arrayResultMock); + $this->arrayResultMock->expects($this->once())->method('get') + ->willReturn(['paymentMethodNonce' => $paymentMethodNonce]); + + $expected = [ + 'payment_method_nonce' => $paymentMethodNonce, + ]; + $actual = $this->paymentAdditionalInformationProvider->getAdditionalInformation($this->paymentTokenMock); + self::assertEquals($expected, $actual); + } +} diff --git a/app/code/Magento/Braintree/Test/Unit/Model/LocaleResolverTest.php b/app/code/Magento/Braintree/Test/Unit/Model/LocaleResolverTest.php new file mode 100644 index 0000000000000..b6ef534c55c29 --- /dev/null +++ b/app/code/Magento/Braintree/Test/Unit/Model/LocaleResolverTest.php @@ -0,0 +1,138 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +declare(strict_types=1); + +namespace Magento\Braintree\Test\Unit\Model; + +use Magento\Braintree\Gateway\Config\PayPal\Config; +use Magento\Braintree\Model\LocaleResolver; +use Magento\Framework\Locale\ResolverInterface; + +/** + * @covers \Magento\Braintree\Model\LocaleResolver + */ +class LocaleResolverTest extends \PHPUnit\Framework\TestCase +{ + /** + * Testable Object + * + * @var LocaleResolver + */ + private $localeResolver; + + /** + * @var Config|\PHPUnit_Framework_MockObject_MockObject + */ + private $configMock; + + /** + * @var ResolverInterface|\PHPUnit_Framework_MockObject_MockObject + */ + private $resolverMock; + + /** + * Set Up + * + * @return void + */ + protected function setUp() + { + $this->configMock = $this->createMock(Config::class); + $this->resolverMock = $this->createMock(ResolverInterface::class); + $this->localeResolver = new LocaleResolver($this->resolverMock, $this->configMock); + } + + /** + * Test getDefaultLocalePath method + * + * @return void + */ + public function testGetDefaultLocalePath() + { + $expected = 'general/locale/code'; + $this->resolverMock->expects($this->once())->method('getDefaultLocalePath')->willReturn($expected); + $actual = $this->localeResolver->getDefaultLocalePath(); + self::assertEquals($expected, $actual); + } + + /** + * Test setDefaultLocale method + * + * @return void + */ + public function testSetDefaultLocale() + { + $defaultLocale = 'en_US'; + $this->resolverMock->expects($this->once())->method('setDefaultLocale')->with($defaultLocale); + $this->localeResolver->setDefaultLocale($defaultLocale); + } + + /** + * Test getDefaultLocale method + * + * @return void + */ + public function testGetDefaultLocale() + { + $expected = 'fr_FR'; + $this->resolverMock->expects($this->once())->method('getDefaultLocale')->willReturn($expected); + $actual = $this->localeResolver->getDefaultLocale(); + self::assertEquals($expected, $actual); + } + + /** + * Test setLocale method + * + * @return void + */ + public function testSetLocale() + { + $locale = 'en_GB'; + $this->resolverMock->expects($this->once())->method('setLocale')->with($locale); + $this->localeResolver->setLocale($locale); + } + + /** + * Test getLocale method + * + * @return void + */ + public function testGetLocale() + { + $locale = 'en_TEST'; + $allowedLocales = 'en_US,en_GB,en_AU,da_DK,fr_FR,fr_CA,de_DE,zh_HK,it_IT,nl_NL'; + $this->resolverMock->expects($this->once())->method('getLocale')->willReturn($locale); + $this->configMock->expects($this->once())->method('getValue')->with('supported_locales') + ->willReturn($allowedLocales); + + $expected = 'en_US'; + $actual = $this->localeResolver->getLocale(); + self::assertEquals($expected, $actual); + } + + /** + * Test emulate method + * + * @return void + */ + public function testEmulate() + { + $scopeId = 12; + $this->resolverMock->expects($this->once())->method('emulate')->with($scopeId); + $this->localeResolver->emulate($scopeId); + } + + /** + * Test revert method + * + * @return void + */ + public function testRevert() + { + $this->resolverMock->expects($this->once())->method('revert'); + $this->localeResolver->revert(); + } +} diff --git a/app/code/Magento/Braintree/composer.json b/app/code/Magento/Braintree/composer.json index 8fb98dce72c92..ba51a5436fedb 100644 --- a/app/code/Magento/Braintree/composer.json +++ b/app/code/Magento/Braintree/composer.json @@ -29,7 +29,8 @@ }, "type": "magento2-module", "license": [ - "proprietary" + "OSL-3.0", + "AFL-3.0" ], "autoload": { "files": [ diff --git a/app/code/Magento/Braintree/etc/acl.xml b/app/code/Magento/Braintree/etc/acl.xml index a188586cc0a26..f50a55911d687 100644 --- a/app/code/Magento/Braintree/etc/acl.xml +++ b/app/code/Magento/Braintree/etc/acl.xml @@ -14,6 +14,15 @@ <resource id="Magento_Braintree::settlement_report" title="Braintree Settlement" sortOrder="80" /> </resource> </resource> + <resource id="Magento_Sales::sales"> + <resource id="Magento_Sales::sales_operation"> + <resource id="Magento_Sales::sales_order"> + <resource id="Magento_Sales::actions"> + <resource id="Magento_Braintree::get_client_token" title="Get Client Token Braintree" sortOrder="170" /> + </resource> + </resource> + </resource> + </resource> </resource> </resources> </acl> diff --git a/app/code/Magento/Braintree/view/frontend/templates/paypal/button.phtml b/app/code/Magento/Braintree/view/frontend/templates/paypal/button.phtml index 1d60d19458a28..c1ef461ecae7c 100644 --- a/app/code/Magento/Braintree/view/frontend/templates/paypal/button.phtml +++ b/app/code/Magento/Braintree/view/frontend/templates/paypal/button.phtml @@ -29,6 +29,7 @@ $config = [ class="action-braintree-paypal-logo" disabled> <img class="braintree-paypal-button-hidden" src="https://checkout.paypal.com/pwpp/2.17.6/images/pay-with-paypal.png" - alt="Pay with PayPal"/> + alt="<?= $block->escapeHtml(__('Pay with PayPal')) ?>" + title="<?= $block->escapeHtml(__('Pay with PayPal')) ?>"/> </button> </div> diff --git a/app/code/Magento/Braintree/view/frontend/web/js/view/payment/method-renderer/paypal.js b/app/code/Magento/Braintree/view/frontend/web/js/view/payment/method-renderer/paypal.js index ca9d3686958b4..7c75cc3e594ee 100644 --- a/app/code/Magento/Braintree/view/frontend/web/js/view/payment/method-renderer/paypal.js +++ b/app/code/Magento/Braintree/view/frontend/web/js/view/payment/method-renderer/paypal.js @@ -7,6 +7,7 @@ define([ 'jquery', 'underscore', + 'mage/utils/wrapper', 'Magento_Checkout/js/view/payment/default', 'Magento_Braintree/js/view/payment/adapter', 'Magento_Checkout/js/model/quote', @@ -18,6 +19,7 @@ define([ ], function ( $, _, + wrapper, Component, Braintree, quote, @@ -218,8 +220,9 @@ define([ /** * Re-init PayPal Auth Flow + * @param {Function} callback - Optional callback */ - reInitPayPal: function () { + reInitPayPal: function (callback) { if (Braintree.checkout) { Braintree.checkout.teardown(function () { Braintree.checkout = null; @@ -228,6 +231,18 @@ define([ this.disableButton(); this.clientConfig.paypal.amount = this.grandTotalAmount; + this.clientConfig.paypal.shippingAddressOverride = this.getShippingAddress(); + + if (callback) { + this.clientConfig.onReady = wrapper.wrap( + this.clientConfig.onReady, + function (original, checkout) { + this.clientConfig.onReady = original; + original(checkout); + callback(); + }.bind(this) + ); + } Braintree.setConfig(this.clientConfig); Braintree.setup(); @@ -403,7 +418,11 @@ define([ * Triggers when customer click "Continue to PayPal" button */ payWithPayPal: function () { - if (additionalValidators.validate()) { + this.reInitPayPal(function () { + if (!additionalValidators.validate()) { + return; + } + try { Braintree.checkout.paypal.initAuthFlow(); } catch (e) { @@ -411,7 +430,7 @@ define([ message: $t('Payment ' + this.getTitle() + ' can\'t be initialized.') }); } - } + }.bind(this)); }, /** diff --git a/app/code/Magento/Braintree/view/frontend/web/template/payment/paypal.html b/app/code/Magento/Braintree/view/frontend/web/template/payment/paypal.html index e47024b7d2330..e1f6a1b4c25ce 100644 --- a/app/code/Magento/Braintree/view/frontend/web/template/payment/paypal.html +++ b/app/code/Magento/Braintree/view/frontend/web/template/payment/paypal.html @@ -12,7 +12,7 @@ data-bind="attr: {'id': getCode()}, value: getCode(), checked: isChecked, click: selectPaymentMethod, visible: isRadioButtonVisible()" /> <label class="label" data-bind="attr: {'for': getCode()}"> <!-- PayPal Logo --> - <img data-bind="attr: {src: getPaymentAcceptanceMarkSrc(), alt: $t('Acceptance Mark')}, title: $t('Acceptance Mark')}" + <img data-bind="attr: {src: getPaymentAcceptanceMarkSrc(), alt: $t('Acceptance Mark'), title: $t('Acceptance Mark')}" class="payment-icon"/> <!-- PayPal Logo --> <span text="getTitle()"></span> @@ -45,7 +45,7 @@ </span> <div class="field-tooltip-content" data-target="dropdown" - translate="'We store you payment information securely on Braintree servers via SSL.'"></div> + translate="'We store your payment information securely on Braintree servers via SSL.'"></div> </div> </div> <!-- /ko --> diff --git a/app/code/Magento/Bundle/Test/Mftf/Data/BundleLinkData.xml b/app/code/Magento/Bundle/Test/Mftf/Data/BundleLinkData.xml index 28fca883350e1..7123a573bc2e1 100644 --- a/app/code/Magento/Bundle/Test/Mftf/Data/BundleLinkData.xml +++ b/app/code/Magento/Bundle/Test/Mftf/Data/BundleLinkData.xml @@ -9,7 +9,6 @@ <entities xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../../../../../dev/tests/acceptance/vendor/magento/magento2-functional-testing-framework/src/Magento/FunctionalTestingFramework/DataGenerator/etc/dataProfileSchema.xsd"> <entity name="ApiBundleLink" type="bundle_link"> - <var key="sku" entityKey="sku" entityType="product2"/> <var key="option_id" entityKey="return" entityType="bundle_option"/> <var key="sku" entityKey="sku" entityType="product"/> <data key="qty">1</data> diff --git a/app/code/Magento/Bundle/Test/Mftf/Data/ProductData.xml b/app/code/Magento/Bundle/Test/Mftf/Data/ProductData.xml index 9c48b904bb7fd..f48810e0534fe 100644 --- a/app/code/Magento/Bundle/Test/Mftf/Data/ProductData.xml +++ b/app/code/Magento/Bundle/Test/Mftf/Data/ProductData.xml @@ -9,7 +9,6 @@ <entities xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../../../../../dev/tests/acceptance/vendor/magento/magento2-functional-testing-framework/src/Magento/FunctionalTestingFramework/DataGenerator/etc/dataProfileSchema.xsd"> <entity name="BundleProduct" type="product"> - <data key="name" unique="suffix">BundleProduct</data> <data key="name" unique="suffix">BundleProduct</data> <data key="name2" unique="suffix">BundleProduct2</data> <data key="sku" unique="suffix">bundleproduct</data> diff --git a/app/code/Magento/Bundle/Test/Mftf/Section/AdminProductFormBundleSection.xml b/app/code/Magento/Bundle/Test/Mftf/Section/AdminProductFormBundleSection.xml index 0d0edbf857515..25f1d95dc863c 100644 --- a/app/code/Magento/Bundle/Test/Mftf/Section/AdminProductFormBundleSection.xml +++ b/app/code/Magento/Bundle/Test/Mftf/Section/AdminProductFormBundleSection.xml @@ -68,5 +68,6 @@ <element name="searchForCategory" type="input" selector="div.action-menu._active > div.admin__action-multiselect-search-wrap input" timeout="30"/> <element name="selectCategory" type="multiselect" selector="//div[@class='action-menu _active']//label[@class='admin__action-multiselect-label']"/> <element name="categoriesLabel" type="text" selector="//div[@class='action-menu _active']//button[@data-action='close-advanced-select']"/> + <element name="userDefinedQuantity" type="checkbox" selector="[name='bundle_options[bundle_options][{{option}}][bundle_selections][{{product}}][selection_can_change_qty]'][type='checkbox']" parameterized="true"/> </section> </sections> diff --git a/app/code/Magento/Bundle/Test/Mftf/Section/BundleStorefrontSection.xml b/app/code/Magento/Bundle/Test/Mftf/Section/BundleStorefrontSection.xml index 9f4e6e04ac351..1a8709bd84e9e 100644 --- a/app/code/Magento/Bundle/Test/Mftf/Section/BundleStorefrontSection.xml +++ b/app/code/Magento/Bundle/Test/Mftf/Section/BundleStorefrontSection.xml @@ -10,8 +10,8 @@ xsi:noNamespaceSchemaLocation="../../../../../../../dev/tests/acceptance/vendor/magento/magento2-functional-testing-framework/src/Magento/FunctionalTestingFramework/Page/etc/SectionObject.xsd"> <section name="BundleStorefrontSection"> <!--TestingForLocationOfOptions--> - <element name="bundleOptionSelector" type="button" selector="//*[@id='bundle-slide']/span"/> - <element name="bundleOptionSelection" type="button" selector="//div[@class='nested options-list']/div[2]/label[@class='label']"/> + <element name="bundleOptionSelector" type="checkbox" selector="//*[@id='bundle-slide']/span" timeout="30"/> + <element name="bundleOptionSelection" type="checkbox" selector="//div[@class='nested options-list']/div[{{optionNumber}}]/label[@class='label']" parameterized="true"/> <!--Description--> <!--CE exclusively--> <element name="longDescriptionText" type="text" selector="//*[@id='description']/div/div" timeout="30"/> diff --git a/app/code/Magento/Bundle/Test/Mftf/Section/StorefrontBundledSection.xml b/app/code/Magento/Bundle/Test/Mftf/Section/StorefrontBundledSection.xml index b462fcd11cfe7..f724f9bbfe1bd 100644 --- a/app/code/Magento/Bundle/Test/Mftf/Section/StorefrontBundledSection.xml +++ b/app/code/Magento/Bundle/Test/Mftf/Section/StorefrontBundledSection.xml @@ -21,5 +21,13 @@ <element name="nthOptionDiv" type="block" selector="#product-options-wrapper div.field.option:nth-of-type({{var}})" parameterized="true"/> <element name="nthItemOptionsTitle" type="text" selector="dl.item-options dt:nth-of-type({{var}})" parameterized="true"/> <element name="nthItemOptionsValue" type="text" selector="dl.item-options dd:nth-of-type({{var}})" parameterized="true"/> + <element name="bundleProductName" type="text" selector="//*[@id='maincontent']//span[@itemprop='name']"/> + <element name="pageNotFound" type="text" selector="//h1[@class='page-title']//span[contains(., 'Whoops, our bad...')]"/> + <element name="dropDownOptionOneProducts" type="select" selector="//label//span[contains(text(), '{{productName}}')]/../..//div[@class='control']//select" parameterized="true"/> + <element name="dropDownOptionOneQuantity" type="input" selector="//span[contains(text(), '{{productName}}')]/../..//input" parameterized="true"/> + <element name="radioButtonOptionTwoProducts" type="checkbox" selector="//label//span[contains(text(), '{{productName}}')]/../..//div[@class='control']//div[@class='field choice'][{{productNumber}}]/input" parameterized="true"/> + <element name="radioButtonOptionTwoQuantity" type="input" selector="//label//span[contains(text(), '{{productName}}')]/../..//div[@class='control']//div[@class='field qty qty-holder']//input" parameterized="true"/> + <element name="checkboxOptionThreeProducts" type="checkbox" selector="//label//span[contains(text(), '{{productName}}')]/../..//div[@class='control']//div[@class='field choice'][{{productNumber}}]/input" parameterized="true"/> + <element name="multiselectOptionFourProducts" type="multiselect" selector="//label//span[contains(text(), '{{productName}}')]/../..//select[@multiple='multiple']" parameterized="true"/> </section> </sections> diff --git a/app/code/Magento/Bundle/Test/Mftf/Test/AdminDeleteABundleProduct.xml b/app/code/Magento/Bundle/Test/Mftf/Test/AdminDeleteABundleProduct.xml index 3f88a9f277105..bf62212babd43 100644 --- a/app/code/Magento/Bundle/Test/Mftf/Test/AdminDeleteABundleProduct.xml +++ b/app/code/Magento/Bundle/Test/Mftf/Test/AdminDeleteABundleProduct.xml @@ -82,6 +82,6 @@ <!--Testing deletion of product--> <amOnPage url="{{BundleProduct.urlKey}}.html" stepKey="GoToProductPageAgain"/> <waitForPageLoad stepKey="WaitForProductPageToLoadToShowElement"/> - <dontSeeElement selector="{{BundleStorefrontSection.bundleProductName}}" stepKey="LookingForNameOfProductTwo"/> + <dontSeeElement selector="{{StorefrontBundledSection.bundleProductName}}" stepKey="LookingForNameOfProductTwo"/> </test> </tests> diff --git a/app/code/Magento/Bundle/Test/Mftf/Test/AdminMassDeleteBundleProducts.xml b/app/code/Magento/Bundle/Test/Mftf/Test/AdminMassDeleteBundleProducts.xml index 708580b3c9940..6cb86d8028352 100644 --- a/app/code/Magento/Bundle/Test/Mftf/Test/AdminMassDeleteBundleProducts.xml +++ b/app/code/Magento/Bundle/Test/Mftf/Test/AdminMassDeleteBundleProducts.xml @@ -133,11 +133,11 @@ <!--Testing deletion of products--> <amOnPage url="{{BundleProduct.urlKey}}.html" stepKey="GoToProductPageAgain"/> <waitForPageLoad stepKey="WaitForProductPageToLoadToShowElement"/> - <dontSeeElement stepKey="LookingForNameOfProduct" selector="{{BundleStorefrontSection.bundleProductName}}"/> - <seeElement stepKey="LookingForPageNotFoundMessage" selector="{{BundleStorefrontSection.pageNotFound}}"/> + <dontSeeElement stepKey="LookingForNameOfProduct" selector="{{StorefrontBundledSection.bundleProductName}}"/> + <seeElement stepKey="LookingForPageNotFoundMessage" selector="{{StorefrontBundledSection.pageNotFound}}"/> <amOnPage url="{{BundleProduct.urlKey2}}.html" stepKey="GoToProductPageAgain2"/> <waitForPageLoad stepKey="WaitForProductPageToLoadToShowElement2"/> - <dontSeeElement stepKey="LookingForNameOfProduct2" selector="{{BundleStorefrontSection.bundleProductName}}"/> - <seeElement stepKey="LookingForPageNotFoundMessage2" selector="{{BundleStorefrontSection.pageNotFound}}"/> + <dontSeeElement stepKey="LookingForNameOfProduct2" selector="{{StorefrontBundledSection.bundleProductName}}"/> + <seeElement stepKey="LookingForPageNotFoundMessage2" selector="{{StorefrontBundledSection.pageNotFound}}"/> </test> </tests> diff --git a/app/code/Magento/Bundle/Test/Mftf/Test/AdminProductBundleCreationTest.xml b/app/code/Magento/Bundle/Test/Mftf/Test/AdminProductBundleCreationTest.xml index 5e7a098790724..643f13dfd61ed 100644 --- a/app/code/Magento/Bundle/Test/Mftf/Test/AdminProductBundleCreationTest.xml +++ b/app/code/Magento/Bundle/Test/Mftf/Test/AdminProductBundleCreationTest.xml @@ -72,6 +72,6 @@ <!--Test Assertion - on correct page/page has been published--> <waitForPageLoad stepKey="waitForBundleProductPageToLoad"/> - <seeElement stepKey="LookingForNameOfProduct" selector="{{BundleStorefrontSection.bundleProductName}}"/> + <seeElement stepKey="LookingForNameOfProduct" selector="{{StorefrontBundledSection.bundleProductName}}"/> </test> </tests> diff --git a/app/code/Magento/Bundle/Test/Mftf/Test/AdminRemoveDefaultImageBundleProductTest.xml b/app/code/Magento/Bundle/Test/Mftf/Test/AdminRemoveDefaultImageBundleProductTest.xml index 9ce345cde681c..ccd729ac841cd 100644 --- a/app/code/Magento/Bundle/Test/Mftf/Test/AdminRemoveDefaultImageBundleProductTest.xml +++ b/app/code/Magento/Bundle/Test/Mftf/Test/AdminRemoveDefaultImageBundleProductTest.xml @@ -74,9 +74,7 @@ <!-- Remove image from product --> <actionGroup ref="removeProductImage" stepKey="removeProductImage"/> - <!-- Skip success message check when saving product because of bug MAGETWO-91177 --> - <!-- actionGroup ref="saveProductForm" stepKey="saveProductFormAfterRemove"/--> - <click selector="{{AdminProductFormActionSection.saveButton}}" stepKey="saveProductFormAfterRemove"/> + <actionGroup ref="saveProductForm" stepKey="saveProductFormAfterRemove"/> <!-- Assert product image not in admin product form --> <actionGroup ref="assertProductImageNotInAdminProductPage" stepKey="assertProductImageNotInAdminProductPage"/> diff --git a/app/code/Magento/Bundle/Test/Mftf/Test/EnableDisableBundleProductStatusTest.xml b/app/code/Magento/Bundle/Test/Mftf/Test/EnableDisableBundleProductStatusTest.xml index e1434e22489ce..7a7b4673eda6d 100644 --- a/app/code/Magento/Bundle/Test/Mftf/Test/EnableDisableBundleProductStatusTest.xml +++ b/app/code/Magento/Bundle/Test/Mftf/Test/EnableDisableBundleProductStatusTest.xml @@ -72,7 +72,7 @@ <!--Go to page--> <amOnPage url="{{BundleProduct.urlKey}}.html" stepKey="GoToProductPage"/> <waitForPageLoad stepKey="waitForBundleProductPageToLoad"/> - <seeElement stepKey="LookingForNameOfProduct" selector="{{BundleStorefrontSection.bundleProductName}}"/> + <seeElement stepKey="LookingForNameOfProduct" selector="{{StorefrontBundledSection.bundleProductName}}"/> <!--Testing disabled view--> <amOnPage url="{{AdminProductIndexPage.url}}" stepKey="GoToProductCatalog"/> @@ -87,6 +87,6 @@ <see selector="{{AdminCategoryMessagesSection.SuccessMessage}}" userInput="You saved the product." stepKey="messageYouSavedTheProductIsShownAgain"/> <amOnPage url="{{BundleProduct.urlKey}}.html" stepKey="GoToProductPageAgain"/> <waitForPageLoad stepKey="WaitForProductPageToLoadToShowElement"/> - <dontSeeElement stepKey="LookingForNameOfProductTwo" selector="{{BundleStorefrontSection.bundleProductName}}"/> + <dontSeeElement stepKey="LookingForNameOfProductTwo" selector="{{StorefrontBundledSection.bundleProductName}}"/> </test> </tests> diff --git a/app/code/Magento/Bundle/Test/Mftf/Test/MassEnableDisableBundleProductsTest.xml b/app/code/Magento/Bundle/Test/Mftf/Test/MassEnableDisableBundleProductsTest.xml index 27d95cfb5cfa5..89867341e96d3 100644 --- a/app/code/Magento/Bundle/Test/Mftf/Test/MassEnableDisableBundleProductsTest.xml +++ b/app/code/Magento/Bundle/Test/Mftf/Test/MassEnableDisableBundleProductsTest.xml @@ -17,8 +17,9 @@ <severity value="CRITICAL"/> <testCaseId value="MC-217"/> <group value="Bundle"/> - <!--Skipped due to MAGETWO-92898--> - <group value="skip"/> + <skip> + <issueId value="MAGETWO-92898"/> + </skip> </annotations> <before> <actionGroup ref="LoginAsAdmin" stepKey="loginAsAdmin"/> @@ -137,7 +138,7 @@ <!--Confirm bundle products have been disabled--> <amOnPage url="{{BundleProduct.urlKey2}}.html" stepKey="GoToProductPage"/> <waitForPageLoad stepKey="WaitForProductPageToLoadToShowElement"/> - <dontSeeElement stepKey="LookingForNameOfProductDisabled" selector="{{BundleStorefrontSection.bundleProductName}}"/> + <dontSeeElement stepKey="LookingForNameOfProductDisabled" selector="{{StorefrontBundledSection.bundleProductName}}"/> <!--Enabling bundle products--> <amOnPage url="{{ProductCatalogPage.url}}" stepKey="GoToCatalogPageChangingView"/> @@ -154,6 +155,6 @@ <!--Confirm bundle products have been enabled--> <amOnPage url="{{BundleProduct.urlKey2}}.html" stepKey="GoToProductPageEnabled"/> <waitForPageLoad stepKey="waitForBundleProductPageToLoad"/> - <seeElement stepKey="LookingForNameOfProduct" selector="{{BundleStorefrontSection.bundleProductName}}"/> + <seeElement stepKey="LookingForNameOfProduct" selector="{{StorefrontBundledSection.bundleProductName}}"/> </test> </tests> diff --git a/app/code/Magento/Bundle/Test/Mftf/Test/StorefrontBundleProductDetailsTest.xml b/app/code/Magento/Bundle/Test/Mftf/Test/StorefrontBundleProductDetailsTest.xml new file mode 100644 index 0000000000000..a475ef16ed5c5 --- /dev/null +++ b/app/code/Magento/Bundle/Test/Mftf/Test/StorefrontBundleProductDetailsTest.xml @@ -0,0 +1,86 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> + +<tests xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="../../../../../../vendor/magento/magento2-functional-testing-framework/src/Magento/FunctionalTestingFramework/Test/etc/testSchema.xsd"> + <test name="StorefrontBundleProductDetailsTest"> + <annotations> + <features value="Bundle"/> + <stories value="Bundle product details page"/> + <title value="Customer should be able to see basic bundle product details"/> + <description value="Customer should be able to see basic bundle product details"/> + <severity value="CRITICAL"/> + <testCaseId value="MC-230"/> + <group value="Bundle"/> + </annotations> + <before> + <!--Creating Data--> + <createData entity="_defaultCategory" stepKey="createPreReqCategory"/> + <createData entity="SimpleProduct2" stepKey="simpleProduct1"/> + <createData entity="SimpleProduct2" stepKey="simpleProduct2"/> + + <!-- Admin Login--> + <actionGroup stepKey="loginToAdminPanel" ref="LoginAsAdmin"/> + <actionGroup ref="DisabledWYSIWYG" stepKey="disableWYSIWYG"/> + </before> + <after> + <deleteData createDataKey="createPreReqCategory" stepKey="deletePreReqCategory"/> + <deleteData createDataKey="simpleProduct1" stepKey="deleteSimpleProduct1"/> + <deleteData createDataKey="simpleProduct2" stepKey="deleteSimpleProduct2"/> + <actionGroup ref="logout" stepKey="logout"/> + </after> + <!-- go to bundle product creation page--> + <amOnPage url="{{AdminProductCreatePage.url(BundleProduct.set, BundleProduct.type)}}" stepKey="goToBundleProductCreationPage" /> + <waitForPageLoad stepKey="waitForBundleProductCreatePageToLoad"/> + + <!--Add description--> + <click selector="{{AdminProductFormBundleSection.contentDropDown}}" stepKey="openDescriptionDropDown"/> + <scrollTo selector="{{AdminProductFormBundleSection.contentDropDown}}" stepKey="scrollToError"/> + <fillField selector="{{AdminProductFormBundleSection.longDescription}}" userInput="This is the long description" stepKey="fillLongDescription"/> + <fillField selector="{{AdminProductFormBundleSection.shortDescription}}" userInput="This is the short description" stepKey="fillShortDescription"/> + + <!-- Add options --> + <conditionalClick selector="{{AdminProductFormBundleSection.bundleItemsToggle}}" dependentSelector="{{AdminProductFormBundleSection.bundleItemsToggle}}" visible="false" stepKey="conditionallyOpenSectionBundleItems"/> + <click selector="{{AdminProductFormBundleSection.addOption}}" stepKey="clickAddOption"/> + <waitForElementVisible selector="{{AdminProductFormBundleSection.bundleOptionXTitle('0')}}" stepKey="waitForBundleOptions"/> + <fillField selector="{{AdminProductFormBundleSection.bundleOptionXTitle('0')}}" userInput="{{BundleProduct.optionTitle1}}" stepKey="fillOptionTitle"/> + <selectOption selector="{{AdminProductFormBundleSection.bundleOptionXInputType('0')}}" userInput="{{BundleProduct.optionInputType1}}" stepKey="selectInputType"/> + <waitForElementVisible selector="{{AdminProductFormBundleSection.addProductsToOption}}" stepKey="waitForAddProductsToBundle"/> + <click selector="{{AdminProductFormBundleSection.addProductsToOption}}" stepKey="clickAddProductsToOption"/> + <waitForPageLoad stepKey="waitForPageLoadAfterBundleProducts"/> + <actionGroup ref="filterProductGridBySku" stepKey="filterBundleProductOptions"> + <argument name="product" value="$$simpleProduct1$$"/> + </actionGroup> + <checkOption selector="{{AdminAddProductsToOptionPanel.firstCheckbox}}" stepKey="selectFirstGridRow"/> + <actionGroup ref="filterProductGridBySku" stepKey="filterBundleProductOptions2"> + <argument name="product" value="$$simpleProduct2$$"/> + </actionGroup> + <checkOption selector="{{AdminAddProductsToOptionPanel.firstCheckbox}}" stepKey="selectFirstGridRow2"/> + <click selector="{{AdminAddProductsToOptionPanel.addSelectedProducts}}" stepKey="clickAddSelectedBundleProducts"/> + <fillField selector="{{AdminProductFormBundleSection.bundleOptionXProductYQuantity('0', '0')}}" userInput="{{BundleProduct.defaultQuantity}}" stepKey="fillProductDefaultQty1"/> + <fillField selector="{{AdminProductFormBundleSection.bundleOptionXProductYQuantity('0', '1')}}" userInput="{{BundleProduct.defaultQuantity}}" stepKey="fillProductDefaultQty2"/> + + <!--Create a basic bundle product--> + <actionGroup ref="CreateBasicBundleProduct" stepKey="createBundledProductForTwoSimpleProducts"> + <argument name="bundleProduct" value="BundleProduct"/> + </actionGroup> + + <!--save the product--> + <click selector="{{AdminProductFormActionSection.saveButton}}" stepKey="clickSaveButtonAgain"/> + <see userInput="You saved the product." stepKey="messageYouSavedTheProductIsShownAgain"/> + + <!--Checking details--> + <amOnPage url="{{BundleProduct.urlKey}}.html" stepKey="goToProductPage"/> + <waitForPageLoad stepKey="waitForProductPageToLoad"/> + <see selector="{{BundleStorefrontSection.shortDescriptionText}}" userInput="This is the short description" stepKey="seeShortDescription"/> + <see selector="{{BundleStorefrontSection.longDescriptionText}}" userInput="This is the long description" stepKey="seeLongDescription"/> + <click selector="{{BundleStorefrontSection.bundleOptionSelector}}" stepKey="clickOnCustomizationOption"/> + <see selector="{{BundleStorefrontSection.bundleOptionSelection('1')}}" userInput="{{BundleProduct.defaultQuantity}} x $$simpleProduct1.name$$" stepKey="seeOption1"/> + <see selector="{{BundleStorefrontSection.bundleOptionSelection('2')}}" userInput="{{BundleProduct.defaultQuantity}} x $$simpleProduct2.name$$" stepKey="seeOption2"/> + </test> +</tests> diff --git a/app/code/Magento/Bundle/Test/Mftf/Test/StorefrontCustomerSelectAndSetBundleOptionsTest.xml b/app/code/Magento/Bundle/Test/Mftf/Test/StorefrontCustomerSelectAndSetBundleOptionsTest.xml new file mode 100644 index 0000000000000..26e5e436ed567 --- /dev/null +++ b/app/code/Magento/Bundle/Test/Mftf/Test/StorefrontCustomerSelectAndSetBundleOptionsTest.xml @@ -0,0 +1,136 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> + +<tests xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="../../../../../../../dev/tests/acceptance/vendor/magento/magento2-functional-testing-framework/src/Magento/FunctionalTestingFramework/Test/etc/testSchema.xsd"> + <test name="StorefrontCustomerSelectAndSetBundleOptionsTest"> + <annotations> + <features value="Bundle"/> + <stories value="Bundle product details page"/> + <title value="Customer should be able to select customisable bundle product options and set quantity for them"/> + <description value="Customer should be able to select customisable bundle product options and set quantity for them"/> + <severity value="CRITICAL"/> + <testCaseId value="MC-231"/> + <group value="Bundle"/> + </annotations> + <before> + <actionGroup ref="LoginAsAdmin" stepKey="login"/> + <createData entity="SimpleProduct2" stepKey="simpleProduct1"/> + <createData entity="SimpleProduct2" stepKey="simpleProduct2"/> + </before> + <after> + <!-- Delete the bundled product --> + <actionGroup stepKey="deleteBundle" ref="deleteProductUsingProductGrid"> + <argument name="product" value="BundleProduct"/> + </actionGroup> + <amOnPage url="{{AdminLogoutPage.url}}" stepKey="logout"/> + <deleteData createDataKey="simpleProduct1" stepKey="deleteSimpleProduct1"/> + <deleteData createDataKey="simpleProduct2" stepKey="deleteSimpleProduct2"/> + </after> + + <!-- Start creating a bundle product --> + <amOnPage url="{{AdminProductIndexPage.url}}" stepKey="goToProductList"/> + <waitForPageLoad stepKey="waitForProductList"/> + <actionGroup ref="goToCreateProductPage" stepKey="goToCreateProduct"> + <argument name="product" value="BundleProduct"/> + </actionGroup> + <actionGroup ref="fillProductNameAndSkuInProductForm" stepKey="fillNameAndSku"> + <argument name="product" value="BundleProduct"/> + </actionGroup> + + <!-- Add Option One, a "Drop-down" type option --> + <actionGroup ref="addBundleOptionWithTwoProducts" stepKey="addBundleOptionWithTwoProducts1"> + <argument name="x" value="0"/> + <argument name="n" value="1"/> + <argument name="prodOneSku" value="$$simpleProduct1.sku$$"/> + <argument name="prodTwoSku" value="$$simpleProduct2.sku$$"/> + <argument name="optionTitle" value="Option One"/> + <argument name="inputType" value="select"/> + </actionGroup> + <checkOption selector="{{AdminProductFormBundleSection.userDefinedQuantity('0', '0')}}" stepKey="userDefinedQuantitiyOption0Product0"/> + <checkOption selector="{{AdminProductFormBundleSection.userDefinedQuantity('0', '1')}}" stepKey="userDefinedQuantitiyOption0Product1"/> + + <!-- Add Option Two, a "Radio Buttons" type option --> + <actionGroup ref="addBundleOptionWithTwoProducts" stepKey="addBundleOptionWithTwoProducts2"> + <argument name="x" value="1"/> + <argument name="n" value="2"/> + <argument name="prodOneSku" value="$$simpleProduct1.sku$$"/> + <argument name="prodTwoSku" value="$$simpleProduct2.sku$$"/> + <argument name="optionTitle" value="Option Two"/> + <argument name="inputType" value="radio"/> + </actionGroup> + <checkOption selector="{{AdminProductFormBundleSection.userDefinedQuantity('1', '0')}}" stepKey="userDefinedQuantitiyOption1Product0"/> + <checkOption selector="{{AdminProductFormBundleSection.userDefinedQuantity('1', '1')}}" stepKey="userDefinedQuantitiyOption1Product1"/> + + <!-- Add Option Three, a "Checkbox" type option --> + <actionGroup ref="addBundleOptionWithTwoProducts" stepKey="addBundleOptionWithTwoProducts3"> + <argument name="x" value="2"/> + <argument name="n" value="3"/> + <argument name="prodOneSku" value="$$simpleProduct1.sku$$"/> + <argument name="prodTwoSku" value="$$simpleProduct2.sku$$"/> + <argument name="optionTitle" value="Option Three"/> + <argument name="inputType" value="checkbox"/> + </actionGroup> + + <!-- Add Option Four, a "Multi Select" type option --> + <actionGroup ref="addBundleOptionWithTwoProducts" stepKey="addBundleOptionWithTwoProducts4"> + <argument name="x" value="3"/> + <argument name="n" value="4"/> + <argument name="prodOneSku" value="$$simpleProduct1.sku$$"/> + <argument name="prodTwoSku" value="$$simpleProduct2.sku$$"/> + <argument name="optionTitle" value="Option Four"/> + <argument name="inputType" value="multi"/> + </actionGroup> + + <!-- Save product and go to storefront --> + <actionGroup ref="saveProductForm" stepKey="saveProduct"/> + <amOnPage url="{{BundleProduct.sku}}.html" stepKey="goToStorefront"/> + <waitForPageLoad stepKey="waitForStorefront"/> + <click selector="{{StorefrontBundledSection.addToCart}}" stepKey="clickCustomize"/> + + <!--Select options - set quantities--> + + <!--"Drop-down" type option--> + <selectOption selector="{{StorefrontBundledSection.dropDownOptionOneProducts('Option One')}}" userInput="$$simpleProduct1.sku$$ +$$$simpleProduct1.price$$.00" stepKey="selectOption0Product0"/> + <seeOptionIsSelected selector="{{StorefrontBundledSection.dropDownOptionOneProducts('Option One')}}" userInput="$$simpleProduct1.sku$$ +$$$simpleProduct1.price$$.00" stepKey="checkOption0Product0"/> + <fillField selector="{{StorefrontBundledSection.dropDownOptionOneQuantity('Option One')}}" userInput="3" stepKey="fillQuantity00"/> + <seeInField selector="{{StorefrontBundledSection.dropDownOptionOneQuantity('Option One')}}" userInput="3" stepKey="checkQuantity00"/> + + <selectOption selector="{{StorefrontBundledSection.dropDownOptionOneProducts('Option One')}}" userInput="$$simpleProduct2.sku$$ +$$$simpleProduct2.price$$.00" stepKey="selectOption0Product1"/> + <seeOptionIsSelected selector="{{StorefrontBundledSection.dropDownOptionOneProducts('Option One')}}" userInput="$$simpleProduct2.sku$$ +$$$simpleProduct2.price$$.00" stepKey="checkOption0Product1"/> + <fillField selector="{{StorefrontBundledSection.dropDownOptionOneQuantity('Option One')}}" userInput="3" stepKey="fillQuantity01"/> + <seeInField selector="{{StorefrontBundledSection.dropDownOptionOneQuantity('Option One')}}" userInput="3" stepKey="checkQuantity01"/> + + <!--"Radio Buttons" type option--> + <checkOption selector="{{StorefrontBundledSection.radioButtonOptionTwoProducts('Option Two', '1')}}" stepKey="selectOption1Product0"/> + <seeCheckboxIsChecked selector="{{StorefrontBundledSection.radioButtonOptionTwoProducts('Option Two', '1')}}" stepKey="checkOption1Product0"/> + <fillField selector="{{StorefrontBundledSection.radioButtonOptionTwoQuantity('Option Two')}}" userInput="3" stepKey="fillQuantity10"/> + <seeInField selector="{{StorefrontBundledSection.radioButtonOptionTwoQuantity('Option Two')}}" userInput="3" stepKey="checkQuantity10"/> + + <checkOption selector="{{StorefrontBundledSection.radioButtonOptionTwoProducts('Option Two', '2')}}" stepKey="selectOption1Product1"/> + <seeCheckboxIsChecked selector="{{StorefrontBundledSection.radioButtonOptionTwoProducts('Option Two', '2')}}" stepKey="checkOption1Product1"/> + <fillField selector="{{StorefrontBundledSection.radioButtonOptionTwoQuantity('Option Two')}}" userInput="3" stepKey="fillQuantity11"/> + <seeInField selector="{{StorefrontBundledSection.radioButtonOptionTwoQuantity('Option Two')}}" userInput="3" stepKey="checkQuantity11"/> + + <!--"Checkbox" type option--> + <!--This option does not support user defined quantities--> + <checkOption selector="{{StorefrontBundledSection.checkboxOptionThreeProducts('Option Three', '1')}}" stepKey="selectOption2Product0"/> + <seeCheckboxIsChecked selector="{{StorefrontBundledSection.checkboxOptionThreeProducts('Option Three', '1')}}" stepKey="checkOption2Product0"/> + + <checkOption selector="{{StorefrontBundledSection.checkboxOptionThreeProducts('Option Three', '2')}}" stepKey="selectOption2Product1"/> + <seeCheckboxIsChecked selector="{{StorefrontBundledSection.checkboxOptionThreeProducts('Option Three', '2')}}" stepKey="checkOption2Product1"/> + + <!--"Multi Select" type option--> + <!--This option does not support user defined quantities--> + <selectOption selector="{{StorefrontBundledSection.multiselectOptionFourProducts('Option Four')}}" userInput="$$simpleProduct1.sku$$ +$$$simpleProduct1.price$$.00" stepKey="selectOption3Product0"/> + <seeOptionIsSelected selector="{{StorefrontBundledSection.multiselectOptionFourProducts('Option Four')}}" userInput="$$simpleProduct1.sku$$ +$$$simpleProduct1.price$$.00" stepKey="checkOption3Product0"/> + + <selectOption selector="{{StorefrontBundledSection.multiselectOptionFourProducts('Option Four')}}" userInput="$$simpleProduct2.sku$$ +$$$simpleProduct2.price$$.00" stepKey="selectOption3Product1"/> + <seeOptionIsSelected selector="{{StorefrontBundledSection.multiselectOptionFourProducts('Option Four')}}" userInput="$$simpleProduct2.sku$$ +$$$simpleProduct2.price$$.00" stepKey="checkOption3Product1"/> + </test> +</tests> diff --git a/app/code/Magento/Bundle/Test/Mftf/Test/StorefrontGoToDetailsPageWhenAddingToCartTest.xml b/app/code/Magento/Bundle/Test/Mftf/Test/StorefrontGoToDetailsPageWhenAddingToCartTest.xml new file mode 100644 index 0000000000000..6c476183a35b3 --- /dev/null +++ b/app/code/Magento/Bundle/Test/Mftf/Test/StorefrontGoToDetailsPageWhenAddingToCartTest.xml @@ -0,0 +1,81 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> + +<tests xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="../../../../../../../dev/tests/acceptance/vendor/magento/magento2-functional-testing-framework/src/Magento/FunctionalTestingFramework/Test/etc/testSchema.xsd"> + <test name="StorefrontGoToDetailsPageWhenAddingToCart"> + <annotations> + <features value="Bundle"/> + <stories value="Bundle products list on Storefront"/> + <title value="Customer should be taken to bundle product details page when clicking “Add to Cart” button"/> + <description value="Customer should be taken to bundle product details page when clicking “Add to Cart” button"/> + <severity value="CRITICAL"/> + <testCaseId value="MC-229"/> + <group value="Bundle"/> + </annotations> + <before> + <actionGroup ref="LoginAsAdmin" stepKey="loginAsAdmin"/> + <createData entity="SimpleProduct2" stepKey="simpleProduct1"/> + <createData entity="SimpleProduct2" stepKey="simpleProduct2"/> + <createData entity="_defaultCategory" stepKey="createCategory"/> + </before> + <after> + <amOnPage url="{{AdminLogoutPage.url}}" stepKey="amOnLogoutPage"/> + <deleteData createDataKey="simpleProduct1" stepKey="deleteSimpleProduct1"/> + <deleteData createDataKey="simpleProduct2" stepKey="deleteSimpleProduct2"/> + <deleteData createDataKey="createCategory" stepKey="deleteCategory"/> + </after> + <!--Go to bundle product creation page--> + <amOnPage url="{{AdminProductCreatePage.url(BundleProduct.set, BundleProduct.type)}}" stepKey="goToBundleProductCreationPage" /> + <waitForPageLoad stepKey="waitForBundleProductCreatePageToLoad"/> + + <!--Categories--> + <click selector="{{AdminProductFormBundleSection.categoriesDropDown}}" stepKey="dropDownCategories"/> + <fillField selector="{{AdminProductFormBundleSection.searchForCategory}}" userInput="$$createCategory.name$$" stepKey="searchForCategory"/> + <click selector="{{AdminProductFormBundleSection.selectCategory}}" stepKey="selectCategory"/> + <click selector="{{AdminProductFormBundleSection.categoriesLabel}}" stepKey="clickOnCategoriesLabelToCloseOptions"/> + + <!--Create bundle product--> + <conditionalClick selector="{{AdminProductFormBundleSection.bundleItemsToggle}}" dependentSelector="{{AdminProductFormBundleSection.bundleItemsToggle}}" visible="false" stepKey="conditionallyOpenSectionBundleItems"/> + <click selector="{{AdminProductFormBundleSection.addOption}}" stepKey="clickAddOption"/> + <waitForElementVisible selector="{{AdminProductFormBundleSection.bundleOptionXTitle('0')}}" stepKey="waitForBundleOptions"/> + <fillField selector="{{AdminProductFormBundleSection.bundleOptionXTitle('0')}}" userInput="{{BundleProduct.optionTitle1}}" stepKey="fillOptionTitle"/> + <selectOption selector="{{AdminProductFormBundleSection.bundleOptionXInputType('0')}}" userInput="{{BundleProduct.optionInputType1}}" stepKey="selectInputType"/> + <waitForElementVisible selector="{{AdminProductFormBundleSection.addProductsToOption}}" stepKey="waitForAddProductsToBundle"/> + <click selector="{{AdminProductFormBundleSection.addProductsToOption}}" stepKey="clickAddProductsToOption"/> + <actionGroup ref="filterProductGridBySku" stepKey="filterBundleProductOptions"> + <argument name="product" value="$$simpleProduct1$$"/> + </actionGroup> + <checkOption selector="{{AdminAddProductsToOptionPanel.firstCheckbox}}" stepKey="selectFirstGridRow"/> + <actionGroup ref="filterProductGridBySku" stepKey="filterBundleProductOptions2"> + <argument name="product" value="$$simpleProduct2$$"/> + </actionGroup> + <checkOption selector="{{AdminAddProductsToOptionPanel.firstCheckbox}}" stepKey="selectFirstGridRow2"/> + <click selector="{{AdminAddProductsToOptionPanel.addSelectedProducts}}" stepKey="clickAddSelectedBundleProducts"/> + <fillField selector="{{AdminProductFormBundleSection.bundleOptionXProductYQuantity('0', '0')}}" userInput="{{BundleProduct.defaultQuantity}}" stepKey="fillProductDefaultQty1"/> + <fillField selector="{{AdminProductFormBundleSection.bundleOptionXProductYQuantity('0', '1')}}" userInput="{{BundleProduct.defaultQuantity}}" stepKey="fillProductDefaultQty2"/> + <actionGroup ref="AncillaryPrepBundleProduct" stepKey="createBundledProductForTwoSimpleProducts"/> + + <!--Save the product--> + <click selector="{{AdminProductFormActionSection.saveButton}}" stepKey="clickSaveButton"/> + <seeElement selector="{{AdminCategoryMessagesSection.SuccessMessage}}" stepKey="messageYouSavedTheProductIsShown"/> + + <!--Go to category page--> + <amOnPage url="{{StorefrontHomePage.url}}" stepKey="goToHomePage"/> + <waitForPageLoad stepKey="waitForHomePageToload"/> + <click selector="{{StorefrontHeaderSection.NavigationCategoryByName($$createCategory.name$$)}}" stepKey="cartClickCategory"/> + + <!--Click add to cart--> + <moveMouseOver selector="{{StorefrontCategoryMainSection.ProductItemInfo}}" stepKey="hoverProduct"/> + <click selector="{{StorefrontCategoryMainSection.AddToCartBtn}}" stepKey="addProductToCart"/> + <waitForPageLoad stepKey="waitForProductPage"/> + + <!--Check for details page--> + <seeInCurrentUrl url="{{BundleProduct.sku}}" stepKey="seeBundleProductDetailsPage"/> + </test> +</tests> diff --git a/app/code/Magento/Bundle/Test/Mftf/composer.json b/app/code/Magento/Bundle/Test/Mftf/composer.json deleted file mode 100644 index 1e379d1bacd44..0000000000000 --- a/app/code/Magento/Bundle/Test/Mftf/composer.json +++ /dev/null @@ -1,36 +0,0 @@ -{ - "name": "magento/functional-test-module-bundle", - "description": "N/A", - "config": { - "sort-packages": true - }, - "require": { - "php": "~7.1.3||~7.2.0", - "magento/magento2-functional-testing-framework": "2.2.0", - "magento/functional-test-module-backend": "100.0.0-dev", - "magento/functional-test-module-catalog": "100.0.0-dev", - "magento/functional-test-module-catalog-inventory": "100.0.0-dev", - "magento/functional-test-module-catalog-rule": "100.0.0-dev", - "magento/functional-test-module-checkout": "100.0.0-dev", - "magento/functional-test-module-config": "100.0.0-dev", - "magento/functional-test-module-customer": "100.0.0-dev", - "magento/functional-test-module-eav": "100.0.0-dev", - "magento/functional-test-module-gift-message": "100.0.0-dev", - "magento/functional-test-module-media-storage": "100.0.0-dev", - "magento/functional-test-module-quote": "100.0.0-dev", - "magento/functional-test-module-sales": "100.0.0-dev", - "magento/functional-test-module-store": "100.0.0-dev", - "magento/functional-test-module-tax": "100.0.0-dev", - "magento/functional-test-module-ui": "100.0.0-dev" - }, - "suggest": { - "magento/functional-test-module-webapi": "100.0.0-dev", - "magento/functional-test-module-bundle-sample-data": "100.0.0-dev", - "magento/functional-test-module-sales-rule": "100.0.0-dev" - }, - "type": "magento2-test", - "license": [ - "OSL-3.0", - "AFL-3.0" - ] -} diff --git a/app/code/Magento/BundleGraphQl/Test/Mftf/composer.json b/app/code/Magento/BundleGraphQl/Test/Mftf/composer.json deleted file mode 100644 index 33dffdc85a364..0000000000000 --- a/app/code/Magento/BundleGraphQl/Test/Mftf/composer.json +++ /dev/null @@ -1,20 +0,0 @@ -{ - "name": "magento/functional-test-module-bundle-graph-ql", - "description": "N/A", - "config": { - "sort-packages": true - }, - "require": { - "php": "~7.1.3||~7.2.0", - "magento/functional-test-module-catalog": "100.0.0-dev", - "magento/functional-test-module-bundle": "100.0.0-dev", - "magento/functional-test-module-catalog-graph-ql": "100.0.0-dev", - "magento/functional-test-module-store": "100.0.0-dev", - "magento/magento2-functional-testing-framework": "2.2.0" - }, - "type": "magento2-test", - "license": [ - "OSL-3.0", - "AFL-3.0" - ] -} diff --git a/app/code/Magento/BundleImportExport/Test/Mftf/composer.json b/app/code/Magento/BundleImportExport/Test/Mftf/composer.json deleted file mode 100644 index 2210ef5248159..0000000000000 --- a/app/code/Magento/BundleImportExport/Test/Mftf/composer.json +++ /dev/null @@ -1,22 +0,0 @@ -{ - "name": "magento/functional-test-module-bundle-import-export", - "description": "N/A", - "config": { - "sort-packages": true - }, - "require": { - "php": "~7.1.3||~7.2.0", - "magento/magento2-functional-testing-framework": "2.2.0", - "magento/functional-test-module-bundle": "100.0.0-dev", - "magento/functional-test-module-store": "100.0.0-dev", - "magento/functional-test-module-catalog": "100.0.0-dev", - "magento/functional-test-module-catalog-import-export": "100.0.0-dev", - "magento/functional-test-module-eav": "100.0.0-dev", - "magento/functional-test-module-import-export": "100.0.0-dev" - }, - "type": "magento2-test", - "license": [ - "OSL-3.0", - "AFL-3.0" - ] -} diff --git a/app/code/Magento/CacheInvalidate/Test/Mftf/composer.json b/app/code/Magento/CacheInvalidate/Test/Mftf/composer.json deleted file mode 100644 index 0a6ffcf2f4661..0000000000000 --- a/app/code/Magento/CacheInvalidate/Test/Mftf/composer.json +++ /dev/null @@ -1,17 +0,0 @@ -{ - "name": "magento/functional-test-module-cache-invalidate", - "description": "N/A", - "config": { - "sort-packages": true - }, - "require": { - "php": "~7.1.3||~7.2.0", - "magento/magento2-functional-testing-framework": "2.2.0", - "magento/functional-test-module-page-cache": "100.0.0-dev" - }, - "type": "magento2-test", - "license": [ - "OSL-3.0", - "AFL-3.0" - ] -} diff --git a/app/code/Magento/Captcha/Model/Customer/Plugin/AjaxLogin.php b/app/code/Magento/Captcha/Model/Customer/Plugin/AjaxLogin.php index e496c36f4de75..91f3a785df36b 100644 --- a/app/code/Magento/Captcha/Model/Customer/Plugin/AjaxLogin.php +++ b/app/code/Magento/Captcha/Model/Customer/Plugin/AjaxLogin.php @@ -3,6 +3,7 @@ * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ + namespace Magento\Captcha\Model\Customer\Plugin; use Magento\Captcha\Helper\Data as CaptchaHelper; @@ -81,27 +82,37 @@ public function aroundExecute( if ($content) { $loginParams = $this->serializer->unserialize($content); } - $username = isset($loginParams['username']) ? $loginParams['username'] : null; - $captchaString = isset($loginParams[$captchaInputName]) ? $loginParams[$captchaInputName] : null; - $loginFormId = isset($loginParams[$captchaFormIdField]) ? $loginParams[$captchaFormIdField] : null; + $username = $loginParams['username'] ?? null; + $captchaString = $loginParams[$captchaInputName] ?? null; + $loginFormId = $loginParams[$captchaFormIdField] ?? null; - foreach ($this->formIds as $formId) { - $captchaModel = $this->helper->getCaptcha($formId); - if ($captchaModel->isRequired($username) && !in_array($loginFormId, $this->formIds)) { - $resultJson = $this->resultJsonFactory->create(); - return $resultJson->setData(['errors' => true, 'message' => __('Provided form does not exist')]); - } + if (!in_array($loginFormId, $this->formIds) && $this->helper->getCaptcha($loginFormId)->isRequired($username)) { + return $this->returnJsonError(__('Provided form does not exist')); + } - if ($formId == $loginFormId) { - $captchaModel->logAttempt($username); - if (!$captchaModel->isCorrect($captchaString)) { - $this->sessionManager->setUsername($username); - /** @var \Magento\Framework\Controller\Result\Json $resultJson */ - $resultJson = $this->resultJsonFactory->create(); - return $resultJson->setData(['errors' => true, 'message' => __('Incorrect CAPTCHA')]); + foreach ($this->formIds as $formId) { + if ($formId === $loginFormId) { + $captchaModel = $this->helper->getCaptcha($formId); + if ($captchaModel->isRequired($username)) { + $captchaModel->logAttempt($username); + if (!$captchaModel->isCorrect($captchaString)) { + $this->sessionManager->setUsername($username); + return $this->returnJsonError(__('Incorrect CAPTCHA')); + } } } } return $proceed(); } + + /** + * + * @param \Magento\Framework\Phrase $phrase + * @return \Magento\Framework\Controller\Result\Json + */ + private function returnJsonError(\Magento\Framework\Phrase $phrase): \Magento\Framework\Controller\Result\Json + { + $resultJson = $this->resultJsonFactory->create(); + return $resultJson->setData(['errors' => true, 'message' => $phrase]); + } } diff --git a/app/code/Magento/Captcha/Model/DefaultModel.php b/app/code/Magento/Captcha/Model/DefaultModel.php index e5c72ba1ae82e..cf6690df5c85d 100644 --- a/app/code/Magento/Captcha/Model/DefaultModel.php +++ b/app/code/Magento/Captcha/Model/DefaultModel.php @@ -5,6 +5,8 @@ */ namespace Magento\Captcha\Model; +use Magento\Captcha\Helper\Data; + /** * Implementation of \Zend\Captcha\Image * @@ -29,7 +31,7 @@ class DefaultModel extends \Zend\Captcha\Image implements \Magento\Captcha\Model const DEFAULT_WORD_LENGTH_TO = 5; /** - * @var \Magento\Captcha\Helper\Data + * @var Data * @since 100.2.0 */ protected $captchaData; @@ -125,8 +127,8 @@ public function getBlockName() */ public function isRequired($login = null) { - if ($this->isUserAuth() - && !$this->isShownToLoggedInUser() + if (($this->isUserAuth() + && !$this->isShownToLoggedInUser()) || !$this->isEnabled() || !in_array( $this->formId, @@ -431,12 +433,14 @@ public function getWordLen() */ private function isShowAlways() { - if ((string)$this->captchaData->getConfig('mode') == \Magento\Captcha\Helper\Data::MODE_ALWAYS) { + $captchaMode = (string)$this->captchaData->getConfig('mode'); + + if ($captchaMode === Data::MODE_ALWAYS) { return true; } - if ((string)$this->captchaData->getConfig('mode') == \Magento\Captcha\Helper\Data::MODE_AFTER_FAIL - && $this->getAllowedAttemptsForSameLogin() == 0 + if ($captchaMode === Data::MODE_AFTER_FAIL + && $this->getAllowedAttemptsForSameLogin() === 0 ) { return true; } diff --git a/app/code/Magento/Captcha/Observer/CheckGuestCheckoutObserver.php b/app/code/Magento/Captcha/Observer/CheckGuestCheckoutObserver.php index 40c215ec218a1..7ccaa76b6c7c8 100644 --- a/app/code/Magento/Captcha/Observer/CheckGuestCheckoutObserver.php +++ b/app/code/Magento/Captcha/Observer/CheckGuestCheckoutObserver.php @@ -66,15 +66,14 @@ public function execute(\Magento\Framework\Event\Observer $observer) $formId = 'guest_checkout'; $captchaModel = $this->_helper->getCaptcha($formId); $checkoutMethod = $this->_typeOnepage->getQuote()->getCheckoutMethod(); - if ($checkoutMethod == \Magento\Checkout\Model\Type\Onepage::METHOD_GUEST) { - if ($captchaModel->isRequired()) { - $controller = $observer->getControllerAction(); - if (!$captchaModel->isCorrect($this->captchaStringResolver->resolve($controller->getRequest(), $formId)) - ) { - $this->_actionFlag->set('', \Magento\Framework\App\Action\Action::FLAG_NO_DISPATCH, true); - $result = ['error' => 1, 'message' => __('Incorrect CAPTCHA')]; - $controller->getResponse()->representJson($this->jsonHelper->jsonEncode($result)); - } + if ($checkoutMethod == \Magento\Checkout\Model\Type\Onepage::METHOD_GUEST + && $captchaModel->isRequired() + ) { + $controller = $observer->getControllerAction(); + if (!$captchaModel->isCorrect($this->captchaStringResolver->resolve($controller->getRequest(), $formId))) { + $this->_actionFlag->set('', \Magento\Framework\App\Action\Action::FLAG_NO_DISPATCH, true); + $result = ['error' => 1, 'message' => __('Incorrect CAPTCHA')]; + $controller->getResponse()->representJson($this->jsonHelper->jsonEncode($result)); } } diff --git a/app/code/Magento/Captcha/Observer/CheckRegisterCheckoutObserver.php b/app/code/Magento/Captcha/Observer/CheckRegisterCheckoutObserver.php index 3bf2ac38debee..8e110a9f4653d 100644 --- a/app/code/Magento/Captcha/Observer/CheckRegisterCheckoutObserver.php +++ b/app/code/Magento/Captcha/Observer/CheckRegisterCheckoutObserver.php @@ -66,15 +66,14 @@ public function execute(\Magento\Framework\Event\Observer $observer) $formId = 'register_during_checkout'; $captchaModel = $this->_helper->getCaptcha($formId); $checkoutMethod = $this->_typeOnepage->getQuote()->getCheckoutMethod(); - if ($checkoutMethod == \Magento\Checkout\Model\Type\Onepage::METHOD_REGISTER) { - if ($captchaModel->isRequired()) { - $controller = $observer->getControllerAction(); - if (!$captchaModel->isCorrect($this->captchaStringResolver->resolve($controller->getRequest(), $formId)) - ) { - $this->_actionFlag->set('', \Magento\Framework\App\Action\Action::FLAG_NO_DISPATCH, true); - $result = ['error' => 1, 'message' => __('Incorrect CAPTCHA')]; - $controller->getResponse()->representJson($this->jsonHelper->jsonEncode($result)); - } + if ($checkoutMethod == \Magento\Checkout\Model\Type\Onepage::METHOD_REGISTER + && $captchaModel->isRequired() + ) { + $controller = $observer->getControllerAction(); + if (!$captchaModel->isCorrect($this->captchaStringResolver->resolve($controller->getRequest(), $formId))) { + $this->_actionFlag->set('', \Magento\Framework\App\Action\Action::FLAG_NO_DISPATCH, true); + $result = ['error' => 1, 'message' => __('Incorrect CAPTCHA')]; + $controller->getResponse()->representJson($this->jsonHelper->jsonEncode($result)); } } diff --git a/app/code/Magento/Captcha/Observer/CheckUserForgotPasswordBackendObserver.php b/app/code/Magento/Captcha/Observer/CheckUserForgotPasswordBackendObserver.php index 402fc028c5ad0..2de93dcf6b59b 100644 --- a/app/code/Magento/Captcha/Observer/CheckUserForgotPasswordBackendObserver.php +++ b/app/code/Magento/Captcha/Observer/CheckUserForgotPasswordBackendObserver.php @@ -69,18 +69,17 @@ public function execute(\Magento\Framework\Event\Observer $observer) $controller = $observer->getControllerAction(); $email = (string)$observer->getControllerAction()->getRequest()->getParam('email'); $params = $observer->getControllerAction()->getRequest()->getParams(); - if (!empty($email) && !empty($params)) { - if ($captchaModel->isRequired()) { - if (!$captchaModel->isCorrect($this->captchaStringResolver->resolve($controller->getRequest(), $formId)) - ) { - $this->_session->setEmail((string)$controller->getRequest()->getPost('email')); - $this->_actionFlag->set('', \Magento\Framework\App\Action\Action::FLAG_NO_DISPATCH, true); - $this->messageManager->addError(__('Incorrect CAPTCHA')); - $controller->getResponse()->setRedirect( - $controller->getUrl('*/*/forgotpassword', ['_nosecret' => true]) - ); - } - } + if (!empty($email) + && !empty($params) + && $captchaModel->isRequired() + && !$captchaModel->isCorrect($this->captchaStringResolver->resolve($controller->getRequest(), $formId)) + ) { + $this->_session->setEmail((string)$controller->getRequest()->getPost('email')); + $this->_actionFlag->set('', \Magento\Framework\App\Action\Action::FLAG_NO_DISPATCH, true); + $this->messageManager->addError(__('Incorrect CAPTCHA')); + $controller->getResponse()->setRedirect( + $controller->getUrl('*/*/forgotpassword', ['_nosecret' => true]) + ); } return $this; diff --git a/app/code/Magento/Captcha/Observer/CheckUserLoginBackendObserver.php b/app/code/Magento/Captcha/Observer/CheckUserLoginBackendObserver.php index 8cc907d7bd12b..924514cd48c5d 100644 --- a/app/code/Magento/Captcha/Observer/CheckUserLoginBackendObserver.php +++ b/app/code/Magento/Captcha/Observer/CheckUserLoginBackendObserver.php @@ -52,11 +52,11 @@ public function execute(\Magento\Framework\Event\Observer $observer) $formId = 'backend_login'; $captchaModel = $this->_helper->getCaptcha($formId); $login = $observer->getEvent()->getUsername(); - if ($captchaModel->isRequired($login)) { - if (!$captchaModel->isCorrect($this->captchaStringResolver->resolve($this->_request, $formId))) { - $captchaModel->logAttempt($login); - throw new PluginAuthenticationException(__('Incorrect CAPTCHA.')); - } + if ($captchaModel->isRequired($login) + && !$captchaModel->isCorrect($this->captchaStringResolver->resolve($this->_request, $formId)) + ) { + $captchaModel->logAttempt($login); + throw new PluginAuthenticationException(__('Incorrect CAPTCHA.')); } $captchaModel->logAttempt($login); diff --git a/app/code/Magento/Captcha/Test/Mftf/composer.json b/app/code/Magento/Captcha/Test/Mftf/composer.json deleted file mode 100644 index 95c3aa5f76078..0000000000000 --- a/app/code/Magento/Captcha/Test/Mftf/composer.json +++ /dev/null @@ -1,20 +0,0 @@ -{ - "name": "magento/functional-test-module-captcha", - "description": "N/A", - "config": { - "sort-packages": true - }, - "require": { - "php": "~7.1.3||~7.2.0", - "magento/magento2-functional-testing-framework": "2.2.0", - "magento/functional-test-module-backend": "100.0.0-dev", - "magento/functional-test-module-checkout": "100.0.0-dev", - "magento/functional-test-module-customer": "100.0.0-dev", - "magento/functional-test-module-store": "100.0.0-dev" - }, - "type": "magento2-test", - "license": [ - "OSL-3.0", - "AFL-3.0" - ] -} diff --git a/app/code/Magento/Captcha/Test/Unit/Model/Customer/Plugin/AjaxLoginTest.php b/app/code/Magento/Captcha/Test/Unit/Model/Customer/Plugin/AjaxLoginTest.php index be9574fff2cfa..ec2a49f3fc566 100644 --- a/app/code/Magento/Captcha/Test/Unit/Model/Customer/Plugin/AjaxLoginTest.php +++ b/app/code/Magento/Captcha/Test/Unit/Model/Customer/Plugin/AjaxLoginTest.php @@ -3,22 +3,23 @@ * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ + namespace Magento\Captcha\Test\Unit\Model\Customer\Plugin; class AjaxLoginTest extends \PHPUnit\Framework\TestCase { /** - * @var \PHPUnit_Framework_MockObject_MockObject + * @var \PHPUnit_Framework_MockObject_MockObject | \Magento\Checkout\Model\Session */ protected $sessionManagerMock; /** - * @var \PHPUnit_Framework_MockObject_MockObject + * @var \PHPUnit_Framework_MockObject_MockObject | \Magento\Captcha\Helper\Data */ protected $captchaHelperMock; /** - * @var \PHPUnit_Framework_MockObject_MockObject + * @var \PHPUnit_Framework_MockObject_MockObject | \Magento\Framework\Controller\Result\JsonFactory */ protected $jsonFactoryMock; @@ -38,12 +39,12 @@ class AjaxLoginTest extends \PHPUnit\Framework\TestCase protected $requestMock; /** - * @var \PHPUnit_Framework_MockObject_MockObject + * @var \PHPUnit_Framework_MockObject_MockObject | \Magento\Customer\Controller\Ajax\Login */ protected $loginControllerMock; /** - * @var \PHPUnit_Framework_MockObject_MockObject + * @var \PHPUnit_Framework_MockObject_MockObject | \Magento\Framework\Serialize\Serializer\Json */ protected $serializerMock; @@ -57,6 +58,9 @@ class AjaxLoginTest extends \PHPUnit\Framework\TestCase */ protected $model; + /** + * @inheritdoc + */ protected function setUp() { $this->sessionManagerMock = $this->createPartialMock(\Magento\Checkout\Model\Session::class, ['setUsername']); @@ -72,8 +76,12 @@ protected function setUp() $this->loginControllerMock->expects($this->any())->method('getRequest') ->will($this->returnValue($this->requestMock)); - $this->captchaHelperMock->expects($this->once())->method('getCaptcha') - ->with('user_login')->will($this->returnValue($this->captchaMock)); + + $this->captchaHelperMock + ->expects($this->exactly(1)) + ->method('getCaptcha') + ->will($this->returnValue($this->captchaMock)); + $this->formIds = ['user_login']; $this->serializerMock = $this->createMock(\Magento\Framework\Serialize\Serializer\Json::class); @@ -86,6 +94,9 @@ protected function setUp() ); } + /** + * Test aroundExecute. + */ public function testAroundExecute() { $username = 'name'; @@ -103,14 +114,24 @@ public function testAroundExecute() $this->captchaMock->expects($this->once())->method('logAttempt')->with($username); $this->captchaMock->expects($this->once())->method('isCorrect')->with($captchaString) ->will($this->returnValue(true)); - $this->serializerMock->expects(($this->once()))->method('unserialize')->will($this->returnValue($requestData)); + $this->serializerMock->expects($this->once())->method('unserialize')->will($this->returnValue($requestData)); $closure = function () { return 'result'; }; + + $this->captchaHelperMock + ->expects($this->exactly(1)) + ->method('getCaptcha') + ->with('user_login') + ->will($this->returnValue($this->captchaMock)); + $this->assertEquals('result', $this->model->aroundExecute($this->loginControllerMock, $closure)); } + /** + * Test aroundExecuteIncorrectCaptcha. + */ public function testAroundExecuteIncorrectCaptcha() { $username = 'name'; @@ -128,18 +149,21 @@ public function testAroundExecuteIncorrectCaptcha() $this->captchaMock->expects($this->once())->method('logAttempt')->with($username); $this->captchaMock->expects($this->once())->method('isCorrect') ->with($captchaString)->will($this->returnValue(false)); - $this->serializerMock->expects(($this->once()))->method('unserialize')->will($this->returnValue($requestData)); + $this->serializerMock->expects($this->once())->method('unserialize')->will($this->returnValue($requestData)); $this->sessionManagerMock->expects($this->once())->method('setUsername')->with($username); $this->jsonFactoryMock->expects($this->once())->method('create') ->will($this->returnValue($this->resultJsonMock)); - $this->resultJsonMock->expects($this->once())->method('setData') - ->with(['errors' => true, 'message' => __('Incorrect CAPTCHA')])->will($this->returnValue('response')); + $this->resultJsonMock + ->expects($this->once()) + ->method('setData') + ->with(['errors' => true, 'message' => __('Incorrect CAPTCHA')]) + ->will($this->returnSelf()); $closure = function () { }; - $this->assertEquals('response', $this->model->aroundExecute($this->loginControllerMock, $closure)); + $this->assertEquals($this->resultJsonMock, $this->model->aroundExecute($this->loginControllerMock, $closure)); } /** @@ -151,7 +175,7 @@ public function testAroundExecuteCaptchaIsNotRequired($username, $requestContent { $this->requestMock->expects($this->once())->method('getContent') ->will($this->returnValue(json_encode($requestContent))); - $this->serializerMock->expects(($this->once()))->method('unserialize') + $this->serializerMock->expects($this->once())->method('unserialize') ->will($this->returnValue($requestContent)); $this->captchaMock->expects($this->once())->method('isRequired')->with($username) @@ -168,16 +192,39 @@ public function testAroundExecuteCaptchaIsNotRequired($username, $requestContent /** * @return array */ - public function aroundExecuteCaptchaIsNotRequired() + public function aroundExecuteCaptchaIsNotRequired(): array { return [ [ 'username' => 'name', 'requestData' => ['username' => 'name', 'captcha_string' => 'string'], ], + [ + 'username' => 'name', + 'requestData' => + [ + 'username' => 'name', + 'captcha_string' => 'string', + 'captcha_form_id' => $this->formIds[0] + ], + ], [ 'username' => null, - 'requestData' => ['captcha_string' => 'string'], + 'requestData' => + [ + 'username' => null, + 'captcha_string' => 'string', + 'captcha_form_id' => $this->formIds[0] + ], + ], + [ + 'username' => 'name', + 'requestData' => + [ + 'username' => 'name', + 'captcha_string' => 'string', + 'captcha_form_id' => null + ], ], ]; } diff --git a/app/code/Magento/Captcha/view/frontend/templates/default.phtml b/app/code/Magento/Captcha/view/frontend/templates/default.phtml index 980a78ff0f7c5..6c9a5fe85f596 100644 --- a/app/code/Magento/Captcha/view/frontend/templates/default.phtml +++ b/app/code/Magento/Captcha/view/frontend/templates/default.phtml @@ -14,7 +14,7 @@ $captcha = $block->getCaptchaModel(); <div class="field captcha required" role="<?= $block->escapeHtmlAttr($block->getFormId()) ?>"> <label for="captcha_<?= $block->escapeHtmlAttr($block->getFormId()) ?>" class="label"><span><?= $block->escapeHtml(__('Please type the letters and numbers below')) ?></span></label> <div class="control captcha"> - <input name="<?= $block->escapeHtmlAttr(\Magento\Captcha\Helper\Data::INPUT_NAME_FIELD_VALUE) ?>[<?= $block->escapeHtmlAttr($block->getFormId()) ?>]" type="text" class="input-text required-entry" data-validate="{required:true}" id="captcha_<?= $block->escapeHtmlAttr($block->getFormId()) ?>" /> + <input name="<?= $block->escapeHtmlAttr(\Magento\Captcha\Helper\Data::INPUT_NAME_FIELD_VALUE) ?>[<?= $block->escapeHtmlAttr($block->getFormId()) ?>]" type="text" class="input-text required-entry" data-validate="{required:true}" id="captcha_<?= $block->escapeHtmlAttr($block->getFormId()) ?>" autocomplete="off"/> <div class="nested"> <div class="field captcha no-label" data-captcha="<?= $block->escapeHtmlAttr($block->getFormId()) ?>" diff --git a/app/code/Magento/Captcha/view/frontend/web/template/checkout/captcha.html b/app/code/Magento/Captcha/view/frontend/web/template/checkout/captcha.html index 97c05249eb463..575b3ca6f732e 100644 --- a/app/code/Magento/Captcha/view/frontend/web/template/checkout/captcha.html +++ b/app/code/Magento/Captcha/view/frontend/web/template/checkout/captcha.html @@ -8,7 +8,7 @@ <div class="field captcha required" data-bind="blockLoader: getIsLoading()"> <label data-bind="attr: {for: 'captcha_' + formId}" class="label"><span data-bind="i18n: 'Please type the letters and numbers below'"></span></label> <div class="control captcha"> - <input name="captcha_string" type="text" class="input-text required-entry" data-bind="value: captchaValue(), attr: {id: 'captcha_' + formId, 'data-scope': dataScope}" /> + <input name="captcha_string" type="text" class="input-text required-entry" data-bind="value: captchaValue(), attr: {id: 'captcha_' + formId, 'data-scope': dataScope}" autocomplete="off"/> <input name="captcha_form_id" type="hidden" data-bind="value: formId, attr: {'data-scope': dataScope}" /> <div class="nested"> <div class="field captcha no-label"> diff --git a/app/code/Magento/Catalog/Block/Adminhtml/Category/Checkboxes/Tree.php b/app/code/Magento/Catalog/Block/Adminhtml/Category/Checkboxes/Tree.php index ad1ccea6f2c5a..1e0015d2be2c6 100644 --- a/app/code/Magento/Catalog/Block/Adminhtml/Category/Checkboxes/Tree.php +++ b/app/code/Magento/Catalog/Block/Adminhtml/Category/Checkboxes/Tree.php @@ -30,7 +30,7 @@ class Tree extends \Magento\Catalog\Block\Adminhtml\Category\Tree */ protected function _prepareLayout() { - $this->setTemplate('catalog/category/checkboxes/tree.phtml'); + $this->setTemplate('Magento_Catalog::catalog/category/checkboxes/tree.phtml'); } /** diff --git a/app/code/Magento/Catalog/Block/Adminhtml/Form/Renderer/Config/YearRange.php b/app/code/Magento/Catalog/Block/Adminhtml/Form/Renderer/Config/YearRange.php index 0026e52e039ef..cd6c5021f0cc9 100644 --- a/app/code/Magento/Catalog/Block/Adminhtml/Form/Renderer/Config/YearRange.php +++ b/app/code/Magento/Catalog/Block/Adminhtml/Form/Renderer/Config/YearRange.php @@ -32,10 +32,9 @@ protected function _getElementHtml(AbstractElement $element) $from = $element->setValue(isset($values[0]) ? $values[0] : null)->getElementHtml(); $to = $element->setValue(isset($values[1]) ? $values[1] : null)->getElementHtml(); - return __( - '<label class="label"><span>from</span></label>' - ) . $from . __( - '<label class="label"><span>to</span></label>' - ) . $to; + return '<label class="label"><span>' . __('from') . '</span></label>' + . $from . + '<label class="label"><span>' . __('to') . '</span></label>' + . $to; } } diff --git a/app/code/Magento/Catalog/Block/Adminhtml/Product/Edit/Tab/Ajax/Serializer.php b/app/code/Magento/Catalog/Block/Adminhtml/Product/Edit/Tab/Ajax/Serializer.php index a7129f509316b..3d131a6e08810 100644 --- a/app/code/Magento/Catalog/Block/Adminhtml/Product/Edit/Tab/Ajax/Serializer.php +++ b/app/code/Magento/Catalog/Block/Adminhtml/Product/Edit/Tab/Ajax/Serializer.php @@ -41,7 +41,7 @@ public function __construct( public function _construct() { parent::_construct(); - $this->setTemplate('catalog/product/edit/serializer.phtml'); + $this->setTemplate('Magento_Catalog::catalog/product/edit/serializer.phtml'); return $this; } diff --git a/app/code/Magento/Catalog/Block/Adminhtml/Product/Helper/Form/Gallery.php b/app/code/Magento/Catalog/Block/Adminhtml/Product/Helper/Form/Gallery.php index f30b37877b78f..0557a215383d3 100644 --- a/app/code/Magento/Catalog/Block/Adminhtml/Product/Helper/Form/Gallery.php +++ b/app/code/Magento/Catalog/Block/Adminhtml/Product/Helper/Form/Gallery.php @@ -102,7 +102,7 @@ public function getElementHtml() */ public function getImages() { - return $this->registry->registry('current_product')->getData('media_gallery') ?: null; + return $this->getDataObject()->getData('media_gallery') ?: null; } /** diff --git a/app/code/Magento/Catalog/Block/Product/View/Attributes.php b/app/code/Magento/Catalog/Block/Product/View/Attributes.php index b353e477a056c..cb59d86a74512 100644 --- a/app/code/Magento/Catalog/Block/Product/View/Attributes.php +++ b/app/code/Magento/Catalog/Block/Product/View/Attributes.php @@ -67,12 +67,11 @@ public function getProduct() } /** - * $excludeAttr is optional array of attribute codes to - * exclude them from additional data array + * $excludeAttr is optional array of attribute codes to exclude them from additional data array * * @param array $excludeAttr * @return array - * @SuppressWarnings(PHPMD.CyclomaticComplexity) + * @throws \Magento\Framework\Exception\LocalizedException */ public function getAdditionalData(array $excludeAttr = []) { @@ -80,7 +79,7 @@ public function getAdditionalData(array $excludeAttr = []) $product = $this->getProduct(); $attributes = $product->getAttributes(); foreach ($attributes as $attribute) { - if ($attribute->getIsVisibleOnFront() && !in_array($attribute->getAttributeCode(), $excludeAttr)) { + if ($this->isVisibleOnFrontend($attribute, $excludeAttr)) { $value = $attribute->getFrontend()->getValue($product); if ($value instanceof Phrase) { @@ -100,4 +99,18 @@ public function getAdditionalData(array $excludeAttr = []) } return $data; } + + /** + * Determine if we should display the attribute on the front-end + * + * @param \Magento\Eav\Model\Entity\Attribute\AbstractAttribute $attribute + * @param array $excludeAttr + * @return bool + */ + protected function isVisibleOnFrontend( + \Magento\Eav\Model\Entity\Attribute\AbstractAttribute $attribute, + array $excludeAttr + ) { + return ($attribute->getIsVisibleOnFront() && !in_array($attribute->getAttributeCode(), $excludeAttr)); + } } diff --git a/app/code/Magento/Catalog/Console/Command/PriceIndexerDimensionsModeSetCommand.php b/app/code/Magento/Catalog/Console/Command/PriceIndexerDimensionsModeSetCommand.php new file mode 100644 index 0000000000000..e331f4d2a2fc4 --- /dev/null +++ b/app/code/Magento/Catalog/Console/Command/PriceIndexerDimensionsModeSetCommand.php @@ -0,0 +1,198 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +declare(strict_types=1); + +namespace Magento\Catalog\Console\Command; + +use Magento\Catalog\Model\Indexer\Product\Price\DimensionModeConfiguration; +use Symfony\Component\Console\Input\InputInterface; +use Symfony\Component\Console\Output\OutputInterface; +use Symfony\Component\Console\Input\InputOption; +use Symfony\Component\Console\Input\InputArgument; +use Magento\Framework\Exception\LocalizedException; +use Magento\Indexer\Console\Command\AbstractIndexerCommand; +use Magento\Framework\App\ObjectManagerFactory; +use Magento\Catalog\Model\Indexer\Product\Price\ModeSwitcher; +use Magento\Framework\App\Config\ScopeConfigInterface; +use Magento\Framework\App\Config\ConfigResource\ConfigInterface; +use Magento\Framework\App\Cache\TypeListInterface; + +/** + * Command to change price indexer dimensions mode + * + * @SuppressWarnings(PHPMD.CouplingBetweenObjects) + */ +class PriceIndexerDimensionsModeSetCommand extends AbstractIndexerCommand +{ + const INPUT_KEY_MODE = 'mode'; + + /** + * ScopeConfigInterface + * + * @var ScopeConfigInterface + */ + private $configReader; + + /** + * ConfigInterface + * + * @var ConfigInterface + */ + private $configWriter; + + /** + * TypeListInterface + * + * @var TypeListInterface + */ + private $cacheTypeList; + + /** + * ModeSwitcher + * + * @var ModeSwitcher + */ + private $modeSwitcher; + + /** + * @param ObjectManagerFactory $objectManagerFactory + * @param ScopeConfigInterface $configReader + * @param ConfigInterface $configWriter + * @param TypeListInterface $cacheTypeList + * @param ModeSwitcher $modeSwitcher + */ + public function __construct( + ObjectManagerFactory $objectManagerFactory, + ScopeConfigInterface $configReader, + ConfigInterface $configWriter, + TypeListInterface $cacheTypeList, + ModeSwitcher $modeSwitcher + ) { + $this->configReader = $configReader; + $this->configWriter = $configWriter; + $this->cacheTypeList = $cacheTypeList; + $this->modeSwitcher = $modeSwitcher; + parent::__construct($objectManagerFactory); + } + + /** + * {@inheritdoc} + */ + protected function configure() + { + $this->setName('indexer:set-dimensions-mode:catalog_product_price') + ->setDescription('Set Indexer Dimensions Mode') + ->setDefinition($this->getInputList()); + + parent::configure(); + } + + /** + * {@inheritdoc} + */ + protected function execute(InputInterface $input, OutputInterface $output) + { + $errors = $this->validate($input); + + if ($errors) { + throw new \InvalidArgumentException(implode(PHP_EOL, $errors)); + } + + $returnValue = \Magento\Framework\Console\Cli::RETURN_SUCCESS; + + $indexer = $this->getObjectManager()->get(\Magento\Indexer\Model\Indexer::class); + $indexer->load(\Magento\Catalog\Model\Indexer\Product\Price\Processor::INDEXER_ID); + + try { + $currentMode = $input->getArgument(self::INPUT_KEY_MODE); + $previousMode = $this->configReader->getValue(ModeSwitcher::XML_PATH_PRICE_DIMENSIONS_MODE) ?: + DimensionModeConfiguration::DIMENSION_NONE; + + if ($previousMode !== $currentMode) { + //Create new tables and move data + $this->modeSwitcher->createTables($currentMode); + $this->modeSwitcher->moveData($currentMode, $previousMode); + + //Change config options + $this->configWriter->saveConfig(ModeSwitcher::XML_PATH_PRICE_DIMENSIONS_MODE, $currentMode); + $this->cacheTypeList->cleanType('config'); + $indexer->invalidate(); + + //Delete old tables + $this->modeSwitcher->dropTables($previousMode); + + $output->writeln( + 'Dimensions mode for indexer ' . $indexer->getTitle() . ' was changed from \'' + . $previousMode . '\' to \'' . $currentMode . '\'' + ); + } else { + $output->writeln('Dimensions mode for indexer ' . $indexer->getTitle() . ' has not been changed'); + } + } catch (LocalizedException $e) { + $output->writeln($e->getMessage() . PHP_EOL); + // we must have an exit code higher than zero to indicate something was wrong + $returnValue = \Magento\Framework\Console\Cli::RETURN_FAILURE; + } catch (\Exception $e) { + $output->writeln($indexer->getTitle() . " indexer process unknown error:" . PHP_EOL); + $output->writeln($e->getMessage() . PHP_EOL); + // we must have an exit code higher than zero to indicate something was wrong + $returnValue = \Magento\Framework\Console\Cli::RETURN_FAILURE; + } + + return $returnValue; + } + + /** + * Get list of arguments for the command + * + * @return InputOption[] + */ + public function getInputList(): array + { + $modeOptions[] = new InputArgument( + self::INPUT_KEY_MODE, + InputArgument::REQUIRED, + 'Indexer dimensions mode ['. DimensionModeConfiguration::DIMENSION_NONE + . '|' . DimensionModeConfiguration::DIMENSION_WEBSITE + . '|' . DimensionModeConfiguration::DIMENSION_CUSTOMER_GROUP + . '|' . DimensionModeConfiguration::DIMENSION_WEBSITE_AND_CUSTOMER_GROUP .']' + ); + return $modeOptions; + } + + /** + * Check if all admin options are provided + * + * @param InputInterface $input + * @return string[] + */ + public function validate(InputInterface $input): array + { + $errors = []; + + $acceptedModeValues = ' Accepted values for ' . self::INPUT_KEY_MODE . ' are \'' + . DimensionModeConfiguration::DIMENSION_NONE . '\', \'' + . DimensionModeConfiguration::DIMENSION_WEBSITE . '\', \'' + . DimensionModeConfiguration::DIMENSION_CUSTOMER_GROUP . '\', \'' + . DimensionModeConfiguration::DIMENSION_WEBSITE_AND_CUSTOMER_GROUP . '\''; + + $inputMode = $input->getArgument(self::INPUT_KEY_MODE); + if (!$inputMode) { + $errors[] = 'Missing argument \'' . self::INPUT_KEY_MODE .'\'.' . $acceptedModeValues; + } elseif (!in_array( + $inputMode, + [ + DimensionModeConfiguration::DIMENSION_NONE, + DimensionModeConfiguration::DIMENSION_WEBSITE, + DimensionModeConfiguration::DIMENSION_CUSTOMER_GROUP, + DimensionModeConfiguration::DIMENSION_WEBSITE_AND_CUSTOMER_GROUP + ] + )) { + $errors[] = $acceptedModeValues; + } + return $errors; + } +} diff --git a/app/code/Magento/Catalog/Controller/Adminhtml/Category/Save.php b/app/code/Magento/Catalog/Controller/Adminhtml/Category/Save.php index cc03ab870739b..aa9ae88754b6a 100644 --- a/app/code/Magento/Catalog/Controller/Adminhtml/Category/Save.php +++ b/app/code/Magento/Catalog/Controller/Adminhtml/Category/Save.php @@ -280,7 +280,7 @@ public function imagePreprocessing($data) continue; } - $data[$attributeCode] = false; + $data[$attributeCode] = ''; } return $data; diff --git a/app/code/Magento/Catalog/Controller/Adminhtml/Product/Attribute/Validate.php b/app/code/Magento/Catalog/Controller/Adminhtml/Product/Attribute/Validate.php index b61be2b95b960..db452113ada06 100644 --- a/app/code/Magento/Catalog/Controller/Adminhtml/Product/Attribute/Validate.php +++ b/app/code/Magento/Catalog/Controller/Adminhtml/Product/Attribute/Validate.php @@ -92,9 +92,7 @@ public function execute() $attributeSet->setEntityTypeId($this->_entityTypeId)->load($setName, 'attribute_set_name'); if ($attributeSet->getId()) { $setName = $this->_objectManager->get(\Magento\Framework\Escaper::class)->escapeHtml($setName); - $this->messageManager->addError( - __('A "%1" attribute set name already exists. Create a new name and try again.', $setName) - ); + $this->messageManager->addErrorMessage(__('An attribute set named \'%1\' already exists.', $setName)); $layout = $this->layoutFactory->create(); $layout->initMessages(); diff --git a/app/code/Magento/Catalog/Controller/Adminhtml/Product/Initialization/Helper.php b/app/code/Magento/Catalog/Controller/Adminhtml/Product/Initialization/Helper.php index 95339870b4d61..d82f4a04fb252 100644 --- a/app/code/Magento/Catalog/Controller/Adminhtml/Product/Initialization/Helper.php +++ b/app/code/Magento/Catalog/Controller/Adminhtml/Product/Initialization/Helper.php @@ -104,7 +104,7 @@ class Helper * @param \Magento\Backend\Helper\Js $jsHelper * @param \Magento\Framework\Stdlib\DateTime\Filter\Date $dateFilter * @param CustomOptionFactory|null $customOptionFactory - * @param ProductLinkFactory |null $productLinkFactory + * @param ProductLinkFactory|null $productLinkFactory * @param ProductRepositoryInterface|null $productRepository * @param LinkTypeProvider|null $linkTypeProvider * @param AttributeFilter|null $attributeFilter @@ -159,6 +159,7 @@ public function initializeFromData(\Magento\Catalog\Model\Product $product, arra } $productData = $this->normalize($productData); + $productData = $this->convertSpecialFromDateStringToObject($productData); if (!empty($productData['is_downloadable'])) { $productData['product_has_weight'] = 0; @@ -452,4 +453,19 @@ private function fillProductOptions(Product $product, array $productOptions) return $product->setOptions($customOptions); } + + /** + * Convert string date presentation into object + * + * @param array $productData + * @return array + */ + private function convertSpecialFromDateStringToObject($productData) + { + if (isset($productData['special_from_date']) && $productData['special_from_date'] != '') { + $productData['special_from_date'] = new \DateTime($productData['special_from_date']); + } + + return $productData; + } } diff --git a/app/code/Magento/Catalog/Controller/Adminhtml/Product/MassDelete.php b/app/code/Magento/Catalog/Controller/Adminhtml/Product/MassDelete.php index 2402fb213cda0..f32c6edd57394 100644 --- a/app/code/Magento/Catalog/Controller/Adminhtml/Product/MassDelete.php +++ b/app/code/Magento/Catalog/Controller/Adminhtml/Product/MassDelete.php @@ -64,9 +64,12 @@ public function execute() $this->productRepository->delete($product); $productDeleted++; } - $this->messageManager->addSuccess( - __('A total of %1 record(s) have been deleted.', $productDeleted) - ); + + if ($productDeleted) { + $this->messageManager->addSuccessMessage( + __('A total of %1 record(s) have been deleted.', $productDeleted) + ); + } return $this->resultFactory->create(ResultFactory::TYPE_REDIRECT)->setPath('catalog/*/index'); } diff --git a/app/code/Magento/Catalog/Controller/Adminhtml/Product/Save.php b/app/code/Magento/Catalog/Controller/Adminhtml/Product/Save.php index 84837262a8154..ff3ce60d92787 100644 --- a/app/code/Magento/Catalog/Controller/Adminhtml/Product/Save.php +++ b/app/code/Magento/Catalog/Controller/Adminhtml/Product/Save.php @@ -204,7 +204,8 @@ private function handleImageRemoveError($postData, $productId) if ($removedImagesAmount) { $expectedImagesAmount = count($postData['product']['media_gallery']['images']) - $removedImagesAmount; $product = $this->productRepository->getById($productId); - if ($expectedImagesAmount != count($product->getMediaGallery('images'))) { + $images = $product->getMediaGallery('images'); + if (is_array($images) && $expectedImagesAmount != count($images)) { $this->messageManager->addNoticeMessage( __('The image cannot be removed as it has been assigned to the other image role') ); diff --git a/app/code/Magento/Catalog/Controller/Category/View.php b/app/code/Magento/Catalog/Controller/Category/View.php index a72f764a5f1f6..226e572505076 100644 --- a/app/code/Magento/Catalog/Controller/Category/View.php +++ b/app/code/Magento/Catalog/Controller/Category/View.php @@ -111,7 +111,7 @@ public function __construct( /** * Initialize requested category object * - * @return \Magento\Catalog\Model\Category + * @return \Magento\Catalog\Model\Category|bool */ protected function _initCategory() { diff --git a/app/code/Magento/Catalog/Controller/Product/Compare/Add.php b/app/code/Magento/Catalog/Controller/Product/Compare/Add.php index 89eb6c9be929f..eb9cc83125541 100644 --- a/app/code/Magento/Catalog/Controller/Product/Compare/Add.php +++ b/app/code/Magento/Catalog/Controller/Product/Compare/Add.php @@ -36,7 +36,14 @@ public function execute() $productName = $this->_objectManager->get( \Magento\Framework\Escaper::class )->escapeHtml($product->getName()); - $this->messageManager->addSuccess(__('You added product %1 to the comparison list.', $productName)); + $this->messageManager->addComplexSuccessMessage( + 'addCompareSuccessMessage', + [ + 'product_name' => $productName, + 'compare_list_url' => $this->_url->getUrl('catalog/product_compare') + ] + ); + $this->_eventManager->dispatch('catalog_product_compare_add_product', ['product' => $product]); } diff --git a/app/code/Magento/Catalog/CustomerData/CompareProducts.php b/app/code/Magento/Catalog/CustomerData/CompareProducts.php index 0e688042c615a..afbeab8c9070e 100644 --- a/app/code/Magento/Catalog/CustomerData/CompareProducts.php +++ b/app/code/Magento/Catalog/CustomerData/CompareProducts.php @@ -19,6 +19,11 @@ class CompareProducts implements SectionSourceInterface */ protected $productUrl; + /** + * @var \Magento\Catalog\Helper\Output + */ + private $outputHelper; + /** * @param \Magento\Catalog\Helper\Product\Compare $helper * @param \Magento\Catalog\Model\Product\Url $productUrl @@ -54,6 +59,7 @@ public function getSectionData() protected function getItems() { $items = []; + /** @var \Magento\Catalog\Model\Product $item */ foreach ($this->helper->getItemCollection() as $item) { $items[] = [ 'id' => $item->getId(), diff --git a/app/code/Magento/Catalog/Model/Category/Attribute/Backend/Image.php b/app/code/Magento/Catalog/Model/Category/Attribute/Backend/Image.php index a2dff83173b37..cd450e26cd832 100644 --- a/app/code/Magento/Catalog/Model/Category/Attribute/Backend/Image.php +++ b/app/code/Magento/Catalog/Model/Category/Attribute/Backend/Image.php @@ -106,7 +106,7 @@ public function beforeSave($object) $object->setData($this->additionalData . $attributeName, $value); $object->setData($attributeName, $imageName); } elseif (!is_string($value)) { - $object->setData($attributeName, ''); + $object->setData($attributeName, null); } return parent::beforeSave($object); diff --git a/app/code/Magento/Catalog/Model/Indexer/Category/Product/Plugin/StoreGroup.php b/app/code/Magento/Catalog/Model/Indexer/Category/Product/Plugin/StoreGroup.php index 9f4e19bf95a8d..005936a75e6d6 100644 --- a/app/code/Magento/Catalog/Model/Indexer/Category/Product/Plugin/StoreGroup.php +++ b/app/code/Magento/Catalog/Model/Indexer/Category/Product/Plugin/StoreGroup.php @@ -97,7 +97,7 @@ protected function validate(AbstractModel $group) public function afterDelete(AbstractDb $subject, AbstractDb $objectResource, AbstractModel $storeGroup) { foreach ($storeGroup->getStores() as $store) { - $this->tableMaintainer->dropTablesForStore($store->getId()); + $this->tableMaintainer->dropTablesForStore((int)$store->getId()); } return $objectResource; } diff --git a/app/code/Magento/Catalog/Model/Indexer/Category/Product/Plugin/StoreView.php b/app/code/Magento/Catalog/Model/Indexer/Category/Product/Plugin/StoreView.php index 114d2a94f5b35..b6f9e6adf4a1c 100644 --- a/app/code/Magento/Catalog/Model/Indexer/Category/Product/Plugin/StoreView.php +++ b/app/code/Magento/Catalog/Model/Indexer/Category/Product/Plugin/StoreView.php @@ -51,7 +51,7 @@ public function afterSave(AbstractDb $subject, AbstractDb $objectResource, Abstr */ public function afterDelete(AbstractDb $subject, AbstractDb $objectResource, AbstractModel $store) { - $this->tableMaintainer->dropTablesForStore($store->getId()); + $this->tableMaintainer->dropTablesForStore((int)$store->getId()); return $objectResource; } } diff --git a/app/code/Magento/Catalog/Model/Indexer/Category/Product/Plugin/Website.php b/app/code/Magento/Catalog/Model/Indexer/Category/Product/Plugin/Website.php index 387a8085310e4..50700e672237e 100644 --- a/app/code/Magento/Catalog/Model/Indexer/Category/Product/Plugin/Website.php +++ b/app/code/Magento/Catalog/Model/Indexer/Category/Product/Plugin/Website.php @@ -39,7 +39,7 @@ public function __construct( public function afterDelete(AbstractDb $subject, AbstractDb $objectResource, AbstractModel $website) { foreach ($website->getStoreIds() as $storeId) { - $this->tableMaintainer->dropTablesForStore($storeId); + $this->tableMaintainer->dropTablesForStore((int)$storeId); } return $objectResource; } diff --git a/app/code/Magento/Catalog/Model/Indexer/Category/Product/TableMaintainer.php b/app/code/Magento/Catalog/Model/Indexer/Category/Product/TableMaintainer.php index 105a6dbf30456..3c2629bc570f2 100644 --- a/app/code/Magento/Catalog/Model/Indexer/Category/Product/TableMaintainer.php +++ b/app/code/Magento/Catalog/Model/Indexer/Category/Product/TableMaintainer.php @@ -91,6 +91,8 @@ private function getTable($table) * @param string $newTableName * * @return void + * + * @throws \Zend_Db_Exception */ private function createTable($mainTableName, $newTableName) { @@ -135,6 +137,8 @@ public function getMainTable(int $storeId) * @param $storeId * * @return void + * + * @throws \Zend_Db_Exception */ public function createTablesForStore(int $storeId) { @@ -206,12 +210,12 @@ public function createMainTmpTable(int $storeId) * * @return string * - * @throws \Exception + * @throws \Magento\Framework\Exception\NoSuchEntityException */ public function getMainTmpTable(int $storeId) { if (!isset($this->mainTmpTable[$storeId])) { - throw new \Exception('Temporary table does not exist'); + throw new \Magento\Framework\Exception\NoSuchEntityException('Temporary table does not exist'); } return $this->mainTmpTable[$storeId]; } diff --git a/app/code/Magento/Catalog/Model/Indexer/Product/Eav/AbstractAction.php b/app/code/Magento/Catalog/Model/Indexer/Product/Eav/AbstractAction.php index b6206f96b91e0..6101e5cd362e4 100644 --- a/app/code/Magento/Catalog/Model/Indexer/Product/Eav/AbstractAction.php +++ b/app/code/Magento/Catalog/Model/Indexer/Product/Eav/AbstractAction.php @@ -3,6 +3,8 @@ * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ +declare(strict_types=1); + namespace Magento\Catalog\Model\Indexer\Product\Eav; use Magento\Catalog\Model\ResourceModel\Product\Indexer\Eav\AbstractEav; @@ -12,6 +14,11 @@ */ abstract class AbstractAction { + /** + * Config path for enable EAV indexer + */ + const ENABLE_EAV_INDEXER = 'catalog/search/enable_eav_indexer'; + /** * EAV Indexers by type * @@ -29,17 +36,27 @@ abstract class AbstractAction */ protected $_eavDecimalFactory; + /** + * @var \Magento\Framework\App\Config\ScopeConfigInterface + */ + private $scopeConfig; + /** * AbstractAction constructor. * @param \Magento\Catalog\Model\ResourceModel\Product\Indexer\Eav\DecimalFactory $eavDecimalFactory * @param \Magento\Catalog\Model\ResourceModel\Product\Indexer\Eav\SourceFactory $eavSourceFactory + * @param \Magento\Framework\App\Config\ScopeConfigInterface|null $scopeConfig */ public function __construct( \Magento\Catalog\Model\ResourceModel\Product\Indexer\Eav\DecimalFactory $eavDecimalFactory, - \Magento\Catalog\Model\ResourceModel\Product\Indexer\Eav\SourceFactory $eavSourceFactory + \Magento\Catalog\Model\ResourceModel\Product\Indexer\Eav\SourceFactory $eavSourceFactory, + \Magento\Framework\App\Config\ScopeConfigInterface $scopeConfig = null ) { $this->_eavDecimalFactory = $eavDecimalFactory; $this->_eavSourceFactory = $eavSourceFactory; + $this->scopeConfig = $scopeConfig ?: \Magento\Framework\App\ObjectManager::getInstance()->get( + \Magento\Framework\App\Config\ScopeConfigInterface::class + ); } /** @@ -92,6 +109,9 @@ public function getIndexer($type) */ public function reindex($ids = null) { + if (!$this->isEavIndexerEnabled()) { + return; + } foreach ($this->getIndexers() as $indexer) { if ($ids === null) { $indexer->reindexAll(); @@ -149,4 +169,19 @@ protected function processRelations(AbstractEav $indexer, array $ids, bool $only return array_unique(array_merge($ids, $childIds, $parentIds)); } + + /** + * Get EAV indexer status + * + * @return bool + */ + private function isEavIndexerEnabled(): bool + { + $eavIndexerStatus = $this->scopeConfig->getValue( + self::ENABLE_EAV_INDEXER, + \Magento\Store\Model\ScopeInterface::SCOPE_STORE + ); + + return (bool)$eavIndexerStatus; + } } diff --git a/app/code/Magento/Catalog/Model/Indexer/Product/Eav/Action/Full.php b/app/code/Magento/Catalog/Model/Indexer/Product/Eav/Action/Full.php index bc747e62f641e..802176092d147 100644 --- a/app/code/Magento/Catalog/Model/Indexer/Product/Eav/Action/Full.php +++ b/app/code/Magento/Catalog/Model/Indexer/Product/Eav/Action/Full.php @@ -3,12 +3,15 @@ * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ +declare(strict_types=1); + namespace Magento\Catalog\Model\Indexer\Product\Eav\Action; use Magento\Catalog\Model\ResourceModel\Indexer\ActiveTableSwitcher; /** * Class Full reindex action + * @SuppressWarnings(PHPMD.CouplingBetweenObjects) */ class Full extends \Magento\Catalog\Model\Indexer\Product\Eav\AbstractAction { @@ -32,6 +35,11 @@ class Full extends \Magento\Catalog\Model\Indexer\Product\Eav\AbstractAction */ private $activeTableSwitcher; + /** + * @var \Magento\Framework\App\Config\ScopeConfigInterface + */ + private $scopeConfig; + /** * @param \Magento\Catalog\Model\ResourceModel\Product\Indexer\Eav\DecimalFactory $eavDecimalFactory * @param \Magento\Catalog\Model\ResourceModel\Product\Indexer\Eav\SourceFactory $eavSourceFactory @@ -39,6 +47,7 @@ class Full extends \Magento\Catalog\Model\Indexer\Product\Eav\AbstractAction * @param \Magento\Framework\Indexer\BatchProviderInterface|null $batchProvider * @param \Magento\Catalog\Model\ResourceModel\Product\Indexer\Eav\BatchSizeCalculator $batchSizeCalculator * @param ActiveTableSwitcher|null $activeTableSwitcher + * @param \Magento\Framework\App\Config\ScopeConfigInterface|null $scopeConfig */ public function __construct( \Magento\Catalog\Model\ResourceModel\Product\Indexer\Eav\DecimalFactory $eavDecimalFactory, @@ -46,9 +55,13 @@ public function __construct( \Magento\Framework\EntityManager\MetadataPool $metadataPool = null, \Magento\Framework\Indexer\BatchProviderInterface $batchProvider = null, \Magento\Catalog\Model\ResourceModel\Product\Indexer\Eav\BatchSizeCalculator $batchSizeCalculator = null, - ActiveTableSwitcher $activeTableSwitcher = null + ActiveTableSwitcher $activeTableSwitcher = null, + \Magento\Framework\App\Config\ScopeConfigInterface $scopeConfig = null ) { - parent::__construct($eavDecimalFactory, $eavSourceFactory); + $this->scopeConfig = $scopeConfig ?: \Magento\Framework\App\ObjectManager::getInstance()->get( + \Magento\Framework\App\Config\ScopeConfigInterface::class + ); + parent::__construct($eavDecimalFactory, $eavSourceFactory, $scopeConfig); $this->metadataPool = $metadataPool ?: \Magento\Framework\App\ObjectManager::getInstance()->get( \Magento\Framework\EntityManager\MetadataPool::class ); @@ -73,6 +86,9 @@ public function __construct( */ public function execute($ids = null) { + if (!$this->isEavIndexerEnabled()) { + return; + } try { foreach ($this->getIndexers() as $indexerName => $indexer) { $connection = $indexer->getConnection(); @@ -129,4 +145,19 @@ protected function syncData($indexer, $destinationTable, $ids = null) throw $e; } } + + /** + * Get EAV indexer status + * + * @return bool + */ + private function isEavIndexerEnabled(): bool + { + $eavIndexerStatus = $this->scopeConfig->getValue( + self::ENABLE_EAV_INDEXER, + \Magento\Store\Model\ScopeInterface::SCOPE_STORE + ); + + return (bool)$eavIndexerStatus; + } } diff --git a/app/code/Magento/Catalog/Model/Indexer/Product/Flat/Action/Indexer.php b/app/code/Magento/Catalog/Model/Indexer/Product/Flat/Action/Indexer.php index 9dd312e9da801..3a1611299288c 100644 --- a/app/code/Magento/Catalog/Model/Indexer/Product/Flat/Action/Indexer.php +++ b/app/code/Magento/Catalog/Model/Indexer/Product/Flat/Action/Indexer.php @@ -175,6 +175,7 @@ public function write($storeId, $productId, $valueFieldSuffix = '') if (!empty($updateData)) { $updateData += ['entity_id' => $productId]; + $updateData += ['row_id' => $productId]; $updateFields = []; foreach ($updateData as $key => $value) { $updateFields[$key] = $key; diff --git a/app/code/Magento/Catalog/Model/Indexer/Product/Price/AbstractAction.php b/app/code/Magento/Catalog/Model/Indexer/Product/Price/AbstractAction.php index 7aed842713f5d..e9a907f0b5097 100644 --- a/app/code/Magento/Catalog/Model/Indexer/Product/Price/AbstractAction.php +++ b/app/code/Magento/Catalog/Model/Indexer/Product/Price/AbstractAction.php @@ -5,7 +5,11 @@ */ namespace Magento\Catalog\Model\Indexer\Product\Price; +use Magento\Catalog\Model\ResourceModel\Product\Indexer\Price\DefaultPrice; +use Magento\Customer\Model\Indexer\CustomerGroupDimensionProvider; use Magento\Framework\App\ObjectManager; +use Magento\Framework\Indexer\DimensionalIndexerInterface; +use Magento\Store\Model\Indexer\WebsiteDimensionProvider; /** * Abstract action reindex class @@ -17,7 +21,7 @@ abstract class AbstractAction /** * Default Product Type Price indexer resource model * - * @var \Magento\Catalog\Model\ResourceModel\Product\Indexer\Price\DefaultPrice + * @var DefaultPrice */ protected $_defaultIndexerResource; @@ -77,6 +81,16 @@ abstract class AbstractAction */ private $tierPriceIndexResource; + /** + * @var \Magento\Catalog\Model\Indexer\Product\Price\DimensionCollectionFactory + */ + private $dimensionCollectionFactory; + + /** + * @var TableMaintainer + */ + private $tableMaintainer; + /** * @param \Magento\Framework\App\Config\ScopeConfigInterface $config * @param \Magento\Store\Model\StoreManagerInterface $storeManager @@ -85,8 +99,13 @@ abstract class AbstractAction * @param \Magento\Framework\Stdlib\DateTime $dateTime * @param \Magento\Catalog\Model\Product\Type $catalogProductType * @param \Magento\Catalog\Model\ResourceModel\Product\Indexer\Price\Factory $indexerPriceFactory - * @param \Magento\Catalog\Model\ResourceModel\Product\Indexer\Price\DefaultPrice $defaultIndexerResource - * @param \Magento\Catalog\Model\ResourceModel\Product\Indexer\Price\TierPrice $tierPriceIndexResource + * @param DefaultPrice $defaultIndexerResource + * @param \Magento\Catalog\Model\ResourceModel\Product\Indexer\Price\TierPrice|null $tierPriceIndexResource + * @param DimensionCollectionFactory|null $dimensionCollectionFactory + * @param TableMaintainer|null $tableMaintainer + * @SuppressWarnings(PHPMD.NPathComplexity) + * @SuppressWarnings(PHPMD.CyclomaticComplexity) + * @SuppressWarnings(PHPMD.ExcessiveParameterList) */ public function __construct( \Magento\Framework\App\Config\ScopeConfigInterface $config, @@ -96,8 +115,10 @@ public function __construct( \Magento\Framework\Stdlib\DateTime $dateTime, \Magento\Catalog\Model\Product\Type $catalogProductType, \Magento\Catalog\Model\ResourceModel\Product\Indexer\Price\Factory $indexerPriceFactory, - \Magento\Catalog\Model\ResourceModel\Product\Indexer\Price\DefaultPrice $defaultIndexerResource, - \Magento\Catalog\Model\ResourceModel\Product\Indexer\Price\TierPrice $tierPriceIndexResource = null + DefaultPrice $defaultIndexerResource, + \Magento\Catalog\Model\ResourceModel\Product\Indexer\Price\TierPrice $tierPriceIndexResource = null, + \Magento\Catalog\Model\Indexer\Product\Price\DimensionCollectionFactory $dimensionCollectionFactory = null, + \Magento\Catalog\Model\Indexer\Product\Price\TableMaintainer $tableMaintainer = null ) { $this->_config = $config; $this->_storeManager = $storeManager; @@ -108,9 +129,15 @@ public function __construct( $this->_indexerPriceFactory = $indexerPriceFactory; $this->_defaultIndexerResource = $defaultIndexerResource; $this->_connection = $this->_defaultIndexerResource->getConnection(); - $this->tierPriceIndexResource = $tierPriceIndexResource ?: ObjectManager::getInstance()->get( + $this->tierPriceIndexResource = $tierPriceIndexResource ?? ObjectManager::getInstance()->get( \Magento\Catalog\Model\ResourceModel\Product\Indexer\Price\TierPrice::class ); + $this->dimensionCollectionFactory = $dimensionCollectionFactory ?? ObjectManager::getInstance()->get( + \Magento\Catalog\Model\Indexer\Product\Price\DimensionCollectionFactory::class + ); + $this->tableMaintainer = $tableMaintainer ?? ObjectManager::getInstance()->get( + \Magento\Catalog\Model\Indexer\Product\Price\TableMaintainer::class + ); } /** @@ -126,30 +153,29 @@ abstract public function execute($ids); * * @param array $processIds * @return \Magento\Catalog\Model\Indexer\Product\Price\AbstractAction + * @SuppressWarnings(PHPMD.UnusedFormalParameter) + * @deprecated Used only for backward compatibility for indexer, which not support indexation by dimensions */ protected function _syncData(array $processIds = []) { - // delete invalid rows - $select = $this->_connection->select()->from( - ['index_price' => $this->getIndexTargetTable()], - null - )->joinLeft( - ['ip_tmp' => $this->_defaultIndexerResource->getIdxTable()], - 'index_price.entity_id = ip_tmp.entity_id AND index_price.website_id = ip_tmp.website_id', - [] - )->where( - 'ip_tmp.entity_id IS NULL' - ); - if (!empty($processIds)) { - $select->where('index_price.entity_id IN(?)', $processIds); - } - $sql = $select->deleteFromSelect('index_price'); - $this->_connection->query($sql); + // for backward compatibility split data from old idx table on dimension tables + foreach ($this->dimensionCollectionFactory->create() as $dimensions) { + $insertSelect = $this->getConnection()->select()->from( + ['ip_tmp' => $this->_defaultIndexerResource->getIdxTable()] + ); - $this->_insertFromTable( - $this->_defaultIndexerResource->getIdxTable(), - $this->getIndexTargetTable() - ); + foreach ($dimensions as $dimension) { + if ($dimension->getName() === WebsiteDimensionProvider::DIMENSION_NAME) { + $insertSelect->where('ip_tmp.website_id = ?', $dimension->getValue()); + } + if ($dimension->getName() === CustomerGroupDimensionProvider::DIMENSION_NAME) { + $insertSelect->where('ip_tmp.customer_group_id = ?', $dimension->getValue()); + } + } + + $query = $insertSelect->insertFromSelect($this->tableMaintainer->getMainTable($dimensions)); + $this->getConnection()->query($query); + } return $this; } @@ -157,12 +183,15 @@ protected function _syncData(array $processIds = []) * Prepare website current dates table * * @return \Magento\Catalog\Model\Indexer\Product\Price\AbstractAction + * + * @throws \Magento\Framework\Exception\LocalizedException + * @throws \Magento\Framework\Exception\NoSuchEntityException */ protected function _prepareWebsiteDateTable() { $baseCurrency = $this->_config->getValue(\Magento\Directory\Model\Currency::XML_PATH_CURRENCY_BASE); - $select = $this->_connection->select()->from( + $select = $this->getConnection()->select()->from( ['cw' => $this->_defaultIndexerResource->getTable('store_website')], ['website_id'] )->join( @@ -174,7 +203,7 @@ protected function _prepareWebsiteDateTable() ); $data = []; - foreach ($this->_connection->fetchAll($select) as $item) { + foreach ($this->getConnection()->fetchAll($select) as $item) { /** @var $website \Magento\Store\Model\Website */ $website = $this->_storeManager->getWebsite($item['website_id']); @@ -199,6 +228,7 @@ protected function _prepareWebsiteDateTable() 'website_id' => $website->getId(), 'website_date' => $this->_dateTime->formatDate($timestamp, false), 'rate' => $rate, + 'default_store_id' => $store->getId() ]; } } @@ -207,7 +237,7 @@ protected function _prepareWebsiteDateTable() $this->_emptyTable($table); if ($data) { foreach ($data as $row) { - $this->_connection->insertOnDuplicate($table, $row, array_keys($row)); + $this->getConnection()->insertOnDuplicate($table, $row, array_keys($row)); } } @@ -230,9 +260,13 @@ protected function _prepareTierPriceIndex($entityIds = null) /** * Retrieve price indexers per product type * + * @param bool $fullReindexAction + * * @return \Magento\Catalog\Model\ResourceModel\Product\Indexer\Price\PriceInterface[] + * + * @throws \Magento\Framework\Exception\LocalizedException */ - public function getTypeIndexers() + public function getTypeIndexers($fullReindexAction = false) { if ($this->_indexers === null) { $this->_indexers = []; @@ -242,14 +276,20 @@ public function getTypeIndexers() $typeInfo['price_indexer'] ) ? $typeInfo['price_indexer'] : get_class($this->_defaultIndexerResource); - $isComposite = !empty($typeInfo['composite']); $indexer = $this->_indexerPriceFactory->create( - $modelName - )->setTypeId( - $typeId - )->setIsComposite( - $isComposite + $modelName, + [ + 'fullReindexAction' => $fullReindexAction + ] ); + // left setters for backward compatibility + if ($indexer instanceof DefaultPrice) { + $indexer->setTypeId( + $typeId + )->setIsComposite( + !empty($typeInfo['composite']) + ); + } $this->_indexers[$typeId] = $indexer; } } @@ -262,7 +302,9 @@ public function getTypeIndexers() * * @param string $productTypeId * @return \Magento\Catalog\Model\ResourceModel\Product\Indexer\Price\PriceInterface + * * @throws \Magento\Framework\Exception\InputException + * @throws \Magento\Framework\Exception\LocalizedException */ protected function _getIndexer($productTypeId) { @@ -283,19 +325,19 @@ protected function _getIndexer($productTypeId) */ protected function _insertFromTable($sourceTable, $destTable, $where = null) { - $sourceColumns = array_keys($this->_connection->describeTable($sourceTable)); - $targetColumns = array_keys($this->_connection->describeTable($destTable)); - $select = $this->_connection->select()->from($sourceTable, $sourceColumns); + $sourceColumns = array_keys($this->getConnection()->describeTable($sourceTable)); + $targetColumns = array_keys($this->getConnection()->describeTable($destTable)); + $select = $this->getConnection()->select()->from($sourceTable, $sourceColumns); if ($where) { $select->where($where); } - $query = $this->_connection->insertFromSelect( + $query = $this->getConnection()->insertFromSelect( $select, $destTable, $targetColumns, \Magento\Framework\DB\Adapter\AdapterInterface::INSERT_ON_DUPLICATE ); - $this->_connection->query($query); + $this->getConnection()->query($query); } /** @@ -306,7 +348,7 @@ protected function _insertFromTable($sourceTable, $destTable, $where = null) */ protected function _emptyTable($table) { - $this->_connection->delete($table); + $this->getConnection()->delete($table); } /** @@ -314,46 +356,64 @@ protected function _emptyTable($table) * * @param array $changedIds * @return array Affected ids + * + * @throws \Magento\Framework\Exception\InputException + * @throws \Magento\Framework\Exception\LocalizedException + * @throws \Magento\Framework\Exception\NoSuchEntityException */ protected function _reindexRows($changedIds = []) { - $this->_emptyTable($this->_defaultIndexerResource->getIdxTable()); $this->_prepareWebsiteDateTable(); $productsTypes = $this->getProductsTypes($changedIds); - $compositeIds = []; - $notCompositeIds = []; + $parentProductsTypes = $this->getParentProductsTypes($changedIds); + $changedIds = array_merge($changedIds, ...array_values($parentProductsTypes)); + $productsTypes = array_merge_recursive($productsTypes, $parentProductsTypes); + + if ($changedIds) { + $this->deleteIndexData($changedIds); + } foreach ($productsTypes as $productType => $entityIds) { $indexer = $this->_getIndexer($productType); - if ($indexer->getIsComposite()) { - $compositeIds += $entityIds; + if ($indexer instanceof DimensionalIndexerInterface) { + foreach ($this->dimensionCollectionFactory->create() as $dimensions) { + $this->tableMaintainer->createMainTmpTable($dimensions); + $temporaryTable = $this->tableMaintainer->getMainTmpTable($dimensions); + $this->_emptyTable($temporaryTable); + $indexer->executeByDimensions($dimensions, \SplFixedArray::fromArray($entityIds, false)); + // copy to index + $this->_insertFromTable( + $temporaryTable, + $this->tableMaintainer->getMainTable($dimensions) + ); + } } else { - $notCompositeIds += $entityIds; + // handle 3d-party indexers for backward compatibility + $this->_emptyTable($this->_defaultIndexerResource->getIdxTable()); + $this->_copyRelationIndexData($entityIds); + $indexer->reindexEntity($entityIds); + $this->_syncData($entityIds); } } - if (!empty($notCompositeIds)) { - $parentProductsTypes = $this->getParentProductsTypes($notCompositeIds); - $productsTypes = array_merge_recursive($productsTypes, $parentProductsTypes); - foreach ($parentProductsTypes as $parentProductsIds) { - $compositeIds = $compositeIds + $parentProductsIds; - $changedIds = array_merge($changedIds, $parentProductsIds); - } - } - - if (!empty($compositeIds)) { - $this->_copyRelationIndexData($compositeIds, $notCompositeIds); - } - $this->_prepareTierPriceIndex($compositeIds + $notCompositeIds); + return $changedIds; + } - foreach ($productsTypes as $productType => $entityIds) { - $indexer = $this->_getIndexer($productType); - $indexer->reindexEntity($entityIds); + /** + * @param array $entityIds + * @return void + */ + private function deleteIndexData(array $entityIds) + { + foreach ($this->dimensionCollectionFactory->create() as $dimensions) { + $select = $this->getConnection()->select()->from( + ['index_price' => $this->tableMaintainer->getMainTable($dimensions)], + null + )->where('index_price.entity_id IN (?)', $entityIds); + $query = $select->deleteFromSelect('index_price'); + $this->getConnection()->query($query); } - $this->_syncData($changedIds); - - return $compositeIds + $notCompositeIds; } /** @@ -362,11 +422,15 @@ protected function _reindexRows($changedIds = []) * @param null|array $parentIds * @param array $excludeIds * @return \Magento\Catalog\Model\Indexer\Product\Price\AbstractAction + * @deprecated Used only for backward compatibility for do not broke custom indexer implementation + * which do not work by dimensions. + * For indexers, which support dimensions all composite products read data directly from main price indexer table + * or replica table for partial or full reindex correspondingly. */ protected function _copyRelationIndexData($parentIds, $excludeIds = null) { $linkField = $this->getProductIdFieldName(); - $select = $this->_connection->select()->from( + $select = $this->getConnection()->select()->from( $this->_defaultIndexerResource->getTable('catalog_product_relation'), ['child_id'] )->join( @@ -381,22 +445,45 @@ protected function _copyRelationIndexData($parentIds, $excludeIds = null) $select->where('child_id NOT IN(?)', $excludeIds); } - $children = $this->_connection->fetchCol($select); + $children = $this->getConnection()->fetchCol($select); if ($children) { - $select = $this->_connection->select()->from( - $this->getIndexTargetTable() - )->where( - 'entity_id IN(?)', - $children - ); - $query = $select->insertFromSelect($this->_defaultIndexerResource->getIdxTable(), [], false); - $this->_connection->query($query); + foreach ($this->dimensionCollectionFactory->create() as $dimensions) { + $select = $this->getConnection()->select()->from( + $this->getIndexTargetTableByDimension($dimensions) + )->where( + 'entity_id IN(?)', + $children + ); + $query = $select->insertFromSelect($this->_defaultIndexerResource->getIdxTable(), [], false); + $this->getConnection()->query($query); + } } return $this; } + /** + * Retrieve index table by dimension that will be used for write operations. + * + * This method is used during both partial and full reindex to identify the table. + * + * @param \Magento\Framework\Search\Request\Dimension[] $dimensions + * + * @return string + */ + private function getIndexTargetTableByDimension(array $dimensions) + { + $indexTargetTable = $this->getIndexTargetTable(); + if ($indexTargetTable === self::getIndexTargetTable()) { + $indexTargetTable = $this->tableMaintainer->getMainTable($dimensions); + } + if ($indexTargetTable === self::getIndexTargetTable() . '_replica') { + $indexTargetTable = $this->tableMaintainer->getMainReplicaTable($dimensions); + } + return $indexTargetTable; + } + /** * Retrieve index table that will be used for write operations. * @@ -415,8 +502,8 @@ protected function getIndexTargetTable() protected function getProductIdFieldName() { $table = $this->_defaultIndexerResource->getTable('catalog_product_entity'); - $indexList = $this->_connection->getIndexList($table); - return $indexList[$this->_connection->getPrimaryKeyName($table)]['COLUMNS_LIST'][0]; + $indexList = $this->getConnection()->getIndexList($table); + return $indexList[$this->getConnection()->getPrimaryKeyName($table)]['COLUMNS_LIST'][0]; } /** @@ -427,14 +514,14 @@ protected function getProductIdFieldName() */ private function getProductsTypes(array $changedIds = []) { - $select = $this->_connection->select()->from( + $select = $this->getConnection()->select()->from( $this->_defaultIndexerResource->getTable('catalog_product_entity'), ['entity_id', 'type_id'] ); if ($changedIds) { $select->where('entity_id IN (?)', $changedIds); } - $pairs = $this->_connection->fetchPairs($select); + $pairs = $this->getConnection()->fetchPairs($select); $byType = []; foreach ($pairs as $productId => $productType) { @@ -445,14 +532,15 @@ private function getProductsTypes(array $changedIds = []) } /** - * Get parent products types. + * Get parent products types + * Used for add composite products to reindex if we have only simple products in changed ids set * * @param array $productsIds * @return array */ private function getParentProductsTypes(array $productsIds) { - $select = $this->_connection->select()->from( + $select = $this->getConnection()->select()->from( ['l' => $this->_defaultIndexerResource->getTable('catalog_product_relation')], '' )->join( @@ -463,7 +551,7 @@ private function getParentProductsTypes(array $productsIds) 'l.child_id IN(?)', $productsIds ); - $pairs = $this->_connection->fetchPairs($select); + $pairs = $this->getConnection()->fetchPairs($select); $byType = []; foreach ($pairs as $productId => $productType) { @@ -472,4 +560,14 @@ private function getParentProductsTypes(array $productsIds) return $byType; } + + /** + * Get connection + * + * @return \Magento\Framework\DB\Adapter\AdapterInterface + */ + private function getConnection() + { + return $this->_defaultIndexerResource->getConnection(); + } } diff --git a/app/code/Magento/Catalog/Model/Indexer/Product/Price/Action/Full.php b/app/code/Magento/Catalog/Model/Indexer/Product/Price/Action/Full.php index ba04af8ec1f41..1a75751570658 100644 --- a/app/code/Magento/Catalog/Model/Indexer/Product/Price/Action/Full.php +++ b/app/code/Magento/Catalog/Model/Indexer/Product/Price/Action/Full.php @@ -6,9 +6,17 @@ namespace Magento\Catalog\Model\Indexer\Product\Price\Action; use Magento\Framework\App\ObjectManager; +use Magento\Catalog\Model\ResourceModel\Product\Indexer\Price\PriceInterface; +use Magento\Framework\EntityManager\EntityMetadataInterface; +use Magento\Catalog\Api\Data\ProductInterface; +use Magento\Framework\Exception\LocalizedException; +use Magento\Framework\Indexer\DimensionalIndexerInterface; +use Magento\Customer\Model\Indexer\CustomerGroupDimensionProvider; +use Magento\Store\Model\Indexer\WebsiteDimensionProvider; /** * Class Full reindex action + * * @SuppressWarnings(PHPMD.CouplingBetweenObjects) */ class Full extends \Magento\Catalog\Model\Indexer\Product\Price\AbstractAction @@ -33,6 +41,26 @@ class Full extends \Magento\Catalog\Model\Indexer\Product\Price\AbstractAction */ private $activeTableSwitcher; + /** + * @var EntityMetadataInterface + */ + private $productMetaDataCached; + + /** + * @var \Magento\Catalog\Model\Indexer\Product\Price\DimensionCollectionFactory + */ + private $dimensionCollectionFactory; + + /** + * @var \Magento\Catalog\Model\Indexer\Product\Price\TableMaintainer + */ + private $dimensionTableMaintainer; + + /** + * @var \Magento\Indexer\Model\ProcessManager + */ + private $processManager; + /** * @param \Magento\Framework\App\Config\ScopeConfigInterface $config * @param \Magento\Store\Model\StoreManagerInterface $storeManager @@ -46,7 +74,9 @@ class Full extends \Magento\Catalog\Model\Indexer\Product\Price\AbstractAction * @param \Magento\Catalog\Model\ResourceModel\Product\Indexer\Price\BatchSizeCalculator|null $batchSizeCalculator * @param \Magento\Framework\Indexer\BatchProviderInterface|null $batchProvider * @param \Magento\Catalog\Model\ResourceModel\Indexer\ActiveTableSwitcher|null $activeTableSwitcher - * + * @param \Magento\Catalog\Model\Indexer\Product\Price\DimensionCollectionFactory|null $dimensionCollectionFactory + * @param \Magento\Catalog\Model\Indexer\Product\Price\TableMaintainer|null $dimensionTableMaintainer + * @param \Magento\Indexer\Model\ProcessManager $processManager * @SuppressWarnings(PHPMD.ExcessiveParameterList) */ public function __construct( @@ -61,7 +91,10 @@ public function __construct( \Magento\Framework\EntityManager\MetadataPool $metadataPool = null, \Magento\Catalog\Model\ResourceModel\Product\Indexer\Price\BatchSizeCalculator $batchSizeCalculator = null, \Magento\Framework\Indexer\BatchProviderInterface $batchProvider = null, - \Magento\Catalog\Model\ResourceModel\Indexer\ActiveTableSwitcher $activeTableSwitcher = null + \Magento\Catalog\Model\ResourceModel\Indexer\ActiveTableSwitcher $activeTableSwitcher = null, + \Magento\Catalog\Model\Indexer\Product\Price\DimensionCollectionFactory $dimensionCollectionFactory = null, + \Magento\Catalog\Model\Indexer\Product\Price\TableMaintainer $dimensionTableMaintainer = null, + \Magento\Indexer\Model\ProcessManager $processManager = null ) { parent::__construct( $config, @@ -85,6 +118,15 @@ public function __construct( $this->activeTableSwitcher = $activeTableSwitcher ?: ObjectManager::getInstance()->get( \Magento\Catalog\Model\ResourceModel\Indexer\ActiveTableSwitcher::class ); + $this->dimensionCollectionFactory = $dimensionCollectionFactory ?: ObjectManager::getInstance()->get( + \Magento\Catalog\Model\Indexer\Product\Price\DimensionCollectionFactory::class + ); + $this->dimensionTableMaintainer = $dimensionTableMaintainer ?: ObjectManager::getInstance()->get( + \Magento\Catalog\Model\Indexer\Product\Price\TableMaintainer::class + ); + $this->processManager = $processManager ?: ObjectManager::getInstance()->get( + \Magento\Indexer\Model\ProcessManager::class + ); } /** @@ -92,75 +134,335 @@ public function __construct( * * @param array|int|null $ids * @return void - * @throws \Magento\Framework\Exception\LocalizedException + * @throws \Exception * @SuppressWarnings(PHPMD.UnusedFormalParameter) */ public function execute($ids = null) { try { - $this->_defaultIndexerResource->getTableStrategy()->setUseIdxTable(false); - $this->_prepareWebsiteDateTable(); + //Prepare indexer tables before full reindex + $this->prepareTables(); + + /** @var \Magento\Catalog\Model\ResourceModel\Product\Indexer\Price\DefaultPrice $indexer */ + foreach ($this->getTypeIndexers(true) as $typeId => $priceIndexer) { + if ($priceIndexer instanceof DimensionalIndexerInterface) { + //New price reindex mechanism + $this->reindexProductTypeWithDimensions($priceIndexer, $typeId); + continue; + } + + $priceIndexer->getTableStrategy()->setUseIdxTable(false); + + //Old price reindex mechanism + $this->reindexProductType($priceIndexer, $typeId); + } + + //Final replacement of tables from replica to main + $this->switchTables(); + } catch (\Exception $e) { + throw new LocalizedException(__($e->getMessage()), $e); + } + } + + /** + * Prepare indexer tables before full reindex + * + * @return void + * @throws \Exception + */ + private function prepareTables() + { + $this->_defaultIndexerResource->getTableStrategy()->setUseIdxTable(false); + + $this->_prepareWebsiteDateTable(); + + $this->truncateReplicaTables(); + } + + /** + * Truncate replica tables by dimensions + * + * @return void + * @throws \Exception + */ + private function truncateReplicaTables() + { + foreach ($this->dimensionCollectionFactory->create() as $dimension) { + $dimensionTable = $this->dimensionTableMaintainer->getMainReplicaTable($dimension); + $this->_defaultIndexerResource->getConnection()->truncateTable($dimensionTable); + } + } + + /** + * Reindex new 'Dimensional' price indexer by product type + * + * @param DimensionalIndexerInterface $priceIndexer + * @param string $typeId + * + * @return void + * @throws \Exception + */ + private function reindexProductTypeWithDimensions(DimensionalIndexerInterface $priceIndexer, string $typeId) + { + $userFunctions = []; + foreach ($this->dimensionCollectionFactory->create() as $dimensions) { + $userFunctions[] = function () use ($priceIndexer, $dimensions, $typeId) { + return $this->reindexByBatches($priceIndexer, $dimensions, $typeId); + }; + } + $this->processManager->execute($userFunctions); + } + + /** + * Reindex new 'Dimensional' price indexer by batches + * + * @param DimensionalIndexerInterface $priceIndexer + * @param array $dimensions + * @param string $typeId + * + * @return void + * @throws \Exception + */ + private function reindexByBatches(DimensionalIndexerInterface $priceIndexer, array $dimensions, string $typeId) + { + foreach ($this->getBatchesForIndexer($typeId) as $batch) { + $this->reindexByBatchWithDimensions($priceIndexer, $batch, $dimensions, $typeId); + } + } + + /** + * Get batches for new 'Dimensional' price indexer + * + * @param string $typeId + * + * @return \Generator + * @throws \Exception + */ + private function getBatchesForIndexer(string $typeId) + { + $connection = $this->_defaultIndexerResource->getConnection(); + return $this->batchProvider->getBatches( + $connection, + $this->getProductMetaData()->getEntityTable(), + $this->getProductMetaData()->getIdentifierField(), + $this->batchSizeCalculator->estimateBatchSize( + $connection, + $typeId + ) + ); + } + + /** + * Reindex by batch for new 'Dimensional' price indexer + * + * @param DimensionalIndexerInterface $priceIndexer + * @param array $batch + * @param array $dimensions + * @param string $typeId + * + * @return void + * @throws \Exception + */ + private function reindexByBatchWithDimensions( + DimensionalIndexerInterface $priceIndexer, + array $batch, + array $dimensions, + string $typeId + ) { + $entityIds = $this->getEntityIdsFromBatch($typeId, $batch); + + if (!empty($entityIds)) { + $this->dimensionTableMaintainer->createMainTmpTable($dimensions); + $temporaryTable = $this->dimensionTableMaintainer->getMainTmpTable($dimensions); + $this->_emptyTable($temporaryTable); + + $priceIndexer->executeByDimensions($dimensions, \SplFixedArray::fromArray($entityIds, false)); - $entityMetadata = $this->metadataPool->getMetadata(\Magento\Catalog\Api\Data\ProductInterface::class); - $replicaTable = $this->activeTableSwitcher->getAdditionalTableName( - $this->_defaultIndexerResource->getMainTable() + // Sync data from temp table to index table + $this->_insertFromTable( + $temporaryTable, + $this->dimensionTableMaintainer->getMainReplicaTable($dimensions) ); + } + } - // Prepare replica table for indexation. - $this->_defaultIndexerResource->getConnection()->truncateTable($replicaTable); + /** + * Reindex old price indexer by product type + * + * @param PriceInterface $priceIndexer + * @param string $typeId + * + * @return void + * @throws \Exception + */ + private function reindexProductType(PriceInterface $priceIndexer, string $typeId) + { + foreach ($this->getBatchesForIndexer($typeId) as $batch) { + $this->reindexBatch($priceIndexer, $batch, $typeId); + } + } - /** @var \Magento\Catalog\Model\ResourceModel\Product\Indexer\Price\DefaultPrice $indexer */ - foreach ($this->getTypeIndexers() as $indexer) { - $indexer->getTableStrategy()->setUseIdxTable(false); - $connection = $indexer->getConnection(); - - $batches = $this->batchProvider->getBatches( - $connection, - $entityMetadata->getEntityTable(), - $entityMetadata->getIdentifierField(), - $this->batchSizeCalculator->estimateBatchSize($connection, $indexer->getTypeId()) - ); - - foreach ($batches as $batch) { - // Get entity ids from batch - $select = $connection->select(); - $select->distinct(true); - $select->from(['e' => $entityMetadata->getEntityTable()], $entityMetadata->getIdentifierField()); - $select->where('type_id = ?', $indexer->getTypeId()); - - $entityIds = $this->batchProvider->getBatchIds($connection, $select, $batch); - - if (!empty($entityIds)) { - // Temporary table will created if not exists - $idxTableName = $this->_defaultIndexerResource->getIdxTable(); - $this->_emptyTable($idxTableName); - - if ($indexer->getIsComposite()) { - $this->_copyRelationIndexData($entityIds); - } - $this->_prepareTierPriceIndex($entityIds); - - // Reindex entities by id - $indexer->reindexEntity($entityIds); - - // Sync data from temp table to index table - $this->_insertFromTable($idxTableName, $replicaTable); - - // Drop temporary index table - $connection->dropTable($idxTableName); - } - } + /** + * Reindex by batch for old price indexer + * + * @param PriceInterface $priceIndexer + * @param array $batch + * @param string $typeId + * + * @return void + * @throws \Exception + */ + private function reindexBatch(PriceInterface $priceIndexer, array $batch, string $typeId) + { + $entityIds = $this->getEntityIdsFromBatch($typeId, $batch); + + if (!empty($entityIds)) { + // Temporary table will created if not exists + $idxTableName = $this->_defaultIndexerResource->getIdxTable(); + $this->_emptyTable($idxTableName); + + if ($priceIndexer->getIsComposite()) { + $this->_copyRelationIndexData($entityIds); } + + // Reindex entities by id + $priceIndexer->reindexEntity($entityIds); + + // Sync data from temp table to index table + $this->_insertFromTable($idxTableName, $this->getReplicaTable()); + + // Drop temporary index table + $this->_defaultIndexerResource->getConnection()->dropTable($idxTableName); + } + } + + /** + * Get Entity Ids from batch + * + * @param string $typeId + * @param array $batch + * + * @return array + * @throws \Exception + */ + private function getEntityIdsFromBatch(string $typeId, array $batch) + { + $connection = $this->_defaultIndexerResource->getConnection(); + + // Get entity ids from batch + $select = $connection + ->select() + ->distinct(true) + ->from( + ['e' => $this->getProductMetaData()->getEntityTable()], + $this->getProductMetaData()->getIdentifierField() + ) + ->where('type_id = ?', $typeId); + + return $this->batchProvider->getBatchIds($connection, $select, $batch); + } + + /** + * Get product meta data + * + * @return EntityMetadataInterface + * @throws \Exception + */ + private function getProductMetaData() + { + if ($this->productMetaDataCached === null) { + $this->productMetaDataCached = $this->metadataPool->getMetadata(ProductInterface::class); + } + + return $this->productMetaDataCached; + } + + /** + * Get replica table + * + * @return string + * @throws \Exception + */ + private function getReplicaTable() + { + return $this->activeTableSwitcher->getAdditionalTableName( + $this->_defaultIndexerResource->getMainTable() + ); + } + + /** + * Replacement of tables from replica to main + * + * @return void + */ + private function switchTables() + { + // Switch dimension tables + $mainTablesByDimension = []; + + foreach ($this->dimensionCollectionFactory->create() as $dimensions) { + $mainTablesByDimension[] = $this->dimensionTableMaintainer->getMainTable($dimensions); + + //Move data from indexers with old realisation + $this->moveDataFromReplicaTableToReplicaTables($dimensions); + } + + if (count($mainTablesByDimension) > 0) { $this->activeTableSwitcher->switchTable( $this->_defaultIndexerResource->getConnection(), - [$this->_defaultIndexerResource->getMainTable()] + $mainTablesByDimension ); - } catch (\Exception $e) { - throw new \Magento\Framework\Exception\LocalizedException(__($e->getMessage()), $e); } } /** + * Move data from old price indexer mechanism to new indexer mechanism by dimensions. + * Used only for backward compatibility + * + * @param array $dimensions + * + * @return void + */ + private function moveDataFromReplicaTableToReplicaTables(array $dimensions) + { + if (!$dimensions) { + return; + } + $select = $this->dimensionTableMaintainer->getConnection()->select()->from( + $this->dimensionTableMaintainer->getMainReplicaTable([]) + ); + + $check = clone $select; + $check->reset('columns')->columns('count(*)'); + + if (!$this->dimensionTableMaintainer->getConnection()->query($check)->fetchColumn()) { + return; + } + + $replicaTablesByDimension = $this->dimensionTableMaintainer->getMainReplicaTable($dimensions); + + foreach ($dimensions as $dimension) { + if ($dimension->getName() === WebsiteDimensionProvider::DIMENSION_NAME) { + $select->where('website_id = ?', $dimension->getValue()); + } + if ($dimension->getName() === CustomerGroupDimensionProvider::DIMENSION_NAME) { + $select->where('customer_group_id = ?', $dimension->getValue()); + } + } + + $this->dimensionTableMaintainer->getConnection()->query( + $this->dimensionTableMaintainer->getConnection()->insertFromSelect( + $select, + $replicaTablesByDimension, + [], + \Magento\Framework\DB\Adapter\AdapterInterface::INSERT_ON_DUPLICATE + ) + ); + } + + /** + * @deprecated + * * @inheritdoc */ protected function getIndexTargetTable() diff --git a/app/code/Magento/Catalog/Model/Indexer/Product/Price/DimensionCollectionFactory.php b/app/code/Magento/Catalog/Model/Indexer/Product/Price/DimensionCollectionFactory.php new file mode 100644 index 0000000000000..31459af81ccc7 --- /dev/null +++ b/app/code/Magento/Catalog/Model/Indexer/Product/Price/DimensionCollectionFactory.php @@ -0,0 +1,72 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +declare(strict_types=1); + +namespace Magento\Catalog\Model\Indexer\Product\Price; + +use Magento\Framework\Indexer\DimensionProviderInterface; +use Magento\Framework\Indexer\MultiDimensionProvider; + +class DimensionCollectionFactory +{ + /** + * @var \Magento\Framework\Indexer\MultiDimensionProviderFactory + */ + private $multiDimensionProviderFactory; + + /** + * @var DimensionProviderInterface[] + */ + private $dimensionProviders; + + /** + * @var DimensionModeConfiguration + */ + private $dimensionModeConfiguration; + + /** + * @param \Magento\Framework\Indexer\MultiDimensionProviderFactory $multiDimensionProviderFactory + * @param DimensionModeConfiguration $dimensionModeConfiguration + * @param array $dimensionProviders + */ + public function __construct( + \Magento\Framework\Indexer\MultiDimensionProviderFactory $multiDimensionProviderFactory, + DimensionModeConfiguration $dimensionModeConfiguration, + array $dimensionProviders + ) { + $this->multiDimensionProviderFactory = $multiDimensionProviderFactory; + $this->dimensionProviders = $dimensionProviders; + $this->dimensionModeConfiguration = $dimensionModeConfiguration; + } + + /** + * Create MultiDimensionProvider for specified "dimension mode". + * By default return multiplication of dimensions by current set mode + * + * @param string|null $dimensionsMode + * @return MultiDimensionProvider + */ + public function create(string $dimensionsMode = null): MultiDimensionProvider + { + $dimensionConfiguration = $this->dimensionModeConfiguration->getDimensionConfiguration($dimensionsMode); + + $providers = []; + foreach ($dimensionConfiguration as $dimensionName) { + if (!isset($this->dimensionProviders[$dimensionName])) { + throw new \LogicException( + 'Dimension Provider is missing. Cannot handle unknown dimension: ' . $dimensionName + ); + } + $providers[] = clone $this->dimensionProviders[$dimensionName]; + } + + return $this->multiDimensionProviderFactory->create( + [ + 'dimensionProviders' => $providers + ] + ); + } +} diff --git a/app/code/Magento/Catalog/Model/Indexer/Product/Price/DimensionModeConfiguration.php b/app/code/Magento/Catalog/Model/Indexer/Product/Price/DimensionModeConfiguration.php new file mode 100644 index 0000000000000..9b8eb55b7aac5 --- /dev/null +++ b/app/code/Magento/Catalog/Model/Indexer/Product/Price/DimensionModeConfiguration.php @@ -0,0 +1,91 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +declare(strict_types=1); + +namespace Magento\Catalog\Model\Indexer\Product\Price; + +use Magento\Framework\App\Config\ScopeConfigInterface; +use Magento\Store\Model\Indexer\WebsiteDimensionProvider; +use Magento\Customer\Model\Indexer\CustomerGroupDimensionProvider; + +class DimensionModeConfiguration +{ + /**#@+ + * Available modes of dimensions for product price indexer + */ + const DIMENSION_NONE = 'none'; + const DIMENSION_WEBSITE = 'website'; + const DIMENSION_CUSTOMER_GROUP = 'customer_group'; + const DIMENSION_WEBSITE_AND_CUSTOMER_GROUP = 'website_and_customer_group'; + /**#@-*/ + + /** + * Mapping between dimension mode and dimension provider name + * + * @var array + */ + private $modesMapping = [ + self::DIMENSION_NONE => [ + ], + self::DIMENSION_WEBSITE => [ + WebsiteDimensionProvider::DIMENSION_NAME + ], + self::DIMENSION_CUSTOMER_GROUP => [ + CustomerGroupDimensionProvider::DIMENSION_NAME + ], + self::DIMENSION_WEBSITE_AND_CUSTOMER_GROUP => [ + WebsiteDimensionProvider::DIMENSION_NAME, + CustomerGroupDimensionProvider::DIMENSION_NAME + ], + ]; + /** + * @var ScopeConfigInterface + */ + private $scopeConfig; + + /** + * @var string + */ + private $currentMode; + + /** + * @param ScopeConfigInterface $scopeConfig + */ + public function __construct(ScopeConfigInterface $scopeConfig) + { + $this->scopeConfig = $scopeConfig; + } + + /** + * Get names of dimensions which used for provided mode. + * By default return dimensions for current enabled mode + * + * @param string|null $mode + * @return string[] + */ + public function getDimensionConfiguration(string $mode = null): array + { + if ($mode && !isset($this->modesMapping[$mode])) { + throw new \InvalidArgumentException( + sprintf('Undefined dimension mode "%s".', $mode) + ); + } + return $this->modesMapping[$mode ?? $this->getCurrentMode()]; + } + + /** + * @return string + */ + private function getCurrentMode(): string + { + if (null === $this->currentMode) { + $this->currentMode = $this->scopeConfig->getValue(ModeSwitcher::XML_PATH_PRICE_DIMENSIONS_MODE) + ?: self::DIMENSION_NONE; + } + + return $this->currentMode; + } +} diff --git a/app/code/Magento/Catalog/Model/Indexer/Product/Price/ModeSwitcher.php b/app/code/Magento/Catalog/Model/Indexer/Product/Price/ModeSwitcher.php new file mode 100644 index 0000000000000..81a170fc0a3d7 --- /dev/null +++ b/app/code/Magento/Catalog/Model/Indexer/Product/Price/ModeSwitcher.php @@ -0,0 +1,166 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +declare(strict_types=1); + +namespace Magento\Catalog\Model\Indexer\Product\Price; + +use Magento\Framework\Search\Request\Dimension; +use Magento\Store\Model\Indexer\WebsiteDimensionProvider; +use Magento\Customer\Model\Indexer\CustomerGroupDimensionProvider; + +/** + * Class to prepare new tables for new indexer mode + */ +class ModeSwitcher +{ + const XML_PATH_PRICE_DIMENSIONS_MODE = 'indexer/catalog_product_price/dimensions_mode'; + + /** + * TableMaintainer + * + * @var \Magento\Catalog\Model\Indexer\Product\Price\TableMaintainer + */ + private $tableMaintainer; + + /** + * DimensionCollectionFactory + * + * @var \Magento\Catalog\Model\Indexer\Product\Price\DimensionCollectionFactory + */ + private $dimensionCollectionFactory; + + /** + * @var array|null + */ + private $dimensionsArray; + + /** + * @param \Magento\Catalog\Model\Indexer\Product\Price\TableMaintainer $tableMaintainer + * @param \Magento\Catalog\Model\Indexer\Product\Price\DimensionCollectionFactory $dimensionCollectionFactory + */ + public function __construct( + \Magento\Catalog\Model\Indexer\Product\Price\TableMaintainer $tableMaintainer, + \Magento\Catalog\Model\Indexer\Product\Price\DimensionCollectionFactory $dimensionCollectionFactory + ) { + $this->tableMaintainer = $tableMaintainer; + $this->dimensionCollectionFactory = $dimensionCollectionFactory; + } + + /** + * Create new tables + * + * @param string $currentMode + * + * @return void + * @throws \Zend_Db_Exception + */ + public function createTables(string $currentMode) + { + foreach ($this->getDimensionsArray($currentMode) as $dimensions) { + if (!empty($dimensions)) { + $this->tableMaintainer->createTablesForDimensions($dimensions); + } + } + } + + /** + * Move data from old tables to new + * + * @param string $currentMode + * @param string $previousMode + * + * @return void + */ + public function moveData(string $currentMode, string $previousMode) + { + $dimensionsArrayForCurrentMode = $this->getDimensionsArray($currentMode); + $dimensionsArrayForPreviousMode = $this->getDimensionsArray($previousMode); + + foreach ($dimensionsArrayForCurrentMode as $dimensionsForCurrentMode) { + $newTable = $this->tableMaintainer->getMainTable($dimensionsForCurrentMode); + if (empty($dimensionsForCurrentMode)) { + // new mode is 'none' + foreach ($dimensionsArrayForPreviousMode as $dimensionsForPreviousMode) { + $oldTable = $this->tableMaintainer->getMainTable($dimensionsForPreviousMode); + $this->insertFromOldTablesToNew($newTable, $oldTable); + } + } else { + // new mode is not 'none' + foreach ($dimensionsArrayForPreviousMode as $dimensionsForPreviousMode) { + $oldTable = $this->tableMaintainer->getMainTable($dimensionsForPreviousMode); + $this->insertFromOldTablesToNew($newTable, $oldTable, $dimensionsForCurrentMode); + } + } + } + } + + /** + * Drop old tables + * + * @param string $previousMode + * + * @return void + */ + public function dropTables(string $previousMode) + { + foreach ($this->getDimensionsArray($previousMode) as $dimensions) { + if (empty($dimensions)) { + $this->tableMaintainer->truncateTablesForDimensions($dimensions); + } else { + $this->tableMaintainer->dropTablesForDimensions($dimensions); + } + } + } + + /** + * Get dimensions array + * + * @param string $mode + * + * @return array + */ + private function getDimensionsArray(string $mode): \Magento\Framework\Indexer\MultiDimensionProvider + { + if (isset($this->dimensionsArray[$mode])) { + return $this->dimensionsArray[$mode]; + } + + $this->dimensionsArray[$mode] = $this->dimensionCollectionFactory->create($mode); + + return $this->dimensionsArray[$mode]; + } + + /** + * Insert from old tables data to new + * + * @param string $newTable + * @param string $oldTable + * @param Dimension[] $dimensions + * + * @return void + */ + private function insertFromOldTablesToNew(string $newTable, string $oldTable, array $dimensions = []) + { + $select = $this->tableMaintainer->getConnection()->select()->from($oldTable); + + foreach ($dimensions as $dimension) { + if ($dimension->getName() === WebsiteDimensionProvider::DIMENSION_NAME) { + $select->where('website_id = ?', $dimension->getValue()); + } + if ($dimension->getName() === CustomerGroupDimensionProvider::DIMENSION_NAME) { + $select->where('customer_group_id = ?', $dimension->getValue()); + } + } + $this->tableMaintainer->getConnection()->query( + $this->tableMaintainer->getConnection()->insertFromSelect( + $select, + $newTable, + [], + \Magento\Framework\DB\Adapter\AdapterInterface::INSERT_ON_DUPLICATE + ) + ); + } +} diff --git a/app/code/Magento/Catalog/Model/Indexer/Product/Price/Plugin/CustomerGroup.php b/app/code/Magento/Catalog/Model/Indexer/Product/Price/Plugin/CustomerGroup.php index 32b2db8a7008c..9b99ee8c8dc8c 100644 --- a/app/code/Magento/Catalog/Model/Indexer/Product/Price/Plugin/CustomerGroup.php +++ b/app/code/Magento/Catalog/Model/Indexer/Product/Price/Plugin/CustomerGroup.php @@ -5,9 +5,15 @@ */ namespace Magento\Catalog\Model\Indexer\Product\Price\Plugin; +use Magento\Catalog\Model\Indexer\Product\Price\DimensionModeConfiguration; use Magento\Customer\Api\GroupRepositoryInterface; use Magento\Customer\Api\Data\GroupInterface; -use \Magento\Catalog\Model\Indexer\Product\Price\UpdateIndexInterface; +use Magento\Catalog\Model\Indexer\Product\Price\UpdateIndexInterface; +use Magento\Catalog\Model\Indexer\Product\Price\TableMaintainer; +use Magento\Framework\Indexer\Dimension; +use Magento\Framework\Indexer\DimensionFactory; +use Magento\Customer\Model\Indexer\CustomerGroupDimensionProvider; +use Magento\Store\Model\Indexer\WebsiteDimensionProvider; class CustomerGroup { @@ -17,14 +23,46 @@ class CustomerGroup private $updateIndex; /** - * Constructor + * @var TableMaintainer + */ + private $tableMaintainer; + + /** + * DimensionFactory * + * @var DimensionFactory + */ + private $dimensionFactory; + + /** + * @var DimensionModeConfiguration + */ + private $dimensionModeConfiguration; + + /** + * @var WebsiteDimensionProvider + */ + private $websiteDimensionProvider; + + /** * @param UpdateIndexInterface $updateIndex + * @param TableMaintainer $tableMaintainer + * @param DimensionFactory $dimensionFactory + * @param DimensionModeConfiguration $dimensionModeConfiguration + * @param WebsiteDimensionProvider $websiteDimensionProvider */ public function __construct( - UpdateIndexInterface $updateIndex + UpdateIndexInterface $updateIndex, + TableMaintainer $tableMaintainer, + DimensionFactory $dimensionFactory, + DimensionModeConfiguration $dimensionModeConfiguration, + WebsiteDimensionProvider $websiteDimensionProvider ) { $this->updateIndex = $updateIndex; + $this->tableMaintainer = $tableMaintainer; + $this->dimensionFactory = $dimensionFactory; + $this->dimensionModeConfiguration = $dimensionModeConfiguration; + $this->websiteDimensionProvider = $websiteDimensionProvider; } /** @@ -32,7 +70,8 @@ public function __construct( * * @param GroupRepositoryInterface $subject * @param \Closure $proceed - * @param GroupInterface $result + * @param GroupInterface $group + * * @return GroupInterface * @SuppressWarnings(PHPMD.UnusedFormalParameter) */ @@ -43,7 +82,64 @@ public function aroundSave( ) { $isGroupNew = !$group->getId(); $group = $proceed($group); + if ($isGroupNew) { + foreach ($this->getAffectedDimensions((string)$group->getId()) as $dimensions) { + $this->tableMaintainer->createTablesForDimensions($dimensions); + } + } $this->updateIndex->update($group, $isGroupNew); return $group; } + + /** + * Update price index after customer group deleted + * + * @param GroupRepositoryInterface $subject + * @param bool $result + * @param string $groupId + * + * @return bool + * @SuppressWarnings(PHPMD.UnusedFormalParameter) + */ + public function afterDeleteById(GroupRepositoryInterface $subject, bool $result, string $groupId) + { + foreach ($this->getAffectedDimensions($groupId) as $dimensions) { + $this->tableMaintainer->dropTablesForDimensions($dimensions); + } + + return $result; + } + + /** + * Get affected dimensions + * + * @param string $groupId + * @return Dimension[][] + */ + private function getAffectedDimensions(string $groupId): array + { + $currentDimensions = $this->dimensionModeConfiguration->getDimensionConfiguration(); + // do not return dimensions if Customer Group dimension is not present in configuration + if (!in_array(CustomerGroupDimensionProvider::DIMENSION_NAME, $currentDimensions, true)) { + return []; + } + $customerGroupDimension = $this->dimensionFactory->create( + CustomerGroupDimensionProvider::DIMENSION_NAME, + $groupId + ); + + $dimensions = []; + if (in_array(WebsiteDimensionProvider::DIMENSION_NAME, $currentDimensions, true)) { + foreach ($this->websiteDimensionProvider as $websiteDimension) { + $dimensions[] = [ + $customerGroupDimension, + $websiteDimension + ]; + } + } else { + $dimensions[] = [$customerGroupDimension]; + } + + return $dimensions; + } } diff --git a/app/code/Magento/Catalog/Model/Indexer/Product/Price/Plugin/TableResolver.php b/app/code/Magento/Catalog/Model/Indexer/Product/Price/Plugin/TableResolver.php new file mode 100644 index 0000000000000..fbeec22783090 --- /dev/null +++ b/app/code/Magento/Catalog/Model/Indexer/Product/Price/Plugin/TableResolver.php @@ -0,0 +1,140 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +declare(strict_types=1); + +namespace Magento\Catalog\Model\Indexer\Product\Price\Plugin; + +use Magento\Catalog\Model\Indexer\Product\Price\DimensionModeConfiguration; +use Magento\Framework\App\ResourceConnection; +use Magento\Framework\Indexer\DimensionFactory; +use Magento\Framework\Search\Request\IndexScopeResolverInterface; +use Magento\Framework\App\Http\Context; +use Magento\Framework\Indexer\Dimension; +use Magento\Store\Model\StoreManagerInterface; +use Magento\Customer\Model\Context as CustomerContext; +use Magento\Customer\Model\Indexer\CustomerGroupDimensionProvider; +use Magento\Store\Model\Indexer\WebsiteDimensionProvider; + +/** + * Replace catalog_product_index_price table name on the table name segmented per dimension. + * Used only for backward compatibility + */ +class TableResolver +{ + /** + * @var IndexScopeResolverInterface + */ + private $priceTableResolver; + + /** + * @var StoreManagerInterface + */ + private $storeManager; + + /** + * @var Context + */ + private $httpContext; + + /** + * @var DimensionFactory + */ + private $dimensionFactory; + + /** + * @var DimensionModeConfiguration + */ + private $dimensionModeConfiguration; + + /** + * @param IndexScopeResolverInterface $priceTableResolver + * @param StoreManagerInterface $storeManager + * @param Context $context + * @param DimensionFactory $dimensionFactory + * @param DimensionModeConfiguration $dimensionModeConfiguration + */ + public function __construct( + IndexScopeResolverInterface $priceTableResolver, + StoreManagerInterface $storeManager, + Context $context, + DimensionFactory $dimensionFactory, + DimensionModeConfiguration $dimensionModeConfiguration + ) { + $this->priceTableResolver = $priceTableResolver; + $this->storeManager = $storeManager; + $this->httpContext = $context; + $this->dimensionFactory = $dimensionFactory; + $this->dimensionModeConfiguration = $dimensionModeConfiguration; + } + + /** + * Replacing catalog_product_index_price table name on the table name segmented per dimension. + * + * @param ResourceConnection $subject + * @param string $result + * @param string|string[] $tableName + * @return string + * @throws \Magento\Framework\Exception\NoSuchEntityException + * @SuppressWarnings(PHPMD.UnusedFormalParameter) + */ + public function afterGetTableName( + ResourceConnection $subject, + string $result, + $tableName + ) { + if (!is_array($tableName) + && $tableName === 'catalog_product_index_price' + && $this->dimensionModeConfiguration->getDimensionConfiguration() + ) { + return $this->priceTableResolver->resolve('catalog_product_index_price', $this->getDimensions()); + } + + return $result; + } + + /** + * @return Dimension[] + * @throws \Magento\Framework\Exception\NoSuchEntityException + */ + private function getDimensions(): array + { + $dimensions = []; + foreach ($this->dimensionModeConfiguration->getDimensionConfiguration() as $dimensionName) { + if ($dimensionName === WebsiteDimensionProvider::DIMENSION_NAME) { + $dimensions[] = $this->createDimensionFromWebsite(); + } + if ($dimensionName === CustomerGroupDimensionProvider::DIMENSION_NAME) { + $dimensions[] = $this->createDimensionFromCustomerGroup(); + } + } + + return $dimensions; + } + + /** + * @return Dimension + * @throws \Magento\Framework\Exception\NoSuchEntityException + */ + private function createDimensionFromWebsite(): Dimension + { + $storeKey = $this->httpContext->getValue(StoreManagerInterface::CONTEXT_STORE); + return $this->dimensionFactory->create( + WebsiteDimensionProvider::DIMENSION_NAME, + (string)$this->storeManager->getStore($storeKey)->getWebsiteId() + ); + } + + /** + * @return Dimension + */ + private function createDimensionFromCustomerGroup(): Dimension + { + return $this->dimensionFactory->create( + CustomerGroupDimensionProvider::DIMENSION_NAME, + (string)$this->httpContext->getValue(CustomerContext::CONTEXT_GROUP) + ); + } +} diff --git a/app/code/Magento/Catalog/Model/Indexer/Product/Price/Plugin/Website.php b/app/code/Magento/Catalog/Model/Indexer/Product/Price/Plugin/Website.php index 269515e292e17..4831680f07c33 100644 --- a/app/code/Magento/Catalog/Model/Indexer/Product/Price/Plugin/Website.php +++ b/app/code/Magento/Catalog/Model/Indexer/Product/Price/Plugin/Website.php @@ -5,33 +5,128 @@ */ namespace Magento\Catalog\Model\Indexer\Product\Price\Plugin; +use Magento\Catalog\Model\Indexer\Product\Price\DimensionModeConfiguration; +use Magento\Catalog\Model\Indexer\Product\Price\TableMaintainer; +use Magento\Framework\Indexer\Dimension; +use Magento\Framework\Indexer\DimensionFactory; +use Magento\Customer\Model\Indexer\CustomerGroupDimensionProvider; +use Magento\Store\Model\Indexer\WebsiteDimensionProvider; +use Magento\Framework\Model\ResourceModel\Db\AbstractDb; +use Magento\Framework\Model\AbstractModel; + class Website { /** - * @var \Magento\Catalog\Model\Indexer\Product\Price\Processor + * @var TableMaintainer + */ + private $tableMaintainer; + + /** + * DimensionFactory + * + * @var DimensionFactory + */ + private $dimensionFactory; + + /** + * @var DimensionModeConfiguration */ - protected $_processor; + private $dimensionModeConfiguration; /** - * @param \Magento\Catalog\Model\Indexer\Product\Price\Processor $processor + * @var CustomerGroupDimensionProvider */ - public function __construct(\Magento\Catalog\Model\Indexer\Product\Price\Processor $processor) + private $customerGroupDimensionProvider; + + /** + * @param TableMaintainer $tableMaintainer + * @param DimensionFactory $dimensionFactory + * @param DimensionModeConfiguration $dimensionModeConfiguration + * @param CustomerGroupDimensionProvider $customerGroupDimensionProvider + */ + public function __construct( + TableMaintainer $tableMaintainer, + DimensionFactory $dimensionFactory, + DimensionModeConfiguration $dimensionModeConfiguration, + CustomerGroupDimensionProvider $customerGroupDimensionProvider + ) { + $this->tableMaintainer = $tableMaintainer; + $this->dimensionFactory = $dimensionFactory; + $this->dimensionModeConfiguration = $dimensionModeConfiguration; + $this->customerGroupDimensionProvider = $customerGroupDimensionProvider; + } + + /** + * Update price index after website deleted + * + * @param AbstractDb $subject + * @param AbstractDb $objectResource + * @param AbstractModel $website + * + * @return AbstractDb + * @SuppressWarnings(PHPMD.UnusedFormalParameter) + */ + public function afterDelete(AbstractDb $subject, AbstractDb $objectResource, AbstractModel $website) { - $this->_processor = $processor; + foreach ($this->getAffectedDimensions($website->getId()) as $dimensions) { + $this->tableMaintainer->dropTablesForDimensions($dimensions); + } + + return $objectResource; } /** - * Invalidate price indexer + * Update price index after website created * - * @param \Magento\Store\Model\ResourceModel\Website $subject - * @param \Magento\Store\Model\ResourceModel\Website $result - * @return \Magento\Store\Model\ResourceModel\Website + * @param AbstractDb $subject + * @param AbstractDb $objectResource + * @param AbstractModel $website * + * @return AbstractDb * @SuppressWarnings(PHPMD.UnusedFormalParameter) */ - public function afterDelete(\Magento\Store\Model\ResourceModel\Website $subject, $result) + public function afterSave(AbstractDb $subject, AbstractDb $objectResource, AbstractModel $website) + { + if ($website->isObjectNew()) { + foreach ($this->getAffectedDimensions($website->getId()) as $dimensions) { + $this->tableMaintainer->createTablesForDimensions($dimensions); + } + } + + return $objectResource; + } + + /** + * Get affected dimensions + * + * @param string $websiteId + * + * @return Dimension[][] + */ + private function getAffectedDimensions(string $websiteId): array { - $this->_processor->markIndexerAsInvalid(); - return $result; + $currentDimensions = $this->dimensionModeConfiguration->getDimensionConfiguration(); + // do not return dimensions if Website dimension is not present in configuration + if (!in_array(WebsiteDimensionProvider::DIMENSION_NAME, $currentDimensions, true)) { + return []; + } + $websiteDimension = $this->dimensionFactory->create( + WebsiteDimensionProvider::DIMENSION_NAME, + $websiteId + ); + + $dimensions = []; + if (in_array(CustomerGroupDimensionProvider::DIMENSION_NAME, $currentDimensions, true)) { + foreach ($this->customerGroupDimensionProvider as $customerGroupDimension) { + $dimensions[] = [ + $customerGroupDimension, + $websiteDimension + ]; + } + } else { + $dimensions[] = [$websiteDimension]; + } + + return $dimensions; } } diff --git a/app/code/Magento/Catalog/Model/Indexer/Product/Price/PriceTableResolver.php b/app/code/Magento/Catalog/Model/Indexer/Product/Price/PriceTableResolver.php new file mode 100644 index 0000000000000..eeaa731aac686 --- /dev/null +++ b/app/code/Magento/Catalog/Model/Indexer/Product/Price/PriceTableResolver.php @@ -0,0 +1,78 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +declare(strict_types=1); + +namespace Magento\Catalog\Model\Indexer\Product\Price; + +use Magento\Framework\Indexer\Dimension; +use Magento\Framework\Indexer\ScopeResolver\IndexScopeResolver; +use Magento\Framework\Search\Request\IndexScopeResolverInterface; + +/** + * Class return price table name based on dimension + * use only on the frontend area + */ +class PriceTableResolver implements IndexScopeResolverInterface +{ + /** + * @var IndexScopeResolver + */ + private $indexScopeResolver; + + /** + * @var DimensionModeConfiguration + */ + private $dimensionModeConfiguration; + + /** + * @param IndexScopeResolver $indexScopeResolver + * @param DimensionModeConfiguration $dimensionModeConfiguration + */ + public function __construct( + IndexScopeResolver $indexScopeResolver, + DimensionModeConfiguration $dimensionModeConfiguration + ) { + $this->indexScopeResolver = $indexScopeResolver; + $this->dimensionModeConfiguration = $dimensionModeConfiguration; + } + + /** + * Return price table name based on dimension + * @param string $index + * @param array $dimensions + * @return string + */ + public function resolve($index, array $dimensions) + { + if ($index === 'catalog_product_index_price') { + $dimensions = $this->filterDimensions($dimensions); + } + return $this->indexScopeResolver->resolve($index, $dimensions); + } + + /** + * @param Dimension[] $dimensions + * @return array + * @throws \Exception + */ + private function filterDimensions($dimensions): array + { + $existDimensions = []; + $currentDimensions = $this->dimensionModeConfiguration->getDimensionConfiguration(); + foreach ($dimensions as $dimension) { + if ((string)$dimension->getValue() === '') { + throw new \InvalidArgumentException( + sprintf('Dimension value of "%s" can not be empty', $dimension->getName()) + ); + } + if (in_array($dimension->getName(), $currentDimensions, true)) { + $existDimensions[] = $dimension; + } + } + + return $existDimensions; + } +} diff --git a/app/code/Magento/Catalog/Model/Indexer/Product/Price/TableMaintainer.php b/app/code/Magento/Catalog/Model/Indexer/Product/Price/TableMaintainer.php new file mode 100644 index 0000000000000..e3077baaeb7a6 --- /dev/null +++ b/app/code/Magento/Catalog/Model/Indexer/Product/Price/TableMaintainer.php @@ -0,0 +1,280 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +declare(strict_types=1); + +namespace Magento\Catalog\Model\Indexer\Product\Price; + +use Magento\Framework\App\ResourceConnection; +use Magento\Framework\Search\Request\Dimension; +use Magento\Framework\DB\Adapter\AdapterInterface; +use Magento\Framework\Search\Request\IndexScopeResolverInterface as TableResolver; + +/** + * Class encapsulate logic of work with tables per store in Product Price indexer + */ +class TableMaintainer +{ + /** + * Catalog product price index table name + */ + const MAIN_INDEX_TABLE = 'catalog_product_index_price'; + + /** + * @var ResourceConnection + */ + private $resource; + + /** + * @var TableResolver + */ + private $tableResolver; + + /** + * @var AdapterInterface + */ + private $connection; + + /** + * Catalog tmp category index table name + */ + private $tmpTableSuffix = '_temp'; + + /** + * Catalog tmp category index table name + */ + private $additionalTableSuffix = '_replica'; + + /** + * @var string[] + */ + private $mainTmpTable; + + /** + * @var null|string + */ + private $connectionName; + + /** + * @param ResourceConnection $resource + * @param TableResolver $tableResolver + * @param null $connectionName + */ + public function __construct( + ResourceConnection $resource, + TableResolver $tableResolver, + $connectionName = null + ) { + $this->resource = $resource; + $this->tableResolver = $tableResolver; + $this->connectionName = $connectionName; + } + + /** + * Get connection for work with price indexer + * + * @return AdapterInterface + */ + public function getConnection(): AdapterInterface + { + if (null === $this->connection) { + $this->connection = $this->resource->getConnection($this->connectionName); + } + return $this->connection; + } + + /** + * Return validated table name + * + * @param string $table + * @return string + */ + private function getTable(string $table): string + { + return $this->resource->getTableName($table); + } + + /** + * Create table based on main table + * + * @param string $mainTableName + * @param string $newTableName + * + * @return void + * + * @throws \Zend_Db_Exception + */ + private function createTable(string $mainTableName, string $newTableName) + { + if (!$this->getConnection()->isTableExists($newTableName)) { + $this->getConnection()->createTable( + $this->getConnection()->createTableByDdl($mainTableName, $newTableName) + ); + } + } + + /** + * Drop table + * + * @param string $tableName + * + * @return void + */ + private function dropTable(string $tableName) + { + if ($this->getConnection()->isTableExists($tableName)) { + $this->getConnection()->dropTable($tableName); + } + } + + /** + * Truncate table + * + * @param string $tableName + * + * @return void + */ + private function truncateTable(string $tableName) + { + if ($this->getConnection()->isTableExists($tableName)) { + $this->getConnection()->truncateTable($tableName); + } + } + + /** + * Get array key for tmp table + * + * @param Dimension[] $dimensions + * + * @return string + */ + private function getArrayKeyForTmpTable(array $dimensions): string + { + $key = 'temp'; + foreach ($dimensions as $dimension) { + $key .= $dimension->getName() . '_' . $dimension->getValue(); + } + return $key; + } + + /** + * Return main index table name + * + * @param Dimension[] $dimensions + * + * @return string + */ + public function getMainTable(array $dimensions): string + { + return $this->tableResolver->resolve(self::MAIN_INDEX_TABLE, $dimensions); + } + + /** + * Create main and replica index tables for dimensions + * + * @param Dimension[] $dimensions + * + * @return void + * + * @throws \Zend_Db_Exception + */ + public function createTablesForDimensions(array $dimensions) + { + $mainTableName = $this->getMainTable($dimensions); + //Create index table for dimensions based on main replica table + //Using main replica table is necessary for backward capability and TableResolver plugin work + $this->createTable( + $this->getTable(self::MAIN_INDEX_TABLE . $this->additionalTableSuffix), + $mainTableName + ); + + $mainReplicaTableName = $this->getMainTable($dimensions) . $this->additionalTableSuffix; + //Create replica table for dimensions based on main replica table + $this->createTable( + $this->getTable(self::MAIN_INDEX_TABLE . $this->additionalTableSuffix), + $mainReplicaTableName + ); + } + + /** + * Drop main and replica index tables for dimensions + * + * @param Dimension[] $dimensions + * + * @return void + */ + public function dropTablesForDimensions(array $dimensions) + { + $mainTableName = $this->getMainTable($dimensions); + $this->dropTable($mainTableName); + + $mainReplicaTableName = $this->getMainTable($dimensions) . $this->additionalTableSuffix; + $this->dropTable($mainReplicaTableName); + } + + /** + * Truncate main and replica index tables for dimensions + * + * @param Dimension[] $dimensions + * + * @return void + */ + public function truncateTablesForDimensions(array $dimensions) + { + $mainTableName = $this->getMainTable($dimensions); + $this->truncateTable($mainTableName); + + $mainReplicaTableName = $this->getMainTable($dimensions) . $this->additionalTableSuffix; + $this->truncateTable($mainReplicaTableName); + } + + /** + * Return replica index table name + * + * @param Dimension[] $dimensions + * + * @return string + */ + public function getMainReplicaTable(array $dimensions): string + { + return $this->getMainTable($dimensions) . $this->additionalTableSuffix; + } + + /** + * Create temporary index table for dimensions + * + * @param Dimension[] $dimensions + * + * @return void + */ + public function createMainTmpTable(array $dimensions) + { + // Create temporary table based on template table catalog_product_index_price_tmp without indexes + $templateTableName = $this->resource->getTableName(self::MAIN_INDEX_TABLE . '_tmp'); + $temporaryTableName = $this->getMainTable($dimensions) . $this->tmpTableSuffix; + $this->getConnection()->createTemporaryTableLike($temporaryTableName, $templateTableName, true); + $this->mainTmpTable[$this->getArrayKeyForTmpTable($dimensions)] = $temporaryTableName; + } + + /** + * Return temporary index table name + * + * @param Dimension[] $dimensions + * + * @return string + * + * @throws \LogicException + */ + public function getMainTmpTable(array $dimensions): string + { + $cacheKey = $this->getArrayKeyForTmpTable($dimensions); + if (!isset($this->mainTmpTable[$cacheKey])) { + throw new \LogicException( + sprintf('Temporary table for provided dimensions "%s" does not exist', $cacheKey) + ); + } + return $this->mainTmpTable[$cacheKey]; + } +} diff --git a/app/code/Magento/Catalog/Model/Product/Option/Validator/DefaultValidator.php b/app/code/Magento/Catalog/Model/Product/Option/Validator/DefaultValidator.php index 1e5c7f76d829b..ee508e30cc93e 100644 --- a/app/code/Magento/Catalog/Model/Product/Option/Validator/DefaultValidator.php +++ b/app/code/Magento/Catalog/Model/Product/Option/Validator/DefaultValidator.php @@ -106,7 +106,9 @@ protected function isValidOptionTitle($title, $storeId) if ($storeId > \Magento\Store\Model\Store::DEFAULT_STORE_ID && $title === null) { return true; } - if ($this->isEmpty($title)) { + + // checking whether title is null and is empty string + if ($title === null || $title === '') { return false; } @@ -132,7 +134,7 @@ protected function validateOptionType(Option $option) */ protected function validateOptionValue(Option $option) { - return $this->isInRange($option->getPriceType(), $this->priceTypes) && !$this->isNegative($option->getPrice()); + return $this->isInRange($option->getPriceType(), $this->priceTypes); } /** diff --git a/app/code/Magento/Catalog/Model/Product/Option/Validator/Select.php b/app/code/Magento/Catalog/Model/Product/Option/Validator/Select.php index f04ab497e1d4f..44756890b6ed7 100644 --- a/app/code/Magento/Catalog/Model/Product/Option/Validator/Select.php +++ b/app/code/Magento/Catalog/Model/Product/Option/Validator/Select.php @@ -83,7 +83,7 @@ protected function isValidOptionPrice($priceType, $price, $storeId) if (!$priceType && !$price) { return true; } - if (!$this->isInRange($priceType, $this->priceTypes) || $this->isNegative($price)) { + if (!$this->isInRange($priceType, $this->priceTypes)) { return false; } diff --git a/app/code/Magento/Catalog/Model/Product/Type/AbstractType.php b/app/code/Magento/Catalog/Model/Product/Type/AbstractType.php index d3f0c8be6f649..1b5cf37f6cbb8 100644 --- a/app/code/Magento/Catalog/Model/Product/Type/AbstractType.php +++ b/app/code/Magento/Catalog/Model/Product/Type/AbstractType.php @@ -292,13 +292,7 @@ public function attributesCompare($attributeOne, $attributeTwo) $sortOne = $attributeOne->getGroupSortPath() * 1000 + $attributeOne->getSortPath() * 0.0001; $sortTwo = $attributeTwo->getGroupSortPath() * 1000 + $attributeTwo->getSortPath() * 0.0001; - if ($sortOne > $sortTwo) { - return 1; - } elseif ($sortOne < $sortTwo) { - return -1; - } - - return 0; + return $sortOne <=> $sortTwo; } /** diff --git a/app/code/Magento/Catalog/Model/ProductRepository.php b/app/code/Magento/Catalog/Model/ProductRepository.php index 4c0122694285d..ef2c99c5cb40e 100644 --- a/app/code/Magento/Catalog/Model/ProductRepository.php +++ b/app/code/Magento/Catalog/Model/ProductRepository.php @@ -514,13 +514,14 @@ protected function processMediaGallery(ProductInterface $product, $mediaGalleryE $newEntries = $mediaGalleryEntries; } + $images = (array)$product->getMediaGallery('images'); + $images = $this->determineImageRoles($product, $images); + $this->getMediaGalleryProcessor()->clearMediaAttribute($product, array_keys($product->getMediaAttributes())); - $images = $product->getMediaGallery('images'); - if ($images) { - foreach ($images as $image) { - if (!isset($image['removed']) && !empty($image['types'])) { - $this->getMediaGalleryProcessor()->setMediaAttribute($product, $image['types'], $image['file']); - } + + foreach ($images as $image) { + if (!isset($image['removed']) && !empty($image['types'])) { + $this->getMediaGalleryProcessor()->setMediaAttribute($product, $image['types'], $image['file']); } } @@ -758,6 +759,32 @@ public function cleanCache() $this->instancesById = null; } + /** + * Ascertain image roles, if they are not set against the gallery entries + * + * @param ProductInterface $product + * @param array $images + * @return array + */ + private function determineImageRoles(ProductInterface $product, array $images) : array + { + $imagesWithRoles = []; + foreach ($images as $image) { + if (!isset($image['types'])) { + $image['types'] = []; + if (isset($image['file'])) { + foreach (array_keys($product->getMediaAttributes()) as $attribute) { + if ($image['file'] == $product->getData($attribute)) { + $image['types'][] = $attribute; + } + } + } + } + $imagesWithRoles[] = $image; + } + return $imagesWithRoles; + } + /** * @return Product\Gallery\Processor */ diff --git a/app/code/Magento/Catalog/Model/ResourceModel/Layer/Filter/Price.php b/app/code/Magento/Catalog/Model/ResourceModel/Layer/Filter/Price.php index bed129e19168f..3699e29f8201a 100644 --- a/app/code/Magento/Catalog/Model/ResourceModel/Layer/Filter/Price.php +++ b/app/code/Magento/Catalog/Model/ResourceModel/Layer/Filter/Price.php @@ -5,6 +5,15 @@ */ namespace Magento\Catalog\Model\ResourceModel\Layer\Filter; +use Magento\Framework\App\Http\Context; +use Magento\Framework\App\ObjectManager; +use Magento\Framework\Indexer\DimensionFactory; +use Magento\Framework\Search\Request\IndexScopeResolverInterface; +use Magento\Store\Model\StoreManagerInterface; +use Magento\Customer\Model\Context as CustomerContext; +use Magento\Customer\Model\Indexer\CustomerGroupDimensionProvider; +use Magento\Store\Model\Indexer\WebsiteDimensionProvider; + /** * Catalog Layer Price Filter resource model * @@ -41,6 +50,21 @@ class Price extends \Magento\Framework\Model\ResourceModel\Db\AbstractDb */ private $storeManager; + /** + * @var IndexScopeResolverInterface|null + */ + private $priceTableResolver; + + /** + * @var Context + */ + private $httpContext; + + /** + * @var DimensionFactory|null + */ + private $dimensionFactory; + /** * @param \Magento\Framework\Model\ResourceModel\Db\Context $context * @param \Magento\Framework\Event\ManagerInterface $eventManager @@ -48,6 +72,9 @@ class Price extends \Magento\Framework\Model\ResourceModel\Db\AbstractDb * @param \Magento\Customer\Model\Session $session * @param \Magento\Store\Model\StoreManagerInterface $storeManager * @param null $connectionName + * @param IndexScopeResolverInterface|null $priceTableResolver + * @param Context|null $httpContext + * @param DimensionFactory|null $dimensionFactory */ public function __construct( \Magento\Framework\Model\ResourceModel\Db\Context $context, @@ -55,12 +82,19 @@ public function __construct( \Magento\Catalog\Model\Layer\Resolver $layerResolver, \Magento\Customer\Model\Session $session, \Magento\Store\Model\StoreManagerInterface $storeManager, - $connectionName = null + $connectionName = null, + IndexScopeResolverInterface $priceTableResolver = null, + Context $httpContext = null, + DimensionFactory $dimensionFactory = null ) { $this->layer = $layerResolver->get(); $this->session = $session; $this->storeManager = $storeManager; $this->_eventManager = $eventManager; + $this->priceTableResolver = $priceTableResolver + ?? ObjectManager::getInstance()->get(IndexScopeResolverInterface::class); + $this->httpContext = $httpContext ?? ObjectManager::getInstance()->get(Context::class); + $this->dimensionFactory = $dimensionFactory ?? ObjectManager::getInstance()->get(DimensionFactory::class); parent::__construct($context, $connectionName); } @@ -118,11 +152,8 @@ protected function _getSelect() // remove join with main table $fromPart = $select->getPart(\Magento\Framework\DB\Select::FROM); - if (!isset( - $fromPart[\Magento\Catalog\Model\ResourceModel\Product\Collection::INDEX_TABLE_ALIAS] - ) || !isset( - $fromPart[\Magento\Catalog\Model\ResourceModel\Product\Collection::MAIN_TABLE_ALIAS] - ) + if (!isset($fromPart[\Magento\Catalog\Model\ResourceModel\Product\Collection::INDEX_TABLE_ALIAS]) || + !isset($fromPart[\Magento\Catalog\Model\ResourceModel\Product\Collection::MAIN_TABLE_ALIAS]) ) { return $select; } @@ -376,6 +407,30 @@ protected function _construct() $this->_init('catalog_product_index_price', 'entity_id'); } + /** + * {@inheritdoc} + * @return string + */ + public function getMainTable() + { + $storeKey = $this->httpContext->getValue(StoreManagerInterface::CONTEXT_STORE); + $priceTableName = $this->priceTableResolver->resolve( + 'catalog_product_index_price', + [ + $this->dimensionFactory->create( + WebsiteDimensionProvider::DIMENSION_NAME, + (string)$this->storeManager->getStore($storeKey)->getWebsiteId() + ), + $this->dimensionFactory->create( + CustomerGroupDimensionProvider::DIMENSION_NAME, + (string)$this->httpContext->getValue(CustomerContext::CONTEXT_GROUP) + ) + ] + ); + + return $this->getTable($priceTableName); + } + /** * Retrieve joined price index table alias * diff --git a/app/code/Magento/Catalog/Model/ResourceModel/Product/Collection.php b/app/code/Magento/Catalog/Model/ResourceModel/Product/Collection.php index 0189263d7cdfb..4384effc4e359 100644 --- a/app/code/Magento/Catalog/Model/ResourceModel/Product/Collection.php +++ b/app/code/Magento/Catalog/Model/ResourceModel/Product/Collection.php @@ -12,11 +12,15 @@ use Magento\Catalog\Model\ResourceModel\Product\Collection\ProductLimitationFactory; use Magento\CatalogUrlRewrite\Model\ProductUrlRewriteGenerator; use Magento\Customer\Api\GroupManagementInterface; +use Magento\Customer\Model\Indexer\CustomerGroupDimensionProvider; use Magento\Framework\App\ObjectManager; use Magento\Framework\DB\Select; use Magento\Framework\EntityManager\MetadataPool; +use Magento\Catalog\Model\Indexer\Product\Price\PriceTableResolver; +use Magento\Store\Model\Indexer\WebsiteDimensionProvider; use Magento\Store\Model\Store; use Magento\Catalog\Model\Indexer\Category\Product\TableMaintainer; +use Magento\Framework\Indexer\DimensionFactory; /** * Product collection @@ -276,9 +280,18 @@ class Collection extends \Magento\Catalog\Model\ResourceModel\Collection\Abstrac */ private $tableMaintainer; + /** + * @var PriceTableResolver + */ + private $priceTableResolver; + + /** + * @var DimensionFactory + */ + private $dimensionFactory; + /** * Collection constructor - * * @param \Magento\Framework\Data\Collection\EntityFactory $entityFactory * @param \Psr\Log\LoggerInterface $logger * @param \Magento\Framework\Data\Collection\Db\FetchStrategyInterface $fetchStrategy @@ -302,7 +315,8 @@ class Collection extends \Magento\Catalog\Model\ResourceModel\Collection\Abstrac * @param ProductLimitationFactory|null $productLimitationFactory * @param MetadataPool|null $metadataPool * @param TableMaintainer|null $tableMaintainer - * + * @param PriceTableResolver|null $priceTableResolver + * @param DimensionFactory|null $dimensionFactory * @SuppressWarnings(PHPMD.ExcessiveParameterList) */ public function __construct( @@ -328,7 +342,9 @@ public function __construct( \Magento\Framework\DB\Adapter\AdapterInterface $connection = null, ProductLimitationFactory $productLimitationFactory = null, MetadataPool $metadataPool = null, - TableMaintainer $tableMaintainer = null + TableMaintainer $tableMaintainer = null, + PriceTableResolver $priceTableResolver = null, + DimensionFactory $dimensionFactory = null ) { $this->moduleManager = $moduleManager; $this->_catalogProductFlatState = $catalogProductFlatState; @@ -359,6 +375,9 @@ public function __construct( $connection ); $this->tableMaintainer = $tableMaintainer ?: ObjectManager::getInstance()->get(TableMaintainer::class); + $this->priceTableResolver = $priceTableResolver ?: ObjectManager::getInstance()->get(PriceTableResolver::class); + $this->dimensionFactory = $dimensionFactory + ?: ObjectManager::getInstance()->get(DimensionFactory::class); } /** @@ -1061,14 +1080,15 @@ public function getAllAttributeValues($attribute) $select = clone $this->getSelect(); $attribute = $this->getEntity()->getAttribute($attribute); - $aiField = $this->getConnection()->getAutoIncrementField($this->getMainTable()); + $fieldMainTable = $this->getConnection()->getAutoIncrementField($this->getMainTable()); + $fieldJoinTable = $attribute->getEntity()->getLinkField(); $select->reset() ->from( ['cpe' => $this->getMainTable()], ['entity_id'] )->join( ['cpa' => $attribute->getBackend()->getTable()], - 'cpe.' . $aiField . ' = cpa.' . $aiField, + 'cpe.' . $fieldMainTable . ' = cpa.' . $fieldJoinTable, ['store_id', 'value'] )->where('attribute_id = ?', (int)$attribute->getId()); @@ -1680,7 +1700,7 @@ public function addAttributeToSort($attribute, $dir = self::SORT_ORDER_ASC) return $this; } elseif ($attribute == 'is_saleable') { - $this->getSelect()->order("is_saleable " . $dir); + $this->getSelect()->order("is_salable " . $dir); return $this; } @@ -1863,7 +1883,12 @@ protected function _productLimitationJoinPrice() protected function _productLimitationPrice($joinLeft = false) { $filters = $this->_productLimitationFilters; - if (!$filters->isUsingPriceIndex()) { + if (!$filters->isUsingPriceIndex() || + !isset($filters['website_id']) || + (string)$filters['website_id'] === '' || + !isset($filters['customer_group_id']) || + (string)$filters['customer_group_id'] === '' + ) { return $this; } @@ -1898,7 +1923,23 @@ protected function _productLimitationPrice($joinLeft = false) 'max_price', 'tier_price', ]; - $tableName = ['price_index' => $this->getTable('catalog_product_index_price')]; + + $tableName = [ + 'price_index' => $this->priceTableResolver->resolve( + 'catalog_product_index_price', + [ + $this->dimensionFactory->create( + CustomerGroupDimensionProvider::DIMENSION_NAME, + (string)$filters['customer_group_id'] + ), + $this->dimensionFactory->create( + WebsiteDimensionProvider::DIMENSION_NAME, + (string)$filters['website_id'] + ) + ] + ) + ]; + if ($joinLeft) { $select->joinLeft($tableName, $joinCond, $colls); } else { @@ -2228,6 +2269,7 @@ public function addPriceDataFieldFilter($comparisonFormat, $fields) * @SuppressWarnings(PHPMD.CyclomaticComplexity) * @SuppressWarnings(PHPMD.NPathComplexity) * @since 101.0.1 + * @throws \Magento\Framework\Exception\LocalizedException */ public function addMediaGalleryData() { @@ -2239,34 +2281,36 @@ public function addMediaGalleryData() return $this; } - /** @var $attribute \Magento\Catalog\Model\ResourceModel\Eav\Attribute */ - $attribute = $this->getAttribute('media_gallery'); - $select = $this->getMediaGalleryResource()->createBatchBaseSelect( - $this->getStoreId(), - $attribute->getAttributeId() - ); - - $mediaGalleries = []; - $linkField = $this->getProductEntityMetadata()->getLinkField(); $items = $this->getItems(); + $linkField = $this->getProductEntityMetadata()->getLinkField(); - $select->where( - 'entity.' . $linkField . ' IN (?)', - array_map( - function ($item) use ($linkField) { - return $item->getData($linkField); - }, - $items - ) - ); + $select = $this->getMediaGalleryResource() + ->createBatchBaseSelect( + $this->getStoreId(), + $this->getAttribute('media_gallery')->getAttributeId() + )->reset( + Select::ORDER // we don't care what order is in current scenario + )->where( + 'entity.' . $linkField . ' IN (?)', + array_map( + function ($item) use ($linkField) { + return (int) $item->getOrigData($linkField); + }, + $items + ) + ); + + $mediaGalleries = []; foreach ($this->getConnection()->fetchAll($select) as $row) { $mediaGalleries[$row[$linkField]][] = $row; } foreach ($items as $item) { - $mediaEntries = isset($mediaGalleries[$item->getData($linkField)]) ? - $mediaGalleries[$item->getData($linkField)] : []; - $this->getGalleryReadHandler()->addMediaDataToProduct($item, $mediaEntries); + $this->getGalleryReadHandler() + ->addMediaDataToProduct( + $item, + $mediaGalleries[$item->getOrigData($linkField)] ?? [] + ); } $this->setFlag('media_gallery_added', true); diff --git a/app/code/Magento/Catalog/Model/ResourceModel/Product/Indexer/LinkedProductSelectBuilderByIndexPrice.php b/app/code/Magento/Catalog/Model/ResourceModel/Product/Indexer/LinkedProductSelectBuilderByIndexPrice.php index ee1df8f23424d..ebe04fb63b217 100644 --- a/app/code/Magento/Catalog/Model/ResourceModel/Product/Indexer/LinkedProductSelectBuilderByIndexPrice.php +++ b/app/code/Magento/Catalog/Model/ResourceModel/Product/Indexer/LinkedProductSelectBuilderByIndexPrice.php @@ -7,9 +7,13 @@ use Magento\Catalog\Api\Data\ProductInterface; use Magento\Catalog\Model\ResourceModel\Product\BaseSelectProcessorInterface; +use Magento\Customer\Model\Indexer\CustomerGroupDimensionProvider; use Magento\Framework\App\ObjectManager; use Magento\Framework\DB\Select; use Magento\Catalog\Model\ResourceModel\Product\LinkedProductSelectBuilderInterface; +use Magento\Framework\Indexer\DimensionFactory; +use Magento\Store\Model\Indexer\WebsiteDimensionProvider; +use Magento\Framework\Search\Request\IndexScopeResolverInterface; class LinkedProductSelectBuilderByIndexPrice implements LinkedProductSelectBuilderInterface { @@ -38,6 +42,16 @@ class LinkedProductSelectBuilderByIndexPrice implements LinkedProductSelectBuild */ private $baseSelectProcessor; + /** + * @var IndexScopeResolverInterface|null + */ + private $priceTableResolver; + + /** + * @var DimensionFactory|null + */ + private $dimensionFactory; + /** * LinkedProductSelectBuilderByIndexPrice constructor. * @param \Magento\Store\Model\StoreManagerInterface $storeManager @@ -45,13 +59,17 @@ class LinkedProductSelectBuilderByIndexPrice implements LinkedProductSelectBuild * @param \Magento\Customer\Model\Session $customerSession * @param \Magento\Framework\EntityManager\MetadataPool $metadataPool * @param BaseSelectProcessorInterface|null $baseSelectProcessor + * @param IndexScopeResolverInterface|null $priceTableResolver + * @param DimensionFactory|null $dimensionFactory */ public function __construct( \Magento\Store\Model\StoreManagerInterface $storeManager, \Magento\Framework\App\ResourceConnection $resourceConnection, \Magento\Customer\Model\Session $customerSession, \Magento\Framework\EntityManager\MetadataPool $metadataPool, - BaseSelectProcessorInterface $baseSelectProcessor = null + BaseSelectProcessorInterface $baseSelectProcessor = null, + IndexScopeResolverInterface $priceTableResolver = null, + DimensionFactory $dimensionFactory = null ) { $this->storeManager = $storeManager; $this->resource = $resourceConnection; @@ -59,6 +77,9 @@ public function __construct( $this->metadataPool = $metadataPool; $this->baseSelectProcessor = (null !== $baseSelectProcessor) ? $baseSelectProcessor : ObjectManager::getInstance()->get(BaseSelectProcessorInterface::class); + $this->priceTableResolver = $priceTableResolver + ?? ObjectManager::getInstance()->get(IndexScopeResolverInterface::class); + $this->dimensionFactory = $dimensionFactory ?? ObjectManager::getInstance()->get(DimensionFactory::class); } /** @@ -68,6 +89,8 @@ public function build($productId) { $linkField = $this->metadataPool->getMetadata(ProductInterface::class)->getLinkField(); $productTable = $this->resource->getTableName('catalog_product_entity'); + $websiteId = $this->storeManager->getStore()->getWebsiteId(); + $customerGroupId = $this->customerSession->getCustomerGroupId(); $priceSelect = $this->resource->getConnection()->select() ->from(['parent' => $productTable], '') @@ -80,12 +103,20 @@ public function build($productId) sprintf('%s.entity_id = link.child_id', BaseSelectProcessorInterface::PRODUCT_TABLE_ALIAS), ['entity_id'] )->joinInner( - ['t' => $this->resource->getTableName('catalog_product_index_price')], + [ + 't' => $this->priceTableResolver->resolve('catalog_product_index_price', [ + $this->dimensionFactory->create(WebsiteDimensionProvider::DIMENSION_NAME, (string)$websiteId), + $this->dimensionFactory->create( + CustomerGroupDimensionProvider::DIMENSION_NAME, + (string)$customerGroupId + ), + ]) + ], sprintf('t.entity_id = %s.entity_id', BaseSelectProcessorInterface::PRODUCT_TABLE_ALIAS), [] )->where('parent.entity_id = ?', $productId) - ->where('t.website_id = ?', $this->storeManager->getStore()->getWebsiteId()) - ->where('t.customer_group_id = ?', $this->customerSession->getCustomerGroupId()) + ->where('t.website_id = ?', $websiteId) + ->where('t.customer_group_id = ?', $customerGroupId) ->order('t.min_price ' . Select::SQL_ASC) ->order(BaseSelectProcessorInterface::PRODUCT_TABLE_ALIAS . '.' . $linkField . ' ' . Select::SQL_ASC) ->limit(1); diff --git a/app/code/Magento/Catalog/Model/ResourceModel/Product/Indexer/Price/BasePriceModifier.php b/app/code/Magento/Catalog/Model/ResourceModel/Product/Indexer/Price/BasePriceModifier.php new file mode 100644 index 0000000000000..cf5ba451c380e --- /dev/null +++ b/app/code/Magento/Catalog/Model/ResourceModel/Product/Indexer/Price/BasePriceModifier.php @@ -0,0 +1,38 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +declare(strict_types=1); + +namespace Magento\Catalog\Model\ResourceModel\Product\Indexer\Price; + +/** + * Apply price modifiers to product price indexer which are common for all product types: + * custom options, catalog rule, catalog inventory modifiers + */ +class BasePriceModifier implements PriceModifierInterface +{ + /** + * @var PriceModifierInterface[] + */ + private $priceModifiers; + + /** + * @param array $priceModifiers + */ + public function __construct(array $priceModifiers) + { + $this->priceModifiers = $priceModifiers; + } + + /** + * {@inheritdoc} + */ + public function modifyPrice(IndexTableStructure $priceTable, array $entityIds = []) : void + { + foreach ($this->priceModifiers as $priceModifier) { + $priceModifier->modifyPrice($priceTable, $entityIds); + } + } +} diff --git a/app/code/Magento/Catalog/Model/ResourceModel/Product/Indexer/Price/CompositeProductRowSizeEstimator.php b/app/code/Magento/Catalog/Model/ResourceModel/Product/Indexer/Price/CompositeProductRowSizeEstimator.php index 24cb4fedd57e5..a499777df871a 100644 --- a/app/code/Magento/Catalog/Model/ResourceModel/Product/Indexer/Price/CompositeProductRowSizeEstimator.php +++ b/app/code/Magento/Catalog/Model/ResourceModel/Product/Indexer/Price/CompositeProductRowSizeEstimator.php @@ -18,7 +18,7 @@ class CompositeProductRowSizeEstimator implements IndexTableRowSizeEstimatorInte /** * Calculated memory size for one record in catalog_product_index_price table */ - const MEMORY_SIZE_FOR_ONE_ROW = 250; + const MEMORY_SIZE_FOR_ONE_ROW = 200; /** * @var WebsiteManagementInterface diff --git a/app/code/Magento/Catalog/Model/ResourceModel/Product/Indexer/Price/CustomOptionPriceModifier.php b/app/code/Magento/Catalog/Model/ResourceModel/Product/Indexer/Price/CustomOptionPriceModifier.php new file mode 100644 index 0000000000000..47fc6802d7eaf --- /dev/null +++ b/app/code/Magento/Catalog/Model/ResourceModel/Product/Indexer/Price/CustomOptionPriceModifier.php @@ -0,0 +1,464 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +declare(strict_types=1); + +namespace Magento\Catalog\Model\ResourceModel\Product\Indexer\Price; + +use Magento\Catalog\Api\Data\ProductInterface; +use Magento\Framework\DB\Select; +use Magento\Framework\DB\Sql\ColumnValueExpression; + +/** + * Class for modify custom option price. + */ +class CustomOptionPriceModifier implements PriceModifierInterface +{ + /** + * @var \Magento\Framework\App\ResourceConnection + */ + private $resource; + + /** + * @var \Magento\Framework\EntityManager\MetadataPool + */ + private $metadataPool; + + /** + * @var \Magento\Framework\DB\Sql\ColumnValueExpression + */ + private $columnValueExpressionFactory; + + /** + * @var \Magento\Catalog\Helper\Data + */ + private $dataHelper; + + /** + * @var string + */ + private $connectionName; + + /** + * @var bool + */ + private $isPriceGlobalFlag; + + /** + * @var \Magento\Framework\DB\Adapter\AdapterInterface + */ + private $connection; + + /** + * @var \Magento\Framework\Indexer\Table\StrategyInterface + */ + private $tableStrategy; + + /** + * @param \Magento\Framework\App\ResourceConnection $resource + * @param \Magento\Framework\EntityManager\MetadataPool $metadataPool + * @param \Magento\Framework\DB\Sql\ColumnValueExpressionFactory $columnValueExpressionFactory + * @param \Magento\Catalog\Helper\Data $dataHelper + * @param \Magento\Framework\Indexer\Table\StrategyInterface $tableStrategy + * @param string $connectionName + */ + public function __construct( + \Magento\Framework\App\ResourceConnection $resource, + \Magento\Framework\EntityManager\MetadataPool $metadataPool, + \Magento\Framework\DB\Sql\ColumnValueExpressionFactory $columnValueExpressionFactory, + \Magento\Catalog\Helper\Data $dataHelper, + \Magento\Framework\Indexer\Table\StrategyInterface $tableStrategy, + $connectionName = 'indexer' + ) { + $this->resource = $resource; + $this->metadataPool = $metadataPool; + $this->connectionName = $connectionName; + $this->columnValueExpressionFactory = $columnValueExpressionFactory; + $this->dataHelper = $dataHelper; + $this->tableStrategy = $tableStrategy; + } + + /** + * Apply custom option price to temporary index price table + * + * @param IndexTableStructure $priceTable + * @param array $entityIds + * @return void + * @throws \Exception + * @SuppressWarnings(PHPMD.UnusedFormalParameter) + */ + public function modifyPrice(IndexTableStructure $priceTable, array $entityIds = []) : void + { + // no need to run all queries if current products have no custom options + if (!$this->checkIfCustomOptionsExist($priceTable)) { + return; + } + + $connection = $this->getConnection(); + $finalPriceTable = $priceTable->getTableName(); + + $coaTable = $this->getCustomOptionAggregateTable(); + $this->prepareCustomOptionAggregateTable(); + + $copTable = $this->getCustomOptionPriceTable(); + $this->prepareCustomOptionPriceTable(); + + $select = $this->getSelectForOptionsWithMultipleValues($finalPriceTable); + $query = $select->insertFromSelect($coaTable); + $connection->query($query); + + $select = $this->getSelectForOptionsWithOneValue($finalPriceTable); + $query = $select->insertFromSelect($coaTable); + $connection->query($query); + + $select = $this->getSelectAggregated($coaTable); + $query = $select->insertFromSelect($copTable); + $connection->query($query); + + // update tmp price index with prices from custom options (from previous aggregated table) + $select = $this->getSelectForUpdate($copTable); + $query = $select->crossUpdateFromSelect(['i' => $finalPriceTable]); + $connection->query($query); + + $connection->delete($coaTable); + $connection->delete($copTable); + } + + /** + * @param IndexTableStructure $priceTable + * @return bool + * @throws \Exception + */ + private function checkIfCustomOptionsExist(IndexTableStructure $priceTable): bool + { + $metadata = $this->metadataPool->getMetadata(ProductInterface::class); + + $select = $this->getConnection() + ->select() + ->from( + ['i' => $priceTable->getTableName()], + ['entity_id'] + )->join( + ['e' => $this->getTable('catalog_product_entity')], + 'e.entity_id = i.entity_id', + [] + )->join( + ['o' => $this->getTable('catalog_product_option')], + 'o.product_id = e.' . $metadata->getLinkField(), + ['option_id'] + ); + + return !empty($this->getConnection()->fetchRow($select)); + } + + /** + * @return \Magento\Framework\DB\Adapter\AdapterInterface + */ + private function getConnection() + { + if (null === $this->connection) { + $this->connection = $this->resource->getConnection($this->connectionName); + } + + return $this->connection; + } + + /** + * Prepare prices for products with custom options that has multiple values + * + * @param string $sourceTable + * @return \Magento\Framework\DB\Select + * @throws \Exception + */ + private function getSelectForOptionsWithMultipleValues(string $sourceTable): Select + { + $connection = $this->resource->getConnection($this->connectionName); + $metadata = $this->metadataPool->getMetadata(ProductInterface::class); + + $select = $connection->select() + ->from( + ['i' => $sourceTable], + ['entity_id', 'customer_group_id', 'website_id'] + )->join( + ['e' => $this->getTable('catalog_product_entity')], + 'e.entity_id = i.entity_id', + [] + )->join( + ['cwd' => $this->getTable('catalog_product_index_website')], + 'i.website_id = cwd.website_id', + [] + )->join( + ['o' => $this->getTable('catalog_product_option')], + 'o.product_id = e.' . $metadata->getLinkField(), + ['option_id'] + )->join( + ['ot' => $this->getTable('catalog_product_option_type_value')], + 'ot.option_id = o.option_id', + [] + )->join( + ['otpd' => $this->getTable('catalog_product_option_type_price')], + 'otpd.option_type_id = ot.option_type_id AND otpd.store_id = 0', + [] + )->group( + ['i.entity_id', 'i.customer_group_id', 'i.website_id', 'o.option_id'] + ); + + if ($this->isPriceGlobal()) { + $optPriceType = 'otpd.price_type'; + $optPriceValue = 'otpd.price'; + } else { + $select->joinLeft( + ['otps' => $this->getTable('catalog_product_option_type_price')], + 'otps.option_type_id = otpd.option_type_id AND otpd.store_id = cwd.default_store_id', + [] + ); + + $optPriceType = $connection->getCheckSql( + 'otps.option_type_price_id > 0', + 'otps.price_type', + 'otpd.price_type' + ); + $optPriceValue = $connection->getCheckSql('otps.option_type_price_id > 0', 'otps.price', 'otpd.price'); + } + + $minPriceRound = $this->columnValueExpressionFactory + ->create([ + 'expression' => "ROUND(i.final_price * ({$optPriceValue} / 100), 4)" + ]); + $minPriceExpr = $connection->getCheckSql("{$optPriceType} = 'fixed'", $optPriceValue, $minPriceRound); + $minPriceMin = $this->columnValueExpressionFactory + ->create([ + 'expression' => "MIN({$minPriceExpr})" + ]); + $minPrice = $connection->getCheckSql("MIN(o.is_require) = 1", $minPriceMin, '0'); + + $tierPriceRound = $this->columnValueExpressionFactory + ->create([ + 'expression' => "ROUND(i.tier_price * ({$optPriceValue} / 100), 4)" + ]); + $tierPriceExpr = $connection->getCheckSql("{$optPriceType} = 'fixed'", $optPriceValue, $tierPriceRound); + $tierPriceMin = $this->columnValueExpressionFactory + ->create([ + 'expression' => "MIN({$tierPriceExpr})" + ]); + $tierPriceValue = $connection->getCheckSql("MIN(o.is_require) > 0", $tierPriceMin, 0); + $tierPrice = $connection->getCheckSql("MIN(i.tier_price) IS NOT NULL", $tierPriceValue, "NULL"); + + $maxPriceRound = $this->columnValueExpressionFactory + ->create([ + 'expression' => "ROUND(i.final_price * ({$optPriceValue} / 100), 4)" + ]); + $maxPriceExpr = $connection->getCheckSql("{$optPriceType} = 'fixed'", $optPriceValue, $maxPriceRound); + $maxPrice = $connection->getCheckSql( + "(MIN(o.type)='radio' OR MIN(o.type)='drop_down')", + "MAX({$maxPriceExpr})", + "SUM({$maxPriceExpr})" + ); + + $select->columns( + [ + 'min_price' => $minPrice, + 'max_price' => $maxPrice, + 'tier_price' => $tierPrice, + ] + ); + + return $select; + } + + /** + * Prepare prices for products with custom options that has single value + * + * @param string $sourceTable + * @return \Magento\Framework\DB\Select + * @throws \Exception + */ + private function getSelectForOptionsWithOneValue(string $sourceTable): Select + { + $connection = $this->resource->getConnection($this->connectionName); + $metadata = $this->metadataPool->getMetadata(ProductInterface::class); + + $select = $connection->select() + ->from( + ['i' => $sourceTable], + ['entity_id', 'customer_group_id', 'website_id'] + )->join( + ['e' => $this->getTable('catalog_product_entity')], + 'e.entity_id = i.entity_id', + [] + )->join( + ['cwd' => $this->getTable('catalog_product_index_website')], + 'i.website_id = cwd.website_id', + [] + )->join( + ['o' => $this->getTable('catalog_product_option')], + 'o.product_id = e.' . $metadata->getLinkField(), + ['option_id'] + )->join( + ['opd' => $this->getTable('catalog_product_option_price')], + 'opd.option_id = o.option_id AND opd.store_id = 0', + [] + ); + + if ($this->isPriceGlobal()) { + $optPriceType = 'opd.price_type'; + $optPriceValue = 'opd.price'; + } else { + $select->joinLeft( + ['ops' => $this->getTable('catalog_product_option_price')], + 'ops.option_id = opd.option_id AND ops.store_id = cwd.default_store_id', + [] + ); + + $optPriceType = $connection->getCheckSql('ops.option_price_id > 0', 'ops.price_type', 'opd.price_type'); + $optPriceValue = $connection->getCheckSql('ops.option_price_id > 0', 'ops.price', 'opd.price'); + } + + $minPriceRound = $this->columnValueExpressionFactory + ->create([ + 'expression' => "ROUND(i.final_price * ({$optPriceValue} / 100), 4)" + ]); + $priceExpr = $connection->getCheckSql("{$optPriceType} = 'fixed'", $optPriceValue, $minPriceRound); + $minPrice = $connection->getCheckSql("{$priceExpr} > 0 AND o.is_require = 1", $priceExpr, 0); + + $maxPrice = $priceExpr; + + $tierPriceRound = $this->columnValueExpressionFactory + ->create([ + 'expression' => "ROUND(i.tier_price * ({$optPriceValue} / 100), 4)" + ]); + $tierPriceExpr = $connection->getCheckSql("{$optPriceType} = 'fixed'", $optPriceValue, $tierPriceRound); + $tierPriceValue = $connection->getCheckSql("{$tierPriceExpr} > 0 AND o.is_require = 1", $tierPriceExpr, 0); + $tierPrice = $connection->getCheckSql("i.tier_price IS NOT NULL", $tierPriceValue, "NULL"); + + $select->columns( + [ + 'min_price' => $minPrice, + 'max_price' => $maxPrice, + 'tier_price' => $tierPrice, + ] + ); + + return $select; + } + + /** + * Aggregate prices with one and multiply options into one table + * + * @param string $sourceTable + * @return \Magento\Framework\DB\Select + */ + private function getSelectAggregated(string $sourceTable): Select + { + $connection = $this->resource->getConnection($this->connectionName); + + $select = $connection->select() + ->from( + [$sourceTable], + [ + 'entity_id', + 'customer_group_id', + 'website_id', + 'min_price' => 'SUM(min_price)', + 'max_price' => 'SUM(max_price)', + 'tier_price' => 'SUM(tier_price)', + ] + )->group( + ['entity_id', 'customer_group_id', 'website_id'] + ); + + return $select; + } + + /** + * @param string $sourceTable + * @return \Magento\Framework\DB\Select + */ + private function getSelectForUpdate(string $sourceTable): Select + { + $connection = $this->resource->getConnection($this->connectionName); + + $select = $connection->select()->join( + ['io' => $sourceTable], + 'i.entity_id = io.entity_id AND i.customer_group_id = io.customer_group_id' . + ' AND i.website_id = io.website_id', + [] + ); + $select->columns( + [ + 'min_price' => new ColumnValueExpression('i.min_price + io.min_price'), + 'max_price' => new ColumnValueExpression('i.max_price + io.max_price'), + 'tier_price' => $connection->getCheckSql( + 'i.tier_price IS NOT NULL', + 'i.tier_price + io.tier_price', + 'NULL' + ), + ] + ); + + return $select; + } + + /** + * @param string $tableName + * @return string + */ + private function getTable(string $tableName): string + { + return $this->resource->getTableName($tableName, $this->connectionName); + } + + /** + * @return bool + */ + private function isPriceGlobal(): bool + { + if ($this->isPriceGlobalFlag === null) { + $this->isPriceGlobalFlag = $this->dataHelper->isPriceGlobal(); + } + + return $this->isPriceGlobalFlag; + } + + /** + * Retrieve table name for custom option temporary aggregation data + * + * @return string + */ + private function getCustomOptionAggregateTable(): string + { + return $this->tableStrategy->getTableName('catalog_product_index_price_opt_agr'); + } + + /** + * Retrieve table name for custom option prices data + * + * @return string + */ + private function getCustomOptionPriceTable(): string + { + return $this->tableStrategy->getTableName('catalog_product_index_price_opt'); + } + + /** + * Prepare table structure for custom option temporary aggregation data + * + * @return void + */ + private function prepareCustomOptionAggregateTable() + { + $this->getConnection()->delete($this->getCustomOptionAggregateTable()); + } + + /** + * Prepare table structure for custom option prices data + * + * @return void + */ + private function prepareCustomOptionPriceTable() + { + $this->getConnection()->delete($this->getCustomOptionPriceTable()); + } +} diff --git a/app/code/Magento/Catalog/Model/ResourceModel/Product/Indexer/Price/DefaultPrice.php b/app/code/Magento/Catalog/Model/ResourceModel/Product/Indexer/Price/DefaultPrice.php index 4ca407a53f8ae..168fa8f50acc2 100644 --- a/app/code/Magento/Catalog/Model/ResourceModel/Product/Indexer/Price/DefaultPrice.php +++ b/app/code/Magento/Catalog/Model/ResourceModel/Product/Indexer/Price/DefaultPrice.php @@ -6,6 +6,7 @@ namespace Magento\Catalog\Model\ResourceModel\Product\Indexer\Price; use Magento\Catalog\Model\ResourceModel\Product\Indexer\AbstractIndexer; +use Magento\Framework\Indexer\DimensionalIndexerInterface; /** * Default Product Type Price Indexer Resource model @@ -16,6 +17,8 @@ * @author Magento Core Team <core@magentocommerce.com> * @SuppressWarnings(PHPMD.CouplingBetweenObjects) * @since 100.0.2 + * @deprecated Not used anymore for price indexation. Class left for backward compatibility + * @see DimensionalIndexerInterface */ class DefaultPrice extends AbstractIndexer implements PriceInterface { @@ -71,7 +74,7 @@ class DefaultPrice extends AbstractIndexer implements PriceInterface * @param \Magento\Framework\Event\ManagerInterface $eventManager * @param \Magento\Framework\Module\Manager $moduleManager * @param string|null $connectionName - * @param null|IndexTableStructureFactory $indexTableStructureFactory + * @param IndexTableStructureFactory $indexTableStructureFactory * @param PriceModifierInterface[] $priceModifiers */ public function __construct( @@ -307,7 +310,7 @@ protected function prepareFinalPriceDataForType($entityIds, $type) $query = $select->insertFromSelect($finalPriceTable->getTableName(), [], false); $this->getConnection()->query($query); - $this->applyDiscountPrices($finalPriceTable); + $this->modifyPriceIndex($finalPriceTable); return $this; } @@ -327,6 +330,7 @@ protected function prepareFinalPriceDataForType($entityIds, $type) protected function getSelect($entityIds = null, $type = null) { $metadata = $this->getMetadataPool()->getMetadata(\Magento\Catalog\Api\Data\ProductInterface::class); + $linkField = $metadata->getLinkField(); $connection = $this->getConnection(); $select = $connection->select()->from( ['e' => $this->getTable('catalog_product_entity')], @@ -356,9 +360,38 @@ protected function getSelect($entityIds = null, $type = null) 'pw.product_id = e.entity_id AND pw.website_id = cw.website_id', [] )->joinLeft( - ['tp' => $this->_getTierPriceIndexTable()], - 'tp.entity_id = e.entity_id AND tp.website_id = cw.website_id' . - ' AND tp.customer_group_id = cg.customer_group_id', + // we need this only for BCC in case someone expects table `tp` to be present in query + ['tp' => $this->getTable('catalog_product_index_tier_price')], + 'tp.entity_id = e.entity_id AND tp.customer_group_id = cg.customer_group_id' . + ' AND tp.website_id = pw.website_id', + [] + )->joinLeft( + // calculate tier price specified as Website = `All Websites` and Customer Group = `Specific Customer Group` + ['tier_price_1' => $this->getTable('catalog_product_entity_tier_price')], + 'tier_price_1.' . $linkField . ' = e.' . $linkField . ' AND tier_price_1.all_groups = 0' . + ' AND tier_price_1.customer_group_id = cg.customer_group_id AND tier_price_1.qty = 1' . + ' AND tier_price_1.website_id = 0', + [] + )->joinLeft( + // calculate tier price specified as Website = `Specific Website` + //and Customer Group = `Specific Customer Group` + ['tier_price_2' => $this->getTable('catalog_product_entity_tier_price')], + 'tier_price_2.' . $linkField . ' = e.' . $linkField . ' AND tier_price_2.all_groups = 0' . + ' AND tier_price_2.customer_group_id = cg.customer_group_id AND tier_price_2.qty = 1' . + ' AND tier_price_2.website_id = cw.website_id', + [] + )->joinLeft( + // calculate tier price specified as Website = `All Websites` and Customer Group = `ALL GROUPS` + ['tier_price_3' => $this->getTable('catalog_product_entity_tier_price')], + 'tier_price_3.' . $linkField . ' = e.' . $linkField . ' AND tier_price_3.all_groups = 1' . + ' AND tier_price_3.customer_group_id = 0 AND tier_price_3.qty = 1 AND tier_price_3.website_id = 0', + [] + )->joinLeft( + // calculate tier price specified as Website = `Specific Website` and Customer Group = `ALL GROUPS` + ['tier_price_4' => $this->getTable('catalog_product_entity_tier_price')], + 'tier_price_4.' . $linkField . ' = e.' . $linkField . ' AND tier_price_4.all_groups = 1' . + ' AND tier_price_4.customer_group_id = 0 AND tier_price_4.qty = 1' . + ' AND tier_price_4.website_id = cw.website_id', [] ); @@ -374,7 +407,7 @@ protected function getSelect($entityIds = null, $type = null) $this->_addAttributeToSelect( $select, 'status', - 'e.' . $metadata->getLinkField(), + 'e.' . $linkField, 'cs.store_id', $statusCond, true @@ -383,7 +416,7 @@ protected function getSelect($entityIds = null, $type = null) $taxClassId = $this->_addAttributeToSelect( $select, 'tax_class_id', - 'e.' . $metadata->getLinkField(), + 'e.' . $linkField, 'cs.store_id' ); } else { @@ -394,25 +427,25 @@ protected function getSelect($entityIds = null, $type = null) $price = $this->_addAttributeToSelect( $select, 'price', - 'e.' . $metadata->getLinkField(), + 'e.' . $linkField, 'cs.store_id' ); $specialPrice = $this->_addAttributeToSelect( $select, 'special_price', - 'e.' . $metadata->getLinkField(), + 'e.' . $linkField, 'cs.store_id' ); $specialFrom = $this->_addAttributeToSelect( $select, 'special_from_date', - 'e.' . $metadata->getLinkField(), + 'e.' . $linkField, 'cs.store_id' ); $specialTo = $this->_addAttributeToSelect( $select, 'special_to_date', - 'e.' . $metadata->getLinkField(), + 'e.' . $linkField, 'cs.store_id' ); $currentDate = 'cwd.website_date'; @@ -423,15 +456,12 @@ protected function getSelect($entityIds = null, $type = null) $specialFromExpr = "{$specialFrom} IS NULL OR {$specialFromDate} <= {$currentDate}"; $specialToExpr = "{$specialTo} IS NULL OR {$specialToDate} >= {$currentDate}"; $specialPriceExpr = $connection->getCheckSql( - "{$specialPrice} IS NOT NULL AND {$specialFromExpr} AND {$specialToExpr}", + "{$specialPrice} IS NOT NULL AND ({$specialFromExpr}) AND ({$specialToExpr})", $specialPrice, $maxUnsignedBigint ); - $tierPrice = new \Zend_Db_Expr('tp.min_price'); - $tierPriceExpr = $connection->getIfNullSql( - $tierPrice, - $maxUnsignedBigint - ); + $tierPrice = $this->getTotalTierPriceExpression($price); + $tierPriceExpr = $connection->getIfNullSql($tierPrice, $maxUnsignedBigint); $finalPrice = $connection->getLeastSql([ $price, $specialPriceExpr, @@ -512,12 +542,12 @@ protected function _prepareCustomOptionPriceTable() } /** - * Apply discount prices to final price index table. + * Modify data in price index table. * * @param IndexTableStructure $finalPriceTable * @return void */ - private function applyDiscountPrices(IndexTableStructure $finalPriceTable) : void + private function modifyPriceIndex(IndexTableStructure $finalPriceTable) : void { foreach ($this->priceModifiers as $priceModifier) { $priceModifier->modifyPrice($finalPriceTable); @@ -791,4 +821,62 @@ protected function hasEntity() return $this->hasEntity; } + + /** + * @param \Zend_Db_Expr $priceExpression + * @return \Zend_Db_Expr + */ + private function getTotalTierPriceExpression(\Zend_Db_Expr $priceExpression) + { + $maxUnsignedBigint = '~0'; + + return $this->getConnection()->getCheckSql( + implode( + ' AND ', + [ + 'tier_price_1.value_id is NULL', + 'tier_price_2.value_id is NULL', + 'tier_price_3.value_id is NULL', + 'tier_price_4.value_id is NULL' + ] + ), + 'NULL', + $this->getConnection()->getLeastSql([ + $this->getConnection()->getIfNullSql( + $this->getTierPriceExpressionForTable('tier_price_1', $priceExpression), + $maxUnsignedBigint + ), + $this->getConnection()->getIfNullSql( + $this->getTierPriceExpressionForTable('tier_price_2', $priceExpression), + $maxUnsignedBigint + ), + $this->getConnection()->getIfNullSql( + $this->getTierPriceExpressionForTable('tier_price_3', $priceExpression), + $maxUnsignedBigint + ), + $this->getConnection()->getIfNullSql( + $this->getTierPriceExpressionForTable('tier_price_4', $priceExpression), + $maxUnsignedBigint + ), + ]) + ); + } + + /** + * @param string $tableAlias + * @param \Zend_Db_Expr $priceExpression + * @return \Zend_Db_Expr + */ + private function getTierPriceExpressionForTable($tableAlias, \Zend_Db_Expr $priceExpression) + { + return $this->getConnection()->getCheckSql( + sprintf('%s.value = 0', $tableAlias), + sprintf( + 'ROUND(%s * (1 - ROUND(%s.percentage_value * cwd.rate, 4) / 100), 4)', + $priceExpression, + $tableAlias + ), + sprintf('ROUND(%s.value * cwd.rate, 4)', $tableAlias) + ); + } } diff --git a/app/code/Magento/Catalog/Model/ResourceModel/Product/Indexer/Price/Factory.php b/app/code/Magento/Catalog/Model/ResourceModel/Product/Indexer/Price/Factory.php index 21a7647214c26..9a310c7365ac9 100644 --- a/app/code/Magento/Catalog/Model/ResourceModel/Product/Indexer/Price/Factory.php +++ b/app/code/Magento/Catalog/Model/ResourceModel/Product/Indexer/Price/Factory.php @@ -9,6 +9,8 @@ */ namespace Magento\Catalog\Model\ResourceModel\Product\Indexer\Price; +use Magento\Framework\Indexer\DimensionalIndexerInterface; + class Factory { /** @@ -40,14 +42,17 @@ public function create($className, array $data = []) { $indexerPrice = $this->_objectManager->create($className, $data); - if (!$indexerPrice instanceof \Magento\Catalog\Model\ResourceModel\Product\Indexer\Price\DefaultPrice) { - throw new \Magento\Framework\Exception\LocalizedException( - __( - '%1 doesn\'t extend \Magento\Catalog\Model\ResourceModel\Product\Indexer\Price\DefaultPrice', - $className - ) - ); + if ($indexerPrice instanceof PriceInterface || $indexerPrice instanceof DimensionalIndexerInterface) { + return $indexerPrice; } - return $indexerPrice; + + throw new \Magento\Framework\Exception\LocalizedException( + __( + 'Price indexer "%1" must implement %2 or %3', + $className, + PriceInterface::class, + DimensionalIndexerInterface::class + ) + ); } } diff --git a/app/code/Magento/Catalog/Model/ResourceModel/Product/Indexer/Price/Query/BaseFinalPrice.php b/app/code/Magento/Catalog/Model/ResourceModel/Product/Indexer/Price/Query/BaseFinalPrice.php new file mode 100644 index 0000000000000..8428ff3688b28 --- /dev/null +++ b/app/code/Magento/Catalog/Model/ResourceModel/Product/Indexer/Price/Query/BaseFinalPrice.php @@ -0,0 +1,330 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +declare(strict_types=1); + +namespace Magento\Catalog\Model\ResourceModel\Product\Indexer\Price\Query; + +use Magento\Catalog\Model\Product\Attribute\Source\Status; +use Magento\Customer\Model\Indexer\CustomerGroupDimensionProvider; +use Magento\Framework\DB\Select; +use Magento\Framework\DB\Sql\ColumnValueExpression; +use Magento\Framework\Indexer\Dimension; +use Magento\Store\Model\Indexer\WebsiteDimensionProvider; + +/** + * Prepare base select for Product Price index limited by specified dimensions: website and customer group + * @SuppressWarnings(PHPMD.CouplingBetweenObjects) + */ +class BaseFinalPrice +{ + /** + * @var \Magento\Framework\App\ResourceConnection + */ + private $resource; + + /** + * @var string + */ + private $connectionName; + + /** + * @var JoinAttributeProcessor + */ + private $joinAttributeProcessor; + + /** + * @var \Magento\Framework\Module\Manager + */ + private $moduleManager; + + /** + * @var \Magento\Framework\Event\ManagerInterface + */ + private $eventManager; + + /** + * Mapping between dimensions and field in database + * + * @var array + */ + private $dimensionToFieldMapper = [ + WebsiteDimensionProvider::DIMENSION_NAME => 'pw.website_id', + CustomerGroupDimensionProvider::DIMENSION_NAME => 'cg.customer_group_id', + ]; + + /** + * @var \Magento\Framework\DB\Adapter\AdapterInterface + */ + private $connection; + + /** + * @var \Magento\Framework\EntityManager\MetadataPool + */ + private $metadataPool; + + /** + * BaseFinalPrice constructor. + * @param \Magento\Framework\App\ResourceConnection $resource + * @param JoinAttributeProcessor $joinAttributeProcessor + * @param \Magento\Framework\Module\Manager $moduleManager + * @param string $connectionName + */ + public function __construct( + \Magento\Framework\App\ResourceConnection $resource, + JoinAttributeProcessor $joinAttributeProcessor, + \Magento\Framework\Module\Manager $moduleManager, + \Magento\Framework\Event\ManagerInterface $eventManager, + \Magento\Framework\EntityManager\MetadataPool $metadataPool, + $connectionName = 'indexer' + ) { + $this->resource = $resource; + $this->connectionName = $connectionName; + $this->joinAttributeProcessor = $joinAttributeProcessor; + $this->moduleManager = $moduleManager; + $this->eventManager = $eventManager; + $this->metadataPool = $metadataPool; + } + + /** + * @param Dimension[] $dimensions + * @param string $productType + * @param array $entityIds + * @return Select + * @throws \LogicException + * @throws \Magento\Framework\Exception\LocalizedException + * @throws \Zend_Db_Select_Exception + * @SuppressWarnings(PHPMD.ExcessiveMethodLength) + */ + public function getQuery(array $dimensions, string $productType, array $entityIds = []): Select + { + $connection = $this->getConnection(); + $metadata = $this->metadataPool->getMetadata(\Magento\Catalog\Api\Data\ProductInterface::class); + $linkField = $metadata->getLinkField(); + + $select = $connection->select()->from( + ['e' => $this->getTable('catalog_product_entity')], + ['entity_id'] + )->joinInner( + ['cg' => $this->getTable('customer_group')], + array_key_exists(CustomerGroupDimensionProvider::DIMENSION_NAME, $dimensions) + ? sprintf( + '%s = %s', + $this->dimensionToFieldMapper[CustomerGroupDimensionProvider::DIMENSION_NAME], + $dimensions[CustomerGroupDimensionProvider::DIMENSION_NAME]->getValue() + ) : '', + ['customer_group_id'] + )->joinInner( + ['pw' => $this->getTable('catalog_product_website')], + 'pw.product_id = e.entity_id', + ['pw.website_id'] + )->joinInner( + ['cwd' => $this->getTable('catalog_product_index_website')], + 'pw.website_id = cwd.website_id', + [] + )->joinLeft( + // we need this only for BCC in case someone expects table `tp` to be present in query + ['tp' => $this->getTable('catalog_product_index_tier_price')], + 'tp.entity_id = e.entity_id AND' . + ' tp.customer_group_id = cg.customer_group_id AND tp.website_id = pw.website_id', + [] + )->joinLeft( + // calculate tier price specified as Website = `All Websites` and Customer Group = `Specific Customer Group` + ['tier_price_1' => $this->getTable('catalog_product_entity_tier_price')], + 'tier_price_1.' . $linkField . ' = e.' . $linkField . ' AND tier_price_1.all_groups = 0' . + ' AND tier_price_1.customer_group_id = cg.customer_group_id AND tier_price_1.qty = 1' . + ' AND tier_price_1.website_id = 0', + [] + )->joinLeft( + // calculate tier price specified as Website = `Specific Website` + //and Customer Group = `Specific Customer Group` + ['tier_price_2' => $this->getTable('catalog_product_entity_tier_price')], + 'tier_price_2.' . $linkField . ' = e.' . $linkField . ' AND tier_price_2.all_groups = 0 ' . + 'AND tier_price_2.customer_group_id = cg.customer_group_id AND tier_price_2.qty = 1' . + ' AND tier_price_2.website_id = pw.website_id', + [] + )->joinLeft( + // calculate tier price specified as Website = `All Websites` and Customer Group = `ALL GROUPS` + ['tier_price_3' => $this->getTable('catalog_product_entity_tier_price')], + 'tier_price_3.' . $linkField . ' = e.' . $linkField . ' AND tier_price_3.all_groups = 1 ' . + 'AND tier_price_3.customer_group_id = 0 AND tier_price_3.qty = 1 AND tier_price_3.website_id = 0', + [] + )->joinLeft( + // calculate tier price specified as Website = `Specific Website` and Customer Group = `ALL GROUPS` + ['tier_price_4' => $this->getTable('catalog_product_entity_tier_price')], + 'tier_price_4.' . $linkField . ' = e.' . $linkField . ' AND tier_price_4.all_groups = 1' . + ' AND tier_price_4.customer_group_id = 0 AND tier_price_4.qty = 1' . + ' AND tier_price_4.website_id = pw.website_id', + [] + ); + + foreach ($dimensions as $dimension) { + if (!isset($this->dimensionToFieldMapper[$dimension->getName()])) { + throw new \LogicException( + 'Provided dimension is not valid for Price indexer: ' . $dimension->getName() + ); + } + $select->where($this->dimensionToFieldMapper[$dimension->getName()] . ' = ?', $dimension->getValue()); + } + + if ($this->moduleManager->isEnabled('Magento_Tax')) { + $taxClassId = $this->joinAttributeProcessor->process($select, 'tax_class_id'); + } else { + $taxClassId = new \Zend_Db_Expr(0); + } + $select->columns(['tax_class_id' => $taxClassId]); + + $this->joinAttributeProcessor->process($select, 'status', Status::STATUS_ENABLED); + + $price = $this->joinAttributeProcessor->process($select, 'price'); + $specialPrice = $this->joinAttributeProcessor->process($select, 'special_price'); + $specialFrom = $this->joinAttributeProcessor->process($select, 'special_from_date'); + $specialTo = $this->joinAttributeProcessor->process($select, 'special_to_date'); + $currentDate = 'cwd.website_date'; + + $maxUnsignedBigint = '~0'; + $specialFromDate = $connection->getDatePartSql($specialFrom); + $specialToDate = $connection->getDatePartSql($specialTo); + $specialFromExpr = "{$specialFrom} IS NULL OR {$specialFromDate} <= {$currentDate}"; + $specialToExpr = "{$specialTo} IS NULL OR {$specialToDate} >= {$currentDate}"; + $specialPriceExpr = $connection->getCheckSql( + "{$specialPrice} IS NOT NULL AND {$specialFromExpr} AND {$specialToExpr}", + $specialPrice, + $maxUnsignedBigint + ); + $tierPrice = $this->getTotalTierPriceExpression($price); + $tierPriceExpr = $connection->getIfNullSql($tierPrice, $maxUnsignedBigint); + $finalPrice = $connection->getLeastSql([ + $price, + $specialPriceExpr, + $tierPriceExpr, + ]); + + $select->columns( + [ + //orig_price in catalog_product_index_price_final_tmp + 'price' => $connection->getIfNullSql($price, 0), + //price in catalog_product_index_price_final_tmp + 'final_price' => $connection->getIfNullSql($finalPrice, 0), + 'min_price' => $connection->getIfNullSql($finalPrice, 0), + 'max_price' => $connection->getIfNullSql($finalPrice, 0), + 'tier_price' => $tierPrice, + ] + ); + + $select->where("e.type_id = ?", $productType); + + if ($entityIds !== null) { + if (count($entityIds) > 1) { + $select->where(sprintf('e.entity_id BETWEEN %s AND %s', min($entityIds), max($entityIds))); + } else { + $select->where('e.entity_id = ?', $entityIds); + } + } + + /** + * throw event for backward compatibility + */ + $this->eventManager->dispatch( + 'prepare_catalog_product_index_select', + [ + 'select' => $select, + 'entity_field' => new ColumnValueExpression('e.entity_id'), + 'website_field' => new ColumnValueExpression('pw.website_id'), + 'store_field' => new ColumnValueExpression('cwd.default_store_id'), + ] + ); + + return $select; + } + + /** + * Get total tier price expression + * + * @param \Zend_Db_Expr $priceExpression + * @return \Zend_Db_Expr + */ + private function getTotalTierPriceExpression(\Zend_Db_Expr $priceExpression) + { + $maxUnsignedBigint = '~0'; + + return $this->getConnection()->getCheckSql( + implode( + ' AND ', + [ + 'tier_price_1.value_id is NULL', + 'tier_price_2.value_id is NULL', + 'tier_price_3.value_id is NULL', + 'tier_price_4.value_id is NULL' + ] + ), + 'NULL', + $this->getConnection()->getLeastSql([ + $this->getConnection()->getIfNullSql( + $this->getTierPriceExpressionForTable('tier_price_1', $priceExpression), + $maxUnsignedBigint + ), + $this->getConnection()->getIfNullSql( + $this->getTierPriceExpressionForTable('tier_price_2', $priceExpression), + $maxUnsignedBigint + ), + $this->getConnection()->getIfNullSql( + $this->getTierPriceExpressionForTable('tier_price_3', $priceExpression), + $maxUnsignedBigint + ), + $this->getConnection()->getIfNullSql( + $this->getTierPriceExpressionForTable('tier_price_4', $priceExpression), + $maxUnsignedBigint + ), + ]) + ); + } + + /** + * Get tier price expression for table + * + * @param $tableAlias + * @param \Zend_Db_Expr $priceExpression + * @return \Zend_Db_Expr + */ + private function getTierPriceExpressionForTable($tableAlias, \Zend_Db_Expr $priceExpression): \Zend_Db_Expr + { + return $this->getConnection()->getCheckSql( + sprintf('%s.value = 0', $tableAlias), + sprintf( + 'ROUND(%s * (1 - ROUND(%s.percentage_value * cwd.rate, 4) / 100), 4)', + $priceExpression, + $tableAlias + ), + sprintf('ROUND(%s.value * cwd.rate, 4)', $tableAlias) + ); + } + + /** + * Get connection + * + * return \Magento\Framework\DB\Adapter\AdapterInterface + * @throws \DomainException + */ + private function getConnection(): \Magento\Framework\DB\Adapter\AdapterInterface + { + if ($this->connection === null) { + $this->connection = $this->resource->getConnection($this->connectionName); + } + + return $this->connection; + } + + /** + * Get table + * + * @param string $tableName + * @return string + */ + private function getTable($tableName) + { + return $this->resource->getTableName($tableName, $this->connectionName); + } +} diff --git a/app/code/Magento/Catalog/Model/ResourceModel/Product/Indexer/Price/Query/JoinAttributeProcessor.php b/app/code/Magento/Catalog/Model/ResourceModel/Product/Indexer/Price/Query/JoinAttributeProcessor.php new file mode 100644 index 0000000000000..888e68a817081 --- /dev/null +++ b/app/code/Magento/Catalog/Model/ResourceModel/Product/Indexer/Price/Query/JoinAttributeProcessor.php @@ -0,0 +1,112 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +declare(strict_types=1); + +namespace Magento\Catalog\Model\ResourceModel\Product\Indexer\Price\Query; + +use Magento\Catalog\Api\Data\ProductInterface; +use Magento\Framework\DB\Select; +use Magento\Framework\DB\Sql\Expression; + +/** + * Allows to join product attribute to Select. Used for build price index for specified dimension + */ +class JoinAttributeProcessor +{ + /** + * @var \Magento\Eav\Model\Config + */ + private $eavConfig; + + /** + * @var \Magento\Framework\EntityManager\MetadataPool + */ + private $metadataPool; + + /** + * @var \Magento\Framework\App\ResourceConnection + */ + private $resource; + + /** + * @var string + */ + private $connectionName; + + /** + * @param \Magento\Eav\Model\Config $eavConfig + * @param \Magento\Framework\EntityManager\MetadataPool $metadataPool + * @param \Magento\Framework\App\ResourceConnection $resource + * @param string $connectionName + */ + public function __construct( + \Magento\Eav\Model\Config $eavConfig, + \Magento\Framework\EntityManager\MetadataPool $metadataPool, + \Magento\Framework\App\ResourceConnection $resource, + $connectionName = 'indexer' + ) { + $this->eavConfig = $eavConfig; + $this->metadataPool = $metadataPool; + $this->resource = $resource; + $this->connectionName = $connectionName; + } + + /** + * @param Select $select + * @param string $attributeCode + * @param string|null $attributeValue + * @return \Zend_Db_Expr + * @throws \Magento\Framework\Exception\LocalizedException + * @throws \Zend_Db_Select_Exception + */ + public function process(Select $select, $attributeCode, $attributeValue = null): \Zend_Db_Expr + { + $attribute = $this->eavConfig->getAttribute(\Magento\Catalog\Model\Product::ENTITY, $attributeCode); + $attributeId = $attribute->getAttributeId(); + $attributeTable = $attribute->getBackend()->getTable(); + $connection = $this->resource->getConnection($this->connectionName); + $joinType = $attributeValue !== null ? 'join' : 'joinLeft'; + $productIdField = $this->metadataPool->getMetadata(ProductInterface::class)->getLinkField(); + + if ($attribute->isScopeGlobal()) { + $alias = 'ta_' . $attributeCode; + $select->{$joinType}( + [$alias => $attributeTable], + "{$alias}.{$productIdField} = e.{$productIdField} AND {$alias}.attribute_id = {$attributeId}" . + " AND {$alias}.store_id = 0", + [] + ); + $whereExpression = new Expression("{$alias}.value"); + } else { + $dAlias = 'tad_' . $attributeCode; + $sAlias = 'tas_' . $attributeCode; + + $select->{$joinType}( + [$dAlias => $attributeTable], + "{$dAlias}.{$productIdField} = e.{$productIdField} AND {$dAlias}.attribute_id = {$attributeId}" . + " AND {$dAlias}.store_id = 0", + [] + ); + $select->joinLeft( + [$sAlias => $attributeTable], + "{$sAlias}.{$productIdField} = e.{$productIdField} AND {$sAlias}.attribute_id = {$attributeId}" . + " AND {$sAlias}.store_id = cwd.default_store_id", + [] + ); + $whereExpression = $connection->getCheckSql( + $connection->getIfNullSql("{$sAlias}.value_id", -1) . ' > 0', + "{$sAlias}.value", + "{$dAlias}.value" + ); + } + + if ($attributeValue !== null) { + $select->where("{$whereExpression} = ?", $attributeValue); + } + + return $whereExpression; + } +} diff --git a/app/code/Magento/Catalog/Model/ResourceModel/Product/Indexer/Price/SimpleProductPrice.php b/app/code/Magento/Catalog/Model/ResourceModel/Product/Indexer/Price/SimpleProductPrice.php new file mode 100644 index 0000000000000..5a055e5ed9603 --- /dev/null +++ b/app/code/Magento/Catalog/Model/ResourceModel/Product/Indexer/Price/SimpleProductPrice.php @@ -0,0 +1,89 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +declare(strict_types=1); +namespace Magento\Catalog\Model\ResourceModel\Product\Indexer\Price; + +use Magento\Catalog\Model\Indexer\Product\Price\TableMaintainer; +use Magento\Catalog\Model\ResourceModel\Product\Indexer\Price\Query\BaseFinalPrice; +use Magento\Framework\Indexer\DimensionalIndexerInterface; + +/** + * Simple Product Type Price Indexer + */ +class SimpleProductPrice implements DimensionalIndexerInterface +{ + /** + * @var BaseFinalPrice + */ + private $baseFinalPrice; + + /** + * @var IndexTableStructureFactory + */ + private $indexTableStructureFactory; + + /** + * @var TableMaintainer + */ + private $tableMaintainer; + + /** + * @var string + */ + private $productType; + + /** + * @var BasePriceModifier + */ + private $basePriceModifier; + + /** + * @param BaseFinalPrice $baseFinalPrice + * @param IndexTableStructureFactory $indexTableStructureFactory + * @param TableMaintainer $tableMaintainer + * @param BasePriceModifier $basePriceModifier + * @param string $productType + */ + public function __construct( + BaseFinalPrice $baseFinalPrice, + IndexTableStructureFactory $indexTableStructureFactory, + TableMaintainer $tableMaintainer, + BasePriceModifier $basePriceModifier, + $productType = \Magento\Catalog\Model\Product\Type::TYPE_SIMPLE + ) { + $this->baseFinalPrice = $baseFinalPrice; + $this->indexTableStructureFactory = $indexTableStructureFactory; + $this->tableMaintainer = $tableMaintainer; + $this->productType = $productType; + $this->basePriceModifier = $basePriceModifier; + } + + /** + * {@inheritdoc} + */ + public function executeByDimensions(array $dimensions, \Traversable $entityIds) + { + $this->tableMaintainer->createMainTmpTable($dimensions); + + $temporaryPriceTable = $this->indexTableStructureFactory->create([ + 'tableName' => $this->tableMaintainer->getMainTmpTable($dimensions), + 'entityField' => 'entity_id', + 'customerGroupField' => 'customer_group_id', + 'websiteField' => 'website_id', + 'taxClassField' => 'tax_class_id', + 'originalPriceField' => 'price', + 'finalPriceField' => 'final_price', + 'minPriceField' => 'min_price', + 'maxPriceField' => 'max_price', + 'tierPriceField' => 'tier_price', + ]); + $select = $this->baseFinalPrice->getQuery($dimensions, $this->productType, iterator_to_array($entityIds)); + $query = $select->insertFromSelect($temporaryPriceTable->getTableName(), [], false); + $this->tableMaintainer->getConnection()->query($query); + + $this->basePriceModifier->modifyPrice($temporaryPriceTable, iterator_to_array($entityIds)); + } +} diff --git a/app/code/Magento/Catalog/Model/ResourceModel/Product/Option/Value.php b/app/code/Magento/Catalog/Model/ResourceModel/Product/Option/Value.php index 4ebcd1f4b9ae4..ce0a9b6e461ce 100644 --- a/app/code/Magento/Catalog/Model/ResourceModel/Product/Option/Value.php +++ b/app/code/Magento/Catalog/Model/ResourceModel/Product/Option/Value.php @@ -256,7 +256,8 @@ protected function _saveValueTitles(AbstractModel $object) $object->unsetData('title'); } - if ($object->getTitle()) { + /*** Checking whether title is not null ***/ + if ($object->getTitle()!= null) { if ($existInCurrentStore) { if ($storeId == $object->getStoreId()) { $where = [ diff --git a/app/code/Magento/Catalog/Setup/Patch/Data/InstallDefaultPriceIndexerDimensionsMode.php b/app/code/Magento/Catalog/Setup/Patch/Data/InstallDefaultPriceIndexerDimensionsMode.php new file mode 100644 index 0000000000000..9cb417383255e --- /dev/null +++ b/app/code/Magento/Catalog/Setup/Patch/Data/InstallDefaultPriceIndexerDimensionsMode.php @@ -0,0 +1,79 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +declare(strict_types=1); + +namespace Magento\Catalog\Setup\Patch\Data; + +use Magento\Catalog\Model\Indexer\Product\Price\ModeSwitcher; +use Magento\Framework\Setup\ModuleDataSetupInterface; +use Magento\Framework\Setup\Patch\DataPatchInterface; +use Magento\Framework\Setup\Patch\PatchVersionInterface; +use Magento\Catalog\Model\Indexer\Product\Price\DimensionModeConfiguration; + +/** + * Class InstallDefaultCategories data patch. + * + * @package Magento\Catalog\Setup\Patch + */ +class InstallDefaultPriceIndexerDimensionsMode implements DataPatchInterface, PatchVersionInterface +{ + /** + * @var ModuleDataSetupInterface + */ + private $moduleDataSetup; + + /** + * PatchInitial constructor. + * @param ModuleDataSetupInterface $moduleDataSetup + */ + public function __construct( + ModuleDataSetupInterface $moduleDataSetup + ) { + $this->moduleDataSetup = $moduleDataSetup; + } + + /** + * {@inheritdoc} + */ + public function apply() + { + $configTable = $this->moduleDataSetup->getTable('core_config_data'); + + $this->moduleDataSetup->getConnection()->insert( + $configTable, + [ + 'scope' => 'default', + 'scope_id' => 0, + 'value' => DimensionModeConfiguration::DIMENSION_NONE, + 'path' => ModeSwitcher::XML_PATH_PRICE_DIMENSIONS_MODE + ] + ); + } + + /** + * {@inheritdoc} + */ + public static function getDependencies() + { + return []; + } + + /** + * {@inheritdoc} + */ + public function getAliases() + { + return []; + } + + /** + * {@inheritdoc} + */ + public static function getVersion() + { + return '2.2.6'; + } +} diff --git a/app/code/Magento/Catalog/Test/Mftf/ActionGroup/AdminProductGridActionGroup.xml b/app/code/Magento/Catalog/Test/Mftf/ActionGroup/AdminProductGridActionGroup.xml index 9d6af144b8f22..c2620bc5a3672 100644 --- a/app/code/Magento/Catalog/Test/Mftf/ActionGroup/AdminProductGridActionGroup.xml +++ b/app/code/Magento/Catalog/Test/Mftf/ActionGroup/AdminProductGridActionGroup.xml @@ -53,6 +53,18 @@ <waitForElementNotVisible selector="{{AdminProductGridSection.loadingMask}}" stepKey="waitForFilteredGridLoad" time="30"/> </actionGroup> + <!--Filter the product grid by the Name field--> + <actionGroup name="filterProductGridByName2"> + <arguments> + <argument name="name" type="string"/> + </arguments> + <conditionalClick selector="{{AdminProductGridFilterSection.clearFilters}}" dependentSelector="{{AdminProductGridFilterSection.clearFilters}}" visible="true" stepKey="clickClearFilters"/> + <click selector="{{AdminProductGridFilterSection.filters}}" stepKey="openProductFilters"/> + <fillField selector="{{AdminProductGridFilterSection.nameFilter}}" userInput="{{name}}" stepKey="fillProductNameFilter"/> + <click selector="{{AdminProductGridFilterSection.applyFilters}}" stepKey="clickApplyFilters"/> + <waitForElementNotVisible selector="{{AdminProductGridSection.loadingMask}}" stepKey="waitForFilteredGridLoad" time="30"/> + </actionGroup> + <!--Filter the product grid by new from date filter--> <actionGroup name="filterProductGridBySetNewFromDate"> <conditionalClick selector="{{AdminProductGridFilterSection.clearFilters}}" dependentSelector="{{AdminProductGridFilterSection.clearFilters}}" visible="true" stepKey="clickClearFilters"/> diff --git a/app/code/Magento/Catalog/Test/Mftf/ActionGroup/StorefrontProductPageActionGroup.xml b/app/code/Magento/Catalog/Test/Mftf/ActionGroup/StorefrontProductPageActionGroup.xml index d688a1dc2844e..d46b895044531 100644 --- a/app/code/Magento/Catalog/Test/Mftf/ActionGroup/StorefrontProductPageActionGroup.xml +++ b/app/code/Magento/Catalog/Test/Mftf/ActionGroup/StorefrontProductPageActionGroup.xml @@ -13,11 +13,8 @@ <argument name="productName"/> </arguments> <click selector="{{StorefrontProductActionSection.addToCart}}" stepKey="addToCart"/> - <waitForElementVisible selector="{{StorefrontProductActionSection.addToCartButtonTitleIsAdding}}" stepKey="waitForElementVisibleAddToCartButtonTitleIsAdding"/> <waitForElementNotVisible selector="{{StorefrontProductActionSection.addToCartButtonTitleIsAdding}}" stepKey="waitForElementNotVisibleAddToCartButtonTitleIsAdding"/> - <waitForElementVisible selector="{{StorefrontProductActionSection.addToCartButtonTitleIsAdded}}" stepKey="waitForElementVisibleAddToCartButtonTitleIsAdded"/> <waitForElementNotVisible selector="{{StorefrontProductActionSection.addToCartButtonTitleIsAdded}}" stepKey="waitForElementNotVisibleAddToCartButtonTitleIsAdded"/> - <waitForElementVisible selector="{{StorefrontProductActionSection.addToCartButtonTitleIsAddToCart}}" stepKey="waitForElementVisibleAddToCartButtonTitleIsAddToCart"/> <waitForPageLoad stepKey="waitForPageLoad"/> <see selector="{{StorefrontMessagesSection.success}}" userInput="You added {{productName}} to your shopping cart." stepKey="seeAddToCartSuccessMessage"/> </actionGroup> diff --git a/app/code/Magento/Catalog/Test/Mftf/Data/ProductData.xml b/app/code/Magento/Catalog/Test/Mftf/Data/ProductData.xml index 48313230ff1ca..0df091eb5f8ef 100644 --- a/app/code/Magento/Catalog/Test/Mftf/Data/ProductData.xml +++ b/app/code/Magento/Catalog/Test/Mftf/Data/ProductData.xml @@ -219,6 +219,32 @@ <requiredEntity type="product_extension_attribute">EavStockItem</requiredEntity> <requiredEntity type="custom_attribute_array">CustomAttributeCategoryIds</requiredEntity> </entity> + <entity name="productWithHTMLEntityOne" type="product"> + <data key="sku" unique="suffix">SimpleOne™Product</data> + <data key="type_id">simple</data> + <data key="attribute_set_id">4</data> + <data key="visibility">4</data> + <data key="name" unique="suffix">SimpleOne™Product</data> + <data key="price">50.00</data> + <data key="urlKey" unique="suffix">testurlkey</data> + <data key="status">1</data> + <data key="quantity">100</data> + <requiredEntity type="product_extension_attribute">EavStockItem</requiredEntity> + <requiredEntity type="custom_attribute_array">CustomAttributeCategoryIds</requiredEntity> + </entity> + <entity name="productWithHTMLEntityTwo" type="product"> + <data key="sku" unique="suffix">SimpleTwo霁产品<カネボウPro</data> + <data key="type_id">simple</data> + <data key="attribute_set_id">4</data> + <data key="visibility">4</data> + <data key="name" unique="suffix">SimpleTwo霁产品<カネボウPro</data> + <data key="price">50.00</data> + <data key="urlKey" unique="suffix">testurlkey</data> + <data key="status">1</data> + <data key="quantity">100</data> + <requiredEntity type="product_extension_attribute">EavStockItem</requiredEntity> + <requiredEntity type="custom_attribute_array">CustomAttributeCategoryIds</requiredEntity> + </entity> <entity name="defaultVirtualProduct" type="product"> <data key="sku" unique="suffix">virtualProduct</data> <data key="type_id">virtual</data> diff --git a/app/code/Magento/Catalog/Test/Mftf/Section/AdminCreateProductAttributeSection.xml b/app/code/Magento/Catalog/Test/Mftf/Section/AdminCreateProductAttributeSection.xml index e1eef15e9d476..377bc18d64764 100644 --- a/app/code/Magento/Catalog/Test/Mftf/Section/AdminCreateProductAttributeSection.xml +++ b/app/code/Magento/Catalog/Test/Mftf/Section/AdminCreateProductAttributeSection.xml @@ -14,8 +14,9 @@ <element name="ValueRequired" type="select" selector="#is_required"/> <element name="AdvancedProperties" type="button" selector="#advanced_fieldset-wrapper"/> <element name="DefaultValue" type="input" selector="#default_value_text"/> - <element name="Save" type="button" selector="#save"/> - <element name="SaveAndEdit" type="button" selector="#save_and_edit_button"/> + <element name="Scope" type="select" selector="#is_global"/> + <element name="Save" type="button" selector="#save" timeout="30"/> + <element name="SaveAndEdit" type="button" selector="#save_and_edit_button" timeout="30"/> <element name="TinyMCE4" type="button" selector="//span[text()='Default Value']/parent::label/following-sibling::div//div[@class='mce-branding-powered-by']"/> <element name="checkIfTabOpen" selector="//div[@id='advanced_fieldset-wrapper' and not(contains(@class,'opened'))]" type="button"/> </section> diff --git a/app/code/Magento/Catalog/Test/Mftf/Section/AdminProductAttributeGridSection.xml b/app/code/Magento/Catalog/Test/Mftf/Section/AdminProductAttributeGridSection.xml index 820e03a0f5e98..caf34a9f355a0 100644 --- a/app/code/Magento/Catalog/Test/Mftf/Section/AdminProductAttributeGridSection.xml +++ b/app/code/Magento/Catalog/Test/Mftf/Section/AdminProductAttributeGridSection.xml @@ -9,11 +9,12 @@ <sections xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../../../../../dev/tests/acceptance/vendor/magento/magento2-functional-testing-framework/src/Magento/FunctionalTestingFramework/Page/etc/SectionObject.xsd"> <section name="AdminProductAttributeGridSection"> - <element name="AttributeCode" type="text" selector="//td[contains(text(),'{{var1}}')]" parameterized="true"/> + <element name="AttributeCode" type="text" selector="//td[contains(text(),'{{var1}}')]" parameterized="true" timeout="30"/> <element name="createNewAttributeBtn" type="button" selector="button[data-index='add_new_attribute_button']"/> <element name="GridFilterFrontEndLabel" type="input" selector="#attributeGrid_filter_frontend_label"/> <element name="Search" type="button" selector="button[data-action=grid-filter-apply]" timeout="30"/> <element name="ResetFilter" type="button" selector="button[data-action='grid-filter-reset']" timeout="30"/> <element name="FirstRow" type="button" selector="//*[@id='attributeGrid_table']/tbody/tr[1]"/> + <element name="FilterByAttributeCode" type="input" selector="#attributeGrid_filter_attribute_code"/> </section> </sections> diff --git a/app/code/Magento/Catalog/Test/Mftf/Section/AdminProductCustomizableOptionsSection.xml b/app/code/Magento/Catalog/Test/Mftf/Section/AdminProductCustomizableOptionsSection.xml index d991580d58124..80ed5cb2d7e9d 100644 --- a/app/code/Magento/Catalog/Test/Mftf/Section/AdminProductCustomizableOptionsSection.xml +++ b/app/code/Magento/Catalog/Test/Mftf/Section/AdminProductCustomizableOptionsSection.xml @@ -14,18 +14,18 @@ <element name="useDefaultOptionTitle" type="text" selector="[data-index='options'] tr.data-row [data-index='title'] [name^='options_use_default']"/> <element name="useDefaultOptionTitleByIndex" type="text" selector="[data-index='options'] [data-index='values'] tr[data-repeat-index='{{var1}}'] [name^='options_use_default']" parameterized="true"/> <element name="addOptionBtn" type="button" selector="button[data-index='button_add']"/> - <element name="fillOptionTitle" type="input" selector="//span[text()='{{var1}}']/parent::div/parent::div/parent::div//span[text()='Option Title']/parent::label/parent::div//input[@class='admin__control-text']" parameterized="true"/> + <element name="fillOptionTitle" type="input" selector="//span[text()='{{var1}}']/parent::div/parent::div/parent::div//label[text()='Option Title']/parent::span/parent::div//input[@class='admin__control-text']" parameterized="true"/> <element name="optionTitleInput" type="input" selector="input[name='product[options][0][title]']"/> <element name="optionTypeOpenDropDown" type="button" selector=".admin__dynamic-rows[data-index='options'] .action-select"/> <element name="optionTypeTextField" type="button" selector=".admin__dynamic-rows[data-index='options'] .action-menu._active li li"/> <element name="maxCharactersInput" type="input" selector="input[name='product[options][0][max_characters]']"/> - <element name="checkSelect" type="select" selector="//span[text()='{{var1}}']/parent::div/parent::div/parent::div//span[text()='Option Type']/parent::label/parent::div//div[@data-role='selected-option']" parameterized="true"/> - <element name="checkDropDown" type="select" selector="//span[text()='{{var1}}']/parent::div/parent::div/parent::div//parent::label/parent::div//li[@class='admin__action-multiselect-menu-inner-item']//label[text()='Drop-down']" parameterized="true"/> + <element name="checkSelect" type="select" selector="//span[text()='{{var1}}']/parent::div/parent::div/parent::div//label[text()='Option Type']/parent::span/parent::div//div[@data-role='selected-option']" parameterized="true"/> + <element name="checkDropDown" type="select" selector="//span[text()='{{var1}}']/parent::div/parent::div/parent::div//parent::label/parent::span/parent::div//li[@class='admin__action-multiselect-menu-inner-item']//label[text()='Drop-down']" parameterized="true"/> <element name="clickAddValue" type="button" selector="//span[text()='{{var1}}']/parent::div/parent::div/parent::div//tfoot//button" parameterized="true"/> - <element name="fillOptionValueTitle" type="input" selector="//span[text()='{{var1}}']/parent::div/parent::div/parent::div//tbody/tr[@data-repeat-index='{{var2}}']//span[text()='Title']/parent::label/parent::div//div[@class='admin__field-control']/input" parameterized="true"/> + <element name="fillOptionValueTitle" type="input" selector="//span[text()='{{var1}}']/parent::div/parent::div/parent::div//tbody/tr[@data-repeat-index='{{var2}}']//label[text()='Title']/parent::span/parent::div//div[@class='admin__field-control']/input" parameterized="true"/> <element name="fillOptionValuePrice" type="input" selector="//span[text()='{{var1}}']/parent::div/parent::div/parent::div//tbody/tr[@data-repeat-index='{{var2}}']//span[text()='Price']/parent::label/parent::div//div[@class='admin__control-addon']/input" parameterized="true"/> - <element name="clickSelectPriceType" type="select" selector="//span[text()='{{var1}}']/parent::div/parent::div/parent::div//tbody//tr[@data-repeat-index='{{var2}}']//span[text()='Price Type']/parent::label/parent::div//select" parameterized="true"/> + <element name="clickSelectPriceType" type="select" selector="//span[text()='{{var1}}']/parent::div/parent::div/parent::div//tbody//tr[@data-repeat-index='{{var2}}']//label[text()='Price Type']/parent::span/parent::div//select" parameterized="true"/> <element name="checkboxUseDefaultTitle" type="checkbox" selector="//span[text()='Option Title']/parent::label/parent::div/div//input[@type='checkbox']"/> <element name="checkboxUseDefaultOption" type="checkbox" selector="//table[@data-index='values']//tbody//tr[@data-repeat-index='{{var1}}']//div[@class='admin__field-control']//input[@type='checkbox']" parameterized="true"/> diff --git a/app/code/Magento/Catalog/Test/Mftf/Section/AdminProductFormSection.xml b/app/code/Magento/Catalog/Test/Mftf/Section/AdminProductFormSection.xml index dd297bf301fa0..604eba61a05af 100644 --- a/app/code/Magento/Catalog/Test/Mftf/Section/AdminProductFormSection.xml +++ b/app/code/Magento/Catalog/Test/Mftf/Section/AdminProductFormSection.xml @@ -13,6 +13,8 @@ <element name="attributeSetFilterResult" type="input" selector="div[data-index='attribute_set_id'] .action-menu-item._last" timeout="30"/> <element name="productName" type="input" selector=".admin__field[data-index=name] input"/> <element name="productSku" type="input" selector=".admin__field[data-index=sku] input"/> + <element name="enableProductAttributeLabel" type="text" selector="//label[text()='Enable Product']"/> + <element name="enableProductAttributeLabelWrapper" type="text" selector="//label[text()='Enable Product']/parent::span"/> <element name="productStatus" type="checkbox" selector="input[name='product[status]']"/> <element name="enableProductLabel" type="checkbox" selector="input[name='product[status]']+label"/> <element name="productStatusUseDefault" type="checkbox" selector="input[name='use_default[status]']"/> @@ -39,11 +41,10 @@ <element name="visibility" type="select" selector="//select[@name='product[visibility]']"/> <element name="visibilityUseDefault" type="checkbox" selector="//input[@name='use_default[visibility]']"/> <element name="divByDataIndex" type="input" selector="div[data-index='{{var}}']" parameterized="true"/> - <element name="attributeLabelByText" type="text" selector="//*[@class='admin__field']//span[text()='{{attributeLabel}}']" parameterized="true"/> + <element name="attributeLabelByText" type="text" selector="//*[@class='admin__field']//label[text()='{{attributeLabel}}']" parameterized="true"/> </section> <section name="ProductInWebsitesSection"> <element name="sectionHeader" type="button" selector="div[data-index='websites']" timeout="30"/> - <!--<element name="websites" type="checkbox" selector="input[name='product[website_ids][{{var1}}]']" parameterized="true"/>--> <element name="website" type="checkbox" selector="//label[contains(text(), '{{var1}}')]/parent::div//input[@type='checkbox']" parameterized="true"/> </section> <section name="ProductDesignSection"> @@ -58,7 +59,7 @@ </section> <section name="ProductWYSIWYGSection"> <element name="Switcher" type="button" selector="//select[@id='dropdown-switcher']"/> - <element name="v4" type ="button" selector="//select[@id='dropdown-switcher']/option[text()='TinyMCE 4.3.6']" /> + <element name="v436" type ="button" selector="//select[@id='dropdown-switcher']/option[text()='TinyMCE 4.3.6']" /> <element name="v3" type ="button" selector="//select[@id='dropdown-switcher']/option[text()='TinyMCE 3.6(Deprecated)']" /> <element name="TinymceDescription3" type ="button" selector="//span[text()='Description']" /> <element name="SaveConfig" type ="button" selector="#save" /> diff --git a/app/code/Magento/Catalog/Test/Mftf/Section/StorefrontProductPageSection.xml b/app/code/Magento/Catalog/Test/Mftf/Section/StorefrontProductPageSection.xml index acda5c40af8a3..2de616819b2f7 100644 --- a/app/code/Magento/Catalog/Test/Mftf/Section/StorefrontProductPageSection.xml +++ b/app/code/Magento/Catalog/Test/Mftf/Section/StorefrontProductPageSection.xml @@ -12,6 +12,7 @@ <element name="qtyInput" type="button" selector="input.input-text.qty"/> <element name="addToCartBtn" type="button" selector="button.action.tocart.primary" timeout="30"/> <element name="successMsg" type="button" selector="div.message-success"/> + <element name="errorMsg" type="button" selector="div.message-error"/> <element name="alertMessage" type="text" selector=".page.messages [role=alert]"/> <element name="messagesBlock" type="text" selector=".page.messages"/> <element name="addToWishlist" type="button" selector="//a[@class='action towishlist']" timeout="30"/> diff --git a/app/code/Magento/Catalog/Test/Mftf/Test/AdminRemoveDefaultImageSimpleProductTest.xml b/app/code/Magento/Catalog/Test/Mftf/Test/AdminRemoveDefaultImageSimpleProductTest.xml index f20e6caf637d4..4a3b370c7da08 100644 --- a/app/code/Magento/Catalog/Test/Mftf/Test/AdminRemoveDefaultImageSimpleProductTest.xml +++ b/app/code/Magento/Catalog/Test/Mftf/Test/AdminRemoveDefaultImageSimpleProductTest.xml @@ -46,9 +46,7 @@ <!-- Remove image from product --> <actionGroup ref="removeProductImage" stepKey="removeProductImage"/> - <!-- Skip success message check when saving product because of bug MAGETWO-91177 --> - <!-- actionGroup ref="saveProductForm" stepKey="saveProductFormAfterRemove"/--> - <click selector="{{AdminProductFormActionSection.saveButton}}" stepKey="saveProductFormAfterRemove"/> + <actionGroup ref="saveProductForm" stepKey="saveProductFormAfterRemove"/> <!-- Assert product image not in admin product form --> <actionGroup ref="assertProductImageNotInAdminProductPage" stepKey="assertProductImageNotInAdminProductPage"/> diff --git a/app/code/Magento/Catalog/Test/Mftf/Test/AdminRemoveDefaultImageVirtualProductTest.xml b/app/code/Magento/Catalog/Test/Mftf/Test/AdminRemoveDefaultImageVirtualProductTest.xml index 86cc16e141e0a..e249c8e8ceabc 100644 --- a/app/code/Magento/Catalog/Test/Mftf/Test/AdminRemoveDefaultImageVirtualProductTest.xml +++ b/app/code/Magento/Catalog/Test/Mftf/Test/AdminRemoveDefaultImageVirtualProductTest.xml @@ -46,9 +46,7 @@ <!-- Remove image from product --> <actionGroup ref="removeProductImage" stepKey="removeProductImage"/> - <!-- Skip success message check when saving product because of bug MAGETWO-91177 --> - <!-- actionGroup ref="saveProductForm" stepKey="saveProductFormAfterRemove"/--> - <click selector="{{AdminProductFormActionSection.saveButton}}" stepKey="saveProductFormAfterRemove"/> + <actionGroup ref="saveProductForm" stepKey="saveProductFormAfterRemove"/> <!-- Assert product image not in admin product form --> <actionGroup ref="assertProductImageNotInAdminProductPage" stepKey="assertProductImageNotInAdminProductPage"/> diff --git a/app/code/Magento/Catalog/Test/Mftf/Test/AdminSimpleProductEditUiTest.xml b/app/code/Magento/Catalog/Test/Mftf/Test/AdminSimpleProductEditUiTest.xml new file mode 100644 index 0000000000000..2b9733fd2fa5c --- /dev/null +++ b/app/code/Magento/Catalog/Test/Mftf/Test/AdminSimpleProductEditUiTest.xml @@ -0,0 +1,46 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> + +<tests xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="../../../../../../vendor/magento/magento2-functional-testing-framework/src/Magento/FunctionalTestingFramework/Test/etc/testSchema.xsd"> + <test name="AdminSimpleProductUiValidationTest"> + <annotations> + <title value="UI elements on the simple product edit screen should be organized as expected"/> + <description value="Admin should be able to use simple product UI in expected manner"/> + <testCaseId value="MAGETWO-92835"/> + <group value="Catalog"/> + </annotations> + + <before> + <!-- This was copied and modified from the EndToEndB2CGuestUserTest --> + <createData entity="ApiCategory" stepKey="createCategory"/> + <createData entity="_defaultProduct" stepKey="createSimpleProduct"> + <requiredEntity createDataKey="createCategory"/> + </createData> + </before> + + <after> + <deleteData createDataKey="createSimpleProduct" stepKey="deleteSimpleProduct"/> + <deleteData createDataKey="createCategory" stepKey="deleteCategory"/> + </after> + + <!--check admin for valid Enable Status label--> + <actionGroup ref="LoginAsAdmin" stepKey="loginAsAdmin"/> + <amOnPage url="{{AdminProductEditPage.url($$createSimpleProduct.id$$)}}" stepKey="goToEditPage"/> + <waitForPageLoad stepKey="wait1"/> + <seeCheckboxIsChecked selector="{{AdminProductFormSection.productStatus}}" stepKey="seeCheckboxEnableProductIsChecked"/> + + <!--check click on wrapping container does not trigger status change--> + <click selector="{{AdminProductFormSection.enableProductAttributeLabelWrapper}}" stepKey="clickEnableProductWrapper"/> + <seeCheckboxIsChecked selector="{{AdminProductFormSection.productStatus}}" stepKey="seeCheckboxEnableProductIsCheckedAfterWrapperClick"/> + + <!--check click on label itself does trigger status change--> + <click selector="{{AdminProductFormSection.enableProductAttributeLabel}}" stepKey="clickEnableProductLabel"/> + <dontSeeCheckboxIsChecked selector="{{AdminProductFormSection.productStatus}}" stepKey="dontSeeCheckboxEnableProductIsCheckedAfterLabelClick"/> + </test> +</tests> \ No newline at end of file diff --git a/app/code/Magento/Catalog/Test/Mftf/Test/AdminUnassignProductAttributeFromAttributeSetTest.xml b/app/code/Magento/Catalog/Test/Mftf/Test/AdminUnassignProductAttributeFromAttributeSetTest.xml index 1441e2175d08e..5a07b11a204af 100644 --- a/app/code/Magento/Catalog/Test/Mftf/Test/AdminUnassignProductAttributeFromAttributeSetTest.xml +++ b/app/code/Magento/Catalog/Test/Mftf/Test/AdminUnassignProductAttributeFromAttributeSetTest.xml @@ -17,8 +17,9 @@ <severity value="CRITICAL"/> <testCaseId value="MC-194"/> <group value="Catalog"/> - <!-- Skip because of MAGETWO-92780 --> - <group value="skip"/> + <skip> + <issueId value="MAGETWO-92780"/> + </skip> </annotations> <before> <createData entity="productDropDownAttribute" stepKey="attribute"/> diff --git a/app/code/Magento/Catalog/Test/Mftf/Test/EndToEndB2CAdminTest.xml b/app/code/Magento/Catalog/Test/Mftf/Test/EndToEndB2CAdminTest.xml index a9829b67189cb..d5d9de2648ecf 100644 --- a/app/code/Magento/Catalog/Test/Mftf/Test/EndToEndB2CAdminTest.xml +++ b/app/code/Magento/Catalog/Test/Mftf/Test/EndToEndB2CAdminTest.xml @@ -16,8 +16,9 @@ <description value="Admin creates products, creates and manages categories, creates promotions, creates an order, processes an order, processes a return, uses admin grids"/> <severity value="CRITICAL"/> <testCaseId value="MAGETWO-87014"/> - <!-- Skipped, see: https://jira.corp.magento.com/browse/MQE-891 --> - <group value="skip"/> + <skip> + <issueId value="MQE-891"/> + </skip> </annotations> <after> <actionGroup ref="logout" stepKey="logoutOfAdmin"/> diff --git a/app/code/Magento/Catalog/Test/Mftf/Test/SaveProductWithCustomOptionsSecondWebsiteTest.xml b/app/code/Magento/Catalog/Test/Mftf/Test/SaveProductWithCustomOptionsSecondWebsiteTest.xml index 23d9a2a9e4cd0..26f6eb7910fa2 100644 --- a/app/code/Magento/Catalog/Test/Mftf/Test/SaveProductWithCustomOptionsSecondWebsiteTest.xml +++ b/app/code/Magento/Catalog/Test/Mftf/Test/SaveProductWithCustomOptionsSecondWebsiteTest.xml @@ -18,6 +18,7 @@ <testCaseId value="MAGETWO-91436"/> <group value="product"/> </annotations> + <before> <actionGroup ref="LoginAsAdmin" stepKey="loginAsAdmin"/> <!--Create new website --> <actionGroup ref="AdminCreateWebsiteActionGroup" stepKey="createAdditionalWebsite"> @@ -34,7 +35,7 @@ <!--Create Store view --> <amOnPage url="{{AdminSystemStorePage.url}}" stepKey="amOnAdminSystemStorePage"/> - <waitForElementVisible selector="{{AdminStoresMainActionsSection.createStoreViewButton}}" stepKey="waitForStoreViewBtn"/> + <waitForPageLoad stepKey="waitForAdminSystemStorePage"/> <click selector="{{AdminStoresMainActionsSection.createStoreViewButton}}" stepKey="createStoreViewButton"/> <waitForPageLoad stepKey="waitForProductPageLoad"/> <selectOption userInput="Second Store" selector="{{AdminNewStoreSection.storeGrpDropdown}}" stepKey="selectStoreGroup"/> @@ -46,7 +47,7 @@ <conditionalClick selector="{{AdminNewStoreSection.acceptNewStoreViewCreation}}" dependentSelector="{{AdminNewStoreSection.acceptNewStoreViewCreation}}" visible="true" stepKey="AcceptNewStoreViewCreation"/> <waitForElementVisible selector="{{AdminStoresGridSection.storeFilterTextField}}" stepKey="waitForPageReolad"/> <see userInput="You saved the store view." stepKey="seeSaveMessage" /> - + </before> <after> <actionGroup ref="ResetWebUrlOptions" stepKey="resetUrlOption"/> <actionGroup ref="AdminDeleteWebsiteActionGroup" stepKey="deleteTestWebsite"> @@ -58,6 +59,7 @@ <actionGroup ref="EnableWebUrlOptions" stepKey="addStoreCodeToUrls"/> <!--Create a Simple Product with Custom Options --> <amOnPage url="{{AdminProductIndexPage.url}}" stepKey="navigateToCatalogProductGrid"/> + <waitForPageLoad stepKey="waitForCatalogProductGrid"/> <click selector="{{AdminProductGridActionSection.addProductToggle}}" stepKey="clickAddProductDropdown"/> <click selector="{{AdminProductGridActionSection.addSimpleProduct}}" stepKey="clickAddSimpleProduct"/> <fillField userInput="{{_defaultProduct.name}}" selector="{{AdminProductFormSection.productName}}" stepKey="fillName"/> @@ -65,8 +67,7 @@ <fillField userInput="{{_defaultProduct.price}}" selector="{{AdminProductFormSection.productPrice}}" stepKey="fillPrice"/> <fillField userInput="{{_defaultProduct.quantity}}" selector="{{AdminProductFormSection.productQuantity}}" stepKey="fillQuantity"/> - <!--<click selector="{{AdminProductCustomizableOptionsSection.customizableOptions}}" stepKey="openCustomOptionsSection"/>--> - <conditionalClick selector="{{AdminProductCustomizableOptionsSection.customizableOptions}}" dependentSelector="{{AdminProductCustomizableOptionsSection.checkIfCustomizableOptionsTabOpen}}" visible="true" stepKey="clickIfContentTabCloses2"/> + <conditionalClick selector="{{AdminProductCustomizableOptionsSection.customizableOptions}}" dependentSelector="{{AdminProductCustomizableOptionsSection.checkIfCustomizableOptionsTabOpen}}" visible="true" stepKey="clickIfContentTabCloses2"/> <click selector="{{AdminProductCustomizableOptionsSection.addOptionBtn}}" stepKey="clickAddOption"/> <waitForPageLoad stepKey="waitAfterAddOption"/> <fillField selector="input[name='product[options][0][title]']" userInput="Radio Option" stepKey="fillOptionTitle"/> diff --git a/app/code/Magento/Catalog/Test/Mftf/Test/StorefrontProductNameWithDoubleQuote.xml b/app/code/Magento/Catalog/Test/Mftf/Test/StorefrontProductNameWithDoubleQuote.xml index 956677c8b5de5..05964c5cce264 100644 --- a/app/code/Magento/Catalog/Test/Mftf/Test/StorefrontProductNameWithDoubleQuote.xml +++ b/app/code/Magento/Catalog/Test/Mftf/Test/StorefrontProductNameWithDoubleQuote.xml @@ -15,6 +15,8 @@ <severity value="CRITICAL"/> <group value="product"/> <testCaseId value="MAGETWO-92384"/> + <!-- Skipped due to MAGETWO-93261 --> + <group value="skip"/> </annotations> <before> <createData entity="_defaultCategory" stepKey="createCategory"/> @@ -60,4 +62,62 @@ <argument name="product" value="SimpleProductNameWithDoubleQuote"/> </actionGroup> </test> + + <test name="StorefrontProductNameWithHTMLEntities"> + <annotations> + <features value="Catalog"/> + <title value=":Proudct with html special characters in name"/> + <description value="Product with html entities in the name should appear correctly on the PDP breadcrumbs on storefront"/> + <severity value="CRITICAL"/> + <group value="product"/> + <testCaseId value="MAGETWO-93794"/> + </annotations> + <before> + <createData entity="_defaultCategory" stepKey="createCategoryOne"/> + <createData entity="productWithHTMLEntityOne" stepKey="productOne"> + <requiredEntity createDataKey="createCategoryOne"/> + </createData> + <createData entity="productWithHTMLEntityTwo" stepKey="productTwo"> + <requiredEntity createDataKey="createCategoryOne"/> + </createData> + </before> + <after> + <deleteData createDataKey="productOne" stepKey="deleteProductOne"/> + <deleteData createDataKey="productTwo" stepKey="deleteProductTwo"/> + <deleteData createDataKey="createCategoryOne" stepKey="deleteCategory"/> + </after> + + <!--Check product in category listing--> + <amOnPage url="{{StorefrontCategoryPage.url($$createCategoryOne.name$$)}}" stepKey="navigateToCategoryPage"/> + <waitForPageLoad stepKey="waitforCategoryPageToLoad"/> + <see selector="{{StorefrontCategoryProductSection.ProductTitleByName(productWithHTMLEntityOne.name)}}" userInput="{{productWithHTMLEntityOne.name}}" stepKey="seeCorrectNameProd1CategoryPage"/> + <see selector="{{StorefrontCategoryProductSection.ProductTitleByName(productWithHTMLEntityTwo.name)}}" userInput="{{productWithHTMLEntityTwo.name}}" stepKey="seeCorrectNameProd2CategoryPage"/> + + <!--Open product display page--> + <click selector="{{StorefrontCategoryProductSection.ProductTitleByName(productWithHTMLEntityOne.name)}}" stepKey="clickProductToGoProductPage"/> + <waitForPageLoad stepKey="waitForProductDisplayPageLoad2"/> + + <see selector="{{StorefrontProductInfoMainSection.productName}}" userInput="{{productWithHTMLEntityOne.name}}" stepKey="seeCorrectName"/> + <see selector="{{StorefrontProductInfoMainSection.productSku}}" userInput="{{productWithHTMLEntityOne.sku}}" stepKey="seeCorrectSku"/> + <see selector="{{StorefrontProductInfoMainSection.productPrice}}" userInput="${{productWithHTMLEntityOne.price}}" stepKey="seeCorrectPrice"/> + + <!--Veriy the breadcrumbs on Product Display page--> + <see selector="{{StorefrontNavigationSection.breadcrumbs}}" userInput="Home" stepKey="seeHomePageInBreadcrumbs1"/> + <see selector="{{StorefrontNavigationSection.breadcrumbs}}" userInput="$$createCategoryOne.name$$" stepKey="seeCorrectBreadCrumbCategory"/> + <see selector="{{StorefrontNavigationSection.breadcrumbs}}" userInput="$$productOne.name$$" stepKey="seeCorrectBreadCrumbProduct"/> + + <click selector="{{StorefrontNavigationSection.topCategory($$createCategoryOne.name$$)}}" stepKey="goBackToCategoryPage"/> + <waitForPageLoad stepKey="waitforCategoryPageToLoad2"/> + + <!--Open product display page--> + <click selector="{{StorefrontCategoryProductSection.ProductTitleByNumber('1')}}" stepKey="goToProduct2DisplayPage"/> + <!--<click selector="{{StorefrontCategoryProductSection.ProductTitleByName(productWithHTMLEntityOne.name)}}" stepKey="clickProductToGoProductPage"/>--> + <waitForPageLoad stepKey="waitForProductDisplayPageLoad3"/> + + <!--Veriy the breadcrumbs on Product Display page--> + <see selector="{{StorefrontNavigationSection.breadcrumbs}}" userInput="Home" stepKey="seeHomePageInBreadcrumbs2"/> + <see selector="{{StorefrontNavigationSection.breadcrumbs}}" userInput="$$createCategoryOne.name$$" stepKey="seeCorrectBreadCrumbCategory2"/> + <see selector="{{StorefrontNavigationSection.breadcrumbs}}" userInput="$$productTwo.name$$" stepKey="seeCorrectBreadCrumbProduct2"/> + + </test> </tests> diff --git a/app/code/Magento/Catalog/Test/Mftf/Test/StorefrontPurchaseProductWithCustomOptions.xml b/app/code/Magento/Catalog/Test/Mftf/Test/StorefrontPurchaseProductWithCustomOptions.xml index 3a7feb34354d7..6e43753220d7c 100644 --- a/app/code/Magento/Catalog/Test/Mftf/Test/StorefrontPurchaseProductWithCustomOptions.xml +++ b/app/code/Magento/Catalog/Test/Mftf/Test/StorefrontPurchaseProductWithCustomOptions.xml @@ -16,8 +16,7 @@ <description value="Admin should be able to sell products with different variants of their own"/> <severity value="CRITICAL"/> <testCaseId value="MAGETWO-61717"/> - <!--Skip because of issue MAGETWO-90719--> - <group value="skip"/> + <group value="Catalog"/> </annotations> <before> <createData entity="Simple_US_Customer" stepKey="createCustomer"/> diff --git a/app/code/Magento/Catalog/Test/Mftf/composer.json b/app/code/Magento/Catalog/Test/Mftf/composer.json deleted file mode 100644 index 501fc0fa6c8db..0000000000000 --- a/app/code/Magento/Catalog/Test/Mftf/composer.json +++ /dev/null @@ -1,44 +0,0 @@ -{ - "name": "magento/functional-test-module-catalog", - "description": "N/A", - "config": { - "sort-packages": true - }, - "require": { - "php": "~7.1.3||~7.2.0", - "magento/magento2-functional-testing-framework": "2.2.0", - "magento/functional-test-module-backend": "100.0.0-dev", - "magento/functional-test-module-catalog-inventory": "100.0.0-dev", - "magento/functional-test-module-catalog-rule": "100.0.0-dev", - "magento/functional-test-module-catalog-url-rewrite": "100.0.0-dev", - "magento/functional-test-module-checkout": "100.0.0-dev", - "magento/functional-test-module-cms": "100.0.0-dev", - "magento/functional-test-module-config": "100.0.0-dev", - "magento/functional-test-module-customer": "100.0.0-dev", - "magento/functional-test-module-directory": "100.0.0-dev", - "magento/functional-test-module-eav": "100.0.0-dev", - "magento/functional-test-module-indexer": "100.0.0-dev", - "magento/functional-test-module-media-storage": "100.0.0-dev", - "magento/functional-test-module-msrp": "100.0.0-dev", - "magento/functional-test-module-page-cache": "100.0.0-dev", - "magento/functional-test-module-product-alert": "100.0.0-dev", - "magento/functional-test-module-quote": "100.0.0-dev", - "magento/functional-test-module-store": "100.0.0-dev", - "magento/functional-test-module-tax": "100.0.0-dev", - "magento/functional-test-module-theme": "100.0.0-dev", - "magento/functional-test-module-ui": "100.0.0-dev", - "magento/functional-test-module-url-rewrite": "100.0.0-dev", - "magento/functional-test-module-widget": "100.0.0-dev", - "magento/functional-test-module-wishlist": "100.0.0-dev" - }, - "suggest": { - "magento/functional-test-module-cookie": "100.0.0-dev", - "magento/functional-test-module-sales": "100.0.0-dev", - "magento/functional-test-module-catalog-sample-data": "100.0.0-dev" - }, - "type": "magento2-test", - "license": [ - "OSL-3.0", - "AFL-3.0" - ] -} diff --git a/app/code/Magento/Catalog/Test/Unit/Controller/Adminhtml/Category/SaveTest.php b/app/code/Magento/Catalog/Test/Unit/Controller/Adminhtml/Category/SaveTest.php index f6a586950afdc..53f7fa0ed7e63 100644 --- a/app/code/Magento/Catalog/Test/Unit/Controller/Adminhtml/Category/SaveTest.php +++ b/app/code/Magento/Catalog/Test/Unit/Controller/Adminhtml/Category/SaveTest.php @@ -5,8 +5,6 @@ */ namespace Magento\Catalog\Test\Unit\Controller\Adminhtml\Category; -use Magento\Catalog\Controller\Adminhtml\Category\Save as Model; - /** * Class SaveTest * @SuppressWarnings(PHPMD.CouplingBetweenObjects) @@ -463,9 +461,25 @@ public function dataProviderExecute() */ public function imagePreprocessingDataProvider() { + $dataWithImage = [ + 'image' => 'path.jpg', + 'name' => 'category', + 'description' => '', + 'parent' => 0 + ]; + $expectedSameAsDataWithImage = $dataWithImage; + + $dataWithoutImage = [ + 'name' => 'category', + 'description' => '', + 'parent' => 0 + ]; + $expectedIfDataWithoutImage = $dataWithoutImage; + $expectedIfDataWithoutImage['image'] = ''; + return [ - [['attribute1' => null, 'attribute2' => 123]], - [['attribute2' => 123]] + 'categoryPostData contains image' => [$dataWithImage, $expectedSameAsDataWithImage], + 'categoryPostData doesn\'t contain image' => [$dataWithoutImage, $expectedIfDataWithoutImage], ]; } @@ -473,8 +487,9 @@ public function imagePreprocessingDataProvider() * @dataProvider imagePreprocessingDataProvider * * @param array $data + * @param array $expected */ - public function testImagePreprocessingWithoutValue($data) + public function testImagePreprocessing($data, $expected) { $eavConfig = $this->createPartialMock(\Magento\Eav\Model\Config::class, ['getEntityType']); @@ -484,49 +499,17 @@ public function testImagePreprocessingWithoutValue($data) $collection = new \Magento\Framework\DataObject(['attribute_collection' => [ new \Magento\Framework\DataObject([ - 'attribute_code' => 'attribute1', + 'attribute_code' => 'image', 'backend' => $imageBackendModel ]), new \Magento\Framework\DataObject([ - 'attribute_code' => 'attribute2', + 'attribute_code' => 'name', 'backend' => new \Magento\Framework\DataObject() - ]) - ]]); - - $eavConfig->expects($this->once()) - ->method('getEntityType') - ->with(\Magento\Catalog\Api\Data\CategoryAttributeInterface::ENTITY_TYPE_CODE) - ->will($this->returnValue($collection)); - - $model = $this->objectManager->getObject(\Magento\Catalog\Controller\Adminhtml\Category\Save::class, [ - 'eavConfig' => $eavConfig - ]); - - $result = $model->imagePreprocessing($data); - - $this->assertEquals([ - 'attribute1' => false, - 'attribute2' => 123 - ], $result); - } - - public function testImagePreprocessingWithValue() - { - $eavConfig = $this->createPartialMock(\Magento\Eav\Model\Config::class, ['getEntityType']); - - $imageBackendModel = $this->objectManager->getObject( - \Magento\Catalog\Model\Category\Attribute\Backend\Image::class - ); - - $collection = new \Magento\Framework\DataObject(['attribute_collection' => [ - new \Magento\Framework\DataObject([ - 'attribute_code' => 'attribute1', - 'backend' => $imageBackendModel ]), new \Magento\Framework\DataObject([ - 'attribute_code' => 'attribute2', + 'attribute_code' => 'level', 'backend' => new \Magento\Framework\DataObject() - ]) + ]), ]]); $eavConfig->expects($this->once()) @@ -534,18 +517,12 @@ public function testImagePreprocessingWithValue() ->with(\Magento\Catalog\Api\Data\CategoryAttributeInterface::ENTITY_TYPE_CODE) ->will($this->returnValue($collection)); - $model = $this->objectManager->getObject(Model::class, [ + $model = $this->objectManager->getObject(\Magento\Catalog\Controller\Adminhtml\Category\Save::class, [ 'eavConfig' => $eavConfig ]); - $result = $model->imagePreprocessing([ - 'attribute1' => 'somevalue', - 'attribute2' => null - ]); + $result = $model->imagePreprocessing($data); - $this->assertEquals([ - 'attribute1' => 'somevalue', - 'attribute2' => null - ], $result); + $this->assertEquals($expected, $result); } } diff --git a/app/code/Magento/Catalog/Test/Unit/Controller/Adminhtml/Product/Initialization/HelperTest.php b/app/code/Magento/Catalog/Test/Unit/Controller/Adminhtml/Product/Initialization/HelperTest.php index dce3f5886d1a8..ff44a91a64998 100644 --- a/app/code/Magento/Catalog/Test/Unit/Controller/Adminhtml/Product/Initialization/HelperTest.php +++ b/app/code/Magento/Catalog/Test/Unit/Controller/Adminhtml/Product/Initialization/HelperTest.php @@ -95,6 +95,9 @@ class HelperTest extends \PHPUnit\Framework\TestCase */ protected $attributeFilterMock; + /** + * @inheritdoc + */ protected function setUp() { $this->objectManager = new ObjectManager($this); @@ -198,10 +201,12 @@ public function testInitialize( 'option2' => ['is_delete' => false, 'name' => 'name1', 'price' => 'price1', 'option_id' => '13'], 'option3' => ['is_delete' => false, 'name' => 'name1', 'price' => 'price1', 'option_id' => '14'] ]; + $specialFromDate = '2018-03-03 19:30:00'; $productData = [ 'stock_data' => ['stock_data'], 'options' => $optionsData, - 'website_ids' => $websiteIds + 'website_ids' => $websiteIds, + 'special_from_date' => $specialFromDate, ]; if (!empty($tierPrice)) { $productData = array_merge($productData, ['tier_price' => $tierPrice]); @@ -306,6 +311,7 @@ public function testInitialize( } $this->assertEquals($expectedLinks, $resultLinks); + $this->assertEquals($specialFromDate, $productData['special_from_date']); } /** diff --git a/app/code/Magento/Catalog/Test/Unit/Cron/DeleteAbandonedStoreFlatTablesTest.php b/app/code/Magento/Catalog/Test/Unit/Cron/DeleteAbandonedStoreFlatTablesTest.php new file mode 100644 index 0000000000000..1a9d7959dda9c --- /dev/null +++ b/app/code/Magento/Catalog/Test/Unit/Cron/DeleteAbandonedStoreFlatTablesTest.php @@ -0,0 +1,51 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +declare(strict_types=1); + +namespace Magento\Catalog\Test\Unit\Cron; + +use Magento\Catalog\Cron\DeleteAbandonedStoreFlatTables; +use Magento\Catalog\Helper\Product\Flat\Indexer; + +/** + * @covers \Magento\Catalog\Cron\DeleteAbandonedStoreFlatTables + */ +class DeleteAbandonedStoreFlatTablesTest extends \PHPUnit\Framework\TestCase +{ + /** + * Testable Object + * + * @var DeleteAbandonedStoreFlatTables + */ + private $deleteAbandonedStoreFlatTables; + + /** + * @var Indexer|\PHPUnit_Framework_MockObject_MockObject + */ + private $indexerMock; + + /** + * Set Up + * + * @return void + */ + protected function setUp() + { + $this->indexerMock = $this->createMock(Indexer::class); + $this->deleteAbandonedStoreFlatTables = new DeleteAbandonedStoreFlatTables($this->indexerMock); + } + + /** + * Test execute method + * + * @return void + */ + public function testExecute() + { + $this->indexerMock->expects($this->once())->method('deleteAbandonedStoreFlatTables'); + $this->deleteAbandonedStoreFlatTables->execute(); + } +} diff --git a/app/code/Magento/Catalog/Test/Unit/Cron/DeleteOutdatedPriceValuesTest.php b/app/code/Magento/Catalog/Test/Unit/Cron/DeleteOutdatedPriceValuesTest.php new file mode 100644 index 0000000000000..f1d0034c29580 --- /dev/null +++ b/app/code/Magento/Catalog/Test/Unit/Cron/DeleteOutdatedPriceValuesTest.php @@ -0,0 +1,139 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +declare(strict_types=1); + +namespace Magento\Catalog\Test\Unit\Cron; + +use Magento\Catalog\Api\Data\ProductAttributeInterface; +use Magento\Catalog\Cron\DeleteOutdatedPriceValues; +use Magento\Eav\Api\AttributeRepositoryInterface as AttributeRepository; +use Magento\Eav\Model\Entity\Attribute; +use Magento\Eav\Model\Entity\Attribute\Backend\BackendInterface; +use Magento\Framework\App\Config\MutableScopeConfigInterface as ScopeConfig; +use Magento\Framework\App\ResourceConnection; +use Magento\Framework\DB\Adapter\AdapterInterface; +use Magento\Store\Model\Store; + +/** + * @covers \Magento\Catalog\Cron\DeleteOutdatedPriceValues + */ +class DeleteOutdatedPriceValuesTest extends \PHPUnit\Framework\TestCase +{ + /** + * Testable Object + * + * @var DeleteOutdatedPriceValues + */ + private $deleteOutdatedPriceValues; + + /** + * @var AttributeRepository|\PHPUnit_Framework_MockObject_MockObject + */ + private $attributeRepositoryMock; + + /** + * @var ResourceConnection|\PHPUnit_Framework_MockObject_MockObject + */ + private $resourceConnectionMock; + + /** + * @var ScopeConfig|\PHPUnit_Framework_MockObject_MockObject + */ + private $scopeConfigMock; + + /** + * @var Attribute|\PHPUnit_Framework_MockObject_MockObject + */ + private $attributeMock; + + /** + * @var AdapterInterface|\PHPUnit_Framework_MockObject_MockObject + */ + private $dbAdapterMock; + + /** + * @var BackendInterface|\PHPUnit_Framework_MockObject_MockObject + */ + private $attributeBackendMock; + + /** + * Set Up + * + * @return void + */ + protected function setUp() + { + $this->resourceConnectionMock = $this->createMock(ResourceConnection::class); + $this->attributeRepositoryMock = $this->createMock(AttributeRepository::class); + $this->attributeMock = $this->createMock(Attribute::class); + $this->scopeConfigMock = $this->createMock(ScopeConfig::class); + $this->dbAdapterMock = $this->createMock(AdapterInterface::class); + $this->attributeBackendMock = $this->createMock(BackendInterface::class); + $this->deleteOutdatedPriceValues = new DeleteOutdatedPriceValues( + $this->resourceConnectionMock, + $this->attributeRepositoryMock, + $this->scopeConfigMock + ); + } + + /** + * Test execute method + * + * @return void + */ + public function testExecute() + { + $table = 'catalog_product_entity_decimal'; + $attributeId = 15; + $conditions = ['first', 'second']; + + $this->scopeConfigMock + ->expects($this->once()) + ->method('getValue') + ->with(Store::XML_PATH_PRICE_SCOPE) + ->willReturn(Store::XML_PATH_PRICE_SCOPE); + $this->attributeRepositoryMock + ->expects($this->once()) + ->method('get') + ->with(ProductAttributeInterface::ENTITY_TYPE_CODE, ProductAttributeInterface::CODE_PRICE) + ->willReturn($this->attributeMock); + $this->attributeMock->expects($this->once())->method('getId')->willReturn($attributeId); + $this->attributeMock->expects($this->once())->method('getBackend')->willReturn($this->attributeBackendMock); + $this->attributeBackendMock->expects($this->once())->method('getTable')->willReturn($table); + $this->resourceConnectionMock->expects($this->once()) + ->method('getConnection') + ->willReturn($this->dbAdapterMock); + $this->dbAdapterMock->expects($this->exactly(2))->method('quoteInto')->willReturnMap([ + ['attribute_id = ?', $attributeId, null, null, $conditions[0]], + ['store_id != ?', Store::DEFAULT_STORE_ID, null, null, $conditions[1]], + ]); + $this->dbAdapterMock->expects($this->once())->method('delete')->with($table, $conditions); + $this->deleteOutdatedPriceValues->execute(); + } + + /** + * Test execute method + * The price scope config option is not equal to global value + * + * @return void + */ + public function testExecutePriceConfigIsNotSetToGlobal() + { + $this->scopeConfigMock + ->expects($this->once()) + ->method('getValue') + ->with(Store::XML_PATH_PRICE_SCOPE) + ->willReturn(null); + $this->attributeRepositoryMock + ->expects($this->never()) + ->method('get'); + $this->dbAdapterMock + ->expects($this->never()) + ->method('delete'); + + $this->deleteOutdatedPriceValues->execute(); + } +} diff --git a/app/code/Magento/Catalog/Test/Unit/CustomerData/CompareProductsTest.php b/app/code/Magento/Catalog/Test/Unit/CustomerData/CompareProductsTest.php new file mode 100644 index 0000000000000..e30ddda0b70b9 --- /dev/null +++ b/app/code/Magento/Catalog/Test/Unit/CustomerData/CompareProductsTest.php @@ -0,0 +1,286 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ + +declare(strict_types=1); + +namespace Magento\Catalog\Test\Unit\CustomerData; + +use Magento\Catalog\Api\Data\ProductInterface; +use Magento\Catalog\CustomerData\CompareProducts; +use Magento\Catalog\Helper\Output; +use Magento\Catalog\Helper\Product\Compare; +use Magento\Catalog\Model\Product; +use Magento\Catalog\Model\Product\Url; +use Magento\Catalog\Model\ResourceModel\Product\Compare\Item\Collection; +use Magento\Framework\TestFramework\Unit\Helper\ObjectManager as ObjectManagerHelper; + +class CompareProductsTest extends \PHPUnit\Framework\TestCase +{ + /** + * @var CompareProducts + */ + private $model; + + /** + * @var Compare|\PHPUnit_Framework_MockObject_MockObject + */ + private $helperMock; + + /** + * @var Url|\PHPUnit_Framework_MockObject_MockObject + */ + private $productUrlMock; + + /** + * @var Output|\PHPUnit_Framework_MockObject_MockObject + */ + private $outputHelperMock; + + /** + * @var \Magento\Framework\TestFramework\Unit\Helper\ObjectManager + */ + private $objectManagerHelper; + + /** + * @var array + */ + private $productValueMap = [ + 'id' => 'getId', + ProductInterface::NAME => 'getName' + ]; + + protected function setUp() + { + parent::setUp(); + + $this->helperMock = $this->getMockBuilder(Compare::class) + ->disableOriginalConstructor() + ->getMock(); + $this->productUrlMock = $this->getMockBuilder(Url::class) + ->disableOriginalConstructor() + ->getMock(); + $this->outputHelperMock = $this->getMockBuilder(Output::class) + ->disableOriginalConstructor() + ->getMock(); + + $this->objectManagerHelper = new ObjectManagerHelper($this); + + $this->model = $this->objectManagerHelper->getObject( + CompareProducts::class, + [ + 'helper' => $this->helperMock, + 'productUrl' => $this->productUrlMock, + 'outputHelper' => $this->outputHelperMock + ] + ); + } + + /** + * Prepare compare items collection. + * + * @param array $items + * @return \PHPUnit_Framework_MockObject_MockObject + */ + private function getItemCollectionMock(array $items) : \PHPUnit_Framework_MockObject_MockObject + { + $itemCollectionMock = $this->getMockBuilder(Collection::class) + ->disableOriginalConstructor() + ->getMock(); + + $itemCollectionMock->expects($this->any()) + ->method('getIterator') + ->willReturn(new \ArrayIterator($items)); + + return $itemCollectionMock; + } + + /** + * Prepare product mocks objects and add corresponding method mocks for helpers. + * + * @param array $dataSet + * @return array + */ + private function prepareProductsWithCorrespondingMocks(array $dataSet) : array + { + $items = []; + $urlMap = []; + $outputMap = []; + $helperMap = []; + + $count = count($dataSet); + + foreach ($dataSet as $data) { + $item = $this->getProductMock($data); + $items[] = $item; + + $outputMap[] = [$item, $data['name'], 'name', 'productName#' . $data['id']]; + $helperMap[] = [$item, 'http://remove.url/' . $data['id']]; + $urlMap[] = [$item, [], 'http://product.url/' . $data['id']]; + } + + $this->productUrlMock->expects($this->exactly($count)) + ->method('getUrl') + ->will($this->returnValueMap($urlMap)); + + $this->outputHelperMock->expects($this->exactly($count)) + ->method('productAttribute') + ->will($this->returnValueMap($outputMap)); + + $this->helperMock->expects($this->exactly($count)) + ->method('getPostDataRemove') + ->will($this->returnValueMap($helperMap)); + + return $items; + } + + /** + * Prepare mock of product object. + * + * @param array $data + * @return \PHPUnit_Framework_MockObject_MockObject + */ + private function getProductMock(array $data) : \PHPUnit_Framework_MockObject_MockObject + { + $product = $this->getMockBuilder(Product::class) + ->disableOriginalConstructor() + ->getMock(); + + foreach ($data as $index => $value) { + $product->expects($this->once()) + ->method($this->productValueMap[$index]) + ->willReturn($value); + } + + return $product; + } + + public function testGetSectionData() + { + $dataSet = [ + ['id' => 1, 'name' => 'product#1'], + ['id' => 2, 'name' => 'product#2'], + ['id' => 3, 'name' => 'product#3'] + ]; + + $count = count($dataSet); + + $this->helperMock->expects($this->once()) + ->method('getItemCount') + ->willReturn($count); + + $items = $this->prepareProductsWithCorrespondingMocks($dataSet); + + $itemCollectionMock = $this->getItemCollectionMock($items); + + $this->helperMock->expects($this->once()) + ->method('getItemCollection') + ->willReturn($itemCollectionMock); + + $this->helperMock->expects($this->once()) + ->method('getListUrl') + ->willReturn('http://list.url'); + + $this->assertEquals( + [ + 'count' => $count, + 'countCaption' => __('%1 items', $count), + 'listUrl' => 'http://list.url', + 'items' => [ + [ + 'id' => 1, + 'product_url' => 'http://product.url/1', + 'name' => 'productName#1', + 'remove_url' => 'http://remove.url/1' + ], + [ + 'id' => 2, + 'product_url' => 'http://product.url/2', + 'name' => 'productName#2', + 'remove_url' => 'http://remove.url/2' + ], + [ + 'id' => 3, + 'product_url' => 'http://product.url/3', + 'name' => 'productName#3', + 'remove_url' => 'http://remove.url/3' + ] + ] + ], + $this->model->getSectionData() + ); + } + + public function testGetSectionDataNoItems() + { + $count = 0; + + $this->helperMock->expects($this->once()) + ->method('getItemCount') + ->willReturn($count); + + $this->helperMock->expects($this->never()) + ->method('getItemCollection'); + + $this->helperMock->expects($this->once()) + ->method('getListUrl') + ->willReturn('http://list.url'); + + $this->assertEquals( + [ + 'count' => $count, + 'countCaption' => __('%1 items', $count), + 'listUrl' => 'http://list.url', + 'items' => [] + ], + $this->model->getSectionData() + ); + } + + public function testGetSectionDataSingleItem() + { + $count = 1; + + $this->helperMock->expects($this->once()) + ->method('getItemCount') + ->willReturn($count); + + $items = $this->prepareProductsWithCorrespondingMocks( + [ + [ + 'id' => 12345, + 'name' => 'SingleProduct' + ] + ] + ); + + $itemCollectionMock = $this->getItemCollectionMock($items); + + $this->helperMock->expects($this->once()) + ->method('getItemCollection') + ->willReturn($itemCollectionMock); + + $this->helperMock->expects($this->once()) + ->method('getListUrl') + ->willReturn('http://list.url'); + + $this->assertEquals( + [ + 'count' => 1, + 'countCaption' => __('1 item'), + 'listUrl' => 'http://list.url', + 'items' => [ + [ + 'id' => 12345, + 'product_url' => 'http://product.url/12345', + 'name' => 'productName#12345', + 'remove_url' => 'http://remove.url/12345' + ] + ] + ], + $this->model->getSectionData() + ); + } +} diff --git a/app/code/Magento/Catalog/Test/Unit/Model/Category/Attribute/Backend/ImageTest.php b/app/code/Magento/Catalog/Test/Unit/Model/Category/Attribute/Backend/ImageTest.php index 8d63530b91287..f1672d842de4e 100644 --- a/app/code/Magento/Catalog/Test/Unit/Model/Category/Attribute/Backend/ImageTest.php +++ b/app/code/Magento/Catalog/Test/Unit/Model/Category/Attribute/Backend/ImageTest.php @@ -34,6 +34,9 @@ class ImageTest extends \PHPUnit\Framework\TestCase */ private $filesystem; + /** + * @inheritdoc + */ protected function setUp() { $this->objectManager = new \Magento\Framework\TestFramework\Unit\Helper\ObjectManager($this); @@ -98,7 +101,7 @@ public function testBeforeSaveValueDeletion($value) $model->beforeSave($object); - $this->assertEquals('', $object->getTestAttribute()); + $this->assertEquals(null, $object->getTestAttribute()); } /** @@ -138,6 +141,9 @@ public function testBeforeSaveValueInvalid($value) $this->assertEquals('', $object->getTestAttribute()); } + /** + * Test beforeSaveAttributeFileName. + */ public function testBeforeSaveAttributeFileName() { $model = $this->objectManager->getObject(\Magento\Catalog\Model\Category\Attribute\Backend\Image::class); @@ -154,6 +160,9 @@ public function testBeforeSaveAttributeFileName() $this->assertEquals('test123.jpg', $object->getTestAttribute()); } + /** + * Test beforeSaveAttributeFileNameOutsideOfCategoryDir. + */ public function testBeforeSaveAttributeFileNameOutsideOfCategoryDir() { $model = $this->objectManager->getObject(\Magento\Catalog\Model\Category\Attribute\Backend\Image::class, [ @@ -186,6 +195,9 @@ public function testBeforeSaveAttributeFileNameOutsideOfCategoryDir() ); } + /** + * Test beforeSaveTemporaryAttribute. + */ public function testBeforeSaveTemporaryAttribute() { $model = $this->objectManager->getObject(\Magento\Catalog\Model\Category\Attribute\Backend\Image::class); @@ -204,6 +216,9 @@ public function testBeforeSaveTemporaryAttribute() ], $object->getData('_additional_data_test_attribute')); } + /** + * Test beforeSaveAttributeStringValue. + */ public function testBeforeSaveAttributeStringValue() { $model = $this->objectManager->getObject(\Magento\Catalog\Model\Category\Attribute\Backend\Image::class); @@ -304,6 +319,9 @@ public function testAfterSaveWithoutAdditionalData($value) $model->afterSave($object); } + /** + * Test afterSaveWithExceptions. + */ public function testAfterSaveWithExceptions() { $model = $this->setUpModelForAfterSave(); diff --git a/app/code/Magento/Catalog/Test/Unit/Model/Indexer/Product/Eav/AbstractActionTest.php b/app/code/Magento/Catalog/Test/Unit/Model/Indexer/Product/Eav/AbstractActionTest.php index 9d58822fb6073..6ad14af44304e 100644 --- a/app/code/Magento/Catalog/Test/Unit/Model/Indexer/Product/Eav/AbstractActionTest.php +++ b/app/code/Magento/Catalog/Test/Unit/Model/Indexer/Product/Eav/AbstractActionTest.php @@ -22,6 +22,14 @@ class AbstractActionTest extends \PHPUnit\Framework\TestCase */ protected $_eavSourceFactoryMock; + /** + * @var \Magento\Framework\App\Config\ScopeConfigInterface|\PHPUnit_Framework_MockObject_MockObject + */ + private $scopeConfig; + + /** + * @return void + */ protected function setUp() { $this->_eavDecimalFactoryMock = $this->createPartialMock( @@ -32,12 +40,22 @@ protected function setUp() \Magento\Catalog\Model\ResourceModel\Product\Indexer\Eav\SourceFactory::class, ['create'] ); + $this->scopeConfig = $this->getMockBuilder(\Magento\Framework\App\Config\ScopeConfigInterface::class) + ->disableOriginalConstructor() + ->getMockForAbstractClass(); $this->_model = $this->getMockForAbstractClass( \Magento\Catalog\Model\Indexer\Product\Eav\AbstractAction::class, - [$this->_eavDecimalFactoryMock, $this->_eavSourceFactoryMock, []] + [ + $this->_eavDecimalFactoryMock, + $this->_eavSourceFactoryMock, + $this->scopeConfig + ] ); } + /** + * @return void + */ public function testGetIndexers() { $expectedIndexers = [ @@ -73,6 +91,10 @@ public function testGetIndexerWithUnknownTypeThrowsException() $this->_model->getIndexer('unknown_type'); } + /** + * @return void + * @throws \Magento\Framework\Exception\LocalizedException + */ public function testGetIndexer() { $this->_eavSourceFactoryMock->expects($this->once()) @@ -86,6 +108,10 @@ public function testGetIndexer() $this->assertEquals('source_return_value', $this->_model->getIndexer('source')); } + /** + * @return void + * @throws \Exception + */ public function testReindexWithoutArgumentsExecutesReindexAll() { $eavSource = $this->getMockBuilder(\Magento\Catalog\Model\ResourceModel\Product\Indexer\Eav\Source::class) @@ -110,6 +136,10 @@ public function testReindexWithoutArgumentsExecutesReindexAll() ->method('create') ->will($this->returnValue($eavDecimal)); + $this->scopeConfig->expects($this->once()) + ->method('getValue') + ->willReturn(1); + $this->_model->reindex(); } @@ -174,9 +204,25 @@ public function testReindexWithNotNullArgumentExecutesReindexEntities( ->method('create') ->will($this->returnValue($eavDecimal)); + $this->scopeConfig->expects($this->once()) + ->method('getValue') + ->willReturn(1); + $this->_model->reindex($ids); } + /** + * @return void + * @throws \Exception + */ + public function testReindexWithDisabledEavIndexer() + { + $this->scopeConfig->expects($this->once())->method('getValue')->willReturn(0); + $this->_eavSourceFactoryMock->expects($this->never())->method('create'); + $this->_eavDecimalFactoryMock->expects($this->never())->method('create'); + $this->_model->reindex(); + } + /** * @return array */ diff --git a/app/code/Magento/Catalog/Test/Unit/Model/Indexer/Product/Eav/Action/FullTest.php b/app/code/Magento/Catalog/Test/Unit/Model/Indexer/Product/Eav/Action/FullTest.php index c254557904da1..90c3f999a6a8b 100644 --- a/app/code/Magento/Catalog/Test/Unit/Model/Indexer/Product/Eav/Action/FullTest.php +++ b/app/code/Magento/Catalog/Test/Unit/Model/Indexer/Product/Eav/Action/FullTest.php @@ -5,53 +5,87 @@ */ namespace Magento\Catalog\Test\Unit\Model\Indexer\Product\Eav\Action; +use Magento\Catalog\Model\ResourceModel\Indexer\ActiveTableSwitcher; +use Magento\Framework\TestFramework\Unit\Helper\ObjectManager; +use Magento\Catalog\Model\ResourceModel\Product\Indexer\Eav\DecimalFactory; +use Magento\Catalog\Model\ResourceModel\Product\Indexer\Eav\SourceFactory; +use Magento\Framework\EntityManager\MetadataPool; +use Magento\Framework\Indexer\BatchProviderInterface; +use Magento\Catalog\Model\ResourceModel\Product\Indexer\Eav\BatchSizeCalculator; + /** * @SuppressWarnings(PHPMD.CouplingBetweenObjects) */ class FullTest extends \PHPUnit\Framework\TestCase { - public function testExecuteWithAdapterErrorThrowsException() - { - $eavDecimalFactory = $this->createPartialMock( - \Magento\Catalog\Model\ResourceModel\Product\Indexer\Eav\DecimalFactory::class, - ['create'] - ); - $eavSourceFactory = $this->createPartialMock( - \Magento\Catalog\Model\ResourceModel\Product\Indexer\Eav\SourceFactory::class, - ['create'] - ); + /** + * @var \Magento\Catalog\Model\Indexer\Product\Eav\Action\Full|\PHPUnit_Framework_MockObject_MockObject + */ + private $model; - $exceptionMessage = 'exception message'; - $exception = new \Exception($exceptionMessage); + /** + * @var DecimalFactory|\PHPUnit_Framework_MockObject_MockObject + */ + private $eavDecimalFactory; - $eavDecimalFactory->expects($this->once()) - ->method('create') - ->will($this->throwException($exception)); + /** + * @var SourceFactory|\PHPUnit_Framework_MockObject_MockObject + */ + private $eavSourceFactory; - $metadataMock = $this->createMock(\Magento\Framework\EntityManager\MetadataPool::class); - $batchProviderMock = $this->createMock(\Magento\Framework\Indexer\BatchProviderInterface::class); + /** + * @var MetadataPool|\PHPUnit_Framework_MockObject_MockObject + */ + private $metadataPool; - $batchManagementMock = $this->createMock( - \Magento\Catalog\Model\ResourceModel\Product\Indexer\Eav\BatchSizeCalculator::class - ); + /** + * @var BatchProviderInterface|\PHPUnit_Framework_MockObject_MockObject + */ + private $batchProvider; - $tableSwitcherMock = $this->getMockBuilder( - \Magento\Catalog\Model\ResourceModel\Indexer\ActiveTableSwitcher::class - )->disableOriginalConstructor()->getMock(); - - $model = new \Magento\Catalog\Model\Indexer\Product\Eav\Action\Full( - $eavDecimalFactory, - $eavSourceFactory, - $metadataMock, - $batchProviderMock, - $batchManagementMock, - $tableSwitcherMock - ); + /** + * @var BatchSizeCalculator|\PHPUnit_Framework_MockObject_MockObject + */ + private $batchSizeCalculator; + + /** + * @var ActiveTableSwitcher|\PHPUnit_Framework_MockObject_MockObject + */ + private $activeTableSwitcher; + + /** + * @var \Magento\Framework\App\Config\ScopeConfigInterface|\PHPUnit_Framework_MockObject_MockObject + */ + private $scopeConfig; - $this->expectException(\Magento\Framework\Exception\LocalizedException::class); - $this->expectExceptionMessage($exceptionMessage); + /** + * @return void + */ + protected function setUp() + { + $this->eavDecimalFactory = $this->createPartialMock(DecimalFactory::class, ['create']); + $this->eavSourceFactory = $this->createPartialMock(SourceFactory::class, ['create']); + $this->metadataPool = $this->createMock(MetadataPool::class); + $this->batchProvider = $this->getMockForAbstractClass(BatchProviderInterface::class); + $this->batchSizeCalculator = $this->createMock(BatchSizeCalculator::class); + $this->activeTableSwitcher = $this->createMock(ActiveTableSwitcher::class); + $this->scopeConfig = $this->getMockBuilder(\Magento\Framework\App\Config\ScopeConfigInterface::class) + ->disableOriginalConstructor() + ->getMockForAbstractClass(); - $model->execute(); + $objectManager = new ObjectManager($this); + $this->model = $objectManager->getObject( + \Magento\Catalog\Model\Indexer\Product\Eav\Action\Full::class, + [ + 'eavDecimalFactory' => $this->eavDecimalFactory, + 'eavSourceFactory' => $this->eavSourceFactory, + 'metadataPool' => $this->metadataPool, + 'batchProvider' => $this->batchProvider, + 'batchSizeCalculator' => $this->batchSizeCalculator, + 'activeTableSwitcher' => $this->activeTableSwitcher, + 'scopeConfig' => $this->scopeConfig + ] + ); } /** @@ -59,14 +93,7 @@ public function testExecuteWithAdapterErrorThrowsException() */ public function testExecute() { - $eavDecimalFactory = $this->createPartialMock( - \Magento\Catalog\Model\ResourceModel\Product\Indexer\Eav\DecimalFactory::class, - ['create'] - ); - $eavSourceFactory = $this->createPartialMock( - \Magento\Catalog\Model\ResourceModel\Product\Indexer\Eav\SourceFactory::class, - ['create'] - ); + $this->scopeConfig->expects($this->once())->method('getValue')->willReturn(1); $ids = [1, 2, 3]; $connectionMock = $this->getMockBuilder(\Magento\Framework\DB\Adapter\AdapterInterface::class) @@ -90,42 +117,29 @@ public function testExecute() $eavSource->expects($this->atLeastOnce())->method('getConnection')->willReturn($connectionMock); $eavDecimal->expects($this->atLeastOnce())->method('getConnection')->willReturn($connectionMock); - $eavDecimal->expects($this->once()) - ->method('reindexEntities') - ->with($ids); + $eavDecimal->expects($this->once())->method('reindexEntities')->with($ids); - $eavSource->expects($this->once()) - ->method('reindexEntities') - ->with($ids); + $eavSource->expects($this->once())->method('reindexEntities')->with($ids); - $eavDecimalFactory->expects($this->once()) - ->method('create') - ->will($this->returnValue($eavSource)); + $this->eavDecimalFactory->expects($this->once())->method('create')->will($this->returnValue($eavSource)); - $eavSourceFactory->expects($this->once()) - ->method('create') - ->will($this->returnValue($eavDecimal)); + $this->eavSourceFactory->expects($this->once())->method('create')->will($this->returnValue($eavDecimal)); - $metadataMock = $this->createMock(\Magento\Framework\EntityManager\MetadataPool::class); $entityMetadataMock = $this->getMockBuilder(\Magento\Framework\EntityManager\EntityMetadataInterface::class) ->getMockForAbstractClass(); - $metadataMock->expects($this->atLeastOnce()) + $this->metadataPool->expects($this->atLeastOnce()) ->method('getMetadata') ->with(\Magento\Catalog\Api\Data\ProductInterface::class) ->willReturn($entityMetadataMock); - $batchProviderMock = $this->createMock(\Magento\Framework\Indexer\BatchProviderInterface::class); - $batchProviderMock->expects($this->atLeastOnce()) + $this->batchProvider->expects($this->atLeastOnce()) ->method('getBatches') ->willReturn([['from' => 10, 'to' => 100]]); - $batchProviderMock->expects($this->atLeastOnce()) + $this->batchProvider->expects($this->atLeastOnce()) ->method('getBatchIds') ->willReturn($ids); - $batchManagementMock = $this->createMock( - \Magento\Catalog\Model\ResourceModel\Product\Indexer\Eav\BatchSizeCalculator::class - ); $selectMock = $this->getMockBuilder(\Magento\Framework\DB\Select::class) ->disableOriginalConstructor() ->getMock(); @@ -134,19 +148,17 @@ public function testExecute() $selectMock->expects($this->atLeastOnce())->method('distinct')->willReturnSelf(); $selectMock->expects($this->atLeastOnce())->method('from')->willReturnSelf(); - $tableSwitcherMock = $this->getMockBuilder( - \Magento\Catalog\Model\ResourceModel\Indexer\ActiveTableSwitcher::class - )->disableOriginalConstructor()->getMock(); - - $model = new \Magento\Catalog\Model\Indexer\Product\Eav\Action\Full( - $eavDecimalFactory, - $eavSourceFactory, - $metadataMock, - $batchProviderMock, - $batchManagementMock, - $tableSwitcherMock - ); + $this->model->execute(); + } - $model->execute(); + /** + * @return void + * @throws \Magento\Framework\Exception\LocalizedException + */ + public function testExecuteWithDisabledEavIndexer() + { + $this->scopeConfig->expects($this->once())->method('getValue')->willReturn(0); + $this->metadataPool->expects($this->never())->method('getMetadata'); + $this->model->execute(); } } diff --git a/app/code/Magento/Catalog/Test/Unit/Model/Indexer/Product/Price/Plugin/WebsiteTest.php b/app/code/Magento/Catalog/Test/Unit/Model/Indexer/Product/Price/Plugin/WebsiteTest.php index d551822d975ea..f64789a2a3d82 100644 --- a/app/code/Magento/Catalog/Test/Unit/Model/Indexer/Product/Price/Plugin/WebsiteTest.php +++ b/app/code/Magento/Catalog/Test/Unit/Model/Indexer/Product/Price/Plugin/WebsiteTest.php @@ -5,43 +5,179 @@ */ namespace Magento\Catalog\Test\Unit\Model\Indexer\Product\Price\Plugin; +use Magento\Catalog\Model\Indexer\Product\Price\DimensionModeConfiguration; + class WebsiteTest extends \PHPUnit\Framework\TestCase { /** * @var \Magento\Framework\TestFramework\Unit\Helper\ObjectManager */ - protected $_objectManager; + protected $objectManager; /** * @var \Magento\Catalog\Model\Indexer\Product\Price\Plugin\Website */ - protected $_model; + protected $model; + + /** + * @var \Magento\Framework\Indexer\DimensionFactory|\PHPUnit_Framework_MockObject_MockObject + */ + protected $dimensionFactory; + + /** + * @var \Magento\Catalog\Model\Indexer\Product\Price\TableMaintainer|\PHPUnit_Framework_MockObject_MockObject + */ + protected $tableMaintainer; /** - * @var \Magento\Catalog\Model\Indexer\Product\Price\Processor|\PHPUnit_Framework_MockObject_MockObject + * @var DimensionModeConfiguration|\PHPUnit_Framework_MockObject_MockObject */ - protected $_priceProcessorMock; + protected $dimensionModeConfiguration; protected function setUp() { - $this->_objectManager = new \Magento\Framework\TestFramework\Unit\Helper\ObjectManager($this); + $this->objectManager = new \Magento\Framework\TestFramework\Unit\Helper\ObjectManager($this); - $this->_priceProcessorMock = $this->createPartialMock( - \Magento\Catalog\Model\Indexer\Product\Price\Processor::class, - ['markIndexerAsInvalid'] + $this->dimensionFactory = $this->createPartialMock( + \Magento\Framework\Indexer\DimensionFactory::class, + ['create'] ); - $this->_model = $this->_objectManager->getObject( + $this->tableMaintainer = $this->createPartialMock( + \Magento\Catalog\Model\Indexer\Product\Price\TableMaintainer::class, + ['dropTablesForDimensions', 'createTablesForDimensions'] + ); + + $this->dimensionModeConfiguration = $this->createPartialMock( + DimensionModeConfiguration::class, + ['getDimensionConfiguration'] + ); + + $this->model = $this->objectManager->getObject( \Magento\Catalog\Model\Indexer\Product\Price\Plugin\Website::class, - ['processor' => $this->_priceProcessorMock] + [ + 'dimensionFactory' => $this->dimensionFactory, + 'tableMaintainer' => $this->tableMaintainer, + 'dimensionModeConfiguration' => $this->dimensionModeConfiguration, + ] ); } public function testAfterDelete() { - $this->_priceProcessorMock->expects($this->once())->method('markIndexerAsInvalid'); + $dimensionMock = $this->createMock(\Magento\Framework\Indexer\Dimension::class); + + $this->dimensionFactory->expects($this->once())->method('create')->willReturn( + $dimensionMock + ); + $this->tableMaintainer->expects($this->once())->method('dropTablesForDimensions')->with( + [$dimensionMock] + ); + + $this->dimensionModeConfiguration->expects($this->once())->method('getDimensionConfiguration')->willReturn( + [\Magento\Store\Model\Indexer\WebsiteDimensionProvider::DIMENSION_NAME] + ); + + $subjectMock = $this->createMock(\Magento\Framework\Model\ResourceModel\Db\AbstractDb::class); + $objectResourceMock = $this->createMock(\Magento\Framework\Model\ResourceModel\Db\AbstractDb::class); + $websiteMock = $this->createMock(\Magento\Framework\Model\AbstractModel::class); + $websiteMock->expects($this->once()) + ->method('getId') + ->willReturn(1); + + $this->assertEquals( + $objectResourceMock, + $this->model->afterDelete($subjectMock, $objectResourceMock, $websiteMock) + ); + } + + public function testAfterDeleteOnModeWithoutWebsiteDimension() + { + $dimensionMock = $this->createMock(\Magento\Framework\Indexer\Dimension::class); + + $this->dimensionFactory->expects($this->never())->method('create')->willReturn( + $dimensionMock + ); + $this->tableMaintainer->expects($this->never())->method('dropTablesForDimensions')->with( + [$dimensionMock] + ); - $websiteMock = $this->createMock(\Magento\Store\Model\ResourceModel\Website::class); - $this->assertEquals('return_value', $this->_model->afterDelete($websiteMock, 'return_value')); + $this->dimensionModeConfiguration->expects($this->once())->method('getDimensionConfiguration')->willReturn( + [] + ); + + $subjectMock = $this->createMock(\Magento\Framework\Model\ResourceModel\Db\AbstractDb::class); + $objectResourceMock = $this->createMock(\Magento\Framework\Model\ResourceModel\Db\AbstractDb::class); + $websiteMock = $this->createMock(\Magento\Framework\Model\AbstractModel::class); + $websiteMock->expects($this->once()) + ->method('getId') + ->willReturn(1); + + $this->assertEquals( + $objectResourceMock, + $this->model->afterDelete($subjectMock, $objectResourceMock, $websiteMock) + ); + } + + public function testAfterSave() + { + $dimensionMock = $this->createMock(\Magento\Framework\Indexer\Dimension::class); + + $this->dimensionFactory->expects($this->once())->method('create')->willReturn( + $dimensionMock + ); + $this->tableMaintainer->expects($this->once())->method('createTablesForDimensions')->with( + [$dimensionMock] + ); + + $this->dimensionModeConfiguration->expects($this->once())->method('getDimensionConfiguration')->willReturn( + [\Magento\Store\Model\Indexer\WebsiteDimensionProvider::DIMENSION_NAME] + ); + + $subjectMock = $this->createMock(\Magento\Framework\Model\ResourceModel\Db\AbstractDb::class); + $objectResourceMock = $this->createMock(\Magento\Framework\Model\ResourceModel\Db\AbstractDb::class); + $websiteMock = $this->createMock(\Magento\Framework\Model\AbstractModel::class); + $websiteMock->expects($this->once()) + ->method('getId') + ->willReturn(1); + $websiteMock->expects($this->once()) + ->method('isObjectNew') + ->willReturn(true); + + $this->assertEquals( + $objectResourceMock, + $this->model->afterSave($subjectMock, $objectResourceMock, $websiteMock) + ); + } + + public function testAfterSaveOnModeWithoutWebsiteDimension() + { + $dimensionMock = $this->createMock(\Magento\Framework\Indexer\Dimension::class); + + $this->dimensionFactory->expects($this->never())->method('create')->willReturn( + $dimensionMock + ); + $this->tableMaintainer->expects($this->never())->method('createTablesForDimensions')->with( + [$dimensionMock] + ); + + $this->dimensionModeConfiguration->expects($this->once())->method('getDimensionConfiguration')->willReturn( + [] + ); + + $subjectMock = $this->createMock(\Magento\Framework\Model\ResourceModel\Db\AbstractDb::class); + $objectResourceMock = $this->createMock(\Magento\Framework\Model\ResourceModel\Db\AbstractDb::class); + $websiteMock = $this->createMock(\Magento\Framework\Model\AbstractModel::class); + $websiteMock->expects($this->once()) + ->method('getId') + ->willReturn(1); + $websiteMock->expects($this->once()) + ->method('isObjectNew') + ->willReturn(true); + + $this->assertEquals( + $objectResourceMock, + $this->model->afterSave($subjectMock, $objectResourceMock, $websiteMock) + ); } } diff --git a/app/code/Magento/Catalog/Test/Unit/Model/Product/Option/Validator/DefaultValidatorTest.php b/app/code/Magento/Catalog/Test/Unit/Model/Product/Option/Validator/DefaultValidatorTest.php index 1eb5f1a2dacd2..da6b790fedfa6 100644 --- a/app/code/Magento/Catalog/Test/Unit/Model/Product/Option/Validator/DefaultValidatorTest.php +++ b/app/code/Magento/Catalog/Test/Unit/Model/Product/Option/Validator/DefaultValidatorTest.php @@ -18,6 +18,9 @@ class DefaultValidatorTest extends \PHPUnit\Framework\TestCase */ protected $valueMock; + /** + * @inheritdoc + */ protected function setUp() { $configMock = $this->createMock(\Magento\Catalog\Model\ProductOptions\ConfigInterface::class); @@ -60,31 +63,30 @@ public function isValidTitleDataProvider() { $mess = ['option required fields' => 'Missed values for option required fields']; return [ - ['option_title', 'name 1.1', 'fixed', 10, new \Magento\Framework\DataObject(['store_id' => 1]), [], true], - ['option_title', 'name 1.1', 'fixed', 10, new \Magento\Framework\DataObject(['store_id' => 0]), [], true], - [null, 'name 1.1', 'fixed', 10, new \Magento\Framework\DataObject(['store_id' => 1]), [], true], - [null, 'name 1.1', 'fixed', 10, new \Magento\Framework\DataObject(['store_id' => 0]), $mess, false], + ['option_title', 'name 1.1', 'fixed', new \Magento\Framework\DataObject(['store_id' => 1]), [], true], + ['option_title', 'name 1.1', 'fixed', new \Magento\Framework\DataObject(['store_id' => 0]), [], true], + [null, 'name 1.1', 'fixed', new \Magento\Framework\DataObject(['store_id' => 1]), [], true], + [null, 'name 1.1', 'fixed', new \Magento\Framework\DataObject(['store_id' => 0]), $mess, false], ]; } /** - * @param $title - * @param $type - * @param $priceType - * @param $price - * @param $product - * @param $messages - * @param $result + * @param string $title + * @param string $type + * @param string $priceType + * @param \Magento\Framework\DataObject $product + * @param array $messages + * @param bool $result * @dataProvider isValidTitleDataProvider */ - public function testIsValidTitle($title, $type, $priceType, $price, $product, $messages, $result) + public function testIsValidTitle($title, $type, $priceType, $product, $messages, $result) { - $methods = ['getTitle', 'getType', 'getPriceType', 'getPrice', '__wakeup', 'getProduct']; + $methods = ['getTitle', 'getType', 'getPriceType', '__wakeup', 'getProduct']; $valueMock = $this->createPartialMock(\Magento\Catalog\Model\Product\Option::class, $methods); $valueMock->expects($this->once())->method('getTitle')->will($this->returnValue($title)); $valueMock->expects($this->any())->method('getType')->will($this->returnValue($type)); $valueMock->expects($this->once())->method('getPriceType')->will($this->returnValue($priceType)); - $valueMock->expects($this->once())->method('getPrice')->will($this->returnValue($price)); + // $valueMock->expects($this->once())->method('getPrice')->will($this->returnValue($price)); $valueMock->expects($this->once())->method('getProduct')->will($this->returnValue($product)); $this->assertEquals($result, $this->validator->isValid($valueMock)); $this->assertEquals($messages, $this->validator->getMessages()); @@ -104,7 +106,7 @@ public function isValidFailDataProvider() } /** - * @param $product + * @param \Magento\Framework\DataObject $product * @dataProvider isValidFailDataProvider */ public function testIsValidFail($product) @@ -124,41 +126,4 @@ public function testIsValidFail($product) $this->assertFalse($this->validator->isValid($valueMock)); $this->assertEquals($messages, $this->validator->getMessages()); } - - /** - * Data provider for testValidationNegativePrice - * @return array - */ - public function validationNegativePriceDataProvider() - { - return [ - ['option_title', 'name 1.1', 'fixed', -12, new \Magento\Framework\DataObject(['store_id' => 1])], - ['option_title', 'name 1.1', 'fixed', -12, new \Magento\Framework\DataObject(['store_id' => 0])], - ]; - } - - /** - * @param $title - * @param $type - * @param $priceType - * @param $price - * @param $product - * @dataProvider validationNegativePriceDataProvider - */ - public function testValidationNegativePrice($title, $type, $priceType, $price, $product) - { - $methods = ['getTitle', 'getType', 'getPriceType', 'getPrice', '__wakeup', 'getProduct']; - $valueMock = $this->createPartialMock(\Magento\Catalog\Model\Product\Option::class, $methods); - $valueMock->expects($this->once())->method('getTitle')->will($this->returnValue($title)); - $valueMock->expects($this->exactly(2))->method('getType')->will($this->returnValue($type)); - $valueMock->expects($this->once())->method('getPriceType')->will($this->returnValue($priceType)); - $valueMock->expects($this->once())->method('getPrice')->will($this->returnValue($price)); - $valueMock->expects($this->once())->method('getProduct')->will($this->returnValue($product)); - - $messages = [ - 'option values' => 'Invalid option value', - ]; - $this->assertFalse($this->validator->isValid($valueMock)); - $this->assertEquals($messages, $this->validator->getMessages()); - } } diff --git a/app/code/Magento/Catalog/Test/Unit/Model/Product/Option/Validator/FileTest.php b/app/code/Magento/Catalog/Test/Unit/Model/Product/Option/Validator/FileTest.php index 3c06db0e7ce5f..2de993c075514 100644 --- a/app/code/Magento/Catalog/Test/Unit/Model/Product/Option/Validator/FileTest.php +++ b/app/code/Magento/Catalog/Test/Unit/Model/Product/Option/Validator/FileTest.php @@ -18,6 +18,9 @@ class FileTest extends \PHPUnit\Framework\TestCase */ protected $valueMock; + /** + * @inheritdoc + */ protected function setUp() { $configMock = $this->createMock(\Magento\Catalog\Model\ProductOptions\ConfigInterface::class); @@ -54,24 +57,34 @@ protected function setUp() ); } + /** + * @return void + */ public function testIsValidSuccess() { $this->valueMock->expects($this->once())->method('getTitle')->will($this->returnValue('option_title')); $this->valueMock->expects($this->exactly(2))->method('getType')->will($this->returnValue('name 1.1')); - $this->valueMock->expects($this->once())->method('getPriceType')->will($this->returnValue('fixed')); - $this->valueMock->expects($this->once())->method('getPrice')->will($this->returnValue(10)); + $this->valueMock->method('getPriceType') + ->willReturn('fixed'); + $this->valueMock->method('getPrice') + ->willReturn(10); $this->valueMock->expects($this->once())->method('getImageSizeX')->will($this->returnValue(10)); $this->valueMock->expects($this->once())->method('getImageSizeY')->will($this->returnValue(15)); $this->assertEmpty($this->validator->getMessages()); $this->assertTrue($this->validator->isValid($this->valueMock)); } + /** + * @return void + */ public function testIsValidWithNegativeImageSize() { $this->valueMock->expects($this->once())->method('getTitle')->will($this->returnValue('option_title')); $this->valueMock->expects($this->exactly(2))->method('getType')->will($this->returnValue('name 1.1')); - $this->valueMock->expects($this->once())->method('getPriceType')->will($this->returnValue('fixed')); - $this->valueMock->expects($this->once())->method('getPrice')->will($this->returnValue(10)); + $this->valueMock->method('getPriceType') + ->willReturn('fixed'); + $this->valueMock->method('getPrice') + ->willReturn(10); $this->valueMock->expects($this->once())->method('getImageSizeX')->will($this->returnValue(-10)); $this->valueMock->expects($this->never())->method('getImageSizeY'); $messages = [ @@ -81,12 +94,17 @@ public function testIsValidWithNegativeImageSize() $this->assertEquals($messages, $this->validator->getMessages()); } + /** + * @return void + */ public function testIsValidWithNegativeImageSizeY() { $this->valueMock->expects($this->once())->method('getTitle')->will($this->returnValue('option_title')); $this->valueMock->expects($this->exactly(2))->method('getType')->will($this->returnValue('name 1.1')); - $this->valueMock->expects($this->once())->method('getPriceType')->will($this->returnValue('fixed')); - $this->valueMock->expects($this->once())->method('getPrice')->will($this->returnValue(10)); + $this->valueMock->method('getPriceType') + ->willReturn('fixed'); + $this->valueMock->method('getPrice') + ->willReturn(10); $this->valueMock->expects($this->once())->method('getImageSizeX')->will($this->returnValue(10)); $this->valueMock->expects($this->once())->method('getImageSizeY')->will($this->returnValue(-10)); $messages = [ diff --git a/app/code/Magento/Catalog/Test/Unit/Model/Product/Option/Validator/SelectTest.php b/app/code/Magento/Catalog/Test/Unit/Model/Product/Option/Validator/SelectTest.php index 95a9b961c8d81..b97783edf856c 100644 --- a/app/code/Magento/Catalog/Test/Unit/Model/Product/Option/Validator/SelectTest.php +++ b/app/code/Magento/Catalog/Test/Unit/Model/Product/Option/Validator/SelectTest.php @@ -18,6 +18,9 @@ class SelectTest extends \PHPUnit\Framework\TestCase */ protected $valueMock; + /** + * @inheritdoc + */ protected function setUp() { $configMock = $this->createMock(\Magento\Catalog\Model\ProductOptions\ConfigInterface::class); @@ -90,7 +93,7 @@ public function isValidSuccessDataProvider() ] ], [ - false, + true, [ 'title' => 'Some Title', 'price_type' => 'fixed', @@ -100,6 +103,9 @@ public function isValidSuccessDataProvider() ]; } + /** + * @return void + */ public function testIsValidateWithInvalidOptionValues() { $this->valueMock->expects($this->once())->method('getTitle')->will($this->returnValue('option_title')); @@ -118,6 +124,9 @@ public function testIsValidateWithInvalidOptionValues() $this->assertEquals($messages, $this->validator->getMessages()); } + /** + * @return void + */ public function testIsValidateWithEmptyValues() { $this->valueMock->expects($this->once())->method('getTitle')->will($this->returnValue('option_title')); @@ -163,7 +172,6 @@ public function testIsValidateWithInvalidData($priceType, $price, $title) public function isValidateWithInvalidDataDataProvider() { return [ - 'invalid_price' => ['fixed', -10, 'Title'], 'invalid_price_type' => ['some_value', '10', 'Title'], 'empty_title' => ['fixed', 10, null] ]; diff --git a/app/code/Magento/Catalog/Test/Unit/Model/Product/Option/Validator/TextTest.php b/app/code/Magento/Catalog/Test/Unit/Model/Product/Option/Validator/TextTest.php index cf31d67817684..4881154728ddc 100644 --- a/app/code/Magento/Catalog/Test/Unit/Model/Product/Option/Validator/TextTest.php +++ b/app/code/Magento/Catalog/Test/Unit/Model/Product/Option/Validator/TextTest.php @@ -18,6 +18,9 @@ class TextTest extends \PHPUnit\Framework\TestCase */ protected $valueMock; + /** + * @inheritdoc + */ protected function setUp() { $configMock = $this->createMock(\Magento\Catalog\Model\ProductOptions\ConfigInterface::class); @@ -54,23 +57,33 @@ protected function setUp() ); } + /** + * @return void + */ public function testIsValidSuccess() { $this->valueMock->expects($this->once())->method('getTitle')->will($this->returnValue('option_title')); $this->valueMock->expects($this->exactly(2))->method('getType')->will($this->returnValue('name 1.1')); - $this->valueMock->expects($this->once())->method('getPriceType')->will($this->returnValue('fixed')); - $this->valueMock->expects($this->once())->method('getPrice')->will($this->returnValue(10)); + $this->valueMock->method('getPriceType') + ->willReturn('fixed'); + $this->valueMock->method('getPrice') + ->willReturn(10); $this->valueMock->expects($this->once())->method('getMaxCharacters')->will($this->returnValue(10)); $this->assertTrue($this->validator->isValid($this->valueMock)); $this->assertEmpty($this->validator->getMessages()); } + /** + * @return void + */ public function testIsValidWithNegativeMaxCharacters() { $this->valueMock->expects($this->once())->method('getTitle')->will($this->returnValue('option_title')); $this->valueMock->expects($this->exactly(2))->method('getType')->will($this->returnValue('name 1.1')); - $this->valueMock->expects($this->once())->method('getPriceType')->will($this->returnValue('fixed')); - $this->valueMock->expects($this->once())->method('getPrice')->will($this->returnValue(10)); + $this->valueMock->method('getPriceType') + ->willReturn('fixed'); + $this->valueMock->method('getPrice') + ->willReturn(10); $this->valueMock->expects($this->once())->method('getMaxCharacters')->will($this->returnValue(-10)); $messages = [ 'option values' => 'Invalid option value', diff --git a/app/code/Magento/Catalog/Test/Unit/Model/ResourceModel/Layer/Filter/PriceTest.php b/app/code/Magento/Catalog/Test/Unit/Model/ResourceModel/Layer/Filter/PriceTest.php deleted file mode 100644 index 9fba7d833c25a..0000000000000 --- a/app/code/Magento/Catalog/Test/Unit/Model/ResourceModel/Layer/Filter/PriceTest.php +++ /dev/null @@ -1,48 +0,0 @@ -<?php -/** - * Copyright © Magento, Inc. All rights reserved. - * See COPYING.txt for license details. - */ - -namespace Magento\Catalog\Test\Unit\Model\ResourceModel\Layer\Filter; - -use Magento\Framework\TestFramework\Unit\Helper\ObjectManager; - -class PriceTest extends \PHPUnit\Framework\TestCase -{ - /** - * @var \Magento\Catalog\Model\ResourceModel\Layer\Filter\Price - */ - private $model; - - /** - * @var \PHPUnit_Framework_MockObject_MockObject - */ - private $resourceMock; - - protected function setUp() - { - $objectManagerHelper = new ObjectManager($this); - - $contextMock = $this->getMockBuilder(\Magento\Framework\Model\ResourceModel\Db\Context::class) - ->disableOriginalConstructor() - ->getMock(); - $this->resourceMock = $this->getMockBuilder(\Magento\Framework\App\ResourceConnection::class) - ->disableOriginalConstructor() - ->getMock(); - $contextMock->expects($this->once())->method('getResources')->willReturn($this->resourceMock); - $this->model = $objectManagerHelper->getObject( - \Magento\Catalog\Model\ResourceModel\Layer\Filter\Price::class, - [ - 'context' => $contextMock - ] - ); - } - - public function testGetMainTable() - { - $expectedTableName = 'expectedTableName'; - $this->resourceMock->expects($this->once())->method('getTableName')->willReturn($expectedTableName); - $this->assertEquals($expectedTableName, $this->model->getMainTable()); - } -} diff --git a/app/code/Magento/Catalog/Test/Unit/Model/ResourceModel/Product/CollectionTest.php b/app/code/Magento/Catalog/Test/Unit/Model/ResourceModel/Product/CollectionTest.php index c73e772de3702..dbbb3fb29513b 100644 --- a/app/code/Magento/Catalog/Test/Unit/Model/ResourceModel/Product/CollectionTest.php +++ b/app/code/Magento/Catalog/Test/Unit/Model/ResourceModel/Product/CollectionTest.php @@ -6,6 +6,7 @@ namespace Magento\Catalog\Test\Unit\Model\ResourceModel\Product; use Magento\Catalog\Model\ResourceModel\Product\Collection\ProductLimitationFactory; +use Magento\Framework\DB\Select; /** * @SuppressWarnings(PHPMD.CouplingBetweenObjects) @@ -239,7 +240,7 @@ public function testAddMediaGalleryData() $mediaGalleriesMock = [[$linkField => $rowId]]; $itemMock = $this->getMockBuilder(\Magento\Catalog\Model\Product::class) ->disableOriginalConstructor() - ->setMethods(['getData']) + ->setMethods(['getOrigData']) ->getMock(); $attributeMock = $this->getMockBuilder(\Magento\Eav\Model\Entity\Attribute\AbstractAttribute::class) ->disableOriginalConstructor() @@ -254,8 +255,10 @@ public function testAddMediaGalleryData() $this->galleryResourceMock->expects($this->once())->method('createBatchBaseSelect')->willReturn($selectMock); $attributeMock->expects($this->once())->method('getAttributeId')->willReturn($attributeId); $this->entityMock->expects($this->once())->method('getAttribute')->willReturn($attributeMock); - $itemMock->expects($this->atLeastOnce())->method('getData')->willReturn($rowId); - $selectMock->expects($this->once())->method('where')->with('entity.' . $linkField . ' IN (?)', [$rowId]); + $itemMock->expects($this->atLeastOnce())->method('getOrigData')->willReturn($rowId); + $selectMock->expects($this->once())->method('reset')->with(Select::ORDER)->willReturnSelf(); + $selectMock->expects($this->once())->method('where')->with('entity.' . $linkField . ' IN (?)', [$rowId]) + ->willReturnSelf(); $this->metadataPoolMock->expects($this->once())->method('getMetadata')->willReturn($metadataMock); $metadataMock->expects($this->once())->method('getLinkField')->willReturn($linkField); diff --git a/app/code/Magento/Catalog/Test/Unit/Model/ResourceModel/Product/Indexer/LinkedProductSelectBuilderByIndexPriceTest.php b/app/code/Magento/Catalog/Test/Unit/Model/ResourceModel/Product/Indexer/LinkedProductSelectBuilderByIndexPriceTest.php index cec862ee9661f..6f3d8e1a84b17 100644 --- a/app/code/Magento/Catalog/Test/Unit/Model/ResourceModel/Product/Indexer/LinkedProductSelectBuilderByIndexPriceTest.php +++ b/app/code/Magento/Catalog/Test/Unit/Model/ResourceModel/Product/Indexer/LinkedProductSelectBuilderByIndexPriceTest.php @@ -7,6 +7,9 @@ use Magento\Catalog\Model\ResourceModel\Product\BaseSelectProcessorInterface; +/** + * @SuppressWarnings(PHPMD.CouplingBetweenObjects) + */ class LinkedProductSelectBuilderByIndexPriceTest extends \PHPUnit\Framework\TestCase { /** @@ -56,12 +59,26 @@ protected function setUp() $this->getMockBuilder(\Magento\Catalog\Model\ResourceModel\Product\BaseSelectProcessorInterface::class) ->disableOriginalConstructor() ->getMockForAbstractClass(); + + $this->indexScopeResolverMock = $this->createMock( + \Magento\Framework\Search\Request\IndexScopeResolverInterface::class + ); + $this->dimensionMock = $this->createMock(\Magento\Framework\Indexer\Dimension::class); + $this->dimensionFactoryMock = $this->createMock(\Magento\Framework\Indexer\DimensionFactory::class); + $this->dimensionFactoryMock->method('create')->willReturn($this->dimensionMock); + $storeMock = $this->createMock(\Magento\Store\Api\Data\StoreInterface::class); + $storeMock->method('getId')->willReturn(1); + $storeMock->method('getWebsiteId')->willReturn(1); + $this->storeManagerMock->method('getStore')->willReturn($storeMock); + $this->model = new \Magento\Catalog\Model\ResourceModel\Product\Indexer\LinkedProductSelectBuilderByIndexPrice( $this->storeManagerMock, $this->resourceMock, $this->customerSessionMock, $this->metadataPoolMock, - $this->baseSelectProcessorMock + $this->baseSelectProcessorMock, + $this->indexScopeResolverMock, + $this->dimensionFactoryMock ); } @@ -79,7 +96,7 @@ public function testBuild() $storeMock = $this->getMockBuilder(\Magento\Store\Api\Data\StoreInterface::class) ->getMockForAbstractClass(); $this->storeManagerMock->expects($this->once())->method('getStore')->willReturn($storeMock); - $this->customerSessionMock->expects($this->once())->method('getCustomerGroupId'); + $this->customerSessionMock->expects($this->once())->method('getCustomerGroupId')->willReturn(1); $connection->expects($this->any())->method('select')->willReturn($select); $select->expects($this->any())->method('from')->willReturnSelf(); $select->expects($this->any())->method('joinInner')->willReturnSelf(); diff --git a/app/code/Magento/Catalog/Test/Unit/ViewModel/Product/BreadcrumbsTest.php b/app/code/Magento/Catalog/Test/Unit/ViewModel/Product/BreadcrumbsTest.php index 316e08a56f99c..dbf1292e57368 100644 --- a/app/code/Magento/Catalog/Test/Unit/ViewModel/Product/BreadcrumbsTest.php +++ b/app/code/Magento/Catalog/Test/Unit/ViewModel/Product/BreadcrumbsTest.php @@ -41,7 +41,7 @@ class BreadcrumbsTest extends \PHPUnit\Framework\TestCase /** * @inheritdoc */ - protected function setUp() + protected function setUp() : void { $this->catalogHelper = $this->getMockBuilder(CatalogHelper::class) ->setMethods(['getProduct']) @@ -53,11 +53,14 @@ protected function setUp() ->disableOriginalConstructor() ->getMockForAbstractClass(); + $escaper = $this->getObjectManager()->getObject(\Magento\Framework\Escaper::class); + $this->viewModel = $this->getObjectManager()->getObject( Breadcrumbs::class, [ 'catalogData' => $this->catalogHelper, 'scopeConfig' => $this->scopeConfig, + 'escaper' => $escaper ] ); } @@ -65,7 +68,7 @@ protected function setUp() /** * @return void */ - public function testGetCategoryUrlSuffix() + public function testGetCategoryUrlSuffix() : void { $this->scopeConfig->expects($this->once()) ->method('getValue') @@ -78,7 +81,7 @@ public function testGetCategoryUrlSuffix() /** * @return void */ - public function testIsCategoryUsedInProductUrl() + public function testIsCategoryUsedInProductUrl() : void { $this->scopeConfig->expects($this->once()) ->method('isSetFlag') @@ -95,7 +98,7 @@ public function testIsCategoryUsedInProductUrl() * @param string $expectedName * @return void */ - public function testGetProductName($product, string $expectedName) + public function testGetProductName($product, string $expectedName) : void { $this->catalogHelper->expects($this->atLeastOnce()) ->method('getProduct') @@ -107,7 +110,7 @@ public function testGetProductName($product, string $expectedName) /** * @return array */ - public function productDataProvider() + public function productDataProvider() : array { return [ [$this->getObjectManager()->getObject(Product::class, ['data' => ['name' => 'Test']]), 'Test'], @@ -115,10 +118,63 @@ public function productDataProvider() ]; } + /** + * @dataProvider productJsonEncodeDataProvider + * + * @param Product|null $product + * @param string $expectedJson + * @return void + */ + public function testGetJsonConfiguration($product, string $expectedJson) : void + { + $this->catalogHelper->expects($this->atLeastOnce()) + ->method('getProduct') + ->willReturn($product); + + $this->scopeConfig->expects($this->any()) + ->method('isSetFlag') + ->with('catalog/seo/product_use_categories', \Magento\Store\Model\ScopeInterface::SCOPE_STORE) + ->willReturn(false); + + $this->scopeConfig->expects($this->any()) + ->method('getValue') + ->with('catalog/seo/category_url_suffix', \Magento\Store\Model\ScopeInterface::SCOPE_STORE) + ->willReturn('."html'); + + $this->assertEquals($expectedJson, $this->viewModel->getJsonConfiguration()); + } + + /** + * @return array + */ + public function productJsonEncodeDataProvider() : array + { + return [ + [ + $this->getObjectManager()->getObject(Product::class, ['data' => ['name' => 'Test ™']]), + '{"breadcrumbs":{"categoryUrlSuffix":"."html","userCategoryPathInUrl":0,"product":"Test \u2122"}}', + ], + [ + $this->getObjectManager()->getObject(Product::class, ['data' => ['name' => 'Test "']]), + '{"breadcrumbs":{"categoryUrlSuffix":"."html","userCategoryPathInUrl":0,"product":"Test ""}}', + ], + [ + $this->getObjectManager()->getObject(Product::class, ['data' => ['name' => 'Test <b>x</b>']]), + '{"breadcrumbs":{"categoryUrlSuffix":"."html","userCategoryPathInUrl":0,"product":' + . '"Test <b>x<\/b>"}}', + ], + [ + $this->getObjectManager()->getObject(Product::class, ['data' => ['name' => 'Test \'abc\'']]), + '{"breadcrumbs":' + . '{"categoryUrlSuffix":"."html","userCategoryPathInUrl":0,"product":"Test 'abc'"}}' + ], + ]; + } + /** * @return ObjectManager */ - private function getObjectManager() + private function getObjectManager() : ObjectManager { if (null === $this->objectManager) { $this->objectManager = new ObjectManager($this); diff --git a/app/code/Magento/Catalog/Ui/DataProvider/Product/Form/Modifier/CustomOptions.php b/app/code/Magento/Catalog/Ui/DataProvider/Product/Form/Modifier/CustomOptions.php index 7196a721f1d02..86f1db2022cc9 100755 --- a/app/code/Magento/Catalog/Ui/DataProvider/Product/Form/Modifier/CustomOptions.php +++ b/app/code/Magento/Catalog/Ui/DataProvider/Product/Form/Modifier/CustomOptions.php @@ -166,7 +166,7 @@ public function __construct( } /** - * {@inheritdoc} + * @inheritdoc * @since 101.0.0 */ public function modifyData(array $data) @@ -226,7 +226,7 @@ protected function formatPriceByPath($path, array $data) } /** - * {@inheritdoc} + * @inheritdoc * @since 101.0.0 */ public function modifyMeta(array $meta) @@ -923,7 +923,7 @@ protected function getPriceFieldConfig($sortOrder) 'addbeforePool' => $this->productOptionsPrice->prefixesToOptionArray(), 'sortOrder' => $sortOrder, 'validation' => [ - 'validate-zero-or-greater' => true + 'validate-number' => true ], ], ], diff --git a/app/code/Magento/Catalog/ViewModel/Product/Breadcrumbs.php b/app/code/Magento/Catalog/ViewModel/Product/Breadcrumbs.php index 6e84c2ae93afe..3b6ec7deff413 100644 --- a/app/code/Magento/Catalog/ViewModel/Product/Breadcrumbs.php +++ b/app/code/Magento/Catalog/ViewModel/Product/Breadcrumbs.php @@ -3,7 +3,6 @@ * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ -declare(strict_types=1); namespace Magento\Catalog\ViewModel\Product; @@ -93,11 +92,11 @@ public function getProductName(): string } /** - * Returns breadcrumb json. + * Returns breadcrumb json with html escaped names * * @return string */ - public function getJsonConfiguration() + public function getJsonConfigurationHtmlEscaped() : string { return $this->json->serialize([ 'breadcrumbs' => [ @@ -107,4 +106,15 @@ public function getJsonConfiguration() ] ]); } + + /** + * Returns breadcrumb json. + * + * @return string + * @deprecated in favor of new method with name {suffix}Html{postfix}() + */ + public function getJsonConfiguration() + { + return $this->getJsonConfigurationHtmlEscaped(); + } } diff --git a/app/code/Magento/Catalog/etc/db_schema.xml b/app/code/Magento/Catalog/etc/db_schema.xml index 60789c016ff0f..7b4e1a96adda0 100644 --- a/app/code/Magento/Catalog/etc/db_schema.xml +++ b/app/code/Magento/Catalog/etc/db_schema.xml @@ -1199,6 +1199,8 @@ comment="Catalog Product Website Index Table"> <column xsi:type="smallint" name="website_id" padding="5" unsigned="true" nullable="false" identity="false" comment="Website ID"/> + <column xsi:type="smallint" name="default_store_id" padding="5" unsigned="true" nullable="false" identity="false" + comment="Default store id for website"/> <column xsi:type="date" name="website_date" comment="Website Date"/> <column xsi:type="float" name="rate" unsigned="false" nullable="true" default="1" comment="Rate"/> <constraint xsi:type="primary" name="PRIMARY"> diff --git a/app/code/Magento/Catalog/etc/di.xml b/app/code/Magento/Catalog/etc/di.xml index c9e18e7b8c823..44564da388fc9 100644 --- a/app/code/Magento/Catalog/etc/di.xml +++ b/app/code/Magento/Catalog/etc/di.xml @@ -239,7 +239,8 @@ </arguments> </type> <type name="Magento\Store\Model\ResourceModel\Website"> - <plugin name="priceIndexerOnWebsiteDelete" type="Magento\Catalog\Model\Indexer\Product\Price\Plugin\Website"/> + <plugin name="invalidatePriceIndexerOnWebsite" type="Magento\Catalog\Model\Indexer\Product\Price\Plugin\Website"/> + <plugin name="categoryProductWebsiteAfterDelete" type="\Magento\Catalog\Model\Indexer\Category\Product\Plugin\Website"/> </type> <type name="Magento\Store\Model\ResourceModel\Store"> <plugin name="storeViewResourceAroundSave" type="Magento\Catalog\Model\Indexer\Category\Flat\Plugin\StoreView"/> @@ -562,6 +563,7 @@ <arguments> <argument name="commands" xsi:type="array"> <item name="productAttributesCleanUp" xsi:type="object">Magento\Catalog\Console\Command\ProductAttributesCleanUp</item> + <item name="setPriceDimensionsMode" xsi:type="object">Magento\Catalog\Console\Command\PriceIndexerDimensionsModeSetCommand</item> </argument> </arguments> </type> @@ -923,6 +925,7 @@ <type name="Magento\Catalog\Model\ResourceModel\Product\Indexer\LinkedProductSelectBuilderByIndexPrice"> <arguments> <argument name="baseSelectProcessor" xsi:type="object">Magento\Catalog\Model\ResourceModel\Product\CompositeBaseSelectProcessor</argument> + <argument name="priceTableResolver" xsi:type="object">Magento\Catalog\Model\Indexer\Product\Price\PriceTableResolver</argument> </arguments> </type> <type name="Magento\Catalog\Model\Product\Price\CostStorage"> @@ -1088,4 +1091,55 @@ <argument name="nativeAttributeConditionBuilder" xsi:type="object">Magento\Catalog\Model\Api\SearchCriteria\CollectionProcessor\ConditionProcessor\ConditionBuilder\NativeAttributeCondition</argument> </arguments> </type> + <type name="Magento\Catalog\Model\Indexer\Product\Price\DimensionCollectionFactory"> + <arguments> + <argument name="dimensionProviders" xsi:type="array"> + <!-- @see \Magento\Store\Model\Indexer\WebsiteDimensionProvider::DIMENSION_NAME --> + <item name="ws" xsi:type="object">Magento\Store\Model\Indexer\WebsiteDimensionProvider</item> + <!-- @see \Magento\Customer\Model\Indexer\CustomerGroupDimensionProvider::DIMENSION_NAME --> + <item name="cg" xsi:type="object">Magento\Customer\Model\Indexer\CustomerGroupDimensionProvider</item> + </argument> + </arguments> + </type> + <type name="Magento\Catalog\Model\Indexer\Product\Price\Plugin\TableResolver"> + <arguments> + <argument name="priceTableResolver" xsi:type="object">Magento\Catalog\Model\Indexer\Product\Price\PriceTableResolver\Proxy</argument> + <argument name="storeManager" xsi:type="object">Magento\Store\Model\StoreManagerInterface\Proxy</argument> + <argument name="context" xsi:type="object">Magento\Framework\App\Http\Context\Proxy</argument> + <!-- Unccomment after fix issue with Proxy generation --> + <!--<argument name="dimensionModeConfiguration" xsi:type="object">--> + <!--Magento\Catalog\Model\Indexer\Product\Price\DimensionModeConfiguration\Proxy--> + <!--</argument>--> + </arguments> + </type> + <type name="Magento\Catalog\Model\ResourceModel\Layer\Filter\Price"> + <arguments> + <argument name="priceTableResolver" xsi:type="object"> + Magento\Catalog\Model\Indexer\Product\Price\PriceTableResolver + </argument> + </arguments> + </type> + <type name="Magento\Catalog\Model\ResourceModel\Product\Indexer\Price\CustomOptionPriceModifier"> + <arguments> + <argument name="tableStrategy" xsi:type="object">Magento\Catalog\Model\ResourceModel\Product\Indexer\TemporaryTableStrategy</argument> + </arguments> + </type> + <type name="Magento\Catalog\Model\Indexer\Product\Price\TableMaintainer"> + <arguments> + <argument name="connectionName" xsi:type="string">indexer</argument> + <argument name="tableResolver" xsi:type="object">Magento\Framework\Indexer\ScopeResolver\IndexScopeResolver</argument> + </arguments> + </type> + <type name="Magento\Catalog\Model\ResourceModel\Product\Indexer\Price\BasePriceModifier"> + <arguments> + <argument name="priceModifiers" xsi:type="array"> + <item name="customOptionPriceModifier" xsi:type="object">Magento\Catalog\Model\ResourceModel\Product\Indexer\Price\CustomOptionPriceModifier</item> + </argument> + </arguments> + </type> + <virtualType name="Magento\Catalog\Model\ResourceModel\Product\Indexer\Price\VirtualProductPrice" type="Magento\Catalog\Model\ResourceModel\Product\Indexer\Price\SimpleProductPrice"> + <arguments> + <argument name="productType" xsi:type="string">virtual</argument> + </arguments> + </virtualType> </config> diff --git a/app/code/Magento/Catalog/etc/frontend/di.xml b/app/code/Magento/Catalog/etc/frontend/di.xml index 659ba2b731366..55098037191e8 100644 --- a/app/code/Magento/Catalog/etc/frontend/di.xml +++ b/app/code/Magento/Catalog/etc/frontend/di.xml @@ -79,6 +79,18 @@ <argument name="typeId" xsi:type="string">recently_compared_product</argument> </arguments> </virtualType> + <type name="Magento\Framework\View\Element\Message\MessageConfigurationsPool"> + <arguments> + <argument name="configurationsMap" xsi:type="array"> + <item name="addCompareSuccessMessage" xsi:type="array"> + <item name="renderer" xsi:type="const">\Magento\Framework\View\Element\Message\Renderer\BlockRenderer::CODE</item> + <item name="data" xsi:type="array"> + <item name="template" xsi:type="string">Magento_Catalog::messages/addCompareSuccessMessage.phtml</item> + </item> + </item> + </argument> + </arguments> + </type> <type name="Magento\Catalog\Block\Product\View\Gallery"> <arguments> <argument name="galleryImagesConfig" xsi:type="array"> @@ -102,5 +114,6 @@ </type> <type name="Magento\Framework\App\ResourceConnection"> <plugin name="get_catalog_category_product_index_table_name" type="Magento\Catalog\Model\Indexer\Category\Product\Plugin\TableResolver"/> + <plugin name="get_catalog_product_price_index_table_name" type="Magento\Catalog\Model\Indexer\Product\Price\Plugin\TableResolver"/> </type> </config> diff --git a/app/code/Magento/Catalog/etc/product_types.xml b/app/code/Magento/Catalog/etc/product_types.xml index fe4922ab8fa1f..fdcb67ae484d2 100644 --- a/app/code/Magento/Catalog/etc/product_types.xml +++ b/app/code/Magento/Catalog/etc/product_types.xml @@ -7,11 +7,13 @@ --> <config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:module:Magento_Catalog:etc/product_types.xsd"> <type name="simple" label="Simple Product" modelInstance="Magento\Catalog\Model\Product\Type\Simple" indexPriority="10" sortOrder="10"> + <indexerModel instance="Magento\Catalog\Model\ResourceModel\Product\Indexer\Price\SimpleProductPrice" /> <customAttributes> <attribute name="refundable" value="true"/> </customAttributes> </type> <type name="virtual" label="Virtual Product" modelInstance="Magento\Catalog\Model\Product\Type\Virtual" indexPriority="20" sortOrder="40"> + <indexerModel instance="Magento\Catalog\Model\ResourceModel\Product\Indexer\Price\VirtualProductPrice" /> <customAttributes> <attribute name="is_real_product" value="false"/> <attribute name="refundable" value="false"/> diff --git a/app/code/Magento/Catalog/etc/webapi_rest/di.xml b/app/code/Magento/Catalog/etc/webapi_rest/di.xml index a0d3e850b3c64..2a5d60222e9f8 100644 --- a/app/code/Magento/Catalog/etc/webapi_rest/di.xml +++ b/app/code/Magento/Catalog/etc/webapi_rest/di.xml @@ -17,5 +17,6 @@ </type> <type name="Magento\Framework\App\ResourceConnection"> <plugin name="get_catalog_category_product_index_table_name" type="Magento\Catalog\Model\Indexer\Category\Product\Plugin\TableResolver"/> + <plugin name="get_catalog_product_price_index_table_name" type="Magento\Catalog\Model\Indexer\Product\Price\Plugin\TableResolver"/> </type> </config> diff --git a/app/code/Magento/Catalog/etc/webapi_soap/di.xml b/app/code/Magento/Catalog/etc/webapi_soap/di.xml index a0d3e850b3c64..2a5d60222e9f8 100644 --- a/app/code/Magento/Catalog/etc/webapi_soap/di.xml +++ b/app/code/Magento/Catalog/etc/webapi_soap/di.xml @@ -17,5 +17,6 @@ </type> <type name="Magento\Framework\App\ResourceConnection"> <plugin name="get_catalog_category_product_index_table_name" type="Magento\Catalog\Model\Indexer\Category\Product\Plugin\TableResolver"/> + <plugin name="get_catalog_product_price_index_table_name" type="Magento\Catalog\Model\Indexer\Product\Price\Plugin\TableResolver"/> </type> </config> diff --git a/app/code/Magento/Catalog/i18n/en_US.csv b/app/code/Magento/Catalog/i18n/en_US.csv index a399f67e3130f..f2a3ab8f83f24 100644 --- a/app/code/Magento/Catalog/i18n/en_US.csv +++ b/app/code/Magento/Catalog/i18n/en_US.csv @@ -13,8 +13,8 @@ Position,Position Day,Day Month,Month Year,Year -"<label class=""label""><span>from</span></label>","<label class=""label""><span>from</span></label>" -"<label class=""label""><span>to</span></label>","<label class=""label""><span>to</span></label>" +from,from +to,to [GLOBAL],[GLOBAL] [WEBSITE],[WEBSITE] "[STORE VIEW]","[STORE VIEW]" diff --git a/app/code/Magento/Catalog/view/adminhtml/requirejs-config.js b/app/code/Magento/Catalog/view/adminhtml/requirejs-config.js index 9053c700d1a3b..0677b0a5811c2 100644 --- a/app/code/Magento/Catalog/view/adminhtml/requirejs-config.js +++ b/app/code/Magento/Catalog/view/adminhtml/requirejs-config.js @@ -17,5 +17,18 @@ var config = { }, deps: [ 'Magento_Catalog/catalog/product' - ] + ], + config: { + mixins: { + 'Magento_Catalog/js/components/use-parent-settings/select': { + 'Magento_Catalog/js/components/use-parent-settings/toggle-disabled-mixin': true + }, + 'Magento_Catalog/js/components/use-parent-settings/textarea': { + 'Magento_Catalog/js/components/use-parent-settings/toggle-disabled-mixin': true + }, + 'Magento_Catalog/js/components/use-parent-settings/single-checkbox': { + 'Magento_Catalog/js/components/use-parent-settings/toggle-disabled-mixin': true + } + } + } }; diff --git a/app/code/Magento/Catalog/view/adminhtml/ui_component/category_form.xml b/app/code/Magento/Catalog/view/adminhtml/ui_component/category_form.xml index 2976f1be14fa5..dafea71f872d0 100644 --- a/app/code/Magento/Catalog/view/adminhtml/ui_component/category_form.xml +++ b/app/code/Magento/Catalog/view/adminhtml/ui_component/category_form.xml @@ -42,7 +42,7 @@ </settings> </dataProvider> </dataSource> - <fieldset name="general"> + <fieldset name="general" sortOrder="5"> <settings> <collapsible>false</collapsible> <label/> @@ -452,34 +452,34 @@ </checkbox> </formElements> </field> - <field name="custom_design" sortOrder="180" formElement="select"> + <field name="custom_design" component="Magento_Catalog/js/components/use-parent-settings/select" sortOrder="180" formElement="select"> <settings> <dataType>string</dataType> <label translate="true">Theme</label> <imports> - <link name="disabled">${ $.parentName }.custom_use_parent_settings:checked</link> + <link name="serviceDisabled">${ $.parentName }.custom_use_parent_settings:checked</link> </imports> </settings> </field> - <field name="page_layout" sortOrder="190" formElement="select" class="Magento\Catalog\Ui\Component\Form\Field\Category\PageLayout"> + <field name="page_layout" sortOrder="190" formElement="select" component="Magento_Catalog/js/components/use-parent-settings/select" class="Magento\Catalog\Ui\Component\Form\Field\Category\PageLayout"> <settings> <dataType>string</dataType> <label translate="true">Layout</label> <imports> - <link name="disabled">${ $.parentName }.custom_use_parent_settings:checked</link> + <link name="serviceDisabled">${ $.parentName }.custom_use_parent_settings:checked</link> </imports> </settings> </field> - <field name="custom_layout_update" sortOrder="200" formElement="textarea"> + <field name="custom_layout_update" component="Magento_Catalog/js/components/use-parent-settings/textarea" sortOrder="200" formElement="textarea"> <settings> <dataType>string</dataType> <label translate="true">Layout Update XML</label> <imports> - <link name="disabled">ns = ${ $.ns }, index = custom_use_parent_settings :checked</link> + <link name="serviceDisabled">${ $.parentName }.custom_use_parent_settings:checked</link> </imports> </settings> </field> - <field name="custom_apply_to_products" component="Magento_Ui/js/form/element/single-checkbox" sortOrder="210" formElement="checkbox"> + <field name="custom_apply_to_products" component="Magento_Catalog/js/components/use-parent-settings/single-checkbox" sortOrder="210" formElement="checkbox"> <argument name="data" xsi:type="array"> <item name="config" xsi:type="array"> <item name="default" xsi:type="number">0</item> @@ -492,7 +492,7 @@ <dataType>boolean</dataType> <label translate="true">Apply Design to Products</label> <imports> - <link name="disabled">ns = ${ $.ns }, index = custom_use_parent_settings:checked</link> + <link name="serviceDisabled">${ $.parentName }.custom_use_parent_settings:checked</link> </imports> </settings> <formElements> diff --git a/app/code/Magento/Catalog/view/adminhtml/web/js/components/use-parent-settings/select.js b/app/code/Magento/Catalog/view/adminhtml/web/js/components/use-parent-settings/select.js new file mode 100644 index 0000000000000..1ddb24f3eefbb --- /dev/null +++ b/app/code/Magento/Catalog/view/adminhtml/web/js/components/use-parent-settings/select.js @@ -0,0 +1,15 @@ +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ + +/** + * @api + */ +define([ + 'Magento_Ui/js/form/element/select' +], function (Component) { + 'use strict'; + + return Component; +}); diff --git a/app/code/Magento/Catalog/view/adminhtml/web/js/components/use-parent-settings/single-checkbox.js b/app/code/Magento/Catalog/view/adminhtml/web/js/components/use-parent-settings/single-checkbox.js new file mode 100644 index 0000000000000..0f166d3b45582 --- /dev/null +++ b/app/code/Magento/Catalog/view/adminhtml/web/js/components/use-parent-settings/single-checkbox.js @@ -0,0 +1,15 @@ +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ + +/** + * @api + */ +define([ + 'Magento_Ui/js/form/element/single-checkbox' +], function (Component) { + 'use strict'; + + return Component; +}); diff --git a/app/code/Magento/Catalog/view/adminhtml/web/js/components/use-parent-settings/textarea.js b/app/code/Magento/Catalog/view/adminhtml/web/js/components/use-parent-settings/textarea.js new file mode 100644 index 0000000000000..3ef2bb21241a7 --- /dev/null +++ b/app/code/Magento/Catalog/view/adminhtml/web/js/components/use-parent-settings/textarea.js @@ -0,0 +1,15 @@ +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ + +/** + * @api + */ +define([ + 'Magento_Ui/js/form/element/textarea' +], function (Component) { + 'use strict'; + + return Component; +}); diff --git a/app/code/Magento/Catalog/view/adminhtml/web/js/components/use-parent-settings/toggle-disabled-mixin.js b/app/code/Magento/Catalog/view/adminhtml/web/js/components/use-parent-settings/toggle-disabled-mixin.js new file mode 100644 index 0000000000000..d140cc0fad74e --- /dev/null +++ b/app/code/Magento/Catalog/view/adminhtml/web/js/components/use-parent-settings/toggle-disabled-mixin.js @@ -0,0 +1,62 @@ +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ + +define([ + 'underscore' +], function (_) { + 'use strict'; + + var mixin = { + defaults: { + imports: { + toggleDisabled: '${ $.parentName }.custom_use_parent_settings:checked' + }, + useParent: false, + useDefaults: false + }, + + /** + * Disable form input if settings for parent section is used + * or default value is applied. + * + * @param {Boolean} isUseParent + */ + toggleDisabled: function (isUseParent) { + var disabled = this.useParent = isUseParent; + + if (!disabled && !_.isUndefined(this.service)) { + disabled = !!this.isUseDefault(); + } + + this.saveUseDefaults(); + this.disabled(disabled); + }, + + /** + * Stores original state of the field. + */ + saveUseDefaults: function () { + this.useDefaults = this.disabled(); + }, + + /** @inheritdoc */ + setInitialValue: function () { + this._super(); + this.isUseDefault(this.useDefaults); + + return this; + }, + + /** @inheritdoc */ + toggleUseDefault: function (state) { + this._super(); + this.disabled(state || this.useParent); + } + }; + + return function (target) { + return target.extend(mixin); + }; +}); diff --git a/app/code/Magento/Catalog/view/base/templates/product/price/amount/default.phtml b/app/code/Magento/Catalog/view/base/templates/product/price/amount/default.phtml index 86168c742c0f1..ce1561e382eed 100644 --- a/app/code/Magento/Catalog/view/base/templates/product/price/amount/default.phtml +++ b/app/code/Magento/Catalog/view/base/templates/product/price/amount/default.phtml @@ -19,9 +19,8 @@ <?= ($block->getPriceDisplayLabel()) ? 'data-label="' . $block->getPriceDisplayLabel() . $block->getPriceDisplayInclExclTaxes() . '"' : '' ?> data-price-amount="<?= /* @escapeNotVerified */ $block->getDisplayValue() ?>" data-price-type="<?= /* @escapeNotVerified */ $block->getPriceType() ?>" - class="price-wrapper <?= /* @escapeNotVerified */ $block->getPriceWrapperCss() ?>"> - <?= /* @escapeNotVerified */ $block->formatCurrency($block->getDisplayValue(), (bool)$block->getIncludeContainer()) ?> - </span> + class="price-wrapper <?= /* @escapeNotVerified */ $block->getPriceWrapperCss() ?>" + ><?= /* @escapeNotVerified */ $block->formatCurrency($block->getDisplayValue(), (bool)$block->getIncludeContainer()) ?></span> <?php if ($block->hasAdjustmentsHtml()): ?> <?= $block->getAdjustmentsHtml() ?> <?php endif; ?> diff --git a/app/code/Magento/Catalog/view/frontend/templates/messages/addCompareSuccessMessage.phtml b/app/code/Magento/Catalog/view/frontend/templates/messages/addCompareSuccessMessage.phtml new file mode 100644 index 0000000000000..5f44c42e17c57 --- /dev/null +++ b/app/code/Magento/Catalog/view/frontend/templates/messages/addCompareSuccessMessage.phtml @@ -0,0 +1,14 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +// @codingStandardsIgnoreFile +/** @var \Magento\Framework\View\Element\Template $block */ +?> +<?= $block->escapeHtml(__( + 'You added product %1 to the <a href="%2">comparison list</a>.', + $block->getData('product_name'), + $block->getData('compare_list_url')), + ['a'] +); diff --git a/app/code/Magento/Catalog/view/frontend/templates/product/breadcrumbs.phtml b/app/code/Magento/Catalog/view/frontend/templates/product/breadcrumbs.phtml index c54ce5340851c..c4aa84704b598 100644 --- a/app/code/Magento/Catalog/view/frontend/templates/product/breadcrumbs.phtml +++ b/app/code/Magento/Catalog/view/frontend/templates/product/breadcrumbs.phtml @@ -7,4 +7,9 @@ /** @var \Magento\Catalog\ViewModel\Product\Breadcrumbs $viewModel */ $viewModel = $block->getData('viewModel'); ?> -<div class="breadcrumbs" data-mage-init='<?= /* @escapeNotVerified */ $viewModel->getJsonConfiguration() ?>'></div> +<div class="breadcrumbs"></div> +<script type="text/x-magento-init"> + { + ".breadcrumbs": <?= $viewModel->getJsonConfigurationHtmlEscaped() ?> + } +</script> diff --git a/app/code/Magento/Catalog/view/frontend/web/js/product/storage/storage-service.js b/app/code/Magento/Catalog/view/frontend/web/js/product/storage/storage-service.js index 014002bdc4af9..e571baa23e497 100644 --- a/app/code/Magento/Catalog/view/frontend/web/js/product/storage/storage-service.js +++ b/app/code/Magento/Catalog/view/frontend/web/js/product/storage/storage-service.js @@ -47,7 +47,7 @@ define([ * @param {*} data */ add: function (data) { - if (!utils.compare(data, this.data()).equal) { + if (!_.isEmpty(data) && !utils.compare(data, this.data()).equal) { this.data(_.extend(utils.copy(this.data()), data)); } }, diff --git a/app/code/Magento/CatalogAnalytics/Test/Mftf/composer.json b/app/code/Magento/CatalogAnalytics/Test/Mftf/composer.json deleted file mode 100644 index c03b128d9ad83..0000000000000 --- a/app/code/Magento/CatalogAnalytics/Test/Mftf/composer.json +++ /dev/null @@ -1,17 +0,0 @@ -{ - "name": "magento/functional-test-module-catalog-analytics", - "description": "N/A", - "config": { - "sort-packages": true - }, - "require": { - "php": "~7.1.3||~7.2.0", - "magento/magento2-functional-testing-framework": "2.2.0", - "magento/functional-test-module-catalog": "100.0.0-dev" - }, - "type": "magento2-test", - "license": [ - "OSL-3.0", - "AFL-3.0" - ] -} diff --git a/app/code/Magento/CatalogGraphQl/Test/Mftf/composer.json b/app/code/Magento/CatalogGraphQl/Test/Mftf/composer.json deleted file mode 100644 index 81a291e1527fc..0000000000000 --- a/app/code/Magento/CatalogGraphQl/Test/Mftf/composer.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "name": "magento/functional-test-module-catalog-graph-ql", - "description": "N/A", - "config": { - "sort-packages": true - }, - "require": { - "php": "~7.1.3||~7.2.0", - "magento/functional-test-module-eav": "100.0.0-dev", - "magento/functional-test-module-catalog": "100.0.0-dev", - "magento/functional-test-module-catalog-inventory": "100.0.0-dev", - "magento/functional-test-module-search": "100.0.0-dev", - "magento/functional-test-module-store": "100.0.0-dev", - "magento/functional-test-module-eav-graph-ql": "100.0.0-dev", - "magento/magento2-functional-testing-framework": "2.2.0" - }, - "suggest": { - "magento/functional-test-module-graph-ql": "100.0.0-dev", - "magento/functional-test-module-store-graph-ql": "100.0.0-dev" - }, - "type": "magento2-test", - "license": [ - "OSL-3.0", - "AFL-3.0" - ] -} diff --git a/app/code/Magento/CatalogImportExport/Test/Mftf/composer.json b/app/code/Magento/CatalogImportExport/Test/Mftf/composer.json deleted file mode 100644 index 1f223fc5f46b5..0000000000000 --- a/app/code/Magento/CatalogImportExport/Test/Mftf/composer.json +++ /dev/null @@ -1,25 +0,0 @@ -{ - "name": "magento/functional-test-module-catalog-import-export", - "description": "N/A", - "config": { - "sort-packages": true - }, - "require": { - "php": "~7.1.3||~7.2.0", - "magento/magento2-functional-testing-framework": "2.2.0", - "magento/functional-test-module-catalog": "100.0.0-dev", - "magento/functional-test-module-catalog-inventory": "100.0.0-dev", - "magento/functional-test-module-catalog-url-rewrite": "100.0.0-dev", - "magento/functional-test-module-customer": "100.0.0-dev", - "magento/functional-test-module-eav": "100.0.0-dev", - "magento/functional-test-module-import-export": "100.0.0-dev", - "magento/functional-test-module-media-storage": "100.0.0-dev", - "magento/functional-test-module-store": "100.0.0-dev", - "magento/functional-test-module-tax": "100.0.0-dev" - }, - "type": "magento2-test", - "license": [ - "OSL-3.0", - "AFL-3.0" - ] -} diff --git a/app/code/Magento/CatalogInventory/Api/StockRegistryInterface.php b/app/code/Magento/CatalogInventory/Api/StockRegistryInterface.php index c9b6abeb72e23..2d011e24f4105 100644 --- a/app/code/Magento/CatalogInventory/Api/StockRegistryInterface.php +++ b/app/code/Magento/CatalogInventory/Api/StockRegistryInterface.php @@ -72,7 +72,7 @@ public function getProductStockStatusBySku($productSku, $scopeId = null); * @param float $qty * @param int $currentPage * @param int $pageSize - * @return \Magento\CatalogInventory\Api\Data\StockStatusCollectionInterface + * @return \Magento\CatalogInventory\Api\Data\StockItemCollectionInterface */ public function getLowStockItems($scopeId, $qty, $currentPage = 1, $pageSize = 0); diff --git a/app/code/Magento/CatalogInventory/Model/Indexer/ProductPriceIndexFilter.php b/app/code/Magento/CatalogInventory/Model/Indexer/ProductPriceIndexFilter.php new file mode 100644 index 0000000000000..5e7210c1b7444 --- /dev/null +++ b/app/code/Magento/CatalogInventory/Model/Indexer/ProductPriceIndexFilter.php @@ -0,0 +1,107 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +declare(strict_types=1); + +namespace Magento\CatalogInventory\Model\Indexer; + +use Magento\CatalogInventory\Api\StockConfigurationInterface; +use Magento\CatalogInventory\Model\ResourceModel\Stock\Item; +use Magento\CatalogInventory\Model\Stock; +use Magento\Catalog\Model\ResourceModel\Product\Indexer\Price\PriceModifierInterface; +use Magento\Catalog\Model\ResourceModel\Product\Indexer\Price\IndexTableStructure; +use Magento\Framework\App\ResourceConnection; +use Magento\Framework\App\ObjectManager; + +/** + * Class for filter product price index. + */ +class ProductPriceIndexFilter implements PriceModifierInterface +{ + /** + * @var StockConfigurationInterface + */ + private $stockConfiguration; + + /** + * @var Item + */ + private $stockItem; + + /** + * @var ResourceConnection + */ + private $resourceConnection; + + /** + * @var string + */ + private $connectionName; + + /** + * @param StockConfigurationInterface $stockConfiguration + * @param Item $stockItem + * @param ResourceConnection $resourceConnection + * @param string $connectionName + */ + public function __construct( + StockConfigurationInterface $stockConfiguration, + Item $stockItem, + ResourceConnection $resourceConnection = null, + $connectionName = 'indexer' + ) { + $this->stockConfiguration = $stockConfiguration; + $this->stockItem = $stockItem; + $this->resourceConnection = $resourceConnection ?: ObjectManager::getInstance()->get(ResourceConnection::class); + $this->connectionName = $connectionName; + } + + /** + * Remove out of stock products data from price index. + * + * @param IndexTableStructure $priceTable + * @param array $entityIds + * @return void + * + * @throws \Magento\Framework\Exception\LocalizedException + * @SuppressWarnings(PHPMD.UnusedFormalParameter) + */ + public function modifyPrice(IndexTableStructure $priceTable, array $entityIds = []) : void + { + if ($this->stockConfiguration->isShowOutOfStock()) { + return; + } + + $connection = $this->resourceConnection->getConnection($this->connectionName); + $select = $connection->select(); + $select->from( + ['price_index' => $priceTable->getTableName()], + [] + ); + $select->joinInner( + ['stock_item' => $this->stockItem->getMainTable()], + 'stock_item.product_id = price_index.' . $priceTable->getEntityField() + . ' AND stock_item.stock_id = ' . Stock::DEFAULT_STOCK_ID, + [] + ); + if ($this->stockConfiguration->getManageStock()) { + $stockStatus = $connection->getCheckSql( + 'use_config_manage_stock = 0 AND manage_stock = 0', + Stock::STOCK_IN_STOCK, + 'is_in_stock' + ); + } else { + $stockStatus = $connection->getCheckSql( + 'use_config_manage_stock = 0 AND manage_stock = 1', + 'is_in_stock', + Stock::STOCK_IN_STOCK + ); + } + $select->where($stockStatus . ' = ?', Stock::STOCK_OUT_OF_STOCK); + + $query = $select->deleteFromSelect('price_index'); + $connection->query($query); + } +} diff --git a/app/code/Magento/CatalogInventory/Model/Plugin/PriceIndexUpdater.php b/app/code/Magento/CatalogInventory/Model/Plugin/PriceIndexUpdater.php new file mode 100644 index 0000000000000..c061c459bfb49 --- /dev/null +++ b/app/code/Magento/CatalogInventory/Model/Plugin/PriceIndexUpdater.php @@ -0,0 +1,79 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +declare(strict_types=1); + +namespace Magento\CatalogInventory\Model\Plugin; + +use Magento\CatalogInventory\Model\ResourceModel\Stock\Item; +use Magento\Catalog\Model\Indexer\Product\Price\Processor; +use Magento\Framework\Model\AbstractModel; + +/** + * Update product price index after product stock status changed. + */ +class PriceIndexUpdater +{ + /** + * @var Processor + */ + private $priceIndexProcessor; + + /** + * @param Processor $priceIndexProcessor + */ + public function __construct(Processor $priceIndexProcessor) + { + $this->priceIndexProcessor = $priceIndexProcessor; + } + + /** + * @param Item $subject + * @param Item $result + * @param AbstractModel $model + * @return Item + * @SuppressWarnings(PHPMD.UnusedFormalParameter) + */ + public function afterSave(Item $subject, Item $result, AbstractModel $model): Item + { + $fields = [ + 'is_in_stock', + 'use_config_manage_stock', + 'manage_stock', + ]; + foreach ($fields as $field) { + if ($model->dataHasChangedFor($field)) { + $this->priceIndexProcessor->reindexRow($model->getProductId()); + break; + } + } + + return $result; + } + + /** + * @param Item $subject + * @param mixed $result + * @param int $websiteId + * @return void + * @SuppressWarnings(PHPMD.UnusedFormalParameter) + */ + public function afterUpdateSetOutOfStock(Item $subject, $result, int $websiteId) + { + $this->priceIndexProcessor->markIndexerAsInvalid(); + } + + /** + * @param Item $subject + * @param mixed $result + * @param int $websiteId + * @return void + * @SuppressWarnings(PHPMD.UnusedFormalParameter) + */ + public function afterUpdateSetInStock(Item $subject, $result, int $websiteId) + { + $this->priceIndexProcessor->markIndexerAsInvalid(); + } +} diff --git a/app/code/Magento/CatalogInventory/Model/ResourceModel/Stock.php b/app/code/Magento/CatalogInventory/Model/ResourceModel/Stock.php index f1dc9715fd247..53f00529b9bcc 100644 --- a/app/code/Magento/CatalogInventory/Model/ResourceModel/Stock.php +++ b/app/code/Magento/CatalogInventory/Model/ResourceModel/Stock.php @@ -119,7 +119,7 @@ protected function _construct() * @param int $websiteId * @return array */ - public function lockProductsStock(array $productIds, int $websiteId) + public function lockProductsStock(array $productIds, $websiteId) { if (empty($productIds)) { return []; @@ -206,6 +206,8 @@ protected function _initConfig() /** * Set items out of stock basing on their quantities and config settings * + * @deprecated + * @see \Magento\CatalogInventory\Model\ResourceModel\Stock\Item::updateSetOutOfStock * @param string|int $website * @SuppressWarnings(PHPMD.UnusedFormalParameter) * @return void @@ -241,6 +243,8 @@ public function updateSetOutOfStock($website = null) /** * Set items in stock basing on their quantities and config settings * + * @deprecated + * @see \Magento\CatalogInventory\Model\ResourceModel\Stock\Item::updateSetInStock * @param int|string $website * @SuppressWarnings(PHPMD.UnusedFormalParameter) * @return void @@ -274,6 +278,8 @@ public function updateSetInStock($website) /** * Update items low stock date basing on their quantities and config settings * + * @deprecated + * @see \Magento\CatalogInventory\Model\ResourceModel\Stock\Item::updateLowStockDate * @param int|string $website * @SuppressWarnings(PHPMD.UnusedFormalParameter) * @return void diff --git a/app/code/Magento/CatalogInventory/Model/ResourceModel/Stock/Item.php b/app/code/Magento/CatalogInventory/Model/ResourceModel/Stock/Item.php index 895fffaa4f80b..ce8930ad4f7a6 100644 --- a/app/code/Magento/CatalogInventory/Model/ResourceModel/Stock/Item.php +++ b/app/code/Magento/CatalogInventory/Model/ResourceModel/Stock/Item.php @@ -6,10 +6,14 @@ namespace Magento\CatalogInventory\Model\ResourceModel\Stock; use Magento\CatalogInventory\Api\Data\StockItemInterface; +use Magento\CatalogInventory\Api\StockConfigurationInterface; +use Magento\CatalogInventory\Model\Stock; use Magento\CatalogInventory\Model\Indexer\Stock\Processor; -use Magento\Framework\App\ResourceConnection as AppResource; use Magento\Framework\Model\AbstractModel; -use Magento\Framework\Model\ResourceModel\Db\TransactionManagerInterface; +use Magento\Framework\Model\ResourceModel\Db\Context; +use Magento\Framework\DB\Select; +use Magento\Framework\App\ObjectManager; +use Magento\Framework\Stdlib\DateTime\DateTime; /** * Stock item resource model @@ -29,17 +33,36 @@ class Item extends \Magento\Framework\Model\ResourceModel\Db\AbstractDb protected $stockIndexerProcessor; /** - * @param \Magento\Framework\Model\ResourceModel\Db\Context $context + * @var StockConfigurationInterface + */ + private $stockConfiguration; + + /** + * @var DateTime + */ + private $dateTime; + + /** + * @param Context $context * @param Processor $processor * @param string $connectionName + * @param StockConfigurationInterface $stockConfiguration + * @param DateTime $dateTime */ public function __construct( - \Magento\Framework\Model\ResourceModel\Db\Context $context, + Context $context, Processor $processor, - $connectionName = null + $connectionName = null, + StockConfigurationInterface $stockConfiguration = null, + DateTime $dateTime = null ) { $this->stockIndexerProcessor = $processor; parent::__construct($context, $connectionName); + + $this->stockConfiguration = $stockConfiguration ?? + ObjectManager::getInstance()->get(StockConfigurationInterface::class); + $this->dateTime = $dateTime ?? + ObjectManager::getInstance()->get(DateTime::class); } /** @@ -139,4 +162,160 @@ public function setProcessIndexEvents($process = true) $this->processIndexEvents = $process; return $this; } + + /** + * Set items out of stock basing on their quantities and config settings + * + * @param int $websiteId + * @return void + */ + public function updateSetOutOfStock(int $websiteId) + { + $connection = $this->getConnection(); + + $values = [ + 'is_in_stock' => Stock::STOCK_OUT_OF_STOCK, + 'stock_status_changed_auto' => 1, + ]; + $select = $this->buildProductsSelectByConfigTypes(); + $where = [ + 'website_id = ' . $websiteId, + 'is_in_stock = ' . Stock::STOCK_IN_STOCK, + '(use_config_manage_stock = 1 AND 1 = ' . $this->stockConfiguration->getManageStock() . ')' + . ' OR (use_config_manage_stock = 0 AND manage_stock = 1)', + '(use_config_min_qty = 1 AND qty <= ' . $this->stockConfiguration->getMinQty() . ')' + . ' OR (use_config_min_qty = 0 AND qty <= min_qty)', + 'product_id IN (' . $select->assemble() . ')', + ]; + $backordersWhere = '(use_config_backorders = 0 AND backorders = ' . Stock::BACKORDERS_NO . ')'; + if (Stock::BACKORDERS_NO == $this->stockConfiguration->getBackorders()) { + $where[] = $backordersWhere . ' OR use_config_backorders = 1'; + } else { + $where[] = $backordersWhere; + } + $connection->update($this->getMainTable(), $values, $where); + + $this->stockIndexerProcessor->markIndexerAsInvalid(); + } + + /** + * Set items in stock basing on their quantities and config settings + * + * @param int $websiteId + * @return void + */ + public function updateSetInStock(int $websiteId) + { + $connection = $this->getConnection(); + + $values = [ + 'is_in_stock' => Stock::STOCK_IN_STOCK, + ]; + $select = $this->buildProductsSelectByConfigTypes(); + $where = [ + 'website_id = ' . $websiteId, + 'stock_status_changed_auto = 1', + '(use_config_min_qty = 1 AND qty > ' . $this->stockConfiguration->getMinQty() . ')' + . ' OR (use_config_min_qty = 0 AND qty > min_qty)', + 'product_id IN (' . $select->assemble() . ')', + ]; + $manageStockWhere = '(use_config_manage_stock = 0 AND manage_stock = 1)'; + if ($this->stockConfiguration->getManageStock()) { + $where[] = $manageStockWhere . ' OR use_config_manage_stock = 1'; + } else { + $where[] = $manageStockWhere; + } + $connection->update($this->getMainTable(), $values, $where); + + $this->stockIndexerProcessor->markIndexerAsInvalid(); + } + + /** + * Update items low stock date basing on their quantities and config settings + * + * @param int $websiteId + * @return void + */ + public function updateLowStockDate(int $websiteId) + { + $connection = $this->getConnection(); + + $condition = $connection->quoteInto( + '(use_config_notify_stock_qty = 1 AND qty < ?)', + $this->stockConfiguration->getNotifyStockQty() + ) . ' OR (use_config_notify_stock_qty = 0 AND qty < notify_stock_qty)'; + $currentDbTime = $connection->quoteInto('?', $this->dateTime->gmtDate()); + $conditionalDate = $connection->getCheckSql($condition, $currentDbTime, 'NULL'); + $value = [ + 'low_stock_date' => new \Zend_Db_Expr($conditionalDate), + ]; + $select = $this->buildProductsSelectByConfigTypes(); + $where = [ + 'website_id = ' . $websiteId, + 'product_id IN (' . $select->assemble() . ')' + ]; + $manageStockWhere = '(use_config_manage_stock = 0 AND manage_stock = 1)'; + if ($this->stockConfiguration->getManageStock()) { + $where[] = $manageStockWhere . ' OR use_config_manage_stock = 1'; + } else { + $where[] = $manageStockWhere; + } + $connection->update($this->getMainTable(), $value, $where); + } + + public function getManageStockExpr(string $tableAlias = ''): \Zend_Db_Expr + { + if ($tableAlias) { + $tableAlias .= '.'; + } + $manageStock = $this->getConnection()->getCheckSql( + $tableAlias . 'use_config_manage_stock = 1', + $this->stockConfiguration->getManageStock(), + $tableAlias . 'manage_stock' + ); + + return $manageStock; + } + + public function getBackordersExpr(string $tableAlias = ''): \Zend_Db_Expr + { + if ($tableAlias) { + $tableAlias .= '.'; + } + $itemBackorders = $this->getConnection()->getCheckSql( + $tableAlias . 'use_config_backorders = 1', + $this->stockConfiguration->getBackorders(), + $tableAlias . 'backorders' + ); + + return $itemBackorders; + } + + public function getMinSaleQtyExpr(string $tableAlias = ''): \Zend_Db_Expr + { + if ($tableAlias) { + $tableAlias .= '.'; + } + $itemMinSaleQty = $this->getConnection()->getCheckSql( + $tableAlias . 'use_config_min_sale_qty = 1', + $this->stockConfiguration->getMinSaleQty(), + $tableAlias . 'min_sale_qty' + ); + + return $itemMinSaleQty; + } + + /** + * Build select for products with types from config + * + * @return Select + */ + private function buildProductsSelectByConfigTypes(): Select + { + $select = $this->getConnection()->select() + ->from($this->getTable('catalog_product_entity'), 'entity_id') + ->where('type_id IN (?)', array_keys($this->stockConfiguration->getIsQtyTypeIds(true))); + + return $select; + } } diff --git a/app/code/Magento/CatalogInventory/Model/StockStateProvider.php b/app/code/Magento/CatalogInventory/Model/StockStateProvider.php index ea4fdc994d682..fb6fc3be61375 100644 --- a/app/code/Magento/CatalogInventory/Model/StockStateProvider.php +++ b/app/code/Magento/CatalogInventory/Model/StockStateProvider.php @@ -160,7 +160,7 @@ public function checkQuoteItemQty(StockItemInterface $stockItem, $qty, $summaryQ } if (!$this->checkQty($stockItem, $summaryQty) || !$this->checkQty($stockItem, $qty)) { - $message = __('We don\'t have as many "%1" as you requested.', $stockItem->getProductName()); + $message = __('The requested qty is not available'); $result->setHasError(true)->setMessage($message)->setQuoteMessage($message)->setQuoteMessageIndex('qty'); return $result; } else { @@ -212,7 +212,7 @@ public function checkQuoteItemQty(StockItemInterface $stockItem, $qty, $summaryQ } } elseif ($stockItem->getShowDefaultNotificationMessage()) { $result->setMessage( - __('We don\'t have as many "%1" as you requested.', $stockItem->getProductName()) + __('The requested qty is not available') ); } } diff --git a/app/code/Magento/CatalogInventory/Observer/InvalidatePriceIndexUponConfigChangeObserver.php b/app/code/Magento/CatalogInventory/Observer/InvalidatePriceIndexUponConfigChangeObserver.php new file mode 100644 index 0000000000000..976110ec76cf3 --- /dev/null +++ b/app/code/Magento/CatalogInventory/Observer/InvalidatePriceIndexUponConfigChangeObserver.php @@ -0,0 +1,49 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +declare(strict_types=1); + +namespace Magento\CatalogInventory\Observer; + +use Magento\Framework\Event\ObserverInterface; +use Magento\Framework\Event\Observer; +use Magento\CatalogInventory\Model\Configuration; +use Magento\Catalog\Model\Indexer\Product\Price\Processor; + +/** + * Catalog inventory config changes module observer. + */ +class InvalidatePriceIndexUponConfigChangeObserver implements ObserverInterface +{ + /** + * @var Processor + */ + private $priceIndexProcessor; + + /** + * @param Processor $priceIndexProcessor + */ + public function __construct(Processor $priceIndexProcessor) + { + $this->priceIndexProcessor = $priceIndexProcessor; + } + + /** + * Invalidate product price index on catalog inventory config changes. + * + * @param Observer $observer + * @return void + * @SuppressWarnings(PHPMD.UnusedFormalParameter) + */ + public function execute(Observer $observer) + { + $changedPaths = (array) $observer->getEvent()->getChangedPaths(); + + if (\in_array(Configuration::XML_PATH_SHOW_OUT_OF_STOCK, $changedPaths, true)) { + $priceIndexer = $this->priceIndexProcessor->getIndexer(); + $priceIndexer->invalidate(); + } + } +} diff --git a/app/code/Magento/CatalogInventory/Observer/UpdateItemsStockUponConfigChangeObserver.php b/app/code/Magento/CatalogInventory/Observer/UpdateItemsStockUponConfigChangeObserver.php index 47ee6512920d8..21c78eca93695 100644 --- a/app/code/Magento/CatalogInventory/Observer/UpdateItemsStockUponConfigChangeObserver.php +++ b/app/code/Magento/CatalogInventory/Observer/UpdateItemsStockUponConfigChangeObserver.php @@ -3,11 +3,12 @@ * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ - namespace Magento\CatalogInventory\Observer; use Magento\Framework\Event\Observer as EventObserver; use Magento\Framework\Event\ObserverInterface; +use Magento\CatalogInventory\Model\Configuration; +use Magento\CatalogInventory\Model\ResourceModel\Stock\Item; /** * Catalog inventory module observer @@ -15,16 +16,16 @@ class UpdateItemsStockUponConfigChangeObserver implements ObserverInterface { /** - * @var \Magento\CatalogInventory\Model\ResourceModel\Stock + * @var Item */ - protected $resourceStock; + protected $resourceStockItem; /** - * @param \Magento\CatalogInventory\Model\ResourceModel\Stock $resourceStock + * @param Item $resourceStockItem */ - public function __construct(\Magento\CatalogInventory\Model\ResourceModel\Stock $resourceStock) + public function __construct(Item $resourceStockItem) { - $this->resourceStock = $resourceStock; + $this->resourceStockItem = $resourceStockItem; } /** @@ -35,9 +36,18 @@ public function __construct(\Magento\CatalogInventory\Model\ResourceModel\Stock */ public function execute(EventObserver $observer) { - $website = $observer->getEvent()->getWebsite(); - $this->resourceStock->updateSetOutOfStock($website); - $this->resourceStock->updateSetInStock($website); - $this->resourceStock->updateLowStockDate($website); + $website = (int) $observer->getEvent()->getWebsite(); + $changedPaths = (array) $observer->getEvent()->getChangedPaths(); + + if (\array_intersect([ + Configuration::XML_PATH_MANAGE_STOCK, + Configuration::XML_PATH_MIN_QTY, + Configuration::XML_PATH_BACKORDERS, + Configuration::XML_PATH_NOTIFY_STOCK_QTY, + ], $changedPaths)) { + $this->resourceStockItem->updateSetOutOfStock($website); + $this->resourceStockItem->updateSetInStock($website); + $this->resourceStockItem->updateLowStockDate($website); + } } } diff --git a/app/code/Magento/CatalogInventory/Test/Mftf/composer.json b/app/code/Magento/CatalogInventory/Test/Mftf/composer.json deleted file mode 100644 index afd8d3ddb661a..0000000000000 --- a/app/code/Magento/CatalogInventory/Test/Mftf/composer.json +++ /dev/null @@ -1,23 +0,0 @@ -{ - "name": "magento/functional-test-module-catalog-inventory", - "description": "N/A", - "config": { - "sort-packages": true - }, - "require": { - "php": "~7.1.3||~7.2.0", - "magento/magento2-functional-testing-framework": "2.2.0", - "magento/functional-test-module-catalog": "100.0.0-dev", - "magento/functional-test-module-config": "100.0.0-dev", - "magento/functional-test-module-customer": "100.0.0-dev", - "magento/functional-test-module-eav": "100.0.0-dev", - "magento/functional-test-module-quote": "100.0.0-dev", - "magento/functional-test-module-store": "100.0.0-dev", - "magento/functional-test-module-ui": "100.0.0-dev" - }, - "type": "magento2-test", - "license": [ - "OSL-3.0", - "AFL-3.0" - ] -} diff --git a/app/code/Magento/CatalogInventory/Test/Unit/Observer/UpdateItemsStockUponConfigChangeObserverTest.php b/app/code/Magento/CatalogInventory/Test/Unit/Observer/UpdateItemsStockUponConfigChangeObserverTest.php index 70a179b484379..7b82b5927d22c 100644 --- a/app/code/Magento/CatalogInventory/Test/Unit/Observer/UpdateItemsStockUponConfigChangeObserverTest.php +++ b/app/code/Magento/CatalogInventory/Test/Unit/Observer/UpdateItemsStockUponConfigChangeObserverTest.php @@ -15,9 +15,9 @@ class UpdateItemsStockUponConfigChangeObserverTest extends \PHPUnit\Framework\Te protected $observer; /** - * @var \Magento\CatalogInventory\Model\ResourceModel\Stock|\PHPUnit_Framework_MockObject_MockObject + * @var \Magento\CatalogInventory\Model\ResourceModel\Stock\Item|\PHPUnit_Framework_MockObject_MockObject */ - protected $resourceStock; + protected $resourceStockItem; /** * @var \Magento\Framework\Event|\PHPUnit_Framework_MockObject_MockObject @@ -31,11 +31,11 @@ class UpdateItemsStockUponConfigChangeObserverTest extends \PHPUnit\Framework\Te protected function setUp() { - $this->resourceStock = $this->createMock(\Magento\CatalogInventory\Model\ResourceModel\Stock::class); + $this->resourceStockItem = $this->createMock(\Magento\CatalogInventory\Model\ResourceModel\Stock\Item::class); $this->event = $this->getMockBuilder(\Magento\Framework\Event::class) ->disableOriginalConstructor() - ->setMethods(['getWebsite']) + ->setMethods(['getWebsite', 'getChangedPaths']) ->getMock(); $this->eventObserver = $this->getMockBuilder(\Magento\Framework\Event\Observer::class) @@ -50,7 +50,7 @@ protected function setUp() $this->observer = (new \Magento\Framework\TestFramework\Unit\Helper\ObjectManager($this))->getObject( \Magento\CatalogInventory\Observer\UpdateItemsStockUponConfigChangeObserver::class, [ - 'resourceStock' => $this->resourceStock, + 'resourceStockItem' => $this->resourceStockItem, ] ); } @@ -58,13 +58,16 @@ protected function setUp() public function testUpdateItemsStockUponConfigChange() { $websiteId = 1; - $this->resourceStock->expects($this->once())->method('updateSetOutOfStock'); - $this->resourceStock->expects($this->once())->method('updateSetInStock'); - $this->resourceStock->expects($this->once())->method('updateLowStockDate'); + $this->resourceStockItem->expects($this->once())->method('updateSetOutOfStock'); + $this->resourceStockItem->expects($this->once())->method('updateSetInStock'); + $this->resourceStockItem->expects($this->once())->method('updateLowStockDate'); $this->event->expects($this->once()) ->method('getWebsite') ->will($this->returnValue($websiteId)); + $this->event->expects($this->once()) + ->method('getChangedPaths') + ->will($this->returnValue([\Magento\CatalogInventory\Model\Configuration::XML_PATH_MANAGE_STOCK])); $this->observer->execute($this->eventObserver); } diff --git a/app/code/Magento/CatalogInventory/etc/di.xml b/app/code/Magento/CatalogInventory/etc/di.xml index 65bc277121429..912ab48d28824 100644 --- a/app/code/Magento/CatalogInventory/etc/di.xml +++ b/app/code/Magento/CatalogInventory/etc/di.xml @@ -118,4 +118,21 @@ </argument> </arguments> </type> + <type name="Magento\Catalog\Model\ResourceModel\Product\Indexer\Price\PriceInterface"> + <arguments> + <argument name="priceModifiers" xsi:type="array"> + <item name="inventoryProductPriceIndexFilter" xsi:type="object">Magento\CatalogInventory\Model\Indexer\ProductPriceIndexFilter</item> + </argument> + </arguments> + </type> + <type name="Magento\Catalog\Model\ResourceModel\Product\Indexer\Price\BasePriceModifier"> + <arguments> + <argument name="priceModifiers" xsi:type="array"> + <item name="inventoryProductPriceIndexFilter" xsi:type="object">Magento\CatalogInventory\Model\Indexer\ProductPriceIndexFilter</item> + </argument> + </arguments> + </type> + <type name="Magento\CatalogInventory\Model\ResourceModel\Stock\Item"> + <plugin name="priceIndexUpdater" type="Magento\CatalogInventory\Model\Plugin\PriceIndexUpdater" /> + </type> </config> diff --git a/app/code/Magento/CatalogInventory/etc/events.xml b/app/code/Magento/CatalogInventory/etc/events.xml index 3197501e9b70b..328edbade6068 100644 --- a/app/code/Magento/CatalogInventory/etc/events.xml +++ b/app/code/Magento/CatalogInventory/etc/events.xml @@ -38,6 +38,7 @@ </event> <event name="admin_system_config_changed_section_cataloginventory"> <observer name="inventory" instance="Magento\CatalogInventory\Observer\UpdateItemsStockUponConfigChangeObserver"/> + <observer name="invalidatePriceIndex" instance="Magento\CatalogInventory\Observer\InvalidatePriceIndexUponConfigChangeObserver"/> </event> <event name="sales_quote_item_collection_products_after_load"> <observer name="add_stock_items" instance="Magento\CatalogInventory\Observer\AddStockItemsObserver"/> diff --git a/app/code/Magento/CatalogInventory/etc/mview.xml b/app/code/Magento/CatalogInventory/etc/mview.xml index c3d73ff43e8eb..72dda16e8b5bb 100644 --- a/app/code/Magento/CatalogInventory/etc/mview.xml +++ b/app/code/Magento/CatalogInventory/etc/mview.xml @@ -11,4 +11,9 @@ <table name="cataloginventory_stock_item" entity_column="product_id" /> </subscriptions> </view> + <view id="catalog_product_price" class="Magento\Catalog\Model\Indexer\Product\Price" group="indexer"> + <subscriptions> + <table name="cataloginventory_stock_item" entity_column="product_id" /> + </subscriptions> + </view> </config> diff --git a/app/code/Magento/CatalogInventory/view/adminhtml/ui_component/product_form.xml b/app/code/Magento/CatalogInventory/view/adminhtml/ui_component/product_form.xml index d82b4a97ddbf6..f8571b6e332b6 100644 --- a/app/code/Magento/CatalogInventory/view/adminhtml/ui_component/product_form.xml +++ b/app/code/Magento/CatalogInventory/view/adminhtml/ui_component/product_form.xml @@ -571,6 +571,7 @@ <settings> <scopeLabel>[GLOBAL]</scopeLabel> <validation> + <rule name="validate-integer" xsi:type="boolean">true</rule> <rule name="validate-number" xsi:type="boolean">true</rule> </validation> <label translate="true">Qty Increments</label> diff --git a/app/code/Magento/CatalogInventory/view/adminhtml/web/js/components/qty-validator-changer.js b/app/code/Magento/CatalogInventory/view/adminhtml/web/js/components/qty-validator-changer.js index 23a33f51af6d4..75d684137a28b 100644 --- a/app/code/Magento/CatalogInventory/view/adminhtml/web/js/components/qty-validator-changer.js +++ b/app/code/Magento/CatalogInventory/view/adminhtml/web/js/components/qty-validator-changer.js @@ -20,7 +20,6 @@ define([ var isDigits = value !== 1; this.validation['validate-integer'] = isDigits; - this.validation['validate-digits'] = isDigits; this.validation['less-than-equals-to'] = isDigits ? 99999999 : 99999999.9999; this.validate(); } diff --git a/app/code/Magento/CatalogRule/Block/Adminhtml/Promo/Catalog/Edit/Tab/Conditions.php b/app/code/Magento/CatalogRule/Block/Adminhtml/Promo/Catalog/Edit/Tab/Conditions.php index 0b4748c933a3c..9d1a23611dc27 100644 --- a/app/code/Magento/CatalogRule/Block/Adminhtml/Promo/Catalog/Edit/Tab/Conditions.php +++ b/app/code/Magento/CatalogRule/Block/Adminhtml/Promo/Catalog/Edit/Tab/Conditions.php @@ -66,7 +66,7 @@ public function getTabTitle() } /** - * Returns status flag about this tab can be showen or not + * Returns status flag about this tab can be shown or not * * @return bool * @codeCoverageIgnore diff --git a/app/code/Magento/CatalogRule/Block/Adminhtml/Promo/Widget/Chooser/Sku.php b/app/code/Magento/CatalogRule/Block/Adminhtml/Promo/Widget/Chooser/Sku.php index 306d3b9a347b4..87cb18253a107 100644 --- a/app/code/Magento/CatalogRule/Block/Adminhtml/Promo/Widget/Chooser/Sku.php +++ b/app/code/Magento/CatalogRule/Block/Adminhtml/Promo/Widget/Chooser/Sku.php @@ -139,7 +139,7 @@ protected function _getCpCollectionInstance() } /** - * Define Cooser Grid Columns and filters + * Define Chooser Grid Columns and filters * * @return $this */ diff --git a/app/code/Magento/CatalogRule/Controller/Adminhtml/Promo/Catalog/ApplyRules.php b/app/code/Magento/CatalogRule/Controller/Adminhtml/Promo/Catalog/ApplyRules.php index 85ad74f7bbfe2..4badfa1219e10 100644 --- a/app/code/Magento/CatalogRule/Controller/Adminhtml/Promo/Catalog/ApplyRules.php +++ b/app/code/Magento/CatalogRule/Controller/Adminhtml/Promo/Catalog/ApplyRules.php @@ -25,14 +25,14 @@ public function execute() $ruleJob->applyAll(); if ($ruleJob->hasSuccess()) { - $this->messageManager->addSuccess($ruleJob->getSuccess()); + $this->messageManager->addSuccessMessage($ruleJob->getSuccess()); $this->_objectManager->create(\Magento\CatalogRule\Model\Flag::class)->loadSelf()->setState(0)->save(); } elseif ($ruleJob->hasError()) { - $this->messageManager->addError($errorMessage . ' ' . $ruleJob->getError()); + $this->messageManager->addErrorMessage($errorMessage . ' ' . $ruleJob->getError()); } } catch (\Exception $e) { $this->_objectManager->create(\Psr\Log\LoggerInterface::class)->critical($e); - $this->messageManager->addError($errorMessage); + $this->messageManager->addErrorMessage($errorMessage); } /** @var \Magento\Backend\Model\View\Result\Redirect $resultRedirect */ diff --git a/app/code/Magento/CatalogRule/Controller/Adminhtml/Promo/Catalog/Delete.php b/app/code/Magento/CatalogRule/Controller/Adminhtml/Promo/Catalog/Delete.php index 8b007031f3305..3500506d8d6c5 100644 --- a/app/code/Magento/CatalogRule/Controller/Adminhtml/Promo/Catalog/Delete.php +++ b/app/code/Magento/CatalogRule/Controller/Adminhtml/Promo/Catalog/Delete.php @@ -25,13 +25,13 @@ public function execute() $ruleRepository->deleteById($id); $this->_objectManager->create(\Magento\CatalogRule\Model\Flag::class)->loadSelf()->setState(1)->save(); - $this->messageManager->addSuccess(__('You deleted the rule.')); + $this->messageManager->addSuccessMessage(__('You deleted the rule.')); $this->_redirect('catalog_rule/*/'); return; } catch (LocalizedException $e) { - $this->messageManager->addError($e->getMessage()); + $this->messageManager->addErrorMessage($e->getMessage()); } catch (\Exception $e) { - $this->messageManager->addError( + $this->messageManager->addErrorMessage( __('We can\'t delete this rule right now. Please review the log and try again.') ); $this->_objectManager->get(\Psr\Log\LoggerInterface::class)->critical($e); @@ -39,7 +39,7 @@ public function execute() return; } } - $this->messageManager->addError(__('We can\'t find a rule to delete.')); + $this->messageManager->addErrorMessage(__('We can\'t find a rule to delete.')); $this->_redirect('catalog_rule/*/'); } } diff --git a/app/code/Magento/CatalogRule/Controller/Adminhtml/Promo/Catalog/Edit.php b/app/code/Magento/CatalogRule/Controller/Adminhtml/Promo/Catalog/Edit.php index 97a5693b18117..945c28b2088f2 100644 --- a/app/code/Magento/CatalogRule/Controller/Adminhtml/Promo/Catalog/Edit.php +++ b/app/code/Magento/CatalogRule/Controller/Adminhtml/Promo/Catalog/Edit.php @@ -24,7 +24,7 @@ public function execute() try { $model = $ruleRepository->get($id); } catch (\Magento\Framework\Exception\NoSuchEntityException $exception) { - $this->messageManager->addError(__('This rule no longer exists.')); + $this->messageManager->addErrorMessage(__('This rule no longer exists.')); $this->_redirect('catalog_rule/*'); return; } diff --git a/app/code/Magento/CatalogRule/Controller/Adminhtml/Promo/Catalog/Save.php b/app/code/Magento/CatalogRule/Controller/Adminhtml/Promo/Catalog/Save.php index 0170fc76b6aab..f3046c58a389b 100644 --- a/app/code/Magento/CatalogRule/Controller/Adminhtml/Promo/Catalog/Save.php +++ b/app/code/Magento/CatalogRule/Controller/Adminhtml/Promo/Catalog/Save.php @@ -68,7 +68,7 @@ public function execute() $validateResult = $model->validateData(new \Magento\Framework\DataObject($data)); if ($validateResult !== true) { foreach ($validateResult as $errorMessage) { - $this->messageManager->addError($errorMessage); + $this->messageManager->addErrorMessage($errorMessage); } $this->_getSession()->setPageData($data); $this->dataPersistor->set('catalog_rule', $data); @@ -88,7 +88,7 @@ public function execute() $ruleRepository->save($model); - $this->messageManager->addSuccess(__('You saved the rule.')); + $this->messageManager->addSuccessMessage(__('You saved the rule.')); $this->_objectManager->get(\Magento\Backend\Model\Session::class)->setPageData(false); $this->dataPersistor->clear('catalog_rule'); @@ -111,9 +111,9 @@ public function execute() } return; } catch (LocalizedException $e) { - $this->messageManager->addError($e->getMessage()); + $this->messageManager->addErrorMessage($e->getMessage()); } catch (\Exception $e) { - $this->messageManager->addError( + $this->messageManager->addErrorMessage( __('Something went wrong while saving the rule data. Please review the error log.') ); $this->_objectManager->get(\Psr\Log\LoggerInterface::class)->critical($e); diff --git a/app/code/Magento/CatalogRule/Model/Indexer/ProductPriceIndexModifier.php b/app/code/Magento/CatalogRule/Model/Indexer/ProductPriceIndexModifier.php index a60b05dc7c9bc..404fc32e0c0d4 100644 --- a/app/code/Magento/CatalogRule/Model/Indexer/ProductPriceIndexModifier.php +++ b/app/code/Magento/CatalogRule/Model/Indexer/ProductPriceIndexModifier.php @@ -10,6 +10,8 @@ use Magento\Catalog\Model\ResourceModel\Product\Indexer\Price\PriceModifierInterface; use Magento\Catalog\Model\ResourceModel\Product\Indexer\Price\IndexTableStructure; use Magento\CatalogRule\Model\ResourceModel\Rule\Product\Price; +use Magento\Framework\App\ResourceConnection; +use Magento\Framework\App\ObjectManager; /** * Class for adding catalog rule prices to price index table. @@ -21,12 +23,29 @@ class ProductPriceIndexModifier implements PriceModifierInterface */ private $priceResourceModel; + /** + * @var ResourceConnection + */ + private $resourceConnection; + + /** + * @var string + */ + private $connectionName; + /** * @param Price $priceResourceModel + * @param ResourceConnection $resourceConnection + * @param string $connectionName */ - public function __construct(Price $priceResourceModel) - { + public function __construct( + Price $priceResourceModel, + ResourceConnection $resourceConnection, + $connectionName = 'indexer' + ) { $this->priceResourceModel = $priceResourceModel; + $this->resourceConnection = $resourceConnection ?: ObjectManager::getInstance()->get(ResourceConnection::class); + $this->connectionName = $connectionName; } /** @@ -34,7 +53,8 @@ public function __construct(Price $priceResourceModel) */ public function modifyPrice(IndexTableStructure $priceTable, array $entityIds = []) : void { - $connection = $this->priceResourceModel->getConnection(); + $connection = $this->resourceConnection->getConnection($this->connectionName); + $select = $connection->select(); $select->join( diff --git a/app/code/Magento/CatalogRule/Model/Rule/Condition/Product.php b/app/code/Magento/CatalogRule/Model/Rule/Condition/Product.php index 51cb6638af48b..ab650c94a0f08 100644 --- a/app/code/Magento/CatalogRule/Model/Rule/Condition/Product.php +++ b/app/code/Magento/CatalogRule/Model/Rule/Condition/Product.php @@ -99,6 +99,10 @@ protected function _prepareDatetimeValue($value, \Magento\Framework\Model\Abstra { $attribute = $model->getResource()->getAttribute($this->getAttribute()); if ($attribute && $attribute->getBackendType() == 'datetime') { + if (!$value) { + return null; + } + $this->setValue(strtotime($this->getValue())); $value = strtotime($value); } diff --git a/app/code/Magento/CatalogRule/Plugin/Indexer/Product/Attribute.php b/app/code/Magento/CatalogRule/Plugin/Indexer/Product/Attribute.php index cc808a38db698..7fdffe933db8c 100644 --- a/app/code/Magento/CatalogRule/Plugin/Indexer/Product/Attribute.php +++ b/app/code/Magento/CatalogRule/Plugin/Indexer/Product/Attribute.php @@ -103,7 +103,7 @@ protected function checkCatalogRulesAvailability($attributeCode) if ($disabledRulesCount) { $this->ruleProductProcessor->markIndexerAsInvalid(); - $this->messageManager->addWarning( + $this->messageManager->addWarningMessage( __( 'You disabled %1 Catalog Price Rules based on "%2" attribute.', $disabledRulesCount, diff --git a/app/code/Magento/CatalogRule/Test/Mftf/ActionGroup/CatalogPriceRuleActionGroup.xml b/app/code/Magento/CatalogRule/Test/Mftf/ActionGroup/CatalogPriceRuleActionGroup.xml index 2d437ab086f82..f82974b7bc82a 100644 --- a/app/code/Magento/CatalogRule/Test/Mftf/ActionGroup/CatalogPriceRuleActionGroup.xml +++ b/app/code/Magento/CatalogRule/Test/Mftf/ActionGroup/CatalogPriceRuleActionGroup.xml @@ -17,12 +17,12 @@ <amOnPage stepKey="goToPriceRulePage" url="{{CatalogRulePage.url}}"/> <waitForPageLoad stepKey="waitForPriceRulePage"/> <click stepKey="addNewRule" selector="{{AdminGridMainControls.add}}"/> + <waitForPageLoad stepKey="waitForIndividualRulePage"/> <!-- Fill the form according the attributes of the entity --> <fillField stepKey="fillName" selector="{{AdminNewCatalogPriceRule.ruleName}}" userInput="{{catalogRule.name}}"/> <fillField stepKey="fillDescription" selector="{{AdminNewCatalogPriceRule.description}}" userInput="{{catalogRule.description}}"/> <selectOption stepKey="selectSite" selector="{{AdminNewCatalogPriceRule.websites}}" userInput="{{catalogRule.website_ids[0]}}"/> - <selectOption stepKey="selectCustomerGroups" selector="{{AdminNewCatalogPriceRule.customerGroups}}" userInput="{{catalogRule.customer_group_ids[0]}}"/> <click stepKey="clickFromCalender" selector="{{AdminNewCatalogPriceRule.fromDateButton}}"/> <click stepKey="clickFromToday" selector="{{AdminNewCatalogPriceRule.todayDate}}"/> <click stepKey="clickToCalender" selector="{{AdminNewCatalogPriceRule.toDateButton}}"/> @@ -30,11 +30,14 @@ <click stepKey="openActionDropdown" selector="{{AdminNewCatalogPriceRule.actionsTab}}"/> <selectOption stepKey="discountType" selector="{{AdminNewCatalogPriceRuleActions.apply}}" userInput="{{catalogRule.simple_action}}"/> <fillField stepKey="fillDiscountValue" selector="{{AdminNewCatalogPriceRuleActions.discountAmount}}" userInput="{{catalogRule.discount_amount}}"/> + <selectOption stepKey="discardSubsequentRules" selector="{{AdminNewCatalogPriceRuleActions.disregardRules}}" userInput="Yes"/> <!-- Scroll to top and either save or save and apply after the action group --> <scrollToTopOfPage stepKey="scrollToTop"/> + <waitForPageLoad stepKey="waitForApplied"/> </actionGroup> + <!-- Apply all of the saved catalog price rules --> <actionGroup name="applyCatalogPriceRules"> <amOnPage stepKey="goToPriceRulePage" url="{{CatalogRulePage.url}}"/> <waitForPageLoad stepKey="waitForPriceRulePage"/> diff --git a/app/code/Magento/CatalogRule/Test/Mftf/Section/AdminCatalogPriceRuleStagingSection.xml b/app/code/Magento/CatalogRule/Test/Mftf/Section/AdminCatalogPriceRuleStagingSection.xml new file mode 100644 index 0000000000000..d212aac1c0d4a --- /dev/null +++ b/app/code/Magento/CatalogRule/Test/Mftf/Section/AdminCatalogPriceRuleStagingSection.xml @@ -0,0 +1,14 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> + +<sections xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="../../../../../../../dev/tests/acceptance/vendor/magento/magento2-functional-testing-framework/src/Magento/FunctionalTestingFramework/Page/etc/SectionObject.xsd"> + <section name="AdminCatalogPriceRuleStagingSection"> + <element name="status" type="select" selector=".modal-component [data-index='is_active'] select"/> + </section> +</sections> diff --git a/app/code/Magento/CatalogRule/Test/Mftf/Section/AdminNewCatalogPriceRuleSection.xml b/app/code/Magento/CatalogRule/Test/Mftf/Section/AdminNewCatalogPriceRuleSection.xml index b60a4c6516a82..4773fd8224fe3 100644 --- a/app/code/Magento/CatalogRule/Test/Mftf/Section/AdminNewCatalogPriceRuleSection.xml +++ b/app/code/Magento/CatalogRule/Test/Mftf/Section/AdminNewCatalogPriceRuleSection.xml @@ -11,6 +11,7 @@ <section name="AdminNewCatalogPriceRule"> <element name="saveAndApply" type="button" selector="#save_and_apply" timeout="30"/> <element name="save" type="button" selector="#save" timeout="30"/> + <element name="saveAndContinue" type="button" selector="#save_and_continue" timeout="30"/> <element name="delete" type="button" selector="#delete" timeout="30"/> <element name="ruleName" type="input" selector="[name='name']"/> @@ -33,7 +34,7 @@ <section name="AdminNewCatalogPriceRuleActions"> <element name="apply" type="select" selector="[name='simple_action']"/> <element name="discountAmount" type="input" selector="[name='discount_amount']"/> - <element name="disgardRules" type="select" selector="[name='stop_rules_processing']"/> + <element name="disregardRules" type="select" selector="[name='stop_rules_processing']"/> </section> <section name="AdminCatalogPriceRuleGrid"> diff --git a/app/code/Magento/CatalogRule/Test/Mftf/Test/AdminCreateCatalogPriceRuleTest.xml b/app/code/Magento/CatalogRule/Test/Mftf/Test/AdminCreateCatalogPriceRuleTest.xml index a68965d97e879..70fd745986567 100644 --- a/app/code/Magento/CatalogRule/Test/Mftf/Test/AdminCreateCatalogPriceRuleTest.xml +++ b/app/code/Magento/CatalogRule/Test/Mftf/Test/AdminCreateCatalogPriceRuleTest.xml @@ -28,6 +28,7 @@ <!-- log in and create the price rule --> <actionGroup ref="LoginAsAdmin" stepKey="loginAsAdmin"/> <actionGroup stepKey="createNewPriceRule" ref="newCatalogPriceRuleByUI"/> + <actionGroup stepKey="selectLoggedInCustomers" ref="selectNotLoggedInCustomerGroup"/> <click stepKey="saveAndApply" selector="{{AdminNewCatalogPriceRule.saveAndApply}}"/> <see stepKey="assertSuccess" selector="{{AdminCategoryMessagesSection.SuccessMessage}}" userInput="You saved the rule."/> </before> @@ -86,6 +87,7 @@ <actionGroup stepKey="createNewPriceRule" ref="newCatalogPriceRuleByUI"> <argument name="catalogRule" value="CatalogRuleByFixed"/> </actionGroup> + <actionGroup stepKey="selectLoggedInCustomers" ref="selectNotLoggedInCustomerGroup"/> <click stepKey="saveAndApply" selector="{{AdminNewCatalogPriceRule.saveAndApply}}"/> <see stepKey="assertSuccess" selector="{{AdminCategoryMessagesSection.SuccessMessage}}" userInput="You saved the rule."/> </before> @@ -144,6 +146,7 @@ <actionGroup stepKey="createNewPriceRule" ref="newCatalogPriceRuleByUI"> <argument name="catalogRule" value="CatalogRuleToPercent"/> </actionGroup> + <actionGroup stepKey="selectLoggedInCustomers" ref="selectNotLoggedInCustomerGroup"/> <click stepKey="saveAndApply" selector="{{AdminNewCatalogPriceRule.saveAndApply}}"/> <see stepKey="assertSuccess" selector="{{AdminCategoryMessagesSection.SuccessMessage}}" userInput="You saved the rule."/> </before> @@ -202,6 +205,7 @@ <actionGroup stepKey="createNewPriceRule" ref="newCatalogPriceRuleByUI"> <argument name="catalogRule" value="CatalogRuleToFixed"/> </actionGroup> + <actionGroup stepKey="selectLoggedInCustomers" ref="selectNotLoggedInCustomerGroup"/> <click stepKey="saveAndApply" selector="{{AdminNewCatalogPriceRule.saveAndApply}}"/> <see stepKey="assertSuccess" selector="{{AdminCategoryMessagesSection.SuccessMessage}}" userInput="You saved the rule."/> </before> diff --git a/app/code/Magento/CatalogRule/Test/Mftf/Test/StorefrontInactiveCatalogRuleTest.xml b/app/code/Magento/CatalogRule/Test/Mftf/Test/StorefrontInactiveCatalogRuleTest.xml index 77a9a48074c29..64f19cb3ca881 100644 --- a/app/code/Magento/CatalogRule/Test/Mftf/Test/StorefrontInactiveCatalogRuleTest.xml +++ b/app/code/Magento/CatalogRule/Test/Mftf/Test/StorefrontInactiveCatalogRuleTest.xml @@ -24,7 +24,8 @@ <createData entity="ApiSimpleProduct" stepKey="createProduct"> <requiredEntity createDataKey="createCategory"/> </createData> - <actionGroup ref="newCatalogPriceRuleByUI" stepKey="createNewPriceRule"/> + <actionGroup stepKey="createNewPriceRule" ref="newCatalogPriceRuleByUI"/> + <actionGroup stepKey="selectLoggedInCustomers" ref="selectNotLoggedInCustomerGroup"/> <selectOption selector="{{AdminNewCatalogPriceRule.status}}" userInput="Inactive" stepKey="setInactive"/> <click selector="{{AdminNewCatalogPriceRule.saveAndApply}}" stepKey="saveAndApply"/> <see selector="{{AdminCategoryMessagesSection.SuccessMessage}}" userInput="You saved the rule." stepKey="seeSuccess"/> diff --git a/app/code/Magento/CatalogRule/Test/Mftf/composer.json b/app/code/Magento/CatalogRule/Test/Mftf/composer.json deleted file mode 100644 index 0b57cf8dfaefa..0000000000000 --- a/app/code/Magento/CatalogRule/Test/Mftf/composer.json +++ /dev/null @@ -1,27 +0,0 @@ -{ - "name": "magento/functional-test-module-catalog-rule", - "description": "N/A", - "config": { - "sort-packages": true - }, - "require": { - "php": "~7.1.3||~7.2.0", - "magento/magento2-functional-testing-framework": "2.2.0", - "magento/functional-test-module-backend": "100.0.0-dev", - "magento/functional-test-module-catalog": "100.0.0-dev", - "magento/functional-test-module-customer": "100.0.0-dev", - "magento/functional-test-module-eav": "100.0.0-dev", - "magento/functional-test-module-rule": "100.0.0-dev", - "magento/functional-test-module-store": "100.0.0-dev", - "magento/functional-test-module-ui": "100.0.0-dev" - }, - "suggest": { - "magento/functional-test-module-import-export": "100.0.0-dev", - "magento/functional-test-module-catalog-rule-sample-data": "100.0.0-dev" - }, - "type": "magento2-test", - "license": [ - "OSL-3.0", - "AFL-3.0" - ] -} diff --git a/app/code/Magento/CatalogRule/etc/di.xml b/app/code/Magento/CatalogRule/etc/di.xml index 8ed88dd4f3fdb..e0d91db542390 100644 --- a/app/code/Magento/CatalogRule/etc/di.xml +++ b/app/code/Magento/CatalogRule/etc/di.xml @@ -126,6 +126,21 @@ </argument> </arguments> </type> + <preference for="Magento\CatalogRule\Model\Indexer\IndexerTableSwapperInterface" type="Magento\CatalogRule\Model\Indexer\IndexerTableSwapper" /> + <type name="Magento\Catalog\Model\ResourceModel\Product\Indexer\Price\PriceInterface"> + <arguments> + <argument name="priceModifiers" xsi:type="array"> + <item name="catalogRulePriceModifier" xsi:type="object">Magento\CatalogRule\Model\Indexer\ProductPriceIndexModifier</item> + </argument> + </arguments> + </type> + <type name="Magento\Catalog\Model\ResourceModel\Product\Indexer\Price\BasePriceModifier"> + <arguments> + <argument name="priceModifiers" xsi:type="array"> + <item name="catalogRulePriceModifier" xsi:type="object">Magento\CatalogRule\Model\Indexer\ProductPriceIndexModifier</item> + </argument> + </arguments> + </type> <virtualType name="CatalogRuleCustomConditionProvider" type="Magento\Framework\Api\SearchCriteria\CollectionProcessor\ConditionProcessor\CustomConditionProvider"> <arguments> <argument name="customConditionProcessors" xsi:type="array"> @@ -149,12 +164,4 @@ <argument name="customConditionProvider" xsi:type="object">CatalogRuleCustomConditionProvider</argument> </arguments> </type> - <preference for="Magento\CatalogRule\Model\Indexer\IndexerTableSwapperInterface" type="Magento\CatalogRule\Model\Indexer\IndexerTableSwapper" /> - <type name="Magento\Catalog\Model\ResourceModel\Product\Indexer\Price\PriceInterface"> - <arguments> - <argument name="priceModifiers" xsi:type="array"> - <item name="catalogRulePriceModifier" xsi:type="object">Magento\CatalogRule\Model\Indexer\ProductPriceIndexModifier</item> - </argument> - </arguments> - </type> </config> diff --git a/app/code/Magento/CatalogRule/etc/mview.xml b/app/code/Magento/CatalogRule/etc/mview.xml index 4b1166941bdc8..35efe33461afc 100644 --- a/app/code/Magento/CatalogRule/etc/mview.xml +++ b/app/code/Magento/CatalogRule/etc/mview.xml @@ -24,4 +24,9 @@ <table name="catalog_category_product" entity_column="product_id" /> </subscriptions> </view> + <view id="catalog_product_price" class="Magento\Catalog\Model\Indexer\Product\Price" group="indexer"> + <subscriptions> + <table name="catalogrule_product_price" entity_column="product_id" /> + </subscriptions> + </view> </config> diff --git a/app/code/Magento/CatalogRuleConfigurable/Test/Mftf/composer.json b/app/code/Magento/CatalogRuleConfigurable/Test/Mftf/composer.json deleted file mode 100644 index 20b1a74c9416a..0000000000000 --- a/app/code/Magento/CatalogRuleConfigurable/Test/Mftf/composer.json +++ /dev/null @@ -1,23 +0,0 @@ -{ - "name": "magento/functional-test-module-catalog-rule-configurable", - "description": "N/A", - "config": { - "sort-packages": true - }, - "require": { - "php": "~7.1.3||~7.2.0", - "magento/magento2-functional-testing-framework": "2.2.0", - "magento/magento-composer-installer": "100.0.0-dev", - "magento/functional-test-module-catalog": "100.0.0-dev", - "magento/functional-test-module-catalog-rule": "100.0.0-dev", - "magento/functional-test-module-configurable-product": "100.0.0-dev" - }, - "suggest": { - "magento/functional-test-module-catalog-rule": "100.0.0-dev" - }, - "type": "magento2-test", - "license": [ - "OSL-3.0", - "AFL-3.0" - ] -} diff --git a/app/code/Magento/CatalogSearch/Block/Advanced/Form.php b/app/code/Magento/CatalogSearch/Block/Advanced/Form.php index 68e4233e8deaf..4d1957991d1bf 100644 --- a/app/code/Magento/CatalogSearch/Block/Advanced/Form.php +++ b/app/code/Magento/CatalogSearch/Block/Advanced/Form.php @@ -177,19 +177,11 @@ public function getCurrencyCount() * * @param AbstractAttribute $attribute * @return string + * @SuppressWarnings(PHPMD.UnusedFormalParameter) */ public function getCurrency($attribute) { return $this->_storeManager->getStore()->getCurrentCurrencyCode(); - - $baseCurrency = $this->_storeManager->getStore()->getBaseCurrency()->getCurrencyCode(); - return $this->getAttributeValue( - $attribute, - 'currency' - ) ? $this->getAttributeValue( - $attribute, - 'currency' - ) : $baseCurrency; } /** diff --git a/app/code/Magento/CatalogSearch/Controller/Advanced/Result.php b/app/code/Magento/CatalogSearch/Controller/Advanced/Result.php index 86195aa31f0e4..d6a30f4f3141d 100644 --- a/app/code/Magento/CatalogSearch/Controller/Advanced/Result.php +++ b/app/code/Magento/CatalogSearch/Controller/Advanced/Result.php @@ -6,7 +6,6 @@ */ namespace Magento\CatalogSearch\Controller\Advanced; -use Magento\Catalog\Model\Layer\Resolver; use Magento\CatalogSearch\Model\Advanced as ModelAdvanced; use Magento\Framework\App\Action\Context; use Magento\Framework\UrlFactory; @@ -45,7 +44,7 @@ public function __construct( } /** - * @return void + * @return \Magento\Framework\Controller\Result\Redirect */ public function execute() { @@ -58,7 +57,9 @@ public function execute() $defaultUrl = $this->_urlFactory->create() ->addQueryParams($this->getRequest()->getQueryValue()) ->getUrl('*/*/'); - $this->getResponse()->setRedirect($this->_redirect->error($defaultUrl)); + $resultRedirect = $this->resultRedirectFactory->create(); + $resultRedirect->setUrl($this->_redirect->error($defaultUrl)); + return $resultRedirect; } } } diff --git a/app/code/Magento/CatalogSearch/Model/Adapter/Mysql/Aggregation/DataProvider/QueryBuilder.php b/app/code/Magento/CatalogSearch/Model/Adapter/Mysql/Aggregation/DataProvider/QueryBuilder.php index ca077ef7227d5..7ebf71f424439 100644 --- a/app/code/Magento/CatalogSearch/Model/Adapter/Mysql/Aggregation/DataProvider/QueryBuilder.php +++ b/app/code/Magento/CatalogSearch/Model/Adapter/Mysql/Aggregation/DataProvider/QueryBuilder.php @@ -8,18 +8,29 @@ use Magento\CatalogInventory\Model\Configuration as CatalogInventoryConfiguration; use Magento\CatalogInventory\Model\Stock; +use Magento\Customer\Model\Indexer\CustomerGroupDimensionProvider; use Magento\Eav\Model\Entity\Attribute\AbstractAttribute; use Magento\Framework\App\ResourceConnection; use Magento\Framework\App\ScopeResolverInterface; -use Magento\Framework\DB\Adapter\AdapterInterface; use Magento\Framework\DB\Select; use Magento\Framework\Search\Request\BucketInterface; +use Magento\Framework\App\ObjectManager; +use Magento\Framework\Indexer\DimensionFactory; +use Magento\Framework\Search\Request\IndexScopeResolverInterface; +use Magento\Store\Model\Indexer\WebsiteDimensionProvider; /** - * Attribute query builder + * Attribute query builder + * + * @SuppressWarnings(PHPMD.CouplingBetweenObjects) */ class QueryBuilder { + /** + * @var DimensionFactory + */ + private $dimensionFactory; + /** * @var Resource */ @@ -35,19 +46,31 @@ class QueryBuilder */ private $inventoryConfig; + /** + * @var IndexScopeResolverInterface + */ + private $priceTableResolver; + /** * @param ResourceConnection $resource * @param ScopeResolverInterface $scopeResolver * @param CatalogInventoryConfiguration $inventoryConfig + * @param IndexScopeResolverInterface $priceTableResolver + * @param DimensionFactory|null $dimensionFactory */ public function __construct( ResourceConnection $resource, ScopeResolverInterface $scopeResolver, - CatalogInventoryConfiguration $inventoryConfig + CatalogInventoryConfiguration $inventoryConfig, + IndexScopeResolverInterface $priceTableResolver = null, + DimensionFactory $dimensionFactory = null ) { $this->resource = $resource; $this->scopeResolver = $scopeResolver; $this->inventoryConfig = $inventoryConfig; + $this->priceTableResolver = $priceTableResolver + ?: ObjectManager::getInstance()->get(IndexScopeResolverInterface::class); + $this->dimensionFactory = $dimensionFactory ?: ObjectManager::getInstance()->get(DimensionFactory::class); } /** @@ -99,12 +122,25 @@ private function buildQueryForPriceAttribute( if (!$store instanceof \Magento\Store\Model\Store) { throw new \RuntimeException('Illegal scope resolved'); } + $websiteId = $store->getWebsiteId(); - $table = $this->resource->getTableName('catalog_product_index_price'); - $select->from(['main_table' => $table], null) + $tableName = $this->priceTableResolver->resolve( + 'catalog_product_index_price', + [ + $this->dimensionFactory->create( + WebsiteDimensionProvider::DIMENSION_NAME, + (string)$websiteId + ), + $this->dimensionFactory->create( + CustomerGroupDimensionProvider::DIMENSION_NAME, + (string)$customerGroupId + ), + ] + ); + $select->from(['main_table' => $tableName], null) ->columns([BucketInterface::FIELD_VALUE => 'main_table.min_price']) ->where('main_table.customer_group_id = ?', $customerGroupId) - ->where('main_table.website_id = ?', $store->getWebsiteId()); + ->where('main_table.website_id = ?', $websiteId); return $select; } diff --git a/app/code/Magento/CatalogSearch/Model/Adapter/Mysql/Dynamic/DataProvider.php b/app/code/Magento/CatalogSearch/Model/Adapter/Mysql/Dynamic/DataProvider.php index 8b7a7ed214e36..d2e653ac9b9ae 100644 --- a/app/code/Magento/CatalogSearch/Model/Adapter/Mysql/Dynamic/DataProvider.php +++ b/app/code/Magento/CatalogSearch/Model/Adapter/Mysql/Dynamic/DataProvider.php @@ -6,17 +6,21 @@ namespace Magento\CatalogSearch\Model\Adapter\Mysql\Dynamic; use Magento\Catalog\Model\Layer\Filter\Price\Range; +use Magento\Customer\Model\Indexer\CustomerGroupDimensionProvider; use Magento\Customer\Model\Session; use Magento\Framework\App\ResourceConnection; use Magento\Framework\DB\Adapter\AdapterInterface; use Magento\Framework\DB\Ddl\Table; use Magento\Framework\DB\Select; +use Magento\Framework\Indexer\DimensionFactory; use Magento\Framework\Search\Adapter\Mysql\Aggregation\DataProviderInterface as MysqlDataProviderInterface; use Magento\Framework\Search\Dynamic\DataProviderInterface; use Magento\Framework\Search\Dynamic\IntervalFactory; use Magento\Framework\Search\Request\BucketInterface; use Magento\Framework\App\ObjectManager; +use Magento\Store\Model\Indexer\WebsiteDimensionProvider; use Magento\Store\Model\StoreManager; +use \Magento\Framework\Search\Request\IndexScopeResolverInterface; /** * @SuppressWarnings(PHPMD.CouplingBetweenObjects) @@ -58,6 +62,16 @@ class DataProvider implements DataProviderInterface */ private $storeManager; + /** + * @var IndexScopeResolverInterface + */ + private $priceTableResolver; + + /** + * @var DimensionFactory|null + */ + private $dimensionFactory; + /** * @param ResourceConnection $resource * @param Range $range @@ -65,6 +79,8 @@ class DataProvider implements DataProviderInterface * @param MysqlDataProviderInterface $dataProvider * @param IntervalFactory $intervalFactory * @param StoreManager $storeManager + * @param IndexScopeResolverInterface|null $priceTableResolver + * @param DimensionFactory|null $dimensionFactory */ public function __construct( ResourceConnection $resource, @@ -72,7 +88,9 @@ public function __construct( Session $customerSession, MysqlDataProviderInterface $dataProvider, IntervalFactory $intervalFactory, - StoreManager $storeManager = null + StoreManager $storeManager = null, + IndexScopeResolverInterface $priceTableResolver = null, + DimensionFactory $dimensionFactory = null ) { $this->resource = $resource; $this->connection = $resource->getConnection(); @@ -81,6 +99,10 @@ public function __construct( $this->dataProvider = $dataProvider; $this->intervalFactory = $intervalFactory; $this->storeManager = $storeManager ?: ObjectManager::getInstance()->get(StoreManager::class); + $this->priceTableResolver = $priceTableResolver ?: ObjectManager::getInstance()->get( + IndexScopeResolverInterface::class + ); + $this->dimensionFactory = $dimensionFactory ?: ObjectManager::getInstance()->get(DimensionFactory::class); } /** @@ -104,16 +126,30 @@ public function getAggregations(\Magento\Framework\Search\Dynamic\EntityStorage ]; $select = $this->getSelect(); - - $tableName = $this->resource->getTableName('catalog_product_index_price'); + $websiteId = $this->storeManager->getStore()->getWebsiteId(); + $customerGroupId = $this->customerSession->getCustomerGroupId(); + + $tableName = $this->priceTableResolver->resolve( + 'catalog_product_index_price', + [ + $this->dimensionFactory->create( + WebsiteDimensionProvider::DIMENSION_NAME, + (string)$websiteId + ), + $this->dimensionFactory->create( + CustomerGroupDimensionProvider::DIMENSION_NAME, + (string)$customerGroupId + ), + ] + ); /** @var Table $table */ $table = $entityStorage->getSource(); $select->from(['main_table' => $tableName], []) ->where('main_table.entity_id in (select entity_id from ' . $table->getName() . ')') ->columns($aggregation); - $select = $this->setCustomerGroupId($select); - $select->where('main_table.website_id = ?', $this->storeManager->getStore()->getWebsiteId()); + $select->where('customer_group_id = ?', $customerGroupId); + $select->where('main_table.website_id = ?', $websiteId); return $this->connection->fetchRow($select); } @@ -192,13 +228,4 @@ private function getSelect() { return $this->connection->select(); } - - /** - * @param Select $select - * @return Select - */ - private function setCustomerGroupId($select) - { - return $select->where('customer_group_id = ?', $this->customerSession->getCustomerGroupId()); - } } diff --git a/app/code/Magento/CatalogSearch/Model/Adapter/Mysql/Plugin/Aggregation/Category/DataProvider.php b/app/code/Magento/CatalogSearch/Model/Adapter/Mysql/Plugin/Aggregation/Category/DataProvider.php index 182ecf873d77a..94432bbfe4a71 100644 --- a/app/code/Magento/CatalogSearch/Model/Adapter/Mysql/Plugin/Aggregation/Category/DataProvider.php +++ b/app/code/Magento/CatalogSearch/Model/Adapter/Mysql/Plugin/Aggregation/Category/DataProvider.php @@ -13,7 +13,7 @@ use Magento\Framework\Search\Request\BucketInterface; use Magento\Framework\Search\Request\Dimension; use Magento\Framework\App\ObjectManager; -use Magento\Framework\Indexer\ScopeResolver\IndexScopeResolver as TableResolver; +use Magento\Framework\Search\Request\IndexScopeResolverInterface as TableResolver; use Magento\Catalog\Model\Indexer\Category\Product\AbstractAction; /** diff --git a/app/code/Magento/CatalogSearch/Model/Indexer/Fulltext.php b/app/code/Magento/CatalogSearch/Model/Indexer/Fulltext.php index df9eb6e78990a..37208ed896e85 100644 --- a/app/code/Magento/CatalogSearch/Model/Indexer/Fulltext.php +++ b/app/code/Magento/CatalogSearch/Model/Indexer/Fulltext.php @@ -8,7 +8,7 @@ use Magento\CatalogSearch\Model\Indexer\Fulltext\Action\FullFactory; use Magento\CatalogSearch\Model\Indexer\Scope\StateFactory; use Magento\CatalogSearch\Model\ResourceModel\Fulltext as FulltextResource; -use Magento\Framework\Indexer\Dimension\DimensionProviderInterface; +use Magento\Framework\Indexer\DimensionProviderInterface; use Magento\Store\Model\StoreDimensionProvider; use Magento\Indexer\Model\ProcessManager; @@ -23,7 +23,7 @@ class Fulltext implements \Magento\Framework\Indexer\ActionInterface, \Magento\Framework\Mview\ActionInterface, - \Magento\Framework\Indexer\Dimension\DimensionalIndexerInterface + \Magento\Framework\Indexer\DimensionalIndexerInterface { /** * Indexer ID in configuration @@ -112,7 +112,7 @@ public function __construct( public function execute($entityIds) { foreach ($this->dimensionProvider->getIterator() as $dimension) { - $this->executeByDimension($dimension, new \ArrayIterator($entityIds)); + $this->executeByDimensions($dimension, new \ArrayIterator($entityIds)); } } @@ -120,7 +120,7 @@ public function execute($entityIds) * {@inheritdoc} * @throws \InvalidArgumentException */ - public function executeByDimension(array $dimensions, \Traversable $entityIds = null) + public function executeByDimensions(array $dimensions, \Traversable $entityIds = null) { if (count($dimensions) > 1 || !isset($dimensions[StoreDimensionProvider::DIMENSION_NAME])) { throw new \InvalidArgumentException('Indexer "' . self::INDEXER_ID . '" support only Store dimension'); @@ -161,7 +161,7 @@ public function executeFull() $userFunctions = []; foreach ($this->dimensionProvider->getIterator() as $dimension) { $userFunctions[] = function () use ($dimension) { - $this->executeByDimension($dimension); + $this->executeByDimensions($dimension); }; } $this->processManager->execute($userFunctions); diff --git a/app/code/Magento/CatalogSearch/Model/Indexer/Fulltext/Action/DataProvider.php b/app/code/Magento/CatalogSearch/Model/Indexer/Fulltext/Action/DataProvider.php index 5ad2635576857..a8d46911193a8 100644 --- a/app/code/Magento/CatalogSearch/Model/Indexer/Fulltext/Action/DataProvider.php +++ b/app/code/Magento/CatalogSearch/Model/Indexer/Fulltext/Action/DataProvider.php @@ -538,7 +538,7 @@ private function getProductEmulator($typeId) * @param array $indexData * @param array $productData * @param int $storeId - * @return string + * @return array * @SuppressWarnings(PHPMD.CyclomaticComplexity) * @since 100.0.3 */ diff --git a/app/code/Magento/CatalogSearch/Model/ResourceModel/EngineInterface.php b/app/code/Magento/CatalogSearch/Model/ResourceModel/EngineInterface.php index 399f8f763d945..0182b09bcacff 100644 --- a/app/code/Magento/CatalogSearch/Model/ResourceModel/EngineInterface.php +++ b/app/code/Magento/CatalogSearch/Model/ResourceModel/EngineInterface.php @@ -61,7 +61,7 @@ public function processAttributeValue($attribute, $value); * * @param array $index * @param string $separator - * @return string + * @return array */ public function prepareEntityIndex($index, $separator = ' '); } diff --git a/app/code/Magento/CatalogSearch/Model/Search/FilterMapper/ExclusionStrategy.php b/app/code/Magento/CatalogSearch/Model/Search/FilterMapper/ExclusionStrategy.php index 66e0457e7fadd..512dd69aad952 100644 --- a/app/code/Magento/CatalogSearch/Model/Search/FilterMapper/ExclusionStrategy.php +++ b/app/code/Magento/CatalogSearch/Model/Search/FilterMapper/ExclusionStrategy.php @@ -7,13 +7,21 @@ namespace Magento\CatalogSearch\Model\Search\FilterMapper; use Magento\CatalogSearch\Model\Adapter\Mysql\Filter\AliasResolver; +use Magento\Customer\Model\Indexer\CustomerGroupDimensionProvider; +use Magento\Framework\App\Http\Context; use Magento\Framework\App\ObjectManager; -use Magento\Framework\Indexer\ScopeResolver\IndexScopeResolver as TableResolver; +use Magento\Framework\Indexer\DimensionFactory; +use Magento\Framework\Search\Request\IndexScopeResolverInterface as TableResolver; use Magento\Framework\Search\Request\Dimension; use Magento\Catalog\Model\Indexer\Category\Product\AbstractAction; +use Magento\Customer\Model\Context as CustomerContext; +use Magento\Framework\Search\Request\IndexScopeResolverInterface; +use Magento\Store\Model\Indexer\WebsiteDimensionProvider; /** * Strategy which processes exclusions from general rules + * + * @SuppressWarnings(PHPMD.CouplingBetweenObjects) */ class ExclusionStrategy implements FilterStrategyInterface { @@ -43,22 +51,48 @@ class ExclusionStrategy implements FilterStrategyInterface */ private $tableResolver; + /** + * @var IndexScopeResolverInterface + */ + private $priceTableResolver; + + /** + * @var DimensionFactory + */ + private $dimensionFactory; + + /** + * @var Context + */ + private $httpContext; + /** * @param \Magento\Framework\App\ResourceConnection $resourceConnection * @param \Magento\Store\Model\StoreManagerInterface $storeManager * @param AliasResolver $aliasResolver * @param TableResolver|null $tableResolver + * @param DimensionFactory $dimensionFactory + * @param IndexScopeResolverInterface $priceTableResolver + * @param Context $httpContext */ public function __construct( \Magento\Framework\App\ResourceConnection $resourceConnection, \Magento\Store\Model\StoreManagerInterface $storeManager, AliasResolver $aliasResolver, - TableResolver $tableResolver = null + TableResolver $tableResolver = null, + DimensionFactory $dimensionFactory = null, + IndexScopeResolverInterface $priceTableResolver = null, + Context $httpContext = null ) { $this->resourceConnection = $resourceConnection; $this->storeManager = $storeManager; $this->aliasResolver = $aliasResolver; $this->tableResolver = $tableResolver ?: ObjectManager::getInstance()->get(TableResolver::class); + $this->dimensionFactory = $dimensionFactory ?: ObjectManager::getInstance()->get(DimensionFactory::class); + $this->priceTableResolver = $priceTableResolver ?: ObjectManager::getInstance()->get( + IndexScopeResolverInterface::class + ); + $this->httpContext = $httpContext ?: ObjectManager::getInstance()->get(Context::class); } /** @@ -93,7 +127,17 @@ private function applyPriceFilter( \Magento\Framework\DB\Select $select ) { $alias = $this->aliasResolver->getAlias($filter); - $tableName = $this->resourceConnection->getTableName('catalog_product_index_price'); + $websiteId = $this->storeManager->getWebsite()->getId(); + $tableName = $this->priceTableResolver->resolve( + 'catalog_product_index_price', + [ + $this->dimensionFactory->create(WebsiteDimensionProvider::DIMENSION_NAME, (string)$websiteId), + $this->dimensionFactory->create( + CustomerGroupDimensionProvider::DIMENSION_NAME, + (string)$this->httpContext->getValue(CustomerContext::CONTEXT_GROUP) + ) + ] + ); $mainTableAlias = $this->extractTableAliasFromSelect($select); $select->joinInner( @@ -102,7 +146,7 @@ private function applyPriceFilter( ], $this->resourceConnection->getConnection()->quoteInto( sprintf('%s.entity_id = price_index.entity_id AND price_index.website_id = ?', $mainTableAlias), - $this->storeManager->getWebsite()->getId() + $websiteId ), [] ); diff --git a/app/code/Magento/CatalogSearch/Plugin/EnableEavIndexer.php b/app/code/Magento/CatalogSearch/Plugin/EnableEavIndexer.php new file mode 100644 index 0000000000000..c624f9d1c2e52 --- /dev/null +++ b/app/code/Magento/CatalogSearch/Plugin/EnableEavIndexer.php @@ -0,0 +1,33 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +declare(strict_types=1); + +namespace Magento\CatalogSearch\Plugin; + +/** + * Enable Product EAV indexer in configuration for MySQL search engine + */ +class EnableEavIndexer +{ + /** + * Config search engine path + */ + const SEARCH_ENGINE_VALUE_PATH = 'groups/search/fields/engine/value'; + + /** + * @param \Magento\Config\Model\Config $subject + */ + public function beforeSave(\Magento\Config\Model\Config $subject) + { + $searchEngine = $subject->getData(self::SEARCH_ENGINE_VALUE_PATH); + if ($searchEngine === 'mysql') { + $data = $subject->getData(); + $data['groups']['search']['fields']['enable_eav_indexer']['value'] = 1; + + $subject->setData($data); + } + } +} diff --git a/app/code/Magento/CatalogSearch/Test/Mftf/composer.json b/app/code/Magento/CatalogSearch/Test/Mftf/composer.json deleted file mode 100644 index 7d54620eeac83..0000000000000 --- a/app/code/Magento/CatalogSearch/Test/Mftf/composer.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "name": "magento/functional-test-module-catalog-search", - "description": "N/A", - "config": { - "sort-packages": true - }, - "require": { - "php": "~7.1.3||~7.2.0", - "magento/magento2-functional-testing-framework": "2.2.0", - "magento/functional-test-module-backend": "100.0.0-dev", - "magento/functional-test-module-catalog": "100.0.0-dev", - "magento/functional-test-module-catalog-inventory": "100.0.0-dev", - "magento/functional-test-module-customer": "100.0.0-dev", - "magento/functional-test-module-directory": "100.0.0-dev", - "magento/functional-test-module-eav": "100.0.0-dev", - "magento/functional-test-module-search": "100.0.0-dev", - "magento/functional-test-module-store": "100.0.0-dev", - "magento/functional-test-module-theme": "100.0.0-dev", - "magento/functional-test-module-ui": "100.0.0-dev" - }, - "type": "magento2-test", - "license": [ - "OSL-3.0", - "AFL-3.0" - ] -} diff --git a/app/code/Magento/CatalogSearch/Test/Unit/Controller/Advanced/ResultTest.php b/app/code/Magento/CatalogSearch/Test/Unit/Controller/Advanced/ResultTest.php index 9aa97f8e6b52a..891f008979e17 100644 --- a/app/code/Magento/CatalogSearch/Test/Unit/Controller/Advanced/ResultTest.php +++ b/app/code/Magento/CatalogSearch/Test/Unit/Controller/Advanced/ResultTest.php @@ -5,6 +5,9 @@ */ namespace Magento\CatalogSearch\Test\Unit\Controller\Advanced; +/** + * @SuppressWarnings(PHPMD.CouplingBetweenObjects) + */ class ResultTest extends \PHPUnit\Framework\TestCase { public function testResultActionFiltersSetBeforeLoadLayout() @@ -49,4 +52,90 @@ function ($added) use (&$filters) { ); $instance->execute(); } + + public function testUrlSetOnException() + { + $redirectResultMock = $this->createMock(\Magento\Framework\Controller\Result\Redirect::class); + $redirectResultMock->expects($this->once()) + ->method('setUrl'); + + $redirectFactoryMock = $this->getMockBuilder(\Magento\Framework\Controller\Result\RedirectFactory::class) + ->setMethods(['create']) + ->disableOriginalConstructor() + ->getMock(); + + $redirectFactoryMock->expects($this->any()) + ->method('create') + ->willReturn($redirectResultMock); + + $catalogSearchAdvanced = $this->createPartialMock( + \Magento\CatalogSearch\Model\Advanced::class, + ['addFilters'] + ); + + $catalogSearchAdvanced->expects($this->once())->method('addFilters')->will( + $this->throwException(new \Magento\Framework\Exception\LocalizedException( + new \Magento\Framework\Phrase("Test Exception") + )) + ); + + $responseMock = $this->createMock(\Magento\Framework\Webapi\Response::class); + $requestMock = $this->createPartialMock( + \Magento\Framework\App\Request\Http::class, + ['getQueryValue'] + ); + $requestMock->expects($this->any())->method('getQueryValue')->willReturn(['key' => 'value']); + + $redirectMock = $this->createMock(\Magento\Framework\App\Response\RedirectInterface::class); + $redirectMock->expects($this->any())->method('error')->with('urlstring'); + + $messageManagerMock = $this->createMock(\Magento\Framework\Message\Manager::class); + + $eventManagerMock = $this->createMock(\Magento\Framework\Event\ManagerInterface::class); + + $contextMock = $this->createMock(\Magento\Framework\App\Action\Context::class); + $contextMock->expects($this->any()) + ->method('getRequest') + ->willReturn($requestMock); + $contextMock->expects($this->any()) + ->method('getResponse') + ->willReturn($responseMock); + $contextMock->expects($this->any()) + ->method('getRedirect') + ->willReturn($redirectMock); + $contextMock->expects($this->any()) + ->method('getMessageManager') + ->willReturn($messageManagerMock); + $contextMock->expects($this->any()) + ->method('getEventManager') + ->willReturn($eventManagerMock); + $contextMock->expects($this->any()) + ->method('getResultRedirectFactory') + ->willReturn($redirectFactoryMock); + + $urlMock = $this->createMock(\Magento\Framework\Url::class); + $urlMock->expects($this->once()) + ->method('addQueryParams') + ->willReturnSelf(); + $urlMock->expects($this->once()) + ->method('getUrl') + ->willReturn("urlstring"); + + $urlFactoryMock = $this->createMock(\Magento\Framework\UrlFactory::class); + $urlFactoryMock->expects($this->once()) + ->method('create') + ->will($this->returnValue($urlMock)); + + $objectManager = new \Magento\Framework\TestFramework\Unit\Helper\ObjectManager($this); + + /** @var \Magento\CatalogSearch\Controller\Advanced\Result $instance */ + $instance = $objectManager->getObject( + \Magento\CatalogSearch\Controller\Advanced\Result::class, + ['context' => $contextMock, + 'catalogSearchAdvanced' => $catalogSearchAdvanced, + 'urlFactory' => $urlFactoryMock + ] + ); + $this->assertEquals($redirectResultMock, $instance->execute()); + } } diff --git a/app/code/Magento/CatalogSearch/Test/Unit/Model/Adapter/Mysql/Aggregation/DataProvider/QueryBuilderTest.php b/app/code/Magento/CatalogSearch/Test/Unit/Model/Adapter/Mysql/Aggregation/DataProvider/QueryBuilderTest.php index b52664df749fe..72379c3819dea 100644 --- a/app/code/Magento/CatalogSearch/Test/Unit/Model/Adapter/Mysql/Aggregation/DataProvider/QueryBuilderTest.php +++ b/app/code/Magento/CatalogSearch/Test/Unit/Model/Adapter/Mysql/Aggregation/DataProvider/QueryBuilderTest.php @@ -17,7 +17,9 @@ use Magento\Store\Model\Store; /** - * Test for Magento\CatalogSearch\Model\Adapter\Mysql\Aggregation\DataProvider\QueryBuilder. + * Test for Magento\CatalogSearch\Model\Adapter\Mysql\Aggregation\DataProvider\QueryBuilder. + * + * @SuppressWarnings(PHPMD.CouplingBetweenObjects) */ class QueryBuilderTest extends \PHPUnit\Framework\TestCase { @@ -57,10 +59,25 @@ protected function setUp() ->method('getConnection') ->willReturn($this->adapterMock); + $this->indexScopeResolverMock = $this->createMock( + \Magento\Framework\Search\Request\IndexScopeResolverInterface::class + ); + $this->dimensionMock = $this->createMock(\Magento\Framework\Indexer\Dimension::class); + $this->dimensionFactoryMock = $this->createMock(\Magento\Framework\Indexer\DimensionFactory::class); + $this->dimensionFactoryMock->method('create')->willReturn($this->dimensionMock); + $storeMock = $this->createMock(\Magento\Store\Api\Data\StoreInterface::class); + $storeMock->method('getId')->willReturn(1); + $storeMock->method('getWebsiteId')->willReturn(1); + $this->storeManagerMock = $this->createMock(\Magento\Store\Model\StoreManagerInterface::class); + $this->storeManagerMock->method('getStore')->willReturn($storeMock); + $this->indexScopeResolverMock->method('resolve')->willReturn('catalog_product_index_price'); + $this->model = new QueryBuilder( $this->resourceConnectionMock, $this->scopeResolverMock, - $this->inventoryConfigMock + $this->inventoryConfigMock, + $this->indexScopeResolverMock, + $this->dimensionFactoryMock ); } @@ -81,8 +98,6 @@ public function testBuildWithPriceAttributeCode() $this->scopeResolverMock->expects($this->once())->method('getScope') ->with($scope)->willReturn($storeMock); $storeMock->expects($this->once())->method('getWebsiteId')->willReturn(1); - $this->resourceConnectionMock->expects($this->once())->method('getTableName') - ->with('catalog_product_index_price')->willReturn('catalog_product_index_price'); $selectMock->expects($this->once())->method('from') ->with(['main_table' => 'catalog_product_index_price'], null) ->willReturn($selectMock); diff --git a/app/code/Magento/CatalogSearch/Test/Unit/Model/Adapter/Mysql/Dynamic/DataProviderTest.php b/app/code/Magento/CatalogSearch/Test/Unit/Model/Adapter/Mysql/Dynamic/DataProviderTest.php index 1aeeb0d9bd731..1186dd6936cc6 100644 --- a/app/code/Magento/CatalogSearch/Test/Unit/Model/Adapter/Mysql/Dynamic/DataProviderTest.php +++ b/app/code/Magento/CatalogSearch/Test/Unit/Model/Adapter/Mysql/Dynamic/DataProviderTest.php @@ -74,6 +74,18 @@ protected function setUp() $this->mysqlDataProviderMock = $this->createMock(DataProviderInterface::class); $this->intervalFactoryMock = $this->createMock(IntervalFactory::class); $this->storeManagerMock = $this->createMock(StoreManager::class); + $this->indexScopeResolverMock = $this->createMock( + \Magento\Framework\Search\Request\IndexScopeResolverInterface::class + ); + $this->dimensionMock = $this->createMock(\Magento\Framework\Indexer\Dimension::class); + $this->dimensionFactoryMock = $this->createMock(\Magento\Framework\Indexer\DimensionFactory::class); + $this->dimensionFactoryMock->method('create')->willReturn($this->dimensionMock); + $storeMock = $this->createMock(\Magento\Store\Api\Data\StoreInterface::class); + $storeMock->method('getId')->willReturn(1); + $storeMock->method('getWebsiteId')->willReturn(1); + $this->storeManagerMock->method('getStore')->willReturn($storeMock); + $this->indexScopeResolverMock->method('resolve')->willReturn('catalog_product_index_price'); + $this->sessionMock->method('getCustomerGroupId')->willReturn(1); $this->model = new DataProvider( $this->resourceConnectionMock, @@ -81,7 +93,9 @@ protected function setUp() $this->sessionMock, $this->mysqlDataProviderMock, $this->intervalFactoryMock, - $this->storeManagerMock + $this->storeManagerMock, + $this->indexScopeResolverMock, + $this->dimensionFactoryMock ); } @@ -97,10 +111,6 @@ public function testGetAggregationsUsesFrontendPriceIndexerTable() $entityStorageMock = $this->createMock(EntityStorage::class); $entityStorageMock->expects($this->any())->method('getSource')->willReturn($tableMock); - $storeMock = $this->createMock(\Magento\Store\Api\Data\StoreInterface::class); - $storeMock->expects($this->once())->method('getWebsiteId')->willReturn(42); - $this->storeManagerMock->expects($this->once())->method('getStore')->willReturn($storeMock); - $this->model->getAggregations($entityStorageMock); } } diff --git a/app/code/Magento/CatalogSearch/Test/Unit/Model/Indexer/FulltextTest.php b/app/code/Magento/CatalogSearch/Test/Unit/Model/Indexer/FulltextTest.php index 595e32b4c1988..d7129b9c224fc 100644 --- a/app/code/Magento/CatalogSearch/Test/Unit/Model/Indexer/FulltextTest.php +++ b/app/code/Magento/CatalogSearch/Test/Unit/Model/Indexer/FulltextTest.php @@ -6,7 +6,7 @@ namespace Magento\CatalogSearch\Test\Unit\Model\Indexer; use \Magento\Framework\Indexer\Dimension; -use Magento\Framework\Indexer\Dimension\DimensionProviderInterface; +use Magento\Framework\Indexer\DimensionProviderInterface; use Magento\Framework\TestFramework\Unit\Helper\ObjectManager as ObjectManagerHelper; /** diff --git a/app/code/Magento/CatalogSearch/Test/Unit/Model/Search/FilterMapper/ExclusionStrategyTest.php b/app/code/Magento/CatalogSearch/Test/Unit/Model/Search/FilterMapper/ExclusionStrategyTest.php index 7c6cafd7e9924..09591532f9f06 100644 --- a/app/code/Magento/CatalogSearch/Test/Unit/Model/Search/FilterMapper/ExclusionStrategyTest.php +++ b/app/code/Magento/CatalogSearch/Test/Unit/Model/Search/FilterMapper/ExclusionStrategyTest.php @@ -15,6 +15,9 @@ use Magento\Framework\Search\Request\Filter\Term; use Magento\Store\Api\Data\WebsiteInterface; +/** + * @SuppressWarnings(PHPMD.CouplingBetweenObjects) + */ class ExclusionStrategyTest extends \PHPUnit\Framework\TestCase { /** @@ -50,10 +53,31 @@ protected function setUp() $this->storeManagerMock = $this->createMock(StoreManagerInterface::class); $this->aliasResolverMock = $this->createMock(AliasResolver::class); + $this->indexScopeResolverMock = $this->createMock( + \Magento\Framework\Search\Request\IndexScopeResolverInterface::class + ); + $this->tableResolverMock = $this->createMock( + \Magento\Framework\Indexer\ScopeResolver\IndexScopeResolver::class + ); + $this->dimensionMock = $this->createMock(\Magento\Framework\Indexer\Dimension::class); + $this->dimensionFactoryMock = $this->createMock(\Magento\Framework\Indexer\DimensionFactory::class); + $this->dimensionFactoryMock->method('create')->willReturn($this->dimensionMock); + $storeMock = $this->createMock(\Magento\Store\Api\Data\StoreInterface::class); + $storeMock->method('getId')->willReturn(1); + $storeMock->method('getWebsiteId')->willReturn(1); + $this->storeManagerMock->method('getStore')->willReturn($storeMock); + $this->indexScopeResolverMock->method('resolve')->willReturn('catalog_product_index_price'); + $this->httpContextMock = $this->createMock(\Magento\Framework\App\Http\Context::class); + $this->httpContextMock->method('getValue')->willReturn(1); + $this->model = new ExclusionStrategy( $this->resourceConnectionMock, $this->storeManagerMock, - $this->aliasResolverMock + $this->aliasResolverMock, + $this->tableResolverMock, + $this->dimensionFactoryMock, + $this->indexScopeResolverMock, + $this->httpContextMock ); } diff --git a/app/code/Magento/CatalogSearch/Test/Unit/Plugin/EnableEavIndexerTest.php b/app/code/Magento/CatalogSearch/Test/Unit/Plugin/EnableEavIndexerTest.php new file mode 100644 index 0000000000000..0eac2e3309aec --- /dev/null +++ b/app/code/Magento/CatalogSearch/Test/Unit/Plugin/EnableEavIndexerTest.php @@ -0,0 +1,68 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +declare(strict_types=1); + +namespace Magento\CatalogSearch\Test\Unit\Plugin; + +use Magento\Framework\TestFramework\Unit\Helper\ObjectManager as ObjectManagerHelper; + +class EnableEavIndexerTest extends \PHPUnit\Framework\TestCase +{ + /** + * @var \Magento\CatalogSearch\Plugin\EnableEavIndexer + */ + private $model; + + /** + * @var \Magento\Config\Model\Config|\PHPUnit_Framework_MockObject_MockObject + */ + private $config; + + /** + * Set up + * + * @return void + */ + protected function setUp() + { + $this->config = $this->getMockBuilder(\Magento\Config\Model\Config::class) + ->disableOriginalConstructor() + ->setMethods(['getData', 'setData']) + ->getMock(); + + $objectManagerHelper = new ObjectManagerHelper($this); + $this->model = $objectManagerHelper->getObject( + \Magento\CatalogSearch\Plugin\EnableEavIndexer::class + ); + } + + /** + * Test with other search engine (not MySQL) selected in config + * + * @return void + */ + public function testBeforeSave() + { + $this->config->expects($this->once())->method('getData')->willReturn('elasticsearch'); + $this->config->expects($this->never())->method('setData')->willReturnSelf(); + + $this->model->beforeSave($this->config); + } + + /** + * Test with MySQL search engine selected in config + * + * @return void + */ + public function testBeforeSaveMysqlSearchEngine() + { + $this->config->expects($this->at(0))->method('getData')->willReturn('mysql'); + $this->config->expects($this->at(1))->method('getData')->willReturn([]); + $this->config->expects($this->once())->method('setData')->willReturnSelf(); + + $this->model->beforeSave($this->config); + } +} diff --git a/app/code/Magento/CatalogSearch/composer.json b/app/code/Magento/CatalogSearch/composer.json index 298511ef428a9..1000e349b6f9a 100644 --- a/app/code/Magento/CatalogSearch/composer.json +++ b/app/code/Magento/CatalogSearch/composer.json @@ -9,7 +9,7 @@ "magento/framework": "*", "magento/module-backend": "*", "magento/module-catalog": "*", - "magento/module-indexer": "100.2.*", + "magento/module-indexer": "*", "magento/module-catalog-inventory": "*", "magento/module-customer": "*", "magento/module-directory": "*", @@ -19,6 +19,9 @@ "magento/module-theme": "*", "magento/module-ui": "*" }, + "suggest": { + "magento/module-config": "*" + }, "type": "magento2-module", "license": [ "OSL-3.0", diff --git a/app/code/Magento/CatalogSearch/etc/adminhtml/system.xml b/app/code/Magento/CatalogSearch/etc/adminhtml/system.xml index 18d2cdf542799..39235511eaeec 100644 --- a/app/code/Magento/CatalogSearch/etc/adminhtml/system.xml +++ b/app/code/Magento/CatalogSearch/etc/adminhtml/system.xml @@ -36,6 +36,14 @@ <label>Autocomplete Limit</label> <validate>validate-digits</validate> </field> + <field id="enable_eav_indexer" translate="label" type="select" sortOrder="18" showInDefault="1" showInWebsite="0" showInStore="0"> + <label>Enable EAV Indexer</label> + <comment>Enable/Disable Product EAV indexer to improve indexation speed. Make sure that indexer is not used by 3rd party extensions.</comment> + <depends> + <field id="engine" separator="," negative="1">mysql</field> + </depends> + <source_model>Magento\Config\Model\Config\Source\Yesno</source_model> + </field> </group> </section> </system> diff --git a/app/code/Magento/CatalogSearch/etc/config.xml b/app/code/Magento/CatalogSearch/etc/config.xml index d2b50fe9f5336..66b79226c9f34 100644 --- a/app/code/Magento/CatalogSearch/etc/config.xml +++ b/app/code/Magento/CatalogSearch/etc/config.xml @@ -17,6 +17,7 @@ <max_query_length>128</max_query_length> <max_count_cacheable_search_terms>100</max_count_cacheable_search_terms> <autocomplete_limit>8</autocomplete_limit> + <enable_eav_indexer>1</enable_eav_indexer> </search> </catalog> </default> diff --git a/app/code/Magento/CatalogSearch/etc/di.xml b/app/code/Magento/CatalogSearch/etc/di.xml index 3d1c4470b1ae8..cc07384d4c525 100644 --- a/app/code/Magento/CatalogSearch/etc/di.xml +++ b/app/code/Magento/CatalogSearch/etc/di.xml @@ -316,4 +316,28 @@ </argument> </arguments> </type> + <type name="Magento\CatalogSearch\Model\Search\FilterMapper\ExclusionStrategy"> + <arguments> + <argument name="priceTableResolver" xsi:type="object"> + Magento\Catalog\Model\Indexer\Product\Price\PriceTableResolver + </argument> + </arguments> + </type> + <type name="Magento\CatalogSearch\Model\Adapter\Mysql\Dynamic\DataProvider"> + <arguments> + <argument name="priceTableResolver" xsi:type="object"> + Magento\Catalog\Model\Indexer\Product\Price\PriceTableResolver + </argument> + </arguments> + </type> + <type name="Magento\CatalogSearch\Model\Adapter\Mysql\Aggregation\DataProvider\QueryBuilder"> + <arguments> + <argument name="priceTableResolver" xsi:type="object"> + Magento\Catalog\Model\Indexer\Product\Price\PriceTableResolver + </argument> + </arguments> + </type> + <type name="Magento\Config\Model\Config"> + <plugin name="config_enable_eav_indexer" type="Magento\CatalogSearch\Plugin\EnableEavIndexer" /> + </type> </config> diff --git a/app/code/Magento/CatalogUrlRewrite/Plugin/Store/Block/Switcher.php b/app/code/Magento/CatalogUrlRewrite/Plugin/Store/Block/Switcher.php deleted file mode 100644 index 44213c007551c..0000000000000 --- a/app/code/Magento/CatalogUrlRewrite/Plugin/Store/Block/Switcher.php +++ /dev/null @@ -1,86 +0,0 @@ -<?php -/** - * Copyright © Magento, Inc. All rights reserved. - * See COPYING.txt for license details. - */ -declare(strict_types=1); - -namespace Magento\CatalogUrlRewrite\Plugin\Store\Block; - -use Magento\Framework\Data\Helper\PostHelper; -use Magento\Store\Api\StoreResolverInterface; -use Magento\Store\Model\Store; -use Magento\UrlRewrite\Model\UrlFinderInterface; -use Magento\UrlRewrite\Service\V1\Data\UrlRewrite; -use Magento\Framework\App\Request\Http as HttpRequest; - -/** - * Plugin makes connection between Store and UrlRewrite modules - * because Magento\Store\Block\Switcher should not know about UrlRewrite module functionality. - */ -class Switcher -{ - /** - * @var PostHelper - */ - private $postHelper; - - /** - * @var UrlFinderInterface - */ - private $urlFinder; - - /** - * @var HttpRequest - */ - private $request; - - /** - * @param PostHelper $postHelper - * @param UrlFinderInterface $urlFinder - * @param HttpRequest $request - */ - public function __construct( - PostHelper $postHelper, - UrlFinderInterface $urlFinder, - HttpRequest $request - ) { - $this->postHelper = $postHelper; - $this->urlFinder = $urlFinder; - $this->request = $request; - } - - /** - * @param \Magento\Store\Block\Switcher $subject - * @param string $result - * @param Store $store - * @param array $data - * @return string - * @SuppressWarnings(PHPMD.UnusedFormalParameter) - */ - public function afterGetTargetStorePostData( - \Magento\Store\Block\Switcher $subject, - string $result, - Store $store, - array $data = [] - ): string { - $data[StoreResolverInterface::PARAM_NAME] = $store->getCode(); - $currentUrl = $store->getCurrentUrl(true); - $baseUrl = $store->getBaseUrl(); - $urlPath = parse_url($currentUrl, PHP_URL_PATH); - $urlToSwitch = $currentUrl; - - //check only catalog pages - if ($this->request->getFrontName() === 'catalog') { - $currentRewrite = $this->urlFinder->findOneByData([ - UrlRewrite::REQUEST_PATH => ltrim($urlPath, '/'), - UrlRewrite::STORE_ID => $store->getId(), - ]); - if (null === $currentRewrite) { - $urlToSwitch = $baseUrl; - } - } - - return $this->postHelper->getPostData($urlToSwitch, $data); - } -} diff --git a/app/code/Magento/CatalogUrlRewrite/Test/Mftf/composer.json b/app/code/Magento/CatalogUrlRewrite/Test/Mftf/composer.json deleted file mode 100644 index 03c48982f5865..0000000000000 --- a/app/code/Magento/CatalogUrlRewrite/Test/Mftf/composer.json +++ /dev/null @@ -1,24 +0,0 @@ -{ - "name": "magento/functional-test-module-catalog-url-rewrite", - "description": "N/A", - "config": { - "sort-packages": true - }, - "require": { - "php": "~7.1.3||~7.2.0", - "magento/magento2-functional-testing-framework": "2.2.0", - "magento/functional-test-module-backend": "100.0.0-dev", - "magento/functional-test-module-catalog": "100.0.0-dev", - "magento/functional-test-module-catalog-import-export": "100.0.0-dev", - "magento/functional-test-module-eav": "100.0.0-dev", - "magento/functional-test-module-import-export": "100.0.0-dev", - "magento/functional-test-module-store": "100.0.0-dev", - "magento/functional-test-module-ui": "100.0.0-dev", - "magento/functional-test-module-url-rewrite": "100.0.0-dev" - }, - "type": "magento2-test", - "license": [ - "OSL-3.0", - "AFL-3.0" - ] -} diff --git a/app/code/Magento/CatalogUrlRewrite/etc/frontend/di.xml b/app/code/Magento/CatalogUrlRewrite/etc/frontend/di.xml deleted file mode 100644 index 3a9122b2f748d..0000000000000 --- a/app/code/Magento/CatalogUrlRewrite/etc/frontend/di.xml +++ /dev/null @@ -1,12 +0,0 @@ -<?xml version="1.0"?> -<!-- -/** - * Copyright © Magento, Inc. All rights reserved. - * See COPYING.txt for license details. - */ ---> -<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:ObjectManager/etc/config.xsd"> - <type name="\Magento\Store\Block\Switcher"> - <plugin name="store_switcher_plugin" type="Magento\CatalogUrlRewrite\Plugin\Store\Block\Switcher"/> - </type> -</config> diff --git a/app/code/Magento/CatalogUrlRewriteGraphQl/Test/Mftf/composer.json b/app/code/Magento/CatalogUrlRewriteGraphQl/Test/Mftf/composer.json deleted file mode 100644 index a66ca925561c1..0000000000000 --- a/app/code/Magento/CatalogUrlRewriteGraphQl/Test/Mftf/composer.json +++ /dev/null @@ -1,21 +0,0 @@ -{ - "name": "magento/functional-test-module-catalog-url-rewrite-graph-ql", - "description": "N/A", - "config": { - "sort-packages": true - }, - "require": { - "php": "~7.1.3||~7.2.0", - "magento/magento2-functional-testing-framework": "2.2.0" - }, - "suggest": { - "magento/functional-test-module-catalog-url-rewrite": "100.0.0-dev", - "magento/functional-test-module-catalog-graph-ql": "100.0.0-dev", - "magento/functional-test-module-url-rewrite-graph-ql": "100.0.0-dev" - }, - "type": "magento2-test", - "license": [ - "OSL-3.0", - "AFL-3.0" - ] -} diff --git a/app/code/Magento/CatalogWidget/Model/Rule/Condition/Product.php b/app/code/Magento/CatalogWidget/Model/Rule/Condition/Product.php index f22879df0ae0c..29adc1816d337 100644 --- a/app/code/Magento/CatalogWidget/Model/Rule/Condition/Product.php +++ b/app/code/Magento/CatalogWidget/Model/Rule/Condition/Product.php @@ -101,6 +101,9 @@ public function loadAttributeOptions() /** * {@inheritdoc} + * + * @param array &$attributes + * @return void */ protected function _addSpecialAttributes(array &$attributes) { @@ -163,8 +166,6 @@ protected function addGlobalAttribute( \Magento\Catalog\Model\ResourceModel\Eav\Attribute $attribute, \Magento\Catalog\Model\ResourceModel\Product\Collection $collection ) { - $storeId = $this->storeManager->getStore()->getId(); - switch ($attribute->getBackendType()) { case 'decimal': case 'datetime': @@ -173,10 +174,15 @@ protected function addGlobalAttribute( $collection->addAttributeToSelect($attribute->getAttributeCode(), 'inner'); break; default: - $alias = 'at_' . md5($this->getId()) . $attribute->getAttributeCode(); + $alias = 'at_' . sha1($this->getId()) . $attribute->getAttributeCode(); + + $connection = $this->_productResource->getConnection(); + $storeId = $connection->getIfNullSql($alias . '.store_id', $this->storeManager->getStore()->getId()); + $linkField = $attribute->getEntity()->getLinkField(); + $collection->getSelect()->join( - [$alias => $collection->getTable('catalog_product_index_eav')], - "($alias.entity_id = e.entity_id) AND ($alias.store_id = $storeId)" . + [$alias => $collection->getTable('catalog_product_entity_varchar')], + "($alias.$linkField = e.$linkField) AND ($alias.store_id = $storeId)" . " AND ($alias.attribute_id = {$attribute->getId()})", [] ); @@ -225,6 +231,8 @@ protected function addNotGlobalAttribute( /** * {@inheritdoc} + * + * @return string */ public function getMappedSqlField() { @@ -244,6 +252,9 @@ public function getMappedSqlField() /** * {@inheritdoc} + * + * @param \Magento\Catalog\Model\ResourceModel\Product\Collection $productCollection + * @return $this */ public function collectValidatedAttributes($productCollection) { diff --git a/app/code/Magento/CatalogWidget/Test/Mftf/composer.json b/app/code/Magento/CatalogWidget/Test/Mftf/composer.json deleted file mode 100644 index 9b3437526718a..0000000000000 --- a/app/code/Magento/CatalogWidget/Test/Mftf/composer.json +++ /dev/null @@ -1,24 +0,0 @@ -{ - "name": "magento/functional-test-module-catalog-widget", - "description": "N/A", - "config": { - "sort-packages": true - }, - "require": { - "php": "~7.1.3||~7.2.0", - "magento/magento2-functional-testing-framework": "2.2.0", - "magento/functional-test-module-backend": "100.0.0-dev", - "magento/functional-test-module-catalog": "100.0.0-dev", - "magento/functional-test-module-customer": "100.0.0-dev", - "magento/functional-test-module-eav": "100.0.0-dev", - "magento/functional-test-module-rule": "100.0.0-dev", - "magento/functional-test-module-store": "100.0.0-dev", - "magento/functional-test-module-widget": "100.0.0-dev", - "magento/functional-test-module-wishlist": "100.0.0-dev" - }, - "type": "magento2-test", - "license": [ - "OSL-3.0", - "AFL-3.0" - ] -} diff --git a/app/code/Magento/CatalogWidget/Test/Unit/Model/Rule/Condition/ProductTest.php b/app/code/Magento/CatalogWidget/Test/Unit/Model/Rule/Condition/ProductTest.php index 09270b6b41fc7..219cae6829299 100644 --- a/app/code/Magento/CatalogWidget/Test/Unit/Model/Rule/Condition/ProductTest.php +++ b/app/code/Magento/CatalogWidget/Test/Unit/Model/Rule/Condition/ProductTest.php @@ -17,11 +17,21 @@ class ProductTest extends \PHPUnit\Framework\TestCase */ private $model; + /** + * @var \Magento\Catalog\Model\ResourceModel\Product|\PHPUnit_Framework_MockObject_MockObject + */ + private $productResource; + /** * @var \PHPUnit_Framework_MockObject_MockObject */ private $attributeMock; + /** + * @inheritdoc + * + * @return void + */ protected function setUp() { $objectManagerHelper = new ObjectManager($this); @@ -33,9 +43,9 @@ protected function setUp() $storeManager = $this->createMock(\Magento\Store\Model\StoreManagerInterface::class); $storeMock = $this->createMock(\Magento\Store\Api\Data\StoreInterface::class); $storeManager->expects($this->any())->method('getStore')->willReturn($storeMock); - $productResource = $this->createMock(\Magento\Catalog\Model\ResourceModel\Product::class); - $productResource->expects($this->once())->method('loadAllAttributes')->willReturnSelf(); - $productResource->expects($this->once())->method('getAttributesByCode')->willReturn([]); + $this->productResource = $this->createMock(\Magento\Catalog\Model\ResourceModel\Product::class); + $this->productResource->expects($this->once())->method('loadAllAttributes')->willReturnSelf(); + $this->productResource->expects($this->once())->method('getAttributesByCode')->willReturn([]); $productCategoryList = $this->getMockBuilder(\Magento\Catalog\Model\ProductCategoryList::class) ->disableOriginalConstructor() ->getMock(); @@ -45,7 +55,7 @@ protected function setUp() [ 'config' => $eavConfig, 'storeManager' => $storeManager, - 'productResource' => $productResource, + 'productResource' => $this->productResource, 'productCategoryList' => $productCategoryList, 'data' => [ 'rule' => $ruleMock, @@ -55,6 +65,11 @@ protected function setUp() ); } + /** + * Test addToCollection method. + * + * @return void + */ public function testAddToCollection() { $collectionMock = $this->createMock(\Magento\Catalog\Model\ResourceModel\Product\Collection::class); @@ -67,9 +82,22 @@ public function testAddToCollection() $this->attributeMock->expects($this->once())->method('isScopeGlobal')->willReturn(true); $this->attributeMock->expects($this->once())->method('isScopeGlobal')->willReturn(true); $this->attributeMock->expects($this->once())->method('getBackendType')->willReturn('multiselect'); + + $entityMock = $this->createMock(\Magento\Eav\Model\Entity\AbstractEntity::class); + $entityMock->expects($this->once())->method('getLinkField')->willReturn('entitiy_id'); + $this->attributeMock->expects($this->once())->method('getEntity')->willReturn($entityMock); + $connection = $this->createMock(\Magento\Framework\DB\Adapter\AdapterInterface::class); + + $this->productResource->expects($this->atLeastOnce())->method('getConnection')->willReturn($connection); + $this->model->addToCollection($collectionMock); } + /** + * Test getMappedSqlField method. + * + * @return void + */ public function testGetMappedSqlFieldSku() { $this->model->setAttribute('sku'); diff --git a/app/code/Magento/CatalogWidget/etc/widget.xml b/app/code/Magento/CatalogWidget/etc/widget.xml index bcc1b623da02e..1e6ed19057171 100644 --- a/app/code/Magento/CatalogWidget/etc/widget.xml +++ b/app/code/Magento/CatalogWidget/etc/widget.xml @@ -33,7 +33,7 @@ <parameter name="template" xsi:type="select" required="true" visible="true"> <label translate="true">Template</label> <options> - <option name="default" value="product/widget/content/grid.phtml" selected="true"> + <option name="default" value="Magento_CatalogWidget::product/widget/content/grid.phtml" selected="true"> <label translate="true">Products Grid Template</label> </option> </options> diff --git a/app/code/Magento/Checkout/Controller/Cart/UpdateItemQty.php b/app/code/Magento/Checkout/Controller/Cart/UpdateItemQty.php new file mode 100644 index 0000000000000..ac4a93e6066a4 --- /dev/null +++ b/app/code/Magento/Checkout/Controller/Cart/UpdateItemQty.php @@ -0,0 +1,161 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +declare(strict_types=1); + +namespace Magento\Checkout\Controller\Cart; + +use Magento\Checkout\Model\Cart\RequestQuantityProcessor; +use Magento\Framework\App\Action\Context; +use Magento\Framework\Exception\LocalizedException; +use Magento\Checkout\Model\Session as CheckoutSession; +use Magento\Framework\Serialize\Serializer\Json; +use Magento\Framework\Data\Form\FormKey\Validator as FormKeyValidator; +use Magento\Quote\Model\Quote\Item; +use Psr\Log\LoggerInterface; + +class UpdateItemQty extends \Magento\Framework\App\Action\Action +{ + /** + * @var RequestQuantityProcessor + */ + private $quantityProcessor; + + /** + * @var FormKeyValidator + */ + private $formKeyValidator; + + /** + * @var CheckoutSession + */ + private $checkoutSession; + + /** + * @var Json + */ + private $json; + + /** + * @var LoggerInterface + */ + private $logger; + + /** + * @param Context $context, + * @param RequestQuantityProcessor $quantityProcessor + * @param FormKeyValidator $formKeyValidator + * @param CheckoutSession $checkoutSession + * @param Json $json + * @param LoggerInterface $logger + */ + public function __construct( + Context $context, + RequestQuantityProcessor $quantityProcessor, + FormKeyValidator $formKeyValidator, + CheckoutSession $checkoutSession, + Json $json, + LoggerInterface $logger + ) { + $this->quantityProcessor = $quantityProcessor; + $this->formKeyValidator = $formKeyValidator; + $this->checkoutSession = $checkoutSession; + $this->json = $json; + $this->logger = $logger; + parent::__construct($context); + } + + /** + * @return void + */ + public function execute() + { + try { + if (!$this->formKeyValidator->validate($this->getRequest())) { + throw new LocalizedException( + __('Something went wrong while saving the page. Please refresh the page and try again.') + ); + } + + $cartData = $this->getRequest()->getParam('cart'); + if (!is_array($cartData)) { + throw new LocalizedException( + __('Something went wrong while saving the page. Please refresh the page and try again.') + ); + } + + $cartData = $this->quantityProcessor->process($cartData); + $quote = $this->checkoutSession->getQuote(); + + foreach ($cartData as $itemId => $itemInfo) { + $item = $quote->getItemById($itemId); + $qty = isset($itemInfo['qty']) ? (double)$itemInfo['qty'] : 0; + if ($item) { + $this->updateItemQuantity($item, $qty); + } + } + + $this->jsonResponse(); + } catch (LocalizedException $e) { + $this->jsonResponse($e->getMessage()); + } catch (\Exception $e) { + $this->logger->critical($e->getMessage()); + $this->jsonResponse('Something went wrong while saving the page. Please refresh the page and try again.'); + } + } + + /** + * Updates quote item quantity. + * + * @param Item $item + * @param float $qty + * @throws LocalizedException + */ + private function updateItemQuantity(Item $item, float $qty) + { + if ($qty > 0) { + $item->setQty($qty); + + if ($item->getHasError()) { + throw new LocalizedException(__($item->getMessage())); + } + } + } + + /** + * JSON response builder. + * + * @param string $error + * @return void + */ + private function jsonResponse(string $error = '') + { + $this->getResponse()->representJson( + $this->json->serialize($this->getResponseData($error)) + ); + } + + /** + * Returns response data. + * + * @param string $error + * @return array + */ + private function getResponseData(string $error = ''): array + { + $response = [ + 'success' => true, + ]; + + if (!empty($error)) { + $response = [ + 'success' => false, + 'error_message' => $error, + ]; + } + + return $response; + } +} diff --git a/app/code/Magento/Checkout/Controller/Cart/UpdatePost.php b/app/code/Magento/Checkout/Controller/Cart/UpdatePost.php index 174cb38b0e9a9..05ce48c9b46ce 100644 --- a/app/code/Magento/Checkout/Controller/Cart/UpdatePost.php +++ b/app/code/Magento/Checkout/Controller/Cart/UpdatePost.php @@ -6,8 +6,45 @@ */ namespace Magento\Checkout\Controller\Cart; +use Magento\Checkout\Model\Cart\RequestQuantityProcessor; + class UpdatePost extends \Magento\Checkout\Controller\Cart { + /** + * @var RequestQuantityProcessor + */ + private $quantityProcessor; + + /** + * @param \Magento\Framework\App\Action\Context $context + * @param \Magento\Framework\App\Config\ScopeConfigInterface $scopeConfig + * @param \Magento\Checkout\Model\Session $checkoutSession + * @param \Magento\Store\Model\StoreManagerInterface $storeManager + * @param \Magento\Framework\Data\Form\FormKey\Validator $formKeyValidator + * @param \Magento\Checkout\Model\Cart $cart + * @param RequestQuantityProcessor $quantityProcessor + */ + public function __construct( + \Magento\Framework\App\Action\Context $context, + \Magento\Framework\App\Config\ScopeConfigInterface $scopeConfig, + \Magento\Checkout\Model\Session $checkoutSession, + \Magento\Store\Model\StoreManagerInterface $storeManager, + \Magento\Framework\Data\Form\FormKey\Validator $formKeyValidator, + \Magento\Checkout\Model\Cart $cart, + RequestQuantityProcessor $quantityProcessor = null + ) { + parent::__construct( + $context, + $scopeConfig, + $checkoutSession, + $storeManager, + $formKeyValidator, + $cart + ); + + $this->quantityProcessor = $quantityProcessor ?: $this->_objectManager->get(RequestQuantityProcessor::class); + } + /** * Empty customer's shopping cart * @@ -34,20 +71,10 @@ protected function _updateShoppingCart() try { $cartData = $this->getRequest()->getParam('cart'); if (is_array($cartData)) { - $filter = new \Zend_Filter_LocalizedToNormalized( - ['locale' => $this->_objectManager->get( - \Magento\Framework\Locale\ResolverInterface::class - )->getLocale()] - ); - foreach ($cartData as $index => $data) { - if (isset($data['qty'])) { - $cartData[$index]['qty'] = $filter->filter(trim($data['qty'])); - } - } if (!$this->cart->getCustomerSession()->getCustomerId() && $this->cart->getQuote()->getCustomerId()) { $this->cart->getQuote()->setCustomerId(null); } - + $cartData = $this->quantityProcessor->process($cartData); $cartData = $this->cart->suggestItemsQty($cartData); $this->cart->updateItems($cartData)->save(); } diff --git a/app/code/Magento/Checkout/Model/Cart/RequestQuantityProcessor.php b/app/code/Magento/Checkout/Model/Cart/RequestQuantityProcessor.php new file mode 100644 index 0000000000000..971b35c8f3e3d --- /dev/null +++ b/app/code/Magento/Checkout/Model/Cart/RequestQuantityProcessor.php @@ -0,0 +1,48 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +declare(strict_types=1); + +namespace Magento\Checkout\Model\Cart; + +use Magento\Framework\Locale\ResolverInterface; + +class RequestQuantityProcessor +{ + /** + * @var ResolverInterface + */ + private $localeResolver; + + /** + * RequestQuantityProcessor constructor. + * @param ResolverInterface $localeResolver + */ + public function __construct( + ResolverInterface $localeResolver + ) { + $this->localeResolver = $localeResolver; + } + + /** + * Process cart request data + * + * @param array $cartData + * @return array + */ + public function process(array $cartData): array + { + $filter = new \Zend\I18n\Filter\NumberParse($this->localeResolver->getLocale()); + + foreach ($cartData as $index => $data) { + if (isset($data['qty'])) { + $data['qty'] = is_string($data['qty']) ? trim($data['qty']) : $data['qty']; + $cartData[$index]['qty'] = $filter->filter($data['qty']); + } + } + + return $cartData; + } +} diff --git a/app/code/Magento/Checkout/Model/DefaultConfigProvider.php b/app/code/Magento/Checkout/Model/DefaultConfigProvider.php index b5727bf8f365e..16f13511001e9 100644 --- a/app/code/Magento/Checkout/Model/DefaultConfigProvider.php +++ b/app/code/Magento/Checkout/Model/DefaultConfigProvider.php @@ -8,12 +8,14 @@ use Magento\Catalog\Helper\Product\ConfigurationPool; use Magento\Checkout\Helper\Data as CheckoutHelper; use Magento\Checkout\Model\Session as CheckoutSession; +use Magento\Customer\Api\AddressMetadataInterface; use Magento\Customer\Api\CustomerRepositoryInterface as CustomerRepository; use Magento\Customer\Model\Context as CustomerContext; use Magento\Customer\Model\Session as CustomerSession; use Magento\Customer\Model\Url as CustomerUrlManager; use Magento\Framework\App\Config\ScopeConfigInterface; use Magento\Framework\App\Http\Context as HttpContext; +use Magento\Framework\App\ObjectManager; use Magento\Framework\Data\Form\FormKey; use Magento\Framework\Locale\FormatInterface as LocaleFormat; use Magento\Framework\UrlInterface; @@ -159,6 +161,11 @@ class DefaultConfigProvider implements ConfigProviderInterface */ protected $urlBuilder; + /** + * @var AddressMetadataInterface + */ + private $addressMetadata; + /** * @param CheckoutHelper $checkoutHelper * @param Session $checkoutSession @@ -186,6 +193,7 @@ class DefaultConfigProvider implements ConfigProviderInterface * @param \Magento\Store\Model\StoreManagerInterface $storeManager * @param \Magento\Quote\Api\PaymentMethodManagementInterface $paymentMethodManagement * @param UrlInterface $urlBuilder + * @param AddressMetadataInterface $addressMetadata * @codeCoverageIgnore * @SuppressWarnings(PHPMD.ExcessiveParameterList) */ @@ -215,7 +223,8 @@ public function __construct( \Magento\Shipping\Model\Config $shippingMethodConfig, \Magento\Store\Model\StoreManagerInterface $storeManager, \Magento\Quote\Api\PaymentMethodManagementInterface $paymentMethodManagement, - UrlInterface $urlBuilder + UrlInterface $urlBuilder, + AddressMetadataInterface $addressMetadata = null ) { $this->checkoutHelper = $checkoutHelper; $this->checkoutSession = $checkoutSession; @@ -243,6 +252,7 @@ public function __construct( $this->storeManager = $storeManager; $this->paymentMethodManagement = $paymentMethodManagement; $this->urlBuilder = $urlBuilder; + $this->addressMetadata = $addressMetadata ?: ObjectManager::getInstance()->get(AddressMetadataInterface::class); } /** @@ -324,11 +334,34 @@ private function getCustomerData() $customerData = $customer->__toArray(); foreach ($customer->getAddresses() as $key => $address) { $customerData['addresses'][$key]['inline'] = $this->getCustomerAddressInline($address); + if ($address->getCustomAttributes()) { + $customerData['addresses'][$key]['custom_attributes'] = $this->filterNotVisibleAttributes( + $customerData['addresses'][$key]['custom_attributes'] + ); + } } } return $customerData; } + /** + * Filter not visible on storefront custom attributes. + * + * @param array $attributes + * @return array + */ + private function filterNotVisibleAttributes(array $attributes) + { + $attributesMetadata = $this->addressMetadata->getAllAttributesMetadata(); + foreach ($attributesMetadata as $attributeMetadata) { + if (!$attributeMetadata->isVisible()) { + unset($attributes[$attributeMetadata->getAttributeCode()]); + } + } + + return $attributes; + } + /** * Set additional customer address data * diff --git a/app/code/Magento/Checkout/Test/Mftf/ActionGroup/CheckoutActionGroup.xml b/app/code/Magento/Checkout/Test/Mftf/ActionGroup/CheckoutActionGroup.xml index e70bccbfdfe2b..4c9ef93c2c4d3 100644 --- a/app/code/Magento/Checkout/Test/Mftf/ActionGroup/CheckoutActionGroup.xml +++ b/app/code/Magento/Checkout/Test/Mftf/ActionGroup/CheckoutActionGroup.xml @@ -93,13 +93,13 @@ <argument name="customerAddressVar"/> </arguments> <waitForElement selector="{{CheckoutPaymentSection.paymentSectionTitle}}" time="30" stepKey="waitForPaymentSectionLoaded"/> - <see userInput="{{customerVar.firstname}}" selector="{{CheckoutPaymentSection.shipToInfomation}}" stepKey="assertShipToInformationFirstName"/> - <see userInput="{{customerVar.lastname}}" selector="{{CheckoutPaymentSection.shipToInfomation}}" stepKey="assertShipToInformationLastName"/> - <see userInput="{{customerAddressVar.street[0]}}" selector="{{CheckoutPaymentSection.shipToInfomation}}" stepKey="assertShipToInformationStreet"/> - <see userInput="{{customerAddressVar.city}}" selector="{{CheckoutPaymentSection.shipToInfomation}}" stepKey="assertShipToInformationCity"/> - <see userInput="{{customerAddressVar.state}}" selector="{{CheckoutPaymentSection.shipToInfomation}}" stepKey="assertShipToInformationState"/> - <see userInput="{{customerAddressVar.postcode}}" selector="{{CheckoutPaymentSection.shipToInfomation}}" stepKey="assertShipToInformationPostcode"/> - <see userInput="{{customerAddressVar.telephone}}" selector="{{CheckoutPaymentSection.shipToInfomation}}" stepKey="assertShipToInformationTelephone"/> + <see userInput="{{customerVar.firstname}}" selector="{{CheckoutPaymentSection.shipToInformation}}" stepKey="assertShipToInformationFirstName"/> + <see userInput="{{customerVar.lastname}}" selector="{{CheckoutPaymentSection.shipToInformation}}" stepKey="assertShipToInformationLastName"/> + <see userInput="{{customerAddressVar.street[0]}}" selector="{{CheckoutPaymentSection.shipToInformation}}" stepKey="assertShipToInformationStreet"/> + <see userInput="{{customerAddressVar.city}}" selector="{{CheckoutPaymentSection.shipToInformation}}" stepKey="assertShipToInformationCity"/> + <see userInput="{{customerAddressVar.state}}" selector="{{CheckoutPaymentSection.shipToInformation}}" stepKey="assertShipToInformationState"/> + <see userInput="{{customerAddressVar.postcode}}" selector="{{CheckoutPaymentSection.shipToInformation}}" stepKey="assertShipToInformationPostcode"/> + <see userInput="{{customerAddressVar.telephone}}" selector="{{CheckoutPaymentSection.shipToInformation}}" stepKey="assertShipToInformationTelephone"/> </actionGroup> <!-- Check shipping method in checkout --> @@ -108,7 +108,7 @@ <argument name="shippingMethod"/> </arguments> <waitForElement selector="{{CheckoutPaymentSection.paymentSectionTitle}}" time="30" stepKey="waitForPaymentSectionLoaded"/> - <see userInput="{{shippingMethod}}" selector="{{CheckoutPaymentSection.shippingMethodInfomation}}" stepKey="assertshippingMethodInfomation"/> + <see userInput="{{shippingMethod}}" selector="{{CheckoutPaymentSection.shippingMethodInformation}}" stepKey="assertshippingMethodInformation"/> </actionGroup> <!-- Checkout select Check/Money Order payment --> diff --git a/app/code/Magento/Checkout/Test/Mftf/Section/CheckoutPaymentSection.xml b/app/code/Magento/Checkout/Test/Mftf/Section/CheckoutPaymentSection.xml index 6d7533be7e9ea..a12852ea1ef25 100644 --- a/app/code/Magento/Checkout/Test/Mftf/Section/CheckoutPaymentSection.xml +++ b/app/code/Magento/Checkout/Test/Mftf/Section/CheckoutPaymentSection.xml @@ -12,7 +12,7 @@ <element name="isPaymentSection" type="text" selector="//*[@class='opc-progress-bar']/li[contains(@class, '_active') and span[contains(.,'Review & Payments')]]"/> <element name="availablePaymentSolutions" type="text" selector="#checkout-payment-method-load>div>div>div:nth-child(2)>div.payment-method-title.field.choice"/> <element name="notAvailablePaymentSolutions" type="text" selector="#checkout-payment-method-load>div>div>div.payment-method._active>div.payment-method-title.field.choice"/> - <element name="billingNewAddressForm" type="text" selector=".billing-new-address-form"/> + <element name="billingNewAddressForm" type="text" selector="[data-form='billing-new-address']"/> <element name="placeOrderDisabled" type="button" selector="#checkout-payment-method-load button.disabled"/> <element name="update" type="button" selector=".payment-method-billing-address .action.action-update"/> <element name="guestFirstName" type="input" selector=".billing-address-form input[name*='firstname']"/> @@ -36,8 +36,8 @@ <element name="ProductItemByName" type="text" selector="//div[@class='product-item-details']//strong[@class='product-item-name'][text()='{{var1}}']" parameterized="true" /> <element name="ProductOptionsByProductItemName" type="text" selector="//div[@class='product-item-details']//strong[@class='product-item-name'][text()='{{var1}}']//ancestor::div[@class='product-item-details']//div[@class='product options']" parameterized="true" /> <element name="ProductOptionsActiveByProductItemName" type="text" selector="//div[@class='product-item-details']//strong[@class='product-item-name'][text()='{{var1}}']//ancestor::div[@class='product-item-details']//div[@class='product options active']" parameterized="true" /> - <element name="shipToInfomation" type="text" selector="//div[@class='ship-to']//div[@class='shipping-information-content']" /> - <element name="shippingMethodInfomation" type="text" selector="//div[@class='ship-via']//div[@class='shipping-information-content']" /> + <element name="shipToInformation" type="text" selector="//div[@class='ship-to']//div[@class='shipping-information-content']" /> + <element name="shippingMethodInformation" type="text" selector="//div[@class='ship-via']//div[@class='shipping-information-content']" /> <element name="paymentMethodTitle" type="text" selector=".payment-method-title span" /> <element name="productOptionsByProductItemPrice" type="text" selector="//div[@class='product-item-inner']//div[@class='subtotal']//span[@class='price'][contains(.,'{{var1}}')]//ancestor::div[@class='product-item-details']//div[@class='product options']" parameterized="true"/> <element name="productOptionsActiveByProductItemPrice" type="text" selector="//div[@class='subtotal']//span[@class='price'][contains(.,'{{var1}}')]//ancestor::div[@class='product-item-details']//div[@class='product options active']" parameterized="true"/> diff --git a/app/code/Magento/Checkout/Test/Mftf/Section/CheckoutShippingMethodsSection.xml b/app/code/Magento/Checkout/Test/Mftf/Section/CheckoutShippingMethodsSection.xml index 552341a531106..2d07cdd9bd08d 100644 --- a/app/code/Magento/Checkout/Test/Mftf/Section/CheckoutShippingMethodsSection.xml +++ b/app/code/Magento/Checkout/Test/Mftf/Section/CheckoutShippingMethodsSection.xml @@ -14,5 +14,7 @@ <element name="shippingMethodRow" type="text" selector=".form.methods-shipping table tbody tr"/> <element name="checkShippingMethodByName" type="radio" selector="//div[@id='checkout-shipping-method-load']//td[contains(., '{{var1}}')]/..//input" parameterized="true"/> <element name="shippingMethodRowByName" type="text" selector="//div[@id='checkout-shipping-method-load']//td[contains(., '{{var1}}')]/.." parameterized="true"/> + <element name="shipHereButton" type="button" selector="//button[contains(@class, 'action-select-shipping-item')]/parent::div/following-sibling::div/button[contains(@class, 'action-select-shipping-item')]"/> + <element name="shippingMethodLoader" type="button" selector="//div[contains(@class, 'checkout-shipping-method')]/following-sibling::div[contains(@class, 'loading-mask')]"/> </section> </sections> diff --git a/app/code/Magento/Checkout/Test/Mftf/Section/StorefrontMiniCartSection.xml b/app/code/Magento/Checkout/Test/Mftf/Section/StorefrontMiniCartSection.xml index faee71a54a0be..2c556f25f2064 100644 --- a/app/code/Magento/Checkout/Test/Mftf/Section/StorefrontMiniCartSection.xml +++ b/app/code/Magento/Checkout/Test/Mftf/Section/StorefrontMiniCartSection.xml @@ -10,7 +10,6 @@ xsi:noNamespaceSchemaLocation="../../../../../../../dev/tests/acceptance/vendor/magento/magento2-functional-testing-framework/src/Magento/FunctionalTestingFramework/Page/etc/SectionObject.xsd"> <section name="StorefrontMinicartSection"> <element name="productCount" type="text" selector="//header//div[contains(@class, 'minicart-wrapper')]//a[contains(@class, 'showcart')]//span[@class='counter-number']"/> - <element name="viewAndEditCart" type="button" selector="//header//div[contains(@class, 'minicart-wrapper')]//a[contains(@class, 'viewcart')]"/> <element name="productLinkByName" type="button" selector="//header//ol[@id='mini-cart']//div[@class='product-item-details']//a[contains(text(), '{{var1}}')]" parameterized="true"/> <element name="productPriceByName" type="text" selector="//header//ol[@id='mini-cart']//div[@class='product-item-details'][.//a[contains(text(), '{{var1}}')]]//span[@class='price']" parameterized="true"/> <element name="productImageByName" type="text" selector="//header//ol[@id='mini-cart']//span[@class='product-image-container']//img[@alt='{{var1}}']" parameterized="true"/> diff --git a/app/code/Magento/Checkout/Test/Mftf/Test/AddressStateFieldForUKCustomerRemainOptionAfterRefreshTest.xml b/app/code/Magento/Checkout/Test/Mftf/Test/AddressStateFieldForUKCustomerRemainOptionAfterRefreshTest.xml index 4b8d48a84073a..66146137d0122 100644 --- a/app/code/Magento/Checkout/Test/Mftf/Test/AddressStateFieldForUKCustomerRemainOptionAfterRefreshTest.xml +++ b/app/code/Magento/Checkout/Test/Mftf/Test/AddressStateFieldForUKCustomerRemainOptionAfterRefreshTest.xml @@ -16,6 +16,8 @@ <severity value="MAJOR"/> <testCaseId value="MAGETWO-93329"/> <group value="checkout"/> + <!-- Skipped because of MAGETWO-93726 --> + <group value="skip"/> </annotations> <before> <createData entity="_defaultCategory" stepKey="createCategory"/> @@ -45,6 +47,7 @@ <fillField selector="{{CheckoutShippingSection.lastName}}" userInput="{{CustomerEntityOne.lastname}}" stepKey="enterLastName"/> <fillField selector="{{CheckoutShippingSection.street}}" userInput="{{UK_Address.street[0]}}" stepKey="enterStreet"/> <fillField selector="{{CheckoutShippingSection.city}}" userInput="{{UK_Address.city}}" stepKey="enterCity"/> + <fillField selector="{{CheckoutShippingSection.stateInput}}" userInput="{{UK_Address.province}}" stepKey="enterProvince"/> <waitForPageLoad stepKey="waitFormToReload2"/> <see userInput="State/Province" stepKey="StateFieldStillExists"/> <fillField selector="{{CheckoutShippingSection.telephone}}" userInput="{{UK_Address.telephone}}" stepKey="enterTelephone"/> diff --git a/app/code/Magento/Checkout/Test/Mftf/Test/StorefrontCustomerCheckoutTest.xml b/app/code/Magento/Checkout/Test/Mftf/Test/StorefrontCustomerCheckoutTest.xml index c88f6cec4bcdb..1efff9783b90c 100644 --- a/app/code/Magento/Checkout/Test/Mftf/Test/StorefrontCustomerCheckoutTest.xml +++ b/app/code/Magento/Checkout/Test/Mftf/Test/StorefrontCustomerCheckoutTest.xml @@ -7,7 +7,7 @@ --> <tests xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" - xsi:noNamespaceSchemaLocation="../../../../../../../dev/tests/acceptance/vendor/magento/magento2-functional-testing-framework/src/Magento/FunctionalTestingFramework/Test/etc/testSchema.xsd"> + xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/testSchema.xsd"> <test name="StorefrontCustomerCheckoutTest"> <annotations> <features value="Checkout"/> @@ -60,6 +60,7 @@ <amOnPage stepKey="s67" url="{{AdminOrdersPage.url}}"/> <waitForPageLoad stepKey="s75"/> + <actionGroup ref="AdminOrdersGridClearFiltersActionGroup" stepKey="clearFiltersIfPresent"/> <fillField stepKey="s77" selector="{{AdminOrdersGridSection.search}}" userInput="{$s53}" /> <waitForPageLoad stepKey="s78"/> @@ -82,4 +83,111 @@ <click stepKey="s102" selector="{{AdminEditCustomerInformationSection.orders}}"/> <see stepKey="s103" selector="{{AdminEditCustomerOrdersSection.orderGrid}}" userInput="$$simpleuscustomer.firstname$$ $$simpleuscustomer.lastname$$" /> </test> + <test name="StorefrontCustomerCheckoutTestWithMultipleAddressesAndTaxRates"> + <annotations> + <title value="Customer Checkout with multiple addresses and tax rates"/> + <description value="Should be able to place an order as a customer with multiple addresses and tax rates."/> + <testCaseId value="MAGETWO-93109"/> + <skip> + <issueId value="MQE-1187" /> + </skip> + </annotations> + <before> + <createData entity="SimpleSubCategory" stepKey="simplecategory"/> + <createData entity="SimpleProduct" stepKey="simpleproduct1"> + <requiredEntity createDataKey="simplecategory"/> + </createData> + <createData entity="Simple_US_Customer_Multiple_Addresses" stepKey="multiple_address_customer"/> + + <actionGroup ref="LoginAsAdmin" stepKey="loginAsAdmin"/> + + <!-- Go to tax rule page --> + <amOnPage url="{{AdminTaxRuleGridPage.url}}" stepKey="goToTaxRulePage"/> + <waitForPageLoad stepKey="waitForTaxRatePage"/> + <click stepKey="addNewTaxRate" selector="{{AdminGridMainControls.add}}"/> + <fillField stepKey="fillRuleName" selector="{{AdminTaxRulesSection.ruleName}}" userInput="SampleRule"/> + + <!-- Add NY and CA tax rules --> + <actionGroup ref="addNewTaxRateNoZip" stepKey="addNYTaxRate"> + <argument name="taxCode" value="SimpleTaxNY"/> + </actionGroup> + + <actionGroup ref="addNewTaxRateNoZip" stepKey="addCATaxRate"> + <argument name="taxCode" value="SimpleTaxCA"/> + </actionGroup> + + <click stepKey="clickSave" selector="{{AdminStoresMainActionsSection.saveButton}}"/> + </before> + <after> + <!-- Go to the tax rule page and delete the row we created--> + <amOnPage url="{{AdminTaxRuleGridPage.url}}" stepKey="goToTaxRulesPage"/> + <waitForPageLoad stepKey="waitForRulesPage"/> + <actionGroup ref="deleteEntitySecondaryGrid" stepKey="deleteRule"> + <argument name="name" value="SampleRule"/> + <argument name="searchInput" value="{{AdminSecondaryGridSection.taxIdentifierSearch}}"/> + </actionGroup> + + <!-- Go to the tax rate page --> + <amOnPage url="{{AdminTaxRateGridPage.url}}" stepKey="goToTaxRatesPage"/> + <waitForPageLoad stepKey="waitForRatesPage"/> + <!-- Delete the two tax rates that were created --> + <actionGroup ref="deleteEntitySecondaryGrid" stepKey="deleteNYRate"> + <argument name="name" value="{{SimpleTaxNY.state}}-{{SimpleTaxNY.rate}}"/> + <argument name="searchInput" value="{{AdminSecondaryGridSection.taxIdentifierSearch}}"/> + </actionGroup> + + <actionGroup ref="deleteEntitySecondaryGrid" stepKey="deleteCARate"> + <argument name="name" value="{{SimpleTaxCA.state}}-{{SimpleTaxCA.rate}}"/> + <argument name="searchInput" value="{{AdminSecondaryGridSection.taxIdentifierSearch}}"/> + </actionGroup> + <amOnPage url="admin/admin/auth/logout/" stepKey="amOnLogoutPage"/> + <deleteData createDataKey="simpleproduct1" stepKey="deleteProduct1"/> + <deleteData createDataKey="simplecategory" stepKey="deleteCategory"/> + <deleteData createDataKey="multiple_address_customer" stepKey="deleteCustomer"/> + </after> + + <actionGroup ref="LoginToStorefrontActionGroup" stepKey="customerLogin"> + <argument name="Customer" value="$$multiple_address_customer$$" /> + </actionGroup> + + <amOnPage url="{{StorefrontCategoryPage.url($$simplecategory.name$$)}}" stepKey="onCategoryPage1"/> + <waitForPageLoad stepKey="waitForCatalogPageLoad1"/> + <moveMouseOver selector="{{StorefrontCategoryMainSection.ProductItemInfo}}" stepKey="hoverProduct1"/> + <click selector="{{StorefrontCategoryMainSection.AddToCartBtn}}" stepKey="addToCart1"/> + <waitForElementVisible selector="{{StorefrontCategoryMainSection.SuccessMsg}}" time="30" stepKey="waitForProductAdded1"/> + <see selector="{{StorefrontCategoryMainSection.SuccessMsg}}" userInput="You added $$simpleproduct1.name$$ to your shopping cart." stepKey="seeAddedToCartMessage1"/> + <see selector="{{StorefrontMinicartSection.quantity}}" userInput="1" stepKey="seeCartQuantity1"/> + <actionGroup ref="GoToCheckoutFromMinicartActionGroup" stepKey="goToCheckoutFromMinicart1" /> + + <click stepKey="selectFirstShippingMethod1" selector="{{CheckoutShippingMethodsSection.firstShippingMethod}}"/> + <waitForElement stepKey="waitForShippingMethodSelect1" selector="{{CheckoutShippingMethodsSection.next}}" time="30"/> + <click stepKey="clickNextOnShippingMethodLoad1" selector="{{CheckoutShippingMethodsSection.next}}" /> + <waitForPageLoad stepKey="waitForPaymentLoad1"/> + <waitForElement stepKey="waitForPlaceOrderButton1" selector="{{CheckoutPaymentSection.placeOrder}}" time="30" /> + <see stepKey="seeBillingAddressIsCorrect1" selector="{{CheckoutPaymentSection.billingAddress}}" userInput="{{US_Address_NY.street[0]}}" /> + <click stepKey="clickPlaceOrderButton1" selector="{{CheckoutPaymentSection.placeOrder}}" /> + <waitForPageLoad stepKey="waitForOrderSuccessPage1"/> + <see stepKey="seeSuccessMessage1" selector="{{CheckoutSuccessMainSection.success}}" userInput="Your order number is:" /> + + <amOnPage url="{{StorefrontCategoryPage.url($$simplecategory.name$$)}}" stepKey="onCategoryPage2"/> + <waitForPageLoad stepKey="waitForCatalogPageLoad2"/> + <moveMouseOver selector="{{StorefrontCategoryMainSection.ProductItemInfo}}" stepKey="hoverProduct2"/> + <click selector="{{StorefrontCategoryMainSection.AddToCartBtn}}" stepKey="addToCart2"/> + <waitForElementVisible selector="{{StorefrontCategoryMainSection.SuccessMsg}}" time="30" stepKey="waitForProductAdded2"/> + <see selector="{{StorefrontCategoryMainSection.SuccessMsg}}" userInput="You added $$simpleproduct1.name$$ to your shopping cart." stepKey="seeAddedToCartMessage2"/> + <see selector="{{StorefrontMinicartSection.quantity}}" userInput="1" stepKey="seeCartQuantity2"/> + <actionGroup ref="GoToCheckoutFromMinicartActionGroup" stepKey="goToCheckoutFromMinicart2" /> + + <click stepKey="changeShippingAddress" selector="{{CheckoutShippingMethodsSection.shipHereButton}}"/> + <waitForElementNotVisible stepKey="waitForShippingMethodLoaderNotVisible" selector="{{CheckoutShippingMethodsSection.shippingMethodLoader}}" time="30"/> + <click stepKey="selectFirstShippingMethod2" selector="{{CheckoutShippingMethodsSection.firstShippingMethod}}"/> + <waitForElement stepKey="waitForShippingMethodSelect2" selector="{{CheckoutShippingMethodsSection.next}}" time="30"/> + <click stepKey="clickNextOnShippingMethodLoad2" selector="{{CheckoutShippingMethodsSection.next}}" /> + <waitForPageLoad stepKey="waitForPaymentLoad2"/> + <waitForElement stepKey="waitForPlaceOrderButton2" selector="{{CheckoutPaymentSection.placeOrder}}" time="30" /> + <see stepKey="seeBillingAddressIsCorrect2" selector="{{CheckoutPaymentSection.billingAddress}}" userInput="{{UK_Not_Default_Address.street[0]}}" /> + <click stepKey="clickPlaceOrderButton2" selector="{{CheckoutPaymentSection.placeOrder}}" /> + <waitForPageLoad stepKey="waitForOrderSuccessPage2"/> + <see stepKey="seeSuccessMessage2" selector="{{CheckoutSuccessMainSection.success}}" userInput="Your order number is:" /> + </test> </tests> diff --git a/app/code/Magento/Checkout/Test/Mftf/composer.json b/app/code/Magento/Checkout/Test/Mftf/composer.json deleted file mode 100644 index 32c1a2c6bcd3f..0000000000000 --- a/app/code/Magento/Checkout/Test/Mftf/composer.json +++ /dev/null @@ -1,36 +0,0 @@ -{ - "name": "magento/functional-test-module-checkout", - "description": "N/A", - "config": { - "sort-packages": true - }, - "require": { - "php": "~7.1.3||~7.2.0", - "magento/magento2-functional-testing-framework": "2.2.0", - "magento/functional-test-module-catalog": "100.0.0-dev", - "magento/functional-test-module-catalog-inventory": "100.0.0-dev", - "magento/functional-test-module-config": "100.0.0-dev", - "magento/functional-test-module-customer": "100.0.0-dev", - "magento/functional-test-module-directory": "100.0.0-dev", - "magento/functional-test-module-eav": "100.0.0-dev", - "magento/functional-test-module-msrp": "100.0.0-dev", - "magento/functional-test-module-page-cache": "100.0.0-dev", - "magento/functional-test-module-payment": "100.0.0-dev", - "magento/functional-test-module-quote": "100.0.0-dev", - "magento/functional-test-module-sales": "100.0.0-dev", - "magento/functional-test-module-sales-rule": "100.0.0-dev", - "magento/functional-test-module-shipping": "100.0.0-dev", - "magento/functional-test-module-store": "100.0.0-dev", - "magento/functional-test-module-tax": "100.0.0-dev", - "magento/functional-test-module-theme": "100.0.0-dev", - "magento/functional-test-module-ui": "100.0.0-dev" - }, - "suggest": { - "magento/functional-test-module-cookie": "100.0.0-dev" - }, - "type": "magento2-test", - "license": [ - "OSL-3.0", - "AFL-3.0" - ] -} diff --git a/app/code/Magento/Checkout/Test/Unit/Model/Cart/RequestQuantityProcessorTest.php b/app/code/Magento/Checkout/Test/Unit/Model/Cart/RequestQuantityProcessorTest.php new file mode 100644 index 0000000000000..daabb080b1c9a --- /dev/null +++ b/app/code/Magento/Checkout/Test/Unit/Model/Cart/RequestQuantityProcessorTest.php @@ -0,0 +1,88 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +declare(strict_types=1); + +namespace Magento\Checkout\Test\Unit\Model\Cart; + +use Magento\Checkout\Model\Cart\RequestQuantityProcessor; +use Magento\Framework\Locale\ResolverInterface; +use \PHPUnit_Framework_MockObject_MockObject as MockObject; + +class RequestQuantityProcessorTest extends \PHPUnit\Framework\TestCase +{ + /** + * @var ResolverInterface | MockObject + */ + private $localeResolver; + + /** + * @var RequestQuantityProcessor + */ + private $requestProcessor; + + protected function setUp() + { + $this->localeResolver = $this->getMockBuilder(ResolverInterface::class) + ->getMockForAbstractClass(); + + $this->localeResolver->method('getLocale') + ->willReturn('en_US'); + + $this->requestProcessor = new RequestQuantityProcessor( + $this->localeResolver + ); + } + + /** + * Test of cart data processing. + * + * @param array $cartData + * @param array $expected + * @dataProvider cartDataProvider + */ + public function testProcess($cartData, $expected) + { + $this->assertEquals($this->requestProcessor->process($cartData), $expected); + } + + public function cartDataProvider() + { + return [ + 'empty_array' => [ + 'cartData' => [], + 'expected' => [], + ], + 'strings_array' => [ + 'cartData' => [ + ['qty' => ' 10 '], + ['qty' => ' 0.5 '] + ], + 'expected' => [ + ['qty' => 10], + ['qty' => 0.5] + ], + ], + 'integer_array' => [ + 'cartData' => [ + ['qty' => 1], + ['qty' => 0.002] + ], + 'expected' => [ + ['qty' => 1], + ['qty' => 0.002] + ], + ], + 'array_of arrays' => [ + 'cartData' => [ + ['qty' => [1, 2 ,3]], + ], + 'expected' => [ + ['qty' => [1, 2, 3]], + ], + ], + ]; + } +} diff --git a/app/code/Magento/Checkout/view/frontend/templates/cart/form.phtml b/app/code/Magento/Checkout/view/frontend/templates/cart/form.phtml index 4940cd7f26747..71b1392d5391f 100644 --- a/app/code/Magento/Checkout/view/frontend/templates/cart/form.phtml +++ b/app/code/Magento/Checkout/view/frontend/templates/cart/form.phtml @@ -13,7 +13,9 @@ <form action="<?= /* @escapeNotVerified */ $block->getUrl('checkout/cart/updatePost') ?>" method="post" id="form-validate" - data-mage-init='{"validation":{}}' + data-mage-init='{"Magento_Checkout/js/action/update-shopping-cart": + {"validationURL" : "/checkout/cart/updateItemQty"} + }' class="form form-cart"> <?= $block->getBlockHtml('formkey') ?> <div class="cart table-wrapper<?= $mergedCells == 2 ? ' detailed' : '' ?>"> diff --git a/app/code/Magento/Checkout/view/frontend/templates/cart/methods.phtml b/app/code/Magento/Checkout/view/frontend/templates/cart/methods.phtml index 5530f7661bb1b..d329e2e8c1770 100644 --- a/app/code/Magento/Checkout/view/frontend/templates/cart/methods.phtml +++ b/app/code/Magento/Checkout/view/frontend/templates/cart/methods.phtml @@ -14,7 +14,8 @@ <?php $methods = $block->getMethods('methods') ?: $block->getMethods('top_methods') ?> <ul class="checkout methods items checkout-methods-items"> <?php foreach ($methods as $method): ?> - <?php if ($methodHtml = $block->getMethodHtml($method)): ?> + <?php $methodHtml = $block->getMethodHtml($method); ?> + <?php if (trim($methodHtml) !== ''): ?> <li class="item"><?= /* @escapeNotVerified */ $methodHtml ?></li> <?php endif; ?> <?php endforeach; ?> diff --git a/app/code/Magento/Checkout/view/frontend/web/js/action/update-shopping-cart.js b/app/code/Magento/Checkout/view/frontend/web/js/action/update-shopping-cart.js new file mode 100644 index 0000000000000..ce1527b3d72d6 --- /dev/null +++ b/app/code/Magento/Checkout/view/frontend/web/js/action/update-shopping-cart.js @@ -0,0 +1,127 @@ +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ + +define([ + 'Magento_Ui/js/modal/alert', + 'jquery', + 'jquery/ui', + 'mage/validation' +], function (alert, $) { + 'use strict'; + + $.widget('mage.updateShoppingCart', { + options: { + validationURL: '', + eventName: 'updateCartItemQty' + }, + + /** @inheritdoc */ + _create: function () { + this._on(this.element, { + 'submit': this.onSubmit + }); + }, + + /** + * Prevents default submit action and calls form validator. + * + * @param {Event} event + * @return {Boolean} + */ + onSubmit: function (event) { + if (!this.options.validationURL) { + return true; + } + + if (this.isValid()) { + event.preventDefault(); + this.validateItems(this.options.validationURL, this.element.serialize()); + } + + return false; + }, + + /** + * Validates requested form. + * + * @return {Boolean} + */ + isValid: function () { + return this.element.validation() && this.element.validation('isValid'); + }, + + /** + * Validates updated shopping cart data. + * + * @param {String} url - request url + * @param {Object} data - post data for ajax call + */ + validateItems: function (url, data) { + $.extend(data, { + 'form_key': $.mage.cookies.get('form_key') + }); + + $.ajax({ + url: url, + data: data, + type: 'post', + dataType: 'json', + context: this, + + /** @inheritdoc */ + beforeSend: function () { + $(document.body).trigger('processStart'); + }, + + /** @inheritdoc */ + complete: function () { + $(document.body).trigger('processStop'); + } + }) + .done(function (response) { + if (response.success) { + this.onSuccess(); + } else { + this.onError(response); + } + }) + .fail(function () { + this.submitForm(); + }); + }, + + /** + * Form validation succeed. + */ + onSuccess: function () { + $(document).trigger('ajax:' + this.options.eventName); + this.submitForm(); + }, + + /** + * Form validation failed. + */ + onError: function (response) { + if (response['error_message']) { + alert({ + content: response['error_message'] + }); + } else { + this.submitForm(); + } + }, + + /** + * Real submit of validated form. + */ + submitForm: function () { + this.element + .off('submit', this.onSubmit) + .submit(); + } + }); + + return $.mage.updateShoppingCart; +}); diff --git a/app/code/Magento/Checkout/view/frontend/web/js/model/cart/totals-processor/default.js b/app/code/Magento/Checkout/view/frontend/web/js/model/cart/totals-processor/default.js index e269462047748..0e94232786c65 100644 --- a/app/code/Magento/Checkout/view/frontend/web/js/model/cart/totals-processor/default.js +++ b/app/code/Magento/Checkout/view/frontend/web/js/model/cart/totals-processor/default.js @@ -38,7 +38,7 @@ define([ payload.addressInformation['shipping_carrier_code'] = quote.shippingMethod()['carrier_code']; } - storage.post( + return storage.post( serviceUrl, JSON.stringify(payload), false ).done(function (result) { var data = { @@ -96,7 +96,7 @@ define([ ) { quote.setTotals(cartCache.get('totals')); } else { - loadFromServer(address); + return loadFromServer(address); } } }; diff --git a/app/code/Magento/Checkout/view/frontend/web/js/region-updater.js b/app/code/Magento/Checkout/view/frontend/web/js/region-updater.js index dacebd75c3c68..cf2a59cdba427 100644 --- a/app/code/Magento/Checkout/view/frontend/web/js/region-updater.js +++ b/app/code/Magento/Checkout/view/frontend/web/js/region-updater.js @@ -188,6 +188,8 @@ define([ if (!this.options.optionalRegionAllowed) { //eslint-disable-line max-depth regionList.attr('disabled', 'disabled'); + } else { + regionList.removeAttr('disabled'); } } diff --git a/app/code/Magento/Checkout/view/frontend/web/js/sidebar.js b/app/code/Magento/Checkout/view/frontend/web/js/sidebar.js index 3fb8743e951c8..3b5168453e11a 100644 --- a/app/code/Magento/Checkout/view/frontend/web/js/sidebar.js +++ b/app/code/Magento/Checkout/view/frontend/web/js/sidebar.js @@ -9,11 +9,12 @@ define([ 'Magento_Customer/js/customer-data', 'Magento_Ui/js/modal/alert', 'Magento_Ui/js/modal/confirm', + 'underscore', 'jquery/ui', 'mage/decorate', 'mage/collapsible', 'mage/cookies' -], function ($, authenticationPopup, customerData, alert, confirm) { +], function ($, authenticationPopup, customerData, alert, confirm, _) { 'use strict'; $.widget('mage.sidebar', { @@ -60,13 +61,15 @@ define([ }; events['click ' + this.options.button.checkout] = $.proxy(function () { var cart = customerData.get('cart'), - customer = customerData.get('customer'); + customer = customerData.get('customer'), + element = $(this.options.button.checkout); if (!customer().firstname && cart().isGuestCheckoutAllowed === false) { // set URL for redirect on successful login/registration. It's postprocessed on backend. $.cookie('login_redirect', this.options.url.checkout); if (this.options.url.isRedirectRequired) { + element.prop('disabled', true); location.href = this.options.url.loginUrl; } else { authenticationPopup.showModal(); @@ -74,6 +77,7 @@ define([ return false; } + element.prop('disabled', true); location.href = this.options.url.checkout; }, this); @@ -219,8 +223,12 @@ define([ * @param {HTMLElement} elem */ _updateItemQtyAfter: function (elem) { + var productData = this._getProductById(Number(elem.data('cart-item'))); + + if (!_.isUndefined(productData)) { + $(document).trigger('ajax:updateCartItemQty', productData['product_sku']); + } this._hideItemButton(elem); - $(document).trigger('ajax:updateItemQty'); }, /** @@ -242,11 +250,24 @@ define([ * @private */ _removeItemAfter: function (elem) { - var productData = customerData.get('cart')().items.find(function (item) { - return Number(elem.data('cart-item')) === Number(item['item_id']); - }); + var productData = this._getProductById(Number(elem.data('cart-item'))); + + if (!_.isUndefined(productData)) { + $(document).trigger('ajax:removeFromCart', productData['product_sku']); + } + }, - $(document).trigger('ajax:removeFromCart', productData['product_sku']); + /** + * Retrieves product data by Id. + * + * @param {Number} productId - product Id + * @returns {Object|undefined} + * @private + */ + _getProductById: function (productId) { + return _.find(customerData.get('cart')().items, function (item) { + return productId === Number(item['item_id']); + }); }, /** diff --git a/app/code/Magento/Checkout/view/frontend/web/js/view/configure/product-customer-data.js b/app/code/Magento/Checkout/view/frontend/web/js/view/configure/product-customer-data.js index 9af5201c267e8..0e2fc6bbfc8fe 100644 --- a/app/code/Magento/Checkout/view/frontend/web/js/view/configure/product-customer-data.js +++ b/app/code/Magento/Checkout/view/frontend/web/js/view/configure/product-customer-data.js @@ -1,8 +1,9 @@ require([ 'jquery', 'Magento_Customer/js/customer-data', + 'underscore', 'domReady!' -], function ($, customerData) { +], function ($, customerData, _) { 'use strict'; var selectors = { @@ -41,7 +42,7 @@ require([ if (!(data && data.items && data.items.length && productId)) { return; } - product = data.items.find(function (item) { + product = _.find(data.items, function (item) { if (item['item_id'] === itemId) { return item['product_id'] === productId || item['item_id'] === productId; diff --git a/app/code/Magento/Checkout/view/frontend/web/js/view/summary/shipping.js b/app/code/Magento/Checkout/view/frontend/web/js/view/summary/shipping.js index 3fda260339254..db30d0a2647b1 100644 --- a/app/code/Magento/Checkout/view/frontend/web/js/view/summary/shipping.js +++ b/app/code/Magento/Checkout/view/frontend/web/js/view/summary/shipping.js @@ -22,13 +22,18 @@ define([ */ getShippingMethodTitle: function () { var shippingMethod; + var shippingMethodTitle = ''; if (!this.isCalculated()) { return ''; } shippingMethod = quote.shippingMethod(); - return shippingMethod ? shippingMethod['carrier_title'] + ' - ' + shippingMethod['method_title'] : ''; + if (typeof(shippingMethod['method_title']) !== 'undefined') { + shippingMethodTitle = ' - ' + shippingMethod['method_title']; + } + + return shippingMethod ? shippingMethod['carrier_title'] + shippingMethodTitle : ''; }, /** diff --git a/app/code/Magento/Checkout/view/frontend/web/template/billing-address/form.html b/app/code/Magento/Checkout/view/frontend/web/template/billing-address/form.html index dcd726076d900..54fe9a1f59394 100644 --- a/app/code/Magento/Checkout/view/frontend/web/template/billing-address/form.html +++ b/app/code/Magento/Checkout/view/frontend/web/template/billing-address/form.html @@ -9,8 +9,7 @@ <!-- ko template: getTemplate() --><!-- /ko --> <!--/ko--> <form data-bind="attr: {'data-hasrequired': $t('* Required Fields')}"> - <fieldset data-bind="attr: { id:'billing-new-address-form-'+index, value:index}" - class="billing-new-address-form fieldset address"> + <fieldset class="fieldset address" data-form="billing-new-address"> <!-- ko foreach: getRegion('additional-fieldsets') --> <!-- ko template: getTemplate() --><!-- /ko --> <!--/ko--> diff --git a/app/code/Magento/Checkout/view/frontend/web/template/summary/item/details.html b/app/code/Magento/Checkout/view/frontend/web/template/summary/item/details.html index 94f94ec878151..730ceadbd914c 100644 --- a/app/code/Magento/Checkout/view/frontend/web/template/summary/item/details.html +++ b/app/code/Magento/Checkout/view/frontend/web/template/summary/item/details.html @@ -12,7 +12,7 @@ <div class="product-item-inner"> <div class="product-item-name-block"> - <strong class="product-item-name" data-bind="text: $parent.name"></strong> + <strong class="product-item-name" data-bind="html: $parent.name"></strong> <div class="details-qty"> <span class="label"><!-- ko i18n: 'Qty' --><!-- /ko --></span> <span class="value" data-bind="text: $parent.qty"></span> diff --git a/app/code/Magento/CheckoutAgreements/Controller/Adminhtml/Agreement.php b/app/code/Magento/CheckoutAgreements/Controller/Adminhtml/Agreement.php index 13130a4491eb2..aa6f461fc5ee2 100644 --- a/app/code/Magento/CheckoutAgreements/Controller/Adminhtml/Agreement.php +++ b/app/code/Magento/CheckoutAgreements/Controller/Adminhtml/Agreement.php @@ -5,7 +5,11 @@ */ namespace Magento\CheckoutAgreements\Controller\Adminhtml; -abstract class Agreement extends \Magento\Backend\App\Action +use Magento\Backend\App\Action; +use Magento\Backend\App\Action\Context; +use Magento\Framework\Registry; + +abstract class Agreement extends Action { /** * Authorization level of a basic admin session @@ -22,12 +26,14 @@ abstract class Agreement extends \Magento\Backend\App\Action protected $_coreRegistry = null; /** - * @param \Magento\Backend\App\Action\Context $context - * @param \Magento\Framework\Registry $coreRegistry + * @param Context $context + * @param Registry $coreRegistry * @codeCoverageIgnore */ - public function __construct(\Magento\Backend\App\Action\Context $context, \Magento\Framework\Registry $coreRegistry) - { + public function __construct( + Context $context, + Registry $coreRegistry + ) { $this->_coreRegistry = $coreRegistry; parent::__construct($context); } diff --git a/app/code/Magento/CheckoutAgreements/Controller/Adminhtml/Agreement/Delete.php b/app/code/Magento/CheckoutAgreements/Controller/Adminhtml/Agreement/Delete.php index 65aca6205caa4..f7b178df99624 100644 --- a/app/code/Magento/CheckoutAgreements/Controller/Adminhtml/Agreement/Delete.php +++ b/app/code/Magento/CheckoutAgreements/Controller/Adminhtml/Agreement/Delete.php @@ -6,27 +6,53 @@ */ namespace Magento\CheckoutAgreements\Controller\Adminhtml\Agreement; -class Delete extends \Magento\CheckoutAgreements\Controller\Adminhtml\Agreement +use Magento\CheckoutAgreements\Api\CheckoutAgreementsRepositoryInterface; +use Magento\CheckoutAgreements\Controller\Adminhtml\Agreement; +use Magento\Backend\App\Action\Context; +use Magento\Framework\Registry; +use Magento\Framework\App\ObjectManager; +use Magento\Framework\Exception\LocalizedException; + +class Delete extends Agreement { + /** + * @var CheckoutAgreementsRepositoryInterface + */ + private $agreementRepository; + + /** + * @param Context $context + * @param Registry $coreRegistry + * @param CheckoutAgreementsRepositoryInterface $agreementRepository + */ + public function __construct( + Context $context, + Registry $coreRegistry, + CheckoutAgreementsRepositoryInterface $agreementRepository = null + ) { + $this->agreementRepository = $agreementRepository ?: + ObjectManager::getInstance()->get(CheckoutAgreementsRepositoryInterface::class); + parent::__construct($context, $coreRegistry); + } /** * @return void */ public function execute() { $id = (int)$this->getRequest()->getParam('id'); - $model = $this->_objectManager->get(\Magento\CheckoutAgreements\Model\Agreement::class)->load($id); - if (!$model->getId()) { + $agreement = $this->agreementRepository->get($id); + if (!$agreement->getAgreementId()) { $this->messageManager->addError(__('This condition no longer exists.')); $this->_redirect('checkout/*/'); return; } try { - $model->delete(); + $this->agreementRepository->delete($agreement); $this->messageManager->addSuccess(__('You deleted the condition.')); $this->_redirect('checkout/*/'); return; - } catch (\Magento\Framework\Exception\LocalizedException $e) { + } catch (LocalizedException $e) { $this->messageManager->addError($e->getMessage()); } catch (\Exception $e) { $this->messageManager->addError(__('Something went wrong while deleting this condition.')); diff --git a/app/code/Magento/CheckoutAgreements/Controller/Adminhtml/Agreement/Edit.php b/app/code/Magento/CheckoutAgreements/Controller/Adminhtml/Agreement/Edit.php index 73ac129bc993c..8bec3b581cd54 100644 --- a/app/code/Magento/CheckoutAgreements/Controller/Adminhtml/Agreement/Edit.php +++ b/app/code/Magento/CheckoutAgreements/Controller/Adminhtml/Agreement/Edit.php @@ -6,8 +6,34 @@ */ namespace Magento\CheckoutAgreements\Controller\Adminhtml\Agreement; -class Edit extends \Magento\CheckoutAgreements\Controller\Adminhtml\Agreement +use Magento\CheckoutAgreements\Controller\Adminhtml\Agreement; +use Magento\CheckoutAgreements\Model\AgreementFactory; +use Magento\Backend\App\Action\Context; +use Magento\Framework\Registry; +use Magento\Framework\App\ObjectManager; +use Magento\CheckoutAgreements\Block\Adminhtml\Agreement\Edit as BlockEdit; + +class Edit extends Agreement { + /** + * @var AgreementFactory + */ + private $agreementFactory; + + /** + * @param Context $context + * @param Registry $coreRegistry + * @param AgreementFactory $agreementFactory + */ + public function __construct( + Context $context, + Registry $coreRegistry, + AgreementFactory $agreementFactory = null + ) { + $this->agreementFactory = $agreementFactory ?: + ObjectManager::getInstance()->get(AgreementFactory::class); + parent::__construct($context, $coreRegistry); + } /** * @return void * @SuppressWarnings(PHPMD.NPathComplexity) @@ -15,7 +41,7 @@ class Edit extends \Magento\CheckoutAgreements\Controller\Adminhtml\Agreement public function execute() { $id = $this->getRequest()->getParam('id'); - $agreementModel = $this->_objectManager->create(\Magento\CheckoutAgreements\Model\Agreement::class); + $agreementModel = $this->agreementFactory->create(); if ($id) { $agreementModel->load($id); @@ -26,7 +52,7 @@ public function execute() } } - $data = $this->_objectManager->get(\Magento\Backend\Model\Session::class)->getAgreementData(true); + $data = $this->_session->getAgreementData(true); if (!empty($data)) { $agreementModel->setData($data); } @@ -38,7 +64,7 @@ public function execute() $id ? __('Edit Condition') : __('New Condition') )->_addContent( $this->_view->getLayout()->createBlock( - \Magento\CheckoutAgreements\Block\Adminhtml\Agreement\Edit::class + BlockEdit::class )->setData( 'action', $this->getUrl('checkout/*/save') diff --git a/app/code/Magento/CheckoutAgreements/Controller/Adminhtml/Agreement/Save.php b/app/code/Magento/CheckoutAgreements/Controller/Adminhtml/Agreement/Save.php index 25c034203620b..05a16d3dd4264 100644 --- a/app/code/Magento/CheckoutAgreements/Controller/Adminhtml/Agreement/Save.php +++ b/app/code/Magento/CheckoutAgreements/Controller/Adminhtml/Agreement/Save.php @@ -6,8 +6,35 @@ */ namespace Magento\CheckoutAgreements\Controller\Adminhtml\Agreement; -class Save extends \Magento\CheckoutAgreements\Controller\Adminhtml\Agreement +use Magento\CheckoutAgreements\Controller\Adminhtml\Agreement; +use Magento\CheckoutAgreements\Model\AgreementFactory; +use Magento\Backend\App\Action\Context; +use Magento\Framework\Registry; +use Magento\Framework\App\ObjectManager; +use Magento\Framework\DataObject; +use Magento\Framework\Exception\LocalizedException; + +class Save extends Agreement { + /** + * @var AgreementFactory + */ + private $agreementFactory; + + /** + * @param Context $context + * @param Registry $coreRegistry + * @param AgreementFactory $agreementFactory + */ + public function __construct( + Context $context, + Registry $coreRegistry, + AgreementFactory $agreementFactory = null + ) { + $this->agreementFactory = $agreementFactory ?: + ObjectManager::getInstance()->get(AgreementFactory::class); + parent::__construct($context, $coreRegistry); + } /** * @return void */ @@ -15,11 +42,11 @@ public function execute() { $postData = $this->getRequest()->getPostValue(); if ($postData) { - $model = $this->_objectManager->get(\Magento\CheckoutAgreements\Model\Agreement::class); + $model = $this->agreementFactory->create(); $model->setData($postData); try { - $validationResult = $model->validateData(new \Magento\Framework\DataObject($postData)); + $validationResult = $model->validateData(new DataObject($postData)); if ($validationResult !== true) { foreach ($validationResult as $message) { $this->messageManager->addError($message); @@ -30,13 +57,13 @@ public function execute() $this->_redirect('checkout/*/'); return; } - } catch (\Magento\Framework\Exception\LocalizedException $e) { + } catch (LocalizedException $e) { $this->messageManager->addError($e->getMessage()); } catch (\Exception $e) { $this->messageManager->addError(__('Something went wrong while saving this condition.')); } - $this->_objectManager->get(\Magento\Backend\Model\Session::class)->setAgreementData($postData); + $this->_session->setAgreementData($postData); $this->getResponse()->setRedirect($this->_redirect->getRedirectUrl($this->getUrl('*'))); } } diff --git a/app/code/Magento/CheckoutAgreements/Test/Mftf/composer.json b/app/code/Magento/CheckoutAgreements/Test/Mftf/composer.json deleted file mode 100644 index 5ba702a5903a5..0000000000000 --- a/app/code/Magento/CheckoutAgreements/Test/Mftf/composer.json +++ /dev/null @@ -1,20 +0,0 @@ -{ - "name": "magento/functional-test-module-checkout-agreements", - "description": "N/A", - "config": { - "sort-packages": true - }, - "require": { - "php": "~7.1.3||~7.2.0", - "magento/magento2-functional-testing-framework": "2.2.0", - "magento/functional-test-module-backend": "100.0.0-dev", - "magento/functional-test-module-checkout": "100.0.0-dev", - "magento/functional-test-module-quote": "100.0.0-dev", - "magento/functional-test-module-store": "100.0.0-dev" - }, - "type": "magento2-test", - "license": [ - "OSL-3.0", - "AFL-3.0" - ] -} diff --git a/app/code/Magento/Cms/Api/BlockRepositoryInterface.php b/app/code/Magento/Cms/Api/BlockRepositoryInterface.php index 9b285051fc44b..b713ca91ea852 100644 --- a/app/code/Magento/Cms/Api/BlockRepositoryInterface.php +++ b/app/code/Magento/Cms/Api/BlockRepositoryInterface.php @@ -5,8 +5,6 @@ */ namespace Magento\Cms\Api; -use Magento\Framework\Api\SearchCriteriaInterface; - /** * CMS block CRUD interface. * @api diff --git a/app/code/Magento/Cms/Controller/Index/Index.php b/app/code/Magento/Cms/Controller/Index/Index.php index 8e20feb0f058f..c027bd1a2b717 100644 --- a/app/code/Magento/Cms/Controller/Index/Index.php +++ b/app/code/Magento/Cms/Controller/Index/Index.php @@ -1,27 +1,55 @@ <?php /** - * * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ namespace Magento\Cms\Controller\Index; +use Magento\Framework\App\Action\Context; +use Magento\Framework\App\Config\ScopeConfigInterface; +use Magento\Framework\App\ObjectManager; +use Magento\Framework\App\ResponseInterface; +use Magento\Framework\Controller\ResultInterface; +use Magento\Framework\Controller\Result\Forward; +use Magento\Framework\Controller\Result\ForwardFactory; +use Magento\Framework\View\Result\Page as ResultPage; +use Magento\Cms\Helper\Page; +use Magento\Store\Model\ScopeInterface; + class Index extends \Magento\Framework\App\Action\Action { /** - * @var \Magento\Framework\Controller\Result\ForwardFactory + * @var ForwardFactory */ protected $resultForwardFactory; /** - * @param \Magento\Framework\App\Action\Context $context - * @param \Magento\Framework\Controller\Result\ForwardFactory $resultForwardFactory + * @var ScopeConfigInterface + */ + private $scopeConfig; + + /** + * @var Page + */ + private $page; + + /** + * Index constructor. + * + * @param Context $context + * @param ForwardFactory $resultForwardFactory + * @param ScopeConfigInterface|null $scopeConfig + * @param Page|null $page */ public function __construct( - \Magento\Framework\App\Action\Context $context, - \Magento\Framework\Controller\Result\ForwardFactory $resultForwardFactory + Context $context, + ForwardFactory $resultForwardFactory, + ScopeConfigInterface $scopeConfig = null, + Page $page = null ) { $this->resultForwardFactory = $resultForwardFactory; + $this->scopeConfig = $scopeConfig ? : ObjectManager::getInstance()->get(ScopeConfigInterface::class); + $this->page = $page ? : ObjectManager::getInstance()->get(Page::class); parent::__construct($context); } @@ -29,20 +57,17 @@ public function __construct( * Renders CMS Home page * * @param string|null $coreRoute - * @return \Magento\Framework\Controller\Result\Forward + * + * @return bool|ResponseInterface|Forward|ResultInterface|ResultPage + * * @SuppressWarnings(PHPMD.UnusedFormalParameter) */ public function execute($coreRoute = null) { - $pageId = $this->_objectManager->get( - \Magento\Framework\App\Config\ScopeConfigInterface::class - )->getValue( - \Magento\Cms\Helper\Page::XML_PATH_HOME_PAGE, - \Magento\Store\Model\ScopeInterface::SCOPE_STORE - ); - $resultPage = $this->_objectManager->get(\Magento\Cms\Helper\Page::class)->prepareResultPage($this, $pageId); + $pageId = $this->scopeConfig->getValue(Page::XML_PATH_HOME_PAGE, ScopeInterface::SCOPE_STORE); + $resultPage = $this->page->prepareResultPage($this, $pageId); if (!$resultPage) { - /** @var \Magento\Framework\Controller\Result\Forward $resultForward */ + /** @var Forward $resultForward */ $resultForward = $this->resultForwardFactory->create(); $resultForward->forward('defaultIndex'); return $resultForward; diff --git a/app/code/Magento/Cms/Helper/Page.php b/app/code/Magento/Cms/Helper/Page.php index bf51c5f0210e9..abd260b260b93 100644 --- a/app/code/Magento/Cms/Helper/Page.php +++ b/app/code/Magento/Cms/Helper/Page.php @@ -116,7 +116,7 @@ public function __construct( * Return result CMS page * * @param Action $action - * @param null $pageId + * @param int $pageId * @return \Magento\Framework\View\Result\Page|bool */ public function prepareResultPage(Action $action, $pageId = null) @@ -189,9 +189,7 @@ public function getPageUrl($pageId = null) $page = $this->_pageFactory->create(); if ($pageId !== null && $pageId !== $page->getId()) { $page->setStoreId($this->_storeManager->getStore()->getId()); - if (!$page->load($pageId)) { - return null; - } + $page->load($pageId); } if (!$page->getId()) { diff --git a/app/code/Magento/Cms/Model/Config/Source/Block.php b/app/code/Magento/Cms/Model/Config/Source/Block.php new file mode 100644 index 0000000000000..85dc4e4dd24bf --- /dev/null +++ b/app/code/Magento/Cms/Model/Config/Source/Block.php @@ -0,0 +1,48 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +declare(strict_types=1); + +namespace Magento\Cms\Model\Config\Source; + +use Magento\Cms\Model\ResourceModel\Block\CollectionFactory; +use Magento\Framework\Data\OptionSourceInterface; + +/** + * Class Block + */ +class Block implements OptionSourceInterface +{ + /** + * @var array + */ + private $options; + + /** + * @var \Magento\Cms\Model\ResourceModel\Block\CollectionFactory + */ + private $collectionFactory; + + /** + * @param \Magento\Cms\Model\ResourceModel\Block\CollectionFactory $collectionFactory + */ + public function __construct( + CollectionFactory $collectionFactory + ) { + $this->collectionFactory = $collectionFactory; + } + + /** + * {@inheritdoc} + */ + public function toOptionArray() + { + if (!$this->options) { + $this->options = $this->collectionFactory->create()->toOptionIdArray(); + } + + return $this->options; + } +} diff --git a/app/code/Magento/Cms/Model/ResourceModel/AbstractCollection.php b/app/code/Magento/Cms/Model/ResourceModel/AbstractCollection.php index cd5945c2f47cb..2a67378614445 100644 --- a/app/code/Magento/Cms/Model/ResourceModel/AbstractCollection.php +++ b/app/code/Magento/Cms/Model/ResourceModel/AbstractCollection.php @@ -176,4 +176,32 @@ public function getSelectCountSql() return $countSelect; } + + /** + * Returns pairs identifier - title for unique identifiers + * and pairs identifier|entity_id - title for non-unique after first + * + * @return array + */ + public function toOptionIdArray() + { + $res = []; + $existingIdentifiers = []; + foreach ($this as $item) { + $identifier = $item->getData('identifier'); + + $data['value'] = $identifier; + $data['label'] = $item->getData('title'); + + if (in_array($identifier, $existingIdentifiers)) { + $data['value'] .= '|' . $item->getData($this->getIdFieldName()); + } else { + $existingIdentifiers[] = $identifier; + } + + $res[] = $data; + } + + return $res; + } } diff --git a/app/code/Magento/Cms/Model/ResourceModel/Page/Collection.php b/app/code/Magento/Cms/Model/ResourceModel/Page/Collection.php index 98c071890be46..4ccc2c8f6e77d 100644 --- a/app/code/Magento/Cms/Model/ResourceModel/Page/Collection.php +++ b/app/code/Magento/Cms/Model/ResourceModel/Page/Collection.php @@ -51,34 +51,6 @@ protected function _construct() $this->_map['fields']['store'] = 'store_table.store_id'; } - /** - * Returns pairs identifier - title for unique identifiers - * and pairs identifier|page_id - title for non-unique after first - * - * @return array - */ - public function toOptionIdArray() - { - $res = []; - $existingIdentifiers = []; - foreach ($this as $item) { - $identifier = $item->getData('identifier'); - - $data['value'] = $identifier; - $data['label'] = $item->getData('title'); - - if (in_array($identifier, $existingIdentifiers)) { - $data['value'] .= '|' . $item->getData('page_id'); - } else { - $existingIdentifiers[] = $identifier; - } - - $res[] = $data; - } - - return $res; - } - /** * Set first store flag * diff --git a/app/code/Magento/Cms/Model/Wysiwyg/Images/Storage.php b/app/code/Magento/Cms/Model/Wysiwyg/Images/Storage.php index 9e095fb6cdec4..dfd55f5346e59 100644 --- a/app/code/Magento/Cms/Model/Wysiwyg/Images/Storage.php +++ b/app/code/Magento/Cms/Model/Wysiwyg/Images/Storage.php @@ -567,10 +567,10 @@ public function getThumbnailUrl($filePath, $checkFile = false) * Create thumbnail for image and save it to thumbnails directory * * @param string $source Image path to be resized - * @param bool $keepRation Keep aspect ratio or not + * @param bool $keepRatio Keep aspect ratio or not * @return bool|string Resized filepath or false if errors were occurred */ - public function resizeFile($source, $keepRation = true) + public function resizeFile($source, $keepRatio = true) { $realPath = $this->_directory->getRelativePath($source); if (!$this->_directory->isFile($realPath) || !$this->_directory->isExist($realPath)) { @@ -587,7 +587,7 @@ public function resizeFile($source, $keepRation = true) } $image = $this->_imageFactory->create(); $image->open($source); - $image->keepAspectRatio($keepRation); + $image->keepAspectRatio($keepRatio); $image->resize($this->_resizeParameters['width'], $this->_resizeParameters['height']); $dest = $targetDir . '/' . pathinfo($source, PATHINFO_BASENAME); $image->save($dest); diff --git a/app/code/Magento/Cms/Test/Mftf/ActionGroup/VerifyTinyMCEActionGroup.xml b/app/code/Magento/Cms/Test/Mftf/ActionGroup/VerifyTinyMCEActionGroup.xml index 24900ad33b560..6c4a42d64404e 100644 --- a/app/code/Magento/Cms/Test/Mftf/ActionGroup/VerifyTinyMCEActionGroup.xml +++ b/app/code/Magento/Cms/Test/Mftf/ActionGroup/VerifyTinyMCEActionGroup.xml @@ -8,8 +8,6 @@ <actionGroups xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../../../../../dev/tests/acceptance/vendor/magento/magento2-functional-testing-framework/src/Magento/FunctionalTestingFramework/Test/etc/actionGroupSchema.xsd"> <actionGroup name="VerifyTinyMCEActionGroup"> - <waitForElementVisible selector="{{TinyMCESection.TinyMCE4}}" stepKey="waitForTinyMCE" time="30" /> - <seeElement selector="{{TinyMCESection.TinyMCE4}}" stepKey="seeTinyMCE4" /> <seeElement selector="{{TinyMCESection.Style}}" stepKey="assertInfo2"/> <seeElement selector="{{TinyMCESection.Bold}}" stepKey="assertInfo3"/> <seeElement selector="{{TinyMCESection.Italic}}" stepKey="assertInfo4"/> diff --git a/app/code/Magento/Cms/Test/Mftf/Data/CmsPageData.xml b/app/code/Magento/Cms/Test/Mftf/Data/CmsPageData.xml index 5df8ebab2d380..84561d6cd96ca 100644 --- a/app/code/Magento/Cms/Test/Mftf/Data/CmsPageData.xml +++ b/app/code/Magento/Cms/Test/Mftf/Data/CmsPageData.xml @@ -75,6 +75,7 @@ <data key="extension">jpg</data> <data key="content">Image content. Yeah.</data> <data key="height">1000</data> + <data key="path">wysiwyg</data> </entity> <entity name="ImageFolder" type="uploadImage"> <data key="name" unique="suffix">Test</data> diff --git a/app/code/Magento/Cms/Test/Mftf/Section/CmsNewPagePageContentSection.xml b/app/code/Magento/Cms/Test/Mftf/Section/CmsNewPagePageContentSection.xml index 8015134c90f9c..8ec0c8349c104 100644 --- a/app/code/Magento/Cms/Test/Mftf/Section/CmsNewPagePageContentSection.xml +++ b/app/code/Magento/Cms/Test/Mftf/Section/CmsNewPagePageContentSection.xml @@ -19,6 +19,8 @@ <element name="InsertWidgetBtn" type="button" selector=".action-add-widget"/> <element name="InsertVariableBtn" type="button" selector=".scalable.add-variable.plugin"/> <element name="InsertImageBtn" type="button" selector=".scalable.action-add-image.plugin"/> + <element name="imageSource" type="text" selector="//img[contains(@src,'{{var1}}')]" parameterized="true"/> + <element name="ImageAlt" type="text" selector="//img[contains(@alt,'{{var1}}')]" parameterized="true"/> </section> <section name="CmsDesignSection"> <element name="DesignTab" type="button" selector="//strong[@class='admin__collapsible-title']//span[text()='Design']"/> diff --git a/app/code/Magento/Cms/Test/Mftf/Section/TinyMCESection.xml b/app/code/Magento/Cms/Test/Mftf/Section/TinyMCESection.xml index fef9e2d851652..0f13c3de47da0 100644 --- a/app/code/Magento/Cms/Test/Mftf/Section/TinyMCESection.xml +++ b/app/code/Magento/Cms/Test/Mftf/Section/TinyMCESection.xml @@ -36,7 +36,7 @@ <element name="Browse" type="button" selector=".mce-i-browse"/> <element name="BrowseUploadImage" type="file" selector=".fileupload" /> <element name="image" type="text" selector="//small[text()='{{var1}}']" parameterized="true"/> - <element name="imageOrImageCopy" type="text" selector="//img[contains(@alt, '{{arg1}}.{{arg2}}')]|//img[contains(@alt,'{{arg1}}_') and contains(@alt,'.{{arg2}}')]" parameterized="true"/> + <element name="imageOrImageCopy" type="text" selector="//div[contains(@class,'media-gallery-modal')]//img[contains(@alt, '{{arg1}}.{{arg2}}')]|//img[contains(@alt,'{{arg1}}_') and contains(@alt,'.{{arg2}}')]" parameterized="true"/> <element name="imageSelected" type="text" selector="//small[text()='{{var1}}']/parent::*[@class='filecnt selected']" parameterized="true"/> <element name="ImageSource" type="input" selector=".mce-combobox.mce-abs-layout-item.mce-last.mce-has-open" /> <element name="ImageDescription" type="input" selector=".mce-textbox.mce-abs-layout-item.mce-last" /> @@ -98,9 +98,6 @@ <element name="PageSize" type="input" selector="input[name='parameters[page_size]']"/> <element name="ProductAttribute" type="multiselect" selector="select[name='parameters[show_attributes][]']" /> <element name="ButtonToShow" type="multiselect" selector="select[name='parameters[show_buttons][]']"/> - <!--Widget on Storefront--> - <element name="CategoryWidget" type="text" selector="//a[@href='http://magento2.vagrant42/{{var1}}.html?___store=default']" parameterized="true"/> - <element name="CMSPageWidget" type="text" selector="//a[@href='http://magento2.vagrant42/home']"/> <!--Compare on Storefront--> <element name="ProductName" type="text" selector=".product.name.product-item-name" /> <element name="CompareBtn" type="button" selector=".action.tocompare"/> diff --git a/app/code/Magento/Cms/Test/Mftf/Test/AdminAddImageToWYSIWYGBlockTest.xml b/app/code/Magento/Cms/Test/Mftf/Test/AdminAddImageToWYSIWYGBlockTest.xml index b37c9e97a78fc..46aa4ac22e03c 100644 --- a/app/code/Magento/Cms/Test/Mftf/Test/AdminAddImageToWYSIWYGBlockTest.xml +++ b/app/code/Magento/Cms/Test/Mftf/Test/AdminAddImageToWYSIWYGBlockTest.xml @@ -16,6 +16,9 @@ <description value="Admin should be able to add image to WYSIWYG content of Block"/> <severity value="CRITICAL"/> <testCaseId value="MAGETWO-84376"/> + <skip> + <issueId value="MQE-1187" /> + </skip> </annotations> <before> <createData entity="_defaultCmsPage" stepKey="createCMSPage" /> diff --git a/app/code/Magento/Cms/Test/Mftf/composer.json b/app/code/Magento/Cms/Test/Mftf/composer.json deleted file mode 100644 index cdf6572dc1460..0000000000000 --- a/app/code/Magento/Cms/Test/Mftf/composer.json +++ /dev/null @@ -1,28 +0,0 @@ -{ - "name": "magento/functional-test-module-cms", - "description": "N/A", - "config": { - "sort-packages": true - }, - "require": { - "php": "~7.1.3||~7.2.0", - "magento/magento2-functional-testing-framework": "2.2.0", - "magento/functional-test-module-backend": "100.0.0-dev", - "magento/functional-test-module-catalog": "100.0.0-dev", - "magento/functional-test-module-email": "100.0.0-dev", - "magento/functional-test-module-media-storage": "100.0.0-dev", - "magento/functional-test-module-store": "100.0.0-dev", - "magento/functional-test-module-theme": "100.0.0-dev", - "magento/functional-test-module-ui": "100.0.0-dev", - "magento/functional-test-module-variable": "100.0.0-dev", - "magento/functional-test-module-widget": "100.0.0-dev" - }, - "suggest": { - "magento/functional-test-module-cms-sample-data": "100.0.0-dev" - }, - "type": "magento2-test", - "license": [ - "OSL-3.0", - "AFL-3.0" - ] -} diff --git a/app/code/Magento/Cms/Test/Unit/Controller/Index/IndexTest.php b/app/code/Magento/Cms/Test/Unit/Controller/Index/IndexTest.php index 8ff206e8a80fc..53064e87c2755 100644 --- a/app/code/Magento/Cms/Test/Unit/Controller/Index/IndexTest.php +++ b/app/code/Magento/Cms/Test/Unit/Controller/Index/IndexTest.php @@ -42,6 +42,9 @@ class IndexTest extends \PHPUnit\Framework\TestCase */ protected $pageId = 'home'; + /** + * Test setUp + */ protected function setUp() { $helper = new \Magento\Framework\TestFramework\Unit\Helper\ObjectManager($this); @@ -84,11 +87,16 @@ protected function setUp() 'response' => $responseMock, 'objectManager' => $objectManagerMock, 'request' => $this->requestMock, - 'resultForwardFactory' => $this->forwardFactoryMock + 'resultForwardFactory' => $this->forwardFactoryMock, + 'scopeConfig' => $scopeConfigMock, + 'page' => $this->cmsHelperMock ] ); } + /** + * Controller test + */ public function testExecuteResultPage() { $this->cmsHelperMock->expects($this->once()) @@ -98,6 +106,9 @@ public function testExecuteResultPage() $this->assertSame($this->resultPageMock, $this->controller->execute()); } + /** + * Controller test + */ public function testExecuteResultForward() { $this->forwardMock->expects($this->once()) diff --git a/app/code/Magento/Cms/Test/Unit/Helper/PageTest.php b/app/code/Magento/Cms/Test/Unit/Helper/PageTest.php index c50f33caa6bc2..19f3b113c5e2c 100644 --- a/app/code/Magento/Cms/Test/Unit/Helper/PageTest.php +++ b/app/code/Magento/Cms/Test/Unit/Helper/PageTest.php @@ -118,6 +118,9 @@ class PageTest extends \PHPUnit\Framework\TestCase */ private $httpRequestMock; + /** + * Test Setup + */ protected function setUp() { $this->actionMock = $this->getMockBuilder(\Magento\Framework\App\Action\Action::class) @@ -478,7 +481,7 @@ public function getPageUrlDataProvider() return [ 'ids NOT EQUAL BUT page->load() NOT SUCCESSFUL' => [ 'pageId' => 123, - 'internalPageId' => 234, + 'internalPageId' => null, 'pageLoadResultIndex' => 0, 'expectedResult' => null, ], diff --git a/app/code/Magento/Cms/Test/Unit/Model/Config/Source/BlockTest.php b/app/code/Magento/Cms/Test/Unit/Model/Config/Source/BlockTest.php new file mode 100644 index 0000000000000..b6a91e9f56b30 --- /dev/null +++ b/app/code/Magento/Cms/Test/Unit/Model/Config/Source/BlockTest.php @@ -0,0 +1,66 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +declare(strict_types=1); + +namespace Magento\Cms\Test\Unit\Model\Config\Source; + +/** + * Class BlockTest + */ +class BlockTest extends \PHPUnit\Framework\TestCase +{ + /** + * @var \Magento\Cms\Model\ResourceModel\Block\CollectionFactory|\PHPUnit_Framework_MockObject_MockObject + */ + protected $collectionFactory; + + /** + * @var \Magento\Cms\Model\Config\Source\Block + */ + protected $block; + + /** + * Set up + * + * @return void + */ + protected function setUp() + { + $objectManager = new \Magento\Framework\TestFramework\Unit\Helper\ObjectManager($this); + + $this->collectionFactory = $this->createPartialMock( + \Magento\Cms\Model\ResourceModel\Block\CollectionFactory::class, + ['create'] + ); + + $this->block = $objectManager->getObject( + \Magento\Cms\Model\Config\Source\Block::class, + [ + 'collectionFactory' => $this->collectionFactory, + ] + ); + } + + /** + * Run test toOptionArray method + * + * @return void + */ + public function testToOptionArray() + { + $blockCollectionMock = $this->createMock(\Magento\Cms\Model\ResourceModel\Block\Collection::class); + + $this->collectionFactory->expects($this->once()) + ->method('create') + ->will($this->returnValue($blockCollectionMock)); + + $blockCollectionMock->expects($this->once()) + ->method('toOptionIdArray') + ->will($this->returnValue('return-value')); + + $this->assertEquals('return-value', $this->block->toOptionArray()); + } +} diff --git a/app/code/Magento/Cms/Ui/Component/AddFilterInterface.php b/app/code/Magento/Cms/Ui/Component/AddFilterInterface.php new file mode 100644 index 0000000000000..406b40fbc1647 --- /dev/null +++ b/app/code/Magento/Cms/Ui/Component/AddFilterInterface.php @@ -0,0 +1,26 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +declare(strict_types=1); + +namespace Magento\Cms\Ui\Component; + +use Magento\Framework\Api\Filter; +use Magento\Framework\Api\Search\SearchCriteriaBuilder; + +/** + * Provides extension point to add additional filters to search criteria. + */ +interface AddFilterInterface +{ + /** + * Adds custom filter to search criteria builder based on received filter. + * + * @param SearchCriteriaBuilder $searchCriteriaBuilder + * @param Filter $filter + * @return void + */ + public function addFilter(SearchCriteriaBuilder $searchCriteriaBuilder, Filter $filter); +} diff --git a/app/code/Magento/Cms/Ui/Component/DataProvider.php b/app/code/Magento/Cms/Ui/Component/DataProvider.php index 3298d66b0b877..5fc9c5a896037 100644 --- a/app/code/Magento/Cms/Ui/Component/DataProvider.php +++ b/app/code/Magento/Cms/Ui/Component/DataProvider.php @@ -5,6 +5,7 @@ */ namespace Magento\Cms\Ui\Component; +use Magento\Framework\Api\Filter; use Magento\Framework\Api\FilterBuilder; use Magento\Framework\Api\Search\SearchCriteriaBuilder; use Magento\Framework\App\ObjectManager; @@ -19,6 +20,11 @@ class DataProvider extends \Magento\Framework\View\Element\UiComponent\DataProvi */ private $authorization; + /** + * @var AddFilterInterface[] + */ + private $additionalFilterPool; + /** * @param string $name * @param string $primaryFieldName @@ -29,6 +35,8 @@ class DataProvider extends \Magento\Framework\View\Element\UiComponent\DataProvi * @param FilterBuilder $filterBuilder * @param array $meta * @param array $data + * @param array $additionalFilterPool + * @SuppressWarnings(PHPMD.ExcessiveParameterList) */ public function __construct( $name, @@ -39,7 +47,8 @@ public function __construct( RequestInterface $request, FilterBuilder $filterBuilder, array $meta = [], - array $data = [] + array $data = [], + array $additionalFilterPool = [] ) { parent::__construct( $name, @@ -54,6 +63,7 @@ public function __construct( ); $this->meta = array_replace_recursive($meta, $this->prepareMetadata()); + $this->additionalFilterPool = $additionalFilterPool; } /** @@ -95,4 +105,16 @@ public function prepareMetadata() return $metadata; } + + /** + * @inheritdoc + */ + public function addFilter(Filter $filter) + { + if (!empty($this->additionalFilterPool[$filter->getField()])) { + $this->additionalFilterPool[$filter->getField()]->addFilter($this->searchCriteriaBuilder, $filter); + } else { + parent::addFilter($filter); + } + } } diff --git a/app/code/Magento/Cms/Ui/Component/Page/FulltextFilter.php b/app/code/Magento/Cms/Ui/Component/Page/FulltextFilter.php new file mode 100644 index 0000000000000..9b0c69a4f10c4 --- /dev/null +++ b/app/code/Magento/Cms/Ui/Component/Page/FulltextFilter.php @@ -0,0 +1,44 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +declare(strict_types=1); + +namespace Magento\Cms\Ui\Component\Page; + +use Magento\Cms\Ui\Component\AddFilterInterface; +use Magento\Framework\Api\Filter; +use Magento\Framework\Api\FilterBuilder; +use Magento\Framework\Api\Search\SearchCriteriaBuilder; + +/** + * Adds fulltext filter for CMS Page title attribute. + */ +class FulltextFilter implements AddFilterInterface +{ + /** + * @var FilterBuilder + */ + private $filterBuilder; + + /** + * @param FilterBuilder $filterBuilder + */ + public function __construct(FilterBuilder $filterBuilder) + { + $this->filterBuilder = $filterBuilder; + } + + /** + * @inheritdoc + */ + public function addFilter(SearchCriteriaBuilder $searchCriteriaBuilder, Filter $filter) + { + $titleFilter = $this->filterBuilder->setField('title') + ->setValue(sprintf('%%%s%%', $filter->getValue())) + ->setConditionType('like') + ->create(); + $searchCriteriaBuilder->addFilter($titleFilter); + } +} diff --git a/app/code/Magento/Cms/etc/di.xml b/app/code/Magento/Cms/etc/di.xml index 978d75c9b1e56..b6e13c63302cd 100644 --- a/app/code/Magento/Cms/etc/di.xml +++ b/app/code/Magento/Cms/etc/di.xml @@ -225,5 +225,13 @@ <argument name="collectionProcessor" xsi:type="object">Magento\Cms\Model\Api\SearchCriteria\BlockCollectionProcessor</argument> </arguments> </type> + + <type name="Magento\Cms\Ui\Component\DataProvider"> + <arguments> + <argument name="additionalFilterPool" xsi:type="array"> + <item name="fulltext" xsi:type="object">Magento\Cms\Ui\Component\Page\FulltextFilter</item> + </argument> + </arguments> + </type> </config> diff --git a/app/code/Magento/CmsUrlRewrite/Test/Mftf/composer.json b/app/code/Magento/CmsUrlRewrite/Test/Mftf/composer.json deleted file mode 100644 index 9bed46134f87e..0000000000000 --- a/app/code/Magento/CmsUrlRewrite/Test/Mftf/composer.json +++ /dev/null @@ -1,19 +0,0 @@ -{ - "name": "magento/functional-test-module-cms-url-rewrite", - "description": "N/A", - "config": { - "sort-packages": true - }, - "require": { - "php": "~7.1.3||~7.2.0", - "magento/magento2-functional-testing-framework": "2.2.0", - "magento/functional-test-module-cms": "100.0.0-dev", - "magento/functional-test-module-store": "100.0.0-dev", - "magento/functional-test-module-url-rewrite": "100.0.0-dev" - }, - "type": "magento2-test", - "license": [ - "OSL-3.0", - "AFL-3.0" - ] -} diff --git a/app/code/Magento/CmsUrlRewriteGraphQl/Test/Mftf/composer.json b/app/code/Magento/CmsUrlRewriteGraphQl/Test/Mftf/composer.json deleted file mode 100644 index edd1c6b352623..0000000000000 --- a/app/code/Magento/CmsUrlRewriteGraphQl/Test/Mftf/composer.json +++ /dev/null @@ -1,23 +0,0 @@ -{ - "name": "magento/functional-test-module-cms-url-rewrite-graph-ql", - "description": "N/A", - "config": { - "sort-packages": true - }, - "require": { - "php": "~7.1.3||~7.2.0", - "magento/magento2-functional-testing-framework": "2.2.0", - "magento/functional-test-module-url-rewrite-graph-ql": "100.0.0-dev", - "magento/functional-test-module-store": "100.0.0-dev", - "magento/functional-test-module-cms": "100.0.0-dev" - }, - "suggest": { - "magento/functional-test-module-cms-url-rewrite": "100.0.0-dev", - "magento/functional-test-module-catalog-graph-ql": "100.0.0-dev" - }, - "type": "magento2-test", - "license": [ - "OSL-3.0", - "AFL-3.0" - ] -} diff --git a/app/code/Magento/Config/App/Config/Type/System.php b/app/code/Magento/Config/App/Config/Type/System.php index 4f6d9c14346f0..479b4f5c21732 100644 --- a/app/code/Magento/Config/App/Config/Type/System.php +++ b/app/code/Magento/Config/App/Config/Type/System.php @@ -245,7 +245,7 @@ private function cacheData(array $data) ); $scopes = []; foreach (['websites', 'stores'] as $curScopeType) { - foreach ($data[$curScopeType] as $curScopeId => $curScopeData) { + foreach ($data[$curScopeType] ?? [] as $curScopeId => $curScopeData) { $scopes[$curScopeType][$curScopeId] = 1; $this->cache->save( $this->serializer->serialize($curScopeData), diff --git a/app/code/Magento/Config/Model/Config.php b/app/code/Magento/Config/Model/Config.php index bc1515aadb0ca..c6e2412f7e58f 100644 --- a/app/code/Magento/Config/Model/Config.php +++ b/app/code/Magento/Config/Model/Config.php @@ -5,6 +5,11 @@ */ namespace Magento\Config\Model; +use Magento\Config\Model\Config\Reader\Source\Deployed\SettingChecker; +use Magento\Config\Model\Config\Structure\Element\Group; +use Magento\Config\Model\Config\Structure\Element\Field; +use Magento\Framework\App\ObjectManager; + /** * Backend config model * Used to save configuration @@ -77,6 +82,11 @@ class Config extends \Magento\Framework\DataObject */ protected $_storeManager; + /** + * @var Config\Reader\Source\Deployed\SettingChecker + */ + private $settingChecker; + /** * @param \Magento\Framework\App\Config\ReinitableConfigInterface $config * @param \Magento\Framework\Event\ManagerInterface $eventManager @@ -85,6 +95,7 @@ class Config extends \Magento\Framework\DataObject * @param \Magento\Config\Model\Config\Loader $configLoader * @param \Magento\Framework\App\Config\ValueFactory $configValueFactory * @param \Magento\Store\Model\StoreManagerInterface $storeManager + * @param Config\Reader\Source\Deployed\SettingChecker|null $settingChecker * @param array $data */ public function __construct( @@ -95,6 +106,7 @@ public function __construct( \Magento\Config\Model\Config\Loader $configLoader, \Magento\Framework\App\Config\ValueFactory $configValueFactory, \Magento\Store\Model\StoreManagerInterface $storeManager, + SettingChecker $settingChecker = null, array $data = [] ) { parent::__construct($data); @@ -105,6 +117,7 @@ public function __construct( $this->_configLoader = $configLoader; $this->_configValueFactory = $configValueFactory; $this->_storeManager = $storeManager; + $this->settingChecker = $settingChecker ?: ObjectManager::getInstance()->get(SettingChecker::class); } /** @@ -126,11 +139,12 @@ public function save() $oldConfig = $this->_getConfig(true); + /** @var \Magento\Framework\DB\Transaction $deleteTransaction */ $deleteTransaction = $this->_transactionFactory->create(); - /* @var $deleteTransaction \Magento\Framework\DB\Transaction */ + /** @var \Magento\Framework\DB\Transaction $saveTransaction */ $saveTransaction = $this->_transactionFactory->create(); - /* @var $saveTransaction \Magento\Framework\DB\Transaction */ + $changedPaths = []; // Extends for old config data $extraOldGroups = []; @@ -145,6 +159,9 @@ public function save() $saveTransaction, $deleteTransaction ); + + $groupChangedPaths = $this->getChangedPaths($sectionId, $groupId, $groupData, $oldConfig, $extraOldGroups); + $changedPaths = \array_merge($changedPaths, $groupChangedPaths); } try { @@ -157,7 +174,11 @@ public function save() // website and store codes can be used in event implementation, so set them as well $this->_eventManager->dispatch( "admin_system_config_changed_section_{$this->getSection()}", - ['website' => $this->getWebsite(), 'store' => $this->getStore()] + [ + 'website' => $this->getWebsite(), + 'store' => $this->getStore(), + 'changed_paths' => $changedPaths, + ] ); } catch (\Exception $e) { // re-init configuration @@ -168,6 +189,144 @@ public function save() return $this; } + /** + * Map field name if they were cloned + * + * @param Group $group + * @param string $fieldId + * @return string + */ + private function getOriginalFieldId(Group $group, string $fieldId): string + { + if ($group->shouldCloneFields()) { + $cloneModel = $group->getCloneModel(); + + /** @var \Magento\Config\Model\Config\Structure\Element\Field $field */ + foreach ($group->getChildren() as $field) { + foreach ($cloneModel->getPrefixes() as $prefix) { + if ($prefix['field'] . $field->getId() === $fieldId) { + $fieldId = $field->getId(); + break(2); + } + } + } + } + + return $fieldId; + } + + /** + * Get field object + * + * @param string $sectionId + * @param string $groupId + * @param string $fieldId + * @return Field + */ + private function getField(string $sectionId, string $groupId, string $fieldId): Field + { + /** @var \Magento\Config\Model\Config\Structure\Element\Group $group */ + $group = $this->_configStructure->getElement($sectionId . '/' . $groupId); + $fieldPath = $group->getPath() . '/' . $this->getOriginalFieldId($group, $fieldId); + $field = $this->_configStructure->getElement($fieldPath); + + return $field; + } + + /** + * Get field path + * + * @param Field $field + * @param array &$oldConfig Need for compatibility with _processGroup() + * @param array &$extraOldGroups Need for compatibility with _processGroup() + * @return string + */ + private function getFieldPath(Field $field, array &$oldConfig, array &$extraOldGroups): string + { + $path = $field->getGroupPath() . '/' . $field->getId(); + + /** + * Look for custom defined field path + */ + $configPath = $field->getConfigPath(); + if ($configPath && strrpos($configPath, '/') > 0) { + // Extend old data with specified section group + $configGroupPath = substr($configPath, 0, strrpos($configPath, '/')); + if (!isset($extraOldGroups[$configGroupPath])) { + $oldConfig = $this->extendConfig($configGroupPath, true, $oldConfig); + $extraOldGroups[$configGroupPath] = true; + } + $path = $configPath; + } + + return $path; + } + + /** + * Check is config value changed + * + * @param array $oldConfig + * @param string $path + * @param array $fieldData + * @return bool + */ + private function isValueChanged(array $oldConfig, string $path, array $fieldData): bool + { + if (isset($oldConfig[$path]['value'])) { + $result = !isset($fieldData['value']) || $oldConfig[$path]['value'] !== $fieldData['value']; + } else { + $result = empty($fieldData['inherit']); + } + + return $result; + } + + /** + * Get changed paths + * + * @param string $sectionId + * @param string $groupId + * @param array $groupData + * @param array &$oldConfig + * @param array &$extraOldGroups + * @return array + */ + private function getChangedPaths( + string $sectionId, + string $groupId, + array $groupData, + array &$oldConfig, + array &$extraOldGroups + ): array { + $changedPaths = []; + + if (isset($groupData['fields'])) { + foreach ($groupData['fields'] as $fieldId => $fieldData) { + $field = $this->getField($sectionId, $groupId, $fieldId); + $path = $this->getFieldPath($field, $oldConfig, $extraOldGroups); + if ($this->isValueChanged($oldConfig, $path, $fieldData)) { + $changedPaths[] = $path; + } + } + } + + if (isset($groupData['groups'])) { + $subSectionId = $sectionId . '/' . $groupId; + foreach ($groupData['groups'] as $subGroupId => $subGroupData) { + $subGroupChangedPaths = $this->getChangedPaths( + $subSectionId, + $subGroupId, + $subGroupData, + $oldConfig, + $extraOldGroups + ); + $changedPaths = \array_merge($changedPaths, $subGroupChangedPaths); + } + } + + return $changedPaths; + } + /** * Process group data * @@ -182,7 +341,6 @@ public function save() * @return void * @SuppressWarnings(PHPMD.CyclomaticComplexity) * @SuppressWarnings(PHPMD.NPathComplexity) - * @SuppressWarnings(PHPMD.ExcessiveMethodLength) */ protected function _processGroup( $groupId, @@ -195,92 +353,55 @@ protected function _processGroup( \Magento\Framework\DB\Transaction $deleteTransaction ) { $groupPath = $sectionPath . '/' . $groupId; - $scope = $this->getScope(); - $scopeId = $this->getScopeId(); - $scopeCode = $this->getScopeCode(); - /** - * - * Map field names if they were cloned - */ - /** @var $group \Magento\Config\Model\Config\Structure\Element\Group */ - $group = $this->_configStructure->getElement($groupPath); - // set value for group field entry by fieldname - // use extra memory - $fieldsetData = []; if (isset($groupData['fields'])) { - if ($group->shouldCloneFields()) { - $cloneModel = $group->getCloneModel(); - $mappedFields = []; - - /** @var $field \Magento\Config\Model\Config\Structure\Element\Field */ - foreach ($group->getChildren() as $field) { - foreach ($cloneModel->getPrefixes() as $prefix) { - $mappedFields[$prefix['field'] . $field->getId()] = $field->getId(); - } - } - } + /** @var \Magento\Config\Model\Config\Structure\Element\Group $group */ + $group = $this->_configStructure->getElement($groupPath); + + // set value for group field entry by fieldname + // use extra memory + $fieldsetData = []; foreach ($groupData['fields'] as $fieldId => $fieldData) { - $fieldsetData[$fieldId] = is_array( - $fieldData - ) && isset( - $fieldData['value'] - ) ? $fieldData['value'] : null; + $fieldsetData[$fieldId] = $fieldData['value'] ?? null; } foreach ($groupData['fields'] as $fieldId => $fieldData) { - $originalFieldId = $fieldId; - if ($group->shouldCloneFields() && isset($mappedFields[$fieldId])) { - $originalFieldId = $mappedFields[$fieldId]; + $isReadOnly = $this->settingChecker->isReadOnly( + $groupPath . '/' . $fieldId, + $this->getScope(), + $this->getScopeCode() + ); + + if ($isReadOnly) { + continue; } - /** @var $field \Magento\Config\Model\Config\Structure\Element\Field */ - $field = $this->_configStructure->getElement($groupPath . '/' . $originalFieldId); + $field = $this->getField($sectionPath, $groupId, $fieldId); /** @var \Magento\Framework\App\Config\ValueInterface $backendModel */ - $backendModel = $field->hasBackendModel() ? $field - ->getBackendModel() : $this - ->_configValueFactory - ->create(); + $backendModel = $field->hasBackendModel() + ? $field->getBackendModel() + : $this->_configValueFactory->create(); + if (!isset($fieldData['value'])) { + $fieldData['value'] = null; + } $data = [ 'field' => $fieldId, 'groups' => $groups, 'group_id' => $group->getId(), - 'scope' => $scope, - 'scope_id' => $scopeId, - 'scope_code' => $scopeCode, + 'scope' => $this->getScope(), + 'scope_id' => $this->getScopeId(), + 'scope_code' => $this->getScopeCode(), 'field_config' => $field->getData(), - 'fieldset_data' => $fieldsetData + 'fieldset_data' => $fieldsetData, ]; $backendModel->addData($data); - $this->_checkSingleStoreMode($field, $backendModel); - if (false == isset($fieldData['value'])) { - $fieldData['value'] = null; - } - - $path = $field->getGroupPath() . '/' . $fieldId; - /** - * Look for custom defined field path - */ - if ($field && $field->getConfigPath()) { - $configPath = $field->getConfigPath(); - if (!empty($configPath) && strrpos($configPath, '/') > 0) { - // Extend old data with specified section group - $configGroupPath = substr($configPath, 0, strrpos($configPath, '/')); - if (!isset($extraOldGroups[$configGroupPath])) { - $oldConfig = $this->extendConfig($configGroupPath, true, $oldConfig); - $extraOldGroups[$configGroupPath] = true; - } - $path = $configPath; - } - } - - $inherit = !empty($fieldData['inherit']); - + $path = $this->getFieldPath($field, $extraOldGroups, $oldConfig); $backendModel->setPath($path)->setValue($fieldData['value']); + $inherit = !empty($fieldData['inherit']); if (isset($oldConfig[$path])) { $backendModel->setConfigId($oldConfig[$path]['config_id']); diff --git a/app/code/Magento/Config/Test/Mftf/ActionGroup/ConfigWYSIWYGActionGroup.xml b/app/code/Magento/Config/Test/Mftf/ActionGroup/ConfigWYSIWYGActionGroup.xml index 52adb0b1f50a5..80351c9d97520 100644 --- a/app/code/Magento/Config/Test/Mftf/ActionGroup/ConfigWYSIWYGActionGroup.xml +++ b/app/code/Magento/Config/Test/Mftf/ActionGroup/ConfigWYSIWYGActionGroup.xml @@ -29,4 +29,17 @@ <click selector="{{ContentManagementSection.WYSIWYGOptions}}" stepKey="collapseWYSIWYGOptions" /> <click selector="{{ContentManagementSection.Save}}" stepKey="saveConfig" /> </actionGroup> + <actionGroup name="UseStaticURLForMediaContentInWYSIWYG"> + <arguments> + <argument name="value" defaultValue="Yes" type="string"/> + </arguments> + <amOnPage url="{{ConfigurationStoresPage.url}}" stepKey="navigateToWYSIWYGConfigPage1"/> + <waitForPageLoad stepKey="waitForPageLoad1"/> + <conditionalClick stepKey="expandWYSIWYGOptions" selector="{{ContentManagementSection.WYSIWYGOptions}}" dependentSelector="{{ContentManagementSection.CheckIfTabExpand}}" visible="true" /> + <waitForElementVisible selector="{{ContentManagementSection.EnableWYSIWYG}}" stepKey="waitForEnableWYSIWYGDropdown1" /> + <selectOption selector="{{ContentManagementSection.StaticURL}}" userInput="{{value}}" stepKey="selectOption1"/> + <click selector="{{ContentManagementSection.WYSIWYGOptions}}" stepKey="collapseWYSIWYGOptions" /> + <click selector="{{ContentManagementSection.Save}}" stepKey="saveConfig" /> + <waitForPageLoad stepKey="waitForPageLoad2" /> + </actionGroup> </actionGroups> diff --git a/app/code/Magento/Config/Test/Mftf/Section/GeneralSection.xml b/app/code/Magento/Config/Test/Mftf/Section/GeneralSection.xml index b1454ff07ee9e..18e91dc017cfc 100644 --- a/app/code/Magento/Config/Test/Mftf/Section/GeneralSection.xml +++ b/app/code/Magento/Config/Test/Mftf/Section/GeneralSection.xml @@ -15,6 +15,7 @@ <element name="EnableWYSIWYG" type="button" selector="#cms_wysiwyg_enabled"/> <element name="SwitcherSystemValue" type="button" selector="#cms_wysiwyg_editor_inherit"/> <element name="Switcher" type="button" selector="#cms_wysiwyg_editor" /> + <element name="StaticURL" type="button" selector="#cms_wysiwyg_use_static_urls_in_catalog" /> <element name="Save" type="button" selector="#save"/> </section> <section name="WebSection"> diff --git a/app/code/Magento/Config/Test/Mftf/composer.json b/app/code/Magento/Config/Test/Mftf/composer.json deleted file mode 100644 index 0dacef66e5dce..0000000000000 --- a/app/code/Magento/Config/Test/Mftf/composer.json +++ /dev/null @@ -1,23 +0,0 @@ -{ - "name": "magento/functional-test-module-config", - "description": "N/A", - "config": { - "sort-packages": true - }, - "require": { - "php": "~7.1.3||~7.2.0", - "magento/magento2-functional-testing-framework": "2.2.0", - "magento/functional-test-module-backend": "100.0.0-dev", - "magento/functional-test-module-cron": "100.0.0-dev", - "magento/functional-test-module-deploy": "100.0.0-dev", - "magento/functional-test-module-directory": "100.0.0-dev", - "magento/functional-test-module-email": "100.0.0-dev", - "magento/functional-test-module-media-storage": "100.0.0-dev", - "magento/functional-test-module-store": "100.0.0-dev" - }, - "type": "magento2-test", - "license": [ - "OSL-3.0", - "AFL-3.0" - ] -} diff --git a/app/code/Magento/Config/Test/Unit/Model/ConfigTest.php b/app/code/Magento/Config/Test/Unit/Model/ConfigTest.php index 2ddbbd5ffe1e8..d0568f48ded1e 100644 --- a/app/code/Magento/Config/Test/Unit/Model/ConfigTest.php +++ b/app/code/Magento/Config/Test/Unit/Model/ConfigTest.php @@ -60,6 +60,11 @@ class ConfigTest extends \PHPUnit\Framework\TestCase */ protected $_configStructure; + /** + * @var \PHPUnit_Framework_MockObject_MockObject + */ + private $_settingsChecker; + protected function setUp() { $this->_eventManagerMock = $this->createMock(\Magento\Framework\Event\ManagerInterface::class); @@ -79,7 +84,7 @@ protected function setUp() $this->_transFactoryMock = $this->createPartialMock( \Magento\Framework\DB\TransactionFactory::class, - ['create'] + ['create', 'addObject'] ); $this->_appConfigMock = $this->createMock(\Magento\Framework\App\Config\ReinitableConfigInterface::class); $this->_configLoaderMock = $this->createPartialMock( @@ -90,6 +95,9 @@ protected function setUp() $this->_storeManager = $this->getMockForAbstractClass(\Magento\Store\Model\StoreManagerInterface::class); + $this->_settingsChecker = $this + ->createMock(\Magento\Config\Model\Config\Reader\Source\Deployed\SettingChecker::class); + $this->_model = new \Magento\Config\Model\Config( $this->_appConfigMock, $this->_eventManagerMock, @@ -97,7 +105,8 @@ protected function setUp() $this->_transFactoryMock, $this->_configLoaderMock, $this->_dataFactoryMock, - $this->_storeManager + $this->_storeManager, + $this->_settingsChecker ); } @@ -149,55 +158,96 @@ public function testSaveToCheckAdminSystemConfigChangedSectionEvent() $this->_model->save(); } - public function testSaveToCheckScopeDataSet() + public function testDoNotSaveReadOnlyFields() { $transactionMock = $this->createMock(\Magento\Framework\DB\Transaction::class); - $this->_transFactoryMock->expects($this->any())->method('create')->will($this->returnValue($transactionMock)); + $this->_settingsChecker->expects($this->any())->method('isReadOnly')->will($this->returnValue(true)); $this->_configLoaderMock->expects($this->any())->method('getConfigByPath')->will($this->returnValue([])); - $this->_eventManagerMock->expects( - $this->at(0) - )->method( - 'dispatch' - )->with( - $this->equalTo('admin_system_config_changed_section_'), - $this->arrayHasKey('website') - ); - - $this->_eventManagerMock->expects( - $this->at(0) - )->method( - 'dispatch' - )->with( - $this->equalTo('admin_system_config_changed_section_'), - $this->arrayHasKey('store') - ); + $this->_model->setGroups(['1' => ['fields' => ['key' => ['data']]]]); + $this->_model->setSection('section'); $group = $this->createMock(\Magento\Config\Model\Config\Structure\Element\Group::class); + $group->method('getPath')->willReturn('section/1'); $field = $this->createMock(\Magento\Config\Model\Config\Structure\Element\Field::class); + $field->method('getGroupPath')->willReturn('section/1'); + $field->method('getId')->willReturn('key'); + + $this->_configStructure->expects($this->at(0)) + ->method('getElement') + ->with('section/1') + ->will($this->returnValue($group)); + $this->_configStructure->expects($this->at(1)) + ->method('getElement') + ->with('section/1') + ->will($this->returnValue($group)); + $this->_configStructure->expects($this->at(2)) + ->method('getElement') + ->with('section/1/key') + ->will($this->returnValue($field)); - $this->_configStructure->expects( - $this->at(0) - )->method( - 'getElement' - )->with( - '/1' - )->will( - $this->returnValue($group) + $backendModel = $this->createPartialMock( + \Magento\Framework\App\Config\Value::class, + ['addData'] ); + $this->_dataFactoryMock->expects($this->any())->method('create')->will($this->returnValue($backendModel)); - $this->_configStructure->expects( - $this->at(1) - )->method( - 'getElement' - )->with( - '/1/key' - )->will( - $this->returnValue($field) - ); + $this->_transFactoryMock->expects($this->never())->method('addObject'); + $backendModel->expects($this->never())->method('addData'); + + $this->_model->save(); + } + + public function testSaveToCheckScopeDataSet() + { + $transactionMock = $this->createMock(\Magento\Framework\DB\Transaction::class); + $this->_transFactoryMock->expects($this->any())->method('create')->will($this->returnValue($transactionMock)); + + $this->_configLoaderMock->expects($this->any())->method('getConfigByPath')->will($this->returnValue([])); + + $this->_eventManagerMock->expects($this->at(0)) + ->method('dispatch') + ->with( + $this->equalTo('admin_system_config_changed_section_section'), + $this->arrayHasKey('website') + ); + $this->_eventManagerMock->expects($this->at(0)) + ->method('dispatch') + ->with( + $this->equalTo('admin_system_config_changed_section_section'), + $this->arrayHasKey('store') + ); + + $group = $this->createMock(\Magento\Config\Model\Config\Structure\Element\Group::class); + $group->method('getPath')->willReturn('section/1'); + + $field = $this->createMock(\Magento\Config\Model\Config\Structure\Element\Field::class); + $field->method('getGroupPath')->willReturn('section/1'); + $field->method('getId')->willReturn('key'); + + $this->_configStructure->expects($this->at(0)) + ->method('getElement') + ->with('section/1') + ->will($this->returnValue($group)); + $this->_configStructure->expects($this->at(1)) + ->method('getElement') + ->with('section/1') + ->will($this->returnValue($group)); + $this->_configStructure->expects($this->at(2)) + ->method('getElement') + ->with('section/1/key') + ->will($this->returnValue($field)); + $this->_configStructure->expects($this->at(3)) + ->method('getElement') + ->with('section/1') + ->will($this->returnValue($group)); + $this->_configStructure->expects($this->at(4)) + ->method('getElement') + ->with('section/1/key') + ->will($this->returnValue($field)); $website = $this->createMock(\Magento\Store\Model\Website::class); $website->expects($this->any())->method('getCode')->will($this->returnValue('website_code')); @@ -206,19 +256,16 @@ public function testSaveToCheckScopeDataSet() $this->_storeManager->expects($this->any())->method('isSingleStoreMode')->will($this->returnValue(true)); $this->_model->setWebsite('website'); - + $this->_model->setSection('section'); $this->_model->setGroups(['1' => ['fields' => ['key' => ['data']]]]); $backendModel = $this->createPartialMock( \Magento\Framework\App\Config\Value::class, ['setPath', 'addData', '__sleep', '__wakeup'] ); - $backendModel->expects( - $this->once() - )->method( - 'addData' - )->with( - [ + $backendModel->expects($this->once()) + ->method('addData') + ->with([ 'field' => 'key', 'groups' => [1 => ['fields' => ['key' => ['data']]]], 'group_id' => null, @@ -227,17 +274,11 @@ public function testSaveToCheckScopeDataSet() 'scope_code' => 'website_code', 'field_config' => null, 'fieldset_data' => ['key' => null], - ] - ); - $backendModel->expects( - $this->once() - )->method( - 'setPath' - )->with( - '/key' - )->will( - $this->returnValue($backendModel) - ); + ]); + $backendModel->expects($this->once()) + ->method('setPath') + ->with('section/1/key') + ->will($this->returnValue($backendModel)); $this->_dataFactoryMock->expects($this->any())->method('create')->will($this->returnValue($backendModel)); @@ -295,7 +336,7 @@ public function setDataByPathWrongDepthDataProvider() 'depth 2' => ['section/group', "Your configuration depth is 2 for path 'section/group'"], 'depth 1' => ['section', "Your configuration depth is 1 for path 'section'"], 'depth 4' => ['section/group/field/sub-field', "Your configuration depth is 4 for path" - . " 'section/group/field/sub-field'", ], + . " 'section/group/field/sub-field'", ], ]; } } diff --git a/app/code/Magento/Config/etc/system_file.xsd b/app/code/Magento/Config/etc/system_file.xsd index 5a2b915262a9a..f1688b2e35371 100644 --- a/app/code/Magento/Config/etc/system_file.xsd +++ b/app/code/Magento/Config/etc/system_file.xsd @@ -474,7 +474,7 @@ </xs:documentation> </xs:annotation> <xs:restriction base="xs:string"> - <xs:pattern value="[A-Za-z0-9\\:]+" /> + <xs:pattern value="[A-Za-z0-9_\\:]+" /> <xs:minLength value="5" /> </xs:restriction> </xs:simpleType> diff --git a/app/code/Magento/ConfigurableImportExport/Test/Mftf/composer.json b/app/code/Magento/ConfigurableImportExport/Test/Mftf/composer.json deleted file mode 100644 index 74322a53512f9..0000000000000 --- a/app/code/Magento/ConfigurableImportExport/Test/Mftf/composer.json +++ /dev/null @@ -1,21 +0,0 @@ -{ - "name": "magento/functional-test-module-configurable-import-export", - "description": "N/A", - "config": { - "sort-packages": true - }, - "require": { - "php": "~7.1.3||~7.2.0", - "magento/magento2-functional-testing-framework": "2.2.0", - "magento/functional-test-module-catalog": "100.0.0-dev", - "magento/functional-test-module-catalog-import-export": "100.0.0-dev", - "magento/functional-test-module-configurable-product": "100.0.0-dev", - "magento/functional-test-module-eav": "100.0.0-dev", - "magento/functional-test-module-import-export": "100.0.0-dev" - }, - "type": "magento2-test", - "license": [ - "OSL-3.0", - "AFL-3.0" - ] -} diff --git a/app/code/Magento/ConfigurableProduct/Model/Quote/Item/CartItemProcessor.php b/app/code/Magento/ConfigurableProduct/Model/Quote/Item/CartItemProcessor.php index 4450bbd75e574..56993ecec1fbf 100644 --- a/app/code/Magento/ConfigurableProduct/Model/Quote/Item/CartItemProcessor.php +++ b/app/code/Magento/ConfigurableProduct/Model/Quote/Item/CartItemProcessor.php @@ -59,7 +59,7 @@ public function __construct( } /** - * {@inheritdoc} + * @inheritdoc */ public function convertToBuyRequest(CartItemInterface $cartItem) { @@ -69,7 +69,7 @@ public function convertToBuyRequest(CartItemInterface $cartItem) if (is_array($options)) { $requestData = []; foreach ($options as $option) { - $requestData['super_attribute'][$option->getOptionId()] = $option->getOptionValue(); + $requestData['super_attribute'][$option->getOptionId()] = (string) $option->getOptionValue(); } return $this->objectFactory->create($requestData); } @@ -78,7 +78,7 @@ public function convertToBuyRequest(CartItemInterface $cartItem) } /** - * {@inheritdoc} + * @inheritdoc */ public function processOptions(CartItemInterface $cartItem) { diff --git a/app/code/Magento/ConfigurableProduct/Model/ResourceModel/Product/Indexer/Price/Configurable.php b/app/code/Magento/ConfigurableProduct/Model/ResourceModel/Product/Indexer/Price/Configurable.php index 087931ebe5dcc..81e2e99bfe93a 100644 --- a/app/code/Magento/ConfigurableProduct/Model/ResourceModel/Product/Indexer/Price/Configurable.php +++ b/app/code/Magento/ConfigurableProduct/Model/ResourceModel/Product/Indexer/Price/Configurable.php @@ -5,91 +5,176 @@ */ namespace Magento\ConfigurableProduct\Model\ResourceModel\Product\Indexer\Price; -use Magento\Catalog\Api\Data\ProductInterface; -use Magento\Store\Api\StoreResolverInterface; +use Magento\Catalog\Model\ResourceModel\Product\Indexer\Price\BasePriceModifier; +use Magento\Framework\Indexer\DimensionalIndexerInterface; +use Magento\Framework\EntityManager\MetadataPool; +use Magento\Catalog\Model\Indexer\Product\Price\TableMaintainer; +use Magento\Catalog\Model\ResourceModel\Product\Indexer\Price\Query\BaseFinalPrice; +use Magento\Catalog\Model\ResourceModel\Product\Indexer\Price\IndexTableStructureFactory; +use Magento\Catalog\Model\ResourceModel\Product\Indexer\Price\IndexTableStructure; /** * Configurable Products Price Indexer Resource model + * + * @SuppressWarnings(PHPMD.CouplingBetweenObjects) */ -class Configurable extends \Magento\Catalog\Model\ResourceModel\Product\Indexer\Price\DefaultPrice +class Configurable implements DimensionalIndexerInterface { /** - * @param null|int|array $entityIds - * @return \Magento\ConfigurableProduct\Model\ResourceModel\Product\Indexer\Price\Configurable + * @var BaseFinalPrice */ - protected function reindex($entityIds = null) - { - if ($this->hasEntity() || !empty($entityIds)) { - $this->prepareFinalPriceDataForType($entityIds, $this->getTypeId()); - $this->_applyCustomOption(); - $this->_applyConfigurableOption($entityIds); - $this->_movePriceDataToIndexTable($entityIds); - } + private $baseFinalPrice; - return $this; - } + /** + * @var IndexTableStructureFactory + */ + private $indexTableStructureFactory; /** - * Retrieve table name for custom option temporary aggregation data - * - * @return string + * @var TableMaintainer */ - protected function _getConfigurableOptionAggregateTable() - { - return $this->tableStrategy->getTableName('catalog_product_index_price_cfg_opt_agr'); - } + private $tableMaintainer; /** - * Retrieve table name for custom option prices data - * - * @return string + * @var MetadataPool */ - protected function _getConfigurableOptionPriceTable() - { - return $this->tableStrategy->getTableName('catalog_product_index_price_cfg_opt'); + private $metadataPool; + + /** + * @var \Magento\Framework\App\ResourceConnection + */ + private $resource; + + /** + * @var bool + */ + private $fullReindexAction; + + /** + * @var string + */ + private $connectionName; + + /** + * @var \Magento\Framework\DB\Adapter\AdapterInterface + */ + private $connection; + + /** + * @var BasePriceModifier + */ + private $basePriceModifier; + + /** + * @param BaseFinalPrice $baseFinalPrice + * @param IndexTableStructureFactory $indexTableStructureFactory + * @param TableMaintainer $tableMaintainer + * @param MetadataPool $metadataPool + * @param \Magento\Framework\App\ResourceConnection $resource + * @param BasePriceModifier $basePriceModifier + * @param bool $fullReindexAction + * @param string $connectionName + */ + public function __construct( + BaseFinalPrice $baseFinalPrice, + IndexTableStructureFactory $indexTableStructureFactory, + TableMaintainer $tableMaintainer, + MetadataPool $metadataPool, + \Magento\Framework\App\ResourceConnection $resource, + BasePriceModifier $basePriceModifier, + $fullReindexAction = false, + $connectionName = 'indexer' + ) { + $this->baseFinalPrice = $baseFinalPrice; + $this->indexTableStructureFactory = $indexTableStructureFactory; + $this->tableMaintainer = $tableMaintainer; + $this->connectionName = $connectionName; + $this->metadataPool = $metadataPool; + $this->resource = $resource; + $this->fullReindexAction = $fullReindexAction; + $this->basePriceModifier = $basePriceModifier; } /** - * Prepare table structure for custom option temporary aggregation data + * {@inheritdoc} * - * @return \Magento\ConfigurableProduct\Model\ResourceModel\Product\Indexer\Price\Configurable + * @throws \Exception */ - protected function _prepareConfigurableOptionAggregateTable() + public function executeByDimensions(array $dimensions, \Traversable $entityIds) { - $this->getConnection()->delete($this->_getConfigurableOptionAggregateTable()); - return $this; + $this->tableMaintainer->createMainTmpTable($dimensions); + + $temporaryPriceTable = $this->indexTableStructureFactory->create([ + 'tableName' => $this->tableMaintainer->getMainTmpTable($dimensions), + 'entityField' => 'entity_id', + 'customerGroupField' => 'customer_group_id', + 'websiteField' => 'website_id', + 'taxClassField' => 'tax_class_id', + 'originalPriceField' => 'price', + 'finalPriceField' => 'final_price', + 'minPriceField' => 'min_price', + 'maxPriceField' => 'max_price', + 'tierPriceField' => 'tier_price', + ]); + $select = $this->baseFinalPrice->getQuery( + $dimensions, + \Magento\ConfigurableProduct\Model\Product\Type\Configurable::TYPE_CODE, + iterator_to_array($entityIds) + ); + $query = $select->insertFromSelect($temporaryPriceTable->getTableName(), [], false); + $this->tableMaintainer->getConnection()->query($query); + + $this->basePriceModifier->modifyPrice($temporaryPriceTable, iterator_to_array($entityIds)); + $this->applyConfigurableOption($temporaryPriceTable, $dimensions, iterator_to_array($entityIds)); } /** - * Prepare table structure for custom option prices data + * Apply configurable option * - * @return \Magento\ConfigurableProduct\Model\ResourceModel\Product\Indexer\Price\Configurable + * @param IndexTableStructure $temporaryPriceTable + * @param array $dimensions + * @param array $entityIds + * + * @return $this + * @throws \Exception */ - protected function _prepareConfigurableOptionPriceTable() - { - $this->getConnection()->delete($this->_getConfigurableOptionPriceTable()); + private function applyConfigurableOption( + IndexTableStructure $temporaryPriceTable, + array $dimensions, + array $entityIds + ) { + $temporaryOptionsTableName = 'catalog_product_index_price_cfg_opt_temp'; + $this->getConnection()->createTemporaryTableLike( + $temporaryOptionsTableName, + $this->getTable('catalog_product_index_price_cfg_opt_tmp'), + true + ); + + $this->fillTemporaryOptionsTable($temporaryOptionsTableName, $dimensions, $entityIds); + $this->updateTemporaryTable($temporaryPriceTable->getTableName(), $temporaryOptionsTableName); + + $this->getConnection()->delete($temporaryOptionsTableName); + return $this; } /** - * Calculate minimal and maximal prices for configurable product options - * and apply it to final price + * Put data into catalog product price indexer config option temp table + * + * @param string $temporaryOptionsTableName + * @param array $dimensions + * @param array $entityIds * - * @param array|null $entityIds - * @return \Magento\ConfigurableProduct\Model\ResourceModel\Product\Indexer\Price\Configurable + * @return void + * @throws \Exception */ - protected function _applyConfigurableOption($entityIds = null) + private function fillTemporaryOptionsTable(string $temporaryOptionsTableName, array $dimensions, array $entityIds) { - $metadata = $this->getMetadataPool()->getMetadata(ProductInterface::class); - $connection = $this->getConnection(); - $copTable = $this->_getConfigurableOptionPriceTable(); - $finalPriceTable = $this->_getDefaultFinalPriceTable(); + $metadata = $this->metadataPool->getMetadata(\Magento\Catalog\Api\Data\ProductInterface::class); $linkField = $metadata->getLinkField(); - $this->_prepareConfigurableOptionPriceTable(); - - $select = $connection->select()->from( - ['i' => $this->getIdxTable()], + $select = $this->getConnection()->select()->from( + ['i' => $this->getMainTable($dimensions)], [] )->join( ['l' => $this->getTable('catalog_product_super_link')], @@ -107,7 +192,6 @@ protected function _applyConfigurableOption($entityIds = null) 'MIN(final_price)', 'MAX(final_price)', 'MIN(tier_price)', - ] )->group( ['le.entity_id', 'customer_group_id', 'website_id'] @@ -115,31 +199,77 @@ protected function _applyConfigurableOption($entityIds = null) if ($entityIds !== null) { $select->where('le.entity_id IN (?)', $entityIds); } + $query = $select->insertFromSelect($temporaryOptionsTableName); + $this->getConnection()->query($query); + } - $query = $select->insertFromSelect($copTable); - $connection->query($query); - - $table = ['i' => $finalPriceTable]; - $select = $connection->select()->join( - ['io' => $copTable], + /** + * Update data in the catalog product price indexer temp table + * + * @param string $temporaryPriceTableName + * @param string $temporaryOptionsTableName + * + * @return void + */ + private function updateTemporaryTable(string $temporaryPriceTableName, string $temporaryOptionsTableName) + { + $table = ['i' => $temporaryPriceTableName]; + $selectForCrossUpdate = $this->getConnection()->select()->join( + ['io' => $temporaryOptionsTableName], 'i.entity_id = io.entity_id AND i.customer_group_id = io.customer_group_id' . ' AND i.website_id = io.website_id', [] ); // adds price of custom option, that was applied in DefaultPrice::_applyCustomOption - $select->columns( + $selectForCrossUpdate->columns( [ - 'min_price' => new \Zend_Db_Expr('i.min_price - i.orig_price + io.min_price'), - 'max_price' => new \Zend_Db_Expr('i.max_price - i.orig_price + io.max_price'), + 'min_price' => new \Zend_Db_Expr('i.min_price - i.price + io.min_price'), + 'max_price' => new \Zend_Db_Expr('i.max_price - i.price + io.max_price'), 'tier_price' => 'io.tier_price', ] ); - $query = $select->crossUpdateFromSelect($table); - $connection->query($query); + $query = $selectForCrossUpdate->crossUpdateFromSelect($table); + $this->getConnection()->query($query); + } + + /** + * Get main table + * + * @param array $dimensions + * @return string + */ + private function getMainTable($dimensions) + { + if ($this->fullReindexAction) { + return $this->tableMaintainer->getMainReplicaTable($dimensions); + } + return $this->tableMaintainer->getMainTable($dimensions); + } + + /** + * Get connection + * + * return \Magento\Framework\DB\Adapter\AdapterInterface + * @throws \DomainException + */ + private function getConnection(): \Magento\Framework\DB\Adapter\AdapterInterface + { + if ($this->connection === null) { + $this->connection = $this->resource->getConnection($this->connectionName); + } - $connection->delete($copTable); + return $this->connection; + } - return $this; + /** + * Get table + * + * @param string $tableName + * @return string + */ + private function getTable($tableName) + { + return $this->resource->getTableName($tableName, $this->connectionName); } } diff --git a/app/code/Magento/ConfigurableProduct/Setup/Patch/Data/InstallInitialConfigurableAttributes.php b/app/code/Magento/ConfigurableProduct/Setup/Patch/Data/InstallInitialConfigurableAttributes.php index c9fea3e74d3d2..f69d8529fb801 100644 --- a/app/code/Magento/ConfigurableProduct/Setup/Patch/Data/InstallInitialConfigurableAttributes.php +++ b/app/code/Magento/ConfigurableProduct/Setup/Patch/Data/InstallInitialConfigurableAttributes.php @@ -51,6 +51,7 @@ public function apply() $eavSetup = $this->eavSetupFactory->create(['setup' => $this->moduleDataSetup]); $attributes = [ 'country_of_manufacture', + 'manufacturer', 'minimal_price', 'msrp', 'msrp_display_actual_price_type', diff --git a/app/code/Magento/ConfigurableProduct/Setup/Patch/Data/UpdateManufacturerAttribute.php b/app/code/Magento/ConfigurableProduct/Setup/Patch/Data/UpdateManufacturerAttribute.php new file mode 100644 index 0000000000000..c9a2f7d373a63 --- /dev/null +++ b/app/code/Magento/ConfigurableProduct/Setup/Patch/Data/UpdateManufacturerAttribute.php @@ -0,0 +1,94 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +declare(strict_types=1); + +namespace Magento\ConfigurableProduct\Setup\Patch\Data; + +use Magento\Eav\Setup\EavSetup; +use Magento\Eav\Setup\EavSetupFactory; +use Magento\Framework\Setup\ModuleDataSetupInterface; +use Magento\Framework\Setup\Patch\DataPatchInterface; +use Magento\Framework\Setup\Patch\PatchVersionInterface; +use Magento\ConfigurableProduct\Model\Product\Type\Configurable; + +/** + * Class UpdateManufacturerAttribute + * @package Magento\ConfigurableProduct\Setup\Patch + */ +class UpdateManufacturerAttribute implements DataPatchInterface, PatchVersionInterface +{ + /** + * @var ModuleDataSetupInterface + */ + private $moduleDataSetup; + + /** + * @var EavSetupFactory + */ + private $eavSetupFactory; + + /** + * UpdateTierPriceAttribute constructor. + * @param ModuleDataSetupInterface $moduleDataSetup + * @param EavSetupFactory $eavSetupFactory + */ + public function __construct( + ModuleDataSetupInterface $moduleDataSetup, + EavSetupFactory $eavSetupFactory + ) { + $this->moduleDataSetup = $moduleDataSetup; + $this->eavSetupFactory = $eavSetupFactory; + } + + /** + * {@inheritdoc} + */ + public function apply() + { + /** @var EavSetup $eavSetup */ + $eavSetup = $this->eavSetupFactory->create(['setup' => $this->moduleDataSetup]); + $relatedProductTypes = explode( + ',', + $eavSetup->getAttribute(\Magento\Catalog\Model\Product::ENTITY, 'manufacturer', 'apply_to') + ); + + if (!in_array(Configurable::TYPE_CODE, $relatedProductTypes)) { + $relatedProductTypes[] = Configurable::TYPE_CODE; + $eavSetup->updateAttribute( + \Magento\Catalog\Model\Product::ENTITY, + 'manufacturer', + 'apply_to', + implode(',', $relatedProductTypes) + ); + } + } + + /** + * {@inheritdoc} + */ + public static function getDependencies() + { + return [ + InstallInitialConfigurableAttributes::class, + ]; + } + + /** + * {@inheritdoc}\ + */ + public static function getVersion() + { + return '2.2.1'; + } + + /** + * {@inheritdoc} + */ + public function getAliases() + { + return []; + } +} diff --git a/app/code/Magento/ConfigurableProduct/Test/Mftf/ActionGroup/ConfigurableProductAttributeNameDesignActionGroup.xml b/app/code/Magento/ConfigurableProduct/Test/Mftf/ActionGroup/ConfigurableProductAttributeNameDesignActionGroup.xml new file mode 100644 index 0000000000000..eec1fd6273ee3 --- /dev/null +++ b/app/code/Magento/ConfigurableProduct/Test/Mftf/ActionGroup/ConfigurableProductAttributeNameDesignActionGroup.xml @@ -0,0 +1,166 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> + +<actionGroups xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="../../../../../../../dev/tests/acceptance/vendor/magento/magento2-functional-testing-framework/src/Magento/FunctionalTestingFramework/Test/etc/actionGroupSchema.xsd"> + + <actionGroup name="GotoCatalogProductsPage"> + + <!--Click on Catalog item--> + <click stepKey="clickOnCatalogItem" selector="{{CatalogProductsSection.catalogItem}}"/> + <waitForPageLoad stepKey="waitForCatalogLoad"/> + + <!--Click on Products item--> + <click stepKey="clickOnProductItem" selector="{{CatalogProductsSection.productItem}}"/> + <waitForPageLoad stepKey="waitForCatalogProductPageLoad"/> + + <!--Assert we have gone desired page successfully--> + <seeInCurrentUrl stepKey="assertWeAreOnTheCatalogProductPage" url="{{assertionData.catalogProduct}}"/> + + </actionGroup> + + <actionGroup name="GotoConfigurableProductPage"> + + <!--Click on Add product item--> + <click stepKey="clickOnAddProductItem" selector="{{ConfigurableProductSection.addProductItem}}"/> + + <!--Click on Configuration Product item--> + <click stepKey="clickOnConfigurationProductItem" selector="{{ConfigurableProductSection.configProductItem}}"/> + <waitForPageLoad stepKey="waitForConfigurableProductPageLoad"/> + + <!--Assert we have gone desired page successfully--> + <seeInCurrentUrl stepKey="assertWeAreOnTheConfigurableProductPage" url="{{assertionData.configurableProduct}}"/> + + </actionGroup> + + <actionGroup name="FillAllRequiredFields"> + + <!--Fill In Product Name Fields--> + <fillField stepKey="fillInProductNameFields" selector="{{NewProduct.productName}}" userInput="{{NewProductsData.productName}}"/> + + <!--Fill In Price Fields--> + <fillField stepKey="fillInPriceFields" selector="{{NewProduct.price}}" userInput="{{NewProductsData.price}}"/> + + <!--Fill In Weight Fields--> + <fillField stepKey="fillInWeightFields" selector="{{NewProduct.weight}}" userInput="{{NewProductsData.weight}}"/> + + <!--Click "Create Configurations" button in configurations field--> + <click stepKey="clickOnCreateConfigurationsButton" selector="{{NewProduct.createConfigurationButton}}"/> + <waitForPageLoad stepKey="waitForCreateProductConfigurationsPageLoad"/> + + <!--Click "Create New Attribute" button--> + <click stepKey="clickOnCreateNewAttributeButton" selector="{{NewProduct.createNewAttributeButton}}"/> + <waitForPageLoad stepKey="waitForNewAttributePageLoad"/> + + </actionGroup> + + + <actionGroup name="CreateNewAttribute"> + + <switchToIFrame stepKey="NewAttributePage" selector="{{NewProduct.newAttributeIFrame}}"/> + + <!--Fill In Product Name Fields--> + <fillField stepKey="fillInDefaultLabelField" selector="{{NewProduct.defaultLabel}}" userInput="{{NewProductsData.defaultLabel}}"/> + + <!--Add option 1 to attribute--> + <click selector="{{NewProduct.addOptionButton}}" stepKey="clickAddOption1"/> + <fillField stepKey="fillInAdminFieldRed" selector="{{NewProduct.adminFieldRed}}" userInput="{{NewProductsData.adminFieldRed}}"/> + <fillField stepKey="fillInDefaultStoreViewFieldRed" selector="{{NewProduct.defaultStoreViewFieldRed}}" userInput="{{NewProductsData.defaultStoreViewFieldRed}}"/> + + <!--Add option 2 to attribute--> + <click selector="{{NewProduct.addOptionButton}}" stepKey="clickAddOption2"/> + <fillField stepKey="fillInAdminFieldBlue" selector="{{NewProduct.adminFieldBlue}}" userInput="{{NewProductsData.adminFieldBlue}}"/> + <fillField stepKey="fillInDefaultStoreViewFieldBlue" selector="{{NewProduct.defaultStoreViewFieldBlue}}" userInput="{{NewProductsData.defaultStoreViewFieldBlue}}"/> + + <!--Add option 3 to attribute--> + <click selector="{{NewProduct.addOptionButton}}" stepKey="clickAddOption3"/> + <fillField stepKey="fillInAdminFieldYellow" selector="{{NewProduct.adminFieldYellow}}" userInput="{{NewProductsData.adminFieldYellow}}"/> + <fillField stepKey="fillInDefaultStoreViewFieldYellow" selector="{{NewProduct.defaultStoreViewFieldYellow}}" userInput="{{NewProductsData.defaultStoreViewFieldYellow}}"/> + + <!--Add option 4 to attribute--> + <click selector="{{NewProduct.addOptionButton}}" stepKey="clickAddOption4"/> + <fillField stepKey="fillInAdminFieldGreen" selector="{{NewProduct.adminFieldGreen}}" userInput="{{NewProductsData.adminFieldGreen}}"/> + <fillField stepKey="fillInDefaultStoreViewFieldGreen" selector="{{NewProduct.defaultStoreViewFieldGreen}}" userInput="{{NewProductsData.defaultStoreViewFieldGreen}}"/> + + <!--Add option 5 to attribute--> + <click selector="{{NewProduct.addOptionButton}}" stepKey="clickAddOption5"/> + <fillField stepKey="fillInAdminFieldBlack" selector="{{NewProduct.adminFieldBlack}}" userInput="{{NewProductsData.adminFieldBlack}}"/> + <fillField stepKey="fillInDefaultStoreViewFieldBlack" selector="{{NewProduct.defaultStoreViewFieldBlack}}" userInput="{{NewProductsData.defaultStoreViewFieldBlack}}"/> + + <!--Click Save Attribute button--> + <click selector="{{NewProduct.saveAttributeButton}}" stepKey="clickSaveAttributeButton"/> + <waitForPageLoad stepKey="waitForSavingSettings"/> + + <!--Select created Attribute --> + <click selector="{{ConfigurableProductSection.selectCreatedAttribute}}" stepKey="selectCreatedAttribute"/> + + <!--Click Next button--> + <click selector="{{ConfigurableProductSection.nextButton}}" stepKey="clickNextButton"/> + <waitForPageLoad stepKey="waitForNextPageLoaded"/> + + <!--Select all the options of all the attributes button--> + <click selector="{{CreateProductConfigurations.checkboxRed}}" stepKey="selectCheckboxRed"/> + <click selector="{{CreateProductConfigurations.checkboxBlue}}" stepKey="selectCheckboxBlue"/> + <click selector="{{CreateProductConfigurations.checkboxYellow}}" stepKey="selectCheckboxYellow"/> + <click selector="{{CreateProductConfigurations.checkboxGreen}}" stepKey="selectCheckboxGreen"/> + <click selector="{{CreateProductConfigurations.checkboxBlack}}" stepKey="selectCheckboxBlack"/> + + <!--Click Next button--> + <click selector="{{ConfigurableProductSection.nextButton}}" stepKey="clickNextButton2"/> + <waitForPageLoad stepKey="waitForBulkImagesPricePageLoaded"/> + + <!--Click Next button--> + <click selector="{{ConfigurableProductSection.nextButton}}" stepKey="clickNextButton3"/> + <waitForPageLoad stepKey="waitForSummaryPageLoaded"/> + + <!--Click Generate Configure button--> + <click selector="{{ConfigurableProductSection.generateConfigure}}" stepKey="generateConfigure"/> + <waitForPageLoad stepKey="waitForGenerateConfigure"/> + + <!-- This Error message shouldn't appear: Test will pass when bug will be fixed--> + <dontSee selector="{{CreateProductConfigurations.errorMessage}}" userInput="{{assertionData.errorMessage}}" stepKey="dontSeeError"/> + + <!--Close frame--> + <conditionalClick selector="{{ConfigurableProductSection.closeFrame}}" dependentSelector="{{ConfigurableProductSection.closeFrame}}" visible="1" stepKey="closeFrame"/> + <waitForPageLoad stepKey="waitForClosingFrame"/> + + </actionGroup> + + <actionGroup name="DeleteCreatedAttribute"> + + <!--Click on Stores item--> + <click stepKey="clickOnStoresItem" selector="{{CatalogProductsSection.storesItem}}"/> + + <!--Click on Products item--> + <waitForElementVisible selector="{{CatalogProductsSection.storesProductItem}}" stepKey="waitForCatalogLoad"/> + <click stepKey="clickOnStoresProductItem" selector="{{CatalogProductsSection.storesProductItem}}"/> + <waitForPageLoad stepKey="waitForStoresProductPageLoad"/> + + <!--Click on created Attribute --> + <fillField stepKey="searchProductDefaultLabel" selector="{{CatalogProductsSection.searchDefaultLabelField}}" userInput="{{NewProductsData.defaultLabel}}"/> + <click stepKey="clickSearchButton" selector="{{CatalogProductsSection.searchButton}}"/> + <waitForPageLoad stepKey="waitForCreatedAttributeLoad"/> + <click stepKey="clickOnCreatedAttributeItem" selector="{{CatalogProductsSection.createdAttributeItem}}"/> + <waitForPageLoad stepKey="waitForAttributePropertiesPageLoad"/> + + <!--Click on Delete Attribute item--> + <click stepKey="clickOnDeleteAttributeItem" selector="{{CatalogProductsSection.deleteAttributeItem}}"/> + <waitForPageLoad stepKey="waitForDeletedDialogOpened"/> + + <!--Click on OK button--> + <click stepKey="clickOnOKButton" selector="{{CatalogProductsSection.okButton}}"/> + <waitForPageLoad stepKey="waitFordAttributeDeleted"/> + <see userInput="You deleted the product attribute." stepKey="seeDeletedTheProductAttributeMessage"/> + + <!-- Click Reset Filter button--> + <click stepKey="clickResetFilterButton" selector="{{CatalogProductsSection.resetFilter}}"/> + <waitForPageLoad stepKey="waitForAllFilterReset"/> + + </actionGroup> + +</actionGroups> diff --git a/app/code/Magento/ConfigurableProduct/Test/Mftf/Data/ConfigurableProductAttributeNameDesignData.xml b/app/code/Magento/ConfigurableProduct/Test/Mftf/Data/ConfigurableProductAttributeNameDesignData.xml new file mode 100644 index 0000000000000..73a668fd2fefd --- /dev/null +++ b/app/code/Magento/ConfigurableProduct/Test/Mftf/Data/ConfigurableProductAttributeNameDesignData.xml @@ -0,0 +1,35 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> + +<entities xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="../../../../../../../dev/tests/acceptance/vendor/magento/magento2-functional-testing-framework/src/Magento/FunctionalTestingFramework/DataGenerator/etc/dataProfileSchema.xsd"> + <entity name="NewProductsData" type="user"> + <data key="productName" unique="prefix">Shoes</data> + <data key="price">60</data> + <data key="weight">100</data> + <data key="defaultLabel">design</data> + <data key="adminFieldRed">red</data> + <data key="defaultStoreViewFieldRed">red123</data> + <data key="adminFieldBlue">blue</data> + <data key="defaultStoreViewFieldBlue">blue123</data> + <data key="adminFieldYellow">yellow</data> + <data key="defaultStoreViewFieldYellow">yellow123</data> + <data key="adminFieldGreen">green</data> + <data key="defaultStoreViewFieldGreen">green123</data> + <data key="adminFieldBlack">black</data> + <data key="defaultStoreViewFieldBlack">black123</data> + <data key="attributeCodeField">bug91524</data> + </entity> + + <entity name="assertionData" type="assertion"> + <data key="catalogProduct">product</data> + <data key="configurableProduct">configurable</data> + <data key="errorMessage">element.disabled is not a function</data> + </entity> + +</entities> diff --git a/app/code/Magento/ConfigurableProduct/Test/Mftf/Section/ConfigurableProductAttributeNameDesignSection.xml b/app/code/Magento/ConfigurableProduct/Test/Mftf/Section/ConfigurableProductAttributeNameDesignSection.xml new file mode 100644 index 0000000000000..b3077d9d5d566 --- /dev/null +++ b/app/code/Magento/ConfigurableProduct/Test/Mftf/Section/ConfigurableProductAttributeNameDesignSection.xml @@ -0,0 +1,68 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> + +<sections xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="../../../../../../../dev/tests/acceptance/vendor/magento/magento2-functional-testing-framework/src/Magento/FunctionalTestingFramework/Page/etc/SectionObject.xsd"> + <section name="CatalogProductsSection"> + <element name="catalogItem" type="button" selector="//*[@id='menu-magento-catalog-catalog']/a/span"/> + <element name="productItem" type="button" selector="//*[@data-ui-id='menu-magento-catalog-catalog-products']/a"/> + <element name="storesItem" type="button" selector="//*[@id='menu-magento-backend-stores']/a/span"/> + <element name="searchDefaultLabelField" type="input" selector="//*[@id='attributeGrid_filter_frontend_label']"/> + <element name="searchButton" type="button" selector="//div[@class='admin__filter-actions']//*[contains(text(), 'Search')]"/> + <element name="storesProductItem" type="button" selector="//*[@data-ui-id='menu-magento-catalog-catalog-attributes-attributes']/a"/> + <element name="createdAttributeItem" type="button" selector="//td[contains(@class, 'col-label') and normalize-space()='design']"/> + <element name="deleteAttributeItem" type="button" selector="//*[@id='delete']"/> + <element name="okButton" type="button" selector="//footer[@class='modal-footer']//*[contains(text(),'OK')]"/> + <element name="messageSuccessSavedProduct" type="button" selector="//div[@data-ui-id='messages-message-success']"/> + <element name="resetFilter" type="button" selector="//span[contains(text(), 'Reset Filter')]"/> + </section> + + <section name="ConfigurableProductSection"> + <element name="addProductItem" type="button" selector="//*[@id='add_new_product']/button[2]"/> + <element name="configProductItem" type="button" selector="//*[@id='add_new_product']//*[contains(text(),'Configurable Product')]"/> + <element name="nextButton" type="button" selector="//div[@class='nav-bar-outer-actions']//*[contains(text(),'Next')]"/> + <element name="generateConfigure" type="button" selector="//div[@class='nav-bar-outer-actions']//*[contains(text(),'Generate Products')]"/> + <element name="selectCreatedAttribute" type="button" selector="//*[@class='admin__data-grid-wrap']//td[normalize-space()='design']/preceding-sibling::td"/> + <element name="closeFrame" type="button" selector="//*[@class='modal-header']//*[contains(text(),'Create Product Configurations')]/following-sibling::button"/> + </section> + + <section name="NewProduct"> + <element name="productName" type="input" selector="//input[@name='product[name]']"/> + <element name="price" type="input" selector="//input[@name='product[price]']"/> + <element name="weight" type="input" selector="//input[@name='product[weight]']"/> + <element name="createConfigurationButton" type="button" selector="//*[contains(text(),'Create Configurations')]"/> + <element name="createNewAttributeButton" type="button" selector="//*[contains(text(),'Create New Attribute')]"/> + <element name="newAttributeIFrame" type="iframe" selector="create_new_attribute_container"/> + <element name="defaultLabel" type="input" selector="//*[@id='attribute_label']"/> + <element name="addOptionButton" type="button" selector="//*[@id='add_new_option_button']"/> + <element name="adminFieldRed" type="input" selector="//input[@name='option[value][option_0][0]']"/> + <element name="defaultStoreViewFieldRed" type="input" selector="//input[@name='option[value][option_0][1]']"/> + <element name="adminFieldBlue" type="input" selector="//input[@name='option[value][option_1][0]']"/> + <element name="defaultStoreViewFieldBlue" type="input" selector="//input[@name='option[value][option_1][1]']"/> + <element name="adminFieldYellow" type="input" selector="//input[@name='option[value][option_2][0]']"/> + <element name="defaultStoreViewFieldYellow" type="input" selector="//input[@name='option[value][option_2][1]']"/> + <element name="adminFieldGreen" type="input" selector="//input[@name='option[value][option_3][0]']"/> + <element name="defaultStoreViewFieldGreen" type="input" selector="//input[@name='option[value][option_3][1]']"/> + <element name="adminFieldBlack" type="input" selector="//input[@name='option[value][option_4][0]']"/> + <element name="defaultStoreViewFieldBlack" type="input" selector="//input[@name='option[value][option_4][1]']"/> + <element name="saveAttributeButton" type="button" selector="//*[@id='save']"/> + <element name="advancedAttributeProperties" type="button" selector="//*[@id='advanced_fieldset-wrapper']//*[contains(text(),'Advanced Attribute Properties')]"/> + <element name="attributeCodeField" type="input" selector="//*[@id='attribute_code']"/> + + </section> + + <section name="CreateProductConfigurations"> + <element name="checkboxRed" type="input" selector="//fieldset[@class='admin__fieldset admin__fieldset-options']//*[contains(text(),'red')]/preceding-sibling::input"/> + <element name="checkboxBlue" type="input" selector="//fieldset[@class='admin__fieldset admin__fieldset-options']//*[contains(text(),'blue')]/preceding-sibling::input"/> + <element name="checkboxYellow" type="input" selector="//fieldset[@class='admin__fieldset admin__fieldset-options']//*[contains(text(),'yellow')]/preceding-sibling::input"/> + <element name="checkboxGreen" type="input" selector="//fieldset[@class='admin__fieldset admin__fieldset-options']//*[contains(text(),'green')]/preceding-sibling::input"/> + <element name="checkboxBlack" type="input" selector="//fieldset[@class='admin__fieldset admin__fieldset-options']//*[contains(text(),'black')]/preceding-sibling::input"/> + <element name="errorMessage" type="input" selector="//div[@data-ui-id='messages-message-error']"/> + </section> + +</sections> diff --git a/app/code/Magento/ConfigurableProduct/Test/Mftf/Test/AdminRemoveDefaultImageConfigurableTest.xml b/app/code/Magento/ConfigurableProduct/Test/Mftf/Test/AdminRemoveDefaultImageConfigurableTest.xml index 1c34566322c23..65e1300a4e6b3 100644 --- a/app/code/Magento/ConfigurableProduct/Test/Mftf/Test/AdminRemoveDefaultImageConfigurableTest.xml +++ b/app/code/Magento/ConfigurableProduct/Test/Mftf/Test/AdminRemoveDefaultImageConfigurableTest.xml @@ -109,9 +109,7 @@ <!-- Remove image from product --> <actionGroup ref="removeProductImage" stepKey="removeProductImage"/> - <!-- Skip success message check when saving product because of bug MAGETWO-91177 --> - <!-- actionGroup ref="saveProductForm" stepKey="saveProductFormAfterRemove"/--> - <click selector="{{AdminProductFormActionSection.saveButton}}" stepKey="saveProductFormAfterRemove"/> + <actionGroup ref="saveProductForm" stepKey="saveProductFormAfterRemove"/> <!-- Assert product image not in admin product form --> <actionGroup ref="assertProductImageNotInAdminProductPage" stepKey="assertProductImageNotInAdminProductPage"/> diff --git a/app/code/Magento/ConfigurableProduct/Test/Mftf/Test/ConfigurableProductAttributeNameDesignTest.xml b/app/code/Magento/ConfigurableProduct/Test/Mftf/Test/ConfigurableProductAttributeNameDesignTest.xml new file mode 100644 index 0000000000000..bb7792b9d375e --- /dev/null +++ b/app/code/Magento/ConfigurableProduct/Test/Mftf/Test/ConfigurableProductAttributeNameDesignTest.xml @@ -0,0 +1,41 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> + +<tests xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="../../../../../../../dev/tests/acceptance/vendor/magento/magento2-functional-testing-framework/src/Magento/FunctionalTestingFramework/Test/etc/testSchema.xsd"> + <test name="ConfigurableProductAttributeNameDesignTest"> + <annotations> + <title value="Generation of configurable products with an attribute named 'design'"/> + <features value="Product Customizable Option"/> + <severity value="AVERAGE"/> + <testCaseId value="MAGETWO-93307"/> + <stories value="MAGETWO-91524 : 'element.disabled is not a function' error is thrown when configurable products are generated with an attribute named 'design'"/> + <group value="product"/> + </annotations> + + <before> + <!-- Log in to Dashboard page --> + <actionGroup ref="LoginAsAdmin" stepKey="loginAsAdmin1"/> + </before> + + + <!-- Navigate to Catalog-> Products --> + <actionGroup ref="GotoCatalogProductsPage" stepKey="goToCatalogProductsPage"/> + <!-- Fill the fields on Configurable Product--> + <actionGroup ref="GotoConfigurableProductPage" stepKey="goToConfigurableProductPage"/> + <actionGroup ref="FillAllRequiredFields" stepKey="fillInAllRequiredFields"/> + <!-- Create New Attribute (Default Label= design) --> + <actionGroup ref="CreateNewAttribute" stepKey="createNewAttribute"/> + + <after> + <!-- Delete Created Attribute --> + <actionGroup ref="DeleteCreatedAttribute" stepKey="deleteCreatedAttribute"/> + </after> + + </test> +</tests> diff --git a/app/code/Magento/ConfigurableProduct/Test/Mftf/Test/ConfigurableProductPriceAdditionalStoreViewTest.xml b/app/code/Magento/ConfigurableProduct/Test/Mftf/Test/ConfigurableProductPriceAdditionalStoreViewTest.xml index 9467f82ebae24..676c23f1cfb88 100644 --- a/app/code/Magento/ConfigurableProduct/Test/Mftf/Test/ConfigurableProductPriceAdditionalStoreViewTest.xml +++ b/app/code/Magento/ConfigurableProduct/Test/Mftf/Test/ConfigurableProductPriceAdditionalStoreViewTest.xml @@ -15,7 +15,9 @@ <description value="Configurable product price should not disappear for additional stores on frontEnd if disabled for default store"/> <severity value="CRITICAL"/> <testCaseId value="MAGETWO-92247"/> - <group value="skip"/> + <skip> + <issueId value="MAGETWO-92247"/> + </skip> </annotations> <before> diff --git a/app/code/Magento/ConfigurableProduct/Test/Mftf/Test/StorefrontConfigurableProductWithFileCustomOptionTest.xml b/app/code/Magento/ConfigurableProduct/Test/Mftf/Test/StorefrontConfigurableProductWithFileCustomOptionTest.xml index e7091dbfae215..602e04b138ea3 100644 --- a/app/code/Magento/ConfigurableProduct/Test/Mftf/Test/StorefrontConfigurableProductWithFileCustomOptionTest.xml +++ b/app/code/Magento/ConfigurableProduct/Test/Mftf/Test/StorefrontConfigurableProductWithFileCustomOptionTest.xml @@ -17,6 +17,7 @@ <severity value="CRITICAL"/> <testCaseId value="MAGETWO-93059"/> <group value="ConfigurableProduct"/> + <group value="skip"/><!-- MAGETWO-94170 --> </annotations> <before> diff --git a/app/code/Magento/ConfigurableProduct/Test/Mftf/composer.json b/app/code/Magento/ConfigurableProduct/Test/Mftf/composer.json deleted file mode 100644 index 64ef047693cf0..0000000000000 --- a/app/code/Magento/ConfigurableProduct/Test/Mftf/composer.json +++ /dev/null @@ -1,34 +0,0 @@ -{ - "name": "magento/functional-test-module-configurable-product", - "description": "N/A", - "config": { - "sort-packages": true - }, - "require": { - "php": "~7.1.3||~7.2.0", - "magento/magento2-functional-testing-framework": "2.2.0", - "magento/functional-test-module-backend": "100.0.0-dev", - "magento/functional-test-module-catalog": "100.0.0-dev", - "magento/functional-test-module-catalog-inventory": "100.0.0-dev", - "magento/functional-test-module-checkout": "100.0.0-dev", - "magento/functional-test-module-customer": "100.0.0-dev", - "magento/functional-test-module-eav": "100.0.0-dev", - "magento/functional-test-module-media-storage": "100.0.0-dev", - "magento/functional-test-module-quote": "100.0.0-dev", - "magento/functional-test-module-store": "100.0.0-dev", - "magento/functional-test-module-ui": "100.0.0-dev" - }, - "suggest": { - "magento/functional-test-module-msrp": "100.0.0-dev", - "magento/functional-test-module-webapi": "100.0.0-dev", - "magento/functional-test-module-sales": "100.0.0-dev", - "magento/functional-test-module-product-video": "100.0.0-dev", - "magento/functional-test-module-configurable-sample-data": "100.0.0-dev", - "magento/functional-test-module-product-links-sample-data": "100.0.0-dev" - }, - "type": "magento2-test", - "license": [ - "OSL-3.0", - "AFL-3.0" - ] -} diff --git a/app/code/Magento/ConfigurableProduct/Test/Unit/Block/Product/View/Type/ConfigurableTest.php b/app/code/Magento/ConfigurableProduct/Test/Unit/Block/Product/View/Type/ConfigurableTest.php index b45306d670bff..25d8412c91056 100644 --- a/app/code/Magento/ConfigurableProduct/Test/Unit/Block/Product/View/Type/ConfigurableTest.php +++ b/app/code/Magento/ConfigurableProduct/Test/Unit/Block/Product/View/Type/ConfigurableTest.php @@ -3,6 +3,7 @@ * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ + namespace Magento\ConfigurableProduct\Test\Unit\Block\Product\View\Type; use Magento\Customer\Model\Session; @@ -83,6 +84,9 @@ class ConfigurableTest extends \PHPUnit\Framework\TestCase */ private $variationPricesMock; + /** + * {@inheritDoc} + */ protected function setUp() { $this->mockContextObject(); @@ -174,7 +178,7 @@ protected function setUp() * * @return array */ - public function cacheKeyProvider() : array + public function cacheKeyProvider(): array { return [ 'without_currency_and_customer_group' => [ @@ -313,11 +317,7 @@ public function testGetJsonConfig() $this->localeFormat->expects($this->atLeastOnce())->method('getPriceFormat')->willReturn([]); $this->localeFormat->expects($this->any()) ->method('getNumber') - ->willReturnMap([ - [$amount, $amount], - [$priceQty, $priceQty], - [$percentage, $percentage], - ]); + ->willReturnArgument(0); $this->variationPricesMock->expects($this->once()) ->method('getFormattedPrices') @@ -349,13 +349,13 @@ public function testGetJsonConfig() /** * Retrieve array with expected parameters for method getJsonConfig() * - * @param $productId - * @param $amount - * @param $priceQty - * @param $percentage + * @param int $productId + * @param double $amount + * @param int $priceQty + * @param int $percentage * @return array */ - private function getExpectedArray($productId, $amount, $priceQty, $percentage) + private function getExpectedArray($productId, $amount, $priceQty, $percentage): array { $expectedArray = [ 'attributes' => [], diff --git a/app/code/Magento/ConfigurableProduct/etc/di.xml b/app/code/Magento/ConfigurableProduct/etc/di.xml index bba9cdae0debb..a16feacc4f993 100644 --- a/app/code/Magento/ConfigurableProduct/etc/di.xml +++ b/app/code/Magento/ConfigurableProduct/etc/di.xml @@ -176,6 +176,14 @@ <argument name="batchSizeAdjusters" xsi:type="array"> <item name="configurable" xsi:type="object">Magento\Catalog\Model\ResourceModel\Product\Indexer\Price\CompositeProductBatchSizeAdjuster</item> </argument> + <!-- + real batch size will be smaller. + It depends on amount configurable product variations. + E.g for 100 variations real batch size will be 50000/100=500 + --> + <argument name="batchRowsCount" xsi:type="array"> + <item name="configurable" xsi:type="number">50000</item> + </argument> </arguments> </type> <type name="Magento\ConfigurableProduct\Model\ResourceModel\Product\Indexer\Price\Configurable"> diff --git a/app/code/Magento/ConfigurableProduct/view/adminhtml/web/js/variations/variations.js b/app/code/Magento/ConfigurableProduct/view/adminhtml/web/js/variations/variations.js index 9aa67beb3a51d..e7c8aa6f71745 100644 --- a/app/code/Magento/ConfigurableProduct/view/adminhtml/web/js/variations/variations.js +++ b/app/code/Magento/ConfigurableProduct/view/adminhtml/web/js/variations/variations.js @@ -357,12 +357,12 @@ define([ var element; _.each(this.disabledAttributes, function (attribute) { - registry.get('index = ' + attribute).disabled(false); + registry.get('inputName = ' + 'product[' + attribute + ']').disabled(false); }); this.disabledAttributes = []; _.each(attributes, function (attribute) { - element = registry.get('index = ' + attribute.code); + element = registry.get('inputName = ' + 'product[' + attribute.code + ']'); if (!_.isUndefined(element)) { element.disabled(true); diff --git a/app/code/Magento/ConfigurableProductGraphQl/Test/Mftf/composer.json b/app/code/Magento/ConfigurableProductGraphQl/Test/Mftf/composer.json deleted file mode 100644 index 6d32ef35f6eb2..0000000000000 --- a/app/code/Magento/ConfigurableProductGraphQl/Test/Mftf/composer.json +++ /dev/null @@ -1,19 +0,0 @@ -{ - "name": "magento/functional-test-module-configurable-product-graph-ql", - "description": "N/A", - "config": { - "sort-packages": true - }, - "require": { - "php": "~7.1.3||~7.2.0", - "magento/functional-test-module-catalog": "100.0.0-dev", - "magento/functional-test-module-configurable-product": "100.0.0-dev", - "magento/functional-test-module-catalog-graph-ql": "100.0.0-dev", - "magento/magento2-functional-testing-framework": "2.2.0" - }, - "type": "magento2-test", - "license": [ - "OSL-3.0", - "AFL-3.0" - ] -} diff --git a/app/code/Magento/ConfigurableProductSales/Model/Order/Reorder/OrderedProductAvailabilityChecker.php b/app/code/Magento/ConfigurableProductSales/Model/Order/Reorder/OrderedProductAvailabilityChecker.php index 42d7d91fb90e8..8ef1e24125981 100644 --- a/app/code/Magento/ConfigurableProductSales/Model/Order/Reorder/OrderedProductAvailabilityChecker.php +++ b/app/code/Magento/ConfigurableProductSales/Model/Order/Reorder/OrderedProductAvailabilityChecker.php @@ -5,11 +5,12 @@ */ namespace Magento\ConfigurableProductSales\Model\Order\Reorder; -use Magento\Sales\Model\Order\Reorder\OrderedProductAvailabilityCheckerInterface; -use Magento\Sales\Model\Order\Item; use Magento\Catalog\Api\Data\ProductInterface; +use Magento\Catalog\Api\ProductRepositoryInterface; use Magento\Framework\App\ResourceConnection; use Magento\Framework\EntityManager\MetadataPool; +use Magento\Sales\Model\Order\Item; +use Magento\Sales\Model\Order\Reorder\OrderedProductAvailabilityCheckerInterface; use Magento\Store\Model\Store; /** @@ -27,16 +28,24 @@ class OrderedProductAvailabilityChecker implements OrderedProductAvailabilityChe */ private $metadataPool; + /** + * @var ProductRepositoryInterface + */ + private $productRepository; + /** * @param ResourceConnection $resourceConnection * @param MetadataPool $metadataPool + * @param ProductRepositoryInterface $productRepository */ public function __construct( ResourceConnection $resourceConnection, - MetadataPool $metadataPool + MetadataPool $metadataPool, + ProductRepositoryInterface $productRepository ) { $this->resourceConnection = $resourceConnection; $this->metadataPool = $metadataPool; + $this->productRepository = $productRepository; } /** @@ -48,7 +57,9 @@ public function isAvailable(Item $item) $superAttribute = $buyRequest->getData()['super_attribute'] ?? []; $connection = $this->getConnection(); $select = $connection->select(); - $orderItemParentId = $item->getParentItem()->getProductId(); + $linkField = $this->getMetadata()->getLinkField(); + $parentItem = $this->productRepository->getById($item->getParentItem()->getProductId()); + $orderItemParentId = $parentItem->getData($linkField); $select->from( ['cpe' => $this->resourceConnection->getTableName('catalog_product_entity')], ['cpe.entity_id'] @@ -67,7 +78,7 @@ public function isAvailable(Item $item) ['cpid' . $attributeId => $this->resourceConnection->getTableName('catalog_product_entity_int')], sprintf( 'cpe.%1$s = cpid%2$d.%1$s AND cpid%2$d.attribute_id = %2$d AND cpid%2$d.store_id = %3$d', - $this->getMetadata()->getLinkField(), + $linkField, $attributeId, Store::DEFAULT_STORE_ID ), @@ -77,7 +88,7 @@ public function isAvailable(Item $item) ['cpis' . $attributeId => $this->resourceConnection->getTableName('catalog_product_entity_int')], sprintf( 'cpe.%1$s = cpis%2$d.%1$s AND cpis%2$d.attribute_id = %2$d AND cpis%2$d.store_id = %3$d', - $this->getMetadata()->getLinkField(), + $linkField, $attributeId, $item->getStoreId() ), diff --git a/app/code/Magento/ConfigurableProductSales/Test/Mftf/composer.json b/app/code/Magento/ConfigurableProductSales/Test/Mftf/composer.json deleted file mode 100644 index 416e6a0c45ce1..0000000000000 --- a/app/code/Magento/ConfigurableProductSales/Test/Mftf/composer.json +++ /dev/null @@ -1,22 +0,0 @@ -{ - "name": "magento/functional-test-module-configurable-product-sales", - "description": "N/A", - "config": { - "sort-packages": true - }, - "require": { - "php": "~7.1.3||~7.2.0", - "magento/magento2-functional-testing-framework": "2.2.0", - "magento/functional-test-module-catalog": "100.0.0-dev", - "magento/functional-test-module-sales": "100.0.0-dev", - "magento/functional-test-module-store": "100.0.0-dev" - }, - "suggest": { - "magento/functional-test-module-configurable-product": "100.0.0-dev" - }, - "type": "magento2-test", - "license": [ - "OSL-3.0", - "AFL-3.0" - ] -} diff --git a/app/code/Magento/Contact/Controller/Index/Post.php b/app/code/Magento/Contact/Controller/Index/Post.php index b51e3c9189502..bdc2fee088d9e 100644 --- a/app/code/Magento/Contact/Controller/Index/Post.php +++ b/app/code/Magento/Contact/Controller/Index/Post.php @@ -13,7 +13,6 @@ use Magento\Framework\App\Request\DataPersistorInterface; use Magento\Framework\Controller\Result\Redirect; use Magento\Framework\Exception\LocalizedException; -use Magento\Framework\HTTP\PhpEnvironment\Request; use Psr\Log\LoggerInterface; use Magento\Framework\App\ObjectManager; use Magento\Framework\DataObject; @@ -68,7 +67,7 @@ public function __construct( */ public function execute() { - if (!$this->isPostRequest()) { + if (!$this->getRequest()->isPost()) { return $this->resultRedirectFactory->create()->setPath('*/*/'); } try { @@ -102,16 +101,6 @@ private function sendEmail($post) ); } - /** - * @return bool - */ - private function isPostRequest() - { - /** @var Request $request */ - $request = $this->getRequest(); - return !empty($request->getPostValue()); - } - /** * @return array * @throws \Exception diff --git a/app/code/Magento/Contact/Test/Mftf/composer.json b/app/code/Magento/Contact/Test/Mftf/composer.json deleted file mode 100644 index 824257ae8d0c4..0000000000000 --- a/app/code/Magento/Contact/Test/Mftf/composer.json +++ /dev/null @@ -1,20 +0,0 @@ -{ - "name": "magento/functional-test-module-contact", - "description": "N/A", - "config": { - "sort-packages": true - }, - "require": { - "php": "~7.1.3||~7.2.0", - "magento/magento2-functional-testing-framework": "2.2.0", - "magento/functional-test-module-cms": "100.0.0-dev", - "magento/functional-test-module-config": "100.0.0-dev", - "magento/functional-test-module-customer": "100.0.0-dev", - "magento/functional-test-module-store": "100.0.0-dev" - }, - "type": "magento2-test", - "license": [ - "OSL-3.0", - "AFL-3.0" - ] -} diff --git a/app/code/Magento/Contact/Test/Unit/Controller/Index/PostTest.php b/app/code/Magento/Contact/Test/Unit/Controller/Index/PostTest.php index 4b49373201e51..e5b7f53ecb26b 100644 --- a/app/code/Magento/Contact/Test/Unit/Controller/Index/PostTest.php +++ b/app/code/Magento/Contact/Test/Unit/Controller/Index/PostTest.php @@ -65,6 +65,9 @@ class PostTest extends \PHPUnit\Framework\TestCase */ private $mailMock; + /** + * test setup + */ protected function setUp() { $this->mailMock = $this->getMockBuilder(MailInterface::class)->getMockForAbstractClass(); @@ -78,7 +81,7 @@ protected function setUp() $this->createMock(\Magento\Framework\Message\ManagerInterface::class); $this->requestStub = $this->createPartialMock( \Magento\Framework\App\Request\Http::class, - ['getPostValue', 'getParams', 'getParam'] + ['getPostValue', 'getParams', 'getParam', 'isPost'] ); $this->redirectResultMock = $this->createMock(\Magento\Framework\Controller\Result\Redirect::class); $this->redirectResultMock->method('setPath')->willReturnSelf(); @@ -120,6 +123,9 @@ protected function setUp() ); } + /** + * testExecuteEmptyPost + */ public function testExecuteEmptyPost() { $this->stubRequestPostData([]); @@ -127,6 +133,8 @@ public function testExecuteEmptyPost() } /** + * @param array $postData + * @param bool $exceptionExpected * @dataProvider postDataProvider */ public function testExecutePostValidation($postData, $exceptionExpected) @@ -159,6 +167,9 @@ public function postDataProvider() ]; } + /** + * testExecuteValidPost + */ public function testExecuteValidPost() { $post = ['name' => 'Name', 'comment' => 'Comment', 'email' => 'valid@mail.com', 'hideit' => null]; @@ -177,6 +188,10 @@ public function testExecuteValidPost() */ private function stubRequestPostData($post) { + $this->requestStub + ->expects($this->once()) + ->method('isPost') + ->willReturn(!empty($post)); $this->requestStub->method('getPostValue')->willReturn($post); $this->requestStub->method('getParams')->willReturn($post); $this->requestStub->method('getParam')->willReturnCallback( diff --git a/app/code/Magento/Cookie/Test/Mftf/composer.json b/app/code/Magento/Cookie/Test/Mftf/composer.json deleted file mode 100644 index 54578425c5516..0000000000000 --- a/app/code/Magento/Cookie/Test/Mftf/composer.json +++ /dev/null @@ -1,20 +0,0 @@ -{ - "name": "magento/functional-test-module-cookie", - "description": "N/A", - "config": { - "sort-packages": true - }, - "require": { - "php": "~7.1.3||~7.2.0", - "magento/magento2-functional-testing-framework": "2.2.0", - "magento/functional-test-module-store": "100.0.0-dev" - }, - "suggest": { - "magento/functional-test-module-backend": "100.0.0-dev" - }, - "type": "magento2-test", - "license": [ - "OSL-3.0", - "AFL-3.0" - ] -} diff --git a/app/code/Magento/Cron/Console/Command/CronCommand.php b/app/code/Magento/Cron/Console/Command/CronCommand.php index 78bbb2329f8dc..142a9a397eb5f 100644 --- a/app/code/Magento/Cron/Console/Command/CronCommand.php +++ b/app/code/Magento/Cron/Console/Command/CronCommand.php @@ -10,10 +10,12 @@ use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Output\OutputInterface; use Symfony\Component\Console\Input\InputOption; +use Magento\Framework\App\ObjectManager; use Magento\Framework\App\ObjectManagerFactory; use Magento\Store\Model\Store; use Magento\Store\Model\StoreManager; use Magento\Cron\Observer\ProcessCronQueueObserver; +use Magento\Framework\App\DeploymentConfig; use Magento\Framework\Console\Cli; use Magento\Framework\Shell\ComplexParameter; @@ -35,13 +37,24 @@ class CronCommand extends Command private $objectManagerFactory; /** - * Constructor + * Application deployment configuration * + * @var DeploymentConfig + */ + private $deploymentConfig; + + /** * @param ObjectManagerFactory $objectManagerFactory + * @param DeploymentConfig $deploymentConfig Application deployment configuration */ - public function __construct(ObjectManagerFactory $objectManagerFactory) - { + public function __construct( + ObjectManagerFactory $objectManagerFactory, + DeploymentConfig $deploymentConfig = null + ) { $this->objectManagerFactory = $objectManagerFactory; + $this->deploymentConfig = $deploymentConfig ?: ObjectManager::getInstance()->get( + DeploymentConfig::class + ); parent::__construct(); } @@ -71,10 +84,16 @@ protected function configure() } /** + * Runs cron jobs if cron is not disabled in Magento configurations + * * {@inheritdoc} */ protected function execute(InputInterface $input, OutputInterface $output) { + if (!$this->deploymentConfig->get('cron/enabled', 1)) { + $output->writeln('<info>' . 'Cron is disabled. Jobs were not run.' . '</info>'); + return; + } $omParams = $_SERVER; $omParams[StoreManager::PARAM_RUN_CODE] = 'admin'; $omParams[Store::CUSTOM_ENTRY_POINT_PARAM] = true; diff --git a/app/code/Magento/Cron/Test/Mftf/composer.json b/app/code/Magento/Cron/Test/Mftf/composer.json deleted file mode 100644 index a091882117d12..0000000000000 --- a/app/code/Magento/Cron/Test/Mftf/composer.json +++ /dev/null @@ -1,20 +0,0 @@ -{ - "name": "magento/functional-test-module-cron", - "description": "N/A", - "config": { - "sort-packages": true - }, - "require": { - "php": "~7.1.3||~7.2.0", - "magento/magento2-functional-testing-framework": "2.2.0", - "magento/functional-test-module-store": "100.0.0-dev" - }, - "suggest": { - "magento/functional-test-module-config": "100.0.0-dev" - }, - "type": "magento2-test", - "license": [ - "OSL-3.0", - "AFL-3.0" - ] -} diff --git a/app/code/Magento/Cron/Test/Unit/Console/Command/CronCommandTest.php b/app/code/Magento/Cron/Test/Unit/Console/Command/CronCommandTest.php index 8b3e50d6afb3a..6b1af9323cc93 100644 --- a/app/code/Magento/Cron/Test/Unit/Console/Command/CronCommandTest.php +++ b/app/code/Magento/Cron/Test/Unit/Console/Command/CronCommandTest.php @@ -6,19 +6,74 @@ namespace Magento\Cron\Test\Unit\Console\Command; use Magento\Cron\Console\Command\CronCommand; +use Magento\Framework\App\DeploymentConfig; +use Magento\Framework\App\ObjectManagerFactory; +use PHPUnit_Framework_MockObject_MockObject as MockObject; use Symfony\Component\Console\Tester\CommandTester; class CronCommandTest extends \PHPUnit\Framework\TestCase { + /** + * @var ObjectManagerFactory|MockObject + */ + private $objectManagerFactory; + + /** + * @var DeploymentConfig|MockObject + */ + private $deploymentConfigMock; + + protected function setUp() + { + $this->objectManagerFactory = $this->createMock(ObjectManagerFactory::class); + $this->deploymentConfigMock = $this->createMock(DeploymentConfig::class); + } + + /** + * Test command with disables cron + * + * @return void + */ + public function testExecuteWithDisabledCrons() + { + $this->objectManagerFactory->expects($this->never()) + ->method('create'); + $this->deploymentConfigMock->expects($this->once()) + ->method('get') + ->with('cron/enabled', 1) + ->willReturn(0); + $commandTester = new CommandTester( + new CronCommand($this->objectManagerFactory, $this->deploymentConfigMock) + ); + $commandTester->execute([]); + $expectedMsg = 'Cron is disabled. Jobs were not run.' . PHP_EOL; + $this->assertEquals($expectedMsg, $commandTester->getDisplay()); + } + + /** + * Test command with enabled cron + * + * @return void + */ public function testExecute() { - $objectManagerFactory = $this->createMock(\Magento\Framework\App\ObjectManagerFactory::class); $objectManager = $this->createMock(\Magento\Framework\ObjectManagerInterface::class); $cron = $this->createMock(\Magento\Framework\App\Cron::class); - $objectManager->expects($this->once())->method('create')->willReturn($cron); - $cron->expects($this->once())->method('launch'); - $objectManagerFactory->expects($this->once())->method('create')->willReturn($objectManager); - $commandTester = new CommandTester(new CronCommand($objectManagerFactory)); + $objectManager->expects($this->once()) + ->method('create') + ->willReturn($cron); + $cron->expects($this->once()) + ->method('launch'); + $this->objectManagerFactory->expects($this->once()) + ->method('create') + ->willReturn($objectManager); + $this->deploymentConfigMock->expects($this->once()) + ->method('get') + ->with('cron/enabled', 1) + ->willReturn(1); + $commandTester = new CommandTester( + new CronCommand($this->objectManagerFactory, $this->deploymentConfigMock) + ); $commandTester->execute([]); $expectedMsg = 'Ran jobs by schedule.' . PHP_EOL; $this->assertEquals($expectedMsg, $commandTester->getDisplay()); diff --git a/app/code/Magento/CurrencySymbol/Test/Mftf/composer.json b/app/code/Magento/CurrencySymbol/Test/Mftf/composer.json deleted file mode 100644 index ca14f3ebd0bf9..0000000000000 --- a/app/code/Magento/CurrencySymbol/Test/Mftf/composer.json +++ /dev/null @@ -1,21 +0,0 @@ -{ - "name": "magento/functional-test-module-currency-symbol", - "description": "N/A", - "config": { - "sort-packages": true - }, - "require": { - "php": "~7.1.3||~7.2.0", - "magento/magento2-functional-testing-framework": "2.2.0", - "magento/functional-test-module-backend": "100.0.0-dev", - "magento/functional-test-module-config": "100.0.0-dev", - "magento/functional-test-module-directory": "100.0.0-dev", - "magento/functional-test-module-page-cache": "100.0.0-dev", - "magento/functional-test-module-store": "100.0.0-dev" - }, - "type": "magento2-test", - "license": [ - "OSL-3.0", - "AFL-3.0" - ] -} diff --git a/app/code/Magento/Customer/Block/Account/Navigation.php b/app/code/Magento/Customer/Block/Account/Navigation.php index 64ced9d592e11..705acbcda4c6a 100644 --- a/app/code/Magento/Customer/Block/Account/Navigation.php +++ b/app/code/Magento/Customer/Block/Account/Navigation.php @@ -3,6 +3,7 @@ * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ +declare(strict_types=1); namespace Magento\Customer\Block\Account; @@ -44,12 +45,8 @@ public function getLinks() * @return int * @SuppressWarnings(PHPMD.UnusedPrivateMethod) */ - private function compare(SortLinkInterface $firstLink, SortLinkInterface $secondLink) + private function compare(SortLinkInterface $firstLink, SortLinkInterface $secondLink): int { - if ($firstLink->getSortOrder() == $secondLink->getSortOrder()) { - return 0; - } - - return ($firstLink->getSortOrder() < $secondLink->getSortOrder()) ? 1 : -1; + return $secondLink->getSortOrder() <=> $firstLink->getSortOrder(); } } diff --git a/app/code/Magento/Customer/Block/Adminhtml/Edit/Tab/Cart.php b/app/code/Magento/Customer/Block/Adminhtml/Edit/Tab/Cart.php index 9ee152078d960..db560f7de3ecb 100644 --- a/app/code/Magento/Customer/Block/Adminhtml/Edit/Tab/Cart.php +++ b/app/code/Magento/Customer/Block/Adminhtml/Edit/Tab/Cart.php @@ -82,7 +82,7 @@ protected function _construct() parent::_construct(); $this->setUseAjax(true); $this->_parentTemplate = $this->getTemplate(); - $this->setTemplate('tab/cart.phtml'); + $this->setTemplate('Magento_Customer::tab/cart.phtml'); } /** @@ -220,7 +220,7 @@ public function getGridParentHtml() } /** - * {@inheritdoc} + * @inheritdoc */ public function getRowUrl($row) { diff --git a/app/code/Magento/Customer/Block/Adminhtml/System/Config/Validatevat.php b/app/code/Magento/Customer/Block/Adminhtml/System/Config/Validatevat.php index 83ce7bef26d60..8cbe5c0680bd3 100644 --- a/app/code/Magento/Customer/Block/Adminhtml/System/Config/Validatevat.php +++ b/app/code/Magento/Customer/Block/Adminhtml/System/Config/Validatevat.php @@ -99,7 +99,7 @@ protected function _prepareLayout() { parent::_prepareLayout(); if (!$this->getTemplate()) { - $this->setTemplate('system/config/validatevat.phtml'); + $this->setTemplate('Magento_Customer::system/config/validatevat.phtml'); } return $this; } diff --git a/app/code/Magento/Customer/Block/Widget/Company.php b/app/code/Magento/Customer/Block/Widget/Company.php index 4b928805fa543..8052e396f7dda 100644 --- a/app/code/Magento/Customer/Block/Widget/Company.php +++ b/app/code/Magento/Customer/Block/Widget/Company.php @@ -40,12 +40,12 @@ class Company extends AbstractWidget protected $options; /** - * @param Context $context - * @param AddressHelper $addressHelper + * @param Context $context + * @param AddressHelper $addressHelper * @param CustomerMetadataInterface $customerMetadata - * @param Options $options - * @param AddressMetadataInterface $addressMetadata - * @param array $data + * @param Options $options + * @param AddressMetadataInterface $addressMetadata + * @param array $data */ public function __construct( Context $context, @@ -69,7 +69,7 @@ public function _construct() parent::_construct(); // default template location - $this->setTemplate('widget/company.phtml'); + $this->setTemplate('Magento_Customer::widget/company.phtml'); } /** @@ -95,7 +95,7 @@ public function showCompany() } /** - * {@inheritdoc} + * @inheritdoc */ protected function _getAttribute($attributeCode) { diff --git a/app/code/Magento/Customer/Block/Widget/Dob.php b/app/code/Magento/Customer/Block/Widget/Dob.php index 1a1d5d81bf13d..936563d519823 100644 --- a/app/code/Magento/Customer/Block/Widget/Dob.php +++ b/app/code/Magento/Customer/Block/Widget/Dob.php @@ -66,7 +66,7 @@ public function __construct( public function _construct() { parent::_construct(); - $this->setTemplate('widget/dob.phtml'); + $this->setTemplate('Magento_Customer::widget/dob.phtml'); } /** diff --git a/app/code/Magento/Customer/Block/Widget/Fax.php b/app/code/Magento/Customer/Block/Widget/Fax.php index 2ede51f0eec96..aa1cff632abd3 100644 --- a/app/code/Magento/Customer/Block/Widget/Fax.php +++ b/app/code/Magento/Customer/Block/Widget/Fax.php @@ -40,12 +40,12 @@ class Fax extends AbstractWidget protected $options; /** - * @param Context $context - * @param AddressHelper $addressHelper + * @param Context $context + * @param AddressHelper $addressHelper * @param CustomerMetadataInterface $customerMetadata - * @param Options $options - * @param AddressMetadataInterface $addressMetadata - * @param array $data + * @param Options $options + * @param AddressMetadataInterface $addressMetadata + * @param array $data */ public function __construct( Context $context, @@ -69,7 +69,7 @@ public function _construct() parent::_construct(); // default template location - $this->setTemplate('widget/fax.phtml'); + $this->setTemplate('Magento_Customer::widget/fax.phtml'); } /** @@ -95,7 +95,7 @@ public function showFax() } /** - * {@inheritdoc} + * @inheritdoc */ protected function _getAttribute($attributeCode) { diff --git a/app/code/Magento/Customer/Block/Widget/Gender.php b/app/code/Magento/Customer/Block/Widget/Gender.php index 1d3730e6c6d58..d03c64a54fb94 100644 --- a/app/code/Magento/Customer/Block/Widget/Gender.php +++ b/app/code/Magento/Customer/Block/Widget/Gender.php @@ -59,7 +59,7 @@ public function __construct( public function _construct() { parent::_construct(); - $this->setTemplate('widget/gender.phtml'); + $this->setTemplate('Magento_Customer::widget/gender.phtml'); } /** diff --git a/app/code/Magento/Customer/Block/Widget/Name.php b/app/code/Magento/Customer/Block/Widget/Name.php index 35f3bbefb8f00..d50045f4a4092 100644 --- a/app/code/Magento/Customer/Block/Widget/Name.php +++ b/app/code/Magento/Customer/Block/Widget/Name.php @@ -62,7 +62,7 @@ public function _construct() parent::_construct(); // default template location - $this->setTemplate('widget/name.phtml'); + $this->setTemplate('Magento_Customer::widget/name.phtml'); } /** @@ -201,7 +201,7 @@ public function getContainerClassName() } /** - * {@inheritdoc} + * @inheritdoc */ protected function _getAttribute($attributeCode) { diff --git a/app/code/Magento/Customer/Block/Widget/Taxvat.php b/app/code/Magento/Customer/Block/Widget/Taxvat.php index e695681ad4a6c..e5c9c01dc3ac5 100644 --- a/app/code/Magento/Customer/Block/Widget/Taxvat.php +++ b/app/code/Magento/Customer/Block/Widget/Taxvat.php @@ -41,7 +41,7 @@ public function __construct( public function _construct() { parent::_construct(); - $this->setTemplate('widget/taxvat.phtml'); + $this->setTemplate('Magento_Customer::widget/taxvat.phtml'); } /** diff --git a/app/code/Magento/Customer/Block/Widget/Telephone.php b/app/code/Magento/Customer/Block/Widget/Telephone.php index b0d155eff6db5..b67e92ed7d29f 100644 --- a/app/code/Magento/Customer/Block/Widget/Telephone.php +++ b/app/code/Magento/Customer/Block/Widget/Telephone.php @@ -40,12 +40,12 @@ class Telephone extends AbstractWidget protected $options; /** - * @param Context $context - * @param AddressHelper $addressHelper + * @param Context $context + * @param AddressHelper $addressHelper * @param CustomerMetadataInterface $customerMetadata - * @param Options $options - * @param AddressMetadataInterface $addressMetadata - * @param array $data + * @param Options $options + * @param AddressMetadataInterface $addressMetadata + * @param array $data */ public function __construct( Context $context, @@ -69,7 +69,7 @@ public function _construct() parent::_construct(); // default template location - $this->setTemplate('widget/telephone.phtml'); + $this->setTemplate('Magento_Customer::widget/telephone.phtml'); } /** @@ -95,7 +95,7 @@ public function showTelephone() } /** - * {@inheritdoc} + * @inheritdoc */ protected function _getAttribute($attributeCode) { diff --git a/app/code/Magento/Customer/Controller/Address/FormPost.php b/app/code/Magento/Customer/Controller/Address/FormPost.php index 21334f51b1752..60e1f6eb172f5 100644 --- a/app/code/Magento/Customer/Controller/Address/FormPost.php +++ b/app/code/Magento/Customer/Controller/Address/FormPost.php @@ -3,6 +3,7 @@ * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ + namespace Magento\Customer\Controller\Address; use Magento\Customer\Api\AddressRepositoryInterface; @@ -197,17 +198,17 @@ public function execute() try { $address = $this->_extractAddress(); $this->_addressRepository->save($address); - $this->messageManager->addSuccess(__('You saved the address.')); + $this->messageManager->addSuccessMessage(__('You saved the address.')); $url = $this->_buildUrl('*/*/index', ['_secure' => true]); return $this->resultRedirectFactory->create()->setUrl($this->_redirect->success($url)); } catch (InputException $e) { - $this->messageManager->addError($e->getMessage()); + $this->messageManager->addErrorMessage($e->getMessage()); foreach ($e->getErrors() as $error) { - $this->messageManager->addError($error->getMessage()); + $this->messageManager->addErrorMessage($error->getMessage()); } } catch (\Exception $e) { $redirectUrl = $this->_buildUrl('*/*/index'); - $this->messageManager->addException($e, __('We can\'t save the address.')); + $this->messageManager->addExceptionMessage($e, __('We can\'t save the address.')); } $url = $redirectUrl; diff --git a/app/code/Magento/Customer/Model/AccountManagement.php b/app/code/Magento/Customer/Model/AccountManagement.php index 63eb1efa64be6..3aba7d1da89fb 100644 --- a/app/code/Magento/Customer/Model/AccountManagement.php +++ b/app/code/Magento/Customer/Model/AccountManagement.php @@ -442,7 +442,7 @@ private function getAuthentication() } /** - * {@inheritdoc} + * @inheritdoc */ public function resendConfirmation($email, $websiteId = null, $redirectUrl = '') { @@ -465,7 +465,7 @@ public function resendConfirmation($email, $websiteId = null, $redirectUrl = '') } /** - * {@inheritdoc} + * @inheritdoc */ public function activate($email, $confirmationKey) { @@ -474,7 +474,7 @@ public function activate($email, $confirmationKey) } /** - * {@inheritdoc} + * @inheritdoc */ public function activateById($customerId, $confirmationKey) { @@ -514,7 +514,7 @@ private function activateCustomer($customer, $confirmationKey) } /** - * {@inheritdoc} + * @inheritdoc */ public function authenticate($username, $password) { @@ -549,7 +549,7 @@ public function authenticate($username, $password) } /** - * {@inheritdoc} + * @inheritdoc */ public function validateResetPasswordLinkToken($customerId, $resetPasswordLinkToken) { @@ -558,7 +558,7 @@ public function validateResetPasswordLinkToken($customerId, $resetPasswordLinkTo } /** - * {@inheritdoc} + * @inheritdoc */ public function initiatePasswordReset($email, $template, $websiteId = null) { @@ -611,7 +611,7 @@ private function handleUnknownTemplate($template) } /** - * {@inheritdoc} + * @inheritdoc */ public function resetPassword($email, $resetToken, $newPassword) { @@ -720,7 +720,7 @@ protected function getMinPasswordLength() } /** - * {@inheritdoc} + * @inheritdoc */ public function getConfirmationStatus($customerId) { @@ -736,7 +736,7 @@ public function getConfirmationStatus($customerId) } /** - * {@inheritdoc} + * @inheritdoc */ public function createAccount(CustomerInterface $customer, $password = null, $redirectUrl = '') { @@ -758,7 +758,7 @@ public function createAccount(CustomerInterface $customer, $password = null, $re } /** - * {@inheritdoc} + * @inheritdoc * @SuppressWarnings(PHPMD.CyclomaticComplexity) * @SuppressWarnings(PHPMD.NPathComplexity) */ @@ -794,6 +794,11 @@ public function createAccountWithPasswordHash(CustomerInterface $customer, $hash // Update 'created_in' value with actual store name if ($customer->getId() === null) { + $websiteId = $customer->getWebsiteId(); + if ($websiteId && !$this->isCustomerInStore($websiteId, $customer->getStoreId())) { + throw new LocalizedException(__('The store view is not in the associated website.')); + } + $storeName = $this->storeManager->getStore($customer->getStoreId())->getName(); $customer->setCreatedIn($storeName); } @@ -836,7 +841,7 @@ public function createAccountWithPasswordHash(CustomerInterface $customer, $hash } /** - * {@inheritdoc} + * @inheritdoc */ public function getDefaultBillingAddress($customerId) { @@ -845,7 +850,7 @@ public function getDefaultBillingAddress($customerId) } /** - * {@inheritdoc} + * @inheritdoc */ public function getDefaultShippingAddress($customerId) { @@ -880,7 +885,7 @@ protected function sendEmailConfirmation(CustomerInterface $customer, $redirectU } /** - * {@inheritdoc} + * @inheritdoc */ public function changePassword($email, $currentPassword, $newPassword) { @@ -893,7 +898,7 @@ public function changePassword($email, $currentPassword, $newPassword) } /** - * {@inheritdoc} + * @inheritdoc */ public function changePasswordById($customerId, $currentPassword, $newPassword) { @@ -961,7 +966,7 @@ private function getEavValidator() } /** - * {@inheritdoc} + * @inheritdoc */ public function validate(CustomerInterface $customer) { @@ -986,7 +991,7 @@ public function validate(CustomerInterface $customer) } /** - * {@inheritdoc} + * @inheritdoc */ public function isEmailAvailable($customerEmail, $websiteId = null) { @@ -1002,7 +1007,7 @@ public function isEmailAvailable($customerEmail, $websiteId = null) } /** - * {@inheritDoc} + * @inheritDoc */ public function isCustomerInStore($customerWebsiteId, $storeId) { diff --git a/app/code/Magento/Customer/Model/Indexer/CustomerGroupDimensionProvider.php b/app/code/Magento/Customer/Model/Indexer/CustomerGroupDimensionProvider.php new file mode 100644 index 0000000000000..d4e0c5cce3401 --- /dev/null +++ b/app/code/Magento/Customer/Model/Indexer/CustomerGroupDimensionProvider.php @@ -0,0 +1,62 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +declare(strict_types=1); + +namespace Magento\Customer\Model\Indexer; + +use Magento\Customer\Model\ResourceModel\Group\CollectionFactory as CustomerGroupCollectionFactory; +use Magento\Framework\Indexer\DimensionFactory; +use Magento\Framework\Indexer\DimensionProviderInterface; + +class CustomerGroupDimensionProvider implements DimensionProviderInterface +{ + /** + * Name for customer group dimension for multidimensional indexer + * 'cg' - stands for 'customer_group' + */ + const DIMENSION_NAME = 'cg'; + + /** + * @var CustomerGroupCollectionFactory + */ + private $collectionFactory; + + /** + * @var \SplFixedArray + */ + private $customerGroupsDataIterator; + + /** + * @var DimensionFactory + */ + private $dimensionFactory; + + public function __construct(CustomerGroupCollectionFactory $collectionFactory, DimensionFactory $dimensionFactory) + { + $this->dimensionFactory = $dimensionFactory; + $this->collectionFactory = $collectionFactory; + } + + public function getIterator(): \Traversable + { + foreach ($this->getCustomerGroups() as $customerGroup) { + yield $this->dimensionFactory->create(self::DIMENSION_NAME, (string)$customerGroup); + } + } + + /** + * @return array + */ + private function getCustomerGroups(): array + { + if ($this->customerGroupsDataIterator === null) { + $customerGroups = $this->collectionFactory->create()->getAllIds(); + $this->customerGroupsDataIterator = is_array($customerGroups) ? $customerGroups : []; + } + + return $this->customerGroupsDataIterator; + } +} diff --git a/app/code/Magento/Customer/Model/Metadata/AttributeMetadataHydrator.php b/app/code/Magento/Customer/Model/Metadata/AttributeMetadataHydrator.php index 190a3a38e0bf0..f61f064e3f97e 100644 --- a/app/code/Magento/Customer/Model/Metadata/AttributeMetadataHydrator.php +++ b/app/code/Magento/Customer/Model/Metadata/AttributeMetadataHydrator.php @@ -11,6 +11,7 @@ use Magento\Customer\Api\Data\OptionInterfaceFactory; use Magento\Customer\Api\Data\ValidationRuleInterface; use Magento\Customer\Api\Data\ValidationRuleInterfaceFactory; +use Magento\Customer\Model\Data\AttributeMetadata; use Magento\Framework\Reflection\DataObjectProcessor; /** @@ -120,7 +121,7 @@ public function extract($attributeMetadata) { return $this->dataObjectProcessor->buildOutputDataArray( $attributeMetadata, - AttributeMetadataInterface::class + AttributeMetadata::class ); } } diff --git a/app/code/Magento/Customer/Model/Metadata/Form/Text.php b/app/code/Magento/Customer/Model/Metadata/Form/Text.php index 9ef6df0a6d36e..c8b9a1e46a127 100644 --- a/app/code/Magento/Customer/Model/Metadata/Form/Text.php +++ b/app/code/Magento/Customer/Model/Metadata/Form/Text.php @@ -5,8 +5,10 @@ * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ + namespace Magento\Customer\Model\Metadata\Form; +use Magento\Customer\Api\Data\AttributeMetadataInterface; use Magento\Framework\Api\ArrayObjectSearch; class Text extends AbstractData @@ -19,7 +21,7 @@ class Text extends AbstractData /** * @param \Magento\Framework\Stdlib\DateTime\TimezoneInterface $localeDate * @param \Psr\Log\LoggerInterface $logger - * @param \Magento\Customer\Api\Data\AttributeMetadataInterface $attribute + * @param AttributeMetadataInterface $attribute * @param \Magento\Framework\Locale\ResolverInterface $localeResolver * @param string $value * @param string $entityTypeCode @@ -29,7 +31,7 @@ class Text extends AbstractData public function __construct( \Magento\Framework\Stdlib\DateTime\TimezoneInterface $localeDate, \Psr\Log\LoggerInterface $logger, - \Magento\Customer\Api\Data\AttributeMetadataInterface $attribute, + AttributeMetadataInterface $attribute, \Magento\Framework\Locale\ResolverInterface $localeResolver, $value, $entityTypeCode, @@ -41,7 +43,7 @@ public function __construct( } /** - * {@inheritdoc} + * @inheritdoc */ public function extractValue(\Magento\Framework\App\RequestInterface $request) { @@ -49,7 +51,7 @@ public function extractValue(\Magento\Framework\App\RequestInterface $request) } /** - * {@inheritdoc} + * @inheritdoc * @SuppressWarnings(PHPMD.CyclomaticComplexity) * @SuppressWarnings(PHPMD.NPathComplexity) */ @@ -72,26 +74,7 @@ public function validateValue($value) return true; } - // validate length - $length = $this->_string->strlen(trim($value)); - - $validateRules = $attribute->getValidationRules(); - - $minTextLength = ArrayObjectSearch::getArrayElementByName( - $validateRules, - 'min_text_length' - ); - if ($minTextLength !== null && $length < $minTextLength) { - $errors[] = __('"%1" length must be equal or greater than %2 characters.', $label, $minTextLength); - } - - $maxTextLength = ArrayObjectSearch::getArrayElementByName( - $validateRules, - 'max_text_length' - ); - if ($maxTextLength !== null && $length > $maxTextLength) { - $errors[] = __('"%1" length must be equal or less than %2 characters.', $label, $maxTextLength); - } + $errors = $this->validateLength($value, $attribute, $errors); $result = $this->_validateInputRule($value); if ($result !== true) { @@ -105,7 +88,7 @@ public function validateValue($value) } /** - * {@inheritdoc} + * @inheritdoc */ public function compactValue($value) { @@ -113,7 +96,7 @@ public function compactValue($value) } /** - * {@inheritdoc} + * @inheritdoc */ public function restoreValue($value) { @@ -121,10 +104,48 @@ public function restoreValue($value) } /** - * {@inheritdoc} + * @inheritdoc */ public function outputValue($format = \Magento\Customer\Model\Metadata\ElementFactory::OUTPUT_FORMAT_TEXT) { return $this->_applyOutputFilter($this->_value); } + + /** + * Length validation + * + * @param mixed $value + * @param AttributeMetadataInterface $attribute + * @param array $errors + * @return array + */ + private function validateLength($value, AttributeMetadataInterface $attribute, array $errors): array + { + // validate length + $label = __($attribute->getStoreLabel()); + + $length = $this->_string->strlen(trim($value)); + + $validateRules = $attribute->getValidationRules(); + + if (!empty(ArrayObjectSearch::getArrayElementByName($validateRules, 'input_validation'))) { + $minTextLength = ArrayObjectSearch::getArrayElementByName( + $validateRules, + 'min_text_length' + ); + if ($minTextLength !== null && $length < $minTextLength) { + $errors[] = __('"%1" length must be equal or greater than %2 characters.', $label, $minTextLength); + } + + $maxTextLength = ArrayObjectSearch::getArrayElementByName( + $validateRules, + 'max_text_length' + ); + if ($maxTextLength !== null && $length > $maxTextLength) { + $errors[] = __('"%1" length must be equal or less than %2 characters.', $label, $maxTextLength); + } + } + + return $errors; + } } diff --git a/app/code/Magento/Customer/Model/Session.php b/app/code/Magento/Customer/Model/Session.php index 680e68b5c4c0f..5900fed218edf 100644 --- a/app/code/Magento/Customer/Model/Session.php +++ b/app/code/Magento/Customer/Model/Session.php @@ -487,7 +487,7 @@ public function authenticate($loginUrl = null) $this->response->setRedirect($loginUrl); } else { $arguments = $this->_customerUrl->getLoginUrlParams(); - if ($this->_session->getCookieShouldBeReceived() && $this->_createUrl()->getUseSession()) { + if ($this->_createUrl()->getUseSession()) { $arguments += [ '_query' => [ $this->sidResolver->getSessionIdQueryParam($this->_session) => $this->_session->getSessionId(), diff --git a/app/code/Magento/Customer/Test/Mftf/Data/AddressData.xml b/app/code/Magento/Customer/Test/Mftf/Data/AddressData.xml index d26ecac28113e..d84dcef5b9229 100644 --- a/app/code/Magento/Customer/Test/Mftf/Data/AddressData.xml +++ b/app/code/Magento/Customer/Test/Mftf/Data/AddressData.xml @@ -92,5 +92,18 @@ <data key="city">London</data> <data key="country_id">GB</data> <data key="telephone">512-345-6789</data> + <data key="province">JS</data> + </entity> + <entity name="UK_Not_Default_Address" type="address"> + <data key="firstname">Jane</data> + <data key="lastname">Doe</data> + <data key="company">Magento</data> + <array key="street"> + <item>172, Westminster Bridge Rd</item> + </array> + <data key="city">London</data> + <data key="postcode">SE1 7RW</data> + <data key="country_id">GB</data> + <data key="telephone">444-44-444-44</data> </entity> </entities> diff --git a/app/code/Magento/Customer/Test/Mftf/Data/CustomerData.xml b/app/code/Magento/Customer/Test/Mftf/Data/CustomerData.xml index 1827824ba4b92..1f6a01ea815d1 100644 --- a/app/code/Magento/Customer/Test/Mftf/Data/CustomerData.xml +++ b/app/code/Magento/Customer/Test/Mftf/Data/CustomerData.xml @@ -45,6 +45,20 @@ <data key="website_id">0</data> <requiredEntity type="address">US_Address_TX</requiredEntity> </entity> + <entity name="Simple_US_Customer_Multiple_Addresses" type="customer"> + <data key="group_id">0</data> + <data key="default_billing">true</data> + <data key="default_shipping">true</data> + <data key="email" unique="prefix">John.Doe@example.com</data> + <data key="firstname">John</data> + <data key="lastname">Doe</data> + <data key="fullname">John Doe</data> + <data key="password">pwdTest123!</data> + <data key="store_id">0</data> + <data key="website_id">0</data> + <requiredEntity type="address">US_Address_NY</requiredEntity> + <requiredEntity type="address">UK_Not_Default_Address</requiredEntity> + </entity> <entity name="Simple_US_Customer_NY" type="customer"> <data key="group_id">0</data> <data key="default_billing">true</data> diff --git a/app/code/Magento/Customer/Test/Mftf/composer.json b/app/code/Magento/Customer/Test/Mftf/composer.json deleted file mode 100644 index 4bf83a4bf800a..0000000000000 --- a/app/code/Magento/Customer/Test/Mftf/composer.json +++ /dev/null @@ -1,39 +0,0 @@ -{ - "name": "magento/functional-test-module-customer", - "description": "N/A", - "config": { - "sort-packages": true - }, - "require": { - "php": "~7.1.3||~7.2.0", - "magento/magento2-functional-testing-framework": "2.2.0", - "magento/functional-test-module-authorization": "100.0.0-dev", - "magento/functional-test-module-backend": "100.0.0-dev", - "magento/functional-test-module-catalog": "100.0.0-dev", - "magento/functional-test-module-checkout": "100.0.0-dev", - "magento/functional-test-module-config": "100.0.0-dev", - "magento/functional-test-module-directory": "100.0.0-dev", - "magento/functional-test-module-eav": "100.0.0-dev", - "magento/functional-test-module-integration": "100.0.0-dev", - "magento/functional-test-module-media-storage": "100.0.0-dev", - "magento/functional-test-module-newsletter": "100.0.0-dev", - "magento/functional-test-module-page-cache": "100.0.0-dev", - "magento/functional-test-module-quote": "100.0.0-dev", - "magento/functional-test-module-review": "100.0.0-dev", - "magento/functional-test-module-sales": "100.0.0-dev", - "magento/functional-test-module-store": "100.0.0-dev", - "magento/functional-test-module-tax": "100.0.0-dev", - "magento/functional-test-module-theme": "100.0.0-dev", - "magento/functional-test-module-ui": "100.0.0-dev", - "magento/functional-test-module-wishlist": "100.0.0-dev" - }, - "suggest": { - "magento/functional-test-module-cookie": "100.0.0-dev", - "magento/functional-test-module-customer-sample-data": "100.0.0-dev" - }, - "type": "magento2-test", - "license": [ - "OSL-3.0", - "AFL-3.0" - ] -} diff --git a/app/code/Magento/Customer/Test/Unit/Controller/Address/FormPostTest.php b/app/code/Magento/Customer/Test/Unit/Controller/Address/FormPostTest.php index 4ad1b5cbc96bd..c2a795fc95016 100644 --- a/app/code/Magento/Customer/Test/Unit/Controller/Address/FormPostTest.php +++ b/app/code/Magento/Customer/Test/Unit/Controller/Address/FormPostTest.php @@ -3,6 +3,7 @@ * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ + namespace Magento\Customer\Test\Unit\Controller\Address; use Magento\Customer\Api\AddressRepositoryInterface; @@ -162,6 +163,9 @@ class FormPostTest extends \PHPUnit\Framework\TestCase */ private $customerAddressMapper; + /** + * {@inheritDoc} + */ protected function setUp() { $this->prepareContext(); @@ -230,7 +234,10 @@ protected function setUp() ); } - protected function prepareContext() + /** + * Prepares context + */ + protected function prepareContext(): void { $this->context = $this->getMockBuilder(\Magento\Framework\App\Action\Context::class) ->disableOriginalConstructor() @@ -284,7 +291,10 @@ protected function prepareContext() ->willReturn($this->messageManager); } - protected function prepareAddress() + /** + * Prepare address + */ + protected function prepareAddress(): void { $this->addressRepository = $this->getMockBuilder(\Magento\Customer\Api\AddressRepositoryInterface::class) ->getMockForAbstractClass(); @@ -303,7 +313,10 @@ protected function prepareAddress() ->willReturn($this->addressData); } - protected function prepareRegion() + /** + * Prepare region + */ + protected function prepareRegion(): void { $this->region = $this->getMockBuilder(\Magento\Directory\Model\Region::class) ->disableOriginalConstructor() @@ -335,7 +348,10 @@ protected function prepareRegion() ->willReturn($this->regionData); } - protected function prepareForm() + /** + * Prepare form + */ + protected function prepareForm(): void { $this->form = $this->getMockBuilder(\Magento\Customer\Model\Metadata\Form::class) ->disableOriginalConstructor() @@ -346,7 +362,10 @@ protected function prepareForm() ->getMock(); } - public function testExecuteNoFormKey() + /** + * Test form without formKey + */ + public function testExecuteNoFormKey(): void { $this->formKeyValidator->expects($this->once()) ->method('validate') @@ -361,7 +380,10 @@ public function testExecuteNoFormKey() $this->assertEquals($this->resultRedirect, $this->model->execute()); } - public function testExecuteNoPostData() + /** + * Test executing without post data + */ + public function testExecuteNoPostData(): void { $postValue = 'post_value'; $url = 'url'; @@ -409,10 +431,11 @@ public function testExecuteNoPostData() } /** + * Tests executing + * * @param int $addressId * @param int $countryId * @param int $customerId - * @param bool $isRegionRequired * @param int $regionId * @param string $region * @param string $regionCode @@ -433,7 +456,7 @@ public function testExecute( $newRegionId, $newRegion, $newRegionCode - ) { + ): void { $existingAddressData = [ 'country_id' => $countryId, 'region_id' => $regionId, @@ -517,7 +540,8 @@ public function testExecute( ->willReturnMap([ [ $this->regionData, - $regionData, \Magento\Customer\Api\Data\RegionInterface::class, + $regionData, + \Magento\Customer\Api\Data\RegionInterface::class, $this->dataObjectHelper, ], [ @@ -549,7 +573,7 @@ public function testExecute( ->willReturnSelf(); $this->messageManager->expects($this->once()) - ->method('addSuccess') + ->method('addSuccessMessage') ->with(__('You saved the address.')) ->willReturnSelf(); @@ -581,7 +605,7 @@ public function testExecute( /** * @return array */ - public function dataProviderTestExecute() + public function dataProviderTestExecute(): array { return [ [1, 1, 1, null, '', null, '', null, ''], @@ -612,7 +636,10 @@ public function dataProviderTestExecute() ]; } - public function testExecuteInputException() + /** + * Tests input exception + */ + public function testExecuteInputException(): void { $addressId = 1; $postValue = 'post_value'; @@ -640,7 +667,7 @@ public function testExecuteInputException() ->willThrowException(new InputException(__('InputException'))); $this->messageManager->expects($this->once()) - ->method('addError') + ->method('addErrorMessage') ->with('InputException') ->willReturnSelf(); @@ -674,7 +701,10 @@ public function testExecuteInputException() $this->assertEquals($this->resultRedirect, $this->model->execute()); } - public function testExecuteException() + /** + * Tests exception + */ + public function testExecuteException(): void { $addressId = 1; $postValue = 'post_value'; @@ -703,7 +733,7 @@ public function testExecuteException() ->willThrowException($exception); $this->messageManager->expects($this->once()) - ->method('addException') + ->method('addExceptionMessage') ->with($exception, __('We can\'t save the address.')) ->willReturnSelf(); diff --git a/app/code/Magento/Customer/Test/Unit/Model/AccountManagementTest.php b/app/code/Magento/Customer/Test/Unit/Model/AccountManagementTest.php index 9e3a16a307923..86e7683545fa2 100644 --- a/app/code/Magento/Customer/Test/Unit/Model/AccountManagementTest.php +++ b/app/code/Magento/Customer/Test/Unit/Model/AccountManagementTest.php @@ -318,7 +318,7 @@ public function testCreateAccountWithPasswordHashWithCustomerWithoutStoreId() ->method('getId') ->willReturn($defaultStoreId); $website = $this->getMockBuilder(\Magento\Store\Model\Website::class)->disableOriginalConstructor()->getMock(); - $website->expects($this->once()) + $website->expects($this->atLeastOnce()) ->method('getStoreIds') ->willReturn([1, 2, 3]); $website->expects($this->once()) @@ -354,7 +354,7 @@ public function testCreateAccountWithPasswordHashWithCustomerWithoutStoreId() ->with($customerEmail) ->willReturn($customer); $this->share - ->expects($this->once()) + ->expects($this->atLeastOnce()) ->method('isWebsiteScope') ->willReturn(true); $this->storeManager @@ -545,6 +545,7 @@ public function testCreateAccountWithPasswordHashWithNewCustomerAndLocalizedExce { $storeId = 1; $storeName = 'store_name'; + $websiteId = 1; $hash = '4nj54lkj5jfi03j49f8bgujfgsd'; $customerMock = $this->getMockBuilder(\Magento\Customer\Api\Data\CustomerInterface::class) @@ -556,6 +557,9 @@ public function testCreateAccountWithPasswordHashWithNewCustomerAndLocalizedExce $customerMock->expects($this->atLeastOnce()) ->method('getStoreId') ->willReturn($storeId); + $customerMock->expects($this->atLeastOnce()) + ->method('getWebsiteId') + ->willReturn($websiteId); $customerMock->expects($this->once()) ->method('setCreatedIn') ->with($storeName) @@ -567,6 +571,19 @@ public function testCreateAccountWithPasswordHashWithNewCustomerAndLocalizedExce ->method('setAddresses') ->with(null) ->willReturnSelf(); + $this->share + ->expects($this->once()) + ->method('isWebsiteScope') + ->willReturn(true); + $website = $this->getMockBuilder(\Magento\Store\Model\Website::class)->disableOriginalConstructor()->getMock(); + $website->expects($this->once()) + ->method('getStoreIds') + ->willReturn([1, 2, 3]); + $this->storeManager + ->expects($this->atLeastOnce()) + ->method('getWebsite') + ->with($websiteId) + ->willReturn($website); $storeMock = $this->getMockBuilder(\Magento\Store\Model\Store::class) ->disableOriginalConstructor() @@ -576,7 +593,7 @@ public function testCreateAccountWithPasswordHashWithNewCustomerAndLocalizedExce ->method('getName') ->willReturn($storeName); - $this->storeManager->expects($this->exactly(2)) + $this->storeManager->expects($this->exactly(1)) ->method('getStore') ->with($storeId) ->willReturn($storeMock); @@ -772,6 +789,9 @@ public function testCreateAccountWithPasswordInputException( $this->accountManagement->createAccount($customer, $password); } + /** + * @throws \Magento\Framework\Exception\LocalizedException + */ public function testCreateAccountInputExceptionExtraLongPassword() { $password = '257*chars*************************************************************************************' @@ -1129,11 +1149,11 @@ protected function prepareInitiatePasswordReset($email, $templateIdentifier, $se } /** - * @param $email - * @param $templateIdentifier - * @param $sender - * @param $storeId - * @param $customerName + * @param string $email + * @param int $templateIdentifier + * @param string $sender + * @param int $storeId + * @param string $customerName */ protected function prepareEmailSend($email, $templateIdentifier, $sender, $storeId, $customerName) { @@ -1168,6 +1188,9 @@ protected function prepareEmailSend($email, $templateIdentifier, $sender, $store ->method('sendMessage'); } + /** + * @throws \Magento\Framework\Exception\LocalizedException + */ public function testInitiatePasswordResetEmailReminder() { $customerId = 1; @@ -1191,6 +1214,9 @@ public function testInitiatePasswordResetEmailReminder() $this->assertTrue($this->accountManagement->initiatePasswordReset($email, $template)); } + /** + * @throws \Magento\Framework\Exception\LocalizedException + */ public function testInitiatePasswordResetEmailReset() { $storeId = 1; @@ -1213,6 +1239,9 @@ public function testInitiatePasswordResetEmailReset() $this->assertTrue($this->accountManagement->initiatePasswordReset($email, $template)); } + /** + * @throws \Magento\Framework\Exception\LocalizedException + */ public function testInitiatePasswordResetNoTemplate() { $storeId = 1; @@ -1492,6 +1521,9 @@ public function testChangePassword() $this->assertTrue($this->accountManagement->changePassword($email, $currentPassword, $newPassword)); } + /** + * @throws \Magento\Framework\Exception\LocalizedException + */ public function testResetPassword() { $customerEmail = 'customer@example.com'; @@ -1720,7 +1752,7 @@ public function testCreateAccountWithPasswordHashForGuest() $customerMock->expects($this->exactly(3)) ->method('getStoreId') ->willReturn(null); - $customerMock->expects($this->exactly(2)) + $customerMock->expects($this->exactly(3)) ->method('getWebsiteId') ->willReturn(null); $customerMock->expects($this->once()) @@ -1752,6 +1784,9 @@ public function testCreateAccountWithPasswordHashForGuest() $this->accountManagement->createAccountWithPasswordHash($customerMock, $hash); } + /** + * @SuppressWarnings(PHPMD.ExcessiveMethodLength) + */ public function testCreateAccountWithPasswordHashWithCustomerAddresses() { $websiteId = 1; @@ -1846,6 +1881,19 @@ public function testCreateAccountWithPasswordHashWithCustomerAddresses() ->expects($this->atLeastOnce()) ->method('getStore') ->willReturn($store); + $this->share + ->expects($this->once()) + ->method('isWebsiteScope') + ->willReturn(true); + $website = $this->getMockBuilder(\Magento\Store\Model\Website::class)->disableOriginalConstructor()->getMock(); + $website->expects($this->once()) + ->method('getStoreIds') + ->willReturn([1, 2, 3]); + $this->storeManager + ->expects($this->atLeastOnce()) + ->method('getWebsite') + ->with($websiteId) + ->willReturn($website); $this->assertSame($customer, $this->accountManagement->createAccountWithPasswordHash($customer, $hash)); } @@ -1976,4 +2024,39 @@ public function testCreateAccountUnexpectedValueException(): void $this->accountManagement->createAccount($customer); } + + /** + * @expectedException \Magento\Framework\Exception\LocalizedException + */ + public function testCreateAccountWithStoreNotInWebsite() + { + $storeId = 1; + $websiteId = 1; + $hash = '4nj54lkj5jfi03j49f8bgujfgsd'; + $customerMock = $this->getMockBuilder(\Magento\Customer\Api\Data\CustomerInterface::class) + ->getMockForAbstractClass(); + $customerMock->expects($this->atLeastOnce()) + ->method('getId') + ->willReturn(null); + $customerMock->expects($this->atLeastOnce()) + ->method('getStoreId') + ->willReturn($storeId); + $customerMock->expects($this->atLeastOnce()) + ->method('getWebsiteId') + ->willReturn($websiteId); + $this->share + ->expects($this->once()) + ->method('isWebsiteScope') + ->willReturn(true); + $website = $this->getMockBuilder(\Magento\Store\Model\Website::class)->disableOriginalConstructor()->getMock(); + $website->expects($this->once()) + ->method('getStoreIds') + ->willReturn([2, 3]); + $this->storeManager + ->expects($this->atLeastOnce()) + ->method('getWebsite') + ->with($websiteId) + ->willReturn($website); + $this->accountManagement->createAccountWithPasswordHash($customerMock, $hash); + } } diff --git a/app/code/Magento/Customer/Test/Unit/Model/Metadata/AttributeMetadataHydratorTest.php b/app/code/Magento/Customer/Test/Unit/Model/Metadata/AttributeMetadataHydratorTest.php index ec9831dde081e..248cae999065c 100644 --- a/app/code/Magento/Customer/Test/Unit/Model/Metadata/AttributeMetadataHydratorTest.php +++ b/app/code/Magento/Customer/Test/Unit/Model/Metadata/AttributeMetadataHydratorTest.php @@ -205,7 +205,7 @@ public function testExtract() ->method('buildOutputDataArray') ->with( $this->attributeMetadataMock, - AttributeMetadataInterface::class + AttributeMetadata::class ) ->willReturn($data); $this->assertSame( diff --git a/app/code/Magento/Customer/Test/Unit/Model/Metadata/Form/TextTest.php b/app/code/Magento/Customer/Test/Unit/Model/Metadata/Form/TextTest.php index b95987cba1dcf..7987bdc79ed98 100644 --- a/app/code/Magento/Customer/Test/Unit/Model/Metadata/Form/TextTest.php +++ b/app/code/Magento/Customer/Test/Unit/Model/Metadata/Form/TextTest.php @@ -5,8 +5,10 @@ * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ + namespace Magento\Customer\Test\Unit\Model\Metadata\Form; +use Magento\Customer\Api\Data\ValidationRuleInterface; use Magento\Customer\Model\Metadata\Form\Text; class TextTest extends AbstractFormTestCase @@ -14,6 +16,9 @@ class TextTest extends AbstractFormTestCase /** @var \Magento\Framework\Stdlib\StringUtils */ protected $stringHelper; + /** + * {@inheritDoc} + */ protected function setUp() { parent::setUp(); @@ -111,7 +116,7 @@ public function validateValueRequiredDataProvider() */ public function testValidateValueLength($value, $expected) { - $minTextLengthRule = $this->getMockBuilder(\Magento\Customer\Api\Data\ValidationRuleInterface::class) + $minTextLengthRule = $this->getMockBuilder(ValidationRuleInterface::class) ->disableOriginalConstructor() ->setMethods(['getName', 'getValue']) ->getMockForAbstractClass(); @@ -122,7 +127,7 @@ public function testValidateValueLength($value, $expected) ->method('getValue') ->will($this->returnValue(4)); - $maxTextLengthRule = $this->getMockBuilder(\Magento\Customer\Api\Data\ValidationRuleInterface::class) + $maxTextLengthRule = $this->getMockBuilder(ValidationRuleInterface::class) ->disableOriginalConstructor() ->setMethods(['getName', 'getValue']) ->getMockForAbstractClass(); @@ -133,7 +138,19 @@ public function testValidateValueLength($value, $expected) ->method('getValue') ->will($this->returnValue(8)); + $inputValidationRule = $this->getMockBuilder(ValidationRuleInterface::class) + ->disableOriginalConstructor() + ->setMethods(['getName', 'getValue']) + ->getMockForAbstractClass(); + $inputValidationRule->expects($this->any()) + ->method('getName') + ->will($this->returnValue('input_validation')); + $inputValidationRule->expects($this->any()) + ->method('getValue') + ->will($this->returnValue('other')); + $validationRules = [ + 'input_validation' => $inputValidationRule, 'min_text_length' => $minTextLengthRule, 'max_text_length' => $maxTextLengthRule, ]; diff --git a/app/code/Magento/Customer/Test/Unit/Model/SessionTest.php b/app/code/Magento/Customer/Test/Unit/Model/SessionTest.php index 7a6807562f906..7efc61af800d3 100644 --- a/app/code/Magento/Customer/Test/Unit/Model/SessionTest.php +++ b/app/code/Magento/Customer/Test/Unit/Model/SessionTest.php @@ -52,6 +52,9 @@ class SessionTest extends \PHPUnit\Framework\TestCase */ protected $_model; + /** + * @return void + */ protected function setUp() { $this->_storageMock = $this->createPartialMock( @@ -82,6 +85,9 @@ protected function setUp() ); } + /** + * @return void + */ public function testSetCustomerAsLoggedIn() { $customer = $this->createMock(\Magento\Customer\Model\Customer::class); @@ -102,6 +108,9 @@ public function testSetCustomerAsLoggedIn() $this->assertSame($customer, $this->_model->getCustomer()); } + /** + * @return void + */ public function testSetCustomerDataAsLoggedIn() { $customer = $this->createMock(\Magento\Customer\Model\Customer::class); @@ -126,27 +135,36 @@ public function testSetCustomerDataAsLoggedIn() $this->assertSame($customer, $this->_model->getCustomer()); } + /** + * @return void + */ public function testAuthenticate() { $urlMock = $this->createMock(\Magento\Framework\Url::class); $urlMock->expects($this->exactly(2)) ->method('getUrl') - ->will($this->returnValue('')); + ->willReturn(''); $urlMock->expects($this->once()) ->method('getRebuiltUrl') - ->will($this->returnValue('')); - $this->urlFactoryMock->expects($this->exactly(3)) + ->willReturn(''); + $this->urlFactoryMock->expects($this->exactly(4)) ->method('create') - ->will($this->returnValue($urlMock)); + ->willReturn($urlMock); + $urlMock->expects($this->once()) + ->method('getUseSession') + ->willReturn(false); $this->responseMock->expects($this->once()) ->method('setRedirect') ->with('') - ->will($this->returnValue('')); + ->willReturn(''); $this->assertFalse($this->_model->authenticate()); } + /** + * @return void + */ public function testLoginById() { $customerId = 1; @@ -162,7 +180,7 @@ public function testLoginById() } /** - * @param $customerId + * @param int $customerId * @return \PHPUnit_Framework_MockObject_MockObject */ protected function prepareLoginDataMock($customerId) @@ -239,6 +257,9 @@ public function getIsLoggedInDataProvider() ]; } + /** + * @return void + */ public function testSetCustomerRemovesFlagThatShowsIfCustomerIsEmulated() { $customerMock = $this->createMock(\Magento\Customer\Model\Customer::class); diff --git a/app/code/Magento/Customer/etc/acl.xml b/app/code/Magento/Customer/etc/acl.xml index a500608e1cdf5..e8e6219bef4fe 100644 --- a/app/code/Magento/Customer/etc/acl.xml +++ b/app/code/Magento/Customer/etc/acl.xml @@ -12,6 +12,7 @@ <resource id="Magento_Customer::customer" title="Customers" translate="title" sortOrder="40"> <resource id="Magento_Customer::manage" title="All Customers" translate="title" sortOrder="10" /> <resource id="Magento_Customer::online" title="Now Online" translate="title" sortOrder="20" /> + <resource id="Magento_Customer::group" title="Customer Groups" translate="title" sortOrder="30" /> </resource> <resource id="Magento_Backend::stores"> <resource id="Magento_Backend::stores_settings"> @@ -19,10 +20,7 @@ <resource id="Magento_Customer::config_customer" title="Customers Section" translate="title" sortOrder="50" /> </resource> </resource> - <resource id="Magento_Backend::stores_other_settings"> - <resource id="Magento_Customer::group" title="Customer Groups" translate="title" sortOrder="10" /> - </resource> - </resource> + </resource> </resource> </resources> </acl> diff --git a/app/code/Magento/Customer/etc/di.xml b/app/code/Magento/Customer/etc/di.xml index 717b2b6c67e20..6e8c3dc68ed28 100644 --- a/app/code/Magento/Customer/etc/di.xml +++ b/app/code/Magento/Customer/etc/di.xml @@ -75,6 +75,13 @@ <argument name="addressConfig" xsi:type="object">Magento\Customer\Model\Address\Config\Proxy</argument> </arguments> </type> + <type name="Magento\Framework\App\Http\Context"> + <arguments> + <argument name="default" xsi:type="array"> + <item name="customer_group" xsi:type="const">Magento\Customer\Api\Data\GroupInterface::NOT_LOGGED_IN_ID</item> + </argument> + </arguments> + </type> <type name="Magento\Customer\Model\Config\Share"> <arguments> <argument name="customerResource" xsi:type="object">Magento\Customer\Model\ResourceModel\Customer\Proxy</argument> diff --git a/app/code/Magento/Customer/etc/webapi.xml b/app/code/Magento/Customer/etc/webapi.xml index f9ef3a5f88228..c536e26bcc82a 100644 --- a/app/code/Magento/Customer/etc/webapi.xml +++ b/app/code/Magento/Customer/etc/webapi.xml @@ -200,12 +200,6 @@ <resource ref="anonymous"/> </resources> </route> - <route url="/V1/customers/resetPassword" method="POST"> - <service class="Magento\Customer\Api\AccountManagementInterface" method="resetPassword"/> - <resources> - <resource ref="anonymous"/> - </resources> - </route> <route url="/V1/customers/:customerId/confirm" method="GET"> <service class="Magento\Customer\Api\AccountManagementInterface" method="getConfirmationStatus"/> <resources> diff --git a/app/code/Magento/Customer/view/frontend/web/js/customer-data.js b/app/code/Magento/Customer/view/frontend/web/js/customer-data.js index c4672c48e1f4a..ec21e45da6852 100644 --- a/app/code/Magento/Customer/view/frontend/web/js/customer-data.js +++ b/app/code/Magento/Customer/view/frontend/web/js/customer-data.js @@ -27,7 +27,8 @@ define([ //TODO: remove global change, in this case made for initNamespaceStorage $.cookieStorage.setConf({ - path: '/' + path: '/', + expires: 1 }); storage = $.initNamespaceStorage('mage-cache-storage').localStorage; diff --git a/app/code/Magento/CustomerAnalytics/Test/Mftf/composer.json b/app/code/Magento/CustomerAnalytics/Test/Mftf/composer.json deleted file mode 100644 index 9b90f06de29c6..0000000000000 --- a/app/code/Magento/CustomerAnalytics/Test/Mftf/composer.json +++ /dev/null @@ -1,17 +0,0 @@ -{ - "name": "magento/functional-test-module-customer-analytics", - "description": "N/A", - "config": { - "sort-packages": true - }, - "require": { - "php": "~7.1.3||~7.2.0", - "magento/magento2-functional-testing-framework": "2.2.0", - "magento/functional-test-module-customer": "100.0.0-dev" - }, - "type": "magento2-test", - "license": [ - "OSL-3.0", - "AFL-3.0" - ] -} diff --git a/app/code/Magento/CustomerGraphQl/Test/Mftf/composer.json b/app/code/Magento/CustomerGraphQl/Test/Mftf/composer.json deleted file mode 100644 index b173084a84d10..0000000000000 --- a/app/code/Magento/CustomerGraphQl/Test/Mftf/composer.json +++ /dev/null @@ -1,21 +0,0 @@ -{ - "name": "magento/functional-test-module-customer-graph-ql", - "description": "N/A", - "config": { - "sort-packages": true - }, - "require": { - "php": "~7.1.3||~7.2.0", - "magento/functional-test-module-customer": "100.0.0-dev", - "magento/functional-test-module-authorization": "100.0.0-dev", - "magento/magento2-functional-testing-framework": "2.2.0" - }, - "suggest": { - "magento/functional-test-module-graph-ql": "100.0.0-dev" - }, - "type": "magento2-test", - "license": [ - "OSL-3.0", - "AFL-3.0" - ] -} diff --git a/app/code/Magento/CustomerGraphQl/etc/schema.graphqls b/app/code/Magento/CustomerGraphQl/etc/schema.graphqls index 687826cff001d..91b7ef1f9be15 100644 --- a/app/code/Magento/CustomerGraphQl/etc/schema.graphqls +++ b/app/code/Magento/CustomerGraphQl/etc/schema.graphqls @@ -19,9 +19,9 @@ type Customer @doc(description: "Customer defines the customer name and address dob: String @doc(description: "The customer's date of birth") taxvat: String @doc(description: "The customer's Tax/VAT number (for corporate customers)") id: Int @doc(description: "The ID assigned to the customer") - is_subscribed: Boolean @doc(description: "An array containing the customer's shipping and billing addresses") - addresses: [CustomerAddress] @doc(description: "Indicates whether the customer is subscribed to the company's newsletter") -} + is_subscribed: Boolean @doc(description: "Indicates whether the customer is subscribed to the company's newsletter") + addresses: [CustomerAddress] @doc(description: "An array containing the customer's shipping and billing addresses") +} type CustomerAddress @doc(description: "CustomerAddress contains detailed information about a customer's billing and shipping addresses"){ id: Int @doc(description: "The ID assigned to the address object") diff --git a/app/code/Magento/CustomerImportExport/Test/Mftf/composer.json b/app/code/Magento/CustomerImportExport/Test/Mftf/composer.json deleted file mode 100644 index adddda9ff7370..0000000000000 --- a/app/code/Magento/CustomerImportExport/Test/Mftf/composer.json +++ /dev/null @@ -1,22 +0,0 @@ -{ - "name": "magento/functional-test-module-customer-import-export", - "description": "N/A", - "config": { - "sort-packages": true - }, - "require": { - "php": "~7.1.3||~7.2.0", - "magento/magento2-functional-testing-framework": "2.2.0", - "magento/functional-test-module-backend": "100.0.0-dev", - "magento/functional-test-module-customer": "100.0.0-dev", - "magento/functional-test-module-directory": "100.0.0-dev", - "magento/functional-test-module-eav": "100.0.0-dev", - "magento/functional-test-module-import-export": "100.0.0-dev", - "magento/functional-test-module-store": "100.0.0-dev" - }, - "type": "magento2-test", - "license": [ - "OSL-3.0", - "AFL-3.0" - ] -} diff --git a/app/code/Magento/Deploy/Test/Mftf/composer.json b/app/code/Magento/Deploy/Test/Mftf/composer.json deleted file mode 100644 index 7e18c4d1d1222..0000000000000 --- a/app/code/Magento/Deploy/Test/Mftf/composer.json +++ /dev/null @@ -1,20 +0,0 @@ -{ - "name": "magento/functional-test-module-deploy", - "description": "N/A", - "config": { - "sort-packages": true - }, - "require": { - "php": "~7.1.3||~7.2.0", - "magento/magento2-functional-testing-framework": "2.2.0", - "magento/functional-test-module-config": "100.0.0-dev", - "magento/functional-test-module-require-js": "100.0.0-dev", - "magento/functional-test-module-store": "100.0.0-dev", - "magento/functional-test-module-user": "100.0.0-dev" - }, - "type": "magento2-test", - "license": [ - "OSL-3.0", - "AFL-3.0" - ] -} diff --git a/app/code/Magento/Developer/Test/Mftf/composer.json b/app/code/Magento/Developer/Test/Mftf/composer.json deleted file mode 100644 index ebd6230526271..0000000000000 --- a/app/code/Magento/Developer/Test/Mftf/composer.json +++ /dev/null @@ -1,18 +0,0 @@ -{ - "name": "magento/functional-test-module-developer", - "description": "N/A", - "config": { - "sort-packages": true - }, - "require": { - "php": "~7.1.3||~7.2.0", - "magento/magento2-functional-testing-framework": "2.2.0", - "magento/functional-test-module-config": "100.0.0-dev", - "magento/functional-test-module-store": "100.0.0-dev" - }, - "type": "magento2-test", - "license": [ - "OSL-3.0", - "AFL-3.0" - ] -} diff --git a/app/code/Magento/Dhl/Block/Adminhtml/Unitofmeasure.php b/app/code/Magento/Dhl/Block/Adminhtml/Unitofmeasure.php index deeb769c808fa..bf94a3b5c89ad 100644 --- a/app/code/Magento/Dhl/Block/Adminhtml/Unitofmeasure.php +++ b/app/code/Magento/Dhl/Block/Adminhtml/Unitofmeasure.php @@ -86,7 +86,7 @@ public function _construct() ) ); - $this->setTemplate('unitofmeasure.phtml'); + $this->setTemplate('Magento_Dhl::unitofmeasure.phtml'); } /** diff --git a/app/code/Magento/Dhl/Model/Carrier.php b/app/code/Magento/Dhl/Model/Carrier.php index 6262d71c4edcc..d997db6ac1a3e 100644 --- a/app/code/Magento/Dhl/Model/Carrier.php +++ b/app/code/Magento/Dhl/Model/Carrier.php @@ -232,7 +232,7 @@ class Carrier extends \Magento\Dhl\Model\AbstractDhl implements \Magento\Shippin * @param \Magento\Framework\Stdlib\DateTime $dateTime * @param \Magento\Framework\HTTP\ZendClientFactory $httpClientFactory * @param array $data - * @param \Magento\Dhl\Model\Validator\XmlValidatorFactory $xmlValidatorFactory + * @param \Magento\Dhl\Model\Validator\XmlValidator $xmlValidator * @SuppressWarnings(PHPMD.ExcessiveParameterList) */ public function __construct( @@ -1970,6 +1970,6 @@ protected function isDutiable($origCountryId, $destCountryId) return self::DHL_CONTENT_TYPE_NON_DOC == $this->getConfigData('content_type') - && !$this->_isDomestic; + || !$this->_isDomestic; } } diff --git a/app/code/Magento/Dhl/Test/Mftf/composer.json b/app/code/Magento/Dhl/Test/Mftf/composer.json deleted file mode 100644 index 0da17d213c84e..0000000000000 --- a/app/code/Magento/Dhl/Test/Mftf/composer.json +++ /dev/null @@ -1,28 +0,0 @@ -{ - "name": "magento/functional-test-module-dhl", - "description": "N/A", - "config": { - "sort-packages": true - }, - "require": { - "php": "~7.1.3||~7.2.0", - "magento/magento2-functional-testing-framework": "2.2.0", - "magento/functional-test-module-backend": "100.0.0-dev", - "magento/functional-test-module-catalog": "100.0.0-dev", - "magento/functional-test-module-catalog-inventory": "100.0.0-dev", - "magento/functional-test-module-config": "100.0.0-dev", - "magento/functional-test-module-directory": "100.0.0-dev", - "magento/functional-test-module-quote": "100.0.0-dev", - "magento/functional-test-module-sales": "100.0.0-dev", - "magento/functional-test-module-shipping": "100.0.0-dev", - "magento/functional-test-module-store": "100.0.0-dev" - }, - "suggest": { - "magento/functional-test-module-checkout": "100.0.0-dev" - }, - "type": "magento2-test", - "license": [ - "OSL-3.0", - "AFL-3.0" - ] -} diff --git a/app/code/Magento/Directory/Model/AllowedCountries.php b/app/code/Magento/Directory/Model/AllowedCountries.php index 46fa04ba22651..b9f2d829dd1a6 100644 --- a/app/code/Magento/Directory/Model/AllowedCountries.php +++ b/app/code/Magento/Directory/Model/AllowedCountries.php @@ -46,8 +46,8 @@ public function __construct( /** * Retrieve all allowed countries for scope or scopes * - * @param string | null $scopeCode * @param string $scope + * @param string|null $scopeCode * @return array * @since 100.1.2 */ @@ -55,7 +55,7 @@ public function getAllowedCountries( $scope = ScopeInterface::SCOPE_WEBSITE, $scopeCode = null ) { - if (empty($scopeCode)) { + if ($scopeCode === null) { $scopeCode = $this->getDefaultScopeCode($scope); } diff --git a/app/code/Magento/Directory/Model/Config/Source/Country.php b/app/code/Magento/Directory/Model/Config/Source/Country.php index e807f34456e24..a38ac4b62e1ee 100644 --- a/app/code/Magento/Directory/Model/Config/Source/Country.php +++ b/app/code/Magento/Directory/Model/Config/Source/Country.php @@ -20,6 +20,13 @@ class Country implements \Magento\Framework\Option\ArrayInterface */ protected $_countryCollection; + /** + * Options array + * + * @var array + */ + protected $_options; + /** * @param \Magento\Directory\Model\ResourceModel\Country\Collection $countryCollection */ @@ -28,13 +35,6 @@ public function __construct(\Magento\Directory\Model\ResourceModel\Country\Colle $this->_countryCollection = $countryCollection; } - /** - * Options array - * - * @var array - */ - protected $_options; - /** * Return options array * diff --git a/app/code/Magento/Directory/Model/Currency/Import/CurrencyConverterApi.php b/app/code/Magento/Directory/Model/Currency/Import/CurrencyConverterApi.php new file mode 100644 index 0000000000000..f52886a14264d --- /dev/null +++ b/app/code/Magento/Directory/Model/Currency/Import/CurrencyConverterApi.php @@ -0,0 +1,146 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +declare(strict_types=1); + +namespace Magento\Directory\Model\Currency\Import; + +class CurrencyConverterApi extends AbstractImport +{ + /** + * @var string + */ + const CURRENCY_CONVERTER_URL = 'http://free.currencyconverterapi.com/api/v3/convert?q={{CURRENCY_FROM}}_{{CURRENCY_TO}}&compact=ultra'; //@codingStandardsIgnoreLine + + /** + * Http Client Factory + * + * @var \Magento\Framework\HTTP\ZendClientFactory + */ + private $httpClientFactory; + + /** + * Core scope config + * + * @var \Magento\Framework\App\Config\ScopeConfigInterface + */ + private $scopeConfig; + + /** + * Initialize dependencies + * + * @param \Magento\Directory\Model\CurrencyFactory $currencyFactory + * @param \Magento\Framework\App\Config\ScopeConfigInterface $scopeConfig + * @param \Magento\Framework\HTTP\ZendClientFactory $httpClientFactory + */ + public function __construct( + \Magento\Directory\Model\CurrencyFactory $currencyFactory, + \Magento\Framework\App\Config\ScopeConfigInterface $scopeConfig, + \Magento\Framework\HTTP\ZendClientFactory $httpClientFactory + ) { + parent::__construct($currencyFactory); + $this->scopeConfig = $scopeConfig; + $this->httpClientFactory = $httpClientFactory; + } + + /** + * {@inheritdoc} + */ + public function fetchRates() + { + $data = []; + $currencies = $this->_getCurrencyCodes(); + $defaultCurrencies = $this->_getDefaultCurrencyCodes(); + + foreach ($defaultCurrencies as $currencyFrom) { + if (!isset($data[$currencyFrom])) { + $data[$currencyFrom] = []; + } + $data = $this->convertBatch($data, $currencyFrom, $currencies); + ksort($data[$currencyFrom]); + } + return $data; + } + + /** + * Return currencies convert rates in batch mode + * + * @param array $data + * @param string $currencyFrom + * @param array $currenciesTo + * @return array + */ + private function convertBatch($data, $currencyFrom, $currenciesTo) + { + foreach ($currenciesTo as $to) { + set_time_limit(0); + try { + $url = str_replace('{{CURRENCY_FROM}}', $currencyFrom, self::CURRENCY_CONVERTER_URL); + $url = str_replace('{{CURRENCY_TO}}', $to, $url); + $response = $this->getServiceResponse($url); + if ($currencyFrom == $to) { + $data[$currencyFrom][$to] = $this->_numberFormat(1); + } else { + if (empty($response)) { + $this->_messages[] = __('We can\'t retrieve a rate from %1 for %2.', $url, $to); + $data[$currencyFrom][$to] = null; + } else { + $data[$currencyFrom][$to] = $this->_numberFormat( + (double)$response[$currencyFrom . '_' . $to] + ); + } + } + } finally { + ini_restore('max_execution_time'); + } + } + + return $data; + } + + /** + * Get Fixer.io service response + * + * @param string $url + * @param int $retry + * @return array + */ + private function getServiceResponse($url, $retry = 0) + { + /** @var \Magento\Framework\HTTP\ZendClient $httpClient */ + $httpClient = $this->httpClientFactory->create(); + $response = []; + + try { + $jsonResponse = $httpClient->setUri( + $url + )->setConfig( + [ + 'timeout' => $this->scopeConfig->getValue( + 'currency/currencyconverterapi/timeout', + \Magento\Store\Model\ScopeInterface::SCOPE_STORE + ), + ] + )->request( + 'GET' + )->getBody(); + + $response = json_decode($jsonResponse, true); + } catch (\Exception $e) { + if ($retry == 0) { + $response = $this->getServiceResponse($url, 1); + } + } + return $response; + } + + /** + * {@inheritdoc} + */ + protected function _convert($currencyFrom, $currencyTo) + { + return 1; + } +} diff --git a/app/code/Magento/Directory/Test/Mftf/composer.json b/app/code/Magento/Directory/Test/Mftf/composer.json deleted file mode 100644 index c23156f6d923e..0000000000000 --- a/app/code/Magento/Directory/Test/Mftf/composer.json +++ /dev/null @@ -1,19 +0,0 @@ -{ - "name": "magento/functional-test-module-directory", - "description": "N/A", - "config": { - "sort-packages": true - }, - "require": { - "php": "~7.1.3||~7.2.0", - "magento/magento2-functional-testing-framework": "2.2.0", - "magento/functional-test-module-backend": "100.0.0-dev", - "magento/functional-test-module-config": "100.0.0-dev", - "magento/functional-test-module-store": "100.0.0-dev" - }, - "type": "magento2-test", - "license": [ - "OSL-3.0", - "AFL-3.0" - ] -} diff --git a/app/code/Magento/Directory/Test/Unit/Model/AllowedCountriesTest.php b/app/code/Magento/Directory/Test/Unit/Model/AllowedCountriesTest.php index 5931e5a839341..c0d549ee11d6d 100644 --- a/app/code/Magento/Directory/Test/Unit/Model/AllowedCountriesTest.php +++ b/app/code/Magento/Directory/Test/Unit/Model/AllowedCountriesTest.php @@ -8,7 +8,6 @@ use Magento\Directory\Model\AllowedCountries; use Magento\Framework\App\Config\ScopeConfigInterface; -use Magento\Framework\Data\Collection\AbstractDb; use Magento\Store\Api\Data\WebsiteInterface; use Magento\Store\Model\ScopeInterface; use Magento\Store\Model\StoreManagerInterface; @@ -30,6 +29,9 @@ class AllowedCountriesTest extends \PHPUnit\Framework\TestCase */ private $allowedCountriesReader; + /** + * Test setUp + */ public function setUp() { $this->scopeConfigMock = $this->createMock(ScopeConfigInterface::class); @@ -41,6 +43,9 @@ public function setUp() ); } + /** + * Test for getAllowedCountries + */ public function testGetAllowedCountriesWithEmptyFilter() { $website1 = $this->createMock(WebsiteInterface::class); @@ -58,6 +63,9 @@ public function testGetAllowedCountriesWithEmptyFilter() $this->assertEquals(['AM' => 'AM'], $this->allowedCountriesReader->getAllowedCountries()); } + /** + * Test for getAllowedCountries + */ public function testGetAllowedCountries() { $this->scopeConfigMock->expects($this->once()) @@ -70,4 +78,23 @@ public function testGetAllowedCountries() $this->allowedCountriesReader->getAllowedCountries(ScopeInterface::SCOPE_WEBSITE, true) ); } + + /** + * Test for getAllowedCountries + */ + public function testGetAllowedCountriesDefaultScope() + { + $this->storeManagerMock->expects($this->never()) + ->method('getStore'); + + $this->scopeConfigMock->expects($this->once()) + ->method('getValue') + ->with(AllowedCountries::ALLOWED_COUNTRIES_PATH, ScopeInterface::SCOPE_STORE, 0) + ->willReturn('AM'); + + $this->assertEquals( + ['AM' => 'AM'], + $this->allowedCountriesReader->getAllowedCountries(ScopeInterface::SCOPE_STORE, 0) + ); + } } diff --git a/app/code/Magento/Directory/etc/adminhtml/system.xml b/app/code/Magento/Directory/etc/adminhtml/system.xml index 15a82e006bffe..cae3b1c41db36 100644 --- a/app/code/Magento/Directory/etc/adminhtml/system.xml +++ b/app/code/Magento/Directory/etc/adminhtml/system.xml @@ -52,6 +52,12 @@ <label>Connection Timeout in Seconds</label> </field> </group> + <group id="currencyconverterapi" translate="label" sortOrder="45" showInDefault="1" showInWebsite="0" showInStore="0"> + <label>Currency Converter API</label> + <field id="timeout" translate="label" type="text" sortOrder="0" showInDefault="1" showInWebsite="0" showInStore="0"> + <label>Connection Timeout in Seconds</label> + </field> + </group> <group id="import" translate="label" type="text" sortOrder="50" showInDefault="1" showInWebsite="0" showInStore="0"> <label>Scheduled Import Settings</label> <field id="enabled" translate="label" type="select" sortOrder="1" showInDefault="1" showInWebsite="1" showInStore="1" canRestore="1"> diff --git a/app/code/Magento/Directory/etc/config.xml b/app/code/Magento/Directory/etc/config.xml index fa4e9d64d10d8..de3ff626bc12c 100644 --- a/app/code/Magento/Directory/etc/config.xml +++ b/app/code/Magento/Directory/etc/config.xml @@ -27,6 +27,9 @@ <webservicex> <timeout>100</timeout> </webservicex> + <currencyconverterapi> + <timeout>100</timeout> + </currencyconverterapi> <import> <enabled>0</enabled> <error_email /> diff --git a/app/code/Magento/Directory/etc/di.xml b/app/code/Magento/Directory/etc/di.xml index 02e16af29ea14..4d0e51ab9f45a 100644 --- a/app/code/Magento/Directory/etc/di.xml +++ b/app/code/Magento/Directory/etc/di.xml @@ -22,6 +22,10 @@ <item name="label" xsi:type="string" translatable="true">Fixer.io</item> <item name="class" xsi:type="string">Magento\Directory\Model\Currency\Import\FixerIo</item> </item> + <item name="currencyconverterapi" xsi:type="array"> + <item name="label" xsi:type="string" translatable="true">Currency Converter API</item> + <item name="class" xsi:type="string">Magento\Directory\Model\Currency\Import\CurrencyConverterApi</item> + </item> </argument> </arguments> </type> diff --git a/app/code/Magento/Downloadable/Test/Mftf/Test/AdminRemoveDefaultImageDownloadableProductTest.xml b/app/code/Magento/Downloadable/Test/Mftf/Test/AdminRemoveDefaultImageDownloadableProductTest.xml index 370148c6a4167..3b10f60c97340 100644 --- a/app/code/Magento/Downloadable/Test/Mftf/Test/AdminRemoveDefaultImageDownloadableProductTest.xml +++ b/app/code/Magento/Downloadable/Test/Mftf/Test/AdminRemoveDefaultImageDownloadableProductTest.xml @@ -59,9 +59,7 @@ <!-- Remove image from product --> <actionGroup ref="removeProductImage" stepKey="removeProductImage"/> - <!-- Skip success message check when saving product because of bug MAGETWO-91177 --> - <!-- actionGroup ref="saveProductForm" stepKey="saveProductFormAfterRemove"/--> - <click selector="{{AdminProductFormActionSection.saveButton}}" stepKey="saveProductFormAfterRemove"/> + <actionGroup ref="saveProductForm" stepKey="saveProductFormAfterRemove"/> <!-- Assert product image not in admin product form --> <actionGroup ref="assertProductImageNotInAdminProductPage" stepKey="assertProductImageNotInAdminProductPage"/> diff --git a/app/code/Magento/Downloadable/Test/Mftf/composer.json b/app/code/Magento/Downloadable/Test/Mftf/composer.json deleted file mode 100644 index 6a2a5bb00f01e..0000000000000 --- a/app/code/Magento/Downloadable/Test/Mftf/composer.json +++ /dev/null @@ -1,35 +0,0 @@ -{ - "name": "magento/functional-test-module-downloadable", - "description": "N/A", - "config": { - "sort-packages": true - }, - "require": { - "php": "~7.1.3||~7.2.0", - "magento/magento2-functional-testing-framework": "2.2.0", - "magento/functional-test-module-backend": "100.0.0-dev", - "magento/functional-test-module-catalog": "100.0.0-dev", - "magento/functional-test-module-catalog-inventory": "100.0.0-dev", - "magento/functional-test-module-checkout": "100.0.0-dev", - "magento/functional-test-module-config": "100.0.0-dev", - "magento/functional-test-module-customer": "100.0.0-dev", - "magento/functional-test-module-directory": "100.0.0-dev", - "magento/functional-test-module-eav": "100.0.0-dev", - "magento/functional-test-module-gift-message": "100.0.0-dev", - "magento/functional-test-module-media-storage": "100.0.0-dev", - "magento/functional-test-module-quote": "100.0.0-dev", - "magento/functional-test-module-sales": "100.0.0-dev", - "magento/functional-test-module-store": "100.0.0-dev", - "magento/functional-test-module-tax": "100.0.0-dev", - "magento/functional-test-module-theme": "100.0.0-dev", - "magento/functional-test-module-ui": "100.0.0-dev" - }, - "suggest": { - "magento/functional-test-module-downloadable-sample-data": "100.0.0-dev" - }, - "type": "magento2-test", - "license": [ - "OSL-3.0", - "AFL-3.0" - ] -} diff --git a/app/code/Magento/DownloadableGraphQl/Test/Mftf/composer.json b/app/code/Magento/DownloadableGraphQl/Test/Mftf/composer.json deleted file mode 100644 index 725f17975e581..0000000000000 --- a/app/code/Magento/DownloadableGraphQl/Test/Mftf/composer.json +++ /dev/null @@ -1,21 +0,0 @@ -{ - "name": "magento/functional-test-module-downloadable-graph-ql", - "description": "N/A", - "config": { - "sort-packages": true - }, - "require": { - "php": "~7.1.3||~7.2.0", - "magento/functional-test-module-catalog": "100.0.0-dev", - "magento/functional-test-module-downloadable": "100.0.0-dev", - "magento/magento2-functional-testing-framework": "2.2.0" - }, - "suggest": { - "magento/functional-test-module-catalog-graph-ql": "100.0.0-dev" - }, - "type": "magento2-test", - "license": [ - "OSL-3.0", - "AFL-3.0" - ] -} diff --git a/app/code/Magento/DownloadableImportExport/Test/Mftf/composer.json b/app/code/Magento/DownloadableImportExport/Test/Mftf/composer.json deleted file mode 100644 index da5caa42b87d5..0000000000000 --- a/app/code/Magento/DownloadableImportExport/Test/Mftf/composer.json +++ /dev/null @@ -1,22 +0,0 @@ -{ - "name": "magento/functional-test-module-downloadable-import-export", - "description": "N/A", - "config": { - "sort-packages": true - }, - "require": { - "php": "~7.1.3||~7.2.0", - "magento/magento2-functional-testing-framework": "2.2.0", - "magento/functional-test-module-catalog": "100.0.0-dev", - "magento/functional-test-module-catalog-import-export": "100.0.0-dev", - "magento/functional-test-module-downloadable": "100.0.0-dev", - "magento/functional-test-module-eav": "100.0.0-dev", - "magento/functional-test-module-import-export": "100.0.0-dev", - "magento/functional-test-module-store": "100.0.0-dev" - }, - "type": "magento2-test", - "license": [ - "OSL-3.0", - "AFL-3.0" - ] -} diff --git a/app/code/Magento/Eav/Api/Data/AttributeInterface.php b/app/code/Magento/Eav/Api/Data/AttributeInterface.php index e8970d2b42149..55d6e58b64b71 100644 --- a/app/code/Magento/Eav/Api/Data/AttributeInterface.php +++ b/app/code/Magento/Eav/Api/Data/AttributeInterface.php @@ -6,12 +6,15 @@ */ namespace Magento\Eav\Api\Data; +use Magento\Framework\Api\CustomAttributesDataInterface; +use Magento\Framework\Api\MetadataObjectInterface; + /** * Interface AttributeInterface * @api * @since 100.0.2 */ -interface AttributeInterface extends \Magento\Framework\Api\CustomAttributesDataInterface +interface AttributeInterface extends CustomAttributesDataInterface, MetadataObjectInterface { const ATTRIBUTE_ID = 'attribute_id'; diff --git a/app/code/Magento/Eav/Model/Attribute/Data/Text.php b/app/code/Magento/Eav/Model/Attribute/Data/Text.php index 242f4e98108c9..f81fb2affd3b3 100644 --- a/app/code/Magento/Eav/Model/Attribute/Data/Text.php +++ b/app/code/Magento/Eav/Model/Attribute/Data/Text.php @@ -3,6 +3,7 @@ * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ + namespace Magento\Eav\Model\Attribute\Data; use Magento\Framework\App\RequestInterface; @@ -76,19 +77,9 @@ public function validateValue($value) return true; } - // validate length - $length = $this->_string->strlen(trim($value)); - - $validateRules = $attribute->getValidateRules(); - if (!empty($validateRules['min_text_length']) && $length < $validateRules['min_text_length']) { - $label = __($attribute->getStoreLabel()); - $v = $validateRules['min_text_length']; - $errors[] = __('"%1" length must be equal or greater than %2 characters.', $label, $v); - } - if (!empty($validateRules['max_text_length']) && $length > $validateRules['max_text_length']) { - $label = __($attribute->getStoreLabel()); - $v = $validateRules['max_text_length']; - $errors[] = __('"%1" length must be equal or less than %2 characters.', $label, $v); + $result = $this->validateLength($attribute, $value); + if (count($result) !== 0) { + $errors = array_merge($errors, $result); } $result = $this->_validateInputRule($value); @@ -142,4 +133,33 @@ public function outputValue($format = \Magento\Eav\Model\AttributeDataFactory::O return $value; } + + /** + * Validates value length by attribute rules + * + * @param \Magento\Eav\Model\Attribute $attribute + * @param string $value + * @return array errors + */ + private function validateLength(\Magento\Eav\Model\Attribute $attribute, $value): array + { + $errors = []; + $length = $this->_string->strlen(trim($value)); + $validateRules = $attribute->getValidateRules(); + + if (!empty($validateRules['input_validation'])) { + if (!empty($validateRules['min_text_length']) && $length < $validateRules['min_text_length']) { + $label = __($attribute->getStoreLabel()); + $v = $validateRules['min_text_length']; + $errors[] = __('"%1" length must be equal or greater than %2 characters.', $label, $v); + } + if (!empty($validateRules['max_text_length']) && $length > $validateRules['max_text_length']) { + $label = __($attribute->getStoreLabel()); + $v = $validateRules['max_text_length']; + $errors[] = __('"%1" length must be equal or less than %2 characters.', $label, $v); + } + } + + return $errors; + } } diff --git a/app/code/Magento/Eav/Model/Entity/AbstractEntity.php b/app/code/Magento/Eav/Model/Entity/AbstractEntity.php index 7159cedb61cee..0522ea0432176 100644 --- a/app/code/Magento/Eav/Model/Entity/AbstractEntity.php +++ b/app/code/Magento/Eav/Model/Entity/AbstractEntity.php @@ -591,13 +591,7 @@ public function attributesCompare($firstAttribute, $secondAttribute) $firstSort = $firstAttribute->getSortWeight((int) $this->_sortingSetId); $secondSort = $secondAttribute->getSortWeight((int) $this->_sortingSetId); - if ($firstSort > $secondSort) { - return 1; - } elseif ($firstSort < $secondSort) { - return -1; - } - - return 0; + return $firstSort <=> $secondSort; } /** diff --git a/app/code/Magento/Eav/Model/Entity/Attribute.php b/app/code/Magento/Eav/Model/Entity/Attribute.php index 1b20858a0c424..c605f3ce17e30 100644 --- a/app/code/Magento/Eav/Model/Entity/Attribute.php +++ b/app/code/Magento/Eav/Model/Entity/Attribute.php @@ -8,6 +8,7 @@ use Magento\Framework\Api\AttributeValueFactory; use Magento\Framework\Exception\LocalizedException; +use Magento\Framework\Stdlib\DateTime; use Magento\Framework\Stdlib\DateTime\DateTimeFormatterInterface; /** @@ -284,12 +285,10 @@ public function beforeSave() // save default date value as timestamp if ($hasDefaultValue) { - $format = $this->_localeDate->getDateFormat( - \IntlDateFormatter::SHORT - ); try { - $defaultValue = $this->dateTimeFormatter->formatObject(new \DateTime($defaultValue), $format); - $this->setDefaultValue($defaultValue); + $locale = $this->_localeResolver->getLocale(); + $defaultValue = $this->_localeDate->date($defaultValue, $locale, false, false); + $this->setDefaultValue($defaultValue->format(DateTime::DATETIME_PHP_FORMAT)); } catch (\Exception $e) { throw new LocalizedException(__('The default date is invalid. Verify the date and try again.')); } diff --git a/app/code/Magento/Eav/Model/ResourceModel/Entity/Attribute/Collection.php b/app/code/Magento/Eav/Model/ResourceModel/Entity/Attribute/Collection.php index 492da0b72c122..cec415e513677 100644 --- a/app/code/Magento/Eav/Model/ResourceModel/Entity/Attribute/Collection.php +++ b/app/code/Magento/Eav/Model/ResourceModel/Entity/Attribute/Collection.php @@ -222,7 +222,7 @@ public function setInAllAttributeSetsFilter(array $setIds) $setIds ) ->group('entity_attribute.attribute_id') - ->having('count = ' . count($setIds)); + ->having(new \Zend_Db_Expr('COUNT(*)') . ' = ' . count($setIds)); } //$this->getSelect()->distinct(true); diff --git a/app/code/Magento/Eav/Test/Mftf/composer.json b/app/code/Magento/Eav/Test/Mftf/composer.json deleted file mode 100644 index 8ad451d607263..0000000000000 --- a/app/code/Magento/Eav/Test/Mftf/composer.json +++ /dev/null @@ -1,21 +0,0 @@ -{ - "name": "magento/functional-test-module-eav", - "description": "N/A", - "config": { - "sort-packages": true - }, - "require": { - "php": "~7.1.3||~7.2.0", - "magento/magento2-functional-testing-framework": "2.2.0", - "magento/functional-test-module-backend": "100.0.0-dev", - "magento/functional-test-module-catalog": "100.0.0-dev", - "magento/functional-test-module-config": "100.0.0-dev", - "magento/functional-test-module-media-storage": "100.0.0-dev", - "magento/functional-test-module-store": "100.0.0-dev" - }, - "type": "magento2-test", - "license": [ - "OSL-3.0", - "AFL-3.0" - ] -} diff --git a/app/code/Magento/Eav/Test/Unit/Model/Attribute/Data/MultilineTest.php b/app/code/Magento/Eav/Test/Unit/Model/Attribute/Data/MultilineTest.php index f628d52f6647f..bde4a3adb9de5 100644 --- a/app/code/Magento/Eav/Test/Unit/Model/Attribute/Data/MultilineTest.php +++ b/app/code/Magento/Eav/Test/Unit/Model/Attribute/Data/MultilineTest.php @@ -3,8 +3,12 @@ * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ + namespace Magento\Eav\Test\Unit\Model\Attribute\Data; +use Magento\Framework\Locale\ResolverInterface; +use Magento\Framework\Stdlib\DateTime\TimezoneInterface; + class MultilineTest extends \PHPUnit\Framework\TestCase { /** @@ -13,15 +17,21 @@ class MultilineTest extends \PHPUnit\Framework\TestCase protected $model; /** - * @var \PHPUnit_Framework_MockObject_MockObject + * @var \PHPUnit_Framework_MockObject_MockObject | \Magento\Framework\Stdlib\StringUtils */ protected $stringMock; + /** + * {@inheritDoc} + */ protected function setUp() { - $timezoneMock = $this->createMock(\Magento\Framework\Stdlib\DateTime\TimezoneInterface::class); + /** @var TimezoneInterface $timezoneMock */ + $timezoneMock = $this->createMock(TimezoneInterface::class); + /** @var \Psr\Log\LoggerInterface $loggerMock */ $loggerMock = $this->createMock(\Psr\Log\LoggerInterface::class); - $localeResolverMock = $this->createMock(\Magento\Framework\Locale\ResolverInterface::class); + /** @var ResolverInterface $localeResolverMock */ + $localeResolverMock = $this->createMock(ResolverInterface::class); $this->stringMock = $this->createMock(\Magento\Framework\Stdlib\StringUtils::class); $this->model = new \Magento\Eav\Model\Attribute\Data\Multiline( @@ -33,7 +43,7 @@ protected function setUp() } /** - * @covers \Magento\Eav\Model\Attribute\Data\Multiline::extractValue + * @covers \Magento\Eav\Model\Attribute\Data\Multiline::extractValue * * @param mixed $param * @param mixed $expectedResult @@ -41,11 +51,15 @@ protected function setUp() */ public function testExtractValue($param, $expectedResult) { + /** @var \PHPUnit_Framework_MockObject_MockObject | \Magento\Framework\App\RequestInterface $requestMock */ $requestMock = $this->createMock(\Magento\Framework\App\RequestInterface::class); + /** @var \PHPUnit_Framework_MockObject_MockObject | \Magento\Eav\Model\Attribute $attributeMock */ $attributeMock = $this->createMock(\Magento\Eav\Model\Attribute::class); $requestMock->expects($this->once())->method('getParam')->will($this->returnValue($param)); - $attributeMock->expects($this->once())->method('getAttributeCode')->will($this->returnValue('attributeCode')); + $attributeMock->expects($this->once()) + ->method('getAttributeCode') + ->will($this->returnValue('attributeCode')); $this->model->setAttribute($attributeMock); $this->assertEquals($expectedResult, $this->model->extractValue($requestMock)); @@ -69,7 +83,7 @@ public function extractValueDataProvider() } /** - * @covers \Magento\Eav\Model\Attribute\Data\Multiline::outputValue + * @covers \Magento\Eav\Model\Attribute\Data\Multiline::outputValue * * @param string $format * @param mixed $expectedResult @@ -77,9 +91,13 @@ public function extractValueDataProvider() */ public function testOutputValue($format, $expectedResult) { + /** @var \PHPUnit_Framework_MockObject_MockObject | \Magento\Framework\Model\AbstractModel $entityMock */ $entityMock = $this->createMock(\Magento\Framework\Model\AbstractModel::class); - $entityMock->expects($this->once())->method('getData')->will($this->returnValue("value1\nvalue2")); + $entityMock->expects($this->once()) + ->method('getData') + ->will($this->returnValue("value1\nvalue2")); + /** @var \PHPUnit_Framework_MockObject_MockObject | \Magento\Eav\Model\Attribute $attributeMock */ $attributeMock = $this->createMock(\Magento\Eav\Model\Attribute::class); $this->model->setEntity($entityMock); @@ -113,8 +131,8 @@ public function outputValueDataProvider() } /** - * @covers \Magento\Eav\Model\Attribute\Data\Multiline::validateValue - * @covers \Magento\Eav\Model\Attribute\Data\Text::validateValue + * @covers \Magento\Eav\Model\Attribute\Data\Multiline::validateValue + * @covers \Magento\Eav\Model\Attribute\Data\Text::validateValue * * @param mixed $value * @param bool $isAttributeRequired @@ -124,14 +142,23 @@ public function outputValueDataProvider() */ public function testValidateValue($value, $isAttributeRequired, $rules, $expectedResult) { + /** @var \PHPUnit_Framework_MockObject_MockObject | \Magento\Framework\Model\AbstractModel $entityMock */ $entityMock = $this->createMock(\Magento\Framework\Model\AbstractModel::class); - $entityMock->expects($this->any())->method('getDataUsingMethod')->will($this->returnValue("value1\nvalue2")); + $entityMock->expects($this->any()) + ->method('getDataUsingMethod') + ->will($this->returnValue("value1\nvalue2")); + /** @var \PHPUnit_Framework_MockObject_MockObject | \Magento\Eav\Model\Attribute $attributeMock */ $attributeMock = $this->createMock(\Magento\Eav\Model\Attribute::class); $attributeMock->expects($this->any())->method('getMultilineCount')->will($this->returnValue(2)); $attributeMock->expects($this->any())->method('getValidateRules')->will($this->returnValue($rules)); - $attributeMock->expects($this->any())->method('getStoreLabel')->will($this->returnValue('Label')); - $attributeMock->expects($this->any())->method('getIsRequired')->will($this->returnValue($isAttributeRequired)); + $attributeMock->expects($this->any()) + ->method('getStoreLabel') + ->will($this->returnValue('Label')); + + $attributeMock->expects($this->any()) + ->method('getIsRequired') + ->will($this->returnValue($isAttributeRequired)); $this->stringMock->expects($this->any())->method('strlen')->will($this->returnValue(5)); @@ -159,7 +186,7 @@ public function validateValueDataProvider() 'expectedResult' => true, ], [ - 'value' => ['value1', 'value2'], + 'value' => ['value1', 'value2'], 'isAttributeRequired' => false, 'rules' => [], 'expectedResult' => true, @@ -167,13 +194,13 @@ public function validateValueDataProvider() [ 'value' => 'value', 'isAttributeRequired' => false, - 'rules' => ['max_text_length' => 3], + 'rules' => ['input_validation' => 'other', 'max_text_length' => 3], 'expectedResult' => ['"Label" length must be equal or less than 3 characters.'], ], [ 'value' => 'value', 'isAttributeRequired' => false, - 'rules' => ['min_text_length' => 10], + 'rules' => ['input_validation' => 'other', 'min_text_length' => 10], 'expectedResult' => ['"Label" length must be equal or greater than 10 characters.'], ], [ diff --git a/app/code/Magento/Eav/Test/Unit/Model/Attribute/Data/TextTest.php b/app/code/Magento/Eav/Test/Unit/Model/Attribute/Data/TextTest.php index 36eac0bfab27b..bbbe712b2bb42 100644 --- a/app/code/Magento/Eav/Test/Unit/Model/Attribute/Data/TextTest.php +++ b/app/code/Magento/Eav/Test/Unit/Model/Attribute/Data/TextTest.php @@ -3,6 +3,7 @@ * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ + namespace Magento\Eav\Test\Unit\Model\Attribute\Data; class TextTest extends \PHPUnit\Framework\TestCase @@ -12,6 +13,9 @@ class TextTest extends \PHPUnit\Framework\TestCase */ protected $_model; + /** + * {@inheritDoc} + */ protected function setUp() { $locale = $this->createMock(\Magento\Framework\Stdlib\DateTime\TimezoneInterface::class); @@ -19,14 +23,77 @@ protected function setUp() $logger = $this->createMock(\Psr\Log\LoggerInterface::class); $helper = $this->createMock(\Magento\Framework\Stdlib\StringUtils::class); - $attributeData = [ + $this->_model = new \Magento\Eav\Model\Attribute\Data\Text($locale, $logger, $localeResolver, $helper); + $this->_model->setAttribute( + $this->createAttribute( + [ + 'store_label' => 'Test', + 'attribute_code' => 'test', + 'is_required' => 1, + 'validate_rules' => ['min_text_length' => 0, 'max_text_length' => 0, 'input_validation' => 0], + ] + ) + ); + } + + /** + * {@inheritDoc} + */ + protected function tearDown() + { + $this->_model = null; + } + + /** + * Test for string validation + */ + public function testValidateValueString(): void + { + $inputValue = '0'; + $expectedResult = true; + $this->assertEquals($expectedResult, $this->_model->validateValue($inputValue)); + } + + /** + * Test for integer validation + */ + public function testValidateValueInteger(): void + { + $inputValue = 0; + $expectedResult = ['"Test" is a required value.']; + $result = $this->_model->validateValue($inputValue); + $this->assertEquals($expectedResult, [(string)$result[0]]); + } + + /** + * Test without length validation + */ + public function testWithoutLengthValidation(): void + { + $expectedResult = true; + $defaultAttributeData = [ 'store_label' => 'Test', 'attribute_code' => 'test', 'is_required' => 1, 'validate_rules' => ['min_text_length' => 0, 'max_text_length' => 0, 'input_validation' => 0], ]; - $attributeClass = \Magento\Eav\Model\Entity\Attribute\AbstractAttribute::class; + $defaultAttributeData['validate_rules']['min_text_length'] = 2; + $this->_model->setAttribute($this->createAttribute($defaultAttributeData)); + $this->assertEquals($expectedResult, $this->_model->validateValue('t')); + + $defaultAttributeData['validate_rules']['max_text_length'] = 3; + $this->_model->setAttribute($this->createAttribute($defaultAttributeData)); + $this->assertEquals($expectedResult, $this->_model->validateValue('test')); + } + + /** + * @param array $attributeData + * @return \Magento\Eav\Model\Attribute + */ + protected function createAttribute($attributeData): \Magento\Eav\Model\Entity\Attribute\AbstractAttribute + { + $attributeClass = \Magento\Eav\Model\Attribute::class; $objectManagerHelper = new \Magento\Framework\TestFramework\Unit\Helper\ObjectManager($this); $eavTypeFactory = $this->createMock(\Magento\Eav\Model\Entity\TypeFactory::class); $arguments = $objectManagerHelper->getConstructArguments( @@ -41,27 +108,6 @@ protected function setUp() ->setMethods(['_init']) ->setConstructorArgs($arguments) ->getMock(); - $this->_model = new \Magento\Eav\Model\Attribute\Data\Text($locale, $logger, $localeResolver, $helper); - $this->_model->setAttribute($attribute); - } - - protected function tearDown() - { - $this->_model = null; - } - - public function testValidateValueString() - { - $inputValue = '0'; - $expectedResult = true; - $this->assertEquals($expectedResult, $this->_model->validateValue($inputValue)); - } - - public function testValidateValueInteger() - { - $inputValue = 0; - $expectedResult = ['"Test" is a required value.']; - $result = $this->_model->validateValue($inputValue); - $this->assertEquals($expectedResult, [(string)$result[0]]); + return $attribute; } } diff --git a/app/code/Magento/Eav/Test/Unit/Model/ResourceModel/Entity/Attribute/CollectionTest.php b/app/code/Magento/Eav/Test/Unit/Model/ResourceModel/Entity/Attribute/CollectionTest.php index 138e1363bb6dd..4a0fd5469767e 100644 --- a/app/code/Magento/Eav/Test/Unit/Model/ResourceModel/Entity/Attribute/CollectionTest.php +++ b/app/code/Magento/Eav/Test/Unit/Model/ResourceModel/Entity/Attribute/CollectionTest.php @@ -150,8 +150,8 @@ public function testSetInAllAttributeSetsFilter() $this->selectMock->expects($this->atLeastOnce())->method('group')->with('entity_attribute.attribute_id') ->willReturnSelf(); - $this->selectMock->expects($this->atLeastOnce())->method('having')->with('count = ' . count($setIds)) - ->willReturnSelf(); + $this->selectMock->expects($this->atLeastOnce())->method('having') + ->with(new \Zend_Db_Expr('COUNT(*)') . ' = ' . count($setIds))->willReturnSelf(); $this->model->setInAllAttributeSetsFilter($setIds); } diff --git a/app/code/Magento/EavGraphQl/Test/Mftf/composer.json b/app/code/Magento/EavGraphQl/Test/Mftf/composer.json deleted file mode 100644 index f0390a211f3dc..0000000000000 --- a/app/code/Magento/EavGraphQl/Test/Mftf/composer.json +++ /dev/null @@ -1,19 +0,0 @@ -{ - "name": "magento/functional-test-module-eav-graph-ql", - "description": "N/A", - "config": { - "sort-packages": true - }, - "require": { - "php": "~7.1.3||~7.2.0", - "magento/magento2-functional-testing-framework": "2.2.0" - }, - "suggest": { - "magento/functional-test-module-graph-ql": "100.0.0-dev" - }, - "type": "magento2-test", - "license": [ - "OSL-3.0", - "AFL-3.0" - ] -} diff --git a/app/code/Magento/Elasticsearch/Elasticsearch5/Model/Adapter/FieldMapper/ProductFieldMapper.php b/app/code/Magento/Elasticsearch/Elasticsearch5/Model/Adapter/FieldMapper/ProductFieldMapper.php index 8590c9b58786e..09357216d2067 100644 --- a/app/code/Magento/Elasticsearch/Elasticsearch5/Model/Adapter/FieldMapper/ProductFieldMapper.php +++ b/app/code/Magento/Elasticsearch/Elasticsearch5/Model/Adapter/FieldMapper/ProductFieldMapper.php @@ -69,7 +69,9 @@ public function __construct( } /** - * {@inheritdoc} + * @param string $attributeCode + * @param array $context + * @return string */ public function getFieldName($attributeCode, $context = []) { @@ -105,8 +107,10 @@ public function getFieldName($attributeCode, $context = []) } /** - * {@inheritdoc} + * @param array $context + * @return array * @SuppressWarnings(PHPMD.CyclomaticComplexity) + * @SuppressWarnings(PHPMD.UnusedFormalParameter) */ public function getAllAttributesTypes($context = []) { @@ -173,8 +177,14 @@ protected function isAttributeUsedInAdvancedSearch($attribute) */ protected function getRefinedFieldName($frontendInput, $fieldType, $attributeCode) { - return (in_array($frontendInput, ['select', 'boolean'], true) && $fieldType === 'integer') - ? $attributeCode . '_value' : $attributeCode; + switch ($frontendInput) { + case 'select': + return in_array($fieldType, ['text','integer'], true) ? $attributeCode . '_value' : $attributeCode; + case 'boolean': + return $fieldType === 'integer' ? $attributeCode . '_value' : $attributeCode; + default: + return $attributeCode; + } } /** diff --git a/app/code/Magento/Elasticsearch/Elasticsearch5/Model/Client/Elasticsearch.php b/app/code/Magento/Elasticsearch/Elasticsearch5/Model/Client/Elasticsearch.php index c0ecaadaea504..39b2f772c8e8f 100644 --- a/app/code/Magento/Elasticsearch/Elasticsearch5/Model/Client/Elasticsearch.php +++ b/app/code/Magento/Elasticsearch/Elasticsearch5/Model/Client/Elasticsearch.php @@ -3,7 +3,6 @@ * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ - namespace Magento\Elasticsearch\Elasticsearch5\Model\Client; use Magento\Framework\Exception\LocalizedException; @@ -15,21 +14,21 @@ class Elasticsearch implements ClientInterface { /** - * Elasticsearch Client instance + * Elasticsearch Client instances * - * @var \Elasticsearch\Client + * @var \Elasticsearch\Client[] */ - protected $client; + private $client; /** * @var array */ - protected $clientOptions; + private $clientOptions; /** * @var bool */ - protected $pingResult; + private $pingResult; /** * @var string @@ -48,7 +47,7 @@ public function __construct( $elasticsearchClient = null ) { if (empty($options['hostname']) || ((!empty($options['enableAuth']) && - ($options['enableAuth'] == 1)) && (empty($options['username']) || empty($options['password'])))) { + ($options['enableAuth'] == 1)) && (empty($options['username']) || empty($options['password'])))) { throw new LocalizedException( __('The search failed because of a search engine misconfiguration.') ); @@ -58,10 +57,25 @@ public function __construct( $config = $this->buildConfig($options); $elasticsearchClient = \Elasticsearch\ClientBuilder::fromConfig($config, true); } - $this->client = $elasticsearchClient; + $this->client[getmypid()] = $elasticsearchClient; $this->clientOptions = $options; } + /** + * Get Elasticsearch Client + * + * @return \Elasticsearch\Client + */ + private function getClient() + { + $pid = getmypid(); + if (!isset($this->client[$pid])) { + $config = $this->buildConfig($this->clientOptions); + $this->client[$pid] = \Elasticsearch\ClientBuilder::fromConfig($config, true); + } + return $this->client[$pid]; + } + /** * Ping the Elasticsearch client * @@ -70,7 +84,7 @@ public function __construct( public function ping() { if ($this->pingResult === null) { - $this->pingResult = $this->client->ping(['client' => ['timeout' => $this->clientOptions['timeout']]]); + $this->pingResult = $this->getClient()->ping(['client' => ['timeout' => $this->clientOptions['timeout']]]); } return $this->pingResult; @@ -116,7 +130,7 @@ private function buildConfig($options = []) */ public function bulkQuery($query) { - $this->client->bulk($query); + $this->getClient()->bulk($query); } /** @@ -128,7 +142,7 @@ public function bulkQuery($query) */ public function createIndex($index, $settings) { - $this->client->indices()->create([ + $this->getClient()->indices()->create([ 'index' => $index, 'body' => $settings, ]); @@ -142,7 +156,7 @@ public function createIndex($index, $settings) */ public function deleteIndex($index) { - $this->client->indices()->delete(['index' => $index]); + $this->getClient()->indices()->delete(['index' => $index]); } /** @@ -153,7 +167,7 @@ public function deleteIndex($index) */ public function isEmptyIndex($index) { - $stats = $this->client->indices()->stats(['index' => $index, 'metric' => 'docs']); + $stats = $this->getClient()->indices()->stats(['index' => $index, 'metric' => 'docs']); if ($stats['indices'][$index]['primaries']['docs']['count'] == 0) { return true; } @@ -178,7 +192,7 @@ public function updateAlias($alias, $newIndex, $oldIndex = '') $params['body']['actions'][] = ['add' => ['alias' => $alias, 'index' => $newIndex]]; } - $this->client->indices()->updateAliases($params); + $this->getClient()->indices()->updateAliases($params); } /** @@ -189,7 +203,7 @@ public function updateAlias($alias, $newIndex, $oldIndex = '') */ public function indexExists($index) { - return $this->client->indices()->exists(['index' => $index]); + return $this->getClient()->indices()->exists(['index' => $index]); } /** @@ -204,7 +218,7 @@ public function existsAlias($alias, $index = '') if ($index) { $params['index'] = $index; } - return $this->client->indices()->existsAlias($params); + return $this->getClient()->indices()->existsAlias($params); } /** @@ -214,7 +228,7 @@ public function existsAlias($alias, $index = '') */ public function getAlias($alias) { - return $this->client->indices()->getAlias(['name' => $alias]); + return $this->getClient()->indices()->getAlias(['name' => $alias]); } /** @@ -274,7 +288,7 @@ public function addFieldsMapping(array $fields, $index, $entityType) $params['body'][$entityType]['properties'][$field] = $this->prepareFieldInfo($fieldInfo); } - $this->client->indices()->putMapping($params); + $this->getClient()->indices()->putMapping($params); } /** @@ -311,7 +325,7 @@ private function prepareFieldInfo($fieldInfo) */ public function deleteMapping($index, $entityType) { - $this->client->indices()->deleteMapping([ + $this->getClient()->indices()->deleteMapping([ 'index' => $index, 'type' => $entityType, ]); @@ -327,7 +341,7 @@ public function query($query) { $query = $this->prepareSearchQuery($query); - return $this->client->search($query); + return $this->getClient()->search($query); } /** @@ -358,7 +372,7 @@ private function prepareSearchQuery($query) */ public function suggest($query) { - return $this->client->suggest($query); + return $this->getClient()->suggest($query); } /** @@ -369,7 +383,7 @@ public function suggest($query) private function getServerVersion() { if ($this->serverVersion === null) { - $info = $this->client->info(); + $info = $this->getClient()->info(); $this->serverVersion = $info['version']['number']; } diff --git a/app/code/Magento/Elasticsearch/Model/Adapter/FieldMapper/ProductFieldMapper.php b/app/code/Magento/Elasticsearch/Model/Adapter/FieldMapper/ProductFieldMapper.php index d0258286b6484..2a8ccdb5c72ac 100644 --- a/app/code/Magento/Elasticsearch/Model/Adapter/FieldMapper/ProductFieldMapper.php +++ b/app/code/Magento/Elasticsearch/Model/Adapter/FieldMapper/ProductFieldMapper.php @@ -42,7 +42,9 @@ public function __construct( } /** - * {@inheritdoc} + * @param string $attributeCode + * @param array $context + * @return string */ public function getFieldName($attributeCode, $context = []) { @@ -78,7 +80,8 @@ public function getFieldName($attributeCode, $context = []) } /** - * {@inheritdoc} + * @param array $context + * @return array */ public function getAllAttributesTypes($context = []) { @@ -115,4 +118,22 @@ public function getAllAttributesTypes($context = []) return $allAttributes; } + + /** + * @param string $frontendInput + * @param string $fieldType + * @param string $attributeCode + * @return string + */ + protected function getRefinedFieldName($frontendInput, $fieldType, $attributeCode) + { + switch ($frontendInput) { + case 'select': + return in_array($fieldType, ['string','integer'], true) ? $attributeCode . '_value' : $attributeCode; + case 'boolean': + return $fieldType === 'integer' ? $attributeCode . '_value' : $attributeCode; + default: + return $attributeCode; + } + } } diff --git a/app/code/Magento/Elasticsearch/Model/Client/Elasticsearch.php b/app/code/Magento/Elasticsearch/Model/Client/Elasticsearch.php index 118535c36560b..44ab0dbc4d46c 100644 --- a/app/code/Magento/Elasticsearch/Model/Client/Elasticsearch.php +++ b/app/code/Magento/Elasticsearch/Model/Client/Elasticsearch.php @@ -15,21 +15,21 @@ class Elasticsearch implements ClientInterface { /** - * Elasticsearch Client instance + * Elasticsearch Client instances * * @var \Elasticsearch\Client[] */ - protected $client; + private $client; /** * @var array */ - protected $clientOptions; + private $clientOptions; /** * @var bool */ - protected $pingResult; + private $pingResult; /** * Initialize Elasticsearch Client @@ -57,6 +57,11 @@ public function __construct( $this->clientOptions = $options; } + /** + * Get Elasticsearch Client + * + * @return \Elasticsearch\Client + */ private function getClient() { $pid = getmypid(); @@ -66,6 +71,7 @@ private function getClient() } return $this->client[$pid]; } + /** * Ping the Elasticsearch client * diff --git a/app/code/Magento/Elasticsearch/Model/ResourceModel/Index.php b/app/code/Magento/Elasticsearch/Model/ResourceModel/Index.php index 49489f1cdb43d..d75bb9c8ccd34 100644 --- a/app/code/Magento/Elasticsearch/Model/ResourceModel/Index.php +++ b/app/code/Magento/Elasticsearch/Model/ResourceModel/Index.php @@ -5,6 +5,7 @@ */ namespace Magento\Elasticsearch\Model\ResourceModel; +use Magento\Catalog\Model\Indexer\Product\Price\DimensionCollectionFactory; use Magento\Framework\Model\ResourceModel\Db\Context; use Magento\Store\Model\StoreManagerInterface; use Magento\Catalog\Api\ProductRepositoryInterface; @@ -12,6 +13,7 @@ use Magento\Eav\Model\Config; use Magento\Catalog\Api\Data\ProductAttributeInterface; use Magento\Framework\EntityManager\MetadataPool; +use Magento\Framework\Search\Request\IndexScopeResolverInterface as TableResolver; /** * Elasticsearch index resource model @@ -47,6 +49,8 @@ class Index extends \Magento\AdvancedSearch\Model\ResourceModel\Index * @param CategoryRepositoryInterface $categoryRepository * @param Config $eavConfig * @param null $connectionName + * @param TableResolver|null $tableResolver + * @param DimensionCollectionFactory|null $dimensionCollectionFactory * @SuppressWarnings(Magento.TypeDuplication) */ public function __construct( @@ -56,7 +60,9 @@ public function __construct( ProductRepositoryInterface $productRepository, CategoryRepositoryInterface $categoryRepository, Config $eavConfig, - $connectionName = null + $connectionName = null, + TableResolver $tableResolver = null, + DimensionCollectionFactory $dimensionCollectionFactory = null ) { $this->productRepository = $productRepository; $this->categoryRepository = $categoryRepository; @@ -65,7 +71,9 @@ public function __construct( $context, $storeManager, $metadataPool, - $connectionName + $connectionName, + $tableResolver, + $dimensionCollectionFactory ); } diff --git a/app/code/Magento/Elasticsearch/Test/Mftf/composer.json b/app/code/Magento/Elasticsearch/Test/Mftf/composer.json deleted file mode 100644 index 4f0b74e9c5660..0000000000000 --- a/app/code/Magento/Elasticsearch/Test/Mftf/composer.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "name": "magento/functional-test-module-elasticsearch", - "description": "N/A", - "config": { - "sort-packages": true - }, - "require": { - "php": "~7.1.3||~7.2.0", - "magento/functional-test-module-advanced-search": "100.0.0-dev", - "magento/functional-test-module-catalog": "100.0.0-dev", - "magento/functional-test-module-catalog-search": "100.0.0-dev", - "magento/functional-test-module-customer": "100.0.0-dev", - "magento/functional-test-module-eav": "100.0.0-dev", - "magento/functional-test-module-search": "100.0.0-dev", - "magento/functional-test-module-store": "100.0.0-dev", - "magento/functional-test-module-catalog-inventory": "100.0.0-dev", - "magento/magento2-functional-testing-framework": "2.2.0" - }, - "suggest": { - "magento/functional-test-module-config": "100.0.0-dev" - }, - "type": "magento2-test", - "license": [ - "proprietary" - ] -} diff --git a/app/code/Magento/Elasticsearch/Test/Unit/Elasticsearch5/Model/Adapter/FieldMapper/ProductFieldMapperTest.php b/app/code/Magento/Elasticsearch/Test/Unit/Elasticsearch5/Model/Adapter/FieldMapper/ProductFieldMapperTest.php index 2128ee57681a8..6ee32a58698c6 100644 --- a/app/code/Magento/Elasticsearch/Test/Unit/Elasticsearch5/Model/Adapter/FieldMapper/ProductFieldMapperTest.php +++ b/app/code/Magento/Elasticsearch/Test/Unit/Elasticsearch5/Model/Adapter/FieldMapper/ProductFieldMapperTest.php @@ -180,7 +180,9 @@ public function testGetFieldNameWithoutAttribute() /** * @dataProvider attributeProvider * @param string $attributeCode - * + * @param string $inputType + * @param array $searchAttributes + * @param array $expected * @return void */ public function testGetAllAttributesTypes($attributeCode, $inputType, $searchAttributes, $expected) @@ -227,17 +229,17 @@ public function testGetAllAttributesTypes($attributeCode, $inputType, $searchAtt public function attributeCodeProvider() { return [ - ['id', 'id', 'string'], - ['status', 'status', 'string'], - ['status', 'status', 'string', ['type'=>'default']], - ['price', 'price_0_1', 'string', ['type'=>'default']], - ['position', 'position_category_1', 'string', ['type'=>'default']], - ['price', 'price_2_3', 'string', ['type'=>'default', 'customerGroupId'=>'2', 'websiteId'=>'3']], - ['position', 'position_category_3', 'string', ['type'=>'default', 'categoryId'=>'3']], - ['color', 'color', 'select', ['type'=>'default']], - ['description', 'sort_description', 'string', ['type'=>'some']], - ['*', '_all', 'string', ['type'=>'text']], - ['description', 'description', 'string', ['type'=>'text']], + ['id', 'id', 'text'], + ['status', 'status', 'text'], + ['status', 'status_value', 'text', ['type'=>'default']], + ['price', 'price_0_1', 'text', ['type'=>'default']], + ['position', 'position_category_1', 'text', ['type'=>'default']], + ['price', 'price_2_3', 'text', ['type'=>'default', 'customerGroupId'=>'2', 'websiteId'=>'3']], + ['position', 'position_category_3', 'text', ['type'=>'default', 'categoryId'=>'3']], + ['color', 'color_value', 'text', ['type'=>'text']], + ['description', 'sort_description', 'text', ['type'=>'some']], + ['*', '_all', 'text', ['type'=>'text']], + ['description', 'description_value', 'text', ['type'=>'text']], ]; } diff --git a/app/code/Magento/Elasticsearch/Test/Unit/Model/Adapter/FieldMapper/ProductFieldMapperTest.php b/app/code/Magento/Elasticsearch/Test/Unit/Model/Adapter/FieldMapper/ProductFieldMapperTest.php new file mode 100644 index 0000000000000..8b7ac6abbb190 --- /dev/null +++ b/app/code/Magento/Elasticsearch/Test/Unit/Model/Adapter/FieldMapper/ProductFieldMapperTest.php @@ -0,0 +1,298 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +declare(strict_types=1); + +namespace Magento\Elasticsearch\Test\Unit\Model\Adapter\FieldMapper; + +use Magento\Catalog\Api\Data\ProductAttributeInterface; +use Magento\Elasticsearch\Model\Adapter\FieldType; +use Magento\Framework\TestFramework\Unit\Helper\ObjectManager as ObjectManagerHelper; + +class ProductFieldMapperTest extends \PHPUnit\Framework\TestCase +{ + /** + * @var \Magento\Elasticsearch\Model\Adapter\FieldMapper\ProductFieldMapper + */ + protected $mapper; + + /** + * @var \Magento\Eav\Model\Config|\PHPUnit_Framework_MockObject_MockObject + */ + protected $eavConfig; + + /** + * @var \Magento\Framework\Registry|\PHPUnit_Framework_MockObject_MockObject + */ + protected $coreRegistry; + + /** + * @var \Magento\Customer\Model\Session|\PHPUnit_Framework_MockObject_MockObject + */ + protected $customerSession; + + /** + * @var \Magento\Store\Model\StoreManagerInterface|\PHPUnit_Framework_MockObject_MockObject + */ + protected $storeManager; + + /** + * @var \Magento\Catalog\Model\ResourceModel\Eav\Attribute|\PHPUnit_Framework_MockObject_MockObject + */ + protected $eavAttributeResource; + + /** + * @var FieldType|\PHPUnit_Framework_MockObject_MockObject + */ + protected $fieldType; + + /** + * @var \Magento\Store\Model\StoreManagerInterface|\PHPUnit_Framework_MockObject_MockObject + */ + protected $store; + + /** + * Set up test environment + * + * @return void + */ + protected function setUp() + { + $this->eavConfig = $this->getMockBuilder(\Magento\Eav\Model\Config::class) + ->disableOriginalConstructor() + ->setMethods(['getEntityType', 'getAttribute', 'getEntityAttributeCodes']) + ->getMock(); + + $this->fieldType = $this->getMockBuilder(FieldType::class) + ->disableOriginalConstructor() + ->setMethods(['getFieldType']) + ->getMock(); + + $this->customerSession = $this->getMockBuilder(\Magento\Customer\Model\Session::class) + ->disableOriginalConstructor() + ->setMethods(['getCustomerGroupId']) + ->getMock(); + + $this->storeManager = $this->storeManager = $this->getMockForAbstractClass( + \Magento\Store\Model\StoreManagerInterface::class, + [], + '', + false + ); + + $this->store = $this->getMockForAbstractClass( + \Magento\Store\Api\Data\StoreInterface::class, + [], + '', + false, + false, + true, + ['getWebsiteId', 'getRootCategoryId'] + ); + + $this->coreRegistry = $this->createMock(\Magento\Framework\Registry::class); + + $objectManager = new ObjectManagerHelper($this); + + $this->eavAttributeResource = $this->createPartialMock( + \Magento\Catalog\Model\ResourceModel\Eav\Attribute::class, + [ + '__wakeup', + 'getBackendType', + 'getFrontendInput' + ] + ); + + $this->mapper = $objectManager->getObject( + \Magento\Elasticsearch\Model\Adapter\FieldMapper\ProductFieldMapper::class, + [ + 'eavConfig' => $this->eavConfig, + 'storeManager' => $this->storeManager, + 'fieldType' => $this->fieldType, + 'customerSession' => $this->customerSession, + 'coreRegistry' => $this->coreRegistry + ] + ); + } + + /** + * @dataProvider attributeCodeProvider + * @param string $attributeCode + * @param string $fieldName + * @param string $fieldType + * @param array $context + * + * @return void + */ + public function testGetFieldName($attributeCode, $fieldName, $fieldType, $context = []) + { + $attributeMock = $this->getMockBuilder(\Magento\Catalog\Model\ResourceModel\Eav\Attribute::class) + ->setMethods(['getBackendType', 'getFrontendInput', 'getAttribute']) + ->disableOriginalConstructor() + ->getMock(); + + $this->customerSession->expects($this->any()) + ->method('getCustomerGroupId') + ->willReturn('0'); + + $this->storeManager->expects($this->any()) + ->method('getStore') + ->willReturn($this->store); + $this->store->expects($this->any()) + ->method('getWebsiteId') + ->willReturn('1'); + $this->store->expects($this->any()) + ->method('getRootCategoryId') + ->willReturn('1'); + + $this->eavConfig->expects($this->any())->method('getAttribute') + ->with(ProductAttributeInterface::ENTITY_TYPE_CODE, $attributeCode) + ->willReturn($attributeMock); + + $attributeMock->expects($this->any())->method('getFrontendInput') + ->will($this->returnValue('select')); + + $this->fieldType->expects($this->any())->method('getFieldType') + ->with($attributeMock) + ->willReturn($fieldType); + + $this->assertEquals( + $fieldName, + $this->mapper->getFieldName($attributeCode, $context) + ); + } + + /** + * @return void + */ + public function testGetFieldNameWithoutAttribute() + { + $this->eavConfig->expects($this->any())->method('getAttribute') + ->with(ProductAttributeInterface::ENTITY_TYPE_CODE, 'attr1') + ->willReturn(''); + + $this->assertEquals( + 'attr1', + $this->mapper->getFieldName('attr1', []) + ); + } + + /** + * @dataProvider attributeProvider + * @param string $attributeCode + * @param string $inputType + * @param array $searchAttributes + * @param array $expected + * @return void + */ + public function testGetAllAttributesTypes($attributeCode, $inputType, $searchAttributes, $expected) + { + $attributeMock = $this->getMockBuilder(\Magento\Catalog\Model\ResourceModel\Eav\Attribute::class) + ->disableOriginalConstructor() + ->getMock(); + + $this->eavConfig->expects($this->any())->method('getEntityAttributeCodes') + ->with(ProductAttributeInterface::ENTITY_TYPE_CODE) + ->willReturn([$attributeCode]); + + $this->eavConfig->expects($this->any())->method('getAttribute') + ->with(ProductAttributeInterface::ENTITY_TYPE_CODE, $attributeCode) + ->willReturn($attributeMock); + + $this->fieldType->expects($this->once())->method('getFieldType')->willReturn(FieldType::ES_DATA_TYPE_INT); + + $attributeMock->expects($this->any()) + ->method('getIsSearchable') + ->willReturn($searchAttributes['searchable']); + $attributeMock->expects($this->any()) + ->method('getIsFilterable') + ->willReturn($searchAttributes['filterable']); + $attributeMock->expects($this->any()) + ->method('getIsFilterableInSearch') + ->willReturn($searchAttributes['filterableInSearch']); + $attributeMock->expects($this->any()) + ->method('getIsVisibleInAdvancedSearch') + ->willReturn($searchAttributes['advSearch']); + + $attributeMock->expects($this->any())->method('getFrontendInput') + ->will($this->returnValue($inputType)); + + $this->assertEquals( + $expected, + $this->mapper->getAllAttributesTypes() + ); + } + + /** + * @return array + */ + public function attributeCodeProvider() + { + return [ + ['id', 'id', 'string'], + ['status', 'status', 'string'], + ['status', 'status_value', 'string', ['type'=>'default']], + ['price', 'price_0_1', 'string', ['type'=>'default']], + ['position', 'position_category_1', 'string', ['type'=>'default']], + ['price', 'price_2_3', 'string', ['type'=>'default', 'customerGroupId'=>'2', 'websiteId'=>'3']], + ['position', 'position_category_3', 'string', ['type'=>'default', 'categoryId'=>'3']], + ['color', 'color_value', 'string', ['type'=>'text']], + ['description', 'sort_description', 'string', ['type'=>'some']], + ['*', '_all', 'string', ['type'=>'text']], + ['description', 'description_value', 'string', ['type'=>'text']], + ]; + } + + /** + * @return array + */ + public function attributeProvider() + { + return [ + [ + 'category_ids', + 'text', + ['searchable' => false, 'filterable' => false, 'filterableInSearch' => false, 'advSearch' => false], + ['category_ids' => ['type' => 'integer']] + ], + [ + 'attr_code', + 'string', + ['searchable' => false, 'filterable' => false, 'filterableInSearch' => false, 'advSearch' => false], + ['attr_code' => ['type' => 'integer', 'index' => 'no']] + ], + [ + 'attr_code', + 'string', + ['searchable' => '0', 'filterable' => '0', 'filterableInSearch' => '0', 'advSearch' => '0'], + ['attr_code' => ['type' => 'integer', 'index' => 'no']] + ], + [ + 'attr_code', + 'string', + ['searchable' => true, 'filterable' => false, 'filterableInSearch' => false, 'advSearch' => false], + ['attr_code' => ['type' => 'integer']] + ], + [ + 'attr_code', + 'string', + ['searchable' => '1', 'filterable' => '0', 'filterableInSearch' => '0', 'advSearch' => '0'], + ['attr_code' => ['type' => 'integer']] + ], + [ + 'attr_code', + 'string', + ['searchable' => false, 'filterable' => false, 'filterableInSearch' => false, 'advSearch' => true], + ['attr_code' => ['type' => 'integer']] + ], + [ + 'attr_code', + 'string', + ['searchable' => '0', 'filterable' => '0', 'filterableInSearch' => '1', 'advSearch' => '0'], + ['attr_code' => ['type' => 'integer']] + ], + ]; + } +} diff --git a/app/code/Magento/Elasticsearch/Test/Unit/Model/ResourceModel/IndexTest.php b/app/code/Magento/Elasticsearch/Test/Unit/Model/ResourceModel/IndexTest.php index c11fb64cde7e6..bac2b7ea28908 100644 --- a/app/code/Magento/Elasticsearch/Test/Unit/Model/ResourceModel/IndexTest.php +++ b/app/code/Magento/Elasticsearch/Test/Unit/Model/ResourceModel/IndexTest.php @@ -239,6 +239,20 @@ protected function setUp() ] ); + $traversableMock = $this->createMock(\Traversable::class); + $dimensionsMock = $this->createMock(\Magento\Framework\Indexer\MultiDimensionProvider::class); + $dimensionsMock->method('getIterator')->willReturn($traversableMock); + + $indexScopeResolverMock = $this->createMock( + \Magento\Framework\Search\Request\IndexScopeResolverInterface::class + ); + + $dimensionFactoryMock = $this->createMock( + \Magento\Catalog\Model\Indexer\Product\Price\DimensionCollectionFactory::class + ); + $dimensionFactoryMock->method('create')->willReturn($dimensionsMock); + $indexScopeResolverMock->method('resolve')->willReturn('catalog_product_index_price'); + $this->model = $objectManager->getObject( \Magento\Elasticsearch\Model\ResourceModel\Index::class, [ @@ -249,7 +263,8 @@ protected function setUp() 'categoryRepository' => $this->categoryRepository, 'eavConfig' => $this->eavConfig, 'connectionName' => 'default', - 'tableResolver' => $this->tableResolver + 'tableResolver' => $this->tableResolver, + 'dimensionCollectionFactory' => $dimensionFactoryMock, ] ); } diff --git a/app/code/Magento/Elasticsearch/composer.json b/app/code/Magento/Elasticsearch/composer.json index a6b4f93ade579..a821506f5ef6e 100644 --- a/app/code/Magento/Elasticsearch/composer.json +++ b/app/code/Magento/Elasticsearch/composer.json @@ -19,7 +19,8 @@ }, "type": "magento2-module", "license": [ - "proprietary" + "OSL-3.0", + "AFL-3.0" ], "autoload": { "files": [ diff --git a/app/code/Magento/Email/Test/Mftf/composer.json b/app/code/Magento/Email/Test/Mftf/composer.json deleted file mode 100644 index 9f9b087c5fc15..0000000000000 --- a/app/code/Magento/Email/Test/Mftf/composer.json +++ /dev/null @@ -1,25 +0,0 @@ -{ - "name": "magento/functional-test-module-email", - "description": "N/A", - "config": { - "sort-packages": true - }, - "require": { - "php": "~7.1.3||~7.2.0", - "magento/magento2-functional-testing-framework": "2.2.0", - "magento/functional-test-module-backend": "100.0.0-dev", - "magento/functional-test-module-cms": "100.0.0-dev", - "magento/functional-test-module-config": "100.0.0-dev", - "magento/functional-test-module-store": "100.0.0-dev", - "magento/functional-test-module-theme": "100.0.0-dev", - "magento/functional-test-module-variable": "100.0.0-dev" - }, - "suggest": { - "magento/functional-test-module-theme": "100.0.0-dev" - }, - "type": "magento2-test", - "license": [ - "OSL-3.0", - "AFL-3.0" - ] -} diff --git a/app/code/Magento/EncryptionKey/Test/Mftf/composer.json b/app/code/Magento/EncryptionKey/Test/Mftf/composer.json deleted file mode 100644 index 732a18753779f..0000000000000 --- a/app/code/Magento/EncryptionKey/Test/Mftf/composer.json +++ /dev/null @@ -1,17 +0,0 @@ -{ - "name": "magento/functional-test-module-encryption-key", - "description": "N/A", - "config": { - "sort-packages": true - }, - "require": { - "php": "~7.1.3||~7.2.0", - "magento/magento2-functional-testing-framework": "2.2.0", - "magento/functional-test-module-backend": "100.0.0-dev", - "magento/functional-test-module-config": "100.0.0-dev" - }, - "type": "magento2-test", - "license": [ - "proprietary" - ] -} diff --git a/app/code/Magento/EncryptionKey/composer.json b/app/code/Magento/EncryptionKey/composer.json index 0bf0728606684..4a140c4b1315e 100644 --- a/app/code/Magento/EncryptionKey/composer.json +++ b/app/code/Magento/EncryptionKey/composer.json @@ -12,7 +12,8 @@ }, "type": "magento2-module", "license": [ - "proprietary" + "OSL-3.0", + "AFL-3.0" ], "autoload": { "files": [ diff --git a/app/code/Magento/Fedex/Model/Carrier.php b/app/code/Magento/Fedex/Model/Carrier.php index 8841cdd4f9a8b..f6e63e04ac559 100644 --- a/app/code/Magento/Fedex/Model/Carrier.php +++ b/app/code/Magento/Fedex/Model/Carrier.php @@ -7,8 +7,10 @@ namespace Magento\Fedex\Model; use Magento\Framework\App\ObjectManager; +use Magento\Framework\DataObject; use Magento\Framework\Module\Dir; use Magento\Framework\Serialize\Serializer\Json; +use Magento\Framework\Webapi\Soap\ClientFactory; use Magento\Framework\Xml\Security; use Magento\Quote\Model\Quote\Address\RateRequest; use Magento\Shipping\Model\Carrier\AbstractCarrierOnline; @@ -17,7 +19,6 @@ /** * Fedex shipping implementation * - * @author Magento Core Team <core@magentocommerce.com> * @SuppressWarnings(PHPMD.ExcessiveClassComplexity) * @SuppressWarnings(PHPMD.CouplingBetweenObjects) */ @@ -143,6 +144,11 @@ class Carrier extends AbstractCarrierOnline implements \Magento\Shipping\Model\C */ private $serializer; + /** + * @var ClientFactory + */ + private $soapClientFactory; + /** * @param \Magento\Framework\App\Config\ScopeConfigInterface $scopeConfig * @param \Magento\Quote\Model\Quote\Address\RateResult\ErrorFactory $rateErrorFactory @@ -164,7 +170,7 @@ class Carrier extends AbstractCarrierOnline implements \Magento\Shipping\Model\C * @param \Magento\Catalog\Model\ResourceModel\Product\CollectionFactory $productCollectionFactory * @param array $data * @param Json|null $serializer - * + * @param ClientFactory|null $soapClientFactory * @SuppressWarnings(PHPMD.ExcessiveParameterList) */ public function __construct( @@ -187,7 +193,8 @@ public function __construct( \Magento\Framework\Module\Dir\Reader $configReader, \Magento\Catalog\Model\ResourceModel\Product\CollectionFactory $productCollectionFactory, array $data = [], - Json $serializer = null + Json $serializer = null, + ClientFactory $soapClientFactory = null ) { $this->_storeManager = $storeManager; $this->_productCollectionFactory = $productCollectionFactory; @@ -214,6 +221,7 @@ public function __construct( $this->_rateServiceWsdl = $wsdlBasePath . 'RateService_v10.wsdl'; $this->_trackServiceWsdl = $wsdlBasePath . 'TrackService_v' . self::$trackServiceVersion . '.wsdl'; $this->serializer = $serializer ?: ObjectManager::getInstance()->get(Json::class); + $this->soapClientFactory = $soapClientFactory ?: ObjectManager::getInstance()->get(ClientFactory::class); } /** @@ -225,7 +233,7 @@ public function __construct( */ protected function _createSoapClient($wsdl, $trace = false) { - $client = new \SoapClient($wsdl, ['trace' => $trace]); + $client = $this->soapClientFactory->create($wsdl, ['trace' => $trace]); $client->__setLocation( $this->getConfigFlag( 'sandbox_mode' @@ -1263,7 +1271,7 @@ protected function _formShipmentRequest(\Magento\Framework\DataObject $request) $countriesOfManufacture[] = $product->getCountryOfManufacture(); } - $paymentType = $request->getIsReturn() ? 'RECIPIENT' : 'SENDER'; + $paymentType = $this->getPaymentType($request); $optionType = $request->getShippingMethod() == self::RATE_REQUEST_SMARTPOST ? 'SERVICE_DEFAULT' : $packageParams->getDeliveryConfirmation(); $requestClient = [ @@ -1749,4 +1757,18 @@ private function parseDate($timestamp) return false; } + + /** + * Defines payment type by request. + * Two values are available: RECIPIENT or SENDER. + * + * @param DataObject $request + * @return string + */ + private function getPaymentType(DataObject $request): string + { + return $request->getIsReturn() && $request->getShippingMethod() !== self::RATE_REQUEST_SMARTPOST + ? 'RECIPIENT' + : 'SENDER'; + } } diff --git a/app/code/Magento/Fedex/Test/Mftf/composer.json b/app/code/Magento/Fedex/Test/Mftf/composer.json deleted file mode 100644 index 6152c679ec796..0000000000000 --- a/app/code/Magento/Fedex/Test/Mftf/composer.json +++ /dev/null @@ -1,24 +0,0 @@ -{ - "name": "magento/functional-test-module-fedex", - "description": "N/A", - "config": { - "sort-packages": true - }, - "require": { - "php": "~7.1.3||~7.2.0", - "magento/magento2-functional-testing-framework": "2.2.0", - "magento/functional-test-module-catalog": "100.0.0-dev", - "magento/functional-test-module-catalog-inventory": "100.0.0-dev", - "magento/functional-test-module-config": "100.0.0-dev", - "magento/functional-test-module-directory": "100.0.0-dev", - "magento/functional-test-module-quote": "100.0.0-dev", - "magento/functional-test-module-sales": "100.0.0-dev", - "magento/functional-test-module-shipping": "100.0.0-dev", - "magento/functional-test-module-store": "100.0.0-dev" - }, - "type": "magento2-test", - "license": [ - "OSL-3.0", - "AFL-3.0" - ] -} diff --git a/app/code/Magento/GiftMessage/Observer/SalesEventQuoteMerge.php b/app/code/Magento/GiftMessage/Observer/SalesEventQuoteMerge.php new file mode 100644 index 0000000000000..0d2280d29fed4 --- /dev/null +++ b/app/code/Magento/GiftMessage/Observer/SalesEventQuoteMerge.php @@ -0,0 +1,35 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +declare(strict_types=1); + +namespace Magento\GiftMessage\Observer; + +use Magento\Framework\Event\ObserverInterface; +use Magento\Quote\Model\Quote; + +/** + * Gift Message Observer Model + */ +class SalesEventQuoteMerge implements ObserverInterface +{ + /** + * Sets gift message to customer quote from guest quote. + * + * @param \Magento\Framework\Event\Observer $observer + * @return $this + */ + public function execute(\Magento\Framework\Event\Observer $observer) + { + /** @var Quote $targetQuote */ + $targetQuote = $observer->getData('quote'); + /** @var Quote $sourceQuote */ + $sourceQuote = $observer->getData('source'); + + $targetQuote->setGiftMessageId($sourceQuote->getGiftMessageId()); + + return $this; + } +} diff --git a/app/code/Magento/GiftMessage/Test/Mftf/composer.json b/app/code/Magento/GiftMessage/Test/Mftf/composer.json deleted file mode 100644 index 06f8c507d25c9..0000000000000 --- a/app/code/Magento/GiftMessage/Test/Mftf/composer.json +++ /dev/null @@ -1,27 +0,0 @@ -{ - "name": "magento/functional-test-module-gift-message", - "description": "N/A", - "config": { - "sort-packages": true - }, - "require": { - "php": "~7.1.3||~7.2.0", - "magento/magento2-functional-testing-framework": "2.2.0", - "magento/functional-test-module-backend": "100.0.0-dev", - "magento/functional-test-module-catalog": "100.0.0-dev", - "magento/functional-test-module-checkout": "100.0.0-dev", - "magento/functional-test-module-customer": "100.0.0-dev", - "magento/functional-test-module-quote": "100.0.0-dev", - "magento/functional-test-module-sales": "100.0.0-dev", - "magento/functional-test-module-store": "100.0.0-dev", - "magento/functional-test-module-ui": "100.0.0-dev" - }, - "suggest": { - "magento/functional-test-module-multishipping": "100.0.0-dev" - }, - "type": "magento2-test", - "license": [ - "OSL-3.0", - "AFL-3.0" - ] -} diff --git a/app/code/Magento/GiftMessage/etc/frontend/events.xml b/app/code/Magento/GiftMessage/etc/frontend/events.xml index 3af69730838ad..c786373b2094f 100644 --- a/app/code/Magento/GiftMessage/etc/frontend/events.xml +++ b/app/code/Magento/GiftMessage/etc/frontend/events.xml @@ -12,6 +12,9 @@ <event name="sales_convert_order_to_quote"> <observer name="giftmessage" instance="Magento\GiftMessage\Observer\SalesEventOrderToQuoteObserver" shared="false" /> </event> + <event name="sales_quote_merge_after"> + <observer name="giftmessage" instance="Magento\GiftMessage\Observer\SalesEventQuoteMerge" shared="false" /> + </event> <event name="checkout_type_multishipping_create_orders_single"> <observer name="giftmessage" instance="Magento\GiftMessage\Observer\MultishippingEventCreateOrdersObserver" shared="false" /> </event> diff --git a/app/code/Magento/GoogleAdwords/Test/Mftf/composer.json b/app/code/Magento/GoogleAdwords/Test/Mftf/composer.json deleted file mode 100644 index d40fb323175fe..0000000000000 --- a/app/code/Magento/GoogleAdwords/Test/Mftf/composer.json +++ /dev/null @@ -1,18 +0,0 @@ -{ - "name": "magento/functional-test-module-google-adwords", - "description": "N/A", - "config": { - "sort-packages": true - }, - "require": { - "php": "~7.1.3||~7.2.0", - "magento/magento2-functional-testing-framework": "2.2.0", - "magento/functional-test-module-sales": "100.0.0-dev", - "magento/functional-test-module-store": "100.0.0-dev" - }, - "type": "magento2-test", - "license": [ - "OSL-3.0", - "AFL-3.0" - ] -} diff --git a/app/code/Magento/GoogleAnalytics/Test/Mftf/composer.json b/app/code/Magento/GoogleAnalytics/Test/Mftf/composer.json deleted file mode 100644 index 3413ffcac6e42..0000000000000 --- a/app/code/Magento/GoogleAnalytics/Test/Mftf/composer.json +++ /dev/null @@ -1,22 +0,0 @@ -{ - "name": "magento/functional-test-module-google-analytics", - "description": "N/A", - "config": { - "sort-packages": true - }, - "require": { - "php": "~7.1.3||~7.2.0", - "magento/magento2-functional-testing-framework": "2.2.0", - "magento/functional-test-module-cookie": "100.0.0-dev", - "magento/functional-test-module-sales": "100.0.0-dev", - "magento/functional-test-module-store": "100.0.0-dev" - }, - "suggest": { - "magento/functional-test-module-config": "100.0.0-dev" - }, - "type": "magento2-test", - "license": [ - "OSL-3.0", - "AFL-3.0" - ] -} diff --git a/app/code/Magento/GoogleAnalytics/Test/Unit/Observer/SetGoogleAnalyticsOnOrderSuccessPageViewObserverTest.php b/app/code/Magento/GoogleAnalytics/Test/Unit/Observer/SetGoogleAnalyticsOnOrderSuccessPageViewObserverTest.php new file mode 100644 index 0000000000000..a883b0dab8c3b --- /dev/null +++ b/app/code/Magento/GoogleAnalytics/Test/Unit/Observer/SetGoogleAnalyticsOnOrderSuccessPageViewObserverTest.php @@ -0,0 +1,132 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +declare(strict_types=1); + +namespace Magento\GoogleAnalytics\Test\Unit\Observer; + +use Magento\Framework\Event; +use Magento\Framework\Event\Observer; +use Magento\Framework\TestFramework\Unit\Helper\ObjectManager; +use Magento\Framework\View\Element\AbstractBlock; +use Magento\Framework\View\LayoutInterface; +use Magento\GoogleAnalytics\Helper\Data as GaDataHelper; +use Magento\GoogleAnalytics\Observer\SetGoogleAnalyticsOnOrderSuccessPageViewObserver; +use Magento\Store\Model\StoreManagerInterface; +use PHPUnit\Framework\TestCase; + +class SetGoogleAnalyticsOnOrderSuccessPageViewObserverTest extends TestCase +{ + /** + * @var Event|\PHPUnit_Framework_MockObject_MockObject + */ + private $eventMock; + + /** + * @var Observer|\PHPUnit_Framework_MockObject_MockObject + */ + private $observerMock; + + /** + * @var GaDataHelper|\PHPUnit_Framework_MockObject_MockObject + */ + private $googleAnalyticsDataMock; + + /** + * @var LayoutInterface|\PHPUnit_Framework_MockObject_MockObject + */ + private $layoutMock; + + /** + * @var StoreManagerInterface|\PHPUnit_Framework_MockObject_MockObject + */ + private $storeManagerMock; + + /** + * @var SetGoogleAnalyticsOnOrderSuccessPageViewObserver + */ + private $orderSuccessObserver; + + /** + * Test setUp + */ + protected function setUp() + { + $this->googleAnalyticsDataMock = $this->getMockBuilder(GaDataHelper::class) + ->disableOriginalConstructor() + ->getMock(); + $this->storeManagerMock = $this->getMockBuilder(StoreManagerInterface::class) + ->disableOriginalConstructor() + ->getMock(); + $this->layoutMock = $this->getMockBuilder(LayoutInterface::class) + ->disableOriginalConstructor() + ->getMock(); + $this->observerMock = $this->getMockBuilder(Observer::class)->getMock(); + $this->eventMock = $this->getMockBuilder(Event::class)->getMock(); + + $objectManager = new ObjectManager($this); + + $this->orderSuccessObserver = $objectManager->getObject( + SetGoogleAnalyticsOnOrderSuccessPageViewObserver::class, + [ + 'storeManager' => $this->storeManagerMock, + 'layout' => $this->layoutMock, + 'googleAnalyticsData' => $this->googleAnalyticsDataMock + ] + ); + } + + /** + * Observer test + */ + public function testExecuteWithNoOrderIds() + { + $this->observerMock->expects($this->once()) + ->method('getEvent') + ->willReturn($this->eventMock); + $this->eventMock->expects($this->once()) + ->method('__call') + ->with( + $this->equalTo('getOrderIds') + ) + ->willReturn([]); + $this->layoutMock->expects($this->never()) + ->method('getBlock'); + + $this->orderSuccessObserver->execute($this->observerMock); + } + + /** + * Observer test + */ + public function testExecuteWithOrderIds() + { + $blockMock = $this->getMockBuilder(AbstractBlock::class) + ->disableOriginalConstructor() + ->getMock(); + $orderIds = [8]; + + $this->observerMock->expects($this->once()) + ->method('getEvent') + ->willReturn($this->eventMock); + $this->eventMock->expects($this->once()) + ->method('__call') + ->with( + $this->equalTo('getOrderIds') + ) + ->willReturn($orderIds); + $this->layoutMock->expects($this->once()) + ->method('getBlock') + ->willReturn($blockMock); + $blockMock->expects($this->once()) + ->method('__call') + ->with( + $this->equalTo('setOrderIds'), + $this->equalTo([$orderIds]) + ); + + $this->orderSuccessObserver->execute($this->observerMock); + } +} diff --git a/app/code/Magento/GoogleOptimizer/Test/Mftf/composer.json b/app/code/Magento/GoogleOptimizer/Test/Mftf/composer.json deleted file mode 100644 index 2378140ac272a..0000000000000 --- a/app/code/Magento/GoogleOptimizer/Test/Mftf/composer.json +++ /dev/null @@ -1,22 +0,0 @@ -{ - "name": "magento/functional-test-module-google-optimizer", - "description": "N/A", - "config": { - "sort-packages": true - }, - "require": { - "php": "~7.1.3||~7.2.0", - "magento/magento2-functional-testing-framework": "2.2.0", - "magento/functional-test-module-backend": "100.0.0-dev", - "magento/functional-test-module-catalog": "100.0.0-dev", - "magento/functional-test-module-cms": "100.0.0-dev", - "magento/functional-test-module-google-analytics": "100.0.0-dev", - "magento/functional-test-module-store": "100.0.0-dev", - "magento/functional-test-module-ui": "100.0.0-dev" - }, - "type": "magento2-test", - "license": [ - "OSL-3.0", - "AFL-3.0" - ] -} diff --git a/app/code/Magento/GraphQl/Test/Mftf/composer.json b/app/code/Magento/GraphQl/Test/Mftf/composer.json deleted file mode 100644 index e86f458e9e6a4..0000000000000 --- a/app/code/Magento/GraphQl/Test/Mftf/composer.json +++ /dev/null @@ -1,22 +0,0 @@ -{ - "name": "magento/functional-test-module-graph-ql", - "description": "N/A", - "config": { - "sort-packages": true - }, - "require": { - "php": "~7.1.3||~7.2.0", - "magento/functional-test-module-authorization": "100.0.0-dev", - "magento/functional-test-module-store": "100.0.0-dev", - "magento/functional-test-module-eav": "100.0.0-dev", - "magento/magento2-functional-testing-framework": "2.2.0" - }, - "suggest": { - "magento/functional-test-module-webapi": "100.0.0-dev" - }, - "type": "magento2-test", - "license": [ - "OSL-3.0", - "AFL-3.0" - ] -} diff --git a/app/code/Magento/GroupedImportExport/Test/Mftf/composer.json b/app/code/Magento/GroupedImportExport/Test/Mftf/composer.json deleted file mode 100644 index 37d7a9ffe9f52..0000000000000 --- a/app/code/Magento/GroupedImportExport/Test/Mftf/composer.json +++ /dev/null @@ -1,21 +0,0 @@ -{ - "name": "magento/functional-test-module-grouped-import-export", - "description": "N/A", - "config": { - "sort-packages": true - }, - "require": { - "php": "~7.1.3||~7.2.0", - "magento/magento2-functional-testing-framework": "2.2.0", - "magento/functional-test-module-catalog": "100.0.0-dev", - "magento/functional-test-module-catalog-import-export": "100.0.0-dev", - "magento/functional-test-module-eav": "100.0.0-dev", - "magento/functional-test-module-grouped-product": "100.0.0-dev", - "magento/functional-test-module-import-export": "100.0.0-dev" - }, - "type": "magento2-test", - "license": [ - "OSL-3.0", - "AFL-3.0" - ] -} diff --git a/app/code/Magento/GroupedProduct/Test/Mftf/Test/AdminRemoveDefaultImageGroupedProductTest.xml b/app/code/Magento/GroupedProduct/Test/Mftf/Test/AdminRemoveDefaultImageGroupedProductTest.xml index a0408a744cc7e..54062d97f7c8f 100644 --- a/app/code/Magento/GroupedProduct/Test/Mftf/Test/AdminRemoveDefaultImageGroupedProductTest.xml +++ b/app/code/Magento/GroupedProduct/Test/Mftf/Test/AdminRemoveDefaultImageGroupedProductTest.xml @@ -69,9 +69,7 @@ <!-- Remove image from product --> <actionGroup ref="removeProductImage" stepKey="removeProductImage"/> - <!-- Skip success message check when saving product because of bug MAGETWO-91177 --> - <!-- actionGroup ref="saveProductForm" stepKey="saveProductFormAfterRemove"/--> - <click selector="{{AdminProductFormActionSection.saveButton}}" stepKey="saveProductFormAfterRemove"/> + <actionGroup ref="saveProductForm" stepKey="saveProductFormAfterRemove"/> <!-- Assert product image not in admin product form --> <actionGroup ref="assertProductImageNotInAdminProductPage" stepKey="assertProductImageNotInAdminProductPage"/> diff --git a/app/code/Magento/GroupedProduct/Test/Mftf/composer.json b/app/code/Magento/GroupedProduct/Test/Mftf/composer.json deleted file mode 100644 index ebd0d3656952f..0000000000000 --- a/app/code/Magento/GroupedProduct/Test/Mftf/composer.json +++ /dev/null @@ -1,31 +0,0 @@ -{ - "name": "magento/functional-test-module-grouped-product", - "description": "N/A", - "config": { - "sort-packages": true - }, - "require": { - "php": "~7.1.3||~7.2.0", - "magento/magento2-functional-testing-framework": "2.2.0", - "magento/functional-test-module-backend": "100.0.0-dev", - "magento/functional-test-module-catalog": "100.0.0-dev", - "magento/functional-test-module-catalog-inventory": "100.0.0-dev", - "magento/functional-test-module-checkout": "100.0.0-dev", - "magento/functional-test-module-customer": "100.0.0-dev", - "magento/functional-test-module-eav": "100.0.0-dev", - "magento/functional-test-module-media-storage": "100.0.0-dev", - "magento/functional-test-module-msrp": "100.0.0-dev", - "magento/functional-test-module-quote": "100.0.0-dev", - "magento/functional-test-module-sales": "100.0.0-dev", - "magento/functional-test-module-store": "100.0.0-dev", - "magento/functional-test-module-ui": "100.0.0-dev" - }, - "suggest": { - "magento/functional-test-module-grouped-product-sample-data": "100.0.0-dev" - }, - "type": "magento2-test", - "license": [ - "OSL-3.0", - "AFL-3.0" - ] -} diff --git a/app/code/Magento/GroupedProductGraphQl/Test/Mftf/composer.json b/app/code/Magento/GroupedProductGraphQl/Test/Mftf/composer.json deleted file mode 100644 index 6335b45595db7..0000000000000 --- a/app/code/Magento/GroupedProductGraphQl/Test/Mftf/composer.json +++ /dev/null @@ -1,18 +0,0 @@ -{ - "name": "magento/functional-test-module-grouped-product-graph-ql", - "description": "N/A", - "config": { - "sort-packages": true - }, - "require": { - "php": "~7.1.3||~7.2.0", - "magento/functional-test-module-grouped-product": "100.0.0-dev", - "magento/functional-test-module-catalog-graph-ql": "100.0.0-dev", - "magento/magento2-functional-testing-framework": "2.2.0" - }, - "type": "magento2-test", - "license": [ - "OSL-3.0", - "AFL-3.0" - ] -} diff --git a/app/code/Magento/ImportExport/Test/Mftf/composer.json b/app/code/Magento/ImportExport/Test/Mftf/composer.json deleted file mode 100644 index fcce7ec7e84ff..0000000000000 --- a/app/code/Magento/ImportExport/Test/Mftf/composer.json +++ /dev/null @@ -1,21 +0,0 @@ -{ - "name": "magento/functional-test-module-import-export", - "description": "N/A", - "config": { - "sort-packages": true - }, - "require": { - "php": "~7.1.3||~7.2.0", - "magento/magento2-functional-testing-framework": "2.2.0", - "magento/functional-test-module-backend": "100.0.0-dev", - "magento/functional-test-module-catalog": "100.0.0-dev", - "magento/functional-test-module-eav": "100.0.0-dev", - "magento/functional-test-module-media-storage": "100.0.0-dev", - "magento/functional-test-module-store": "100.0.0-dev" - }, - "type": "magento2-test", - "license": [ - "OSL-3.0", - "AFL-3.0" - ] -} diff --git a/app/code/Magento/ImportExport/view/adminhtml/templates/import/form/before.phtml b/app/code/Magento/ImportExport/view/adminhtml/templates/import/form/before.phtml index 73b013fdb8df4..8a52f4ca88e75 100644 --- a/app/code/Magento/ImportExport/view/adminhtml/templates/import/form/before.phtml +++ b/app/code/Magento/ImportExport/view/adminhtml/templates/import/form/before.phtml @@ -178,9 +178,13 @@ require([ .loader('show'); var form = jQuery('#edit_form') .one('invalid-form.validate', function(e){jQuery('body').loader('hide')}); - newActionUrl = (newActionUrl ? newActionUrl : form.attr('action')) + - (form.attr('action').lastIndexOf('?') != -1 ? '&' : '?')+ - 'form_key=' + encodeURIComponent(form.find('[name="form_key"]').val()); + + newActionUrl = (newActionUrl ? newActionUrl : form.attr('action')); + if (newActionUrl.lastIndexOf('form_key') === -1) { + newActionUrl = newActionUrl + + (newActionUrl.lastIndexOf('?') !== -1 ? '&' : '?') + + 'form_key=' + encodeURIComponent(form.find('[name="form_key"]').val()); + } form.trigger('save', [{ action: newActionUrl, diff --git a/app/code/Magento/Indexer/Model/Indexer/DependencyDecorator.php b/app/code/Magento/Indexer/Model/Indexer/DependencyDecorator.php index d22795f127138..829df74a1b0ed 100644 --- a/app/code/Magento/Indexer/Model/Indexer/DependencyDecorator.php +++ b/app/code/Magento/Indexer/Model/Indexer/DependencyDecorator.php @@ -256,7 +256,10 @@ public function reindexRow($id) $this->indexer->reindexRow($id); $dependentIndexerIds = $this->dependencyInfoProvider->getIndexerIdsToRunAfter($this->indexer->getId()); foreach ($dependentIndexerIds as $indexerId) { - $this->indexerRegistry->get($indexerId)->reindexRow($id); + $dependentIndexer = $this->indexerRegistry->get($indexerId); + if (!$dependentIndexer->isScheduled()) { + $dependentIndexer->reindexRow($id); + } } } @@ -268,7 +271,10 @@ public function reindexList($ids) $this->indexer->reindexList($ids); $dependentIndexerIds = $this->dependencyInfoProvider->getIndexerIdsToRunAfter($this->indexer->getId()); foreach ($dependentIndexerIds as $indexerId) { - $this->indexerRegistry->get($indexerId)->reindexList($ids); + $dependentIndexer = $this->indexerRegistry->get($indexerId); + if (!$dependentIndexer->isScheduled()) { + $dependentIndexer->reindexList($ids); + } } } } diff --git a/app/code/Magento/Indexer/Test/Mftf/composer.json b/app/code/Magento/Indexer/Test/Mftf/composer.json deleted file mode 100644 index 487c2ac1abc85..0000000000000 --- a/app/code/Magento/Indexer/Test/Mftf/composer.json +++ /dev/null @@ -1,17 +0,0 @@ -{ - "name": "magento/functional-test-module-indexer", - "description": "N/A", - "config": { - "sort-packages": true - }, - "require": { - "php": "~7.1.3||~7.2.0", - "magento/magento2-functional-testing-framework": "2.2.0", - "magento/functional-test-module-backend": "100.0.0-dev" - }, - "type": "magento2-test", - "license": [ - "OSL-3.0", - "AFL-3.0" - ] -} diff --git a/app/code/Magento/InstantPurchase/Model/ShippingMethodChoose/CarrierFinder.php b/app/code/Magento/InstantPurchase/Model/ShippingMethodChoose/CarrierFinder.php index 0eb2afd04140a..d3e84083e5b42 100644 --- a/app/code/Magento/InstantPurchase/Model/ShippingMethodChoose/CarrierFinder.php +++ b/app/code/Magento/InstantPurchase/Model/ShippingMethodChoose/CarrierFinder.php @@ -11,7 +11,7 @@ use Magento\Store\Model\StoreManagerInterface; /** - * Collect shipping rates for customer address without packaging estiamtion. + * Collect shipping rates for customer address without packaging estimation. */ class CarrierFinder { diff --git a/app/code/Magento/InstantPurchase/Test/Mftf/composer.json b/app/code/Magento/InstantPurchase/Test/Mftf/composer.json deleted file mode 100644 index 465002e5c4244..0000000000000 --- a/app/code/Magento/InstantPurchase/Test/Mftf/composer.json +++ /dev/null @@ -1,23 +0,0 @@ -{ - "name": "magento/functional-test-module-instant-purchase", - "description": "N/A", - "config": { - "sort-packages": true - }, - "require": { - "php": "~7.1.3||~7.2.0", - "magento/functional-test-module-store": "100.0.0-dev", - "magento/functional-test-module-catalog": "100.0.0-dev", - "magento/functional-test-module-customer": "100.0.0-dev", - "magento/functional-test-module-sales": "100.0.0-dev", - "magento/functional-test-module-shipping": "100.0.0-dev", - "magento/functional-test-module-quote": "100.0.0-dev", - "magento/functional-test-module-vault": "100.0.0-dev", - "magento/magento2-functional-testing-framework": "2.2.0" - }, - "type": "magento2-test", - "license": [ - "OSL-3.0", - "AFL-3.0" - ] -} diff --git a/app/code/Magento/Integration/Test/Mftf/composer.json b/app/code/Magento/Integration/Test/Mftf/composer.json deleted file mode 100644 index 7168fc1945dab..0000000000000 --- a/app/code/Magento/Integration/Test/Mftf/composer.json +++ /dev/null @@ -1,22 +0,0 @@ -{ - "name": "magento/functional-test-module-integration", - "description": "N/A", - "config": { - "sort-packages": true - }, - "require": { - "php": "~7.1.3||~7.2.0", - "magento/magento2-functional-testing-framework": "2.2.0", - "magento/functional-test-module-authorization": "100.0.0-dev", - "magento/functional-test-module-backend": "100.0.0-dev", - "magento/functional-test-module-customer": "100.0.0-dev", - "magento/functional-test-module-security": "100.0.0-dev", - "magento/functional-test-module-store": "100.0.0-dev", - "magento/functional-test-module-user": "100.0.0-dev" - }, - "type": "magento2-test", - "license": [ - "OSL-3.0", - "AFL-3.0" - ] -} diff --git a/app/code/Magento/Integration/Test/Unit/Oauth/OauthTest.php b/app/code/Magento/Integration/Test/Unit/Oauth/OauthTest.php index 7ca29e99d9ba9..7af2b3563478a 100644 --- a/app/code/Magento/Integration/Test/Unit/Oauth/OauthTest.php +++ b/app/code/Magento/Integration/Test/Unit/Oauth/OauthTest.php @@ -629,7 +629,7 @@ public function testGetAccessTokenVerifierInvalid($verifier, $verifierFromToken) public function dataProviderForGetAccessTokenVerifierInvalidTest() { // Verifier is not a string - return [[3, 3], ['wrong_length', 'wrong_length'], ['verifier', 'doesnt match']]; + return [[3, 3], ['wrong_length', 'wrong_length'], ['verifier', 'doesn\'t match']]; } public function testGetAccessToken() diff --git a/app/code/Magento/LayeredNavigation/Test/Mftf/composer.json b/app/code/Magento/LayeredNavigation/Test/Mftf/composer.json deleted file mode 100644 index 9d046b8c2a105..0000000000000 --- a/app/code/Magento/LayeredNavigation/Test/Mftf/composer.json +++ /dev/null @@ -1,18 +0,0 @@ -{ - "name": "magento/functional-test-module-layered-navigation", - "description": "N/A", - "config": { - "sort-packages": true - }, - "require": { - "php": "~7.1.3||~7.2.0", - "magento/magento2-functional-testing-framework": "2.2.0", - "magento/functional-test-module-catalog": "100.0.0-dev", - "magento/functional-test-module-config": "100.0.0-dev" - }, - "type": "magento2-test", - "license": [ - "OSL-3.0", - "AFL-3.0" - ] -} diff --git a/app/code/Magento/LayeredNavigation/view/frontend/layout/catalogsearch_result_index.xml b/app/code/Magento/LayeredNavigation/view/frontend/layout/catalogsearch_result_index.xml index ab9aa485aeea2..3bb21ed09a01c 100644 --- a/app/code/Magento/LayeredNavigation/view/frontend/layout/catalogsearch_result_index.xml +++ b/app/code/Magento/LayeredNavigation/view/frontend/layout/catalogsearch_result_index.xml @@ -7,6 +7,7 @@ --> <page xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:View/Layout/etc/page_configuration.xsd"> <body> + <attribute name="class" value="page-with-filter"/> <referenceContainer name="sidebar.main"> <block class="Magento\LayeredNavigation\Block\Navigation\Search" name="catalogsearch.leftnav" before="-" template="Magento_LayeredNavigation::layer/view.phtml"> <block class="Magento\LayeredNavigation\Block\Navigation\State" name="catalogsearch.navigation.state" as="state" /> diff --git a/app/code/Magento/Marketplace/Test/Mftf/composer.json b/app/code/Magento/Marketplace/Test/Mftf/composer.json deleted file mode 100644 index 3d4fd741bc4ad..0000000000000 --- a/app/code/Magento/Marketplace/Test/Mftf/composer.json +++ /dev/null @@ -1,17 +0,0 @@ -{ - "name": "magento/functional-test-module-marketplace", - "description": "N/A", - "config": { - "sort-packages": true - }, - "require": { - "php": "~7.1.3||~7.2.0", - "magento/magento2-functional-testing-framework": "2.2.0", - "magento/functional-test-module-backend": "100.0.0-dev" - }, - "type": "magento2-test", - "license": [ - "OSL-3.0", - "AFL-3.0" - ] -} diff --git a/app/code/Magento/MediaStorage/Model/File/Storage/File.php b/app/code/Magento/MediaStorage/Model/File/Storage/File.php index 149d829e2acbe..ffbc2e3e90aad 100644 --- a/app/code/Magento/MediaStorage/Model/File/Storage/File.php +++ b/app/code/Magento/MediaStorage/Model/File/Storage/File.php @@ -286,11 +286,10 @@ public function saveDir($dir) */ public function saveFile($file, $overwrite = true) { - if (isset( - $file['filename'] - ) && !empty($file['filename']) && isset( - $file['content'] - ) && !empty($file['content']) + if (isset($file['filename']) + && !empty($file['filename']) + && isset($file['content']) + && !empty($file['content']) ) { try { $filename = isset( @@ -307,8 +306,6 @@ public function saveFile($file, $overwrite = true) } else { throw new \Magento\Framework\Exception\LocalizedException(__('Wrong file info format')); } - - return false; } /** diff --git a/app/code/Magento/MediaStorage/Test/Mftf/composer.json b/app/code/Magento/MediaStorage/Test/Mftf/composer.json deleted file mode 100644 index 7e7aeeef14517..0000000000000 --- a/app/code/Magento/MediaStorage/Test/Mftf/composer.json +++ /dev/null @@ -1,21 +0,0 @@ -{ - "name": "magento/functional-test-module-media-storage", - "description": "N/A", - "config": { - "sort-packages": true - }, - "require": { - "php": "~7.1.3||~7.2.0", - "magento/magento2-functional-testing-framework": "2.2.0", - "magento/functional-test-module-backend": "100.0.0-dev", - "magento/functional-test-module-config": "100.0.0-dev", - "magento/functional-test-module-store": "100.0.0-dev", - "magento/functional-test-module-catalog": "100.0.0-dev", - "magento/functional-test-module-theme": "100.0.0-dev" - }, - "type": "magento2-test", - "license": [ - "OSL-3.0", - "AFL-3.0" - ] -} diff --git a/app/code/Magento/MessageQueue/Test/Mftf/composer.json b/app/code/Magento/MessageQueue/Test/Mftf/composer.json deleted file mode 100644 index e499fed390751..0000000000000 --- a/app/code/Magento/MessageQueue/Test/Mftf/composer.json +++ /dev/null @@ -1,16 +0,0 @@ -{ - "name": "magento/functional-test-module-message-queue", - "description": "N/A", - "config": { - "sort-packages": true - }, - "require": { - "magento/magento2-functional-testing-framework": "2.2.0", - "magento/magento-composer-installer": "100.0.0-dev", - "php": "~7.1.3||~7.2.0" - }, - "type": "magento2-test", - "license": [ - "proprietary" - ] -} diff --git a/app/code/Magento/MessageQueue/composer.json b/app/code/Magento/MessageQueue/composer.json index 5cdf7351bbb61..9d3c77fa0184a 100644 --- a/app/code/Magento/MessageQueue/composer.json +++ b/app/code/Magento/MessageQueue/composer.json @@ -11,7 +11,8 @@ }, "type": "magento2-module", "license": [ - "proprietary" + "OSL-3.0", + "AFL-3.0" ], "autoload": { "files": [ diff --git a/app/code/Magento/Msrp/Test/Mftf/composer.json b/app/code/Magento/Msrp/Test/Mftf/composer.json deleted file mode 100644 index cd85cb6cb268a..0000000000000 --- a/app/code/Magento/Msrp/Test/Mftf/composer.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "name": "magento/functional-test-module-msrp", - "description": "N/A", - "config": { - "sort-packages": true - }, - "require": { - "php": "~7.1.3||~7.2.0", - "magento/magento2-functional-testing-framework": "2.2.0", - "magento/functional-test-module-catalog": "100.0.0-dev", - "magento/functional-test-module-downloadable": "100.0.0-dev", - "magento/functional-test-module-eav": "100.0.0-dev", - "magento/functional-test-module-grouped-product": "100.0.0-dev", - "magento/functional-test-module-store": "100.0.0-dev", - "magento/functional-test-module-tax": "100.0.0-dev" - }, - "suggest": { - "magento/functional-test-module-bundle": "100.0.0-dev", - "magento/functional-test-module-msrp-sample-data": "100.0.0-dev" - }, - "type": "magento2-test", - "license": [ - "OSL-3.0", - "AFL-3.0" - ] -} diff --git a/app/code/Magento/Multishipping/Controller/Checkout.php b/app/code/Magento/Multishipping/Controller/Checkout.php index 1870736a0efd9..92417c7cb3a18 100644 --- a/app/code/Magento/Multishipping/Controller/Checkout.php +++ b/app/code/Magento/Multishipping/Controller/Checkout.php @@ -8,6 +8,7 @@ use Magento\Customer\Api\AccountManagementInterface; use Magento\Customer\Api\CustomerRepositoryInterface; use Magento\Framework\App\RequestInterface; +use Magento\Framework\Exception\StateException; /** * Multishipping checkout controller @@ -84,6 +85,7 @@ protected function _getCheckoutSession() * * @param RequestInterface $request * @return \Magento\Framework\App\ResponseInterface + * @throws \Magento\Framework\Exception\NotFoundException * @SuppressWarnings(PHPMD.CyclomaticComplexity) * @SuppressWarnings(PHPMD.NPathComplexity) */ @@ -152,7 +154,15 @@ public function dispatch(RequestInterface $request) return parent::dispatch($request); } - $quote = $this->_getCheckout()->getQuote(); + try { + $checkout = $this->_getCheckout(); + } catch (StateException $e) { + $this->getResponse()->setRedirect($this->_getHelper()->getMSNewShippingUrl()); + $this->_actionFlag->set('', self::FLAG_NO_DISPATCH, true); + return parent::dispatch($request); + } + + $quote = $checkout->getQuote(); if (!$quote->hasItems() || $quote->getHasError() || $quote->isVirtual()) { $this->getResponse()->setRedirect($this->_getHelper()->getCartUrl()); $this->_actionFlag->set('', self::FLAG_NO_DISPATCH, true); diff --git a/app/code/Magento/Multishipping/Controller/Checkout/CheckItems.php b/app/code/Magento/Multishipping/Controller/Checkout/CheckItems.php new file mode 100644 index 0000000000000..e9a46f1cf00f7 --- /dev/null +++ b/app/code/Magento/Multishipping/Controller/Checkout/CheckItems.php @@ -0,0 +1,196 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +declare(strict_types=1); + +namespace Magento\Multishipping\Controller\Checkout; + +use Magento\Customer\Model\Session as CustomerSession; +use Magento\Framework\App\Action\Context; +use Magento\Framework\Exception\LocalizedException; +use Magento\Framework\Serialize\Serializer\Json; +use Magento\Checkout\Model\Session as CheckoutSession; +use Magento\Customer\Api\AccountManagementInterface; +use Magento\Customer\Api\CustomerRepositoryInterface; +use Magento\Multishipping\Controller\Checkout; +use Magento\Multishipping\Helper\Data as MultishippingHelper; +use Magento\Quote\Model\Quote\Item; +use Psr\Log\LoggerInterface; + +class CheckItems extends Checkout +{ + /** + * @var CheckoutSession + */ + private $checkoutSession; + + /** + * @var MultishippingHelper + */ + private $helper; + + /** + * @var Json + */ + private $json; + + /** + * @var LoggerInterface + */ + private $logger; + + /** + * @param Context $context, + * @param CustomerSession $customerSession + * @param CustomerRepositoryInterface $customerRepository + * @param AccountManagementInterface $accountManagement + * @param CheckoutSession $checkoutSession + * @param MultishippingHelper $helper + * @param Json $json + * @param LoggerInterface $logger + */ + + public function __construct( + Context $context, + CustomerSession $customerSession, + CustomerRepositoryInterface $customerRepository, + AccountManagementInterface $accountManagement, + CheckoutSession $checkoutSession, + MultishippingHelper $helper, + Json $json, + LoggerInterface $logger + ) { + $this->checkoutSession = $checkoutSession; + $this->helper = $helper; + $this->json = $json; + $this->logger = $logger; + + parent::__construct( + $context, + $customerSession, + $customerRepository, + $accountManagement + ); + } + + /** + * @return void + */ + public function execute() + { + try { + $shippingInfo = $this->getRequest()->getPost('ship'); + if (!\is_array($shippingInfo)) { + throw new LocalizedException( + __('We are unable to process your request. Please, try again later.') + ); + } + + $itemsInfo = $this->collectItemsInfo($shippingInfo); + $totalQuantity = array_sum($itemsInfo); + + $maxQuantity = $this->helper->getMaximumQty(); + if ($totalQuantity > $maxQuantity) { + throw new LocalizedException( + __('Maximum qty allowed for Shipping to multiple addresses is %1', $maxQuantity) + ); + } + + $quote = $this->checkoutSession->getQuote(); + foreach ($quote->getAllItems() as $item) { + if (isset($itemsInfo[$item->getId()])) { + $this->updateItemQuantity($item, $itemsInfo[$item->getId()]); + } + } + + if ($quote->getHasError()) { + throw new LocalizedException(__($quote->getMessage())); + } + + $this->jsonResponse(); + } catch (LocalizedException $e) { + $this->jsonResponse($e->getMessage()); + } catch (\Exception $e) { + $this->logger->critical($e->getMessage()); + $this->jsonResponse('We are unable to process your request. Please, try again later.'); + } + } + + /** + * Updates quote item quantity. + * + * @param Item $item + * @param float $quantity + * @throws LocalizedException + */ + private function updateItemQuantity(Item $item, float $quantity) + { + if ($quantity > 0) { + $item->setQty($quantity); + if ($item->getHasError()) { + throw new LocalizedException(__($item->getMessage())); + } + } + } + + /** + * Group posted items. + * + * @param array $shippingInfo + * @return array + */ + private function collectItemsInfo(array $shippingInfo): array + { + $itemsInfo = []; + foreach ($shippingInfo as $itemData) { + if (!\is_array($itemData)) { + continue; + } + foreach ($itemData as $quoteItemId => $data) { + if (!isset($itemsInfo[$quoteItemId])) { + $itemsInfo[$quoteItemId] = 0; + } + $itemsInfo[$quoteItemId] += (double)$data['qty']; + } + } + + return $itemsInfo; + } + + /** + * JSON response builder. + * + * @param string $error + * @return void + */ + private function jsonResponse(string $error = '') + { + $this->getResponse()->representJson( + $this->json->serialize($this->getResponseData($error)) + ); + } + + /** + * Returns response data. + * + * @param string $error + * @return array + */ + private function getResponseData(string $error = ''): array + { + $response = [ + 'success' => true, + ]; + + if (!empty($error)) { + $response = [ + 'success' => false, + 'error_message' => $error, + ]; + } + + return $response; + } +} diff --git a/app/code/Magento/Multishipping/Helper/Url.php b/app/code/Magento/Multishipping/Helper/Url.php index e293e3d4d7121..eaefa8fe8bee3 100644 --- a/app/code/Magento/Multishipping/Helper/Url.php +++ b/app/code/Magento/Multishipping/Helper/Url.php @@ -63,6 +63,16 @@ public function getMSShippingAddressSavedUrl() return $this->_getUrl('multishipping/checkout_address/shippingSaved'); } + /** + * Retrieve register url + * + * @return string + */ + public function getMSNewShippingUrl() + { + return $this->_getUrl('multishipping/checkout_address/newShipping'); + } + /** * Retrieve register url * diff --git a/app/code/Magento/Multishipping/Test/Mftf/composer.json b/app/code/Magento/Multishipping/Test/Mftf/composer.json deleted file mode 100644 index 344b2b1ef6525..0000000000000 --- a/app/code/Magento/Multishipping/Test/Mftf/composer.json +++ /dev/null @@ -1,25 +0,0 @@ -{ - "name": "magento/functional-test-module-multishipping", - "description": "N/A", - "config": { - "sort-packages": true - }, - "require": { - "php": "~7.1.3||~7.2.0", - "magento/magento2-functional-testing-framework": "2.2.0", - "magento/functional-test-module-checkout": "100.0.0-dev", - "magento/functional-test-module-customer": "100.0.0-dev", - "magento/functional-test-module-directory": "100.0.0-dev", - "magento/functional-test-module-payment": "100.0.0-dev", - "magento/functional-test-module-quote": "100.0.0-dev", - "magento/functional-test-module-sales": "100.0.0-dev", - "magento/functional-test-module-store": "100.0.0-dev", - "magento/functional-test-module-tax": "100.0.0-dev", - "magento/functional-test-module-theme": "100.0.0-dev" - }, - "type": "magento2-test", - "license": [ - "OSL-3.0", - "AFL-3.0" - ] -} diff --git a/app/code/Magento/Multishipping/i18n/en_US.csv b/app/code/Magento/Multishipping/i18n/en_US.csv index 43cc785c56eab..43615e697b931 100644 --- a/app/code/Magento/Multishipping/i18n/en_US.csv +++ b/app/code/Magento/Multishipping/i18n/en_US.csv @@ -89,4 +89,5 @@ Options,Options "Select Shipping Method","Select Shipping Method" "We received your order!","We received your order!" "Ship to:","Ship to:" -"Error:","Error:" \ No newline at end of file +"Error:","Error:" +"We are unable to process your request. Please, try again later.","We are unable to process your request. Please, try again later." diff --git a/app/code/Magento/Multishipping/view/frontend/requirejs-config.js b/app/code/Magento/Multishipping/view/frontend/requirejs-config.js index f14159ba0a85a..0235d8b848154 100644 --- a/app/code/Magento/Multishipping/view/frontend/requirejs-config.js +++ b/app/code/Magento/Multishipping/view/frontend/requirejs-config.js @@ -9,7 +9,8 @@ var config = { multiShipping: 'Magento_Multishipping/js/multi-shipping', orderOverview: 'Magento_Multishipping/js/overview', payment: 'Magento_Multishipping/js/payment', - billingLoader: 'Magento_Checkout/js/checkout-loader' + billingLoader: 'Magento_Checkout/js/checkout-loader', + cartUpdate: 'Magento_Checkout/js/action/update-shopping-cart' } } }; diff --git a/app/code/Magento/Multishipping/view/frontend/templates/checkout/addresses.phtml b/app/code/Magento/Multishipping/view/frontend/templates/checkout/addresses.phtml index a55b84c0a2d8a..0f96f7cdb708a 100644 --- a/app/code/Magento/Multishipping/view/frontend/templates/checkout/addresses.phtml +++ b/app/code/Magento/Multishipping/view/frontend/templates/checkout/addresses.phtml @@ -14,20 +14,42 @@ * @var $block \Magento\Multishipping\Block\Checkout\Addresses */ ?> -<form id="checkout_multishipping_form" data-mage-init='{"multiShipping":{}, "validation":{}}' action="<?= /* @escapeNotVerified */ $block->getPostActionUrl() ?>" method="post" class="multicheckout address form"> +<form id="checkout_multishipping_form" + data-mage-init='{ + "multiShipping":{}, + "validation":{}, + "cartUpdate": { + "validationURL": "/multishipping/checkout/checkItems", + "eventName": "updateMulticartItemQty" + }}' + action="<?= $block->escapeUrl($block->getPostActionUrl()) ?>" + method="post" + class="multicheckout address form"> +<form id="checkout_multishipping_form" + data-mage-init='{ + "multiShipping":{}, + "cartUpdate": { + "validationURL": "/multishipping/checkout/checkItems", + "eventName": "updateMulticartItemQty" + }}' + action="<?= $block->escapeUrl($block->getPostActionUrl()) ?>" + method="post" + class="multicheckout address form"> <div class="title"> - <strong><?= /* @escapeNotVerified */ __('Please select a shipping address for applicable items.') ?></strong> + <strong><?= $block->escapeHtml(__('Please select a shipping address for applicable items.')) ?></strong> </div> <input type="hidden" name="continue" value="0" id="can_continue_flag"/> <input type="hidden" name="new_address" value="0" id="add_new_address_flag"/> <div class="table-wrapper"> <table class="items data table" id="multiship-addresses-table"> - <caption class="table-caption"><?= /* @escapeNotVerified */ __('Please select a shipping address for applicable items.') ?></caption> + <caption class="table-caption"> + <?= $block->escapeHtml(__('Please select a shipping address for applicable items.')) ?> + </caption> <thead> <tr> - <th class="col product" scope="col"><?= /* @escapeNotVerified */ __('Product') ?></th> - <th class="col qty" scope="col"><?= /* @escapeNotVerified */ __('Qty') ?></th> - <th class="col address" scope="col"><?= /* @escapeNotVerified */ __('Send To') ?></th> + <th class="col product" scope="col"><?= $block->escapeHtml(__('Product')) ?></th> + <th class="col qty" scope="col"><?= $block->escapeHtml(__('Qty')) ?></th> + <th class="col address" scope="col"><?= $block->escapeHtml(__('Send To')) ?></th> <th class="col actions" scope="col"> </th> </tr> </thead> @@ -35,24 +57,37 @@ <?php foreach ($block->getItems() as $_index => $_item): ?> <?php if ($_item->getQuoteItem()) : ?> <tr> - <td class="col product" data-th="<?= $block->escapeHtml(__('Product')) ?>"><?= $block->getItemHtml($_item->getQuoteItem()) ?></td> + <td class="col product" data-th="<?= $block->escapeHtml(__('Product')) ?>"> + <?= $block->getItemHtml($_item->getQuoteItem()) ?> + </td> <td class="col qty" data-th="<?= $block->escapeHtml(__('Qty')) ?>"> <div class="field qty"> - <label for="ship-<?= /* @escapeNotVerified */ $_index ?>-<?= /* @escapeNotVerified */ $_item->getQuoteItemId() ?>-qty" class="label"> - <span><?= /* @escapeNotVerified */ __('Qty') ?></span> + <label for="ship-<?= $block->escapeHtml($_index) ?>-<?= $block->escapeHtml($_item->getQuoteItemId()) ?>-qty" + class="label"> + <span><?= $block->escapeHtml(__('Qty')) ?></span> </label> <div class="control"> - <input type="number" data-multiship-item-id="<?= /* @escapeNotVerified */ $_item->getSku() ?>" id="ship-<?= /* @escapeNotVerified */ $_index ?>-<?= /* @escapeNotVerified */ $_item->getQuoteItemId() ?>-qty" name="ship[<?= /* @escapeNotVerified */ $_index ?>][<?= /* @escapeNotVerified */ $_item->getQuoteItemId() ?>][qty]" value="<?= $block->escapeHtml($_item->getQty()) ?>" size="2" class="input-text qty" data-validate="{number: true}"/> + <input type="number" + data-multiship-item-id="<?= $block->escapeHtml($_item->getSku()) ?>" + id="ship-<?= $block->escapeHtml($_index) ?>-<?= $block->escapeHtml($_item->getQuoteItemId()) ?>-qty" + name="ship[<?= $block->escapeHtml($_index) ?>][<?= $block->escapeHtml($_item->getQuoteItemId()) ?>][qty]" + value="<?= $block->escapeHtml($_item->getQty()) ?>" + size="2" + class="input-text qty" + data-validate="{number: true}"/> </div> </div> </td> <td class="col address" data-th="<?= $block->escapeHtml(__('Send To')) ?>"> <?php if ($_item->getProduct()->getIsVirtual()): ?> - <div class="applicable"><?= /* @escapeNotVerified */ __('A shipping selection is not applicable.') ?></div> + <div class="applicable"> + <?= $block->escapeHtml(__('A shipping selection is not applicable.')) ?> + </div> <?php else: ?> <div class="field address"> - <label for="ship_<?= /* @escapeNotVerified */ $_index ?>_<?= /* @escapeNotVerified */ $_item->getQuoteItemId() ?>_address" class="label"> - <span><?= /* @escapeNotVerified */ __('Send To') ?></span> + <label for="ship_<?= $block->escapeHtml($_index) ?>_<?= $block->escapeHtml($_item->getQuoteItemId()) ?>_address" + class="label"> + <span><?= $block->escapeHtml(__('Send To')) ?></span> </label> <div class="control"> <?= $block->getAddressesHtmlSelect($_item, $_index) ?> @@ -61,8 +96,11 @@ <?php endif; ?> </td> <td class="col actions" data-th="<?= $block->escapeHtml(__('Actions')) ?>"> - <a href="<?= /* @escapeNotVerified */ $block->getItemDeleteUrl($_item) ?>" title="<?= /* @escapeNotVerified */ __('Remove Item') ?>" class="action delete" data-multiship-item-update=""> - <span><?= /* @escapeNotVerified */ __('Remove item') ?></span> + <a href="<?= $block->escapeUrl($block->getItemDeleteUrl($_item)) ?>" + title="<?= $block->escapeHtml(__('Remove Item')) ?>" + class="action delete" + data-multiship-item-remove=""> + <span><?= $block->escapeHtml(__('Remove item')) ?></span> </a> </td> </tr> @@ -73,12 +111,35 @@ </div> <div class="actions-toolbar"> <div class="primary"> - <button type="submit" title="<?= /* @escapeNotVerified */ __('Go to Shipping Information') ?>" class="action primary continue<?php if ($block->isContinueDisabled()):?> disabled<?php endif; ?>" data-role="can-continue" data-flag="1"<?php if ($block->isContinueDisabled()):?> disabled="disabled"<?php endif; ?>><span><?= /* @escapeNotVerified */ __('Go to Shipping Information') ?></span></button> + <button type="submit" + title="<?= $block->escapeHtml(__('Go to Shipping Information')) ?>" + class="action primary continue<?php if ($block->isContinueDisabled()):?> disabled<?php endif; ?>" + data-role="can-continue" + data-flag="1" + <?php if ($block->isContinueDisabled()):?> + disabled="disabled" + <?php endif; ?>> + <span><?= $block->escapeHtml(__('Go to Shipping Information')) ?></span> + </button> </div> <div class="secondary"> - <button type="submit" data-multiship-item-update="" class="action update" data-role="can-continue" data-flag="0"><span><?= /* @escapeNotVerified */ __('Update Qty & Addresses') ?></span></button> - <button type="button" title="<?= /* @escapeNotVerified */ __('Enter a New Address') ?>" class="action add" data-role="add-new-address"><span><?= /* @escapeNotVerified */ __('Enter a New Address') ?></span></button> - <a href="<?= /* @escapeNotVerified */ $block->getBackUrl() ?>" class="action back"><span><?= /* @escapeNotVerified */ __('Back to Shopping Cart') ?></span></a> + <button type="submit" + data-multiship-item-update="" + class="action update" + data-role="can-continue" + data-flag="0"> + <span><?= $block->escapeHtml(__('Update Qty & Addresses')) ?></span> + </button> + <button type="button" + title="<?= $block->escapeHtml(__('Enter a New Address')) ?>" + class="action add" + data-role="add-new-address"> + <span><?= $block->escapeHtml(__('Enter a New Address')) ?></span> + </button> + <a href="<?= $block->escapeUrl($block->getBackUrl()) ?>" + class="action back"> + <span><?= $block->escapeHtml(__('Back to Shopping Cart')) ?></span> + </a> </div> </div> </form> diff --git a/app/code/Magento/MysqlMq/Model/ResourceModel/Queue.php b/app/code/Magento/MysqlMq/Model/ResourceModel/Queue.php index c1cdd23be622c..d50ed851b64a9 100644 --- a/app/code/Magento/MysqlMq/Model/ResourceModel/Queue.php +++ b/app/code/Magento/MysqlMq/Model/ResourceModel/Queue.php @@ -151,7 +151,7 @@ public function getMessages($queueName, $limit = null) 'queue_message_status.status IN (?)', [QueueManagement::MESSAGE_STATUS_NEW, QueueManagement::MESSAGE_STATUS_RETRY_REQUIRED] )->where('queue.name = ?', $queueName) - ->order('queue_message_status.updated_at DESC'); + ->order('queue_message_status.updated_at ASC'); if ($limit) { $select->limit($limit); diff --git a/app/code/Magento/MysqlMq/Test/Mftf/composer.json b/app/code/Magento/MysqlMq/Test/Mftf/composer.json deleted file mode 100644 index 0aa70a28428e4..0000000000000 --- a/app/code/Magento/MysqlMq/Test/Mftf/composer.json +++ /dev/null @@ -1,17 +0,0 @@ -{ - "name": "magento/functional-test-module-mysql-mq", - "description": "N/A", - "config": { - "sort-packages": true - }, - "require": { - "magento/magento2-functional-testing-framework": "2.2.0", - "magento/magento-composer-installer": "100.0.0-dev", - "magento/functional-test-module-store": "100.0.0-dev", - "php": "~7.1.3||~7.2.0" - }, - "type": "magento2-test", - "license": [ - "proprietary" - ] -} diff --git a/app/code/Magento/MysqlMq/Test/Unit/Model/ResourceModel/QueueTest.php b/app/code/Magento/MysqlMq/Test/Unit/Model/ResourceModel/QueueTest.php index 7f364054ec921..d3fe09a712945 100644 --- a/app/code/Magento/MysqlMq/Test/Unit/Model/ResourceModel/QueueTest.php +++ b/app/code/Magento/MysqlMq/Test/Unit/Model/ResourceModel/QueueTest.php @@ -206,7 +206,7 @@ public function testGetMessages() ] )->willReturnSelf(); $select->expects($this->once()) - ->method('order')->with('queue_message_status.updated_at DESC')->willReturnSelf(); + ->method('order')->with('queue_message_status.updated_at ASC')->willReturnSelf(); $select->expects($this->once())->method('limit')->with($limit)->willReturnSelf(); $connection->expects($this->once())->method('fetchAll')->with($select)->willReturn($messages); $this->assertEquals($messages, $this->queue->getMessages($queueName, $limit)); diff --git a/app/code/Magento/MysqlMq/composer.json b/app/code/Magento/MysqlMq/composer.json index 3d7ee4f8b037b..d9bcf307a5bf9 100644 --- a/app/code/Magento/MysqlMq/composer.json +++ b/app/code/Magento/MysqlMq/composer.json @@ -12,7 +12,8 @@ }, "type": "magento2-module", "license": [ - "proprietary" + "OSL-3.0", + "AFL-3.0" ], "autoload": { "files": [ diff --git a/app/code/Magento/NewRelicReporting/Test/Mftf/composer.json b/app/code/Magento/NewRelicReporting/Test/Mftf/composer.json deleted file mode 100644 index 287475d097084..0000000000000 --- a/app/code/Magento/NewRelicReporting/Test/Mftf/composer.json +++ /dev/null @@ -1,23 +0,0 @@ -{ - "name": "magento/functional-test-module-new-relic-reporting", - "description": "N/A", - "config": { - "sort-packages": true - }, - "require": { - "php": "~7.1.3||~7.2.0", - "magento/magento2-functional-testing-framework": "2.2.0", - "magento/magento-composer-installer": "100.0.0-dev", - "magento/functional-test-module-backend": "100.0.0-dev", - "magento/functional-test-module-catalog": "100.0.0-dev", - "magento/functional-test-module-config": "100.0.0-dev", - "magento/functional-test-module-configurable-product": "100.0.0-dev", - "magento/functional-test-module-customer": "100.0.0-dev", - "magento/functional-test-module-store": "100.0.0-dev" - }, - "type": "magento2-test", - "license": [ - "OSL-3.0", - "AFL-3.0" - ] -} diff --git a/app/code/Magento/Newsletter/Block/Adminhtml/Template/Edit.php b/app/code/Magento/Newsletter/Block/Adminhtml/Template/Edit.php index 33c3706183368..236101745b98e 100644 --- a/app/code/Magento/Newsletter/Block/Adminhtml/Template/Edit.php +++ b/app/code/Magento/Newsletter/Block/Adminhtml/Template/Edit.php @@ -67,12 +67,6 @@ public function getModel() */ protected function _prepareLayout() { - // Load Wysiwyg on demand and Prepare layout -// $block = $this->getLayout()->getBlock('head'); -// if ($this->_wysiwygConfig->isEnabled() && $block) { -// $block->setCanLoadTinyMce(true); -// } - $this->getToolbar()->addChild( 'back_button', \Magento\Backend\Block\Widget\Button::class, diff --git a/app/code/Magento/Newsletter/Controller/Manage/Save.php b/app/code/Magento/Newsletter/Controller/Manage/Save.php index 75ef8b26f50a9..419cbac10ffd1 100644 --- a/app/code/Magento/Newsletter/Controller/Manage/Save.php +++ b/app/code/Magento/Newsletter/Controller/Manage/Save.php @@ -4,9 +4,11 @@ * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ + namespace Magento\Newsletter\Controller\Manage; use Magento\Customer\Api\CustomerRepositoryInterface as CustomerRepository; +use Magento\Newsletter\Model\Subscriber; class Save extends \Magento\Newsletter\Controller\Manage { @@ -74,13 +76,28 @@ public function execute() $customer = $this->customerRepository->getById($customerId); $storeId = $this->storeManager->getStore()->getId(); $customer->setStoreId($storeId); - $this->customerRepository->save($customer); - if ((boolean)$this->getRequest()->getParam('is_subscribed', false)) { - $this->subscriberFactory->create()->subscribeCustomerById($customerId); - $this->messageManager->addSuccess(__('We saved the subscription.')); + $isSubscribedState = $customer->getExtensionAttributes() + ->getIsSubscribed(); + $isSubscribedParam = (boolean)$this->getRequest() + ->getParam('is_subscribed', false); + if ($isSubscribedParam !== $isSubscribedState) { + $this->customerRepository->save($customer); + if ($isSubscribedParam) { + $subscribeModel = $this->subscriberFactory->create() + ->subscribeCustomerById($customerId); + $subscribeStatus = $subscribeModel->getStatus(); + if ($subscribeStatus == Subscriber::STATUS_SUBSCRIBED) { + $this->messageManager->addSuccess(__('We have saved your subscription.')); + } else { + $this->messageManager->addSuccess(__('A confirmation request has been sent.')); + } + } else { + $this->subscriberFactory->create() + ->unsubscribeCustomerById($customerId); + $this->messageManager->addSuccess(__('We have removed your newsletter subscription.')); + } } else { - $this->subscriberFactory->create()->unsubscribeCustomerById($customerId); - $this->messageManager->addSuccess(__('We removed the subscription.')); + $this->messageManager->addSuccess(__('We have updated your subscription.')); } } catch (\Exception $e) { $this->messageManager->addError(__('Something went wrong while saving your subscription.')); diff --git a/app/code/Magento/Newsletter/Controller/Subscriber/NewAction.php b/app/code/Magento/Newsletter/Controller/Subscriber/NewAction.php index 13ab40665e591..fd2a61702e909 100644 --- a/app/code/Magento/Newsletter/Controller/Subscriber/NewAction.php +++ b/app/code/Magento/Newsletter/Controller/Subscriber/NewAction.php @@ -10,19 +10,32 @@ use Magento\Customer\Model\Session; use Magento\Customer\Model\Url as CustomerUrl; use Magento\Framework\App\Action\Context; +use Magento\Framework\App\Config\ScopeConfigInterface; +use Magento\Framework\App\ObjectManager; +use Magento\Framework\Exception\LocalizedException; +use Magento\Framework\Phrase; +use Magento\Framework\Validator\EmailAddress as EmailValidator; +use Magento\Newsletter\Controller\Subscriber as SubscriberController; +use Magento\Newsletter\Model\Subscriber; +use Magento\Store\Model\ScopeInterface; use Magento\Store\Model\StoreManagerInterface; use Magento\Newsletter\Model\SubscriberFactory; /** * @SuppressWarnings(PHPMD.CouplingBetweenObjects) */ -class NewAction extends \Magento\Newsletter\Controller\Subscriber +class NewAction extends SubscriberController { /** * @var CustomerAccountManagement */ protected $customerAccountManagement; + /** + * @var EmailValidator + */ + private $emailValidator; + /** * Initialize dependencies. * @@ -32,6 +45,7 @@ class NewAction extends \Magento\Newsletter\Controller\Subscriber * @param StoreManagerInterface $storeManager * @param CustomerUrl $customerUrl * @param CustomerAccountManagement $customerAccountManagement + * @param EmailValidator $emailValidator */ public function __construct( Context $context, @@ -39,9 +53,11 @@ public function __construct( Session $customerSession, StoreManagerInterface $storeManager, CustomerUrl $customerUrl, - CustomerAccountManagement $customerAccountManagement + CustomerAccountManagement $customerAccountManagement, + EmailValidator $emailValidator = null ) { $this->customerAccountManagement = $customerAccountManagement; + $this->emailValidator = $emailValidator ?: ObjectManager::getInstance()->get(EmailValidator::class); parent::__construct( $context, $subscriberFactory, @@ -55,7 +71,7 @@ public function __construct( * Validates that the email address isn't being used by a different account. * * @param string $email - * @throws \Magento\Framework\Exception\LocalizedException + * @throws LocalizedException * @return void */ protected function validateEmailAvailable($email) @@ -64,7 +80,7 @@ protected function validateEmailAvailable($email) if ($this->_customerSession->getCustomerDataObject()->getEmail() !== $email && !$this->customerAccountManagement->isEmailAvailable($email, $websiteId) ) { - throw new \Magento\Framework\Exception\LocalizedException( + throw new LocalizedException( __('This email address is already assigned to another user.') ); } @@ -73,19 +89,19 @@ protected function validateEmailAvailable($email) /** * Validates that if the current user is a guest, that they can subscribe to a newsletter. * - * @throws \Magento\Framework\Exception\LocalizedException + * @throws LocalizedException * @return void */ protected function validateGuestSubscription() { - if ($this->_objectManager->get(\Magento\Framework\App\Config\ScopeConfigInterface::class) + if ($this->_objectManager->get(ScopeConfigInterface::class) ->getValue( - \Magento\Newsletter\Model\Subscriber::XML_PATH_ALLOW_GUEST_SUBSCRIBE_FLAG, - \Magento\Store\Model\ScopeInterface::SCOPE_STORE + Subscriber::XML_PATH_ALLOW_GUEST_SUBSCRIBE_FLAG, + ScopeInterface::SCOPE_STORE ) != 1 && !$this->_customerSession->isLoggedIn() ) { - throw new \Magento\Framework\Exception\LocalizedException( + throw new LocalizedException( __( 'Sorry, but the administrator denied subscription for guests. Please <a href="%1">register</a>.', $this->_customerUrl->getRegisterUrl() @@ -98,20 +114,19 @@ protected function validateGuestSubscription() * Validates the format of the email address * * @param string $email - * @throws \Magento\Framework\Exception\LocalizedException + * @throws LocalizedException * @return void */ protected function validateEmailFormat($email) { - if (!\Zend_Validate::is($email, \Magento\Framework\Validator\EmailAddress::class)) { - throw new \Magento\Framework\Exception\LocalizedException(__('Please enter a valid email address.')); + if (!$this->emailValidator->isValid($email)) { + throw new LocalizedException(__('Please enter a valid email address.')); } } /** * New subscription action * - * @throws \Magento\Framework\Exception\LocalizedException * @return void */ public function execute() @@ -126,28 +141,37 @@ public function execute() $subscriber = $this->_subscriberFactory->create()->loadByEmail($email); if ($subscriber->getId() - && $subscriber->getSubscriberStatus() == \Magento\Newsletter\Model\Subscriber::STATUS_SUBSCRIBED + && (int) $subscriber->getSubscriberStatus() === Subscriber::STATUS_SUBSCRIBED ) { - throw new \Magento\Framework\Exception\LocalizedException( + throw new LocalizedException( __('This email address is already subscribed.') ); } - $status = $this->_subscriberFactory->create()->subscribe($email); - if ($status == \Magento\Newsletter\Model\Subscriber::STATUS_NOT_ACTIVE) { - $this->messageManager->addSuccess(__('The confirmation request has been sent.')); - } else { - $this->messageManager->addSuccess(__('Thank you for your subscription.')); - } - } catch (\Magento\Framework\Exception\LocalizedException $e) { - $this->messageManager->addException( + $status = (int) $this->_subscriberFactory->create()->subscribe($email); + $this->messageManager->addSuccessMessage($this->getSuccessMessage($status)); + } catch (LocalizedException $e) { + $this->messageManager->addExceptionMessage( $e, __('There was a problem with the subscription: %1', $e->getMessage()) ); } catch (\Exception $e) { - $this->messageManager->addException($e, __('Something went wrong with the subscription.')); + $this->messageManager->addExceptionMessage($e, __('Something went wrong with the subscription.')); } } $this->getResponse()->setRedirect($this->_redirect->getRedirectUrl()); } + + /** + * @param int $status + * @return Phrase + */ + private function getSuccessMessage(int $status): Phrase + { + if ($status === Subscriber::STATUS_NOT_ACTIVE) { + return __('The confirmation request has been sent.'); + } + + return __('Thank you for your subscription.'); + } } diff --git a/app/code/Magento/Newsletter/Model/Subscriber.php b/app/code/Magento/Newsletter/Model/Subscriber.php index 76d55de5954b1..27ee8197778ff 100644 --- a/app/code/Magento/Newsletter/Model/Subscriber.php +++ b/app/code/Magento/Newsletter/Model/Subscriber.php @@ -559,7 +559,9 @@ protected function _updateCustomerSubscription($customerId, $subscribe) ) { $status = self::STATUS_UNCONFIRMED; } elseif ($isConfirmNeed) { - $status = self::STATUS_NOT_ACTIVE; + if ($this->getStatus() != self::STATUS_SUBSCRIBED) { + $status = self::STATUS_NOT_ACTIVE; + } } } elseif (($this->getStatus() == self::STATUS_UNCONFIRMED) && ($customerData->getConfirmation() === null)) { $status = self::STATUS_SUBSCRIBED; diff --git a/app/code/Magento/Newsletter/Test/Mftf/composer.json b/app/code/Magento/Newsletter/Test/Mftf/composer.json deleted file mode 100644 index 2a2ab444dd08a..0000000000000 --- a/app/code/Magento/Newsletter/Test/Mftf/composer.json +++ /dev/null @@ -1,24 +0,0 @@ -{ - "name": "magento/functional-test-module-newsletter", - "description": "N/A", - "config": { - "sort-packages": true - }, - "require": { - "php": "~7.1.3||~7.2.0", - "magento/magento2-functional-testing-framework": "2.2.0", - "magento/functional-test-module-backend": "100.0.0-dev", - "magento/functional-test-module-cms": "100.0.0-dev", - "magento/functional-test-module-customer": "100.0.0-dev", - "magento/functional-test-module-eav": "100.0.0-dev", - "magento/functional-test-module-email": "100.0.0-dev", - "magento/functional-test-module-require-js": "100.0.0-dev", - "magento/functional-test-module-store": "100.0.0-dev", - "magento/functional-test-module-widget": "100.0.0-dev" - }, - "type": "magento2-test", - "license": [ - "OSL-3.0", - "AFL-3.0" - ] -} diff --git a/app/code/Magento/OfflinePayments/Test/Mftf/composer.json b/app/code/Magento/OfflinePayments/Test/Mftf/composer.json deleted file mode 100644 index 7ce98340d75ee..0000000000000 --- a/app/code/Magento/OfflinePayments/Test/Mftf/composer.json +++ /dev/null @@ -1,21 +0,0 @@ -{ - "name": "magento/functional-test-module-offline-payments", - "description": "N/A", - "config": { - "sort-packages": true - }, - "require": { - "php": "~7.1.3||~7.2.0", - "magento/magento2-functional-testing-framework": "2.2.0", - "magento/functional-test-module-checkout": "100.0.0-dev", - "magento/functional-test-module-payment": "100.0.0-dev" - }, - "suggest": { - "magento/functional-test-module-config": "100.0.0-dev" - }, - "type": "magento2-test", - "license": [ - "OSL-3.0", - "AFL-3.0" - ] -} diff --git a/app/code/Magento/OfflineShipping/Model/Quote/Address/FreeShipping.php b/app/code/Magento/OfflineShipping/Model/Quote/Address/FreeShipping.php index e1397dc6e097b..c6234a1247a53 100644 --- a/app/code/Magento/OfflineShipping/Model/Quote/Address/FreeShipping.php +++ b/app/code/Magento/OfflineShipping/Model/Quote/Address/FreeShipping.php @@ -3,27 +3,35 @@ * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ +declare(strict_types=1); + namespace Magento\OfflineShipping\Model\Quote\Address; -class FreeShipping implements \Magento\Quote\Model\Quote\Address\FreeShippingInterface +use Magento\OfflineShipping\Model\SalesRule\Calculator; +use Magento\OfflineShipping\Model\SalesRule\ExtendedCalculator; +use Magento\Quote\Model\Quote\Address\FreeShippingInterface; +use Magento\Quote\Model\Quote\Item\AbstractItem; +use Magento\Store\Model\StoreManagerInterface; + +class FreeShipping implements FreeShippingInterface { /** - * @var \Magento\OfflineShipping\Model\SalesRule\Calculator + * @var ExtendedCalculator */ protected $calculator; /** - * @var \Magento\Store\Model\StoreManagerInterface + * @var StoreManagerInterface */ protected $storeManager; /** - * @param \Magento\Store\Model\StoreManagerInterface $storeManager - * @param \Magento\OfflineShipping\Model\SalesRule\Calculator $calculator + * @param StoreManagerInterface $storeManager + * @param Calculator $calculator */ public function __construct( - \Magento\Store\Model\StoreManagerInterface $storeManager, - \Magento\OfflineShipping\Model\SalesRule\Calculator $calculator + StoreManagerInterface $storeManager, + Calculator $calculator ) { $this->storeManager = $storeManager; $this->calculator = $calculator; @@ -39,6 +47,7 @@ public function isFreeShipping(\Magento\Quote\Model\Quote $quote, $items) return false; } + $result = false; $addressFreeShipping = true; $store = $this->storeManager->getStore($quote->getStoreId()); $this->calculator->init( @@ -62,21 +71,24 @@ public function isFreeShipping(\Magento\Quote\Model\Quote $quote, $items) } $this->calculator->processFreeShipping($item); - $itemFreeShipping = (bool)$item->getFreeShipping(); - $addressFreeShipping = $addressFreeShipping && $itemFreeShipping; - - if ($addressFreeShipping && !$item->getAddress()->getFreeShipping()) { - $item->getAddress()->setFreeShipping(true); + // at least one item matches to the rule and the rule mode is not a strict + if ((bool)$item->getAddress()->getFreeShipping()) { + $result = true; + break; } - /** Parent free shipping we apply to all children*/ - $this->applyToChildren($item, $itemFreeShipping); + $itemFreeShipping = (bool)$item->getFreeShipping(); + $addressFreeShipping = $addressFreeShipping && $itemFreeShipping; + $result = $addressFreeShipping; } - return (bool)$shippingAddress->getFreeShipping(); + + $shippingAddress->setFreeShipping((int)$result); + $this->applyToItems($items, $result); + return $result; } /** - * @param \Magento\Quote\Model\Quote\Item\AbstractItem $item + * @param AbstractItem $item * @param bool $isFreeShipping * @return void */ @@ -91,4 +103,20 @@ protected function applyToChildren(\Magento\Quote\Model\Quote\Item\AbstractItem } } } + + /** + * Sets free shipping availability to the quote items. + * + * @param array $items + * @param bool $freeShipping + */ + private function applyToItems(array $items, bool $freeShipping) + { + /** @var AbstractItem $item */ + foreach ($items as $item) { + $item->getAddress() + ->setFreeShipping((int)$freeShipping); + $this->applyToChildren($item, $freeShipping); + } + } } diff --git a/app/code/Magento/OfflineShipping/Test/Mftf/composer.json b/app/code/Magento/OfflineShipping/Test/Mftf/composer.json deleted file mode 100644 index acca01f787402..0000000000000 --- a/app/code/Magento/OfflineShipping/Test/Mftf/composer.json +++ /dev/null @@ -1,29 +0,0 @@ -{ - "name": "magento/functional-test-module-offline-shipping", - "description": "N/A", - "config": { - "sort-packages": true - }, - "require": { - "php": "~7.1.3||~7.2.0", - "magento/magento2-functional-testing-framework": "2.2.0", - "magento/functional-test-module-backend": "100.0.0-dev", - "magento/functional-test-module-catalog": "100.0.0-dev", - "magento/functional-test-module-config": "100.0.0-dev", - "magento/functional-test-module-directory": "100.0.0-dev", - "magento/functional-test-module-quote": "100.0.0-dev", - "magento/functional-test-module-sales": "100.0.0-dev", - "magento/functional-test-module-sales-rule": "100.0.0-dev", - "magento/functional-test-module-shipping": "100.0.0-dev", - "magento/functional-test-module-store": "100.0.0-dev" - }, - "suggest": { - "magento/functional-test-module-checkout": "100.0.0-dev", - "magento/functional-test-module-offline-shipping-sample-data": "100.0.0-dev" - }, - "type": "magento2-test", - "license": [ - "OSL-3.0", - "AFL-3.0" - ] -} diff --git a/app/code/Magento/OfflineShipping/Test/Unit/Model/Quote/Address/FreeShippingTest.php b/app/code/Magento/OfflineShipping/Test/Unit/Model/Quote/Address/FreeShippingTest.php index 5a8b1afa786bb..8266a39bbbb6d 100644 --- a/app/code/Magento/OfflineShipping/Test/Unit/Model/Quote/Address/FreeShippingTest.php +++ b/app/code/Magento/OfflineShipping/Test/Unit/Model/Quote/Address/FreeShippingTest.php @@ -3,94 +3,193 @@ * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ +declare(strict_types=1); namespace Magento\OfflineShipping\Test\Unit\Model\Quote\Address; -use Magento\Framework\TestFramework\Unit\Helper\ObjectManager as ObjectManagerHelper; +use Magento\OfflineShipping\Model\Quote\Address\FreeShipping; +use Magento\OfflineShipping\Model\SalesRule\Calculator; +use Magento\Quote\Model\Quote; +use Magento\Quote\Model\Quote\Address; +use Magento\Quote\Model\Quote\Item; +use Magento\Store\Api\Data\StoreInterface; +use Magento\Store\Model\StoreManagerInterface; +use PHPUnit_Framework_MockObject_MockObject as MockObject; class FreeShippingTest extends \PHPUnit\Framework\TestCase { + private static $websiteId = 1; + + private static $customerGroupId = 2; + + private static $couponCode = 3; + + private static $storeId = 1; + /** - * @var \Magento\OfflineShipping\Model\Quote\Address\FreeShipping + * @var FreeShipping */ private $model; /** - * @var \PHPUnit_Framework_MockObject_MockObject|\Magento\Store\Model\StoreManagerInterface + * @var MockObject|StoreManagerInterface */ - private $storeManagerMock; + private $storeManager; /** - * @var \PHPUnit_Framework_MockObject_MockObject|\Magento\OfflineShipping\Model\SalesRule\Calculator + * @var MockObject|Calculator */ - private $calculatorMock; + private $calculator; protected function setUp() { - $this->storeManagerMock = $this->createMock(\Magento\Store\Model\StoreManagerInterface::class); - $this->calculatorMock = $this->createMock(\Magento\OfflineShipping\Model\SalesRule\Calculator::class); + $this->storeManager = $this->createMock(StoreManagerInterface::class); + $this->calculator = $this->createMock(Calculator::class); - $this->model = new \Magento\OfflineShipping\Model\Quote\Address\FreeShipping( - $this->storeManagerMock, - $this->calculatorMock + $this->model = new FreeShipping( + $this->storeManager, + $this->calculator ); } - public function testIsFreeShippingIfNoItems() + /** + * Checks free shipping availability based on quote items and cart rule calculations. + * + * @param int $addressFree + * @param int $fItemFree + * @param int $sItemFree + * @param bool $expected + * @dataProvider itemsDataProvider + */ + public function testIsFreeShipping(int $addressFree, int $fItemFree, int $sItemFree, bool $expected) { - $quoteMock = $this->createMock(\Magento\Quote\Model\Quote::class); - $this->assertFalse($this->model->isFreeShipping($quoteMock, [])); + $address = $this->getShippingAddress(); + $this->withStore(); + $quote = $this->getQuote($address); + $fItem = $this->getItem($quote); + $sItem = $this->getItem($quote); + $items = [$fItem, $sItem]; + + $this->calculator->method('init') + ->with(self::$websiteId, self::$customerGroupId, self::$couponCode); + $this->calculator->method('processFreeShipping') + ->withConsecutive( + [$fItem], + [$sItem] + ) + ->willReturnCallback(function () use ($fItem, $sItem, $addressFree, $fItemFree, $sItemFree) { + // emulate behavior of cart rule calculator + $fItem->getAddress()->setFreeShipping($addressFree); + $fItem->setFreeShipping($fItemFree); + $sItem->setFreeShipping($sItemFree); + }); + + $actual = $this->model->isFreeShipping($quote, $items); + self::assertEquals($expected, $actual); + self::assertEquals($expected, $address->getFreeShipping()); } - public function testIsFreeShipping() + /** + * Gets list of variations with free shipping availability. + * + * @return array + */ + public function itemsDataProvider(): array { - $storeId = 100; - $websiteId = 200; - $customerGroupId = 300; - $objectManagerMock = new ObjectManagerHelper($this); - $quoteMock = $this->createPartialMock( - \Magento\Quote\Model\Quote::class, - ['getShippingAddress', 'getStoreId', 'getCustomerGroupId', 'getCouponCode'] - ); - $itemMock = $this->createPartialMock(\Magento\Quote\Model\Quote\Item::class, [ - 'getNoDiscount', - 'getParentItemId', - 'getFreeShipping', - 'getAddress', - 'isChildrenCalculated', - 'getHasChildren', - 'getChildren' - ]); - - $quoteMock->expects($this->once())->method('getStoreId')->willReturn($storeId); - $storeMock = $this->createMock(\Magento\Store\Api\Data\StoreInterface::class); - $storeMock->expects($this->once())->method('getWebsiteId')->willReturn($websiteId); - $this->storeManagerMock->expects($this->once())->method('getStore')->with($storeId)->willReturn($storeMock); - - $quoteMock->expects($this->once())->method('getCustomerGroupId')->willReturn($customerGroupId); - $quoteMock->expects($this->once())->method('getCouponCode')->willReturn(null); - - $this->calculatorMock->expects($this->once()) - ->method('init') - ->with($websiteId, $customerGroupId, null) - ->willReturnSelf(); - - $itemMock->expects($this->once())->method('getNoDiscount')->willReturn(false); - $itemMock->expects($this->once())->method('getParentItemId')->willReturn(false); - $this->calculatorMock->expects($this->exactly(2))->method('processFreeShipping')->willReturnSelf(); - $itemMock->expects($this->once())->method('getFreeShipping')->willReturn(true); - - $addressMock = $objectManagerMock->getObject(\Magento\Quote\Model\Quote\Address::class); - $quoteMock->expects($this->once())->method('getShippingAddress')->willReturn($addressMock); - $itemMock->expects($this->exactly(2))->method('getAddress')->willReturn($addressMock); - - $itemMock->expects($this->once())->method('getHasChildren')->willReturn(true); - $itemMock->expects($this->once())->method('isChildrenCalculated')->willReturn(true); - - $childMock = $this->createPartialMock(\Magento\Quote\Model\Quote\Item::class, ['setFreeShipping']); - $childMock->expects($this->once())->method('setFreeShipping')->with(true)->willReturnSelf(); - $itemMock->expects($this->once())->method('getChildren')->willReturn([$childMock]); - - $this->assertTrue($this->model->isFreeShipping($quoteMock, [$itemMock])); + return [ + ['addressFree' => 1, 'fItemFree' => 0, 'sItemFree' => 0, 'expected' => true], + ['addressFree' => 0, 'fItemFree' => 1, 'sItemFree' => 0, 'expected' => false], + ['addressFree' => 0, 'fItemFree' => 0, 'sItemFree' => 1, 'expected' => false], + ['addressFree' => 0, 'fItemFree' => 1, 'sItemFree' => 1, 'expected' => true], + ]; + } + + /** + * Creates mock object for store entity. + */ + private function withStore() + { + $store = $this->getMockBuilder(StoreInterface::class) + ->disableOriginalConstructor() + ->getMock(); + $this->storeManager->method('getStore') + ->with(self::$storeId) + ->willReturn($store); + + $store->method('getWebsiteId') + ->willReturn(self::$websiteId); + } + + /** + * Get mock object for quote entity. + * + * @param Address $address + * @return Quote + */ + private function getQuote(Address $address): Quote + { + /** @var Quote|MockObject $quote */ + $quote = $this->getMockBuilder(Quote::class) + ->disableOriginalConstructor() + ->setMethods( + [ + 'getCouponCode', 'getCustomerGroupId', 'getShippingAddress', 'getStoreId', 'getItemsQty', + 'getVirtualItemsQty' + ] + ) + ->getMock(); + + $quote->method('getStoreId') + ->willReturn(self::$storeId); + $quote->method('getCustomerGroupId') + ->willReturn(self::$customerGroupId); + $quote->method('getCouponCode') + ->willReturn(self::$couponCode); + $quote->method('getShippingAddress') + ->willReturn($address); + $quote->method('getItemsQty') + ->willReturn(2); + $quote->method('getVirtualItemsQty') + ->willReturn(0); + + return $quote; + } + + /** + * Gets stub object for shipping address. + * + * @return Address|MockObject + */ + private function getShippingAddress(): Address + { + /** @var Address|MockObject $address */ + $address = $this->getMockBuilder(Address::class) + ->disableOriginalConstructor() + ->setMethods(['beforeSave']) + ->getMock(); + + return $address; + } + + /** + * Gets stub object for quote item. + * + * @param Quote $quote + * @return Item + */ + private function getItem(Quote $quote): Item + { + /** @var Item|MockObject $item */ + $item = $this->getMockBuilder(Item::class) + ->disableOriginalConstructor() + ->setMethods(['getHasChildren']) + ->getMock(); + $item->setQuote($quote); + $item->setNoDiscount(0); + $item->setParentItemId(0); + $item->method('getHasChildren') + ->willReturn(0); + + return $item; } } diff --git a/app/code/Magento/PageCache/Model/Config.php b/app/code/Magento/PageCache/Model/Config.php index 6debbdf3e728a..83db8c0dec3b1 100644 --- a/app/code/Magento/PageCache/Model/Config.php +++ b/app/code/Magento/PageCache/Model/Config.php @@ -113,7 +113,6 @@ public function __construct( * * @return int * @api - * @deprecated 100.2.0 see \Magento\PageCache\Model\VclGeneratorInterface::generateVcl */ public function getType() { @@ -125,7 +124,6 @@ public function getType() * * @return int * @api - * @deprecated 100.2.0 see \Magento\PageCache\Model\VclGeneratorInterface::generateVcl */ public function getTtl() { @@ -255,7 +253,6 @@ protected function _getDesignExceptions() * * @return bool * @api - * @deprecated 100.2.0 see \Magento\PageCache\Model\VclGeneratorInterface::generateVcl */ public function isEnabled() { diff --git a/app/code/Magento/PageCache/Test/Mftf/composer.json b/app/code/Magento/PageCache/Test/Mftf/composer.json deleted file mode 100644 index 3bfe8f15ef64e..0000000000000 --- a/app/code/Magento/PageCache/Test/Mftf/composer.json +++ /dev/null @@ -1,19 +0,0 @@ -{ - "name": "magento/functional-test-module-page-cache", - "description": "N/A", - "config": { - "sort-packages": true - }, - "require": { - "php": "~7.1.3||~7.2.0", - "magento/magento2-functional-testing-framework": "2.2.0", - "magento/functional-test-module-backend": "100.0.0-dev", - "magento/functional-test-module-config": "100.0.0-dev", - "magento/functional-test-module-store": "100.0.0-dev" - }, - "type": "magento2-test", - "license": [ - "OSL-3.0", - "AFL-3.0" - ] -} diff --git a/app/code/Magento/Payment/Helper/Data.php b/app/code/Magento/Payment/Helper/Data.php index 5fd23c195f0c4..0a4990313fa82 100644 --- a/app/code/Magento/Payment/Helper/Data.php +++ b/app/code/Magento/Payment/Helper/Data.php @@ -151,15 +151,7 @@ public function getStoreMethods($store = null, $quote = null) @uasort( $res, function (MethodInterface $a, MethodInterface $b) { - if ((int)$a->getConfigData('sort_order') < (int)$b->getConfigData('sort_order')) { - return -1; - } - - if ((int)$a->getConfigData('sort_order') > (int)$b->getConfigData('sort_order')) { - return 1; - } - - return 0; + return (int)$a->getConfigData('sort_order') <=> (int)$b->getConfigData('sort_order'); } ); diff --git a/app/code/Magento/Payment/Test/Mftf/composer.json b/app/code/Magento/Payment/Test/Mftf/composer.json deleted file mode 100644 index 7311dae6fb074..0000000000000 --- a/app/code/Magento/Payment/Test/Mftf/composer.json +++ /dev/null @@ -1,22 +0,0 @@ -{ - "name": "magento/functional-test-module-payment", - "description": "N/A", - "config": { - "sort-packages": true - }, - "require": { - "php": "~7.1.3||~7.2.0", - "magento/magento2-functional-testing-framework": "2.2.0", - "magento/functional-test-module-checkout": "100.0.0-dev", - "magento/functional-test-module-config": "100.0.0-dev", - "magento/functional-test-module-directory": "100.0.0-dev", - "magento/functional-test-module-quote": "100.0.0-dev", - "magento/functional-test-module-sales": "100.0.0-dev", - "magento/functional-test-module-store": "100.0.0-dev" - }, - "type": "magento2-test", - "license": [ - "OSL-3.0", - "AFL-3.0" - ] -} diff --git a/app/code/Magento/Payment/view/frontend/templates/transparent/iframe.phtml b/app/code/Magento/Payment/view/frontend/templates/transparent/iframe.phtml index f1988f1ca86bb..c127371cb5f47 100644 --- a/app/code/Magento/Payment/view/frontend/templates/transparent/iframe.phtml +++ b/app/code/Magento/Payment/view/frontend/templates/transparent/iframe.phtml @@ -67,9 +67,10 @@ $params = $block->getParams(); 'jquery', 'Magento_Checkout/js/model/quote', 'Magento_Checkout/js/action/place-order', - 'Magento_Checkout/js/action/redirect-on-success' + 'Magento_Checkout/js/action/redirect-on-success', + 'Magento_Checkout/js/model/full-screen-loader' ], - function($, quote, placeOrderAction, redirectOnSuccessAction) { + function($, quote, placeOrderAction, redirectOnSuccessAction, fullScreenLoader) { var parent = window.top; $(parent).trigger('clearTimeout'); @@ -79,6 +80,12 @@ $params = $block->getParams(); function () { redirectOnSuccessAction.execute(); } + ).fail( + function () { + var parent = window.top; + $(parent).trigger('clearTimeout'); + fullScreenLoader.stopLoader(); + } ); } ); diff --git a/app/code/Magento/Paypal/Block/Adminhtml/System/Config/ApiWizard.php b/app/code/Magento/Paypal/Block/Adminhtml/System/Config/ApiWizard.php index a1cfabd48440f..afa80892487a5 100644 --- a/app/code/Magento/Paypal/Block/Adminhtml/System/Config/ApiWizard.php +++ b/app/code/Magento/Paypal/Block/Adminhtml/System/Config/ApiWizard.php @@ -13,7 +13,7 @@ class ApiWizard extends \Magento\Config\Block\System\Config\Form\Field /** * Path to block template */ - const WIZARD_TEMPLATE = 'system/config/api_wizard.phtml'; + const WIZARD_TEMPLATE = 'Magento_Paypal::system/config/api_wizard.phtml'; /** * Set template to itself diff --git a/app/code/Magento/Paypal/Block/Adminhtml/System/Config/BmlApiWizard.php b/app/code/Magento/Paypal/Block/Adminhtml/System/Config/BmlApiWizard.php index bdca98e089e7b..c481871e1fb0f 100644 --- a/app/code/Magento/Paypal/Block/Adminhtml/System/Config/BmlApiWizard.php +++ b/app/code/Magento/Paypal/Block/Adminhtml/System/Config/BmlApiWizard.php @@ -11,7 +11,7 @@ class BmlApiWizard extends ApiWizard /** * Path to block template */ - const WIZARD_TEMPLATE = 'system/config/bml_api_wizard.phtml'; + const WIZARD_TEMPLATE = 'Magento_Paypal::system/config/bml_api_wizard.phtml'; /** * Get the button and scripts contents diff --git a/app/code/Magento/Paypal/Block/Iframe.php b/app/code/Magento/Paypal/Block/Iframe.php index 98fc05d0d2f60..bcdfae6b86dbe 100644 --- a/app/code/Magento/Paypal/Block/Iframe.php +++ b/app/code/Magento/Paypal/Block/Iframe.php @@ -110,13 +110,13 @@ protected function _construct() if (in_array($paymentCode, $this->_hssHelper->getHssMethods())) { $this->_paymentMethodCode = $paymentCode; $templatePath = str_replace('_', '', $paymentCode); - $templateFile = "{$templatePath}/iframe.phtml"; + $templateFile = "Magento_Paypal::{$templatePath}/iframe.phtml"; $directory = $this->readFactory->create($this->reader->getModuleDir('', 'Magento_Paypal')); $file = $this->resolver->getTemplateFileName($templateFile, ['module' => 'Magento_Paypal']); if ($file && $directory->isExist($directory->getRelativePath($file))) { $this->setTemplate($templateFile); } else { - $this->setTemplate('hss/iframe.phtml'); + $this->setTemplate('Magento_Paypal::hss/iframe.phtml'); } } } @@ -198,7 +198,7 @@ protected function _beforeToHtml() protected function _toHtml() { if ($this->_isAfterPaymentSave()) { - $this->setTemplate('hss/js.phtml'); + $this->setTemplate('Magento_Paypal::hss/js.phtml'); return parent::_toHtml(); } if (!$this->_shouldRender) { diff --git a/app/code/Magento/Paypal/Controller/Transparent/Response.php b/app/code/Magento/Paypal/Controller/Transparent/Response.php index c54dd529588b9..67ec9afff2c44 100644 --- a/app/code/Magento/Paypal/Controller/Transparent/Response.php +++ b/app/code/Magento/Paypal/Controller/Transparent/Response.php @@ -5,6 +5,7 @@ */ namespace Magento\Paypal\Controller\Transparent; +use Magento\Framework\App\CsrfAwareActionInterface; use Magento\Framework\Registry; use Magento\Framework\App\Action\Context; use Magento\Framework\View\Result\LayoutFactory; @@ -16,11 +17,13 @@ use Magento\Paypal\Model\Payflow\Transparent; use Magento\Sales\Api\PaymentFailuresInterface; use Magento\Framework\Session\Generic as Session; +use Magento\Framework\App\RequestInterface; +use Magento\Framework\App\Request\InvalidRequestException; /** - * Class Response + * @SuppressWarnings(PHPMD.CouplingBetweenObjects) */ -class Response extends \Magento\Framework\App\Action\Action +class Response extends \Magento\Framework\App\Action\Action implements CsrfAwareActionInterface { /** * Core registry @@ -91,6 +94,23 @@ public function __construct( $this->paymentFailures = $paymentFailures ?: $this->_objectManager->get(PaymentFailuresInterface::class); } + /** + * @inheritDoc + */ + public function createCsrfValidationException( + RequestInterface $request + ): ?InvalidRequestException { + return null; + } + + /** + * @inheritDoc + */ + public function validateForCsrf(RequestInterface $request): ?bool + { + return true; + } + /** * @return ResultInterface */ diff --git a/app/code/Magento/Paypal/Test/Mftf/composer.json b/app/code/Magento/Paypal/Test/Mftf/composer.json deleted file mode 100644 index 4822c694580ef..0000000000000 --- a/app/code/Magento/Paypal/Test/Mftf/composer.json +++ /dev/null @@ -1,34 +0,0 @@ -{ - "name": "magento/functional-test-module-paypal", - "description": "N/A", - "config": { - "sort-packages": true - }, - "require": { - "php": "~7.1.3||~7.2.0", - "magento/magento2-functional-testing-framework": "2.2.0", - "magento/functional-test-module-backend": "100.0.0-dev", - "magento/functional-test-module-catalog": "100.0.0-dev", - "magento/functional-test-module-checkout": "100.0.0-dev", - "magento/functional-test-module-config": "100.0.0-dev", - "magento/functional-test-module-customer": "100.0.0-dev", - "magento/functional-test-module-directory": "100.0.0-dev", - "magento/functional-test-module-eav": "100.0.0-dev", - "magento/functional-test-module-instant-purchase": "100.0.0-dev", - "magento/functional-test-module-payment": "100.0.0-dev", - "magento/functional-test-module-quote": "100.0.0-dev", - "magento/functional-test-module-sales": "100.0.0-dev", - "magento/functional-test-module-store": "100.0.0-dev", - "magento/functional-test-module-tax": "100.0.0-dev", - "magento/functional-test-module-theme": "100.0.0-dev", - "magento/functional-test-module-ui": "100.0.0-dev", - "magento/functional-test-module-vault": "100.0.0-dev" - }, - "suggest": { - "magento/functional-test-module-checkout-agreements": "100.0.0-dev" - }, - "type": "magento2-test", - "license": [ - "proprietary" - ] -} diff --git a/app/code/Magento/Paypal/composer.json b/app/code/Magento/Paypal/composer.json index 8bc05710452bb..b62985e8b8b70 100644 --- a/app/code/Magento/Paypal/composer.json +++ b/app/code/Magento/Paypal/composer.json @@ -30,7 +30,8 @@ }, "type": "magento2-module", "license": [ - "proprietary" + "OSL-3.0", + "AFL-3.0" ], "autoload": { "files": [ diff --git a/app/code/Magento/Paypal/etc/adminhtml/system/express_checkout.xml b/app/code/Magento/Paypal/etc/adminhtml/system/express_checkout.xml index a726439331cb0..bff076aad9cb5 100644 --- a/app/code/Magento/Paypal/etc/adminhtml/system/express_checkout.xml +++ b/app/code/Magento/Paypal/etc/adminhtml/system/express_checkout.xml @@ -162,7 +162,7 @@ <label>Enable PayPal Credit</label> <comment><![CDATA[PayPal Express Checkout lets you give customers access to financing through PayPal Credit® - at no additional cost to you. You get paid up front, even though customers have more time to pay. A pre-integrated payment button lets customers pay quickly with PayPal Credit®. - <a href="https:/www.paypal.com/webapps/mpp/promotional-financing" target="_blank">Learn More</a>]]> + <a href="https://www.paypal.com/webapps/mpp/promotional-financing" target="_blank">Learn More</a>]]> </comment> <config_path>payment/paypal_express_bml/active</config_path> <source_model>Magento\Config\Model\Config\Source\Yesno</source_model> @@ -184,12 +184,12 @@ <group id="advertise_bml" translate="label comment" showInDefault="1" showInWebsite="1" sortOrder="30"> <label>Advertise PayPal Credit</label> <comment> - <![CDATA[<a href="https:/financing.paypal.com/ppfinportal/content/whyUseFinancing" target="_blank">Why Advertise Financing?</a><br/> + <![CDATA[<a href="https://financing.paypal.com/ppfinportal/content/whyUseFinancing" target="_blank">Why Advertise Financing?</a><br/> <strong>Give your sales a boost when you advertise financing.</strong><br/>PayPal helps turn browsers into buyers with financing from PayPal Credit®. Your customers have more time to pay, while you get paid up front – at no additional cost to you. Use PayPal’s free banner ads that let you advertise PayPal Credit® financing as a payment option when your customers check out with PayPal. The PayPal Advertising Program has been shown to generate additional purchases as well as increase consumer's average purchase sizes by 15% - or more. <a href="https:/financing.paypal.com/ppfinportal/content/forrester" target="_blank">See Details</a>.]]> + or more. <a href="https://financing.paypal.com/ppfinportal/content/forrester" target="_blank">See Details</a>.]]> </comment> <field id="bml_publisher_id" translate="label comment tooltip" showInDefault="1" showInWebsite="1" sortOrder="10"> <label>Publisher ID</label> @@ -199,7 +199,7 @@ </field> <field id="bml_wizard" translate="button_label" sortOrder="15" showInDefault="1" showInWebsite="1"> <button_label>Get Publisher ID from PayPal</button_label> - <button_url><![CDATA[https:/financing.paypal.com/ppfinportal/cart/index?dcp=4eff8563b9cc505e0b9afaff3256705081553c79]]></button_url> + <button_url><![CDATA[https://financing.paypal.com/ppfinportal/cart/index?dcp=4eff8563b9cc505e0b9afaff3256705081553c79]]></button_url> <frontend_model>Magento\Paypal\Block\Adminhtml\System\Config\BmlApiWizard</frontend_model> </field> <group id="settings_bml_homepage" translate="label" showInDefault="1" showInWebsite="1" showInStore="1" sortOrder="20"> diff --git a/app/code/Magento/Paypal/etc/adminhtml/system/payflow_advanced.xml b/app/code/Magento/Paypal/etc/adminhtml/system/payflow_advanced.xml index 3012ff4361483..5eb596c9c4f45 100644 --- a/app/code/Magento/Paypal/etc/adminhtml/system/payflow_advanced.xml +++ b/app/code/Magento/Paypal/etc/adminhtml/system/payflow_advanced.xml @@ -100,7 +100,7 @@ <field id="enable_express_checkout_bml" sortOrder="42" extends="payment_all_paypal/express_checkout/express_checkout_required/enable_express_checkout_bml"> <comment><![CDATA[PayPal Express Checkout Payflow Edition lets you give customers access to financing through PayPal Credit® - at no additional cost to you. You get paid up front, even though customers have more time to pay. A pre-integrated payment button lets customers pay quickly with PayPal Credit®. - <a href="https:/www.paypal.com/webapps/mpp/promotional-financing" target="_blank">Learn More</a>]]> + <a href="https://www.paypal.com/webapps/mpp/promotional-financing" target="_blank">Learn More</a>]]> </comment> <config_path>payment/payflow_express_bml/active</config_path> <frontend_model>Magento\Paypal\Block\Adminhtml\System\Config\Field\Enable\Bml</frontend_model> diff --git a/app/code/Magento/Paypal/etc/adminhtml/system/payflow_link.xml b/app/code/Magento/Paypal/etc/adminhtml/system/payflow_link.xml index 60a4d670e8a18..d27dde02c579e 100644 --- a/app/code/Magento/Paypal/etc/adminhtml/system/payflow_link.xml +++ b/app/code/Magento/Paypal/etc/adminhtml/system/payflow_link.xml @@ -109,7 +109,7 @@ <field id="enable_express_checkout_bml" extends="payment_all_paypal/express_checkout/express_checkout_required/enable_express_checkout_bml" sortOrder="41"> <comment><![CDATA[Payflow Link lets you give customers access to financing through PayPal Credit® - at no additional cost to you. You get paid up front, even though customers have more time to pay. A pre-integrated payment button lets customers pay quickly with PayPal Credit®. - <a href="https:/www.paypal.com/webapps/mpp/promotional-financing" target="_blank">Learn More</a>]]> + <a href="https://www.paypal.com/webapps/mpp/promotional-financing" target="_blank">Learn More</a>]]> </comment> <config_path>payment/payflow_express_bml/active</config_path> <frontend_model>Magento\Paypal\Block\Adminhtml\System\Config\Field\Enable\Bml</frontend_model> @@ -130,12 +130,12 @@ <group id="payflow_link_advertise_bml" translate="label comment" showInDefault="1" showInWebsite="1" sortOrder="60"> <label>Advertise PayPal Credit</label> <comment> - <![CDATA[<a href="https:/financing.paypal.com/ppfinportal/content/whyUseFinancing" target="_blank">Why Advertise Financing?</a><br/> + <![CDATA[<a href="https://financing.paypal.com/ppfinportal/content/whyUseFinancing" target="_blank">Why Advertise Financing?</a><br/> <strong>Give your sales a boost when you advertise financing.</strong><br/>PayPal helps turn browsers into buyers with financing from PayPal Credit®. Your customers have more time to pay, while you get paid up front – at no additional cost to you. Use PayPal’s free banner ads that let you advertise PayPal Credit® financing as a payment option when your customers check out with PayPal. The PayPal Advertising Program has been shown to generate additional purchases as well as increase consumer's average purchase sizes by 15% - or more. <a href="https:/financing.paypal.com/ppfinportal/content/forrester" target="_blank">See Details</a>.]]> + or more. <a href="https://financing.paypal.com/ppfinportal/content/forrester" target="_blank">See Details</a>.]]> </comment> <field id="bml_publisher_id" extends="payment_all_paypal/express_checkout/express_checkout_required/advertise_bml/bml_publisher_id" /> <field id="bml_wizard" extends="payment_all_paypal/express_checkout/express_checkout_required/advertise_bml/bml_wizard" /> diff --git a/app/code/Magento/Paypal/etc/adminhtml/system/payments_pro_hosted_solution.xml b/app/code/Magento/Paypal/etc/adminhtml/system/payments_pro_hosted_solution.xml index 80ba1c3ac03a2..77acff48c247e 100644 --- a/app/code/Magento/Paypal/etc/adminhtml/system/payments_pro_hosted_solution.xml +++ b/app/code/Magento/Paypal/etc/adminhtml/system/payments_pro_hosted_solution.xml @@ -49,7 +49,7 @@ <field id="enable_express_checkout_bml" extends="payment_all_paypal/express_checkout/express_checkout_required/enable_express_checkout_bml" sortOrder="21"> <comment><![CDATA[Payments Pro Hosted Solution lets you give customers access to financing through PayPal Credit® - at no additional cost to you. You get paid up front, even though customers have more time to pay. A pre-integrated payment button lets customers pay quickly with PayPal Credit®. - <a href="https:/www.paypal.com/webapps/mpp/promotional-financing" target="_blank">Learn More</a>]]> + <a href="https://www.paypal.com/webapps/mpp/promotional-financing" target="_blank">Learn More</a>]]> </comment> <requires> <field id="pphs_enable"/> @@ -58,12 +58,12 @@ <group id="pphs_advertise_bml" translate="label comment" showInDefault="1" showInWebsite="1" sortOrder="22"> <label>Advertise PayPal Credit</label> <comment> - <![CDATA[<a href="https:/financing.paypal.com/ppfinportal/content/whyUseFinancing" target="_blank">Why Advertise Financing?</a><br/> + <![CDATA[<a href="https://financing.paypal.com/ppfinportal/content/whyUseFinancing" target="_blank">Why Advertise Financing?</a><br/> <strong>Give your sales a boost when you advertise financing.</strong><br/>PayPal helps turn browsers into buyers with financing from PayPal Credit®. Your customers have more time to pay, while you get paid up front – at no additional cost to you. Use PayPal’s free banner ads that let you advertise PayPal Credit® financing as a payment option when your customers check out with PayPal. The PayPal Advertising Program has been shown to generate additional purchases as well as increase consumer's average purchase sizes by 15% - or more. <a href="https:/financing.paypal.com/ppfinportal/content/forrester" target="_blank">See Details</a>.]]> + or more. <a href="https://financing.paypal.com/ppfinportal/content/forrester" target="_blank">See Details</a>.]]> </comment> <field id="bml_publisher_id" extends="payment_all_paypal/express_checkout/express_checkout_required/advertise_bml/bml_publisher_id" /> <field id="bml_wizard" extends="payment_all_paypal/express_checkout/express_checkout_required/advertise_bml/bml_wizard" /> diff --git a/app/code/Magento/Paypal/etc/adminhtml/system/paypal_payflowpro_with_express_checkout.xml b/app/code/Magento/Paypal/etc/adminhtml/system/paypal_payflowpro_with_express_checkout.xml index 90ffeddbb812e..6090025024dd7 100644 --- a/app/code/Magento/Paypal/etc/adminhtml/system/paypal_payflowpro_with_express_checkout.xml +++ b/app/code/Magento/Paypal/etc/adminhtml/system/paypal_payflowpro_with_express_checkout.xml @@ -34,7 +34,7 @@ <label>Enable PayPal Credit</label> <comment><![CDATA[PayPal Express Checkout Payflow Edition lets you give customers access to financing through PayPal Credit® - at no additional cost to you. You get paid up front, even though customers have more time to pay. A pre-integrated payment button lets customers pay quickly with PayPal Credit®. - <a href="https:/www.paypal.com/webapps/mpp/promotional-financing" target="_blank">Learn More</a>]]> + <a href="https://www.paypal.com/webapps/mpp/promotional-financing" target="_blank">Learn More</a>]]> </comment> <config_path>payment/payflow_express_bml/active</config_path> <source_model>Magento\Config\Model\Config\Source\Yesno</source_model> @@ -53,12 +53,12 @@ <group id="paypal_payflow_advertise_bml" translate="label comment" showInDefault="1" showInWebsite="1" sortOrder="40"> <label>Advertise PayPal Credit</label> <comment> - <![CDATA[<a href="https:/financing.paypal.com/ppfinportal/content/whyUseFinancing" target="_blank">Why Advertise Financing?</a><br/> + <![CDATA[<a href="https://financing.paypal.com/ppfinportal/content/whyUseFinancing" target="_blank">Why Advertise Financing?</a><br/> <strong>Give your sales a boost when you advertise financing.</strong><br/>PayPal helps turn browsers into buyers with financing from PayPal Credit®. Your customers have more time to pay, while you get paid up front – at no additional cost to you. Use PayPal’s free banner ads that let you advertise PayPal Credit® financing as a payment option when your customers check out with PayPal. The PayPal Advertising Program has been shown to generate additional purchases as well as increase consumer's average purchase sizes by 15% - or more. <a href="https:/financing.paypal.com/ppfinportal/content/forrester" target="_blank">See Details</a>.]]> + or more. <a href="https://financing.paypal.com/ppfinportal/content/forrester" target="_blank">See Details</a>.]]> </comment> <field id="bml_publisher_id" extends="payment_all_paypal/express_checkout/express_checkout_required/advertise_bml/bml_publisher_id" /> <field id="bml_wizard" extends="payment_all_paypal/express_checkout/express_checkout_required/advertise_bml/bml_wizard" /> diff --git a/app/code/Magento/Paypal/i18n/en_US.csv b/app/code/Magento/Paypal/i18n/en_US.csv index 797edbf8bfa1e..e47264878f16e 100644 --- a/app/code/Magento/Paypal/i18n/en_US.csv +++ b/app/code/Magento/Paypal/i18n/en_US.csv @@ -1,17 +1,17 @@ " - <a href=""https:/financing.paypal.com/ppfinportal/content/whyUseFinancing"" target=""_blank"">Why Advertise Financing?</a><br/> + <a href=""https://financing.paypal.com/ppfinportal/content/whyUseFinancing"" target=""_blank"">Why Advertise Financing?</a><br/> <strong>Give your sales a boost when you advertise financing.</strong><br/>PayPal helps turn browsers into buyers with financing from PayPal Credit®. Your customers have more time to pay, while you get paid up front – at no additional cost to you. Use PayPal’ s free banner ads that let you advertise PayPal Credit® financing as a payment option when your customers check out with PayPal. The PayPal Advertising Program has been shown to generate additional purchases as well as increase consumer's average purchase sizes by 15% - or more. <a href=""https:/financing.paypal.com/ppfinportal/content/forrester"" target=""_blank"">See Details</a>. + or more. <a href=""https://financing.paypal.com/ppfinportal/content/forrester"" target=""_blank"">See Details</a>. "," - <a href=""https:/financing.paypal.com/ppfinportal/content/whyUseFinancing"" target=""_blank"">Why Advertise Financing?</a><br/> + <a href=""https://financing.paypal.com/ppfinportal/content/whyUseFinancing"" target=""_blank"">Why Advertise Financing?</a><br/> <strong>Give your sales a boost when you advertise financing.</strong><br/>PayPal helps turn browsers into buyers with financing from PayPal Credit®. Your customers have more time to pay, while you get paid up front – at no additional cost to you. Use PayPal’s free banner ads that let you advertise PayPal Credit® financing as a payment option when your customers check out with PayPal. The PayPal Advertising Program has been shown to generate additional purchases as well as increase consumer's average purchase sizes by 15% - or more. <a href=""https:/financing.paypal.com/ppfinportal/content/forrester"" target=""_blank"">See Details</a>. + or more. <a href=""https://financing.paypal.com/ppfinportal/content/forrester"" target=""_blank"">See Details</a>. " payflowpro,"Payflow Pro" "Billing Agreements","Billing Agreements" @@ -484,27 +484,27 @@ Manage,Manage "Enable PayPal Credit","Enable PayPal Credit" "PayPal Express Checkout lets you give customers access to financing through PayPal Credit® - at no additional cost to you. You get paid up front, even though customers have more time to pay. A pre-integrated payment button lets customers pay quickly with PayPal Credit®. - <a href=""https:/www.paypal.com/webapps/mpp/promotional-financing"" target=""_blank"">Learn More</a> + <a href=""https://www.paypal.com/webapps/mpp/promotional-financing"" target=""_blank"">Learn More</a> ","PayPal Express Checkout lets you give customers access to financing through PayPal Credit® - at no additional cost to you. You get paid up front, even though customers have more time to pay. A pre-integrated payment button lets customers pay quickly with PayPal Credit®. - <a href=""https:/www.paypal.com/webapps/mpp/promotional-financing"" target=""_blank"">Learn More</a> + <a href=""https://www.paypal.com/webapps/mpp/promotional-financing"" target=""_blank"">Learn More</a> " "Sort Order PayPal Credit","Sort Order PayPal Credit" "Advertise PayPal Credit","Advertise PayPal Credit" " - <a href=""https:/financing.paypal.com/ppfinportal/content/whyUseFinancing"" target=""_blank"">Why Advertise Financing?</a><br/> + <a href=""https://financing.paypal.com/ppfinportal/content/whyUseFinancing"" target=""_blank"">Why Advertise Financing?</a><br/> <strong>Give your sales a boost when you advertise financing.</strong><br/>PayPal helps turn browsers into buyers with financing from PayPal Credit®. Your customers have more time to pay, while you get paid up front – at no additional cost to you. Use PayPal’s free banner ads that let you advertise PayPal Credit® financing as a payment option when your customers check out with PayPal. The PayPal Advertising Program has been shown to generate additional purchases as well as increase consumer's average purchase sizes by 15% - or more. <a href=""https:/financing.paypal.com/ppfinportal/content/forrester"" target=""_blank"">See Details</a>. + or more. <a href=""https://financing.paypal.com/ppfinportal/content/forrester"" target=""_blank"">See Details</a>. "," - <a href=""https:/financing.paypal.com/ppfinportal/content/whyUseFinancing"" target=""_blank"">Why Advertise Financing?</a><br/> + <a href=""https://financing.paypal.com/ppfinportal/content/whyUseFinancing"" target=""_blank"">Why Advertise Financing?</a><br/> <strong>Give your sales a boost when you advertise financing.</strong><br/>PayPal helps turn browsers into buyers with financing from PayPal Credit®. Your customers have more time to pay, while you get paid up front – at no additional cost to you. Use PayPal’s free banner ads that let you advertise PayPal Credit® financing as a payment option when your customers check out with PayPal. The PayPal Advertising Program has been shown to generate additional purchases as well as increase consumer's average purchase sizes by 15% - or more. <a href=""https:/financing.paypal.com/ppfinportal/content/forrester"" target=""_blank"">See Details</a>. + or more. <a href=""https://financing.paypal.com/ppfinportal/content/forrester"" target=""_blank"">See Details</a>. " "Publisher ID","Publisher ID" "Required to display a banner","Required to display a banner" @@ -645,19 +645,19 @@ User,User "Accept payments with a PCI compliant checkout that keeps customers on your site. (<u>Includes Express Checkout</u>)","Accept payments with a PCI compliant checkout that keeps customers on your site. (<u>Includes Express Checkout</u>)" "Payments Pro Hosted Solution","Payments Pro Hosted Solution" " - <a href=""https:/financing.paypal.com/ppfinportal/content/whyUseFinancing"" target=""_blank"">Why Advertise Financing?</a><br/> + <a href=""https://financing.paypal.com/ppfinportal/content/whyUseFinancing"" target=""_blank"">Why Advertise Financing?</a><br/> <strong>Give your sales a boost when you advertise financing.</strong><br/>PayPal helps turn browsers into buyers with financing from PayPal Credit®. Your customers have more time to pay, while you get paid up front – at no additional cost to you. Use PayPal’s free banner ads that let you advertise PayPal Credit® financing as a payment option when your customers check out with PayPal. The PayPal Advertising Program has been shown to generate additional purchases as well as increase consumer's average purchase sizes by 15% - or more. <a href=""https:/financing.paypal.com/ppfinportal/content/forrester"" target=""_blank"">See Details</a>. + or more. <a href=""https://financing.paypal.com/ppfinportal/content/forrester"" target=""_blank"">See Details</a>. "," - <a href=""https:/financing.paypal.com/ppfinportal/content/whyUseFinancing"" target=""_blank"">Why Advertise Financing?</a><br/> + <a href=""https://financing.paypal.com/ppfinportal/content/whyUseFinancing"" target=""_blank"">Why Advertise Financing?</a><br/> <strong>Give your sales a boost when you advertise financing.</strong><br/>PayPal helps turn browsers into buyers with financing from PayPal Credit®. Your customers have more time to pay, while you get paid up front – at no additional cost to you. Use PayPal’s free banner ads that let you advertise PayPal Credit® financing as a payment option when your customers check out with PayPal. The PayPal Advertising Program has been shown to generate additional purchases as well as increase consumer's average purchase sizes by 15% - or more. <a href=""https:/financing.paypal.com/ppfinportal/content/forrester"" target=""_blank"">See Details</a>. + or more. <a href=""https://financing.paypal.com/ppfinportal/content/forrester"" target=""_blank"">See Details</a>. " "Basic Settings - PayPal Payments Pro Hosted Solution","Basic Settings - PayPal Payments Pro Hosted Solution" "Display Express Checkout in the Payment Information step","Display Express Checkout in the Payment Information step" @@ -683,17 +683,17 @@ User,User "Card Security Code Does Not Match","Card Security Code Does Not Match" "Payflow Pro and Express Checkout","Payflow Pro and Express Checkout" " - <a href=""https:/financing.paypal.com/ppfinportal/content/whyUseFinancing"" target=""_blank"">Why Advertise Financing?</a><br/> + <a href=""https://financing.paypal.com/ppfinportal/content/whyUseFinancing"" target=""_blank"">Why Advertise Financing?</a><br/> <strong>Give your sales a boost when you advertise financing.</strong><br/>PayPal helps turn browsers into buyers with financing from PayPal Credit®. Your customers have more time to pay, while you get paid up front – at no additional cost to you. Use PayPal’s free banner ads that let you advertise PayPal Credit® financing as a payment option when your customers check out with PayPal. The PayPal Advertising Program has been shown to generate additional purchases as well as increase consumer's average purchase sizes by 15% - or more. <a href=""https:/financing.paypal.com/ppfinportal/content/forrester"" target=""_blank"">See Details</a>. + or more. <a href=""https://financing.paypal.com/ppfinportal/content/forrester"" target=""_blank"">See Details</a>. "," - <a href=""https:/financing.paypal.com/ppfinportal/content/whyUseFinancing"" target=""_blank"">Why Advertise Financing?</a><br/> + <a href=""https://financing.paypal.com/ppfinportal/content/whyUseFinancing"" target=""_blank"">Why Advertise Financing?</a><br/> <strong>Give your sales a boost when you advertise financing.</strong><br/>PayPal helps turn browsers into buyers with financing from PayPal Credit®. Your customers have more time to pay, while you get paid up front – at no additional cost to you. Use PayPal’s free banner ads that let you advertise PayPal Credit® financing as a payment option when your customers check out with PayPal. The PayPal Advertising Program has been shown to generate additional purchases as well as increase consumer's average purchase sizes by 15% - or more. <a href=""https:/financing.paypal.com/ppfinportal/content/forrester"" target=""_blank"">See Details</a>. + or more. <a href=""https://financing.paypal.com/ppfinportal/content/forrester"" target=""_blank"">See Details</a>. " diff --git a/app/code/Magento/Persistent/Test/Mftf/Test/GuestCheckoutWithEnabledPersistentTest.xml b/app/code/Magento/Persistent/Test/Mftf/Test/GuestCheckoutWithEnabledPersistentTest.xml index 49d07992694d4..03509268751ed 100644 --- a/app/code/Magento/Persistent/Test/Mftf/Test/GuestCheckoutWithEnabledPersistentTest.xml +++ b/app/code/Magento/Persistent/Test/Mftf/Test/GuestCheckoutWithEnabledPersistentTest.xml @@ -72,12 +72,12 @@ <see selector="{{CheckoutPaymentSection.billingAddress}}" userInput="{{CustomerAddressSimple.postcode}}" stepKey="seeBilllingPostcode" /> <see selector="{{CheckoutPaymentSection.billingAddress}}" userInput="{{CustomerAddressSimple.telephone}}" stepKey="seeBilllingTelephone" /> <!-- Check that "Ship To" block contains correct information --> - <see selector="{{CheckoutPaymentSection.shipToInfomation}}" userInput="{{CustomerAddressSimple.firstName}}" stepKey="seeShipToFirstName" /> - <see selector="{{CheckoutPaymentSection.shipToInfomation}}" userInput="{{CustomerAddressSimple.lastName}}" stepKey="seeShipToLastName" /> - <see selector="{{CheckoutPaymentSection.shipToInfomation}}" userInput="{{CustomerAddressSimple.street[0]}}" stepKey="seeShipToStreet" /> - <see selector="{{CheckoutPaymentSection.shipToInfomation}}" userInput="{{CustomerAddressSimple.city}}" stepKey="seeShipToCity" /> - <see selector="{{CheckoutPaymentSection.shipToInfomation}}" userInput="{{CustomerAddressSimple.state}}" stepKey="seeShipToState" /> - <see selector="{{CheckoutPaymentSection.shipToInfomation}}" userInput="{{CustomerAddressSimple.postcode}}" stepKey="seeShipToPostcode" /> - <see selector="{{CheckoutPaymentSection.shipToInfomation}}" userInput="{{CustomerAddressSimple.telephone}}" stepKey="seeShipToTelephone" /> + <see selector="{{CheckoutPaymentSection.shipToInformation}}" userInput="{{CustomerAddressSimple.firstName}}" stepKey="seeShipToFirstName" /> + <see selector="{{CheckoutPaymentSection.shipToInformation}}" userInput="{{CustomerAddressSimple.lastName}}" stepKey="seeShipToLastName" /> + <see selector="{{CheckoutPaymentSection.shipToInformation}}" userInput="{{CustomerAddressSimple.street[0]}}" stepKey="seeShipToStreet" /> + <see selector="{{CheckoutPaymentSection.shipToInformation}}" userInput="{{CustomerAddressSimple.city}}" stepKey="seeShipToCity" /> + <see selector="{{CheckoutPaymentSection.shipToInformation}}" userInput="{{CustomerAddressSimple.state}}" stepKey="seeShipToState" /> + <see selector="{{CheckoutPaymentSection.shipToInformation}}" userInput="{{CustomerAddressSimple.postcode}}" stepKey="seeShipToPostcode" /> + <see selector="{{CheckoutPaymentSection.shipToInformation}}" userInput="{{CustomerAddressSimple.telephone}}" stepKey="seeShipToTelephone" /> </test> </tests> diff --git a/app/code/Magento/Persistent/Test/Mftf/composer.json b/app/code/Magento/Persistent/Test/Mftf/composer.json deleted file mode 100644 index 0ea42b2755a0d..0000000000000 --- a/app/code/Magento/Persistent/Test/Mftf/composer.json +++ /dev/null @@ -1,22 +0,0 @@ -{ - "name": "magento/functional-test-module-persistent", - "description": "N/A", - "config": { - "sort-packages": true - }, - "require": { - "php": "~7.1.3||~7.2.0", - "magento/magento2-functional-testing-framework": "2.2.0", - "magento/functional-test-module-checkout": "100.0.0-dev", - "magento/functional-test-module-cron": "100.0.0-dev", - "magento/functional-test-module-customer": "100.0.0-dev", - "magento/functional-test-module-page-cache": "100.0.0-dev", - "magento/functional-test-module-quote": "100.0.0-dev", - "magento/functional-test-module-store": "100.0.0-dev" - }, - "type": "magento2-test", - "license": [ - "OSL-3.0", - "AFL-3.0" - ] -} diff --git a/app/code/Magento/ProductAlert/Test/Mftf/composer.json b/app/code/Magento/ProductAlert/Test/Mftf/composer.json deleted file mode 100644 index 37fda5965a0f8..0000000000000 --- a/app/code/Magento/ProductAlert/Test/Mftf/composer.json +++ /dev/null @@ -1,23 +0,0 @@ -{ - "name": "magento/functional-test-module-product-alert", - "description": "N/A", - "config": { - "sort-packages": true - }, - "require": { - "php": "~7.1.3||~7.2.0", - "magento/magento2-functional-testing-framework": "2.2.0", - "magento/functional-test-module-backend": "100.0.0-dev", - "magento/functional-test-module-catalog": "100.0.0-dev", - "magento/functional-test-module-customer": "100.0.0-dev", - "magento/functional-test-module-store": "100.0.0-dev" - }, - "suggest": { - "magento/functional-test-module-config": "100.0.0-dev" - }, - "type": "magento2-test", - "license": [ - "OSL-3.0", - "AFL-3.0" - ] -} diff --git a/app/code/Magento/ProductVideo/Block/Product/View/Gallery.php b/app/code/Magento/ProductVideo/Block/Product/View/Gallery.php index 2277aa980f66c..45c4925640a0c 100644 --- a/app/code/Magento/ProductVideo/Block/Product/View/Gallery.php +++ b/app/code/Magento/ProductVideo/Block/Product/View/Gallery.php @@ -9,9 +9,8 @@ * * @author Magento Core Team <core@magentocommerce.com> */ -namespace Magento\ProductVideo\Block\Product\View; -use Magento\Catalog\Model\Product\Image\UrlBuilder; +namespace Magento\ProductVideo\Block\Product\View; /** * @api @@ -93,6 +92,6 @@ public function getVideoSettingsJson() */ public function getOptionsMediaGalleryDataJson() { - return $this->jsonEncoder->encode([]); + return $this->jsonEncoder->encode([]); } } diff --git a/app/code/Magento/ProductVideo/Model/Plugin/Catalog/Product/Gallery/CreateHandler.php b/app/code/Magento/ProductVideo/Model/Plugin/Catalog/Product/Gallery/CreateHandler.php index ab3c8f3c5269a..ce1493b349a85 100644 --- a/app/code/Magento/ProductVideo/Model/Plugin/Catalog/Product/Gallery/CreateHandler.php +++ b/app/code/Magento/ProductVideo/Model/Plugin/Catalog/Product/Gallery/CreateHandler.php @@ -3,6 +3,7 @@ * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ + namespace Magento\ProductVideo\Model\Plugin\Catalog\Product\Gallery; use Magento\ProductVideo\Model\Product\Attribute\Media\ExternalVideoEntryConverter; @@ -29,6 +30,7 @@ public function beforeExecute( \Magento\Catalog\Model\Product $product, array $arguments = [] ) { + /** @var \Magento\Catalog\Model\ResourceModel\Eav\Attribute $attribute */ $attribute = $mediaGalleryCreateHandler->getAttribute(); $mediaCollection = $this->getMediaEntriesDataCollection($product, $attribute); if (!empty($mediaCollection)) { @@ -36,7 +38,7 @@ public function beforeExecute( $mediaCollection = $this->addAdditionalStoreData($mediaCollection, $storeDataCollection); $product->setData( $attribute->getAttributeCode(), - $mediaCollection + $product->getData($attribute->getAttributeCode()) + $mediaCollection ); } } @@ -56,6 +58,9 @@ public function afterExecute( ); if (!empty($mediaCollection)) { + $newVideoCollection = $this->collectNewVideos($mediaCollection); + $this->saveVideoData($newVideoCollection, 0); + $videoDataCollection = $this->collectVideoData($mediaCollection); $this->saveVideoData($videoDataCollection, $product->getStoreId()); $this->saveAdditionalStoreData($videoDataCollection); @@ -167,10 +172,7 @@ protected function collectVideoData(array $mediaCollection) { $videoDataCollection = []; foreach ($mediaCollection as $item) { - if (!empty($item['media_type']) - && empty($item['removed']) - && $item['media_type'] == ExternalVideoEntryConverter::MEDIA_TYPE_CODE - ) { + if ($this->isVideoItem($item)) { $videoData = $this->extractVideoDataFromRowData($item); $videoDataCollection[] = $videoData; } @@ -199,11 +201,7 @@ protected function collectVideoEntriesIdsToAdditionalLoad(array $mediaCollection { $ids = []; foreach ($mediaCollection as $item) { - if (!empty($item['media_type']) - && empty($item['removed']) - && $item['media_type'] == ExternalVideoEntryConverter::MEDIA_TYPE_CODE - && isset($item['save_data_from']) - ) { + if ($this->isVideoItem($item) && isset($item['save_data_from'])) { $ids[] = $item['save_data_from']; } } @@ -215,18 +213,19 @@ protected function collectVideoEntriesIdsToAdditionalLoad(array $mediaCollection * @param array $data * @return array */ - protected function addAdditionalStoreData(array $mediaCollection, array $data) + protected function addAdditionalStoreData(array $mediaCollection, array $data): array { - foreach ($mediaCollection as &$mediaItem) { + $return = []; + foreach ($mediaCollection as $key => $mediaItem) { if (!empty($mediaItem['save_data_from'])) { $additionalData = $this->createAdditionalStoreDataCollection($data, $mediaItem['save_data_from']); if (!empty($additionalData)) { $mediaItem[self::ADDITIONAL_STORE_DATA_KEY] = $additionalData; } } + $return[$key] = $mediaItem; } - - return ['images' => $mediaCollection]; + return ['images' => $return]; } /** @@ -234,7 +233,7 @@ protected function addAdditionalStoreData(array $mediaCollection, array $data) * @param int $valueId * @return array */ - protected function createAdditionalStoreDataCollection(array $storeData, $valueId) + protected function createAdditionalStoreDataCollection(array $storeData, $valueId): array { $result = []; foreach ($storeData as $item) { @@ -246,4 +245,41 @@ protected function createAdditionalStoreDataCollection(array $storeData, $valueI return $result; } + + /** + * @param array $mediaCollection + * @return array + */ + private function collectNewVideos(array $mediaCollection): array + { + $return = []; + foreach ($mediaCollection as $item) { + if ($this->isVideoItem($item) && $this->isNewVideo($item)) { + $return[] = $this->extractVideoDataFromRowData($item); + } + } + return $return; + } + + /** + * @param array $item + * @return bool + */ + private function isVideoItem(array $item): bool + { + return !empty($item['media_type']) + && empty($item['removed']) + && $item['media_type'] == ExternalVideoEntryConverter::MEDIA_TYPE_CODE; + } + + /** + * @param array $item + * @return bool + */ + private function isNewVideo(array $item): bool + { + return !isset($item['video_url_default'], $item['video_title_default']) + || empty($item['video_url_default']) + || empty($item['video_title_default']); + } } diff --git a/app/code/Magento/ProductVideo/Model/Plugin/Catalog/Product/Gallery/ReadHandler.php b/app/code/Magento/ProductVideo/Model/Plugin/Catalog/Product/Gallery/ReadHandler.php index 6c534580c39d9..31d63efcf8cb0 100644 --- a/app/code/Magento/ProductVideo/Model/Plugin/Catalog/Product/Gallery/ReadHandler.php +++ b/app/code/Magento/ProductVideo/Model/Plugin/Catalog/Product/Gallery/ReadHandler.php @@ -3,6 +3,7 @@ * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ + namespace Magento\ProductVideo\Model\Plugin\Catalog\Product\Gallery; use Magento\ProductVideo\Model\Product\Attribute\Media\ExternalVideoEntryConverter; @@ -55,8 +56,8 @@ protected function collectVideoEntriesIds(array $mediaCollection) { $ids = []; foreach ($mediaCollection as $item) { - if ($item['media_type'] == ExternalVideoEntryConverter::MEDIA_TYPE_CODE - && !array_key_exists('video_url', $item) + if ($item['media_type'] === ExternalVideoEntryConverter::MEDIA_TYPE_CODE + && !isset($item['video_url']) ) { $ids[] = $item['value_id']; } @@ -72,7 +73,7 @@ protected function collectVideoEntriesIds(array $mediaCollection) protected function loadVideoDataById(array $ids, $storeId = null) { $mainTableAlias = $this->resourceModel->getMainTableAlias(); - $joinConditions = $mainTableAlias.'.value_id = store_value.value_id'; + $joinConditions = $mainTableAlias . '.value_id = store_value.value_id'; if (null !== $storeId) { $joinConditions = implode( ' AND ', @@ -138,10 +139,10 @@ protected function addVideoDataToMediaEntries(array $mediaCollection, array $dat protected function substituteNullsWithDefaultValues(array $rowData) { foreach ($this->getVideoProperties(false) as $key) { - if (empty($rowData[$key]) && !empty($rowData[$key.'_default'])) { - $rowData[$key] = $rowData[$key.'_default']; + if (empty($rowData[$key]) && !empty($rowData[$key . '_default'])) { + $rowData[$key] = $rowData[$key . '_default']; } - unset($rowData[$key.'_default']); + unset($rowData[$key . '_default']); } return $rowData; @@ -154,8 +155,7 @@ protected function substituteNullsWithDefaultValues(array $rowData) protected function getVideoProperties($withDbMapping = true) { $properties = $this->videoPropertiesDbMapping; - unset($properties['value_id']); - unset($properties['store_id']); + unset($properties['value_id'], $properties['store_id']); return $withDbMapping ? $properties : array_keys($properties); } diff --git a/app/code/Magento/ProductVideo/Test/Mftf/composer.json b/app/code/Magento/ProductVideo/Test/Mftf/composer.json deleted file mode 100644 index a2f1223db010d..0000000000000 --- a/app/code/Magento/ProductVideo/Test/Mftf/composer.json +++ /dev/null @@ -1,25 +0,0 @@ -{ - "name": "magento/functional-test-module-product-video", - "description": "Add Video to Products", - "config": { - "sort-packages": true - }, - "require": { - "php": "~7.1.3||~7.2.0", - "magento/magento2-functional-testing-framework": "2.2.0", - "magento/magento-composer-installer": "100.0.0-dev", - "magento/functional-test-module-backend": "100.0.0-dev", - "magento/functional-test-module-catalog": "100.0.0-dev", - "magento/functional-test-module-eav": "100.0.0-dev", - "magento/functional-test-module-media-storage": "100.0.0-dev", - "magento/functional-test-module-store": "100.0.0-dev" - }, - "suggest": { - "magento/functional-test-module-customer": "100.0.0-dev", - "magento/functional-test-module-config": "100.0.0-dev" - }, - "type": "magento2-test", - "license": [ - "proprietary" - ] -} diff --git a/app/code/Magento/ProductVideo/Test/Unit/Model/Plugin/Catalog/Product/Gallery/CreateHandlerTest.php b/app/code/Magento/ProductVideo/Test/Unit/Model/Plugin/Catalog/Product/Gallery/CreateHandlerTest.php index 5770ea8b5689d..57ad71997dad7 100644 --- a/app/code/Magento/ProductVideo/Test/Unit/Model/Plugin/Catalog/Product/Gallery/CreateHandlerTest.php +++ b/app/code/Magento/ProductVideo/Test/Unit/Model/Plugin/Catalog/Product/Gallery/CreateHandlerTest.php @@ -3,6 +3,7 @@ * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ + namespace Magento\ProductVideo\Test\Unit\Model\Plugin\Catalog\Product\Gallery; /** @@ -37,6 +38,9 @@ class CreateHandlerTest extends \PHPUnit\Framework\TestCase */ protected $mediaGalleryCreateHandler; + /** + * {@inheritDoc} + */ protected function setUp() { $this->product = $this->createMock(\Magento\Catalog\Model\Product::class); @@ -62,72 +66,18 @@ protected function setUp() ); } - public function testAfterExecute() + /** + * @dataProvider provideImageForAfterExecute + * @param array $image + * @param array $expectedSave + * @param int $rowSaved + */ + public function testAfterExecute($image, $expectedSave, $rowSaved): void { - $mediaData = [ - 'images' => [ - '72mljfhmasfilp9cuq' => [ - 'position' => '3', - 'media_type' => 'external-video', - 'file' => '/i/n/index111111.jpg', - 'value_id' => '4', - 'label' => '', - 'disabled' => '0', - 'removed' => '', - 'video_provider' => 'youtube', - 'video_url' => 'https://www.youtube.com/watch?v=ab123456', - 'video_title' => 'Some second title', - 'video_description' => 'Description second', - 'video_metadata' => 'meta two', - 'role' => '', - ], - 'w596fi79hv1p6wj21u' => [ - 'position' => '4', - 'media_type' => 'image', - 'video_provider' => '', - 'file' => '/h/d/hd_image.jpg', - 'value_id' => '7', - 'label' => '', - 'disabled' => '0', - 'removed' => '', - 'video_url' => '', - 'video_title' => '', - 'video_description' => '', - 'video_metadata' => '', - 'role' => '', - ], - 'tcodwd7e0dirifr64j' => [ - 'position' => '4', - 'media_type' => 'external-video', - 'file' => '/s/a/sample_3.jpg', - 'value_id' => '5', - 'label' => '', - 'disabled' => '0', - 'removed' => '', - 'video_provider' => 'youtube', - 'video_url' => 'https://www.youtube.com/watch?v=ab123456', - 'video_title' => 'Some second title', - 'video_description' => 'Description second', - 'video_metadata' => 'meta two', - 'role' => '', - 'additional_store_data' => [ - 0 => [ - 'store_id' => '0', - 'video_provider' => null, - 'video_url' => 'https://www.youtube.com/watch?v=ab123456', - 'video_title' => 'New Title', - 'video_description' => 'New Description', - 'video_metadata' => 'New metadata', - ], - ] - ], - ], - ]; - $this->product->expects($this->once()) ->method('getData') ->with('media_gallery') - ->willReturn($mediaData); + ->willReturn(['images' => $image]); $this->product->expects($this->once()) ->method('getStoreId') ->willReturn(0); @@ -136,13 +86,150 @@ public function testAfterExecute() ->method('getAttribute') ->willReturn($this->attribute); - $this->subject->afterExecute( - $this->mediaGalleryCreateHandler, - $this->product - ); + $this->resourceModel->expects($this->exactly($rowSaved)) + ->method('saveDataRow') + ->with('catalog_product_entity_media_gallery_value_video', $expectedSave) + ->willReturn(1); + + $this->subject->afterExecute($this->mediaGalleryCreateHandler, $this->product); + } + + /** + * DataProvider for testAfterExecute + * + * @SuppressWarnings(PHPMD.ExcessiveMethodLength) + * @return array + */ + public function provideImageForAfterExecute(): array + { + return [ + 'new_video' => [ + [ + '72mljfhmasfilp9cuq' => [ + 'position' => '3', + 'media_type' => 'external-video', + 'file' => '/i/n/index111111.jpg', + 'value_id' => '4', + 'label' => '', + 'disabled' => '0', + 'removed' => '', + 'video_provider' => 'youtube', + 'video_url' => 'https://www.youtube.com/watch?v=ab123456', + 'video_title' => 'Some second title', + 'video_description' => 'Description second', + 'video_metadata' => 'meta two', + 'role' => '', + ], + ], + [ + 'value_id' => '4', + 'store_id' => 0, + 'provider' => 'youtube', + 'url' => 'https://www.youtube.com/watch?v=ab123456', + 'title' => 'Some second title', + 'description' => 'Description second', + 'metadata' => 'meta two', + ], + 2 + ], + 'image' => [ + [ + 'w596fi79hv1p6wj21u' => [ + 'position' => '4', + 'media_type' => 'image', + 'video_provider' => '', + 'file' => '/h/d/hd_image.jpg', + 'value_id' => '7', + 'label' => '', + 'disabled' => '0', + 'removed' => '', + 'video_url' => '', + 'video_title' => '', + 'video_description' => '', + 'video_metadata' => '', + 'role' => '', + ], + ], + [], + 0 + ], + 'new_video_with_additional_data' => [ + [ + 'tcodwd7e0dirifr64j' => [ + 'position' => '4', + 'media_type' => 'external-video', + 'file' => '/s/a/sample_3.jpg', + 'value_id' => '5', + 'label' => '', + 'disabled' => '0', + 'removed' => '', + 'video_provider' => 'youtube', + 'video_url' => 'https://www.youtube.com/watch?v=ab123456', + 'video_title' => 'Some second title', + 'video_description' => 'Description second', + 'video_metadata' => 'meta two', + 'role' => '', + 'additional_store_data' => [ + 0 => [ + 'store_id' => 0, + 'video_provider' => 'youtube', + 'video_url' => 'https://www.youtube.com/watch?v=ab123456', + 'video_title' => 'Some second title', + 'video_description' => 'Description second', + 'video_metadata' => 'meta two', + ], + ] + ], + ], + [ + 'value_id' => '5', + 'store_id' => 0, + 'provider' => 'youtube', + 'url' => 'https://www.youtube.com/watch?v=ab123456', + 'title' => 'Some second title', + 'description' => 'Description second', + 'metadata' => 'meta two', + ], + 3 + ], + 'not_new_video' => [ + [ + '72mljfhmasfilp9cuq' => [ + 'position' => '3', + 'media_type' => 'external-video', + 'file' => '/i/n/index111111.jpg', + 'value_id' => '4', + 'label' => '', + 'disabled' => '0', + 'removed' => '', + 'video_provider' => 'youtube', + 'video_url' => 'https://www.youtube.com/watch?v=ab123456', + 'video_url_default' => 'https://www.youtube.com/watch?v=ab123456', + 'video_title' => 'Some second title', + 'video_title_default' => 'Some second title', + 'video_description' => 'Description second', + 'video_metadata' => 'meta two', + 'role' => '', + ], + ], + [ + 'value_id' => '4', + 'store_id' => 0, + 'provider' => 'youtube', + 'url' => 'https://www.youtube.com/watch?v=ab123456', + 'title' => 'Some second title', + 'description' => 'Description second', + 'metadata' => 'meta two', + ], + 1 + ], + ]; } - public function testAfterExecuteEmpty() + /** + * Tests empty media gallery + */ + public function testAfterExecuteEmpty(): void { $this->product->expects($this->once()) ->method('getData') @@ -162,7 +249,7 @@ public function testAfterExecuteEmpty() /** * @SuppressWarnings(PHPMD.ExcessiveMethodLength) */ - public function testBeforeExecute() + public function testBeforeExecute(): void { $mediaData = [ 'images' => [ diff --git a/app/code/Magento/ProductVideo/composer.json b/app/code/Magento/ProductVideo/composer.json index 829816321c1a5..24497f891db43 100644 --- a/app/code/Magento/ProductVideo/composer.json +++ b/app/code/Magento/ProductVideo/composer.json @@ -20,7 +20,8 @@ }, "type": "magento2-module", "license": [ - "proprietary" + "OSL-3.0", + "AFL-3.0" ], "autoload": { "files": [ diff --git a/app/code/Magento/Quote/Model/Cart/CartTotalRepository.php b/app/code/Magento/Quote/Model/Cart/CartTotalRepository.php index 9fe69b691424d..e18ab8587fc71 100644 --- a/app/code/Magento/Quote/Model/Cart/CartTotalRepository.php +++ b/app/code/Magento/Quote/Model/Cart/CartTotalRepository.php @@ -10,6 +10,7 @@ use Magento\Quote\Api\CartTotalRepositoryInterface; use Magento\Catalog\Helper\Product\ConfigurationPool; use Magento\Framework\Api\DataObjectHelper; +use Magento\Framework\Api\ExtensibleDataInterface; use Magento\Quote\Model\Cart\Totals\ItemConverter; use Magento\Quote\Api\CouponManagementInterface; @@ -94,6 +95,7 @@ public function get($cartId) $addressTotalsData = $quote->getShippingAddress()->getData(); $addressTotals = $quote->getShippingAddress()->getTotals(); } + unset($addressTotalsData[ExtensibleDataInterface::EXTENSION_ATTRIBUTES_KEY]); /** @var \Magento\Quote\Api\Data\TotalsInterface $quoteTotals */ $quoteTotals = $this->totalsFactory->create(); diff --git a/app/code/Magento/Quote/Model/Quote.php b/app/code/Magento/Quote/Model/Quote.php index 3b19c6495dd99..b7a1b7d563ef6 100644 --- a/app/code/Magento/Quote/Model/Quote.php +++ b/app/code/Magento/Quote/Model/Quote.php @@ -1399,7 +1399,7 @@ public function getAllVisibleItems() { $items = []; foreach ($this->getItemsCollection() as $item) { - if (!$item->isDeleted() && !$item->getParentItemId()) { + if (!$item->isDeleted() && !$item->getParentItemId() && !$item->getParentItem()) { $items[] = $item; } } diff --git a/app/code/Magento/Quote/Model/Quote/Address.php b/app/code/Magento/Quote/Model/Quote/Address.php index 87c5feaba8f2e..3eb5d68885035 100644 --- a/app/code/Magento/Quote/Model/Quote/Address.php +++ b/app/code/Magento/Quote/Model/Quote/Address.php @@ -872,13 +872,7 @@ public function getGroupedAllShippingRates() */ protected function _sortRates($firstItem, $secondItem) { - if ((int)$firstItem[0]->carrier_sort_order < (int)$secondItem[0]->carrier_sort_order) { - return -1; - } elseif ((int)$firstItem[0]->carrier_sort_order > (int)$secondItem[0]->carrier_sort_order) { - return 1; - } else { - return 0; - } + return (int) $firstItem[0]->carrier_sort_order <=> (int) $secondItem[0]->carrier_sort_order; } /** diff --git a/app/code/Magento/Quote/Model/QuoteRepository.php b/app/code/Magento/Quote/Model/QuoteRepository.php index d3967794b300a..01c21bbbe50a7 100644 --- a/app/code/Magento/Quote/Model/QuoteRepository.php +++ b/app/code/Magento/Quote/Model/QuoteRepository.php @@ -212,7 +212,7 @@ protected function loadQuote($loadMethod, $loadField, $identifier, array $shared if ($sharedStoreIds) { $quote->setSharedStoreIds($sharedStoreIds); } - $quote->$loadMethod($identifier)->setStoreId($this->storeManager->getStore()->getId()); + $quote->setStoreId($this->storeManager->getStore()->getId())->$loadMethod($identifier); if (!$quote->getId()) { throw NoSuchEntityException::singleField($loadField, $identifier); } diff --git a/app/code/Magento/Quote/Model/ResourceModel/Quote/Item/Collection.php b/app/code/Magento/Quote/Model/ResourceModel/Quote/Item/Collection.php index 2405eaa9d37a3..c7525754dffd9 100644 --- a/app/code/Magento/Quote/Model/ResourceModel/Quote/Item/Collection.php +++ b/app/code/Magento/Quote/Model/ResourceModel/Quote/Item/Collection.php @@ -323,6 +323,10 @@ private function addTierPriceData(ProductCollection $productCollection) */ private function removeItemsWithAbsentProducts() { + if (count($this->_productIds) === 0) { + return; + } + $productCollection = $this->_productCollectionFactory->create()->addIdFilter($this->_productIds); $existingProductsIds = $productCollection->getAllIds(); $absentProductsIds = array_diff($this->_productIds, $existingProductsIds); diff --git a/app/code/Magento/Quote/Model/ShippingMethodManagement.php b/app/code/Magento/Quote/Model/ShippingMethodManagement.php index ade2649d0b1b0..f62866539c6cc 100644 --- a/app/code/Magento/Quote/Model/ShippingMethodManagement.php +++ b/app/code/Magento/Quote/Model/ShippingMethodManagement.php @@ -16,6 +16,7 @@ use Magento\Quote\Api\Data\AddressInterface; use Magento\Quote\Api\Data\EstimateAddressInterface; use Magento\Quote\Api\ShipmentEstimationInterface; +use Magento\Quote\Model\ResourceModel\Quote\Address as QuoteAddressResource; /** * Shipping method read service @@ -63,6 +64,11 @@ class ShippingMethodManagement implements */ private $addressFactory; + /** + * @var QuoteAddressResource + */ + private $quoteAddressResource; + /** * Constructor * @@ -71,13 +77,15 @@ class ShippingMethodManagement implements * @param \Magento\Customer\Api\AddressRepositoryInterface $addressRepository * @param Quote\TotalsCollector $totalsCollector * @param AddressInterfaceFactory|null $addressFactory + * @param QuoteAddressResource|null $quoteAddressResource */ public function __construct( \Magento\Quote\Api\CartRepositoryInterface $quoteRepository, Cart\ShippingMethodConverter $converter, \Magento\Customer\Api\AddressRepositoryInterface $addressRepository, \Magento\Quote\Model\Quote\TotalsCollector $totalsCollector, - AddressInterfaceFactory $addressFactory = null + AddressInterfaceFactory $addressFactory = null, + QuoteAddressResource $quoteAddressResource = null ) { $this->quoteRepository = $quoteRepository; $this->converter = $converter; @@ -85,6 +93,8 @@ public function __construct( $this->totalsCollector = $totalsCollector; $this->addressFactory = $addressFactory ?: ObjectManager::getInstance() ->get(AddressInterfaceFactory::class); + $this->quoteAddressResource = $quoteAddressResource ?: ObjectManager::getInstance() + ->get(QuoteAddressResource::class); } /** @@ -171,9 +181,9 @@ public function set($cartId, $carrierCode, $methodCode) * @param string $methodCode The shipping method code. * @return void * @throws InputException The shipping method is not valid for an empty cart. - * @throws CouldNotSaveException The shipping method could not be saved. * @throws NoSuchEntityException CThe Cart includes virtual product(s) only, so a shipping address is not used. - * @throws StateException The billing or shipping address is missing. Set the address and try again. + * @throws StateException The billing or shipping address is not set. + * @throws \Exception */ public function apply($cartId, $carrierCode, $methodCode) { @@ -191,6 +201,8 @@ public function apply($cartId, $carrierCode, $methodCode) } $shippingAddress = $quote->getShippingAddress(); if (!$shippingAddress->getCountryId()) { + // Remove empty quote address + $this->quoteAddressResource->delete($shippingAddress); throw new StateException(__('The shipping address is missing. Set the address and try again.')); } $shippingAddress->setShippingMethod($carrierCode . '_' . $methodCode); diff --git a/app/code/Magento/Quote/Plugin/UpdateQuoteStore.php b/app/code/Magento/Quote/Plugin/UpdateQuoteStore.php new file mode 100644 index 0000000000000..de2fc76b9179f --- /dev/null +++ b/app/code/Magento/Quote/Plugin/UpdateQuoteStore.php @@ -0,0 +1,69 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +declare(strict_types=1); + +namespace Magento\Quote\Plugin; + +use Magento\Checkout\Model\Session; +use Magento\Quote\Model\QuoteRepository; +use Magento\Store\Api\Data\StoreInterface; +use Magento\Store\Api\StoreCookieManagerInterface; + +/** + * Updates quote store id. + */ +class UpdateQuoteStore +{ + /** + * @var QuoteRepository + */ + private $quoteRepository; + + /** + * @var Session + */ + private $checkoutSession; + + /** + * @param QuoteRepository $quoteRepository + * @param Session $checkoutSession + */ + public function __construct( + QuoteRepository $quoteRepository, + Session $checkoutSession + ) { + $this->quoteRepository = $quoteRepository; + $this->checkoutSession = $checkoutSession; + } + + /** + * Update store id in active quote after store view switching. + * + * @param StoreCookieManagerInterface $subject + * @param null $result + * @param StoreInterface $store + * @return void + * @SuppressWarnings(PHPMD.UnusedFormalParameter) + */ + public function afterSetStoreCookie( + StoreCookieManagerInterface $subject, + $result, + StoreInterface $store + ) { + $storeCodeFromCookie = $subject->getStoreCodeFromCookie(); + if (null === $storeCodeFromCookie) { + return; + } + + $quote = $this->checkoutSession->getQuote(); + if ($quote->getIsActive() && $store->getCode() != $storeCodeFromCookie) { + $quote->setStoreId( + $store->getId() + ); + $this->quoteRepository->save($quote); + } + } +} diff --git a/app/code/Magento/Quote/Test/Mftf/composer.json b/app/code/Magento/Quote/Test/Mftf/composer.json deleted file mode 100644 index 62932a84f3059..0000000000000 --- a/app/code/Magento/Quote/Test/Mftf/composer.json +++ /dev/null @@ -1,33 +0,0 @@ -{ - "name": "magento/functional-test-module-quote", - "description": "N/A", - "config": { - "sort-packages": true - }, - "require": { - "php": "~7.1.3||~7.2.0", - "magento/magento2-functional-testing-framework": "2.2.0", - "magento/functional-test-module-authorization": "100.0.0-dev", - "magento/functional-test-module-backend": "100.0.0-dev", - "magento/functional-test-module-catalog": "100.0.0-dev", - "magento/functional-test-module-catalog-inventory": "100.0.0-dev", - "magento/functional-test-module-checkout": "100.0.0-dev", - "magento/functional-test-module-customer": "100.0.0-dev", - "magento/functional-test-module-directory": "100.0.0-dev", - "magento/functional-test-module-eav": "100.0.0-dev", - "magento/functional-test-module-payment": "100.0.0-dev", - "magento/functional-test-module-sales": "100.0.0-dev", - "magento/functional-test-module-sales-sequence": "100.0.0-dev", - "magento/functional-test-module-shipping": "100.0.0-dev", - "magento/functional-test-module-store": "100.0.0-dev", - "magento/functional-test-module-tax": "100.0.0-dev" - }, - "suggest": { - "magento/functional-test-module-webapi": "100.0.0-dev" - }, - "type": "magento2-test", - "license": [ - "OSL-3.0", - "AFL-3.0" - ] -} diff --git a/app/code/Magento/Quote/Test/Unit/Model/ShippingMethodManagementTest.php b/app/code/Magento/Quote/Test/Unit/Model/ShippingMethodManagementTest.php index 198f1c54a42b4..34d7707d31666 100644 --- a/app/code/Magento/Quote/Test/Unit/Model/ShippingMethodManagementTest.php +++ b/app/code/Magento/Quote/Test/Unit/Model/ShippingMethodManagementTest.php @@ -15,7 +15,9 @@ use Magento\Quote\Model\Quote\Address\Rate; use Magento\Quote\Model\Quote\TotalsCollector; use Magento\Quote\Model\QuoteRepository; +use Magento\Quote\Model\ResourceModel\Quote\Address as QuoteAddressResource; use Magento\Quote\Model\ShippingMethodManagement; +use Magento\Store\Model\Store; use PHPUnit_Framework_MockObject_MockObject as MockObject; /** @@ -83,6 +85,16 @@ class ShippingMethodManagementTest extends \PHPUnit\Framework\TestCase */ private $totalsCollector; + /** + * @var Store|MockObject + */ + private $storeMock; + + /** + * @var QuoteAddressResource|MockObject + */ + private $quoteAddressResource; + protected function setUp() { $this->objectManager = new ObjectManager($this); @@ -98,7 +110,8 @@ protected function setUp() $className = \Magento\Framework\Reflection\DataObjectProcessor::class; $this->dataProcessor = $this->createMock($className); - $this->storeMock = $this->createMock(\Magento\Store\Model\Store::class); + $this->quoteAddressResource = $this->createMock(QuoteAddressResource::class); + $this->storeMock = $this->createMock(Store::class); $this->quote = $this->getMockBuilder(Quote::class) ->disableOriginalConstructor() ->setMethods([ @@ -150,6 +163,7 @@ protected function setUp() 'converter' => $this->converter, 'totalsCollector' => $this->totalsCollector, 'addressRepository' => $this->addressRepository, + 'quoteAddressResource' => $this->quoteAddressResource, ] ); @@ -362,6 +376,7 @@ public function testSetMethodWithoutShippingAddress() $this->quote->expects($this->once()) ->method('getShippingAddress')->will($this->returnValue($this->shippingAddress)); $this->shippingAddress->expects($this->once())->method('getCountryId')->will($this->returnValue(null)); + $this->quoteAddressResource->expects($this->once())->method('delete')->with($this->shippingAddress); $this->model->set($cartId, $carrierCode, $methodCode); } @@ -421,6 +436,7 @@ public function testSetMethodWithoutAddress() ->method('getShippingAddress') ->willReturn($this->shippingAddress); $this->shippingAddress->expects($this->once())->method('getCountryId'); + $this->quoteAddressResource->expects($this->once())->method('delete')->with($this->shippingAddress); $this->model->set($cartId, $carrierCode, $methodCode); } diff --git a/app/code/Magento/Quote/etc/frontend/di.xml b/app/code/Magento/Quote/etc/frontend/di.xml new file mode 100644 index 0000000000000..25acd6763ba56 --- /dev/null +++ b/app/code/Magento/Quote/etc/frontend/di.xml @@ -0,0 +1,18 @@ +<?xml version="1.0"?> +<!-- +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> +<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:ObjectManager/etc/config.xsd"> + <type name="Magento\Quote\Plugin\UpdateQuoteStore"> + <arguments> + <argument name="quoteRepository" xsi:type="object">Magento\Quote\Model\QuoteRepository\Proxy</argument> + <argument name="checkoutSession" xsi:type="object">Magento\Checkout\Model\Session\Proxy</argument> + </arguments> + </type> + <type name="Magento\Store\Api\StoreCookieManagerInterface"> + <plugin name="update_quote_store_after_switch_store_view" type="Magento\Quote\Plugin\UpdateQuoteStore"/> + </type> +</config> diff --git a/app/code/Magento/QuoteAnalytics/Test/Mftf/composer.json b/app/code/Magento/QuoteAnalytics/Test/Mftf/composer.json deleted file mode 100644 index 4f0f8f2c07344..0000000000000 --- a/app/code/Magento/QuoteAnalytics/Test/Mftf/composer.json +++ /dev/null @@ -1,17 +0,0 @@ -{ - "name": "magento/functional-test-module-quote-analytics", - "description": "N/A", - "config": { - "sort-packages": true - }, - "require": { - "php": "~7.1.3||~7.2.0", - "magento/magento2-functional-testing-framework": "2.2.0", - "magento/functional-test-module-quote": "100.0.0-dev" - }, - "type": "magento2-test", - "license": [ - "OSL-3.0", - "AFL-3.0" - ] -} diff --git a/app/code/Magento/ReleaseNotification/Test/Mftf/composer.json b/app/code/Magento/ReleaseNotification/Test/Mftf/composer.json deleted file mode 100644 index 9499e710aaed2..0000000000000 --- a/app/code/Magento/ReleaseNotification/Test/Mftf/composer.json +++ /dev/null @@ -1,22 +0,0 @@ -{ - "name": "magento/functional-test-module-release-notification", - "description": "N/A", - "config": { - "sort-packages": true - }, - "require": { - "php": "~7.1.3||~7.2.0", - "magento/functional-test-module-user": "100.0.0-dev", - "magento/functional-test-module-backend": "100.0.0-dev", - "magento/functional-test-module-ui": "100.0.0-dev", - "magento/magento2-functional-testing-framework": "2.2.0" - }, - "suggest": { - "magento/functional-test-module-config": "100.0.0-dev" - }, - "type": "magento2-test", - "license": [ - "OSL-3.0", - "AFL-3.0" - ] -} diff --git a/app/code/Magento/Reports/Block/Adminhtml/Config/Form/Field/YtdStart.php b/app/code/Magento/Reports/Block/Adminhtml/Config/Form/Field/YtdStart.php index 5a27b4dc7666f..4ac12501aa90f 100644 --- a/app/code/Magento/Reports/Block/Adminhtml/Config/Form/Field/YtdStart.php +++ b/app/code/Magento/Reports/Block/Adminhtml/Config/Form/Field/YtdStart.php @@ -23,9 +23,8 @@ protected function _getElementHtml(AbstractElement $element) { $_months = []; for ($i = 1; $i <= 12; $i++) { - $_months[$i] = $this->_localeDate->date(mktime(null, null, null, $i))->format('m'); + $_months[$i] = $this->_localeDate->date(mktime(null, null, null, $i, 1))->format('m'); } - $_days = []; for ($i = 1; $i <= 31; $i++) { $_days[$i] = $i < 10 ? '0' . $i : $i; diff --git a/app/code/Magento/Reports/Test/Mftf/composer.json b/app/code/Magento/Reports/Test/Mftf/composer.json deleted file mode 100644 index 6801ad5adaf2e..0000000000000 --- a/app/code/Magento/Reports/Test/Mftf/composer.json +++ /dev/null @@ -1,32 +0,0 @@ -{ - "name": "magento/functional-test-module-reports", - "description": "N/A", - "config": { - "sort-packages": true - }, - "require": { - "php": "~7.1.3||~7.2.0", - "magento/magento2-functional-testing-framework": "2.2.0", - "magento/functional-test-module-backend": "100.0.0-dev", - "magento/functional-test-module-catalog": "100.0.0-dev", - "magento/functional-test-module-catalog-inventory": "100.0.0-dev", - "magento/functional-test-module-cms": "100.0.0-dev", - "magento/functional-test-module-config": "100.0.0-dev", - "magento/functional-test-module-customer": "100.0.0-dev", - "magento/functional-test-module-downloadable": "100.0.0-dev", - "magento/functional-test-module-eav": "100.0.0-dev", - "magento/functional-test-module-quote": "100.0.0-dev", - "magento/functional-test-module-review": "100.0.0-dev", - "magento/functional-test-module-sales": "100.0.0-dev", - "magento/functional-test-module-sales-rule": "100.0.0-dev", - "magento/functional-test-module-store": "100.0.0-dev", - "magento/functional-test-module-tax": "100.0.0-dev", - "magento/functional-test-module-widget": "100.0.0-dev", - "magento/functional-test-module-wishlist": "100.0.0-dev" - }, - "type": "magento2-test", - "license": [ - "OSL-3.0", - "AFL-3.0" - ] -} diff --git a/app/code/Magento/RequireJs/Test/Mftf/composer.json b/app/code/Magento/RequireJs/Test/Mftf/composer.json deleted file mode 100644 index 57bd4809b4140..0000000000000 --- a/app/code/Magento/RequireJs/Test/Mftf/composer.json +++ /dev/null @@ -1,16 +0,0 @@ -{ - "name": "magento/functional-test-module-require-js", - "description": "N/A", - "config": { - "sort-packages": true - }, - "require": { - "php": "~7.1.3||~7.2.0", - "magento/magento2-functional-testing-framework": "2.2.0" - }, - "type": "magento2-test", - "license": [ - "OSL-3.0", - "AFL-3.0" - ] -} diff --git a/app/code/Magento/Review/Block/Adminhtml/Add/Form.php b/app/code/Magento/Review/Block/Adminhtml/Add/Form.php index 2d619725ae201..04e6343eb43ca 100644 --- a/app/code/Magento/Review/Block/Adminhtml/Add/Form.php +++ b/app/code/Magento/Review/Block/Adminhtml/Add/Form.php @@ -142,11 +142,6 @@ protected function _prepareForm() $fieldset->addField('product_id', 'hidden', ['name' => 'product_id']); - /*$gridFieldset = $form->addFieldset('add_review_grid', array('legend' => __('Please select a product'))); - $gridFieldset->addField('products_grid', 'note', array( - 'text' => $this->getLayout()->createBlock(\Magento\Review\Block\Adminhtml\Product\Grid::class)->toHtml(), - ));*/ - $form->setMethod('post'); $form->setUseContainer(true); $form->setId('edit_form'); diff --git a/app/code/Magento/Review/Block/Customer/ListCustomer.php b/app/code/Magento/Review/Block/Customer/ListCustomer.php index 8377cc73646b9..eb67af5780ddb 100644 --- a/app/code/Magento/Review/Block/Customer/ListCustomer.php +++ b/app/code/Magento/Review/Block/Customer/ListCustomer.php @@ -154,13 +154,13 @@ public function getProductLink() /** * Get product URL * - * @param \Magento\Review\Model\Review $review + * @param \Magento\Catalog\Model\Product $product * @return string * @since 100.2.0 */ - public function getProductUrl($review) + public function getProductUrl($product) { - return $this->getUrl('catalog/product/view', ['id' => $review->getEntityPkValue()]); + return $product->getProductUrl(); } /** diff --git a/app/code/Magento/Review/Block/Form.php b/app/code/Magento/Review/Block/Form.php index 440e13deb5839..c6dfad8265ac7 100644 --- a/app/code/Magento/Review/Block/Form.php +++ b/app/code/Magento/Review/Block/Form.php @@ -139,7 +139,7 @@ protected function _construct() ); } - $this->setTemplate('form.phtml'); + $this->setTemplate('Magento_Review::form.phtml'); } /** diff --git a/app/code/Magento/Review/Block/Rating/Entity/Detailed.php b/app/code/Magento/Review/Block/Rating/Entity/Detailed.php index 0ce4f436ae704..eee00483ace66 100644 --- a/app/code/Magento/Review/Block/Rating/Entity/Detailed.php +++ b/app/code/Magento/Review/Block/Rating/Entity/Detailed.php @@ -49,7 +49,7 @@ protected function _toHtml() $reviewsCount = $this->_ratingFactory->create()->getTotalReviews($entityId, true); if ($reviewsCount == 0) { #return __('Be the first to review this product'); - $this->setTemplate('empty.phtml'); + $this->setTemplate('Magento_Review::empty.phtml'); return parent::_toHtml(); } diff --git a/app/code/Magento/Review/Model/ResourceModel/Rating/Collection.php b/app/code/Magento/Review/Model/ResourceModel/Rating/Collection.php index cbbe17a47c0ad..0dcb9da6a8c75 100644 --- a/app/code/Magento/Review/Model/ResourceModel/Rating/Collection.php +++ b/app/code/Magento/Review/Model/ResourceModel/Rating/Collection.php @@ -141,7 +141,6 @@ public function setStoreFilter($storeId) 'main_table.rating_id = store.rating_id', [] ); - // ->group('main_table.rating_id') $this->_isStoreJoined = true; } $inCondition = $connection->prepareSqlCondition('store.store_id', ['in' => $storeId]); diff --git a/app/code/Magento/Review/Test/Mftf/composer.json b/app/code/Magento/Review/Test/Mftf/composer.json deleted file mode 100644 index ae12d545ec244..0000000000000 --- a/app/code/Magento/Review/Test/Mftf/composer.json +++ /dev/null @@ -1,28 +0,0 @@ -{ - "name": "magento/functional-test-module-review", - "description": "N/A", - "config": { - "sort-packages": true - }, - "require": { - "php": "~7.1.3||~7.2.0", - "magento/magento2-functional-testing-framework": "2.2.0", - "magento/functional-test-module-backend": "100.0.0-dev", - "magento/functional-test-module-catalog": "100.0.0-dev", - "magento/functional-test-module-customer": "100.0.0-dev", - "magento/functional-test-module-eav": "100.0.0-dev", - "magento/functional-test-module-newsletter": "100.0.0-dev", - "magento/functional-test-module-store": "100.0.0-dev", - "magento/functional-test-module-theme": "100.0.0-dev", - "magento/functional-test-module-ui": "100.0.0-dev" - }, - "suggest": { - "magento/functional-test-module-cookie": "100.0.0-dev", - "magento/functional-test-module-review-sample-data": "100.0.0-dev" - }, - "type": "magento2-test", - "license": [ - "OSL-3.0", - "AFL-3.0" - ] -} diff --git a/app/code/Magento/Review/view/frontend/templates/customer/list.phtml b/app/code/Magento/Review/view/frontend/templates/customer/list.phtml index 725df702bb465..a65ec01d626eb 100644 --- a/app/code/Magento/Review/view/frontend/templates/customer/list.phtml +++ b/app/code/Magento/Review/view/frontend/templates/customer/list.phtml @@ -22,29 +22,29 @@ </tr> </thead> <tbody> - <?php foreach ($block->getReviews() as $_review): ?> + <?php foreach ($block->getReviews() as $review): ?> <tr> - <td data-th="<?= $block->escapeHtml(__('Created')) ?>" class="col date"><?= $block->escapeHtml($block->dateFormat($_review->getReviewCreatedAt())) ?></td> + <td data-th="<?= $block->escapeHtml(__('Created')) ?>" class="col date"><?= $block->escapeHtml($block->dateFormat($review->getReviewCreatedAt())) ?></td> <td data-th="<?= $block->escapeHtml(__('Product Name')) ?>" class="col item"> <strong class="product-name"> - <a href="<?= $block->escapeUrl($block->getProductUrl($_review)) ?>"><?= $block->escapeHtml($_review->getName()) ?></a> + <a href="<?= $block->escapeUrl($block->getProductUrl($review)) ?>"><?= $block->escapeHtml($review->getName()) ?></a> </strong> </td> <td data-th="<?= $block->escapeHtml(__('Rating')) ?>" class="col summary"> - <?php if ($_review->getSum()): ?> + <?php if ($review->getSum()): ?> <div class="rating-summary"> <span class="label"><span><?= $block->escapeHtml(__('Rating')) ?>:</span></span> - <div class="rating-result" title="<?= /* @noEscape */ ((int)$_review->getSum() / (int)$_review->getCount()) ?>%"> - <span style="width:<?= /* @noEscape */ ((int)$_review->getSum() / (int)$_review->getCount()) ?>%;"><span><?= /* @noEscape */ ((int)$_review->getSum() / (int)$_review->getCount()) ?>%</span></span> + <div class="rating-result" title="<?= /* @noEscape */ ((int)$review->getSum() / (int)$review->getCount()) ?>%"> + <span style="width:<?= /* @noEscape */ ((int)$review->getSum() / (int)$review->getCount()) ?>%;"><span><?= /* @noEscape */ ((int)$review->getSum() / (int)$review->getCount()) ?>%</span></span> </div> </div> <?php endif; ?> </td> <td data-th="<?= $block->escapeHtmlAttr(__('Review')) ?>" class="col description"> - <?= $this->helper('Magento\Review\Helper\Data')->getDetailHtml($_review->getDetail()) ?> + <?= $this->helper('Magento\Review\Helper\Data')->getDetailHtml($review->getDetail()) ?> </td> <td data-th="<?= $block->escapeHtmlAttr(__('Actions')) ?>" class="col actions"> - <a href="<?= $block->escapeUrl($block->getReviewUrl($_review)) ?>" class="action more"> + <a href="<?= $block->escapeUrl($block->getReviewUrl($review)) ?>" class="action more"> <span><?= $block->escapeHtml(__('See Details')) ?></span> </a> </td> diff --git a/app/code/Magento/ReviewAnalytics/Test/Mftf/composer.json b/app/code/Magento/ReviewAnalytics/Test/Mftf/composer.json deleted file mode 100644 index 0164913753cb4..0000000000000 --- a/app/code/Magento/ReviewAnalytics/Test/Mftf/composer.json +++ /dev/null @@ -1,17 +0,0 @@ -{ - "name": "magento/functional-test-module-review-analytics", - "description": "N/A", - "config": { - "sort-packages": true - }, - "require": { - "php": "~7.1.3||~7.2.0", - "magento/magento2-functional-testing-framework": "2.2.0", - "magento/functional-test-module-review": "100.0.0-dev" - }, - "type": "magento2-test", - "license": [ - "OSL-3.0", - "AFL-3.0" - ] -} diff --git a/app/code/Magento/Robots/Test/Mftf/composer.json b/app/code/Magento/Robots/Test/Mftf/composer.json deleted file mode 100644 index d3f2447e7970a..0000000000000 --- a/app/code/Magento/Robots/Test/Mftf/composer.json +++ /dev/null @@ -1,20 +0,0 @@ -{ - "name": "magento/functional-test-module-robots", - "description": "N/A", - "config": { - "sort-packages": true - }, - "require": { - "php": "~7.1.3||~7.2.0", - "magento/magento2-functional-testing-framework": "2.2.0", - "magento/functional-test-module-store": "100.0.0-dev" - }, - "suggest": { - "magento/functional-test-module-theme": "100.0.0-dev" - }, - "type": "magento2-test", - "license": [ - "OSL-3.0", - "AFL-3.0" - ] -} diff --git a/app/code/Magento/Rss/Test/Mftf/composer.json b/app/code/Magento/Rss/Test/Mftf/composer.json deleted file mode 100644 index cf3a9dae8a054..0000000000000 --- a/app/code/Magento/Rss/Test/Mftf/composer.json +++ /dev/null @@ -1,19 +0,0 @@ -{ - "name": "magento/functional-test-module-rss", - "description": "N/A", - "config": { - "sort-packages": true - }, - "require": { - "php": "~7.1.3||~7.2.0", - "magento/magento2-functional-testing-framework": "2.2.0", - "magento/functional-test-module-backend": "100.0.0-dev", - "magento/functional-test-module-customer": "100.0.0-dev", - "magento/functional-test-module-store": "100.0.0-dev" - }, - "type": "magento2-test", - "license": [ - "OSL-3.0", - "AFL-3.0" - ] -} diff --git a/app/code/Magento/Rule/Model/Condition/AbstractCondition.php b/app/code/Magento/Rule/Model/Condition/AbstractCondition.php index e3bec2d9959b1..a1987f67e47f2 100644 --- a/app/code/Magento/Rule/Model/Condition/AbstractCondition.php +++ b/app/code/Magento/Rule/Model/Condition/AbstractCondition.php @@ -355,10 +355,10 @@ public function getValueParsed() { if (!$this->hasValueParsed()) { $value = $this->getData('value'); - if (is_array($value) && isset($value[0]) && is_string($value[0])) { - $value = $value[0]; + if (is_array($value) && count($value) === 1) { + $value = reset($value); } - if ($this->isArrayOperatorType() && $value) { + if (!is_array($value) && $this->isArrayOperatorType() && $value) { $value = preg_split('#\s*[,;]\s*#', $value, null, PREG_SPLIT_NO_EMPTY); } $this->setValueParsed($value); @@ -380,7 +380,7 @@ public function isArrayOperatorType() } /** - * @return array + * @return mixed */ public function getValue() { diff --git a/app/code/Magento/Rule/Model/Condition/Sql/Builder.php b/app/code/Magento/Rule/Model/Condition/Sql/Builder.php index e1c9bf99f2675..2894de0f19b87 100644 --- a/app/code/Magento/Rule/Model/Condition/Sql/Builder.php +++ b/app/code/Magento/Rule/Model/Condition/Sql/Builder.php @@ -163,8 +163,22 @@ protected function _getMappedSqlCondition( $this->_conditionOperatorMap[$conditionOperator] ); + $bindValue = $condition->getBindArgumentValue(); + $expression = $value . $this->_connection->quoteInto($sql, $bindValue); + + // values for multiselect attributes can be saved in comma-separated format + // below is a solution for matching such conditions with selected values + if (is_array($bindValue) && \in_array($conditionOperator, ['()', '{}'], true)) { + foreach ($bindValue as $item) { + $expression .= $this->_connection->quoteInto( + " OR (FIND_IN_SET (?, {$this->_connection->quoteIdentifier($argument)}) > 0)", + $item + ); + } + } + return $this->_expressionFactory->create( - ['expression' => $value . $this->_connection->quoteInto($sql, $condition->getBindArgumentValue())] + ['expression' => $expression] ); } @@ -174,6 +188,7 @@ protected function _getMappedSqlCondition( * @param bool $isDefaultStoreUsed * @return string * @SuppressWarnings(PHPMD.NPathComplexity) + * @throws \Magento\Framework\Exception\LocalizedException */ protected function _getMappedSqlCombination( Combine $combine, diff --git a/app/code/Magento/Rule/Test/Mftf/composer.json b/app/code/Magento/Rule/Test/Mftf/composer.json deleted file mode 100644 index 827d8603fdb99..0000000000000 --- a/app/code/Magento/Rule/Test/Mftf/composer.json +++ /dev/null @@ -1,20 +0,0 @@ -{ - "name": "magento/functional-test-module-rule", - "description": "N/A", - "config": { - "sort-packages": true - }, - "require": { - "php": "~7.1.3||~7.2.0", - "magento/magento2-functional-testing-framework": "2.2.0", - "magento/functional-test-module-backend": "100.0.0-dev", - "magento/functional-test-module-catalog": "100.0.0-dev", - "magento/functional-test-module-eav": "100.0.0-dev", - "magento/functional-test-module-store": "100.0.0-dev" - }, - "type": "magento2-test", - "license": [ - "OSL-3.0", - "AFL-3.0" - ] -} diff --git a/app/code/Magento/Sales/Block/Adminhtml/Order/Create/Form.php b/app/code/Magento/Sales/Block/Adminhtml/Order/Create/Form.php index 37e8d8e784744..12a8270acfff0 100644 --- a/app/code/Magento/Sales/Block/Adminhtml/Order/Create/Form.php +++ b/app/code/Magento/Sales/Block/Adminhtml/Order/Create/Form.php @@ -189,6 +189,7 @@ public function getOrderDataJson() $data['shipping_method_reseted'] = !(bool)$this->getQuote()->getShippingAddress()->getShippingMethod(); $data['payment_method'] = $this->getQuote()->getPayment()->getMethod(); } + $data['quote_id'] = $this->_sessionQuote->getQuoteId(); return $this->_jsonEncoder->encode($data); } diff --git a/app/code/Magento/Sales/Block/Adminhtml/Order/Create/Form/Account.php b/app/code/Magento/Sales/Block/Adminhtml/Order/Create/Form/Account.php index 3623e72341a22..26379a05fe694 100644 --- a/app/code/Magento/Sales/Block/Adminhtml/Order/Create/Form/Account.php +++ b/app/code/Magento/Sales/Block/Adminhtml/Order/Create/Form/Account.php @@ -132,7 +132,15 @@ protected function _prepareForm() $this->_addAttributesToForm($attributes, $fieldset); $this->_form->addFieldNameSuffix('order[account]'); - $this->_form->setValues($this->getFormValues()); + + $formValues = $this->getFormValues(); + foreach ($attributes as $code => $attribute) { + $defaultValue = $attribute->getDefaultValue(); + if (isset($defaultValue) && !isset($formValues[$code])) { + $formValues[$code] = $defaultValue; + } + } + $this->_form->setValues($formValues); return $this; } diff --git a/app/code/Magento/Sales/Block/Adminhtml/Order/Totalbar.php b/app/code/Magento/Sales/Block/Adminhtml/Order/Totalbar.php index 648a281228908..c4ce48d162c2c 100644 --- a/app/code/Magento/Sales/Block/Adminhtml/Order/Totalbar.php +++ b/app/code/Magento/Sales/Block/Adminhtml/Order/Totalbar.php @@ -8,6 +8,7 @@ /** * Adminhtml creditmemo bar * + * @deprecated * @api * @author Magento Core Team <core@magentocommerce.com> * @since 100.0.2 diff --git a/app/code/Magento/Sales/Controller/AbstractController/Reorder.php b/app/code/Magento/Sales/Controller/AbstractController/Reorder.php index d7ab99377e1b5..dd4d73930cc8f 100644 --- a/app/code/Magento/Sales/Controller/AbstractController/Reorder.php +++ b/app/code/Magento/Sales/Controller/AbstractController/Reorder.php @@ -59,13 +59,16 @@ public function execute() $cart->addOrderItem($item); } catch (\Magento\Framework\Exception\LocalizedException $e) { if ($this->_objectManager->get(\Magento\Checkout\Model\Session::class)->getUseNotice(true)) { - $this->messageManager->addNotice($e->getMessage()); + $this->messageManager->addNoticeMessage($e->getMessage()); } else { - $this->messageManager->addError($e->getMessage()); + $this->messageManager->addErrorMessage($e->getMessage()); } return $resultRedirect->setPath('*/*/history'); } catch (\Exception $e) { - $this->messageManager->addException($e, __('We can\'t add this item to your shopping cart right now.')); + $this->messageManager->addExceptionMessage( + $e, + __('We can\'t add this item to your shopping cart right now.') + ); return $resultRedirect->setPath('checkout/cart'); } } diff --git a/app/code/Magento/Sales/Controller/Adminhtml/Creditmemo/AbstractCreditmemo/Email.php b/app/code/Magento/Sales/Controller/Adminhtml/Creditmemo/AbstractCreditmemo/Email.php index ac34af6f4ce6e..e3571f3cc02bc 100644 --- a/app/code/Magento/Sales/Controller/Adminhtml/Creditmemo/AbstractCreditmemo/Email.php +++ b/app/code/Magento/Sales/Controller/Adminhtml/Creditmemo/AbstractCreditmemo/Email.php @@ -33,7 +33,7 @@ public function execute() $this->_objectManager->create(\Magento\Sales\Api\CreditmemoManagementInterface::class) ->notify($creditmemoId); - $this->messageManager->addSuccess(__('You sent the message.')); + $this->messageManager->addSuccessMessage(__('You sent the message.')); $resultRedirect = $this->resultRedirectFactory->create(); $resultRedirect->setPath('sales/order_creditmemo/view', ['creditmemo_id' => $creditmemoId]); return $resultRedirect; diff --git a/app/code/Magento/Sales/Controller/Adminhtml/Creditmemo/AbstractCreditmemo/Pdfcreditmemos.php b/app/code/Magento/Sales/Controller/Adminhtml/Creditmemo/AbstractCreditmemo/Pdfcreditmemos.php index 83486704984f7..94ca6a0375e7c 100644 --- a/app/code/Magento/Sales/Controller/Adminhtml/Creditmemo/AbstractCreditmemo/Pdfcreditmemos.php +++ b/app/code/Magento/Sales/Controller/Adminhtml/Creditmemo/AbstractCreditmemo/Pdfcreditmemos.php @@ -74,9 +74,12 @@ public function __construct( */ public function massAction(AbstractCollection $collection) { + $pdf = $this->pdfCreditmemo->getPdf($collection); + $fileContent = ['type' => 'string', 'value' => $pdf->render(), 'rm' => true]; + return $this->fileFactory->create( sprintf('creditmemo%s.pdf', $this->dateTime->date('Y-m-d_H-i-s')), - $this->pdfCreditmemo->getPdf($collection)->render(), + $fileContent, DirectoryList::VAR_DIR, 'application/pdf' ); diff --git a/app/code/Magento/Sales/Controller/Adminhtml/Creditmemo/AbstractCreditmemo/PrintAction.php b/app/code/Magento/Sales/Controller/Adminhtml/Creditmemo/AbstractCreditmemo/PrintAction.php index d6c94feb57606..c5902aac33355 100644 --- a/app/code/Magento/Sales/Controller/Adminhtml/Creditmemo/AbstractCreditmemo/PrintAction.php +++ b/app/code/Magento/Sales/Controller/Adminhtml/Creditmemo/AbstractCreditmemo/PrintAction.php @@ -53,6 +53,7 @@ public function __construct( /** * @return ResponseInterface|\Magento\Backend\Model\View\Result\Forward + * @throws \Exception */ public function execute() { @@ -69,9 +70,11 @@ public function execute() $date = $this->_objectManager->get( \Magento\Framework\Stdlib\DateTime\DateTime::class )->date('Y-m-d_H-i-s'); + $fileContent = ['type' => 'string', 'value' => $pdf->render(), 'rm' => true]; + return $this->_fileFactory->create( \creditmemo::class . $date . '.pdf', - $pdf->render(), + $fileContent, DirectoryList::VAR_DIR, 'application/pdf' ); diff --git a/app/code/Magento/Sales/Controller/Adminhtml/Invoice/AbstractInvoice/Email.php b/app/code/Magento/Sales/Controller/Adminhtml/Invoice/AbstractInvoice/Email.php index e491dd78db617..c645df152ba8f 100644 --- a/app/code/Magento/Sales/Controller/Adminhtml/Invoice/AbstractInvoice/Email.php +++ b/app/code/Magento/Sales/Controller/Adminhtml/Invoice/AbstractInvoice/Email.php @@ -57,7 +57,7 @@ public function execute() \Magento\Sales\Api\InvoiceManagementInterface::class )->notify($invoice->getEntityId()); - $this->messageManager->addSuccess(__('You sent the message.')); + $this->messageManager->addSuccessMessage(__('You sent the message.')); return $this->resultRedirectFactory->create()->setPath( 'sales/invoice/view', ['order_id' => $invoice->getOrder()->getId(), 'invoice_id' => $invoiceId] diff --git a/app/code/Magento/Sales/Controller/Adminhtml/Invoice/AbstractInvoice/Pdfinvoices.php b/app/code/Magento/Sales/Controller/Adminhtml/Invoice/AbstractInvoice/Pdfinvoices.php index a949ceca53961..18cf397c0e3b9 100644 --- a/app/code/Magento/Sales/Controller/Adminhtml/Invoice/AbstractInvoice/Pdfinvoices.php +++ b/app/code/Magento/Sales/Controller/Adminhtml/Invoice/AbstractInvoice/Pdfinvoices.php @@ -75,9 +75,12 @@ public function __construct( */ public function massAction(AbstractCollection $collection) { + $pdf = $this->pdfInvoice->getPdf($collection); + $fileContent = ['type' => 'string', 'value' => $pdf->render(), 'rm' => true]; + return $this->fileFactory->create( sprintf('invoice%s.pdf', $this->dateTime->date('Y-m-d_H-i-s')), - $this->pdfInvoice->getPdf($collection)->render(), + $fileContent, DirectoryList::VAR_DIR, 'application/pdf' ); diff --git a/app/code/Magento/Sales/Controller/Adminhtml/Invoice/AbstractInvoice/PrintAction.php b/app/code/Magento/Sales/Controller/Adminhtml/Invoice/AbstractInvoice/PrintAction.php index 2421267aa753d..2caa8ec2dcb83 100644 --- a/app/code/Magento/Sales/Controller/Adminhtml/Invoice/AbstractInvoice/PrintAction.php +++ b/app/code/Magento/Sales/Controller/Adminhtml/Invoice/AbstractInvoice/PrintAction.php @@ -45,6 +45,7 @@ public function __construct( /** * @return ResponseInterface|void + * @throws \Exception */ public function execute() { @@ -58,9 +59,11 @@ public function execute() $date = $this->_objectManager->get( \Magento\Framework\Stdlib\DateTime\DateTime::class )->date('Y-m-d_H-i-s'); + $fileContent = ['type' => 'string', 'value' => $pdf->render(), 'rm' => true]; + return $this->_fileFactory->create( 'invoice' . $date . '.pdf', - $pdf->render(), + $fileContent, DirectoryList::VAR_DIR, 'application/pdf' ); diff --git a/app/code/Magento/Sales/Controller/Adminhtml/Invoice/AbstractInvoice/View.php b/app/code/Magento/Sales/Controller/Adminhtml/Invoice/AbstractInvoice/View.php index 3615f3033ca81..300b7ee37f2ef 100644 --- a/app/code/Magento/Sales/Controller/Adminhtml/Invoice/AbstractInvoice/View.php +++ b/app/code/Magento/Sales/Controller/Adminhtml/Invoice/AbstractInvoice/View.php @@ -79,7 +79,7 @@ protected function getInvoice() ->get($this->getRequest()->getParam('invoice_id')); $this->registry->register('current_invoice', $invoice); } catch (\Exception $e) { - $this->messageManager->addError(__('Invoice capturing error')); + $this->messageManager->addErrorMessage(__('Invoice capturing error')); return false; } diff --git a/app/code/Magento/Sales/Controller/Adminhtml/Order.php b/app/code/Magento/Sales/Controller/Adminhtml/Order.php index c2299374c798c..0066c5f4c828a 100644 --- a/app/code/Magento/Sales/Controller/Adminhtml/Order.php +++ b/app/code/Magento/Sales/Controller/Adminhtml/Order.php @@ -154,11 +154,11 @@ protected function _initOrder() try { $order = $this->orderRepository->get($id); } catch (NoSuchEntityException $e) { - $this->messageManager->addError(__('This order no longer exists.')); + $this->messageManager->addErrorMessage(__('This order no longer exists.')); $this->_actionFlag->set('', self::FLAG_NO_DISPATCH, true); return false; } catch (InputException $e) { - $this->messageManager->addError(__('This order no longer exists.')); + $this->messageManager->addErrorMessage(__('This order no longer exists.')); $this->_actionFlag->set('', self::FLAG_NO_DISPATCH, true); return false; } diff --git a/app/code/Magento/Sales/Controller/Adminhtml/Order/AbstractMassAction.php b/app/code/Magento/Sales/Controller/Adminhtml/Order/AbstractMassAction.php index 05066fe5b125e..c6b45f282debc 100644 --- a/app/code/Magento/Sales/Controller/Adminhtml/Order/AbstractMassAction.php +++ b/app/code/Magento/Sales/Controller/Adminhtml/Order/AbstractMassAction.php @@ -61,7 +61,7 @@ public function execute() $collection = $this->filter->getCollection($this->collectionFactory->create()); return $this->massAction($collection); } catch (\Exception $e) { - $this->messageManager->addError($e->getMessage()); + $this->messageManager->addErrorMessage($e->getMessage()); /** @var \Magento\Backend\Model\View\Result\Redirect $resultRedirect */ $resultRedirect = $this->resultFactory->create(ResultFactory::TYPE_REDIRECT); return $resultRedirect->setPath($this->redirectUrl); diff --git a/app/code/Magento/Sales/Controller/Adminhtml/Order/AddressSave.php b/app/code/Magento/Sales/Controller/Adminhtml/Order/AddressSave.php index dde2192c3b82c..c71de8cb0252d 100644 --- a/app/code/Magento/Sales/Controller/Adminhtml/Order/AddressSave.php +++ b/app/code/Magento/Sales/Controller/Adminhtml/Order/AddressSave.php @@ -114,12 +114,12 @@ public function execute() 'order_id' => $address->getParentId() ] ); - $this->messageManager->addSuccess(__('You updated the order address.')); + $this->messageManager->addSuccessMessage(__('You updated the order address.')); return $resultRedirect->setPath('sales/*/view', ['order_id' => $address->getParentId()]); } catch (LocalizedException $e) { - $this->messageManager->addError($e->getMessage()); + $this->messageManager->addErrorMessage($e->getMessage()); } catch (\Exception $e) { - $this->messageManager->addException($e, __('We can\'t update the order address right now.')); + $this->messageManager->addExceptionMessage($e, __('We can\'t update the order address right now.')); } return $resultRedirect->setPath('sales/*/address', ['address_id' => $address->getId()]); } else { diff --git a/app/code/Magento/Sales/Controller/Adminhtml/Order/Cancel.php b/app/code/Magento/Sales/Controller/Adminhtml/Order/Cancel.php index de41c3c737968..7e41c7417b38d 100644 --- a/app/code/Magento/Sales/Controller/Adminhtml/Order/Cancel.php +++ b/app/code/Magento/Sales/Controller/Adminhtml/Order/Cancel.php @@ -24,18 +24,18 @@ public function execute() { $resultRedirect = $this->resultRedirectFactory->create(); if (!$this->isValidPostRequest()) { - $this->messageManager->addError(__('You have not canceled the item.')); + $this->messageManager->addErrorMessage(__('You have not canceled the item.')); return $resultRedirect->setPath('sales/*/'); } $order = $this->_initOrder(); if ($order) { try { $this->orderManagement->cancel($order->getEntityId()); - $this->messageManager->addSuccess(__('You canceled the order.')); + $this->messageManager->addSuccessMessage(__('You canceled the order.')); } catch (\Magento\Framework\Exception\LocalizedException $e) { - $this->messageManager->addError($e->getMessage()); + $this->messageManager->addErrorMessage($e->getMessage()); } catch (\Exception $e) { - $this->messageManager->addError(__('You have not canceled the item.')); + $this->messageManager->addErrorMessage(__('You have not canceled the item.')); $this->_objectManager->get(\Psr\Log\LoggerInterface::class)->critical($e); } return $resultRedirect->setPath('sales/order/view', ['order_id' => $order->getId()]); diff --git a/app/code/Magento/Sales/Controller/Adminhtml/Order/Create.php b/app/code/Magento/Sales/Controller/Adminhtml/Order/Create.php index a7b41d0a780f3..dcf5e617d055c 100644 --- a/app/code/Magento/Sales/Controller/Adminhtml/Order/Create.php +++ b/app/code/Magento/Sales/Controller/Adminhtml/Order/Create.php @@ -317,7 +317,7 @@ protected function _processActionData($action = null) } } if (!$isApplyDiscount) { - $this->messageManager->addError( + $this->messageManager->addErrorMessage( __( '"%1" coupon code was not applied. Do not apply discount is selected for item(s)', $this->escaper->escapeHtml($couponCode) @@ -325,14 +325,14 @@ protected function _processActionData($action = null) ); } else { if ($this->_getQuote()->getCouponCode() !== $couponCode) { - $this->messageManager->addError( + $this->messageManager->addErrorMessage( __( 'The "%1" coupon code isn\'t valid. Verify the code and try again.', $this->escaper->escapeHtml($couponCode) ) ); } else { - $this->messageManager->addSuccess(__('The coupon code has been accepted.')); + $this->messageManager->addSuccessMessage(__('The coupon code has been accepted.')); } } } diff --git a/app/code/Magento/Sales/Controller/Adminhtml/Order/Create/LoadBlock.php b/app/code/Magento/Sales/Controller/Adminhtml/Order/Create/LoadBlock.php index 6a9d0a5dcb8ed..bc4eb3cfba423 100644 --- a/app/code/Magento/Sales/Controller/Adminhtml/Order/Create/LoadBlock.php +++ b/app/code/Magento/Sales/Controller/Adminhtml/Order/Create/LoadBlock.php @@ -55,10 +55,10 @@ public function execute() $this->_initSession()->_processData(); } catch (\Magento\Framework\Exception\LocalizedException $e) { $this->_reloadQuote(); - $this->messageManager->addError($e->getMessage()); + $this->messageManager->addErrorMessage($e->getMessage()); } catch (\Exception $e) { $this->_reloadQuote(); - $this->messageManager->addException($e, $e->getMessage()); + $this->messageManager->addExceptionMessage($e, $e->getMessage()); } $asJson = $request->getParam('json'); diff --git a/app/code/Magento/Sales/Controller/Adminhtml/Order/Create/Save.php b/app/code/Magento/Sales/Controller/Adminhtml/Order/Create/Save.php index 621705c7937cb..929e23075e070 100644 --- a/app/code/Magento/Sales/Controller/Adminhtml/Order/Create/Save.php +++ b/app/code/Magento/Sales/Controller/Adminhtml/Order/Create/Save.php @@ -3,6 +3,7 @@ * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ + namespace Magento\Sales\Controller\Adminhtml\Order\Create; use Magento\Framework\Exception\PaymentException; @@ -12,14 +13,15 @@ class Save extends \Magento\Sales\Controller\Adminhtml\Order\Create /** * Saving quote and create order * - * @return \Magento\Backend\Model\View\Result\Forward|\Magento\Backend\Model\View\Result\Redirect + * @return \Magento\Framework\Controller\ResultInterface * * @SuppressWarnings(PHPMD.CyclomaticComplexity) */ public function execute() { - /** @var \Magento\Backend\Model\View\Result\Redirect $resultRedirect */ - $resultRedirect = $this->resultRedirectFactory->create(); + $path = 'sales/*/'; + $pathParams = []; + try { // check if the creation of a new customer is allowed if (!$this->_authorization->isAllowed('Magento_Customer::manage') @@ -49,31 +51,30 @@ public function execute() ->createOrder(); $this->_getSession()->clearStorage(); - $this->messageManager->addSuccess(__('You created the order.')); + $this->messageManager->addSuccessMessage(__('You created the order.')); if ($this->_authorization->isAllowed('Magento_Sales::actions_view')) { - $resultRedirect->setPath('sales/order/view', ['order_id' => $order->getId()]); + $pathParams = ['order_id' => $order->getId()]; + $path = 'sales/order/view'; } else { - $resultRedirect->setPath('sales/order/index'); + $path = 'sales/order/index'; } } catch (PaymentException $e) { $this->_getOrderCreateModel()->saveQuote(); $message = $e->getMessage(); if (!empty($message)) { - $this->messageManager->addError($message); + $this->messageManager->addErrorMessage($message); } - $resultRedirect->setPath('sales/*/'); } catch (\Magento\Framework\Exception\LocalizedException $e) { // customer can be created before place order flow is completed and should be stored in current session - $this->_getSession()->setCustomerId($this->_getSession()->getQuote()->getCustomerId()); + $this->_getSession()->setCustomerId((int)$this->_getSession()->getQuote()->getCustomerId()); $message = $e->getMessage(); if (!empty($message)) { - $this->messageManager->addError($message); + $this->messageManager->addErrorMessage($message); } - $resultRedirect->setPath('sales/*/'); } catch (\Exception $e) { - $this->messageManager->addException($e, __('Order saving error: %1', $e->getMessage())); - $resultRedirect->setPath('sales/*/'); + $this->messageManager->addExceptionMessage($e, __('Order saving error: %1', $e->getMessage())); } - return $resultRedirect; + + return $this->resultRedirectFactory->create()->setPath($path, $pathParams); } } diff --git a/app/code/Magento/Sales/Controller/Adminhtml/Order/Creditmemo/Cancel.php b/app/code/Magento/Sales/Controller/Adminhtml/Order/Creditmemo/Cancel.php index eedf49a6cae9a..1ca0b53ee8784 100644 --- a/app/code/Magento/Sales/Controller/Adminhtml/Order/Creditmemo/Cancel.php +++ b/app/code/Magento/Sales/Controller/Adminhtml/Order/Creditmemo/Cancel.php @@ -47,11 +47,11 @@ public function execute() \Magento\Sales\Api\CreditmemoManagementInterface::class ); $creditmemoManagement->cancel($creditmemoId); - $this->messageManager->addSuccess(__('The credit memo has been canceled.')); + $this->messageManager->addSuccessMessage(__('The credit memo has been canceled.')); } catch (\Magento\Framework\Exception\LocalizedException $e) { - $this->messageManager->addError($e->getMessage()); + $this->messageManager->addErrorMessage($e->getMessage()); } catch (\Exception $e) { - $this->messageManager->addError(__('Credit memo has not been canceled.')); + $this->messageManager->addErrorMessage(__('Credit memo has not been canceled.')); } $resultRedirect = $this->resultRedirectFactory->create(); $resultRedirect->setPath('sales/*/view', ['creditmemo_id' => $creditmemoId]); diff --git a/app/code/Magento/Sales/Controller/Adminhtml/Order/Creditmemo/Save.php b/app/code/Magento/Sales/Controller/Adminhtml/Order/Creditmemo/Save.php index 826a2a2a8b6c1..2a2445d2b2ae0 100644 --- a/app/code/Magento/Sales/Controller/Adminhtml/Order/Creditmemo/Save.php +++ b/app/code/Magento/Sales/Controller/Adminhtml/Order/Creditmemo/Save.php @@ -109,7 +109,7 @@ public function execute() $this->creditmemoSender->send($creditmemo); } - $this->messageManager->addSuccess(__('You created the credit memo.')); + $this->messageManager->addSuccessMessage(__('You created the credit memo.')); $this->_getSession()->getCommentText(true); $resultRedirect->setPath('sales/order/view', ['order_id' => $creditmemo->getOrderId()]); return $resultRedirect; @@ -119,11 +119,11 @@ public function execute() return $resultForward; } } catch (\Magento\Framework\Exception\LocalizedException $e) { - $this->messageManager->addError($e->getMessage()); + $this->messageManager->addErrorMessage($e->getMessage()); $this->_getSession()->setFormData($data); } catch (\Exception $e) { $this->_objectManager->get(\Psr\Log\LoggerInterface::class)->critical($e); - $this->messageManager->addError(__('We can\'t save the credit memo right now.')); + $this->messageManager->addErrorMessage(__('We can\'t save the credit memo right now.')); } $resultRedirect->setPath('sales/*/new', ['_current' => true]); return $resultRedirect; diff --git a/app/code/Magento/Sales/Controller/Adminhtml/Order/Creditmemo/VoidAction.php b/app/code/Magento/Sales/Controller/Adminhtml/Order/Creditmemo/VoidAction.php index e7bd891fbfbff..146514265517a 100644 --- a/app/code/Magento/Sales/Controller/Adminhtml/Order/Creditmemo/VoidAction.php +++ b/app/code/Magento/Sales/Controller/Adminhtml/Order/Creditmemo/VoidAction.php @@ -64,11 +64,11 @@ public function execute() $transactionSave->addObject($creditmemo->getInvoice()); } $transactionSave->save(); - $this->messageManager->addSuccess(__('You voided the credit memo.')); + $this->messageManager->addSuccessMessage(__('You voided the credit memo.')); } catch (\Magento\Framework\Exception\LocalizedException $e) { - $this->messageManager->addError($e->getMessage()); + $this->messageManager->addErrorMessage($e->getMessage()); } catch (\Exception $e) { - $this->messageManager->addError(__('We can\'t void the credit memo.')); + $this->messageManager->addErrorMessage(__('We can\'t void the credit memo.')); } $resultRedirect = $this->resultRedirectFactory->create(); $resultRedirect->setPath('sales/*/view', ['creditmemo_id' => $creditmemo->getId()]); diff --git a/app/code/Magento/Sales/Controller/Adminhtml/Order/CreditmemoLoader.php b/app/code/Magento/Sales/Controller/Adminhtml/Order/CreditmemoLoader.php index 057e72b6176d3..0c5864e954a4f 100644 --- a/app/code/Magento/Sales/Controller/Adminhtml/Order/CreditmemoLoader.php +++ b/app/code/Magento/Sales/Controller/Adminhtml/Order/CreditmemoLoader.php @@ -138,7 +138,7 @@ protected function _canCreditmemo($order) * Check order existing */ if (!$order->getId()) { - $this->messageManager->addError(__('The order no longer exists.')); + $this->messageManager->addErrorMessage(__('The order no longer exists.')); return false; } @@ -146,7 +146,7 @@ protected function _canCreditmemo($order) * Check creditmemo create availability */ if (!$order->canCreditmemo()) { - $this->messageManager->addError(__('We can\'t create credit memo for the order.')); + $this->messageManager->addErrorMessage(__('We can\'t create credit memo for the order.')); return false; } return true; diff --git a/app/code/Magento/Sales/Controller/Adminhtml/Order/Edit/Start.php b/app/code/Magento/Sales/Controller/Adminhtml/Order/Edit/Start.php index 14c630542dbde..b1eba5f661c2e 100644 --- a/app/code/Magento/Sales/Controller/Adminhtml/Order/Edit/Start.php +++ b/app/code/Magento/Sales/Controller/Adminhtml/Order/Edit/Start.php @@ -36,10 +36,10 @@ public function execute() $resultRedirect->setPath('sales/order/'); } } catch (\Magento\Framework\Exception\LocalizedException $e) { - $this->messageManager->addError($e->getMessage()); + $this->messageManager->addErrorMessage($e->getMessage()); $resultRedirect->setPath('sales/order/view', ['order_id' => $orderId]); } catch (\Exception $e) { - $this->messageManager->addException($e, $e->getMessage()); + $this->messageManager->addExceptionMessage($e, $e->getMessage()); $resultRedirect->setPath('sales/order/view', ['order_id' => $orderId]); } return $resultRedirect; diff --git a/app/code/Magento/Sales/Controller/Adminhtml/Order/Email.php b/app/code/Magento/Sales/Controller/Adminhtml/Order/Email.php index 1573a07710b65..3500de798979a 100644 --- a/app/code/Magento/Sales/Controller/Adminhtml/Order/Email.php +++ b/app/code/Magento/Sales/Controller/Adminhtml/Order/Email.php @@ -25,11 +25,11 @@ public function execute() if ($order) { try { $this->orderManagement->notify($order->getEntityId()); - $this->messageManager->addSuccess(__('You sent the order email.')); + $this->messageManager->addSuccessMessage(__('You sent the order email.')); } catch (\Magento\Framework\Exception\LocalizedException $e) { - $this->messageManager->addError($e->getMessage()); + $this->messageManager->addErrorMessage($e->getMessage()); } catch (\Exception $e) { - $this->messageManager->addError(__('We can\'t send the email order right now.')); + $this->messageManager->addErrorMessage(__('We can\'t send the email order right now.')); $this->logger->critical($e); } return $this->resultRedirectFactory->create()->setPath( diff --git a/app/code/Magento/Sales/Controller/Adminhtml/Order/Hold.php b/app/code/Magento/Sales/Controller/Adminhtml/Order/Hold.php index feb307ca19c31..7d2c713eece48 100644 --- a/app/code/Magento/Sales/Controller/Adminhtml/Order/Hold.php +++ b/app/code/Magento/Sales/Controller/Adminhtml/Order/Hold.php @@ -23,18 +23,18 @@ public function execute() { $resultRedirect = $this->resultRedirectFactory->create(); if (!$this->isValidPostRequest()) { - $this->messageManager->addError(__('You have not put the order on hold.')); + $this->messageManager->addErrorMessage(__('You have not put the order on hold.')); return $resultRedirect->setPath('sales/*/'); } $order = $this->_initOrder(); if ($order) { try { $this->orderManagement->hold($order->getEntityId()); - $this->messageManager->addSuccess(__('You put the order on hold.')); + $this->messageManager->addSuccessMessage(__('You put the order on hold.')); } catch (\Magento\Framework\Exception\LocalizedException $e) { - $this->messageManager->addError($e->getMessage()); + $this->messageManager->addErrorMessage($e->getMessage()); } catch (\Exception $e) { - $this->messageManager->addError(__('You have not put the order on hold.')); + $this->messageManager->addErrorMessage(__('You have not put the order on hold.')); } $resultRedirect->setPath('sales/order/view', ['order_id' => $order->getId()]); return $resultRedirect; diff --git a/app/code/Magento/Sales/Controller/Adminhtml/Order/Invoice/Cancel.php b/app/code/Magento/Sales/Controller/Adminhtml/Order/Invoice/Cancel.php index a031591b37fae..e4a74329502f1 100644 --- a/app/code/Magento/Sales/Controller/Adminhtml/Order/Invoice/Cancel.php +++ b/app/code/Magento/Sales/Controller/Adminhtml/Order/Invoice/Cancel.php @@ -31,11 +31,11 @@ public function execute() )->addObject( $invoice->getOrder() )->save(); - $this->messageManager->addSuccess(__('You canceled the invoice.')); + $this->messageManager->addSuccessMessage(__('You canceled the invoice.')); } catch (\Magento\Framework\Exception\LocalizedException $e) { - $this->messageManager->addError($e->getMessage()); + $this->messageManager->addErrorMessage($e->getMessage()); } catch (\Exception $e) { - $this->messageManager->addError(__('Invoice canceling error')); + $this->messageManager->addErrorMessage(__('Invoice canceling error')); } /** @var \Magento\Backend\Model\View\Result\Redirect $resultRedirect */ $resultRedirect = $this->resultRedirectFactory->create(); diff --git a/app/code/Magento/Sales/Controller/Adminhtml/Order/Invoice/Capture.php b/app/code/Magento/Sales/Controller/Adminhtml/Order/Invoice/Capture.php index 030ccc9d9d3f6..43270264ecbda 100644 --- a/app/code/Magento/Sales/Controller/Adminhtml/Order/Invoice/Capture.php +++ b/app/code/Magento/Sales/Controller/Adminhtml/Order/Invoice/Capture.php @@ -33,11 +33,11 @@ public function execute() )->addObject( $invoice->getOrder() )->save(); - $this->messageManager->addSuccess(__('The invoice has been captured.')); + $this->messageManager->addSuccessMessage(__('The invoice has been captured.')); } catch (\Magento\Framework\Exception\LocalizedException $e) { - $this->messageManager->addError($e->getMessage()); + $this->messageManager->addErrorMessage($e->getMessage()); } catch (\Exception $e) { - $this->messageManager->addError(__('Invoice capturing error')); + $this->messageManager->addErrorMessage(__('Invoice capturing error')); } /** @var \Magento\Backend\Model\View\Result\Redirect $resultRedirect */ $resultRedirect = $this->resultRedirectFactory->create(); diff --git a/app/code/Magento/Sales/Controller/Adminhtml/Order/Invoice/NewAction.php b/app/code/Magento/Sales/Controller/Adminhtml/Order/Invoice/NewAction.php index 359bbafd45105..2d7826807a6c3 100644 --- a/app/code/Magento/Sales/Controller/Adminhtml/Order/Invoice/NewAction.php +++ b/app/code/Magento/Sales/Controller/Adminhtml/Order/Invoice/NewAction.php @@ -112,10 +112,10 @@ public function execute() $resultPage->getConfig()->getTitle()->prepend(__('New Invoice')); return $resultPage; } catch (\Magento\Framework\Exception\LocalizedException $exception) { - $this->messageManager->addError($exception->getMessage()); + $this->messageManager->addErrorMessage($exception->getMessage()); return $this->_redirectToOrder($orderId); } catch (\Exception $exception) { - $this->messageManager->addException($exception, 'Cannot create an invoice.'); + $this->messageManager->addExceptionMessage($exception, 'Cannot create an invoice.'); return $this->_redirectToOrder($orderId); } } diff --git a/app/code/Magento/Sales/Controller/Adminhtml/Order/Invoice/Save.php b/app/code/Magento/Sales/Controller/Adminhtml/Order/Invoice/Save.php index d804dff5d48a0..71338c818c418 100644 --- a/app/code/Magento/Sales/Controller/Adminhtml/Order/Invoice/Save.php +++ b/app/code/Magento/Sales/Controller/Adminhtml/Order/Invoice/Save.php @@ -118,7 +118,8 @@ public function execute() $formKeyIsValid = $this->_formKeyValidator->validate($this->getRequest()); $isPost = $this->getRequest()->isPost(); if (!$formKeyIsValid || !$isPost) { - $this->messageManager->addError(__("The invoice can't be saved at this time. Please try again later.")); + $this->messageManager + ->addErrorMessage(__("The invoice can't be saved at this time. Please try again later.")); return $resultRedirect->setPath('sales/order/index'); } @@ -193,9 +194,9 @@ public function execute() $transactionSave->save(); if (!empty($data['do_shipment'])) { - $this->messageManager->addSuccess(__('You created the invoice and shipment.')); + $this->messageManager->addSuccessMessage(__('You created the invoice and shipment.')); } else { - $this->messageManager->addSuccess(__('The invoice has been created.')); + $this->messageManager->addSuccessMessage(__('The invoice has been created.')); } // send invoice/shipment emails @@ -205,7 +206,7 @@ public function execute() } } catch (\Exception $e) { $this->_objectManager->get(\Psr\Log\LoggerInterface::class)->critical($e); - $this->messageManager->addError(__('We can\'t send the invoice email right now.')); + $this->messageManager->addErrorMessage(__('We can\'t send the invoice email right now.')); } if ($shipment) { try { @@ -214,15 +215,17 @@ public function execute() } } catch (\Exception $e) { $this->_objectManager->get(\Psr\Log\LoggerInterface::class)->critical($e); - $this->messageManager->addError(__('We can\'t send the shipment right now.')); + $this->messageManager->addErrorMessage(__('We can\'t send the shipment right now.')); } } $this->_objectManager->get(\Magento\Backend\Model\Session::class)->getCommentText(true); return $resultRedirect->setPath('sales/order/view', ['order_id' => $orderId]); } catch (LocalizedException $e) { - $this->messageManager->addError($e->getMessage()); + $this->messageManager->addErrorMessage($e->getMessage()); } catch (\Exception $e) { - $this->messageManager->addError(__("The invoice can't be saved at this time. Please try again later.")); + $this->messageManager->addErrorMessage( + __("The invoice can't be saved at this time. Please try again later.") + ); $this->_objectManager->get(\Psr\Log\LoggerInterface::class)->critical($e); } return $resultRedirect->setPath('sales/*/new', ['order_id' => $orderId]); diff --git a/app/code/Magento/Sales/Controller/Adminhtml/Order/Invoice/VoidAction.php b/app/code/Magento/Sales/Controller/Adminhtml/Order/Invoice/VoidAction.php index 6c91001cbb3da..4888ed555234c 100644 --- a/app/code/Magento/Sales/Controller/Adminhtml/Order/Invoice/VoidAction.php +++ b/app/code/Magento/Sales/Controller/Adminhtml/Order/Invoice/VoidAction.php @@ -34,11 +34,11 @@ public function execute() )->addObject( $invoice->getOrder() )->save(); - $this->messageManager->addSuccess(__('The invoice has been voided.')); + $this->messageManager->addSuccessMessage(__('The invoice has been voided.')); } catch (\Magento\Framework\Exception\LocalizedException $e) { - $this->messageManager->addError($e->getMessage()); + $this->messageManager->addErrorMessage($e->getMessage()); } catch (\Exception $e) { - $this->messageManager->addError(__('Invoice voiding error')); + $this->messageManager->addErrorMessage(__('Invoice voiding error')); } /** @var \Magento\Backend\Model\View\Result\Redirect $resultRedirect */ $resultRedirect = $this->resultRedirectFactory->create(); diff --git a/app/code/Magento/Sales/Controller/Adminhtml/Order/MassCancel.php b/app/code/Magento/Sales/Controller/Adminhtml/Order/MassCancel.php index 8488e402caf69..32cf6dbfc7c35 100644 --- a/app/code/Magento/Sales/Controller/Adminhtml/Order/MassCancel.php +++ b/app/code/Magento/Sales/Controller/Adminhtml/Order/MassCancel.php @@ -61,13 +61,13 @@ protected function massAction(AbstractCollection $collection) $countNonCancelOrder = $collection->count() - $countCancelOrder; if ($countNonCancelOrder && $countCancelOrder) { - $this->messageManager->addError(__('%1 order(s) cannot be canceled.', $countNonCancelOrder)); + $this->messageManager->addErrorMessage(__('%1 order(s) cannot be canceled.', $countNonCancelOrder)); } elseif ($countNonCancelOrder) { - $this->messageManager->addError(__('You cannot cancel the order(s).')); + $this->messageManager->addErrorMessage(__('You cannot cancel the order(s).')); } if ($countCancelOrder) { - $this->messageManager->addSuccess(__('We canceled %1 order(s).', $countCancelOrder)); + $this->messageManager->addSuccessMessage(__('We canceled %1 order(s).', $countCancelOrder)); } $resultRedirect = $this->resultRedirectFactory->create(); $resultRedirect->setPath($this->getComponentRefererUrl()); diff --git a/app/code/Magento/Sales/Controller/Adminhtml/Order/MassHold.php b/app/code/Magento/Sales/Controller/Adminhtml/Order/MassHold.php index e894957dc8b6c..241255f68e39f 100644 --- a/app/code/Magento/Sales/Controller/Adminhtml/Order/MassHold.php +++ b/app/code/Magento/Sales/Controller/Adminhtml/Order/MassHold.php @@ -62,13 +62,13 @@ protected function massAction(AbstractCollection $collection) $countNonHoldOrder = $collection->count() - $countHoldOrder; if ($countNonHoldOrder && $countHoldOrder) { - $this->messageManager->addError(__('%1 order(s) were not put on hold.', $countNonHoldOrder)); + $this->messageManager->addErrorMessage(__('%1 order(s) were not put on hold.', $countNonHoldOrder)); } elseif ($countNonHoldOrder) { - $this->messageManager->addError(__('No order(s) were put on hold.')); + $this->messageManager->addErrorMessage(__('No order(s) were put on hold.')); } if ($countHoldOrder) { - $this->messageManager->addSuccess(__('You have put %1 order(s) on hold.', $countHoldOrder)); + $this->messageManager->addSuccessMessage(__('You have put %1 order(s) on hold.', $countHoldOrder)); } $resultRedirect = $this->resultRedirectFactory->create(); diff --git a/app/code/Magento/Sales/Controller/Adminhtml/Order/MassUnhold.php b/app/code/Magento/Sales/Controller/Adminhtml/Order/MassUnhold.php index 2eb54c9814ef7..5e8ea9c4ad071 100644 --- a/app/code/Magento/Sales/Controller/Adminhtml/Order/MassUnhold.php +++ b/app/code/Magento/Sales/Controller/Adminhtml/Order/MassUnhold.php @@ -64,15 +64,15 @@ protected function massAction(AbstractCollection $collection) $countNonUnHoldOrder = $collection->count() - $countUnHoldOrder; if ($countNonUnHoldOrder && $countUnHoldOrder) { - $this->messageManager->addError( + $this->messageManager->addErrorMessage( __('%1 order(s) were not released from on hold status.', $countNonUnHoldOrder) ); } elseif ($countNonUnHoldOrder) { - $this->messageManager->addError(__('No order(s) were released from on hold status.')); + $this->messageManager->addErrorMessage(__('No order(s) were released from on hold status.')); } if ($countUnHoldOrder) { - $this->messageManager->addSuccess( + $this->messageManager->addSuccessMessage( __('%1 order(s) have been released from on hold status.', $countUnHoldOrder) ); } diff --git a/app/code/Magento/Sales/Controller/Adminhtml/Order/PdfDocumentsMassAction.php b/app/code/Magento/Sales/Controller/Adminhtml/Order/PdfDocumentsMassAction.php index c53e4d48925c0..eeda8699a8b10 100644 --- a/app/code/Magento/Sales/Controller/Adminhtml/Order/PdfDocumentsMassAction.php +++ b/app/code/Magento/Sales/Controller/Adminhtml/Order/PdfDocumentsMassAction.php @@ -27,7 +27,7 @@ public function execute() $collection = $this->filter->getCollection($this->getOrderCollection()->create()); return $this->massAction($collection); } catch (\Exception $e) { - $this->messageManager->addError($e->getMessage()); + $this->messageManager->addErrorMessage($e->getMessage()); /** @var \Magento\Backend\Model\View\Result\Redirect $resultRedirect */ $resultRedirect = $this->resultFactory->create(ResultFactory::TYPE_REDIRECT); return $resultRedirect->setPath($this->redirectUrl); diff --git a/app/code/Magento/Sales/Controller/Adminhtml/Order/Pdfcreditmemos.php b/app/code/Magento/Sales/Controller/Adminhtml/Order/Pdfcreditmemos.php index f96e2fd09c2b0..e731c54d8305a 100644 --- a/app/code/Magento/Sales/Controller/Adminhtml/Order/Pdfcreditmemos.php +++ b/app/code/Magento/Sales/Controller/Adminhtml/Order/Pdfcreditmemos.php @@ -76,18 +76,22 @@ public function __construct( * * @param AbstractCollection $collection * @return ResponseInterface|ResultInterface + * @throws \Exception */ protected function massAction(AbstractCollection $collection) { $creditmemoCollection = $this->collectionFactory->create()->setOrderFilter(['in' => $collection->getAllIds()]); if (!$creditmemoCollection->getSize()) { - $this->messageManager->addError(__('There are no printable documents related to selected orders.')); + $this->messageManager->addErrorMessage(__('There are no printable documents related to selected orders.')); return $this->resultRedirectFactory->create()->setPath($this->getComponentRefererUrl()); } + $pdf = $this->pdfCreditmemo->getPdf($creditmemoCollection->getItems()); + $fileContent = ['type' => 'string', 'value' => $pdf->render(), 'rm' => true]; + return $this->fileFactory->create( sprintf('creditmemo%s.pdf', $this->dateTime->date('Y-m-d_H-i-s')), - $this->pdfCreditmemo->getPdf($creditmemoCollection->getItems())->render(), + $fileContent, DirectoryList::VAR_DIR, 'application/pdf' ); diff --git a/app/code/Magento/Sales/Controller/Adminhtml/Order/Pdfdocs.php b/app/code/Magento/Sales/Controller/Adminhtml/Order/Pdfdocs.php index d68cfe696b0ef..f641a7bde7335 100644 --- a/app/code/Magento/Sales/Controller/Adminhtml/Order/Pdfdocs.php +++ b/app/code/Magento/Sales/Controller/Adminhtml/Order/Pdfdocs.php @@ -113,6 +113,7 @@ public function __construct( * @return ResponseInterface|\Magento\Backend\Model\View\Result\Redirect * * @SuppressWarnings(PHPMD.CyclomaticComplexity) + * @throws \Exception */ protected function massAction(AbstractCollection $collection) { @@ -134,7 +135,7 @@ protected function massAction(AbstractCollection $collection) } if (empty($documents)) { - $this->messageManager->addError(__('There are no printable documents related to selected orders.')); + $this->messageManager->addErrorMessage(__('There are no printable documents related to selected orders.')); return $this->resultRedirectFactory->create()->setPath($this->getComponentRefererUrl()); } @@ -142,10 +143,11 @@ protected function massAction(AbstractCollection $collection) foreach ($documents as $document) { $pdf->pages = array_merge($pdf->pages, $document->pages); } + $fileContent = ['type' => 'string', 'value' => $pdf->render(), 'rm' => true]; return $this->fileFactory->create( sprintf('docs%s.pdf', $this->dateTime->date('Y-m-d_H-i-s')), - $pdf->render(), + $fileContent, DirectoryList::VAR_DIR, 'application/pdf' ); diff --git a/app/code/Magento/Sales/Controller/Adminhtml/Order/Pdfinvoices.php b/app/code/Magento/Sales/Controller/Adminhtml/Order/Pdfinvoices.php index fee124a91410d..9e637c8883485 100644 --- a/app/code/Magento/Sales/Controller/Adminhtml/Order/Pdfinvoices.php +++ b/app/code/Magento/Sales/Controller/Adminhtml/Order/Pdfinvoices.php @@ -75,17 +75,21 @@ public function __construct( * * @param AbstractCollection $collection * @return ResponseInterface|ResultInterface + * @throws \Exception */ protected function massAction(AbstractCollection $collection) { $invoicesCollection = $this->collectionFactory->create()->setOrderFilter(['in' => $collection->getAllIds()]); if (!$invoicesCollection->getSize()) { - $this->messageManager->addError(__('There are no printable documents related to selected orders.')); + $this->messageManager->addErrorMessage(__('There are no printable documents related to selected orders.')); return $this->resultRedirectFactory->create()->setPath($this->getComponentRefererUrl()); } + $pdf = $this->pdfInvoice->getPdf($invoicesCollection->getItems()); + $fileContent = ['type' => 'string', 'value' => $pdf->render(), 'rm' => true]; + return $this->fileFactory->create( sprintf('invoice%s.pdf', $this->dateTime->date('Y-m-d_H-i-s')), - $this->pdfInvoice->getPdf($invoicesCollection->getItems())->render(), + $fileContent, DirectoryList::VAR_DIR, 'application/pdf' ); diff --git a/app/code/Magento/Sales/Controller/Adminhtml/Order/Pdfshipments.php b/app/code/Magento/Sales/Controller/Adminhtml/Order/Pdfshipments.php index 1aa5bfdb83878..6ce2557703ece 100644 --- a/app/code/Magento/Sales/Controller/Adminhtml/Order/Pdfshipments.php +++ b/app/code/Magento/Sales/Controller/Adminhtml/Order/Pdfshipments.php @@ -77,6 +77,7 @@ public function __construct( * * @param AbstractCollection $collection * @return ResponseInterface|\Magento\Backend\Model\View\Result\Redirect + * @throws \Exception */ protected function massAction(AbstractCollection $collection) { @@ -84,12 +85,16 @@ protected function massAction(AbstractCollection $collection) ->create() ->setOrderFilter(['in' => $collection->getAllIds()]); if (!$shipmentsCollection->getSize()) { - $this->messageManager->addError(__('There are no printable documents related to selected orders.')); + $this->messageManager->addErrorMessage(__('There are no printable documents related to selected orders.')); return $this->resultRedirectFactory->create()->setPath($this->getComponentRefererUrl()); } + + $pdf = $this->pdfShipment->getPdf($shipmentsCollection->getItems()); + $fileContent = ['type' => 'string', 'value' => $pdf->render(), 'rm' => true]; + return $this->fileFactory->create( sprintf('packingslip%s.pdf', $this->dateTime->date('Y-m-d_H-i-s')), - $this->pdfShipment->getPdf($shipmentsCollection->getItems())->render(), + $fileContent, DirectoryList::VAR_DIR, 'application/pdf' ); diff --git a/app/code/Magento/Sales/Controller/Adminhtml/Order/ReviewPayment.php b/app/code/Magento/Sales/Controller/Adminhtml/Order/ReviewPayment.php index 88abdb76d26f7..09a52a113617a 100644 --- a/app/code/Magento/Sales/Controller/Adminhtml/Order/ReviewPayment.php +++ b/app/code/Magento/Sales/Controller/Adminhtml/Order/ReviewPayment.php @@ -53,15 +53,15 @@ public function execute() throw new \Exception(sprintf('Action "%s" is not supported.', $action)); } $this->orderRepository->save($order); - $this->messageManager->addSuccess($message); + $this->messageManager->addSuccessMessage($message); } else { $resultRedirect->setPath('sales/*/'); return $resultRedirect; } } catch (\Magento\Framework\Exception\LocalizedException $e) { - $this->messageManager->addError($e->getMessage()); + $this->messageManager->addErrorMessage($e->getMessage()); } catch (\Exception $e) { - $this->messageManager->addError(__('We can\'t update the payment right now.')); + $this->messageManager->addErrorMessage(__('We can\'t update the payment right now.')); $this->logger->critical($e); } $resultRedirect->setPath('sales/order/view', ['order_id' => $order->getEntityId()]); diff --git a/app/code/Magento/Sales/Controller/Adminhtml/Order/Status/AssignPost.php b/app/code/Magento/Sales/Controller/Adminhtml/Order/Status/AssignPost.php index 89820b41a68da..3b98d206d5f66 100644 --- a/app/code/Magento/Sales/Controller/Adminhtml/Order/Status/AssignPost.php +++ b/app/code/Magento/Sales/Controller/Adminhtml/Order/Status/AssignPost.php @@ -26,18 +26,18 @@ public function execute() if ($status && $status->getStatus()) { try { $status->assignState($state, $isDefault, $visibleOnFront); - $this->messageManager->addSuccess(__('You assigned the order status.')); + $this->messageManager->addSuccessMessage(__('You assigned the order status.')); return $resultRedirect->setPath('sales/*/'); } catch (\Magento\Framework\Exception\LocalizedException $e) { - $this->messageManager->addError($e->getMessage()); + $this->messageManager->addErrorMessage($e->getMessage()); } catch (\Exception $e) { - $this->messageManager->addException( + $this->messageManager->addExceptionMessage( $e, __('Something went wrong while assigning the order status.') ); } } else { - $this->messageManager->addError(__('We can\'t find this order status.')); + $this->messageManager->addErrorMessage(__('We can\'t find this order status.')); } return $resultRedirect->setPath('sales/*/assign'); } diff --git a/app/code/Magento/Sales/Controller/Adminhtml/Order/Status/Edit.php b/app/code/Magento/Sales/Controller/Adminhtml/Order/Status/Edit.php index 69e051b20c4dd..7a4a1918bc1a2 100644 --- a/app/code/Magento/Sales/Controller/Adminhtml/Order/Status/Edit.php +++ b/app/code/Magento/Sales/Controller/Adminhtml/Order/Status/Edit.php @@ -48,7 +48,7 @@ public function execute() $resultPage->getConfig()->getTitle()->prepend(__('Edit Order Status')); return $resultPage; } else { - $this->messageManager->addError(__('We can\'t find this order status.')); + $this->messageManager->addErrorMessage(__('We can\'t find this order status.')); /** @var \Magento\Backend\Model\View\Result\Redirect $resultRedirect */ $resultRedirect = $this->resultRedirectFactory->create(); return $resultRedirect->setPath('sales/'); diff --git a/app/code/Magento/Sales/Controller/Adminhtml/Order/Status/Save.php b/app/code/Magento/Sales/Controller/Adminhtml/Order/Status/Save.php index 849a7e2d0c817..bd0ad771815b1 100644 --- a/app/code/Magento/Sales/Controller/Adminhtml/Order/Status/Save.php +++ b/app/code/Magento/Sales/Controller/Adminhtml/Order/Status/Save.php @@ -40,7 +40,8 @@ public function execute() $status = $this->_objectManager->create(\Magento\Sales\Model\Order\Status::class)->load($statusCode); // check if status exist if ($isNew && $status->getStatus()) { - $this->messageManager->addError(__('We found another order status with the same order status code.')); + $this->messageManager + ->addErrorMessage(__('We found another order status with the same order status code.')); $this->_getSession()->setFormData($data); return $resultRedirect->setPath('sales/*/new'); } @@ -49,23 +50,33 @@ public function execute() try { $status->save(); - $this->messageManager->addSuccess(__('You saved the order status.')); + $this->messageManager->addSuccessMessage(__('You saved the order status.')); return $resultRedirect->setPath('sales/*/'); } catch (\Magento\Framework\Exception\LocalizedException $e) { - $this->messageManager->addError($e->getMessage()); + $this->messageManager->addErrorMessage($e->getMessage()); } catch (\Exception $e) { - $this->messageManager->addException( + $this->messageManager->addExceptionMessage( $e, __('We can\'t add the order status right now.') ); } $this->_getSession()->setFormData($data); - if ($isNew) { - return $resultRedirect->setPath('sales/*/new'); - } else { - return $resultRedirect->setPath('sales/*/edit', ['status' => $this->getRequest()->getParam('status')]); - } + return $this->getRedirect($resultRedirect, $isNew); } return $resultRedirect->setPath('sales/*/'); } + + /** + * @param \Magento\Backend\Model\View\Result\Redirect $resultRedirect + * @param bool $isNew + * @return \Magento\Backend\Model\View\Result\Redirect + */ + private function getRedirect(\Magento\Backend\Model\View\Result\Redirect $resultRedirect, $isNew) + { + if ($isNew) { + return $resultRedirect->setPath('sales/*/new'); + } else { + return $resultRedirect->setPath('sales/*/edit', ['status' => $this->getRequest()->getParam('status')]); + } + } } diff --git a/app/code/Magento/Sales/Controller/Adminhtml/Order/Status/Unassign.php b/app/code/Magento/Sales/Controller/Adminhtml/Order/Status/Unassign.php index 04db430e1ffa4..2723d483dd38b 100644 --- a/app/code/Magento/Sales/Controller/Adminhtml/Order/Status/Unassign.php +++ b/app/code/Magento/Sales/Controller/Adminhtml/Order/Status/Unassign.php @@ -18,17 +18,17 @@ public function execute() if ($status) { try { $status->unassignState($state); - $this->messageManager->addSuccess(__('You have unassigned the order status.')); + $this->messageManager->addSuccessMessage(__('You have unassigned the order status.')); } catch (\Magento\Framework\Exception\LocalizedException $e) { - $this->messageManager->addError($e->getMessage()); + $this->messageManager->addErrorMessage($e->getMessage()); } catch (\Exception $e) { - $this->messageManager->addException( + $this->messageManager->addExceptionMessage( $e, __('Something went wrong while unassigning the order.') ); } } else { - $this->messageManager->addError(__('We can\'t find this order status.')); + $this->messageManager->addErrorMessage(__('We can\'t find this order status.')); } /** @var \Magento\Backend\Model\View\Result\Redirect $resultRedirect */ $resultRedirect = $this->resultRedirectFactory->create(); diff --git a/app/code/Magento/Sales/Controller/Adminhtml/Order/Unhold.php b/app/code/Magento/Sales/Controller/Adminhtml/Order/Unhold.php index fa9676856a442..8d7f27069eeb7 100644 --- a/app/code/Magento/Sales/Controller/Adminhtml/Order/Unhold.php +++ b/app/code/Magento/Sales/Controller/Adminhtml/Order/Unhold.php @@ -23,7 +23,7 @@ public function execute() { $resultRedirect = $this->resultRedirectFactory->create(); if (!$this->isValidPostRequest()) { - $this->messageManager->addError(__('Can\'t unhold order.')); + $this->messageManager->addErrorMessage(__('Can\'t unhold order.')); return $resultRedirect->setPath('sales/*/'); } $order = $this->_initOrder(); @@ -33,11 +33,11 @@ public function execute() throw new \Magento\Framework\Exception\LocalizedException(__('Can\'t unhold order.')); } $this->orderManagement->unHold($order->getEntityId()); - $this->messageManager->addSuccess(__('You released the order from holding status.')); + $this->messageManager->addSuccessMessage(__('You released the order from holding status.')); } catch (\Magento\Framework\Exception\LocalizedException $e) { - $this->messageManager->addError($e->getMessage()); + $this->messageManager->addErrorMessage($e->getMessage()); } catch (\Exception $e) { - $this->messageManager->addError(__('The order was not on hold.')); + $this->messageManager->addErrorMessage(__('The order was not on hold.')); } $resultRedirect->setPath('sales/order/view', ['order_id' => $order->getId()]); return $resultRedirect; diff --git a/app/code/Magento/Sales/Controller/Adminhtml/Order/View.php b/app/code/Magento/Sales/Controller/Adminhtml/Order/View.php index 7be17f865312e..8906d11dd776f 100644 --- a/app/code/Magento/Sales/Controller/Adminhtml/Order/View.php +++ b/app/code/Magento/Sales/Controller/Adminhtml/Order/View.php @@ -31,7 +31,7 @@ public function execute() $resultPage->getConfig()->getTitle()->prepend(__('Orders')); } catch (\Exception $e) { $this->logger->critical($e); - $this->messageManager->addError(__('Exception occurred during order load')); + $this->messageManager->addErrorMessage(__('Exception occurred during order load')); $resultRedirect->setPath('sales/order/index'); return $resultRedirect; } diff --git a/app/code/Magento/Sales/Controller/Adminhtml/Order/View/Giftmessage/Save.php b/app/code/Magento/Sales/Controller/Adminhtml/Order/View/Giftmessage/Save.php index 61dc325c05c91..88fdbe58271f6 100644 --- a/app/code/Magento/Sales/Controller/Adminhtml/Order/View/Giftmessage/Save.php +++ b/app/code/Magento/Sales/Controller/Adminhtml/Order/View/Giftmessage/Save.php @@ -18,9 +18,9 @@ public function execute() $this->getRequest()->getParam('giftmessage') )->saveAllInOrder(); } catch (\Magento\Framework\Exception\LocalizedException $e) { - $this->messageManager->addError($e->getMessage()); + $this->messageManager->addErrorMessage($e->getMessage()); } catch (\Exception $e) { - $this->messageManager->addError(__('Something went wrong while saving the gift message.')); + $this->messageManager->addErrorMessage(__('Something went wrong while saving the gift message.')); } if ($this->getRequest()->getParam('type') == 'order_item') { diff --git a/app/code/Magento/Sales/Controller/Adminhtml/Order/VoidPayment.php b/app/code/Magento/Sales/Controller/Adminhtml/Order/VoidPayment.php index 3e7ce50f9a6f1..4ead8885087c3 100644 --- a/app/code/Magento/Sales/Controller/Adminhtml/Order/VoidPayment.php +++ b/app/code/Magento/Sales/Controller/Adminhtml/Order/VoidPayment.php @@ -21,11 +21,11 @@ public function execute() // workaround for backwards compatibility $order->getPayment()->void(new \Magento\Framework\DataObject()); $order->save(); - $this->messageManager->addSuccess(__('The payment has been voided.')); + $this->messageManager->addSuccessMessage(__('The payment has been voided.')); } catch (\Magento\Framework\Exception\LocalizedException $e) { - $this->messageManager->addError($e->getMessage()); + $this->messageManager->addErrorMessage($e->getMessage()); } catch (\Exception $e) { - $this->messageManager->addError(__('We can\'t void the payment right now.')); + $this->messageManager->addErrorMessage(__('We can\'t void the payment right now.')); $this->_objectManager->get(\Psr\Log\LoggerInterface::class)->critical($e); } $resultRedirect->setPath('sales/*/view', ['order_id' => $order->getId()]); diff --git a/app/code/Magento/Sales/Controller/Adminhtml/Shipment/AbstractShipment/Pdfshipments.php b/app/code/Magento/Sales/Controller/Adminhtml/Shipment/AbstractShipment/Pdfshipments.php index b10dca908fe6a..4a7c6e0533e33 100644 --- a/app/code/Magento/Sales/Controller/Adminhtml/Shipment/AbstractShipment/Pdfshipments.php +++ b/app/code/Magento/Sales/Controller/Adminhtml/Shipment/AbstractShipment/Pdfshipments.php @@ -70,9 +70,12 @@ public function __construct( */ public function massAction(AbstractCollection $collection) { + $pdf = $this->pdfShipment->getPdf($collection); + $fileContent = ['type' => 'string', 'value' => $pdf->render(), 'rm' => true]; + return $this->fileFactory->create( sprintf('packingslip%s.pdf', $this->dateTime->date('Y-m-d_H-i-s')), - $this->pdfShipment->getPdf($collection)->render(), + $fileContent, DirectoryList::VAR_DIR, 'application/pdf' ); diff --git a/app/code/Magento/Sales/Controller/Adminhtml/Shipment/AbstractShipment/PrintAction.php b/app/code/Magento/Sales/Controller/Adminhtml/Shipment/AbstractShipment/PrintAction.php index da8646a0c30b2..1e49fe7eff60a 100644 --- a/app/code/Magento/Sales/Controller/Adminhtml/Shipment/AbstractShipment/PrintAction.php +++ b/app/code/Magento/Sales/Controller/Adminhtml/Shipment/AbstractShipment/PrintAction.php @@ -48,6 +48,7 @@ public function __construct( /** * @return ResponseInterface|\Magento\Backend\Model\View\Result\Forward + * @throws \Exception */ public function execute() { @@ -63,9 +64,11 @@ public function execute() $date = $this->_objectManager->get( \Magento\Framework\Stdlib\DateTime\DateTime::class )->date('Y-m-d_H-i-s'); + $fileContent = ['type' => 'string', 'value' => $pdf->render(), 'rm' => true]; + return $this->_fileFactory->create( 'packingslip' . $date . '.pdf', - $pdf->render(), + $fileContent, DirectoryList::VAR_DIR, 'application/pdf' ); diff --git a/app/code/Magento/Sales/Controller/Adminhtml/Transactions.php b/app/code/Magento/Sales/Controller/Adminhtml/Transactions.php index d5c1186964076..e344b258c5198 100644 --- a/app/code/Magento/Sales/Controller/Adminhtml/Transactions.php +++ b/app/code/Magento/Sales/Controller/Adminhtml/Transactions.php @@ -82,7 +82,7 @@ protected function _initTransaction() ); if (!$txn->getId()) { - $this->messageManager->addError(__('Please correct the transaction ID and try again.')); + $this->messageManager->addErrorMessage(__('Please correct the transaction ID and try again.')); $this->_actionFlag->set('', self::FLAG_NO_DISPATCH, true); return false; } diff --git a/app/code/Magento/Sales/Controller/Adminhtml/Transactions/Fetch.php b/app/code/Magento/Sales/Controller/Adminhtml/Transactions/Fetch.php index e77c65716fdd7..1b72ce3f13e33 100644 --- a/app/code/Magento/Sales/Controller/Adminhtml/Transactions/Fetch.php +++ b/app/code/Magento/Sales/Controller/Adminhtml/Transactions/Fetch.php @@ -38,11 +38,11 @@ public function execute() ->setOrder($txn->getOrder()) ->importTransactionInfo($txn); $txn->save(); - $this->messageManager->addSuccess(__('The transaction details have been updated.')); + $this->messageManager->addSuccessMessage(__('The transaction details have been updated.')); } catch (\Magento\Framework\Exception\LocalizedException $e) { - $this->messageManager->addError($e->getMessage()); + $this->messageManager->addErrorMessage($e->getMessage()); } catch (\Exception $e) { - $this->messageManager->addError(__('We can\'t update the transaction details.')); + $this->messageManager->addErrorMessage(__('We can\'t update the transaction details.')); $this->_objectManager->get(\Psr\Log\LoggerInterface::class)->critical($e); } diff --git a/app/code/Magento/Sales/Helper/Guest.php b/app/code/Magento/Sales/Helper/Guest.php index 8407ce5a8d7cb..a3f2ac6ba3556 100644 --- a/app/code/Magento/Sales/Helper/Guest.php +++ b/app/code/Magento/Sales/Helper/Guest.php @@ -165,7 +165,7 @@ public function loadValidOrder(App\RequestInterface $request) $this->coreRegistry->register('current_order', $order); return true; } catch (InputException $e) { - $this->messageManager->addError($e->getMessage()); + $this->messageManager->addErrorMessage($e->getMessage()); return $this->resultRedirectFactory->create()->setPath('sales/guest/form'); } } diff --git a/app/code/Magento/Sales/Model/AdminOrder/Create.php b/app/code/Magento/Sales/Model/AdminOrder/Create.php index 07716ff8274c6..b690395ebab7c 100644 --- a/app/code/Magento/Sales/Model/AdminOrder/Create.php +++ b/app/code/Magento/Sales/Model/AdminOrder/Create.php @@ -1075,7 +1075,7 @@ public function addProducts(array $products) try { $this->addProduct($productId, $config); } catch (\Magento\Framework\Exception\LocalizedException $e) { - $this->messageManager->addError($e->getMessage()); + $this->messageManager->addErrorMessage($e->getMessage()); } catch (\Exception $e) { return $e; } @@ -1956,21 +1956,17 @@ public function createOrder() */ protected function _validate() { - $customerId = $this->getSession()->getCustomerId(); - if ($customerId === null) { - throw new \Magento\Framework\Exception\LocalizedException(__('Please select a customer')); - } - if (!$this->getSession()->getStore()->getId()) { throw new \Magento\Framework\Exception\LocalizedException(__('Please select a store')); } $items = $this->getQuote()->getAllItems(); - if (count($items) == 0) { + if (count($items) === 0) { $this->_errors[] = __('Please specify order items.'); } foreach ($items as $item) { + /** @var \Magento\Quote\Model\Quote\Item $item */ $messages = $item->getMessage(false); if ($item->getHasError() && is_array($messages) && !empty($messages)) { $this->_errors = array_merge($this->_errors, $messages); @@ -2002,7 +1998,7 @@ protected function _validate() $logger = ObjectManager::getInstance()->get(LoggerInterface::class); foreach ($this->_errors as $error) { $logger->error($error); - $this->messageManager->addError($error); + $this->messageManager->addErrorMessage($error); } throw new \Magento\Framework\Exception\LocalizedException(__('Validation is failed.')); diff --git a/app/code/Magento/Sales/Model/AdminOrder/EmailSender.php b/app/code/Magento/Sales/Model/AdminOrder/EmailSender.php index 8ba0b5b071395..4e068eb571deb 100644 --- a/app/code/Magento/Sales/Model/AdminOrder/EmailSender.php +++ b/app/code/Magento/Sales/Model/AdminOrder/EmailSender.php @@ -55,7 +55,7 @@ public function send(Order $order) $this->orderSender->send($order); } catch (\Magento\Framework\Exception\MailException $exception) { $this->logger->critical($exception); - $this->messageManager->addWarning( + $this->messageManager->addWarningMessage( __('You did not email your customer. Please check your email settings.') ); return false; diff --git a/app/code/Magento/Sales/Model/Config/Ordered.php b/app/code/Magento/Sales/Model/Config/Ordered.php index 8c5ddb8e07df7..bae6223ee7d5e 100644 --- a/app/code/Magento/Sales/Model/Config/Ordered.php +++ b/app/code/Magento/Sales/Model/Config/Ordered.php @@ -167,13 +167,8 @@ function ($a, $b) { if (!isset($a['sort_order']) || !isset($b['sort_order'])) { return 0; } - if ($a['sort_order'] > $b['sort_order']) { - return 1; - } elseif ($a['sort_order'] < $b['sort_order']) { - return -1; - } else { - return 0; - } + + return $a['sort_order'] <=> $b['sort_order']; } ); } diff --git a/app/code/Magento/Sales/Model/Order/Creditmemo.php b/app/code/Magento/Sales/Model/Order/Creditmemo.php index 19aac897c21e2..7ea7e4af3c36e 100644 --- a/app/code/Magento/Sales/Model/Order/Creditmemo.php +++ b/app/code/Magento/Sales/Model/Order/Creditmemo.php @@ -469,13 +469,6 @@ public function getStateName($stateId = null) */ public function setShippingAmount($amount) { - // base shipping amount calculated in total model - // $amount = $this->getStore()->round($amount); - // $this->setData('base_shipping_amount', $amount); - // - // $amount = $this->getStore()->round( - // $amount*$this->getOrder()->getStoreToOrderRate() - // ); return $this->setData(CreditmemoInterface::SHIPPING_AMOUNT, $amount); } @@ -582,13 +575,6 @@ public function getCommentsCollection($reload = false) { $collection = $this->_commentCollectionFactory->create()->setCreditmemoFilter($this->getId()) ->setCreatedAtOrder(); -// -// $this->setComments($comments); -// /** -// * When credit memo created with adding comment, -// * comments collection must be loaded before we added this comment. -// */ -// $this->getComments()->load(); if ($this->getId()) { foreach ($collection as $comment) { diff --git a/app/code/Magento/Sales/Model/Order/Pdf/Items/Invoice/DefaultInvoice.php b/app/code/Magento/Sales/Model/Order/Pdf/Items/Invoice/DefaultInvoice.php index bb6078e425900..7f5d880915cfc 100644 --- a/app/code/Magento/Sales/Model/Order/Pdf/Items/Invoice/DefaultInvoice.php +++ b/app/code/Magento/Sales/Model/Order/Pdf/Items/Invoice/DefaultInvoice.php @@ -127,7 +127,8 @@ public function draw() 'feed' => 35, ]; - if ($option['value']) { + // Checking whether option value is not null + if ($option['value']!= null) { if (isset($option['print_value'])) { $printValue = $option['print_value']; } else { diff --git a/app/code/Magento/Sales/Model/Order/Pdf/Items/Shipment/DefaultShipment.php b/app/code/Magento/Sales/Model/Order/Pdf/Items/Shipment/DefaultShipment.php index 0e6f345e19bc3..433a4b7e314f4 100644 --- a/app/code/Magento/Sales/Model/Order/Pdf/Items/Shipment/DefaultShipment.php +++ b/app/code/Magento/Sales/Model/Order/Pdf/Items/Shipment/DefaultShipment.php @@ -89,7 +89,7 @@ public function draw() ]; // draw options value - if ($option['value']) { + if ($option['value']!= null) { $printValue = isset( $option['print_value'] ) ? $option['print_value'] : $this->filterManager->stripTags( diff --git a/app/code/Magento/Sales/Model/Service/CreditmemoService.php b/app/code/Magento/Sales/Model/Service/CreditmemoService.php index 24f56c0dbd595..e8f2e6e5305f7 100644 --- a/app/code/Magento/Sales/Model/Service/CreditmemoService.php +++ b/app/code/Magento/Sales/Model/Service/CreditmemoService.php @@ -100,22 +100,11 @@ public function __construct( * @param int $id Credit Memo Id * @return bool * @throws \Magento\Framework\Exception\LocalizedException + * @SuppressWarnings(PHPMD.UnusedFormalParameter) */ public function cancel($id) { throw new \Magento\Framework\Exception\LocalizedException(__('You can not cancel Credit Memo')); - try { - $creditmemo = $this->creditmemoRepository->get($id); - $creditmemo->setState(\Magento\Sales\Model\Order\Creditmemo::STATE_CANCELED); - foreach ($creditmemo->getAllItems() as $item) { - $item->cancel(); - } - $this->eventManager->dispatch('sales_order_creditmemo_cancel', ['creditmemo' => $creditmemo]); - $this->creditmemoRepository->save($creditmemo); - } catch (\Exception $e) { - throw new \Magento\Framework\Exception\LocalizedException(__('Could not cancel creditmemo'), $e); - } - return true; } /** diff --git a/app/code/Magento/Sales/Test/Mftf/composer.json b/app/code/Magento/Sales/Test/Mftf/composer.json deleted file mode 100644 index ac26bb1bf49f5..0000000000000 --- a/app/code/Magento/Sales/Test/Mftf/composer.json +++ /dev/null @@ -1,43 +0,0 @@ -{ - "name": "magento/functional-test-module-sales", - "description": "N/A", - "config": { - "sort-packages": true - }, - "require": { - "php": "~7.1.3||~7.2.0", - "magento/magento2-functional-testing-framework": "2.2.0", - "magento/functional-test-module-authorization": "100.0.0-dev", - "magento/functional-test-module-backend": "100.0.0-dev", - "magento/functional-test-module-catalog": "100.0.0-dev", - "magento/functional-test-module-bundle": "100.0.0-dev", - "magento/functional-test-module-catalog-inventory": "100.0.0-dev", - "magento/functional-test-module-checkout": "100.0.0-dev", - "magento/functional-test-module-config": "100.0.0-dev", - "magento/functional-test-module-customer": "100.0.0-dev", - "magento/functional-test-module-directory": "100.0.0-dev", - "magento/functional-test-module-eav": "100.0.0-dev", - "magento/functional-test-module-gift-message": "100.0.0-dev", - "magento/functional-test-module-media-storage": "100.0.0-dev", - "magento/functional-test-module-payment": "100.0.0-dev", - "magento/functional-test-module-quote": "100.0.0-dev", - "magento/functional-test-module-reports": "100.0.0-dev", - "magento/functional-test-module-sales-rule": "100.0.0-dev", - "magento/functional-test-module-sales-sequence": "100.0.0-dev", - "magento/functional-test-module-shipping": "100.0.0-dev", - "magento/functional-test-module-store": "100.0.0-dev", - "magento/functional-test-module-tax": "100.0.0-dev", - "magento/functional-test-module-theme": "100.0.0-dev", - "magento/functional-test-module-ui": "100.0.0-dev", - "magento/functional-test-module-widget": "100.0.0-dev", - "magento/functional-test-module-wishlist": "100.0.0-dev" - }, - "suggest": { - "magento/functional-test-module-sales-sample-data": "100.0.0-dev" - }, - "type": "magento2-test", - "license": [ - "OSL-3.0", - "AFL-3.0" - ] -} diff --git a/app/code/Magento/Sales/Test/Unit/Block/Adminhtml/Order/Create/FormTest.php b/app/code/Magento/Sales/Test/Unit/Block/Adminhtml/Order/Create/FormTest.php new file mode 100644 index 0000000000000..4cbd30b1392fa --- /dev/null +++ b/app/code/Magento/Sales/Test/Unit/Block/Adminhtml/Order/Create/FormTest.php @@ -0,0 +1,197 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +declare(strict_types=1); + +namespace Magento\Sales\Test\Unit\Block\Adminhtml\Order\Create; + +use Magento\Backend\Block\Template\Context; +use Magento\Backend\Model\Session\Quote as QuoteSession; +use Magento\Customer\Api\CustomerRepositoryInterface; +use Magento\Customer\Api\Data\CustomerInterface; +use Magento\Customer\Model\Address\Mapper; +use Magento\Customer\Model\Metadata\FormFactory; +use Magento\Framework\Currency; +use Magento\Framework\Json\EncoderInterface; +use Magento\Framework\Locale\CurrencyInterface; +use Magento\Framework\Pricing\PriceCurrencyInterface; +use Magento\Quote\Model\Quote; +use Magento\Quote\Model\Quote\Address; +use Magento\Quote\Model\Quote\Payment; +use Magento\Sales\Block\Adminhtml\Order\Create\Form; +use Magento\Sales\Model\AdminOrder\Create; +use Magento\Store\Model\Store; +use PHPUnit\Framework\TestCase; +use PHPUnit_Framework_MockObject_MockObject as MockObject; + +/** + * @SuppressWarnings(PHPMD.CouplingBetweenObjects) + */ +class FormTest extends TestCase +{ + /** + * @var QuoteSession|MockObject + */ + private $quoteSession; + + /** + * @var CustomerRepositoryInterface|MockObject + */ + private $customerRepository; + + /** + * @var CurrencyInterface|MockObject + */ + private $localeCurrency; + + /** + * @var Form + */ + private $block; + + /** + * @inheritdoc + */ + protected function setUp() + { + /** @var Context|MockObject $context */ + $context = $this->getMockBuilder(Context::class) + ->disableOriginalConstructor() + ->getMock(); + $this->quoteSession = $this->getMockBuilder(QuoteSession::class) + ->disableOriginalConstructor() + ->setMethods(['getCustomerId', 'getQuoteId', 'getStoreId', 'getStore', 'getQuote']) + ->getMock(); + /** @var Create|MockObject $create */ + $create = $this->getMockBuilder(Create::class) + ->disableOriginalConstructor() + ->getMock(); + /** @var PriceCurrencyInterface|MockObject $priceCurrency */ + $priceCurrency = $this->getMockForAbstractClass(PriceCurrencyInterface::class); + /** @var EncoderInterface|MockObject $encoder */ + $encoder = $this->getMockForAbstractClass(EncoderInterface::class); + $encoder->method('encode') + ->willReturnCallback(function ($param) { + return json_encode($param); + }); + /** @var FormFactory|MockObject $formFactory */ + $formFactory = $this->getMockBuilder(FormFactory::class) + ->disableOriginalConstructor() + ->getMock(); + $this->customerRepository = $this->getMockForAbstractClass(CustomerRepositoryInterface::class); + + $this->localeCurrency = $this->getMockForAbstractClass(CurrencyInterface::class); + /** @var Mapper|MockObject $addressMapper */ + $addressMapper = $this->getMockBuilder(Mapper::class) + ->disableOriginalConstructor() + ->getMock(); + + $this->block = new Form( + $context, + $this->quoteSession, + $create, + $priceCurrency, + $encoder, + $formFactory, + $this->customerRepository, + $this->localeCurrency, + $addressMapper + ); + } + + /** + * Checks if order contains all needed data. + */ + public function testGetOrderDataJson() + { + $customerId = 1; + $storeId = 1; + $quoteId = 2; + $expected = [ + 'customer_id' => $customerId, + 'addresses' => [], + 'store_id' => $storeId, + 'currency_symbol' => '$', + 'shipping_method_reseted' => false, + 'payment_method' => 'free', + 'quote_id' => $quoteId + ]; + + $this->quoteSession->method('getCustomerId') + ->willReturn($customerId); + $this->quoteSession->method('getStoreId') + ->willReturn($storeId); + $this->quoteSession->method('getQuoteId') + ->willReturn($quoteId); + + $customer = $this->getMockBuilder(CustomerInterface::class) + ->disableOriginalConstructor() + ->getMock(); + $customer->method('getAddresses') + ->willReturn([]); + $this->customerRepository->method('getById') + ->with($customerId) + ->willReturn($customer); + + $this->withCurrencySymbol('$'); + + $this->withQuote(); + + self::assertEquals($expected, json_decode($this->block->getOrderDataJson(), true)); + } + + /** + * Configures mock object for currency. + * + * @param string $symbol + */ + private function withCurrencySymbol(string $symbol) + { + $store = $this->getMockBuilder(Store::class) + ->disableOriginalConstructor() + ->getMock(); + $store->method('getCurrentCurrencyCode') + ->willReturn('USD'); + $this->quoteSession->method('getStore') + ->willReturn($store); + + $currency = $this->getMockBuilder(Currency::class) + ->disableOriginalConstructor() + ->getMock(); + $currency->method('getSymbol') + ->willReturn($symbol); + $this->localeCurrency->method('getCurrency') + ->with('USD') + ->willReturn($currency); + } + + /** + * Configures shipping and payment mock objects. + */ + private function withQuote() + { + $quote = $this->getMockBuilder(Quote::class) + ->disableOriginalConstructor() + ->getMock(); + $this->quoteSession->method('getQuote') + ->willReturn($quote); + + $address = $this->getMockBuilder(Address::class) + ->disableOriginalConstructor() + ->getMock(); + $address->method('getShippingMethod') + ->willReturn('free'); + $quote->method('getShippingAddress') + ->willReturn($address); + + $payment = $this->getMockBuilder(Payment::class) + ->disableOriginalConstructor() + ->getMock(); + $payment->method('getMethod') + ->willReturn('free'); + $quote->method('getPayment') + ->willReturn($payment); + } +} diff --git a/app/code/Magento/Sales/Test/Unit/Controller/Adminhtml/Creditmemo/AbstractCreditmemo/EmailTest.php b/app/code/Magento/Sales/Test/Unit/Controller/Adminhtml/Creditmemo/AbstractCreditmemo/EmailTest.php index c6f1be2a88540..910164f029f1c 100644 --- a/app/code/Magento/Sales/Test/Unit/Controller/Adminhtml/Creditmemo/AbstractCreditmemo/EmailTest.php +++ b/app/code/Magento/Sales/Test/Unit/Controller/Adminhtml/Creditmemo/AbstractCreditmemo/EmailTest.php @@ -73,6 +73,9 @@ class EmailTest extends \PHPUnit\Framework\TestCase */ protected $resultRedirectMock; + /** + * Test setup + */ protected function setUp() { $objectManagerHelper = new ObjectManagerHelper($this); @@ -98,7 +101,10 @@ protected function setUp() \Magento\Framework\ObjectManager\ObjectManager::class, ['create'] ); - $this->messageManager = $this->createPartialMock(\Magento\Framework\Message\Manager::class, ['addSuccess']); + $this->messageManager = $this->createPartialMock( + \Magento\Framework\Message\Manager::class, + ['addSuccessMessage'] + ); $this->session = $this->createPartialMock(\Magento\Backend\Model\Session::class, ['setIsUrlNotice']); $this->actionFlag = $this->createPartialMock(\Magento\Framework\App\ActionFlag::class, ['get']); $this->helper = $this->createPartialMock(\Magento\Backend\Helper\Data::class, ['getUrl']); @@ -128,6 +134,9 @@ protected function setUp() ); } + /** + * testEmail + */ public function testEmail() { $cmId = 10000031; @@ -147,7 +156,7 @@ public function testEmail() ->method('notify') ->willReturn(true); $this->messageManager->expects($this->once()) - ->method('addSuccess') + ->method('addSuccessMessage') ->with('You sent the message.'); $this->assertInstanceOf( @@ -157,6 +166,9 @@ public function testEmail() $this->assertEquals($this->response, $this->creditmemoEmail->getResponse()); } + /** + * testEmailNoCreditmemoId + */ public function testEmailNoCreditmemoId() { $this->request->expects($this->once()) diff --git a/app/code/Magento/Sales/Test/Unit/Controller/Adminhtml/Invoice/AbstractInvoice/EmailTest.php b/app/code/Magento/Sales/Test/Unit/Controller/Adminhtml/Invoice/AbstractInvoice/EmailTest.php index f71d98f94a82a..8407cc251db93 100644 --- a/app/code/Magento/Sales/Test/Unit/Controller/Adminhtml/Invoice/AbstractInvoice/EmailTest.php +++ b/app/code/Magento/Sales/Test/Unit/Controller/Adminhtml/Invoice/AbstractInvoice/EmailTest.php @@ -89,6 +89,9 @@ class EmailTest extends \PHPUnit\Framework\TestCase */ protected $invoiceManagement; + /** + * Test setup + */ protected function setUp() { $objectManagerHelper = new ObjectManagerHelper($this); @@ -153,6 +156,9 @@ protected function setUp() ); } + /** + * testEmail + */ public function testEmail() { $invoiceId = 10000031; @@ -196,7 +202,7 @@ public function testEmail() ->with($invoiceId) ->willReturn(true); $this->messageManager->expects($this->once()) - ->method('addSuccess') + ->method('addSuccessMessage') ->with('You sent the message.'); $this->resultRedirectFactory->expects($this->atLeastOnce()) @@ -209,6 +215,9 @@ public function testEmail() $this->assertInstanceOf(\Magento\Backend\Model\View\Result\Redirect::class, $this->invoiceEmail->execute()); } + /** + * testEmailNoInvoiceId + */ public function testEmailNoInvoiceId() { $this->request->expects($this->once()) @@ -226,6 +235,9 @@ public function testEmailNoInvoiceId() $this->assertInstanceOf(\Magento\Backend\Model\View\Result\Forward::class, $this->invoiceEmail->execute()); } + /** + * testEmailNoInvoice + */ public function testEmailNoInvoice() { $invoiceId = 10000031; diff --git a/app/code/Magento/Sales/Test/Unit/Controller/Adminhtml/Order/CancelTest.php b/app/code/Magento/Sales/Test/Unit/Controller/Adminhtml/Order/CancelTest.php index 363f78e738f12..a368bf779398f 100644 --- a/app/code/Magento/Sales/Test/Unit/Controller/Adminhtml/Order/CancelTest.php +++ b/app/code/Magento/Sales/Test/Unit/Controller/Adminhtml/Order/CancelTest.php @@ -61,6 +61,9 @@ class CancelTest extends \PHPUnit\Framework\TestCase */ protected $objectManager; + /** + * Test setup + */ protected function setUp() { $objectManagerHelper = new ObjectManagerHelper($this); @@ -77,7 +80,7 @@ protected function setUp() ->disableOriginalConstructor()->getMock(); $this->messageManager = $this->createPartialMock( \Magento\Framework\Message\Manager::class, - ['addSuccess', 'addError'] + ['addSuccessMessage', 'addErrorMessage'] ); $this->orderRepositoryMock = $this->getMockBuilder(\Magento\Sales\Api\OrderRepositoryInterface::class) ->disableOriginalConstructor() @@ -108,6 +111,9 @@ protected function setUp() ); } + /** + * testExecuteNotPost + */ public function testExecuteNotPost() { $this->validatorMock->expects($this->once()) @@ -117,7 +123,7 @@ public function testExecuteNotPost() ->method('isPost') ->willReturn(false); $this->messageManager->expects($this->once()) - ->method('addError') + ->method('addErrorMessage') ->with('You have not canceled the item.'); $this->resultRedirect->expects($this->once()) ->method('setPath') diff --git a/app/code/Magento/Sales/Test/Unit/Controller/Adminhtml/Order/Create/ProcessDataTest.php b/app/code/Magento/Sales/Test/Unit/Controller/Adminhtml/Order/Create/ProcessDataTest.php index e818b1edbc1d7..3e22867ce1f65 100644 --- a/app/code/Magento/Sales/Test/Unit/Controller/Adminhtml/Order/Create/ProcessDataTest.php +++ b/app/code/Magento/Sales/Test/Unit/Controller/Adminhtml/Order/Create/ProcessDataTest.php @@ -63,6 +63,9 @@ class ProcessDataTest extends \PHPUnit\Framework\TestCase */ protected $resultForwardFactory; + /** + * Test setup + */ protected function setUp() { $objectManagerHelper = new ObjectManagerHelper($this); @@ -226,7 +229,11 @@ public function testExecute($noDiscount, $couponCode, $errorMessage, $actualCoup ); $this->escaper->expects($this->once())->method('escapeHtml')->with($couponCode)->willReturn($couponCode); - $this->messageManager->expects($this->once())->method('addError')->with($errorMessageManager)->willReturnSelf(); + $this->messageManager + ->expects($this->once()) + ->method('addErrorMessage') + ->with($errorMessageManager) + ->willReturnSelf(); $this->resultForward->expects($this->once()) ->method('forward') diff --git a/app/code/Magento/Sales/Test/Unit/Controller/Adminhtml/Order/Creditmemo/CancelTest.php b/app/code/Magento/Sales/Test/Unit/Controller/Adminhtml/Order/Creditmemo/CancelTest.php index af218903a3868..3e9e6af0b4181 100644 --- a/app/code/Magento/Sales/Test/Unit/Controller/Adminhtml/Order/Creditmemo/CancelTest.php +++ b/app/code/Magento/Sales/Test/Unit/Controller/Adminhtml/Order/Creditmemo/CancelTest.php @@ -292,7 +292,7 @@ public function testExecute() ->method('cancel') ->with($creditmemoId); $this->messageManagerMock->expects($this->once()) - ->method('addSuccess') + ->method('addSuccessMessage') ->with('The credit memo has been canceled.'); $this->resultRedirectFactoryMock->expects($this->once()) ->method('create') diff --git a/app/code/Magento/Sales/Test/Unit/Controller/Adminhtml/Order/Creditmemo/PrintActionTest.php b/app/code/Magento/Sales/Test/Unit/Controller/Adminhtml/Order/Creditmemo/PrintActionTest.php index 881af16f5fe69..11ccdd87a5664 100644 --- a/app/code/Magento/Sales/Test/Unit/Controller/Adminhtml/Order/Creditmemo/PrintActionTest.php +++ b/app/code/Magento/Sales/Test/Unit/Controller/Adminhtml/Order/Creditmemo/PrintActionTest.php @@ -81,6 +81,9 @@ class PrintActionTest extends \PHPUnit\Framework\TestCase */ protected $resultForwardMock; + /** + * test setup + */ protected function setUp() { $this->requestMock = $this->getMockBuilder(\Magento\Framework\App\RequestInterface::class) @@ -155,7 +158,8 @@ public function testExecute() $creditmemoId = 2; $date = '2015-01-19_13-03-45'; $fileName = 'creditmemo2015-01-19_13-03-45.pdf'; - $fileContents = 'pdf0123456789'; + $pdfContent = 'pdf0123456789'; + $fileData = ['type' => 'string', 'value' => $pdfContent, 'rm' => true]; $this->prepareTestExecute($creditmemoId); $this->objectManagerMock->expects($this->any()) @@ -184,12 +188,12 @@ public function testExecute() ->willReturn($date); $this->pdfMock->expects($this->once()) ->method('render') - ->willReturn($fileContents); + ->willReturn($pdfContent); $this->fileFactoryMock->expects($this->once()) ->method('create') ->with( $fileName, - $fileContents, + $fileData, \Magento\Framework\App\Filesystem\DirectoryList::VAR_DIR, 'application/pdf' ) diff --git a/app/code/Magento/Sales/Test/Unit/Controller/Adminhtml/Order/Creditmemo/SaveTest.php b/app/code/Magento/Sales/Test/Unit/Controller/Adminhtml/Order/Creditmemo/SaveTest.php index 490203563bb36..0112d09eb735f 100644 --- a/app/code/Magento/Sales/Test/Unit/Controller/Adminhtml/Order/Creditmemo/SaveTest.php +++ b/app/code/Magento/Sales/Test/Unit/Controller/Adminhtml/Order/Creditmemo/SaveTest.php @@ -235,7 +235,7 @@ public function testSaveActionWithNegativeCreditmemo() */ protected function _setSaveActionExpectationForMageCoreException($data, $errorMessage) { - $this->_messageManager->expects($this->once())->method('addError')->with($this->equalTo($errorMessage)); + $this->_messageManager->expects($this->once())->method('addErrorMessage')->with($this->equalTo($errorMessage)); $this->_sessionMock->expects($this->once())->method('setFormData')->with($this->equalTo($data)); } } diff --git a/app/code/Magento/Sales/Test/Unit/Controller/Adminhtml/Order/Creditmemo/VoidActionTest.php b/app/code/Magento/Sales/Test/Unit/Controller/Adminhtml/Order/Creditmemo/VoidActionTest.php index 7e0163002b437..04adb63bc88ac 100644 --- a/app/code/Magento/Sales/Test/Unit/Controller/Adminhtml/Order/Creditmemo/VoidActionTest.php +++ b/app/code/Magento/Sales/Test/Unit/Controller/Adminhtml/Order/Creditmemo/VoidActionTest.php @@ -335,7 +335,7 @@ public function testExecute() ->method('getInvoice') ->willReturn($invoiceMock); $this->messageManagerMock->expects($this->once()) - ->method('addSuccess') + ->method('addSuccessMessage') ->with('You voided the credit memo.'); $this->resultRedirectFactoryMock->expects($this->once()) ->method('create') diff --git a/app/code/Magento/Sales/Test/Unit/Controller/Adminhtml/Order/EmailTest.php b/app/code/Magento/Sales/Test/Unit/Controller/Adminhtml/Order/EmailTest.php index bb826be85850c..e9a0e573e3f9a 100644 --- a/app/code/Magento/Sales/Test/Unit/Controller/Adminhtml/Order/EmailTest.php +++ b/app/code/Magento/Sales/Test/Unit/Controller/Adminhtml/Order/EmailTest.php @@ -87,6 +87,9 @@ class EmailTest extends \PHPUnit\Framework\TestCase */ protected $orderMock; + /** + * Test setup + */ protected function setUp() { $objectManagerHelper = new ObjectManagerHelper($this); @@ -119,7 +122,7 @@ protected function setUp() ->disableOriginalConstructor()->getMock(); $this->messageManager = $this->createPartialMock( \Magento\Framework\Message\Manager::class, - ['addSuccess', 'addError'] + ['addSuccessMessage', 'addErrorMessage'] ); $this->orderMock = $this->getMockBuilder(\Magento\Sales\Api\Data\OrderInterface::class) @@ -152,6 +155,9 @@ protected function setUp() ); } + /** + * testEmail + */ public function testEmail() { $orderId = 10000031; @@ -171,7 +177,7 @@ public function testEmail() ->with($orderId) ->willReturn(true); $this->messageManager->expects($this->once()) - ->method('addSuccess') + ->method('addSuccessMessage') ->with('You sent the order email.'); $this->resultRedirect->expects($this->once()) ->method('setPath') @@ -185,6 +191,9 @@ public function testEmail() $this->assertEquals($this->response, $this->orderEmail->getResponse()); } + /** + * testEmailNoOrderId + */ public function testEmailNoOrderId() { $this->request->expects($this->once()) @@ -200,7 +209,7 @@ public function testEmailNoOrderId() ) ); $this->messageManager->expects($this->once()) - ->method('addError') + ->method('addErrorMessage') ->with('This order no longer exists.'); $this->actionFlag->expects($this->once()) diff --git a/app/code/Magento/Sales/Test/Unit/Controller/Adminhtml/Order/HoldTest.php b/app/code/Magento/Sales/Test/Unit/Controller/Adminhtml/Order/HoldTest.php index 68ce75781db78..30e25605f0b94 100644 --- a/app/code/Magento/Sales/Test/Unit/Controller/Adminhtml/Order/HoldTest.php +++ b/app/code/Magento/Sales/Test/Unit/Controller/Adminhtml/Order/HoldTest.php @@ -61,6 +61,9 @@ class HoldTest extends \PHPUnit\Framework\TestCase */ protected $objectManager; + /** + * Test setup + */ protected function setUp() { $objectManagerHelper = new ObjectManagerHelper($this); @@ -77,7 +80,7 @@ protected function setUp() ->disableOriginalConstructor()->getMock(); $this->messageManager = $this->createPartialMock( \Magento\Framework\Message\Manager::class, - ['addSuccess', 'addError'] + ['addSuccessMessage', 'addErrorMessage'] ); $this->orderRepositoryMock = $this->getMockBuilder(\Magento\Sales\Api\OrderRepositoryInterface::class) ->disableOriginalConstructor() @@ -108,6 +111,9 @@ protected function setUp() ); } + /** + * testExecuteNotPost + */ public function testExecuteNotPost() { $this->validatorMock->expects($this->once()) @@ -117,7 +123,7 @@ public function testExecuteNotPost() ->method('isPost') ->willReturn(false); $this->messageManager->expects($this->once()) - ->method('addError') + ->method('addErrorMessage') ->with('You have not put the order on hold.'); $this->resultRedirect->expects($this->once()) ->method('setPath') diff --git a/app/code/Magento/Sales/Test/Unit/Controller/Adminhtml/Order/Invoice/CancelTest.php b/app/code/Magento/Sales/Test/Unit/Controller/Adminhtml/Order/Invoice/CancelTest.php index 83b897656d185..667b6775384cf 100644 --- a/app/code/Magento/Sales/Test/Unit/Controller/Adminhtml/Order/Invoice/CancelTest.php +++ b/app/code/Magento/Sales/Test/Unit/Controller/Adminhtml/Order/Invoice/CancelTest.php @@ -213,7 +213,7 @@ public function testExecute() ->method('save'); $this->messageManagerMock->expects($this->once()) - ->method('addSuccess') + ->method('addSuccessMessage') ->with('You canceled the invoice.'); $this->invoiceRepository->expects($this->once()) @@ -295,7 +295,7 @@ public function testExecuteModelException() ->will($this->throwException($e)); $this->messageManagerMock->expects($this->once()) - ->method('addError') + ->method('addErrorMessage') ->with($message); $invoiceMock->expects($this->once()) @@ -343,7 +343,7 @@ public function testExecuteException() ->will($this->throwException($e)); $this->messageManagerMock->expects($this->once()) - ->method('addError') + ->method('addErrorMessage') ->with($message); $invoiceMock->expects($this->once()) diff --git a/app/code/Magento/Sales/Test/Unit/Controller/Adminhtml/Order/Invoice/CaptureTest.php b/app/code/Magento/Sales/Test/Unit/Controller/Adminhtml/Order/Invoice/CaptureTest.php index 0fabc24dd4421..fd53d91b9d9ea 100644 --- a/app/code/Magento/Sales/Test/Unit/Controller/Adminhtml/Order/Invoice/CaptureTest.php +++ b/app/code/Magento/Sales/Test/Unit/Controller/Adminhtml/Order/Invoice/CaptureTest.php @@ -223,7 +223,7 @@ public function testExecute() ->method('save'); $this->messageManagerMock->expects($this->once()) - ->method('addSuccess') + ->method('addSuccessMessage') ->with('The invoice has been captured.'); $invoiceMock->expects($this->once()) @@ -304,7 +304,7 @@ public function testExecuteModelException() ->getMock(); $this->messageManagerMock->expects($this->once()) - ->method('addError') + ->method('addErrorMessage') ->with($message); $invoiceMock->expects($this->once()) @@ -355,7 +355,7 @@ public function testExecuteException() ->getMock(); $this->messageManagerMock->expects($this->once()) - ->method('addError') + ->method('addErrorMessage') ->with($message); $invoiceMock->expects($this->once()) diff --git a/app/code/Magento/Sales/Test/Unit/Controller/Adminhtml/Order/Invoice/SaveTest.php b/app/code/Magento/Sales/Test/Unit/Controller/Adminhtml/Order/Invoice/SaveTest.php index 3ffa0971770b1..17dc3f42a2fe2 100644 --- a/app/code/Magento/Sales/Test/Unit/Controller/Adminhtml/Order/Invoice/SaveTest.php +++ b/app/code/Magento/Sales/Test/Unit/Controller/Adminhtml/Order/Invoice/SaveTest.php @@ -122,7 +122,7 @@ public function testExecuteNotValidPost() ->method('isPost') ->willReturn(false); $this->messageManagerMock->expects($this->once()) - ->method('addError') + ->method('addErrorMessage') ->with("The invoice can't be saved at this time. Please try again later."); $redirectMock->expects($this->once()) ->method('setPath') diff --git a/app/code/Magento/Sales/Test/Unit/Controller/Adminhtml/Order/Invoice/VoidActionTest.php b/app/code/Magento/Sales/Test/Unit/Controller/Adminhtml/Order/Invoice/VoidActionTest.php index d7766d79e9c30..0fbff061650f8 100644 --- a/app/code/Magento/Sales/Test/Unit/Controller/Adminhtml/Order/Invoice/VoidActionTest.php +++ b/app/code/Magento/Sales/Test/Unit/Controller/Adminhtml/Order/Invoice/VoidActionTest.php @@ -250,7 +250,7 @@ public function testExecute() ->will($this->returnValue($transactionMock)); $this->messageManagerMock->expects($this->once()) - ->method('addSuccess') + ->method('addSuccessMessage') ->with('The invoice has been voided.'); $resultRedirect = $this->getMockBuilder(\Magento\Backend\Model\View\Result\Redirect::class) @@ -283,9 +283,9 @@ public function testExecuteNoInvoice() ->willReturn(null); $this->messageManagerMock->expects($this->never()) - ->method('addError'); + ->method('addErrorMessage'); $this->messageManagerMock->expects($this->never()) - ->method('addSuccess'); + ->method('addSuccessMessage'); $resultForward = $this->getMockBuilder(\Magento\Backend\Model\View\Result\Forward::class) ->disableOriginalConstructor() @@ -334,7 +334,7 @@ public function testExecuteModelException() ->willReturn($invoiceMock); $this->messageManagerMock->expects($this->once()) - ->method('addError'); + ->method('addErrorMessage'); $resultRedirect = $this->getMockBuilder(\Magento\Backend\Model\View\Result\Redirect::class) ->disableOriginalConstructor() diff --git a/app/code/Magento/Sales/Test/Unit/Controller/Adminhtml/Order/MassCancelTest.php b/app/code/Magento/Sales/Test/Unit/Controller/Adminhtml/Order/MassCancelTest.php index 756bade3c83c9..38449c5686631 100644 --- a/app/code/Magento/Sales/Test/Unit/Controller/Adminhtml/Order/MassCancelTest.php +++ b/app/code/Magento/Sales/Test/Unit/Controller/Adminhtml/Order/MassCancelTest.php @@ -90,6 +90,9 @@ class MassCancelTest extends \PHPUnit\Framework\TestCase */ private $orderManagementMock; + /** + * Test setup + */ protected function setUp() { $objectManagerHelper = new ObjectManagerHelper($this); @@ -201,11 +204,11 @@ public function testExecuteCanCancelOneOrder() $this->orderManagementMock->expects($this->at(1))->method('cancel')->with($order2id)->willReturn(false); $this->messageManagerMock->expects($this->once()) - ->method('addError') + ->method('addErrorMessage') ->with('1 order(s) cannot be canceled.'); $this->messageManagerMock->expects($this->once()) - ->method('addSuccess') + ->method('addSuccessMessage') ->with('We canceled 1 order(s).'); $this->resultRedirectMock->expects($this->once()) @@ -251,7 +254,7 @@ public function testExcludedCannotCancelOrders() $this->orderManagementMock->expects($this->atLeastOnce())->method('cancel')->willReturn(false); $this->messageManagerMock->expects($this->once()) - ->method('addError') + ->method('addErrorMessage') ->with('You cannot cancel the order(s).'); $this->resultRedirectMock->expects($this->once()) @@ -283,7 +286,7 @@ public function testException() $this->orderManagementMock->expects($this->atLeastOnce())->method('cancel')->willThrowException($exception); $this->messageManagerMock->expects($this->once()) - ->method('addError') + ->method('addErrorMessage') ->with('Can not cancel'); $this->massAction->execute(); diff --git a/app/code/Magento/Sales/Test/Unit/Controller/Adminhtml/Order/MassHoldTest.php b/app/code/Magento/Sales/Test/Unit/Controller/Adminhtml/Order/MassHoldTest.php index 02ff208445596..bfd1d1e825f89 100644 --- a/app/code/Magento/Sales/Test/Unit/Controller/Adminhtml/Order/MassHoldTest.php +++ b/app/code/Magento/Sales/Test/Unit/Controller/Adminhtml/Order/MassHoldTest.php @@ -90,6 +90,9 @@ class MassHoldTest extends \PHPUnit\Framework\TestCase */ protected $orderManagementMock; + /** + * Test setup + */ protected function setUp() { $objectManagerHelper = new ObjectManagerHelper($this); @@ -166,6 +169,9 @@ protected function setUp() ); } + /** + * @throws \Magento\Framework\Exception\LocalizedException + */ public function testExecuteOneOrderPutOnHold() { $order1 = $this->getMockBuilder(\Magento\Sales\Model\Order::class) @@ -196,11 +202,11 @@ public function testExecuteOneOrderPutOnHold() ->willReturn(false); $this->messageManagerMock->expects($this->once()) - ->method('addError') + ->method('addErrorMessage') ->with('1 order(s) were not put on hold.'); $this->messageManagerMock->expects($this->once()) - ->method('addSuccess') + ->method('addSuccessMessage') ->with('You have put 1 order(s) on hold.'); $this->resultRedirectMock->expects($this->once()) @@ -211,6 +217,9 @@ public function testExecuteOneOrderPutOnHold() $this->massAction->execute(); } + /** + * @throws \Magento\Framework\Exception\LocalizedException + */ public function testExecuteNoOrdersPutOnHold() { $order1 = $this->getMockBuilder(\Magento\Sales\Model\Order::class) @@ -240,7 +249,7 @@ public function testExecuteNoOrdersPutOnHold() ->willReturn(false); $this->messageManagerMock->expects($this->once()) - ->method('addError') + ->method('addErrorMessage') ->with('No order(s) were put on hold.'); $this->resultRedirectMock->expects($this->once()) diff --git a/app/code/Magento/Sales/Test/Unit/Controller/Adminhtml/Order/MassUnholdTest.php b/app/code/Magento/Sales/Test/Unit/Controller/Adminhtml/Order/MassUnholdTest.php index cddb503925987..56473ec948f27 100644 --- a/app/code/Magento/Sales/Test/Unit/Controller/Adminhtml/Order/MassUnholdTest.php +++ b/app/code/Magento/Sales/Test/Unit/Controller/Adminhtml/Order/MassUnholdTest.php @@ -90,6 +90,9 @@ class MassUnholdTest extends \PHPUnit\Framework\TestCase */ private $orderManagementMock; + /** + * Test setup + */ protected function setUp() { $objectManagerHelper = new ObjectManagerHelper($this); @@ -164,6 +167,9 @@ protected function setUp() ); } + /** + * @throws \Magento\Framework\Exception\LocalizedException + */ public function testExecuteOneOrdersReleasedFromHold() { $order1 = $this->getMockBuilder(\Magento\Sales\Model\Order::class) @@ -196,11 +202,11 @@ public function testExecuteOneOrdersReleasedFromHold() $this->orderManagementMock->expects($this->atLeastOnce())->method('unHold')->willReturn(true); $this->messageManagerMock->expects($this->once()) - ->method('addError') + ->method('addErrorMessage') ->with('1 order(s) were not released from on hold status.'); $this->messageManagerMock->expects($this->once()) - ->method('addSuccess') + ->method('addSuccessMessage') ->with('1 order(s) have been released from on hold status.'); $this->resultRedirectMock->expects($this->once()) @@ -211,6 +217,9 @@ public function testExecuteOneOrdersReleasedFromHold() $this->massAction->execute(); } + /** + * @throws \Magento\Framework\Exception\LocalizedException + */ public function testExecuteNoReleasedOrderFromHold() { $order1 = $this->getMockBuilder(\Magento\Sales\Model\Order::class) @@ -239,7 +248,7 @@ public function testExecuteNoReleasedOrderFromHold() ->willReturn(false); $this->messageManagerMock->expects($this->once()) - ->method('addError') + ->method('addErrorMessage') ->with('No order(s) were released from on hold status.'); $this->resultRedirectMock->expects($this->once()) diff --git a/app/code/Magento/Sales/Test/Unit/Controller/Adminhtml/Order/ReviewPaymentTest.php b/app/code/Magento/Sales/Test/Unit/Controller/Adminhtml/Order/ReviewPaymentTest.php index 27bbbd4eb0043..452bde7023f9d 100644 --- a/app/code/Magento/Sales/Test/Unit/Controller/Adminhtml/Order/ReviewPaymentTest.php +++ b/app/code/Magento/Sales/Test/Unit/Controller/Adminhtml/Order/ReviewPaymentTest.php @@ -51,6 +51,9 @@ class ReviewPaymentTest extends \PHPUnit\Framework\TestCase */ protected $loggerMock; + /** + * Test setup + */ protected function setUp() { $this->contextMock = $this->createPartialMock(\Magento\Backend\App\Action\Context::class, [ @@ -75,7 +78,7 @@ protected function setUp() ->getMockForAbstractClass(); $this->messageManagerMock = $this->createPartialMock( \Magento\Framework\Message\Manager::class, - ['addSuccess', 'addError'] + ['addSuccessMessage', 'addErrorMessage'] ); $this->resultRedirectFactoryMock = $this->createPartialMock( @@ -112,6 +115,9 @@ protected function setUp() ); } + /** + * testExecuteUpdateAction + */ public function testExecuteUpdateAction() { $orderId = 30; @@ -137,7 +143,7 @@ public function testExecuteUpdateAction() $this->paymentMock->expects($this->once())->method('update'); $this->paymentMock->expects($this->any())->method('getIsTransactionApproved')->willReturn(true); - $this->messageManagerMock->expects($this->once())->method('addSuccess'); + $this->messageManagerMock->expects($this->once())->method('addSuccessMessage'); $this->resultRedirectMock->expects($this->once()) ->method('setPath') diff --git a/app/code/Magento/Sales/Test/Unit/Controller/Adminhtml/Order/UnholdTest.php b/app/code/Magento/Sales/Test/Unit/Controller/Adminhtml/Order/UnholdTest.php index 7720b7615c3fa..cc4720f1c6b44 100644 --- a/app/code/Magento/Sales/Test/Unit/Controller/Adminhtml/Order/UnholdTest.php +++ b/app/code/Magento/Sales/Test/Unit/Controller/Adminhtml/Order/UnholdTest.php @@ -61,6 +61,9 @@ class UnholdTest extends \PHPUnit\Framework\TestCase */ protected $objectManager; + /** + * Test setup + */ protected function setUp() { $objectManagerHelper = new ObjectManagerHelper($this); @@ -77,7 +80,7 @@ protected function setUp() ->disableOriginalConstructor()->getMock(); $this->messageManager = $this->createPartialMock( \Magento\Framework\Message\Manager::class, - ['addSuccess', 'addError'] + ['addSuccessMessage', 'addErrorMessage'] ); $this->orderRepositoryMock = $this->getMockBuilder(\Magento\Sales\Api\OrderRepositoryInterface::class) ->disableOriginalConstructor() @@ -108,6 +111,9 @@ protected function setUp() ); } + /** + * testExecuteNotPost + */ public function testExecuteNotPost() { $this->validatorMock->expects($this->once()) @@ -117,7 +123,7 @@ public function testExecuteNotPost() ->method('isPost') ->willReturn(false); $this->messageManager->expects($this->once()) - ->method('addError') + ->method('addErrorMessage') ->with('Can\'t unhold order.'); $this->resultRedirect->expects($this->once()) ->method('setPath') diff --git a/app/code/Magento/Sales/Test/Unit/Controller/Adminhtml/Order/ViewTest.php b/app/code/Magento/Sales/Test/Unit/Controller/Adminhtml/Order/ViewTest.php index 97b3fe630aa52..7d39aca35d2c1 100644 --- a/app/code/Magento/Sales/Test/Unit/Controller/Adminhtml/Order/ViewTest.php +++ b/app/code/Magento/Sales/Test/Unit/Controller/Adminhtml/Order/ViewTest.php @@ -98,6 +98,9 @@ class ViewTest extends \PHPUnit\Framework\TestCase */ protected $orderRepositoryMock; + /** + * Test setup + */ protected function setUp() { $this->orderManagementMock = $this->getMockBuilder(\Magento\Sales\Api\OrderManagementInterface::class) @@ -251,7 +254,7 @@ public function testGlobalException() ->method('critical') ->with($exception); $this->messageManagerMock->expects($this->once()) - ->method('addError') + ->method('addErrorMessage') ->with('Exception occurred during order load') ->willReturnSelf(); $this->setPath('sales/order/index'); @@ -262,6 +265,9 @@ public function testGlobalException() ); } + /** + * initOrder + */ protected function initOrder() { $orderIdParam = 111; @@ -289,10 +295,13 @@ protected function initOrderSuccess() ); } + /** + * initOrderFail + */ protected function initOrderFail() { $this->messageManagerMock->expects($this->once()) - ->method('addError') + ->method('addErrorMessage') ->with('This order no longer exists.') ->willReturnSelf(); $this->actionFlagMock->expects($this->once()) @@ -300,6 +309,9 @@ protected function initOrderFail() ->with('', \Magento\Sales\Controller\Adminhtml\Order::FLAG_NO_DISPATCH, true); } + /** + * initAction + */ protected function initAction() { $this->resultPageFactoryMock->expects($this->once()) @@ -318,6 +330,9 @@ protected function initAction() ->willReturnSelf(); } + /** + * prepareRedirect + */ protected function prepareRedirect() { $this->resultRedirectFactoryMock->expects($this->once()) diff --git a/app/code/Magento/Sales/Test/Unit/Controller/Adminhtml/PdfDocumentsMassActionTest.php b/app/code/Magento/Sales/Test/Unit/Controller/Adminhtml/PdfDocumentsMassActionTest.php index 0841e239429a5..bb9662b7e02d8 100644 --- a/app/code/Magento/Sales/Test/Unit/Controller/Adminhtml/PdfDocumentsMassActionTest.php +++ b/app/code/Magento/Sales/Test/Unit/Controller/Adminhtml/PdfDocumentsMassActionTest.php @@ -40,13 +40,16 @@ class PdfDocumentsMassActionTest extends \PHPUnit\Framework\TestCase */ private $filterMock; + /** + * Test setup + */ protected function setUp() { $objectManagerHelper = new ObjectManagerHelper($this); $this->messageManager = $this->createPartialMock( \Magento\Framework\Message\Manager::class, - ['addSuccess', 'addError'] + ['addSuccessMessage', 'addErrorMessage'] ); $this->orderCollectionMock = $this->createMock(\Magento\Sales\Model\ResourceModel\Order\Collection::class); @@ -80,6 +83,9 @@ protected function setUp() ); } + /** + * @throws \Magento\Framework\Exception\LocalizedException + */ public function testExecute() { $exception = new \Exception(); @@ -88,7 +94,7 @@ public function testExecute() ->method('getCollection') ->with($this->orderCollectionMock) ->willThrowException($exception); - $this->messageManager->expects($this->once())->method('addError'); + $this->messageManager->expects($this->once())->method('addErrorMessage'); $this->resultRedirect->expects($this->once())->method('setPath')->willReturnSelf(); $this->controller->execute($exception); diff --git a/app/code/Magento/Sales/Test/Unit/Model/AdminOrder/EmailSenderTest.php b/app/code/Magento/Sales/Test/Unit/Model/AdminOrder/EmailSenderTest.php index ccc0bfe309f0c..37f0f754c7074 100644 --- a/app/code/Magento/Sales/Test/Unit/Model/AdminOrder/EmailSenderTest.php +++ b/app/code/Magento/Sales/Test/Unit/Model/AdminOrder/EmailSenderTest.php @@ -34,6 +34,9 @@ class EmailSenderTest extends \PHPUnit\Framework\TestCase */ protected $orderSenderMock; + /** + * Test setup + */ protected function setUp() { $this->messageManagerMock = $this->createMock(\Magento\Framework\Message\Manager::class); @@ -44,6 +47,9 @@ protected function setUp() $this->emailSender = new EmailSender($this->messageManagerMock, $this->loggerMock, $this->orderSenderMock); } + /** + * testSendSuccess + */ public function testSendSuccess() { $this->orderSenderMock->expects($this->once()) @@ -51,13 +57,16 @@ public function testSendSuccess() $this->assertTrue($this->emailSender->send($this->orderMock)); } + /** + * testSendFailure + */ public function testSendFailure() { $this->orderSenderMock->expects($this->once()) ->method('send') ->willThrowException(new \Magento\Framework\Exception\MailException(__('test message'))); $this->messageManagerMock->expects($this->once()) - ->method('addWarning'); + ->method('addWarningMessage'); $this->loggerMock->expects($this->once()) ->method('critical'); diff --git a/app/code/Magento/Sales/view/adminhtml/layout/sales_order_creditmemo_new.xml b/app/code/Magento/Sales/view/adminhtml/layout/sales_order_creditmemo_new.xml index 0c1b395b5116d..71490553aff17 100644 --- a/app/code/Magento/Sales/view/adminhtml/layout/sales_order_creditmemo_new.xml +++ b/app/code/Magento/Sales/view/adminhtml/layout/sales_order_creditmemo_new.xml @@ -22,7 +22,6 @@ <block class="Magento\Sales\Block\Adminhtml\Items\Column\Qty" name="column_qty" template="Magento_Sales::items/column/qty.phtml" group="column"/> <block class="Magento\Sales\Block\Adminhtml\Items\Column\Name" name="column_name" template="Magento_Sales::items/column/name.phtml" group="column"/> <block class="Magento\Framework\View\Element\Text\ListText" name="order_item_extra_info"/> - <block class="Magento\Sales\Block\Adminhtml\Order\Totalbar" name="order_totalbar" template="Magento_Sales::order/totalbar.phtml"/> <block class="Magento\Sales\Block\Adminhtml\Order\Creditmemo\Totals" name="creditmemo_totals" template="Magento_Sales::order/totals.phtml"> <block class="Magento\Sales\Block\Adminhtml\Order\Creditmemo\Create\Adjustments" name="adjustments" template="Magento_Sales::order/creditmemo/create/totals/adjustments.phtml"/> <block class="Magento\Sales\Block\Adminhtml\Order\Totals\Tax" name="tax" template="Magento_Sales::order/totals/tax.phtml"/> diff --git a/app/code/Magento/Sales/view/adminhtml/layout/sales_order_creditmemo_updateqty.xml b/app/code/Magento/Sales/view/adminhtml/layout/sales_order_creditmemo_updateqty.xml index 29a61308391c6..8375bec965794 100644 --- a/app/code/Magento/Sales/view/adminhtml/layout/sales_order_creditmemo_updateqty.xml +++ b/app/code/Magento/Sales/view/adminhtml/layout/sales_order_creditmemo_updateqty.xml @@ -13,7 +13,6 @@ <block class="Magento\Sales\Block\Adminhtml\Items\Column\Qty" name="column_qty" template="Magento_Sales::items/column/qty.phtml" group="column"/> <block class="Magento\Sales\Block\Adminhtml\Items\Column\Name" name="column_name" template="Magento_Sales::items/column/name.phtml" group="column"/> <block class="Magento\Framework\View\Element\Text\ListText" name="order_item_extra_info"/> - <block class="Magento\Sales\Block\Adminhtml\Order\Totalbar" name="order_totalbar" template="Magento_Sales::order/totalbar.phtml"/> <block class="Magento\Sales\Block\Adminhtml\Order\Creditmemo\Totals" name="creditmemo_totals" template="Magento_Sales::order/totals.phtml"> <block class="Magento\Sales\Block\Adminhtml\Order\Creditmemo\Create\Adjustments" name="adjustments" template="Magento_Sales::order/creditmemo/create/totals/adjustments.phtml"/> <block class="Magento\Sales\Block\Adminhtml\Order\Totals\Tax" name="tax" template="Magento_Sales::order/totals/tax.phtml"/> diff --git a/app/code/Magento/Sales/view/adminhtml/layout/sales_order_invoice_new.xml b/app/code/Magento/Sales/view/adminhtml/layout/sales_order_invoice_new.xml index def5ebaf546cd..b589ac0ac793d 100644 --- a/app/code/Magento/Sales/view/adminhtml/layout/sales_order_invoice_new.xml +++ b/app/code/Magento/Sales/view/adminhtml/layout/sales_order_invoice_new.xml @@ -25,7 +25,6 @@ <block class="Magento\Sales\Block\Adminhtml\Items\Column\Qty" name="column_qty" template="Magento_Sales::items/column/qty.phtml" group="column"/> <block class="Magento\Sales\Block\Adminhtml\Items\Column\Name" name="column_name" template="Magento_Sales::items/column/name.phtml" group="column"/> <block class="Magento\Framework\View\Element\Text\ListText" name="order_item_extra_info"/> - <block class="Magento\Sales\Block\Adminhtml\Order\Totalbar" name="order_totalbar" template="Magento_Sales::order/totalbar.phtml"/> <block class="Magento\Sales\Block\Adminhtml\Order\Invoice\Totals" name="invoice_totals" template="Magento_Sales::order/totals.phtml"> <block class="Magento\Sales\Block\Adminhtml\Order\Totals\Tax" name="tax" template="Magento_Sales::order/totals/tax.phtml"/> </block> diff --git a/app/code/Magento/Sales/view/adminhtml/layout/sales_order_invoice_updateqty.xml b/app/code/Magento/Sales/view/adminhtml/layout/sales_order_invoice_updateqty.xml index 4df3f057f6a58..38e4cb50f4343 100644 --- a/app/code/Magento/Sales/view/adminhtml/layout/sales_order_invoice_updateqty.xml +++ b/app/code/Magento/Sales/view/adminhtml/layout/sales_order_invoice_updateqty.xml @@ -13,7 +13,6 @@ <block class="Magento\Sales\Block\Adminhtml\Items\Column\Qty" name="column_qty" template="Magento_Sales::items/column/qty.phtml" group="column"/> <block class="Magento\Sales\Block\Adminhtml\Items\Column\Name" name="column_name" template="Magento_Sales::items/column/name.phtml" group="column"/> <block class="Magento\Framework\View\Element\Text\ListText" name="order_item_extra_info"/> - <block class="Magento\Sales\Block\Adminhtml\Order\Totalbar" name="order_totalbar" template="Magento_Sales::order/totalbar.phtml"/> <block class="Magento\Sales\Block\Adminhtml\Order\Invoice\Totals" name="invoice_totals" template="Magento_Sales::order/totals.phtml"> <block class="Magento\Sales\Block\Adminhtml\Order\Totals\Tax" name="tax" template="Magento_Sales::order/totals/tax.phtml"/> </block> diff --git a/app/code/Magento/Sales/view/adminhtml/templates/order/totalbar.phtml b/app/code/Magento/Sales/view/adminhtml/templates/order/totalbar.phtml index af7dfbc4e2ab3..14025eb2dd51a 100644 --- a/app/code/Magento/Sales/view/adminhtml/templates/order/totalbar.phtml +++ b/app/code/Magento/Sales/view/adminhtml/templates/order/totalbar.phtml @@ -4,6 +4,7 @@ * See COPYING.txt for license details. */ +// @deprecated // @codingStandardsIgnoreFile $totals = $block->getTotals(); diff --git a/app/code/Magento/Sales/view/adminhtml/templates/order/totals.phtml b/app/code/Magento/Sales/view/adminhtml/templates/order/totals.phtml index d23ebac84e6c2..27b82505a11d3 100644 --- a/app/code/Magento/Sales/view/adminhtml/templates/order/totals.phtml +++ b/app/code/Magento/Sales/view/adminhtml/templates/order/totals.phtml @@ -7,14 +7,6 @@ // @codingStandardsIgnoreFile ?> -<?php /*$_source = $block->getSource(); ?> -<?php $block->setPriceDataObject($_source) ?> -<?php if ($_source): ?> -<table width="100%"> - <?= $block->getChildHtml('main') ?> - <?= $block->getChildHtml('footer') ?> -</table> -<?php endif;*/ ?> <table class="data-table admin__table-secondary order-subtotal-table"> <?php $_totals = $block->getTotals('footer')?> diff --git a/app/code/Magento/Sales/view/adminhtml/web/order/create/scripts.js b/app/code/Magento/Sales/view/adminhtml/web/order/create/scripts.js index 62bd9e27c832d..fbf5f5c1023e3 100644 --- a/app/code/Magento/Sales/view/adminhtml/web/order/create/scripts.js +++ b/app/code/Magento/Sales/view/adminhtml/web/order/create/scripts.js @@ -21,6 +21,7 @@ define([ this.loadBaseUrl = false; this.customerId = data.customer_id ? data.customer_id : false; this.storeId = data.store_id ? data.store_id : false; + this.quoteId = data['quote_id'] ? data['quote_id'] : false; this.currencyId = false; this.currencySymbol = data.currency_symbol ? data.currency_symbol : ''; this.addresses = data.addresses ? data.addresses : $H({}); diff --git a/app/code/Magento/SalesAnalytics/Test/Mftf/composer.json b/app/code/Magento/SalesAnalytics/Test/Mftf/composer.json deleted file mode 100644 index 7382a7dcc8e5a..0000000000000 --- a/app/code/Magento/SalesAnalytics/Test/Mftf/composer.json +++ /dev/null @@ -1,17 +0,0 @@ -{ - "name": "magento/functional-test-module-sales-analytics", - "description": "N/A", - "config": { - "sort-packages": true - }, - "require": { - "php": "~7.1.3||~7.2.0", - "magento/magento2-functional-testing-framework": "2.2.0", - "magento/functional-test-module-sales": "100.0.0-dev" - }, - "type": "magento2-test", - "license": [ - "OSL-3.0", - "AFL-3.0" - ] -} diff --git a/app/code/Magento/SalesInventory/Test/Mftf/composer.json b/app/code/Magento/SalesInventory/Test/Mftf/composer.json deleted file mode 100644 index 7a72dfc649780..0000000000000 --- a/app/code/Magento/SalesInventory/Test/Mftf/composer.json +++ /dev/null @@ -1,20 +0,0 @@ -{ - "name": "magento/functional-test-module-sales-inventory", - "description": "N/A", - "config": { - "sort-packages": true - }, - "require": { - "php": "~7.1.3||~7.2.0", - "magento/magento2-functional-testing-framework": "2.2.0", - "magento/functional-test-module-catalog": "100.0.0-dev", - "magento/functional-test-module-catalog-inventory": "100.0.0-dev", - "magento/functional-test-module-sales": "100.0.0-dev", - "magento/functional-test-module-store": "100.0.0-dev" - }, - "type": "magento2-test", - "license": [ - "OSL-3.0", - "AFL-3.0" - ] -} diff --git a/app/code/Magento/SalesRule/Controller/Adminhtml/Promo/Quote/Delete.php b/app/code/Magento/SalesRule/Controller/Adminhtml/Promo/Quote/Delete.php index 9adb62583985d..28993e159499b 100644 --- a/app/code/Magento/SalesRule/Controller/Adminhtml/Promo/Quote/Delete.php +++ b/app/code/Magento/SalesRule/Controller/Adminhtml/Promo/Quote/Delete.php @@ -21,13 +21,13 @@ public function execute() $model = $this->_objectManager->create(\Magento\SalesRule\Model\Rule::class); $model->load($id); $model->delete(); - $this->messageManager->addSuccess(__('You deleted the rule.')); + $this->messageManager->addSuccessMessage(__('You deleted the rule.')); $this->_redirect('sales_rule/*/'); return; } catch (\Magento\Framework\Exception\LocalizedException $e) { - $this->messageManager->addError($e->getMessage()); + $this->messageManager->addErrorMessage($e->getMessage()); } catch (\Exception $e) { - $this->messageManager->addError( + $this->messageManager->addErrorMessage( __('We can\'t delete the rule right now. Please review the log and try again.') ); $this->_objectManager->get(\Psr\Log\LoggerInterface::class)->critical($e); @@ -35,7 +35,7 @@ public function execute() return; } } - $this->messageManager->addError(__('We can\'t find a rule to delete.')); + $this->messageManager->addErrorMessage(__('We can\'t find a rule to delete.')); $this->_redirect('sales_rule/*/'); } } diff --git a/app/code/Magento/SalesRule/Controller/Adminhtml/Promo/Quote/Edit.php b/app/code/Magento/SalesRule/Controller/Adminhtml/Promo/Quote/Edit.php index 7221f49b852d3..717c71fde4837 100644 --- a/app/code/Magento/SalesRule/Controller/Adminhtml/Promo/Quote/Edit.php +++ b/app/code/Magento/SalesRule/Controller/Adminhtml/Promo/Quote/Edit.php @@ -51,7 +51,7 @@ public function execute() if ($id) { $model->load($id); if (!$model->getRuleId()) { - $this->messageManager->addError(__('This rule no longer exists.')); + $this->messageManager->addErrorMessage(__('This rule no longer exists.')); $this->_redirect('sales_rule/*'); return; } diff --git a/app/code/Magento/SalesRule/Controller/Adminhtml/Promo/Quote/Generate.php b/app/code/Magento/SalesRule/Controller/Adminhtml/Promo/Quote/Generate.php index 297db7d96939d..12d34b8320d07 100644 --- a/app/code/Magento/SalesRule/Controller/Adminhtml/Promo/Quote/Generate.php +++ b/app/code/Magento/SalesRule/Controller/Adminhtml/Promo/Quote/Generate.php @@ -64,7 +64,7 @@ public function execute() $couponCodes = $this->couponGenerator->generateCodes($data); $generated = count($couponCodes); - $this->messageManager->addSuccess(__('%1 coupon(s) have been generated.', $generated)); + $this->messageManager->addSuccessMessage(__('%1 coupon(s) have been generated.', $generated)); $this->_view->getLayout()->initMessages(); $result['messages'] = $this->_view->getLayout()->getMessagesBlock()->getGroupedHtml(); } catch (\Magento\Framework\Exception\InputException $inputException) { diff --git a/app/code/Magento/SalesRule/Controller/Adminhtml/Promo/Quote/Save.php b/app/code/Magento/SalesRule/Controller/Adminhtml/Promo/Quote/Save.php index f28b245ee04ab..a5b71130e70eb 100644 --- a/app/code/Magento/SalesRule/Controller/Adminhtml/Promo/Quote/Save.php +++ b/app/code/Magento/SalesRule/Controller/Adminhtml/Promo/Quote/Save.php @@ -50,7 +50,7 @@ public function execute() $validateResult = $model->validateData(new \Magento\Framework\DataObject($data)); if ($validateResult !== true) { foreach ($validateResult as $errorMessage) { - $this->messageManager->addError($errorMessage); + $this->messageManager->addErrorMessage($errorMessage); } $session->setPageData($data); $this->_redirect('sales_rule/*/edit', ['id' => $model->getId()]); @@ -82,7 +82,7 @@ public function execute() $session->setPageData($model->getData()); $model->save(); - $this->messageManager->addSuccess(__('You saved the rule.')); + $this->messageManager->addSuccessMessage(__('You saved the rule.')); $session->setPageData(false); if ($this->getRequest()->getParam('back')) { $this->_redirect('sales_rule/*/edit', ['id' => $model->getId()]); @@ -91,7 +91,7 @@ public function execute() $this->_redirect('sales_rule/*/'); return; } catch (\Magento\Framework\Exception\LocalizedException $e) { - $this->messageManager->addError($e->getMessage()); + $this->messageManager->addErrorMessage($e->getMessage()); $id = (int)$this->getRequest()->getParam('rule_id'); if (!empty($id)) { $this->_redirect('sales_rule/*/edit', ['id' => $id]); @@ -100,7 +100,7 @@ public function execute() } return; } catch (\Exception $e) { - $this->messageManager->addError( + $this->messageManager->addErrorMessage( __('Something went wrong while saving the rule data. Please review the error log.') ); $this->_objectManager->get(\Psr\Log\LoggerInterface::class)->critical($e); diff --git a/app/code/Magento/SalesRule/Model/ResourceModel/Rule/Collection.php b/app/code/Magento/SalesRule/Model/ResourceModel/Rule/Collection.php index 54b50dbdf38db..59f24fa8b6e03 100644 --- a/app/code/Magento/SalesRule/Model/ResourceModel/Rule/Collection.php +++ b/app/code/Magento/SalesRule/Model/ResourceModel/Rule/Collection.php @@ -6,6 +6,7 @@ namespace Magento\SalesRule\Model\ResourceModel\Rule; +use Magento\Framework\DB\Select; use Magento\Framework\Serialize\Serializer\Json; use Magento\Quote\Model\Quote\Address; @@ -209,7 +210,9 @@ public function setValidationFilter( $andWhereCondition = implode(' AND ', $andWhereConditions); $select->where( - $noCouponWhereCondition . ' OR ((' . $orWhereCondition . ') AND ' . $andWhereCondition . ')' + $noCouponWhereCondition . ' OR ((' . $orWhereCondition . ') AND ' . $andWhereCondition . ')', + null, + Select::TYPE_CONDITION ); } else { $this->addFieldToFilter( @@ -320,7 +323,7 @@ public function addAttributeInConditionFilter($attributeCode) $this->getSelect()->where( sprintf('(%s OR %s)', $cCond, $aCond), null, - \Magento\Framework\DB\Select::TYPE_CONDITION + Select::TYPE_CONDITION ); return $this; diff --git a/app/code/Magento/SalesRule/Model/Rule/Condition/Product.php b/app/code/Magento/SalesRule/Model/Rule/Condition/Product.php index 499e35db9dfd6..d2e7cabe473f4 100644 --- a/app/code/Magento/SalesRule/Model/Rule/Condition/Product.php +++ b/app/code/Magento/SalesRule/Model/Rule/Condition/Product.php @@ -3,6 +3,7 @@ * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ + namespace Magento\SalesRule\Model\Rule\Condition; /** @@ -51,10 +52,17 @@ public function validate(\Magento\Framework\Model\AbstractModel $model) $attrCode = $this->getAttribute(); - if ('category_ids' == $attrCode) { + if ($attrCode === 'category_ids') { return $this->validateAttribute($this->_getAvailableInCategories($product->getId())); } + if ($attrCode === 'quote_item_price') { + $numericOperations = $this->getDefaultOperatorInputByType()['numeric']; + if (in_array($this->getOperator(), $numericOperations)) { + $this->setData('value', $this->getFormattedPrice($this->getValue())); + } + } + return parent::validate($product); } @@ -79,4 +87,23 @@ public function getValueElementChooserUrl() } return $url !== false ? $this->_backendData->getUrl($url) : ''; } + + /** + * @param string $value + * @return float|null + */ + private function getFormattedPrice($value) + { + $value = preg_replace('/[^0-9^\^.,-]/m', '', $value); + + /** + * If the comma is the third symbol in the number, we consider it to be a decimal separator + */ + $separatorComa = strpos($value, ','); + $separatorDot = strpos($value, '.'); + if ($separatorComa !== false && $separatorDot === false && preg_match('/,\d{3}$/m', $value) === 1) { + $value .= '.00'; + } + return $this->_localeFormat->getNumber($value); + } } diff --git a/app/code/Magento/SalesRule/Model/Utility.php b/app/code/Magento/SalesRule/Model/Utility.php index a3876a9d7e046..45c5dc3da0ebd 100644 --- a/app/code/Magento/SalesRule/Model/Utility.php +++ b/app/code/Magento/SalesRule/Model/Utility.php @@ -189,6 +189,8 @@ public function deltaRoundingFix( ) { $discountAmount = $discountData->getAmount(); $baseDiscountAmount = $discountData->getBaseAmount(); + $rowTotalInclTax = $item->getRowTotalInclTax(); + $baseRowTotalInclTax = $item->getBaseRowTotalInclTax(); //TODO Seems \Magento\Quote\Model\Quote\Item\AbstractItem::getDiscountPercent() returns float value //that can not be used as array index @@ -205,6 +207,23 @@ public function deltaRoundingFix( - $this->priceCurrency->round($baseDiscountAmount); } + /** + * When we have 100% discount check if totals will not be negative + */ + + if ($percentKey == 100) { + $discountDelta = $rowTotalInclTax - $discountAmount; + $baseDiscountDelta = $baseRowTotalInclTax - $baseDiscountAmount; + + if ($discountDelta < 0) { + $discountAmount += $discountDelta; + } + + if ($baseDiscountDelta < 0) { + $baseDiscountAmount += $baseDiscountDelta; + } + } + $discountData->setAmount($this->priceCurrency->round($discountAmount)); $discountData->setBaseAmount($this->priceCurrency->round($baseDiscountAmount)); diff --git a/app/code/Magento/SalesRule/Observer/CheckSalesRulesAvailability.php b/app/code/Magento/SalesRule/Observer/CheckSalesRulesAvailability.php index 4b66d2b98642c..f2819a06fe1bf 100644 --- a/app/code/Magento/SalesRule/Observer/CheckSalesRulesAvailability.php +++ b/app/code/Magento/SalesRule/Observer/CheckSalesRulesAvailability.php @@ -54,7 +54,7 @@ public function checkSalesRulesAvailability($attributeCode) } if ($disabledRulesCount) { - $this->messageManager->addWarning( + $this->messageManager->addWarningMessage( __( '%1 Cart Price Rules based on "%2" attribute have been disabled.', $disabledRulesCount, diff --git a/app/code/Magento/SalesRule/Test/Mftf/composer.json b/app/code/Magento/SalesRule/Test/Mftf/composer.json deleted file mode 100644 index 8839051a0848e..0000000000000 --- a/app/code/Magento/SalesRule/Test/Mftf/composer.json +++ /dev/null @@ -1,35 +0,0 @@ -{ - "name": "magento/functional-test-module-sales-rule", - "description": "N/A", - "config": { - "sort-packages": true - }, - "require": { - "php": "~7.1.3||~7.2.0", - "magento/magento2-functional-testing-framework": "2.2.0", - "magento/functional-test-module-backend": "100.0.0-dev", - "magento/functional-test-module-catalog": "100.0.0-dev", - "magento/functional-test-module-catalog-rule": "100.0.0-dev", - "magento/functional-test-module-config": "100.0.0-dev", - "magento/functional-test-module-customer": "100.0.0-dev", - "magento/functional-test-module-directory": "100.0.0-dev", - "magento/functional-test-module-eav": "100.0.0-dev", - "magento/functional-test-module-payment": "100.0.0-dev", - "magento/functional-test-module-quote": "100.0.0-dev", - "magento/functional-test-module-reports": "100.0.0-dev", - "magento/functional-test-module-rule": "100.0.0-dev", - "magento/functional-test-module-sales": "100.0.0-dev", - "magento/functional-test-module-shipping": "100.0.0-dev", - "magento/functional-test-module-store": "100.0.0-dev", - "magento/functional-test-module-ui": "100.0.0-dev", - "magento/functional-test-module-widget": "100.0.0-dev" - }, - "suggest": { - "magento/functional-test-module-sales-rule-sample-data": "100.0.0-dev" - }, - "type": "magento2-test", - "license": [ - "OSL-3.0", - "AFL-3.0" - ] -} diff --git a/app/code/Magento/SalesRule/Test/Unit/Controller/Adminhtml/Promo/Quote/GenerateTest.php b/app/code/Magento/SalesRule/Test/Unit/Controller/Adminhtml/Promo/Quote/GenerateTest.php index 8bcffcab9ca0a..2ef77d72a8af5 100644 --- a/app/code/Magento/SalesRule/Test/Unit/Controller/Adminhtml/Promo/Quote/GenerateTest.php +++ b/app/code/Magento/SalesRule/Test/Unit/Controller/Adminhtml/Promo/Quote/GenerateTest.php @@ -50,6 +50,9 @@ class GenerateTest extends \PHPUnit\Framework\TestCase /** @var CouponGenerator | \PHPUnit_Framework_MockObject_MockObject */ private $couponGenerator; + /** + * Test setup + */ protected function setUp() { $this->contextMock = $this->getMockBuilder(\Magento\Backend\App\Action\Context::class) @@ -109,6 +112,9 @@ protected function setUp() ); } + /** + * testExecute + */ public function testExecute() { $helperData = $this->getMockBuilder(\Magento\Framework\Json\Helper\Data::class) @@ -143,7 +149,7 @@ public function testExecute() ->with($requestData) ->willReturn(['some_data', 'some_data_2']); $this->messageManager->expects($this->once()) - ->method('addSuccess'); + ->method('addSuccessMessage'); $this->responseMock->expects($this->once()) ->method('representJson') ->with(); diff --git a/app/code/Magento/SalesRule/Test/Unit/Model/Rule/Condition/ProductTest.php b/app/code/Magento/SalesRule/Test/Unit/Model/Rule/Condition/ProductTest.php index 0bce282747b16..51c7b9ede5aa2 100644 --- a/app/code/Magento/SalesRule/Test/Unit/Model/Rule/Condition/ProductTest.php +++ b/app/code/Magento/SalesRule/Test/Unit/Model/Rule/Condition/ProductTest.php @@ -3,11 +3,15 @@ * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ + namespace Magento\SalesRule\Test\Unit\Model\Rule\Condition; +use Magento\Directory\Model\CurrencyFactory; +use Magento\Framework\App\ScopeResolverInterface; use \Magento\Framework\DB\Adapter\AdapterInterface; use \Magento\Framework\DB\Select; -use \Magento\Framework\Model\AbstractModel; +use Magento\Framework\Locale\Format; +use Magento\Framework\Locale\ResolverInterface; use Magento\Quote\Model\Quote\Item\AbstractItem; use \Magento\Rule\Model\Condition\Context; use \Magento\Backend\Helper\Data; @@ -50,8 +54,8 @@ class ProductTest extends \PHPUnit\Framework\TestCase /** @var Collection|\PHPUnit_Framework_MockObject_MockObject */ protected $collectionMock; - /** @var FormatInterface|\PHPUnit_Framework_MockObject_MockObject */ - protected $formatMock; + /** @var FormatInterface */ + protected $format; /** @var AttributeLoaderInterface|\PHPUnit_Framework_MockObject_MockObject */ protected $attributeLoaderInterfaceMock; @@ -130,8 +134,12 @@ protected function setUp() $this->collectionMock = $this->getMockBuilder(Collection::class) ->disableOriginalConstructor() ->getMock(); - $this->formatMock = $this->getMockBuilder(FormatInterface::class) - ->getMockForAbstractClass(); + $this->format = new Format( + $this->getMockBuilder(ScopeResolverInterface::class)->disableOriginalConstructor()->getMock(), + $this->getMockBuilder(ResolverInterface::class)->disableOriginalConstructor()->getMock(), + $this->getMockBuilder(CurrencyFactory::class)->disableOriginalConstructor()->getMock() + ); + $this->model = new SalesRuleProduct( $this->contextMock, $this->backendHelperMock, @@ -140,7 +148,7 @@ protected function setUp() $this->productRepositoryMock, $this->productMock, $this->collectionMock, - $this->formatMock + $this->format ); } @@ -199,7 +207,10 @@ public function testGetValueElementChooserUrl($attribute, $url, $jsObject = '') $this->assertEquals($url, $this->model->getValueElementChooserUrl()); } - public function testValidateCategoriesIgnoresVisibility() + /** + * test ValidateCategoriesIgnoresVisibility + */ + public function testValidateCategoriesIgnoresVisibility(): void { /* @var \Magento\Catalog\Model\Product|\PHPUnit_Framework_MockObject_MockObject $product */ $product = $this->getMockBuilder(\Magento\Catalog\Model\Product::class) @@ -231,4 +242,81 @@ public function testValidateCategoriesIgnoresVisibility() $this->model->validate($item); } + + /** + * @param boolean $isValid + * @param string $conditionValue + * @param string $operator + * @param double $productPrice + * @dataProvider localisationProvider + */ + public function testQuoteLocaleFormatPrice($isValid, $conditionValue, $operator = '>=', $productPrice = 2000.00) + { + $attr = $this->getMockBuilder(\Magento\Framework\Model\ResourceModel\Db\AbstractDb::class) + ->disableOriginalConstructor() + ->setMethods(['getAttribute']) + ->getMockForAbstractClass(); + + $attr->expects($this->any()) + ->method('getAttribute') + ->willReturn(''); + + /* @var \Magento\Catalog\Model\Product|\PHPUnit_Framework_MockObject_MockObject $product */ + $product = $this->getMockBuilder(\Magento\Catalog\Model\Product::class) + ->disableOriginalConstructor() + ->setMethods(['setQuoteItemPrice', 'getResource', 'hasData', 'getData',]) + ->getMock(); + + $product->expects($this->any()) + ->method('setQuoteItemPrice') + ->willReturnSelf(); + + $product->expects($this->any()) + ->method('getResource') + ->willReturn($attr); + + $product->expects($this->any()) + ->method('hasData') + ->willReturn(true); + + $product->expects($this->any()) + ->method('getData') + ->with('quote_item_price') + ->willReturn($productPrice); + + /* @var AbstractItem|\PHPUnit_Framework_MockObject_MockObject $item */ + $item = $this->getMockBuilder(AbstractItem::class) + ->disableOriginalConstructor() + ->setMethods(['getPrice', 'getProduct',]) + ->getMockForAbstractClass(); + + $item->expects($this->any()) + ->method('getPrice') + ->willReturn($productPrice); + + $item->expects($this->any()) + ->method('getProduct') + ->willReturn($product); + + $this->model->setAttribute('quote_item_price') + ->setOperator($operator); + + $this->assertEquals($isValid, $this->model->setValue($conditionValue)->validate($item)); + } + + /** + * DataProvider for testQuoteLocaleFormatPrice + * + * @return array + */ + public function localisationProvider(): array + { + return [ + 'number' => [true, 500.01], + 'locale' => [true, '1,500.03'], + 'operation' => [true, '1,500.03', '!='], + 'stringOperation' => [false, '1,500.03', '{}'], + 'smallPrice' => [false, '1,500.03', '>=', 1000], + ]; + } } diff --git a/app/code/Magento/SalesSequence/Test/Mftf/composer.json b/app/code/Magento/SalesSequence/Test/Mftf/composer.json deleted file mode 100644 index 5649df3b7e0ea..0000000000000 --- a/app/code/Magento/SalesSequence/Test/Mftf/composer.json +++ /dev/null @@ -1,16 +0,0 @@ -{ - "name": "magento/functional-test-module-sales-sequence", - "description": "N/A", - "config": { - "sort-packages": true - }, - "require": { - "php": "~7.1.3||~7.2.0", - "magento/magento2-functional-testing-framework": "2.2.0" - }, - "type": "magento2-test", - "license": [ - "OSL-3.0", - "AFL-3.0" - ] -} diff --git a/app/code/Magento/SampleData/Test/Mftf/composer.json b/app/code/Magento/SampleData/Test/Mftf/composer.json deleted file mode 100644 index 039b87fa858b5..0000000000000 --- a/app/code/Magento/SampleData/Test/Mftf/composer.json +++ /dev/null @@ -1,19 +0,0 @@ -{ - "name": "magento/functional-test-module-sample-data", - "description": "Sample Data fixtures", - "config": { - "sort-packages": true - }, - "require": { - "php": "~7.1.3||~7.2.0", - "magento/magento2-functional-testing-framework": "2.2.0" - }, - "suggest": { - "magento/sample-data-media": "100.0.0-dev" - }, - "type": "magento2-test", - "license": [ - "OSL-3.0", - "AFL-3.0" - ] -} diff --git a/app/code/Magento/Search/Block/Adminhtml/Dashboard/Last.php b/app/code/Magento/Search/Block/Adminhtml/Dashboard/Last.php index 03c298b23a43e..5ead8437f943a 100644 --- a/app/code/Magento/Search/Block/Adminhtml/Dashboard/Last.php +++ b/app/code/Magento/Search/Block/Adminhtml/Dashboard/Last.php @@ -63,6 +63,7 @@ protected function _construct() /** * @return $this + * @throws \Magento\Framework\Exception\LocalizedException */ protected function _prepareCollection() { @@ -86,6 +87,7 @@ protected function _prepareCollection() /** * @return $this + * @throws \Exception */ protected function _prepareColumns() { @@ -118,7 +120,7 @@ protected function _prepareColumns() } /** - * {@inheritdoc} + * @inheritdoc */ public function getRowUrl($row) { diff --git a/app/code/Magento/Search/Block/Adminhtml/Term/Edit/Form.php b/app/code/Magento/Search/Block/Adminhtml/Term/Edit/Form.php index 9019a127c5b64..18d6d2cf54c3a 100644 --- a/app/code/Magento/Search/Block/Adminhtml/Term/Edit/Form.php +++ b/app/code/Magento/Search/Block/Adminhtml/Term/Edit/Form.php @@ -51,6 +51,8 @@ protected function _construct() * Prepare form fields * * @return $this + * @throws \Magento\Framework\Exception\LocalizedException + * @throws \Magento\Framework\Exception\NoSuchEntityException * @SuppressWarnings(PHPMD.ExcessiveMethodLength) */ protected function _prepareForm() diff --git a/app/code/Magento/Search/Block/Term.php b/app/code/Magento/Search/Block/Term.php index e6c5c2b82ab5e..b27ef6b01fda2 100644 --- a/app/code/Magento/Search/Block/Term.php +++ b/app/code/Magento/Search/Block/Term.php @@ -71,6 +71,7 @@ public function __construct( * Load terms and try to sort it by names * * @return $this + * @throws \Magento\Framework\Exception\NoSuchEntityException */ protected function _loadTerms() { @@ -109,6 +110,7 @@ protected function _loadTerms() /** * @return array + * @throws \Magento\Framework\Exception\NoSuchEntityException */ public function getTerms() { diff --git a/app/code/Magento/Search/Controller/Adminhtml/Synonyms/Delete.php b/app/code/Magento/Search/Controller/Adminhtml/Synonyms/Delete.php index bb476423692d1..9d8b612cefadf 100644 --- a/app/code/Magento/Search/Controller/Adminhtml/Synonyms/Delete.php +++ b/app/code/Magento/Search/Controller/Adminhtml/Synonyms/Delete.php @@ -60,16 +60,18 @@ public function execute() /** @var \Magento\Search\Model\SynonymGroup $synGroupModel */ $synGroupModel = $this->synGroupRepository->get($id); $this->synGroupRepository->delete($synGroupModel); - $this->messageManager->addSuccess(__('The synonym group has been deleted.')); + $this->messageManager->addSuccessMessage(__('The synonym group has been deleted.')); } catch (\Magento\Framework\Exception\LocalizedException $e) { - $this->messageManager->addError($e->getMessage()); + $this->messageManager->addErrorMessage($e->getMessage()); $this->logger->error($e); } catch (\Exception $e) { - $this->messageManager->addError(__('An error was encountered while performing delete operation.')); + $this->messageManager->addErrorMessage( + __('An error was encountered while performing delete operation.') + ); $this->logger->error($e); } } else { - $this->messageManager->addError(__('We can\'t find a synonym group to delete.')); + $this->messageManager->addErrorMessage(__('We can\'t find a synonym group to delete.')); } return $resultRedirect->setPath('*/*/'); diff --git a/app/code/Magento/Search/Controller/Adminhtml/Synonyms/Edit.php b/app/code/Magento/Search/Controller/Adminhtml/Synonyms/Edit.php index 506976247327f..adc4ecc52030a 100644 --- a/app/code/Magento/Search/Controller/Adminhtml/Synonyms/Edit.php +++ b/app/code/Magento/Search/Controller/Adminhtml/Synonyms/Edit.php @@ -34,7 +34,6 @@ class Edit extends \Magento\Backend\App\Action * Edit constructor. * * @param \Magento\Backend\App\Action\Context $context - * @param \Magento\Backend\Model\Session $session * @param \Magento\Framework\Registry $registry * @param \Magento\Search\Controller\Adminhtml\Synonyms\ResultPageBuilder $pageBuilder * @param \Magento\Search\Api\SynonymGroupRepositoryInterface $synGroupRepository @@ -66,7 +65,7 @@ public function execute() // 2. Initial checking if ($groupId && (!$synGroup->getGroupId())) { - $this->messageManager->addError(__('This synonyms group no longer exists.')); + $this->messageManager->addErrorMessage(__('This synonyms group no longer exists.')); /** @var \Magento\Backend\Model\View\Result\Redirect $resultRedirect */ $resultRedirect = $this->resultRedirectFactory->create(); return $resultRedirect->setPath('*/*/'); diff --git a/app/code/Magento/Search/Controller/Adminhtml/Synonyms/MassDelete.php b/app/code/Magento/Search/Controller/Adminhtml/Synonyms/MassDelete.php index 4add418d95325..f2770f77cc533 100644 --- a/app/code/Magento/Search/Controller/Adminhtml/Synonyms/MassDelete.php +++ b/app/code/Magento/Search/Controller/Adminhtml/Synonyms/MassDelete.php @@ -72,17 +72,17 @@ public function execute() $this->synGroupRepository->delete($synonymGroup); $deletedItems++; } catch (\Exception $e) { - $this->messageManager->addError($e->getMessage()); + $this->messageManager->addErrorMessage($e->getMessage()); } } if ($deletedItems != 0) { if ($collectionSize != $deletedItems) { - $this->messageManager->addError( + $this->messageManager->addErrorMessage( __('Failed to delete %1 synonym group(s).', $collectionSize - $deletedItems) ); } - $this->messageManager->addSuccess( + $this->messageManager->addSuccessMessage( __('A total of %1 synonym group(s) have been deleted.', $deletedItems) ); } diff --git a/app/code/Magento/Search/Controller/Adminhtml/Synonyms/Save.php b/app/code/Magento/Search/Controller/Adminhtml/Synonyms/Save.php index ffa97ceb3e0e1..0ed73fd0cee32 100644 --- a/app/code/Magento/Search/Controller/Adminhtml/Synonyms/Save.php +++ b/app/code/Magento/Search/Controller/Adminhtml/Synonyms/Save.php @@ -59,7 +59,7 @@ public function execute() $synGroup = $this->synGroupRepository->get($synGroupId); if (!$synGroup->getGroupId() && $synGroupId) { - $this->messageManager->addError(__('This synonym group no longer exists.')); + $this->messageManager->addErrorMessage(__('This synonym group no longer exists.')); return $resultRedirect->setPath('*/*/'); } diff --git a/app/code/Magento/Search/Controller/Adminhtml/Term/Delete.php b/app/code/Magento/Search/Controller/Adminhtml/Term/Delete.php index 3a1b80df2ea7e..c7adf32da0fb0 100644 --- a/app/code/Magento/Search/Controller/Adminhtml/Term/Delete.php +++ b/app/code/Magento/Search/Controller/Adminhtml/Term/Delete.php @@ -23,16 +23,16 @@ public function execute() $model = $this->_objectManager->create(\Magento\Search\Model\Query::class); $model->setId($id); $model->delete(); - $this->messageManager->addSuccess(__('You deleted the search.')); + $this->messageManager->addSuccessMessage(__('You deleted the search.')); $resultRedirect->setPath('search/*/'); return $resultRedirect; } catch (\Exception $e) { - $this->messageManager->addError($e->getMessage()); + $this->messageManager->addErrorMessage($e->getMessage()); $resultRedirect->setPath('search/*/edit', ['id' => $this->getRequest()->getParam('id')]); return $resultRedirect; } } - $this->messageManager->addError(__('We can\'t find a search term to delete.')); + $this->messageManager->addErrorMessage(__('We can\'t find a search term to delete.')); $resultRedirect->setPath('search/*/'); return $resultRedirect; } diff --git a/app/code/Magento/Search/Controller/Adminhtml/Term/Edit.php b/app/code/Magento/Search/Controller/Adminhtml/Term/Edit.php index 85e14ae9fe0b0..3ee0ea240377f 100644 --- a/app/code/Magento/Search/Controller/Adminhtml/Term/Edit.php +++ b/app/code/Magento/Search/Controller/Adminhtml/Term/Edit.php @@ -43,7 +43,7 @@ public function execute() if ($id) { $model->load($id); if (!$model->getId()) { - $this->messageManager->addError(__('This search no longer exists.')); + $this->messageManager->addErrorMessage(__('This search no longer exists.')); /** @var \Magento\Backend\Model\View\Result\Redirect $resultRedirect */ $resultRedirect = $this->resultFactory->create(ResultFactory::TYPE_REDIRECT); $resultRedirect->setPath('search/*'); diff --git a/app/code/Magento/Search/Controller/Adminhtml/Term/ExportSearchCsv.php b/app/code/Magento/Search/Controller/Adminhtml/Term/ExportSearchCsv.php index 75173381b5239..128fa1c6c687c 100644 --- a/app/code/Magento/Search/Controller/Adminhtml/Term/ExportSearchCsv.php +++ b/app/code/Magento/Search/Controller/Adminhtml/Term/ExportSearchCsv.php @@ -34,6 +34,7 @@ public function __construct( * Export search report grid to CSV format * * @return \Magento\Framework\App\ResponseInterface + * @throws \Exception */ public function execute() { diff --git a/app/code/Magento/Search/Controller/Adminhtml/Term/ExportSearchExcel.php b/app/code/Magento/Search/Controller/Adminhtml/Term/ExportSearchExcel.php index e3859bc5aefd2..d7e2b02bc5249 100644 --- a/app/code/Magento/Search/Controller/Adminhtml/Term/ExportSearchExcel.php +++ b/app/code/Magento/Search/Controller/Adminhtml/Term/ExportSearchExcel.php @@ -34,6 +34,7 @@ public function __construct( * Export search report to Excel XML format * * @return \Magento\Framework\App\ResponseInterface + * @throws \Exception */ public function execute() { diff --git a/app/code/Magento/Search/Controller/Adminhtml/Term/MassDelete.php b/app/code/Magento/Search/Controller/Adminhtml/Term/MassDelete.php index b38d883b8faae..f6874078f2f64 100644 --- a/app/code/Magento/Search/Controller/Adminhtml/Term/MassDelete.php +++ b/app/code/Magento/Search/Controller/Adminhtml/Term/MassDelete.php @@ -17,16 +17,16 @@ public function execute() { $searchIds = $this->getRequest()->getParam('search'); if (!is_array($searchIds)) { - $this->messageManager->addError(__('Please select searches.')); + $this->messageManager->addErrorMessage(__('Please select searches.')); } else { try { foreach ($searchIds as $searchId) { $model = $this->_objectManager->create(\Magento\Search\Model\Query::class)->load($searchId); $model->delete(); } - $this->messageManager->addSuccess(__('Total of %1 record(s) were deleted.', count($searchIds))); + $this->messageManager->addSuccessMessage(__('Total of %1 record(s) were deleted.', count($searchIds))); } catch (\Exception $e) { - $this->messageManager->addError($e->getMessage()); + $this->messageManager->addErrorMessage($e->getMessage()); } } /** @var \Magento\Backend\Model\View\Result\Redirect $resultRedirect */ diff --git a/app/code/Magento/Search/Controller/Adminhtml/Term/Save.php b/app/code/Magento/Search/Controller/Adminhtml/Term/Save.php index 42e9373a20fe2..cd9b1347ed1ed 100644 --- a/app/code/Magento/Search/Controller/Adminhtml/Term/Save.php +++ b/app/code/Magento/Search/Controller/Adminhtml/Term/Save.php @@ -45,12 +45,15 @@ public function execute() $model->addData($data); $model->setIsProcessed(0); $model->save(); - $this->messageManager->addSuccess(__('You saved the search term.')); + $this->messageManager->addSuccessMessage(__('You saved the search term.')); } catch (LocalizedException $e) { - $this->messageManager->addError($e->getMessage()); + $this->messageManager->addErrorMessage($e->getMessage()); return $this->proceedToEdit($data); } catch (\Exception $e) { - $this->messageManager->addException($e, __('Something went wrong while saving the search query.')); + $this->messageManager->addExceptionMessage( + $e, + __('Something went wrong while saving the search query.') + ); return $this->proceedToEdit($data); } } diff --git a/app/code/Magento/Search/Controller/Term/Popular.php b/app/code/Magento/Search/Controller/Term/Popular.php index acc1ce324567e..0573fe6a81a12 100644 --- a/app/code/Magento/Search/Controller/Term/Popular.php +++ b/app/code/Magento/Search/Controller/Term/Popular.php @@ -34,6 +34,7 @@ public function __construct(Context $context, ScopeConfigInterface $scopeConfig) * * @param \Magento\Framework\App\RequestInterface $request * @return \Magento\Framework\App\ResponseInterface + * @throws \Magento\Framework\Exception\NotFoundException */ public function dispatch(RequestInterface $request) { diff --git a/app/code/Magento/Search/Model/Query.php b/app/code/Magento/Search/Model/Query.php index 404d93f76da6d..365e03b3648a7 100644 --- a/app/code/Magento/Search/Model/Query.php +++ b/app/code/Magento/Search/Model/Query.php @@ -147,6 +147,7 @@ public function getSearchCollection() * Retrieve collection of suggest queries * * @return QueryCollection + * @throws \Magento\Framework\Exception\NoSuchEntityException */ public function getSuggestCollection() { @@ -167,6 +168,7 @@ public function getSuggestCollection() * * @param string $text * @return $this + * @throws \Magento\Framework\Exception\LocalizedException * @deprecated 100.1.0 "synonym for" feature has been removed */ public function loadByQuery($text) @@ -180,6 +182,7 @@ public function loadByQuery($text) * * @param string $text * @return $this + * @throws \Magento\Framework\Exception\LocalizedException */ public function loadByQueryText($text) { @@ -204,6 +207,7 @@ public function setStoreId($storeId) * Retrieve store Id * * @return int + * @throws \Magento\Framework\Exception\NoSuchEntityException */ public function getStoreId() { @@ -217,6 +221,7 @@ public function getStoreId() * Prepare save query for result * * @return $this + * @throws \Exception */ public function prepare() { @@ -264,6 +269,7 @@ public function saveNumResults($numResults) * Retrieve minimum query length * * @return int + * @throws \Magento\Framework\Exception\NoSuchEntityException */ public function getMinQueryLength() { @@ -278,6 +284,7 @@ public function getMinQueryLength() * Retrieve maximum query length * * @return int + * @throws \Magento\Framework\Exception\NoSuchEntityException */ public function getMaxQueryLength() { diff --git a/app/code/Magento/Search/Model/SynonymGroupRepository.php b/app/code/Magento/Search/Model/SynonymGroupRepository.php index 6c5bdfb597487..75d7049afd949 100644 --- a/app/code/Magento/Search/Model/SynonymGroupRepository.php +++ b/app/code/Magento/Search/Model/SynonymGroupRepository.php @@ -45,7 +45,7 @@ public function __construct( } /** - * {@inheritdoc} + * @inheritdoc */ public function save(SynonymGroupInterface $synonymGroup, $errorOnMergeConflict = false) { @@ -106,6 +106,7 @@ public function get($synonymGroupId) * @param bool $errorOnMergeConflict * @return SynonymGroupInterface * @throws Synonym\MergeConflictException + * @throws \Magento\Framework\Exception\AlreadyExistsException */ private function create(SynonymGroupInterface $synonymGroup, $errorOnMergeConflict) { @@ -144,6 +145,7 @@ private function create(SynonymGroupInterface $synonymGroup, $errorOnMergeConfli * @param SynonymGroupInterface $synonymGroupToMerge * @param array $matchingGroupIds * @return array + * @throws \Exception */ private function merge(SynonymGroupInterface $synonymGroupToMerge, array $matchingGroupIds) { @@ -182,6 +184,7 @@ private function populateSynonymGroupModel(SynonymGroup $modelToPopulate, Synony * @param bool $errorOnMergeConflict * @return SynonymGroupInterface * @throws Synonym\MergeConflictException + * @throws \Magento\Framework\Exception\AlreadyExistsException */ private function update( SynonymGroup $oldSynonymGroup, diff --git a/app/code/Magento/Search/Test/Mftf/composer.json b/app/code/Magento/Search/Test/Mftf/composer.json deleted file mode 100644 index 97cef910ffa02..0000000000000 --- a/app/code/Magento/Search/Test/Mftf/composer.json +++ /dev/null @@ -1,21 +0,0 @@ -{ - "name": "magento/functional-test-module-search", - "description": "N/A", - "config": { - "sort-packages": true - }, - "require": { - "php": "~7.1.3||~7.2.0", - "magento/magento2-functional-testing-framework": "2.2.0", - "magento/functional-test-module-backend": "100.0.0-dev", - "magento/functional-test-module-catalog-search": "100.0.0-dev", - "magento/functional-test-module-reports": "100.0.0-dev", - "magento/functional-test-module-store": "100.0.0-dev", - "magento/functional-test-module-ui": "100.0.0-dev" - }, - "type": "magento2-test", - "license": [ - "OSL-3.0", - "AFL-3.0" - ] -} diff --git a/app/code/Magento/Search/Test/Unit/Controller/Adminhtml/Synonyms/DeleteTest.php b/app/code/Magento/Search/Test/Unit/Controller/Adminhtml/Synonyms/DeleteTest.php index a7f71941dc6b2..38c78b986faf4 100644 --- a/app/code/Magento/Search/Test/Unit/Controller/Adminhtml/Synonyms/DeleteTest.php +++ b/app/code/Magento/Search/Test/Unit/Controller/Adminhtml/Synonyms/DeleteTest.php @@ -107,10 +107,10 @@ public function testDeleteAction() $this->repository->expects($this->once())->method('get')->with(10)->willReturn($this->synonymGroupMock); $this->messageManagerMock->expects($this->once()) - ->method('addSuccess') + ->method('addSuccessMessage') ->with(__('The synonym group has been deleted.')); - $this->messageManagerMock->expects($this->never())->method('addError'); + $this->messageManagerMock->expects($this->never())->method('addErrorMessage'); $this->resultRedirectMock->expects($this->once())->method('setPath')->with('*/*/')->willReturnSelf(); @@ -124,10 +124,10 @@ public function testDeleteActionNoId() ->willReturn(null); $this->messageManagerMock->expects($this->once()) - ->method('addError') + ->method('addErrorMessage') ->with(__('We can\'t find a synonym group to delete.')); $this->messageManagerMock->expects($this->never()) - ->method('addSuccess'); + ->method('addSuccessMessage'); $this->resultRedirectMock->expects($this->once()) ->method('setPath') diff --git a/app/code/Magento/Search/Test/Unit/Controller/Adminhtml/Term/MassDeleteTest.php b/app/code/Magento/Search/Test/Unit/Controller/Adminhtml/Term/MassDeleteTest.php index efda8f52fcfe9..60cc958a6187c 100644 --- a/app/code/Magento/Search/Test/Unit/Controller/Adminhtml/Term/MassDeleteTest.php +++ b/app/code/Magento/Search/Test/Unit/Controller/Adminhtml/Term/MassDeleteTest.php @@ -54,7 +54,7 @@ protected function setUp() ->getMockForAbstractClass(); $this->messageManager = $this->getMockBuilder(\Magento\Framework\Message\ManagerInterface::class) ->disableOriginalConstructor() - ->setMethods(['addSuccess', 'addError']) + ->setMethods(['addSuccessMessage', 'addErrorMessage']) ->getMockForAbstractClass(); $this->pageFactory = $this->getMockBuilder(\Magento\Framework\View\Result\PageFactory::class) ->setMethods([]) @@ -107,7 +107,7 @@ public function testExecute() $this->createQuery(0, 1); $this->createQuery(1, 2); $this->messageManager->expects($this->once()) - ->method('addSuccess') + ->method('addSuccessMessage') ->will($this->returnSelf()); $this->resultRedirectMock->expects($this->once()) ->method('setPath') diff --git a/app/code/Magento/Search/Test/Unit/Controller/Adminhtml/Term/SaveTest.php b/app/code/Magento/Search/Test/Unit/Controller/Adminhtml/Term/SaveTest.php index 09ae2c38fe525..28f4b65cd412f 100644 --- a/app/code/Magento/Search/Test/Unit/Controller/Adminhtml/Term/SaveTest.php +++ b/app/code/Magento/Search/Test/Unit/Controller/Adminhtml/Term/SaveTest.php @@ -75,7 +75,7 @@ protected function setUp() $this->messageManager = $this->getMockBuilder(\Magento\Framework\Message\ManagerInterface::class) ->disableOriginalConstructor() - ->setMethods(['addSuccess', 'addError', 'addException']) + ->setMethods(['addSuccessMessage', 'addErrorMessage', 'addExceptionMessage']) ->getMockForAbstractClass(); $this->context->expects($this->any()) ->method('getMessageManager') @@ -143,7 +143,7 @@ public function testExecuteLoadQueryQueryId() $this->query->expects($this->once())->method('getId')->willReturn(false); $this->query->expects($this->once())->method('load')->with($queryId); - $this->messageManager->expects($this->once())->method('addSuccess'); + $this->messageManager->expects($this->once())->method('addSuccessMessage'); $this->redirect->expects($this->once())->method('setPath')->willReturnSelf(); $this->assertSame($this->redirect, $this->controller->execute()); @@ -161,7 +161,7 @@ public function testExecuteLoadQueryQueryIdQueryText() $this->query->expects($this->once())->method('loadByQueryText')->with($queryText); $this->query->expects($this->any())->method('getId')->willReturn($queryId); - $this->messageManager->expects($this->once())->method('addSuccess'); + $this->messageManager->expects($this->once())->method('addSuccessMessage'); $this->redirect->expects($this->once())->method('setPath')->willReturnSelf(); $this->assertSame($this->redirect, $this->controller->execute()); @@ -180,7 +180,7 @@ public function testExecuteLoadQueryQueryIdQueryText2() $this->query->expects($this->any())->method('getId')->willReturn(false); $this->query->expects($this->once())->method('load')->with($queryId); - $this->messageManager->expects($this->once())->method('addSuccess'); + $this->messageManager->expects($this->once())->method('addSuccessMessage'); $this->redirect->expects($this->once())->method('setPath')->willReturnSelf(); $this->assertSame($this->redirect, $this->controller->execute()); @@ -199,7 +199,7 @@ public function testExecuteLoadQueryQueryIdQueryTextException() $this->query->expects($this->once())->method('loadByQueryText')->with($queryText); $this->query->expects($this->any())->method('getId')->willReturn($anotherQueryId); - $this->messageManager->expects($this->once())->method('addError'); + $this->messageManager->expects($this->once())->method('addErrorMessage'); $this->session->expects($this->once())->method('setPageData'); $this->redirect->expects($this->once())->method('setPath')->willReturnSelf(); $this->assertSame($this->redirect, $this->controller->execute()); @@ -216,7 +216,7 @@ public function testExecuteException() $this->query->expects($this->once())->method('setStoreId'); $this->query->expects($this->once())->method('loadByQueryText')->willThrowException(new \Exception()); - $this->messageManager->expects($this->once())->method('addException'); + $this->messageManager->expects($this->once())->method('addExceptionMessage'); $this->session->expects($this->once())->method('setPageData'); $this->redirect->expects($this->once())->method('setPath')->willReturnSelf(); $this->assertSame($this->redirect, $this->controller->execute()); diff --git a/app/code/Magento/Search/Ui/Component/Listing/Column/StoreView.php b/app/code/Magento/Search/Ui/Component/Listing/Column/StoreView.php index 1a66d9242b343..405042f2e7825 100644 --- a/app/code/Magento/Search/Ui/Component/Listing/Column/StoreView.php +++ b/app/code/Magento/Search/Ui/Component/Listing/Column/StoreView.php @@ -46,6 +46,7 @@ public function __construct( * * @param array $dataSource * @return array + * @throws \Magento\Framework\Exception\NoSuchEntityException */ public function prepareDataSource(array $dataSource) { @@ -62,6 +63,7 @@ public function prepareDataSource(array $dataSource) * * @param array $item * @return string + * @throws \Magento\Framework\Exception\NoSuchEntityException */ protected function prepareItem(array $item) { diff --git a/app/code/Magento/Search/Ui/Component/Listing/Column/Website.php b/app/code/Magento/Search/Ui/Component/Listing/Column/Website.php index 216e0b3877ddb..78fd4b9c36a80 100644 --- a/app/code/Magento/Search/Ui/Component/Listing/Column/Website.php +++ b/app/code/Magento/Search/Ui/Component/Listing/Column/Website.php @@ -47,6 +47,7 @@ public function __construct( * * @param array $dataSource * @return array + * @throws \Magento\Framework\Exception\LocalizedException */ public function prepareDataSource(array $dataSource) { @@ -63,6 +64,7 @@ public function prepareDataSource(array $dataSource) * * @param array $item * @return string + * @throws \Magento\Framework\Exception\LocalizedException */ protected function prepareItem(array $item) { diff --git a/app/code/Magento/Search/i18n/pt_BR.csv b/app/code/Magento/Search/i18n/pt_BR.csv index 8b4b04aa3b9ec..c10566a7c9800 100644 --- a/app/code/Magento/Search/i18n/pt_BR.csv +++ b/app/code/Magento/Search/i18n/pt_BR.csv @@ -1 +1 @@ -"Search Engine","Search Engine" +"Search Engine","Mecanismo de Busca" diff --git a/app/code/Magento/Security/Controller/Adminhtml/Session/LogoutAll.php b/app/code/Magento/Security/Controller/Adminhtml/Session/LogoutAll.php index c533e740b2251..35d8f22d84d51 100644 --- a/app/code/Magento/Security/Controller/Adminhtml/Session/LogoutAll.php +++ b/app/code/Magento/Security/Controller/Adminhtml/Session/LogoutAll.php @@ -38,11 +38,11 @@ public function execute() { try { $this->sessionsManager->logoutOtherUserSessions(); - $this->messageManager->addSuccess(__('All other open sessions for this account were terminated.')); + $this->messageManager->addSuccessMessage(__('All other open sessions for this account were terminated.')); } catch (\Magento\Framework\Exception\LocalizedException $e) { - $this->messageManager->addError($e->getMessage()); + $this->messageManager->addErrorMessage($e->getMessage()); } catch (\Exception $e) { - $this->messageManager->addException($e, __("We couldn't logout because of an error.")); + $this->messageManager->addExceptionMessage($e, __("We couldn't logout because of an error.")); } $this->_redirect('*/*/activity'); } diff --git a/app/code/Magento/Security/Model/Plugin/AuthSession.php b/app/code/Magento/Security/Model/Plugin/AuthSession.php index abec4dc7c29ef..01203caaa31cd 100644 --- a/app/code/Magento/Security/Model/Plugin/AuthSession.php +++ b/app/code/Magento/Security/Model/Plugin/AuthSession.php @@ -82,7 +82,7 @@ private function addUserLogoutNotification() $this->sessionsManager->getCurrentSession()->getStatus() ); } elseif ($message = $this->sessionsManager->getLogoutReasonMessage()) { - $this->messageManager->addError($message); + $this->messageManager->addErrorMessage($message); } return $this; diff --git a/app/code/Magento/Security/Model/Plugin/LoginController.php b/app/code/Magento/Security/Model/Plugin/LoginController.php index ab9c6e2857bce..ba1a18c4f0c06 100644 --- a/app/code/Magento/Security/Model/Plugin/LoginController.php +++ b/app/code/Magento/Security/Model/Plugin/LoginController.php @@ -53,7 +53,7 @@ public function beforeExecute(Login $login) { $logoutReasonCode = $this->securityCookie->getLogoutReasonCookie(); if ($this->isLoginForm($login) && $logoutReasonCode >= 0) { - $this->messageManager->addError( + $this->messageManager->addErrorMessage( $this->sessionsManager->getLogoutReasonMessageByStatus($logoutReasonCode) ); $this->securityCookie->deleteLogoutReasonCookie(); diff --git a/app/code/Magento/Security/Test/Mftf/composer.json b/app/code/Magento/Security/Test/Mftf/composer.json deleted file mode 100644 index 3429571c9b6d8..0000000000000 --- a/app/code/Magento/Security/Test/Mftf/composer.json +++ /dev/null @@ -1,22 +0,0 @@ -{ - "name": "magento/functional-test-module-security", - "description": "Security management module", - "config": { - "sort-packages": true - }, - "require": { - "php": "~7.1.3||~7.2.0", - "magento/magento2-functional-testing-framework": "2.2.0", - "magento/functional-test-module-backend": "100.0.0-dev", - "magento/functional-test-module-store": "100.0.0-dev", - "magento/functional-test-module-user": "100.0.0-dev" - }, - "suggest": { - "magento/functional-test-module-customer": "100.0.0-dev" - }, - "type": "magento2-test", - "license": [ - "OSL-3.0", - "AFL-3.0" - ] -} diff --git a/app/code/Magento/Security/Test/Unit/Controller/Adminhtml/Session/LogoutAllTest.php b/app/code/Magento/Security/Test/Unit/Controller/Adminhtml/Session/LogoutAllTest.php index 8c2119bde667e..02335ef55aa93 100644 --- a/app/code/Magento/Security/Test/Unit/Controller/Adminhtml/Session/LogoutAllTest.php +++ b/app/code/Magento/Security/Test/Unit/Controller/Adminhtml/Session/LogoutAllTest.php @@ -74,7 +74,7 @@ public function setUp() $this->messageManager = $this->getMockBuilder(\Magento\Framework\Message\ManagerInterface::class) ->disableOriginalConstructor() - ->setMethods(['addSuccess', 'addError', 'addException']) + ->setMethods(['addSuccessMessage', 'addErrorMessage', 'addExceptionMessage']) ->getMockForAbstractClass(); $this->contextMock->expects($this->any()) ->method('getMessageManager') @@ -132,12 +132,12 @@ public function testExecute() $this->sessionsManager->expects($this->once()) ->method('logoutOtherUserSessions'); $this->messageManager->expects($this->once()) - ->method('addSuccess') + ->method('addSuccessMessage') ->with($successMessage); $this->messageManager->expects($this->never()) - ->method('addError'); + ->method('addErrorMessage'); $this->messageManager->expects($this->never()) - ->method('addException'); + ->method('addExceptionMessage'); $this->responseMock->expects($this->once()) ->method('setRedirect'); $this->actionFlagMock->expects($this->once()) @@ -158,7 +158,7 @@ public function testExecuteLocalizedException() ->method('logoutOtherUserSessions') ->willThrowException(new LocalizedException($phrase)); $this->messageManager->expects($this->once()) - ->method('addError') + ->method('addErrorMessage') ->with($phrase); $this->controller->execute(); } @@ -173,7 +173,7 @@ public function testExecuteException() ->method('logoutOtherUserSessions') ->willThrowException(new \Exception()); $this->messageManager->expects($this->once()) - ->method('addException') + ->method('addExceptionMessage') ->with(new \Exception(), $phrase); $this->controller->execute(); } diff --git a/app/code/Magento/Security/Test/Unit/Model/Plugin/AuthSessionTest.php b/app/code/Magento/Security/Test/Unit/Model/Plugin/AuthSessionTest.php index 5cb06d6143023..0f7f590b71de4 100644 --- a/app/code/Magento/Security/Test/Unit/Model/Plugin/AuthSessionTest.php +++ b/app/code/Magento/Security/Test/Unit/Model/Plugin/AuthSessionTest.php @@ -112,7 +112,7 @@ public function testAroundProlongSessionIsNotActiveAndIsNotAjaxRequest() ->willReturn($errorMessage); $this->messageManagerMock->expects($this->once()) - ->method('addError') + ->method('addErrorMessage') ->with($errorMessage); $this->model->aroundProlong($this->authSessionMock, $proceed); diff --git a/app/code/Magento/Security/Test/Unit/Model/Plugin/LoginControllerTest.php b/app/code/Magento/Security/Test/Unit/Model/Plugin/LoginControllerTest.php index 2bb2bc3cafac7..aa066e23f67cb 100644 --- a/app/code/Magento/Security/Test/Unit/Model/Plugin/LoginControllerTest.php +++ b/app/code/Magento/Security/Test/Unit/Model/Plugin/LoginControllerTest.php @@ -103,7 +103,7 @@ public function testBeforeExecute() ->willReturn($errorMessage); $this->messageManagerMock->expects($this->once()) - ->method('addError') + ->method('addErrorMessage') ->with($errorMessage); $this->securityCookieMock->expects($this->once()) diff --git a/app/code/Magento/SendFriend/Test/Mftf/composer.json b/app/code/Magento/SendFriend/Test/Mftf/composer.json deleted file mode 100644 index 7e061e0159f02..0000000000000 --- a/app/code/Magento/SendFriend/Test/Mftf/composer.json +++ /dev/null @@ -1,19 +0,0 @@ -{ - "name": "magento/functional-test-module-send-friend", - "description": "N/A", - "config": { - "sort-packages": true - }, - "require": { - "php": "~7.1.3||~7.2.0", - "magento/magento2-functional-testing-framework": "2.2.0", - "magento/functional-test-module-catalog": "100.0.0-dev", - "magento/functional-test-module-customer": "100.0.0-dev", - "magento/functional-test-module-store": "100.0.0-dev" - }, - "type": "magento2-test", - "license": [ - "OSL-3.0", - "AFL-3.0" - ] -} diff --git a/app/code/Magento/Shipping/Block/Adminhtml/Order/Tracking/View.php b/app/code/Magento/Shipping/Block/Adminhtml/Order/Tracking/View.php index 00fc6fce1bfb8..356483c9a5dd7 100644 --- a/app/code/Magento/Shipping/Block/Adminhtml/Order/Tracking/View.php +++ b/app/code/Magento/Shipping/Block/Adminhtml/Order/Tracking/View.php @@ -92,11 +92,6 @@ public function getRemoveUrl($track) public function getCarrierTitle($code) { $carrier = $this->_carrierFactory->create($code); - if ($carrier) { - return $carrier->getConfigData('title'); - } else { - return __('Custom Value'); - } - return false; + return $carrier ? $carrier->getConfigData('title') : __('Custom Value'); } } diff --git a/app/code/Magento/Shipping/Model/Carrier/AbstractCarrier.php b/app/code/Magento/Shipping/Model/Carrier/AbstractCarrier.php index 6763046373ce7..f9030ee75630b 100644 --- a/app/code/Magento/Shipping/Model/Carrier/AbstractCarrier.php +++ b/app/code/Magento/Shipping/Model/Carrier/AbstractCarrier.php @@ -407,6 +407,9 @@ public function getSortOrder() */ protected function _updateFreeMethodQuote($request) { + if (!$request->getFreeShipping()) { + return; + } if ($request->getFreeMethodWeight() == $request->getPackageWeight() || !$request->hasFreeMethodWeight()) { return; } @@ -448,6 +451,12 @@ protected function _updateFreeMethodQuote($request) } } } + } else { + /** + * if we can apply free shipping for all order we should force price + * to $0.00 for shipping with out sending second request to carrier + */ + $price = 0; } /** diff --git a/app/code/Magento/Shipping/Test/Mftf/composer.json b/app/code/Magento/Shipping/Test/Mftf/composer.json deleted file mode 100644 index 1b640d86f907d..0000000000000 --- a/app/code/Magento/Shipping/Test/Mftf/composer.json +++ /dev/null @@ -1,34 +0,0 @@ -{ - "name": "magento/functional-test-module-shipping", - "description": "N/A", - "config": { - "sort-packages": true - }, - "require": { - "php": "~7.1.3||~7.2.0", - "magento/magento2-functional-testing-framework": "2.2.0", - "magento/functional-test-module-backend": "100.0.0-dev", - "magento/functional-test-module-catalog": "100.0.0-dev", - "magento/functional-test-module-catalog-inventory": "100.0.0-dev", - "magento/functional-test-module-contact": "100.0.0-dev", - "magento/functional-test-module-customer": "100.0.0-dev", - "magento/functional-test-module-directory": "100.0.0-dev", - "magento/functional-test-module-payment": "100.0.0-dev", - "magento/functional-test-module-quote": "100.0.0-dev", - "magento/functional-test-module-sales": "100.0.0-dev", - "magento/functional-test-module-store": "100.0.0-dev", - "magento/functional-test-module-tax": "100.0.0-dev", - "magento/functional-test-module-ui": "100.0.0-dev", - "magento/functional-test-module-user": "100.0.0-dev" - }, - "suggest": { - "magento/functional-test-module-fedex": "100.0.0-dev", - "magento/functional-test-module-ups": "100.0.0-dev", - "magento/functional-test-module-config": "100.0.0-dev" - }, - "type": "magento2-test", - "license": [ - "OSL-3.0", - "AFL-3.0" - ] -} diff --git a/app/code/Magento/Shipping/view/frontend/templates/tracking/progress.phtml b/app/code/Magento/Shipping/view/frontend/templates/tracking/progress.phtml index 84126d8eeb636..237eba09ff802 100644 --- a/app/code/Magento/Shipping/view/frontend/templates/tracking/progress.phtml +++ b/app/code/Magento/Shipping/view/frontend/templates/tracking/progress.phtml @@ -23,7 +23,7 @@ $track = $block->getData('track'); </thead> <tbody> <?php foreach ($track->getProgressdetail() as $detail): ?> - <?php $detailDate = (!empty($detail['deliverydate']) ? $parentBlock->formatDeliveryDate($detail['deliverydate']) : ''); ?> + <?php $detailDate = (!empty($detail['deliverydate']) ? $parentBlock->formatDeliveryDate($detail['deliverydate'] . ' ' . $detail['deliverytime']) : ''); ?> <?php $detailTime = (!empty($detail['deliverytime']) ? $parentBlock->formatDeliveryTime($detail['deliverytime'], $detail['deliverydate']) : ''); ?> <tr> <td data-th="<?= $block->escapeHtml(__('Location')) ?>" class="col location"> diff --git a/app/code/Magento/Signifyd/Controller/Webhooks/Handler.php b/app/code/Magento/Signifyd/Controller/Webhooks/Handler.php index 12bd773d35a2f..2dee31f4048b9 100644 --- a/app/code/Magento/Signifyd/Controller/Webhooks/Handler.php +++ b/app/code/Magento/Signifyd/Controller/Webhooks/Handler.php @@ -7,6 +7,8 @@ use Magento\Framework\App\Action\Action; use Magento\Framework\App\Action\Context; +use Magento\Framework\App\Request\InvalidRequestException; +use Magento\Framework\App\RequestInterface; use Magento\Framework\Exception\LocalizedException; use Magento\Signifyd\Api\CaseRepositoryInterface; use Magento\Signifyd\Model\CaseServices\UpdatingServiceFactory; @@ -21,7 +23,7 @@ * * @see https://www.signifyd.com/docs/api/#/reference/webhooks/ */ -class Handler extends Action +class Handler extends Action implements \Magento\Framework\App\CsrfAwareActionInterface { /** * Event topic of test webhook request. @@ -136,4 +138,20 @@ public function execute() $this->logger->critical($e); } } + + /** + * @inheritDoc + */ + public function createCsrfValidationException(RequestInterface $request): ?InvalidRequestException + { + return null; + } + + /** + * @inheritDoc + */ + public function validateForCsrf(RequestInterface $request): ?bool + { + return true; + } } diff --git a/app/code/Magento/Signifyd/Test/Mftf/composer.json b/app/code/Magento/Signifyd/Test/Mftf/composer.json deleted file mode 100644 index dc969cc4780ef..0000000000000 --- a/app/code/Magento/Signifyd/Test/Mftf/composer.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "name": "magento/functional-test-module-signifyd", - "description": "Submitting Case Entry to Signifyd on Order Creation", - "config": { - "sort-packages": true - }, - "require": { - "magento/magento2-functional-testing-framework": "2.2.0", - "magento/functional-test-module-backend": "100.0.0-dev", - "magento/functional-test-module-checkout": "100.0.0-dev", - "magento/functional-test-module-config": "100.0.0-dev", - "magento/functional-test-module-customer": "100.0.0-dev", - "magento/functional-test-module-directory": "100.0.0-dev", - "magento/functional-test-module-payment": "100.0.0-dev", - "magento/functional-test-module-sales": "100.0.0-dev", - "magento/functional-test-module-store": "100.0.0-dev", - "php": "~7.1.3||~7.2.0" - }, - "suggest": { - "magento/functional-test-module-config": "100.0.0-dev" - }, - "type": "magento2-test", - "license": [ - "proprietary" - ] -} diff --git a/app/code/Magento/Signifyd/composer.json b/app/code/Magento/Signifyd/composer.json index c766ccd848ca4..992a74d0dc3ec 100644 --- a/app/code/Magento/Signifyd/composer.json +++ b/app/code/Magento/Signifyd/composer.json @@ -21,7 +21,8 @@ }, "type": "magento2-module", "license": [ - "proprietary" + "OSL-3.0", + "AFL-3.0" ], "autoload": { "files": [ diff --git a/app/code/Magento/Sitemap/Controller/Adminhtml/Sitemap/Delete.php b/app/code/Magento/Sitemap/Controller/Adminhtml/Sitemap/Delete.php index 422fed9d9a688..29d50ea8408fd 100644 --- a/app/code/Magento/Sitemap/Controller/Adminhtml/Sitemap/Delete.php +++ b/app/code/Magento/Sitemap/Controller/Adminhtml/Sitemap/Delete.php @@ -65,20 +65,20 @@ public function execute() } $sitemap->delete(); // display success message - $this->messageManager->addSuccess(__('You deleted the sitemap.')); + $this->messageManager->addSuccessMessage(__('You deleted the sitemap.')); // go to grid $this->_redirect('adminhtml/*/'); return; } catch (\Exception $e) { // display error message - $this->messageManager->addError($e->getMessage()); + $this->messageManager->addErrorMessage($e->getMessage()); // go back to edit form $this->_redirect('adminhtml/*/edit', ['sitemap_id' => $id]); return; } } // display error message - $this->messageManager->addError(__('We can\'t find a sitemap to delete.')); + $this->messageManager->addErrorMessage(__('We can\'t find a sitemap to delete.')); // go to grid $this->_redirect('adminhtml/*/'); } diff --git a/app/code/Magento/Sitemap/Controller/Adminhtml/Sitemap/Edit.php b/app/code/Magento/Sitemap/Controller/Adminhtml/Sitemap/Edit.php index 04ab4f8725e0e..111353550b9cd 100644 --- a/app/code/Magento/Sitemap/Controller/Adminhtml/Sitemap/Edit.php +++ b/app/code/Magento/Sitemap/Controller/Adminhtml/Sitemap/Edit.php @@ -41,7 +41,7 @@ public function execute() if ($id) { $model->load($id); if (!$model->getId()) { - $this->messageManager->addError(__('This sitemap no longer exists.')); + $this->messageManager->addErrorMessage(__('This sitemap no longer exists.')); $this->_redirect('adminhtml/*/'); return; } diff --git a/app/code/Magento/Sitemap/Controller/Adminhtml/Sitemap/Generate.php b/app/code/Magento/Sitemap/Controller/Adminhtml/Sitemap/Generate.php index 67d2ce4f4f148..9592ab6f57c55 100644 --- a/app/code/Magento/Sitemap/Controller/Adminhtml/Sitemap/Generate.php +++ b/app/code/Magento/Sitemap/Controller/Adminhtml/Sitemap/Generate.php @@ -6,8 +6,29 @@ */ namespace Magento\Sitemap\Controller\Adminhtml\Sitemap; +use Magento\Backend\App\Action; +use Magento\Store\Model\App\Emulation; +use Magento\Framework\App\ObjectManager; + class Generate extends \Magento\Sitemap\Controller\Adminhtml\Sitemap { + /** @var \Magento\Store\Model\App\Emulation $appEmulation */ + private $appEmulation; + + /** + * Generate constructor. + * @param Action\Context $context + * @param \Magento\Store\Model\App\Emulation|null $appEmulation + */ + public function __construct( + Action\Context $context, + Emulation $appEmulation = null + ) { + parent::__construct($context); + $this->appEmulation = $appEmulation ?: ObjectManager::getInstance() + ->get(\Magento\Store\Model\App\Emulation::class); + } + /** * Generate sitemap * @@ -23,18 +44,26 @@ public function execute() // if sitemap record exists if ($sitemap->getId()) { try { + //We need to emulate to get the correct frontend URL for the product images + $this->appEmulation->startEnvironmentEmulation( + $sitemap->getStoreId(), + \Magento\Framework\App\Area::AREA_FRONTEND, + true + ); $sitemap->generateXml(); - $this->messageManager->addSuccess( + $this->messageManager->addSuccessMessage( __('The sitemap "%1" has been generated.', $sitemap->getSitemapFilename()) ); } catch (\Magento\Framework\Exception\LocalizedException $e) { - $this->messageManager->addError($e->getMessage()); + $this->messageManager->addErrorMessage($e->getMessage()); } catch (\Exception $e) { - $this->messageManager->addException($e, __('We can\'t generate the sitemap right now.')); + $this->messageManager->addExceptionMessage($e, __('We can\'t generate the sitemap right now.')); + } finally { + $this->appEmulation->stopEnvironmentEmulation(); } } else { - $this->messageManager->addError(__('We can\'t find a sitemap to generate.')); + $this->messageManager->addErrorMessage(__('We can\'t find a sitemap to generate.')); } // go to grid diff --git a/app/code/Magento/Sitemap/Controller/Adminhtml/Sitemap/Save.php b/app/code/Magento/Sitemap/Controller/Adminhtml/Sitemap/Save.php index 5c38cc68e6ef7..1e0d1cb248f00 100644 --- a/app/code/Magento/Sitemap/Controller/Adminhtml/Sitemap/Save.php +++ b/app/code/Magento/Sitemap/Controller/Adminhtml/Sitemap/Save.php @@ -30,7 +30,7 @@ protected function validatePath(array $data) $validator->setPaths($helper->getValidPaths()); if (!$validator->isValid($path)) { foreach ($validator->getMessages() as $message) { - $this->messageManager->addError($message); + $this->messageManager->addErrorMessage($message); } // save data in session $this->_objectManager->get(\Magento\Backend\Model\Session::class)->setFormData($data); @@ -83,13 +83,13 @@ protected function saveData($data) // save the data $model->save(); // display success message - $this->messageManager->addSuccess(__('You saved the sitemap.')); + $this->messageManager->addSuccessMessage(__('You saved the sitemap.')); // clear previously saved data from session $this->_objectManager->get(\Magento\Backend\Model\Session::class)->setFormData(false); return $model->getId(); } catch (\Exception $e) { // display error message - $this->messageManager->addError($e->getMessage()); + $this->messageManager->addErrorMessage($e->getMessage()); // save data in session $this->_objectManager->get(\Magento\Backend\Model\Session::class)->setFormData($data); } diff --git a/app/code/Magento/Sitemap/Test/Mftf/composer.json b/app/code/Magento/Sitemap/Test/Mftf/composer.json deleted file mode 100644 index 46ad680c9fb1e..0000000000000 --- a/app/code/Magento/Sitemap/Test/Mftf/composer.json +++ /dev/null @@ -1,28 +0,0 @@ -{ - "name": "magento/functional-test-module-sitemap", - "description": "N/A", - "config": { - "sort-packages": true - }, - "require": { - "php": "~7.1.3||~7.2.0", - "magento/magento2-functional-testing-framework": "2.2.0", - "magento/functional-test-module-backend": "100.0.0-dev", - "magento/functional-test-module-catalog": "100.0.0-dev", - "magento/functional-test-module-catalog-url-rewrite": "100.0.0-dev", - "magento/functional-test-module-cms": "100.0.0-dev", - "magento/functional-test-module-config": "100.0.0-dev", - "magento/functional-test-module-eav": "100.0.0-dev", - "magento/functional-test-module-media-storage": "100.0.0-dev", - "magento/functional-test-module-robots": "100.0.0-dev", - "magento/functional-test-module-store": "100.0.0-dev" - }, - "suggest": { - "magento/functional-test-module-config": "100.0.0-dev" - }, - "type": "magento2-test", - "license": [ - "OSL-3.0", - "AFL-3.0" - ] -} diff --git a/app/code/Magento/Sitemap/Test/Unit/Controller/Adminhtml/Sitemap/SaveTest.php b/app/code/Magento/Sitemap/Test/Unit/Controller/Adminhtml/Sitemap/SaveTest.php index 36e3aa0312627..f77954101df7c 100644 --- a/app/code/Magento/Sitemap/Test/Unit/Controller/Adminhtml/Sitemap/SaveTest.php +++ b/app/code/Magento/Sitemap/Test/Unit/Controller/Adminhtml/Sitemap/SaveTest.php @@ -154,7 +154,7 @@ public function testTryToSaveInvalidDataShouldFailWithErrors() ->willReturnMap([[$helperClass, $helper], [$sessionClass, $session]]); $this->messageManagerMock->expects($this->at(0)) - ->method('addError') + ->method('addErrorMessage') ->withConsecutive( [$messages[0]], [$messages[1]] diff --git a/app/code/Magento/Store/App/Config/Type/Scopes.php b/app/code/Magento/Store/App/Config/Type/Scopes.php index 9fbecc4db303e..e6b9d0000e4a6 100644 --- a/app/code/Magento/Store/App/Config/Type/Scopes.php +++ b/app/code/Magento/Store/App/Config/Type/Scopes.php @@ -114,5 +114,6 @@ private function convertIdPathToCodePath(array $patchChunks) public function clean() { $this->data = null; + $this->idCodeMap = []; } } diff --git a/app/code/Magento/Store/App/Response/Redirect.php b/app/code/Magento/Store/App/Response/Redirect.php index b18f2cfc22613..534c6be41c937 100644 --- a/app/code/Magento/Store/App/Response/Redirect.php +++ b/app/code/Magento/Store/App/Response/Redirect.php @@ -171,16 +171,6 @@ public function success($defaultUrl) */ public function updatePathParams(array $arguments) { - if ($this->_session->getCookieShouldBeReceived() - && $this->_sidResolver->getUseSessionInUrl() - && $this->_canUseSessionIdInParam - ) { - $arguments += [ - '_query' => [ - $this->_sidResolver->getSessionIdQueryParam($this->_session) => $this->_session->getSessionId(), - ] - ]; - } return $arguments; } diff --git a/app/code/Magento/Store/Block/Switcher.php b/app/code/Magento/Store/Block/Switcher.php index b0659b7caf7e8..58a7ba3c1c283 100644 --- a/app/code/Magento/Store/Block/Switcher.php +++ b/app/code/Magento/Store/Block/Switcher.php @@ -13,6 +13,9 @@ use Magento\Store\Api\StoreResolverInterface; use Magento\Store\Model\Group; use Magento\Store\Model\Store; +use Magento\Framework\App\ActionInterface; +use Magento\Framework\App\ObjectManager; +use Magento\Framework\Url\Helper\Data as UrlHelper; /** * @api @@ -30,20 +33,28 @@ class Switcher extends \Magento\Framework\View\Element\Template */ protected $_postDataHelper; + /** + * @var UrlHelper + */ + private $urlHelper; + /** * Constructs * * @param \Magento\Framework\View\Element\Template\Context $context * @param \Magento\Framework\Data\Helper\PostHelper $postDataHelper * @param array $data + * @param UrlHelper $urlHelper */ public function __construct( \Magento\Framework\View\Element\Template\Context $context, \Magento\Framework\Data\Helper\PostHelper $postDataHelper, - array $data = [] + array $data = [], + UrlHelper $urlHelper = null ) { $this->_postDataHelper = $postDataHelper; parent::__construct($context, $data); + $this->urlHelper = $urlHelper ?: ObjectManager::getInstance()->get(UrlHelper::class); } /** @@ -222,15 +233,20 @@ public function getStoreName() * @param Store $store * @param array $data * @return string + * @throws \Magento\Framework\Exception\NoSuchEntityException */ public function getTargetStorePostData(Store $store, $data = []) { - $data[StoreResolverInterface::PARAM_NAME] = $store->getCode(); + $data[\Magento\Store\Api\StoreResolverInterface::PARAM_NAME] = $store->getCode(); + $data['___from_store'] = $this->_storeManager->getStore()->getCode(); + + $urlOnTargetStore = $store->getCurrentUrl(false); + $data[ActionInterface::PARAM_NAME_URL_ENCODED] = $this->urlHelper->getEncodedUrl($urlOnTargetStore); + + $url = $this->getUrl('stores/store/redirect'); - //We need to set fromStore argument as true because - //it will enable proper URL rewriting during store switching. return $this->_postDataHelper->getPostData( - $store->getCurrentUrl(true), + $url, $data ); } diff --git a/app/code/Magento/Store/Controller/Store/Redirect.php b/app/code/Magento/Store/Controller/Store/Redirect.php new file mode 100644 index 0000000000000..21692e9d6dd1e --- /dev/null +++ b/app/code/Magento/Store/Controller/Store/Redirect.php @@ -0,0 +1,113 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +declare(strict_types=1); + +namespace Magento\Store\Controller\Store; + +use Magento\Framework\App\Action\Context; +use Magento\Framework\App\ResponseInterface; +use Magento\Framework\Exception\NoSuchEntityException; +use Magento\Store\Api\StoreRepositoryInterface; +use Magento\Store\Api\StoreResolverInterface; +use Magento\Store\Model\StoreResolver; +use Magento\Framework\Session\SidResolverInterface; +use Magento\Framework\Session\Generic as Session; + +/** + * Builds correct url to target store and performs redirect. + */ +class Redirect extends \Magento\Framework\App\Action\Action +{ + /** + * @var StoreRepositoryInterface + */ + private $storeRepository; + + /** + * @var StoreResolverInterface + */ + private $storeResolver; + + /** + * @var SidResolverInterface + */ + private $sidResolver; + + /** + * @var Session + */ + private $session; + + /** + * @param Context $context + * @param StoreRepositoryInterface $storeRepository + * @param StoreResolverInterface $storeResolver + * @param Session $session + * @param SidResolverInterface $sidResolver + */ + public function __construct( + Context $context, + StoreRepositoryInterface $storeRepository, + StoreResolverInterface $storeResolver, + Session $session, + SidResolverInterface $sidResolver + ) { + parent::__construct($context); + $this->storeRepository = $storeRepository; + $this->storeResolver = $storeResolver; + $this->session = $session; + $this->sidResolver = $sidResolver; + } + + /** + * @return ResponseInterface|\Magento\Framework\Controller\ResultInterface + * @throws NoSuchEntityException + */ + public function execute() + { + /** @var \Magento\Store\Model\Store $currentStore */ + $currentStore = $this->storeRepository->getById($this->storeResolver->getCurrentStoreId()); + $targetStoreCode = $this->_request->getParam(StoreResolver::PARAM_NAME); + $fromStoreCode = $this->_request->getParam('___from_store'); + $error = null; + + if ($targetStoreCode === null) { + return $this->_redirect($currentStore->getBaseUrl()); + } + + try { + /** @var \Magento\Store\Model\Store $targetStore */ + $fromStore = $this->storeRepository->get($fromStoreCode); + } catch (NoSuchEntityException $e) { + $error = __('Requested store is not found'); + } + + if ($error !== null) { + $this->messageManager->addErrorMessage($error); + $this->_redirect->redirect($this->_response, $currentStore->getBaseUrl()); + } else { + $encodedUrl = $this->_request->getParam(\Magento\Framework\App\ActionInterface::PARAM_NAME_URL_ENCODED); + + $query = [ + '___from_store' => $fromStore->getCode(), + StoreResolverInterface::PARAM_NAME => $targetStoreCode, + \Magento\Framework\App\ActionInterface::PARAM_NAME_URL_ENCODED => $encodedUrl, + ]; + + if ($this->sidResolver->getUseSessionInUrl()) { + // allow customers to stay logged in during store switching + $sidName = $this->sidResolver->getSessionIdQueryParam($this->session); + $query[$sidName] = $this->session->getSessionId(); + } + + $arguments = [ + '_nosid' => true, + '_query' => $query + ]; + $this->_redirect->redirect($this->_response, 'stores/store/switch', $arguments); + } + } +} diff --git a/app/code/Magento/Store/Controller/Store/SwitchAction.php b/app/code/Magento/Store/Controller/Store/SwitchAction.php index f2872a51db6f4..df946b45d60e5 100644 --- a/app/code/Magento/Store/Controller/Store/SwitchAction.php +++ b/app/code/Magento/Store/Controller/Store/SwitchAction.php @@ -10,16 +10,19 @@ use Magento\Framework\App\Action\Action; use Magento\Framework\App\Action\Context as ActionContext; use Magento\Framework\App\Http\Context as HttpContext; +use Magento\Framework\App\ObjectManager; use Magento\Framework\Exception\NoSuchEntityException; use Magento\Store\Api\StoreCookieManagerInterface; use Magento\Store\Api\StoreRepositoryInterface; -use Magento\Store\Model\Store; use Magento\Store\Model\StoreIsInactiveException; use Magento\Store\Model\StoreResolver; use Magento\Store\Model\StoreManagerInterface; +use Magento\Store\Model\StoreSwitcher; +use Magento\Store\Model\StoreSwitcherInterface; /** - * Switch current store view. + * Handles store switching url and makes redirect. + * @SuppressWarnings(PHPMD.CouplingBetweenObjects) */ class SwitchAction extends Action { @@ -30,6 +33,7 @@ class SwitchAction extends Action /** * @var HttpContext + * @deprecated */ protected $httpContext; @@ -40,9 +44,15 @@ class SwitchAction extends Action /** * @var StoreManagerInterface + * @deprecated */ protected $storeManager; + /** + * @var StoreSwitcherInterface + */ + private $storeSwitcher; + /** * Initialize dependencies. * @@ -51,69 +61,55 @@ class SwitchAction extends Action * @param HttpContext $httpContext * @param StoreRepositoryInterface $storeRepository * @param StoreManagerInterface $storeManager + * @param StoreSwitcherInterface $storeSwitcher */ public function __construct( ActionContext $context, StoreCookieManagerInterface $storeCookieManager, HttpContext $httpContext, StoreRepositoryInterface $storeRepository, - StoreManagerInterface $storeManager + StoreManagerInterface $storeManager, + StoreSwitcherInterface $storeSwitcher = null ) { parent::__construct($context); $this->storeCookieManager = $storeCookieManager; $this->httpContext = $httpContext; $this->storeRepository = $storeRepository; $this->storeManager = $storeManager; + $this->messageManager = $context->getMessageManager(); + $this->storeSwitcher = $storeSwitcher ?: ObjectManager::getInstance()->get(StoreSwitcherInterface::class); } /** * @return void + * @throws StoreSwitcher\CannotSwitchStoreException */ public function execute() { - $currentActiveStore = $this->storeManager->getStore(); - $storeCode = $this->_request->getParam( + $targetStoreCode = $this->_request->getParam( StoreResolver::PARAM_NAME, $this->storeCookieManager->getStoreCodeFromCookie() ); + $fromStoreCode = $this->_request->getParam('___from_store'); + $requestedUrlToRedirect = $this->_redirect->getRedirectUrl(); + $redirectUrl = $requestedUrlToRedirect; + + $error = null; try { - $store = $this->storeRepository->getActiveStoreByCode($storeCode); + $fromStore = $this->storeRepository->get($fromStoreCode); + $targetStore = $this->storeRepository->getActiveStoreByCode($targetStoreCode); } catch (StoreIsInactiveException $e) { $error = __('Requested store is inactive'); } catch (NoSuchEntityException $e) { $error = __("The store that was requested wasn't found. Verify the store and try again."); } - - if (isset($error)) { - $this->messageManager->addError($error); - $this->getResponse()->setRedirect($this->_redirect->getRedirectUrl()); - return; - } - - $defaultStoreView = $this->storeManager->getDefaultStoreView(); - if ($defaultStoreView->getId() == $store->getId()) { - $this->storeCookieManager->deleteStoreCookie($store); + if ($error !== null) { + $this->messageManager->addErrorMessage($error); } else { - $this->httpContext->setValue(Store::ENTITY, $store->getCode(), $defaultStoreView->getCode()); - $this->storeCookieManager->setStoreCookie($store); + $redirectUrl = $this->storeSwitcher->switch($fromStore, $targetStore, $requestedUrlToRedirect); } - if ($store->isUseStoreInUrl()) { - // Change store code in redirect url - if (strpos($this->_redirect->getRedirectUrl(), $currentActiveStore->getBaseUrl()) !== false) { - $this->getResponse()->setRedirect( - str_replace( - $currentActiveStore->getBaseUrl(), - $store->getBaseUrl(), - $this->_redirect->getRedirectUrl() - ) - ); - } else { - $this->getResponse()->setRedirect($store->getBaseUrl()); - } - } else { - $this->getResponse()->setRedirect($this->_redirect->getRedirectUrl()); - } + $this->getResponse()->setRedirect($redirectUrl); } } diff --git a/app/code/Magento/Store/Model/Indexer/WebsiteDimensionProvider.php b/app/code/Magento/Store/Model/Indexer/WebsiteDimensionProvider.php new file mode 100644 index 0000000000000..6fceeabc3597e --- /dev/null +++ b/app/code/Magento/Store/Model/Indexer/WebsiteDimensionProvider.php @@ -0,0 +1,73 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +declare(strict_types=1); + +namespace Magento\Store\Model\Indexer; + +use Magento\Framework\Indexer\Dimension; +use Magento\Store\Model\ResourceModel\Website\CollectionFactory as WebsiteCollectionFactory; +use Magento\Framework\Indexer\DimensionFactory; +use Magento\Framework\Indexer\DimensionProviderInterface; +use Magento\Store\Model\Store; + +class WebsiteDimensionProvider implements DimensionProviderInterface +{ + /** + * Name for website dimension for multidimensional indexer + * 'ws' - stands for 'website_store' + */ + const DIMENSION_NAME = 'ws'; + + /** + * @var WebsiteCollectionFactory + */ + private $collectionFactory; + + /** + * @var \SplFixedArray + */ + private $websitesDataIterator; + + /** + * @var DimensionFactory + */ + private $dimensionFactory; + + /** + * @param WebsiteCollectionFactory $collectionFactory + * @param DimensionFactory $dimensionFactory + */ + public function __construct(WebsiteCollectionFactory $collectionFactory, DimensionFactory $dimensionFactory) + { + $this->dimensionFactory = $dimensionFactory; + $this->collectionFactory = $collectionFactory; + } + + /** + * @return Dimension[]|\Traversable + */ + public function getIterator(): \Traversable + { + foreach ($this->getWebsites() as $website) { + yield $this->dimensionFactory->create(self::DIMENSION_NAME, (string)$website); + } + } + + /** + * @return array + */ + private function getWebsites(): array + { + if ($this->websitesDataIterator === null) { + $websites = $this->collectionFactory->create() + ->addFieldToFilter('code', ['neq' => Store::ADMIN_CODE]) + ->getAllIds(); + $this->websitesDataIterator = is_array($websites) ? $websites : []; + } + + return $this->websitesDataIterator; + } +} diff --git a/app/code/Magento/Store/Model/Plugin/StoreCookie.php b/app/code/Magento/Store/Model/Plugin/StoreCookie.php index 612d35e136d7e..9fca86ab71762 100644 --- a/app/code/Magento/Store/Model/Plugin/StoreCookie.php +++ b/app/code/Magento/Store/Model/Plugin/StoreCookie.php @@ -82,12 +82,5 @@ public function beforeDispatch( $this->storeCookieManager->deleteStoreCookie($this->storeManager->getDefaultStoreView()); } } - if ($this->storeCookieManager->getStoreCodeFromCookie() === null - || $request->getParam(StoreResolverInterface::PARAM_NAME) !== null - ) { - $storeId = $this->storeResolver->getCurrentStoreId(); - $store = $this->storeRepository->getActiveStoreById($storeId); - $this->storeCookieManager->setStoreCookie($store); - } } } diff --git a/app/code/Magento/Store/Model/Store.php b/app/code/Magento/Store/Model/Store.php index 6e749df6a768d..af25957257421 100644 --- a/app/code/Magento/Store/Model/Store.php +++ b/app/code/Magento/Store/Model/Store.php @@ -1163,7 +1163,7 @@ public function isDefault() /** * Retrieve current url for store * - * @param bool|string $fromStore + * @param bool $fromStore * @return string * @SuppressWarnings(PHPMD.CyclomaticComplexity) * @SuppressWarnings(PHPMD.NPathComplexity) @@ -1223,7 +1223,7 @@ public function getCurrentUrl($fromStore = true) . (isset($storeParsedUrl['port']) ? ':' . $storeParsedUrl['port'] : '') . $storeParsedUrl['path'] . $requestStringPath - . ($currentUrlQueryParams ? '?' . http_build_query($currentUrlQueryParams, '', '&') : ''); + . ($currentUrlQueryParams ? '?' . http_build_query($currentUrlQueryParams) : ''); return $currentUrl; } @@ -1379,7 +1379,8 @@ public function getExtensionAttributes() } /** - * {@inheritdoc} + * @param \Magento\Store\Api\Data\StoreExtensionInterface $extensionAttributes + * @return $this */ public function setExtensionAttributes( \Magento\Store\Api\Data\StoreExtensionInterface $extensionAttributes diff --git a/app/code/Magento/Store/Model/StoreDimensionProvider.php b/app/code/Magento/Store/Model/StoreDimensionProvider.php index 5bc019ea6835f..17f75fb863d9c 100644 --- a/app/code/Magento/Store/Model/StoreDimensionProvider.php +++ b/app/code/Magento/Store/Model/StoreDimensionProvider.php @@ -8,7 +8,7 @@ namespace Magento\Store\Model; use Magento\Framework\Indexer\DimensionFactory; -use Magento\Framework\Indexer\Dimension\DimensionProviderInterface; +use Magento\Framework\Indexer\DimensionProviderInterface; /** * Provide a list of stores as Dimension @@ -47,7 +47,7 @@ public function __construct(StoreManagerInterface $storeManager, DimensionFactor public function getIterator(): \Traversable { foreach (array_keys($this->storeManager->getStores()) as $storeId) { - yield [self::DIMENSION_NAME => $this->dimensionFactory->create(self::DIMENSION_NAME, $storeId)]; + yield [self::DIMENSION_NAME => $this->dimensionFactory->create(self::DIMENSION_NAME, (string)$storeId)]; } } } diff --git a/app/code/Magento/Store/Model/StoreSwitcher.php b/app/code/Magento/Store/Model/StoreSwitcher.php new file mode 100644 index 0000000000000..a294b6a0d6b0a --- /dev/null +++ b/app/code/Magento/Store/Model/StoreSwitcher.php @@ -0,0 +1,58 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +declare(strict_types=1); + +namespace Magento\Store\Model; + +use Magento\Store\Api\Data\StoreInterface; +use Magento\Store\Model\StoreSwitcher\CannotSwitchStoreException; + +/** + * Handles store switching procedure and detects url for final redirect after store switching. + */ +class StoreSwitcher implements StoreSwitcherInterface +{ + /** + * @var StoreSwitcherInterface[] + */ + private $storeSwitchers; + + /** + * @param StoreSwitcherInterface[] $storeSwitchers + * @throws \Exception + */ + public function __construct(array $storeSwitchers) + { + foreach ($storeSwitchers as $switcherName => $switcherInstance) { + if (!$switcherInstance instanceof StoreSwitcherInterface) { + throw new \InvalidArgumentException( + "Store switcher '{$switcherName}' is expected to implement interface " + . StoreSwitcherInterface::class + ); + } + } + $this->storeSwitchers = $storeSwitchers; + } + + /** + * @param StoreInterface $fromStore store where we came from + * @param StoreInterface $targetStore store where to go to + * @param string $redirectUrl original url requested for redirect after switching + * @return string url to be redirected after switching + * @SuppressWarnings(PHPMD.UnusedFormalParameter) + * @throws CannotSwitchStoreException + */ + public function switch(StoreInterface $fromStore, StoreInterface $targetStore, string $redirectUrl): string + { + $targetUrl = $redirectUrl; + + foreach ($this->storeSwitchers as $storeSwitcher) { + $targetUrl = $storeSwitcher->switch($fromStore, $targetStore, $targetUrl); + } + + return $targetUrl; + } +} diff --git a/app/code/Magento/Store/Model/StoreSwitcher/CannotSwitchStoreException.php b/app/code/Magento/Store/Model/StoreSwitcher/CannotSwitchStoreException.php new file mode 100644 index 0000000000000..c6afd71cb6f01 --- /dev/null +++ b/app/code/Magento/Store/Model/StoreSwitcher/CannotSwitchStoreException.php @@ -0,0 +1,27 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +declare(strict_types=1); + +namespace Magento\Store\Model\StoreSwitcher; + +use Magento\Framework\Exception\RuntimeException; +use Magento\Framework\Phrase; + +/** + * Exception thrown if store cannot be switched. + */ +class CannotSwitchStoreException extends RuntimeException +{ + /** + * @param \Exception|null $cause + * @param Phrase|null $phrase + * @param int $code + */ + public function __construct(\Exception $cause = null, Phrase $phrase = null, int $code = 0) + { + parent::__construct($phrase ?: __('The store cannot be switched.'), $cause, $code); + } +} diff --git a/app/code/Magento/Store/Model/StoreSwitcher/CleanTargetUrl.php b/app/code/Magento/Store/Model/StoreSwitcher/CleanTargetUrl.php new file mode 100644 index 0000000000000..3328a21e8f5e1 --- /dev/null +++ b/app/code/Magento/Store/Model/StoreSwitcher/CleanTargetUrl.php @@ -0,0 +1,66 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +declare(strict_types=1); + +namespace Magento\Store\Model\StoreSwitcher; + +use Magento\Store\Api\Data\StoreInterface; +use Magento\Store\Api\StoreResolverInterface; +use Magento\Store\Model\StoreSwitcherInterface; +use Magento\Framework\Url\Helper\Data as UrlHelper; + +/** + * Remove SID, from_store, store from target url. + */ +class CleanTargetUrl implements StoreSwitcherInterface +{ + /** + * @var UrlHelper + */ + private $urlHelper; + + /** + * @var \Magento\Framework\Session\Generic + */ + private $session; + + /** + * @var \Magento\Framework\Session\SidResolverInterface + */ + private $sidResolver; + + /** + * @param UrlHelper $urlHelper + * @param \Magento\Framework\Session\Generic $session + * @param \Magento\Framework\Session\SidResolverInterface $sidResolver + */ + public function __construct( + UrlHelper $urlHelper, + \Magento\Framework\Session\Generic $session, + \Magento\Framework\Session\SidResolverInterface $sidResolver + ) { + $this->urlHelper = $urlHelper; + $this->session = $session; + $this->sidResolver = $sidResolver; + } + + /** + * @param StoreInterface $fromStore store where we came from + * @param StoreInterface $targetStore store where to go to + * @param string $redirectUrl original url requested for redirect after switching + * @return string redirect url + */ + public function switch(StoreInterface $fromStore, StoreInterface $targetStore, string $redirectUrl): string + { + $targetUrl = $redirectUrl; + $sidName = $this->sidResolver->getSessionIdQueryParam($this->session); + $targetUrl = $this->urlHelper->removeRequestParam($targetUrl, $sidName); + $targetUrl = $this->urlHelper->removeRequestParam($targetUrl, '___from_store'); + $targetUrl = $this->urlHelper->removeRequestParam($targetUrl, StoreResolverInterface::PARAM_NAME); + + return $targetUrl; + } +} diff --git a/app/code/Magento/Store/Model/StoreSwitcher/ManagePrivateContent.php b/app/code/Magento/Store/Model/StoreSwitcher/ManagePrivateContent.php new file mode 100644 index 0000000000000..8aed785641efe --- /dev/null +++ b/app/code/Magento/Store/Model/StoreSwitcher/ManagePrivateContent.php @@ -0,0 +1,66 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +declare(strict_types=1); + +namespace Magento\Store\Model\StoreSwitcher; + +use Magento\Store\Model\StoreSwitcherInterface; +use Magento\Store\Api\Data\StoreInterface; + +/** + * Set private content cookie to have actual local storage data on target store after store switching. + */ +class ManagePrivateContent implements StoreSwitcherInterface +{ + /** + * @var \Magento\Framework\Stdlib\Cookie\CookieMetadataFactory + */ + private $cookieMetadataFactory; + + /** + * @var \Magento\Framework\Stdlib\CookieManagerInterface + */ + private $cookieManager; + + /** + * @param \Magento\Framework\Stdlib\Cookie\CookieMetadataFactory $cookieMetadataFactory + * @param \Magento\Framework\Stdlib\CookieManagerInterface $cookieManager + */ + public function __construct( + \Magento\Framework\Stdlib\Cookie\CookieMetadataFactory $cookieMetadataFactory, + \Magento\Framework\Stdlib\CookieManagerInterface $cookieManager + ) { + $this->cookieMetadataFactory = $cookieMetadataFactory; + $this->cookieManager = $cookieManager; + } + + /** + * @param StoreInterface $fromStore store where we came from + * @param StoreInterface $targetStore store where to go to + * @param string $redirectUrl original url requested for redirect after switching + * @return string redirect url + * @throws CannotSwitchStoreException + */ + public function switch(StoreInterface $fromStore, StoreInterface $targetStore, string $redirectUrl): string + { + try { + $publicCookieMetadata = $this->cookieMetadataFactory->createPublicCookieMetadata() + ->setDurationOneYear() + ->setPath('/') + ->setSecure(false) + ->setHttpOnly(false); + $this->cookieManager->setPublicCookie( + \Magento\Framework\App\PageCache\Version::COOKIE_NAME, + 'should_be_updated', + $publicCookieMetadata + ); + } catch (\Exception $e) { + throw new CannotSwitchStoreException($e); + } + + return $redirectUrl; + } +} diff --git a/app/code/Magento/Store/Model/StoreSwitcher/ManageStoreCookie.php b/app/code/Magento/Store/Model/StoreSwitcher/ManageStoreCookie.php new file mode 100644 index 0000000000000..7a485be090af6 --- /dev/null +++ b/app/code/Magento/Store/Model/StoreSwitcher/ManageStoreCookie.php @@ -0,0 +1,72 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +declare(strict_types=1); + +namespace Magento\Store\Model\StoreSwitcher; + +use Magento\Store\Model\StoreSwitcherInterface; +use Magento\Store\Api\Data\StoreInterface; +use Magento\Framework\App\Http\Context as HttpContext; +use Magento\Store\Api\StoreCookieManagerInterface; +use Magento\Store\Model\StoreManagerInterface; +use Magento\Store\Model\Store; + +/** + * Manage store cookie depending on what store view customer is. + */ +class ManageStoreCookie implements StoreSwitcherInterface +{ + /** + * @var StoreCookieManagerInterface + */ + private $storeCookieManager; + + /** + * @var HttpContext + */ + private $httpContext; + + /** + * @var StoreManagerInterface + */ + private $storeManager; + + /** + * @param StoreCookieManagerInterface $storeCookieManager + * @param HttpContext $httpContext + * @param StoreManagerInterface $storeManager + */ + public function __construct( + StoreCookieManagerInterface $storeCookieManager, + HttpContext $httpContext, + StoreManagerInterface $storeManager + ) { + $this->storeCookieManager = $storeCookieManager; + $this->httpContext = $httpContext; + $this->storeManager = $storeManager; + } + + /** + * @param StoreInterface $fromStore store where we came from + * @param StoreInterface $targetStore store where to go to + * @param string $redirectUrl original url requested for redirect after switching + * @return string redirect url + */ + public function switch(StoreInterface $fromStore, StoreInterface $targetStore, string $redirectUrl): string + { + $defaultStoreView = $this->storeManager->getDefaultStoreView(); + if ($defaultStoreView !== null) { + if ($defaultStoreView->getId() === $targetStore->getId()) { + $this->storeCookieManager->deleteStoreCookie($targetStore); + } else { + $this->httpContext->setValue(Store::ENTITY, $targetStore->getCode(), $defaultStoreView->getCode()); + $this->storeCookieManager->setStoreCookie($targetStore); + } + } + + return $redirectUrl; + } +} diff --git a/app/code/Magento/Store/Model/StoreSwitcherInterface.php b/app/code/Magento/Store/Model/StoreSwitcherInterface.php new file mode 100644 index 0000000000000..ee6fb0b4763c6 --- /dev/null +++ b/app/code/Magento/Store/Model/StoreSwitcherInterface.php @@ -0,0 +1,26 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +declare(strict_types=1); + +namespace Magento\Store\Model; + +use Magento\Store\Api\Data\StoreInterface; +use Magento\Store\Model\StoreSwitcher\CannotSwitchStoreException; + +/** + * Handles store switching procedure and detects url for final redirect after store switching. + */ +interface StoreSwitcherInterface +{ + /** + * @param StoreInterface $fromStore store where we came from + * @param StoreInterface $targetStore store where to go to + * @param string $redirectUrl original url requested for redirect after switching + * @return string url to be redirected after switching + * @throws CannotSwitchStoreException + */ + public function switch(StoreInterface $fromStore, StoreInterface $targetStore, string $redirectUrl): string; +} diff --git a/app/code/Magento/Store/Test/Mftf/Data/StoreData.xml b/app/code/Magento/Store/Test/Mftf/Data/StoreData.xml index 4e3c724572e79..9c3330ba74140 100644 --- a/app/code/Magento/Store/Test/Mftf/Data/StoreData.xml +++ b/app/code/Magento/Store/Test/Mftf/Data/StoreData.xml @@ -18,7 +18,7 @@ <data key="is_active">1</data> <data key="store_id">null</data> <data key="store_action">add</data> - <data key="store_type">group</data> + <data key="store_type">store</data> <requiredEntity type="storeGroup">customStoreGroup</requiredEntity> </entity> <entity name="customStoreEN" type="store"> @@ -27,7 +27,7 @@ <data key="is_active">1</data> <data key="store_id">null</data> <data key="store_action">add</data> - <data key="store_type">group</data> + <data key="store_type">store</data> <requiredEntity type="storeGroup">customStoreGroup</requiredEntity> </entity> <entity name="customStoreFR" type="store"> @@ -46,7 +46,7 @@ <data key="is_active">1</data> <data key="store_id">null</data> <data key="store_action">add</data> - <data key="store_type">group</data> + <data key="store_type">store</data> <requiredEntity type="storeGroup">customStoreGroup</requiredEntity> </entity> </entities> diff --git a/app/code/Magento/Store/Test/Mftf/composer.json b/app/code/Magento/Store/Test/Mftf/composer.json deleted file mode 100644 index 81305cf049e6c..0000000000000 --- a/app/code/Magento/Store/Test/Mftf/composer.json +++ /dev/null @@ -1,24 +0,0 @@ -{ - "name": "magento/functional-test-module-store", - "description": "N/A", - "config": { - "sort-packages": true - }, - "require": { - "php": "~7.1.3||~7.2.0", - "magento/magento2-functional-testing-framework": "2.2.0", - "magento/functional-test-module-catalog": "100.0.0-dev", - "magento/functional-test-module-config": "100.0.0-dev", - "magento/functional-test-module-directory": "100.0.0-dev", - "magento/functional-test-module-media-storage": "100.0.0-dev", - "magento/functional-test-module-ui": "100.0.0-dev" - }, - "suggest": { - "magento/functional-test-module-deploy": "100.0.0-dev" - }, - "type": "magento2-test", - "license": [ - "OSL-3.0", - "AFL-3.0" - ] -} diff --git a/app/code/Magento/Store/Test/Unit/Block/SwitcherTest.php b/app/code/Magento/Store/Test/Unit/Block/SwitcherTest.php index 8b4799d2b3437..aca3525a4400e 100644 --- a/app/code/Magento/Store/Test/Unit/Block/SwitcherTest.php +++ b/app/code/Magento/Store/Test/Unit/Block/SwitcherTest.php @@ -25,6 +25,12 @@ class SwitcherTest extends \PHPUnit\Framework\TestCase /** @var \Magento\Framework\UrlInterface|\PHPUnit_Framework_MockObject_MockObject */ protected $urlBuilder; + /** @var \Magento\Store\Api\Data\StoreInterface|\PHPUnit_Framework_MockObject_MockObject */ + private $store; + + /** + * @return void + */ protected function setUp() { $this->storeManager = $this->getMockBuilder(\Magento\Store\Model\StoreManagerInterface::class)->getMock(); @@ -33,6 +39,9 @@ protected function setUp() $this->context->expects($this->any())->method('getStoreManager')->will($this->returnValue($this->storeManager)); $this->context->expects($this->any())->method('getUrlBuilder')->will($this->returnValue($this->urlBuilder)); $this->corePostDataHelper = $this->createMock(\Magento\Framework\Data\Helper\PostHelper::class); + $this->store = $this->getMockBuilder(\Magento\Store\Api\Data\StoreInterface::class) + ->disableOriginalConstructor() + ->getMockForAbstractClass(); $this->switcher = (new ObjectManager($this))->getObject( \Magento\Store\Block\Switcher::class, [ @@ -42,6 +51,9 @@ protected function setUp() ); } + /** + * @return void + */ public function testGetTargetStorePostData() { $store = $this->getMockBuilder(\Magento\Store\Model\Store::class) @@ -50,20 +62,30 @@ public function testGetTargetStorePostData() $store->expects($this->any()) ->method('getCode') ->willReturn('new-store'); - $storeSwitchUrl = 'http://domain.com/stores/store/switch'; + $storeSwitchUrl = 'http://domain.com/stores/store/redirect'; $store->expects($this->atLeastOnce()) ->method('getCurrentUrl') - ->with(true) + ->with(false) + ->willReturn($storeSwitchUrl); + $this->storeManager->expects($this->once()) + ->method('getStore') + ->willReturn($this->store); + $this->store->expects($this->once()) + ->method('getCode') + ->willReturn('old-store'); + $this->urlBuilder->expects($this->once()) + ->method('getUrl') ->willReturn($storeSwitchUrl); $this->corePostDataHelper->expects($this->any()) ->method('getPostData') - ->with($storeSwitchUrl, ['___store' => 'new-store']); + ->with($storeSwitchUrl, ['___store' => 'new-store', 'uenc' => null, '___from_store' => 'old-store']); $this->switcher->getTargetStorePostData($store); } /** * @dataProvider isStoreInUrlDataProvider + * @param bool $isUseStoreInUrl */ public function testIsStoreInUrl($isUseStoreInUrl) { diff --git a/app/code/Magento/Store/Test/Unit/Controller/Store/SwitchActionTest.php b/app/code/Magento/Store/Test/Unit/Controller/Store/SwitchActionTest.php index 1e7b2691a0084..0d337b91c192a 100644 --- a/app/code/Magento/Store/Test/Unit/Controller/Store/SwitchActionTest.php +++ b/app/code/Magento/Store/Test/Unit/Controller/Store/SwitchActionTest.php @@ -8,13 +8,15 @@ use Magento\Framework\App\Http\Context as HttpContext; use Magento\Store\Api\StoreCookieManagerInterface; use Magento\Store\Api\StoreRepositoryInterface; -use Magento\Store\Model\Store; -use Magento\Store\Model\StoreResolver; use Magento\Store\Model\StoreManagerInterface; use Magento\Framework\TestFramework\Unit\Helper\ObjectManager; +use Magento\Store\Model\StoreResolver; +use Magento\Store\Model\StoreSwitcher; +use Magento\Store\Model\StoreSwitcherInterface; /** * Test class for \Magento\Store\Controller\Store\SwitchAction + * @SuppressWarnings(PHPMD.CouplingBetweenObjects) */ class SwitchActionTest extends \PHPUnit\Framework\TestCase { @@ -58,6 +60,12 @@ class SwitchActionTest extends \PHPUnit\Framework\TestCase */ private $redirectMock; + /** @var StoreSwitcherInterface|\PHPUnit_Framework_MockObject_MockObject */ + private $storeSwitcher; + + /** + * @return void + */ protected function setUp() { $this->storeManagerMock = $this->getMockBuilder(\Magento\Store\Model\StoreManagerInterface::class)->getMock(); @@ -73,6 +81,10 @@ protected function setUp() ->getMockForAbstractClass(); $this->redirectMock = $this->getMockBuilder(\Magento\Framework\App\Response\RedirectInterface::class)->getMock(); + $this->storeSwitcher = $this->getMockBuilder(StoreSwitcher::class) + ->disableOriginalConstructor() + ->setMethods(['switch']) + ->getMock(); $this->model = (new ObjectManager($this))->getObject( \Magento\Store\Controller\Store\SwitchAction::class, @@ -83,81 +95,48 @@ protected function setUp() 'storeManager' => $this->storeManagerMock, '_request' => $this->requestMock, '_response' => $this->responseMock, - '_redirect' => $this->redirectMock + '_redirect' => $this->redirectMock, + 'storeSwitcher' => $this->storeSwitcher ] ); } - public function testExecuteSuccessWithoutUseStoreInUrl() + /** + * @return void + */ + public function testExecute() { $storeToSwitchToCode = 'sv2'; $defaultStoreViewCode = 'default'; $expectedRedirectUrl = "magento.com/{$storeToSwitchToCode}"; - $currentActiveStoreMock = $this->getMockBuilder(\Magento\Store\Api\Data\StoreInterface::class)->getMock(); $defaultStoreViewMock = $this->getMockBuilder(\Magento\Store\Api\Data\StoreInterface::class)->getMock(); $storeToSwitchToMock = $this->getMockBuilder(\Magento\Store\Api\Data\StoreInterface::class) ->disableOriginalConstructor() ->setMethods(['isUseStoreInUrl']) ->getMockForAbstractClass(); - $this->storeManagerMock->expects($this->once())->method('getStore')->willReturn($currentActiveStoreMock); - $this->requestMock->expects($this->once())->method('getParam')->willReturn($storeToSwitchToCode); + $this->requestMock->expects($this->any())->method('getParam')->willReturnMap( + [ + [StoreResolver::PARAM_NAME, null, $storeToSwitchToCode], + ['___from_store', null, $defaultStoreViewCode] + ] + ); $this->storeRepositoryMock ->expects($this->once()) - ->method('getActiveStoreByCode') - ->willReturn($storeToSwitchToMock); - $this->storeManagerMock - ->expects($this->once()) - ->method('getDefaultStoreView') + ->method('get') + ->with($defaultStoreViewCode) ->willReturn($defaultStoreViewMock); - $defaultStoreViewMock->expects($this->once())->method('getId')->willReturn($defaultStoreViewCode); - $storeToSwitchToMock->expects($this->once())->method('getId')->willReturn($storeToSwitchToCode); - $storeToSwitchToMock->expects($this->once())->method('isUseStoreInUrl')->willReturn(false); - $this->redirectMock->expects($this->once())->method('getRedirectUrl')->willReturn($expectedRedirectUrl); - $this->responseMock->expects($this->once())->method('setRedirect')->with($expectedRedirectUrl); - - $this->model->execute(); - } - - public function testExecuteSuccessWithUseStoreInUrl() - { - $currentActiveStoreCode = 'sv1'; - $storeToSwitchToCode = 'sv2'; - $defaultStoreViewCode = 'default'; - $originalRedirectUrl = "magento.com/{$currentActiveStoreCode}/test-page/test-sub-page"; - $expectedRedirectUrl = "magento.com/{$storeToSwitchToCode}/test-page/test-sub-page"; - $currentActiveStoreMock = $this->getMockBuilder(\Magento\Store\Api\Data\StoreInterface::class) - ->disableOriginalConstructor() - ->setMethods(['isUseStoreInUrl', 'getBaseUrl']) - ->getMockForAbstractClass(); - $defaultStoreViewMock = $this->getMockBuilder(\Magento\Store\Api\Data\StoreInterface::class)->getMock(); - $storeToSwitchToMock = $this->getMockBuilder(\Magento\Store\Api\Data\StoreInterface::class) - ->disableOriginalConstructor() - ->setMethods(['isUseStoreInUrl', 'getBaseUrl']) - ->getMockForAbstractClass(); - - $this->storeManagerMock->expects($this->once())->method('getStore')->willReturn($currentActiveStoreMock); - $this->requestMock->expects($this->once())->method('getParam')->willReturn($storeToSwitchToCode); $this->storeRepositoryMock ->expects($this->once()) ->method('getActiveStoreByCode') + ->with($storeToSwitchToCode) ->willReturn($storeToSwitchToMock); - $this->storeManagerMock - ->expects($this->once()) - ->method('getDefaultStoreView') - ->willReturn($defaultStoreViewMock); - $defaultStoreViewMock->expects($this->once())->method('getId')->willReturn($defaultStoreViewCode); - $storeToSwitchToMock->expects($this->once())->method('getId')->willReturn($storeToSwitchToCode); - $storeToSwitchToMock->expects($this->once())->method('isUseStoreInUrl')->willReturn(true); - $this->redirectMock->expects($this->any())->method('getRedirectUrl')->willReturn($originalRedirectUrl); - $currentActiveStoreMock - ->expects($this->any()) - ->method('getBaseUrl') - ->willReturn("magento.com/{$currentActiveStoreCode}"); - $storeToSwitchToMock - ->expects($this->once()) - ->method('getBaseUrl') - ->willReturn("magento.com/{$storeToSwitchToCode}"); + $this->storeSwitcher->expects($this->once()) + ->method('switch') + ->with($defaultStoreViewMock, $storeToSwitchToMock, $expectedRedirectUrl) + ->willReturn($expectedRedirectUrl); + + $this->redirectMock->expects($this->once())->method('getRedirectUrl')->willReturn($expectedRedirectUrl); $this->responseMock->expects($this->once())->method('setRedirect')->with($expectedRedirectUrl); $this->model->execute(); diff --git a/app/code/Magento/Store/Test/Unit/Model/Plugin/StoreCookieTest.php b/app/code/Magento/Store/Test/Unit/Model/Plugin/StoreCookieTest.php index e56b5c7fcaa19..0454c0096a6ab 100644 --- a/app/code/Magento/Store/Test/Unit/Model/Plugin/StoreCookieTest.php +++ b/app/code/Magento/Store/Test/Unit/Model/Plugin/StoreCookieTest.php @@ -110,6 +110,9 @@ protected function setUp() ); } + /** + * @return void + */ public function testBeforeDispatchNoSuchEntity() { $storeCode = 'store'; @@ -125,14 +128,13 @@ public function testBeforeDispatchNoSuchEntity() $this->storeCookieManagerMock->expects($this->once()) ->method('deleteStoreCookie') ->with($this->storeMock); - $this->requestMock->expects($this->atLeastOnce()) - ->method('getParam') - ->with(StoreResolverInterface::PARAM_NAME) - ->willReturn(null); $this->plugin->beforeDispatch($this->subjectMock, $this->requestMock); } + /** + * @return void + */ public function testBeforeDispatchStoreIsInactive() { $storeCode = 'store'; @@ -148,14 +150,13 @@ public function testBeforeDispatchStoreIsInactive() $this->storeCookieManagerMock->expects($this->once()) ->method('deleteStoreCookie') ->with($this->storeMock); - $this->requestMock->expects($this->atLeastOnce()) - ->method('getParam') - ->with(StoreResolverInterface::PARAM_NAME) - ->willReturn(null); $this->plugin->beforeDispatch($this->subjectMock, $this->requestMock); } + /** + * @return void + */ public function testBeforeDispatchInvalidArgument() { $storeCode = 'store'; @@ -171,14 +172,13 @@ public function testBeforeDispatchInvalidArgument() $this->storeCookieManagerMock->expects($this->once()) ->method('deleteStoreCookie') ->with($this->storeMock); - $this->requestMock->expects($this->atLeastOnce()) - ->method('getParam') - ->with(StoreResolverInterface::PARAM_NAME) - ->willReturn(null); $this->plugin->beforeDispatch($this->subjectMock, $this->requestMock); } + /** + * @return void + */ public function testBeforeDispatchNoStoreCookie() { $storeCode = null; @@ -194,21 +194,12 @@ public function testBeforeDispatchNoStoreCookie() ->method('deleteStoreCookie') ->with($this->storeMock); - $this->storeResolverMock->expects($this->atLeastOnce()) - ->method('getCurrentStoreId') - ->willReturn(1); - - $this->storeRepositoryMock->expects($this->atLeastOnce()) - ->method('getActiveStoreById') - ->willReturn($this->storeMock); - - $this->storeCookieManagerMock->expects($this->atLeastOnce()) - ->method('setStoreCookie') - ->with($this->storeMock); - $this->plugin->beforeDispatch($this->subjectMock, $this->requestMock); } + /** + * @return void + */ public function testBeforeDispatchWithStoreRequestParam() { $storeCode = 'store'; @@ -222,23 +213,6 @@ public function testBeforeDispatchWithStoreRequestParam() ->method('deleteStoreCookie') ->with($this->storeMock); - $this->requestMock->expects($this->atLeastOnce()) - ->method('getParam') - ->with(StoreResolverInterface::PARAM_NAME) - ->willReturn($storeCode); - - $this->storeResolverMock->expects($this->atLeastOnce()) - ->method('getCurrentStoreId') - ->willReturn(1); - - $this->storeRepositoryMock->expects($this->atLeastOnce()) - ->method('getActiveStoreById') - ->willReturn($this->storeMock); - - $this->storeCookieManagerMock->expects($this->atLeastOnce()) - ->method('setStoreCookie') - ->with($this->storeMock); - $this->plugin->beforeDispatch($this->subjectMock, $this->requestMock); } } diff --git a/app/code/Magento/Store/Test/Unit/Model/StoreTest.php b/app/code/Magento/Store/Test/Unit/Model/StoreTest.php index 4cbf78d0d6471..f98cf5d892e07 100644 --- a/app/code/Magento/Store/Test/Unit/Model/StoreTest.php +++ b/app/code/Magento/Store/Test/Unit/Model/StoreTest.php @@ -43,6 +43,9 @@ class StoreTest extends \PHPUnit\Framework\TestCase */ private $urlModifierMock; + /** + * @return void + */ protected function setUp() { $this->objectManagerHelper = new \Magento\Framework\TestFramework\Unit\Helper\ObjectManager($this); @@ -105,6 +108,9 @@ public function loadDataProvider() ]; } + /** + * @return void + */ public function testSetWebsite() { $website = $this->createPartialMock(\Magento\Store\Model\Website::class, ['getId', '__wakeup']); @@ -115,6 +121,9 @@ public function testSetWebsite() $this->assertEquals(2, $model->getWebsiteId()); } + /** + * @return void + */ public function testGetWebsite() { $websiteId = 2; @@ -138,6 +147,9 @@ public function testGetWebsite() $this->assertEquals($website, $model->getWebsite()); } + /** + * @return void + */ public function testGetWebsiteIfWebsiteIsNotExist() { $websiteRepository = $this->getMockBuilder(\Magento\Store\Api\WebsiteRepositoryInterface::class) @@ -156,6 +168,9 @@ public function testGetWebsiteIfWebsiteIsNotExist() $this->assertFalse($model->getWebsite()); } + /** + * @return void + */ public function testGetGroup() { $groupId = 2; @@ -179,6 +194,9 @@ public function testGetGroup() $this->assertEquals($group, $model->getGroup()); } + /** + * @return void + */ public function testGetGroupIfGroupIsNotExist() { $groupRepository = $this->getMockBuilder(\Magento\Store\Api\GroupRepositoryInterface::class) @@ -197,6 +215,9 @@ public function testGetGroupIfGroupIsNotExist() $this->assertFalse($model->getGroup()); } + /** + * @return void + */ public function testGetUrl() { $params = ['_scope_to_url' => true]; @@ -325,6 +346,9 @@ public function getBaseUrlDataProvider() ]; } + /** + * @return void + */ public function testGetBaseUrlEntryPoint() { $expectedPath = 'web/unsecure/base_link_url'; @@ -377,10 +401,11 @@ public function testGetBaseUrlWrongType() * @param boolean $secure * @param string $url * @param string $expected + * @param bool|string $fromStore */ - public function testGetCurrentUrl($secure, $url, $expected) + public function testGetCurrentUrl($secure, $url, $expected, $fromStore) { - $defaultStore = $this->createPartialMock(\Magento\Store\Model\Store::class, [ + $defaultStore = $this->createPartialMock(Store::class, [ 'getId', 'isCurrentlySecure', '__wakeup' @@ -393,15 +418,31 @@ public function testGetCurrentUrl($secure, $url, $expected) $config = $this->getMockForAbstractClass(\Magento\Framework\App\Config\ReinitableConfigInterface::class); - $this->requestMock->expects($this->atLeastOnce())->method('getRequestString')->will($this->returnValue('')); + $requestString = preg_replace( + '/http(s?)\:\/\/[a-z0-9\-]+\//i', + '', + $url + ); + $this->requestMock + ->expects($this->atLeastOnce()) + ->method('getRequestString') + ->willReturn($requestString); $this->requestMock->expects($this->atLeastOnce())->method('getQueryValue')->will($this->returnValue([ 'SID' => 'sid' ])); $urlMock = $this->getMockForAbstractClass(\Magento\Framework\UrlInterface::class); - $urlMock->expects($this->atLeastOnce())->method('setScope')->will($this->returnSelf()); - $urlMock->expects($this->any())->method('getUrl') - ->will($this->returnValue($url)); + $urlMock + ->expects($this->atLeastOnce()) + ->method('setScope') + ->will($this->returnSelf()); + $urlMock->expects($this->any()) + ->method('getUrl') + ->will($this->returnValue(str_replace($requestString, '', $url))); + $urlMock + ->expects($this->atLeastOnce()) + ->method('escape') + ->willReturnArgument(0); $storeManager = $this->getMockForAbstractClass(\Magento\Store\Model\StoreManagerInterface::class); $storeManager->expects($this->any()) @@ -416,7 +457,7 @@ public function testGetCurrentUrl($secure, $url, $expected) $model->setStoreId(2); $model->setCode('scope_code'); - $this->assertEquals($expected, $model->getCurrentUrl(false)); + $this->assertEquals($expected, $model->getCurrentUrl($fromStore)); } /** @@ -425,9 +466,31 @@ public function testGetCurrentUrl($secure, $url, $expected) public function getCurrentUrlDataProvider() { return [ - [true, 'http://test/url', 'http://test/url?SID=sid&___store=scope_code'], - [true, 'http://test/url?SID=sid1&___store=scope', 'http://test/url?SID=sid&___store=scope_code'], - [false, 'https://test/url', 'https://test/url?SID=sid&___store=scope_code'] + [ + true, + 'http://test/url', + 'http://test/url?SID=sid&___store=scope_code', + false + ], + [ + true, + 'http://test/url?SID=sid1&___store=scope', + 'http://test/url?SID=sid&___store=scope_code', + false + ], + [ + false, + 'https://test/url', + 'https://test/url?SID=sid&___store=scope_code', + false + ], + [ + true, + 'http://test/u/u.2?___store=scope_code', + 'http://test/u/u.2?' + . '___store=scope_code&SID=sid&___from_store=old-store', + 'old-store' + ] ]; } @@ -487,6 +550,9 @@ public function getBaseCurrencyDataProvider() ]; } + /** + * @return void + */ public function testGetAllowedCurrencies() { $currencyPath = 'cur/ren/cy/path'; @@ -612,11 +678,17 @@ public function testGetBaseStaticDir() $this->assertEquals($expectedResult, $this->store->getBaseStaticDir()); } + /** + * @return void + */ public function testGetScopeType() { $this->assertEquals(ScopeInterface::SCOPE_STORE, $this->store->getScopeType()); } + /** + * @return void + */ public function testGetScopeTypeName() { $this->assertEquals('Store View', $this->store->getScopeTypeName()); diff --git a/app/code/Magento/Store/Test/Unit/Url/Plugin/RouteParamsResolverTest.php b/app/code/Magento/Store/Test/Unit/Url/Plugin/RouteParamsResolverTest.php index ed9ac7ebe438a..f31acd40a2e69 100644 --- a/app/code/Magento/Store/Test/Unit/Url/Plugin/RouteParamsResolverTest.php +++ b/app/code/Magento/Store/Test/Unit/Url/Plugin/RouteParamsResolverTest.php @@ -22,6 +22,11 @@ class RouteParamsResolverTest extends \PHPUnit\Framework\TestCase */ protected $queryParamsResolverMock; + /** + * @var \PHPUnit_Framework_MockObject_MockObject|\Magento\Store\Model\Store + */ + protected $storeMock; + /** * @var \Magento\Store\Url\Plugin\RouteParamsResolver */ @@ -30,7 +35,19 @@ class RouteParamsResolverTest extends \PHPUnit\Framework\TestCase protected function setUp() { $this->scopeConfigMock = $this->createMock(\Magento\Framework\App\Config\ScopeConfigInterface::class); + + $this->storeMock = $this->getMockBuilder(\Magento\Store\Model\Store::class) + ->setMethods(['getCode']) + ->disableOriginalConstructor() + ->getMock(); + $this->storeMock->expects($this->any())->method('getCode')->willReturn('custom_store'); + $this->storeManagerMock = $this->createMock(\Magento\Store\Model\StoreManagerInterface::class); + $this->storeManagerMock + ->expects($this->once()) + ->method('getStore') + ->willReturn($this->storeMock); + $this->queryParamsResolverMock = $this->createMock(\Magento\Framework\Url\QueryParamsResolverInterface::class); $this->model = new \Magento\Store\Url\Plugin\RouteParamsResolver( $this->scopeConfigMock, @@ -42,6 +59,8 @@ protected function setUp() public function testBeforeSetRouteParamsScopeInParams() { $storeCode = 'custom_store'; + $data = ['_scope' => $storeCode, '_scope_to_url' => true]; + $this->scopeConfigMock ->expects($this->once()) ->method('getValue') @@ -52,7 +71,7 @@ public function testBeforeSetRouteParamsScopeInParams() ) ->will($this->returnValue(false)); $this->storeManagerMock->expects($this->any())->method('hasSingleStore')->willReturn(false); - $data = ['_scope' => $storeCode, '_scope_to_url' => true]; + /** @var \PHPUnit_Framework_MockObject_MockObject $routeParamsResolverMock */ $routeParamsResolverMock = $this->getMockBuilder(\Magento\Framework\Url\RouteParamsResolver::class) ->setMethods(['setScope', 'getScope']) @@ -61,7 +80,7 @@ public function testBeforeSetRouteParamsScopeInParams() $routeParamsResolverMock->expects($this->once())->method('setScope')->with($storeCode); $routeParamsResolverMock->expects($this->once())->method('getScope')->willReturn($storeCode); - $this->queryParamsResolverMock->expects($this->once())->method('setQueryParam')->with('___store', $storeCode); + $this->queryParamsResolverMock->expects($this->never())->method('setQueryParam'); $this->model->beforeSetRouteParams( $routeParamsResolverMock, @@ -72,6 +91,8 @@ public function testBeforeSetRouteParamsScopeInParams() public function testBeforeSetRouteParamsScopeUseStoreInUrl() { $storeCode = 'custom_store'; + $data = ['_scope' => $storeCode, '_scope_to_url' => true]; + $this->scopeConfigMock ->expects($this->once()) ->method('getValue') @@ -81,8 +102,9 @@ public function testBeforeSetRouteParamsScopeUseStoreInUrl() $storeCode ) ->will($this->returnValue(true)); + $this->storeManagerMock->expects($this->any())->method('hasSingleStore')->willReturn(false); - $data = ['_scope' => $storeCode, '_scope_to_url' => true]; + /** @var \PHPUnit_Framework_MockObject_MockObject $routeParamsResolverMock */ $routeParamsResolverMock = $this->getMockBuilder(\Magento\Framework\Url\RouteParamsResolver::class) ->setMethods(['setScope', 'getScope']) @@ -91,7 +113,7 @@ public function testBeforeSetRouteParamsScopeUseStoreInUrl() $routeParamsResolverMock->expects($this->once())->method('setScope')->with($storeCode); $routeParamsResolverMock->expects($this->once())->method('getScope')->willReturn($storeCode); - $this->queryParamsResolverMock->expects($this->never())->method('setQueryParam'); + $this->queryParamsResolverMock->expects($this->once())->method('setQueryParam')->with('___store', $storeCode); $this->model->beforeSetRouteParams( $routeParamsResolverMock, @@ -102,6 +124,8 @@ public function testBeforeSetRouteParamsScopeUseStoreInUrl() public function testBeforeSetRouteParamsSingleStore() { $storeCode = 'custom_store'; + $data = ['_scope' => $storeCode, '_scope_to_url' => true]; + $this->scopeConfigMock ->expects($this->once()) ->method('getValue') @@ -112,7 +136,7 @@ public function testBeforeSetRouteParamsSingleStore() ) ->will($this->returnValue(false)); $this->storeManagerMock->expects($this->any())->method('hasSingleStore')->willReturn(true); - $data = ['_scope' => $storeCode, '_scope_to_url' => true]; + /** @var \PHPUnit_Framework_MockObject_MockObject $routeParamsResolverMock */ $routeParamsResolverMock = $this->getMockBuilder(\Magento\Framework\Url\RouteParamsResolver::class) ->setMethods(['setScope', 'getScope']) @@ -132,6 +156,8 @@ public function testBeforeSetRouteParamsSingleStore() public function testBeforeSetRouteParamsNoScopeInParams() { $storeCode = 'custom_store'; + $data = ['_scope_to_url' => true]; + $this->scopeConfigMock ->expects($this->once()) ->method('getValue') @@ -140,17 +166,10 @@ public function testBeforeSetRouteParamsNoScopeInParams() \Magento\Store\Model\ScopeInterface::SCOPE_STORE, $storeCode ) - ->will($this->returnValue(false)); + ->will($this->returnValue(true)); + $this->storeManagerMock->expects($this->any())->method('hasSingleStore')->willReturn(false); - /** @var \PHPUnit_Framework_MockObject_MockObject| $routeParamsResolverMock */ - $storeMock = $this->getMockBuilder(\Magento\Store\Model\Store::class) - ->setMethods(['getCode']) - ->disableOriginalConstructor() - ->getMock(); - $storeMock->expects($this->any())->method('getCode')->willReturn($storeCode); - $this->storeManagerMock->expects($this->any())->method('getStore')->willReturn($storeMock); - $data = ['_scope_to_url' => true]; /** @var \PHPUnit_Framework_MockObject_MockObject $routeParamsResolverMock */ $routeParamsResolverMock = $this->getMockBuilder(\Magento\Framework\Url\RouteParamsResolver::class) ->setMethods(['setScope', 'getScope']) diff --git a/app/code/Magento/Store/Url/Plugin/RouteParamsResolver.php b/app/code/Magento/Store/Url/Plugin/RouteParamsResolver.php index c4f8a31430963..468352af78cbc 100644 --- a/app/code/Magento/Store/Url/Plugin/RouteParamsResolver.php +++ b/app/code/Magento/Store/Url/Plugin/RouteParamsResolver.php @@ -6,6 +6,7 @@ namespace Magento\Store\Url\Plugin; use \Magento\Store\Model\Store; +use \Magento\Store\Api\Data\StoreInterface; use \Magento\Store\Model\ScopeInterface as StoreScopeInterface; /** @@ -51,6 +52,8 @@ public function __construct( * @param \Magento\Framework\Url\RouteParamsResolver $subject * @param array $data * @param bool $unsetOldParams + * @throws \Magento\Framework\Exception\NoSuchEntityException + * * @return array */ public function beforeSetRouteParams( @@ -63,13 +66,19 @@ public function beforeSetRouteParams( unset($data['_scope']); } if (isset($data['_scope_to_url']) && (bool)$data['_scope_to_url'] === true) { - $storeCode = $subject->getScope() ?: $this->storeManager->getStore()->getCode(); + /** @var StoreInterface $currentScope */ + $currentScope = $subject->getScope(); + $storeCode = $currentScope && $currentScope instanceof StoreInterface ? + $currentScope->getCode() : + $this->storeManager->getStore()->getCode(); + $useStoreInUrl = $this->scopeConfig->getValue( Store::XML_PATH_STORE_IN_URL, StoreScopeInterface::SCOPE_STORE, $storeCode ); - if (!$useStoreInUrl && !$this->storeManager->hasSingleStore()) { + + if ($useStoreInUrl && !$this->storeManager->hasSingleStore()) { $this->queryParamsResolver->setQueryParam('___store', $storeCode); } } diff --git a/app/code/Magento/Store/etc/di.xml b/app/code/Magento/Store/etc/di.xml index 27133de270e2f..5f088558b41d9 100644 --- a/app/code/Magento/Store/etc/di.xml +++ b/app/code/Magento/Store/etc/di.xml @@ -25,6 +25,14 @@ <preference for="Magento\Framework\App\ScopeFallbackResolverInterface" type="Magento\Store\Model\ScopeFallbackResolver"/> <preference for="Magento\Framework\App\ScopeTreeProviderInterface" type="Magento\Store\Model\ScopeTreeProvider"/> <preference for="Magento\Framework\App\ScopeValidatorInterface" type="Magento\Store\Model\ScopeValidator"/> + <preference for="Magento\Store\Model\StoreSwitcherInterface" type="Magento\Store\Model\StoreSwitcher" /> + <type name="Magento\Framework\App\Http\Context"> + <arguments> + <argument name="default" xsi:type="array"> + <item name="website" xsi:type="string">0</item> + </argument> + </arguments> + </type> <type name="Magento\Framework\App\Response\Http"> <plugin name="genericHeaderPlugin" type="Magento\Framework\App\Response\HeaderManager"/> </type> @@ -417,4 +425,13 @@ </argument> </arguments> </type> + <type name="Magento\Store\Model\StoreSwitcher"> + <arguments> + <argument name="storeSwitchers" xsi:type="array"> + <item name="cleanTargetUrl" xsi:type="object">Magento\Store\Model\StoreSwitcher\CleanTargetUrl</item> + <item name="manageStoreCookie" xsi:type="object">Magento\Store\Model\StoreSwitcher\ManageStoreCookie</item> + <item name="managePrivateContent" xsi:type="object">Magento\Store\Model\StoreSwitcher\ManagePrivateContent</item> + </argument> + </arguments> + </type> </config> diff --git a/app/code/Magento/StoreGraphQl/Test/Mftf/composer.json b/app/code/Magento/StoreGraphQl/Test/Mftf/composer.json deleted file mode 100644 index 10407d0dc179c..0000000000000 --- a/app/code/Magento/StoreGraphQl/Test/Mftf/composer.json +++ /dev/null @@ -1,20 +0,0 @@ -{ - "name": "magento/functional-test-module-store-graph-ql", - "description": "N/A", - "config": { - "sort-packages": true - }, - "require": { - "php": "~7.1.3||~7.2.0", - "magento/magento2-functional-testing-framework": "2.2.0" - }, - "suggest": { - "magento/functional-test-module-graph-ql": "100.0.0-dev", - "magento/functional-test-module-catalog-graph-ql": "100.0.0-dev" - }, - "type": "magento2-test", - "license": [ - "OSL-3.0", - "AFL-3.0" - ] -} diff --git a/app/code/Magento/Swagger/Test/Mftf/composer.json b/app/code/Magento/Swagger/Test/Mftf/composer.json deleted file mode 100644 index a997257192fce..0000000000000 --- a/app/code/Magento/Swagger/Test/Mftf/composer.json +++ /dev/null @@ -1,16 +0,0 @@ -{ - "name": "magento/functional-test-module-swagger", - "description": "N/A", - "config": { - "sort-packages": true - }, - "require": { - "php": "~7.1.3||~7.2.0", - "magento/magento2-functional-testing-framework": "2.2.0" - }, - "type": "magento2-test", - "license": [ - "OSL-3.0", - "AFL-3.0" - ] -} diff --git a/app/code/Magento/SwaggerWebapi/Test/Mftf/composer.json b/app/code/Magento/SwaggerWebapi/Test/Mftf/composer.json deleted file mode 100644 index 22ed346ef2081..0000000000000 --- a/app/code/Magento/SwaggerWebapi/Test/Mftf/composer.json +++ /dev/null @@ -1,17 +0,0 @@ -{ - "name": "magento/functional-test-module-swagger-webapi", - "description": "N/A", - "config": { - "sort-packages": true - }, - "require": { - "php": "~7.1.3||~7.2.0", - "magento/magento2-functional-testing-framework": "2.2.0", - "magento/functional-test-module-swagger": "100.0.0-dev" - }, - "type": "magento2-test", - "license": [ - "OSL-3.0", - "AFL-3.0" - ] -} diff --git a/app/code/Magento/SwaggerWebapiAsync/Test/Mftf/composer.json b/app/code/Magento/SwaggerWebapiAsync/Test/Mftf/composer.json deleted file mode 100644 index fe20e7a539d03..0000000000000 --- a/app/code/Magento/SwaggerWebapiAsync/Test/Mftf/composer.json +++ /dev/null @@ -1,19 +0,0 @@ -{ - "name": "magento/functional-test-module-swagger-webapi-async", - "description": "N/A", - "config": { - "sort-packages": true - }, - "require": { - "php": "~7.1.3||~7.2.0", - "magento/magento2-functional-testing-framework": "2.2.0", - "magento/functional-test-module-swagger": "100.0.0-dev" - }, - "suggest": { - "magento/functional-test-module-config": "100.0.0-dev" - }, - "type": "magento2-test", - "license": [ - "proprietary" - ] -} diff --git a/app/code/Magento/SwaggerWebapiAsync/composer.json b/app/code/Magento/SwaggerWebapiAsync/composer.json index 5ca538636b38a..3735bcd0ee458 100644 --- a/app/code/Magento/SwaggerWebapiAsync/composer.json +++ b/app/code/Magento/SwaggerWebapiAsync/composer.json @@ -14,7 +14,8 @@ }, "type": "magento2-module", "license": [ - "proprietary" + "OSL-3.0", + "AFL-3.0" ], "autoload": { "files": [ diff --git a/app/code/Magento/Swatches/Test/Mftf/ActionGroup/ColorPickerActionGroup.xml b/app/code/Magento/Swatches/Test/Mftf/ActionGroup/ColorPickerActionGroup.xml new file mode 100644 index 0000000000000..f8cfa3071ce0f --- /dev/null +++ b/app/code/Magento/Swatches/Test/Mftf/ActionGroup/ColorPickerActionGroup.xml @@ -0,0 +1,49 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> + +<actionGroups xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="../../../../../../../dev/tests/acceptance/vendor/magento/magento2-functional-testing-framework/src/Magento/FunctionalTestingFramework/Test/etc/actionGroupSchema.xsd"> + <actionGroup name="setColorPickerByHex"> + <arguments> + <argument name="nthColorPicker" type="string" defaultValue="1"/> + <argument name="hexColor" type="string" defaultValue="e74c3c"/> + </arguments> + <!-- This 6x backspace stuff is some magic that is necessary to interact with this field correctly --> + <pressKey selector="{{AdminColorPickerSection.hexByIndex(nthColorPicker)}}" parameterArray="[\Facebook\WebDriver\WebDriverKeys::BACKSPACE,\Facebook\WebDriver\WebDriverKeys::BACKSPACE,\Facebook\WebDriver\WebDriverKeys::BACKSPACE,\Facebook\WebDriver\WebDriverKeys::BACKSPACE,\Facebook\WebDriver\WebDriverKeys::BACKSPACE,\Facebook\WebDriver\WebDriverKeys::BACKSPACE,'{{hexColor}}']" stepKey="fillHex1"/> + <click selector="{{AdminColorPickerSection.submitByIndex(nthColorPicker)}}" stepKey="submitColor1"/> + </actionGroup> + <actionGroup name="assertSwatchColor"> + <arguments> + <argument name="nthSwatch" type="string" defaultValue="1"/> + <argument name="expectedStyle" type="string" defaultValue="background: rgb(0, 0, 0);"/> + </arguments> + <grabAttributeFrom selector="{{AdminManageSwatchSection.nthSwatch(nthSwatch)}}" userInput="style" stepKey="grabStyle1"/> + <assertEquals stepKey="assertStyle1"> + <actualResult type="string">{$grabStyle1}</actualResult> + <expectedResult type="string">{{expectedStyle}}</expectedResult> + </assertEquals> + </actionGroup> + <actionGroup name="assertStorefrontSwatchColor"> + <arguments> + <argument name="nthSwatch" type="string" defaultValue="1"/> + <argument name="expectedRgb" type="string" defaultValue="rgb(231, 77, 60)"/> + </arguments> + <grabAttributeFrom selector="{{StorefrontProductInfoMainSection.nthSwatchOption(nthSwatch)}}" userInput="style" stepKey="grabStyle1"/> + <assertEquals stepKey="assertStyle1"> + <actualResult type="string">{$grabStyle1}</actualResult> + <expectedResult type="string">background: center center no-repeat {{expectedRgb}};</expectedResult> + </assertEquals> + </actionGroup> + <actionGroup name="openSwatchMenuByIndex"> + <arguments> + <argument name="index" type="string" defaultValue="0"/> + </arguments> + <!-- I had to use executeJS to perform the click to get around the use of CSS ::before and ::after --> + <executeJS function="jQuery('#swatch_window_option_option_{{index}}').click()" stepKey="clickSwatch1"/> + </actionGroup> +</actionGroups> \ No newline at end of file diff --git a/app/code/Magento/Swatches/Test/Mftf/Section/AdminColorPickerSection.xml b/app/code/Magento/Swatches/Test/Mftf/Section/AdminColorPickerSection.xml new file mode 100644 index 0000000000000..772b724b6648d --- /dev/null +++ b/app/code/Magento/Swatches/Test/Mftf/Section/AdminColorPickerSection.xml @@ -0,0 +1,15 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> + +<sections xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="../../../../../../../dev/tests/acceptance/vendor/magento/magento2-functional-testing-framework/src/Magento/FunctionalTestingFramework/Page/etc/SectionObject.xsd"> + <section name="AdminColorPickerSection"> + <element name="hexByIndex" type="input" selector="//div[@class='colorpicker'][{{var}}]/div[@class='colorpicker_hex']/input" parameterized="true"/> + <element name="submitByIndex" type="button" selector="//div[@class='colorpicker'][{{var}}]/div[@class='colorpicker_submit']" parameterized="true"/> + </section> +</sections> diff --git a/app/code/Magento/Swatches/Test/Mftf/Section/AdminManageSwatchSection.xml b/app/code/Magento/Swatches/Test/Mftf/Section/AdminManageSwatchSection.xml new file mode 100644 index 0000000000000..39db9f92837e3 --- /dev/null +++ b/app/code/Magento/Swatches/Test/Mftf/Section/AdminManageSwatchSection.xml @@ -0,0 +1,24 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> + +<sections xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="../../../../../../../dev/tests/acceptance/vendor/magento/magento2-functional-testing-framework/src/Magento/FunctionalTestingFramework/Page/etc/SectionObject.xsd"> + <section name="AdminManageSwatchSection"> + <element name="adminInputByIndex" type="input" selector="optionvisual[value][option_{{var}}][0]" parameterized="true"/> + <element name="addSwatch" type="button" selector="#add_new_swatch_visual_option_button" timeout="30"/> + <element name="nthSwatch" type="button" selector="#swatch-visual-options-panel table tbody tr:nth-of-type({{var}}) .swatch_window" parameterized="true"/> + <element name="addSwatchText" type="button" selector="#add_new_swatch_text_option_button"/> + <element name="swatchTextByIndex" type="input" selector="input[name='swatchtext[value][option_{{index}}][0]']" parameterized="true"/> + <element name="nthSwatchText" type="input" selector="#swatch-text-options-panel table tbody tr:nth-of-type({{var}}) td:nth-of-type(3) input" parameterized="true"/> + <element name="nthSwatchAdminDescription" type="input" selector="#swatch-text-options-panel table tbody tr:nth-of-type({{var}}) td:nth-of-type(4) input" parameterized="true"/> + <!-- Selector for Admin Description input where the index is zero-based --> + <element name="swatchAdminDescriptionByIndex" type="input" selector="input[name='optiontext[value][option_{{index}}][0]']" parameterized="true"/> + <element name="nthChooseColor" type="button" selector="#swatch-visual-options-panel table tbody tr:nth-of-type({{var}}) .swatch_row_name.colorpicker_handler" parameterized="true"/> + <element name="nthDelete" type="button" selector="#swatch-visual-options-panel table tbody tr:nth-of-type({{var}}) button.delete-option" parameterized="true"/> + </section> +</sections> diff --git a/app/code/Magento/Swatches/Test/Mftf/Section/StorefrontProductInfoMainSection.xml b/app/code/Magento/Swatches/Test/Mftf/Section/StorefrontProductInfoMainSection.xml index 4da84f92e20ed..68c1d29258727 100644 --- a/app/code/Magento/Swatches/Test/Mftf/Section/StorefrontProductInfoMainSection.xml +++ b/app/code/Magento/Swatches/Test/Mftf/Section/StorefrontProductInfoMainSection.xml @@ -10,6 +10,9 @@ xsi:noNamespaceSchemaLocation="../../../../../../vendor/magento/magento2-functional-testing-framework/src/Magento/FunctionalTestingFramework/Page/etc/SectionObject.xsd"> <section name="StorefrontProductInfoMainSection"> <element name="swatchOptionByLabel" type="button" selector="div.swatch-option[option-label={{opt}}]" parameterized="true"/> + <element name="nthSwatchOption" type="button" selector="div.swatch-option:nth-of-type({{var}})" parameterized="true"/> <element name="selectedSwatchValue" type="text" selector="//div[contains(@class, 'swatch-attribute') and contains(., '{{attr}}')]//span[contains(@class, 'swatch-attribute-selected-option')]" parameterized="true"/> + <element name="swatchAttributeOptions" type="text" selector="div.swatch-attribute-options"/> + <element name="nthSwatchOptionText" type="button" selector="div.swatch-option.text:nth-of-type({{n}})" parameterized="true"/> </section> </sections> diff --git a/app/code/Magento/Swatches/Test/Mftf/Test/AdminCreateTextSwatchTest.xml b/app/code/Magento/Swatches/Test/Mftf/Test/AdminCreateTextSwatchTest.xml new file mode 100644 index 0000000000000..0c26c6a8174af --- /dev/null +++ b/app/code/Magento/Swatches/Test/Mftf/Test/AdminCreateTextSwatchTest.xml @@ -0,0 +1,104 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> + +<tests xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="../../../../../../../dev/tests/acceptance/vendor/magento/magento2-functional-testing-framework/src/Magento/FunctionalTestingFramework/Test/etc/testSchema.xsd"> + <test name="AdminCreateTextSwatchTest"> + <annotations> + <features value="Swatches"/> + <stories value="Create/configure swatches"/> + <title value="Admin can create product attribute with text swatch"/> + <description value="Admin can create product attribute with text swatch"/> + <severity value="CRITICAL"/> + <testCaseId value="MC-3078"/> + <group value="Swatches"/> + </annotations> + <before> + <actionGroup ref="LoginAsAdmin" stepKey="loginAsAdmin"/> + </before> + <after> + <amOnPage url="admin/admin/auth/logout/" stepKey="amOnLogoutPage"/> + </after> + + <!-- Create a new product attribute of type "Text Swatch" --> + <amOnPage url="{{ProductAttributePage.url}}" stepKey="goToNewProductAttributePage"/> + <waitForPageLoad stepKey="waitForNewProductAttributePage"/> + <fillField selector="{{AttributePropertiesSection.DefaultLabel}}" userInput="{{ProductAttributeFrontendLabel.label}}" stepKey="fillDefaultLabel"/> + <selectOption selector="{{AttributePropertiesSection.InputType}}" userInput="swatch_text" stepKey="selectInputType"/> + <click selector="{{AdminManageSwatchSection.addSwatchText}}" stepKey="clickAddSwatch0"/> + <fillField selector="{{AdminManageSwatchSection.swatchTextByIndex('0')}}" userInput="red" stepKey="fillSwatch0"/> + <fillField selector="{{AdminManageSwatchSection.swatchAdminDescriptionByIndex('0')}}" userInput="Something red." stepKey="fillDescription0"/> + <click selector="{{AdminManageSwatchSection.addSwatchText}}" stepKey="clickAddSwatch1"/> + <fillField selector="{{AdminManageSwatchSection.swatchTextByIndex('1')}}" userInput="green" stepKey="fillSwatch1"/> + <fillField selector="{{AdminManageSwatchSection.swatchAdminDescriptionByIndex('1')}}" userInput="Something green." stepKey="fillDescription1"/> + <click selector="{{AdminManageSwatchSection.addSwatchText}}" stepKey="clickAddSwatch2"/> + <fillField selector="{{AdminManageSwatchSection.swatchTextByIndex('2')}}" userInput="blue" stepKey="fillSwatch2"/> + <fillField selector="{{AdminManageSwatchSection.swatchAdminDescriptionByIndex('2')}}" userInput="Something blue." stepKey="fillDescription2"/> + <click selector="{{AttributePropertiesSection.AdvancedProperties}}" stepKey="expandAdvancedProperties"/> + <selectOption selector="{{AttributePropertiesSection.Scope}}" userInput="1" stepKey="selectGlobalScope"/> + <!-- Save and verify --> + <click selector="{{AttributePropertiesSection.SaveAndEdit}}" stepKey="clickSave"/> + <seeInField selector="{{AttributePropertiesSection.DefaultLabel}}" userInput="{{ProductAttributeFrontendLabel.label}}" stepKey="seeDefaultLabel"/> + <seeInField selector="{{AdminManageSwatchSection.nthSwatchText('1')}}" userInput="red" stepKey="seeSwatch0"/> + <seeInField selector="{{AdminManageSwatchSection.nthSwatchAdminDescription('1')}}" userInput="Something red." stepKey="seeDescription0"/> + <seeInField selector="{{AdminManageSwatchSection.nthSwatchText('2')}}" userInput="green" stepKey="seeSwatch1"/> + <seeInField selector="{{AdminManageSwatchSection.nthSwatchAdminDescription('2')}}" userInput="Something green." stepKey="seeDescription1"/> + <seeInField selector="{{AdminManageSwatchSection.nthSwatchText('3')}}" userInput="blue" stepKey="seeSwatch2"/> + <seeInField selector="{{AdminManageSwatchSection.nthSwatchAdminDescription('3')}}" userInput="Something blue." stepKey="seeDescription2"/> + + <!-- Create a configurable product to verify the storefront with --> + <amOnPage url="{{AdminProductIndexPage.url}}" stepKey="amOnProductGridPage"/> + <waitForPageLoad time="30" stepKey="waitForProductGrid"/> + <actionGroup ref="goToCreateProductPage" stepKey="goToCreateConfigurableProduct"> + <argument name="product" value="BaseConfigurableProduct"/> + </actionGroup> + <click selector="{{AdminProductSEOSection.sectionHeader}}" stepKey="openSeoSection"/> + <fillField userInput="{{_defaultProduct.urlKey}}" selector="{{AdminProductSEOSection.urlKeyInput}}" stepKey="fillUrlKey"/> + <actionGroup ref="fillMainProductForm" stepKey="fillProductForm"> + <argument name="product" value="BaseConfigurableProduct"/> + </actionGroup> + + <!-- Create configurations based off the Text Swatch we created earlier --> + <click selector="{{AdminProductFormConfigurationsSection.createConfigurations}}" stepKey="clickCreateConfigurations"/> + <click selector="{{AdminCreateProductConfigurationsPanel.filters}}" stepKey="clickFilters"/> + <fillField selector="{{AdminCreateProductConfigurationsPanel.attributeCode}}" userInput="{{ProductAttributeFrontendLabel.label}}" stepKey="fillFilterAttributeCodeField"/> + <click selector="{{AdminCreateProductConfigurationsPanel.applyFilters}}" stepKey="clickApplyFiltersButton"/> + <click selector="{{AdminCreateProductConfigurationsPanel.firstCheckbox}}" stepKey="clickOnFirstCheckbox"/> + <click selector="{{AdminCreateProductConfigurationsPanel.next}}" stepKey="clickOnNextButton1"/> + <click selector="{{AdminCreateProductConfigurationsPanel.selectAll}}" stepKey="clickOnSelectAll"/> + <click selector="{{AdminCreateProductConfigurationsPanel.next}}" stepKey="clickOnNextButton2"/> + <click selector="{{AdminCreateProductConfigurationsPanel.applySingleQuantityToEachSkus}}" stepKey="clickOnApplySingleQuantityToEachSku"/> + <fillField selector="{{AdminCreateProductConfigurationsPanel.quantity}}" userInput="1" stepKey="enterAttributeQuantity"/> + <click selector="{{AdminCreateProductConfigurationsPanel.next}}" stepKey="clickOnNextButton3"/> + <click selector="{{AdminCreateProductConfigurationsPanel.next}}" stepKey="clickOnNextButton4"/> + <click selector="{{AdminProductFormActionSection.saveButton}}" stepKey="clickOnSaveButton2"/> + <click selector="{{AdminChooseAffectedAttributeSetPopup.confirm}}" stepKey="clickOnConfirmInPopup"/> + + <!-- Go to the product page and see text swatch options --> + <amOnPage url="{{_defaultProduct.urlKey}}.html" stepKey="amOnProductPage"/> + <waitForPageLoad stepKey="waitForProductPage"/> + <see selector="{{StorefrontProductInfoMainSection.swatchAttributeOptions}}" userInput="red" stepKey="seeRed"/> + <grabAttributeFrom selector="{{StorefrontProductInfoMainSection.nthSwatchOptionText('1')}}" userInput="option-label" stepKey="grabRedLabel"/> + <assertEquals stepKey="assertRedLabel"> + <expectedResult type="string">Something red.</expectedResult> + <actualResult type="string">{$grabRedLabel}</actualResult> + </assertEquals> + <see selector="{{StorefrontProductInfoMainSection.swatchAttributeOptions}}" userInput="green" stepKey="seeGreen"/> + <grabAttributeFrom selector="{{StorefrontProductInfoMainSection.nthSwatchOptionText('2')}}" userInput="option-label" stepKey="grabGreenLabel"/> + <assertEquals stepKey="assertGreenLabel"> + <expectedResult type="string">Something green.</expectedResult> + <actualResult type="string">{$grabGreenLabel}</actualResult> + </assertEquals> + <see selector="{{StorefrontProductInfoMainSection.swatchAttributeOptions}}" userInput="blue" stepKey="seeBlue"/> + <grabAttributeFrom selector="{{StorefrontProductInfoMainSection.nthSwatchOptionText('3')}}" userInput="option-label" stepKey="grabBlueLabel"/> + <assertEquals stepKey="assertBlueLabel"> + <expectedResult type="string">Something blue.</expectedResult> + <actualResult type="string">{$grabBlueLabel}</actualResult> + </assertEquals> + </test> +</tests> diff --git a/app/code/Magento/Swatches/Test/Mftf/Test/AdminCreateVisualSwatchTest.xml b/app/code/Magento/Swatches/Test/Mftf/Test/AdminCreateVisualSwatchTest.xml new file mode 100644 index 0000000000000..67750ac931f0b --- /dev/null +++ b/app/code/Magento/Swatches/Test/Mftf/Test/AdminCreateVisualSwatchTest.xml @@ -0,0 +1,159 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> + +<tests xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="../../../../../../../dev/tests/acceptance/vendor/magento/magento2-functional-testing-framework/src/Magento/FunctionalTestingFramework/Test/etc/testSchema.xsd"> + <test name="AdminCreateVisualSwatchTest"> + <annotations> + <features value="Swatches"/> + <stories value="Create/configure swatches"/> + <title value="Admin can create product attribute with picked color swatch"/> + <description value="Admin can create product attribute with picked color swatch"/> + <severity value="CRITICAL"/> + <testCaseId value="MC-3080"/> + <group value="Swatches"/> + </annotations> + <before> + <createData entity="ApiCategory" stepKey="createCategory"/> + <actionGroup ref="LoginAsAdmin" stepKey="loginAsAdmin"/> + </before> + <after> + <!-- Clean up our modifications to the existing color attribute --> + <amOnPage url="{{AdminProductAttributeGridPage.url}}" stepKey="goToProductAttributes"/> + <waitForPageLoad stepKey="waitForProductAttributes"/> + <fillField selector="{{AdminProductAttributeGridSection.FilterByAttributeCode}}" userInput="color" stepKey="fillFilter"/> + <click selector="{{AdminProductAttributeGridSection.Search}}" stepKey="clickSearch"/> + <click selector="{{AdminProductAttributeGridSection.AttributeCode('color')}}" stepKey="clickRowToEdit"/> + <click selector="{{AdminManageSwatchSection.nthDelete('1')}}" stepKey="deleteSwatch1"/> + <click selector="{{AdminManageSwatchSection.nthDelete('2')}}" stepKey="deleteSwatch2"/> + <click selector="{{AdminManageSwatchSection.nthDelete('3')}}" stepKey="deleteSwatch3"/> + <waitForPageLoad stepKey="waitToClickSave"/> + <click selector="{{AttributePropertiesSection.SaveAndEdit}}" stepKey="clickSaveAndEdit"/> + <!-- Logout --> + <amOnPage url="admin/admin/auth/logout/" stepKey="amOnLogoutPage"/> + </after> + + <!-- Go to the edit page for the "color" attribute --> + <amOnPage url="{{AdminProductAttributeGridPage.url}}" stepKey="goToProductAttributes"/> + <waitForPageLoad stepKey="waitForProductAttributes"/> + <fillField selector="{{AdminProductAttributeGridSection.FilterByAttributeCode}}" userInput="color" stepKey="fillFilter"/> + <click selector="{{AdminProductAttributeGridSection.Search}}" stepKey="clickSearch"/> + <click selector="{{AdminProductAttributeGridSection.AttributeCode('color')}}" stepKey="clickRowToEdit"/> + + <!-- Change to visual swatches --> + <selectOption selector="{{AdminNewAttributePanel.inputType}}" userInput="swatch_visual" stepKey="selectVisualSwatch"/> + + <!-- Set swatch #1 using the color picker --> + <click selector="{{AdminManageSwatchSection.addSwatch}}" stepKey="clickAddSwatch1"/> + <actionGroup ref="openSwatchMenuByIndex" stepKey="clickSwatch1"> + <argument name="index" value="0"/> + </actionGroup> + <click selector="{{AdminManageSwatchSection.nthChooseColor('1')}}" stepKey="clickChooseColor1"/> + <actionGroup ref="setColorPickerByHex" stepKey="fillHex1"> + <argument name="nthColorPicker" value="1"/> + <argument name="hexColor" value="e74c3c"/> + </actionGroup> + <fillField selector="{{AdminManageSwatchSection.adminInputByIndex('0')}}" userInput="red" stepKey="fillAdmin1"/> + <!-- Set swatch #2 using the color picker --> + <click selector="{{AdminManageSwatchSection.addSwatch}}" stepKey="clickAddSwatch2"/> + <actionGroup ref="openSwatchMenuByIndex" stepKey="clickSwatch2"> + <argument name="index" value="1"/> + </actionGroup> + <click selector="{{AdminManageSwatchSection.nthChooseColor('2')}}" stepKey="clickChooseColor2"/> + <actionGroup ref="setColorPickerByHex" stepKey="fillHex2"> + <argument name="nthColorPicker" value="2"/> + <argument name="hexColor" value="2ecc71"/> + </actionGroup> + <fillField selector="{{AdminManageSwatchSection.adminInputByIndex('1')}}" userInput="green" stepKey="fillAdmin2"/> + <!-- Set swatch #3 using the color picker --> + <click selector="{{AdminManageSwatchSection.addSwatch}}" stepKey="clickAddSwatch3"/> + <actionGroup ref="openSwatchMenuByIndex" stepKey="clickSwatch3"> + <argument name="index" value="2"/> + </actionGroup> + <click selector="{{AdminManageSwatchSection.nthChooseColor('3')}}" stepKey="clickChooseColor3"/> + <actionGroup ref="setColorPickerByHex" stepKey="fillHex3"> + <argument name="nthColorPicker" value="3"/> + <argument name="hexColor" value="3498db"/> + </actionGroup> + <fillField selector="{{AdminManageSwatchSection.adminInputByIndex('2')}}" userInput="blue" stepKey="fillAdmin3"/> + <waitForPageLoad stepKey="waitToClickSave"/> + + <!-- Save --> + <click selector="{{AttributePropertiesSection.SaveAndEdit}}" stepKey="clickSaveAndEdit1"/> + <waitForElementVisible selector="{{AdminProductMessagesSection.successMessage}}" stepKey="waitForSuccess"/> + + <!-- Assert that the Save was successful after round trip to server --> + <actionGroup ref="assertSwatchColor" stepKey="assertSwatch1"> + <argument name="nthSwatch" value="1"/> + <argument name="expectedStyle" value="background: rgb(231, 77, 60);"/> + </actionGroup> + <actionGroup ref="assertSwatchColor" stepKey="assertSwatch2"> + <argument name="nthSwatch" value="2"/> + <argument name="expectedStyle" value="background: rgb(46, 204, 112);"/> + </actionGroup> + <actionGroup ref="assertSwatchColor" stepKey="assertSwatch3"> + <argument name="nthSwatch" value="3"/> + <argument name="expectedStyle" value="background: rgb(52, 152, 219);"/> + </actionGroup> + + <!-- Create a configurable product to verify the storefront with --> + <amOnPage url="{{AdminProductIndexPage.url}}" stepKey="amOnProductGridPage"/> + <waitForPageLoad stepKey="waitForProductGridPage"/> + <click selector="{{AdminProductGridActionSection.addProductToggle}}" stepKey="clickOnAddProductToggle"/> + <click selector="{{AdminProductGridActionSection.addConfigurableProduct}}" stepKey="clickOnAddConfigurableProduct"/> + <fillField userInput="{{_defaultProduct.name}}" selector="{{AdminProductFormSection.productName}}" stepKey="fillName"/> + <fillField userInput="{{_defaultProduct.sku}}" selector="{{AdminProductFormSection.productSku}}" stepKey="fillSKU"/> + <fillField userInput="{{_defaultProduct.price}}" selector="{{AdminProductFormSection.productPrice}}" stepKey="fillPrice"/> + <fillField userInput="{{_defaultProduct.quantity}}" selector="{{AdminProductFormSection.productQuantity}}" stepKey="fillQuantity"/> + <searchAndMultiSelectOption selector="{{AdminProductFormSection.categoriesDropdown}}" parameterArray="[$$createCategory.name$$]" stepKey="fillCategory"/> + <click selector="{{AdminProductSEOSection.sectionHeader}}" stepKey="openSeoSection"/> + <fillField userInput="{{_defaultProduct.urlKey}}" selector="{{AdminProductSEOSection.urlKeyInput}}" stepKey="fillUrlKey"/> + + <!-- Create configurations based off the Text Swatch we created earlier --> + <click selector="{{AdminProductFormConfigurationsSection.createConfigurations}}" stepKey="clickCreateConfigurations"/> + <click selector="{{AdminCreateProductConfigurationsPanel.filters}}" stepKey="clickFilters"/> + <fillField selector="{{AdminCreateProductConfigurationsPanel.attributeCode}}" userInput="color" stepKey="fillFilterAttributeCodeField"/> + <click selector="{{AdminCreateProductConfigurationsPanel.applyFilters}}" stepKey="clickApplyFiltersButton"/> + <click selector="{{AdminCreateProductConfigurationsPanel.firstCheckbox}}" stepKey="clickOnFirstCheckbox"/> + <click selector="{{AdminCreateProductConfigurationsPanel.next}}" stepKey="clickOnNextButton1"/> + <click selector="{{AdminCreateProductConfigurationsPanel.selectAll}}" stepKey="clickOnSelectAll"/> + <click selector="{{AdminCreateProductConfigurationsPanel.next}}" stepKey="clickOnNextButton2"/> + <click selector="{{AdminCreateProductConfigurationsPanel.applyUniquePricesByAttributeToEachSku}}" stepKey="clickOnApplyUniquePricesByAttributeToEachSku"/> + <selectOption selector="{{AdminCreateProductConfigurationsPanel.selectAttribute}}" userInput="Color" stepKey="selectAttributes"/> + <fillField selector="{{AdminCreateProductConfigurationsPanel.attribute1}}" userInput="10" stepKey="fillAttributePrice1"/> + <fillField selector="{{AdminCreateProductConfigurationsPanel.attribute2}}" userInput="20" stepKey="fillAttributePrice2"/> + <fillField selector="{{AdminCreateProductConfigurationsPanel.attribute3}}" userInput="30" stepKey="fillAttributePrice3"/> + <click selector="{{AdminCreateProductConfigurationsPanel.applySingleQuantityToEachSkus}}" stepKey="clickOnApplySingleQuantityToEachSku"/> + <fillField selector="{{AdminCreateProductConfigurationsPanel.quantity}}" userInput="99" stepKey="enterAttributeQuantity"/> + <click selector="{{AdminCreateProductConfigurationsPanel.next}}" stepKey="clickOnNextButton3"/> + <click selector="{{AdminCreateProductConfigurationsPanel.next}}" stepKey="clickOnNextButton4"/> + <click selector="{{AdminProductFormActionSection.saveButton}}" stepKey="clickOnSaveButton2"/> + <!-- conditionalClick is necessary because this popup appears in Jenkins but not locally. I cannot figure out why. --> + <conditionalClick selector="{{AdminChooseAffectedAttributeSetPopup.confirm}}" dependentSelector="{{AdminChooseAffectedAttributeSetPopup.confirm}}" visible="true" stepKey="clickOnConfirmInPopup"/> + <seeElement selector="{{AdminProductMessagesSection.successMessage}}" stepKey="seeSaveProductMessage"/> + <seeInTitle userInput="{{_defaultProduct.name}}" stepKey="seeProductNameInTitle"/> + + <!-- Go to the product page and see text swatch options --> + <amOnPage url="{{_defaultProduct.urlKey}}.html" stepKey="amOnProductPage"/> + <waitForPageLoad stepKey="waitForProductPage"/> + + <!-- Verify that the storefront shows the swatches too --> + <actionGroup ref="assertStorefrontSwatchColor" stepKey="assertSwatch4"> + <argument name="nthSwatch" value="1"/> + <argument name="expectedRgb" value="rgb(231, 77, 60)"/> + </actionGroup> + <actionGroup ref="assertStorefrontSwatchColor" stepKey="assertSwatch5"> + <argument name="nthSwatch" value="2"/> + <argument name="expectedRgb" value="rgb(46, 204, 112)"/> + </actionGroup> + <actionGroup ref="assertStorefrontSwatchColor" stepKey="assertSwatch6"> + <argument name="nthSwatch" value="3"/> + <argument name="expectedRgb" value="rgb(52, 152, 219)"/> + </actionGroup> + </test> +</tests> diff --git a/app/code/Magento/Swatches/Test/Mftf/Test/StorefrontSwatchProductWithFileCustomOptionTest.xml b/app/code/Magento/Swatches/Test/Mftf/Test/StorefrontSwatchProductWithFileCustomOptionTest.xml index cfd220d12b1d7..cc6699e989101 100644 --- a/app/code/Magento/Swatches/Test/Mftf/Test/StorefrontSwatchProductWithFileCustomOptionTest.xml +++ b/app/code/Magento/Swatches/Test/Mftf/Test/StorefrontSwatchProductWithFileCustomOptionTest.xml @@ -12,7 +12,7 @@ <annotations> <features value="ConfigurableProduct"/> <stories value="Add configurable product to cart"/> - <title value="Correct error message and redirect with invalid file option"/> + <title value="Configurable product with swatch option and file custom option"/> <description value="Configurable product with swatch option and file custom option. When adding to cart with an invalid filetype, the correct error message is shown, and options remain selected."/> <severity value="CRITICAL"/> <testCaseId value="MAGETWO-93101"/> diff --git a/app/code/Magento/Swatches/Test/Mftf/composer.json b/app/code/Magento/Swatches/Test/Mftf/composer.json deleted file mode 100644 index 76c8037995754..0000000000000 --- a/app/code/Magento/Swatches/Test/Mftf/composer.json +++ /dev/null @@ -1,28 +0,0 @@ -{ - "name": "magento/functional-test-module-swatches", - "description": "Add Swatches to Products", - "config": { - "sort-packages": true - }, - "require": { - "php": "~7.1.3||~7.2.0", - "magento/magento2-functional-testing-framework": "2.2.0", - "magento/functional-test-module-backend": "100.0.0-dev", - "magento/functional-test-module-catalog": "100.0.0-dev", - "magento/functional-test-module-config": "100.0.0-dev", - "magento/functional-test-module-configurable-product": "100.0.0-dev", - "magento/functional-test-module-customer": "100.0.0-dev", - "magento/functional-test-module-eav": "100.0.0-dev", - "magento/functional-test-module-media-storage": "100.0.0-dev", - "magento/functional-test-module-store": "100.0.0-dev", - "magento/functional-test-module-theme": "100.0.0-dev" - }, - "suggest": { - "magento/functional-test-module-layered-navigation": "100.0.0-dev", - "magento/functional-test-module-swatches-sample-data": "100.0.0-dev" - }, - "type": "magento2-test", - "license": [ - "proprietary" - ] -} diff --git a/app/code/Magento/Swatches/composer.json b/app/code/Magento/Swatches/composer.json index 71f9fc8f80baa..0940003b6a72d 100644 --- a/app/code/Magento/Swatches/composer.json +++ b/app/code/Magento/Swatches/composer.json @@ -23,7 +23,8 @@ }, "type": "magento2-module", "license": [ - "proprietary" + "OSL-3.0", + "AFL-3.0" ], "autoload": { "files": [ diff --git a/app/code/Magento/SwatchesGraphQl/Test/Mftf/composer.json b/app/code/Magento/SwatchesGraphQl/Test/Mftf/composer.json deleted file mode 100644 index 7a62d9bd33ab9..0000000000000 --- a/app/code/Magento/SwatchesGraphQl/Test/Mftf/composer.json +++ /dev/null @@ -1,21 +0,0 @@ -{ - "name": "magento/functional-test-module-swatches-graph-ql", - "description": "N/A", - "config": { - "sort-packages": true - }, - "require": { - "php": "~7.1.3||~7.2.0", - "magento/magento2-functional-testing-framework": "2.2.0", - "magento/functional-test-module-swatches": "100.0.0-dev", - "magento/functional-test-module-catalog": "100.0.0-dev" - }, - "suggest": { - "magento/functional-test-module-catalog-graph-ql": "100.0.0-dev" - }, - "type": "magento2-test", - "license": [ - "OSL-3.0", - "AFL-3.0" - ] -} diff --git a/app/code/Magento/SwatchesLayeredNavigation/Test/Mftf/composer.json b/app/code/Magento/SwatchesLayeredNavigation/Test/Mftf/composer.json deleted file mode 100644 index e37d2bfda247d..0000000000000 --- a/app/code/Magento/SwatchesLayeredNavigation/Test/Mftf/composer.json +++ /dev/null @@ -1,17 +0,0 @@ -{ - "name": "magento/functional-test-module-swatches-layered-navigation", - "description": "N/A", - "config": { - "sort-packages": true - }, - "require": { - "php": "~7.1.3||~7.2.0", - "magento/magento2-functional-testing-framework": "2.2.0", - "magento/magento-composer-installer": "100.0.0-dev" - }, - "type": "magento2-test", - "license": [ - "OSL-3.0", - "AFL-3.0" - ] -} diff --git a/app/code/Magento/Tax/Model/Calculation/AbstractAggregateCalculator.php b/app/code/Magento/Tax/Model/Calculation/AbstractAggregateCalculator.php index afcfa1bbebcb0..bad64260cf58a 100644 --- a/app/code/Magento/Tax/Model/Calculation/AbstractAggregateCalculator.php +++ b/app/code/Magento/Tax/Model/Calculation/AbstractAggregateCalculator.php @@ -10,7 +10,7 @@ abstract class AbstractAggregateCalculator extends AbstractCalculator { /** - * {@inheritdoc} + * @inheritdoc */ protected function calculateWithTaxInPrice(QuoteDetailsItemInterface $item, $quantity, $round = true) { @@ -86,7 +86,7 @@ protected function calculateWithTaxInPrice(QuoteDetailsItemInterface $item, $qua } /** - * {@inheritdoc} + * @inheritdoc */ protected function calculateWithTaxNotInPrice(QuoteDetailsItemInterface $item, $quantity, $round = true) { @@ -149,6 +149,7 @@ protected function calculateWithTaxNotInPrice(QuoteDetailsItemInterface $item, $ $rowTaxBeforeDiscount = array_sum($rowTaxesBeforeDiscount); $rowTotalInclTax = $rowTotal + $rowTaxBeforeDiscount; $priceInclTax = $rowTotalInclTax / $quantity; + if ($round) { $priceInclTax = $this->calculationTool->round($priceInclTax); } diff --git a/app/code/Magento/Tax/Model/Plugin/OrderSave.php b/app/code/Magento/Tax/Model/Plugin/OrderSave.php index a1a3ebf861d60..38952eec02ca1 100644 --- a/app/code/Magento/Tax/Model/Plugin/OrderSave.php +++ b/app/code/Magento/Tax/Model/Plugin/OrderSave.php @@ -7,6 +7,8 @@ namespace Magento\Tax\Model\Plugin; +use Magento\Tax\Api\Data\OrderTaxDetailsAppliedTaxExtension; + class OrderSave { /** @@ -79,8 +81,9 @@ protected function saveOrderTax(\Magento\Sales\Api\Data\OrderInterface $order) foreach ($taxesForItems as $taxesArray) { foreach ($taxesArray['applied_taxes'] as $rates) { if (isset($rates['extension_attributes'])) { - /** @var \Magento\Tax\Api\Data\AppliedTaxRateInterface[] $taxRates */ - $taxRates = $rates['extension_attributes']->getRates(); + $taxRates = $rates['extension_attributes'] instanceof OrderTaxDetailsAppliedTaxExtension + ? $rates['extension_attributes']->getRates() + : $rates['extension_attributes']['rates']; if (is_array($taxRates)) { if (count($taxRates) == 1) { $ratesIdQuoteItemId[$rates['id']][] = [ @@ -124,8 +127,9 @@ protected function saveOrderTax(\Magento\Sales\Api\Data\OrderInterface $order) foreach ($taxes as $row) { $id = $row['id']; if (isset($row['extension_attributes'])) { - /** @var \Magento\Tax\Api\Data\AppliedTaxRateInterface[] $taxRates */ - $taxRates = $row['extension_attributes']->getRates(); + $taxRates = $row['extension_attributes'] instanceof OrderTaxDetailsAppliedTaxExtension + ? $row['extension_attributes']->getRates() + : $row['extension_attributes']['rates']; if (is_array($taxRates)) { foreach ($taxRates as $tax) { if ($row['percent'] == null) { diff --git a/app/code/Magento/Tax/Test/Mftf/Section/AdminConfigureTaxSection.xml b/app/code/Magento/Tax/Test/Mftf/Section/AdminConfigureTaxSection.xml index c54c525d8d7ed..af33b6b4ad539 100644 --- a/app/code/Magento/Tax/Test/Mftf/Section/AdminConfigureTaxSection.xml +++ b/app/code/Magento/Tax/Test/Mftf/Section/AdminConfigureTaxSection.xml @@ -50,5 +50,6 @@ <element name="dropdownDisplayTaxSummarySales" type="checkbox" selector="#row_tax_sales_display_full_summary select"/> <element name="systemValueDisplayZeroTaxSales" type="checkbox" selector="#row_tax_sales_display_zero_tax input[type='checkbox']"/> <element name="dropdownDisplayZeroTaxSales" type="checkbox" selector="#row_tax_sales_display_zero_tax select"/> + <element name="fixedProductTaxes" type="block" selector="#tax_weee-head" timeout="30"/> </section> </sections> diff --git a/app/code/Magento/Tax/Test/Mftf/Test/StorefrontTaxQuoteCartTest.xml b/app/code/Magento/Tax/Test/Mftf/Test/StorefrontTaxQuoteCartTest.xml index 752585830638f..c0b32e4bc71e7 100644 --- a/app/code/Magento/Tax/Test/Mftf/Test/StorefrontTaxQuoteCartTest.xml +++ b/app/code/Magento/Tax/Test/Mftf/Test/StorefrontTaxQuoteCartTest.xml @@ -248,8 +248,9 @@ <severity value="CRITICAL"/> <testCaseId value="MC-297"/> <group value="Tax"/> - <group value="skip"/> - <!-- skipped due to MAGETWO-90539 --> + <skip> + <issueId value="MAGETWO-90539"/> + </skip> </annotations> <before> <actionGroup ref="LoginAsAdmin" stepKey="loginAsAdmin"/> @@ -356,8 +357,9 @@ <severity value="CRITICAL"/> <testCaseId value="MC-298"/> <group value="Tax"/> - <group value="skip"/> - <!-- Skipped due to MAGETWO-90539 --> + <skip> + <issueId value="MAGETWO-90539"/> + </skip> </annotations> <before> <actionGroup ref="LoginAsAdmin" stepKey="loginAsAdmin"/> diff --git a/app/code/Magento/Tax/Test/Mftf/Test/StorefrontTaxQuoteCheckoutTest.xml b/app/code/Magento/Tax/Test/Mftf/Test/StorefrontTaxQuoteCheckoutTest.xml index f051d4f8c3b82..3e85ecc783253 100644 --- a/app/code/Magento/Tax/Test/Mftf/Test/StorefrontTaxQuoteCheckoutTest.xml +++ b/app/code/Magento/Tax/Test/Mftf/Test/StorefrontTaxQuoteCheckoutTest.xml @@ -313,7 +313,7 @@ </actionGroup> <click stepKey="clickNext" selector="{{CheckoutShippingSection.next}}"/> <see stepKey="seeAddress" selector="{{CheckoutShippingSection.defaultShipping}}" userInput="{{SimpleTaxCA.state}}"/> - <see stepKey="seeShipTo" selector="{{CheckoutPaymentSection.shipToInfomation}}" userInput="{{SimpleTaxCA.state}}"/> + <see stepKey="seeShipTo" selector="{{CheckoutPaymentSection.shipToInformation}}" userInput="{{SimpleTaxCA.state}}"/> <!-- Assert that taxes are applied correctly for CA --> <waitForElementVisible stepKey="waitForOverviewVisible" selector="{{CheckoutPaymentSection.tax}}"/> @@ -329,7 +329,7 @@ <argument name="Address" value="US_Address_NY"/> </actionGroup> <click stepKey="clickNext2" selector="{{CheckoutShippingSection.next}}"/> - <see stepKey="seeShipTo2" selector="{{CheckoutPaymentSection.shipToInfomation}}" userInput="{{SimpleTaxNY.state}}"/> + <see stepKey="seeShipTo2" selector="{{CheckoutPaymentSection.shipToInformation}}" userInput="{{SimpleTaxNY.state}}"/> <!-- Assert that taxes are applied correctly for NY --> <waitForElementVisible stepKey="waitForOverviewVisible2" selector="{{CheckoutPaymentSection.tax}}"/> diff --git a/app/code/Magento/Tax/Test/Mftf/composer.json b/app/code/Magento/Tax/Test/Mftf/composer.json deleted file mode 100644 index e2d9db9f8f76e..0000000000000 --- a/app/code/Magento/Tax/Test/Mftf/composer.json +++ /dev/null @@ -1,32 +0,0 @@ -{ - "name": "magento/functional-test-module-tax", - "description": "N/A", - "config": { - "sort-packages": true - }, - "require": { - "php": "~7.1.3||~7.2.0", - "magento/magento2-functional-testing-framework": "2.2.0", - "magento/functional-test-module-backend": "100.0.0-dev", - "magento/functional-test-module-catalog": "100.0.0-dev", - "magento/functional-test-module-checkout": "100.0.0-dev", - "magento/functional-test-module-config": "100.0.0-dev", - "magento/functional-test-module-customer": "100.0.0-dev", - "magento/functional-test-module-directory": "100.0.0-dev", - "magento/functional-test-module-eav": "100.0.0-dev", - "magento/functional-test-module-page-cache": "100.0.0-dev", - "magento/functional-test-module-quote": "100.0.0-dev", - "magento/functional-test-module-reports": "100.0.0-dev", - "magento/functional-test-module-sales": "100.0.0-dev", - "magento/functional-test-module-shipping": "100.0.0-dev", - "magento/functional-test-module-store": "100.0.0-dev" - }, - "suggest": { - "magento/functional-test-module-tax-sample-data": "100.0.0-dev" - }, - "type": "magento2-test", - "license": [ - "OSL-3.0", - "AFL-3.0" - ] -} diff --git a/app/code/Magento/Tax/Test/Unit/Model/Plugin/OrderSaveTest.php b/app/code/Magento/Tax/Test/Unit/Model/Plugin/OrderSaveTest.php index 82a473b42a82e..17246df8c5b45 100644 --- a/app/code/Magento/Tax/Test/Unit/Model/Plugin/OrderSaveTest.php +++ b/app/code/Magento/Tax/Test/Unit/Model/Plugin/OrderSaveTest.php @@ -222,93 +222,6 @@ public function testAfterSave( */ public function afterSaveDataProvider() { - $orderTaxDetailsApplied = $this->getMockBuilder(\Magento\Tax\Api\Data\OrderTaxDetailsAppliedTaxInterface::class) - ->disableOriginalConstructor() - ->setMethods(['getRates']) - ->getMockForAbstractClass(); - - $orderTaxDetailsApplied->expects($this->at(0)) - ->method('getRates') - ->willReturn( - [ - [ - 'percent' => 6, - 'code' => 'IL', - 'title' => 'IL', - ], - [ - 'percent' => 5, - 'code' => 'US', - 'title' => 'US', - ] - ] - ); - $orderTaxDetailsApplied->expects($this->at(1)) - ->method('getRates') - ->willReturn( - [ - [ - 'percent' => 3, - 'code' => 'CityTax', - 'title' => 'CityTax', - ], - ] - ); - $orderTaxDetailsApplied->expects($this->at(2)) - ->method('getRates') - ->willReturn( - [ - [ - 'percent' => 6, - 'code' => 'IL', - 'title' => 'IL', - ], - [ - 'percent' => 5, - 'code' => 'US', - 'title' => 'US', - ], - ] - ); - $orderTaxDetailsApplied->expects($this->at(3)) - ->method('getRates') - ->willReturn( - [ - [ - 'percent' => 3, - 'code' => 'CityTax', - 'title' => 'CityTax', - ], - ] - ); - $orderTaxDetailsApplied->expects($this->at(4)) - ->method('getRates') - ->willReturn( - [ - [ - 'percent' => 6, - 'code' => 'IL', - 'title' => 'IL', - ], - [ - 'percent' => 5, - 'code' => 'US', - 'title' => 'US', - ], - ] - ); - $orderTaxDetailsApplied->expects($this->at(5)) - ->method('getRates') - ->willReturn( - [ - [ - 'percent' => 3, - 'code' => 'CityTax', - 'title' => 'CityTax', - ], - ] - ); - return [ //one item with shipping //three tax rates: state and national tax rates of 6 and 5 percent with priority 0 @@ -320,14 +233,35 @@ public function afterSaveDataProvider() 'base_amount' => 0.66, 'percent' => 11, 'id' => 'ILUS', - 'extension_attributes' => $orderTaxDetailsApplied, + 'extension_attributes' => [ + 'rates' => [ + [ + 'percent' => 6, + 'code' => 'IL', + 'title' => 'IL', + ], + [ + 'percent' => 5, + 'code' => 'US', + 'title' => 'US', + ], + ] + ], ], [ 'amount' => 0.2, 'base_amount' => 0.2, 'percent' => 3.33, 'id' => 'CityTax', - 'extension_attributes' => $orderTaxDetailsApplied, + 'extension_attributes' => [ + 'rates' => [ + [ + 'percent' => 3, + 'code' => 'CityTax', + 'title' => 'CityTax', + ], + ] + ], ], ], 'item_applied_taxes' => [ @@ -343,7 +277,20 @@ public function afterSaveDataProvider() 'base_amount' => 0.11, 'percent' => 11, 'id' => 'ILUS', - 'extension_attributes' => $orderTaxDetailsApplied, + 'extension_attributes' => [ + 'rates' => [ + [ + 'percent' => 6, + 'code' => 'IL', + 'title' => 'IL', + ], + [ + 'percent' => 5, + 'code' => 'US', + 'title' => 'US', + ], + ] + ], ], //city tax [ @@ -351,7 +298,15 @@ public function afterSaveDataProvider() 'base_amount' => 0.03, 'percent' => 3.33, 'id' => 'CityTax', - 'extension_attributes' => $orderTaxDetailsApplied, + 'extension_attributes' => [ + 'rates' => [ + [ + 'percent' => 3, + 'code' => 'CityTax', + 'title' => 'CityTax', + ], + ] + ], ], ], ], @@ -367,7 +322,20 @@ public function afterSaveDataProvider() 'base_amount' => 0.55, 'percent' => 11, 'id' => 'ILUS', - 'extension_attributes' => $orderTaxDetailsApplied, + 'extension_attributes' => [ + 'rates' => [ + [ + 'percent' => 6, + 'code' => 'IL', + 'title' => 'IL', + ], + [ + 'percent' => 5, + 'code' => 'US', + 'title' => 'US', + ], + ] + ], ], //city tax [ @@ -375,7 +343,15 @@ public function afterSaveDataProvider() 'base_amount' => 0.17, 'percent' => 3.33, 'id' => 'CityTax', - 'extension_attributes' => $orderTaxDetailsApplied, + 'extension_attributes' => [ + 'rates' => [ + [ + 'percent' => 3, + 'code' => 'CityTax', + 'title' => 'CityTax', + ], + ] + ], ], ], ], diff --git a/app/code/Magento/TaxGraphQl/Test/Mftf/composer.json b/app/code/Magento/TaxGraphQl/Test/Mftf/composer.json deleted file mode 100644 index 144f778833cd4..0000000000000 --- a/app/code/Magento/TaxGraphQl/Test/Mftf/composer.json +++ /dev/null @@ -1,20 +0,0 @@ -{ - "name": "magento/functional-test-module-tax-graph-ql", - "description": "N/A", - "config": { - "sort-packages": true - }, - "require": { - "php": "~7.1.3||~7.2.0", - "magento/magento2-functional-testing-framework": "2.2.0" - }, - "suggest": { - "magento/functional-test-module-tax": "100.0.0-dev", - "magento/functional-test-module-catalog-graph-ql": "100.0.0-dev" - }, - "type": "magento2-test", - "license": [ - "OSL-3.0", - "AFL-3.0" - ] -} diff --git a/app/code/Magento/TaxImportExport/Test/Mftf/composer.json b/app/code/Magento/TaxImportExport/Test/Mftf/composer.json deleted file mode 100644 index 39bc90df32651..0000000000000 --- a/app/code/Magento/TaxImportExport/Test/Mftf/composer.json +++ /dev/null @@ -1,20 +0,0 @@ -{ - "name": "magento/functional-test-module-tax-import-export", - "description": "N/A", - "config": { - "sort-packages": true - }, - "require": { - "php": "~7.1.3||~7.2.0", - "magento/magento2-functional-testing-framework": "2.2.0", - "magento/functional-test-module-backend": "100.0.0-dev", - "magento/functional-test-module-directory": "100.0.0-dev", - "magento/functional-test-module-store": "100.0.0-dev", - "magento/functional-test-module-tax": "100.0.0-dev" - }, - "type": "magento2-test", - "license": [ - "OSL-3.0", - "AFL-3.0" - ] -} diff --git a/app/code/Magento/Theme/Controller/Result/MessagePlugin.php b/app/code/Magento/Theme/Controller/Result/MessagePlugin.php index 145493b8e44d8..83172df748a47 100644 --- a/app/code/Magento/Theme/Controller/Result/MessagePlugin.php +++ b/app/code/Magento/Theme/Controller/Result/MessagePlugin.php @@ -5,9 +5,12 @@ */ namespace Magento\Theme\Controller\Result; +use Magento\Framework\App\ObjectManager; use Magento\Framework\Controller\Result\Json; use Magento\Framework\Controller\ResultInterface; use Magento\Framework\Message\MessageInterface; +use Magento\Framework\Translate\Inline\ParserInterface; +use Magento\Framework\Translate\InlineInterface; /** * Plugin for putting messages to cookies @@ -44,26 +47,34 @@ class MessagePlugin */ private $serializer; + /** + * @var InlineInterface + */ + private $inlineTranslate; + /** * @param \Magento\Framework\Stdlib\CookieManagerInterface $cookieManager * @param \Magento\Framework\Stdlib\Cookie\CookieMetadataFactory $cookieMetadataFactory * @param \Magento\Framework\Message\ManagerInterface $messageManager * @param \Magento\Framework\View\Element\Message\InterpretationStrategyInterface $interpretationStrategy * @param \Magento\Framework\Serialize\Serializer\Json|null $serializer + * @param InlineInterface|null $inlineTranslate */ public function __construct( \Magento\Framework\Stdlib\CookieManagerInterface $cookieManager, \Magento\Framework\Stdlib\Cookie\CookieMetadataFactory $cookieMetadataFactory, \Magento\Framework\Message\ManagerInterface $messageManager, \Magento\Framework\View\Element\Message\InterpretationStrategyInterface $interpretationStrategy, - \Magento\Framework\Serialize\Serializer\Json $serializer = null + \Magento\Framework\Serialize\Serializer\Json $serializer = null, + InlineInterface $inlineTranslate = null ) { $this->cookieManager = $cookieManager; $this->cookieMetadataFactory = $cookieMetadataFactory; $this->messageManager = $messageManager; - $this->serializer = $serializer ?: \Magento\Framework\App\ObjectManager::getInstance() + $this->serializer = $serializer ?: ObjectManager::getInstance() ->get(\Magento\Framework\Serialize\Serializer\Json::class); $this->interpretationStrategy = $interpretationStrategy; + $this->inlineTranslate = $inlineTranslate ?: ObjectManager::getInstance()->get(InlineInterface::class); } /** @@ -112,6 +123,12 @@ public function afterRenderResult( private function setCookie(array $messages) { if (!empty($messages)) { + if ($this->inlineTranslate->isAllowed()) { + foreach ($messages as &$message) { + $message['text'] = $this->convertMessageText($message['text']); + } + } + $publicCookieMetadata = $this->cookieMetadataFactory->createPublicCookieMetadata(); $publicCookieMetadata->setDurationOneYear(); $publicCookieMetadata->setPath('/'); @@ -125,6 +142,21 @@ private function setCookie(array $messages) } } + /** + * Replace wrapping translation with html body. + * + * @param string $text + * @return string + */ + private function convertMessageText(string $text): string + { + if (preg_match('#' . ParserInterface::REGEXP_TOKEN . '#', $text, $matches)) { + $text = $matches[1]; + } + + return $text; + } + /** * Return messages array and clean message manager messages * diff --git a/app/code/Magento/Theme/Test/Mftf/Data/DesignData.xml b/app/code/Magento/Theme/Test/Mftf/Data/DesignData.xml new file mode 100644 index 0000000000000..988d71bc4086b --- /dev/null +++ b/app/code/Magento/Theme/Test/Mftf/Data/DesignData.xml @@ -0,0 +1,14 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> + +<entities xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="../../../../../../../dev/tests/acceptance/vendor/magento/magento2-functional-testing-framework/src/Magento/FunctionalTestingFramework/DataGenerator/etc/dataProfileSchema.xsd"> + <entity name="Layout" type="page_layout"> + <data key="1column">1 column</data> + </entity> +</entities> diff --git a/app/code/Magento/Theme/Test/Mftf/Section/AdminThemeSection.xml b/app/code/Magento/Theme/Test/Mftf/Section/AdminThemeSection.xml index 2e5a786d45725..67a5146fd8b3a 100644 --- a/app/code/Magento/Theme/Test/Mftf/Section/AdminThemeSection.xml +++ b/app/code/Magento/Theme/Test/Mftf/Section/AdminThemeSection.xml @@ -10,7 +10,7 @@ xsi:noNamespaceSchemaLocation="../../../../../../../dev/tests/acceptance/vendor/magento/magento2-functional-testing-framework/src/Magento/FunctionalTestingFramework/Page/etc/SectionObject.xsd"> <section name="AdminThemeSection"> <!--All rows in a specific Column e.g. {{Section.rowsInColumn('columnName')}}--> - <element name="rowsInColumn" type="text" selector="//tr/td[contains(@class, '{{column}}')]" parameterized="true"/> + <element name="allRowsInColumn" type="text" selector="//tr/td[contains(@class, '{{column}}')]" parameterized="true"/> <!--selector for Theme Title column since it needs to be handled separately--> <element name="rowsInThemeTitleColumn" type="text" selector="//tbody/tr/td[contains(@class, 'parent_theme')]/preceding-sibling::td"/> <element name="rowsInColumn" type="text" selector="//tbody/tr/td[contains(@class, '{{column}}')]" parameterized="true"/> diff --git a/app/code/Magento/Theme/Test/Mftf/composer.json b/app/code/Magento/Theme/Test/Mftf/composer.json deleted file mode 100644 index f93dac15279a4..0000000000000 --- a/app/code/Magento/Theme/Test/Mftf/composer.json +++ /dev/null @@ -1,32 +0,0 @@ -{ - "name": "magento/functional-test-module-theme", - "description": "N/A", - "config": { - "sort-packages": true - }, - "require": { - "php": "~7.1.3||~7.2.0", - "magento/magento2-functional-testing-framework": "2.2.0", - "magento/functional-test-module-backend": "100.0.0-dev", - "magento/functional-test-module-cms": "100.0.0-dev", - "magento/functional-test-module-config": "100.0.0-dev", - "magento/functional-test-module-customer": "100.0.0-dev", - "magento/functional-test-module-eav": "100.0.0-dev", - "magento/functional-test-module-media-storage": "100.0.0-dev", - "magento/functional-test-module-require-js": "100.0.0-dev", - "magento/functional-test-module-store": "100.0.0-dev", - "magento/functional-test-module-ui": "100.0.0-dev", - "magento/functional-test-module-widget": "100.0.0-dev" - }, - "suggest": { - "magento/functional-test-module-translation": "100.0.0-dev", - "magento/functional-test-module-theme-sample-data": "100.0.0-dev", - "magento/functional-test-module-deploy": "100.0.0-dev", - "magento/functional-test-module-directory": "100.0.0-dev" - }, - "type": "magento2-test", - "license": [ - "OSL-3.0", - "AFL-3.0" - ] -} diff --git a/app/code/Magento/Theme/Test/Unit/Controller/Result/MessagePluginTest.php b/app/code/Magento/Theme/Test/Unit/Controller/Result/MessagePluginTest.php index 60457fc1436c0..748f7a1fcb9fb 100644 --- a/app/code/Magento/Theme/Test/Unit/Controller/Result/MessagePluginTest.php +++ b/app/code/Magento/Theme/Test/Unit/Controller/Result/MessagePluginTest.php @@ -14,6 +14,7 @@ use Magento\Framework\Stdlib\Cookie\CookieMetadataFactory; use Magento\Framework\Stdlib\Cookie\PublicCookieMetadata; use Magento\Framework\Stdlib\CookieManagerInterface; +use Magento\Framework\Translate\InlineInterface; use Magento\Framework\View\Element\Message\InterpretationStrategyInterface; use Magento\Theme\Controller\Result\MessagePlugin; @@ -40,6 +41,9 @@ class MessagePluginTest extends \PHPUnit\Framework\TestCase /** @var \Magento\Framework\Serialize\Serializer\Json|\PHPUnit_Framework_MockObject_MockObject */ private $serializerMock; + /** @var InlineInterface|\PHPUnit_Framework_MockObject_MockObject */ + private $inlineTranslateMock; + protected function setUp() { $this->cookieManagerMock = $this->getMockBuilder(CookieManagerInterface::class) @@ -53,13 +57,15 @@ protected function setUp() ->getMockForAbstractClass(); $this->serializerMock = $this->getMockBuilder(\Magento\Framework\Serialize\Serializer\Json::class) ->getMock(); + $this->inlineTranslateMock = $this->getMockBuilder(InlineInterface::class)->getMockForAbstractClass(); $this->model = new MessagePlugin( $this->cookieManagerMock, $this->cookieMetadataFactoryMock, $this->managerMock, $this->interpretationStrategyMock, - $this->serializerMock + $this->serializerMock, + $this->inlineTranslateMock ); } @@ -450,4 +456,93 @@ function ($data) { $this->assertEquals($resultMock, $this->model->afterRenderResult($resultMock, $resultMock)); } + + /** + * @return void + */ + public function testAfterRenderResultWithAllowedInlineTranslate(): void + { + $messageType = 'message1type'; + $messageText = '{{{message1text}}{{message1text}}{{message1text}}{{theme/luma}}}'; + $expectedMessages = [ + [ + 'type' => $messageType, + 'text' => 'message1text', + ], + ]; + + /** @var Redirect|\PHPUnit_Framework_MockObject_MockObject $resultMock */ + $resultMock = $this->getMockBuilder(Redirect::class) + ->disableOriginalConstructor() + ->getMock(); + + /** @var PublicCookieMetadata|\PHPUnit_Framework_MockObject_MockObject $cookieMetadataMock */ + $cookieMetadataMock = $this->getMockBuilder(PublicCookieMetadata::class) + ->disableOriginalConstructor() + ->getMock(); + + $this->cookieMetadataFactoryMock->expects($this->once()) + ->method('createPublicCookieMetadata') + ->willReturn($cookieMetadataMock); + + $this->cookieManagerMock->expects($this->once()) + ->method('setPublicCookie') + ->with( + MessagePlugin::MESSAGES_COOKIES_NAME, + json_encode($expectedMessages), + $cookieMetadataMock + ); + $this->cookieManagerMock->expects($this->once()) + ->method('getCookie') + ->with( + MessagePlugin::MESSAGES_COOKIES_NAME + ) + ->willReturn(json_encode([])); + + $this->serializerMock->expects($this->once()) + ->method('unserialize') + ->willReturnCallback( + function ($data) { + return json_decode($data, true); + } + ); + $this->serializerMock->expects($this->once()) + ->method('serialize') + ->willReturnCallback( + function ($data) { + return json_encode($data); + } + ); + + /** @var MessageInterface|\PHPUnit_Framework_MockObject_MockObject $messageMock */ + $messageMock = $this->getMockBuilder(MessageInterface::class) + ->getMock(); + $messageMock->expects($this->once()) + ->method('getType') + ->willReturn($messageType); + + $this->interpretationStrategyMock->expects($this->once()) + ->method('interpret') + ->with($messageMock) + ->willReturn($messageText); + + $this->inlineTranslateMock->expects($this->once()) + ->method('isAllowed') + ->willReturn(true); + + /** @var Collection|\PHPUnit_Framework_MockObject_MockObject $collectionMock */ + $collectionMock = $this->getMockBuilder(Collection::class) + ->disableOriginalConstructor() + ->getMock(); + $collectionMock->expects($this->once()) + ->method('getItems') + ->willReturn([$messageMock]); + + $this->managerMock->expects($this->once()) + ->method('getMessages') + ->with(true, null) + ->willReturn($collectionMock); + + $this->assertEquals($resultMock, $this->model->afterRenderResult($resultMock, $resultMock)); + } } diff --git a/app/code/Magento/Theme/etc/di.xml b/app/code/Magento/Theme/etc/di.xml index 55119f3449389..5ff82ce2db6f6 100644 --- a/app/code/Magento/Theme/etc/di.xml +++ b/app/code/Magento/Theme/etc/di.xml @@ -69,7 +69,7 @@ </type> <type name="Magento\Framework\App\Area"> <arguments> - <argument name="translator" xsi:type="object">Magento\Framework\Translate</argument> + <argument name="translator" xsi:type="object">Magento\Framework\TranslateInterface</argument> <argument name="design" xsi:type="object">Magento\Theme\Model\Design\Proxy</argument> </arguments> </type> diff --git a/app/code/Magento/Theme/view/frontend/templates/html/collapsible.phtml b/app/code/Magento/Theme/view/frontend/templates/html/collapsible.phtml index 318bcc8f2cc7c..c3ad4a89399a0 100644 --- a/app/code/Magento/Theme/view/frontend/templates/html/collapsible.phtml +++ b/app/code/Magento/Theme/view/frontend/templates/html/collapsible.phtml @@ -10,7 +10,7 @@ <div class="block <?= /* @escapeNotVerified */ $block->getBlockCss() ?>"> <div class="title <?= /* @escapeNotVerified */ $block->getBlockCss() ?>-title" data-mage-init='{"toggleAdvanced": {"toggleContainers": "#<?= /* @escapeNotVerified */ $block->getBlockCss() ?>", "selectorsToggleClass": "active"}}'> - <strong><?= /* @escapeNotVerified */ $block->getBlockTitle() ?></strong> + <strong><?= /* @escapeNotVerified */ __($block->getBlockTitle()) ?></strong> </div> <div class="content <?= /* @escapeNotVerified */ $block->getBlockCss() ?>-content" id="<?= /* @escapeNotVerified */ $block->getBlockCss() ?>"> <?= $block->getChildHtml() ?> diff --git a/app/code/Magento/Theme/view/frontend/web/templates/breadcrumbs.html b/app/code/Magento/Theme/view/frontend/web/templates/breadcrumbs.html index f298c0a58e814..792eb2e636005 100644 --- a/app/code/Magento/Theme/view/frontend/web/templates/breadcrumbs.html +++ b/app/code/Magento/Theme/view/frontend/web/templates/breadcrumbs.html @@ -10,9 +10,9 @@ <% if (crumb.link) { %> <a href="<%= crumb.link %>" title="<%- crumb.title %>"><%- crumb.label %></a> <% } else if (crumb.last) { %> - <strong><%- crumb.label %></strong> + <strong><%= crumb.label %></strong> <% } else { %> - <%- crumb.label %> + <%= crumb.label %> <% } %> </li> <% }); %> diff --git a/app/code/Magento/Tinymce3/Test/Mftf/Test/AdminSwitchWYSIWYGOptionsTest.xml b/app/code/Magento/Tinymce3/Test/Mftf/Test/AdminSwitchWYSIWYGOptionsTest.xml index 4a1c7e07c38c6..0806011e8ffbc 100644 --- a/app/code/Magento/Tinymce3/Test/Mftf/Test/AdminSwitchWYSIWYGOptionsTest.xml +++ b/app/code/Magento/Tinymce3/Test/Mftf/Test/AdminSwitchWYSIWYGOptionsTest.xml @@ -17,8 +17,9 @@ <description value="Admin should able to switch between versions of TinyMCE"/> <severity value="CRITICAL"/> <testCaseId value="MAGETWO-82936"/> - <!--Skip because of issue MAGETWO-89417--> - <group value="skip"/> + <skip> + <issueId value="MAGETWO-89417"/> + </skip> </annotations> <before> <actionGroup ref="LoginActionGroup" stepKey="loginGetFromGeneralFile"/> diff --git a/app/code/Magento/Tinymce3/Test/Mftf/composer.json b/app/code/Magento/Tinymce3/Test/Mftf/composer.json deleted file mode 100644 index 84c1f9376bf45..0000000000000 --- a/app/code/Magento/Tinymce3/Test/Mftf/composer.json +++ /dev/null @@ -1,22 +0,0 @@ -{ - "name": "magento/functional-test-module-tinymce-3", - "description": "N/A", - "config": { - "sort-packages": true - }, - "require": { - "php": "~7.1.3||~7.2.0", - "magento/magento2-functional-testing-framework": "2.2.0", - "magento/functional-test-module-ui": "100.0.0-dev", - "magento/functional-test-module-variable": "100.0.0-dev", - "magento/functional-test-module-widget": "100.0.0-dev" - }, - "suggest": { - "magento/functional-test-module-cms": "100.0.0-dev" - }, - "type": "magento2-test", - "license": [ - "OSL-3.0", - "AFL-3.0" - ] -} diff --git a/app/code/Magento/Tinymce3/view/base/web/tinymce3Adapter.js b/app/code/Magento/Tinymce3/view/base/web/tinymce3Adapter.js index 88e2d4cc78f96..7c587c1c8768a 100644 --- a/app/code/Magento/Tinymce3/view/base/web/tinymce3Adapter.js +++ b/app/code/Magento/Tinymce3/view/base/web/tinymce3Adapter.js @@ -495,7 +495,7 @@ define([ */ encodeDirectives: function (content) { // collect all HTML tags with attributes that contain directives - return content.gsub(/<([a-z0-9\-\_]+[^>]+?)([a-z0-9\-\_]+=".*?\{\{.+?\}\}.*?".*?)>/i, function (match) { + return content.gsub(/<([a-z0-9\-\_]+[^>]+?)([a-z0-9\-\_]+="[^"]*?\{\{.+?\}\}.*?".*?)>/i, function (match) { var attributesString = match[2], decodedDirectiveString; diff --git a/app/code/Magento/Translation/Model/Js/DataProvider.php b/app/code/Magento/Translation/Model/Js/DataProvider.php index a73d4ee99b5d6..7aad7c765bcd5 100644 --- a/app/code/Magento/Translation/Model/Js/DataProvider.php +++ b/app/code/Magento/Translation/Model/Js/DataProvider.php @@ -113,7 +113,8 @@ public function getData($themePath) } } catch (\Exception $e) { throw new LocalizedException( - __('Error while translating phrase "%s" in file %s.', $phrase, $filePath[0]) + __('Error while translating phrase "%s" in file %s.', $phrase, $filePath[0]), + $e ); } } diff --git a/app/code/Magento/Translation/Test/Mftf/composer.json b/app/code/Magento/Translation/Test/Mftf/composer.json deleted file mode 100644 index 36bfa66adda0f..0000000000000 --- a/app/code/Magento/Translation/Test/Mftf/composer.json +++ /dev/null @@ -1,22 +0,0 @@ -{ - "name": "magento/functional-test-module-translation", - "description": "N/A", - "config": { - "sort-packages": true - }, - "require": { - "php": "~7.1.3||~7.2.0", - "magento/magento2-functional-testing-framework": "2.2.0", - "magento/functional-test-module-backend": "100.0.0-dev", - "magento/functional-test-module-developer": "100.0.0-dev", - "magento/functional-test-module-store": "100.0.0-dev" - }, - "suggest": { - "magento/functional-test-module-deploy": "100.0.0-dev" - }, - "type": "magento2-test", - "license": [ - "OSL-3.0", - "AFL-3.0" - ] -} diff --git a/app/code/Magento/Ui/Component/MassAction/Filter.php b/app/code/Magento/Ui/Component/MassAction/Filter.php index 6877303f5c491..a8ed5d901d860 100644 --- a/app/code/Magento/Ui/Component/MassAction/Filter.php +++ b/app/code/Magento/Ui/Component/MassAction/Filter.php @@ -99,14 +99,12 @@ public function getCollection(AbstractDb $collection) throw new LocalizedException(__('An item needs to be selected. Select and try again.')); } } - /** @var \Magento\Customer\Model\ResourceModel\Customer\Collection $collection */ - $idsArray = $this->getFilterIds(); - if (!empty($idsArray)) { - $collection->addFieldToFilter( - $collection->getIdFieldName(), - ['in' => $idsArray] - ); - } + + $collection->addFieldToFilter( + $collection->getIdFieldName(), + ['in' => $this->getFilterIds()] + ); + return $collection; } diff --git a/app/code/Magento/Ui/DataProvider/EavValidationRules.php b/app/code/Magento/Ui/DataProvider/EavValidationRules.php index 12e345e1fa12c..6e2bb3866e947 100644 --- a/app/code/Magento/Ui/DataProvider/EavValidationRules.php +++ b/app/code/Magento/Ui/DataProvider/EavValidationRules.php @@ -3,6 +3,7 @@ * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ + namespace Magento\Ui\DataProvider; use Magento\Eav\Model\Entity\Attribute\AbstractAttribute; @@ -31,25 +32,51 @@ class EavValidationRules */ public function build(AbstractAttribute $attribute, array $data) { - $validation = []; + $validations = []; if (isset($data['required']) && $data['required'] == 1) { - $validation = array_merge($validation, ['required-entry' => true]); + $validations = array_merge($validations, ['required-entry' => true]); } if ($attribute->getFrontendInput() === 'price') { - $validation = array_merge($validation, ['validate-zero-or-greater' => true]); + $validations = array_merge($validations, ['validate-zero-or-greater' => true]); } if ($attribute->getValidateRules()) { - $validation = array_merge($validation, $attribute->getValidateRules()); + $validations = array_merge($validations, $this->clipLengthRules($attribute->getValidateRules())); } + return $this->aggregateRules($validations); + } + + /** + * @param array $validations + * @return array + */ + private function aggregateRules(array $validations): array + { $rules = []; - foreach ($validation as $type => $ruleName) { - $rule = [$type => $ruleName]; + foreach ($validations as $type => $ruleValue) { + $rule = [$type => $ruleValue]; if ($type === 'input_validation') { - $rule = isset($this->validationRules[$ruleName]) ? $this->validationRules[$ruleName] : []; + $rule = $this->validationRules[$ruleValue] ?? []; + } + if (count($rule) !== 0) { + $key = key($rule); + $rules[$key] = $rule[$key]; } - $rules = array_merge($rules, $rule); } + return $rules; + } + /** + * @param array $rules + * @return array + */ + private function clipLengthRules(array $rules): array + { + if (empty($rules['input_validation'])) { + unset( + $rules['min_text_length'], + $rules['max_text_length'] + ); + } return $rules; } } diff --git a/app/code/Magento/Ui/Test/Mftf/composer.json b/app/code/Magento/Ui/Test/Mftf/composer.json deleted file mode 100644 index 86a99d02bd959..0000000000000 --- a/app/code/Magento/Ui/Test/Mftf/composer.json +++ /dev/null @@ -1,24 +0,0 @@ -{ - "name": "magento/functional-test-module-ui", - "description": "N/A", - "config": { - "sort-packages": true - }, - "require": { - "php": "~7.1.3||~7.2.0", - "magento/magento2-functional-testing-framework": "2.2.0", - "magento/functional-test-module-authorization": "100.0.0-dev", - "magento/functional-test-module-backend": "100.0.0-dev", - "magento/functional-test-module-eav": "100.0.0-dev", - "magento/functional-test-module-store": "100.0.0-dev", - "magento/functional-test-module-user": "100.0.0-dev" - }, - "suggest": { - "magento/functional-test-module-config": "100.0.0-dev" - }, - "type": "magento2-test", - "license": [ - "OSL-3.0", - "AFL-3.0" - ] -} diff --git a/app/code/Magento/Ui/Test/Unit/DataProvider/EavValidationRulesTest.php b/app/code/Magento/Ui/Test/Unit/DataProvider/EavValidationRulesTest.php index debcde4765fc7..cdb62ce1db68d 100644 --- a/app/code/Magento/Ui/Test/Unit/DataProvider/EavValidationRulesTest.php +++ b/app/code/Magento/Ui/Test/Unit/DataProvider/EavValidationRulesTest.php @@ -3,6 +3,7 @@ * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ + namespace Magento\Ui\Test\Unit\DataProvider; use Magento\Eav\Model\Entity\Attribute\AbstractAttribute; @@ -29,6 +30,9 @@ class EavValidationRulesTest extends \PHPUnit\Framework\TestCase */ protected $attributeMock; + /** + * {@inheritDoc} + */ protected function setUp() { $this->objectManager = new ObjectManager($this); @@ -42,11 +46,13 @@ protected function setUp() } /** + * @param string $attributeInputType + * @param mixed $validateRules * @param array $data * @param array $expected * @dataProvider buildDataProvider */ - public function testBuild($attributeInputType, $validateRules, $data, $expected) + public function testBuild($attributeInputType, $validateRules, $data, $expected): void { $this->attributeMock->expects($this->once())->method('getFrontendInput')->willReturn($attributeInputType); $this->attributeMock->expects($this->any())->method('getValidateRules')->willReturn($validateRules); @@ -70,11 +76,25 @@ public function buildDataProvider() ['', ['input_validation' => 'email'], [], ['validate-email' => true]], ['', ['input_validation' => 'date'], [], ['validate-date' => true]], ['', ['input_validation' => 'other'], [], []], - ['', ['max_text_length' => '254'], ['required' => 1], ['max_text_length' => 254, 'required-entry' => true]], - ['', ['max_text_length' => '254', 'min_text_length' => 1], [], - ['max_text_length' => 254, 'min_text_length' => 1]], - ['', ['max_text_length' => '254', 'input_validation' => 'date'], [], - ['max_text_length' => 254, 'validate-date' => true]], + ['', ['max_text_length' => '254'], ['required' => 1], ['required-entry' => true]], + [ + '', + ['input_validation' => 'other', 'max_text_length' => '254'], + ['required' => 1], + ['max_text_length' => 254, 'required-entry' => true] + ], + [ + '', + ['input_validation' => 'other', 'max_text_length' => '254', 'min_text_length' => 1], + [], + ['max_text_length' => 254, 'min_text_length' => 1] + ], + [ + '', + ['max_text_length' => '254', 'input_validation' => 'date'], + [], + ['max_text_length' => 254, 'validate-date' => true] + ], ]; } } diff --git a/app/code/Magento/Ui/etc/adminhtml/system.xml b/app/code/Magento/Ui/etc/adminhtml/system.xml index 74e2e076b93c8..ab4272f8d2a34 100644 --- a/app/code/Magento/Ui/etc/adminhtml/system.xml +++ b/app/code/Magento/Ui/etc/adminhtml/system.xml @@ -9,12 +9,12 @@ <system> <section id="dev"> <group id="js"> - <field id="session_storage_logging" translate="label" type="select" sortOrder="100" showInDefault="1" showInWebsite="0" showInStore="0" canRestore="1"> + <field id="session_storage_logging" translate="label comment" type="select" sortOrder="100" showInDefault="1" showInWebsite="0" showInStore="0" canRestore="1"> <label>Log JS Errors to Session Storage</label> <source_model>Magento\Config\Model\Config\Source\Yesno</source_model> <comment>If enabled, can be used by functional tests for extended reporting</comment> </field> - <field id="session_storage_key" translate="label" type="text" sortOrder="110" showInDefault="1" showInWebsite="0" showInStore="0" canRestore="1"> + <field id="session_storage_key" translate="label comment" type="text" sortOrder="110" showInDefault="1" showInWebsite="0" showInStore="0" canRestore="1"> <label>Log JS Errors to Session Storage Key</label> <comment>Use this key to retrieve collected js errors</comment> </field> diff --git a/app/code/Magento/Ui/i18n/en_US.csv b/app/code/Magento/Ui/i18n/en_US.csv index ed4386f6000c3..106526f66e708 100644 --- a/app/code/Magento/Ui/i18n/en_US.csv +++ b/app/code/Magento/Ui/i18n/en_US.csv @@ -125,30 +125,18 @@ Ok,Ok "Label Actions Two","Label Actions Two" "Some Dynamic Actions","Some Dynamic Actions" "Log JS Errors to Session Storage","Log JS Errors to Session Storage" +"If enabled, can be used by functional tests for extended reporting","If enabled, can be used by functional tests for extended reporting" "Log JS Errors to Session Storage Key","Log JS Errors to Session Storage Key" +"Use this key to retrieve collected js errors","Use this key to retrieve collected js errors" settings/label,settings/label settings/confirm/title,settings/confirm/title -"settings/confirm/message - ","settings/confirm/message - " -" - settings/callback/provider - "," - settings/callback/provider - " -"settings/callback/target - ","settings/callback/target - " -"settings/newViewLabel - ","settings/newViewLabel - " +"settings/confirm/message","settings/confirm/message" +"settings/callback/provider","settings/callback/provider" +"settings/callback/target","settings/callback/target" +"settings/newViewLabel","settings/newViewLabel" settings/title,settings/title settings/description,settings/description -" - settings/addButtonLabel - "," - settings/addButtonLabel - " +"settings/addButtonLabel","settings/addButtonLabel" " formElements/*[name(.)=../../@formElement]/settings/description "," diff --git a/app/code/Magento/Ui/view/base/ui_component/etc/definition.map.xml b/app/code/Magento/Ui/view/base/ui_component/etc/definition.map.xml index 94272f723ec77..ccd702c23ea65 100644 --- a/app/code/Magento/Ui/view/base/ui_component/etc/definition.map.xml +++ b/app/code/Magento/Ui/view/base/ui_component/etc/definition.map.xml @@ -16,15 +16,11 @@ <item name="url" type="url" xsi:type="converter">settings/url</item> <item name="confirm" xsi:type="array"> <item name="title" type="string" translate="true" xsi:type="xpath">settings/confirm/title</item> - <item name="message" type="string" translate="true" xsi:type="xpath">settings/confirm/message - </item> + <item name="message" type="string" translate="true" xsi:type="xpath">settings/confirm/message</item> </item> <item name="callback" xsi:type="array"> - <item name="provider" type="string" translate="true" xsi:type="xpath"> - settings/callback/provider - </item> - <item name="target" type="string" translate="true" xsi:type="xpath">settings/callback/target - </item> + <item name="provider" type="string" translate="true" xsi:type="xpath">settings/callback/provider</item> + <item name="target" type="string" translate="true" xsi:type="xpath">settings/callback/target</item> </item> </item> </argument> @@ -59,8 +55,7 @@ <item name="config" xsi:type="array"> <item name="childDefaults" type="item" xsi:type="converter">settings/childDefaults</item> <item name="viewTmpl" type="string" xsi:type="xpath">settings/viewTmpl</item> - <item name="newViewLabel" translate="true" type="string" xsi:type="xpath">settings/newViewLabel - </item> + <item name="newViewLabel" translate="true" type="string" xsi:type="xpath">settings/newViewLabel</item> </item> </argument> </schema> @@ -265,9 +260,7 @@ <item name="columnsHeaderClasses" type="string" xsi:type="xpath">settings/columnsHeaderClasses</item> <item name="recordTemplate" type="string" xsi:type="xpath">settings/recordTemplate</item> <item name="collapsibleHeader" type="boolean" xsi:type="xpath">settings/collapsibleHeader</item> - <item name="addButtonLabel" type="string" translate="true" xsi:type="xpath"> - settings/addButtonLabel - </item> + <item name="addButtonLabel" type="string" translate="true" xsi:type="xpath">settings/addButtonLabel</item> <item name="addButton" type="boolean" xsi:type="xpath">settings/addButton</item> <item name="deleteProperty" type="string" xsi:type="xpath">settings/deleteProperty</item> <item name="identificationProperty" type="string" xsi:type="xpath">settings/identificationProperty</item> diff --git a/app/code/Magento/Ui/view/base/web/js/dynamic-rows/dynamic-rows.js b/app/code/Magento/Ui/view/base/web/js/dynamic-rows/dynamic-rows.js index 7537107560cb4..1d52fc78d7a85 100644 --- a/app/code/Magento/Ui/view/base/web/js/dynamic-rows/dynamic-rows.js +++ b/app/code/Magento/Ui/view/base/web/js/dynamic-rows/dynamic-rows.js @@ -330,9 +330,7 @@ define([ } if (this.defaultPagesState[this.currentPage()]) { - this.pagesChanged[this.currentPage()] = - !compareArrays(this.defaultPagesState[this.currentPage()], this.arrayFilter(this.getChildItems())); - this.changed(_.some(this.pagesChanged)); + this.setChangedForCurrentPage(); } }, @@ -442,13 +440,9 @@ define([ return initialize; })); - this.pagesChanged[this.currentPage()] = - !compareArrays(this.defaultPagesState[this.currentPage()], this.arrayFilter(this.getChildItems())); - this.changed(_.some(this.pagesChanged)); + this.setChangedForCurrentPage(); } else if (this.hasInitialPagesState[this.currentPage()]) { - this.pagesChanged[this.currentPage()] = - !compareArrays(this.defaultPagesState[this.currentPage()], this.arrayFilter(this.getChildItems())); - this.changed(_.some(this.pagesChanged)); + this.setChangedForCurrentPage(); } }, @@ -848,7 +842,8 @@ define([ deleteRecord: function (index, recordId) { var recordInstance, lastRecord, - recordsData; + recordsData, + lastRecordIndex; if (this.deleteProperty) { recordsData = this.recordData(); @@ -867,12 +862,13 @@ define([ this.update = true; if (~~this.currentPage() === this.pages()) { + lastRecordIndex = this.startIndex + this.getChildItems().length - 1; lastRecord = _.findWhere(this.elems(), { - index: this.startIndex + this.getChildItems().length - 1 + index: lastRecordIndex }) || _.findWhere(this.elems(), { - index: (this.startIndex + this.getChildItems().length - 1).toString() + index: lastRecordIndex.toString() }); lastRecord.destroy(); @@ -1133,6 +1129,18 @@ define([ }); this.isDifferedFromDefault(!_.isEqual(recordData, this.default)); + }, + + /** + * Set the changed property if the current page is different + * than the default state + * + * @return void + */ + setChangedForCurrentPage: function () { + this.pagesChanged[this.currentPage()] = + !compareArrays(this.defaultPagesState[this.currentPage()], this.arrayFilter(this.getChildItems())); + this.changed(_.some(this.pagesChanged)); } }); }); diff --git a/app/code/Magento/Ui/view/base/web/js/form/components/fieldset.js b/app/code/Magento/Ui/view/base/web/js/form/components/fieldset.js index b729dd3127d90..6d33386fa1f1c 100644 --- a/app/code/Magento/Ui/view/base/web/js/form/components/fieldset.js +++ b/app/code/Magento/Ui/view/base/web/js/form/components/fieldset.js @@ -22,7 +22,7 @@ define([ opened: false, level: 0, visible: true, - initializeFieldsetDataByDefault: false, /* Data in some fieldsets should be initialized before open */ + initializeFieldsetDataByDefault: false, /* Data in some fieldsets should be initialized before open */ disabled: false, listens: { 'opened': 'onVisibilityChange' @@ -77,9 +77,9 @@ define([ elem.initContainer(this); elem.on({ - 'update': this.onChildrenUpdate, - 'loading': this.onContentLoading, - 'error': this.onChildrenError + 'update': this.onChildrenUpdate, + 'loading': this.onContentLoading, + 'error': this.onChildrenError }); if (this.disabled) { @@ -155,11 +155,42 @@ define([ * @param {String} message - error message. */ onChildrenError: function (message) { - var hasErrors = this.elems.some('error'); + var hasErrors = false; + + if (!message) { + hasErrors = this._isChildrenHasErrors(hasErrors, this); + } this.error(hasErrors || message); }, + /** + * Returns errors of children if exist + * + * @param {Boolean} hasErrors + * @param {*} container + * @return {Boolean} + * @private + */ + _isChildrenHasErrors: function (hasErrors, container) { + var self = this; + + if (hasErrors === false && container.hasOwnProperty('elems')) { + hasErrors = container.elems.some('error'); + + if (hasErrors === false && container.hasOwnProperty('_elems')) { + container._elems.forEach(function (child) { + + if (hasErrors === false) { + hasErrors = self._isChildrenHasErrors(hasErrors, child); + } + }); + } + } + + return hasErrors; + }, + /** * Callback that sets loading property to true. */ diff --git a/app/code/Magento/Ui/view/base/web/js/form/element/abstract.js b/app/code/Magento/Ui/view/base/web/js/form/element/abstract.js index 5177b4a378d69..5d79ac77218f5 100755 --- a/app/code/Magento/Ui/view/base/web/js/form/element/abstract.js +++ b/app/code/Magento/Ui/view/base/web/js/form/element/abstract.js @@ -40,6 +40,7 @@ define([ showFallbackReset: false, additionalClasses: {}, isUseDefault: '', + serviceDisabled: false, valueUpdate: false, // ko binding valueUpdate switcherConfig: { @@ -97,7 +98,7 @@ define([ this._super(); this.observe('error disabled focused preview visible value warn notice isDifferedFromDefault') - .observe('isUseDefault') + .observe('isUseDefault serviceDisabled') .observe({ 'required': !!rules['required-entry'] }); @@ -407,7 +408,7 @@ define([ this.bubble('error', message); //TODO: Implement proper result propagation for form - if (!isValid) { + if (this.source && !isValid) { this.source.set('params.invalid', true); } diff --git a/app/code/Magento/Ui/view/base/web/js/form/element/file-uploader.js b/app/code/Magento/Ui/view/base/web/js/form/element/file-uploader.js index b583d0be69f34..6492d0821fc21 100644 --- a/app/code/Magento/Ui/view/base/web/js/form/element/file-uploader.js +++ b/app/code/Magento/Ui/view/base/web/js/form/element/file-uploader.js @@ -6,6 +6,7 @@ /** * @api */ +/* global Base64 */ define([ 'jquery', 'underscore', @@ -168,6 +169,10 @@ define([ processFile: function (file) { file.previewType = this.getFilePreviewType(file); + if (!file.id && file.name) { + file.id = Base64.mageEncode(file.name); + } + this.observe.call(file, true, [ 'previewWidth', 'previewHeight' diff --git a/app/code/Magento/Ui/view/base/web/js/form/element/image-uploader.js b/app/code/Magento/Ui/view/base/web/js/form/element/image-uploader.js index 69c9fb74cbce1..0ae09f14fa946 100644 --- a/app/code/Magento/Ui/view/base/web/js/form/element/image-uploader.js +++ b/app/code/Magento/Ui/view/base/web/js/form/element/image-uploader.js @@ -17,6 +17,15 @@ define([ 'use strict'; return Element.extend({ + /** + * {@inheritDoc} + */ + initialize: function () { + this._super(); + + // Listen for file deletions from the media browser + $(window).on('fileDeleted.mediabrowser', this.onDeleteFile.bind(this)); + }, /** * Assign uid for media gallery @@ -76,6 +85,40 @@ define([ browser.openDialog(openDialogUrl, null, null, this.mediaGallery.openDialogTitle); }, + /** + * @param {jQuery.event} e + * @param {Object} data + * @returns {Object} Chainables + */ + onDeleteFile: function (e, data) { + var fileId = this.getFileId(), + deletedFileIds = data.ids; + + if (fileId && $.inArray(fileId, deletedFileIds) > -1) { + this.clear(); + } + + return this; + }, + + /** + * {@inheritDoc} + */ + clear: function () { + this.value([]); + + return this; + }, + + /** + * Gets the ID of the file used if set + * + * @return {String|Null} ID + */ + getFileId: function () { + return this.hasData() ? this.value()[0].id : null; + }, + /** * Trigger native browser file upload UI via clicking on 'Upload' button * diff --git a/app/code/Magento/Ui/view/base/web/js/grid/columns/actions.js b/app/code/Magento/Ui/view/base/web/js/grid/columns/actions.js index a4c56958911a8..be7a1a13fbd61 100644 --- a/app/code/Magento/Ui/view/base/web/js/grid/columns/actions.js +++ b/app/code/Magento/Ui/view/base/web/js/grid/columns/actions.js @@ -78,8 +78,8 @@ define([ }, /** - * Adds new action. If action with a specfied identifier - * already exists, than the original will be overrided. + * Adds new action. If an action with the specified identifier + * already exists, then the original will be overridden. * * @param {String} index - Actions' identifier. * @param {Object} action - Actions' data. @@ -108,7 +108,7 @@ define([ /** * Processes actions, setting additional information to them and - * evaluating ther properties as a string templates. + * evaluating their properties as string templates. * * @private * @param {Object} row - Row object. @@ -204,11 +204,11 @@ define([ }, /** - * Creates action callback based on its' data. If action doesn't spicify + * Creates action callback based on it's data. If the action doesn't specify * a callback function than the default one will be used. * * @private - * @param {Object} action - Actions' object. + * @param {Object} action - Action's object. * @returns {Function} Callback function. */ _getCallback: function (action) { @@ -234,7 +234,7 @@ define([ * Creates action callback for multiple actions. * * @private - * @param {Object} action - Actions' object. + * @param {Object} action - Action's object. * @returns {Function} Callback function. */ _getCallbacks: function (action) { @@ -259,12 +259,12 @@ define([ /** * Default action callback. Redirects to - * the specified in actions' data url. + * the specified in action's data url. * - * @param {String} actionIndex - Actions' identifier. - * @param {(Number|String)} recordId - Id of the record accociated - * with a specfied action. - * @param {Object} action - Actions' data. + * @param {String} actionIndex - Action's identifier. + * @param {(Number|String)} recordId - Id of the record associated + * with a specified action. + * @param {Object} action - Action's data. */ defaultCallback: function (actionIndex, recordId, action) { window.location.href = action.href; @@ -273,7 +273,7 @@ define([ /** * Shows actions' confirmation window. * - * @param {Object} action - Actions' data. + * @param {Object} action - Action's data. * @param {Function} callback - Callback that will be * invoked if action is confirmed. */ diff --git a/app/code/Magento/Ui/view/base/web/js/grid/columns/multiselect.js b/app/code/Magento/Ui/view/base/web/js/grid/columns/multiselect.js index 0a29728390592..ba0f4d25c25a4 100644 --- a/app/code/Magento/Ui/view/base/web/js/grid/columns/multiselect.js +++ b/app/code/Magento/Ui/view/base/web/js/grid/columns/multiselect.js @@ -229,6 +229,15 @@ define([ return this; }, + /** + * Selects or deselects all records on the current page. + * + * @returns {Multiselect} Chainable. + */ + togglePage: function () { + return this.isPageSelected() ? this.deselectPage() : this.selectPage(); + }, + /** * Clears the array of not selected records. * @@ -259,7 +268,7 @@ define([ * Returns identifier of a record. * * @param {*} id - Id of a record or its' index in a rows array. - * @param {Boolean} [isIndex=false] - Flag that specifies whith what + * @param {Boolean} [isIndex=false] - Flag that specifies with what * kind of identifier we are dealing with. * @returns {*} */ diff --git a/app/code/Magento/Ui/view/base/web/js/grid/filters/filters.js b/app/code/Magento/Ui/view/base/web/js/grid/filters/filters.js index ecc4ec1902d87..98c3eb1c6f882 100644 --- a/app/code/Magento/Ui/view/base/web/js/grid/filters/filters.js +++ b/app/code/Magento/Ui/view/base/web/js/grid/filters/filters.js @@ -257,7 +257,7 @@ define([ /** * Creates filter component configuration associated with the provided column. * - * @param {Column} column - Column component whith a basic filter declaration. + * @param {Column} column - Column component with a basic filter declaration. * @returns {Object} Filters' configuration. */ buildFilter: function (column) { @@ -331,7 +331,7 @@ define([ }, /** - * Finds filters whith a not empty data + * Finds filters with a not empty data * and sets them to the 'active' filters array. * * @returns {Filters} Chainable. diff --git a/app/code/Magento/Ui/view/base/web/js/grid/massactions.js b/app/code/Magento/Ui/view/base/web/js/grid/massactions.js index 046ff12bfaa6f..48c04458ff49a 100644 --- a/app/code/Magento/Ui/view/base/web/js/grid/massactions.js +++ b/app/code/Magento/Ui/view/base/web/js/grid/massactions.js @@ -175,11 +175,14 @@ define([ * invoked if action is confirmed. */ _confirm: function (action, callback) { - var confirmData = action.confirm; + var confirmData = action.confirm, + data = this.getSelections(), + total = data.total ? data.total : 0, + confirmMessage = confirmData.message + ' (' + total + ' record' + (total > 1 ? 's' : '') + ')'; confirm({ title: confirmData.title, - content: confirmData.message, + content: confirmMessage, actions: { confirm: callback } diff --git a/app/code/Magento/Ui/view/base/web/js/lib/core/element/element.js b/app/code/Magento/Ui/view/base/web/js/lib/core/element/element.js index 1684f0b220175..b05fed939b7a5 100644 --- a/app/code/Magento/Ui/view/base/web/js/lib/core/element/element.js +++ b/app/code/Magento/Ui/view/base/web/js/lib/core/element/element.js @@ -66,7 +66,7 @@ define([ Element = _.extend({ defaults: { - _requesetd: {}, + _requested: {}, containers: [], exports: {}, imports: {}, @@ -249,7 +249,7 @@ define([ * @returns {Function} Async module wrapper. */ requestModule: function (name) { - var requested = this._requesetd; + var requested = this._requested; if (!requested[name]) { requested[name] = registry.async(name); diff --git a/app/code/Magento/Ui/view/base/web/js/lib/registry/registry.js b/app/code/Magento/Ui/view/base/web/js/lib/registry/registry.js index 5c3c71e31823d..826e8ec8c33b4 100644 --- a/app/code/Magento/Ui/view/base/web/js/lib/registry/registry.js +++ b/app/code/Magento/Ui/view/base/web/js/lib/registry/registry.js @@ -17,7 +17,7 @@ define([ var privateData = new WeakMap(); /** - * Extarcts private items storage associated + * Extracts private item storage associated * with a provided registry instance. * * @param {Object} container @@ -39,7 +39,7 @@ define([ } /** - * Wrapper function used for convinient access to the elements. + * Wrapper function used for convenient access to the elements. * See 'async' method for examples of usage and comparison * with a regular 'get' method. * @@ -139,7 +139,7 @@ define([ * which matches specified search criteria. * * @param {Object} data - Data object where to perform a lookup. - * @param {(String|Object|Function)} query - Seach criteria. + * @param {(String|Object|Function)} query - Search criteria. * @param {Boolean} findAll - Flag that defines whether to * search for all applicable items or to stop on a first found entry. * @returns {Array|Object|*} @@ -322,8 +322,8 @@ define([ /** * Creates a wrapper function over the provided search query - * in order to provide somehow more convinient access to the - * registrie's items. + * in order to provide somehow more convenient access to the + * registry's items. * * @param {(String|Object|Function)} query - Search criteria. * See 'get' method for the syntax examples. diff --git a/app/code/Magento/Ui/view/base/web/js/lib/validation/rules.js b/app/code/Magento/Ui/view/base/web/js/lib/validation/rules.js index c63b4588d2d16..e52791deaf2ad 100644 --- a/app/code/Magento/Ui/view/base/web/js/lib/validation/rules.js +++ b/app/code/Magento/Ui/view/base/web/js/lib/validation/rules.js @@ -636,7 +636,7 @@ define([ 'validate-number': [ function (value) { return utils.isEmptyNoTrim(value) || - !isNaN(utils.parseNumber(value)) && /^\s*-?\d*(\.\d*)?\s*$/.test(value); + !isNaN(utils.parseNumber(value)) && /^\s*-?\d*(,\d*)*(\.\d*)?\s*$/.test(value); }, $.mage.__('Please enter a valid number in this field.') ], diff --git a/app/code/Magento/Ui/view/base/web/js/modal/confirm.js b/app/code/Magento/Ui/view/base/web/js/modal/confirm.js index 9cb14f7b2ef11..eceab940d1141 100644 --- a/app/code/Magento/Ui/view/base/web/js/modal/confirm.js +++ b/app/code/Magento/Ui/view/base/web/js/modal/confirm.js @@ -9,10 +9,10 @@ define([ 'jquery', 'underscore', + 'mage/translate', 'jquery/ui', - 'Magento_Ui/js/modal/modal', - 'mage/translate' -], function ($, _) { + 'Magento_Ui/js/modal/modal' +], function ($, _, $t) { 'use strict'; $.widget('mage.confirm', $.mage.modal, { @@ -38,7 +38,7 @@ define([ cancel: function () {} }, buttons: [{ - text: $.mage.__('Cancel'), + text: $t('Cancel'), class: 'action-secondary action-dismiss', /** @@ -48,7 +48,7 @@ define([ this.closeModal(event); } }, { - text: $.mage.__('OK'), + text: $t('OK'), class: 'action-primary action-accept', /** diff --git a/app/code/Magento/Ui/view/base/web/js/modal/modal.js b/app/code/Magento/Ui/view/base/web/js/modal/modal.js index 147a18c08c54c..f016b0dbefd87 100644 --- a/app/code/Magento/Ui/view/base/web/js/modal/modal.js +++ b/app/code/Magento/Ui/view/base/web/js/modal/modal.js @@ -340,6 +340,12 @@ define([ var zIndex = this.modal.zIndex(), baseIndex = zIndex + this._getVisibleCount(); + if (this.modal.data('active')) { + return; + } + + this.modal.data('active', true); + this.overlay.zIndex(++baseIndex); this.prevOverlayIndex = this.overlay.zIndex(); this.modal.zIndex(this.overlay.zIndex() + 1); @@ -354,6 +360,7 @@ define([ */ _unsetActive: function () { this.modal.removeAttr('style'); + this.modal.data('active', false); if (this.overlay) { // In cases when one modal is closed but there is another modal open (e.g. admin notifications) diff --git a/app/code/Magento/Ui/view/base/web/templates/form/components/collection/preview.html b/app/code/Magento/Ui/view/base/web/templates/form/components/collection/preview.html index 2c0ce802b4bc0..806ac767d7b59 100644 --- a/app/code/Magento/Ui/view/base/web/templates/form/components/collection/preview.html +++ b/app/code/Magento/Ui/view/base/web/templates/form/components/collection/preview.html @@ -11,7 +11,7 @@ 'company', 'street', { - items: 'city region_id postcode', + items: 'city region_id region_id_input postcode', separator: ', ' }, 'country_id', diff --git a/app/code/Magento/Ui/view/base/web/templates/form/element/helper/service.html b/app/code/Magento/Ui/view/base/web/templates/form/element/helper/service.html index e3c3ab5b5df5c..46f0a2df52441 100644 --- a/app/code/Magento/Ui/view/base/web/templates/form/element/helper/service.html +++ b/app/code/Magento/Ui/view/base/web/templates/form/element/helper/service.html @@ -12,6 +12,7 @@ name: 'use_default[' + $data.index + ']', 'data-form-part': $data.ns " - ko-checked="isUseDefault"> + ko-checked="isUseDefault" + ko-disabled="$data.serviceDisabled"> <label translate="'Use Default Value'" attr="for: $data.uid + '_default'" class="admin__field-label"></label> </div> diff --git a/app/code/Magento/Ui/view/base/web/templates/form/field.html b/app/code/Magento/Ui/view/base/web/templates/form/field.html index 888bc911d747f..24ed194d666ee 100644 --- a/app/code/Magento/Ui/view/base/web/templates/form/field.html +++ b/app/code/Magento/Ui/view/base/web/templates/form/field.html @@ -8,9 +8,9 @@ visible="visible" css="$data.additionalClasses" attr="'data-index': index"> - <label class="admin__field-label" if="$data.label" visible="$data.labelVisible" attr="for: uid"> - <span translate="label" attr="'data-config-scope': $data.scopeLabel"/> - </label> + <span class="admin__field-label" if="$data.label" visible="$data.labelVisible"> + <label translate="label" attr="'data-config-scope': $data.scopeLabel, for: uid" /> + </span> <div class="admin__field-control" css="'_with-tooltip': $data.tooltip, '_with-reset': $data.showFallbackReset && $data.isDifferedFromDefault"> <render args="elementTmpl" ifnot="hasAddons()"/> diff --git a/app/code/Magento/Ui/view/base/web/templates/grid/columns/multiselect.html b/app/code/Magento/Ui/view/base/web/templates/grid/columns/multiselect.html index 18dd49bd56ee3..e6e14d5aa335b 100644 --- a/app/code/Magento/Ui/view/base/web/templates/grid/columns/multiselect.html +++ b/app/code/Magento/Ui/view/base/web/templates/grid/columns/multiselect.html @@ -11,7 +11,7 @@ data-bind=" checked: allSelected(), attr: {id: ++ko.uid}, - event: { change: toggleSelectAll }, + event: { change: togglePage }, css: { '_indeterminate': indetermine }, enable: totalRecords"> <label attr="for: ko.uid"/> diff --git a/app/code/Magento/Ups/Test/Mftf/composer.json b/app/code/Magento/Ups/Test/Mftf/composer.json deleted file mode 100644 index 560eaab1a19b1..0000000000000 --- a/app/code/Magento/Ups/Test/Mftf/composer.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "name": "magento/functional-test-module-ups", - "description": "N/A", - "config": { - "sort-packages": true - }, - "require": { - "php": "~7.1.3||~7.2.0", - "magento/magento2-functional-testing-framework": "2.2.0", - "magento/functional-test-module-backend": "100.0.0-dev", - "magento/functional-test-module-catalog-inventory": "100.0.0-dev", - "magento/functional-test-module-directory": "100.0.0-dev", - "magento/functional-test-module-quote": "100.0.0-dev", - "magento/functional-test-module-sales": "100.0.0-dev", - "magento/functional-test-module-shipping": "100.0.0-dev", - "magento/functional-test-module-store": "100.0.0-dev" - }, - "suggest": { - "magento/functional-test-module-config": "100.0.0-dev" - }, - "type": "magento2-test", - "license": [ - "OSL-3.0", - "AFL-3.0" - ] -} diff --git a/app/code/Magento/UrlRewrite/Block/Edit.php b/app/code/Magento/UrlRewrite/Block/Edit.php index baee8af893083..115c5db43a70a 100644 --- a/app/code/Magento/UrlRewrite/Block/Edit.php +++ b/app/code/Magento/UrlRewrite/Block/Edit.php @@ -65,7 +65,7 @@ public function __construct( */ protected function _prepareLayout() { - $this->setTemplate('edit.phtml'); + $this->setTemplate('Magento_UrlRewrite::edit.phtml'); $this->_addBackButton(); $this->_prepareLayoutFeatures(); @@ -243,7 +243,7 @@ private function _getSelectorBlock() * Since buttons are set as children, we remove them as children after generating them * not to duplicate them in future * - * @param null $area + * @param string $area * @return string * @SuppressWarnings(PHPMD.UnusedFormalParameter) */ diff --git a/app/code/Magento/UrlRewrite/Block/Plugin/Store/Switcher/SetRedirectUrl.php b/app/code/Magento/UrlRewrite/Block/Plugin/Store/Switcher/SetRedirectUrl.php deleted file mode 100644 index 9bdff38e7aaa2..0000000000000 --- a/app/code/Magento/UrlRewrite/Block/Plugin/Store/Switcher/SetRedirectUrl.php +++ /dev/null @@ -1,89 +0,0 @@ -<?php -/** - * Copyright © Magento, Inc. All rights reserved. - * See COPYING.txt for license details. - */ -namespace Magento\UrlRewrite\Block\Plugin\Store\Switcher; - -use Magento\Framework\Url\Helper\Data as UrlHelper; -use Magento\Framework\UrlInterface; -use Magento\UrlRewrite\Model\UrlFinderInterface; -use Magento\UrlRewrite\Service\V1\Data\UrlRewrite; -use Magento\Framework\App\RequestInterface; -use Magento\Framework\App\ActionInterface; - -class SetRedirectUrl -{ - /** - * @var \Magento\Framework\Url\Helper\Data - */ - private $urlHelper; - - /** - * @var \Magento\Framework\UrlInterface - */ - private $urlBuilder; - - /** - * @var \Magento\UrlRewrite\Model\UrlFinderInterface - */ - private $urlFinder; - - /** - * @var \Magento\Framework\App\RequestInterface - */ - private $request; - - /** - * @param UrlHelper $urlHelper - * @param UrlInterface $urlBuilder - * @param UrlFinderInterface $urlFinder - * @param RequestInterface $request - */ - public function __construct( - UrlHelper $urlHelper, - UrlInterface $urlBuilder, - UrlFinderInterface $urlFinder, - RequestInterface $request - ) { - $this->urlHelper = $urlHelper; - $this->urlBuilder = $urlBuilder; - $this->urlFinder = $urlFinder; - $this->request = $request; - } - - /** - * Set redirect url for store view based on request path info - * - * @param \Magento\Store\Block\Switcher $switcher - * @param \Magento\Store\Model\Store $store - * @param array $data - * @return array - * @SuppressWarnings(PHPMD.UnusedFormalParameter) - */ - public function beforeGetTargetStorePostData( - \Magento\Store\Block\Switcher $switcher, - \Magento\Store\Model\Store $store, - $data = [] - ) { - $urlRewrite = $this->urlFinder->findOneByData([ - UrlRewrite::TARGET_PATH => $this->trimSlashInPath($this->request->getPathInfo()), - UrlRewrite::STORE_ID => $store->getId(), - ]); - if ($urlRewrite) { - $data[ActionInterface::PARAM_NAME_URL_ENCODED] = $this->urlHelper->getEncodedUrl( - $this->trimSlashInPath($this->urlBuilder->getUrl($urlRewrite->getRequestPath(), ['_scope' => $store])) - ); - } - return [$store, $data]; - } - - /** - * @param string $path - * @return string - */ - private function trimSlashInPath($path) - { - return trim($path, '/'); - } -} diff --git a/app/code/Magento/UrlRewrite/Controller/Router.php b/app/code/Magento/UrlRewrite/Controller/Router.php index 73002c10cf1b6..ce432f24365a6 100644 --- a/app/code/Magento/UrlRewrite/Controller/Router.php +++ b/app/code/Magento/UrlRewrite/Controller/Router.php @@ -7,7 +7,6 @@ use Magento\Framework\App\RequestInterface; use Magento\UrlRewrite\Controller\Adminhtml\Url\Rewrite; -use Magento\UrlRewrite\Model\OptionProvider; use Magento\UrlRewrite\Model\UrlFinderInterface; use Magento\UrlRewrite\Service\V1\Data\UrlRewrite; use Magento\Framework\App\Request\Http as HttpRequest; @@ -78,44 +77,6 @@ public function __construct( */ public function match(RequestInterface $request) { - if ($fromStore = $request->getParam('___from_store')) { - //If we're in the process of switching stores then matching rewrite - //rule from previous store because the URL was not changed yet from - //old store's format. - $oldStoreId = $this->storeManager->getStore($fromStore)->getId(); - $oldRewrite = $this->getRewrite( - $request->getPathInfo(), - $oldStoreId - ); - if ($oldRewrite && $oldRewrite->getRedirectType() === 0) { - //If there is a match and it's a correct URL then just - //redirecting to current store's URL equivalent, - //otherwise just continuing finding a rule within current store. - $currentRewrite = $this->urlFinder->findOneByData( - [ - UrlRewrite::ENTITY_TYPE => $oldRewrite->getEntityType(), - UrlRewrite::ENTITY_ID => $oldRewrite->getEntityId(), - UrlRewrite::STORE_ID => - $this->storeManager->getStore()->getId(), - UrlRewrite::REDIRECT_TYPE => 0, - ] - ); - if ($currentRewrite - && $currentRewrite->getRequestPath() - !== $oldRewrite->getRequestPath() - ) { - return $this->redirect( - $request, - $this->url->getUrl( - '', - ['_direct' => $currentRewrite->getRequestPath()] - ), - OptionProvider::TEMPORARY - ); - } - } - } - $rewrite = $this->getRewrite( $request->getPathInfo(), $this->storeManager->getStore()->getId() diff --git a/app/code/Magento/UrlRewrite/Model/StoreSwitcher/RewriteUrl.php b/app/code/Magento/UrlRewrite/Model/StoreSwitcher/RewriteUrl.php new file mode 100644 index 0000000000000..2ce00d53588b3 --- /dev/null +++ b/app/code/Magento/UrlRewrite/Model/StoreSwitcher/RewriteUrl.php @@ -0,0 +1,82 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +declare(strict_types=1); + +namespace Magento\UrlRewrite\Model\StoreSwitcher; + +use Magento\Store\Api\Data\StoreInterface; +use Magento\Store\Model\StoreSwitcherInterface; +use Magento\UrlRewrite\Model\UrlFinderInterface; +use Magento\UrlRewrite\Service\V1\Data\UrlRewrite; + +/** + * Handle url rewrites for redirect url + */ +class RewriteUrl implements StoreSwitcherInterface +{ + /** + * @var UrlFinderInterface + */ + private $urlFinder; + + /** + * @var \Magento\Framework\HTTP\PhpEnvironment\RequestFactory + */ + private $requestFactory; + + /** + * @param UrlFinderInterface $urlFinder + * @param \Magento\Framework\HTTP\PhpEnvironment\RequestFactory $requestFactory + */ + public function __construct( + UrlFinderInterface $urlFinder, + \Magento\Framework\HTTP\PhpEnvironment\RequestFactory $requestFactory + ) { + $this->urlFinder = $urlFinder; + $this->requestFactory = $requestFactory; + } + + /** + * @param StoreInterface $fromStore + * @param StoreInterface $targetStore + * @param string $redirectUrl + * @return string + */ + public function switch(StoreInterface $fromStore, StoreInterface $targetStore, string $redirectUrl): string + { + $targetUrl = $redirectUrl; + /** @var \Magento\Framework\HTTP\PhpEnvironment\Request $request */ + $request = $this->requestFactory->create(['uri' => $targetUrl]); + + $urlPath = ltrim($request->getPathInfo(), '/'); + + if ($targetStore->isUseStoreInUrl()) { + // Remove store code in redirect url for correct rewrite search + $storeCode = preg_quote($targetStore->getCode() . '/', '/'); + $pattern = "@^($storeCode)@"; + $urlPath = preg_replace($pattern, '', $urlPath); + } + + $oldStoreId = $fromStore->getId(); + $oldRewrite = $this->urlFinder->findOneByData([ + UrlRewrite::REQUEST_PATH => $urlPath, + UrlRewrite::STORE_ID => $oldStoreId, + ]); + if ($oldRewrite) { + // look for url rewrite match on the target store + $currentRewrite = $this->urlFinder->findOneByData([ + UrlRewrite::REQUEST_PATH => $urlPath, + UrlRewrite::STORE_ID => $targetStore->getId(), + ]); + if (null === $currentRewrite) { + /** @var \Magento\Framework\App\Response\Http $response */ + $targetUrl = $targetStore->getBaseUrl(); + } + } + + return $targetUrl; + } +} diff --git a/app/code/Magento/UrlRewrite/Test/Mftf/composer.json b/app/code/Magento/UrlRewrite/Test/Mftf/composer.json deleted file mode 100644 index 2d906c3499ac6..0000000000000 --- a/app/code/Magento/UrlRewrite/Test/Mftf/composer.json +++ /dev/null @@ -1,22 +0,0 @@ -{ - "name": "magento/functional-test-module-url-rewrite", - "description": "N/A", - "config": { - "sort-packages": true - }, - "require": { - "php": "~7.1.3||~7.2.0", - "magento/magento2-functional-testing-framework": "2.2.0", - "magento/functional-test-module-backend": "100.0.0-dev", - "magento/functional-test-module-catalog": "100.0.0-dev", - "magento/functional-test-module-catalog-url-rewrite": "100.0.0-dev", - "magento/functional-test-module-cms": "100.0.0-dev", - "magento/functional-test-module-cms-url-rewrite": "100.0.0-dev", - "magento/functional-test-module-store": "100.0.0-dev" - }, - "type": "magento2-test", - "license": [ - "OSL-3.0", - "AFL-3.0" - ] -} diff --git a/app/code/Magento/UrlRewrite/Test/Unit/Block/Plugin/Store/Switcher/SetRedirectUrlTest.php b/app/code/Magento/UrlRewrite/Test/Unit/Block/Plugin/Store/Switcher/SetRedirectUrlTest.php deleted file mode 100644 index 46bf90493004d..0000000000000 --- a/app/code/Magento/UrlRewrite/Test/Unit/Block/Plugin/Store/Switcher/SetRedirectUrlTest.php +++ /dev/null @@ -1,96 +0,0 @@ -<?php -/** - * Copyright © Magento, Inc. All rights reserved. - * See COPYING.txt for license details. - */ - -namespace Magento\UrlRewrite\Test\Unit\Block\Plugin\Store\Switcher; - -use Magento\Framework\TestFramework\Unit\Helper\ObjectManager; - -class SetRedirectUrlTest extends \PHPUnit\Framework\TestCase -{ - /** @var \Magento\UrlRewrite\Block\Plugin\Store\Switcher\SetRedirectUrl */ - protected $unit; - - /** @var \PHPUnit_Framework_MockObject_MockObject */ - protected $urlFinder; - - /** @var \PHPUnit_Framework_MockObject_MockObject */ - protected $urlHelper; - - /** @var \Magento\Store\Block\Switcher|\PHPUnit_Framework_MockObject_MockObject */ - protected $switcher; - - /** @var \Magento\Store\Model\Store|\PHPUnit_Framework_MockObject_MockObject */ - protected $store; - - /** @var \PHPUnit_Framework_MockObject_MockObject */ - protected $request; - - /** @var \Magento\Framework\UrlInterface|\PHPUnit_Framework_MockObject_MockObject */ - protected $urlBuilder; - - protected function setUp() - { - $this->store = $this->createMock(\Magento\Store\Model\Store::class); - $this->request = $this->createMock(\Magento\Framework\App\Request\Http::class); - $this->urlBuilder = $this->createMock(\Magento\Framework\UrlInterface::class); - $this->urlHelper = $this->createMock(\Magento\Framework\Url\Helper\Data::class); - $this->urlFinder = $this->createMock(\Magento\UrlRewrite\Model\UrlFinderInterface::class); - $this->switcher = $this->createMock(\Magento\Store\Block\Switcher::class); - - $this->unit = (new ObjectManager($this))->getObject( - \Magento\UrlRewrite\Block\Plugin\Store\Switcher\SetRedirectUrl::class, - [ - 'urlFinder' => $this->urlFinder, - 'urlHelper' => $this->urlHelper, - 'urlBuilder' => $this->urlBuilder, - 'request' => $this->request, - ] - ); - } - - public function testNoUrlRewriteForSpecificStoreOnGetTargetStorePostData() - { - $this->request->expects($this->once())->method('getPathInfo')->willReturn('path'); - $this->urlFinder->expects($this->once())->method('findOneByData')->willReturn(null); - $this->urlHelper->expects($this->never())->method('getEncodedUrl'); - $this->assertEquals( - [$this->store, []], - $this->unit->beforeGetTargetStorePostData($this->switcher, $this->store, []) - ); - } - - public function testTrimPathInfoForGetTargetStorePostData() - { - $this->request->expects($this->once())->method('getPathInfo')->willReturn('path/with/trim/'); - $this->store->expects($this->once())->method('getId')->willReturn(1); - $this->urlFinder->expects($this->once())->method('findOneByData') - ->with([ - \Magento\UrlRewrite\Service\V1\Data\UrlRewrite::TARGET_PATH => 'path/with/trim', - \Magento\UrlRewrite\Service\V1\Data\UrlRewrite::STORE_ID => 1, - ]) - ->willReturn(null); - $this->urlHelper->expects($this->never())->method('getEncodedUrl'); - $this->assertEquals( - [$this->store, []], - $this->unit->beforeGetTargetStorePostData($this->switcher, $this->store, []) - ); - } - - public function testGetTargetStorePostData() - { - $urlRewrite = $this->createMock(\Magento\UrlRewrite\Service\V1\Data\UrlRewrite::class); - $urlRewrite->expects($this->once())->method('getRequestPath')->willReturn('path'); - - $this->request->expects($this->once())->method('getPathInfo')->willReturn('path'); - $this->urlFinder->expects($this->once())->method('findOneByData')->willReturn($urlRewrite); - $this->urlHelper->expects($this->once())->method('getEncodedUrl')->willReturn('encoded-path'); - $this->urlBuilder->expects($this->once())->method('getUrl')->willReturn('path'); - $this->assertEquals( - [$this->store, [\Magento\Framework\App\ActionInterface::PARAM_NAME_URL_ENCODED => 'encoded-path']], - $this->unit->beforeGetTargetStorePostData($this->switcher, $this->store, []) - ); - } -} diff --git a/app/code/Magento/UrlRewrite/Test/Unit/Controller/RouterTest.php b/app/code/Magento/UrlRewrite/Test/Unit/Controller/RouterTest.php index 49300448146f2..642ca0f9af6d1 100644 --- a/app/code/Magento/UrlRewrite/Test/Unit/Controller/RouterTest.php +++ b/app/code/Magento/UrlRewrite/Test/Unit/Controller/RouterTest.php @@ -6,9 +6,10 @@ namespace Magento\UrlRewrite\Test\Unit\Controller; +use Magento\Framework\App\Action\Forward; use Magento\Framework\TestFramework\Unit\Helper\ObjectManager; -use Magento\UrlRewrite\Model\OptionProvider; use Magento\UrlRewrite\Service\V1\Data\UrlRewrite; +use Magento\Store\Model\Store; /** * @SuppressWarnings(PHPMD.CouplingBetweenObjects) @@ -39,6 +40,9 @@ class RouterTest extends \PHPUnit\Framework\TestCase /** @var \Magento\UrlRewrite\Model\UrlFinderInterface|\PHPUnit_Framework_MockObject_MockObject */ protected $urlFinder; + /** + * @return void + */ protected function setUp() { $this->actionFactory = $this->createMock(\Magento\Framework\App\ActionFactory::class); @@ -67,6 +71,9 @@ protected function setUp() ); } + /** + * @return void + */ public function testNoRewriteExist() { $this->urlFinder->expects($this->any())->method('findOneByData')->will($this->returnValue(null)); @@ -76,6 +83,81 @@ public function testNoRewriteExist() $this->assertNull($this->router->match($this->request)); } + /** + * @return void + */ + public function testRewriteAfterStoreSwitcher() + { + $initialRequestPath = 'request-path'; + $newRequestPath = 'new-request-path'; + $oldStoreAlias = 'old-store'; + $oldStoreId = 'old-store-id'; + $currentStoreId = 'current-store-id'; + $rewriteEntityType = 'entity-type'; + $rewriteEntityId = 42; + $this->request + ->expects($this->any()) + ->method('getParam') + ->with('___from_store') + ->willReturn($oldStoreAlias); + $this->request + ->expects($this->any()) + ->method('getPathInfo') + ->willReturn($initialRequestPath); + $oldStore = $this->getMockBuilder(Store::class) + ->disableOriginalConstructor() + ->getMock(); + $oldStore->expects($this->any()) + ->method('getId') + ->willReturn($oldStoreId); + $this->store + ->expects($this->any()) + ->method('getId') + ->willReturn($currentStoreId); + $this->storeManager + ->expects($this->any()) + ->method('getStore') + ->willReturnMap([[$oldStoreAlias, $oldStore], [null, $this->store]]); + $oldUrlRewrite = $this->getMockBuilder(UrlRewrite::class) + ->disableOriginalConstructor() + ->getMock(); + $oldUrlRewrite->expects($this->any()) + ->method('getEntityType') + ->willReturn($rewriteEntityType); + $oldUrlRewrite->expects($this->any()) + ->method('getEntityId') + ->willReturn($rewriteEntityId); + $oldUrlRewrite->expects($this->any()) + ->method('getRedirectType') + ->willReturn(0); + $urlRewrite = $this->getMockBuilder(UrlRewrite::class) + ->disableOriginalConstructor() + ->getMock(); + $urlRewrite->expects($this->any()) + ->method('getRequestPath') + ->willReturn($newRequestPath); + $this->urlFinder + ->expects($this->any()) + ->method('findOneByData') + ->willReturnMap([ + [ + [ + UrlRewrite::REQUEST_PATH => $initialRequestPath, + UrlRewrite::STORE_ID => $currentStoreId, + ], + $urlRewrite, + ] + ]); + $this->actionFactory + ->expects($this->once()) + ->method('create') + ->with(Forward::class); + $this->router->match($this->request); + } + + /** + * @return void + */ public function testNoRewriteAfterStoreSwitcherWhenNoOldRewrite() { $this->request->expects($this->any())->method('getPathInfo')->will($this->returnValue('request-path')); @@ -98,6 +180,9 @@ public function testNoRewriteAfterStoreSwitcherWhenNoOldRewrite() $this->assertNull($this->router->match($this->request)); } + /** + * @return void + */ public function testNoRewriteAfterStoreSwitcherWhenOldRewriteEqualsToNewOne() { $this->request->expects($this->any())->method('getPathInfo')->will($this->returnValue('request-path')); @@ -138,6 +223,9 @@ public function testNoRewriteAfterStoreSwitcherWhenOldRewriteEqualsToNewOne() $this->assertNull($this->router->match($this->request)); } + /** + * @return void + */ public function testMatchWithRedirect() { $this->storeManager->expects($this->any())->method('getStore')->will($this->returnValue($this->store)); @@ -157,6 +245,9 @@ public function testMatchWithRedirect() $this->router->match($this->request); } + /** + * @return void + */ public function testMatchWithCustomInternalRedirect() { $this->storeManager->expects($this->any())->method('getStore')->will($this->returnValue($this->store)); @@ -208,6 +299,9 @@ public function externalRedirectTargetPathDataProvider() ]; } + /** + * @return void + */ public function testMatch() { $this->storeManager->expects($this->any())->method('getStore')->will($this->returnValue($this->store)); diff --git a/app/code/Magento/UrlRewrite/etc/di.xml b/app/code/Magento/UrlRewrite/etc/di.xml index dfeb5d026d508..26055efbd2ba8 100644 --- a/app/code/Magento/UrlRewrite/etc/di.xml +++ b/app/code/Magento/UrlRewrite/etc/di.xml @@ -9,4 +9,11 @@ <preference for="Magento\UrlRewrite\Model\StorageInterface" type="Magento\UrlRewrite\Model\Storage\DbStorage"/> <preference for="Magento\UrlRewrite\Model\UrlFinderInterface" type="Magento\UrlRewrite\Model\Storage\DbStorage"/> <preference for="Magento\UrlRewrite\Model\UrlPersistInterface" type="Magento\UrlRewrite\Model\Storage\DbStorage"/> + <type name="Magento\Store\Model\StoreSwitcher"> + <arguments> + <argument name="storeSwitchers" xsi:type="array"> + <item name="rewriteUrl" xsi:type="object">Magento\UrlRewrite\Model\StoreSwitcher\RewriteUrl</item> + </argument> + </arguments> + </type> </config> diff --git a/app/code/Magento/UrlRewrite/etc/frontend/di.xml b/app/code/Magento/UrlRewrite/etc/frontend/di.xml index d46bb1c5d14a2..bc5b6aa767fa8 100644 --- a/app/code/Magento/UrlRewrite/etc/frontend/di.xml +++ b/app/code/Magento/UrlRewrite/etc/frontend/di.xml @@ -17,7 +17,4 @@ </argument> </arguments> </type> - <type name="Magento\Store\Block\Switcher"> - <plugin name="setStoreSpecificRedirectUrl" type="Magento\UrlRewrite\Block\Plugin\Store\Switcher\SetRedirectUrl"/> - </type> </config> diff --git a/app/code/Magento/UrlRewriteGraphQl/Test/Mftf/composer.json b/app/code/Magento/UrlRewriteGraphQl/Test/Mftf/composer.json deleted file mode 100644 index 06c58dbb59468..0000000000000 --- a/app/code/Magento/UrlRewriteGraphQl/Test/Mftf/composer.json +++ /dev/null @@ -1,21 +0,0 @@ -{ - "name": "magento/functional-test-module-url-rewrite-graph-ql", - "description": "N/A", - "config": { - "sort-packages": true - }, - "require": { - "php": "~7.1.3||~7.2.0", - "magento/magento2-functional-testing-framework": "2.2.0", - "magento/functional-test-module-url-rewrite": "100.0.0-dev", - "magento/functional-test-module-store": "100.0.0-dev" - }, - "suggest": { - "magento/functional-test-module-graph-ql": "100.0.0-dev" - }, - "type": "magento2-test", - "license": [ - "OSL-3.0", - "AFL-3.0" - ] -} diff --git a/app/code/Magento/User/Block/Role/Tab/Users.php b/app/code/Magento/User/Block/Role/Tab/Users.php index 27604c9aed29a..a95a68cbe14f3 100644 --- a/app/code/Magento/User/Block/Role/Tab/Users.php +++ b/app/code/Magento/User/Block/Role/Tab/Users.php @@ -45,7 +45,9 @@ protected function _construct() $roleId = $this->getRequest()->getParam('rid', false); /** @var \Magento\User\Model\ResourceModel\User\Collection $users */ $users = $this->_userCollectionFactory->create()->load(); - $this->setTemplate('role/users.phtml')->assign('users', $users->getItems())->assign('roleId', $roleId); + $this->setTemplate('Magento_User::role/users.phtml') + ->assign('users', $users->getItems()) + ->assign('roleId', $roleId); } /** diff --git a/app/code/Magento/User/Controller/Adminhtml/Auth.php b/app/code/Magento/User/Controller/Adminhtml/Auth.php index 173fdcc764f6f..ea539b64a5cc3 100644 --- a/app/code/Magento/User/Controller/Adminhtml/Auth.php +++ b/app/code/Magento/User/Controller/Adminhtml/Auth.php @@ -7,28 +7,32 @@ namespace Magento\User\Controller\Adminhtml; use Magento\Framework\Encryption\Helper\Security; +use Magento\Backend\App\AbstractAction; +use Magento\Backend\App\Action\Context; +use Magento\User\Model\UserFactory; +use Magento\Framework\Exception\LocalizedException; /** * \Magento\User Auth controller */ -abstract class Auth extends \Magento\Backend\App\AbstractAction +abstract class Auth extends AbstractAction { /** * User model factory * - * @var \Magento\User\Model\UserFactory + * @var UserFactory */ protected $_userFactory; /** * Construct * - * @param \Magento\Backend\App\Action\Context $context - * @param \Magento\User\Model\UserFactory $userFactory + * @param Context $context + * @param UserFactory $userFactory */ public function __construct( - \Magento\Backend\App\Action\Context $context, - \Magento\User\Model\UserFactory $userFactory + Context $context, + UserFactory $userFactory ) { parent::__construct($context); $this->_userFactory = $userFactory; @@ -40,7 +44,7 @@ public function __construct( * @param int $userId * @param string $resetPasswordToken * @return void - * @throws \Magento\Framework\Exception\LocalizedException + * @throws LocalizedException */ protected function _validateResetPasswordLinkToken($userId, $resetPasswordToken) { @@ -50,22 +54,20 @@ protected function _validateResetPasswordLinkToken($userId, $resetPasswordToken) $resetPasswordToken ) || empty($resetPasswordToken) || empty($userId) || $userId < 0 ) { - throw new \Magento\Framework\Exception\LocalizedException( - __('The password reset token is incorrect. Verify the token and try again.') - ); + throw new LocalizedException(__('Please correct the password reset token.')); } /** @var $user \Magento\User\Model\User */ $user = $this->_userFactory->create()->load($userId); if (!$user->getId()) { - throw new \Magento\Framework\Exception\LocalizedException( + throw new LocalizedException( __('Please specify the correct account and try again.') ); } $userToken = $user->getRpToken(); if (!Security::compareStrings($userToken, $resetPasswordToken) || $user->isResetPasswordLinkTokenExpired()) { - throw new \Magento\Framework\Exception\LocalizedException(__('Your password reset link has expired.')); + throw new LocalizedException(__('Your password reset link has expired.')); } } diff --git a/app/code/Magento/User/Controller/Adminhtml/Auth/Forgotpassword.php b/app/code/Magento/User/Controller/Adminhtml/Auth/Forgotpassword.php index cd4c3d6950685..c0e78fae2c2c6 100644 --- a/app/code/Magento/User/Controller/Adminhtml/Auth/Forgotpassword.php +++ b/app/code/Magento/User/Controller/Adminhtml/Auth/Forgotpassword.php @@ -7,8 +7,17 @@ namespace Magento\User\Controller\Adminhtml\Auth; use Magento\Security\Model\SecurityManager; +use Magento\Framework\App\ObjectManager; +use Magento\Backend\App\Action\Context; +use Magento\User\Model\UserFactory; +use Magento\User\Model\ResourceModel\User\CollectionFactory; +use Magento\Framework\Validator\EmailAddress; +use Magento\Security\Model\PasswordResetRequestEvent; +use Magento\Framework\Exception\SecurityViolationException; +use Magento\User\Controller\Adminhtml\Auth; +use Magento\Backend\Helper\Data; -class Forgotpassword extends \Magento\User\Controller\Adminhtml\Auth +class Forgotpassword extends Auth { /** * @var SecurityManager @@ -16,17 +25,36 @@ class Forgotpassword extends \Magento\User\Controller\Adminhtml\Auth protected $securityManager; /** - * @param \Magento\Backend\App\Action\Context $context - * @param \Magento\User\Model\UserFactory $userFactory - * @param \Magento\Security\Model\SecurityManager $securityManager + * User model factory + * + * @var CollectionFactory + */ + private $userCollectionFactory; + + /** + * @var Data + */ + private $backendDataHelper; + + /** + * @param Context $context + * @param UserFactory $userFactory + * @param SecurityManager $securityManager + * @param CollectionFactory $userCollectionFactory */ public function __construct( - \Magento\Backend\App\Action\Context $context, - \Magento\User\Model\UserFactory $userFactory, - \Magento\Security\Model\SecurityManager $securityManager + Context $context, + UserFactory $userFactory, + SecurityManager $securityManager, + CollectionFactory $userCollectionFactory = null, + Data $backendDataHelper = null ) { parent::__construct($context, $userFactory); $this->securityManager = $securityManager; + $this->userCollectionFactory = $userCollectionFactory ?: + ObjectManager::getInstance()->get(CollectionFactory::class); + $this->backendDataHelper = $backendDataHelper ?: + ObjectManager::getInstance()->get(Data::class); } /** @@ -44,18 +72,18 @@ public function execute() $resultRedirect = $this->resultRedirectFactory->create(); if (!empty($email) && !empty($params)) { // Validate received data to be an email address - if (\Zend_Validate::is($email, \Magento\Framework\Validator\EmailAddress::class)) { + if (\Zend_Validate::is($email, EmailAddress::class)) { try { $this->securityManager->performSecurityCheck( - \Magento\Security\Model\PasswordResetRequestEvent::ADMIN_PASSWORD_RESET_REQUEST, + PasswordResetRequestEvent::ADMIN_PASSWORD_RESET_REQUEST, $email ); - } catch (\Magento\Framework\Exception\SecurityViolationException $exception) { + } catch (SecurityViolationException $exception) { $this->messageManager->addErrorMessage($exception->getMessage()); return $resultRedirect->setPath('admin'); } - $collection = $this->_objectManager->get(\Magento\User\Model\ResourceModel\User\Collection::class); /** @var $collection \Magento\User\Model\ResourceModel\User\Collection */ + $collection = $this->userCollectionFactory->create(); $collection->addFieldToFilter('email', $email); $collection->load(false); @@ -65,9 +93,7 @@ public function execute() /** @var \Magento\User\Model\User $user */ $user = $this->_userFactory->create()->load($item->getId()); if ($user->getId()) { - $newPassResetToken = $this->_objectManager->get( - \Magento\User\Helper\Data::class - )->generateResetPasswordLinkToken(); + $newPassResetToken = $this->backendDataHelper->generateResetPasswordLinkToken(); $user->changeResetPasswordLinkToken($newPassResetToken); $user->save(); $user->sendPasswordResetConfirmationEmail(); @@ -86,7 +112,7 @@ public function execute() $this->messageManager->addSuccess(__('We\'ll email you a link to reset your password.')); // @codingStandardsIgnoreEnd $this->getResponse()->setRedirect( - $this->_objectManager->get(\Magento\Backend\Helper\Data::class)->getHomePageUrl() + $this->backendDataHelper->getHomePageUrl() ); return; } else { diff --git a/app/code/Magento/User/Controller/Adminhtml/Auth/ResetPasswordPost.php b/app/code/Magento/User/Controller/Adminhtml/Auth/ResetPasswordPost.php index 2c6be98439919..c2e29534b1251 100644 --- a/app/code/Magento/User/Controller/Adminhtml/Auth/ResetPasswordPost.php +++ b/app/code/Magento/User/Controller/Adminhtml/Auth/ResetPasswordPost.php @@ -6,8 +6,32 @@ */ namespace Magento\User\Controller\Adminhtml\Auth; -class ResetPasswordPost extends \Magento\User\Controller\Adminhtml\Auth +use Magento\User\Controller\Adminhtml\Auth; +use Magento\Backend\App\Action\Context; +use Magento\Framework\App\ObjectManager; +use Magento\Backend\Helper\Data; +use Magento\User\Model\UserFactory; + +class ResetPasswordPost extends Auth { + /** + * @var Data + */ + private $backendDataHelper; + + /** + * @param Context $context + * @param UserFactory $userFactory + * @param Data $backendDataHelper + */ + public function __construct( + Context $context, + UserFactory $userFactory, + Data $backendDataHelper = null + ) { + parent::__construct($context, $userFactory); + $this->backendDataHelper = $backendDataHelper ?: ObjectManager::getInstance()->get(Data::class); + } /** * Reset forgotten password * @@ -27,7 +51,7 @@ public function execute() } catch (\Exception $exception) { $this->messageManager->addError(__('Your password reset link has expired.')); $this->getResponse()->setRedirect( - $this->_objectManager->get(\Magento\Backend\Helper\Data::class)->getHomePageUrl() + $this->backendDataHelper->getHomePageUrl() ); return; } @@ -53,7 +77,7 @@ public function execute() $user->save(); $this->messageManager->addSuccess(__('You updated your password.')); $this->getResponse()->setRedirect( - $this->_objectManager->get(\Magento\Backend\Helper\Data::class)->getHomePageUrl() + $this->backendDataHelper->getHomePageUrl() ); } } catch (\Magento\Framework\Validator\Exception $exception) { diff --git a/app/code/Magento/User/Test/Mftf/composer.json b/app/code/Magento/User/Test/Mftf/composer.json deleted file mode 100644 index 6deceeb6b856f..0000000000000 --- a/app/code/Magento/User/Test/Mftf/composer.json +++ /dev/null @@ -1,22 +0,0 @@ -{ - "name": "magento/functional-test-module-user", - "description": "N/A", - "config": { - "sort-packages": true - }, - "require": { - "php": "~7.1.3||~7.2.0", - "magento/magento2-functional-testing-framework": "2.2.0", - "magento/functional-test-module-authorization": "100.0.0-dev", - "magento/functional-test-module-backend": "100.0.0-dev", - "magento/functional-test-module-email": "100.0.0-dev", - "magento/functional-test-module-integration": "100.0.0-dev", - "magento/functional-test-module-security": "100.0.0-dev", - "magento/functional-test-module-store": "100.0.0-dev" - }, - "type": "magento2-test", - "license": [ - "OSL-3.0", - "AFL-3.0" - ] -} diff --git a/app/code/Magento/Usps/Test/Mftf/composer.json b/app/code/Magento/Usps/Test/Mftf/composer.json deleted file mode 100644 index e3b487ad80d9f..0000000000000 --- a/app/code/Magento/Usps/Test/Mftf/composer.json +++ /dev/null @@ -1,24 +0,0 @@ -{ - "name": "magento/functional-test-module-usps", - "description": "N/A", - "config": { - "sort-packages": true - }, - "require": { - "php": "~7.1.3||~7.2.0", - "magento/magento2-functional-testing-framework": "2.2.0", - "magento/functional-test-module-catalog": "100.0.0-dev", - "magento/functional-test-module-catalog-inventory": "100.0.0-dev", - "magento/functional-test-module-config": "100.0.0-dev", - "magento/functional-test-module-directory": "100.0.0-dev", - "magento/functional-test-module-quote": "100.0.0-dev", - "magento/functional-test-module-sales": "100.0.0-dev", - "magento/functional-test-module-shipping": "100.0.0-dev", - "magento/functional-test-module-store": "100.0.0-dev" - }, - "type": "magento2-test", - "license": [ - "OSL-3.0", - "AFL-3.0" - ] -} diff --git a/app/code/Magento/Variable/Test/Mftf/composer.json b/app/code/Magento/Variable/Test/Mftf/composer.json deleted file mode 100644 index 2360634369fed..0000000000000 --- a/app/code/Magento/Variable/Test/Mftf/composer.json +++ /dev/null @@ -1,19 +0,0 @@ -{ - "name": "magento/functional-test-module-variable", - "description": "N/A", - "config": { - "sort-packages": true - }, - "require": { - "php": "~7.1.3||~7.2.0", - "magento/magento2-functional-testing-framework": "2.2.0", - "magento/functional-test-module-backend": "100.0.0-dev", - "magento/functional-test-module-store": "100.0.0-dev", - "magento/functional-test-module-config": "100.0.0-dev" - }, - "type": "magento2-test", - "license": [ - "OSL-3.0", - "AFL-3.0" - ] -} diff --git a/app/code/Magento/Vault/Test/Mftf/composer.json b/app/code/Magento/Vault/Test/Mftf/composer.json deleted file mode 100644 index 78e765bebc429..0000000000000 --- a/app/code/Magento/Vault/Test/Mftf/composer.json +++ /dev/null @@ -1,21 +0,0 @@ -{ - "name": "magento/functional-test-module-vault", - "description": "", - "config": { - "sort-packages": true - }, - "require": { - "php": "~7.1.3||~7.2.0", - "magento/magento2-functional-testing-framework": "2.2.0", - "magento/functional-test-module-checkout": "100.0.0-dev", - "magento/functional-test-module-customer": "100.0.0-dev", - "magento/functional-test-module-payment": "100.0.0-dev", - "magento/functional-test-module-quote": "100.0.0-dev", - "magento/functional-test-module-sales": "100.0.0-dev", - "magento/functional-test-module-store": "100.0.0-dev" - }, - "type": "magento2-test", - "license": [ - "proprietary" - ] -} diff --git a/app/code/Magento/Vault/composer.json b/app/code/Magento/Vault/composer.json index a4093617b82cc..f888a98692288 100644 --- a/app/code/Magento/Vault/composer.json +++ b/app/code/Magento/Vault/composer.json @@ -16,7 +16,8 @@ }, "type": "magento2-module", "license": [ - "proprietary" + "OSL-3.0", + "AFL-3.0" ], "autoload": { "files": [ diff --git a/app/code/Magento/Version/Test/Mftf/composer.json b/app/code/Magento/Version/Test/Mftf/composer.json deleted file mode 100644 index 24037307b7878..0000000000000 --- a/app/code/Magento/Version/Test/Mftf/composer.json +++ /dev/null @@ -1,16 +0,0 @@ -{ - "name": "magento/functional-test-module-version", - "description": "N/A", - "config": { - "sort-packages": true - }, - "require": { - "php": "~7.1.3||~7.2.0", - "magento/magento2-functional-testing-framework": "2.2.0" - }, - "type": "magento2-test", - "license": [ - "OSL-3.0", - "AFL-3.0" - ] -} diff --git a/app/code/Magento/Webapi/Test/Mftf/composer.json b/app/code/Magento/Webapi/Test/Mftf/composer.json deleted file mode 100644 index 28d5769034a39..0000000000000 --- a/app/code/Magento/Webapi/Test/Mftf/composer.json +++ /dev/null @@ -1,24 +0,0 @@ -{ - "name": "magento/functional-test-module-webapi", - "description": "N/A", - "config": { - "sort-packages": true - }, - "require": { - "php": "~7.1.3||~7.2.0", - "magento/magento2-functional-testing-framework": "2.2.0", - "magento/functional-test-module-authorization": "100.0.0-dev", - "magento/functional-test-module-backend": "100.0.0-dev", - "magento/functional-test-module-integration": "100.0.0-dev", - "magento/functional-test-module-store": "100.0.0-dev" - }, - "suggest": { - "magento/functional-test-module-user": "100.0.0-dev", - "magento/functional-test-module-customer": "100.0.0-dev" - }, - "type": "magento2-test", - "license": [ - "OSL-3.0", - "AFL-3.0" - ] -} diff --git a/app/code/Magento/WebapiAsync/Test/Mftf/composer.json b/app/code/Magento/WebapiAsync/Test/Mftf/composer.json deleted file mode 100644 index 6bf5375b7c873..0000000000000 --- a/app/code/Magento/WebapiAsync/Test/Mftf/composer.json +++ /dev/null @@ -1,22 +0,0 @@ -{ - "name": "magento/functional-test-module-webapi-async", - "description": "N/A", - "config": { - "sort-packages": true - }, - "require": { - "php": "~7.1.3||~7.2.0", - "magento/magento2-functional-testing-framework": "2.2.0", - "magento/functional-test-module-webapi": "100.0.0-dev", - "magento/functional-test-module-asynchronous-operations": "100.0.0-dev" - }, - "suggest": { - "magento/functional-test-module-user": "100.0.0-dev", - "magento/functional-test-module-customer": "100.0.0-dev" - }, - "type": "magento2-test", - "license": [ - "OSL-3.0", - "AFL-3.0" - ] -} diff --git a/app/code/Magento/WebapiSecurity/Test/Mftf/composer.json b/app/code/Magento/WebapiSecurity/Test/Mftf/composer.json deleted file mode 100644 index de96b3a3210f0..0000000000000 --- a/app/code/Magento/WebapiSecurity/Test/Mftf/composer.json +++ /dev/null @@ -1,17 +0,0 @@ -{ - "name": "magento/functional-test-module-webapi-security", - "description": "WebapiSecurity module provides option to loosen security on some webapi resources.", - "config": { - "sort-packages": true - }, - "require": { - "php": "~7.1.3||~7.2.0", - "magento/magento2-functional-testing-framework": "2.2.0", - "magento/functional-test-module-webapi": "100.0.0-dev" - }, - "type": "magento2-test", - "license": [ - "OSL-3.0", - "AFL-3.0" - ] -} diff --git a/app/code/Magento/WebapiSecurity/etc/adminhtml/system.xml b/app/code/Magento/WebapiSecurity/etc/adminhtml/system.xml index 425a2047cfd51..c38ea402718e3 100644 --- a/app/code/Magento/WebapiSecurity/etc/adminhtml/system.xml +++ b/app/code/Magento/WebapiSecurity/etc/adminhtml/system.xml @@ -5,10 +5,10 @@ --> <config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:module:Magento_Config:etc/system_file.xsd"> <system> - <section id="webapi" translate="label" type="text" sortOrder="102" showInDefault="1" showInWebsite="1" showInStore="1"> + <section id="webapi" type="text" sortOrder="102" showInDefault="1" showInWebsite="1" showInStore="1"> <group id="webapisecurity" translate="label" type="text" sortOrder="250" showInDefault="1" showInWebsite="0" showInStore="0"> <label>Web API Security</label> - <field id="allow_insecure" translate="label" type="select" sortOrder="1" showInDefault="1" showInWebsite="0" showInStore="0"> + <field id="allow_insecure" translate="label" type="select comment" sortOrder="1" showInDefault="1" showInWebsite="0" showInStore="0"> <label>Allow Anonymous Guest Access</label> <source_model>Magento\Config\Model\Config\Source\Yesno</source_model> <comment>This feature applies only to CMS, Catalog and Store APIs. Please consult your developers for details on potential security risks.</comment> diff --git a/app/code/Magento/WebapiSecurity/i18n/en_US.csv b/app/code/Magento/WebapiSecurity/i18n/en_US.csv index 94a4e8706bcd8..5e5e821e63e7f 100644 --- a/app/code/Magento/WebapiSecurity/i18n/en_US.csv +++ b/app/code/Magento/WebapiSecurity/i18n/en_US.csv @@ -1,2 +1,3 @@ "Web API Security","Web API Security" "Allow Anonymous Guest Access","Allow Anonymous Guest Access" +"This feature applies only to CMS, Catalog and Store APIs. Please consult your developers for details on potential security risks.","This feature applies only to CMS, Catalog and Store APIs. Please consult your developers for details on potential security risks." diff --git a/app/code/Magento/Weee/Model/Tax.php b/app/code/Magento/Weee/Model/Tax.php index 3c6d29ae75217..941faed0498f4 100644 --- a/app/code/Magento/Weee/Model/Tax.php +++ b/app/code/Magento/Weee/Model/Tax.php @@ -248,10 +248,20 @@ public function getProductWeeeAttributes( $round = true ) { $result = []; - - $websiteId = $this->_storeManager->getWebsite($website)->getId(); + $websiteId = null; /** @var \Magento\Store\Model\Store $store */ - $store = $this->_storeManager->getWebsite($website)->getDefaultGroup()->getDefaultStore(); + $store = null; + if (!$website) { + $store = $product->getStore(); + if ($store) { + $websiteId = $store->getWebsiteId(); + } + } + if (!$websiteId) { + $websiteObject = $this->_storeManager->getWebsite($website); + $websiteId = $websiteObject->getId(); + $store = $websiteObject->getDefaultGroup()->getDefaultStore(); + } $allWeee = $this->getWeeeTaxAttributeCodes($store); if (!$allWeee) { diff --git a/app/code/Magento/Weee/Test/Mftf/composer.json b/app/code/Magento/Weee/Test/Mftf/composer.json deleted file mode 100644 index 9e5f7c5772a4e..0000000000000 --- a/app/code/Magento/Weee/Test/Mftf/composer.json +++ /dev/null @@ -1,31 +0,0 @@ -{ - "name": "magento/functional-test-module-weee", - "description": "N/A", - "config": { - "sort-packages": true - }, - "require": { - "php": "~7.1.3||~7.2.0", - "magento/magento2-functional-testing-framework": "2.2.0", - "magento/functional-test-module-backend": "100.0.0-dev", - "magento/functional-test-module-catalog": "100.0.0-dev", - "magento/functional-test-module-checkout": "100.0.0-dev", - "magento/functional-test-module-customer": "100.0.0-dev", - "magento/functional-test-module-directory": "100.0.0-dev", - "magento/functional-test-module-eav": "100.0.0-dev", - "magento/functional-test-module-page-cache": "100.0.0-dev", - "magento/functional-test-module-quote": "100.0.0-dev", - "magento/functional-test-module-sales": "100.0.0-dev", - "magento/functional-test-module-store": "100.0.0-dev", - "magento/functional-test-module-tax": "100.0.0-dev", - "magento/functional-test-module-ui": "100.0.0-dev" - }, - "suggest": { - "magento/functional-test-module-bundle": "100.0.0-dev" - }, - "type": "magento2-test", - "license": [ - "OSL-3.0", - "AFL-3.0" - ] -} diff --git a/app/code/Magento/Weee/Test/Unit/Model/TaxTest.php b/app/code/Magento/Weee/Test/Unit/Model/TaxTest.php index 7414e0444598b..ac90dfade07e2 100644 --- a/app/code/Magento/Weee/Test/Unit/Model/TaxTest.php +++ b/app/code/Magento/Weee/Test/Unit/Model/TaxTest.php @@ -157,13 +157,17 @@ protected function setUp() } /** - * test GetProductWeeeAttributes * @dataProvider getProductWeeeAttributesDataProvider * @param array $weeeTaxCalculationsByEntity - * @param array $expectedFptLabel + * @param mixed $websitePassed + * @param string $expectedFptLabel + * @return void */ - public function testGetProductWeeeAttributes($weeeTaxCalculationsByEntity, $expectedFptLabel) - { + public function testGetProductWeeeAttributes( + array $weeeTaxCalculationsByEntity, + $websitePassed, + string $expectedFptLabel + ): void { $product = $this->createMock(\Magento\Catalog\Model\Product::class); $website = $this->createMock(\Magento\Store\Model\Website::class); $store = $this->createMock(\Magento\Store\Model\Store::class); @@ -187,28 +191,38 @@ public function testGetProductWeeeAttributes($weeeTaxCalculationsByEntity, $expe ->method('getAttributeCodesByFrontendType') ->willReturn(['0'=>'fpt']); - $store->expects($this->any()) - ->method('getId') - ->willReturn(1); - - $product->expects($this->any()) - ->method('getId') - ->willReturn(1); - + $this->storeManager->expects($this->any()) + ->method('getWebsite') + ->willReturn($website); $website->expects($this->any()) ->method('getId') - ->willReturn(1); + ->willReturn($websitePassed); $website->expects($this->any()) ->method('getDefaultGroup') ->willReturn($group); - $group->expects($this->any()) ->method('getDefaultStore') ->willReturn($store); + $store->expects($this->any()) + ->method('getId') + ->willReturn(1); - $this->storeManager->expects($this->any()) - ->method('getWebsite') - ->willReturn($website); + if ($websitePassed) { + $product->expects($this->never()) + ->method('getStore') + ->willReturn($store); + } else { + $product->expects($this->once()) + ->method('getStore') + ->willReturn($store); + $store->expects($this->once()) + ->method('getWebsiteId') + ->willReturn(1); + } + + $product->expects($this->any()) + ->method('getId') + ->willReturn(1); $this->weeeConfig->expects($this->any()) ->method('isEnabled') @@ -237,7 +251,7 @@ public function testGetProductWeeeAttributes($weeeTaxCalculationsByEntity, $expe 0 => $weeeTaxCalculationsByEntity ]); - $result = $this->model->getProductWeeeAttributes($product, null, null, null, true); + $result = $this->model->getProductWeeeAttributes($product, null, null, $websitePassed, true); $this->assertTrue(is_array($result)); $this->assertArrayHasKey(0, $result); $obj = $result[0]; @@ -312,7 +326,8 @@ public function getProductWeeeAttributesDataProvider() 'frontend_label' => 'fpt_label_frontend', 'attribute_code' => 'fpt_code', ], - 'expectedFptLabel' => 'fpt_label' + 'websitePassed' => 1, + 'expectedFptLabel' => 'fpt_label', ], 'store_label_not_defined' => [ 'weeeTaxCalculationsByEntity' => [ @@ -321,8 +336,19 @@ public function getProductWeeeAttributesDataProvider() 'frontend_label' => 'fpt_label_frontend', 'attribute_code' => 'fpt_code', ], - 'expectedFptLabel' => 'fpt_label_frontend' - ] + 'websitePassed' => 1, + 'expectedFptLabel' => 'fpt_label_frontend', + ], + 'website_not_passed' => [ + 'weeeTaxCalculationsByEntity' => [ + 'weee_value' => 1, + 'label_value' => '', + 'frontend_label' => 'fpt_label_frontend', + 'attribute_code' => 'fpt_code', + ], + 'websitePassed' => null, + 'expectedFptLabel' => 'fpt_label_frontend', + ], ]; } diff --git a/app/code/Magento/WeeeGraphQl/Test/Mftf/composer.json b/app/code/Magento/WeeeGraphQl/Test/Mftf/composer.json deleted file mode 100644 index 09b1dc9afe551..0000000000000 --- a/app/code/Magento/WeeeGraphQl/Test/Mftf/composer.json +++ /dev/null @@ -1,20 +0,0 @@ -{ - "name": "magento/functional-test-module-weee-graph-ql", - "description": "N/A", - "config": { - "sort-packages": true - }, - "require": { - "php": "~7.1.3||~7.2.0", - "magento/magento2-functional-testing-framework": "2.2.0" - }, - "suggest": { - "magento/functional-test-module-weee": "100.0.0-dev", - "magento/functional-test-module-catalog-graph-ql": "100.0.0-dev" - }, - "type": "magento2-test", - "license": [ - "OSL-3.0", - "AFL-3.0" - ] -} diff --git a/app/code/Magento/Widget/Controller/Adminhtml/Widget/Instance/Save.php b/app/code/Magento/Widget/Controller/Adminhtml/Widget/Instance/Save.php index 98275c3b906db..b5d31dc10be34 100644 --- a/app/code/Magento/Widget/Controller/Adminhtml/Widget/Instance/Save.php +++ b/app/code/Magento/Widget/Controller/Adminhtml/Widget/Instance/Save.php @@ -49,7 +49,5 @@ public function execute() $this->_redirect('adminhtml/*/edit', ['_current' => true]); return; } - $this->_redirect('adminhtml/*/'); - return; } } diff --git a/app/code/Magento/Widget/Test/Mftf/composer.json b/app/code/Magento/Widget/Test/Mftf/composer.json deleted file mode 100644 index 693fa651f5974..0000000000000 --- a/app/code/Magento/Widget/Test/Mftf/composer.json +++ /dev/null @@ -1,25 +0,0 @@ -{ - "name": "magento/functional-test-module-widget", - "description": "N/A", - "config": { - "sort-packages": true - }, - "require": { - "php": "~7.1.3||~7.2.0", - "magento/magento2-functional-testing-framework": "2.2.0", - "magento/functional-test-module-backend": "100.0.0-dev", - "magento/functional-test-module-catalog": "100.0.0-dev", - "magento/functional-test-module-cms": "100.0.0-dev", - "magento/functional-test-module-store": "100.0.0-dev", - "magento/functional-test-module-theme": "100.0.0-dev", - "magento/functional-test-module-variable": "100.0.0-dev" - }, - "suggest": { - "magento/functional-test-module-widget-sample-data": "100.0.0-dev" - }, - "type": "magento2-test", - "license": [ - "OSL-3.0", - "AFL-3.0" - ] -} diff --git a/app/code/Magento/Widget/Test/Unit/Model/WidgetTest.php b/app/code/Magento/Widget/Test/Unit/Model/WidgetTest.php index 0e1f722cd366a..b85a458ed4121 100644 --- a/app/code/Magento/Widget/Test/Unit/Model/WidgetTest.php +++ b/app/code/Magento/Widget/Test/Unit/Model/WidgetTest.php @@ -168,7 +168,7 @@ public function testGetWidgetDeclaration() 'show_pager' => '1', 'products_per_page' => '5', 'products_count' => '10', - 'template' => 'product/widget/content/grid.phtml', + 'template' => 'Magento_CatalogWidget::product/widget/content/grid.phtml', 'conditions' => $conditions ]; @@ -181,7 +181,10 @@ public function testGetWidgetDeclaration() ['1', false, '1'], ['5', false, '5'], ['10', false, '10'], - ['product/widget/content/grid.phtml', false, 'product/widget/content/grid.phtml'], + ['Magento_CatalogWidget::product/widget/content/grid.phtml', + false, + 'Magento_CatalogWidget::product/widget/content/grid.phtml' + ], ['encoded-conditions-string', false, 'encoded-conditions-string'], ]); @@ -226,7 +229,7 @@ public function testGetWidgetDeclarationWithZeroValueParam() 'show_pager' => '1', 'products_per_page' => '5', 'products_count' => '0', - 'template' => 'product/widget/content/grid.phtml', + 'template' => 'Magento_CatalogWidget::product/widget/content/grid.phtml', 'conditions' => $conditions ]; diff --git a/app/code/Magento/Wishlist/Test/Mftf/Test/ConfigurableProductChildImageShouldBeShownOnWishListTest.xml b/app/code/Magento/Wishlist/Test/Mftf/Test/ConfigurableProductChildImageShouldBeShownOnWishListTest.xml index 981ee51954fb4..95beae991384f 100644 --- a/app/code/Magento/Wishlist/Test/Mftf/Test/ConfigurableProductChildImageShouldBeShownOnWishListTest.xml +++ b/app/code/Magento/Wishlist/Test/Mftf/Test/ConfigurableProductChildImageShouldBeShownOnWishListTest.xml @@ -35,6 +35,10 @@ </after> <amOnPage url="{{AdminProductIndexPage.url}}" stepKey="navigateToProductIndex"/> <waitForPageLoad stepKey="waitForProductIndexPageLoad"/> + <actionGroup ref="resetProductGridToDefaultView" stepKey="resetFiltersIfPresent"/> + <actionGroup ref="searchProductGridByKeyword" stepKey="searchProductGrid"> + <argument name="keyword" value="_defaultProduct.name"/> + </actionGroup> <click selector="{{AdminProductGridSection.selectRowBasedOnName(_defaultProduct.name)}}" stepKey="selectProductToAddImage"/> <waitForPageLoad stepKey="waitForProductEditPageLoad"/> <actionGroup ref="addProductImage" stepKey="addImageForParentProduct"> diff --git a/app/code/Magento/Wishlist/Test/Mftf/composer.json b/app/code/Magento/Wishlist/Test/Mftf/composer.json deleted file mode 100644 index d016f9346f60c..0000000000000 --- a/app/code/Magento/Wishlist/Test/Mftf/composer.json +++ /dev/null @@ -1,33 +0,0 @@ -{ - "name": "magento/functional-test-module-wishlist", - "description": "N/A", - "config": { - "sort-packages": true - }, - "require": { - "php": "~7.1.3||~7.2.0", - "magento/magento2-functional-testing-framework": "2.2.0", - "magento/functional-test-module-backend": "100.0.0-dev", - "magento/functional-test-module-catalog": "100.0.0-dev", - "magento/functional-test-module-catalog-inventory": "100.0.0-dev", - "magento/functional-test-module-checkout": "100.0.0-dev", - "magento/functional-test-module-customer": "100.0.0-dev", - "magento/functional-test-module-rss": "100.0.0-dev", - "magento/functional-test-module-sales": "100.0.0-dev", - "magento/functional-test-module-store": "100.0.0-dev", - "magento/functional-test-module-ui": "100.0.0-dev" - }, - "suggest": { - "magento/functional-test-module-configurable-product": "100.0.0-dev", - "magento/functional-test-module-downloadable": "100.0.0-dev", - "magento/functional-test-module-bundle": "100.0.0-dev", - "magento/functional-test-module-cookie": "100.0.0-dev", - "magento/functional-test-module-grouped-product": "100.0.0-dev", - "magento/functional-test-module-wishlist-sample-data": "100.0.0-dev" - }, - "type": "magento2-test", - "license": [ - "OSL-3.0", - "AFL-3.0" - ] -} diff --git a/app/code/Magento/Wishlist/etc/adminhtml/system.xml b/app/code/Magento/Wishlist/etc/adminhtml/system.xml index 86c24bab11ffb..50ea4b01fe12b 100644 --- a/app/code/Magento/Wishlist/etc/adminhtml/system.xml +++ b/app/code/Magento/Wishlist/etc/adminhtml/system.xml @@ -22,12 +22,12 @@ <comment>Email template chosen based on theme fallback when "Default" option is selected.</comment> <source_model>Magento\Config\Model\Config\Source\Email\Template</source_model> </field> - <field id="number_limit" translate="label" type="text" sortOrder="3" showInDefault="1" showInWebsite="1" showInStore="1" canRestore="1"> + <field id="number_limit" translate="label comment" type="text" sortOrder="3" showInDefault="1" showInWebsite="1" showInStore="1" canRestore="1"> <label>Max Emails Allowed to be Sent</label> <comment>10 by default. Max - 10000</comment> <validate>validate-digits validate-digits-range digits-range-1-10000</validate> </field> - <field id="text_limit" translate="label" type="text" sortOrder="4" showInDefault="1" showInWebsite="1" showInStore="1" canRestore="1"> + <field id="text_limit" translate="label comment" type="text" sortOrder="4" showInDefault="1" showInWebsite="1" showInStore="1" canRestore="1"> <label>Email Text Length Limit</label> <comment>255 by default</comment> <validate>validate-digits validate-digits-range digits-range-1-10000</validate> diff --git a/app/code/Magento/Wishlist/i18n/en_US.csv b/app/code/Magento/Wishlist/i18n/en_US.csv index 75d5a2e840102..a1d33cbd574f0 100644 --- a/app/code/Magento/Wishlist/i18n/en_US.csv +++ b/app/code/Magento/Wishlist/i18n/en_US.csv @@ -99,7 +99,9 @@ Back,Back "Email Template","Email Template" "Email template chosen based on theme fallback when ""Default"" option is selected.","Email template chosen based on theme fallback when ""Default"" option is selected." "Max Emails Allowed to be Sent","Max Emails Allowed to be Sent" +"10 by default. Max - 10000","10 by default. Max - 10000" "Email Text Length Limit","Email Text Length Limit" +"255 by default","255 by default" "General Options","General Options" Enabled,Enabled "My Wish List Link","My Wish List Link" diff --git a/app/code/Magento/Wishlist/view/frontend/templates/sidebar.phtml b/app/code/Magento/Wishlist/view/frontend/templates/sidebar.phtml index 00fb87b411fe0..84b607adb6362 100644 --- a/app/code/Magento/Wishlist/view/frontend/templates/sidebar.phtml +++ b/app/code/Magento/Wishlist/view/frontend/templates/sidebar.phtml @@ -31,7 +31,7 @@ $wishlistHelper = $this->helper('Magento\Wishlist\Helper\Data'); <div class="product-item-details"> <strong class="product-item-name"> <a data-bind="attr: { href: product_url }" class="product-item-link"> - <span data-bind="text: product_name"></span> + <span data-bind="html: product_name"></span> </a> </strong> <div data-bind="html: product_price"></div> diff --git a/app/code/Magento/WishlistAnalytics/Test/Mftf/composer.json b/app/code/Magento/WishlistAnalytics/Test/Mftf/composer.json deleted file mode 100644 index 6969178cfdaa6..0000000000000 --- a/app/code/Magento/WishlistAnalytics/Test/Mftf/composer.json +++ /dev/null @@ -1,17 +0,0 @@ -{ - "name": "magento/functional-test-module-wishlist-analytics", - "description": "N/A", - "config": { - "sort-packages": true - }, - "require": { - "php": "~7.1.3||~7.2.0", - "magento/magento2-functional-testing-framework": "2.2.0", - "magento/functional-test-module-wishlist": "100.0.0-dev" - }, - "type": "magento2-test", - "license": [ - "OSL-3.0", - "AFL-3.0" - ] -} diff --git a/app/design/adminhtml/Magento/backend/Magento_Analytics/web/css/source/_module.less b/app/design/adminhtml/Magento/backend/Magento_Analytics/web/css/source/_module.less index 45f1a835d18d8..6d21462d753ca 100644 --- a/app/design/adminhtml/Magento/backend/Magento_Analytics/web/css/source/_module.less +++ b/app/design/adminhtml/Magento/backend/Magento_Analytics/web/css/source/_module.less @@ -18,65 +18,65 @@ // _____________________________________________ .dashboard-advanced-reports { - .lib-vendor-prefix-display(flex); - border-color: @color-gray89; - border-style: solid; - border-width: 1px 0; - margin-bottom: @indent__l; - padding: @indent__m 0; + .lib-vendor-prefix-display(flex); + border-color: @color-gray89; + border-style: solid; + border-width: 1px 0; + margin-bottom: @indent__l; + padding: @indent__m 0; } .dashboard-advanced-reports-title { - &:extend(.dashboard-item-title all); - margin-bottom: @indent__s; + &:extend(.dashboard-item-title all); + margin-bottom: @indent__s; } .dashboard-advanced-reports-content { - line-height: @line-height__xl; + line-height: @line-height__xl; } .dashboard-advanced-reports-actions { - .lib-vendor-prefix-flex-basis(auto); - .lib-vendor-prefix-flex-grow(1); - .lib-vendor-prefix-flex-shrink(1); - align-self: center; - margin-left: @indent__m; - margin-right: @page-main-actions__padding; - text-align: right; + .lib-vendor-prefix-flex-basis(auto); + .lib-vendor-prefix-flex-grow(1); + .lib-vendor-prefix-flex-shrink(1); + align-self: center; + margin-left: @indent__m; + margin-right: @page-main-actions__padding; + text-align: right; } .action-advanced-reports { - &:extend(.abs-action-l all); - &:extend(.abs-action-pattern all); - background-color: @button-advanced-reports__background-color; - border-color: @button-advanced-reports__background-color; - color: @button-advanced-reports__color; - text-shadow: 1px 1px 0 rgba(0, 0, 0, .25); - white-space: nowrap; - - &:after { - &:extend(.abs-icon all); - content: @icon-external-link__content; - font-size: @font-size__xs; - vertical-align: super; - } - - &:hover, - &:active, - &:focus { - background-color: @button-advanced-reports__hover__background-color; - border-color: @button-advanced-reports__hover__border-color; - box-shadow: @button__hover__box-shadow; + &:extend(.abs-action-l all); + &:extend(.abs-action-pattern all); + background-color: @button-advanced-reports__background-color; + border-color: @button-advanced-reports__background-color; color: @button-advanced-reports__color; - text-decoration: none; - } - - &.disabled, - &[disabled] { - cursor: default; - opacity: @disabled__opacity; - pointer-events: none; - } + text-shadow: 1px 1px 0 rgba(0, 0, 0, .25); + white-space: nowrap; + + &:after { + &:extend(.abs-icon all); + content: @icon-external-link__content; + font-size: @font-size__xs; + vertical-align: super; + } + + &:hover, + &:active, + &:focus { + background-color: @button-advanced-reports__hover__background-color; + border-color: @button-advanced-reports__hover__border-color; + box-shadow: @button__hover__box-shadow; + color: @button-advanced-reports__color; + text-decoration: none; + } + + &.disabled, + &[disabled] { + cursor: default; + opacity: @disabled__opacity; + pointer-events: none; + } } // @@ -84,42 +84,42 @@ // --------------------------------------------- .advanced-reports-subscription-modal { - .modal-inner-wrap { - max-width: 75rem; - margin-top: 13rem; - - .modal-content, .modal-header { - padding-left: 4rem; - padding-right: 4rem; - - .action-close { - display: none; - } + .modal-inner-wrap { + margin-top: 13rem; + max-width: 75rem; + + .modal-content, + .modal-header { + padding-left: 4rem; + padding-right: 4rem; + + .action-close { + display: none; + } + } } - } - .admin__fieldset { - padding: 0; - } + .admin__fieldset { + padding: 0; + } } .advanced-reports-subscription-text { - line-height: @line-height__xl; - padding-bottom: 8rem; + line-height: @line-height__xl; + padding-bottom: 8rem; } .advanced-reports-subscription-close { - display: inline-block; - vertical-align: top; - float: right; + display: block; + float: right; } .advanced-reports-subscription-modal { - h1:first-of-type { - background: url("Magento_Analytics::images/analytics-icon.svg") no-repeat; - background-size: 55px 49.08px; - padding: 1.5rem 0 2rem 7rem; - } + h1:first-of-type { + background: url("Magento_Analytics::images/analytics-icon.svg") no-repeat; + background-size: 55px 49.08px; + padding: 1.5rem 0 2rem 7rem; + } } // @@ -127,41 +127,44 @@ // _____________________________________________ .config-additional-comment { - border-color: @color-gray80; - border-style: solid; - border-width: 1px 0; - margin: @indent__l 0; - padding: @indent__m; + border-color: @color-gray80; + border-style: solid; + border-width: 1px 0; + margin: @indent__l 0; + padding: @indent__m; } .config-additional-comment-title { - margin-bottom: @indent__xs; + margin-bottom: @indent__xs; } .config-additional-comment-content { - line-height: @line-height__l; + line-height: @line-height__l; } .config-vertical-title { - clear: both; - color: #303030; - font-size: 1.7rem; - font-weight: 600; - letter-spacing: .025em; - padding: 1.9rem 2.8rem 1.9rem 0; - position: relative; + clear: both; + color: rgb(48, 48, 48); + font-size: 1.7rem; + font-weight: 600; + letter-spacing: .025em; + padding: 1.9rem 2.8rem 1.9rem 0; + position: relative; } .config-vertical-comment { - line-height: 1.5; - margin-bottom: .5em; - margin-top: 1rem; + line-height: 1.5; + margin-bottom: .5em; + margin-top: 1rem; } +/** + * @codingStandardsIgnoreStart + */ #row_analytics_general_vertical { - >td.config-vertical-label { - >label.admin__field-label { - padding-right: 0; + >td.config-vertical-label { + >label.admin__field-label { + padding-right: 0; + } } - } } diff --git a/app/design/adminhtml/Magento/backend/Magento_Backend/layout/default.xml b/app/design/adminhtml/Magento/backend/Magento_Backend/layout/default.xml index da16bde107673..337d63369b160 100644 --- a/app/design/adminhtml/Magento/backend/Magento_Backend/layout/default.xml +++ b/app/design/adminhtml/Magento/backend/Magento_Backend/layout/default.xml @@ -7,6 +7,7 @@ --> <page xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:View/Layout/etc/page_configuration.xsd"> <head> + <meta name="robots" content="NOINDEX,NOFOLLOW"/> <css src="jquery/jstree/themes/default/style.css"/> <css src="css/styles-old.css"/> <css src="css/styles.css"/> diff --git a/app/design/adminhtml/Magento/backend/Magento_Backend/web/css/source/_module-old.less b/app/design/adminhtml/Magento/backend/Magento_Backend/web/css/source/_module-old.less index 16db9092db368..c4bed53dcbe80 100644 --- a/app/design/adminhtml/Magento/backend/Magento_Backend/web/css/source/_module-old.less +++ b/app/design/adminhtml/Magento/backend/Magento_Backend/web/css/source/_module-old.less @@ -54,7 +54,6 @@ .search-global-field .mage-suggest { position: static; display: block; - vertical-align: baseline; width: auto; background-color: transparent; border: none; @@ -177,7 +176,7 @@ } &:before { - display: inline-block; + display: block; float: right; margin-left: 4px; font-size: 13px; diff --git a/app/design/adminhtml/Magento/backend/Magento_Backend/web/css/source/module/_menu.less b/app/design/adminhtml/Magento/backend/Magento_Backend/web/css/source/module/_menu.less index 8825f4ea3f5a2..ba28108326006 100644 --- a/app/design/adminhtml/Magento/backend/Magento_Backend/web/css/source/module/_menu.less +++ b/app/design/adminhtml/Magento/backend/Magento_Backend/web/css/source/module/_menu.less @@ -187,12 +187,12 @@ display: block; } - // External link marker + // External link marker [target='_blank'] { &:after { &:extend(.abs-icon all); content: @icon-external-link__content; - font-size: 0.5rem; + font-size: .5rem; margin-left: @indent__xs; vertical-align: super; } @@ -263,7 +263,6 @@ visibility: hidden; z-index: @submenu__z-index - 1; - .ie10 &, .ie11 & { height: 100%; } diff --git a/app/design/adminhtml/Magento/backend/Magento_Backend/web/css/source/module/pages/_login.less b/app/design/adminhtml/Magento/backend/Magento_Backend/web/css/source/module/pages/_login.less index 97ed1d8cdb1ec..e7f4c41de9750 100644 --- a/app/design/adminhtml/Magento/backend/Magento_Backend/web/css/source/module/pages/_login.less +++ b/app/design/adminhtml/Magento/backend/Magento_Backend/web/css/source/module/pages/_login.less @@ -49,10 +49,6 @@ position: relative; width: 100%; z-index: 1; - - .ie9 & { - margin-top: 10%; - } } :-ms-input-placeholder { @@ -84,7 +80,7 @@ } .messages { - margin-top: 0.5rem; + margin-top: .5rem; + form .admin__legend { display: none; diff --git a/app/design/adminhtml/Magento/backend/Magento_ConfigurableProduct/web/css/source/module/components/_currency-addon.less b/app/design/adminhtml/Magento/backend/Magento_ConfigurableProduct/web/css/source/module/components/_currency-addon.less index f3bb1fede2512..659b1fa811db1 100644 --- a/app/design/adminhtml/Magento/backend/Magento_ConfigurableProduct/web/css/source/module/components/_currency-addon.less +++ b/app/design/adminhtml/Magento/backend/Magento_ConfigurableProduct/web/css/source/module/components/_currency-addon.less @@ -18,8 +18,8 @@ // _____________________________________________ .currency-addon { + border: 1px solid rgb(173,173,173); position: relative; - border: 1px solid #adadad; display: -webkit-inline-flex; display: -ms-inline-flexbox; -webkit-flex-direction: row; @@ -30,17 +30,18 @@ width: 100%; .admin__control-text { - appearence: none; - -webkit-flex-grow: 1; - flex-grow: 1; -ms-flex-order: 1; - -webkit-order: 1; - order: 1; + -webkit-appearance: none; + -webkit-flex-grow: 1; -webkit-flex-shrink: 1; - flex-shrink: 1; + -webkit-order: 1; + appearance: none; background-color: transparent; border-color: transparent; box-shadow: none; + flex-grow: 1; + flex-shrink: 1; + order: 1; vertical-align: top; &:focus { @@ -51,28 +52,28 @@ } label.error { - position: absolute; left: 0; + position: absolute; top: 33px; } .currency-symbol { + -webkit-flex-basis: auto; + -webkit-flex-grow: 0; + -webkit-flex-shrink: 0; border: solid @currency-addon-symbol__border-color; border-width: 0; box-sizing: border-box; color: @currency-addon-symbol__color; + flex-basis: auto; + flex-grow: 0; + flex-shrink: 0; height: @currency-addon-symbol__height; + order: 0; padding: 7px 0 0 @indent__xs; position: static; transition: @smooth__border-color; - -webkit-flex-basis: auto; - flex-basis: auto; - -webkit-flex-grow: 0; - flex-grow: 0; - -webkit-flex-shrink: 0; - flex-shrink: 0; z-index: 1; - order: 0; } ._error & { diff --git a/app/design/adminhtml/Magento/backend/Magento_ConfigurableProduct/web/css/source/module/steps/_bulk-images.less b/app/design/adminhtml/Magento/backend/Magento_ConfigurableProduct/web/css/source/module/steps/_bulk-images.less index b2dc94d9ffa74..35dae432a6c4f 100644 --- a/app/design/adminhtml/Magento/backend/Magento_ConfigurableProduct/web/css/source/module/steps/_bulk-images.less +++ b/app/design/adminhtml/Magento/backend/Magento_ConfigurableProduct/web/css/source/module/steps/_bulk-images.less @@ -97,8 +97,8 @@ margin-left: 0; .admin__field-control { + display: block; float: right; - display: inline-block; } } } diff --git a/app/design/adminhtml/Magento/backend/Magento_GiftRegistry/web/css/source/_module-old.less b/app/design/adminhtml/Magento/backend/Magento_GiftRegistry/web/css/source/_module-old.less index 6b0d73299d903..3e1a1b9cf9be9 100644 --- a/app/design/adminhtml/Magento/backend/Magento_GiftRegistry/web/css/source/_module-old.less +++ b/app/design/adminhtml/Magento/backend/Magento_GiftRegistry/web/css/source/_module-old.less @@ -7,7 +7,3 @@ // Stores -> Gift Registry // --------------------------------------------- -.eq-ie9 [class^=' adminhtml-giftregistry-'] .custom-options .data-table { - table-layout: auto; - word-wrap: normal; -} diff --git a/app/design/adminhtml/Magento/backend/Magento_Marketplace/web/css/source/_module.less b/app/design/adminhtml/Magento/backend/Magento_Marketplace/web/css/source/_module.less index d4f918567e579..92a08eb7909c4 100644 --- a/app/design/adminhtml/Magento/backend/Magento_Marketplace/web/css/source/_module.less +++ b/app/design/adminhtml/Magento/backend/Magento_Marketplace/web/css/source/_module.less @@ -15,22 +15,12 @@ .lib-vendor-prefix-display(flex); .lib-vendor-prefix-flex-direction(row); .lib-vendor-prefix-flex-wrap(wrap); - - .ie9 & { - word-spacing: -.45rem; - } } .partner { margin-bottom: @indent__xl; padding: 0 @indent__m; width: 100% / 3; - - .ie9 & { - display: inline-block; - vertical-align: top; - word-spacing: normal; - } } } diff --git a/app/design/adminhtml/Magento/backend/Magento_ReleaseNotification/web/css/source/_module.less b/app/design/adminhtml/Magento/backend/Magento_ReleaseNotification/web/css/source/_module.less index a7b6f553f1ff8..6f1e4224fa7a5 100644 --- a/app/design/adminhtml/Magento/backend/Magento_ReleaseNotification/web/css/source/_module.less +++ b/app/design/adminhtml/Magento/backend/Magento_ReleaseNotification/web/css/source/_module.less @@ -8,111 +8,112 @@ // --------------------------------------------- .release-notification-modal { - -webkit-transition: visibility 0s .5s, opacity .5s ease; - transition: visibility 0s .5s, opacity .5s ease; - - &._show { - visibility: visible; - opacity: 1; - -webkit-transition: opacity .5s ease; - transition: opacity .5s ease; - } - - .modal-inner-wrap { - -webkit-transform: translateX(0); - transform: translateX(0); - -webkit-transition: -webkit-transform 0s; - transition: transform 0s; - height: 50rem; - max-width: 75rem; - margin-top: 13rem; - - .modal-content, .modal-header { - padding-left: 4rem; - padding-right: 4rem; - - .action-close { - display: none; - } + -webkit-transition: visibility 0s .5s, opacity .5s ease; + transition: visibility 0s .5s, opacity .5s ease; + + &._show { + -webkit-transition: opacity .5s ease; + opacity: 1; + transition: opacity .5s ease; + visibility: visible; } - } - .admin__fieldset { - padding: 0; - } + .modal-inner-wrap { + .modal-content, + .modal-header { + padding-left: 4rem; + padding-right: 4rem; + + .action-close { + display: none; + } + } + + -webkit-transform: translateX(0); + -webkit-transition: -webkit-transform 0s; + height: 50rem; + transition: transform 0s; + transform: translateX(0); + margin-top: 13rem; + max-width: 75rem; + } + + .admin__fieldset { + padding: 0; + } } .release-notification-title-with-image { - padding: 1.5rem 0 2rem 7rem; - background-size: 55px 49.08px; - background-repeat: no-repeat; + background-repeat: no-repeat; + background-size: 55px 49.08px; + padding: 1.5rem 0 2rem 7rem; } .release-notification-text { - line-height: @line-height__l; - - ul { - margin: 2rem 0 2rem 0; - - li { - font-size: @font-size__xs; - margin: 1.5rem 0 1.5rem 2rem; - - span { - font-size: @font-size__base; - vertical-align: middle; - position: relative; - left: 1rem; - } + line-height: @line-height__l; + + ul { + margin: 2rem 0 2rem 0; + + li { + font-size: @font-size__xs; + margin: 1.5rem 0 1.5rem 2rem; + + span { + font-size: @font-size__base; + vertical-align: middle; + position: relative; + left: 1rem; + } + } } - } } -.release-notification-button-next, .release-notification-button-back { - display: inline-block; - vertical-align: top; - float: right; - position: absolute; - bottom: 4rem; +.release-notification-button-next, +.release-notification-button-back { + bottom: 4rem; + display: block; + float: right; + position: absolute; } .release-notification-button-next { - .lib-button-as-link(); - right: 4rem; - font-weight: 400; + .lib-button-as-link(); + font-weight: 400; + right: 4rem; } .release-notification-button-back { - .lib-button-as-link(); - left: 4rem; - font-weight: 400; + .lib-button-as-link(); + font-weight: 400; + left: 4rem; } .highlight-item { - padding: 0 0 2rem 8.5rem; - margin-left: 1rem; - background-size: 65px 58px; - background-repeat: no-repeat; - - h3 { - margin: 0; - - span { - font-style: @font-style__emphasis; - font-size: @font-size__s; - font-weight: @font-weight__light; + h3 { + margin: 0; + + span { + font-size: @font-size__s; + font-style: @font-style__emphasis; + font-weight: @font-weight__light; + } } - } + + background-size: 65px 58px; + background-repeat: no-repeat; + padding: 0 0 2rem 8.5rem; + margin-left: 1rem; } .highlight-item-no-image { - padding: 0 0 2rem 0; + padding: 0 0 2rem 0; - h3 { - margin: 0; - } + h3 { + margin: 0; + } } .hide-release-notification { - display: none; + display: none; } diff --git a/app/design/adminhtml/Magento/backend/Magento_Staging/web/css/source/module/_staging-preview.less b/app/design/adminhtml/Magento/backend/Magento_Staging/web/css/source/module/_staging-preview.less index a71731320c5ce..3e1f4e75031d2 100644 --- a/app/design/adminhtml/Magento/backend/Magento_Staging/web/css/source/module/_staging-preview.less +++ b/app/design/adminhtml/Magento/backend/Magento_Staging/web/css/source/module/_staging-preview.less @@ -1,5 +1,5 @@ // /** -// * Copyright © 2015 Magento. All rights reserved. +// * Copyright © Magento, Inc. All rights reserved. // * See COPYING.txt for license details. // */ @@ -366,7 +366,7 @@ // Generic data grid .admin__data-grid-outer-wrap { border-top: 1px solid @staging-preview-table-dark__border-color; - max-height: 400px; // ToDO: remove after JS adjustment implemented + max-height: 400px; // ToDO remove after JS adjustment implemented overflow-y: auto; padding: 15px @indent__s 0 0; } @@ -730,15 +730,9 @@ top: @indent__l; width: 1px; - .ie9 &, - .ie10 &, .ie11 & { height: 1000px; } - - .ie9 & { - border-right: 1px dashed @staging-preview-table-lighten__border-color; - } } } } diff --git a/app/design/adminhtml/Magento/backend/Magento_Ui/web/css/source/_module-old.less b/app/design/adminhtml/Magento/backend/Magento_Ui/web/css/source/_module-old.less index 11e0fcc7c8b84..3756fe678a3c9 100644 --- a/app/design/adminhtml/Magento/backend/Magento_Ui/web/css/source/_module-old.less +++ b/app/design/adminhtml/Magento/backend/Magento_Ui/web/css/source/_module-old.less @@ -180,14 +180,14 @@ .lib-clearfix(); [data-part=left] { - display: inline-block; + display: block; width: 45%; float: left; text-align: left; } [data-part=right] { - display: inline-block; + display: block; width: 45%; text-align: right; float: right; diff --git a/app/design/adminhtml/Magento/backend/Magento_Ui/web/css/source/module/_data-grid.less b/app/design/adminhtml/Magento/backend/Magento_Ui/web/css/source/module/_data-grid.less index 065f870dbfe01..d55608ade4a05 100644 --- a/app/design/adminhtml/Magento/backend/Magento_Ui/web/css/source/module/_data-grid.less +++ b/app/design/adminhtml/Magento/backend/Magento_Ui/web/css/source/module/_data-grid.less @@ -59,18 +59,6 @@ margin-top: -(@data-grid-spinner__size / 2); position: absolute; top: 50%; - - .ie9 & { - background: url('@{baseDir}images/loader-2.gif') 50% 50% no-repeat; - bottom: 0; - height: 149px; - left: 0; - margin: auto; - position: absolute; - right: 0; - top: 0; - width: 218px; - } } } @@ -999,10 +987,6 @@ body._in-resize { transform: rotate(45deg); width: 1.6rem; z-index: 3; - - .ie9 & { - display: none; - } } } } diff --git a/app/design/adminhtml/Magento/backend/Magento_Ui/web/css/source/module/data-grid/data-grid-header/_data-grid-action-bookmarks.less b/app/design/adminhtml/Magento/backend/Magento_Ui/web/css/source/module/data-grid/data-grid-header/_data-grid-action-bookmarks.less index dfaf340f90b6c..f9c93dce57002 100644 --- a/app/design/adminhtml/Magento/backend/Magento_Ui/web/css/source/module/data-grid/data-grid-header/_data-grid-action-bookmarks.less +++ b/app/design/adminhtml/Magento/backend/Magento_Ui/web/css/source/module/data-grid/data-grid-header/_data-grid-action-bookmarks.less @@ -132,10 +132,6 @@ font-size: @action-dropdown-menu__font-size; min-width: 15rem; width: ~'calc(100% - 4rem)'; - - .ie9 & { - width: 15rem; - } } .action-dropdown-menu-item-actions { diff --git a/app/design/adminhtml/Magento/backend/Magento_VisualMerchandiser/web/css/source/_module.less b/app/design/adminhtml/Magento/backend/Magento_VisualMerchandiser/web/css/source/_module.less index 909935e1f8ea8..1cd867efdd13b 100644 --- a/app/design/adminhtml/Magento/backend/Magento_VisualMerchandiser/web/css/source/_module.less +++ b/app/design/adminhtml/Magento/backend/Magento_VisualMerchandiser/web/css/source/_module.less @@ -68,7 +68,7 @@ a { color: @color-gray85; - display: inline-block; + display: block; float: left; text-decoration: none; } diff --git a/app/design/adminhtml/Magento/backend/web/app/setup/styles/less/lib/_buttons.less b/app/design/adminhtml/Magento/backend/web/app/setup/styles/less/lib/_buttons.less index ec7509cba6dda..2c60af8dfa178 100644 --- a/app/design/adminhtml/Magento/backend/web/app/setup/styles/less/lib/_buttons.less +++ b/app/design/adminhtml/Magento/backend/web/app/setup/styles/less/lib/_buttons.less @@ -73,12 +73,6 @@ cursor: default; opacity: @disabled__opacity; pointer-events: none; - - .ie9 & { - background-color: @btn__base__disabled__background-color; - opacity: 1; - text-shadow: none; - } } } @@ -135,22 +129,6 @@ ); color: @btn-prime__color; } - - // Disabled state for IE9 - &[disabled], - &.disabled { - .ie9 & { - background-color: @btn-prime__disabled__background-color; - } - - &:hover, - &:active { - .ie9 & { - background-color: @btn-prime__disabled__background-color; - filter: none; - } - } - } } .btn-secondary { @@ -167,21 +145,6 @@ background-color: @btn-secondary__active__background-color; color: @btn-secondary__color; } - - // Disabled state for IE9 - &[disabled], - &.disabled { - .ie9 & { - background-color: @btn-secondary__disabled__background-color; - } - - &:active { - .ie9 & { - background-color: @btn-secondary__disabled__background-color; - filter: none; - } - } - } } // @@ -239,26 +202,6 @@ left: 1px; } } - - // Disabled state for IE9 - &[disabled], - &.disabled { - &:after { - .ie9 & { - border-color: transparent transparent transparent @btn__base__disabled__background-color; - } - } - - &:focus, - &:hover, - &:active { - &:after { - .ie9 & { - border-left-color: @btn__base__disabled__background-color; - } - } - } - } } .btn-prime { @@ -285,25 +228,6 @@ left: 1px; } } - - // Disabled state for IE9 - &[disabled], - &.disabled { - &:after { - .ie9 & { - border-color: transparent transparent transparent @btn-prime__disabled__background-color; - } - } - - &:hover, - &:active { - &:after { - .ie9 & { - border-left-color: @btn-prime__disabled__background-color; - } - } - } - } } } @@ -342,25 +266,6 @@ right: 1px; } } - - // Disabled state for IE9 - &[disabled], - &.disabled { - &:after { - .ie9 & { - border-color: transparent @btn__base__disabled__background-color transparent transparent; - } - } - - &:hover, - &:active { - &:after { - .ie9 & { - border-right-color: @btn__base__disabled__background-color; - } - } - } - } } .btn-prime { @@ -387,25 +292,6 @@ right: 1px; } } - - // Disabled state for IE9 - &[disabled], - &.disabled { - &:after { - .ie9 & { - border-color: transparent @btn-prime__disabled__background-color transparent transparent; - } - } - - &:hover, - &:active { - &:after { - .ie9 & { - border-right-color: @btn-prime__disabled__background-color; - } - } - } - } } } diff --git a/app/design/adminhtml/Magento/backend/web/app/setup/styles/less/lib/forms/_selects.less b/app/design/adminhtml/Magento/backend/web/app/setup/styles/less/lib/forms/_selects.less index 7e5d34e48892a..76973802a3d2e 100644 --- a/app/design/adminhtml/Magento/backend/web/app/setup/styles/less/lib/forms/_selects.less +++ b/app/design/adminhtml/Magento/backend/web/app/setup/styles/less/lib/forms/_selects.less @@ -47,10 +47,6 @@ top: 0; width: @select-check__size; z-index: -2; - - .ie9 & { - display: none; - } } &:before { @@ -66,10 +62,6 @@ top: 50%; width: 0; z-index: -1; - - .ie9 & { - display: none; - } } .form-el-select { @@ -82,11 +74,6 @@ padding: @form-el__padding-top ~'calc(@{select-check__size} + 10%)' @form-el__padding-bottom @form-el__padding-side; width: 110%; - .ie9 & { - padding-right: @form-el__padding-side; - width: 100%; - } - &::-ms-expand { display: none; } diff --git a/app/design/adminhtml/Magento/backend/web/app/setup/styles/less/pages/_common.less b/app/design/adminhtml/Magento/backend/web/app/setup/styles/less/pages/_common.less index b71c94f2917c8..2b33d1fa542b6 100644 --- a/app/design/adminhtml/Magento/backend/web/app/setup/styles/less/pages/_common.less +++ b/app/design/adminhtml/Magento/backend/web/app/setup/styles/less/pages/_common.less @@ -19,12 +19,6 @@ padding-top: @main__indent-top; } -.menu-wrapper { - .logo-static { - pointer-events: none; - } -} - // // Header // _____________________________________________ diff --git a/app/design/adminhtml/Magento/backend/web/css/source/_actions.less b/app/design/adminhtml/Magento/backend/web/css/source/_actions.less index 4377687fd3d39..886bbcc29a3b9 100644 --- a/app/design/adminhtml/Magento/backend/web/css/source/_actions.less +++ b/app/design/adminhtml/Magento/backend/web/css/source/_actions.less @@ -23,8 +23,15 @@ } .abs-action-pattern { + &[disabled], + &.disabled { + cursor: default; + opacity: @disabled__opacity; + pointer-events: none; + } + border: @button__border-size @button__border-style; - border-radius: 0; // ToDo UI: Delete with admin scope + border-radius: 0; // ToDo UI Delete with admin scope display: inline-block; font-family: @button__font-family; font-size: @button__font-size; @@ -33,13 +40,6 @@ padding: @button__padding-top @button__padding-horizontal @button__padding-bottom; text-align: center; vertical-align: baseline; - - &[disabled], - &.disabled { - cursor: default; - opacity: @disabled__opacity; - pointer-events: none; - } } .abs-action-l { @@ -142,16 +142,6 @@ box-shadow: @button__hover__box-shadow; } } - - &[disabled], - &.disabled { - .ie9 &, - .ie10 & { - background-color: @button-triangle__base__disabled__background-color; - opacity: 1; - text-shadow: none; - } - } } } @@ -182,17 +172,6 @@ border-left-color: @button__hover__background-color; } } - - // Disabled state for IE9, IE10 - &.disabled, - &[disabled] { - &:after { - .ie9 &, - .ie10 & { - border-color: transparent transparent transparent @button-triangle__base__disabled__background-color; - } - } - } } .action-primary { @@ -238,17 +217,6 @@ border-right-color: @button__hover__background-color; } } - - // Disabled state for IE9, IE10 - &.disabled, - &[disabled] { - &:after { - .ie9 &, - .ie10 & { - border-color: transparent @button-triangle__base__disabled__background-color transparent transparent; - } - } - } } .action-primary { @@ -433,7 +401,7 @@ button { left: 0; list-style: none; margin: 2px 0 0; // Action box-shadow + 1px indent - min-width: 0; // ToDo UI: Should be deleted with old styles + min-width: 0; // ToDo UI Should be deleted with old styles padding: 0; position: absolute; right: 0; @@ -444,7 +412,7 @@ button { } > li { - border: none; // ToDo UI: Should be deleted with old styles + border: none; // ToDo UI Should be deleted with old styles display: block; padding: 0; transition: background-color .1s linear; @@ -495,11 +463,6 @@ button { position: absolute; right: auto; top: auto; - - .ie9 & { - margin-left: 99%; - margin-top: -3.5rem; - } } a { diff --git a/app/design/adminhtml/Magento/backend/web/css/source/_reset.less b/app/design/adminhtml/Magento/backend/web/css/source/_reset.less index 3a2847c82b8ce..51de756bff16c 100644 --- a/app/design/adminhtml/Magento/backend/web/css/source/_reset.less +++ b/app/design/adminhtml/Magento/backend/web/css/source/_reset.less @@ -12,6 +12,7 @@ html { -ms-text-size-adjust: 100%; -webkit-text-size-adjust: 100%; box-sizing: border-box; + text-size-adjust: 100%; } * { @@ -87,8 +88,6 @@ template { // --------------------------------------------- a { - background-color: transparent; // Remove the gray background color from active links in IE 10. - // Improve readability when focused and also mouse hovered in all browsers. &:active, &:hover { @@ -107,7 +106,7 @@ abbr { } } -// Address style set to 'bolder' in Firefox 4+, Safari, and Chrome. +// Address style set to 'bolder' in Firefox 4 and later, Safari, and Chrome. b, strong { font-weight: bold; @@ -206,9 +205,9 @@ input, optgroup, select, textarea { - color: inherit; // Correct color not being inherited. Known issue: affects color of disabled elements. + color: inherit; // Correct color not being inherited. Known issue affects color of disabled elements. font: inherit; // Correct font properties not being inherited. - margin: 0; // Address margins set differently in Firefox 4+, Safari, and Chrome. + margin: 0; // Address margins set differently in Firefox 4 and later, Safari, and Chrome. } // Address 'overflow' set to 'hidden' in IE 8/9/10/11. @@ -234,6 +233,7 @@ html input[type='button'], input[type='reset'], input[type='submit'] { -webkit-appearance: button; + appearance: button; cursor: pointer; } @@ -243,7 +243,7 @@ html input[disabled] { cursor: default; } -// Remove inner padding and border in Firefox 4+. +// Remove inner padding and border in Firefox 4 and later. button, input { &::-moz-focus-inner { @@ -252,7 +252,7 @@ input { } } -// Address Firefox 4+ setting 'line-height' on 'input' using '!important' in the UA stylesheet. +// Address Firefox 4 and later setting 'line-height' on 'input' using '!important' in the UA stylesheet. input { line-height: normal; } @@ -275,6 +275,7 @@ input[type='number'] { // Address 'appearance' set to 'searchfield' in Safari and Chrome. input[type='search'] { -webkit-appearance: textfield; + appearance: textfield; } // Remove inner padding and search cancel button in Safari and Chrome on OS X. @@ -283,6 +284,7 @@ input[type='search'] { &::-webkit-search-cancel-button, &::-webkit-search-decoration { -webkit-appearance: none; + appearance: none; } } diff --git a/app/design/adminhtml/Magento/backend/web/css/source/actions/_actions-dropdown.less b/app/design/adminhtml/Magento/backend/web/css/source/actions/_actions-dropdown.less index a2e6a4485cc02..cd089232412dc 100644 --- a/app/design/adminhtml/Magento/backend/web/css/source/actions/_actions-dropdown.less +++ b/app/design/adminhtml/Magento/backend/web/css/source/actions/_actions-dropdown.less @@ -168,6 +168,9 @@ width: auto; z-index: 1; + /** + * @codingStandardsIgnoreStart + */ &:hover { &:extend(.abs-form-control-pattern:hover); } @@ -231,7 +234,6 @@ border: 0; display: inline; margin: 0; - width: 6rem; body._keyfocus &:focus { box-shadow: none; diff --git a/app/design/adminhtml/Magento/backend/web/css/source/actions/_actions-switcher.less b/app/design/adminhtml/Magento/backend/web/css/source/actions/_actions-switcher.less index fbef3f4b5f3a6..cf7a8dd56cb3b 100644 --- a/app/design/adminhtml/Magento/backend/web/css/source/actions/_actions-switcher.less +++ b/app/design/adminhtml/Magento/backend/web/css/source/actions/_actions-switcher.less @@ -130,7 +130,6 @@ display: block; height: @actions-switcher__height; transition: background @actions-switcher-speed ease-in 0s; - vertical-align: middle; width: @actions-switcher__width; z-index: 0; } diff --git a/app/design/adminhtml/Magento/backend/web/css/source/components/_file-insertion.less b/app/design/adminhtml/Magento/backend/web/css/source/components/_file-insertion.less index 96b8ce8df1219..88962a1019a19 100644 --- a/app/design/adminhtml/Magento/backend/web/css/source/components/_file-insertion.less +++ b/app/design/adminhtml/Magento/backend/web/css/source/components/_file-insertion.less @@ -26,6 +26,7 @@ border: none; opacity: 1; position: static; + transform: none; } } } diff --git a/app/design/adminhtml/Magento/backend/web/css/source/components/_file-uploader.less b/app/design/adminhtml/Magento/backend/web/css/source/components/_file-uploader.less index 79e3975a41bc6..9a88d5e3593b9 100644 --- a/app/design/adminhtml/Magento/backend/web/css/source/components/_file-uploader.less +++ b/app/design/adminhtml/Magento/backend/web/css/source/components/_file-uploader.less @@ -74,6 +74,14 @@ box-shadow: 0 0 0 1px @file-uploader-preview-focus__color; } } + + &:disabled { + + .file-uploader-button { + cursor: default; + opacity: .5; + pointer-events: none; + } + } } } diff --git a/app/design/adminhtml/Magento/backend/web/css/source/components/_media-gallery.less b/app/design/adminhtml/Magento/backend/web/css/source/components/_media-gallery.less index 85ccc235a3bdd..9a5f35e4ede90 100644 --- a/app/design/adminhtml/Magento/backend/web/css/source/components/_media-gallery.less +++ b/app/design/adminhtml/Magento/backend/web/css/source/components/_media-gallery.less @@ -159,7 +159,7 @@ } .file-row { - background: @color-white url("@{baseDir}mui/images/ajax-loader-big.gif") no-repeat 50% 50%; // TODO UI: remove after new uploader implemented + background: @color-white url("@{baseDir}mui/images/ajax-loader-big.gif") no-repeat 50% 50%; bottom: 0; height: 100%; left: 0; @@ -324,6 +324,7 @@ -ms-flex: 1; -webkit-box-flex: 1; -webkit-flex: 1; + box-flex: 1; flex: 1; } diff --git a/app/design/adminhtml/Magento/backend/web/css/source/components/_popups.less b/app/design/adminhtml/Magento/backend/web/css/source/components/_popups.less index 7bd10ad491f0c..d1d1ff9891634 100644 --- a/app/design/adminhtml/Magento/backend/web/css/source/components/_popups.less +++ b/app/design/adminhtml/Magento/backend/web/css/source/components/_popups.less @@ -283,6 +283,7 @@ border: none; opacity: 1; position: static; + transform: none; } } @@ -462,25 +463,3 @@ } } } - -.ie9 { - .catalog-product-attribute-edit { - &.attribute-popup { - min-width: 0; - - .menu-wrapper { - display: none; - } - - .page-actions { - button { - float: none; - } - - .primary { - float: right; - } - } - } - } -} diff --git a/app/design/adminhtml/Magento/backend/web/css/source/components/_spinner.less b/app/design/adminhtml/Magento/backend/web/css/source/components/_spinner.less index c9e56a29f275f..f6f61c1efae91 100644 --- a/app/design/adminhtml/Magento/backend/web/css/source/components/_spinner.less +++ b/app/design/adminhtml/Magento/backend/web/css/source/components/_spinner.less @@ -33,14 +33,6 @@ position: absolute; width: 1em; } - - .ie9 & { - background: url('@{baseDir}images/ajax-loader.gif') no-repeat center; - - > span { - display: none; - } - } } // ToDo UI: remove old loaders style while loaders redesign diff --git a/app/design/adminhtml/Magento/backend/web/css/source/forms/_controls.less b/app/design/adminhtml/Magento/backend/web/css/source/forms/_controls.less index 5f1cee13b5b88..bb51abaa0f156 100644 --- a/app/design/adminhtml/Magento/backend/web/css/source/forms/_controls.less +++ b/app/design/adminhtml/Magento/backend/web/css/source/forms/_controls.less @@ -100,26 +100,8 @@ &::-ms-expand { display: none; } - - .ie9 & { - background-image: none; - padding-right: @field-control__padding-horizontal; - } } -// ToDo UI: add month and date styles -// .admin__control-select-month { -// width: 140px; -// } - -// .admin__control-select-year { -// width: 103px; -// } - -// .admin__control-cvn { -// width: 3em; -// } - option:empty { display: none; } @@ -152,21 +134,24 @@ option:empty { &:before { &:extend(.abs-form-control-pattern); - content:''; - left: 0; - position: absolute; - top: 0; - width: 100%; - z-index: 0; - .admin__control-file:active + &, .admin__control-file:focus + & { + /** + * @codingStandardsIgnoreStart + */ &:extend(.abs-form-control-pattern:focus); } .admin__control-file[disabled] + & { &:extend(.abs-form-control-pattern[disabled]); } + + content: ''; + left: 0; + position: absolute; + top: 0; + width: 100%; + z-index: 0; } } @@ -336,35 +321,3 @@ option:empty { .admin__addon-prefix { .lib-vendor-prefix-order(0); } - -.ie9 { - .admin__control-addon { - &:after { - clear: both; - content: ''; - display: block; - height: 0; - overflow: hidden; - } - } - - .admin__addon { - min-width: 0; - overflow: hidden; - text-align: right; - white-space: nowrap; - width: auto; - - [class*='admin__control-'] { - display: inline; - } - - &-prefix { - float: left; - } - - &-suffix { - float: right; - } - } -} diff --git a/app/design/adminhtml/Magento/backend/web/css/source/forms/_fields.less b/app/design/adminhtml/Magento/backend/web/css/source/forms/_fields.less index 59675de698787..8f0d4c33a8ee7 100644 --- a/app/design/adminhtml/Magento/backend/web/css/source/forms/_fields.less +++ b/app/design/adminhtml/Magento/backend/web/css/source/forms/_fields.less @@ -183,10 +183,13 @@ .admin__field-label { color: @field-label__color; - cursor: pointer; margin: 0; text-align: right; + label { + cursor: pointer; + } + + br { display: none; } @@ -207,7 +210,7 @@ overflow: hidden; } - span { + label { display: inline-block; line-height: @field-label__line-height; vertical-align: middle; @@ -512,7 +515,7 @@ position: absolute; top: 0; - span { + label { &:before { display: block; } @@ -527,7 +530,7 @@ } & > .admin__field-label { - span { + label { &:before { display: none; } diff --git a/app/design/adminhtml/Magento/backend/web/css/source/forms/_temp.less b/app/design/adminhtml/Magento/backend/web/css/source/forms/_temp.less index 0bfa454adbf0d..df031bebeb24a 100644 --- a/app/design/adminhtml/Magento/backend/web/css/source/forms/_temp.less +++ b/app/design/adminhtml/Magento/backend/web/css/source/forms/_temp.less @@ -408,6 +408,9 @@ label.mage-error { width: 16px; z-index: 1; + /** + * @codingStandardsIgnoreStart + */ &:before { &:extend(.admin__control-checkbox + label:before); left: 0; @@ -434,6 +437,7 @@ label.mage-error { &:before { &:extend(.admin__control-checkbox:checked + label:before); } + // @codingStandardsIgnoreEnd } &._indeterminate { @@ -470,6 +474,7 @@ label.mage-error { .action-select-multiselect { -webkit-appearance: menulist-button; + appearance: menulist-button; height: 38px; left: -1rem; min-width: 0; diff --git a/app/design/adminhtml/Magento/backend/web/css/styles-old.less b/app/design/adminhtml/Magento/backend/web/css/styles-old.less index 8d314e06899b3..74098f127eb73 100644 --- a/app/design/adminhtml/Magento/backend/web/css/styles-old.less +++ b/app/design/adminhtml/Magento/backend/web/css/styles-old.less @@ -279,7 +279,6 @@ .nested .choice .label, .nested .choice .control { float: none; - width: auto; position: static; left: auto; text-align: left; @@ -1215,6 +1214,7 @@ -webkit-user-select: none; // use in 41 Chrome -moz-user-select: none; // use in 36 Firefox -ms-user-select: none; // use in 11 IE + user-select: none; min-height: 39px; } @@ -3905,117 +3905,6 @@ } } -// -// IE9 styles -// --------------------------------------------- - -.ie9 { - .admin__scope-old { - select { - &:not([multiple]) { - padding-right: 4px; - min-width: 0; - } - } - - // Table Filters - .filter select { - &:not([multiple]) { - padding-right: 0; - } - } - - .adminhtml-widget-instance-edit { - .grid-chooser .control { - margin-top: -18px; - } - } - .page-layout-admin-1column .page-columns, - .catalog-product-edit, - .catalog-product-new, - .catalog-category-edit { - table.data { - table-layout: fixed; - word-wrap: break-word; - - th { - word-wrap: normal; - overflow: hidden; - vertical-align: top; - - > span { - white-space: normal; - } - } - - th:not(.col-select):not(.col-id):not(.col-severity), - td:not(.col-select):not(.col-id):not(.col-severity) { - width: auto; - } - } - } - - #setGrid_table, - #attributeGrid_table, - .custom-options .data-table, - .ui-dialog .data, - .page-layout-admin-1column .page-columns .data, - .catalog-category-edit .data { - word-wrap: break-word; - table-layout: fixed; - } - - .fieldset-wrapper { - table.data { - table-layout: inherit; - word-wrap: normal; - } - } - - .sales-order-create-index table.data, - .sales-order-create-index .fieldset-wrapper table.data { - table-layout: fixed; - word-wrap: break-word; - - th { - word-wrap: normal; - overflow: hidden; - vertical-align: top; - - > span { - white-space: normal; - } - } - } - - .entry-edit .product-options .grouped-items-table { - table-layout: fixed; - word-wrap: break-word; - - th { - word-wrap: normal; - overflow: hidden; - vertical-align: top; - - > span { - white-space: normal; - } - } - } - - .catalog-category-edit, - .adminhtml-cache-index, - .adminhtml-process-list, - .indexer-indexer-list, - .adminhtml-notification-index { - table.data { - table-layout: inherit; - word-wrap: normal; - } - } - } -} - // // Pages styles // --------------------------------------------- diff --git a/app/design/adminhtml/Magento/backend/web/mui/styles/_table.less b/app/design/adminhtml/Magento/backend/web/mui/styles/_table.less index 7565ee88714f6..70ae82045b3d1 100644 --- a/app/design/adminhtml/Magento/backend/web/mui/styles/_table.less +++ b/app/design/adminhtml/Magento/backend/web/mui/styles/_table.less @@ -204,16 +204,6 @@ } } -.eq-ie9 { - .hor-scroll { - display: inline-block; - min-height: 0; - overflow-y: hidden; - overflow-x: auto; - width: 100%; - } -} - td.col-period, td.col-date, td.col-date_to, @@ -455,7 +445,6 @@ td.col-type { .import { display: block; - vertical-align: top; } .action-reset { diff --git a/app/design/frontend/Magento/blank/Magento_Checkout/web/css/source/module/_cart.less b/app/design/frontend/Magento/blank/Magento_Checkout/web/css/source/module/_cart.less index bb14a3c2521b0..d3d15019f0e87 100644 --- a/app/design/frontend/Magento/blank/Magento_Checkout/web/css/source/module/_cart.less +++ b/app/design/frontend/Magento/blank/Magento_Checkout/web/css/source/module/_cart.less @@ -305,7 +305,7 @@ white-space: nowrap; width: 33%; - &:before { + &[data-th]:before { content: attr(data-th) ':'; display: block; font-weight: @font-weight__bold; diff --git a/app/design/frontend/Magento/blank/Magento_Sales/web/css/source/_email.less b/app/design/frontend/Magento/blank/Magento_Sales/web/css/source/_email.less index 84adec39c8892..215d7d8b322b4 100644 --- a/app/design/frontend/Magento/blank/Magento_Sales/web/css/source/_email.less +++ b/app/design/frontend/Magento/blank/Magento_Sales/web/css/source/_email.less @@ -203,7 +203,8 @@ text-align: center; } - .item-price { + .item-price, + .item-subtotal { text-align: right; } diff --git a/app/design/frontend/Magento/blank/Magento_Theme/web/css/source/_module.less b/app/design/frontend/Magento/blank/Magento_Theme/web/css/source/_module.less index ed7af5872483b..f1e1529d9820f 100644 --- a/app/design/frontend/Magento/blank/Magento_Theme/web/css/source/_module.less +++ b/app/design/frontend/Magento/blank/Magento_Theme/web/css/source/_module.less @@ -297,7 +297,6 @@ width: 100%; } - .ie10 &, .ie11 & { height: 100%; } diff --git a/app/design/frontend/Magento/blank/web/css/source/_extends.less b/app/design/frontend/Magento/blank/web/css/source/_extends.less index c177f91e9e7e8..6df78859a1a80 100644 --- a/app/design/frontend/Magento/blank/web/css/source/_extends.less +++ b/app/design/frontend/Magento/blank/web/css/source/_extends.less @@ -846,7 +846,7 @@ white-space: nowrap; width: 33%; - &:before { + &[data-th]:before { content: attr(data-th) ':'; display: block; font-weight: @font-weight__bold; diff --git a/app/design/frontend/Magento/blank/web/css/source/_layout.less b/app/design/frontend/Magento/blank/web/css/source/_layout.less index 8d01ddc0a9bd3..a81a3fa8d1f17 100644 --- a/app/design/frontend/Magento/blank/web/css/source/_layout.less +++ b/app/design/frontend/Magento/blank/web/css/source/_layout.less @@ -98,10 +98,6 @@ .lib-vendor-prefix-flex-grow(1); .lib-vendor-prefix-flex-shrink(0); .lib-vendor-prefix-flex-basis(auto); - - .ie9 & { - width: auto; - } } .columns { diff --git a/app/design/frontend/Magento/luma/Magento_Checkout/web/css/source/module/_cart.less b/app/design/frontend/Magento/luma/Magento_Checkout/web/css/source/module/_cart.less index 43b0351f0ff77..9e3a28be4c90e 100644 --- a/app/design/frontend/Magento/luma/Magento_Checkout/web/css/source/module/_cart.less +++ b/app/design/frontend/Magento/luma/Magento_Checkout/web/css/source/module/_cart.less @@ -460,7 +460,7 @@ white-space: nowrap; width: 33%; - &:before { + &[data-th]:before { content: attr(data-th); display: block; font-weight: @font-weight__semibold; diff --git a/app/design/frontend/Magento/luma/Magento_Customer/web/css/source/_module.less b/app/design/frontend/Magento/luma/Magento_Customer/web/css/source/_module.less old mode 100644 new mode 100755 index c6a240fd55ea2..d7ae6c3b28f4a --- a/app/design/frontend/Magento/luma/Magento_Customer/web/css/source/_module.less +++ b/app/design/frontend/Magento/luma/Magento_Customer/web/css/source/_module.less @@ -224,7 +224,7 @@ .column.main & { } } - + display: block; margin-bottom: @indent__s; } diff --git a/app/design/frontend/Magento/luma/Magento_Sales/web/css/source/_email.less b/app/design/frontend/Magento/luma/Magento_Sales/web/css/source/_email.less index 9a3f433618c36..3f19d1020bab9 100644 --- a/app/design/frontend/Magento/luma/Magento_Sales/web/css/source/_email.less +++ b/app/design/frontend/Magento/luma/Magento_Sales/web/css/source/_email.less @@ -207,7 +207,8 @@ text-align: center; } - .item-price { + .item-price, + .item-subtotal { text-align: right; } diff --git a/app/design/frontend/Magento/luma/Magento_Sales/web/css/source/_module.less b/app/design/frontend/Magento/luma/Magento_Sales/web/css/source/_module.less index 692f91ef463b1..a0f734b05cbd1 100644 --- a/app/design/frontend/Magento/luma/Magento_Sales/web/css/source/_module.less +++ b/app/design/frontend/Magento/luma/Magento_Sales/web/css/source/_module.less @@ -482,7 +482,7 @@ .options-label + .item-options-container, .item-options-container + .item-options-container { - &:before { + &[data-th]:before { content: attr(data-th) ':'; display: block; font-weight: @font-weight__bold; diff --git a/app/design/frontend/Magento/luma/Magento_Theme/web/css/source/_module.less b/app/design/frontend/Magento/luma/Magento_Theme/web/css/source/_module.less index 2c177571b9f5a..af6cfa8605f6d 100644 --- a/app/design/frontend/Magento/luma/Magento_Theme/web/css/source/_module.less +++ b/app/design/frontend/Magento/luma/Magento_Theme/web/css/source/_module.less @@ -62,13 +62,6 @@ // Common // _____________________________________________ -.page-wrapper { - .ie9 & { - .lib-css(background-color, @page__background-color); - min-height: 0; - } -} - & when (@media-common = true) { body { .lib-css(background-color, @page__background-color); @@ -433,6 +426,17 @@ } } +// +// Mobile +// _____________________________________________ + +.media-width(@extremum, @break) when (@extremum = 'max') and (@break = @screen__m) { + .cms-page-view .page-main { + padding-top: 41px; + position: relative; + } +} + // // Desktop // _____________________________________________ @@ -443,12 +447,6 @@ height: 100%; // Stretch screen area for sticky footer } - body { - .ie9 & { - .lib-css(background-color, @copyright__background-color); - } - } - .navigation ul { padding: 0 8px; } @@ -630,7 +628,6 @@ width: 100%; } - .ie10 &, .ie11 & { height: 100%; } diff --git a/app/design/frontend/Magento/luma/web/css/source/_extends.less b/app/design/frontend/Magento/luma/web/css/source/_extends.less index 760ec9ed861a9..7c9f5b7a65ab4 100644 --- a/app/design/frontend/Magento/luma/web/css/source/_extends.less +++ b/app/design/frontend/Magento/luma/web/css/source/_extends.less @@ -7,6 +7,8 @@ // List default styles reset // --------------------------------------------- +@_column-number: 1; + & when (@media-common = true) { .abs-reset-list { .lib-list-reset-styles(); @@ -705,7 +707,7 @@ // --------------------------------------------- @abs-form-field-revert-column-1: { - .lib-form-field-column-number(@_column-number: 1); + .lib-form-field-column-number(@_column-number); }; .media-width(@extremum, @break) when (@extremum = 'min') and (@break = @screen__m) { @@ -760,7 +762,7 @@ white-space: nowrap; width: 33%; - &:before { + &[data-th]:before { content: attr(data-th) ':'; display: block; font-weight: @font-weight__bold; diff --git a/app/design/frontend/Magento/luma/web/css/source/_forms.less b/app/design/frontend/Magento/luma/web/css/source/_forms.less index 7c5027aef113b..0c7150c18550b 100644 --- a/app/design/frontend/Magento/luma/web/css/source/_forms.less +++ b/app/design/frontend/Magento/luma/web/css/source/_forms.less @@ -98,11 +98,6 @@ &::-ms-expand { display: none; } - - .lt-ie10 & { - background-image: none; - padding-right: 4px; - } } select { diff --git a/app/etc/di.xml b/app/etc/di.xml index 6a4a6d16b5568..5bc25e6cb85f7 100755 --- a/app/etc/di.xml +++ b/app/etc/di.xml @@ -206,6 +206,7 @@ <preference for="Magento\Framework\MessageQueue\QueueFactoryInterface" type="Magento\Framework\MessageQueue\QueueFactory" /> <preference for="Magento\Framework\App\Request\ValidatorInterface" type="Magento\Framework\App\Request\CsrfValidator" /> + <preference for="Magento\Framework\Search\Request\IndexScopeResolverInterface" type="Magento\Framework\Indexer\ScopeResolver\IndexScopeResolver"/> <type name="Magento\Framework\Model\ResourceModel\Db\TransactionManager" shared="false" /> <type name="Magento\Framework\Acl\Data\Cache"> <arguments> diff --git a/composer.json b/composer.json index 760ec0da13f42..b7435e98695c3 100644 --- a/composer.json +++ b/composer.json @@ -38,7 +38,7 @@ "elasticsearch/elasticsearch": "~2.0|~5.1", "magento/composer": "~1.4.0", "magento/magento-composer-installer": ">=0.1.11", - "magento/zendframework1": "~1.14.0", + "magento/zendframework1": "~1.14.1", "monolog/monolog": "^1.17", "oyejorge/less.php": "~1.7.0", "pelago/emogrifier": "^2.0.0", @@ -81,6 +81,7 @@ "zendframework/zend-view": "~2.10.0" }, "require-dev": { + "magento/magento2-functional-testing-framework": "2.3.4", "friendsofphp/php-cs-fixer": "~2.12.0", "lusitanian/oauth": "~0.8.10", "pdepend/pdepend": "2.5.2", diff --git a/composer.lock b/composer.lock index 0966aee19489e..d90750e2547ef 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "c6ae2be0f066e566e8280b2954aad257", + "content-hash": "74013a4027763e05b29b127b4c03c752", "packages": [ { "name": "braintree/braintree_php", @@ -201,16 +201,16 @@ }, { "name": "composer/ca-bundle", - "version": "1.1.1", + "version": "1.1.2", "source": { "type": "git", "url": "https://github.com/composer/ca-bundle.git", - "reference": "d2c0a83b7533d6912e8d516756ebd34f893e9169" + "reference": "46afded9720f40b9dc63542af4e3e43a1177acb0" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/composer/ca-bundle/zipball/d2c0a83b7533d6912e8d516756ebd34f893e9169", - "reference": "d2c0a83b7533d6912e8d516756ebd34f893e9169", + "url": "https://api.github.com/repos/composer/ca-bundle/zipball/46afded9720f40b9dc63542af4e3e43a1177acb0", + "reference": "46afded9720f40b9dc63542af4e3e43a1177acb0", "shasum": "" }, "require": { @@ -253,30 +253,30 @@ "ssl", "tls" ], - "time": "2018-03-29T19:57:20+00:00" + "time": "2018-08-08T08:57:40+00:00" }, { "name": "composer/composer", - "version": "1.6.5", + "version": "1.7.1", "source": { "type": "git", "url": "https://github.com/composer/composer.git", - "reference": "b184a92419cc9a9c4c6a09db555a94d441cb11c9" + "reference": "5d9311d4555787c8a57fea15f82471499aedf712" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/composer/composer/zipball/b184a92419cc9a9c4c6a09db555a94d441cb11c9", - "reference": "b184a92419cc9a9c4c6a09db555a94d441cb11c9", + "url": "https://api.github.com/repos/composer/composer/zipball/5d9311d4555787c8a57fea15f82471499aedf712", + "reference": "5d9311d4555787c8a57fea15f82471499aedf712", "shasum": "" }, "require": { "composer/ca-bundle": "^1.0", "composer/semver": "^1.0", "composer/spdx-licenses": "^1.2", + "composer/xdebug-handler": "^1.1", "justinrainbow/json-schema": "^3.0 || ^4.0 || ^5.0", "php": "^5.3.2 || ^7.0", "psr/log": "^1.0", - "seld/cli-prompt": "^1.0", "seld/jsonlint": "^1.4", "seld/phar-utils": "^1.0", "symfony/console": "^2.7 || ^3.0 || ^4.0", @@ -302,7 +302,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "1.6-dev" + "dev-master": "1.7-dev" } }, "autoload": { @@ -333,7 +333,7 @@ "dependency", "package" ], - "time": "2018-05-04T09:44:59+00:00" + "time": "2018-08-07T07:39:23+00:00" }, { "name": "composer/semver", @@ -458,6 +458,50 @@ ], "time": "2018-04-30T10:33:04+00:00" }, + { + "name": "composer/xdebug-handler", + "version": "1.1.0", + "source": { + "type": "git", + "url": "https://github.com/composer/xdebug-handler.git", + "reference": "c919dc6c62e221fc6406f861ea13433c0aa24f08" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/composer/xdebug-handler/zipball/c919dc6c62e221fc6406f861ea13433c0aa24f08", + "reference": "c919dc6c62e221fc6406f861ea13433c0aa24f08", + "shasum": "" + }, + "require": { + "php": "^5.3.2 || ^7.0", + "psr/log": "^1.0" + }, + "require-dev": { + "phpunit/phpunit": "^4.8.35 || ^5.7 || ^6.5" + }, + "type": "library", + "autoload": { + "psr-4": { + "Composer\\XdebugHandler\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "John Stevenson", + "email": "john-stevenson@blueyonder.co.uk" + } + ], + "description": "Restarts a process without xdebug.", + "keywords": [ + "Xdebug", + "performance" + ], + "time": "2018-04-11T15:42:36+00:00" + }, { "name": "container-interop/container-interop", "version": "1.2.0", @@ -546,16 +590,16 @@ }, { "name": "guzzlehttp/ringphp", - "version": "1.1.0", + "version": "1.1.1", "source": { "type": "git", "url": "https://github.com/guzzle/RingPHP.git", - "reference": "dbbb91d7f6c191e5e405e900e3102ac7f261bc0b" + "reference": "5e2a174052995663dd68e6b5ad838afd47dd615b" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/guzzle/RingPHP/zipball/dbbb91d7f6c191e5e405e900e3102ac7f261bc0b", - "reference": "dbbb91d7f6c191e5e405e900e3102ac7f261bc0b", + "url": "https://api.github.com/repos/guzzle/RingPHP/zipball/5e2a174052995663dd68e6b5ad838afd47dd615b", + "reference": "5e2a174052995663dd68e6b5ad838afd47dd615b", "shasum": "" }, "require": { @@ -593,7 +637,7 @@ } ], "description": "Provides a simple API and specification that abstracts away the details of HTTP into a single PHP function.", - "time": "2015-05-20T03:37:09+00:00" + "time": "2018-07-31T13:22:33+00:00" }, { "name": "guzzlehttp/streams", @@ -828,25 +872,18 @@ }, { "name": "magento/zendframework1", - "version": "1.14.0", + "version": "1.14.1", "source": { "type": "git", "url": "https://github.com/magento/zf1.git", - "reference": "68522e5768edc8e829d1f64b620a3de3753f1141" + "reference": "4df018254c70b5b998b00a8cb1a30760f831ff0d" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/magento/zf1/zipball/68522e5768edc8e829d1f64b620a3de3753f1141", - "reference": "68522e5768edc8e829d1f64b620a3de3753f1141", + "url": "https://api.github.com/repos/magento/zf1/zipball/4df018254c70b5b998b00a8cb1a30760f831ff0d", + "reference": "4df018254c70b5b998b00a8cb1a30760f831ff0d", "shasum": "" }, - "archive": { - "exclude": [ - "/demos", - "/documentation", - "/tests" - ] - }, "require": { "php": ">=5.2.11" }, @@ -865,6 +902,7 @@ "Zend_": "library/" } }, + "notification-url": "https://packagist.org/downloads/", "include-path": [ "library/" ], @@ -874,14 +912,10 @@ "description": "Magento Zend Framework 1", "homepage": "http://framework.zend.com/", "keywords": [ - "framework", - "zf1" + "ZF1", + "framework" ], - "support": { - "source": "https://github.com/magento-engcom/zf1-php-7.2-support/tree/master", - "issues": "https://github.com/magento-engcom/zf1-php-7.2-support/issues" - }, - "time": "2018-04-06T17:12:22+00:00" + "time": "2018-08-09T15:03:40+00:00" }, { "name": "monolog/monolog", @@ -1025,16 +1059,16 @@ }, { "name": "paragonie/random_compat", - "version": "v2.0.15", + "version": "v2.0.17", "source": { "type": "git", "url": "https://github.com/paragonie/random_compat.git", - "reference": "10bcb46e8f3d365170f6de9d05245aa066b81f09" + "reference": "29af24f25bab834fcbb38ad2a69fa93b867e070d" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/paragonie/random_compat/zipball/10bcb46e8f3d365170f6de9d05245aa066b81f09", - "reference": "10bcb46e8f3d365170f6de9d05245aa066b81f09", + "url": "https://api.github.com/repos/paragonie/random_compat/zipball/29af24f25bab834fcbb38ad2a69fa93b867e070d", + "reference": "29af24f25bab834fcbb38ad2a69fa93b867e070d", "shasum": "" }, "require": { @@ -1070,7 +1104,7 @@ "pseudorandom", "random" ], - "time": "2018-06-08T15:26:40+00:00" + "time": "2018-07-04T16:31:37+00:00" }, { "name": "pelago/emogrifier", @@ -1625,54 +1659,6 @@ ], "time": "2018-06-13T15:59:06+00:00" }, - { - "name": "seld/cli-prompt", - "version": "1.0.3", - "source": { - "type": "git", - "url": "https://github.com/Seldaek/cli-prompt.git", - "reference": "a19a7376a4689d4d94cab66ab4f3c816019ba8dd" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/Seldaek/cli-prompt/zipball/a19a7376a4689d4d94cab66ab4f3c816019ba8dd", - "reference": "a19a7376a4689d4d94cab66ab4f3c816019ba8dd", - "shasum": "" - }, - "require": { - "php": ">=5.3" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.x-dev" - } - }, - "autoload": { - "psr-4": { - "Seld\\CliPrompt\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Jordi Boggiano", - "email": "j.boggiano@seld.be" - } - ], - "description": "Allows you to prompt for user input on the command line, and optionally hide the characters they type", - "keywords": [ - "cli", - "console", - "hidden", - "input", - "prompt" - ], - "time": "2017-03-18T11:32:45+00:00" - }, { "name": "seld/jsonlint", "version": "1.7.1", @@ -1768,16 +1754,16 @@ }, { "name": "symfony/console", - "version": "v4.1.1", + "version": "v4.1.3", "source": { "type": "git", "url": "https://github.com/symfony/console.git", - "reference": "70591cda56b4b47c55776ac78e157c4bb6c8b43f" + "reference": "ca80b8ced97cf07390078b29773dc384c39eee1f" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/console/zipball/70591cda56b4b47c55776ac78e157c4bb6c8b43f", - "reference": "70591cda56b4b47c55776ac78e157c4bb6c8b43f", + "url": "https://api.github.com/repos/symfony/console/zipball/ca80b8ced97cf07390078b29773dc384c39eee1f", + "reference": "ca80b8ced97cf07390078b29773dc384c39eee1f", "shasum": "" }, "require": { @@ -1832,20 +1818,20 @@ ], "description": "Symfony Console Component", "homepage": "https://symfony.com", - "time": "2018-05-31T10:17:53+00:00" + "time": "2018-07-26T11:24:31+00:00" }, { "name": "symfony/event-dispatcher", - "version": "v4.1.1", + "version": "v4.1.3", "source": { "type": "git", "url": "https://github.com/symfony/event-dispatcher.git", - "reference": "2391ed210a239868e7256eb6921b1bd83f3087b5" + "reference": "bfb30c2ad377615a463ebbc875eba64a99f6aa3e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/2391ed210a239868e7256eb6921b1bd83f3087b5", - "reference": "2391ed210a239868e7256eb6921b1bd83f3087b5", + "url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/bfb30c2ad377615a463ebbc875eba64a99f6aa3e", + "reference": "bfb30c2ad377615a463ebbc875eba64a99f6aa3e", "shasum": "" }, "require": { @@ -1895,20 +1881,20 @@ ], "description": "Symfony EventDispatcher Component", "homepage": "https://symfony.com", - "time": "2018-04-06T07:35:57+00:00" + "time": "2018-07-26T09:10:45+00:00" }, { "name": "symfony/filesystem", - "version": "v4.1.1", + "version": "v4.1.3", "source": { "type": "git", "url": "https://github.com/symfony/filesystem.git", - "reference": "562bf7005b55fd80d26b582d28e3e10f2dd5ae9c" + "reference": "2e30335e0aafeaa86645555959572fe7cea22b43" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/filesystem/zipball/562bf7005b55fd80d26b582d28e3e10f2dd5ae9c", - "reference": "562bf7005b55fd80d26b582d28e3e10f2dd5ae9c", + "url": "https://api.github.com/repos/symfony/filesystem/zipball/2e30335e0aafeaa86645555959572fe7cea22b43", + "reference": "2e30335e0aafeaa86645555959572fe7cea22b43", "shasum": "" }, "require": { @@ -1945,20 +1931,20 @@ ], "description": "Symfony Filesystem Component", "homepage": "https://symfony.com", - "time": "2018-05-30T07:26:09+00:00" + "time": "2018-07-26T11:24:31+00:00" }, { "name": "symfony/finder", - "version": "v4.1.1", + "version": "v4.1.3", "source": { "type": "git", "url": "https://github.com/symfony/finder.git", - "reference": "84714b8417d19e4ba02ea78a41a975b3efaafddb" + "reference": "e162f1df3102d0b7472805a5a9d5db9fcf0a8068" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/finder/zipball/84714b8417d19e4ba02ea78a41a975b3efaafddb", - "reference": "84714b8417d19e4ba02ea78a41a975b3efaafddb", + "url": "https://api.github.com/repos/symfony/finder/zipball/e162f1df3102d0b7472805a5a9d5db9fcf0a8068", + "reference": "e162f1df3102d0b7472805a5a9d5db9fcf0a8068", "shasum": "" }, "require": { @@ -1994,29 +1980,32 @@ ], "description": "Symfony Finder Component", "homepage": "https://symfony.com", - "time": "2018-06-19T21:38:16+00:00" + "time": "2018-07-26T11:24:31+00:00" }, { "name": "symfony/polyfill-ctype", - "version": "v1.8.0", + "version": "v1.9.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-ctype.git", - "reference": "7cc359f1b7b80fc25ed7796be7d96adc9b354bae" + "reference": "e3d826245268269cd66f8326bd8bc066687b4a19" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/7cc359f1b7b80fc25ed7796be7d96adc9b354bae", - "reference": "7cc359f1b7b80fc25ed7796be7d96adc9b354bae", + "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/e3d826245268269cd66f8326bd8bc066687b4a19", + "reference": "e3d826245268269cd66f8326bd8bc066687b4a19", "shasum": "" }, "require": { "php": ">=5.3.3" }, + "suggest": { + "ext-ctype": "For best performance" + }, "type": "library", "extra": { "branch-alias": { - "dev-master": "1.8-dev" + "dev-master": "1.9-dev" } }, "autoload": { @@ -2049,20 +2038,20 @@ "polyfill", "portable" ], - "time": "2018-04-30T19:57:29+00:00" + "time": "2018-08-06T14:22:27+00:00" }, { "name": "symfony/polyfill-mbstring", - "version": "v1.8.0", + "version": "v1.9.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-mbstring.git", - "reference": "3296adf6a6454a050679cde90f95350ad604b171" + "reference": "d0cd638f4634c16d8df4508e847f14e9e43168b8" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/3296adf6a6454a050679cde90f95350ad604b171", - "reference": "3296adf6a6454a050679cde90f95350ad604b171", + "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/d0cd638f4634c16d8df4508e847f14e9e43168b8", + "reference": "d0cd638f4634c16d8df4508e847f14e9e43168b8", "shasum": "" }, "require": { @@ -2074,7 +2063,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "1.8-dev" + "dev-master": "1.9-dev" } }, "autoload": { @@ -2108,20 +2097,20 @@ "portable", "shim" ], - "time": "2018-04-26T10:06:28+00:00" + "time": "2018-08-06T14:22:27+00:00" }, { "name": "symfony/process", - "version": "v4.1.1", + "version": "v4.1.3", "source": { "type": "git", "url": "https://github.com/symfony/process.git", - "reference": "1d1677391ecf00d1c5b9482d6050c0c27aa3ac3a" + "reference": "f01fc7a4493572f7f506c49dcb50ad01fb3a2f56" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/process/zipball/1d1677391ecf00d1c5b9482d6050c0c27aa3ac3a", - "reference": "1d1677391ecf00d1c5b9482d6050c0c27aa3ac3a", + "url": "https://api.github.com/repos/symfony/process/zipball/f01fc7a4493572f7f506c49dcb50ad01fb3a2f56", + "reference": "f01fc7a4493572f7f506c49dcb50ad01fb3a2f56", "shasum": "" }, "require": { @@ -2157,7 +2146,7 @@ ], "description": "Symfony Process Component", "homepage": "https://symfony.com", - "time": "2018-05-31T10:17:53+00:00" + "time": "2018-07-26T11:24:31+00:00" }, { "name": "tedivm/jshrink", @@ -2728,16 +2717,16 @@ }, { "name": "zendframework/zend-diactoros", - "version": "1.8.0", + "version": "1.8.5", "source": { "type": "git", "url": "https://github.com/zendframework/zend-diactoros.git", - "reference": "11c9c1835e60eef6f9234377a480fcec096ebd9e" + "reference": "3e4edb822c942f37ade0d09579cfbab11e2fee87" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/zendframework/zend-diactoros/zipball/11c9c1835e60eef6f9234377a480fcec096ebd9e", - "reference": "11c9c1835e60eef6f9234377a480fcec096ebd9e", + "url": "https://api.github.com/repos/zendframework/zend-diactoros/zipball/3e4edb822c942f37ade0d09579cfbab11e2fee87", + "reference": "3e4edb822c942f37ade0d09579cfbab11e2fee87", "shasum": "" }, "require": { @@ -2750,7 +2739,7 @@ "require-dev": { "ext-dom": "*", "ext-libxml": "*", - "phpunit/phpunit": "^5.7.16 || ^6.0.8", + "phpunit/phpunit": "^5.7.16 || ^6.0.8 || ^7.2.7", "zendframework/zend-coding-standard": "~1.0" }, "type": "library", @@ -2787,7 +2776,7 @@ "psr", "psr-7" ], - "time": "2018-06-27T18:52:43+00:00" + "time": "2018-08-10T14:16:32+00:00" }, { "name": "zendframework/zend-escaper", @@ -2883,16 +2872,16 @@ }, { "name": "zendframework/zend-feed", - "version": "2.10.2", + "version": "2.10.3", "source": { "type": "git", "url": "https://github.com/zendframework/zend-feed.git", - "reference": "5253f949f4ad999086ab9b408908b6c6776f24db" + "reference": "6641f4cf3f4586c63f83fd70b6d19966025c8888" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/zendframework/zend-feed/zipball/5253f949f4ad999086ab9b408908b6c6776f24db", - "reference": "5253f949f4ad999086ab9b408908b6c6776f24db", + "url": "https://api.github.com/repos/zendframework/zend-feed/zipball/6641f4cf3f4586c63f83fd70b6d19966025c8888", + "reference": "6641f4cf3f4586c63f83fd70b6d19966025c8888", "shasum": "" }, "require": { @@ -2940,7 +2929,7 @@ "feed", "zf" ], - "time": "2018-06-18T20:14:01+00:00" + "time": "2018-08-01T13:53:20+00:00" }, { "name": "zendframework/zend-filter", @@ -3085,16 +3074,16 @@ }, { "name": "zendframework/zend-http", - "version": "2.8.0", + "version": "2.8.2", "source": { "type": "git", "url": "https://github.com/zendframework/zend-http.git", - "reference": "f48b276ffa11b48dd1ae3c6bc306d6ed7958ef51" + "reference": "2c8aed3d25522618573194e7cc51351f8cd4a45b" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/zendframework/zend-http/zipball/f48b276ffa11b48dd1ae3c6bc306d6ed7958ef51", - "reference": "f48b276ffa11b48dd1ae3c6bc306d6ed7958ef51", + "url": "https://api.github.com/repos/zendframework/zend-http/zipball/2c8aed3d25522618573194e7cc51351f8cd4a45b", + "reference": "2c8aed3d25522618573194e7cc51351f8cd4a45b", "shasum": "" }, "require": { @@ -3136,7 +3125,7 @@ "zend", "zf" ], - "time": "2018-04-26T21:04:50+00:00" + "time": "2018-08-13T18:47:03+00:00" }, { "name": "zendframework/zend-hydrator", @@ -4446,150 +4435,142 @@ ], "packages-dev": [ { - "name": "composer/xdebug-handler", - "version": "1.1.0", + "name": "allure-framework/allure-codeception", + "version": "1.2.7", "source": { "type": "git", - "url": "https://github.com/composer/xdebug-handler.git", - "reference": "c919dc6c62e221fc6406f861ea13433c0aa24f08" + "url": "https://github.com/allure-framework/allure-codeception.git", + "reference": "48598f4b4603b50b663bfe977260113a40912131" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/composer/xdebug-handler/zipball/c919dc6c62e221fc6406f861ea13433c0aa24f08", - "reference": "c919dc6c62e221fc6406f861ea13433c0aa24f08", + "url": "https://api.github.com/repos/allure-framework/allure-codeception/zipball/48598f4b4603b50b663bfe977260113a40912131", + "reference": "48598f4b4603b50b663bfe977260113a40912131", "shasum": "" }, "require": { - "php": "^5.3.2 || ^7.0", - "psr/log": "^1.0" - }, - "require-dev": { - "phpunit/phpunit": "^4.8.35 || ^5.7 || ^6.5" + "allure-framework/allure-php-api": "~1.1.0", + "codeception/codeception": "~2.1", + "php": ">=5.4.0", + "symfony/filesystem": ">=2.6", + "symfony/finder": ">=2.6" }, "type": "library", "autoload": { - "psr-4": { - "Composer\\XdebugHandler\\": "src" + "psr-0": { + "Yandex": "src/" } }, "notification-url": "https://packagist.org/downloads/", "license": [ - "MIT" + "Apache-2.0" ], "authors": [ { - "name": "John Stevenson", - "email": "john-stevenson@blueyonder.co.uk" + "name": "Ivan Krutov", + "email": "vania-pooh@yandex-team.ru", + "role": "Developer" } ], - "description": "Restarts a process without xdebug.", + "description": "A Codeception adapter for Allure report.", + "homepage": "http://allure.qatools.ru/", "keywords": [ - "Xdebug", - "performance" - ], - "time": "2018-04-11T15:42:36+00:00" + "allure", + "attachments", + "cases", + "codeception", + "report", + "steps", + "testing" + ], + "time": "2018-03-07T11:18:27+00:00" }, { - "name": "doctrine/annotations", - "version": "v1.6.0", + "name": "allure-framework/allure-php-api", + "version": "1.1.4", "source": { "type": "git", - "url": "https://github.com/doctrine/annotations.git", - "reference": "c7f2050c68a9ab0bdb0f98567ec08d80ea7d24d5" + "url": "https://github.com/allure-framework/allure-php-adapter-api.git", + "reference": "a462a0da121681577033e13c123b6cc4e89cdc64" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/doctrine/annotations/zipball/c7f2050c68a9ab0bdb0f98567ec08d80ea7d24d5", - "reference": "c7f2050c68a9ab0bdb0f98567ec08d80ea7d24d5", + "url": "https://api.github.com/repos/allure-framework/allure-php-adapter-api/zipball/a462a0da121681577033e13c123b6cc4e89cdc64", + "reference": "a462a0da121681577033e13c123b6cc4e89cdc64", "shasum": "" }, "require": { - "doctrine/lexer": "1.*", - "php": "^7.1" - }, - "require-dev": { - "doctrine/cache": "1.*", - "phpunit/phpunit": "^6.4" + "jms/serializer": ">=0.16.0", + "moontoast/math": ">=1.1.0", + "php": ">=5.4.0", + "phpunit/phpunit": ">=4.0.0", + "ramsey/uuid": ">=3.0.0", + "symfony/http-foundation": ">=2.0" }, "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.6.x-dev" - } - }, "autoload": { - "psr-4": { - "Doctrine\\Common\\Annotations\\": "lib/Doctrine/Common/Annotations" + "psr-0": { + "Yandex": [ + "src/", + "test/" + ] } }, "notification-url": "https://packagist.org/downloads/", "license": [ - "MIT" + "Apache-2.0" ], "authors": [ { - "name": "Roman Borschel", - "email": "roman@code-factory.org" - }, - { - "name": "Benjamin Eberlei", - "email": "kontakt@beberlei.de" - }, - { - "name": "Guilherme Blanco", - "email": "guilhermeblanco@gmail.com" - }, - { - "name": "Jonathan Wage", - "email": "jonwage@gmail.com" - }, - { - "name": "Johannes Schmitt", - "email": "schmittjoh@gmail.com" + "name": "Ivan Krutov", + "email": "vania-pooh@yandex-team.ru", + "role": "Developer" } ], - "description": "Docblock Annotations Parser", - "homepage": "http://www.doctrine-project.org", + "description": "PHP API for Allure adapter", + "homepage": "http://allure.qatools.ru/", "keywords": [ - "annotations", - "docblock", - "parser" + "allure", + "api", + "php", + "report" ], - "time": "2017-12-06T07:11:42+00:00" + "time": "2016-12-07T12:15:46+00:00" }, { - "name": "doctrine/instantiator", - "version": "1.1.0", + "name": "behat/gherkin", + "version": "v4.4.5", "source": { "type": "git", - "url": "https://github.com/doctrine/instantiator.git", - "reference": "185b8868aa9bf7159f5f953ed5afb2d7fcdc3bda" + "url": "https://github.com/Behat/Gherkin.git", + "reference": "5c14cff4f955b17d20d088dec1bde61c0539ec74" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/doctrine/instantiator/zipball/185b8868aa9bf7159f5f953ed5afb2d7fcdc3bda", - "reference": "185b8868aa9bf7159f5f953ed5afb2d7fcdc3bda", + "url": "https://api.github.com/repos/Behat/Gherkin/zipball/5c14cff4f955b17d20d088dec1bde61c0539ec74", + "reference": "5c14cff4f955b17d20d088dec1bde61c0539ec74", "shasum": "" }, "require": { - "php": "^7.1" + "php": ">=5.3.1" }, "require-dev": { - "athletic/athletic": "~0.1.8", - "ext-pdo": "*", - "ext-phar": "*", - "phpunit/phpunit": "^6.2.3", - "squizlabs/php_codesniffer": "^3.0.2" + "phpunit/phpunit": "~4.5|~5", + "symfony/phpunit-bridge": "~2.7|~3", + "symfony/yaml": "~2.3|~3" + }, + "suggest": { + "symfony/yaml": "If you want to parse features, represented in YAML files" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "1.2.x-dev" + "dev-master": "4.4-dev" } }, "autoload": { - "psr-4": { - "Doctrine\\Instantiator\\": "src/Doctrine/Instantiator/" + "psr-0": { + "Behat\\Gherkin": "src/" } }, "notification-url": "https://packagist.org/downloads/", @@ -4598,45 +4579,93 @@ ], "authors": [ { - "name": "Marco Pivetta", - "email": "ocramius@gmail.com", - "homepage": "http://ocramius.github.com/" + "name": "Konstantin Kudryashov", + "email": "ever.zet@gmail.com", + "homepage": "http://everzet.com" } ], - "description": "A small, lightweight utility to instantiate objects in PHP without invoking their constructors", - "homepage": "https://github.com/doctrine/instantiator", + "description": "Gherkin DSL parser for PHP 5.3", + "homepage": "http://behat.org/", "keywords": [ - "constructor", - "instantiate" + "BDD", + "Behat", + "Cucumber", + "DSL", + "gherkin", + "parser" ], - "time": "2017-07-22T11:58:36+00:00" + "time": "2016-10-30T11:50:56+00:00" }, { - "name": "doctrine/lexer", - "version": "v1.0.1", + "name": "codeception/codeception", + "version": "2.3.9", "source": { "type": "git", - "url": "https://github.com/doctrine/lexer.git", - "reference": "83893c552fd2045dd78aef794c31e694c37c0b8c" + "url": "https://github.com/Codeception/Codeception.git", + "reference": "104f46fa0bde339f1bcc3a375aac21eb36e65a1e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/doctrine/lexer/zipball/83893c552fd2045dd78aef794c31e694c37c0b8c", - "reference": "83893c552fd2045dd78aef794c31e694c37c0b8c", + "url": "https://api.github.com/repos/Codeception/Codeception/zipball/104f46fa0bde339f1bcc3a375aac21eb36e65a1e", + "reference": "104f46fa0bde339f1bcc3a375aac21eb36e65a1e", "shasum": "" }, "require": { - "php": ">=5.3.2" + "behat/gherkin": "~4.4.0", + "codeception/stub": "^1.0", + "ext-json": "*", + "ext-mbstring": "*", + "facebook/webdriver": ">=1.1.3 <2.0", + "guzzlehttp/guzzle": ">=4.1.4 <7.0", + "guzzlehttp/psr7": "~1.0", + "php": ">=5.4.0 <8.0", + "phpunit/php-code-coverage": ">=2.2.4 <6.0", + "phpunit/phpunit": ">=4.8.28 <5.0.0 || >=5.6.3 <7.0", + "sebastian/comparator": ">1.1 <3.0", + "sebastian/diff": ">=1.4 <3.0", + "symfony/browser-kit": ">=2.7 <5.0", + "symfony/console": ">=2.7 <5.0", + "symfony/css-selector": ">=2.7 <5.0", + "symfony/dom-crawler": ">=2.7 <5.0", + "symfony/event-dispatcher": ">=2.7 <5.0", + "symfony/finder": ">=2.7 <5.0", + "symfony/yaml": ">=2.7 <5.0" + }, + "require-dev": { + "codeception/specify": "~0.3", + "facebook/graph-sdk": "~5.3", + "flow/jsonpath": "~0.2", + "monolog/monolog": "~1.8", + "pda/pheanstalk": "~3.0", + "php-amqplib/php-amqplib": "~2.4", + "predis/predis": "^1.0", + "squizlabs/php_codesniffer": "~2.0", + "symfony/process": ">=2.7 <5.0", + "vlucas/phpdotenv": "^2.4.0" + }, + "suggest": { + "aws/aws-sdk-php": "For using AWS Auth in REST module and Queue module", + "codeception/phpbuiltinserver": "Start and stop PHP built-in web server for your tests", + "codeception/specify": "BDD-style code blocks", + "codeception/verify": "BDD-style assertions", + "flow/jsonpath": "For using JSONPath in REST module", + "league/factory-muffin": "For DataFactory module", + "league/factory-muffin-faker": "For Faker support in DataFactory module", + "phpseclib/phpseclib": "for SFTP option in FTP Module", + "stecman/symfony-console-completion": "For BASH autocompletion", + "symfony/phpunit-bridge": "For phpunit-bridge support" }, + "bin": [ + "codecept" + ], "type": "library", "extra": { - "branch-alias": { - "dev-master": "1.0.x-dev" - } + "branch-alias": [] }, "autoload": { - "psr-0": { - "Doctrine\\Common\\Lexer\\": "lib/" + "psr-4": { + "Codeception\\": "src\\Codeception", + "Codeception\\Extension\\": "ext" } }, "notification-url": "https://packagist.org/downloads/", @@ -4645,49 +4674,817 @@ ], "authors": [ { - "name": "Roman Borschel", - "email": "roman@code-factory.org" - }, - { - "name": "Guilherme Blanco", - "email": "guilhermeblanco@gmail.com" - }, - { - "name": "Johannes Schmitt", - "email": "schmittjoh@gmail.com" + "name": "Michael Bodnarchuk", + "email": "davert@mail.ua", + "homepage": "http://codegyre.com" } ], - "description": "Base library for a lexer that can be used in Top-Down, Recursive Descent Parsers.", - "homepage": "http://www.doctrine-project.org", + "description": "BDD-style testing framework", + "homepage": "http://codeception.com/", "keywords": [ - "lexer", - "parser" + "BDD", + "TDD", + "acceptance testing", + "functional testing", + "unit testing" ], - "time": "2014-09-09T13:34:57+00:00" + "time": "2018-02-26T23:29:41+00:00" }, { - "name": "friendsofphp/php-cs-fixer", - "version": "v2.12.1", + "name": "codeception/stub", + "version": "1.0.4", "source": { "type": "git", - "url": "https://github.com/FriendsOfPHP/PHP-CS-Fixer.git", - "reference": "beef6cbe6dec7205edcd143842a49f9a691859a6" + "url": "https://github.com/Codeception/Stub.git", + "reference": "681b62348837a5ef07d10d8a226f5bc358cc8805" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/FriendsOfPHP/PHP-CS-Fixer/zipball/beef6cbe6dec7205edcd143842a49f9a691859a6", - "reference": "beef6cbe6dec7205edcd143842a49f9a691859a6", + "url": "https://api.github.com/repos/Codeception/Stub/zipball/681b62348837a5ef07d10d8a226f5bc358cc8805", + "reference": "681b62348837a5ef07d10d8a226f5bc358cc8805", "shasum": "" }, "require": { - "composer/semver": "^1.4", - "composer/xdebug-handler": "^1.0", - "doctrine/annotations": "^1.2", - "ext-json": "*", - "ext-tokenizer": "*", - "php": "^5.6 || >=7.0 <7.3", - "php-cs-fixer/diff": "^1.3", - "symfony/console": "^3.2 || ^4.0", + "phpunit/phpunit-mock-objects": ">2.3 <7.0" + }, + "require-dev": { + "phpunit/phpunit": ">=4.8 <8.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Codeception\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "Flexible Stub wrapper for PHPUnit's Mock Builder", + "time": "2018-05-17T09:31:08+00:00" + }, + { + "name": "consolidation/annotated-command", + "version": "2.8.4", + "source": { + "type": "git", + "url": "https://github.com/consolidation/annotated-command.git", + "reference": "651541a0b68318a2a202bda558a676e5ad92223c" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/consolidation/annotated-command/zipball/651541a0b68318a2a202bda558a676e5ad92223c", + "reference": "651541a0b68318a2a202bda558a676e5ad92223c", + "shasum": "" + }, + "require": { + "consolidation/output-formatters": "^3.1.12", + "php": ">=5.4.0", + "psr/log": "^1", + "symfony/console": "^2.8|^3|^4", + "symfony/event-dispatcher": "^2.5|^3|^4", + "symfony/finder": "^2.5|^3|^4" + }, + "require-dev": { + "g1a/composer-test-scenarios": "^2", + "phpunit/phpunit": "^6", + "satooshi/php-coveralls": "^2", + "squizlabs/php_codesniffer": "^2.7" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.x-dev" + } + }, + "autoload": { + "psr-4": { + "Consolidation\\AnnotatedCommand\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Greg Anderson", + "email": "greg.1.anderson@greenknowe.org" + } + ], + "description": "Initialize Symfony Console commands from annotated command class methods.", + "time": "2018-05-25T18:04:25+00:00" + }, + { + "name": "consolidation/config", + "version": "1.1.0", + "source": { + "type": "git", + "url": "https://github.com/consolidation/config.git", + "reference": "c9fc25e9088a708637e18a256321addc0670e578" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/consolidation/config/zipball/c9fc25e9088a708637e18a256321addc0670e578", + "reference": "c9fc25e9088a708637e18a256321addc0670e578", + "shasum": "" + }, + "require": { + "dflydev/dot-access-data": "^1.1.0", + "grasmash/expander": "^1", + "php": ">=5.4.0" + }, + "require-dev": { + "g1a/composer-test-scenarios": "^1", + "phpunit/phpunit": "^5", + "satooshi/php-coveralls": "^1.0", + "squizlabs/php_codesniffer": "2.*", + "symfony/console": "^2.5|^3|^4", + "symfony/yaml": "^2.8.11|^3|^4" + }, + "suggest": { + "symfony/yaml": "Required to use Consolidation\\Config\\Loader\\YamlConfigLoader" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.x-dev" + } + }, + "autoload": { + "psr-4": { + "Consolidation\\Config\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Greg Anderson", + "email": "greg.1.anderson@greenknowe.org" + } + ], + "description": "Provide configuration services for a commandline tool.", + "time": "2018-08-07T22:57:00+00:00" + }, + { + "name": "consolidation/log", + "version": "1.0.6", + "source": { + "type": "git", + "url": "https://github.com/consolidation/log.git", + "reference": "dfd8189a771fe047bf3cd669111b2de5f1c79395" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/consolidation/log/zipball/dfd8189a771fe047bf3cd669111b2de5f1c79395", + "reference": "dfd8189a771fe047bf3cd669111b2de5f1c79395", + "shasum": "" + }, + "require": { + "php": ">=5.5.0", + "psr/log": "~1.0", + "symfony/console": "^2.8|^3|^4" + }, + "require-dev": { + "g1a/composer-test-scenarios": "^1", + "phpunit/phpunit": "4.*", + "satooshi/php-coveralls": "^2", + "squizlabs/php_codesniffer": "2.*" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.x-dev" + } + }, + "autoload": { + "psr-4": { + "Consolidation\\Log\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Greg Anderson", + "email": "greg.1.anderson@greenknowe.org" + } + ], + "description": "Improved Psr-3 / Psr\\Log logger based on Symfony Console components.", + "time": "2018-05-25T18:14:39+00:00" + }, + { + "name": "consolidation/output-formatters", + "version": "3.2.1", + "source": { + "type": "git", + "url": "https://github.com/consolidation/output-formatters.git", + "reference": "d78ef59aea19d3e2e5a23f90a055155ee78a0ad5" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/consolidation/output-formatters/zipball/d78ef59aea19d3e2e5a23f90a055155ee78a0ad5", + "reference": "d78ef59aea19d3e2e5a23f90a055155ee78a0ad5", + "shasum": "" + }, + "require": { + "php": ">=5.4.0", + "symfony/console": "^2.8|^3|^4", + "symfony/finder": "^2.5|^3|^4" + }, + "require-dev": { + "g1a/composer-test-scenarios": "^2", + "phpunit/phpunit": "^5.7.27", + "satooshi/php-coveralls": "^2", + "squizlabs/php_codesniffer": "^2.7", + "symfony/console": "3.2.3", + "symfony/var-dumper": "^2.8|^3|^4", + "victorjonsson/markdowndocs": "^1.3" + }, + "suggest": { + "symfony/var-dumper": "For using the var_dump formatter" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.x-dev" + } + }, + "autoload": { + "psr-4": { + "Consolidation\\OutputFormatters\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Greg Anderson", + "email": "greg.1.anderson@greenknowe.org" + } + ], + "description": "Format text by applying transformations provided by plug-in formatters.", + "time": "2018-05-25T18:02:34+00:00" + }, + { + "name": "consolidation/robo", + "version": "1.3.0", + "source": { + "type": "git", + "url": "https://github.com/consolidation/Robo.git", + "reference": "ac563abfadf7cb7314b4e152f2b5033a6c255f6f" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/consolidation/Robo/zipball/ac563abfadf7cb7314b4e152f2b5033a6c255f6f", + "reference": "ac563abfadf7cb7314b4e152f2b5033a6c255f6f", + "shasum": "" + }, + "require": { + "consolidation/annotated-command": "^2.8.2", + "consolidation/config": "^1.0.10", + "consolidation/log": "~1", + "consolidation/output-formatters": "^3.1.13", + "grasmash/yaml-expander": "^1.3", + "league/container": "^2.2", + "php": ">=5.5.0", + "symfony/console": "^2.8|^3|^4", + "symfony/event-dispatcher": "^2.5|^3|^4", + "symfony/filesystem": "^2.5|^3|^4", + "symfony/finder": "^2.5|^3|^4", + "symfony/process": "^2.5|^3|^4" + }, + "replace": { + "codegyre/robo": "< 1.0" + }, + "require-dev": { + "codeception/aspect-mock": "^1|^2.1.1", + "codeception/base": "^2.3.7", + "codeception/verify": "^0.3.2", + "g1a/composer-test-scenarios": "^2", + "goaop/framework": "~2.1.2", + "goaop/parser-reflection": "^1.1.0", + "natxet/cssmin": "3.0.4", + "nikic/php-parser": "^3.1.5", + "patchwork/jsqueeze": "~2", + "pear/archive_tar": "^1.4.2", + "phpunit/php-code-coverage": "~2|~4", + "satooshi/php-coveralls": "^2", + "squizlabs/php_codesniffer": "^2.8" + }, + "suggest": { + "henrikbjorn/lurker": "For monitoring filesystem changes in taskWatch", + "natxet/CssMin": "For minifying CSS files in taskMinify", + "patchwork/jsqueeze": "For minifying JS files in taskMinify", + "pear/archive_tar": "Allows tar archives to be created and extracted in taskPack and taskExtract, respectively." + }, + "bin": [ + "robo" + ], + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.x-dev", + "dev-state": "1.x-dev" + } + }, + "autoload": { + "psr-4": { + "Robo\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Davert", + "email": "davert.php@resend.cc" + } + ], + "description": "Modern task runner", + "time": "2018-05-27T01:42:53+00:00" + }, + { + "name": "dflydev/dot-access-data", + "version": "v1.1.0", + "source": { + "type": "git", + "url": "https://github.com/dflydev/dflydev-dot-access-data.git", + "reference": "3fbd874921ab2c041e899d044585a2ab9795df8a" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/dflydev/dflydev-dot-access-data/zipball/3fbd874921ab2c041e899d044585a2ab9795df8a", + "reference": "3fbd874921ab2c041e899d044585a2ab9795df8a", + "shasum": "" + }, + "require": { + "php": ">=5.3.2" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0-dev" + } + }, + "autoload": { + "psr-0": { + "Dflydev\\DotAccessData": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Dragonfly Development Inc.", + "email": "info@dflydev.com", + "homepage": "http://dflydev.com" + }, + { + "name": "Beau Simensen", + "email": "beau@dflydev.com", + "homepage": "http://beausimensen.com" + }, + { + "name": "Carlos Frutos", + "email": "carlos@kiwing.it", + "homepage": "https://github.com/cfrutos" + } + ], + "description": "Given a deep data structure, access data by dot notation.", + "homepage": "https://github.com/dflydev/dflydev-dot-access-data", + "keywords": [ + "access", + "data", + "dot", + "notation" + ], + "time": "2017-01-20T21:14:22+00:00" + }, + { + "name": "doctrine/annotations", + "version": "v1.6.0", + "source": { + "type": "git", + "url": "https://github.com/doctrine/annotations.git", + "reference": "c7f2050c68a9ab0bdb0f98567ec08d80ea7d24d5" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/doctrine/annotations/zipball/c7f2050c68a9ab0bdb0f98567ec08d80ea7d24d5", + "reference": "c7f2050c68a9ab0bdb0f98567ec08d80ea7d24d5", + "shasum": "" + }, + "require": { + "doctrine/lexer": "1.*", + "php": "^7.1" + }, + "require-dev": { + "doctrine/cache": "1.*", + "phpunit/phpunit": "^6.4" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.6.x-dev" + } + }, + "autoload": { + "psr-4": { + "Doctrine\\Common\\Annotations\\": "lib/Doctrine/Common/Annotations" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Roman Borschel", + "email": "roman@code-factory.org" + }, + { + "name": "Benjamin Eberlei", + "email": "kontakt@beberlei.de" + }, + { + "name": "Guilherme Blanco", + "email": "guilhermeblanco@gmail.com" + }, + { + "name": "Jonathan Wage", + "email": "jonwage@gmail.com" + }, + { + "name": "Johannes Schmitt", + "email": "schmittjoh@gmail.com" + } + ], + "description": "Docblock Annotations Parser", + "homepage": "http://www.doctrine-project.org", + "keywords": [ + "annotations", + "docblock", + "parser" + ], + "time": "2017-12-06T07:11:42+00:00" + }, + { + "name": "doctrine/collections", + "version": "v1.5.0", + "source": { + "type": "git", + "url": "https://github.com/doctrine/collections.git", + "reference": "a01ee38fcd999f34d9bfbcee59dbda5105449cbf" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/doctrine/collections/zipball/a01ee38fcd999f34d9bfbcee59dbda5105449cbf", + "reference": "a01ee38fcd999f34d9bfbcee59dbda5105449cbf", + "shasum": "" + }, + "require": { + "php": "^7.1" + }, + "require-dev": { + "doctrine/coding-standard": "~0.1@dev", + "phpunit/phpunit": "^5.7" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.3.x-dev" + } + }, + "autoload": { + "psr-0": { + "Doctrine\\Common\\Collections\\": "lib/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Roman Borschel", + "email": "roman@code-factory.org" + }, + { + "name": "Benjamin Eberlei", + "email": "kontakt@beberlei.de" + }, + { + "name": "Guilherme Blanco", + "email": "guilhermeblanco@gmail.com" + }, + { + "name": "Jonathan Wage", + "email": "jonwage@gmail.com" + }, + { + "name": "Johannes Schmitt", + "email": "schmittjoh@gmail.com" + } + ], + "description": "Collections Abstraction library", + "homepage": "http://www.doctrine-project.org", + "keywords": [ + "array", + "collections", + "iterator" + ], + "time": "2017-07-22T10:37:32+00:00" + }, + { + "name": "doctrine/instantiator", + "version": "1.1.0", + "source": { + "type": "git", + "url": "https://github.com/doctrine/instantiator.git", + "reference": "185b8868aa9bf7159f5f953ed5afb2d7fcdc3bda" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/doctrine/instantiator/zipball/185b8868aa9bf7159f5f953ed5afb2d7fcdc3bda", + "reference": "185b8868aa9bf7159f5f953ed5afb2d7fcdc3bda", + "shasum": "" + }, + "require": { + "php": "^7.1" + }, + "require-dev": { + "athletic/athletic": "~0.1.8", + "ext-pdo": "*", + "ext-phar": "*", + "phpunit/phpunit": "^6.2.3", + "squizlabs/php_codesniffer": "^3.0.2" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.2.x-dev" + } + }, + "autoload": { + "psr-4": { + "Doctrine\\Instantiator\\": "src/Doctrine/Instantiator/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Marco Pivetta", + "email": "ocramius@gmail.com", + "homepage": "http://ocramius.github.com/" + } + ], + "description": "A small, lightweight utility to instantiate objects in PHP without invoking their constructors", + "homepage": "https://github.com/doctrine/instantiator", + "keywords": [ + "constructor", + "instantiate" + ], + "time": "2017-07-22T11:58:36+00:00" + }, + { + "name": "doctrine/lexer", + "version": "v1.0.1", + "source": { + "type": "git", + "url": "https://github.com/doctrine/lexer.git", + "reference": "83893c552fd2045dd78aef794c31e694c37c0b8c" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/doctrine/lexer/zipball/83893c552fd2045dd78aef794c31e694c37c0b8c", + "reference": "83893c552fd2045dd78aef794c31e694c37c0b8c", + "shasum": "" + }, + "require": { + "php": ">=5.3.2" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "psr-0": { + "Doctrine\\Common\\Lexer\\": "lib/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Roman Borschel", + "email": "roman@code-factory.org" + }, + { + "name": "Guilherme Blanco", + "email": "guilhermeblanco@gmail.com" + }, + { + "name": "Johannes Schmitt", + "email": "schmittjoh@gmail.com" + } + ], + "description": "Base library for a lexer that can be used in Top-Down, Recursive Descent Parsers.", + "homepage": "http://www.doctrine-project.org", + "keywords": [ + "lexer", + "parser" + ], + "time": "2014-09-09T13:34:57+00:00" + }, + { + "name": "epfremme/swagger-php", + "version": "v2.0.0", + "source": { + "type": "git", + "url": "https://github.com/epfremmer/swagger-php.git", + "reference": "eee28a442b7e6220391ec953d3c9b936354f23bc" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/epfremmer/swagger-php/zipball/eee28a442b7e6220391ec953d3c9b936354f23bc", + "reference": "eee28a442b7e6220391ec953d3c9b936354f23bc", + "shasum": "" + }, + "require": { + "doctrine/annotations": "^1.2", + "doctrine/collections": "^1.3", + "jms/serializer": "^1.1", + "php": ">=5.5", + "phpoption/phpoption": "^1.1", + "symfony/yaml": "^2.7|^3.1" + }, + "require-dev": { + "mockery/mockery": "^0.9.4", + "phpunit/phpunit": "~4.8|~5.0", + "satooshi/php-coveralls": "^1.0" + }, + "type": "package", + "autoload": { + "psr-4": { + "Epfremme\\Swagger\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Edward Pfremmer", + "email": "epfremme@nerdery.com" + } + ], + "description": "Library for parsing swagger documentation into PHP entities for use in testing and code generation", + "time": "2016-09-26T17:24:17+00:00" + }, + { + "name": "facebook/webdriver", + "version": "1.6.0", + "source": { + "type": "git", + "url": "https://github.com/facebook/php-webdriver.git", + "reference": "bd8c740097eb9f2fc3735250fc1912bc811a954e" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/facebook/php-webdriver/zipball/bd8c740097eb9f2fc3735250fc1912bc811a954e", + "reference": "bd8c740097eb9f2fc3735250fc1912bc811a954e", + "shasum": "" + }, + "require": { + "ext-curl": "*", + "ext-json": "*", + "ext-mbstring": "*", + "ext-zip": "*", + "php": "^5.6 || ~7.0", + "symfony/process": "^2.8 || ^3.1 || ^4.0" + }, + "require-dev": { + "friendsofphp/php-cs-fixer": "^2.0", + "jakub-onderka/php-parallel-lint": "^0.9.2", + "php-coveralls/php-coveralls": "^2.0", + "php-mock/php-mock-phpunit": "^1.1", + "phpunit/phpunit": "^5.7", + "sebastian/environment": "^1.3.4 || ^2.0 || ^3.0", + "squizlabs/php_codesniffer": "^2.6", + "symfony/var-dumper": "^3.3 || ^4.0" + }, + "suggest": { + "ext-SimpleXML": "For Firefox profile creation" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-community": "1.5-dev" + } + }, + "autoload": { + "psr-4": { + "Facebook\\WebDriver\\": "lib/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "Apache-2.0" + ], + "description": "A PHP client for Selenium WebDriver", + "homepage": "https://github.com/facebook/php-webdriver", + "keywords": [ + "facebook", + "php", + "selenium", + "webdriver" + ], + "time": "2018-05-16T17:37:13+00:00" + }, + { + "name": "flow/jsonpath", + "version": "0.4.0", + "source": { + "type": "git", + "url": "https://github.com/FlowCommunications/JSONPath.git", + "reference": "f0222818d5c938e4ab668ab2e2c079bd51a27112" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/FlowCommunications/JSONPath/zipball/f0222818d5c938e4ab668ab2e2c079bd51a27112", + "reference": "f0222818d5c938e4ab668ab2e2c079bd51a27112", + "shasum": "" + }, + "require": { + "php": ">=5.4.0" + }, + "require-dev": { + "peekmo/jsonpath": "dev-master", + "phpunit/phpunit": "^4.0" + }, + "type": "library", + "autoload": { + "psr-0": { + "Flow\\JSONPath": "src/", + "Flow\\JSONPath\\Test": "tests/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Stephen Frank", + "email": "stephen@flowsa.com" + } + ], + "description": "JSONPath implementation for parsing, searching and flattening arrays", + "time": "2018-03-04T16:39:47+00:00" + }, + { + "name": "friendsofphp/php-cs-fixer", + "version": "v2.12.2", + "source": { + "type": "git", + "url": "https://github.com/FriendsOfPHP/PHP-CS-Fixer.git", + "reference": "dcc87d5414e9d0bd316fce81a5bedb9ce720b183" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/FriendsOfPHP/PHP-CS-Fixer/zipball/dcc87d5414e9d0bd316fce81a5bedb9ce720b183", + "reference": "dcc87d5414e9d0bd316fce81a5bedb9ce720b183", + "shasum": "" + }, + "require": { + "composer/semver": "^1.4", + "composer/xdebug-handler": "^1.0", + "doctrine/annotations": "^1.2", + "ext-json": "*", + "ext-tokenizer": "*", + "php": "^5.6 || >=7.0 <7.3", + "php-cs-fixer/diff": "^1.3", + "symfony/console": "^3.2 || ^4.0", "symfony/event-dispatcher": "^3.0 || ^4.0", "symfony/filesystem": "^3.0 || ^4.0", "symfony/finder": "^3.0 || ^4.0", @@ -4698,46 +5495,534 @@ "symfony/stopwatch": "^3.0 || ^4.0" }, "conflict": { - "hhvm": "*" + "hhvm": "*" + }, + "require-dev": { + "johnkary/phpunit-speedtrap": "^1.1 || ^2.0 || ^3.0", + "justinrainbow/json-schema": "^5.0", + "keradus/cli-executor": "^1.1", + "mikey179/vfsstream": "^1.6", + "php-coveralls/php-coveralls": "^2.1", + "php-cs-fixer/accessible-object": "^1.0", + "php-cs-fixer/phpunit-constraint-isidenticalstring": "^1.0.1", + "php-cs-fixer/phpunit-constraint-xmlmatchesxsd": "^1.0.1", + "phpunit/phpunit": "^5.7.27 || ^6.5.8 || ^7.1", + "phpunitgoodpractices/traits": "^1.5.1", + "symfony/phpunit-bridge": "^4.0" + }, + "suggest": { + "ext-mbstring": "For handling non-UTF8 characters in cache signature.", + "php-cs-fixer/phpunit-constraint-isidenticalstring": "For IsIdenticalString constraint.", + "php-cs-fixer/phpunit-constraint-xmlmatchesxsd": "For XmlMatchesXsd constraint.", + "symfony/polyfill-mbstring": "When enabling `ext-mbstring` is not possible." + }, + "bin": [ + "php-cs-fixer" + ], + "type": "application", + "autoload": { + "psr-4": { + "PhpCsFixer\\": "src/" + }, + "classmap": [ + "tests/Test/AbstractFixerTestCase.php", + "tests/Test/AbstractIntegrationCaseFactory.php", + "tests/Test/AbstractIntegrationTestCase.php", + "tests/Test/Assert/AssertTokensTrait.php", + "tests/Test/IntegrationCase.php", + "tests/Test/IntegrationCaseFactory.php", + "tests/Test/IntegrationCaseFactoryInterface.php", + "tests/Test/InternalIntegrationCaseFactory.php", + "tests/TestCase.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Dariusz Rumiński", + "email": "dariusz.ruminski@gmail.com" + }, + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + } + ], + "description": "A tool to automatically fix PHP code style", + "time": "2018-07-06T10:37:40+00:00" + }, + { + "name": "fzaninotto/faker", + "version": "v1.8.0", + "source": { + "type": "git", + "url": "https://github.com/fzaninotto/Faker.git", + "reference": "f72816b43e74063c8b10357394b6bba8cb1c10de" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/fzaninotto/Faker/zipball/f72816b43e74063c8b10357394b6bba8cb1c10de", + "reference": "f72816b43e74063c8b10357394b6bba8cb1c10de", + "shasum": "" + }, + "require": { + "php": "^5.3.3 || ^7.0" + }, + "require-dev": { + "ext-intl": "*", + "phpunit/phpunit": "^4.8.35 || ^5.7", + "squizlabs/php_codesniffer": "^1.5" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.8-dev" + } + }, + "autoload": { + "psr-4": { + "Faker\\": "src/Faker/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "François Zaninotto" + } + ], + "description": "Faker is a PHP library that generates fake data for you.", + "keywords": [ + "data", + "faker", + "fixtures" + ], + "time": "2018-07-12T10:23:15+00:00" + }, + { + "name": "grasmash/expander", + "version": "1.0.0", + "source": { + "type": "git", + "url": "https://github.com/grasmash/expander.git", + "reference": "95d6037344a4be1dd5f8e0b0b2571a28c397578f" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/grasmash/expander/zipball/95d6037344a4be1dd5f8e0b0b2571a28c397578f", + "reference": "95d6037344a4be1dd5f8e0b0b2571a28c397578f", + "shasum": "" + }, + "require": { + "dflydev/dot-access-data": "^1.1.0", + "php": ">=5.4" + }, + "require-dev": { + "greg-1-anderson/composer-test-scenarios": "^1", + "phpunit/phpunit": "^4|^5.5.4", + "satooshi/php-coveralls": "^1.0.2|dev-master", + "squizlabs/php_codesniffer": "^2.7" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.x-dev" + } + }, + "autoload": { + "psr-4": { + "Grasmash\\Expander\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Matthew Grasmick" + } + ], + "description": "Expands internal property references in PHP arrays file.", + "time": "2017-12-21T22:14:55+00:00" + }, + { + "name": "grasmash/yaml-expander", + "version": "1.4.0", + "source": { + "type": "git", + "url": "https://github.com/grasmash/yaml-expander.git", + "reference": "3f0f6001ae707a24f4d9733958d77d92bf9693b1" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/grasmash/yaml-expander/zipball/3f0f6001ae707a24f4d9733958d77d92bf9693b1", + "reference": "3f0f6001ae707a24f4d9733958d77d92bf9693b1", + "shasum": "" + }, + "require": { + "dflydev/dot-access-data": "^1.1.0", + "php": ">=5.4", + "symfony/yaml": "^2.8.11|^3|^4" + }, + "require-dev": { + "greg-1-anderson/composer-test-scenarios": "^1", + "phpunit/phpunit": "^4.8|^5.5.4", + "satooshi/php-coveralls": "^1.0.2|dev-master", + "squizlabs/php_codesniffer": "^2.7" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.x-dev" + } + }, + "autoload": { + "psr-4": { + "Grasmash\\YamlExpander\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Matthew Grasmick" + } + ], + "description": "Expands internal property references in a yaml file.", + "time": "2017-12-16T16:06:03+00:00" + }, + { + "name": "guzzlehttp/guzzle", + "version": "6.3.3", + "source": { + "type": "git", + "url": "https://github.com/guzzle/guzzle.git", + "reference": "407b0cb880ace85c9b63c5f9551db498cb2d50ba" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/guzzle/guzzle/zipball/407b0cb880ace85c9b63c5f9551db498cb2d50ba", + "reference": "407b0cb880ace85c9b63c5f9551db498cb2d50ba", + "shasum": "" + }, + "require": { + "guzzlehttp/promises": "^1.0", + "guzzlehttp/psr7": "^1.4", + "php": ">=5.5" + }, + "require-dev": { + "ext-curl": "*", + "phpunit/phpunit": "^4.8.35 || ^5.7 || ^6.4 || ^7.0", + "psr/log": "^1.0" + }, + "suggest": { + "psr/log": "Required for using the Log middleware" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "6.3-dev" + } + }, + "autoload": { + "files": [ + "src/functions_include.php" + ], + "psr-4": { + "GuzzleHttp\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Michael Dowling", + "email": "mtdowling@gmail.com", + "homepage": "https://github.com/mtdowling" + } + ], + "description": "Guzzle is a PHP HTTP client library", + "homepage": "http://guzzlephp.org/", + "keywords": [ + "client", + "curl", + "framework", + "http", + "http client", + "rest", + "web service" + ], + "time": "2018-04-22T15:46:56+00:00" + }, + { + "name": "guzzlehttp/promises", + "version": "v1.3.1", + "source": { + "type": "git", + "url": "https://github.com/guzzle/promises.git", + "reference": "a59da6cf61d80060647ff4d3eb2c03a2bc694646" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/guzzle/promises/zipball/a59da6cf61d80060647ff4d3eb2c03a2bc694646", + "reference": "a59da6cf61d80060647ff4d3eb2c03a2bc694646", + "shasum": "" + }, + "require": { + "php": ">=5.5.0" + }, + "require-dev": { + "phpunit/phpunit": "^4.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.4-dev" + } + }, + "autoload": { + "psr-4": { + "GuzzleHttp\\Promise\\": "src/" + }, + "files": [ + "src/functions_include.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Michael Dowling", + "email": "mtdowling@gmail.com", + "homepage": "https://github.com/mtdowling" + } + ], + "description": "Guzzle promises library", + "keywords": [ + "promise" + ], + "time": "2016-12-20T10:07:11+00:00" + }, + { + "name": "guzzlehttp/psr7", + "version": "1.4.2", + "source": { + "type": "git", + "url": "https://github.com/guzzle/psr7.git", + "reference": "f5b8a8512e2b58b0071a7280e39f14f72e05d87c" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/guzzle/psr7/zipball/f5b8a8512e2b58b0071a7280e39f14f72e05d87c", + "reference": "f5b8a8512e2b58b0071a7280e39f14f72e05d87c", + "shasum": "" + }, + "require": { + "php": ">=5.4.0", + "psr/http-message": "~1.0" + }, + "provide": { + "psr/http-message-implementation": "1.0" + }, + "require-dev": { + "phpunit/phpunit": "~4.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.4-dev" + } + }, + "autoload": { + "psr-4": { + "GuzzleHttp\\Psr7\\": "src/" + }, + "files": [ + "src/functions_include.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Michael Dowling", + "email": "mtdowling@gmail.com", + "homepage": "https://github.com/mtdowling" + }, + { + "name": "Tobias Schultze", + "homepage": "https://github.com/Tobion" + } + ], + "description": "PSR-7 message implementation that also provides common utility methods", + "keywords": [ + "http", + "message", + "request", + "response", + "stream", + "uri", + "url" + ], + "time": "2017-03-20T17:10:46+00:00" + }, + { + "name": "jms/metadata", + "version": "1.6.0", + "source": { + "type": "git", + "url": "https://github.com/schmittjoh/metadata.git", + "reference": "6a06970a10e0a532fb52d3959547123b84a3b3ab" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/schmittjoh/metadata/zipball/6a06970a10e0a532fb52d3959547123b84a3b3ab", + "reference": "6a06970a10e0a532fb52d3959547123b84a3b3ab", + "shasum": "" + }, + "require": { + "php": ">=5.3.0" + }, + "require-dev": { + "doctrine/cache": "~1.0", + "symfony/cache": "~3.1" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.5.x-dev" + } + }, + "autoload": { + "psr-0": { + "Metadata\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "Apache-2.0" + ], + "authors": [ + { + "name": "Johannes M. Schmitt", + "email": "schmittjoh@gmail.com" + } + ], + "description": "Class/method/property metadata management in PHP", + "keywords": [ + "annotations", + "metadata", + "xml", + "yaml" + ], + "time": "2016-12-05T10:18:33+00:00" + }, + { + "name": "jms/parser-lib", + "version": "1.0.0", + "source": { + "type": "git", + "url": "https://github.com/schmittjoh/parser-lib.git", + "reference": "c509473bc1b4866415627af0e1c6cc8ac97fa51d" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/schmittjoh/parser-lib/zipball/c509473bc1b4866415627af0e1c6cc8ac97fa51d", + "reference": "c509473bc1b4866415627af0e1c6cc8ac97fa51d", + "shasum": "" + }, + "require": { + "phpoption/phpoption": ">=0.9,<2.0-dev" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0-dev" + } + }, + "autoload": { + "psr-0": { + "JMS\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "Apache2" + ], + "description": "A library for easily creating recursive-descent parsers.", + "time": "2012-11-18T18:08:43+00:00" + }, + { + "name": "jms/serializer", + "version": "1.13.0", + "source": { + "type": "git", + "url": "https://github.com/schmittjoh/serializer.git", + "reference": "00863e1d55b411cc33ad3e1de09a4c8d3aae793c" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/schmittjoh/serializer/zipball/00863e1d55b411cc33ad3e1de09a4c8d3aae793c", + "reference": "00863e1d55b411cc33ad3e1de09a4c8d3aae793c", + "shasum": "" + }, + "require": { + "doctrine/annotations": "^1.0", + "doctrine/instantiator": "^1.0.3", + "jms/metadata": "^1.3", + "jms/parser-lib": "1.*", + "php": "^5.5|^7.0", + "phpcollection/phpcollection": "~0.1", + "phpoption/phpoption": "^1.1" + }, + "conflict": { + "twig/twig": "<1.12" }, "require-dev": { - "johnkary/phpunit-speedtrap": "^1.1 || ^2.0 || ^3.0", - "justinrainbow/json-schema": "^5.0", - "keradus/cli-executor": "^1.1", - "mikey179/vfsstream": "^1.6", - "php-coveralls/php-coveralls": "^2.1", - "php-cs-fixer/accessible-object": "^1.0", - "php-cs-fixer/phpunit-constraint-isidenticalstring": "^1.0.1", - "php-cs-fixer/phpunit-constraint-xmlmatchesxsd": "^1.0.1", - "phpunit/phpunit": "^5.7.27 || ^6.5.8 || ^7.1", - "phpunitgoodpractices/traits": "^1.5", - "symfony/phpunit-bridge": "^4.0" + "doctrine/orm": "~2.1", + "doctrine/phpcr-odm": "^1.3|^2.0", + "ext-pdo_sqlite": "*", + "jackalope/jackalope-doctrine-dbal": "^1.1.5", + "phpunit/phpunit": "^4.8|^5.0", + "propel/propel1": "~1.7", + "psr/container": "^1.0", + "symfony/dependency-injection": "^2.7|^3.3|^4.0", + "symfony/expression-language": "^2.6|^3.0", + "symfony/filesystem": "^2.1", + "symfony/form": "~2.1|^3.0", + "symfony/translation": "^2.1|^3.0", + "symfony/validator": "^2.2|^3.0", + "symfony/yaml": "^2.1|^3.0", + "twig/twig": "~1.12|~2.0" }, "suggest": { - "ext-mbstring": "For handling non-UTF8 characters in cache signature.", - "php-cs-fixer/phpunit-constraint-isidenticalstring": "For IsIdenticalString constraint.", - "php-cs-fixer/phpunit-constraint-xmlmatchesxsd": "For XmlMatchesXsd constraint.", - "symfony/polyfill-mbstring": "When enabling `ext-mbstring` is not possible." + "doctrine/cache": "Required if you like to use cache functionality.", + "doctrine/collections": "Required if you like to use doctrine collection types as ArrayCollection.", + "symfony/yaml": "Required if you'd like to serialize data to YAML format." + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-1.x": "1.13-dev" + } }, - "bin": [ - "php-cs-fixer" - ], - "type": "application", "autoload": { - "psr-4": { - "PhpCsFixer\\": "src/" - }, - "classmap": [ - "tests/Test/AbstractFixerTestCase.php", - "tests/Test/AbstractIntegrationCaseFactory.php", - "tests/Test/AbstractIntegrationTestCase.php", - "tests/Test/Assert/AssertTokensTrait.php", - "tests/Test/IntegrationCase.php", - "tests/Test/IntegrationCaseFactory.php", - "tests/Test/IntegrationCaseFactoryInterface.php", - "tests/Test/InternalIntegrationCaseFactory.php", - "tests/TestCase.php" - ] + "psr-0": { + "JMS\\Serializer": "src/" + } }, "notification-url": "https://packagist.org/downloads/", "license": [ @@ -4745,16 +6030,89 @@ ], "authors": [ { - "name": "Dariusz Rumiński", - "email": "dariusz.ruminski@gmail.com" + "name": "Asmir Mustafic", + "email": "goetas@gmail.com" }, { - "name": "Fabien Potencier", - "email": "fabien@symfony.com" + "name": "Johannes M. Schmitt", + "email": "schmittjoh@gmail.com" } ], - "description": "A tool to automatically fix PHP code style", - "time": "2018-06-10T08:26:56+00:00" + "description": "Library for (de-)serializing data of any complexity; supports XML, JSON, and YAML.", + "homepage": "http://jmsyst.com/libs/serializer", + "keywords": [ + "deserialization", + "jaxb", + "json", + "serialization", + "xml" + ], + "time": "2018-07-25T13:58:54+00:00" + }, + { + "name": "league/container", + "version": "2.4.1", + "source": { + "type": "git", + "url": "https://github.com/thephpleague/container.git", + "reference": "43f35abd03a12977a60ffd7095efd6a7808488c0" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/thephpleague/container/zipball/43f35abd03a12977a60ffd7095efd6a7808488c0", + "reference": "43f35abd03a12977a60ffd7095efd6a7808488c0", + "shasum": "" + }, + "require": { + "container-interop/container-interop": "^1.2", + "php": "^5.4.0 || ^7.0" + }, + "provide": { + "container-interop/container-interop-implementation": "^1.2", + "psr/container-implementation": "^1.0" + }, + "replace": { + "orno/di": "~2.0" + }, + "require-dev": { + "phpunit/phpunit": "4.*" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-2.x": "2.x-dev", + "dev-1.x": "1.x-dev" + } + }, + "autoload": { + "psr-4": { + "League\\Container\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Phil Bennett", + "email": "philipobenito@gmail.com", + "homepage": "http://www.philipobenito.com", + "role": "Developer" + } + ], + "description": "A fast and intuitive dependency injection container.", + "homepage": "https://github.com/thephpleague/container", + "keywords": [ + "container", + "dependency", + "di", + "injection", + "league", + "provider", + "service" + ], + "time": "2017-05-10T09:20:27+00:00" }, { "name": "lusitanian/oauth", @@ -4823,6 +6181,172 @@ ], "time": "2018-02-14T22:37:14+00:00" }, + { + "name": "magento/magento2-functional-testing-framework", + "version": "2.3.4", + "source": { + "type": "git", + "url": "https://github.com/magento/magento2-functional-testing-framework.git", + "reference": "ac56e5a6520dd580658034ae53d3724985c2a901" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/magento/magento2-functional-testing-framework/zipball/ac56e5a6520dd580658034ae53d3724985c2a901", + "reference": "ac56e5a6520dd580658034ae53d3724985c2a901", + "shasum": "" + }, + "require": { + "allure-framework/allure-codeception": "~1.2.6", + "codeception/codeception": "~2.3.4", + "consolidation/robo": "^1.0.0", + "epfremme/swagger-php": "^2.0", + "flow/jsonpath": ">0.2", + "fzaninotto/faker": "^1.6", + "monolog/monolog": "^1.0", + "mustache/mustache": "~2.5", + "php": "7.0.2|7.0.4|~7.0.6|~7.1.0|~7.2.0", + "symfony/process": "^2.8 || ^3.1 || ^4.0", + "vlucas/phpdotenv": "^2.4" + }, + "require-dev": { + "brainmaestro/composer-git-hooks": "^2.3", + "codacy/coverage": "^1.4", + "codeception/aspect-mock": "^3.0", + "doctrine/cache": "<1.7.0", + "goaop/framework": "2.2.0", + "php-coveralls/php-coveralls": "^1.0", + "phpmd/phpmd": "^2.6.0", + "rregeer/phpunit-coverage-check": "^0.1.4", + "sebastian/phpcpd": "~3.0 || ~4.0", + "squizlabs/php_codesniffer": "~3.2", + "symfony/stopwatch": "~3.4.6" + }, + "bin": [ + "bin/mftf" + ], + "type": "library", + "extra": { + "hooks": { + "pre-push": "bin/all-checks" + } + }, + "autoload": { + "files": [ + "src/Magento/FunctionalTestingFramework/_bootstrap.php" + ], + "psr-4": { + "Magento\\FunctionalTestingFramework\\": "src/Magento/FunctionalTestingFramework", + "MFTF\\": "dev/tests/functional/MFTF" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "AGPL-3.0" + ], + "description": "Magento2 Functional Testing Framework", + "keywords": [ + "automation", + "functional", + "magento", + "testing" + ], + "time": "2018-08-10T20:16:42+00:00" + }, + { + "name": "moontoast/math", + "version": "1.1.2", + "source": { + "type": "git", + "url": "https://github.com/ramsey/moontoast-math.git", + "reference": "c2792a25df5cad4ff3d760dd37078fc5b6fccc79" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/ramsey/moontoast-math/zipball/c2792a25df5cad4ff3d760dd37078fc5b6fccc79", + "reference": "c2792a25df5cad4ff3d760dd37078fc5b6fccc79", + "shasum": "" + }, + "require": { + "ext-bcmath": "*", + "php": ">=5.3.3" + }, + "require-dev": { + "jakub-onderka/php-parallel-lint": "^0.9.0", + "phpunit/phpunit": "^4.7|>=5.0 <5.4", + "satooshi/php-coveralls": "^0.6.1", + "squizlabs/php_codesniffer": "^2.3" + }, + "type": "library", + "autoload": { + "psr-4": { + "Moontoast\\Math\\": "src/Moontoast/Math/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "Apache-2.0" + ], + "authors": [ + { + "name": "Ben Ramsey", + "email": "ben@benramsey.com", + "homepage": "https://benramsey.com" + } + ], + "description": "A mathematics library, providing functionality for large numbers", + "homepage": "https://github.com/ramsey/moontoast-math", + "keywords": [ + "bcmath", + "math" + ], + "time": "2017-02-16T16:54:46+00:00" + }, + { + "name": "mustache/mustache", + "version": "v2.12.0", + "source": { + "type": "git", + "url": "https://github.com/bobthecow/mustache.php.git", + "reference": "fe8fe72e9d580591854de404cc59a1b83ca4d19e" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/bobthecow/mustache.php/zipball/fe8fe72e9d580591854de404cc59a1b83ca4d19e", + "reference": "fe8fe72e9d580591854de404cc59a1b83ca4d19e", + "shasum": "" + }, + "require": { + "php": ">=5.2.4" + }, + "require-dev": { + "friendsofphp/php-cs-fixer": "~1.11", + "phpunit/phpunit": "~3.7|~4.0|~5.0" + }, + "type": "library", + "autoload": { + "psr-0": { + "Mustache": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Justin Hileman", + "email": "justin@justinhileman.info", + "homepage": "http://justinhileman.com" + } + ], + "description": "A Mustache implementation in PHP.", + "homepage": "https://github.com/bobthecow/mustache.php", + "keywords": [ + "mustache", + "templating" + ], + "time": "2017-07-11T12:54:05+00:00" + }, { "name": "myclabs/deep-copy", "version": "1.8.1", @@ -5064,6 +6588,54 @@ ], "time": "2018-02-15T16:58:55+00:00" }, + { + "name": "phpcollection/phpcollection", + "version": "0.5.0", + "source": { + "type": "git", + "url": "https://github.com/schmittjoh/php-collection.git", + "reference": "f2bcff45c0da7c27991bbc1f90f47c4b7fb434a6" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/schmittjoh/php-collection/zipball/f2bcff45c0da7c27991bbc1f90f47c4b7fb434a6", + "reference": "f2bcff45c0da7c27991bbc1f90f47c4b7fb434a6", + "shasum": "" + }, + "require": { + "phpoption/phpoption": "1.*" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "0.4-dev" + } + }, + "autoload": { + "psr-0": { + "PhpCollection": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "Apache2" + ], + "authors": [ + { + "name": "Johannes M. Schmitt", + "email": "schmittjoh@gmail.com" + } + ], + "description": "General-Purpose Collection Library for PHP", + "keywords": [ + "collection", + "list", + "map", + "sequence", + "set" + ], + "time": "2015-05-17T12:39:23+00:00" + }, { "name": "phpdocumentor/reflection-common", "version": "1.0.1", @@ -5282,18 +6854,68 @@ ], "time": "2017-01-20T14:41:10+00:00" }, + { + "name": "phpoption/phpoption", + "version": "1.5.0", + "source": { + "type": "git", + "url": "https://github.com/schmittjoh/php-option.git", + "reference": "94e644f7d2051a5f0fcf77d81605f152eecff0ed" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/schmittjoh/php-option/zipball/94e644f7d2051a5f0fcf77d81605f152eecff0ed", + "reference": "94e644f7d2051a5f0fcf77d81605f152eecff0ed", + "shasum": "" + }, + "require": { + "php": ">=5.3.0" + }, + "require-dev": { + "phpunit/phpunit": "4.7.*" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.3-dev" + } + }, + "autoload": { + "psr-0": { + "PhpOption\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "Apache2" + ], + "authors": [ + { + "name": "Johannes M. Schmitt", + "email": "schmittjoh@gmail.com" + } + ], + "description": "Option Type for PHP", + "keywords": [ + "language", + "option", + "php", + "type" + ], + "time": "2015-07-25T16:39:46+00:00" + }, { "name": "phpspec/prophecy", - "version": "1.7.6", + "version": "1.8.0", "source": { "type": "git", "url": "https://github.com/phpspec/prophecy.git", - "reference": "33a7e3c4fda54e912ff6338c48823bd5c0f0b712" + "reference": "4ba436b55987b4bf311cb7c6ba82aa528aac0a06" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpspec/prophecy/zipball/33a7e3c4fda54e912ff6338c48823bd5c0f0b712", - "reference": "33a7e3c4fda54e912ff6338c48823bd5c0f0b712", + "url": "https://api.github.com/repos/phpspec/prophecy/zipball/4ba436b55987b4bf311cb7c6ba82aa528aac0a06", + "reference": "4ba436b55987b4bf311cb7c6ba82aa528aac0a06", "shasum": "" }, "require": { @@ -5305,12 +6927,12 @@ }, "require-dev": { "phpspec/phpspec": "^2.5|^3.2", - "phpunit/phpunit": "^4.8.35 || ^5.7 || ^6.5" + "phpunit/phpunit": "^4.8.35 || ^5.7 || ^6.5 || ^7.1" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "1.7.x-dev" + "dev-master": "1.8.x-dev" } }, "autoload": { @@ -5343,7 +6965,7 @@ "spy", "stub" ], - "time": "2018-04-18T13:57:24+00:00" + "time": "2018-08-05T17:53:17+00:00" }, { "name": "phpunit/php-code-coverage", @@ -5596,16 +7218,16 @@ }, { "name": "phpunit/phpunit", - "version": "6.5.8", + "version": "6.5.11", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/phpunit.git", - "reference": "4f21a3c6b97c42952fd5c2837bb354ec0199b97b" + "reference": "7bab54cb366076023bbf457a2a0d513332cd40f2" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/4f21a3c6b97c42952fd5c2837bb354ec0199b97b", - "reference": "4f21a3c6b97c42952fd5c2837bb354ec0199b97b", + "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/7bab54cb366076023bbf457a2a0d513332cd40f2", + "reference": "7bab54cb366076023bbf457a2a0d513332cd40f2", "shasum": "" }, "require": { @@ -5623,7 +7245,7 @@ "phpunit/php-file-iterator": "^1.4.3", "phpunit/php-text-template": "^1.2.1", "phpunit/php-timer": "^1.0.9", - "phpunit/phpunit-mock-objects": "^5.0.5", + "phpunit/phpunit-mock-objects": "^5.0.9", "sebastian/comparator": "^2.1", "sebastian/diff": "^2.0", "sebastian/environment": "^3.1", @@ -5676,20 +7298,20 @@ "testing", "xunit" ], - "time": "2018-04-10T11:38:34+00:00" + "time": "2018-08-07T07:05:35+00:00" }, { "name": "phpunit/phpunit-mock-objects", - "version": "5.0.7", + "version": "5.0.10", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/phpunit-mock-objects.git", - "reference": "3eaf040f20154d27d6da59ca2c6e28ac8fd56dce" + "reference": "cd1cf05c553ecfec36b170070573e540b67d3f1f" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/phpunit-mock-objects/zipball/3eaf040f20154d27d6da59ca2c6e28ac8fd56dce", - "reference": "3eaf040f20154d27d6da59ca2c6e28ac8fd56dce", + "url": "https://api.github.com/repos/sebastianbergmann/phpunit-mock-objects/zipball/cd1cf05c553ecfec36b170070573e540b67d3f1f", + "reference": "cd1cf05c553ecfec36b170070573e540b67d3f1f", "shasum": "" }, "require": { @@ -5702,7 +7324,7 @@ "phpunit/phpunit": "<6.0" }, "require-dev": { - "phpunit/phpunit": "^6.5" + "phpunit/phpunit": "^6.5.11" }, "suggest": { "ext-soap": "*" @@ -5735,7 +7357,7 @@ "mock", "xunit" ], - "time": "2018-05-29T13:50:43+00:00" + "time": "2018-08-09T05:50:03+00:00" }, { "name": "sebastian/code-unit-reverse-lookup", @@ -6314,158 +7936,396 @@ "reference": "ce990bb21759f94aeafd30209e8cfcdfa8bc3f52", "shasum": "" }, - "require": { - "php": ">=5.6.0" + "require": { + "php": ">=5.6.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + } + ], + "description": "Provides a list of PHP built-in functions that operate on resources", + "homepage": "https://www.github.com/sebastianbergmann/resource-operations", + "time": "2015-07-28T20:34:47+00:00" + }, + { + "name": "sebastian/version", + "version": "2.0.1", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/version.git", + "reference": "99732be0ddb3361e16ad77b68ba41efc8e979019" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/version/zipball/99732be0ddb3361e16ad77b68ba41efc8e979019", + "reference": "99732be0ddb3361e16ad77b68ba41efc8e979019", + "shasum": "" + }, + "require": { + "php": ">=5.6" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.0.x-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Library that helps with managing the version number of Git-hosted PHP projects", + "homepage": "https://github.com/sebastianbergmann/version", + "time": "2016-10-03T07:35:21+00:00" + }, + { + "name": "squizlabs/php_codesniffer", + "version": "3.3.0", + "source": { + "type": "git", + "url": "https://github.com/squizlabs/PHP_CodeSniffer.git", + "reference": "d86873af43b4aa9d1f39a3601cc0cfcf02b25266" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/squizlabs/PHP_CodeSniffer/zipball/d86873af43b4aa9d1f39a3601cc0cfcf02b25266", + "reference": "d86873af43b4aa9d1f39a3601cc0cfcf02b25266", + "shasum": "" + }, + "require": { + "ext-simplexml": "*", + "ext-tokenizer": "*", + "ext-xmlwriter": "*", + "php": ">=5.4.0" + }, + "require-dev": { + "phpunit/phpunit": "^4.0 || ^5.0 || ^6.0 || ^7.0" + }, + "bin": [ + "bin/phpcs", + "bin/phpcbf" + ], + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.x-dev" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Greg Sherwood", + "role": "lead" + } + ], + "description": "PHP_CodeSniffer tokenizes PHP, JavaScript and CSS files and detects violations of a defined set of coding standards.", + "homepage": "http://www.squizlabs.com/php-codesniffer", + "keywords": [ + "phpcs", + "standards" + ], + "time": "2018-06-06T23:58:19+00:00" + }, + { + "name": "symfony/browser-kit", + "version": "v4.1.3", + "source": { + "type": "git", + "url": "https://github.com/symfony/browser-kit.git", + "reference": "c55fe9257003b2d95c0211b3f6941e8dfd26dffd" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/browser-kit/zipball/c55fe9257003b2d95c0211b3f6941e8dfd26dffd", + "reference": "c55fe9257003b2d95c0211b3f6941e8dfd26dffd", + "shasum": "" + }, + "require": { + "php": "^7.1.3", + "symfony/dom-crawler": "~3.4|~4.0" + }, + "require-dev": { + "symfony/css-selector": "~3.4|~4.0", + "symfony/process": "~3.4|~4.0" + }, + "suggest": { + "symfony/process": "" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "4.1-dev" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Component\\BrowserKit\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony BrowserKit Component", + "homepage": "https://symfony.com", + "time": "2018-07-26T09:10:45+00:00" + }, + { + "name": "symfony/config", + "version": "v4.1.3", + "source": { + "type": "git", + "url": "https://github.com/symfony/config.git", + "reference": "c868972ac26e4e19860ce11b300bb74145246ff9" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/config/zipball/c868972ac26e4e19860ce11b300bb74145246ff9", + "reference": "c868972ac26e4e19860ce11b300bb74145246ff9", + "shasum": "" + }, + "require": { + "php": "^7.1.3", + "symfony/filesystem": "~3.4|~4.0", + "symfony/polyfill-ctype": "~1.8" + }, + "conflict": { + "symfony/finder": "<3.4" + }, + "require-dev": { + "symfony/dependency-injection": "~3.4|~4.0", + "symfony/event-dispatcher": "~3.4|~4.0", + "symfony/finder": "~3.4|~4.0", + "symfony/yaml": "~3.4|~4.0" + }, + "suggest": { + "symfony/yaml": "To use the yaml reference dumper" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "1.0.x-dev" + "dev-master": "4.1-dev" } }, "autoload": { - "classmap": [ - "src/" + "psr-4": { + "Symfony\\Component\\Config\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" ] }, "notification-url": "https://packagist.org/downloads/", "license": [ - "BSD-3-Clause" + "MIT" ], "authors": [ { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de" + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" } ], - "description": "Provides a list of PHP built-in functions that operate on resources", - "homepage": "https://www.github.com/sebastianbergmann/resource-operations", - "time": "2015-07-28T20:34:47+00:00" + "description": "Symfony Config Component", + "homepage": "https://symfony.com", + "time": "2018-07-26T11:24:31+00:00" }, { - "name": "sebastian/version", - "version": "2.0.1", + "name": "symfony/css-selector", + "version": "v4.1.3", "source": { "type": "git", - "url": "https://github.com/sebastianbergmann/version.git", - "reference": "99732be0ddb3361e16ad77b68ba41efc8e979019" + "url": "https://github.com/symfony/css-selector.git", + "reference": "2a4df7618f869b456f9096781e78c57b509d76c7" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/version/zipball/99732be0ddb3361e16ad77b68ba41efc8e979019", - "reference": "99732be0ddb3361e16ad77b68ba41efc8e979019", + "url": "https://api.github.com/repos/symfony/css-selector/zipball/2a4df7618f869b456f9096781e78c57b509d76c7", + "reference": "2a4df7618f869b456f9096781e78c57b509d76c7", "shasum": "" }, "require": { - "php": ">=5.6" + "php": "^7.1.3" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "2.0.x-dev" + "dev-master": "4.1-dev" } }, "autoload": { - "classmap": [ - "src/" + "psr-4": { + "Symfony\\Component\\CssSelector\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" ] }, "notification-url": "https://packagist.org/downloads/", "license": [ - "BSD-3-Clause" + "MIT" ], "authors": [ { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de", - "role": "lead" + "name": "Jean-François Simon", + "email": "jeanfrancois.simon@sensiolabs.com" + }, + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" } ], - "description": "Library that helps with managing the version number of Git-hosted PHP projects", - "homepage": "https://github.com/sebastianbergmann/version", - "time": "2016-10-03T07:35:21+00:00" + "description": "Symfony CssSelector Component", + "homepage": "https://symfony.com", + "time": "2018-07-26T09:10:45+00:00" }, { - "name": "squizlabs/php_codesniffer", - "version": "3.3.0", + "name": "symfony/dependency-injection", + "version": "v4.1.3", "source": { "type": "git", - "url": "https://github.com/squizlabs/PHP_CodeSniffer.git", - "reference": "d86873af43b4aa9d1f39a3601cc0cfcf02b25266" + "url": "https://github.com/symfony/dependency-injection.git", + "reference": "f4f401fc2766eb8d766fc6043d9e6489b37a41e4" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/squizlabs/PHP_CodeSniffer/zipball/d86873af43b4aa9d1f39a3601cc0cfcf02b25266", - "reference": "d86873af43b4aa9d1f39a3601cc0cfcf02b25266", + "url": "https://api.github.com/repos/symfony/dependency-injection/zipball/f4f401fc2766eb8d766fc6043d9e6489b37a41e4", + "reference": "f4f401fc2766eb8d766fc6043d9e6489b37a41e4", "shasum": "" }, "require": { - "ext-simplexml": "*", - "ext-tokenizer": "*", - "ext-xmlwriter": "*", - "php": ">=5.4.0" + "php": "^7.1.3", + "psr/container": "^1.0" + }, + "conflict": { + "symfony/config": "<4.1.1", + "symfony/finder": "<3.4", + "symfony/proxy-manager-bridge": "<3.4", + "symfony/yaml": "<3.4" + }, + "provide": { + "psr/container-implementation": "1.0" }, "require-dev": { - "phpunit/phpunit": "^4.0 || ^5.0 || ^6.0 || ^7.0" + "symfony/config": "~4.1", + "symfony/expression-language": "~3.4|~4.0", + "symfony/yaml": "~3.4|~4.0" + }, + "suggest": { + "symfony/config": "", + "symfony/expression-language": "For using expressions in service container configuration", + "symfony/finder": "For using double-star glob patterns or when GLOB_BRACE portability is required", + "symfony/proxy-manager-bridge": "Generate service proxies to lazy load them", + "symfony/yaml": "" }, - "bin": [ - "bin/phpcs", - "bin/phpcbf" - ], "type": "library", "extra": { "branch-alias": { - "dev-master": "3.x-dev" + "dev-master": "4.1-dev" } }, + "autoload": { + "psr-4": { + "Symfony\\Component\\DependencyInjection\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, "notification-url": "https://packagist.org/downloads/", "license": [ - "BSD-3-Clause" + "MIT" ], "authors": [ { - "name": "Greg Sherwood", - "role": "lead" + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" } ], - "description": "PHP_CodeSniffer tokenizes PHP, JavaScript and CSS files and detects violations of a defined set of coding standards.", - "homepage": "http://www.squizlabs.com/php-codesniffer", - "keywords": [ - "phpcs", - "standards" - ], - "time": "2018-06-06T23:58:19+00:00" + "description": "Symfony DependencyInjection Component", + "homepage": "https://symfony.com", + "time": "2018-08-01T08:24:03+00:00" }, { - "name": "symfony/config", - "version": "v4.1.1", + "name": "symfony/dom-crawler", + "version": "v4.1.3", "source": { "type": "git", - "url": "https://github.com/symfony/config.git", - "reference": "e57e7b573df9d0eaa8c0152768c708ee7ea2b8e5" + "url": "https://github.com/symfony/dom-crawler.git", + "reference": "1c4519d257e652404c3aa550207ccd8ada66b38e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/config/zipball/e57e7b573df9d0eaa8c0152768c708ee7ea2b8e5", - "reference": "e57e7b573df9d0eaa8c0152768c708ee7ea2b8e5", + "url": "https://api.github.com/repos/symfony/dom-crawler/zipball/1c4519d257e652404c3aa550207ccd8ada66b38e", + "reference": "1c4519d257e652404c3aa550207ccd8ada66b38e", "shasum": "" }, "require": { "php": "^7.1.3", - "symfony/filesystem": "~3.4|~4.0", - "symfony/polyfill-ctype": "~1.8" - }, - "conflict": { - "symfony/finder": "<3.4" + "symfony/polyfill-ctype": "~1.8", + "symfony/polyfill-mbstring": "~1.0" }, "require-dev": { - "symfony/dependency-injection": "~3.4|~4.0", - "symfony/event-dispatcher": "~3.4|~4.0", - "symfony/finder": "~3.4|~4.0", - "symfony/yaml": "~3.4|~4.0" + "symfony/css-selector": "~3.4|~4.0" }, "suggest": { - "symfony/yaml": "To use the yaml reference dumper" + "symfony/css-selector": "" }, "type": "library", "extra": { @@ -6475,7 +8335,7 @@ }, "autoload": { "psr-4": { - "Symfony\\Component\\Config\\": "" + "Symfony\\Component\\DomCrawler\\": "" }, "exclude-from-classmap": [ "/Tests/" @@ -6495,48 +8355,31 @@ "homepage": "https://symfony.com/contributors" } ], - "description": "Symfony Config Component", + "description": "Symfony DomCrawler Component", "homepage": "https://symfony.com", - "time": "2018-06-20T11:15:17+00:00" + "time": "2018-07-26T11:00:49+00:00" }, { - "name": "symfony/dependency-injection", - "version": "v4.1.1", + "name": "symfony/http-foundation", + "version": "v4.1.3", "source": { "type": "git", - "url": "https://github.com/symfony/dependency-injection.git", - "reference": "e761828a85d7dfc00b927f94ccbe1851ce0b6535" + "url": "https://github.com/symfony/http-foundation.git", + "reference": "7d93e3547660ec7ee3dad1428ba42e8076a0e5f1" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/dependency-injection/zipball/e761828a85d7dfc00b927f94ccbe1851ce0b6535", - "reference": "e761828a85d7dfc00b927f94ccbe1851ce0b6535", + "url": "https://api.github.com/repos/symfony/http-foundation/zipball/7d93e3547660ec7ee3dad1428ba42e8076a0e5f1", + "reference": "7d93e3547660ec7ee3dad1428ba42e8076a0e5f1", "shasum": "" }, "require": { "php": "^7.1.3", - "psr/container": "^1.0" - }, - "conflict": { - "symfony/config": "<4.1.1", - "symfony/finder": "<3.4", - "symfony/proxy-manager-bridge": "<3.4", - "symfony/yaml": "<3.4" - }, - "provide": { - "psr/container-implementation": "1.0" + "symfony/polyfill-mbstring": "~1.1" }, "require-dev": { - "symfony/config": "~4.1", - "symfony/expression-language": "~3.4|~4.0", - "symfony/yaml": "~3.4|~4.0" - }, - "suggest": { - "symfony/config": "", - "symfony/expression-language": "For using expressions in service container configuration", - "symfony/finder": "For using double-star glob patterns or when GLOB_BRACE portability is required", - "symfony/proxy-manager-bridge": "Generate service proxies to lazy load them", - "symfony/yaml": "" + "predis/predis": "~1.0", + "symfony/expression-language": "~3.4|~4.0" }, "type": "library", "extra": { @@ -6546,7 +8389,7 @@ }, "autoload": { "psr-4": { - "Symfony\\Component\\DependencyInjection\\": "" + "Symfony\\Component\\HttpFoundation\\": "" }, "exclude-from-classmap": [ "/Tests/" @@ -6566,22 +8409,22 @@ "homepage": "https://symfony.com/contributors" } ], - "description": "Symfony DependencyInjection Component", + "description": "Symfony HttpFoundation Component", "homepage": "https://symfony.com", - "time": "2018-06-25T11:12:43+00:00" + "time": "2018-08-01T14:07:44+00:00" }, { "name": "symfony/options-resolver", - "version": "v4.1.1", + "version": "v4.1.3", "source": { "type": "git", "url": "https://github.com/symfony/options-resolver.git", - "reference": "45cdcc8a96ef92b43a50723e6d1f5f83096e8cef" + "reference": "1913f1962477cdbb13df951f8147d5da1fe2412c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/options-resolver/zipball/45cdcc8a96ef92b43a50723e6d1f5f83096e8cef", - "reference": "45cdcc8a96ef92b43a50723e6d1f5f83096e8cef", + "url": "https://api.github.com/repos/symfony/options-resolver/zipball/1913f1962477cdbb13df951f8147d5da1fe2412c", + "reference": "1913f1962477cdbb13df951f8147d5da1fe2412c", "shasum": "" }, "require": { @@ -6622,30 +8465,30 @@ "configuration", "options" ], - "time": "2018-05-31T10:17:53+00:00" + "time": "2018-07-26T08:55:25+00:00" }, { "name": "symfony/polyfill-php70", - "version": "v1.8.0", + "version": "v1.9.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-php70.git", - "reference": "77454693d8f10dd23bb24955cffd2d82db1007a6" + "reference": "1e24b0c4a56d55aaf368763a06c6d1c7d3194934" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-php70/zipball/77454693d8f10dd23bb24955cffd2d82db1007a6", - "reference": "77454693d8f10dd23bb24955cffd2d82db1007a6", + "url": "https://api.github.com/repos/symfony/polyfill-php70/zipball/1e24b0c4a56d55aaf368763a06c6d1c7d3194934", + "reference": "1e24b0c4a56d55aaf368763a06c6d1c7d3194934", "shasum": "" }, "require": { - "paragonie/random_compat": "~1.0|~2.0", + "paragonie/random_compat": "~1.0|~2.0|~9.99", "php": ">=5.3.3" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "1.8-dev" + "dev-master": "1.9-dev" } }, "autoload": { @@ -6681,20 +8524,20 @@ "portable", "shim" ], - "time": "2018-04-26T10:06:28+00:00" + "time": "2018-08-06T14:22:27+00:00" }, { "name": "symfony/polyfill-php72", - "version": "v1.8.0", + "version": "v1.9.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-php72.git", - "reference": "a4576e282d782ad82397f3e4ec1df8e0f0cafb46" + "reference": "95c50420b0baed23852452a7f0c7b527303ed5ae" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-php72/zipball/a4576e282d782ad82397f3e4ec1df8e0f0cafb46", - "reference": "a4576e282d782ad82397f3e4ec1df8e0f0cafb46", + "url": "https://api.github.com/repos/symfony/polyfill-php72/zipball/95c50420b0baed23852452a7f0c7b527303ed5ae", + "reference": "95c50420b0baed23852452a7f0c7b527303ed5ae", "shasum": "" }, "require": { @@ -6703,7 +8546,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "1.8-dev" + "dev-master": "1.9-dev" } }, "autoload": { @@ -6736,20 +8579,20 @@ "portable", "shim" ], - "time": "2018-04-26T10:06:28+00:00" + "time": "2018-08-06T14:22:27+00:00" }, { "name": "symfony/stopwatch", - "version": "v4.1.1", + "version": "v4.1.3", "source": { "type": "git", "url": "https://github.com/symfony/stopwatch.git", - "reference": "07463bbbbbfe119045a24c4a516f92ebd2752784" + "reference": "966c982df3cca41324253dc0c7ffe76b6076b705" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/stopwatch/zipball/07463bbbbbfe119045a24c4a516f92ebd2752784", - "reference": "07463bbbbbfe119045a24c4a516f92ebd2752784", + "url": "https://api.github.com/repos/symfony/stopwatch/zipball/966c982df3cca41324253dc0c7ffe76b6076b705", + "reference": "966c982df3cca41324253dc0c7ffe76b6076b705", "shasum": "" }, "require": { @@ -6785,7 +8628,66 @@ ], "description": "Symfony Stopwatch Component", "homepage": "https://symfony.com", - "time": "2018-02-19T16:51:42+00:00" + "time": "2018-07-26T11:00:49+00:00" + }, + { + "name": "symfony/yaml", + "version": "v3.4.14", + "source": { + "type": "git", + "url": "https://github.com/symfony/yaml.git", + "reference": "810af2d35fc72b6cf5c01116806d2b65ccaaf2e2" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/yaml/zipball/810af2d35fc72b6cf5c01116806d2b65ccaaf2e2", + "reference": "810af2d35fc72b6cf5c01116806d2b65ccaaf2e2", + "shasum": "" + }, + "require": { + "php": "^5.5.9|>=7.0.8", + "symfony/polyfill-ctype": "~1.8" + }, + "conflict": { + "symfony/console": "<3.4" + }, + "require-dev": { + "symfony/console": "~3.4|~4.0" + }, + "suggest": { + "symfony/console": "For validating YAML files using the lint command" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.4-dev" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Component\\Yaml\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony Yaml Component", + "homepage": "https://symfony.com", + "time": "2018-07-26T11:19:56+00:00" }, { "name": "theseer/fdomdocument", @@ -6867,6 +8769,56 @@ "description": "A small library for converting tokenized PHP source code into XML and potentially other formats", "time": "2017-04-07T12:08:54+00:00" }, + { + "name": "vlucas/phpdotenv", + "version": "v2.5.1", + "source": { + "type": "git", + "url": "https://github.com/vlucas/phpdotenv.git", + "reference": "8abb4f9aa89ddea9d52112c65bbe8d0125e2fa8e" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/vlucas/phpdotenv/zipball/8abb4f9aa89ddea9d52112c65bbe8d0125e2fa8e", + "reference": "8abb4f9aa89ddea9d52112c65bbe8d0125e2fa8e", + "shasum": "" + }, + "require": { + "php": ">=5.3.9" + }, + "require-dev": { + "phpunit/phpunit": "^4.8.35 || ^5.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.5-dev" + } + }, + "autoload": { + "psr-4": { + "Dotenv\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Vance Lucas", + "email": "vance@vancelucas.com", + "homepage": "http://www.vancelucas.com" + } + ], + "description": "Loads environment variables from `.env` to `getenv()`, `$_ENV` and `$_SERVER` automagically.", + "keywords": [ + "dotenv", + "env", + "environment" + ], + "time": "2018-07-29T20:33:41+00:00" + }, { "name": "webmozart/assert", "version": "1.3.0", diff --git a/dev/tests/acceptance/.env.example b/dev/tests/acceptance/.env.example deleted file mode 100644 index 432851acbf286..0000000000000 --- a/dev/tests/acceptance/.env.example +++ /dev/null @@ -1,37 +0,0 @@ -#Copyright © Magento, Inc. All rights reserved. -#See COPYING.txt for license details. - -#*** Set the base URL for your Magento instance ***# -MAGENTO_BASE_URL= - -#*** Set the Admin Username and Password for your Magento instance ***# -MAGENTO_BACKEND_NAME= -MAGENTO_ADMIN_USERNAME= -MAGENTO_ADMIN_PASSWORD= - -#*** Path to CLI entry point and command parameter name. Uncomment and change if folder structure differs from standard Magento installation -#MAGENTO_CLI_COMMAND_PATH=dev/tests/acceptance/utils/command.php -#MAGENTO_CLI_COMMAND_PARAMETER=command - -#*** Selenium Server Protocol, Host, Port, and Path, with local defaults. Uncomment and change if not running Selenium locally. -#SELENIUM_HOST=127.0.0.1 -#SELENIUM_PORT=4444 -#SELENIUM_PROTOCOL=http -#SELENIUM_PATH=/wd/hub - -#*** Uncomment and set host & port if your dev environment needs different value other than MAGENTO_BASE_URL for Rest API Requests ***# -#MAGENTO_RESTAPI_SERVER_HOST= -#MAGENTO_RESTAPI_SERVER_PORT= - -#*** Uncomment these properties to set up a dev environment with symlinked projects ***# -#TESTS_BP= -#FW_BP= -#TESTS_MODULE_PATH= - -#*** These properties impact the modules loaded into MFTF, you can point to your own full path, or a custom set of modules located with the core set -MODULE_WHITELIST=Magento_Framework,Magento_ConfigurableProductWishlist,Magento_ConfigurableProductCatalogSearch -#CUSTOM_MODULE_PATHS= - -#*** Bool property which allows the user to toggle debug output during test execution -#MFTF_DEBUG= -#*** End of .env ***# diff --git a/dev/tests/acceptance/LICENSE.txt b/dev/tests/acceptance/LICENSE.txt deleted file mode 100644 index 49525fd99da9c..0000000000000 --- a/dev/tests/acceptance/LICENSE.txt +++ /dev/null @@ -1,48 +0,0 @@ - -Open Software License ("OSL") v. 3.0 - -This Open Software License (the "License") applies to any original work of authorship (the "Original Work") whose owner (the "Licensor") has placed the following licensing notice adjacent to the copyright notice for the Original Work: - -Licensed under the Open Software License version 3.0 - - 1. Grant of Copyright License. Licensor grants You a worldwide, royalty-free, non-exclusive, sublicensable license, for the duration of the copyright, to do the following: - - 1. to reproduce the Original Work in copies, either alone or as part of a collective work; - - 2. to translate, adapt, alter, transform, modify, or arrange the Original Work, thereby creating derivative works ("Derivative Works") based upon the Original Work; - - 3. to distribute or communicate copies of the Original Work and Derivative Works to the public, with the proviso that copies of Original Work or Derivative Works that You distribute or communicate shall be licensed under this Open Software License; - - 4. to perform the Original Work publicly; and - - 5. to display the Original Work publicly. - - 2. Grant of Patent License. Licensor grants You a worldwide, royalty-free, non-exclusive, sublicensable license, under patent claims owned or controlled by the Licensor that are embodied in the Original Work as furnished by the Licensor, for the duration of the patents, to make, use, sell, offer for sale, have made, and import the Original Work and Derivative Works. - - 3. Grant of Source Code License. The term "Source Code" means the preferred form of the Original Work for making modifications to it and all available documentation describing how to modify the Original Work. Licensor agrees to provide a machine-readable copy of the Source Code of the Original Work along with each copy of the Original Work that Licensor distributes. Licensor reserves the right to satisfy this obligation by placing a machine-readable copy of the Source Code in an information repository reasonably calculated to permit inexpensive and convenient access by You for as long as Licensor continues to distribute the Original Work. - - 4. Exclusions From License Grant. Neither the names of Licensor, nor the names of any contributors to the Original Work, nor any of their trademarks or service marks, may be used to endorse or promote products derived from this Original Work without express prior permission of the Licensor. Except as expressly stated herein, nothing in this License grants any license to Licensor's trademarks, copyrights, patents, trade secrets or any other intellectual property. No patent license is granted to make, use, sell, offer for sale, have made, or import embodiments of any patent claims other than the licensed claims defined in Section 2. No license is granted to the trademarks of Licensor even if such marks are included in the Original Work. Nothing in this License shall be interpreted to prohibit Licensor from licensing under terms different from this License any Original Work that Licensor otherwise would have a right to license. - - 5. External Deployment. The term "External Deployment" means the use, distribution, or communication of the Original Work or Derivative Works in any way such that the Original Work or Derivative Works may be used by anyone other than You, whether those works are distributed or communicated to those persons or made available as an application intended for use over a network. As an express condition for the grants of license hereunder, You must treat any External Deployment by You of the Original Work or a Derivative Work as a distribution under section 1(c). - - 6. Attribution Rights. You must retain, in the Source Code of any Derivative Works that You create, all copyright, patent, or trademark notices from the Source Code of the Original Work, as well as any notices of licensing and any descriptive text identified therein as an "Attribution Notice." You must cause the Source Code for any Derivative Works that You create to carry a prominent Attribution Notice reasonably calculated to inform recipients that You have modified the Original Work. - - 7. Warranty of Provenance and Disclaimer of Warranty. Licensor warrants that the copyright in and to the Original Work and the patent rights granted herein by Licensor are owned by the Licensor or are sublicensed to You under the terms of this License with the permission of the contributor(s) of those copyrights and patent rights. Except as expressly stated in the immediately preceding sentence, the Original Work is provided under this License on an "AS IS" BASIS and WITHOUT WARRANTY, either express or implied, including, without limitation, the warranties of non-infringement, merchantability or fitness for a particular purpose. THE ENTIRE RISK AS TO THE QUALITY OF THE ORIGINAL WORK IS WITH YOU. This DISCLAIMER OF WARRANTY constitutes an essential part of this License. No license to the Original Work is granted by this License except under this disclaimer. - - 8. Limitation of Liability. Under no circumstances and under no legal theory, whether in tort (including negligence), contract, or otherwise, shall the Licensor be liable to anyone for any indirect, special, incidental, or consequential damages of any character arising as a result of this License or the use of the Original Work including, without limitation, damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses. This limitation of liability shall not apply to the extent applicable law prohibits such limitation. - - 9. Acceptance and Termination. If, at any time, You expressly assented to this License, that assent indicates your clear and irrevocable acceptance of this License and all of its terms and conditions. If You distribute or communicate copies of the Original Work or a Derivative Work, You must make a reasonable effort under the circumstances to obtain the express assent of recipients to the terms of this License. This License conditions your rights to undertake the activities listed in Section 1, including your right to create Derivative Works based upon the Original Work, and doing so without honoring these terms and conditions is prohibited by copyright law and international treaty. Nothing in this License is intended to affect copyright exceptions and limitations (including 'fair use' or 'fair dealing'). This License shall terminate immediately and You may no longer exercise any of the rights granted to You by this License upon your failure to honor the conditions in Section 1(c). - - 10. Termination for Patent Action. This License shall terminate automatically and You may no longer exercise any of the rights granted to You by this License as of the date You commence an action, including a cross-claim or counterclaim, against Licensor or any licensee alleging that the Original Work infringes a patent. This termination provision shall not apply for an action alleging patent infringement by combinations of the Original Work with other software or hardware. - - 11. Jurisdiction, Venue and Governing Law. Any action or suit relating to this License may be brought only in the courts of a jurisdiction wherein the Licensor resides or in which Licensor conducts its primary business, and under the laws of that jurisdiction excluding its conflict-of-law provisions. The application of the United Nations Convention on Contracts for the International Sale of Goods is expressly excluded. Any use of the Original Work outside the scope of this License or after its termination shall be subject to the requirements and penalties of copyright or patent law in the appropriate jurisdiction. This section shall survive the termination of this License. - - 12. Attorneys' Fees. In any action to enforce the terms of this License or seeking damages relating thereto, the prevailing party shall be entitled to recover its costs and expenses, including, without limitation, reasonable attorneys' fees and costs incurred in connection with such action, including any appeal of such action. This section shall survive the termination of this License. - - 13. Miscellaneous. If any provision of this License is held to be unenforceable, such provision shall be reformed only to the extent necessary to make it enforceable. - - 14. Definition of "You" in This License. "You" throughout this License, whether in upper or lower case, means an individual or a legal entity exercising rights under, and complying with all of the terms of, this License. For legal entities, "You" includes any entity that controls, is controlled by, or is under common control with you. For purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. - - 15. Right to Use. You may use the Original Work in all ways not otherwise restricted or conditioned by this License or by law, and Licensor promises not to interfere with or be responsible for such uses by You. - - 16. Modification of This License. This License is Copyright (C) 2005 Lawrence Rosen. Permission is granted to copy, distribute, or communicate this License without modification. Nothing in this License permits You to modify this License as applied to the Original Work or to Derivative Works. However, You may modify the text of this License and copy, distribute or communicate your modified version (the "Modified License") and apply it to other original works of authorship subject to the following conditions: (i) You may not indicate in any way that your Modified License is the "Open Software License" or "OSL" and you may not use those names in the name of your Modified License; (ii) You must replace the notice specified in the first paragraph above with the notice "Licensed under <insert your license name here>" or with a notice of your own that is not confusingly similar to the notice in this License; and (iii) You may not claim that your original works are open source software unless your Modified License has been approved by Open Source Initiative (OSI) and You comply with its license review and certification process. \ No newline at end of file diff --git a/dev/tests/acceptance/LICENSE_AFL.txt b/dev/tests/acceptance/LICENSE_AFL.txt deleted file mode 100644 index f39d641b18a19..0000000000000 --- a/dev/tests/acceptance/LICENSE_AFL.txt +++ /dev/null @@ -1,48 +0,0 @@ - -Academic Free License ("AFL") v. 3.0 - -This Academic Free License (the "License") applies to any original work of authorship (the "Original Work") whose owner (the "Licensor") has placed the following licensing notice adjacent to the copyright notice for the Original Work: - -Licensed under the Academic Free License version 3.0 - - 1. Grant of Copyright License. Licensor grants You a worldwide, royalty-free, non-exclusive, sublicensable license, for the duration of the copyright, to do the following: - - 1. to reproduce the Original Work in copies, either alone or as part of a collective work; - - 2. to translate, adapt, alter, transform, modify, or arrange the Original Work, thereby creating derivative works ("Derivative Works") based upon the Original Work; - - 3. to distribute or communicate copies of the Original Work and Derivative Works to the public, under any license of your choice that does not contradict the terms and conditions, including Licensor's reserved rights and remedies, in this Academic Free License; - - 4. to perform the Original Work publicly; and - - 5. to display the Original Work publicly. - - 2. Grant of Patent License. Licensor grants You a worldwide, royalty-free, non-exclusive, sublicensable license, under patent claims owned or controlled by the Licensor that are embodied in the Original Work as furnished by the Licensor, for the duration of the patents, to make, use, sell, offer for sale, have made, and import the Original Work and Derivative Works. - - 3. Grant of Source Code License. The term "Source Code" means the preferred form of the Original Work for making modifications to it and all available documentation describing how to modify the Original Work. Licensor agrees to provide a machine-readable copy of the Source Code of the Original Work along with each copy of the Original Work that Licensor distributes. Licensor reserves the right to satisfy this obligation by placing a machine-readable copy of the Source Code in an information repository reasonably calculated to permit inexpensive and convenient access by You for as long as Licensor continues to distribute the Original Work. - - 4. Exclusions From License Grant. Neither the names of Licensor, nor the names of any contributors to the Original Work, nor any of their trademarks or service marks, may be used to endorse or promote products derived from this Original Work without express prior permission of the Licensor. Except as expressly stated herein, nothing in this License grants any license to Licensor's trademarks, copyrights, patents, trade secrets or any other intellectual property. No patent license is granted to make, use, sell, offer for sale, have made, or import embodiments of any patent claims other than the licensed claims defined in Section 2. No license is granted to the trademarks of Licensor even if such marks are included in the Original Work. Nothing in this License shall be interpreted to prohibit Licensor from licensing under terms different from this License any Original Work that Licensor otherwise would have a right to license. - - 5. External Deployment. The term "External Deployment" means the use, distribution, or communication of the Original Work or Derivative Works in any way such that the Original Work or Derivative Works may be used by anyone other than You, whether those works are distributed or communicated to those persons or made available as an application intended for use over a network. As an express condition for the grants of license hereunder, You must treat any External Deployment by You of the Original Work or a Derivative Work as a distribution under section 1(c). - - 6. Attribution Rights. You must retain, in the Source Code of any Derivative Works that You create, all copyright, patent, or trademark notices from the Source Code of the Original Work, as well as any notices of licensing and any descriptive text identified therein as an "Attribution Notice." You must cause the Source Code for any Derivative Works that You create to carry a prominent Attribution Notice reasonably calculated to inform recipients that You have modified the Original Work. - - 7. Warranty of Provenance and Disclaimer of Warranty. Licensor warrants that the copyright in and to the Original Work and the patent rights granted herein by Licensor are owned by the Licensor or are sublicensed to You under the terms of this License with the permission of the contributor(s) of those copyrights and patent rights. Except as expressly stated in the immediately preceding sentence, the Original Work is provided under this License on an "AS IS" BASIS and WITHOUT WARRANTY, either express or implied, including, without limitation, the warranties of non-infringement, merchantability or fitness for a particular purpose. THE ENTIRE RISK AS TO THE QUALITY OF THE ORIGINAL WORK IS WITH YOU. This DISCLAIMER OF WARRANTY constitutes an essential part of this License. No license to the Original Work is granted by this License except under this disclaimer. - - 8. Limitation of Liability. Under no circumstances and under no legal theory, whether in tort (including negligence), contract, or otherwise, shall the Licensor be liable to anyone for any indirect, special, incidental, or consequential damages of any character arising as a result of this License or the use of the Original Work including, without limitation, damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses. This limitation of liability shall not apply to the extent applicable law prohibits such limitation. - - 9. Acceptance and Termination. If, at any time, You expressly assented to this License, that assent indicates your clear and irrevocable acceptance of this License and all of its terms and conditions. If You distribute or communicate copies of the Original Work or a Derivative Work, You must make a reasonable effort under the circumstances to obtain the express assent of recipients to the terms of this License. This License conditions your rights to undertake the activities listed in Section 1, including your right to create Derivative Works based upon the Original Work, and doing so without honoring these terms and conditions is prohibited by copyright law and international treaty. Nothing in this License is intended to affect copyright exceptions and limitations (including "fair use" or "fair dealing"). This License shall terminate immediately and You may no longer exercise any of the rights granted to You by this License upon your failure to honor the conditions in Section 1(c). - - 10. Termination for Patent Action. This License shall terminate automatically and You may no longer exercise any of the rights granted to You by this License as of the date You commence an action, including a cross-claim or counterclaim, against Licensor or any licensee alleging that the Original Work infringes a patent. This termination provision shall not apply for an action alleging patent infringement by combinations of the Original Work with other software or hardware. - - 11. Jurisdiction, Venue and Governing Law. Any action or suit relating to this License may be brought only in the courts of a jurisdiction wherein the Licensor resides or in which Licensor conducts its primary business, and under the laws of that jurisdiction excluding its conflict-of-law provisions. The application of the United Nations Convention on Contracts for the International Sale of Goods is expressly excluded. Any use of the Original Work outside the scope of this License or after its termination shall be subject to the requirements and penalties of copyright or patent law in the appropriate jurisdiction. This section shall survive the termination of this License. - - 12. Attorneys' Fees. In any action to enforce the terms of this License or seeking damages relating thereto, the prevailing party shall be entitled to recover its costs and expenses, including, without limitation, reasonable attorneys' fees and costs incurred in connection with such action, including any appeal of such action. This section shall survive the termination of this License. - - 13. Miscellaneous. If any provision of this License is held to be unenforceable, such provision shall be reformed only to the extent necessary to make it enforceable. - - 14. Definition of "You" in This License. "You" throughout this License, whether in upper or lower case, means an individual or a legal entity exercising rights under, and complying with all of the terms of, this License. For legal entities, "You" includes any entity that controls, is controlled by, or is under common control with you. For purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. - - 15. Right to Use. You may use the Original Work in all ways not otherwise restricted or conditioned by this License or by law, and Licensor promises not to interfere with or be responsible for such uses by You. - - 16. Modification of This License. This License is Copyright © 2005 Lawrence Rosen. Permission is granted to copy, distribute, or communicate this License without modification. Nothing in this License permits You to modify this License as applied to the Original Work or to Derivative Works. However, You may modify the text of this License and copy, distribute or communicate your modified version (the "Modified License") and apply it to other original works of authorship subject to the following conditions: (i) You may not indicate in any way that your Modified License is the "Academic Free License" or "AFL" and you may not use those names in the name of your Modified License; (ii) You must replace the notice specified in the first paragraph above with the notice "Licensed under <insert your license name here>" or with a notice of your own that is not confusingly similar to the notice in this License; and (iii) You may not claim that your original works are open source software unless your Modified License has been approved by Open Source Initiative (OSI) and You comply with its license review and certification process. diff --git a/dev/tests/acceptance/README.md b/dev/tests/acceptance/README.md deleted file mode 100755 index 6350b9cabcdfa..0000000000000 --- a/dev/tests/acceptance/README.md +++ /dev/null @@ -1,64 +0,0 @@ -# Magento Functional Testing Framework - ----- - -## System Requirements -[Magento Functional Testing Framework system requirements](http://devdocs.magento.com/guides/v2.2/magento-functional-testing-framework/getting-started.html#prepare-environment) - -## Installation -To install the Magento Functional Testing Framework, see [Getting Started](http://devdocs.magento.com/guides/v2.2/magento-functional-testing-framework/getting-started.html) - -## Contributing -Contributions can take the form of new components or features, changes to existing features, tests, documentation (such as developer guides, user guides, examples, or specifications), bug fixes, optimizations, or just good suggestions. - -To learn about how to make a contribution, click [here][1]. - -To open an issue, click [here][2]. - -To suggest documentation improvements, click [here][3]. - -[1]: <http://devdocs.magento.com/guides/v2.2/magento-functional-testing-framework/contribution-guidelines.html> -[2]: <https://github.com/magento/magento2-functional-testing-framework/issues> -[3]: <http://devdocs.magento.com> - -### Labels applied by the MFTF team - -Refer to the tables with descriptions of each label below. These labels are applied by the MFTF development team to community contributed issues and pull requests, to communicate status, impact, or which team is working on it. - -### Pull Request Status - -Label| Description ----|--- -**accept**| The pull request has been accepted and will be merged into mainline code. -**reject**| The pull request has been rejected and will not be merged into mainline code. Possible reasons can include but are not limited to: issue has already been fixed in another code contribution, or there is an issue with the code contribution. -**needsUpdate**| The Magento Team needs additional information from the reporter to properly prioritize and process the pull request. - -### Issue Resolution Status - -Label| Description ----|--- -**acknowledged**| The Magento Team has validated the issue and an internal ticket has been created. -**needsUpdate**| The Magento Team needs additional information from the reporter to properly prioritize and process the issue or pull request. -**cannot reproduce**| The Magento Team has not confirmed that this issue contains the minimum required information to reproduce. -**non-issue**| The Magento Team has not recognised any issue according to provided information. - -### Domains Impacted - -Label| Description ----|--- -**PROD**| Affects the Product team (mostly feature requests or business logic change). -**DOC**| Affects Documentation domain. -**TECH**| Affects Architect Group (mostly to make decisions around technology changes). - -### Type - -Label| Description ----|--- -**bugfix**| The issue or pull request relates to bug fixing. -**enhancement**| The issue or pull request that raises the MFTF to a higher degree (for example new features, optimization, refactoring, etc). - -## License - -Each Magento source file included in this distribution is licensed under APL 3.0 - -Please see LICENSE_APL3.txt for the full text of the APL 3.0 license or contact license@magentocommerce.com for a copy. diff --git a/dev/tests/acceptance/RoboFile.php b/dev/tests/acceptance/RoboFile.php index dd84b4131e502..e6e9e591bbd8b 100644 --- a/dev/tests/acceptance/RoboFile.php +++ b/dev/tests/acceptance/RoboFile.php @@ -15,84 +15,6 @@ class RoboFile extends \Robo\Tasks { use Robo\Task\Base\loadShortcuts; - public function __construct() - { - require 'tests'. DIRECTORY_SEPARATOR . 'functional' . DIRECTORY_SEPARATOR . '_bootstrap.php'; - define('VENDOR_BIN_PATH', PROJECT_ROOT . DIRECTORY_SEPARATOR . 'vendor' . DIRECTORY_SEPARATOR . 'bin' . DIRECTORY_SEPARATOR); - - } - /** - * Duplicate the Example configuration files used to customize the Project for customization. - * - * @return void - */ - function cloneFiles() - { - $this->_exec('cp -vn .env.example .env'); - $this->_exec('cp -vf codeception.dist.yml codeception.yml'); - $this->_exec('cp -vf tests'. DIRECTORY_SEPARATOR .'functional.suite.dist.yml tests'. DIRECTORY_SEPARATOR .'functional.suite.yml'); - } - - /** - * Finds relative paths between codeception.yml file and MFTF path, and overwrites the default paths. - * - * @return void - */ - private function buildCodeceptionPaths() - { - $relativePathFunc = function ($from, $to) - { - $from = is_dir($from) ? rtrim($from, '\/') . '/' : $from; - $to = is_dir($to) ? rtrim($to, '\/') . '/' : $to; - $from = str_replace('\\', '/', $from); - $to = str_replace('\\', '/', $to); - - $from = explode('/', $from); - $to = explode('/', $to); - $relPath = $to; - - foreach($from as $depth => $dir) { - // find first non-matching dir - if($dir === $to[$depth]) { - // ignore this directory - array_shift($relPath); - } else { - // get number of remaining dirs to $from - $remaining = count($from) - $depth; - if($remaining > 1) { - // add traversals up to first matching dir - $padLength = (count($relPath) + $remaining - 1) * -1; - $relPath = array_pad($relPath, $padLength, '..'); - break; - } else { - $relPath[0] = './' . $relPath[0]; - } - } - } - return implode('/', $relPath); - }; - - //Find travel path from codeception.yml to FW_BP - $configYmlPath = dirname(dirname(TESTS_BP)) . DIRECTORY_SEPARATOR; - $relativePath = call_user_func($relativePathFunc, $configYmlPath, FW_BP); - $configYmlFile = $configYmlPath . "codeception.yml"; - $defaultConfigYmlFile = $configYmlPath . "codeception.dist.yml"; - - if (file_exists($configYmlFile)) { - $ymlContents = file_get_contents($configYmlFile); - } else { - $ymlContents = file_get_contents($defaultConfigYmlFile); - } - $ymlArray = Yaml::parse($ymlContents) ?? []; - if (!array_key_exists("paths", $ymlArray)) { - $ymlArray["paths"] = []; - } - $ymlArray["paths"]["support"] = $relativePath . 'src/Magento/FunctionalTestingFramework'; - $ymlArray["paths"]["envs"] = $relativePath . 'etc/_envs'; - $ymlText = Yaml::dump($ymlArray, 10); - file_put_contents($configYmlFile, $ymlText); - } - /** * Duplicate the Example configuration files for the Project. * Build the Codeception project. @@ -101,9 +23,7 @@ private function buildCodeceptionPaths() */ function buildProject() { - $this->cloneFiles(); - $this->buildCodeceptionPaths(); - $this->_exec(VENDOR_BIN_PATH .'codecept build'); + passthru($this->getBaseCmd("build:project")); } /** @@ -111,99 +31,32 @@ function buildProject() * * @param array $tests * @param array $opts - * @return void + * @return \Robo\Result */ function generateTests(array $tests, $opts = [ 'config' => null, 'force' => false, 'nodes' => null, - 'lines' => 500, + 'lines' => null, 'tests' => null ]) { - require 'tests'. DIRECTORY_SEPARATOR . 'functional' . DIRECTORY_SEPARATOR . '_bootstrap.php'; - $testConfiguration = $this->createTestConfiguration($tests, $opts); - - // maintain backwards compatability for devops by not removing the nodes option yet - $lines = $opts['lines']; - - // create our manifest file here - $testManifest = \Magento\FunctionalTestingFramework\Util\Manifest\TestManifestFactory::makeManifest($opts['config'],$testConfiguration['suites']); - \Magento\FunctionalTestingFramework\Util\TestGenerator::getInstance(null, $testConfiguration['tests'])->createAllTestFiles($testManifest); - - if ($opts['config'] == 'parallel') { - $testManifest->createTestGroups($lines); - } - - \Magento\FunctionalTestingFramework\Suite\SuiteGenerator::getInstance()->generateAllSuites($testManifest); - $testManifest->generate(); - - $this->say("Generate Tests Command Run"); - } - + $baseCmd = $this->getBaseCmd("generate:tests"); - /** - * Function which builds up a configuration including test and suites for consumption of Magento generation methods. - * - * @param array $tests - * @param array $opts - * @return array - */ - private function createTestConfiguration($tests, $opts) - { - // set our application configuration so we can references the user options in our framework - Magento\FunctionalTestingFramework\Config\MftfApplicationConfig::create( - $opts['force'], - Magento\FunctionalTestingFramework\Config\MftfApplicationConfig::GENERATION_PHASE, - $opts['verbose'] - ); - - $testConfiguration = []; - $testConfiguration['tests'] = $tests; - $testConfiguration['suites'] = []; - - $testConfiguration = $this->parseTestsConfigJson($opts['tests'], $testConfiguration); - - // if we have references to specific tests, we resolve the test objects and pass them to the config - if (!empty($testConfiguration['tests'])) - { - $testObjects = []; - - foreach ($testConfiguration['tests'] as $test) - { - $testObjects[$test] = Magento\FunctionalTestingFramework\Test\Handlers\TestObjectHandler::getInstance()->getObject($test); + $mftfArgNames = ['config', 'nodes', 'lines', 'tests']; + // append arguments to the end of the command + foreach ($opts as $argName => $argValue) { + if (in_array($argName, $mftfArgNames) && $argValue !== null) { + $baseCmd .= " --$argName $argValue"; } - - $testConfiguration['tests'] = $testObjects; - } - - return $testConfiguration; - } - - /** - * Function which takes a json string of potential custom configuration and parses/validates the resulting json - * passed in by the user. The result is a testConfiguration array. - * - * @param string $json - * @param array $testConfiguration - * @return array - */ - private function parseTestsConfigJson($json, $testConfiguration) { - if ($json == null) { - return $testConfiguration; } - $jsonTestConfiguration = []; - $testConfigArray = json_decode($json, true); - - // stop execution if we have failed to properly parse any json - if (json_last_error() != JSON_ERROR_NONE) { - throw new \Magento\FunctionalTestingFramework\Exceptions\TestFrameworkException("JSON could not be parsed: " . json_last_error_msg()); + // use a separate conditional for the force flag (casting bool to string in php is hard) + if ($opts['force']) { + $baseCmd .= ' --force'; } - $jsonTestConfiguration['tests'] = $testConfigArray['tests'] ?? null;; - $jsonTestConfiguration['suites'] = $testConfigArray['suites'] ?? null; - return $jsonTestConfiguration; + return $this->taskExec($baseCmd)->args($tests)->run(); } /** @@ -211,61 +64,28 @@ private function parseTestsConfigJson($json, $testConfiguration) { * * @param array $args * @throws Exception - * @return void + * @return \Robo\Result */ function generateSuite(array $args) { if (empty($args)) { throw new Exception("Please provide suite name(s) after generate:suite command"); } - - $sg = \Magento\FunctionalTestingFramework\Suite\SuiteGenerator::getInstance(); - - foreach ($args as $arg) { - $sg->generateSuite($arg); - } - } - - /** - * Run all Functional tests. - * - * @return void - */ - function functional() - { - $this->_exec(VENDOR_BIN_PATH . 'codecept run functional'); + $baseCmd = $this->getBaseCmd("generate:suite"); + return $this->taskExec($baseCmd)->args($args)->run(); } /** * Run all Tests with the specified @group tag'. * - * @param string $args - * @return void - */ - function group($args = '') - { - $this->taskExec(VENDOR_BIN_PATH . 'codecept run functional --verbose --steps --group')->args($args)->run(); - } - - /** - * Run all Functional tests located under the Directory Path provided. - * - * @param string $args - * @return void - */ - function folder($args = '') - { - $this->taskExec(VENDOR_BIN_PATH . 'codecept run functional')->args($args)->run(); - } - - /** - * Run all Tests marked with the @group tag 'example'. - * - * @return void + * @param array $args + * @return \Robo\Result */ - function example() + function group(array $args) { - $this->_exec(VENDOR_BIN_PATH . 'codecept run --group example'); + $args = array_merge($args, ['-k']); + $baseCmd = $this->getBaseCmd("run:group"); + return $this->taskExec($baseCmd)->args($args)->run(); } /** @@ -291,58 +111,65 @@ function allure2Generate() /** * Open the HTML Allure report - Allure v1.4.X * - * @return void + * @return \Robo\Result */ function allure1Open() { - $this->_exec('allure report open --report-dir tests'. DIRECTORY_SEPARATOR .'_output'. DIRECTORY_SEPARATOR .'allure-report'. DIRECTORY_SEPARATOR .''); + return $this->_exec('allure report open --report-dir tests'. DIRECTORY_SEPARATOR .'_output'. DIRECTORY_SEPARATOR .'allure-report'. DIRECTORY_SEPARATOR .''); } /** * Open the HTML Allure report - Allure v2.3.X * - * @return void + * @return \Robo\Result */ function allure2Open() { - $this->_exec('allure open --port 0 tests'. DIRECTORY_SEPARATOR .'_output'. DIRECTORY_SEPARATOR .'allure-report'. DIRECTORY_SEPARATOR .''); + return $this->_exec('allure open --port 0 tests'. DIRECTORY_SEPARATOR .'_output'. DIRECTORY_SEPARATOR .'allure-report'. DIRECTORY_SEPARATOR .''); } /** * Generate and open the HTML Allure report - Allure v1.4.X * - * @return void + * @return \Robo\Result */ function allure1Report() { $result1 = $this->allure1Generate(); if ($result1->wasSuccessful()) { - $this->allure1Open(); + return $this->allure1Open(); + } else { + return $result1; } } /** * Generate and open the HTML Allure report - Allure v2.3.X * - * @return void + * @return \Robo\Result */ function allure2Report() { $result1 = $this->allure2Generate(); if ($result1->wasSuccessful()) { - $this->allure2Open(); + return $this->allure2Open(); + } else { + return $result1; } } /** - * Run the Pre-Install system check script. + * Private function for returning the formatted command for the passthru to mftf bin execution. * - * @return void + * @param string $command + * @return string */ - function preInstall() + private function getBaseCmd($command) { - $this->_exec('php pre-install.php'); + $this->writeln("\033[01;31m Use of robo will be deprecated with next major release, please use <root>/vendor/bin/mftf $command \033[0m"); + chdir(__DIR__); + return realpath('../../../vendor/bin/mftf') . " $command"; } -} +} \ No newline at end of file diff --git a/dev/tests/acceptance/codeception.dist.yml b/dev/tests/acceptance/codeception.dist.yml deleted file mode 100644 index 683edcb107fd1..0000000000000 --- a/dev/tests/acceptance/codeception.dist.yml +++ /dev/null @@ -1,35 +0,0 @@ -# Copyright © Magento, Inc. All rights reserved. -# See COPYING.txt for license details. -actor: Tester -paths: - tests: tests - log: tests/_output - data: tests/_data - support: "%REPLACED IN BUILD:PROJECT%" - envs: "%REPLACED IN BUILD:PROJECT%" -settings: - bootstrap: _bootstrap.php - colors: true - memory_limit: 1024M -extensions: - enabled: - - Codeception\Extension\RunFailed - - Magento\FunctionalTestingFramework\Extension\TestContextExtension - - Magento\FunctionalTestingFramework\Allure\Adapter\MagentoAllureAdapter - config: - Yandex\Allure\Adapter\AllureAdapter: - deletePreviousResults: true - outputDirectory: allure-results - ignoredAnnotations: - - env - - zephyrId - - useCaseId -params: - - .env -modules: - config: - Db: - dsn: "%DB_DSN%" - user: "%DB_USERNAME%" - password: "%DB_PASSWORD%" - dump: tests/_data/dump.sql \ No newline at end of file diff --git a/dev/tests/acceptance/composer.json b/dev/tests/acceptance/composer.json index 787d2579e03ca..a20176a29c4c8 100755 --- a/dev/tests/acceptance/composer.json +++ b/dev/tests/acceptance/composer.json @@ -9,20 +9,17 @@ "config": { "sort-packages": true }, - "repositories": [ - { - "type": "git", - "url": "git@github.com:magento/magento2-functional-testing-framework.git" - } - ], "require": { "php": "~7.1.3||~7.2.0", - "magento/magento2-functional-testing-framework": "~2.2.0" + "codeception/codeception": "~2.3.4", + "consolidation/robo": "^1.0.0", + "vlucas/phpdotenv": "^2.4" }, "autoload": { "psr-4": { "Magento\\": "tests/functional/Magento" - } + }, + "files": ["tests/_bootstrap.php"] }, "prefer-stable": true } diff --git a/dev/tests/acceptance/composer.lock b/dev/tests/acceptance/composer.lock index afe2640b442f1..8542402a98f50 100644 --- a/dev/tests/acceptance/composer.lock +++ b/dev/tests/acceptance/composer.lock @@ -4,111 +4,8 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file", "This file is @generated automatically" ], - "content-hash": "9f292f6e226938ad82d1189da7aa4024", + "content-hash": "46ca2d50566f5069daef753664080c5a", "packages": [ - { - "name": "allure-framework/allure-codeception", - "version": "1.2.7", - "source": { - "type": "git", - "url": "https://github.com/allure-framework/allure-codeception.git", - "reference": "48598f4b4603b50b663bfe977260113a40912131" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/allure-framework/allure-codeception/zipball/48598f4b4603b50b663bfe977260113a40912131", - "reference": "48598f4b4603b50b663bfe977260113a40912131", - "shasum": "" - }, - "require": { - "allure-framework/allure-php-api": "~1.1.0", - "codeception/codeception": "~2.1", - "php": ">=5.4.0", - "symfony/filesystem": ">=2.6", - "symfony/finder": ">=2.6" - }, - "type": "library", - "autoload": { - "psr-0": { - "Yandex": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "Apache-2.0" - ], - "authors": [ - { - "name": "Ivan Krutov", - "email": "vania-pooh@yandex-team.ru", - "role": "Developer" - } - ], - "description": "A Codeception adapter for Allure report.", - "homepage": "http://allure.qatools.ru/", - "keywords": [ - "allure", - "attachments", - "cases", - "codeception", - "report", - "steps", - "testing" - ], - "time": "2018-03-07T11:18:27+00:00" - }, - { - "name": "allure-framework/allure-php-api", - "version": "1.1.4", - "source": { - "type": "git", - "url": "https://github.com/allure-framework/allure-php-adapter-api.git", - "reference": "a462a0da121681577033e13c123b6cc4e89cdc64" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/allure-framework/allure-php-adapter-api/zipball/a462a0da121681577033e13c123b6cc4e89cdc64", - "reference": "a462a0da121681577033e13c123b6cc4e89cdc64", - "shasum": "" - }, - "require": { - "jms/serializer": ">=0.16.0", - "moontoast/math": ">=1.1.0", - "php": ">=5.4.0", - "phpunit/phpunit": ">=4.0.0", - "ramsey/uuid": ">=3.0.0", - "symfony/http-foundation": ">=2.0" - }, - "type": "library", - "autoload": { - "psr-0": { - "Yandex": [ - "src/", - "test/" - ] - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "Apache-2.0" - ], - "authors": [ - { - "name": "Ivan Krutov", - "email": "vania-pooh@yandex-team.ru", - "role": "Developer" - } - ], - "description": "PHP API for Allure adapter", - "homepage": "http://allure.qatools.ru/", - "keywords": [ - "allure", - "api", - "php", - "report" - ], - "time": "2016-12-07T12:15:46+00:00" - }, { "name": "behat/gherkin", "version": "v4.4.5", @@ -264,16 +161,16 @@ }, { "name": "codeception/stub", - "version": "1.0.2", + "version": "1.0.4", "source": { "type": "git", "url": "https://github.com/Codeception/Stub.git", - "reference": "95fb7a36b81890dd2e5163e7ab31310df6f1bb99" + "reference": "681b62348837a5ef07d10d8a226f5bc358cc8805" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/Codeception/Stub/zipball/95fb7a36b81890dd2e5163e7ab31310df6f1bb99", - "reference": "95fb7a36b81890dd2e5163e7ab31310df6f1bb99", + "url": "https://api.github.com/repos/Codeception/Stub/zipball/681b62348837a5ef07d10d8a226f5bc358cc8805", + "reference": "681b62348837a5ef07d10d8a226f5bc358cc8805", "shasum": "" }, "require": { @@ -293,20 +190,20 @@ "MIT" ], "description": "Flexible Stub wrapper for PHPUnit's Mock Builder", - "time": "2018-02-18T13:56:56+00:00" + "time": "2018-05-17T09:31:08+00:00" }, { "name": "consolidation/annotated-command", - "version": "2.8.3", + "version": "2.8.4", "source": { "type": "git", "url": "https://github.com/consolidation/annotated-command.git", - "reference": "8f8f5da2ca06fbd3a85f7d551c49f844b7c59437" + "reference": "651541a0b68318a2a202bda558a676e5ad92223c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/consolidation/annotated-command/zipball/8f8f5da2ca06fbd3a85f7d551c49f844b7c59437", - "reference": "8f8f5da2ca06fbd3a85f7d551c49f844b7c59437", + "url": "https://api.github.com/repos/consolidation/annotated-command/zipball/651541a0b68318a2a202bda558a676e5ad92223c", + "reference": "651541a0b68318a2a202bda558a676e5ad92223c", "shasum": "" }, "require": { @@ -318,9 +215,9 @@ "symfony/finder": "^2.5|^3|^4" }, "require-dev": { - "greg-1-anderson/composer-test-scenarios": "^1", - "phpunit/phpunit": "^4.8", - "satooshi/php-coveralls": "^1.0.2 | dev-master", + "g1a/composer-test-scenarios": "^2", + "phpunit/phpunit": "^6", + "satooshi/php-coveralls": "^2", "squizlabs/php_codesniffer": "^2.7" }, "type": "library", @@ -345,20 +242,20 @@ } ], "description": "Initialize Symfony Console commands from annotated command class methods.", - "time": "2018-02-23T16:32:04+00:00" + "time": "2018-05-25T18:04:25+00:00" }, { "name": "consolidation/config", - "version": "1.0.9", + "version": "1.0.11", "source": { "type": "git", "url": "https://github.com/consolidation/config.git", - "reference": "34ca8d7c1ee60a7b591b10617114cf1210a2e92c" + "reference": "ede41d946078e97e7a9513aadc3352f1c26817af" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/consolidation/config/zipball/34ca8d7c1ee60a7b591b10617114cf1210a2e92c", - "reference": "34ca8d7c1ee60a7b591b10617114cf1210a2e92c", + "url": "https://api.github.com/repos/consolidation/config/zipball/ede41d946078e97e7a9513aadc3352f1c26817af", + "reference": "ede41d946078e97e7a9513aadc3352f1c26817af", "shasum": "" }, "require": { @@ -367,7 +264,7 @@ "php": ">=5.4.0" }, "require-dev": { - "greg-1-anderson/composer-test-scenarios": "^1", + "g1a/composer-test-scenarios": "^1", "phpunit/phpunit": "^4", "satooshi/php-coveralls": "^1.0", "squizlabs/php_codesniffer": "2.*", @@ -399,20 +296,20 @@ } ], "description": "Provide configuration services for a commandline tool.", - "time": "2017-12-22T17:28:19+00:00" + "time": "2018-05-27T01:17:02+00:00" }, { "name": "consolidation/log", - "version": "1.0.5", + "version": "1.0.6", "source": { "type": "git", "url": "https://github.com/consolidation/log.git", - "reference": "dbc7c535f319a4a2d5a5077738f8eb7c10df8821" + "reference": "dfd8189a771fe047bf3cd669111b2de5f1c79395" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/consolidation/log/zipball/dbc7c535f319a4a2d5a5077738f8eb7c10df8821", - "reference": "dbc7c535f319a4a2d5a5077738f8eb7c10df8821", + "url": "https://api.github.com/repos/consolidation/log/zipball/dfd8189a771fe047bf3cd669111b2de5f1c79395", + "reference": "dfd8189a771fe047bf3cd669111b2de5f1c79395", "shasum": "" }, "require": { @@ -421,8 +318,9 @@ "symfony/console": "^2.8|^3|^4" }, "require-dev": { + "g1a/composer-test-scenarios": "^1", "phpunit/phpunit": "4.*", - "satooshi/php-coveralls": "dev-master", + "satooshi/php-coveralls": "^2", "squizlabs/php_codesniffer": "2.*" }, "type": "library", @@ -447,20 +345,20 @@ } ], "description": "Improved Psr-3 / Psr\\Log logger based on Symfony Console components.", - "time": "2017-11-29T01:44:16+00:00" + "time": "2018-05-25T18:14:39+00:00" }, { "name": "consolidation/output-formatters", - "version": "3.2.0", + "version": "3.2.1", "source": { "type": "git", "url": "https://github.com/consolidation/output-formatters.git", - "reference": "da889e4bce19f145ca4ec5b1725a946f4eb625a9" + "reference": "d78ef59aea19d3e2e5a23f90a055155ee78a0ad5" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/consolidation/output-formatters/zipball/da889e4bce19f145ca4ec5b1725a946f4eb625a9", - "reference": "da889e4bce19f145ca4ec5b1725a946f4eb625a9", + "url": "https://api.github.com/repos/consolidation/output-formatters/zipball/d78ef59aea19d3e2e5a23f90a055155ee78a0ad5", + "reference": "d78ef59aea19d3e2e5a23f90a055155ee78a0ad5", "shasum": "" }, "require": { @@ -469,7 +367,7 @@ "symfony/finder": "^2.5|^3|^4" }, "require-dev": { - "g-1-a/composer-test-scenarios": "^2", + "g1a/composer-test-scenarios": "^2", "phpunit/phpunit": "^5.7.27", "satooshi/php-coveralls": "^2", "squizlabs/php_codesniffer": "^2.7", @@ -502,25 +400,25 @@ } ], "description": "Format text by applying transformations provided by plug-in formatters.", - "time": "2018-03-20T15:18:32+00:00" + "time": "2018-05-25T18:02:34+00:00" }, { "name": "consolidation/robo", - "version": "1.2.3", + "version": "1.3.0", "source": { "type": "git", "url": "https://github.com/consolidation/Robo.git", - "reference": "54a13e268917b92576d75e10dca8227b95a574d9" + "reference": "ac563abfadf7cb7314b4e152f2b5033a6c255f6f" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/consolidation/Robo/zipball/54a13e268917b92576d75e10dca8227b95a574d9", - "reference": "54a13e268917b92576d75e10dca8227b95a574d9", + "url": "https://api.github.com/repos/consolidation/Robo/zipball/ac563abfadf7cb7314b4e152f2b5033a6c255f6f", + "reference": "ac563abfadf7cb7314b4e152f2b5033a6c255f6f", "shasum": "" }, "require": { "consolidation/annotated-command": "^2.8.2", - "consolidation/config": "^1.0.1", + "consolidation/config": "^1.0.10", "consolidation/log": "~1", "consolidation/output-formatters": "^3.1.13", "grasmash/yaml-expander": "^1.3", @@ -539,7 +437,7 @@ "codeception/aspect-mock": "^1|^2.1.1", "codeception/base": "^2.3.7", "codeception/verify": "^0.3.2", - "g-1-a/composer-test-scenarios": "^2", + "g1a/composer-test-scenarios": "^2", "goaop/framework": "~2.1.2", "goaop/parser-reflection": "^1.1.0", "natxet/cssmin": "3.0.4", @@ -582,7 +480,7 @@ } ], "description": "Modern task runner", - "time": "2018-04-06T05:27:37+00:00" + "time": "2018-05-27T01:42:53+00:00" }, { "name": "container-interop/container-interop", @@ -674,141 +572,6 @@ ], "time": "2017-01-20T21:14:22+00:00" }, - { - "name": "doctrine/annotations", - "version": "v1.6.0", - "source": { - "type": "git", - "url": "https://github.com/doctrine/annotations.git", - "reference": "c7f2050c68a9ab0bdb0f98567ec08d80ea7d24d5" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/doctrine/annotations/zipball/c7f2050c68a9ab0bdb0f98567ec08d80ea7d24d5", - "reference": "c7f2050c68a9ab0bdb0f98567ec08d80ea7d24d5", - "shasum": "" - }, - "require": { - "doctrine/lexer": "1.*", - "php": "^7.1" - }, - "require-dev": { - "doctrine/cache": "1.*", - "phpunit/phpunit": "^6.4" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.6.x-dev" - } - }, - "autoload": { - "psr-4": { - "Doctrine\\Common\\Annotations\\": "lib/Doctrine/Common/Annotations" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Roman Borschel", - "email": "roman@code-factory.org" - }, - { - "name": "Benjamin Eberlei", - "email": "kontakt@beberlei.de" - }, - { - "name": "Guilherme Blanco", - "email": "guilhermeblanco@gmail.com" - }, - { - "name": "Jonathan Wage", - "email": "jonwage@gmail.com" - }, - { - "name": "Johannes Schmitt", - "email": "schmittjoh@gmail.com" - } - ], - "description": "Docblock Annotations Parser", - "homepage": "http://www.doctrine-project.org", - "keywords": [ - "annotations", - "docblock", - "parser" - ], - "time": "2017-12-06T07:11:42+00:00" - }, - { - "name": "doctrine/collections", - "version": "v1.5.0", - "source": { - "type": "git", - "url": "https://github.com/doctrine/collections.git", - "reference": "a01ee38fcd999f34d9bfbcee59dbda5105449cbf" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/doctrine/collections/zipball/a01ee38fcd999f34d9bfbcee59dbda5105449cbf", - "reference": "a01ee38fcd999f34d9bfbcee59dbda5105449cbf", - "shasum": "" - }, - "require": { - "php": "^7.1" - }, - "require-dev": { - "doctrine/coding-standard": "~0.1@dev", - "phpunit/phpunit": "^5.7" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.3.x-dev" - } - }, - "autoload": { - "psr-0": { - "Doctrine\\Common\\Collections\\": "lib/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Roman Borschel", - "email": "roman@code-factory.org" - }, - { - "name": "Benjamin Eberlei", - "email": "kontakt@beberlei.de" - }, - { - "name": "Guilherme Blanco", - "email": "guilhermeblanco@gmail.com" - }, - { - "name": "Jonathan Wage", - "email": "jonwage@gmail.com" - }, - { - "name": "Johannes Schmitt", - "email": "schmittjoh@gmail.com" - } - ], - "description": "Collections Abstraction library", - "homepage": "http://www.doctrine-project.org", - "keywords": [ - "array", - "collections", - "iterator" - ], - "time": "2017-07-22T10:37:32+00:00" - }, { "name": "doctrine/instantiator", "version": "1.1.0", @@ -863,136 +626,41 @@ ], "time": "2017-07-22T11:58:36+00:00" }, - { - "name": "doctrine/lexer", - "version": "v1.0.1", - "source": { - "type": "git", - "url": "https://github.com/doctrine/lexer.git", - "reference": "83893c552fd2045dd78aef794c31e694c37c0b8c" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/doctrine/lexer/zipball/83893c552fd2045dd78aef794c31e694c37c0b8c", - "reference": "83893c552fd2045dd78aef794c31e694c37c0b8c", - "shasum": "" - }, - "require": { - "php": ">=5.3.2" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.0.x-dev" - } - }, - "autoload": { - "psr-0": { - "Doctrine\\Common\\Lexer\\": "lib/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Roman Borschel", - "email": "roman@code-factory.org" - }, - { - "name": "Guilherme Blanco", - "email": "guilhermeblanco@gmail.com" - }, - { - "name": "Johannes Schmitt", - "email": "schmittjoh@gmail.com" - } - ], - "description": "Base library for a lexer that can be used in Top-Down, Recursive Descent Parsers.", - "homepage": "http://www.doctrine-project.org", - "keywords": [ - "lexer", - "parser" - ], - "time": "2014-09-09T13:34:57+00:00" - }, - { - "name": "epfremme/swagger-php", - "version": "v2.0.0", - "source": { - "type": "git", - "url": "https://github.com/epfremmer/swagger-php.git", - "reference": "eee28a442b7e6220391ec953d3c9b936354f23bc" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/epfremmer/swagger-php/zipball/eee28a442b7e6220391ec953d3c9b936354f23bc", - "reference": "eee28a442b7e6220391ec953d3c9b936354f23bc", - "shasum": "" - }, - "require": { - "doctrine/annotations": "^1.2", - "doctrine/collections": "^1.3", - "jms/serializer": "^1.1", - "php": ">=5.5", - "phpoption/phpoption": "^1.1", - "symfony/yaml": "^2.7|^3.1" - }, - "require-dev": { - "mockery/mockery": "^0.9.4", - "phpunit/phpunit": "~4.8|~5.0", - "satooshi/php-coveralls": "^1.0" - }, - "type": "package", - "autoload": { - "psr-4": { - "Epfremme\\Swagger\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Edward Pfremmer", - "email": "epfremme@nerdery.com" - } - ], - "description": "Library for parsing swagger documentation into PHP entities for use in testing and code generation", - "time": "2016-09-26T17:24:17+00:00" - }, { "name": "facebook/webdriver", - "version": "1.5.0", + "version": "1.6.0", "source": { "type": "git", "url": "https://github.com/facebook/php-webdriver.git", - "reference": "86b5ca2f67173c9d34340845dd690149c886a605" + "reference": "bd8c740097eb9f2fc3735250fc1912bc811a954e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/facebook/php-webdriver/zipball/86b5ca2f67173c9d34340845dd690149c886a605", - "reference": "86b5ca2f67173c9d34340845dd690149c886a605", + "url": "https://api.github.com/repos/facebook/php-webdriver/zipball/bd8c740097eb9f2fc3735250fc1912bc811a954e", + "reference": "bd8c740097eb9f2fc3735250fc1912bc811a954e", "shasum": "" }, "require": { "ext-curl": "*", + "ext-json": "*", + "ext-mbstring": "*", "ext-zip": "*", "php": "^5.6 || ~7.0", "symfony/process": "^2.8 || ^3.1 || ^4.0" }, "require-dev": { "friendsofphp/php-cs-fixer": "^2.0", - "guzzle/guzzle": "^3.4.1", - "php-coveralls/php-coveralls": "^1.0.2", + "jakub-onderka/php-parallel-lint": "^0.9.2", + "php-coveralls/php-coveralls": "^2.0", "php-mock/php-mock-phpunit": "^1.1", "phpunit/phpunit": "^5.7", "sebastian/environment": "^1.3.4 || ^2.0 || ^3.0", "squizlabs/php_codesniffer": "^2.6", "symfony/var-dumper": "^3.3 || ^4.0" }, + "suggest": { + "ext-SimpleXML": "For Firefox profile creation" + }, "type": "library", "extra": { "branch-alias": { @@ -1016,98 +684,7 @@ "selenium", "webdriver" ], - "time": "2017-11-15T11:08:09+00:00" - }, - { - "name": "flow/jsonpath", - "version": "0.4.0", - "source": { - "type": "git", - "url": "https://github.com/FlowCommunications/JSONPath.git", - "reference": "f0222818d5c938e4ab668ab2e2c079bd51a27112" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/FlowCommunications/JSONPath/zipball/f0222818d5c938e4ab668ab2e2c079bd51a27112", - "reference": "f0222818d5c938e4ab668ab2e2c079bd51a27112", - "shasum": "" - }, - "require": { - "php": ">=5.4.0" - }, - "require-dev": { - "peekmo/jsonpath": "dev-master", - "phpunit/phpunit": "^4.0" - }, - "type": "library", - "autoload": { - "psr-0": { - "Flow\\JSONPath": "src/", - "Flow\\JSONPath\\Test": "tests/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Stephen Frank", - "email": "stephen@flowsa.com" - } - ], - "description": "JSONPath implementation for parsing, searching and flattening arrays", - "time": "2018-03-04T16:39:47+00:00" - }, - { - "name": "fzaninotto/faker", - "version": "v1.7.1", - "source": { - "type": "git", - "url": "https://github.com/fzaninotto/Faker.git", - "reference": "d3ed4cc37051c1ca52d22d76b437d14809fc7e0d" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/fzaninotto/Faker/zipball/d3ed4cc37051c1ca52d22d76b437d14809fc7e0d", - "reference": "d3ed4cc37051c1ca52d22d76b437d14809fc7e0d", - "shasum": "" - }, - "require": { - "php": "^5.3.3 || ^7.0" - }, - "require-dev": { - "ext-intl": "*", - "phpunit/phpunit": "^4.0 || ^5.0", - "squizlabs/php_codesniffer": "^1.5" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.8-dev" - } - }, - "autoload": { - "psr-4": { - "Faker\\": "src/Faker/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "François Zaninotto" - } - ], - "description": "Faker is a PHP library that generates fake data for you.", - "keywords": [ - "data", - "faker", - "fixtures" - ], - "time": "2017-08-15T16:48:10+00:00" + "time": "2018-05-16T17:37:13+00:00" }, { "name": "grasmash/expander", @@ -1206,16 +783,16 @@ }, { "name": "guzzlehttp/guzzle", - "version": "6.3.2", + "version": "6.3.3", "source": { "type": "git", "url": "https://github.com/guzzle/guzzle.git", - "reference": "68d0ea14d5a3f42a20e87632a5f84931e2709c90" + "reference": "407b0cb880ace85c9b63c5f9551db498cb2d50ba" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/guzzle/guzzle/zipball/68d0ea14d5a3f42a20e87632a5f84931e2709c90", - "reference": "68d0ea14d5a3f42a20e87632a5f84931e2709c90", + "url": "https://api.github.com/repos/guzzle/guzzle/zipball/407b0cb880ace85c9b63c5f9551db498cb2d50ba", + "reference": "407b0cb880ace85c9b63c5f9551db498cb2d50ba", "shasum": "" }, "require": { @@ -1225,7 +802,7 @@ }, "require-dev": { "ext-curl": "*", - "phpunit/phpunit": "^4.8.35 || ^5.7 || ^6.4", + "phpunit/phpunit": "^4.8.35 || ^5.7 || ^6.4 || ^7.0", "psr/log": "^1.0" }, "suggest": { @@ -1267,7 +844,7 @@ "rest", "web service" ], - "time": "2018-03-26T16:33:04+00:00" + "time": "2018-04-22T15:46:56+00:00" }, { "name": "guzzlehttp/promises", @@ -1375,185 +952,15 @@ ], "description": "PSR-7 message implementation that also provides common utility methods", "keywords": [ - "http", - "message", - "request", - "response", - "stream", - "uri", - "url" - ], - "time": "2017-03-20T17:10:46+00:00" - }, - { - "name": "jms/metadata", - "version": "1.6.0", - "source": { - "type": "git", - "url": "https://github.com/schmittjoh/metadata.git", - "reference": "6a06970a10e0a532fb52d3959547123b84a3b3ab" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/schmittjoh/metadata/zipball/6a06970a10e0a532fb52d3959547123b84a3b3ab", - "reference": "6a06970a10e0a532fb52d3959547123b84a3b3ab", - "shasum": "" - }, - "require": { - "php": ">=5.3.0" - }, - "require-dev": { - "doctrine/cache": "~1.0", - "symfony/cache": "~3.1" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.5.x-dev" - } - }, - "autoload": { - "psr-0": { - "Metadata\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "Apache-2.0" - ], - "authors": [ - { - "name": "Johannes M. Schmitt", - "email": "schmittjoh@gmail.com" - } - ], - "description": "Class/method/property metadata management in PHP", - "keywords": [ - "annotations", - "metadata", - "xml", - "yaml" - ], - "time": "2016-12-05T10:18:33+00:00" - }, - { - "name": "jms/parser-lib", - "version": "1.0.0", - "source": { - "type": "git", - "url": "https://github.com/schmittjoh/parser-lib.git", - "reference": "c509473bc1b4866415627af0e1c6cc8ac97fa51d" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/schmittjoh/parser-lib/zipball/c509473bc1b4866415627af0e1c6cc8ac97fa51d", - "reference": "c509473bc1b4866415627af0e1c6cc8ac97fa51d", - "shasum": "" - }, - "require": { - "phpoption/phpoption": ">=0.9,<2.0-dev" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.0-dev" - } - }, - "autoload": { - "psr-0": { - "JMS\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "Apache2" - ], - "description": "A library for easily creating recursive-descent parsers.", - "time": "2012-11-18T18:08:43+00:00" - }, - { - "name": "jms/serializer", - "version": "1.11.0", - "source": { - "type": "git", - "url": "https://github.com/schmittjoh/serializer.git", - "reference": "e7c53477ff55c21d1b1db7d062edc050a24f465f" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/schmittjoh/serializer/zipball/e7c53477ff55c21d1b1db7d062edc050a24f465f", - "reference": "e7c53477ff55c21d1b1db7d062edc050a24f465f", - "shasum": "" - }, - "require": { - "doctrine/annotations": "^1.0", - "doctrine/instantiator": "^1.0.3", - "jms/metadata": "~1.1", - "jms/parser-lib": "1.*", - "php": "^5.5|^7.0", - "phpcollection/phpcollection": "~0.1", - "phpoption/phpoption": "^1.1" - }, - "conflict": { - "twig/twig": "<1.12" - }, - "require-dev": { - "doctrine/orm": "~2.1", - "doctrine/phpcr-odm": "^1.3|^2.0", - "ext-pdo_sqlite": "*", - "jackalope/jackalope-doctrine-dbal": "^1.1.5", - "phpunit/phpunit": "^4.8|^5.0", - "propel/propel1": "~1.7", - "psr/container": "^1.0", - "symfony/dependency-injection": "^2.7|^3.3|^4.0", - "symfony/expression-language": "^2.6|^3.0", - "symfony/filesystem": "^2.1", - "symfony/form": "~2.1|^3.0", - "symfony/translation": "^2.1|^3.0", - "symfony/validator": "^2.2|^3.0", - "symfony/yaml": "^2.1|^3.0", - "twig/twig": "~1.12|~2.0" - }, - "suggest": { - "doctrine/cache": "Required if you like to use cache functionality.", - "doctrine/collections": "Required if you like to use doctrine collection types as ArrayCollection.", - "symfony/yaml": "Required if you'd like to serialize data to YAML format." - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.11-dev" - } - }, - "autoload": { - "psr-0": { - "JMS\\Serializer": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "Apache-2.0" - ], - "authors": [ - { - "name": "Asmir Mustafic", - "email": "goetas@gmail.com" - }, - { - "name": "Johannes M. Schmitt", - "email": "schmittjoh@gmail.com" - } - ], - "description": "Library for (de-)serializing data of any complexity; supports XML, JSON, and YAML.", - "homepage": "http://jmsyst.com/libs/serializer", - "keywords": [ - "deserialization", - "jaxb", - "json", - "serialization", - "xml" + "http", + "message", + "request", + "response", + "stream", + "uri", + "url" ], - "time": "2018-02-04T17:48:54+00:00" + "time": "2017-03-20T17:10:46+00:00" }, { "name": "league/container", @@ -1620,194 +1027,30 @@ ], "time": "2017-05-10T09:20:27+00:00" }, - { - "name": "magento/magento2-functional-testing-framework", - "version": "2.2.0", - "source": { - "type": "git", - "url": "git@github.com:magento/magento2-functional-testing-framework.git", - "reference": "4dd196d745bf836cbf0c5904a1df6dd241124309" - }, - "require": { - "allure-framework/allure-codeception": "~1.2.6", - "codeception/codeception": "~2.3.4", - "consolidation/robo": "^1.0.0", - "epfremme/swagger-php": "^2.0", - "flow/jsonpath": ">0.2", - "fzaninotto/faker": "^1.6", - "mustache/mustache": "~2.5", - "php": "7.0.2|7.0.4|~7.0.6|~7.1.0|~7.2.0", - "symfony/process": "^2.8 || ^3.1 || ^4.0", - "vlucas/phpdotenv": "^2.4" - }, - "require-dev": { - "brainmaestro/composer-git-hooks": "^2.3", - "codacy/coverage": "^1.4", - "codeception/aspect-mock": "^2.0", - "goaop/framework": "2.1.2", - "php-coveralls/php-coveralls": "^1.0", - "phpmd/phpmd": "^2.6.0", - "rregeer/phpunit-coverage-check": "^0.1.4", - "sebastian/phpcpd": "~3.0", - "squizlabs/php_codesniffer": "1.5.3", - "symfony/stopwatch": "~3.4.6" - }, - "bin": [ - "bin/mftf" - ], - "type": "library", - "extra": { - "hooks": { - "pre-push": "bin/all-checks" - } - }, - "autoload": { - "psr-4": { - "Magento\\FunctionalTestingFramework\\": "src/Magento/FunctionalTestingFramework", - "MFTF\\": "dev/tests/functional/MFTF" - } - }, - "autoload-dev": { - "psr-4": { - "tests\\unit\\": "dev/tests/unit" - } - }, - "scripts": { - "tests": [ - "bin/phpunit-checks" - ], - "static": [ - "bin/static-checks" - ] - }, - "license": [ - "AGPL-3.0" - ], - "description": "Magento2 Functional Testing Framework", - "keywords": [ - "automation", - "functional", - "magento", - "testing" - ], - "time": "2018-04-24T01:46:09+00:00" - }, - { - "name": "moontoast/math", - "version": "1.1.2", - "source": { - "type": "git", - "url": "https://github.com/ramsey/moontoast-math.git", - "reference": "c2792a25df5cad4ff3d760dd37078fc5b6fccc79" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/ramsey/moontoast-math/zipball/c2792a25df5cad4ff3d760dd37078fc5b6fccc79", - "reference": "c2792a25df5cad4ff3d760dd37078fc5b6fccc79", - "shasum": "" - }, - "require": { - "ext-bcmath": "*", - "php": ">=5.3.3" - }, - "require-dev": { - "jakub-onderka/php-parallel-lint": "^0.9.0", - "phpunit/phpunit": "^4.7|>=5.0 <5.4", - "satooshi/php-coveralls": "^0.6.1", - "squizlabs/php_codesniffer": "^2.3" - }, - "type": "library", - "autoload": { - "psr-4": { - "Moontoast\\Math\\": "src/Moontoast/Math/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "Apache-2.0" - ], - "authors": [ - { - "name": "Ben Ramsey", - "email": "ben@benramsey.com", - "homepage": "https://benramsey.com" - } - ], - "description": "A mathematics library, providing functionality for large numbers", - "homepage": "https://github.com/ramsey/moontoast-math", - "keywords": [ - "bcmath", - "math" - ], - "time": "2017-02-16T16:54:46+00:00" - }, - { - "name": "mustache/mustache", - "version": "v2.12.0", - "source": { - "type": "git", - "url": "https://github.com/bobthecow/mustache.php.git", - "reference": "fe8fe72e9d580591854de404cc59a1b83ca4d19e" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/bobthecow/mustache.php/zipball/fe8fe72e9d580591854de404cc59a1b83ca4d19e", - "reference": "fe8fe72e9d580591854de404cc59a1b83ca4d19e", - "shasum": "" - }, - "require": { - "php": ">=5.2.4" - }, - "require-dev": { - "friendsofphp/php-cs-fixer": "~1.11", - "phpunit/phpunit": "~3.7|~4.0|~5.0" - }, - "type": "library", - "autoload": { - "psr-0": { - "Mustache": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Justin Hileman", - "email": "justin@justinhileman.info", - "homepage": "http://justinhileman.com" - } - ], - "description": "A Mustache implementation in PHP.", - "homepage": "https://github.com/bobthecow/mustache.php", - "keywords": [ - "mustache", - "templating" - ], - "time": "2017-07-11T12:54:05+00:00" - }, { "name": "myclabs/deep-copy", - "version": "1.7.0", + "version": "1.8.1", "source": { "type": "git", "url": "https://github.com/myclabs/DeepCopy.git", - "reference": "3b8a3a99ba1f6a3952ac2747d989303cbd6b7a3e" + "reference": "3e01bdad3e18354c3dce54466b7fbe33a9f9f7f8" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/3b8a3a99ba1f6a3952ac2747d989303cbd6b7a3e", - "reference": "3b8a3a99ba1f6a3952ac2747d989303cbd6b7a3e", + "url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/3e01bdad3e18354c3dce54466b7fbe33a9f9f7f8", + "reference": "3e01bdad3e18354c3dce54466b7fbe33a9f9f7f8", "shasum": "" }, "require": { - "php": "^5.6 || ^7.0" + "php": "^7.1" + }, + "replace": { + "myclabs/deep-copy": "self.version" }, "require-dev": { "doctrine/collections": "^1.0", "doctrine/common": "^2.6", - "phpunit/phpunit": "^4.1" + "phpunit/phpunit": "^7.1" }, "type": "library", "autoload": { @@ -1830,55 +1073,7 @@ "object", "object graph" ], - "time": "2017-10-19T19:58:43+00:00" - }, - { - "name": "paragonie/random_compat", - "version": "v2.0.12", - "source": { - "type": "git", - "url": "https://github.com/paragonie/random_compat.git", - "reference": "258c89a6b97de7dfaf5b8c7607d0478e236b04fb" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/paragonie/random_compat/zipball/258c89a6b97de7dfaf5b8c7607d0478e236b04fb", - "reference": "258c89a6b97de7dfaf5b8c7607d0478e236b04fb", - "shasum": "" - }, - "require": { - "php": ">=5.2.0" - }, - "require-dev": { - "phpunit/phpunit": "4.*|5.*" - }, - "suggest": { - "ext-libsodium": "Provides a modern crypto API that can be used to generate random bytes." - }, - "type": "library", - "autoload": { - "files": [ - "lib/random.php" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Paragon Initiative Enterprises", - "email": "security@paragonie.com", - "homepage": "https://paragonie.com" - } - ], - "description": "PHP 5.x polyfill for random_bytes() and random_int() from PHP 7", - "keywords": [ - "csprng", - "pseudorandom", - "random" - ], - "time": "2018-04-04T21:24:14+00:00" + "time": "2018-06-11T23:09:50+00:00" }, { "name": "phar-io/manifest", @@ -1982,54 +1177,6 @@ "description": "Library for handling version information and constraints", "time": "2017-03-05T17:38:23+00:00" }, - { - "name": "phpcollection/phpcollection", - "version": "0.5.0", - "source": { - "type": "git", - "url": "https://github.com/schmittjoh/php-collection.git", - "reference": "f2bcff45c0da7c27991bbc1f90f47c4b7fb434a6" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/schmittjoh/php-collection/zipball/f2bcff45c0da7c27991bbc1f90f47c4b7fb434a6", - "reference": "f2bcff45c0da7c27991bbc1f90f47c4b7fb434a6", - "shasum": "" - }, - "require": { - "phpoption/phpoption": "1.*" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "0.4-dev" - } - }, - "autoload": { - "psr-0": { - "PhpCollection": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "Apache2" - ], - "authors": [ - { - "name": "Johannes M. Schmitt", - "email": "schmittjoh@gmail.com" - } - ], - "description": "General-Purpose Collection Library for PHP", - "keywords": [ - "collection", - "list", - "map", - "sequence", - "set" - ], - "time": "2015-05-17T12:39:23+00:00" - }, { "name": "phpdocumentor/reflection-common", "version": "1.0.1", @@ -2182,56 +1329,6 @@ ], "time": "2017-07-14T14:27:02+00:00" }, - { - "name": "phpoption/phpoption", - "version": "1.5.0", - "source": { - "type": "git", - "url": "https://github.com/schmittjoh/php-option.git", - "reference": "94e644f7d2051a5f0fcf77d81605f152eecff0ed" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/schmittjoh/php-option/zipball/94e644f7d2051a5f0fcf77d81605f152eecff0ed", - "reference": "94e644f7d2051a5f0fcf77d81605f152eecff0ed", - "shasum": "" - }, - "require": { - "php": ">=5.3.0" - }, - "require-dev": { - "phpunit/phpunit": "4.7.*" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.3-dev" - } - }, - "autoload": { - "psr-0": { - "PhpOption\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "Apache2" - ], - "authors": [ - { - "name": "Johannes M. Schmitt", - "email": "schmittjoh@gmail.com" - } - ], - "description": "Option Type for PHP", - "keywords": [ - "language", - "option", - "php", - "type" - ], - "time": "2015-07-25T16:39:46+00:00" - }, { "name": "phpspec/prophecy", "version": "1.7.6", @@ -2546,16 +1643,16 @@ }, { "name": "phpunit/phpunit", - "version": "6.5.8", + "version": "6.5.9", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/phpunit.git", - "reference": "4f21a3c6b97c42952fd5c2837bb354ec0199b97b" + "reference": "093ca5508174cd8ab8efe44fd1dde447adfdec8f" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/4f21a3c6b97c42952fd5c2837bb354ec0199b97b", - "reference": "4f21a3c6b97c42952fd5c2837bb354ec0199b97b", + "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/093ca5508174cd8ab8efe44fd1dde447adfdec8f", + "reference": "093ca5508174cd8ab8efe44fd1dde447adfdec8f", "shasum": "" }, "require": { @@ -2626,20 +1723,20 @@ "testing", "xunit" ], - "time": "2018-04-10T11:38:34+00:00" + "time": "2018-07-03T06:40:40+00:00" }, { "name": "phpunit/phpunit-mock-objects", - "version": "5.0.6", + "version": "5.0.8", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/phpunit-mock-objects.git", - "reference": "33fd41a76e746b8fa96d00b49a23dadfa8334cdf" + "reference": "6f9a3c8bf34188a2b53ce2ae7a126089c53e0a9f" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/phpunit-mock-objects/zipball/33fd41a76e746b8fa96d00b49a23dadfa8334cdf", - "reference": "33fd41a76e746b8fa96d00b49a23dadfa8334cdf", + "url": "https://api.github.com/repos/sebastianbergmann/phpunit-mock-objects/zipball/6f9a3c8bf34188a2b53ce2ae7a126089c53e0a9f", + "reference": "6f9a3c8bf34188a2b53ce2ae7a126089c53e0a9f", "shasum": "" }, "require": { @@ -2685,7 +1782,7 @@ "mock", "xunit" ], - "time": "2018-01-06T05:45:45+00:00" + "time": "2018-07-13T03:27:23+00:00" }, { "name": "psr/container", @@ -2833,86 +1930,6 @@ ], "time": "2016-10-10T12:19:37+00:00" }, - { - "name": "ramsey/uuid", - "version": "3.7.3", - "source": { - "type": "git", - "url": "https://github.com/ramsey/uuid.git", - "reference": "44abcdad877d9a46685a3a4d221e3b2c4b87cb76" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/ramsey/uuid/zipball/44abcdad877d9a46685a3a4d221e3b2c4b87cb76", - "reference": "44abcdad877d9a46685a3a4d221e3b2c4b87cb76", - "shasum": "" - }, - "require": { - "paragonie/random_compat": "^1.0|^2.0", - "php": "^5.4 || ^7.0" - }, - "replace": { - "rhumsaa/uuid": "self.version" - }, - "require-dev": { - "codeception/aspect-mock": "^1.0 | ~2.0.0", - "doctrine/annotations": "~1.2.0", - "goaop/framework": "1.0.0-alpha.2 | ^1.0 | ^2.1", - "ircmaxell/random-lib": "^1.1", - "jakub-onderka/php-parallel-lint": "^0.9.0", - "mockery/mockery": "^0.9.9", - "moontoast/math": "^1.1", - "php-mock/php-mock-phpunit": "^0.3|^1.1", - "phpunit/phpunit": "^4.7|^5.0", - "squizlabs/php_codesniffer": "^2.3" - }, - "suggest": { - "ext-libsodium": "Provides the PECL libsodium extension for use with the SodiumRandomGenerator", - "ext-uuid": "Provides the PECL UUID extension for use with the PeclUuidTimeGenerator and PeclUuidRandomGenerator", - "ircmaxell/random-lib": "Provides RandomLib for use with the RandomLibAdapter", - "moontoast/math": "Provides support for converting UUID to 128-bit integer (in string form).", - "ramsey/uuid-console": "A console application for generating UUIDs with ramsey/uuid", - "ramsey/uuid-doctrine": "Allows the use of Ramsey\\Uuid\\Uuid as Doctrine field type." - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "3.x-dev" - } - }, - "autoload": { - "psr-4": { - "Ramsey\\Uuid\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Marijn Huizendveld", - "email": "marijn.huizendveld@gmail.com" - }, - { - "name": "Thibaud Fabre", - "email": "thibaud@aztech.io" - }, - { - "name": "Ben Ramsey", - "email": "ben@benramsey.com", - "homepage": "https://benramsey.com" - } - ], - "description": "Formerly rhumsaa/uuid. A PHP 5.4+ library for generating RFC 4122 version 1, 3, 4, and 5 universally unique identifiers (UUID).", - "homepage": "https://github.com/ramsey/uuid", - "keywords": [ - "guid", - "identifier", - "uuid" - ], - "time": "2018-01-20T00:28:24+00:00" - }, { "name": "sebastian/code-unit-reverse-lookup", "version": "1.0.1", @@ -3474,16 +2491,16 @@ }, { "name": "symfony/browser-kit", - "version": "v4.0.8", + "version": "v4.1.2", "source": { "type": "git", "url": "https://github.com/symfony/browser-kit.git", - "reference": "c43bfa0182363b3fd64331b5e64e467349ff4670" + "reference": "ff9ac5d5808a530b2e7f6abcf3a2412d4f9bcd62" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/browser-kit/zipball/c43bfa0182363b3fd64331b5e64e467349ff4670", - "reference": "c43bfa0182363b3fd64331b5e64e467349ff4670", + "url": "https://api.github.com/repos/symfony/browser-kit/zipball/ff9ac5d5808a530b2e7f6abcf3a2412d4f9bcd62", + "reference": "ff9ac5d5808a530b2e7f6abcf3a2412d4f9bcd62", "shasum": "" }, "require": { @@ -3500,7 +2517,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "4.0-dev" + "dev-master": "4.1-dev" } }, "autoload": { @@ -3527,20 +2544,20 @@ ], "description": "Symfony BrowserKit Component", "homepage": "https://symfony.com", - "time": "2018-03-19T22:35:49+00:00" + "time": "2018-06-04T17:31:56+00:00" }, { "name": "symfony/console", - "version": "v4.0.8", + "version": "v4.1.2", "source": { "type": "git", "url": "https://github.com/symfony/console.git", - "reference": "aad9a6fe47319f22748fd764f52d3a7ca6fa6b64" + "reference": "5c31f6a97c1c240707f6d786e7e59bfacdbc0219" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/console/zipball/aad9a6fe47319f22748fd764f52d3a7ca6fa6b64", - "reference": "aad9a6fe47319f22748fd764f52d3a7ca6fa6b64", + "url": "https://api.github.com/repos/symfony/console/zipball/5c31f6a97c1c240707f6d786e7e59bfacdbc0219", + "reference": "5c31f6a97c1c240707f6d786e7e59bfacdbc0219", "shasum": "" }, "require": { @@ -3560,7 +2577,7 @@ "symfony/process": "~3.4|~4.0" }, "suggest": { - "psr/log": "For using the console logger", + "psr/log-implementation": "For using the console logger", "symfony/event-dispatcher": "", "symfony/lock": "", "symfony/process": "" @@ -3568,7 +2585,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "4.0-dev" + "dev-master": "4.1-dev" } }, "autoload": { @@ -3595,20 +2612,20 @@ ], "description": "Symfony Console Component", "homepage": "https://symfony.com", - "time": "2018-04-03T05:24:00+00:00" + "time": "2018-07-16T14:05:40+00:00" }, { "name": "symfony/css-selector", - "version": "v4.0.8", + "version": "v4.1.2", "source": { "type": "git", "url": "https://github.com/symfony/css-selector.git", - "reference": "03f965583147957f1ecbad7ea1c9d6fd5e525ec2" + "reference": "03ac71606ecb0b0ce792faa17d74cc32c2949ef4" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/css-selector/zipball/03f965583147957f1ecbad7ea1c9d6fd5e525ec2", - "reference": "03f965583147957f1ecbad7ea1c9d6fd5e525ec2", + "url": "https://api.github.com/repos/symfony/css-selector/zipball/03ac71606ecb0b0ce792faa17d74cc32c2949ef4", + "reference": "03ac71606ecb0b0ce792faa17d74cc32c2949ef4", "shasum": "" }, "require": { @@ -3617,7 +2634,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "4.0-dev" + "dev-master": "4.1-dev" } }, "autoload": { @@ -3648,24 +2665,25 @@ ], "description": "Symfony CssSelector Component", "homepage": "https://symfony.com", - "time": "2018-03-19T22:35:49+00:00" + "time": "2018-05-30T07:26:09+00:00" }, { "name": "symfony/dom-crawler", - "version": "v4.0.8", + "version": "v4.1.2", "source": { "type": "git", "url": "https://github.com/symfony/dom-crawler.git", - "reference": "d6c04c7532535b5e0b63db45b543cd60818e0fbc" + "reference": "eb501fa8aab8c8e2db790d8d0f945697769f6c41" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/dom-crawler/zipball/d6c04c7532535b5e0b63db45b543cd60818e0fbc", - "reference": "d6c04c7532535b5e0b63db45b543cd60818e0fbc", + "url": "https://api.github.com/repos/symfony/dom-crawler/zipball/eb501fa8aab8c8e2db790d8d0f945697769f6c41", + "reference": "eb501fa8aab8c8e2db790d8d0f945697769f6c41", "shasum": "" }, "require": { "php": "^7.1.3", + "symfony/polyfill-ctype": "~1.8", "symfony/polyfill-mbstring": "~1.0" }, "require-dev": { @@ -3677,7 +2695,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "4.0-dev" + "dev-master": "4.1-dev" } }, "autoload": { @@ -3704,20 +2722,20 @@ ], "description": "Symfony DomCrawler Component", "homepage": "https://symfony.com", - "time": "2018-03-19T22:35:49+00:00" + "time": "2018-07-05T11:54:23+00:00" }, { "name": "symfony/event-dispatcher", - "version": "v4.0.8", + "version": "v4.1.2", "source": { "type": "git", "url": "https://github.com/symfony/event-dispatcher.git", - "reference": "63353a71073faf08f62caab4e6889b06a787f07b" + "reference": "00d64638e4f0703a00ab7fc2c8ae5f75f3b4020f" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/63353a71073faf08f62caab4e6889b06a787f07b", - "reference": "63353a71073faf08f62caab4e6889b06a787f07b", + "url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/00d64638e4f0703a00ab7fc2c8ae5f75f3b4020f", + "reference": "00d64638e4f0703a00ab7fc2c8ae5f75f3b4020f", "shasum": "" }, "require": { @@ -3740,7 +2758,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "4.0-dev" + "dev-master": "4.1-dev" } }, "autoload": { @@ -3767,29 +2785,30 @@ ], "description": "Symfony EventDispatcher Component", "homepage": "https://symfony.com", - "time": "2018-04-06T07:35:43+00:00" + "time": "2018-07-10T11:02:47+00:00" }, { "name": "symfony/filesystem", - "version": "v4.0.8", + "version": "v4.1.2", "source": { "type": "git", "url": "https://github.com/symfony/filesystem.git", - "reference": "5d2d655b2c72fc4d9bf7e9bf14f72a447b940f21" + "reference": "562bf7005b55fd80d26b582d28e3e10f2dd5ae9c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/filesystem/zipball/5d2d655b2c72fc4d9bf7e9bf14f72a447b940f21", - "reference": "5d2d655b2c72fc4d9bf7e9bf14f72a447b940f21", + "url": "https://api.github.com/repos/symfony/filesystem/zipball/562bf7005b55fd80d26b582d28e3e10f2dd5ae9c", + "reference": "562bf7005b55fd80d26b582d28e3e10f2dd5ae9c", "shasum": "" }, "require": { - "php": "^7.1.3" + "php": "^7.1.3", + "symfony/polyfill-ctype": "~1.8" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "4.0-dev" + "dev-master": "4.1-dev" } }, "autoload": { @@ -3816,20 +2835,20 @@ ], "description": "Symfony Filesystem Component", "homepage": "https://symfony.com", - "time": "2018-02-22T10:50:29+00:00" + "time": "2018-05-30T07:26:09+00:00" }, { "name": "symfony/finder", - "version": "v4.0.8", + "version": "v4.1.2", "source": { "type": "git", "url": "https://github.com/symfony/finder.git", - "reference": "ca27c02b7a3fef4828c998c2ff9ba7aae1641c49" + "reference": "84714b8417d19e4ba02ea78a41a975b3efaafddb" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/finder/zipball/ca27c02b7a3fef4828c998c2ff9ba7aae1641c49", - "reference": "ca27c02b7a3fef4828c998c2ff9ba7aae1641c49", + "url": "https://api.github.com/repos/symfony/finder/zipball/84714b8417d19e4ba02ea78a41a975b3efaafddb", + "reference": "84714b8417d19e4ba02ea78a41a975b3efaafddb", "shasum": "" }, "require": { @@ -3838,7 +2857,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "4.0-dev" + "dev-master": "4.1-dev" } }, "autoload": { @@ -3865,41 +2884,37 @@ ], "description": "Symfony Finder Component", "homepage": "https://symfony.com", - "time": "2018-04-04T05:10:37+00:00" + "time": "2018-06-19T21:38:16+00:00" }, { - "name": "symfony/http-foundation", - "version": "v4.0.8", + "name": "symfony/polyfill-ctype", + "version": "v1.8.0", "source": { "type": "git", - "url": "https://github.com/symfony/http-foundation.git", - "reference": "d0864a82e5891ab61d31eecbaa48bed5a09b8e6c" + "url": "https://github.com/symfony/polyfill-ctype.git", + "reference": "7cc359f1b7b80fc25ed7796be7d96adc9b354bae" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/http-foundation/zipball/d0864a82e5891ab61d31eecbaa48bed5a09b8e6c", - "reference": "d0864a82e5891ab61d31eecbaa48bed5a09b8e6c", + "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/7cc359f1b7b80fc25ed7796be7d96adc9b354bae", + "reference": "7cc359f1b7b80fc25ed7796be7d96adc9b354bae", "shasum": "" }, "require": { - "php": "^7.1.3", - "symfony/polyfill-mbstring": "~1.1" - }, - "require-dev": { - "symfony/expression-language": "~3.4|~4.0" + "php": ">=5.3.3" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "4.0-dev" + "dev-master": "1.8-dev" } }, "autoload": { "psr-4": { - "Symfony\\Component\\HttpFoundation\\": "" + "Symfony\\Polyfill\\Ctype\\": "" }, - "exclude-from-classmap": [ - "/Tests/" + "files": [ + "bootstrap.php" ] }, "notification-url": "https://packagist.org/downloads/", @@ -3907,31 +2922,37 @@ "MIT" ], "authors": [ - { - "name": "Fabien Potencier", - "email": "fabien@symfony.com" - }, { "name": "Symfony Community", "homepage": "https://symfony.com/contributors" + }, + { + "name": "Gert de Pagter", + "email": "BackEndTea@gmail.com" } ], - "description": "Symfony HttpFoundation Component", + "description": "Symfony polyfill for ctype functions", "homepage": "https://symfony.com", - "time": "2018-04-03T05:24:00+00:00" + "keywords": [ + "compatibility", + "ctype", + "polyfill", + "portable" + ], + "time": "2018-04-30T19:57:29+00:00" }, { "name": "symfony/polyfill-mbstring", - "version": "v1.7.0", + "version": "v1.8.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-mbstring.git", - "reference": "78be803ce01e55d3491c1397cf1c64beb9c1b63b" + "reference": "3296adf6a6454a050679cde90f95350ad604b171" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/78be803ce01e55d3491c1397cf1c64beb9c1b63b", - "reference": "78be803ce01e55d3491c1397cf1c64beb9c1b63b", + "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/3296adf6a6454a050679cde90f95350ad604b171", + "reference": "3296adf6a6454a050679cde90f95350ad604b171", "shasum": "" }, "require": { @@ -3943,7 +2964,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "1.7-dev" + "dev-master": "1.8-dev" } }, "autoload": { @@ -3977,20 +2998,20 @@ "portable", "shim" ], - "time": "2018-01-30T19:27:44+00:00" + "time": "2018-04-26T10:06:28+00:00" }, { "name": "symfony/process", - "version": "v4.0.8", + "version": "v4.1.2", "source": { "type": "git", "url": "https://github.com/symfony/process.git", - "reference": "d7dc1ee5dfe9f732cb1bba7310f5b99f2b7a6d25" + "reference": "1d1677391ecf00d1c5b9482d6050c0c27aa3ac3a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/process/zipball/d7dc1ee5dfe9f732cb1bba7310f5b99f2b7a6d25", - "reference": "d7dc1ee5dfe9f732cb1bba7310f5b99f2b7a6d25", + "url": "https://api.github.com/repos/symfony/process/zipball/1d1677391ecf00d1c5b9482d6050c0c27aa3ac3a", + "reference": "1d1677391ecf00d1c5b9482d6050c0c27aa3ac3a", "shasum": "" }, "require": { @@ -3999,7 +3020,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "4.0-dev" + "dev-master": "4.1-dev" } }, "autoload": { @@ -4026,24 +3047,25 @@ ], "description": "Symfony Process Component", "homepage": "https://symfony.com", - "time": "2018-04-03T05:24:00+00:00" + "time": "2018-05-31T10:17:53+00:00" }, { "name": "symfony/yaml", - "version": "v3.4.8", + "version": "v4.1.2", "source": { "type": "git", "url": "https://github.com/symfony/yaml.git", - "reference": "a42f9da85c7c38d59f5e53f076fe81a091f894d0" + "reference": "80e4bfa9685fc4a09acc4a857ec16974a9cd944e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/yaml/zipball/a42f9da85c7c38d59f5e53f076fe81a091f894d0", - "reference": "a42f9da85c7c38d59f5e53f076fe81a091f894d0", + "url": "https://api.github.com/repos/symfony/yaml/zipball/80e4bfa9685fc4a09acc4a857ec16974a9cd944e", + "reference": "80e4bfa9685fc4a09acc4a857ec16974a9cd944e", "shasum": "" }, "require": { - "php": "^5.5.9|>=7.0.8" + "php": "^7.1.3", + "symfony/polyfill-ctype": "~1.8" }, "conflict": { "symfony/console": "<3.4" @@ -4057,7 +3079,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "3.4-dev" + "dev-master": "4.1-dev" } }, "autoload": { @@ -4084,7 +3106,7 @@ ], "description": "Symfony Yaml Component", "homepage": "https://symfony.com", - "time": "2018-04-03T05:14:20+00:00" + "time": "2018-05-30T07:26:09+00:00" }, { "name": "theseer/tokenizer", @@ -4128,28 +3150,28 @@ }, { "name": "vlucas/phpdotenv", - "version": "v2.4.0", + "version": "v2.5.0", "source": { "type": "git", "url": "https://github.com/vlucas/phpdotenv.git", - "reference": "3cc116adbe4b11be5ec557bf1d24dc5e3a21d18c" + "reference": "6ae3e2e6494bb5e58c2decadafc3de7f1453f70a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/vlucas/phpdotenv/zipball/3cc116adbe4b11be5ec557bf1d24dc5e3a21d18c", - "reference": "3cc116adbe4b11be5ec557bf1d24dc5e3a21d18c", + "url": "https://api.github.com/repos/vlucas/phpdotenv/zipball/6ae3e2e6494bb5e58c2decadafc3de7f1453f70a", + "reference": "6ae3e2e6494bb5e58c2decadafc3de7f1453f70a", "shasum": "" }, "require": { "php": ">=5.3.9" }, "require-dev": { - "phpunit/phpunit": "^4.8 || ^5.0" + "phpunit/phpunit": "^4.8.35 || ^5.0" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "2.4-dev" + "dev-master": "2.5-dev" } }, "autoload": { @@ -4159,7 +3181,7 @@ }, "notification-url": "https://packagist.org/downloads/", "license": [ - "BSD-3-Clause-Attribution" + "BSD-3-Clause" ], "authors": [ { @@ -4174,7 +3196,7 @@ "env", "environment" ], - "time": "2016-09-01T10:05:43+00:00" + "time": "2018-07-01T10:25:50+00:00" }, { "name": "webmozart/assert", @@ -4233,6 +3255,8 @@ "stability-flags": [], "prefer-stable": true, "prefer-lowest": false, - "platform": [], + "platform": { + "php": "~7.1.3||~7.2.0" + }, "platform-dev": [] } diff --git a/dev/tests/acceptance/pre-install.php b/dev/tests/acceptance/pre-install.php deleted file mode 100644 index 4021dc1094948..0000000000000 --- a/dev/tests/acceptance/pre-install.php +++ /dev/null @@ -1,395 +0,0 @@ -<?php -/** - * Copyright © Magento, Inc. All rights reserved. - * See COPYING.txt for license details. - */ - -/** - * @codingStandardsIgnoreStart - * @SuppressWarnings(PHPMD) - */ -class CliColors { - private $foreground_colors = array(); - private $background_colors = array(); - - public function __construct() { - // Set up shell colors - $this->foreground_colors['black'] = '0;30'; - $this->foreground_colors['dark_gray'] = '1;30'; - $this->foreground_colors['blue'] = '0;34'; - $this->foreground_colors['light_blue'] = '1;34'; - $this->foreground_colors['green'] = '0;32'; - $this->foreground_colors['light_green'] = '1;32'; - $this->foreground_colors['cyan'] = '0;36'; - $this->foreground_colors['light_cyan'] = '1;36'; - $this->foreground_colors['red'] = '0;31'; - $this->foreground_colors['light_red'] = '1;31'; - $this->foreground_colors['purple'] = '0;35'; - $this->foreground_colors['light_purple'] = '1;35'; - $this->foreground_colors['brown'] = '0;33'; - $this->foreground_colors['yellow'] = '1;33'; - $this->foreground_colors['light_gray'] = '0;37'; - $this->foreground_colors['white'] = '1;37'; - - $this->background_colors['black'] = '40'; - $this->background_colors['red'] = '41'; - $this->background_colors['green'] = '42'; - $this->background_colors['yellow'] = '43'; - $this->background_colors['blue'] = '44'; - $this->background_colors['magenta'] = '45'; - $this->background_colors['cyan'] = '46'; - $this->background_colors['light_gray'] = '47'; - } - - /** - * Returns colored string - * - * @param $string - * @param null $foreground_color - * @param null $background_color - * @return string - */ - public function getColoredString($string, $foreground_color = null, $background_color = null) { - $colored_string = ""; - - // Check if given foreground color found - if (isset($this->foreground_colors[$foreground_color])) { - $colored_string .= "\033[" . $this->foreground_colors[$foreground_color] . "m"; - } - // Check if given background color found - if (isset($this->background_colors[$background_color])) { - $colored_string .= "\033[" . $this->background_colors[$background_color] . "m"; - } - - // Add string and end coloring - $colored_string .= $string . "\033[0m"; - - return $colored_string; - } - - /** - * Returns all foreground color names - * - * @return array - */ - public function getForegroundColors() { - return array_keys($this->foreground_colors); - } - - /** - * Returns all background color names - * - * @return array - */ - public function getBackgroundColors() { - return array_keys($this->background_colors); - } -} - -/** - * @SuppressWarnings(PHPMD) - */ -class PreInstallCheck { - private $installedViaBrew = false; - private $filePath = ''; - private $seleniumJarVersion = ''; - - private $phpWebsite = 'http://php.net/manual/en/install.php'; - private $composerWebsite = 'https://getcomposer.org/download/'; - private $javaWebsite = 'https://www.java.com/en/download/'; - private $allureCliWebsite = 'https://docs.qameta.io/allure/latest/#_installing_a_commandline'; - private $seleniumWebsite = 'http://www.seleniumhq.org/download/'; - private $chromeDriverWebsite = 'https://sites.google.com/a/chromium.org/chromedriver/downloads'; - private $geckoDriverWebsite = 'https://github.com/mozilla/geckodriver'; - private $phantomJsWebsite = 'http://phantomjs.org/'; - - private $phpSupportedVersion = '7.1.0'; - private $composerSupportedVersion = '1.3.0'; - private $javaSupportedVersion = '1.8.0'; - private $allureCliSupportedVersion = '2.3.0'; - private $seleniumSupportedVersion = '3.6.0'; - private $chromeDriverSupportedVersion = '2.33.0'; - private $geckoDriverSupportedVersion = '0.19.0'; - private $phantomJsSupportedVersion = '2.1.0'; - - private $getPhpVersion; - private $getComposerVersion; - private $getJavaVersion; - private $getAllureCliVersion; - private $getSeleniumVersion; - private $getChromeDriverVersion; - private $getGeckoDriverVersion; - private $getPhantomJsVersion; - - private $phpVersion; - private $composerVersion; - private $javaVersion; - private $allureCliVersion; - private $seleniumVersion; - private $chromeDriverVersion; - private $geckoDriverVersion; - private $phantomJsVersion; - - private $phpStatus; - private $composerStatus; - private $javaStatus; - private $allureCliStatus; - private $seleniumStatus; - private $chromeDriverStatus; - private $geckoDriverStatus; - private $phantomJsStatus; - - function __construct() { - $this->didYouInstallViaBrew(); - - $this->getPhpVersion = shell_exec('php --version'); - $this->getComposerVersion = shell_exec('composer --version'); - $this->getJavaVersion = shell_exec("java -version 2>&1"); - $this->getAllureCliVersion = shell_exec('allure --version'); - $this->getSeleniumVersion = $this->getSeleniumVersion(); - $this->getChromeDriverVersion = $this->getChromeDriverVersion(); - $this->getGeckoDriverVersion = shell_exec('geckodriver --version'); - $this->getPhantomJsVersion = $this->getPhantomJsVersion(); - - $this->phpVersion = $this->parseVersion($this->getPhpVersion); - $this->composerVersion = $this->parseVersion($this->getComposerVersion); - $this->javaVersion = $this->parseJavaVersion($this->getJavaVersion); - $this->allureCliVersion = $this->parseVersion($this->getAllureCliVersion); - $this->seleniumVersion = $this->parseVersion($this->getSeleniumVersion); - $this->chromeDriverVersion = $this->parseVersion($this->getChromeDriverVersion); - $this->geckoDriverVersion = $this->parseVersion($this->getGeckoDriverVersion); - $this->phantomJsVersion = $this->parseVersion($this->getPhantomJsVersion); - - // String of null Versions - For Testing -// $this->phpVersion = null; -// $this->composerVersion = null; -// $this->javaVersion = null; -// $this->allureCliVersion = null; -// $this->seleniumVersion = null; -// $this->chromeDriverVersion = null; -// $this->geckoDriverVersion = null; -// $this->phantomJsVersion = null; - - // String of invalid Versions - For Testing -// $this->phpVersion = '7.0.0'; -// $this->composerVersion = '1.0.0'; -// $this->javaVersion = '1.0.0'; -// $this->allureCliVersion = '2.0.0'; -// $this->seleniumVersion = '3.0.0'; -// $this->chromeDriverVersion = '2.0.0'; -// $this->geckoDriverVersion = '0.0.0'; -// $this->phantomJsVersion = '2.0.0'; - - $this->phpStatus = $this->verifyVersion('PHP', $this->phpVersion, $this->phpSupportedVersion, $this->phpWebsite); - $this->composerStatus = $this->verifyVersion('Composer', $this->composerVersion, $this->composerSupportedVersion, $this->composerWebsite); - $this->javaStatus = $this->verifyVersion('Java', $this->javaVersion, $this->javaSupportedVersion, $this->javaWebsite); - $this->allureCliStatus = $this->verifyVersion('Allure CLI', $this->allureCliVersion, $this->allureCliSupportedVersion, $this->allureCliWebsite); - $this->seleniumStatus = $this->verifyVersion('Selenium Standalone Server', $this->seleniumVersion, $this->seleniumSupportedVersion, $this->seleniumWebsite); - $this->chromeDriverStatus = $this->verifyVersion('ChromeDriver', $this->chromeDriverVersion, $this->chromeDriverSupportedVersion, $this->chromeDriverWebsite); - $this->geckoDriverStatus = $this->verifyVersion('GeckoDriver', $this->geckoDriverVersion, $this->geckoDriverSupportedVersion, $this->geckoDriverWebsite); - $this->phantomJsStatus = $this->verifyVersion('PhantomJS', $this->phantomJsVersion, $this->phantomJsSupportedVersion, $this->phantomJsWebsite); - - ECHO "\n"; - $mask = "|%-13.13s |%18.18s |%18.18s |%-23.23s |\n"; - printf("---------------------------------------------------------------------------------\n"); - printf($mask, ' Software', 'Supported Version', 'Installed Version', ' Status'); - printf("---------------------------------------------------------------------------------\n"); - printf($mask, ' PHP', $this->phpSupportedVersion . '+', $this->phpVersion, ' ' . $this->phpStatus); - printf($mask, ' Composer', $this->composerSupportedVersion . '+', $this->composerVersion, ' ' . $this->composerStatus); - printf($mask, ' Java', $this->javaSupportedVersion . '+', $this->javaVersion, ' ' . $this->javaStatus); - printf($mask, ' Allure CLI', $this->allureCliSupportedVersion . '+', $this->allureCliVersion, ' ' . $this->allureCliStatus); - printf($mask, ' Selenium', $this->seleniumSupportedVersion . '+', $this->seleniumVersion, ' ' . $this->seleniumStatus); - printf($mask, ' ChromeDriver', $this->chromeDriverSupportedVersion . '+', $this->chromeDriverVersion, ' ' . $this->chromeDriverStatus); - printf($mask, ' GeckoDriver', $this->geckoDriverSupportedVersion . '+', $this->geckoDriverVersion, ' ' . $this->geckoDriverStatus); - printf($mask, ' PhantomJS', $this->phantomJsSupportedVersion . '+', $this->phantomJsVersion, ' ' . $this->phantomJsStatus); - printf("---------------------------------------------------------------------------------\n"); - } - - /** - * Ask if they installed the Browser Drivers via Brew. - * Brew installs things globally making them easier for us to access. - */ - public function didYouInstallViaBrew() - { - ECHO "Did you install Selenium Server, ChromeDriver, GeckoDriver and PhantomJS using Brew? (y/n) "; - $handle1 = fopen ("php://stdin","r"); - $line1 = fgets($handle1); - if (trim($line1) != 'y') { - ECHO "Where did you save the files? (ex /Users/first_last/Automation/) "; - $handle2 = fopen ("php://stdin","r"); - $this->filePath = fgets($handle2); - fclose($handle2); - - ECHO "Which selenium-server-standalone-X.X.X.jar file did you download? (ex 3.6.0) "; - $handle3 = fopen ("php://stdin","r"); - $this->seleniumJarVersion = fgets($handle3); - fclose($handle3); - fclose($handle1); - ECHO "\n"; - } else { - $this->installedViaBrew = true; - fclose($handle1); - ECHO "\n"; - } - } - - /** - * Parse the string that is returned for the Version number only. - * - * @param $stdout - * @return null - */ - public function parseVersion($stdout) - { - preg_match("/\d+(?:\.\d+)+/", $stdout, $matches); - - if (!is_null($matches) && isset($matches[0])) { - return $matches[0]; - } else { - return null; - } - } - - /** - * Parse the string that is returned for the Version number only. - * The message Java returns differs from the others hence the separate function. - * - * @param $stdout - * @return null - */ - public function parseJavaVersion($stdout) - { - preg_match('/\"(.+?)\"/', $stdout, $output_array); - - if (!is_null($output_array)) { - return $output_array[1]; - } else { - return null; - } - } - - /** - * Get the Selenium Server version based on how it was installed. - * - * @return string - */ - public function getSeleniumVersion() - { - $this->installedViaBrew; - $this->filePath; - $this->seleniumJarVersion; - - if ($this->installedViaBrew) { - return shell_exec('selenium-server --version'); - } else { - $command = sprintf('java -jar %s/selenium-server-standalone-%s.jar --version', $this->filePath, $this->seleniumJarVersion); - $command = str_replace(array("\r", "\n"), '', $command) . "\n"; - return shell_exec($command); - } - } - - /** - * Get the ChromeDriver version based on how it was installed. - * - * @return string - */ - public function getChromeDriverVersion() - { - $this->installedViaBrew; - $this->filePath; - - if ($this->installedViaBrew) { - return shell_exec('chromedriver --version'); - } else { - $command = sprintf('%s/chromedriver --version', $this->filePath); - $command = str_replace(array("\r", "\n"), '', $command) . "\n"; - return shell_exec($command); - } - } - - /** - * Get the PhantomJS version based on how it was installed. - * - * @return string - */ - public function getPhantomJsVersion() - { - $this->installedViaBrew; - $this->filePath; - - if ($this->installedViaBrew) { - return shell_exec('phantomjs --version'); - } else { - $command = sprintf('%s/phantomjs --version', $this->filePath); - $command = str_replace(array("\r", "\n"), '', $command) . "\n"; - return shell_exec($command); - } - } - - /** - * Print a "Valid Version Detected" message in color. - * - * @param $softwareName - */ - public function printValidVersion($softwareName) - { - $colors = new CliColors(); - $string = sprintf("%s detected. Version is supported!", $softwareName); - ECHO $colors->getColoredString($string, "black", "green") . "\n"; - } - - /** - * Print a "Upgraded Version Needed" message in color. - * - * @param $softwareName - * @param $supportedVersion - * @param $website - */ - public function printUpgradeVersion($softwareName, $supportedVersion, $website) - { - $colors = new CliColors(); - $string = sprintf("Unsupported version of %s detected. Please upgrade to v%s+: %s", $softwareName, $supportedVersion, $website); - ECHO $colors->getColoredString($string, "black", "yellow") . "\n"; - } - - /** - * Print a "Not Installed. Install Required." message in color. - * - * @param $softwareName - * @param $supportedVersion - * @param $website - */ - public function printNoInstalledVersion($softwareName, $supportedVersion, $website) - { - $colors = new CliColors(); - $string = sprintf("%s not detected. Please install v%s+: %s", $softwareName, $supportedVersion, $website); - ECHO $colors->getColoredString($string, "black", "red") . "\n"; - } - - /** - * Verify that the versions. - * Print the correct status message. - * - * @param $softwareName - * @param $installedVersion - * @param $supportedVersion - * @param $website - * @return string - */ - public function verifyVersion($softwareName, $installedVersion, $supportedVersion, $website) - { - if (is_null($installedVersion)) { - $this->printNoInstalledVersion($softwareName, $supportedVersion, $website); - return 'Installation Required!'; - } else if ($installedVersion >= $supportedVersion) { - $this->printValidVersion($softwareName); - return 'Correct Version!'; - } else { - $this->printUpgradeVersion($softwareName, $supportedVersion, $website); - return 'Upgrade Required!'; - } - } -} - -$preCheck = new PreInstallCheck(); -// @codingStandardsIgnoreEnd \ No newline at end of file diff --git a/dev/tests/acceptance/tests/_bootstrap.php b/dev/tests/acceptance/tests/_bootstrap.php index d15481d18098c..2fa2da03d8f8b 100644 --- a/dev/tests/acceptance/tests/_bootstrap.php +++ b/dev/tests/acceptance/tests/_bootstrap.php @@ -4,107 +4,6 @@ * See COPYING.txt for license details. */ -$bootstrapRoot = dirname(__DIR__); -$projectRootPath = $bootstrapRoot; - -// If we're under a vendor directory, find project root. -if (strpos($bootstrapRoot, '/vendor') !== false) { - $projectRootPath = substr($bootstrapRoot, 0, strpos($bootstrapRoot, '/vendor/')); -} - -define('PROJECT_ROOT', $projectRootPath); - - -//Load base paths from composer autoload file -$autoloadFile = PROJECT_ROOT . '/vendor/autoload.php'; - -$loader = require $autoloadFile; - -// Package Names. -$FW_PACKAGE_NAME = "Magento\FunctionalTestingFramework\\"; -$TESTS_PACKAGE_NAME = "TODO"; -$MAGENTO_PACKAGE_NAME = "Magento\\"; - -// Find framework path -$COMPOSER_FW_FULL_PREFIX = $loader->getPrefixesPsr4()[$FW_PACKAGE_NAME][0] ?? null; -if ($COMPOSER_FW_FULL_PREFIX === null) { - throw new Exception( - "You must have the magento/magento2-functional-testing-framework - installed to be able to generate tests." - ); -} -$FW_PATH = substr( - $COMPOSER_FW_FULL_PREFIX, - 0, - strpos($COMPOSER_FW_FULL_PREFIX, "/src/Magento/FunctionalTestingFramework") -); - -// Find tests path -$COMPOSER_TEST_FULL_PREFIX = $loader->getPrefixesPsr4()[$TESTS_PACKAGE_NAME][0] ?? null; -if ($COMPOSER_TEST_FULL_PREFIX === null) { - $TEST_PATH = __DIR__ . "/functional"; -} else { - // Can't determine what to trim; we don't know the package name/structure yet - $TEST_PATH = $COMPOSER_TEST_FULL_PREFIX; -} - -// We register "Magento\\" to "tests/functional/Magento" for our own class loading, need to try and find a -// prefix that isn't that one. -$COMPOSER_MAGENTO_PREFIXES = $loader->getPrefixesPsr4()[$MAGENTO_PACKAGE_NAME]; -$COMPOSER_MAGENTO_FULL_PREFIX = null; -foreach ($COMPOSER_MAGENTO_PREFIXES as $path) { - if (strpos($path, "tests/functional/Magento") === 0) { - $COMPOSER_MAGENTO_FULL_PREFIX = $path; - } -} -if ($COMPOSER_MAGENTO_FULL_PREFIX === null) { - $MAGENTO_PATH = dirname(__DIR__ . "/../../../../../"); -} else { - $MAGENTO_PATH = substr( - $COMPOSER_MAGENTO_FULL_PREFIX, - 0, - strpos($COMPOSER_MAGENTO_FULL_PREFIX, "/app/code/Magento") - ); -} - -$RELATIVE_TESTS_MODULE_PATH = '/Magento/FunctionalTest'; - -defined('MAGENTO_BP') || define('MAGENTO_BP', realpath($MAGENTO_PATH)); - -//Load constants from .env file -if (file_exists(MAGENTO_BP . '/dev/tests/acceptance/.env')) { - $env = new \Dotenv\Loader(MAGENTO_BP . '/dev/tests/acceptance/.env'); - $env->load(); - - if (array_key_exists('TESTS_MODULE_PATH', $_ENV) xor array_key_exists('TESTS_BP', $_ENV)) { - throw new Exception( - 'You must define both parameters TESTS_BP and TESTS_MODULE_PATH or neither parameter' - ); - } - - foreach ($_ENV as $key => $var) { - defined($key) || define($key, $var); - } - - defined('MAGENTO_CLI_COMMAND_PATH') || define( - 'MAGENTO_CLI_COMMAND_PATH', - 'dev/tests/acceptance/utils/command.php' - ); - $env->setEnvironmentVariable('MAGENTO_CLI_COMMAND_PATH', MAGENTO_CLI_COMMAND_PATH); - - defined('MAGENTO_CLI_COMMAND_PARAMETER') || define('MAGENTO_CLI_COMMAND_PARAMETER', 'command'); - $env->setEnvironmentVariable('MAGENTO_CLI_COMMAND_PARAMETER', MAGENTO_CLI_COMMAND_PARAMETER); -} - -defined('FW_BP') || define('FW_BP', realpath($FW_PATH)); -defined('TESTS_BP') || define('TESTS_BP', realpath($TEST_PATH)); -defined('TESTS_MODULE_PATH') || define( - 'TESTS_MODULE_PATH', - realpath($TEST_PATH . $RELATIVE_TESTS_MODULE_PATH) -); - -// add the debug flag here -$debug_mode = $_ENV['MFTF_DEBUG'] ?? false; -if (!(bool)$debug_mode && extension_loaded('xdebug')) { - xdebug_disable(); -} +//TODO remove this file once MFTF is fully decoupled from Magento +// Need to load in the root level autload file +require_once realpath(dirname(__DIR__) . "/../../../vendor/autoload.php"); diff --git a/dev/tests/acceptance/tests/functional.suite.dist.yml b/dev/tests/acceptance/tests/functional.suite.dist.yml deleted file mode 100644 index e01c46ea7c649..0000000000000 --- a/dev/tests/acceptance/tests/functional.suite.dist.yml +++ /dev/null @@ -1,42 +0,0 @@ -# Copyright © Magento, Inc. All rights reserved. -# See COPYING.txt for license details. - -# Codeception Test Suite Configuration -# -# Suite for acceptance tests. -# Perform tests in browser using the WebDriver or PhpBrowser. -# If you need both WebDriver and PHPBrowser tests - create a separate suite. - -class_name: AcceptanceTester -namespace: Magento\FunctionalTestingFramework -modules: - enabled: - - \Magento\FunctionalTestingFramework\Module\MagentoWebDriver - - \Magento\FunctionalTestingFramework\Helper\Acceptance - - \Magento\FunctionalTestingFramework\Helper\MagentoFakerData - - \Magento\FunctionalTestingFramework\Module\MagentoRestDriver: - url: "%MAGENTO_BASE_URL%/rest/default/V1/" - username: "%MAGENTO_ADMIN_USERNAME%" - password: "%MAGENTO_ADMIN_PASSWORD%" - depends: PhpBrowser - part: Json - - \Magento\FunctionalTestingFramework\Module\MagentoSequence - - \Magento\FunctionalTestingFramework\Module\MagentoAssert - - Asserts - config: - \Magento\FunctionalTestingFramework\Module\MagentoWebDriver: - url: "%MAGENTO_BASE_URL%" - backend_name: "%MAGENTO_BACKEND_NAME%" - browser: 'chrome' - window_size: maximize - username: "%MAGENTO_ADMIN_USERNAME%" - password: "%MAGENTO_ADMIN_PASSWORD%" - pageload_timeout: 30 - host: %SELENIUM_HOST% - port: %SELENIUM_PORT% - protocol: %SELENIUM_PROTOCOL% - path: %SELENIUM_PATH% - capabilities: - chromeOptions: - args: ["--start-maximized", "--disable-extensions", "--enable-automation"] - diff --git a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/ConfigurableProductCatalogSearch/composer.json b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/ConfigurableProductCatalogSearch/composer.json deleted file mode 100644 index df8598a93a2d8..0000000000000 --- a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/ConfigurableProductCatalogSearch/composer.json +++ /dev/null @@ -1,33 +0,0 @@ -{ - "name": "magento/magento2-functional-test-module-configurable-product-catalog-search", - "description": "Magento 2 Functional Test Module Configurable Product Catalog Search", - "type": "magento2-test-module", - "version": "100.0.0-dev", - "license": [ - "OSL-3.0", - "AFL-3.0" - ], - "config": { - "sort-packages": true - }, - "require": { - "magento/magento2-functional-testing-framework": "1.0.0", - "magento/magento2-functional-test-module-catalog": "100.0.0-dev", - "magento/magento2-functional-test-module-catalog-search": "100.0.0-dev", - "magento/magento2-functional-test-module-configurable-product": "100.0.0-dev", - "php": "~7.1.3||~7.2.0" - }, - "autoload": { - "psr-4": { - "Magento\\FunctionalTest\\ConfigurableProductCatalogSearch\\": "" - } - }, - "extra": { - "map": [ - [ - "*", - "tests/functional/Magento/FunctionalTest/ConfigurableProductCatalogSearch" - ] - ] - } -} diff --git a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/ConfigurableProductWishlist/composer.json b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/ConfigurableProductWishlist/composer.json deleted file mode 100644 index e7f61c1bc660d..0000000000000 --- a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/ConfigurableProductWishlist/composer.json +++ /dev/null @@ -1,33 +0,0 @@ -{ - "name": "magento/magento2-functional-test-module-configurable-product-wishlist", - "description": "Magento 2 Functional Test Module Configurable Product Wishlist", - "type": "magento2-test-module", - "version": "100.0.0-dev", - "license": [ - "OSL-3.0", - "AFL-3.0" - ], - "config": { - "sort-packages": true - }, - "require": { - "magento/magento2-functional-testing-framework": "1.0.0", - "magento/magento2-functional-test-module-catalog": "100.0.0-dev", - "magento/magento2-functional-test-module-configurable-product": "100.0.0-dev", - "magento/magento2-functional-test-module-wishlist": "100.0.0-dev", - "php": "~7.1.3||~7.2.0" - }, - "autoload": { - "psr-4": { - "Magento\\FunctionalTest\\ConfigurableProductWishlist\\": "" - } - }, - "extra": { - "map": [ - [ - "*", - "tests/functional/Magento/FunctionalTest/ConfigurableProductWishlist" - ] - ] - } -} diff --git a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Framework/composer.json b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Framework/composer.json deleted file mode 100644 index 3a00a525a5478..0000000000000 --- a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Framework/composer.json +++ /dev/null @@ -1,30 +0,0 @@ -{ - "name": "magento/magento2-functional-test-framework", - "description": "Magento 2 Functional Test Framework", - "type": "magento2-test-module", - "version": "100.0.0-dev", - "license": [ - "OSL-3.0", - "AFL-3.0" - ], - "config": { - "sort-packages": true - }, - "require": { - "magento/magento2-functional-testing-framework": "~2.0.0", - "php": "~7.1.3||~7.2.0" - }, - "autoload": { - "psr-4": { - "Magento\\FunctionalTest\\Framework\\": "" - } - }, - "extra": { - "map": [ - [ - "*", - "dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Framework" - ] - ] - } -} diff --git a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/SampleTemplates/composer.json b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/SampleTemplates/composer.json deleted file mode 100644 index e0ceb5bd23c1c..0000000000000 --- a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/SampleTemplates/composer.json +++ /dev/null @@ -1,30 +0,0 @@ -{ - "name": "magento/magento2-functional-test-module-sample-templates", - "description": "Magento 2 Functional Test Module Sample Templates", - "type": "magento2-test-module", - "version": "100.0.0-dev", - "license": [ - "OSL-3.0", - "AFL-3.0" - ], - "config": { - "sort-packages": true - }, - "require": { - "magento/magento2-functional-testing-framework": "1.0.0", - "php": "~7.1.3||~7.2.0" - }, - "autoload": { - "psr-4": { - "Magento\\FunctionalTest\\SampleTemplates\\": "" - } - }, - "extra": { - "map": [ - [ - "*", - "tests/functional/Magento/FunctionalTest/SampleTemplates" - ] - ] - } -} diff --git a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/SampleTests/Test/AdvancedSampleTest.xml b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/SampleTests/Test/AdvancedSampleTest.xml index d7a03d4f0198f..4fead0e51497e 100644 --- a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/SampleTests/Test/AdvancedSampleTest.xml +++ b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/SampleTests/Test/AdvancedSampleTest.xml @@ -16,7 +16,9 @@ <description value=""/> <severity value="CRITICAL"/> <testCaseId value="#"/> - <group value="skip"/> + <skip> + <issueId value="SAMPLE"/> + </skip> </annotations> <before> <createData entity="SamplePerson" stepKey="beforeData"/> diff --git a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/SampleTests/Test/AssertsTest.xml b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/SampleTests/Test/AssertsTest.xml index e1e0602d6103d..200c52cab797d 100644 --- a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/SampleTests/Test/AssertsTest.xml +++ b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/SampleTests/Test/AssertsTest.xml @@ -11,7 +11,9 @@ <test name="AssertsTest"> <annotations> <features value="SampleTests"/> - <group value="skip"/> + <skip> + <issueId value="SAMPLE"/> + </skip> </annotations> <createData entity="Simple_US_Customer" stepKey="createData2"/> diff --git a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/SampleTests/Test/CreateConfigurableProductByApiTest.xml b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/SampleTests/Test/CreateConfigurableProductByApiTest.xml index cf0ea0225a4b1..d759d1ab27498 100644 --- a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/SampleTests/Test/CreateConfigurableProductByApiTest.xml +++ b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/SampleTests/Test/CreateConfigurableProductByApiTest.xml @@ -12,7 +12,9 @@ <annotations> <features value="SampleTests"/> <stories value="Create a Configurable Product By API"/> - <group value="skip"/> + <skip> + <issueId value="SAMPLE"/> + </skip> </annotations> <before> <createData stepKey="categoryHandle" entity="SimpleSubCategory" /> diff --git a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/SampleTests/Test/CreateSalesRuleByApiTest.xml b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/SampleTests/Test/CreateSalesRuleByApiTest.xml index 8e9336dd6f149..8cd83fd62067f 100644 --- a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/SampleTests/Test/CreateSalesRuleByApiTest.xml +++ b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/SampleTests/Test/CreateSalesRuleByApiTest.xml @@ -12,7 +12,9 @@ <annotations> <features value="SampleTests"/> <stories value="Create a Sales Rule By API"/> - <group value="skip"/> + <skip> + <issueId value="SAMPLE"/> + </skip> </annotations> <before> <createData stepKey="saleRule" entity="SimpleSalesRule" /> diff --git a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/SampleTests/Test/PersistMultipleEntitiesTest.xml b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/SampleTests/Test/PersistMultipleEntitiesTest.xml index b809ab89cba52..6a196c2c32c02 100644 --- a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/SampleTests/Test/PersistMultipleEntitiesTest.xml +++ b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/SampleTests/Test/PersistMultipleEntitiesTest.xml @@ -11,7 +11,9 @@ <test name="PersistMultipleEntitiesTest"> <annotations> <features value="SampleTests"/> - <group value="skip"/> + <skip> + <issueId value="SAMPLE"/> + </skip> </annotations> <before> <createData entity="simplesubcategory" stepKey="simplecategory"/> diff --git a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/SampleTests/Test/SetPaymentConfigurationTest.xml b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/SampleTests/Test/SetPaymentConfigurationTest.xml index 1bc6bd1865f7c..f908c5cb4572e 100644 --- a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/SampleTests/Test/SetPaymentConfigurationTest.xml +++ b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/SampleTests/Test/SetPaymentConfigurationTest.xml @@ -11,7 +11,9 @@ <test name="SetPaypalConfigurationTest"> <annotations> <features value="SampleTests"/> - <group value="skip"/> + <skip> + <issueId value="SAMPLE"/> + </skip> </annotations> <createData entity="SamplePaypalConfig" stepKey="createSamplePaypalConfig"/> <createData entity="DefaultPayPalConfig" stepKey="restoreDefaultPaypalConfig"/> @@ -19,7 +21,9 @@ <test name="SetBraintreeConfigurationTest"> <annotations> <features value="SampleTests"/> - <group value="skip"/> + <skip> + <issueId value="SAMPLE"/> + </skip> </annotations> <createData entity="SampleBraintreeConfig" stepKey="createSampleBraintreeConfig"/> <createData entity="DefaultBraintreeConfig" stepKey="restoreDefaultBraintreeConfig"/> diff --git a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/SampleTests/Test/UpdateSimpleProductByApiTest.xml b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/SampleTests/Test/UpdateSimpleProductByApiTest.xml index fbf203834b45e..b18c24050d3a6 100644 --- a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/SampleTests/Test/UpdateSimpleProductByApiTest.xml +++ b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/SampleTests/Test/UpdateSimpleProductByApiTest.xml @@ -11,7 +11,9 @@ <annotations> <features value="SampleTests"/> <stories value="Update simple product by api test."/> - <group value="skip"/> + <skip> + <issueId value="SAMPLE"/> + </skip> </annotations> <before> <createData stepKey="categoryHandle" entity="SimpleSubCategory"/> diff --git a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/SampleTests/composer.json b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/SampleTests/composer.json deleted file mode 100644 index dc91e593e745b..0000000000000 --- a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/SampleTests/composer.json +++ /dev/null @@ -1,30 +0,0 @@ -{ - "name": "magento/magento2-functional-test-module-sample-tests", - "description": "Magento 2 Functional Test Module Sample Tests", - "type": "magento2-test-module", - "version": "100.0.0-dev", - "license": [ - "OSL-3.0", - "AFL-3.0" - ], - "config": { - "sort-packages": true - }, - "require": { - "magento/magento2-functional-testing-framework": "1.0.0", - "php": "~7.1.3||~7.2.0" - }, - "autoload": { - "psr-4": { - "Magento\\FunctionalTest\\SampleTests\\": "" - } - }, - "extra": { - "map": [ - [ - "*", - "tests/functional/Magento/FunctionalTest/SampleTests" - ] - ] - } -} diff --git a/dev/tests/acceptance/tests/functional/_bootstrap.php b/dev/tests/acceptance/tests/functional/_bootstrap.php deleted file mode 100644 index ac7a13ea41d29..0000000000000 --- a/dev/tests/acceptance/tests/functional/_bootstrap.php +++ /dev/null @@ -1,8 +0,0 @@ -<?php -/** - * Copyright © Magento, Inc. All rights reserved. - * See COPYING.txt for license details. - */ - -// Here you can initialize variables that will be available to your tests -require_once dirname(__DIR__) . '/_bootstrap.php'; diff --git a/dev/tests/acceptance/utils/command.php b/dev/tests/acceptance/utils/command.php deleted file mode 100644 index 943e2e9776af4..0000000000000 --- a/dev/tests/acceptance/utils/command.php +++ /dev/null @@ -1,69 +0,0 @@ -<?php -/** - * Copyright © Magento, Inc. All rights reserved. - * See COPYING.txt for license details. - */ - -if (isset($_POST['command'])) { - $command = urldecode($_POST['command']); - $php = PHP_BINARY ?: (PHP_BINDIR ? PHP_BINDIR . '/php' : 'php'); - $valid = validateCommand($command); - if ($valid) { - exec(escapeCommand($php . ' -f ../../../../bin/magento ' . $command) . " 2>&1", $output, $exitCode); - if ($exitCode == 0) { - http_response_code(202); - } else { - http_response_code(500); - } - echo implode("\n", $output); - } else { - http_response_code(403); - echo "Given command not found valid in Magento CLI Command list."; - } -} else { - http_response_code(412); - echo("Command parameter is not set."); -} - -/** - * Returns escaped command. - * - * @param string $command - * @return string - */ -function escapeCommand($command) -{ - $escapeExceptions = [ - '> /dev/null &' => '--dev-null-amp--' - ]; - - $command = escapeshellcmd( - str_replace(array_keys($escapeExceptions), array_values($escapeExceptions), $command) - ); - - return str_replace(array_values($escapeExceptions), array_keys($escapeExceptions), $command); -} - -/** - * Checks magento list of CLI commands for given $command. Does not check command parameters, just base command. - * @param string $command - * @return bool - */ -function validateCommand($command) -{ - $php = PHP_BINARY ?: (PHP_BINDIR ? PHP_BINDIR . '/php' : 'php'); - exec($php . ' -f ../../../../bin/magento list', $commandList); - // Trim list of commands after first whitespace - $commandList = array_map("trimAfterWhitespace", $commandList); - return in_array(trimAfterWhitespace($command), $commandList); -} - -/** - * Returns given string trimmed of everything after the first found whitespace. - * @param string $string - * @return string - */ -function trimAfterWhitespace($string) -{ - return strtok($string, ' '); -} diff --git a/dev/tests/api-functional/framework/Magento/TestFramework/TestCase/GraphQlAbstract.php b/dev/tests/api-functional/framework/Magento/TestFramework/TestCase/GraphQlAbstract.php index af01e455fdd9d..84ac6360643c4 100644 --- a/dev/tests/api-functional/framework/Magento/TestFramework/TestCase/GraphQlAbstract.php +++ b/dev/tests/api-functional/framework/Magento/TestFramework/TestCase/GraphQlAbstract.php @@ -92,9 +92,10 @@ private function getAppCache() private function getGraphQlClient() { if ($this->graphQlClient === null) { - return Bootstrap::getObjectManager()->get(\Magento\TestFramework\TestCase\GraphQl\Client::class); - } else { - $this->graphQlClient; + $this->graphQlClient = Bootstrap::getObjectManager()->get( + \Magento\TestFramework\TestCase\GraphQl\Client::class + ); } + return $this->graphQlClient; } } diff --git a/dev/tests/api-functional/testsuite/Magento/Catalog/Api/ProductCustomOptionRepositoryTest.php b/dev/tests/api-functional/testsuite/Magento/Catalog/Api/ProductCustomOptionRepositoryTest.php index 1cd9a5c2b9c86..e83811042fd8b 100644 --- a/dev/tests/api-functional/testsuite/Magento/Catalog/Api/ProductCustomOptionRepositoryTest.php +++ b/dev/tests/api-functional/testsuite/Magento/Catalog/Api/ProductCustomOptionRepositoryTest.php @@ -208,7 +208,7 @@ public function testAddNegative($optionData) ]; if (TESTS_WEB_API_ADAPTER == self::ADAPTER_SOAP) { - if (isset($optionDataPost['title']) && empty($optionDataPost['title'])) { + if ($optionDataPost['title'] === null || $optionDataPost['title'] === '') { $this->expectException('SoapFault'); $this->expectExceptionMessage('Missed values for option required fields'); } else { diff --git a/dev/tests/api-functional/testsuite/Magento/Catalog/Api/ProductRenderListInterfaceTest.php b/dev/tests/api-functional/testsuite/Magento/Catalog/Api/ProductRenderListInterfaceTest.php index 807269c03c06f..fb3ff3b134081 100644 --- a/dev/tests/api-functional/testsuite/Magento/Catalog/Api/ProductRenderListInterfaceTest.php +++ b/dev/tests/api-functional/testsuite/Magento/Catalog/Api/ProductRenderListInterfaceTest.php @@ -25,7 +25,6 @@ class ProductRenderListInterfaceTest extends WebapiAbstract * @magentoApiDataFixture Magento/Catalog/_files/product_special_price.php * @dataProvider productRenderInfoProvider * @param array $expectedRenderInfo - * @param string $ids * @return void */ public function testGetList(array $expectedRenderInfo) diff --git a/dev/tests/api-functional/testsuite/Magento/Catalog/Api/_files/product_options.php b/dev/tests/api-functional/testsuite/Magento/Catalog/Api/_files/product_options.php index 144f3a9926fe3..8a00de1be094f 100644 --- a/dev/tests/api-functional/testsuite/Magento/Catalog/Api/_files/product_options.php +++ b/dev/tests/api-functional/testsuite/Magento/Catalog/Api/_files/product_options.php @@ -10,7 +10,7 @@ 'type' => 'field', 'sort_order' => 1, 'is_require' => 1, - 'price' => 10, + 'price' => -10, 'price_type' => 'fixed', 'sku' => 'sku1', 'max_characters' => 10, diff --git a/dev/tests/api-functional/testsuite/Magento/Catalog/Api/_files/product_options_negative.php b/dev/tests/api-functional/testsuite/Magento/Catalog/Api/_files/product_options_negative.php index 5d2737b3aa532..f8890ca2eaac0 100644 --- a/dev/tests/api-functional/testsuite/Magento/Catalog/Api/_files/product_options_negative.php +++ b/dev/tests/api-functional/testsuite/Magento/Catalog/Api/_files/product_options_negative.php @@ -6,7 +6,7 @@ return [ 'empty_required_field' => [ - 'title' => '', + 'title' => null, 'type' => 'field', 'sort_order' => 1, 'is_require' => 1, @@ -15,17 +15,6 @@ 'sku' => 'sku1', 'max_characters' => 10, ], - 'negative_price' => [ - 'title' => 'area option', - 'type' => 'area', - 'sort_order' => 2, - 'is_require' => 0, - 'price' => -20, - 'price_type' => 'percent', - 'sku' => 'sku2', - 'max_characters' => 20, - - ], 'negative_value_of_image_size' => [ 'title' => 'file option', 'type' => 'file', @@ -54,7 +43,7 @@ 'price' => 10.0, 'price_type' => 'fixed', 'sku' => 'radio option 1 sku', - 'title' => '', + 'title' => null, 'sort_order' => 1, ], ], diff --git a/dev/tests/functional/.gitignore b/dev/tests/functional/.gitignore index d47f62b56bb9a..92e3004580b0c 100644 --- a/dev/tests/functional/.gitignore +++ b/dev/tests/functional/.gitignore @@ -6,3 +6,4 @@ /vendor phpunit.xml credentials.xml +.htaccess diff --git a/dev/tests/functional/bootstrap.php b/dev/tests/functional/bootstrap.php index 9967697124e80..04156ca88ea70 100644 --- a/dev/tests/functional/bootstrap.php +++ b/dev/tests/functional/bootstrap.php @@ -6,23 +6,25 @@ defined('MTF_BOOT_FILE') || define('MTF_BOOT_FILE', __FILE__); defined('MTF_BP') || define('MTF_BP', str_replace('\\', '/', (__DIR__))); +defined('BP') || define('BP', str_replace('\\', '/', dirname(dirname(dirname((__DIR__)))))); defined('MTF_TESTS_PATH') || define('MTF_TESTS_PATH', MTF_BP . '/tests/app/'); defined('MTF_STATES_PATH') || define('MTF_STATES_PATH', MTF_BP . '/lib/Magento/Mtf/App/State/'); -require_once __DIR__ . '/../../../app/bootstrap.php'; restore_error_handler(); -$vendorAutoload = __DIR__ . '/vendor/autoload.php'; - -if (isset($composerAutoloader)) { - /** var $mtfComposerAutoload \Composer\Autoload\ClassLoader */ - $mtfComposerAutoload = include $vendorAutoload; - $composerAutoloader->addClassMap($mtfComposerAutoload->getClassMap()); -} else { - $composerAutoloader = include $vendorAutoload; -} - +include __DIR__ . '/vendor/autoload.php'; setCustomErrorHandler(); +/* Custom umask value may be provided in optional mage_umask file in root */ +$umaskFile = BP . '/magento_umask'; +$mask = file_exists($umaskFile) ? octdec(file_get_contents($umaskFile)) : 002; +umask($mask); + +date_default_timezone_set('UTC'); + +/* For data consistency between displaying (printing) and serialization a float number */ +ini_set('precision', 14); +ini_set('serialize_precision', 14); + /** * Set custom error handler */ diff --git a/dev/tests/functional/lib/Magento/Mtf/Util/Generate/Factory.php b/dev/tests/functional/lib/Magento/Mtf/Util/Generate/Factory.php index 5bb1efee62959..192cab5751986 100644 --- a/dev/tests/functional/lib/Magento/Mtf/Util/Generate/Factory.php +++ b/dev/tests/functional/lib/Magento/Mtf/Util/Generate/Factory.php @@ -6,9 +6,6 @@ namespace Magento\Mtf\Util\Generate; -use Magento\Framework\App; -use Magento\Framework\ObjectManagerInterface; - /** * Factory classes generator. * @@ -16,24 +13,10 @@ */ class Factory extends AbstractGenerate { - /** - * @var \Magento\Framework\ObjectManagerInterface - */ - protected $objectManager; - - /** - * @constructor - * @param ObjectManagerInterface $objectManager - */ - public function __construct(ObjectManagerInterface $objectManager) - { - $this->objectManager = $objectManager; - } - /** * Generate Handlers. * - * @return \Magento\Framework\App\ResponseInterface + * @return bool */ public function launch() { @@ -43,7 +26,7 @@ public function launch() $this->objectManager->create(\Magento\Mtf\Util\Generate\Factory\Page::class)->launch(); $this->objectManager->create(\Magento\Mtf\Util\Generate\Factory\Repository::class)->launch(); - return $this->objectManager->get(\Magento\Framework\App\ResponseInterface::class); + return true; } /** diff --git a/dev/tests/functional/lib/Magento/Mtf/Util/ModuleResolver/SequenceSorter.php b/dev/tests/functional/lib/Magento/Mtf/Util/ModuleResolver/SequenceSorter.php index a4b438a1d2de0..110d9d5fbd6c3 100644 --- a/dev/tests/functional/lib/Magento/Mtf/Util/ModuleResolver/SequenceSorter.php +++ b/dev/tests/functional/lib/Magento/Mtf/Util/ModuleResolver/SequenceSorter.php @@ -10,37 +10,6 @@ */ class SequenceSorter implements SequenceSorterInterface { - /** - * Magento ObjectManager. - * - * @var \Magento\Framework\ObjectManagerInterface - */ - protected $magentoObjectManager; - - /** - * @constructor - */ - public function __construct() - { - $this->initObjectManager(); - } - - /** - * Initialize Magento ObjectManager. - * - * @return void - */ - protected function initObjectManager() - { - if (!$this->magentoObjectManager) { - $objectManagerFactory = \Magento\Framework\App\Bootstrap::createObjectManagerFactory( - BP, - $_SERVER - ); - $this->magentoObjectManager = $objectManagerFactory->create($_SERVER); - } - } - /** * Get Magento module sequence load. * @@ -48,7 +17,8 @@ protected function initObjectManager() */ protected function getModuleSequence() { - return $this->magentoObjectManager->create(\Magento\Framework\Module\ModuleList\Loader::class)->load(); + $ds = DIRECTORY_SEPARATOR; + return json_decode(file_get_contents(MTF_BP . $ds . 'generated' . $ds . 'moduleSequence.json'), true); } /** diff --git a/dev/tests/functional/tests/app/Magento/Backend/Test/Constraint/AssertHttpUsedOnFrontend.php b/dev/tests/functional/tests/app/Magento/Backend/Test/Constraint/AssertHttpUsedOnFrontend.php index f028a0bcf65ba..7d75db5f0368c 100644 --- a/dev/tests/functional/tests/app/Magento/Backend/Test/Constraint/AssertHttpUsedOnFrontend.php +++ b/dev/tests/functional/tests/app/Magento/Backend/Test/Constraint/AssertHttpUsedOnFrontend.php @@ -22,7 +22,7 @@ class AssertHttpUsedOnFrontend extends AbstractConstraint * * @var string */ - private $unsecuredProtocol = \Magento\Framework\HTTP\PhpEnvironment\Request::SCHEME_HTTP; + const SCHEME_HTTP = 'http'; /** * Browser interface. @@ -53,11 +53,11 @@ public function processAssert(BrowserInterface $browser, Customer $customer) // Log in to Customer Account on Storefront to assert that http is used indeed. $this->objectManager->create(LogInCustomerOnStorefront::class, ['customer' => $this->customer])->run(); - $this->assertUsedProtocol($this->unsecuredProtocol); + $this->assertUsedProtocol(self::SCHEME_HTTP); // Log out from Customer Account on Storefront to assert that JS is deployed validly as a part of statics. $this->objectManager->create(LogOutCustomerOnStorefront::class)->run(); - $this->assertUsedProtocol($this->unsecuredProtocol); + $this->assertUsedProtocol(self::SCHEME_HTTP); } /** diff --git a/dev/tests/functional/tests/app/Magento/Backend/Test/Constraint/AssertHttpsUsedOnBackend.php b/dev/tests/functional/tests/app/Magento/Backend/Test/Constraint/AssertHttpsUsedOnBackend.php index 5da51c8079d7f..cc64e4a4c7299 100644 --- a/dev/tests/functional/tests/app/Magento/Backend/Test/Constraint/AssertHttpsUsedOnBackend.php +++ b/dev/tests/functional/tests/app/Magento/Backend/Test/Constraint/AssertHttpsUsedOnBackend.php @@ -16,18 +16,10 @@ class AssertHttpsUsedOnBackend extends AbstractConstraint { /** - * Secured protocol format. - * - * @var string - */ - private $securedProtocol = \Magento\Framework\HTTP\PhpEnvironment\Request::SCHEME_HTTPS; - - /** - * Unsecured protocol format. - * - * @var string + * Protocols */ - private $unsecuredProtocol = \Magento\Framework\HTTP\PhpEnvironment\Request::SCHEME_HTTP; + const SCHEME_HTTP = 'http'; + const SCHEME_HTTPS = 'https'; /** * Browser interface. @@ -50,7 +42,7 @@ public function processAssert(BrowserInterface $browser, Dashboard $adminDashboa // Open specified Admin page using Navigation Menu to assert that JS is deployed validly as a part of statics. $adminDashboardPage->open()->getMenuBlock()->navigate($navMenuPath); - $this->assertUsedProtocol($this->securedProtocol); + $this->assertUsedProtocol(self::SCHEME_HTTPS); $this->assertDirectHttpUnavailable(); } @@ -80,10 +72,10 @@ protected function assertUsedProtocol($expectedProtocol) */ protected function assertDirectHttpUnavailable() { - $fakeUrl = str_replace($this->securedProtocol, $this->unsecuredProtocol, $this->browser->getUrl()); + $fakeUrl = str_replace(self::SCHEME_HTTPS, self::SCHEME_HTTP, $this->browser->getUrl()); $this->browser->open($fakeUrl); \PHPUnit\Framework\Assert::assertStringStartsWith( - $this->securedProtocol, + self::SCHEME_HTTPS, $this->browser->getUrl(), 'Merchant is not redirected to https if tries to access the Admin panel page directly via http.' ); diff --git a/dev/tests/functional/tests/app/Magento/Catalog/Test/Block/Adminhtml/Product/ProductForm.php b/dev/tests/functional/tests/app/Magento/Catalog/Test/Block/Adminhtml/Product/ProductForm.php index 9331c2c987549..61142adc8f9b3 100644 --- a/dev/tests/functional/tests/app/Magento/Catalog/Test/Block/Adminhtml/Product/ProductForm.php +++ b/dev/tests/functional/tests/app/Magento/Catalog/Test/Block/Adminhtml/Product/ProductForm.php @@ -28,7 +28,7 @@ class ProductForm extends FormSections * * @var string */ - protected $attribute = './/*[contains(@class,"label")]/span[text()="%s"]'; + protected $attribute = './/*[contains(@class,"label")]/label[text()="%s"]'; /** * Product new from date field on the product form diff --git a/dev/tests/functional/tests/app/Magento/Catalog/Test/Block/Product/View.php b/dev/tests/functional/tests/app/Magento/Catalog/Test/Block/Product/View.php index 2b72d2b915ee6..990906b7e302a 100644 --- a/dev/tests/functional/tests/app/Magento/Catalog/Test/Block/Product/View.php +++ b/dev/tests/functional/tests/app/Magento/Catalog/Test/Block/Product/View.php @@ -89,7 +89,7 @@ class View extends AbstractConfigureBlock * * @var string */ - protected $productDescription = '.product.attribute.description'; + protected $productDescription = '.product.attribute.description .value'; /** * Product short-description element. diff --git a/dev/tests/functional/tests/app/Magento/Checkout/Test/TestCase/OnePageCheckoutOfflinePaymentMethodsTest.xml b/dev/tests/functional/tests/app/Magento/Checkout/Test/TestCase/OnePageCheckoutOfflinePaymentMethodsTest.xml index b999900042c37..387e6418ee572 100644 --- a/dev/tests/functional/tests/app/Magento/Checkout/Test/TestCase/OnePageCheckoutOfflinePaymentMethodsTest.xml +++ b/dev/tests/functional/tests/app/Magento/Checkout/Test/TestCase/OnePageCheckoutOfflinePaymentMethodsTest.xml @@ -102,7 +102,7 @@ <constraint name="Magento\Sales\Test\Constraint\AssertOrderStatusIsCorrect" /> <constraint name="Magento\Sales\Test\Constraint\AssertOrderButtonsAvailable" /> <constraint name="Magento\Sales\Test\Constraint\AssertOrderGrandTotal" /> - <data name="issue" xsi:type="string">MAGETWO-66737: Magento\Checkout\Test\TestCase\OnePageCheckoutTest with OnePageCheckoutTestVariation3 is not stable</data> + <data name="issue" xsi:type="string">MAGETWO-66737: Magento\Checkout\Test\TestCase\OnePageCheckoutTest with OnePageCheckoutTestVariation3 and 4 is not stable</data> </variation> <variation name="OnePageCheckoutTestVariation4" summary="One Page Checkout Products with Special Prices" ticketId="MAGETWO-12429"> <data name="tag" xsi:type="string">test_type:acceptance_test, test_type:extended_acceptance_test, severity:S0</data> @@ -125,6 +125,7 @@ <constraint name="Magento\Shipping\Test\Constraint\AssertShipmentSuccessCreateMessage" /> <constraint name="Magento\Checkout\Test\Constraint\AssertMinicartEmpty" /> <constraint name="Magento\Sales\Test\Constraint\AssertOrderGrandTotal"/> + <data name="issue" xsi:type="string">MAGETWO-66737: Magento\Checkout\Test\TestCase\OnePageCheckoutTest with OnePageCheckoutTestVariation3 and 4 is not stable</data> </variation> <variation name="OnePageCheckoutTestVariation5" summary="Guest Checkout using Check/Money Order and Free Shipping with Prices/Taxes Verifications" ticketId="MAGETWO-12412"> <data name="tag" xsi:type="string">test_type:acceptance_test, test_type:extended_acceptance_test, severity:S0</data> diff --git a/dev/tests/functional/tests/app/Magento/Checkout/Test/TestCase/OnePageCheckoutTest.xml b/dev/tests/functional/tests/app/Magento/Checkout/Test/TestCase/OnePageCheckoutTest.xml index 9e20bbdaac1d9..5c05d4a840009 100644 --- a/dev/tests/functional/tests/app/Magento/Checkout/Test/TestCase/OnePageCheckoutTest.xml +++ b/dev/tests/functional/tests/app/Magento/Checkout/Test/TestCase/OnePageCheckoutTest.xml @@ -49,6 +49,10 @@ <constraint name="Magento\Checkout\Test\Constraint\AssertOrderSuccessPlacedMessage" /> <constraint name="Magento\Sales\Test\Constraint\AssertOrderGrandTotal" /> <constraint name="Magento\Sales\Test\Constraint\AssertOrderAddresses" /> + <!-- MAGETWO-94169 --> + <data name="tag" xsi:type="string">stable:no</data> + <data name="issue" xsi:type="string">MAGETWO-94169: [MTF] - OnePageCheckoutUsingNonDefaultAddress_0 fails on 2.3-develop</data> + <!-- MAGETWO-94169 --> </variation> <variation name="OnePageCheckoutUsingNewAddress" summary="Checkout as Customer using New address" ticketId="MAGETWO-42601"> <data name="tag" xsi:type="string">severity:S1</data> diff --git a/dev/tests/functional/tests/app/Magento/Checkout/Test/TestStep/AddProductsToTheCartStep.php b/dev/tests/functional/tests/app/Magento/Checkout/Test/TestStep/AddProductsToTheCartStep.php index 37a4d5c26189f..42d6c4502ef49 100644 --- a/dev/tests/functional/tests/app/Magento/Checkout/Test/TestStep/AddProductsToTheCartStep.php +++ b/dev/tests/functional/tests/app/Magento/Checkout/Test/TestStep/AddProductsToTheCartStep.php @@ -123,6 +123,7 @@ public function run() } } $cart['data']['items'] = ['products' => $this->products]; + sleep(10); return ['cart' => $this->fixtureFactory->createByCode('cart', $cart)]; } } diff --git a/dev/tests/functional/tests/app/Magento/Checkout/Test/TestStep/EstimateShippingAndTaxStep.php b/dev/tests/functional/tests/app/Magento/Checkout/Test/TestStep/EstimateShippingAndTaxStep.php index 21da4c66fa2f3..0780b7d13a285 100644 --- a/dev/tests/functional/tests/app/Magento/Checkout/Test/TestStep/EstimateShippingAndTaxStep.php +++ b/dev/tests/functional/tests/app/Magento/Checkout/Test/TestStep/EstimateShippingAndTaxStep.php @@ -107,6 +107,7 @@ public function run() { $this->checkoutCart->open(); $this->checkoutCart->getCartBlock()->waitCartContainerLoading(); + sleep(20); /** @var \Magento\Checkout\Test\Fixture\Cart $cart */ if ($this->cart !== null) { $cart = $this->fixtureFactory->createByCode( diff --git a/dev/tests/functional/tests/app/Magento/Checkout/Test/TestStep/SelectCheckoutMethodStep.php b/dev/tests/functional/tests/app/Magento/Checkout/Test/TestStep/SelectCheckoutMethodStep.php index 9df49d2440568..d951d84bab78d 100644 --- a/dev/tests/functional/tests/app/Magento/Checkout/Test/TestStep/SelectCheckoutMethodStep.php +++ b/dev/tests/functional/tests/app/Magento/Checkout/Test/TestStep/SelectCheckoutMethodStep.php @@ -91,8 +91,10 @@ public function __construct( */ public function run() { + sleep(20); $this->processLogin(); $this->processRegister(); + sleep(20); } /** diff --git a/dev/tests/functional/tests/app/Magento/Customer/Test/TestCase/CreateCustomerBackendEntityTest.php b/dev/tests/functional/tests/app/Magento/Customer/Test/TestCase/CreateCustomerBackendEntityTest.php index 1c697d9f1e5da..f1a8b17ae2855 100644 --- a/dev/tests/functional/tests/app/Magento/Customer/Test/TestCase/CreateCustomerBackendEntityTest.php +++ b/dev/tests/functional/tests/app/Magento/Customer/Test/TestCase/CreateCustomerBackendEntityTest.php @@ -6,9 +6,6 @@ namespace Magento\Customer\Test\TestCase; -use Magento\Config\Test\Fixture\ConfigData; -use Magento\Customer\Test\Constraint\AssertChangingWebsiteChangeCountries; -use Magento\Framework\App\ObjectManager; use Magento\Mtf\Fixture\FixtureFactory; use Magento\Mtf\Fixture\FixtureInterface; use Magento\Mtf\TestCase\Injectable; diff --git a/dev/tests/functional/tests/app/Magento/Sales/Test/Block/Adminhtml/Order/Creditmemo/Form/Items.php b/dev/tests/functional/tests/app/Magento/Sales/Test/Block/Adminhtml/Order/Creditmemo/Form/Items.php index 74d522e9545a8..431116903d372 100644 --- a/dev/tests/functional/tests/app/Magento/Sales/Test/Block/Adminhtml/Order/Creditmemo/Form/Items.php +++ b/dev/tests/functional/tests/app/Magento/Sales/Test/Block/Adminhtml/Order/Creditmemo/Form/Items.php @@ -51,6 +51,9 @@ public function getItemProductBlock($productSku) */ public function clickUpdateQty() { - $this->_rootElement->find($this->updateQty)->click(); + $button = $this->_rootElement->find($this->updateQty); + if (!$button->isDisabled()) { + $button->click(); + } } } diff --git a/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertNoCreditMemoButton.php b/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertNoCreditMemoButton.php index 22ba984b489e2..c9bdbac4aa7ec 100644 --- a/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertNoCreditMemoButton.php +++ b/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertNoCreditMemoButton.php @@ -30,7 +30,7 @@ public function processAssert(SalesOrderView $salesOrderView, OrderIndex $orderI $orderIndex->getSalesOrderGrid()->searchAndOpen(['id' => $order->getId()]); \PHPUnit\Framework\Assert::assertFalse( $salesOrderView->getPageActions()->isActionButtonVisible('Credit Memo'), - 'Credit memo button is present on order view page.' + 'Credit memo button should not be present on order view page.' ); } diff --git a/dev/tests/functional/tests/app/Magento/Setup/Test/Constraint/AssertSuccessfulReadinessCheck.php b/dev/tests/functional/tests/app/Magento/Setup/Test/Constraint/AssertSuccessfulReadinessCheck.php index 96fbc1905b5d0..676703924e59a 100644 --- a/dev/tests/functional/tests/app/Magento/Setup/Test/Constraint/AssertSuccessfulReadinessCheck.php +++ b/dev/tests/functional/tests/app/Magento/Setup/Test/Constraint/AssertSuccessfulReadinessCheck.php @@ -67,11 +67,13 @@ public function processAssert(SetupWizard $setupWizard) $setupWizard->getReadiness()->getDependencyCheck(), 'Dependency check is incorrect.' ); - \PHPUnit\Framework\Assert::assertContains( - self::PHP_VERSION_MESSAGE, - $setupWizard->getReadiness()->getPhpVersionCheck(), - 'PHP version is incorrect.' - ); + if ($setupWizard->getReadiness()->isPhpVersionCheckVisible()) { + \PHPUnit\Framework\Assert::assertContains( + self::PHP_VERSION_MESSAGE, + $setupWizard->getReadiness()->getPhpVersionCheck(), + 'PHP version is incorrect.' + ); + } \PHPUnit\Framework\Assert::assertContains( self::PHP_SETTING_REGEXP, $setupWizard->getReadiness()->getSettingsCheck(), diff --git a/dev/tests/functional/tests/app/Magento/Signifyd/Test/Block/SignifydConsole/CaseInfo.php b/dev/tests/functional/tests/app/Magento/Signifyd/Test/Block/SignifydConsole/CaseInfo.php index 5fe6096035803..1529755fdc3c9 100644 --- a/dev/tests/functional/tests/app/Magento/Signifyd/Test/Block/SignifydConsole/CaseInfo.php +++ b/dev/tests/functional/tests/app/Magento/Signifyd/Test/Block/SignifydConsole/CaseInfo.php @@ -73,7 +73,7 @@ class CaseInfo extends Block * * @var string */ - private $orderAmount = '[ng-bind*="currentCase.orderAmount"]'; + private $orderAmount = '[ng-bind*="currentCase.orderTotalAmount"]'; /** * Locator value for order amount currency. @@ -108,7 +108,7 @@ class CaseInfo extends Block * * @var string */ - private $shippingPrice = '[ng-if$="caseOrderSummary.shipments[0].shippingPrice"]'; + private $shippingPrice = '[ng-if="shipment.shippingPrice"]'; /** * Check if device data are present. diff --git a/dev/tests/functional/tests/app/Magento/Signifyd/Test/Block/SignifydConsole/CaseSearch.php b/dev/tests/functional/tests/app/Magento/Signifyd/Test/Block/SignifydConsole/CaseSearch.php index ef292de3a9e5f..16621f9a0cd48 100644 --- a/dev/tests/functional/tests/app/Magento/Signifyd/Test/Block/SignifydConsole/CaseSearch.php +++ b/dev/tests/functional/tests/app/Magento/Signifyd/Test/Block/SignifydConsole/CaseSearch.php @@ -33,6 +33,20 @@ class CaseSearch extends Form */ private $selectCaseLink = 'ul[case-list=cases] li[case-list-case=case] a'; + /** + * Locator for resolving applied filters list. + * + * @var string + */ + private $appliedFilters = '.app-taglist > ul > li > a'; + + /** + * Locator for loading spinner. + * + * @var string + */ + private $spinner = '.cases-loading-spinner'; + /** * Fill search input with customer name and submit. * @@ -41,8 +55,46 @@ class CaseSearch extends Form */ public function searchCaseByCustomerName($customerName) { + $this->resetFilters(); $this->_rootElement->find($this->searchBar)->setValue($customerName); $this->_rootElement->find($this->submitButton)->click(); + $this->waitLoadingSpinner(); + } + + /** + * Reset applied filters. + * + * @return void + */ + private function resetFilters(): void + { + $filters = $this->_rootElement->getElements($this->appliedFilters); + if (!empty($filters)) { + foreach ($filters as $filter) { + $filter->click(); + $this->waitLoadingSpinner(); + } + } + } + + /** + * Wait until loading spinner disappeared. + * + * @return void + */ + private function waitLoadingSpinner(): void + { + $this->waitForElementNotVisible($this->spinner); + } + + /** + * Checks if any case is visible. + * + * @return bool + */ + public function isAnyCaseVisible(): bool + { + return $this->_rootElement->find($this->selectCaseLink)->isVisible(); } /** diff --git a/dev/tests/functional/tests/app/Magento/Signifyd/Test/Block/SignifydConsole/SignifydLogin.php b/dev/tests/functional/tests/app/Magento/Signifyd/Test/Block/SignifydConsole/SignifydLogin.php index 7f530afe4df63..7705a67360e55 100644 --- a/dev/tests/functional/tests/app/Magento/Signifyd/Test/Block/SignifydConsole/SignifydLogin.php +++ b/dev/tests/functional/tests/app/Magento/Signifyd/Test/Block/SignifydConsole/SignifydLogin.php @@ -6,6 +6,8 @@ namespace Magento\Signifyd\Test\Block\SignifydConsole; use Magento\Mtf\Block\Form; +use Magento\Mtf\Client\Element\SimpleElement; +use Magento\Mtf\Fixture\FixtureInterface; /** * Signifyd login block. @@ -19,6 +21,23 @@ class SignifydLogin extends Form */ private $loginButton = '[type=submit]'; + /** + * Locator for admin form notification window. + * + * @var string + */ + private $notificationCloseButton = '.wm-close-button'; + + /** + * @inheritdoc + */ + public function fill(FixtureInterface $fixture, SimpleElement $element = null) + { + $this->closeNotification(); + + return parent::fill($fixture, $element); + } + /** * Login to Signifyd. * @@ -26,6 +45,20 @@ class SignifydLogin extends Form */ public function login() { + $this->closeNotification(); $this->_rootElement->find($this->loginButton)->click(); } + + /** + * Close notification popup. + * + * @return void + */ + private function closeNotification(): void + { + $notification = $this->browser->find($this->notificationCloseButton); + if ($notification->isVisible()) { + $notification->click(); + } + } } diff --git a/dev/tests/functional/tests/app/Magento/Signifyd/Test/TestCase/CreateSignifydGuaranteeAndCancelOrderTest.xml b/dev/tests/functional/tests/app/Magento/Signifyd/Test/TestCase/CreateSignifydGuaranteeAndCancelOrderTest.xml index 404229c2451cd..082627fe5821d 100644 --- a/dev/tests/functional/tests/app/Magento/Signifyd/Test/TestCase/CreateSignifydGuaranteeAndCancelOrderTest.xml +++ b/dev/tests/functional/tests/app/Magento/Signifyd/Test/TestCase/CreateSignifydGuaranteeAndCancelOrderTest.xml @@ -62,7 +62,6 @@ <constraint name="Magento\Sales\Test\Constraint\AssertCancelInCommentsHistory" /> <constraint name="Magento\Signifyd\Test\Constraint\AssertSignifydCaseInCommentsHistory" /> <constraint name="Magento\Signifyd\Test\Constraint\AssertAwaitingSignifydGuaranteeInCommentsHistory" /> - <constraint name="Magento\Signifyd\Test\Constraint\AssertSignifydGuaranteeCancelInCommentsHistory" /> </variation> </testCase> </config> diff --git a/dev/tests/functional/tests/app/Magento/Signifyd/Test/TestStep/SignifydObserveCaseStep.php b/dev/tests/functional/tests/app/Magento/Signifyd/Test/TestStep/SignifydObserveCaseStep.php index 126e32489e6c9..c00c81fa237e0 100644 --- a/dev/tests/functional/tests/app/Magento/Signifyd/Test/TestStep/SignifydObserveCaseStep.php +++ b/dev/tests/functional/tests/app/Magento/Signifyd/Test/TestStep/SignifydObserveCaseStep.php @@ -75,6 +75,11 @@ class SignifydObserveCaseStep implements TestStepInterface */ private $testStepFactory; + /** + * @var int + */ + private $searchAttempts = 10; + /** * @param AssertCaseInfoOnSignifydConsole $assertCaseInfoOnSignifydConsole * @param SignifydAddress $signifydAddress @@ -111,8 +116,16 @@ public function __construct( public function run() { $this->signifydCases->open(); - $this->signifydCases->getCaseSearchBlock() - ->searchCaseByCustomerName($this->signifydAddress->getFirstname()); + // Search case few times because it can appear with delay. + for ($attempts = $this->searchAttempts; $attempts > 0; $attempts--) { + $this->signifydCases->getCaseSearchBlock() + ->searchCaseByCustomerName($this->signifydAddress->getFirstname()); + if ($this->signifydCases->getCaseSearchBlock()->isAnyCaseVisible()) { + break; + } + sleep(3); + } + $this->signifydCases->getCaseSearchBlock()->selectCase(); $this->signifydCases->getCaseInfoBlock()->flagCase($this->signifydData->getCaseFlag()); diff --git a/dev/tests/functional/tests/app/Magento/Ui/Test/Block/Adminhtml/FormSections.php b/dev/tests/functional/tests/app/Magento/Ui/Test/Block/Adminhtml/FormSections.php index c98b5a874a762..170fef137ec9f 100644 --- a/dev/tests/functional/tests/app/Magento/Ui/Test/Block/Adminhtml/FormSections.php +++ b/dev/tests/functional/tests/app/Magento/Ui/Test/Block/Adminhtml/FormSections.php @@ -6,7 +6,6 @@ namespace Magento\Ui\Test\Block\Adminhtml; -use Magento\Framework\Exception\LocalizedException; use Magento\Mtf\Fixture\InjectableFixture; /** @@ -53,13 +52,13 @@ protected function openContainer($sectionName) * * @param string $sectionName * @return $this - * @throws LocalizedException if section is not visible + * @throws \Exception if section is not visible */ public function openSection($sectionName) { $container = $this->getContainerElement($sectionName); if (!$container->isVisible()) { - throw new LocalizedException(__('Container is not found "' . $sectionName . '""')); + throw new \Exception('Container is not found "' . $sectionName . '""'); } $section = $container->find($this->collapsedSection); if ($section->isVisible()) { diff --git a/dev/tests/functional/utils/bootstrap.php b/dev/tests/functional/utils/bootstrap.php index 00c548e6b5cef..0b74dc6727a13 100644 --- a/dev/tests/functional/utils/bootstrap.php +++ b/dev/tests/functional/utils/bootstrap.php @@ -16,6 +16,3 @@ $objectManager = \Magento\Mtf\ObjectManagerFactory::getObjectManager(); \Magento\Mtf\ObjectManagerFactory::configure($objectManager); - -$magentoObjectManagerFactory = \Magento\Framework\App\Bootstrap::createObjectManagerFactory(BP, $_SERVER); -$magentoObjectManager = $magentoObjectManagerFactory->create($_SERVER); diff --git a/dev/tests/functional/utils/generate.php b/dev/tests/functional/utils/generate.php index e9a81a1eea224..61bcc3523f551 100644 --- a/dev/tests/functional/utils/generate.php +++ b/dev/tests/functional/utils/generate.php @@ -3,19 +3,15 @@ * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ -use Magento\Framework\App\Filesystem\DirectoryList; -use Magento\Framework\Filesystem; require_once dirname(__FILE__) . '/' . 'bootstrap.php'; -// Generate fixtures -$magentoObjectManagerFactory = \Magento\Framework\App\Bootstrap::createObjectManagerFactory(BP, $_SERVER); -$magentoObjectManager = $magentoObjectManagerFactory->create($_SERVER); -// Remove previously generated static classes -$fs = $magentoObjectManager->create(Filesystem::class); -$fs->getDirectoryWrite(DirectoryList::ROOT)->delete('dev/tests/functional/generated/'); +deleteDirectory(MTF_BP . '/generated'); + +// Generate moduleSequence.json file +generateModuleSequence(); // Generate factories for old end-to-end tests -$magentoObjectManager->create(\Magento\Mtf\Util\Generate\Factory::class)->launch(); +$objectManager->create(\Magento\Mtf\Util\Generate\Factory::class)->launch(); $generatorPool = $objectManager->get('Magento\Mtf\Util\Generate\Pool'); foreach ($generatorPool->getGenerators() as $generator) { @@ -28,3 +24,28 @@ } \Magento\Mtf\Util\Generate\GenerateResult::displayResults(); + + +function deleteDirectory($dir) +{ + if (!file_exists($dir)) { + return true; + } + if (!is_dir($dir)) { + return unlink($dir); + } + foreach (scandir($dir) as $item) { + if ($item == '.' || $item == '..') { + continue; + } + if (!deleteDirectory($dir . DIRECTORY_SEPARATOR . $item)) { + return false; + } + } + return rmdir($dir); +} + +function generateModuleSequence() +{ + require_once "generate/moduleSequence.php"; +} diff --git a/dev/tests/functional/utils/generate/fixture.php b/dev/tests/functional/utils/generate/fixture.php index 9f454fb9dc5f1..68cdae4552261 100644 --- a/dev/tests/functional/utils/generate/fixture.php +++ b/dev/tests/functional/utils/generate/fixture.php @@ -5,6 +5,4 @@ */ require_once dirname(__DIR__) . '/' . 'bootstrap.php'; -$magentoObjectManagerFactory = \Magento\Framework\App\Bootstrap::createObjectManagerFactory(BP, $_SERVER); -$magentoObjectManager = $magentoObjectManagerFactory->create($_SERVER); $objectManager->create(\Magento\Mtf\Util\Generate\Fixture::class)->launch(); diff --git a/dev/tests/functional/utils/generate/moduleSequence.php b/dev/tests/functional/utils/generate/moduleSequence.php new file mode 100644 index 0000000000000..22688d1b75820 --- /dev/null +++ b/dev/tests/functional/utils/generate/moduleSequence.php @@ -0,0 +1,20 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ + +declare(strict_types=1); + +require_once __DIR__ . '/../../../../../app/bootstrap.php'; + +$magentoObjectManagerFactory = \Magento\Framework\App\Bootstrap::createObjectManagerFactory(BP, $_SERVER); +$magentoObjectManager = $magentoObjectManagerFactory->create($_SERVER); +$magentoComponentSequence = $magentoObjectManager->create(\Magento\Framework\Module\ModuleList\Loader::class)->load(); +if (!file_exists(dirname(dirname(__DIR__)) . DIRECTORY_SEPARATOR . 'generated')) { + mkdir(dirname(dirname(__DIR__)) . DIRECTORY_SEPARATOR . 'generated'); +} +file_put_contents( + dirname(dirname(__DIR__)) . DIRECTORY_SEPARATOR . 'generated' . DIRECTORY_SEPARATOR . 'moduleSequence.json', + json_encode($magentoComponentSequence, JSON_PRETTY_PRINT) +); diff --git a/dev/tests/functional/utils/generate/repository.php b/dev/tests/functional/utils/generate/repository.php index b2dc75c076f43..6633e776c9410 100644 --- a/dev/tests/functional/utils/generate/repository.php +++ b/dev/tests/functional/utils/generate/repository.php @@ -5,5 +5,4 @@ */ require_once dirname(__DIR__) . '/' . 'bootstrap.php'; -$magentoObjectManager->get(\Magento\Framework\App\State::class)->setAreaCode('frontend'); $objectManager->create(\Magento\Mtf\Util\Generate\Repository::class)->launch(); diff --git a/dev/tests/functional/utils/generateFixtureXml.php b/dev/tests/functional/utils/generateFixtureXml.php deleted file mode 100644 index 73fc266f34052..0000000000000 --- a/dev/tests/functional/utils/generateFixtureXml.php +++ /dev/null @@ -1,12 +0,0 @@ -<?php -/** - * Copyright © Magento, Inc. All rights reserved. - * See COPYING.txt for license details. - */ - -require_once dirname(__FILE__) . DIRECTORY_SEPARATOR . 'bootstrap.php'; - -$magentoObjectManager->create( - \Magento\Mtf\Util\Generate\Fixture\SchemaXml::class, - ['objectManager' => $magentoObjectManager] -)->launch(); diff --git a/dev/tests/integration/testsuite/Magento/AdvancedPricingImportExport/Model/Export/AdvancedPricingTest.php b/dev/tests/integration/testsuite/Magento/AdvancedPricingImportExport/Model/Export/AdvancedPricingTest.php index 1aea568395c99..481cc629c6777 100644 --- a/dev/tests/integration/testsuite/Magento/AdvancedPricingImportExport/Model/Export/AdvancedPricingTest.php +++ b/dev/tests/integration/testsuite/Magento/AdvancedPricingImportExport/Model/Export/AdvancedPricingTest.php @@ -7,7 +7,7 @@ use Magento\Framework\App\Filesystem\DirectoryList; -class AdvancedPricingTest extends \PHPUnit\Framework\TestCase +class AdvancedPricingTest extends \Magento\TestFramework\Indexer\TestCase { /** * @var \Magento\AdvancedPricingImportExport\Model\Export\AdvancedPricing @@ -24,6 +24,19 @@ class AdvancedPricingTest extends \PHPUnit\Framework\TestCase */ protected $fileSystem; + public static function setUpBeforeClass() + { + $db = \Magento\TestFramework\Helper\Bootstrap::getInstance()->getBootstrap() + ->getApplication() + ->getDbInstance(); + if (!$db->isDbDumpExists()) { + throw new \LogicException('DB dump does not exist.'); + } + $db->restoreFromDbDump(); + + parent::setUpBeforeClass(); + } + protected function setUp() { parent::setUp(); @@ -37,7 +50,7 @@ protected function setUp() /** * @magentoAppArea adminhtml - * @magentoDbIsolation enabled + * @magentoDbIsolation disabled * @magentoAppIsolation enabled * @magentoDataFixture Magento/Catalog/_files/product_simple.php */ @@ -49,6 +62,7 @@ public function testExport() $index = 0; $ids = []; $origPricingData = []; + $skus = ['simple']; while (isset($skus[$index])) { $ids[$index] = $productRepository->get($skus[$index])->getId(); $origPricingData[$index] = $this->objectManager->create(\Magento\Catalog\Model\Product::class) @@ -94,7 +108,7 @@ private function assertDiscountTypes($exportContent) /** * @magentoAppArea adminhtml - * @magentoDbIsolation enabled + * @magentoDbIsolation disabled * @magentoAppIsolation enabled * @magentoConfigFixture current_store catalog/price/scope 1 * @magentoDataFixture Magento/AdvancedPricingImportExport/_files/product_with_second_website.php diff --git a/dev/tests/integration/testsuite/Magento/Catalog/Controller/Product/CompareTest.php b/dev/tests/integration/testsuite/Magento/Catalog/Controller/Product/CompareTest.php index cc04e48adb620..ec2e97f942451 100644 --- a/dev/tests/integration/testsuite/Magento/Catalog/Controller/Product/CompareTest.php +++ b/dev/tests/integration/testsuite/Magento/Catalog/Controller/Product/CompareTest.php @@ -22,6 +22,9 @@ class CompareTest extends \Magento\TestFramework\TestCase\AbstractController */ protected $productRepository; + /** + * Test setup + */ protected function setUp() { parent::setUp(); @@ -32,6 +35,9 @@ protected function setUp() $this->productRepository = $objectManager->create(\Magento\Catalog\Model\ProductRepository::class); } + /** + * @throws \Magento\Framework\Exception\NoSuchEntityException + */ public function testAddAction() { $this->_requireVisitorWithNoProducts(); @@ -48,7 +54,12 @@ public function testAddAction() ); $this->assertSessionMessages( - $this->equalTo(['You added product Simple Product 1 Name to the comparison list.']), + $this->equalTo( + [ + 'You added product Simple Product 1 Name to the '. + '<a href="http://localhost/index.php/catalog/product_compare/">comparison list</a>.' + ] + ), MessageInterface::TYPE_SUCCESS ); @@ -57,17 +68,23 @@ public function testAddAction() $this->_assertCompareListEquals([$product->getEntityId()]); } + /** + * @throws \Magento\Framework\Exception\NoSuchEntityException + */ public function testIndexActionAddProducts() { $this->_requireVisitorWithNoProducts(); $product = $this->productRepository->get('simple_product_2'); $this->dispatch('catalog/product_compare/index/items/' . $product->getEntityId()); - $this->assertRedirect($this->equalTo('http://localhost/index.php/catalog/product_compare/index/')); + $this->assertRedirect($this->stringStartsWith('http://localhost/index.php/catalog/product_compare/index/')); $this->_assertCompareListEquals([$product->getEntityId()]); } + /** + * @throws \Magento\Framework\Exception\NoSuchEntityException + */ public function testRemoveAction() { $this->_requireVisitorWithTwoProducts(); @@ -84,6 +101,9 @@ public function testRemoveAction() $this->_assertCompareListEquals([$restProduct->getEntityId()]); } + /** + * @throws \Magento\Framework\Exception\NoSuchEntityException + */ public function testRemoveActionWithSession() { $this->_requireCustomerWithTwoProducts(); @@ -101,6 +121,9 @@ public function testRemoveActionWithSession() $this->_assertCompareListEquals([$secondProduct->getEntityId()]); } + /** + * testIndexActionDisplay + */ public function testIndexActionDisplay() { $this->_requireVisitorWithTwoProducts(); @@ -127,6 +150,9 @@ public function testIndexActionDisplay() $this->assertContains('$987.65', $responseBody); } + /** + * testClearAction + */ public function testClearAction() { $this->_requireVisitorWithTwoProducts(); @@ -160,6 +186,9 @@ public function testRemoveActionProductNameXss() ); } + /** + * @throws \Magento\Framework\Exception\NoSuchEntityException + */ protected function _prepareCompareListWithProductNameXss() { /** @var $visitor \Magento\Customer\Model\Visitor */ @@ -182,6 +211,9 @@ protected function _prepareCompareListWithProductNameXss() ); } + /** + * _requireVisitorWithNoProducts + */ protected function _requireVisitorWithNoProducts() { /** @var $visitor \Magento\Customer\Model\Visitor */ @@ -201,6 +233,9 @@ protected function _requireVisitorWithNoProducts() $this->_assertCompareListEquals([]); } + /** + * @throws \Magento\Framework\Exception\NoSuchEntityException + */ protected function _requireVisitorWithTwoProducts() { /** @var $visitor \Magento\Customer\Model\Visitor */ @@ -233,6 +268,9 @@ protected function _requireVisitorWithTwoProducts() $this->_assertCompareListEquals([$firstProductEntityId, $secondProductEntityId]); } + /** + * @throws \Magento\Framework\Exception\NoSuchEntityException + */ protected function _requireCustomerWithTwoProducts() { $customer = \Magento\TestFramework\Helper\Bootstrap::getObjectManager() diff --git a/dev/tests/integration/testsuite/Magento/Catalog/Model/Indexer/Product/Flat/Action/RowTest.php b/dev/tests/integration/testsuite/Magento/Catalog/Model/Indexer/Product/Flat/Action/RowTest.php index 2b7c416f6be16..15c90891878a0 100644 --- a/dev/tests/integration/testsuite/Magento/Catalog/Model/Indexer/Product/Flat/Action/RowTest.php +++ b/dev/tests/integration/testsuite/Magento/Catalog/Model/Indexer/Product/Flat/Action/RowTest.php @@ -61,12 +61,13 @@ public function testProductUpdate() $this->_processor->getIndexer()->isScheduled(), 'Indexer is in scheduled mode when turned to update on save mode' ); - $this->_processor->reindexAll(); $this->_product->load(1); $this->_product->setName('Updated Product'); $this->_product->save(); + $this->_processor->reindexAll(); + $category = $categoryFactory->create()->load(9); $layer = $listProduct->getLayer(); $layer->setCurrentCategory($category); diff --git a/dev/tests/integration/testsuite/Magento/Catalog/Model/Product/Option/Type/File/ValidatorInfoTest.php b/dev/tests/integration/testsuite/Magento/Catalog/Model/Product/Option/Type/File/ValidatorInfoTest.php index 41556d5558006..d4214a32f31dc 100644 --- a/dev/tests/integration/testsuite/Magento/Catalog/Model/Product/Option/Type/File/ValidatorInfoTest.php +++ b/dev/tests/integration/testsuite/Magento/Catalog/Model/Product/Option/Type/File/ValidatorInfoTest.php @@ -30,6 +30,9 @@ class ValidatorInfoTest extends \PHPUnit\Framework\TestCase */ protected $validateFactoryMock; + /** + * {@inheritdoc} + */ protected function setUp() { $this->objectManager = \Magento\TestFramework\Helper\Bootstrap::getObjectManager(); @@ -111,11 +114,11 @@ public function testExceptionWithoutErrors() */ public function testValidate() { - $validateMock = $this->createPartialMock(\Zend_Validate::class, ['isValid']); - $validateMock->expects($this->once())->method('isValid')->will($this->returnValue(true)); + //use actual zend class to test changed functionality + $validate = $this->objectManager->create(\Zend_Validate::class); $this->validateFactoryMock->expects($this->once()) ->method('create') - ->will($this->returnValue($validateMock)); + ->will($this->returnValue($validate)); $this->assertTrue( $this->model->validate( $this->getOptionValue(), diff --git a/dev/tests/integration/testsuite/Magento/Catalog/Model/ProductPriceTest.php b/dev/tests/integration/testsuite/Magento/Catalog/Model/ProductPriceTest.php index 594133e984a46..7b7a0591d1d97 100644 --- a/dev/tests/integration/testsuite/Magento/Catalog/Model/ProductPriceTest.php +++ b/dev/tests/integration/testsuite/Magento/Catalog/Model/ProductPriceTest.php @@ -8,6 +8,7 @@ use Magento\TestFramework\Helper\Bootstrap; use Magento\Catalog\Api\ProductRepositoryInterface; use Magento\Catalog\Model\ResourceModel\Product\Collection; +use Magento\CatalogInventory\Api\StockRegistryInterface; /** * Tests product model: @@ -23,11 +24,23 @@ class ProductPriceTest extends \PHPUnit\Framework\TestCase */ protected $_model; + /** + * @var ProductRepositoryInterface + */ + private $productRepository; + + /** + * @inheritdoc + */ protected function setUp() { $this->_model = Bootstrap::getObjectManager()->create(Product::class); + $this->productRepository = Bootstrap::getObjectManager()->create(ProductRepositoryInterface::class); } + /** + * @return void + */ public function testGetPrice() { $this->assertEmpty($this->_model->getPrice()); @@ -35,6 +48,9 @@ public function testGetPrice() $this->assertEquals(10.0, $this->_model->getPrice()); } + /** + * @return void + */ public function testGetPriceModel() { $default = $this->_model->getPriceModel(); @@ -66,6 +82,9 @@ public function testGetFormatedPrice() $this->assertEquals('<span class="price">$0.00</span>', $this->_model->getFormatedPrice()); } + /** + * @return void + */ public function testSetGetFinalPrice() { $this->assertEquals(0, $this->_model->getFinalPrice()); @@ -81,14 +100,37 @@ public function testSetGetFinalPrice() */ public function testGetMinPrice(): void { - $productRepository = Bootstrap::getObjectManager()->create(ProductRepositoryInterface::class); - $product = $productRepository->get('simple'); + $product = $this->productRepository->get('simple'); $collection = Bootstrap::getObjectManager()->create(Collection::class); $collection->addIdFilter($product->getId()); $collection->addPriceData(); $collection->load(); /** @var \Magento\Catalog\Model\Product $product */ $product = $collection->getFirstItem(); - $this->assertEquals(333, $product->getData('min_price')); + $this->assertEquals(323, $product->getData('min_price')); + } + + /** + * @magentoDbIsolation disabled + * @magentoDataFixture Magento/ConfigurableProduct/_files/product_configurable_sku.php + */ + public function testGetMinPriceForComposite(): void + { + $confProduct = $this->productRepository->get('configurable'); + $collection = Bootstrap::getObjectManager()->create(Collection::class); + $collection->addIdFilter($confProduct->getId()); + $collection->addPriceData(); + $collection->load(); + $product = $collection->getFirstItem(); + $this->assertEquals(10, $product->getData('min_price')); + + $childProduct = $this->productRepository->get('simple_10'); + $stockRegistry = Bootstrap::getObjectManager()->get(StockRegistryInterface::class); + $stockItem = $stockRegistry->getStockItem($childProduct->getId()); + $stockItem->setIsInStock(false); + $stockRegistry->updateStockItemBySku($childProduct->getSku(), $stockItem); + $collection->clear()->load(); + $product = $collection->getFirstItem(); + $this->assertEquals(20, $product->getData('min_price')); } } diff --git a/dev/tests/integration/testsuite/Magento/Catalog/Model/ProductTest.php b/dev/tests/integration/testsuite/Magento/Catalog/Model/ProductTest.php index b00090850e09b..82d39bbb7066a 100644 --- a/dev/tests/integration/testsuite/Magento/Catalog/Model/ProductTest.php +++ b/dev/tests/integration/testsuite/Magento/Catalog/Model/ProductTest.php @@ -20,6 +20,8 @@ * @magentoDbIsolation enabled * @magentoAppIsolation enabled * @SuppressWarnings(PHPMD.CouplingBetweenObjects) + * @SuppressWarnings(PHPMD.TooManyMethods) + * @SuppressWarnings(PHPMD.TooManyPublicMethods) */ class ProductTest extends \PHPUnit\Framework\TestCase { @@ -33,6 +35,9 @@ class ProductTest extends \PHPUnit\Framework\TestCase */ protected $_model; + /** + * @inheritdoc + */ protected function setUp() { $this->productRepository = \Magento\TestFramework\Helper\Bootstrap::getObjectManager() @@ -43,6 +48,10 @@ protected function setUp() ); } + /** + * @throws \Magento\Framework\Exception\FileSystemException + * @return void + */ public static function tearDownAfterClass() { $objectManager = \Magento\TestFramework\Helper\Bootstrap::getObjectManager(); @@ -64,6 +73,9 @@ public static function tearDownAfterClass() } } + /** + * @return void + */ public function testCanAffectOptions() { $this->assertFalse($this->_model->canAffectOptions()); @@ -103,6 +115,9 @@ public function testCRUD() $crud->testCrud(); } + /** + * @return void + */ public function testCleanCache() { \Magento\TestFramework\Helper\Bootstrap::getObjectManager()->get( @@ -123,6 +138,9 @@ public function testCleanCache() ); } + /** + * @return void + */ public function testAddImageToMediaGallery() { // Model accepts only files in tmp media path, we need to copy fixture file there @@ -330,6 +348,9 @@ public function testIsVirtual() $this->assertTrue($model->getIsVirtual()); } + /** + * @return void + */ public function testToArray() { $this->assertEquals([], $this->_model->toArray()); @@ -337,6 +358,9 @@ public function testToArray() $this->assertEquals(['sku' => 'sku', 'name' => 'name'], $this->_model->toArray()); } + /** + * @return void + */ public function testFromArray() { $this->_model->fromArray(['sku' => 'sku', 'name' => 'name', 'stock_item' => ['key' => 'value']]); @@ -408,6 +432,9 @@ public function testIsProductsHasSku() ); } + /** + * @return void + */ public function testProcessBuyRequest() { $request = new \Magento\Framework\DataObject(); @@ -416,6 +443,9 @@ public function testProcessBuyRequest() $this->assertArrayHasKey('errors', $result->getData()); } + /** + * @return void + */ public function testValidate() { $this->_model->setTypeId( @@ -534,6 +564,8 @@ public function testValidateUniqueInputAttributeOnTheSameProduct() } /** + * Tests Customizable Options price values including negative value. + * * @magentoDataFixture Magento/Catalog/_files/product_simple_with_custom_options.php * @magentoAppIsolation enabled */ @@ -543,7 +575,7 @@ public function testGetOptions() $options = $this->_model->getOptions(); $this->assertNotEmpty($options); $expectedValue = [ - '3-1-select' => 3000.00, + '3-1-select' => -3000.00, '3-2-select' => 5000.00, '4-1-radio' => 600.234, '4-2-radio' => 40000.00 diff --git a/dev/tests/integration/testsuite/Magento/Catalog/Model/ResourceModel/Product/CollectionTest.php b/dev/tests/integration/testsuite/Magento/Catalog/Model/ResourceModel/Product/CollectionTest.php index e58d445a25650..a5e55e181cbaf 100644 --- a/dev/tests/integration/testsuite/Magento/Catalog/Model/ResourceModel/Product/CollectionTest.php +++ b/dev/tests/integration/testsuite/Magento/Catalog/Model/ResourceModel/Product/CollectionTest.php @@ -50,6 +50,7 @@ public function testAddPriceDataOnSchedule() { $this->processor->getIndexer()->setScheduled(true); $this->assertTrue($this->processor->getIndexer()->isScheduled()); + $productRepository = \Magento\TestFramework\Helper\Bootstrap::getObjectManager() ->create(\Magento\Catalog\Api\ProductRepositoryInterface::class); /** @var \Magento\Catalog\Api\Data\ProductInterface $product */ @@ -81,7 +82,6 @@ public function testAddPriceDataOnSchedule() $product = reset($items); $this->assertCount(2, $items); $this->assertEquals(15, $product->getPrice()); - $this->processor->getIndexer()->reindexList([1]); $this->processor->getIndexer()->setScheduled(false); } @@ -127,6 +127,42 @@ public function testGetProductsWithTierPrice() $this->assertEquals(5, $tierPrices[2]->getValue()); } + /** + * Test addAttributeToSort() with attribute 'is_saleable' works properly on frontend. + * + * @dataProvider addAttributeToSortDataProvider + * @magentoDataFixture Magento/Catalog/_files/multiple_products_with_non_saleable_product.php + * @magentoConfigFixture current_store cataloginventory/options/show_out_of_stock 1 + * @magentoAppIsolation enabled + * @magentoAppArea frontend + */ + public function testAddAttributeToSort(string $productSku, string $order) + { + /** @var Collection $productCollection */ + $this->collection->addAttributeToSort('is_saleable', $order); + self::assertEquals(2, $this->collection->count()); + self::assertSame($productSku, $this->collection->getFirstItem()->getSku()); + } + + /** + * Provide test data for testAddAttributeToSort(). + * + * @return array + */ + public function addAttributeToSortDataProvider() + { + return [ + [ + 'product_sku' => 'simple_saleable', + 'order' => Collection::SORT_ORDER_DESC, + ], + [ + 'product_sku' => 'simple_not_saleable', + 'order' => Collection::SORT_ORDER_ASC, + ] + ]; + } + /** * Checks a case if table for join specified as an array. * @@ -151,20 +187,4 @@ public function testJoinTable() self::assertContains($expected, str_replace(PHP_EOL, '', $sql)); } - - /** - * Checks that a collection uses the correct join when filtering by null. - * - * This actually affects AbstractCollection, but inheritance yada yada. - * - * @magentoDataFixture Magento/Catalog/Model/ResourceModel/_files/product_simple.php - * @magentoDbIsolation enabled - */ - public function testFilterByNull() - { - $this->collection->addAttributeToFilter([['attribute' => 'special_price', 'null' => true]]); - $productCount = $this->collection->count(); - - $this->assertEquals(1, $productCount, 'Product with null special_price not found'); - } } diff --git a/dev/tests/integration/testsuite/Magento/Catalog/_files/multiple_products_with_non_saleable_product.php b/dev/tests/integration/testsuite/Magento/Catalog/_files/multiple_products_with_non_saleable_product.php new file mode 100644 index 0000000000000..30b2aad2317c4 --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/Catalog/_files/multiple_products_with_non_saleable_product.php @@ -0,0 +1,53 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +declare(strict_types=1); + +/** @var $product \Magento\Catalog\Model\Product */ +$product = \Magento\TestFramework\Helper\Bootstrap::getObjectManager()->create(\Magento\Catalog\Model\Product::class); +$product->isObjectNew(true); +$product->setTypeId(\Magento\Catalog\Model\Product\Type::TYPE_SIMPLE) + ->setAttributeSetId(4) + ->setName('Simple Product') + ->setSku('simple_saleable') + ->setTaxClassId('none') + ->setDescription('description') + ->setShortDescription('short description') + ->setOptionsContainer('container1') + ->setMsrpDisplayActualPriceType(\Magento\Msrp\Model\Product\Attribute\Source\Type::TYPE_IN_CART) + ->setPrice(10) + ->setWeight(1) + ->setMetaTitle('meta title') + ->setMetaKeyword('meta keyword') + ->setMetaDescription('meta description') + ->setVisibility(\Magento\Catalog\Model\Product\Visibility::VISIBILITY_BOTH) + ->setStatus(\Magento\Catalog\Model\Product\Attribute\Source\Status::STATUS_ENABLED) + ->setWebsiteIds([1]) + ->setCategoryIds([]) + ->setStockData(['use_config_manage_stock' => 1, 'qty' => 100, 'is_qty_decimal' => 0, 'is_in_stock' => 1]) + ->save(); + +$product = \Magento\TestFramework\Helper\Bootstrap::getObjectManager()->create(\Magento\Catalog\Model\Product::class); +$product->isObjectNew(true); +$product->setTypeId(\Magento\Catalog\Model\Product\Type::TYPE_SIMPLE) + ->setAttributeSetId(4) + ->setName('Simple Product2') + ->setSku('simple_not_saleable') + ->setTaxClassId('none') + ->setDescription('description') + ->setShortDescription('short description') + ->setOptionsContainer('container1') + ->setMsrpDisplayActualPriceType(\Magento\Msrp\Model\Product\Attribute\Source\Type::TYPE_ON_GESTURE) + ->setPrice(20) + ->setWeight(1) + ->setMetaTitle('meta title') + ->setMetaKeyword('meta keyword') + ->setMetaDescription('meta description') + ->setVisibility(\Magento\Catalog\Model\Product\Visibility::VISIBILITY_IN_CATALOG) + ->setStatus(\Magento\Catalog\Model\Product\Attribute\Source\Status::STATUS_ENABLED) + ->setWebsiteIds([1]) + ->setCategoryIds([]) + ->setStockData(['use_config_manage_stock' => 1, 'qty' => 50, 'is_qty_decimal' => 0, 'is_in_stock' => 0]) + ->save(); diff --git a/dev/tests/integration/testsuite/Magento/Catalog/_files/multiple_products_with_non_saleable_product_rollback.php b/dev/tests/integration/testsuite/Magento/Catalog/_files/multiple_products_with_non_saleable_product_rollback.php new file mode 100644 index 0000000000000..220509698dc33 --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/Catalog/_files/multiple_products_with_non_saleable_product_rollback.php @@ -0,0 +1,29 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +declare(strict_types=1); + +$objectManager = \Magento\TestFramework\Helper\Bootstrap::getObjectManager(); + +/** @var \Magento\Framework\Registry $registry */ +$registry = \Magento\TestFramework\Helper\Bootstrap::getObjectManager()->get(\Magento\Framework\Registry::class); + +$registry->unregister('isSecureArea'); +$registry->register('isSecureArea', true); + +/** @var \Magento\Catalog\Api\ProductRepositoryInterface $productRepository */ +$productRepository = $objectManager->create(\Magento\Catalog\Api\ProductRepositoryInterface::class); + +foreach (['simple_saleable', 'simple_not_saleable'] as $sku) { + try { + $product = $productRepository->get($sku, false, null, true); + $productRepository->delete($product); + } catch (\Magento\Framework\Exception\NoSuchEntityException $exception) { + //Product already removed + } +} + +$registry->unregister('isSecureArea'); +$registry->register('isSecureArea', false); diff --git a/dev/tests/integration/testsuite/Magento/Catalog/_files/multiselect_attribute.php b/dev/tests/integration/testsuite/Magento/Catalog/_files/multiselect_attribute.php index 6ab607b5de88f..7dacdc42463a9 100644 --- a/dev/tests/integration/testsuite/Magento/Catalog/_files/multiselect_attribute.php +++ b/dev/tests/integration/testsuite/Magento/Catalog/_files/multiselect_attribute.php @@ -12,45 +12,48 @@ $attribute = \Magento\TestFramework\Helper\Bootstrap::getObjectManager()->create( \Magento\Catalog\Model\ResourceModel\Eav\Attribute::class ); -$attribute->setData( - [ - 'attribute_code' => 'multiselect_attribute', - 'entity_type_id' => $installer->getEntityTypeId('catalog_product'), - 'is_global' => 1, - 'is_user_defined' => 1, - 'frontend_input' => 'multiselect', - 'is_unique' => 0, - 'is_required' => 0, - 'is_searchable' => 0, - 'is_visible_in_advanced_search' => 0, - 'is_comparable' => 0, - 'is_filterable' => 1, - 'is_filterable_in_search' => 0, - 'is_used_for_promo_rules' => 0, - 'is_html_allowed_on_front' => 1, - 'is_visible_on_front' => 0, - 'used_in_product_listing' => 0, - 'used_for_sort_by' => 0, - 'frontend_label' => ['Multiselect Attribute'], - 'backend_type' => 'varchar', - 'backend_model' => \Magento\Eav\Model\Entity\Attribute\Backend\ArrayBackend::class, - 'option' => [ - 'value' => [ - 'option_1' => ['Option 1'], - 'option_2' => ['Option 2'], - 'option_3' => ['Option 3'], - 'option_4' => ['Option 4 "!@#$%^&*'] +$entityType = $installer->getEntityTypeId('catalog_product'); +if (!$attribute->loadByCode($entityType, 'multiselect_attribute')->getAttributeId()) { + $attribute->setData( + [ + 'attribute_code' => 'multiselect_attribute', + 'entity_type_id' => $entityType, + 'is_global' => 1, + 'is_user_defined' => 1, + 'frontend_input' => 'multiselect', + 'is_unique' => 0, + 'is_required' => 0, + 'is_searchable' => 0, + 'is_visible_in_advanced_search' => 0, + 'is_comparable' => 0, + 'is_filterable' => 1, + 'is_filterable_in_search' => 0, + 'is_used_for_promo_rules' => 0, + 'is_html_allowed_on_front' => 1, + 'is_visible_on_front' => 0, + 'used_in_product_listing' => 0, + 'used_for_sort_by' => 0, + 'frontend_label' => ['Multiselect Attribute'], + 'backend_type' => 'varchar', + 'backend_model' => \Magento\Eav\Model\Entity\Attribute\Backend\ArrayBackend::class, + 'option' => [ + 'value' => [ + 'option_1' => ['Option 1'], + 'option_2' => ['Option 2'], + 'option_3' => ['Option 3'], + 'option_4' => ['Option 4 "!@#$%^&*'] + ], + 'order' => [ + 'option_1' => 1, + 'option_2' => 2, + 'option_3' => 3, + 'option_4' => 4, + ], ], - 'order' => [ - 'option_1' => 1, - 'option_2' => 2, - 'option_3' => 3, - 'option_4' => 4, - ], - ], - ] -); -$attribute->save(); + ] + ); + $attribute->save(); -/* Assign attribute to attribute set */ -$installer->addAttributeToGroup('catalog_product', 'Default', 'General', $attribute->getId()); + /* Assign attribute to attribute set */ + $installer->addAttributeToGroup('catalog_product', 'Default', 'General', $attribute->getId()); +} diff --git a/dev/tests/integration/testsuite/Magento/Catalog/_files/product_out_of_stock_with_multiselect_attribute.php b/dev/tests/integration/testsuite/Magento/Catalog/_files/product_out_of_stock_with_multiselect_attribute.php new file mode 100644 index 0000000000000..3d2dfcdff53e0 --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/Catalog/_files/product_out_of_stock_with_multiselect_attribute.php @@ -0,0 +1,39 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +declare(strict_types=1); + +/** + * Create multiselect attribute + */ +require __DIR__ . '/multiselect_attribute.php'; + +/** Create product with options out of stock and multiselect attribute */ + +/** @var $installer \Magento\Catalog\Setup\CategorySetup */ +$installer = \Magento\TestFramework\Helper\Bootstrap::getObjectManager()->create( + \Magento\Catalog\Setup\CategorySetup::class +); + +/** @var $options \Magento\Eav\Model\ResourceModel\Entity\Attribute\Option\Collection */ +$options = \Magento\TestFramework\Helper\Bootstrap::getObjectManager()->create( + \Magento\Eav\Model\ResourceModel\Entity\Attribute\Option\Collection::class +); +$options->setAttributeFilter($attribute->getId()); +$optionIds = $options->getAllIds(); + +$product = \Magento\TestFramework\Helper\Bootstrap::getObjectManager()->create(\Magento\Catalog\Model\Product::class); +$product->setTypeId(\Magento\Catalog\Model\Product\Type::TYPE_SIMPLE) + ->setId($optionIds[1] * 20) + ->setAttributeSetId($installer->getAttributeSetId('catalog_product', 'Default')) + ->setWebsiteIds([1]) + ->setName('Out of Stock With Multiselect') + ->setSku('simple_ms_out_of_stock') + ->setPrice(10) + ->setVisibility(\Magento\Catalog\Model\Product\Visibility::VISIBILITY_BOTH) + ->setMultiselectAttribute([$optionIds[1], $optionIds[2], $optionIds[3]]) + ->setStatus(\Magento\Catalog\Model\Product\Attribute\Source\Status::STATUS_ENABLED) + ->setStockData(['use_config_manage_stock' => 1, 'qty' => 0,'is_in_stock' => 0]) + ->save(); diff --git a/dev/tests/integration/testsuite/Magento/Catalog/_files/product_out_of_stock_with_multiselect_attribute_rollback.php b/dev/tests/integration/testsuite/Magento/Catalog/_files/product_out_of_stock_with_multiselect_attribute_rollback.php new file mode 100644 index 0000000000000..d1926f4769f77 --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/Catalog/_files/product_out_of_stock_with_multiselect_attribute_rollback.php @@ -0,0 +1,33 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +declare(strict_types=1); + +require __DIR__ . '/multiselect_attribute_rollback.php'; + +use Magento\Framework\Exception\NoSuchEntityException; +use Magento\Framework\Indexer\IndexerRegistry; + +/** @var \Magento\Framework\Registry $registry */ +$registry = \Magento\TestFramework\Helper\Bootstrap::getObjectManager()->get(\Magento\Framework\Registry::class); + +$registry->unregister('isSecureArea'); +$registry->register('isSecureArea', true); + +/** @var \Magento\Catalog\Api\ProductRepositoryInterface $productRepository */ +$productRepository = \Magento\TestFramework\Helper\Bootstrap::getObjectManager() + ->get(\Magento\Catalog\Api\ProductRepositoryInterface::class); +try { + $product = $productRepository->get('simple_ms_out_of_stock', false, null, true); + $productRepository->delete($product); +} catch (NoSuchEntityException $e) { +} + +\Magento\TestFramework\Helper\Bootstrap::getObjectManager()->get(IndexerRegistry::class) + ->get(Magento\CatalogInventory\Model\Indexer\Stock\Processor::INDEXER_ID) + ->reindexAll(); + +$registry->unregister('isSecureArea'); +$registry->register('isSecureArea', false); diff --git a/dev/tests/integration/testsuite/Magento/Catalog/_files/product_simple_with_custom_options.php b/dev/tests/integration/testsuite/Magento/Catalog/_files/product_simple_with_custom_options.php index c3abd2dfcdae7..059b784978a22 100644 --- a/dev/tests/integration/testsuite/Magento/Catalog/_files/product_simple_with_custom_options.php +++ b/dev/tests/integration/testsuite/Magento/Catalog/_files/product_simple_with_custom_options.php @@ -51,7 +51,7 @@ [ 'option_type_id' => null, 'title' => 'Option 1', - 'price' => '3,000.00', + 'price' => '-3,000.00', 'price_type' => 'fixed', 'sku' => '3-1-select', ], diff --git a/dev/tests/integration/testsuite/Magento/Catalog/_files/product_with_options.php b/dev/tests/integration/testsuite/Magento/Catalog/_files/product_with_options.php index a6e01370dfefb..a9bc557fd9b72 100644 --- a/dev/tests/integration/testsuite/Magento/Catalog/_files/product_with_options.php +++ b/dev/tests/integration/testsuite/Magento/Catalog/_files/product_with_options.php @@ -11,8 +11,6 @@ $product->setTypeId( 'simple' -)->setId( - 1 )->setAttributeSetId( 4 )->setWebsiteIds( @@ -49,7 +47,7 @@ 'type' => 'field', 'is_require' => true, 'sort_order' => 1, - 'price' => 10.0, + 'price' => -10.0, 'price_type' => 'fixed', 'sku' => 'sku1', 'max_characters' => 10, diff --git a/dev/tests/integration/testsuite/Magento/Catalog/_files/products_with_multiselect_attribute_rollback.php b/dev/tests/integration/testsuite/Magento/Catalog/_files/products_with_multiselect_attribute_rollback.php index 7a72f168f924f..eb8201f04e6cc 100644 --- a/dev/tests/integration/testsuite/Magento/Catalog/_files/products_with_multiselect_attribute_rollback.php +++ b/dev/tests/integration/testsuite/Magento/Catalog/_files/products_with_multiselect_attribute_rollback.php @@ -3,7 +3,11 @@ * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ + require __DIR__ . '/multiselect_attribute_rollback.php'; + +use Magento\Framework\Indexer\IndexerRegistry; + /** * Remove all products as strategy of isolation process */ @@ -22,3 +26,7 @@ $registry->unregister('isSecureArea'); $registry->register('isSecureArea', false); + +\Magento\TestFramework\Helper\Bootstrap::getObjectManager()->get(IndexerRegistry::class) + ->get(Magento\CatalogInventory\Model\Indexer\Stock\Processor::INDEXER_ID) + ->reindexAll(); diff --git a/dev/tests/integration/testsuite/Magento/CatalogRule/Model/Indexer/Product/PriceTest.php b/dev/tests/integration/testsuite/Magento/CatalogRule/Model/Indexer/Product/PriceTest.php index b1a10c894f83a..495d19a2745e5 100644 --- a/dev/tests/integration/testsuite/Magento/CatalogRule/Model/Indexer/Product/PriceTest.php +++ b/dev/tests/integration/testsuite/Magento/CatalogRule/Model/Indexer/Product/PriceTest.php @@ -3,8 +3,6 @@ * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ -declare(strict_types=1); - namespace Magento\CatalogRule\Model\Indexer\Product; use Magento\TestFramework\Helper\Bootstrap; @@ -14,13 +12,6 @@ use Magento\Framework\Api\SearchCriteriaInterface; use Magento\Framework\Api\SortOrder; -/** - * @magentoDataFixtureBeforeTransaction Magento/CatalogRule/_files/attribute.php - * @magentoDataFixtureBeforeTransaction Magento/CatalogRule/_files/product_with_attribute.php - * @magentoDataFixtureBeforeTransaction Magento/CatalogRule/_files/rule_by_attribute.php - * @magentoDbIsolation enabled - * @magentoAppIsolation enabled - */ class PriceTest extends \PHPUnit\Framework\TestCase { /** @@ -28,18 +19,18 @@ class PriceTest extends \PHPUnit\Framework\TestCase */ private $resourceRule; - /** - * {@inheritdoc} - */ protected function setUp() { $this->resourceRule = Bootstrap::getObjectManager()->get(Rule::class); } /** - * @return void + * @magentoDataFixtureBeforeTransaction Magento/CatalogRule/_files/configurable_product.php + * @magentoDataFixtureBeforeTransaction Magento/CatalogRule/_files/rule_by_attribute.php + * @magentoDbIsolation enabled + * @magentoAppIsolation enabled */ - public function testPriceApplying() : void + public function testPriceApplying() { $customerGroupId = 1; $websiteId = 1; @@ -52,7 +43,6 @@ public function testPriceApplying() : void /** @var \Magento\Catalog\Model\Product $simpleProduct */ $simpleProduct = $collection->getFirstItem(); $simpleProduct->setPriceCalculation(false); - $rulePrice = $this->resourceRule->getRulePrice(new \DateTime(), $websiteId, $customerGroupId, $simpleProductId); $this->assertEquals($rulePrice, $simpleProduct->getFinalPrice()); @@ -63,16 +53,17 @@ public function testPriceApplying() : void $collection->load(); /** @var \Magento\Catalog\Model\Product $confProduct */ $confProduct = $collection->getFirstItem(); - - $this->assertEquals($simpleProduct->getMinimalPrice(), $confProduct->getMinimalPrice()); + $this->assertEquals($simpleProduct->getFinalPrice(), $confProduct->getMinimalPrice()); } /** + * @magentoDataFixtureBeforeTransaction Magento/CatalogRule/_files/simple_products.php + * @magentoDataFixtureBeforeTransaction Magento/CatalogRule/_files/rule_by_attribute.php + * @magentoDbIsolation enabled + * @magentoAppIsolation enabled * @magentoAppArea frontend - * - * @return void */ - public function testSortByPrice() : void + public function testSortByPrice() { $searchCriteria = Bootstrap::getObjectManager()->create(SearchCriteriaInterface::class); $sortOrder = Bootstrap::getObjectManager()->create(SortOrder::class); @@ -80,10 +71,10 @@ public function testSortByPrice() : void $searchCriteria->setSortOrders([$sortOrder]); $productRepository = Bootstrap::getObjectManager()->get(ProductRepositoryInterface::class); $searchResults = $productRepository->getList($searchCriteria); - $products = $searchResults->getItems(); + /** @var \Magento\Catalog\Model\Product[] $products */ + $products = array_values($searchResults->getItems()); - /** @var \Magento\Catalog\Model\Product $product1 */ - $product1 = array_values($products)[0]; + $product1 = $products[0]; $product1->setPriceCalculation(false); $this->assertEquals('simple1', $product1->getSku()); $rulePrice = $this->resourceRule->getRulePrice(new \DateTime(), 1, 1, $product1->getId()); diff --git a/dev/tests/integration/testsuite/Magento/CatalogRule/_files/product_with_attribute.php b/dev/tests/integration/testsuite/Magento/CatalogRule/_files/configurable_product.php similarity index 52% rename from dev/tests/integration/testsuite/Magento/CatalogRule/_files/product_with_attribute.php rename to dev/tests/integration/testsuite/Magento/CatalogRule/_files/configurable_product.php index 071f5d7d9fd00..ef7144d9d8438 100644 --- a/dev/tests/integration/testsuite/Magento/CatalogRule/_files/product_with_attribute.php +++ b/dev/tests/integration/testsuite/Magento/CatalogRule/_files/configurable_product.php @@ -6,12 +6,12 @@ declare(strict_types=1); require __DIR__ . '/../../ConfigurableProduct/_files/configurable_attribute.php'; +require __DIR__ . '/simple_products.php'; $objectManager = \Magento\TestFramework\Helper\Bootstrap::getObjectManager(); $storeManager = $objectManager->get(\Magento\Store\Model\StoreManager::class); $store = $storeManager->getStore('default'); - $productRepository = $objectManager->get(\Magento\Catalog\Api\ProductRepositoryInterface::class); $installer = $objectManager->get(\Magento\Catalog\Setup\CategorySetup::class); @@ -19,63 +19,22 @@ $attributeValues = []; $associatedProductIds = []; -/** @var Magento\Eav\Model\Entity\Attribute\Option[] $options */ +$attributeRepository = $objectManager->get(\Magento\Eav\Api\AttributeRepositoryInterface::class); +$attribute = $attributeRepository->get('catalog_product', 'test_configurable'); $options = $attribute->getOptions(); array_shift($options); //remove the first option which is empty - -$product = $objectManager->create(\Magento\Catalog\Model\Product::class) - ->setTypeId('simple') - ->setId(1) - ->setAttributeSetId($attributeSetId) - ->setWebsiteIds([1]) - ->setName('Simple Product 1') - ->setSku('simple1') - ->setPrice(10) - ->setVisibility(\Magento\Catalog\Model\Product\Visibility::VISIBILITY_BOTH) - ->setStatus(\Magento\Catalog\Model\Product\Attribute\Source\Status::STATUS_ENABLED) - ->setStockData([ - 'use_config_manage_stock' => 1, - 'qty' => 100, - 'is_qty_decimal' => 0, - 'is_in_stock' => 1, - ]); -$option = array_shift($options); -$product->setTestConfigurable($option->getValue()); -$productRepository->save($product); -$attributeValues[] = [ - 'label' => 'test', - 'attribute_id' => $attribute->getId(), - 'value_index' => $option->getValue(), -]; -$associatedProductIds[] = $product->getId(); -$productAction = $objectManager->get(\Magento\Catalog\Model\Product\Action::class); -$productAction->updateAttributes([$product->getId()], ['test_attribute' => 'test_attribute_value'], $store->getId()); - -$product = $objectManager->create(\Magento\Catalog\Model\Product::class) - ->setTypeId('simple') - ->setId(2) - ->setAttributeSetId($attributeSetId) - ->setWebsiteIds([1]) - ->setName('Simple Product 2') - ->setSku('simple2') - ->setPrice(9.9) - ->setVisibility(\Magento\Catalog\Model\Product\Visibility::VISIBILITY_BOTH) - ->setStatus(\Magento\Catalog\Model\Product\Attribute\Source\Status::STATUS_ENABLED) - ->setStockData([ - 'use_config_manage_stock' => 1, - 'qty' => 100, - 'is_qty_decimal' => 0, - 'is_in_stock' => 1, - ]); -$option = array_shift($options); -$product->setTestConfigurable($option->getValue()); -$productRepository->save($product); -$attributeValues[] = [ - 'label' => 'test', - 'attribute_id' => $attribute->getId(), - 'value_index' => $option->getValue(), -]; -$associatedProductIds[] = $product->getId(); +foreach (['simple1', 'simple2'] as $sku) { + $option = array_shift($options); + $product = $productRepository->get($sku); + $product->setTestConfigurable($option->getValue()); + $productRepository->save($product); + $attributeValues[] = [ + 'label' => 'test', + 'attribute_id' => $attribute->getId(), + 'value_index' => $option->getValue(), + ]; + $associatedProductIds[] = $product->getId(); +} $product = $objectManager->create(\Magento\Catalog\Model\Product::class) ->setTypeId('configurable') @@ -88,7 +47,9 @@ ->setStatus(\Magento\Catalog\Model\Product\Attribute\Source\Status::STATUS_ENABLED) ->setStockData([ 'use_config_manage_stock' => 1, - 'is_in_stock' => 0, + 'qty' => 100, + 'is_qty_decimal' => 0, + 'is_in_stock' => 1, ]); $configurableAttributesData = [ [ diff --git a/dev/tests/integration/testsuite/Magento/CatalogRule/_files/configurable_product_rollback.php b/dev/tests/integration/testsuite/Magento/CatalogRule/_files/configurable_product_rollback.php new file mode 100644 index 0000000000000..915da48c915b2 --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/CatalogRule/_files/configurable_product_rollback.php @@ -0,0 +1,32 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +declare(strict_types=1); + +\Magento\TestFramework\Helper\Bootstrap::getInstance()->getInstance()->reinitialize(); + +/** @var $objectManager \Magento\TestFramework\ObjectManager */ +$objectManager = \Magento\TestFramework\Helper\Bootstrap::getObjectManager(); + +/** @var \Magento\Framework\Registry $registry */ +$registry = $objectManager->get(\Magento\Framework\Registry::class); + +$registry->unregister('isSecureArea'); +$registry->register('isSecureArea', true); + +/** @var \Magento\Catalog\Api\ProductRepositoryInterface $productRepository */ +$productRepository = $objectManager->get(\Magento\Catalog\Api\ProductRepositoryInterface::class); +try { + $product = $productRepository->get('configurable', false, null, true); + $productRepository->delete($product); +} catch (\Magento\Framework\Exception\NoSuchEntityException $e) { + //Nothing to delete +} + +$registry->unregister('isSecureArea'); +$registry->register('isSecureArea', false); + +require __DIR__ . '/simple_products_rollback.php'; +require __DIR__ . '/../../ConfigurableProduct/_files/configurable_attribute_rollback.php'; diff --git a/dev/tests/integration/testsuite/Magento/CatalogRule/_files/simple_products.php b/dev/tests/integration/testsuite/Magento/CatalogRule/_files/simple_products.php new file mode 100644 index 0000000000000..84ce4e1bca87c --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/CatalogRule/_files/simple_products.php @@ -0,0 +1,55 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +declare(strict_types=1); + +require __DIR__ . '/attribute.php'; + +$objectManager = \Magento\TestFramework\Helper\Bootstrap::getObjectManager(); + +$storeManager = $objectManager->get(\Magento\Store\Model\StoreManager::class); +$store = $storeManager->getStore('default'); +$productRepository = $objectManager->get(\Magento\Catalog\Api\ProductRepositoryInterface::class); + +$installer = $objectManager->get(\Magento\Catalog\Setup\CategorySetup::class); +$attributeSetId = $installer->getAttributeSetId('catalog_product', 'Default'); + +$product = $objectManager->create(\Magento\Catalog\Model\Product::class) + ->setTypeId('simple') + ->setId(1) + ->setAttributeSetId($attributeSetId) + ->setWebsiteIds([1]) + ->setName('Simple Product 1') + ->setSku('simple1') + ->setPrice(10) + ->setVisibility(\Magento\Catalog\Model\Product\Visibility::VISIBILITY_BOTH) + ->setStatus(\Magento\Catalog\Model\Product\Attribute\Source\Status::STATUS_ENABLED) + ->setStockData([ + 'use_config_manage_stock' => 1, + 'qty' => 100, + 'is_qty_decimal' => 0, + 'is_in_stock' => 1, + ]); +$productRepository->save($product); +$productAction = $objectManager->get(\Magento\Catalog\Model\Product\Action::class); +$productAction->updateAttributes([$product->getId()], ['test_attribute' => 'test_attribute_value'], $store->getId()); + +$product = $objectManager->create(\Magento\Catalog\Model\Product::class) + ->setTypeId('simple') + ->setId(2) + ->setAttributeSetId($attributeSetId) + ->setWebsiteIds([1]) + ->setName('Simple Product 2') + ->setSku('simple2') + ->setPrice(9.9) + ->setVisibility(\Magento\Catalog\Model\Product\Visibility::VISIBILITY_BOTH) + ->setStatus(\Magento\Catalog\Model\Product\Attribute\Source\Status::STATUS_ENABLED) + ->setStockData([ + 'use_config_manage_stock' => 1, + 'qty' => 100, + 'is_qty_decimal' => 0, + 'is_in_stock' => 1, + ]); +$productRepository->save($product); diff --git a/dev/tests/integration/testsuite/Magento/CatalogRule/_files/product_with_attribute_rollback.php b/dev/tests/integration/testsuite/Magento/CatalogRule/_files/simple_products_rollback.php similarity index 87% rename from dev/tests/integration/testsuite/Magento/CatalogRule/_files/product_with_attribute_rollback.php rename to dev/tests/integration/testsuite/Magento/CatalogRule/_files/simple_products_rollback.php index 0ce909a3f9ecd..6625b1926fc10 100644 --- a/dev/tests/integration/testsuite/Magento/CatalogRule/_files/product_with_attribute_rollback.php +++ b/dev/tests/integration/testsuite/Magento/CatalogRule/_files/simple_products_rollback.php @@ -18,7 +18,7 @@ /** @var \Magento\Catalog\Api\ProductRepositoryInterface $productRepository */ $productRepository = $objectManager->get(\Magento\Catalog\Api\ProductRepositoryInterface::class); -foreach (['simple1', 'simple2', 'configurable'] as $sku) { +foreach (['simple1', 'simple2'] as $sku) { try { $product = $productRepository->get($sku, false, null, true); $productRepository->delete($product); @@ -30,4 +30,4 @@ $registry->unregister('isSecureArea'); $registry->register('isSecureArea', false); -require __DIR__ . '/../../ConfigurableProduct/_files/configurable_attribute_rollback.php'; +require __DIR__ . '/attribute_rollback.php'; diff --git a/dev/tests/integration/testsuite/Magento/CatalogSearch/Model/Search/FilterMapper/StockStatusFilterTest.php b/dev/tests/integration/testsuite/Magento/CatalogSearch/Model/Search/FilterMapper/StockStatusFilterTest.php deleted file mode 100644 index a8a404a1ee2d6..0000000000000 --- a/dev/tests/integration/testsuite/Magento/CatalogSearch/Model/Search/FilterMapper/StockStatusFilterTest.php +++ /dev/null @@ -1,240 +0,0 @@ -<?php -/** - * Copyright © Magento, Inc. All rights reserved. - * See COPYING.txt for license details. - */ -namespace Magento\CatalogSearch\Model\Search\FilterMapper; - -use Magento\Framework\App\ResourceConnection; -use Magento\Framework\Search\Adapter\Mysql\ConditionManager; -use Magento\Framework\DB\Select; -use Magento\CatalogInventory\Api\StockConfigurationInterface; -use Magento\CatalogInventory\Api\StockRegistryInterface; -use Magento\CatalogInventory\Model\Stock; - -class StockStatusFilterTest extends \PHPUnit\Framework\TestCase -{ - /** - * Const to define if 'show out of stock' configuration flag enabled or not - */ - const SHOW_OUT_OF_STOCK_ENABLED = true; - const SHOW_OUT_OF_STOCK_DISABLED = false; - - /** @var \Magento\Framework\ObjectManagerInterface */ - private $objectManager; - - /** @var ResourceConnection */ - private $resource; - - /** @var ConditionManager */ - private $conditionManager; - - /** @var StockConfigurationInterface */ - private $stockConfiguration; - - /** @var StockRegistryInterface */ - private $stockRegistry; - - /** @var StockStatusFilter */ - private $stockStatusFilter; - - protected function setUp() - { - $this->objectManager = \Magento\TestFramework\Helper\Bootstrap::getObjectManager(); - $this->resource = $this->objectManager->create(ResourceConnection::class); - $this->conditionManager = $this->objectManager->create(ConditionManager::class); - $this->stockConfiguration = $this->objectManager->create(StockConfigurationInterface::class); - $this->stockRegistry = $this->objectManager->create(StockRegistryInterface::class); - $this->stockStatusFilter = $this->objectManager->create(StockStatusFilter::class); - } - - /** - * @expectedException InvalidArgumentException - * @expectedExceptionMessage Invalid filter type: Luke I am your father! - */ - public function testApplyWithWrongType() - { - $select = $this->resource->getConnection()->select(); - $this->stockStatusFilter->apply( - $select, - Stock::STOCK_IN_STOCK, - 'Luke I am your father!', - self::SHOW_OUT_OF_STOCK_ENABLED - ); - } - - public function testApplyGeneralFilterWithOutOfStock() - { - $select = $this->resource->getConnection()->select(); - $select->from( - ['some_index' => 'some_table'], - ['entity_id' => 'entity_id'] - ); - - $resultSelect = $this->stockStatusFilter->apply( - $select, - Stock::STOCK_IN_STOCK, - StockStatusFilter::FILTER_JUST_ENTITY, - self::SHOW_OUT_OF_STOCK_ENABLED - ); - - $expectedSelect = $this->getExpectedSelectForGeneralFilter(self::SHOW_OUT_OF_STOCK_ENABLED); - - $this->assertEquals( - (string) $expectedSelect, - (string) $resultSelect, - 'Select queries must be the same' - ); - } - - public function testApplyGeneralFilterWithoutOutOfStock() - { - $select = $this->resource->getConnection()->select(); - $select->from( - ['some_index' => 'some_table'], - ['entity_id' => 'entity_id'] - ); - - $resultSelect = $this->stockStatusFilter->apply( - $select, - Stock::STOCK_IN_STOCK, - StockStatusFilter::FILTER_JUST_ENTITY, - self::SHOW_OUT_OF_STOCK_DISABLED - ); - - $expectedSelect = $this->getExpectedSelectForGeneralFilter(self::SHOW_OUT_OF_STOCK_DISABLED); - - $this->assertEquals( - (string) $expectedSelect, - (string) $resultSelect, - 'Select queries must be the same' - ); - } - - public function testApplyFullFilterWithOutOfStock() - { - $select = $this->resource->getConnection()->select(); - $select->from( - ['some_index' => 'some_table'], - ['entity_id' => 'entity_id'] - ); - - $resultSelect = $this->stockStatusFilter->apply( - $select, - Stock::STOCK_IN_STOCK, - StockStatusFilter::FILTER_ENTITY_AND_SUB_PRODUCTS, - self::SHOW_OUT_OF_STOCK_ENABLED - ); - - $expectedSelect = $this->getExpectedSelectForFullFilter(self::SHOW_OUT_OF_STOCK_ENABLED); - - $this->assertEquals( - (string) $expectedSelect, - (string) $resultSelect, - 'Select queries must be the same' - ); - } - - public function testApplyFullFilterWithoutOutOfStock() - { - $select = $this->resource->getConnection()->select(); - $select->from( - ['some_index' => 'some_table'], - ['entity_id' => 'entity_id'] - ); - - $resultSelect = $this->stockStatusFilter->apply( - $select, - Stock::STOCK_IN_STOCK, - StockStatusFilter::FILTER_ENTITY_AND_SUB_PRODUCTS, - self::SHOW_OUT_OF_STOCK_DISABLED - ); - - $expectedSelect = $this->getExpectedSelectForFullFilter(self::SHOW_OUT_OF_STOCK_DISABLED); - - $this->assertEquals( - (string) $expectedSelect, - (string) $resultSelect, - 'Select queries must be the same' - ); - } - - /** - * @param bool $withOutOfStock - * @return Select - */ - private function getExpectedSelectForGeneralFilter($withOutOfStock) - { - $select = $this->resource->getConnection()->select(); - $select->from( - ['some_index' => 'some_table'], - ['entity_id' => 'entity_id'] - )->joinInner( - ['stock_index' => $this->resource->getTableName('cataloginventory_stock_status')], - $this->conditionManager->combineQueries( - [ - 'stock_index.product_id = some_index.entity_id', - $this->conditionManager->generateCondition( - 'stock_index.website_id', - '=', - $this->stockConfiguration->getDefaultScopeId() - ), - $withOutOfStock - ? '' - : $this->conditionManager->generateCondition( - 'stock_index.stock_status', - '=', - Stock::STOCK_IN_STOCK - ), - $this->conditionManager->generateCondition( - 'stock_index.stock_id', - '=', - (int) $this->stockRegistry->getStock()->getStockId() - ), - ], - Select::SQL_AND - ), - [] - ); - - return $select; - } - - /** - * @param bool $withOutOfStock - * @return Select - */ - private function getExpectedSelectForFullFilter($withOutOfStock) - { - $select = $this->getExpectedSelectForGeneralFilter($withOutOfStock); - $select->joinInner( - ['sub_products_stock_index' => $this->resource->getTableName('cataloginventory_stock_status')], - $this->conditionManager->combineQueries( - [ - 'sub_products_stock_index.product_id = some_index.source_id', - $this->conditionManager->generateCondition( - 'sub_products_stock_index.website_id', - '=', - $this->stockConfiguration->getDefaultScopeId() - ), - $withOutOfStock - ? '' - : $this->conditionManager->generateCondition( - 'sub_products_stock_index.stock_status', - '=', - Stock::STOCK_IN_STOCK - ), - $this->conditionManager->generateCondition( - 'sub_products_stock_index.stock_id', - '=', - (int) $this->stockRegistry->getStock()->getStockId() - ), - ], - Select::SQL_AND - ), - [] - ); - - return $select; - } -} diff --git a/dev/tests/integration/testsuite/Magento/CatalogSearch/Model/Search/FilterMapper/StockStatusFilterWithFullFilterTest.php b/dev/tests/integration/testsuite/Magento/CatalogSearch/Model/Search/FilterMapper/StockStatusFilterWithFullFilterTest.php new file mode 100644 index 0000000000000..e94eda11a3fc5 --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/CatalogSearch/Model/Search/FilterMapper/StockStatusFilterWithFullFilterTest.php @@ -0,0 +1,122 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +declare(strict_types=1); + +namespace Magento\CatalogSearch\Model\Search\FilterMapper; + +use Magento\Catalog\Model\Product; +use Magento\Catalog\Model\ProductRepository; +use Magento\CatalogInventory\Model\Stock; +use Magento\Eav\Model\Config as EavConfig; +use Magento\Framework\App\ResourceConnection; +use Magento\Framework\Search\Request\Filter\Term; +use Magento\Framework\Search\Request\FilterInterface; +use Magento\TestFramework\Helper\Bootstrap; +use PHPUnit\Framework\TestCase; + +/** + * @SuppressWarnings(PHPMD.CouplingBetweenObjects) + * + * @magentoDbIsolation disabled + * + * @magentoDataFixture Magento/Catalog/_files/multiple_products.php + * @magentoDataFixture Magento/Catalog/_files/product_simple_out_of_stock.php + * @magentoDataFixture Magento/Catalog/_files/products_with_multiselect_attribute.php + * @magentoDataFixture Magento/Catalog/_files/product_out_of_stock_with_multiselect_attribute.php + */ +class StockStatusFilterWithFullFilterTest extends TestCase +{ + /** + * @var \Magento\Framework\ObjectManagerInterface + */ + private $objectManager; + + /** + * @var ResourceConnection + */ + private $resource; + + /** + * @var StockStatusFilter + */ + private $stockStatusFilter; + + /** + * @var CustomAttributeFilter + */ + private $customAttributeFilter; + + /** + * @var FilterInterface + */ + private $filter; + + /** + * @inheritdoc + */ + protected function setUp() + { + parent::setUp(); + + $this->objectManager = Bootstrap::getObjectManager(); + $this->resource = $this->objectManager->get(ResourceConnection::class); + $this->stockStatusFilter = $this->objectManager->get(StockStatusFilter::class); + $this->customAttributeFilter = $this->objectManager->get(CustomAttributeFilter::class); + $eavConfig = $this->objectManager->get(EavConfig::class); + $attribute = $eavConfig->getAttribute(Product::ENTITY, 'multiselect_attribute'); + + $productRepository = $this->objectManager->get(ProductRepository::class); + $product = $productRepository->get('simple_ms_2'); + $multiSelectArray = explode(',', $product->getData('multiselect_attribute')); + + $this->filter = $this->objectManager->create( + Term::class, + [ + 'field' => $attribute->getAttributeCode(), + 'name' => $attribute->getAttributeCode() . '_filter', + 'value' => reset($multiSelectArray), + ] + ); + } + + /** + * @param bool $showOutOfStockFlag + * @param int $expectedResult + * @return void + * + * @dataProvider applyDataProvider + */ + public function testApply(bool $showOutOfStockFlag, int $expectedResult) + { + $select = $this->resource->getConnection()->select(); + $select->from( + [$this->resource->getTableName('catalog_product_index_eav')], + ['entity_id'] + )->distinct(true); + $select = $this->customAttributeFilter->apply($select, $this->filter); + $select = $this->stockStatusFilter->apply( + $select, + Stock::STOCK_IN_STOCK, + StockStatusFilter::FILTER_ENTITY_AND_SUB_PRODUCTS, + $showOutOfStockFlag + ); + + $data = $select->query()->fetchAll(); + + $this->assertEquals($expectedResult, count($data)); + } + + /** + * @return array + */ + public function applyDataProvider(): array + { + return [ + [true, 2], + [false, 1], + ]; + } +} diff --git a/dev/tests/integration/testsuite/Magento/CatalogSearch/Model/Search/FilterMapper/StockStatusFilterWithGeneralFilterTest.php b/dev/tests/integration/testsuite/Magento/CatalogSearch/Model/Search/FilterMapper/StockStatusFilterWithGeneralFilterTest.php new file mode 100644 index 0000000000000..809116e9c7d84 --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/CatalogSearch/Model/Search/FilterMapper/StockStatusFilterWithGeneralFilterTest.php @@ -0,0 +1,105 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +declare(strict_types=1); + +namespace Magento\CatalogSearch\Model\Search\FilterMapper; + +use Magento\CatalogInventory\Model\Stock; +use Magento\Framework\App\ResourceConnection; +use Magento\TestFramework\Helper\Bootstrap; +use PHPUnit\Framework\TestCase; + +/** + * @magentoDbIsolation disabled + * + * @magentoDataFixture Magento/Catalog/_files/multiple_products.php + * @magentoDataFixture Magento/Catalog/_files/product_simple_out_of_stock.php + * @magentoDataFixture Magento/Catalog/_files/products_with_multiselect_attribute.php + * @magentoDataFixture Magento/Catalog/_files/product_out_of_stock_with_multiselect_attribute.php + */ +class StockStatusFilterWithGeneralFilterTest extends TestCase +{ + /** + * @var \Magento\Framework\ObjectManagerInterface + */ + private $objectManager; + + /** + * @var ResourceConnection + */ + private $resource; + + /** + * @var StockStatusFilter + */ + private $stockStatusFilter; + + /** + * @inheritdoc + */ + protected function setUp() + { + parent::setUp(); + + $this->objectManager = Bootstrap::getObjectManager(); + $this->resource = $this->objectManager->get(ResourceConnection::class); + $this->stockStatusFilter = $this->objectManager->get(StockStatusFilter::class); + } + + /** + * @return void + * + * @expectedException \InvalidArgumentException + * @expectedExceptionMessage Invalid filter type: some_wrong_type + */ + public function testApplyWithWrongType() + { + $select = $this->resource->getConnection()->select(); + $this->stockStatusFilter->apply( + $select, + Stock::STOCK_IN_STOCK, + 'some_wrong_type', + true + ); + } + + /** + * @param bool $showOutOfStockFlag + * @param int $expectedResult + * @return void + * + * @dataProvider applyDataProvider + */ + public function testApply(bool $showOutOfStockFlag, int $expectedResult) + { + $select = $this->resource->getConnection()->select(); + $select->from( + [$this->resource->getTableName('catalog_product_index_eav')], + ['entity_id'] + )->distinct(true); + + $select = $this->stockStatusFilter->apply( + $select, + Stock::STOCK_IN_STOCK, + StockStatusFilter::FILTER_JUST_ENTITY, + $showOutOfStockFlag + ); + $data = $select->query()->fetchAll(); + + $this->assertEquals($expectedResult, count($data)); + } + + /** + * @return array + */ + public function applyDataProvider(): array + { + return [ + [true, 6], + [false, 4], + ]; + } +} diff --git a/dev/tests/integration/testsuite/Magento/CatalogUrlRewrite/Plugin/Store/Block/SwitcherTest.php b/dev/tests/integration/testsuite/Magento/CatalogUrlRewrite/Plugin/Store/Block/SwitcherTest.php deleted file mode 100644 index 5b3879b592245..0000000000000 --- a/dev/tests/integration/testsuite/Magento/CatalogUrlRewrite/Plugin/Store/Block/SwitcherTest.php +++ /dev/null @@ -1,56 +0,0 @@ -<?php -/** - * Copyright © Magento, Inc. All rights reserved. - * See COPYING.txt for license details. - */ -declare(strict_types=1); - -namespace Magento\CatalogUrlRewrite\Plugin\Store\Block; - -/** - * Integration tests for Magento\CatalogUrlRewrite\Plugin\Store\Block\Switcher block. - */ -class SwitcherTest extends \PHPUnit\Framework\TestCase -{ - /** - * @var \Magento\TestFramework\ObjectManager - */ - private $objectManager; - - /** - * @var \Magento\Store\Block\Switcher - */ - private $model; - - /** - * @var \Magento\Store\Api\StoreRepositoryInterface - */ - private $storeRepository; - - /** - * {@inheritdoc} - */ - protected function setUp() - { - $this->objectManager = \Magento\TestFramework\Helper\Bootstrap::getObjectManager(); - $this->model = $this->objectManager->create(\Magento\Store\Block\Switcher::class); - $this->storeRepository = $this->objectManager->create(\Magento\Store\Api\StoreRepositoryInterface::class); - } - - /** - * Test that after switching from Store 1 to Store 2 with another root Category user gets correct store url. - * - * @magentoDataFixture Magento/Store/_files/store.php - * @magentoDataFixture Magento/CatalogUrlRewrite/_files/two_categories_per_two_store_groups.php - * @magentoAppArea frontend - * @return void - */ - public function testGetTargetStorePostData(): void - { - $storeCode = 'test'; - $store = $this->storeRepository->get($storeCode); - $result = json_decode($this->model->getTargetStorePostData($store), true); - - $this->assertContains($storeCode, $result['action']); - } -} diff --git a/dev/tests/integration/testsuite/Magento/CatalogUrlRewrite/_files/two_categories_per_two_store_groups.php b/dev/tests/integration/testsuite/Magento/CatalogUrlRewrite/_files/two_categories_per_two_store_groups.php deleted file mode 100644 index f77413e18f472..0000000000000 --- a/dev/tests/integration/testsuite/Magento/CatalogUrlRewrite/_files/two_categories_per_two_store_groups.php +++ /dev/null @@ -1,67 +0,0 @@ -<?php -/** - * Copyright © Magento, Inc. All rights reserved. - * See COPYING.txt for license details. - */ -declare(strict_types=1); - -$objectManager = \Magento\TestFramework\Helper\Bootstrap::getObjectManager(); -$defaultCategory = $objectManager->create(\Magento\Catalog\Helper\DefaultCategory::class); -/** @var \Magento\Catalog\Model\Category $category */ -$category = $objectManager->create(\Magento\Catalog\Model\Category::class); -$category->isObjectNew(true); -$category->setCreatedAt('2014-06-23 09:50:07') - ->setName('Category 1') - ->setParentId($defaultCategory->getId()) - ->setPath('1/2/3') - ->setLevel(2) - ->setAvailableSortBy('name') - ->setDefaultSortBy('name') - ->setIsActive(true) - ->setPosition(1) - ->setAvailableSortBy(['position']) - ->save(); - -/** @var \Magento\Store\Model\Store $store */ -$store = $objectManager->create(\Magento\Store\Model\Store::class); - -$category->setStoreId($store->load('default')->getId()) - ->setName('category-default-store') - ->setUrlKey('category-default-store') - ->save(); - -$rootCategoryForTestStoreGroup = $objectManager->create(\Magento\Catalog\Model\Category::class); -$rootCategoryForTestStoreGroup->isObjectNew(true); -$rootCategoryForTestStoreGroup->setCreatedAt('2014-06-23 09:50:07') - ->setName('Category 2') - ->setParentId(\Magento\Catalog\Model\Category::TREE_ROOT_ID) - ->setPath('1/2/334') - ->setLevel(2) - ->setAvailableSortBy('name') - ->setDefaultSortBy('name') - ->setIsActive(true) - ->setPosition(1) - ->setAvailableSortBy(['position']) - ->save(); - -$rootCategoryForTestStoreGroup->setStoreId($store->load('test')->getId()) - ->setName('category-test-store') - ->setUrlKey('category-test-store') - ->save(); - -$storeCode = 'test'; -/** @var \Magento\Store\Api\StoreRepositoryInterface $storeRepository */ -$storeRepository = $objectManager->create(\Magento\Store\Api\StoreRepositoryInterface::class); -/** @var \Magento\Store\Api\Data\StoreInterface $store */ -$store = $storeRepository->get($storeCode); - -/** @var \Magento\Store\Model\Group $storeGroup */ -$storeGroup = $objectManager->create(\Magento\Store\Model\Group::class) - ->setWebsiteId('1') - ->setCode('test_store_group') - ->setName('Test Store Group') - ->setRootCategoryId($rootCategoryForTestStoreGroup->getId()) - ->setDefaultStoreId($store->getId()) - ->save(); - -$store->setGroupId($storeGroup->getId())->save(); diff --git a/dev/tests/integration/testsuite/Magento/CatalogUrlRewrite/_files/two_categories_per_two_store_groups_rollback.php b/dev/tests/integration/testsuite/Magento/CatalogUrlRewrite/_files/two_categories_per_two_store_groups_rollback.php deleted file mode 100644 index 9592e9d0e69b4..0000000000000 --- a/dev/tests/integration/testsuite/Magento/CatalogUrlRewrite/_files/two_categories_per_two_store_groups_rollback.php +++ /dev/null @@ -1,47 +0,0 @@ -<?php -/** - * Copyright © Magento, Inc. All rights reserved. - * See COPYING.txt for license details. - */ -declare(strict_types=1); - -use Magento\Framework\Registry; -use Magento\Store\Model\Group; -use Magento\TestFramework\Helper\Bootstrap; -use Magento\Catalog\Api\CategoryListInterface; -use Magento\Catalog\Api\CategoryRepositoryInterface; -use Magento\Framework\Api\SearchCriteriaBuilder; - -$objectManager = Bootstrap::getObjectManager(); - -/** @var Registry $registry */ -$registry = $objectManager->get(Registry::class); -$registry->unregister('isSecureArea'); -$registry->register('isSecureArea', true); -// Delete first category -/** @var SearchCriteriaBuilder $searchCriteriaBuilder */ -$searchCriteriaBuilder = $objectManager->get(SearchCriteriaBuilder::class); -$searchCriteria = $searchCriteriaBuilder->addFilter('name', 'Category 1')->create(); -/** @var CategoryListInterface $categoryList */ -$categoryList = $objectManager->get(CategoryListInterface::class); -$categories = $categoryList->getList($searchCriteria)->getItems(); -/** @var CategoryRepositoryInterface $categoryRepository */ -$categoryRepository = $objectManager->get(CategoryRepositoryInterface::class); -foreach ($categories as $category) { - $categoryRepository->delete($category); -} -// Delete second category -$searchCriteria = $searchCriteriaBuilder->addFilter('name', 'Category 2')->create(); -$categories = $categoryList->getList($searchCriteria)->getItems(); -foreach ($categories as $category) { - $categoryRepository->delete($category); -} -// Delete store group -/** @var Group $store */ -$storeGroup = $objectManager->get(Group::class); -$storeGroup->load('test_store_group', 'code'); -if ($storeGroup->getId()) { - $storeGroup->delete(); -} -$registry->unregister('isSecureArea'); -$registry->register('isSecureArea', false); diff --git a/dev/tests/integration/testsuite/Magento/Checkout/Controller/Cart/UpdateItemQtyTest.php b/dev/tests/integration/testsuite/Magento/Checkout/Controller/Cart/UpdateItemQtyTest.php new file mode 100644 index 0000000000000..4c653ab9ae33f --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/Checkout/Controller/Cart/UpdateItemQtyTest.php @@ -0,0 +1,120 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +declare(strict_types=1); + +namespace Magento\Checkout\Controller\Cart; + +use Magento\Catalog\Model\Product; +use Magento\Checkout\Model\Session; +use Magento\Catalog\Api\ProductRepositoryInterface; +use Magento\Framework\Data\Form\FormKey; +use Magento\Framework\Serialize\Serializer\Json; + +class UpdateItemQtyTest extends \Magento\TestFramework\TestCase\AbstractController +{ + /** + * @var Json + */ + private $json; + + /** + * @var FormKey + */ + private $formKey; + + /** + * @var Session + */ + private $session; + + /** + * @var ProductRepositoryInterface + */ + private $productRepository; + + protected function setUp() + { + parent::setUp(); + + $this->json = $this->_objectManager->create(Json::class); + $this->formKey = $this->_objectManager->get(FormKey::class); + $this->session = $this->_objectManager->create(Session::class); + $this->productRepository = $this->_objectManager->create(ProductRepositoryInterface::class); + } + + /** + * Tests of cart validation. + * + * @param array $requestQuantity + * @param array $expectedResponse + * + * @magentoDbIsolation enabled + * @magentoAppArea frontend + * @magentoDataFixture Magento/Checkout/_files/quote_with_simple_product.php + * @dataProvider requestDataProvider + */ + public function testExecute($requestQuantity, $expectedResponse) + { + try { + /** @var $product Product */ + $product = $this->productRepository->get('simple'); + } catch (\Exception $e) { + $this->fail('No such product entity'); + } + + $quoteItem = $this->session + ->getQuote() + ->getItemByProduct($product); + + $this->assertNotNull($quoteItem, 'Cannot get quote item for simple product'); + + $request = []; + if (!empty($requestQuantity) && is_array($requestQuantity)) { + $request= [ + 'form_key' => $this->formKey->getFormKey(), + 'cart' => [ + $quoteItem->getId() => $requestQuantity, + ] + ]; + } + + $this->getRequest()->setPostValue($request); + $this->dispatch('checkout/cart/updateItemQty'); + $response = $this->getResponse()->getBody(); + + $this->assertEquals($this->json->unserialize($response), $expectedResponse); + } + + /** + * Variations of request data. + * @returns array + */ + public function requestDataProvider(): array + { + return [ + [ + 'request' => [], + 'response' => [ + 'success' => false, + 'error_message' => 'Something went wrong while saving the page.'. + ' Please refresh the page and try again.' + ] + ], + [ + 'request' => ['qty' => 2], + 'response' => [ + 'success' => true, + ] + ], + [ + 'request' => ['qty' => 230], + 'response' => [ + 'success' => false, + 'error_message' => 'The requested qty is not available'] + ], + ]; + } +} diff --git a/dev/tests/integration/testsuite/Magento/Cms/Controller/Adminhtml/FulltextGridSearchTest.php b/dev/tests/integration/testsuite/Magento/Cms/Controller/Adminhtml/FulltextGridSearchTest.php new file mode 100644 index 0000000000000..c740609773b90 --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/Cms/Controller/Adminhtml/FulltextGridSearchTest.php @@ -0,0 +1,66 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +declare(strict_types=1); + +namespace Magento\Cms\Controller\Adminhtml; + +use Magento\TestFramework\TestCase\AbstractBackendController; + +/** + * @magentoDataFixture Magento/Cms/Fixtures/page_list.php + */ +class FulltextGridSearchTest extends AbstractBackendController +{ + /** + * Checks a fulltext grid search by CMS page title. + * + * @param string $query + * @param int $expectedRows + * @param array $expectedTitles + * @dataProvider queryDataProvider + */ + public function testSearchByTitle(string $query, int $expectedRows, array $expectedTitles) + { + $url = 'backend/mui/index/render/?namespace=cms_page_listing&search=' . $query; + + $this->getRequest() + ->getHeaders() + ->addHeaderLine('Accept', 'application/json'); + $this->dispatch($url); + $response = $this->getResponse(); + $data = json_decode($response->getBody(), true); + self::assertEquals($expectedRows, $data['totalRecords']); + + $titleList = array_column($data['items'], 'title'); + self::assertEquals($expectedTitles, $titleList); + } + + /** + * Gets list of variations with different search queries. + * + * @return array + */ + public function queryDataProvider(): array + { + return [ + [ + 'query' => 'simple', + 'expectedRows' => 3, + 'expectedTitles' => ['simplePage', 'simplePage01', '01simplePage'] + ], + [ + 'query' => 'page01', + 'expectedRows' => 1, + 'expectedTitles' => ['simplePage01'] + ], + [ + 'query' => '01simple', + 'expectedRows' => 1, + 'expectedTitles' => ['01simplePage'] + ], + ]; + } +} diff --git a/dev/tests/integration/testsuite/Magento/Cms/Fixtures/page_list.php b/dev/tests/integration/testsuite/Magento/Cms/Fixtures/page_list.php new file mode 100644 index 0000000000000..ae431f5c4cf1a --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/Cms/Fixtures/page_list.php @@ -0,0 +1,34 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +declare(strict_types=1); + +use Magento\Cms\Api\Data\PageInterface; +use Magento\Cms\Api\PageRepositoryInterface; +use Magento\TestFramework\Helper\Bootstrap; + +$objectManager = Bootstrap::getObjectManager(); + +$data = [ + [ + 'title' => 'simplePage', + 'is_active' => 1 + ], + [ + 'title' => 'simplePage01', + 'is_active' => 1 + ], + [ + 'title' => '01simplePage', + 'is_active' => 1 + ], +]; + +/** @var PageRepositoryInterface $pageRepository */ +$pageRepository = $objectManager->get(PageRepositoryInterface::class); +foreach ($data as $item) { + $page = $objectManager->create(PageInterface::class, ['data' => $item]); + $pageRepository->save($page); +} diff --git a/dev/tests/integration/testsuite/Magento/Cms/Fixtures/page_list_rollback.php b/dev/tests/integration/testsuite/Magento/Cms/Fixtures/page_list_rollback.php new file mode 100644 index 0000000000000..261cdba589653 --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/Cms/Fixtures/page_list_rollback.php @@ -0,0 +1,25 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +declare(strict_types=1); + +use Magento\Cms\Api\PageRepositoryInterface; +use Magento\Framework\Api\SearchCriteriaBuilder; +use Magento\TestFramework\Helper\Bootstrap; + +$objectManager = Bootstrap::getObjectManager(); + +/** @var PageRepositoryInterface $pageRepository */ +$pageRepository = $objectManager->get(PageRepositoryInterface::class); + +/** @var SearchCriteriaBuilder $searchCriteriaBuilder */ +$searchCriteriaBuilder = $objectManager->get(SearchCriteriaBuilder::class); +$searchCriteria = $searchCriteriaBuilder->addFilter('title', ['simplePage', 'simplePage01', '01simplePage'], 'in') + ->create(); +$result = $pageRepository->getList($searchCriteria); + +foreach ($result->getItems() as $item) { + $pageRepository->delete($item); +} diff --git a/dev/tests/integration/testsuite/Magento/Cms/Setup/ContentConverterTest.php b/dev/tests/integration/testsuite/Magento/Cms/Setup/ContentConverterTest.php index b3bbd64b83e7e..7dbc3d2cc1dbd 100644 --- a/dev/tests/integration/testsuite/Magento/Cms/Setup/ContentConverterTest.php +++ b/dev/tests/integration/testsuite/Magento/Cms/Setup/ContentConverterTest.php @@ -34,8 +34,8 @@ public function convertDataProvider() <h2 class="title">Hot Sellers</h2> <p class="info">Here is what`s trending on Luma right now</p> </div>'; - $serializedWidgetContent = '{{widget type="Magento\\CatalogWidget\\Block\\Product\\ProductsList" products_per_page="8" products_count="8" template="product/widget/content/grid.phtml" conditions_encoded="a:2:[i:1;a:4:[s:4:`type`;s:50:`Magento|CatalogWidget|Model|Rule|Condition|Combine`;s:10:`aggregator`;s:3:`all`;s:5:`value`;s:1:`1`;s:9:`new_child`;s:0:``;]s:4:`1--1`;a:4:[s:4:`type`;s:50:`Magento|CatalogWidget|Model|Rule|Condition|Product`;s:9:`attribute`;s:3:`sku`;s:8:`operator`;s:2:`()`;s:5:`value`;a:8:[i:0;s:4:`WS12`;i:1;s:4:`WT09`;i:2;s:4:`MT07`;i:3;s:4:`MH07`;i:4;s:7:`24-MB02`;i:5;s:7:`24-WB04`;i:6;s:8:`241-MB08`;i:7;s:8:`240-LV05`;]]]"}}'; - $jsonEncodedWidgetContent = '{{widget type="Magento\\CatalogWidget\\Block\\Product\\ProductsList" products_per_page="8" products_count="8" template="product/widget/content/grid.phtml" conditions_encoded="^[`1`:^[`type`:`Magento||CatalogWidget||Model||Rule||Condition||Combine`,`aggregator`:`all`,`value`:`1`,`new_child`:``^],`1--1`:^[`type`:`Magento||CatalogWidget||Model||Rule||Condition||Product`,`attribute`:`sku`,`operator`:`()`,`value`:[`WS12`,`WT09`,`MT07`,`MH07`,`24-MB02`,`24-WB04`,`241-MB08`,`240-LV05`]^]^]"}}'; + $serializedWidgetContent = '{{widget type="Magento\\CatalogWidget\\Block\\Product\\ProductsList" products_per_page="8" products_count="8" template="Magento_CatalogWidget::product/widget/content/grid.phtml" conditions_encoded="a:2:[i:1;a:4:[s:4:`type`;s:50:`Magento|CatalogWidget|Model|Rule|Condition|Combine`;s:10:`aggregator`;s:3:`all`;s:5:`value`;s:1:`1`;s:9:`new_child`;s:0:``;]s:4:`1--1`;a:4:[s:4:`type`;s:50:`Magento|CatalogWidget|Model|Rule|Condition|Product`;s:9:`attribute`;s:3:`sku`;s:8:`operator`;s:2:`()`;s:5:`value`;a:8:[i:0;s:4:`WS12`;i:1;s:4:`WT09`;i:2;s:4:`MT07`;i:3;s:4:`MH07`;i:4;s:7:`24-MB02`;i:5;s:7:`24-WB04`;i:6;s:8:`241-MB08`;i:7;s:8:`240-LV05`;]]]"}}'; + $jsonEncodedWidgetContent = '{{widget type="Magento\\CatalogWidget\\Block\\Product\\ProductsList" products_per_page="8" products_count="8" template="Magento_CatalogWidget::product/widget/content/grid.phtml" conditions_encoded="^[`1`:^[`type`:`Magento||CatalogWidget||Model||Rule||Condition||Combine`,`aggregator`:`all`,`value`:`1`,`new_child`:``^],`1--1`:^[`type`:`Magento||CatalogWidget||Model||Rule||Condition||Product`,`attribute`:`sku`,`operator`:`()`,`value`:[`WS12`,`WT09`,`MT07`,`MH07`,`24-MB02`,`24-WB04`,`241-MB08`,`240-LV05`]^]^]"}}'; // @codingStandardsIgnoreEnd return [ 'no widget' => [ diff --git a/dev/tests/integration/testsuite/Magento/Contact/Controller/IndexTest.php b/dev/tests/integration/testsuite/Magento/Contact/Controller/IndexTest.php index a06a981a4c891..2f89cb72b0cd9 100644 --- a/dev/tests/integration/testsuite/Magento/Contact/Controller/IndexTest.php +++ b/dev/tests/integration/testsuite/Magento/Contact/Controller/IndexTest.php @@ -6,11 +6,16 @@ namespace Magento\Contact\Controller; +use Zend\Http\Request; + /** * Contact index controller test */ class IndexTest extends \Magento\TestFramework\TestCase\AbstractController { + /** + * testPostAction + */ public function testPostAction() { $params = [ @@ -20,6 +25,7 @@ public function testPostAction() 'hideit' => '', ]; $this->getRequest()->setPostValue($params); + $this->getRequest()->setMethod(Request::METHOD_POST); $this->dispatch('contact/index/post'); $this->assertRedirect($this->stringContains('contact/index')); @@ -33,12 +39,13 @@ public function testPostAction() /** * @dataProvider dataInvalidPostAction - * @param $params - * @param $expectedMessage + * @param array $params + * @param string $expectedMessage */ public function testInvalidPostAction($params, $expectedMessage) { $this->getRequest()->setPostValue($params); + $this->getRequest()->setMethod(Request::METHOD_POST); $this->dispatch('contact/index/post'); $this->assertRedirect($this->stringContains('contact/index')); @@ -48,6 +55,9 @@ public function testInvalidPostAction($params, $expectedMessage) ); } + /** + * @return array + */ public static function dataInvalidPostAction() { return [ diff --git a/dev/tests/integration/testsuite/Magento/Customer/Controller/AccountTest.php b/dev/tests/integration/testsuite/Magento/Customer/Controller/AccountTest.php index 1cbdbd128bbf4..186d9c8f87dc2 100644 --- a/dev/tests/integration/testsuite/Magento/Customer/Controller/AccountTest.php +++ b/dev/tests/integration/testsuite/Magento/Customer/Controller/AccountTest.php @@ -55,6 +55,9 @@ public function testIndexAction() $this->assertContains('Green str, 67', $body); } + /** + * @return void + */ public function testCreateAction() { $this->dispatch('customer/account/create'); @@ -522,7 +525,7 @@ public function testEditPostAction() $this->dispatch('customer/account/editPost'); - $this->assertRedirect($this->stringEndsWith('customer/account/')); + $this->assertRedirect($this->stringContains('customer/account/')); $this->assertSessionMessages( $this->equalTo(['You saved the account information.']), MessageInterface::TYPE_SUCCESS @@ -570,7 +573,7 @@ public function testChangePasswordEditPostAction() $this->dispatch('customer/account/editPost'); - $this->assertRedirect($this->stringEndsWith('customer/account/')); + $this->assertRedirect($this->stringContains('customer/account/')); $this->assertSessionMessages( $this->equalTo(['You saved the account information.']), MessageInterface::TYPE_SUCCESS @@ -603,7 +606,7 @@ public function testMissingDataEditPostAction() $this->dispatch('customer/account/editPost'); - $this->assertRedirect($this->stringEndsWith('customer/account/edit/')); + $this->assertRedirect($this->stringContains('customer/account/edit/')); $this->assertSessionMessages( $this->equalTo(['"Email" is not a valid email address.']), MessageInterface::TYPE_ERROR @@ -633,7 +636,7 @@ public function testWrongPasswordEditPostAction() $this->dispatch('customer/account/editPost'); - $this->assertRedirect($this->stringEndsWith('customer/account/edit/')); + $this->assertRedirect($this->stringContains('customer/account/edit/')); // Not sure if its the most secure message. Not changing the behavior for now in the new AccountManagement APIs. $this->assertSessionMessages( $this->equalTo(["The password doesn't match this account. Verify the password and try again."]), @@ -662,7 +665,7 @@ public function testWrongConfirmationEditPostAction() $this->dispatch('customer/account/editPost'); - $this->assertRedirect($this->stringEndsWith('customer/account/edit/')); + $this->assertRedirect($this->stringContains('customer/account/edit/')); $this->assertSessionMessages( $this->equalTo(['Password confirmation doesn\'t match entered password.']), MessageInterface::TYPE_ERROR diff --git a/dev/tests/integration/testsuite/Magento/Customer/Controller/AddressTest.php b/dev/tests/integration/testsuite/Magento/Customer/Controller/AddressTest.php index 4c30adb6894e2..32a622d4aa654 100644 --- a/dev/tests/integration/testsuite/Magento/Customer/Controller/AddressTest.php +++ b/dev/tests/integration/testsuite/Magento/Customer/Controller/AddressTest.php @@ -18,6 +18,9 @@ class AddressTest extends \Magento\TestFramework\TestCase\AbstractController /** @var FormKey */ private $formKey; + /** + * {@inheritDoc} + */ protected function setUp() { parent::setUp(); @@ -150,8 +153,8 @@ public function testFailedFormPostAction() $this->equalTo( [ 'One or more input exceptions have occurred.', - '"street" is required. Enter and try again.', - '"city" is required. Enter and try again.', + '"street" is required. Enter and try again.', + '"city" is required. Enter and try again.', ] ), \Magento\Framework\Message\MessageInterface::TYPE_ERROR diff --git a/dev/tests/integration/testsuite/Magento/Customer/Controller/Adminhtml/Index/MassAssignGroupTest.php b/dev/tests/integration/testsuite/Magento/Customer/Controller/Adminhtml/Index/MassAssignGroupTest.php index ef5b4cae5ff16..8ee12fa1aa8d5 100644 --- a/dev/tests/integration/testsuite/Magento/Customer/Controller/Adminhtml/Index/MassAssignGroupTest.php +++ b/dev/tests/integration/testsuite/Magento/Customer/Controller/Adminhtml/Index/MassAssignGroupTest.php @@ -3,16 +3,21 @@ * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ +declare(strict_types=1); namespace Magento\Customer\Controller\Adminhtml\Index; -use Magento\TestFramework\Helper\Bootstrap; +use Magento\Backend\Model\Session; use Magento\Customer\Api\CustomerRepositoryInterface; +use Magento\Customer\Api\Data\CustomerInterface; +use Magento\Framework\Message\MessageInterface; +use Magento\TestFramework\Helper\Bootstrap; +use Magento\TestFramework\TestCase\AbstractBackendController; /** * @magentoAppArea adminhtml */ -class MassAssignGroupTest extends \Magento\TestFramework\TestCase\AbstractBackendController +class MassAssignGroupTest extends AbstractBackendController { /** * Base controller URL @@ -29,9 +34,7 @@ class MassAssignGroupTest extends \Magento\TestFramework\TestCase\AbstractBacken protected function setUp() { parent::setUp(); - $this->customerRepository = Bootstrap::getObjectManager()->get( - \Magento\Customer\Api\CustomerRepositoryInterface::class - ); + $this->customerRepository = Bootstrap::getObjectManager()->get(CustomerRepositoryInterface::class); } protected function tearDown() @@ -39,75 +42,97 @@ protected function tearDown() /** * Unset customer data */ - Bootstrap::getObjectManager()->get(\Magento\Backend\Model\Session::class)->setCustomerData(null); + Bootstrap::getObjectManager()->get(Session::class)->setCustomerData(null); /** * Unset messages */ - Bootstrap::getObjectManager()->get(\Magento\Backend\Model\Session::class)->getMessages(true); + Bootstrap::getObjectManager()->get(Session::class)->getMessages(true); } /** - * @magentoDataFixture Magento/Customer/_files/customer.php + * Tests os update a single customer record. + * + * @magentoDataFixture Magento/Customer/_files/five_repository_customers.php + * @magentoDbIsolation disabled */ public function testMassAssignGroupAction() { - $customer = $this->customerRepository->getById(1); + $customerEmail = 'customer1@example.com'; + /** @var CustomerInterface $customer */ + $customer = $this->customerRepository->get($customerEmail); $this->assertEquals(1, $customer->getGroupId()); - $this->getRequest() - ->setParam('group', 0) - ->setPostValue('namespace', 'customer_listing') - ->setPostValue('selected', [1]); + $params = [ + 'group' => 0, + 'namespace' => 'customer_listing', + 'selected' => [$customer->getId()] + ]; + + $this->getRequest()->setParams($params); $this->dispatch('backend/customer/index/massAssignGroup'); $this->assertSessionMessages( - $this->equalTo(['A total of 1 record(s) were updated.']), - \Magento\Framework\Message\MessageInterface::TYPE_SUCCESS + self::equalTo(['A total of 1 record(s) were updated.']), + MessageInterface::TYPE_SUCCESS ); $this->assertRedirect($this->stringStartsWith($this->baseControllerUrl)); - $customer = $this->customerRepository->getById(1); + $customer = $this->customerRepository->get($customerEmail); $this->assertEquals(0, $customer->getGroupId()); } /** - * @magentoDataFixture Magento/Customer/_files/twenty_one_customers.php + * Tests os update a multiple customer records. + * + * @magentoDataFixture Magento/Customer/_files/five_repository_customers.php + * @magentoDbIsolation disabled */ public function testLargeGroupMassAssignGroupAction() { - - for ($i = 1; $i < 22; $i++) { - $customer = $this->customerRepository->getById($i); + $ids = []; + for ($i = 1; $i <= 5; $i++) { + /** @var CustomerInterface $customer */ + $customer = $this->customerRepository->get('customer' . $i . '@example.com'); $this->assertEquals(1, $customer->getGroupId()); + $ids[] = $customer->getId(); } - $this->getRequest() - ->setParam('group', 0) - ->setPostValue('namespace', 'customer_listing') - ->setPostValue('selected', [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21]); + $params = [ + 'group' => 0, + 'namespace' => 'customer_listing', + 'selected' => $ids, + ]; + + $this->getRequest()->setParams($params); $this->dispatch('backend/customer/index/massAssignGroup'); $this->assertSessionMessages( - $this->equalTo(['A total of 21 record(s) were updated.']), - \Magento\Framework\Message\MessageInterface::TYPE_SUCCESS + self::equalTo(['A total of 5 record(s) were updated.']), + MessageInterface::TYPE_SUCCESS ); $this->assertRedirect($this->stringStartsWith($this->baseControllerUrl)); - for ($i = 1; $i < 22; $i++) { - $customer = $this->customerRepository->getById($i); + for ($i = 1; $i < 5; $i++) { + /** @var CustomerInterface $customer */ + $customer = $this->customerRepository->get('customer' . $i . '@example.com'); $this->assertEquals(0, $customer->getGroupId()); } } /** * Valid group Id but no customer Ids specified + * * @magentoDbIsolation enabled */ public function testMassAssignGroupActionNoCustomerIds() { - $this->getRequest()->setParam('group', 0)->setPostValue('namespace', 'customer_listing'); + $params = [ + 'group' => 0, + 'namespace' => 'customer_listing', + ]; + $this->getRequest()->setParams($params); $this->dispatch('backend/customer/index/massAssignGroup'); $this->assertSessionMessages( $this->equalTo(['An item needs to be selected. Select and try again.']), - \Magento\Framework\Message\MessageInterface::TYPE_ERROR + MessageInterface::TYPE_ERROR ); } } diff --git a/dev/tests/integration/testsuite/Magento/Customer/Controller/Adminhtml/Index/MassDeleteTest.php b/dev/tests/integration/testsuite/Magento/Customer/Controller/Adminhtml/Index/MassDeleteTest.php index b7aefe7c31707..940f7c84325f6 100644 --- a/dev/tests/integration/testsuite/Magento/Customer/Controller/Adminhtml/Index/MassDeleteTest.php +++ b/dev/tests/integration/testsuite/Magento/Customer/Controller/Adminhtml/Index/MassDeleteTest.php @@ -3,61 +3,162 @@ * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ +declare(strict_types=1); namespace Magento\Customer\Controller\Adminhtml\Index; +use Magento\Backend\Model\Session; +use Magento\Customer\Api\CustomerRepositoryInterface; +use Magento\Customer\Api\Data\CustomerInterface; +use PHPUnit\Framework\Constraint\Constraint; +use Magento\Framework\Message\MessageInterface; use Magento\TestFramework\Helper\Bootstrap; +use Magento\TestFramework\TestCase\AbstractBackendController; /** * @magentoAppArea adminhtml */ -class MassDeleteTest extends \Magento\TestFramework\TestCase\AbstractBackendController +class MassDeleteTest extends AbstractBackendController { + /** + * @var CustomerRepositoryInterface + */ + private $customerRepository; + /** * Base controller URL * * @var string */ - protected $baseControllerUrl = 'http://localhost/index.php/backend/customer/index/index'; + private $baseControllerUrl = 'http://localhost/index.php/backend/customer/index/index'; + + protected function setUp() + { + parent::setUp(); + $this->customerRepository = Bootstrap::getObjectManager()->get(CustomerRepositoryInterface::class); + } protected function tearDown() { /** * Unset customer data */ - Bootstrap::getObjectManager()->get(\Magento\Backend\Model\Session::class)->setCustomerData(null); + Bootstrap::getObjectManager()->get(Session::class)->setCustomerData(null); /** * Unset messages */ - Bootstrap::getObjectManager()->get(\Magento\Backend\Model\Session::class)->getMessages(true); + Bootstrap::getObjectManager()->get(Session::class)->getMessages(true); } /** - * @magentoDataFixture Magento/Customer/_files/customer.php + * Validates failure attempts to delete customers from grid. + * + * @param array|null $ids + * @param Constraint $constraint + * @param string|null $messageType + * @magentoDataFixture Magento/Customer/_files/five_repository_customers.php + * @magentoDbIsolation disabled + * @dataProvider failedRequestDataProvider */ - public function testMassDeleteAction() + public function testFailedMassDeleteAction($ids, Constraint $constraint, $messageType) { - $this->getRequest()->setPostValue('selected', [1])->setPostValue('namespace', 'customer_listing'); - $this->dispatch('backend/customer/index/massDelete'); - $this->assertSessionMessages( - $this->equalTo(['A total of 1 record(s) were deleted.']), - \Magento\Framework\Message\MessageInterface::TYPE_SUCCESS + $this->massDeleteAssertions($ids, $constraint, $messageType); + } + + /** + * Validates success attempt to delete customer from grid. + * + * @param array $emails + * @param Constraint $constraint + * @param string $messageType + * @magentoDataFixture Magento/Customer/_files/five_repository_customers.php + * @magentoDbIsolation disabled + * @dataProvider successRequestDataProvider + */ + public function testSuccessMassDeleteAction(array $emails, Constraint $constraint, string $messageType) + { + $ids = []; + foreach ($emails as $email) { + /** @var CustomerInterface $customer */ + $customer = $this->customerRepository->get($email); + $ids[] = $customer->getId(); + } + + $this->massDeleteAssertions( + $ids, + $constraint, + $messageType ); - $this->assertRedirect($this->stringStartsWith($this->baseControllerUrl)); } /** - * Valid group Id but no customer Ids specified - * @magentoDbIsolation enabled + * Performs required request and assertions. + * + * @param array|null $ids + * @param Constraint $constraint + * @param string|null $messageType */ - public function testMassDeleteActionNoCustomerIds() + private function massDeleteAssertions($ids, Constraint $constraint, $messageType) { - $this->getRequest()->setPostValue('namespace', 'customer_listing'); + $requestData = [ + 'selected' => $ids, + 'namespace' => 'customer_listing', + ]; + + $this->getRequest()->setParams($requestData); $this->dispatch('backend/customer/index/massDelete'); $this->assertSessionMessages( - $this->equalTo(['An item needs to be selected. Select and try again.']), - \Magento\Framework\Message\MessageInterface::TYPE_ERROR + $constraint, + $messageType ); + $this->assertRedirect($this->stringStartsWith($this->baseControllerUrl)); + } + + /** + * Provides sets of data for unsuccessful attempts. + * + * @return array + */ + public function failedRequestDataProvider(): array + { + return [ + [ + 'ids' => [], + 'constraint' => self::equalTo(['An item needs to be selected. Select and try again.']), + 'messageType' => MessageInterface::TYPE_ERROR, + ], + [ + 'ids' => [111], + 'constraint' => self::isEmpty(), + 'messageType' => null, + ], + [ + 'ids' => null, + 'constraint' => self::equalTo(['An item needs to be selected. Select and try again.']), + 'messageType' => MessageInterface::TYPE_ERROR, + ] + ]; + } + + /** + * Provides sets of data for successful attempts. + * + * @return array + */ + public function successRequestDataProvider(): array + { + return [ + [ + 'customerEmails' => ['customer1@example.com'], + 'constraint' => self::equalTo(['A total of 1 record(s) were deleted.']), + 'messageType' => MessageInterface::TYPE_SUCCESS, + ], + [ + 'customerEmails' => ['customer2@example.com', 'customer3@example.com'], + 'constraint' => self::equalTo(['A total of 2 record(s) were deleted.']), + 'messageType' => MessageInterface::TYPE_SUCCESS, + ], + ]; } } diff --git a/dev/tests/integration/testsuite/Magento/Customer/Controller/Adminhtml/Index/MassSubscribeTest.php b/dev/tests/integration/testsuite/Magento/Customer/Controller/Adminhtml/Index/MassSubscribeTest.php index d9880b2dc741a..c2fc7b1b58756 100644 --- a/dev/tests/integration/testsuite/Magento/Customer/Controller/Adminhtml/Index/MassSubscribeTest.php +++ b/dev/tests/integration/testsuite/Magento/Customer/Controller/Adminhtml/Index/MassSubscribeTest.php @@ -3,11 +3,17 @@ * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ +declare(strict_types=1); namespace Magento\Customer\Controller\Adminhtml\Index; +use Magento\Backend\Model\Session; +use Magento\Framework\Message\MessageInterface; use Magento\Newsletter\Model\Subscriber; +use Magento\Newsletter\Model\SubscriberFactory; use Magento\TestFramework\Helper\Bootstrap; +use Magento\Customer\Api\CustomerRepositoryInterface; +use Magento\Customer\Api\Data\CustomerInterface; /** * @magentoAppArea adminhtml @@ -26,58 +32,90 @@ protected function tearDown() /** * Unset customer data */ - Bootstrap::getObjectManager()->get(\Magento\Backend\Model\Session::class)->setCustomerData(null); + Bootstrap::getObjectManager()->get(Session::class)->setCustomerData(null); /** * Unset messages */ - Bootstrap::getObjectManager()->get(\Magento\Backend\Model\Session::class)->getMessages(true); + Bootstrap::getObjectManager()->get(Session::class)->getMessages(true); } /** - * @magentoDataFixture Magento/Customer/_files/two_customers.php + * Tests subscriber status of customers. + * + * @magentoDataFixture Magento/Customer/_files/five_repository_customers.php + * @magentoDbIsolation disabled */ public function testMassSubscriberAction() { - // Pre-condition - /** @var \Magento\Newsletter\Model\SubscriberFactory $subscriberFactory */ - $subscriberFactory = Bootstrap::getObjectManager()->get(\Magento\Newsletter\Model\SubscriberFactory::class); - $this->assertNull($subscriberFactory->create()->loadByCustomerId(1)->getSubscriberStatus()); - $this->assertNull($subscriberFactory->create()->loadByCustomerId(2)->getSubscriberStatus()); - // Setup - $this->getRequest()->setPostValue('selected', [1, 2])->setPostValue('namespace', 'customer_listing'); + /** @var SubscriberFactory $subscriberFactory */ + $subscriberFactory = Bootstrap::getObjectManager()->get(SubscriberFactory::class); + $customerRepository = Bootstrap::getObjectManager()->get(CustomerRepositoryInterface::class); + + $this->assertNull( + $subscriberFactory->create() + ->loadByEmail('customer1@example.com') + ->getSubscriberStatus() + ); + $this->assertNull( + $subscriberFactory->create() + ->loadByEmail('customer2@example.com') + ->getSubscriberStatus() + ); + + /** @var CustomerInterface $customer1 */ + $customer1 = $customerRepository->get('customer1@example.com'); + /** @var CustomerInterface $customer2 */ + $customer2 = $customerRepository->get('customer2@example.com'); + + $params = [ + 'selected' => [ + $customer1->getId(), + $customer2->getId(), + ], + 'namespace' => 'customer_listing', + ]; + $this->getRequest()->setParams($params); - // Test $this->dispatch('backend/customer/index/massSubscribe'); // Assertions $this->assertRedirect($this->stringStartsWith($this->baseControllerUrl)); $this->assertSessionMessages( - $this->equalTo(['A total of 2 record(s) were updated.']), - \Magento\Framework\Message\MessageInterface::TYPE_SUCCESS + self::equalTo(['A total of 2 record(s) were updated.']), + MessageInterface::TYPE_SUCCESS ); $this->assertEquals( Subscriber::STATUS_SUBSCRIBED, - $subscriberFactory->create()->loadByCustomerId(1)->getSubscriberStatus() + $subscriberFactory->create() + ->loadByEmail('customer1@example.com') + ->getSubscriberStatus() ); $this->assertEquals( Subscriber::STATUS_SUBSCRIBED, - $subscriberFactory->create()->loadByCustomerId(2)->getSubscriberStatus() + $subscriberFactory->create() + ->loadByEmail('customer2@example.com') + ->getSubscriberStatus() ); } /** + * @magentoAppIsolation enabled * @magentoDbIsolation enabled */ public function testMassSubscriberActionNoSelection() { - $this->getRequest()->setPostValue('namespace', 'customer_listing'); + $params = [ + 'namespace' => 'customer_listing' + ]; + + $this->getRequest()->setParams($params); $this->dispatch('backend/customer/index/massSubscribe'); $this->assertRedirect($this->stringStartsWith($this->baseControllerUrl)); $this->assertSessionMessages( - $this->equalTo(['An item needs to be selected. Select and try again.']), - \Magento\Framework\Message\MessageInterface::TYPE_ERROR + self::equalTo(['An item needs to be selected. Select and try again.']), + MessageInterface::TYPE_ERROR ); } } diff --git a/dev/tests/integration/testsuite/Magento/Customer/Controller/Adminhtml/IndexTest.php b/dev/tests/integration/testsuite/Magento/Customer/Controller/Adminhtml/IndexTest.php index b942365d64a75..6448816c9345c 100644 --- a/dev/tests/integration/testsuite/Magento/Customer/Controller/Adminhtml/IndexTest.php +++ b/dev/tests/integration/testsuite/Magento/Customer/Controller/Adminhtml/IndexTest.php @@ -44,6 +44,9 @@ class IndexTest extends \Magento\TestFramework\TestCase\AbstractBackendControlle /** @var \Magento\TestFramework\ObjectManager */ protected $objectManager; + /** + * {@inheritDoc} + */ protected function setUp() { parent::setUp(); @@ -67,6 +70,9 @@ protected function setUp() ); } + /** + * {@inheritDoc} + */ protected function tearDown() { /** @@ -522,7 +528,10 @@ public function testEditAction() $this->assertContains('<h1 class="page-title">test firstname test lastname</h1>', $body); } - public function testNewAction() + /** + * Tests new action + */ + public function testNewAction(): void { $this->dispatch('backend/customer/index/edit'); $body = $this->getResponse()->getBody(); @@ -717,12 +726,9 @@ public function testValidateCustomerWithAddressFailure() $this->assertContains('{"error":true,"messages":', $body); $this->assertContains('\"First Name\" is a required value', $body); - $this->assertContains('\"First Name\" length must be equal or greater than 1 characters', $body); $this->assertContains('\"Last Name\" is a required value.', $body); - $this->assertContains('\"Last Name\" length must be equal or greater than 1 characters.', $body); $this->assertContains('\"Country\" is a required value.', $body); $this->assertContains('\"Phone Number\" is a required value.', $body); - $this->assertContains('\"Phone Number\" length must be equal or greater than 1 characters.', $body); } /** diff --git a/dev/tests/integration/testsuite/Magento/Customer/_files/customer_with_website_rollback.php b/dev/tests/integration/testsuite/Magento/Customer/_files/customer_with_website_rollback.php new file mode 100644 index 0000000000000..2dbd1381b6f3c --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/Customer/_files/customer_with_website_rollback.php @@ -0,0 +1,28 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +declare(strict_types=1); + +/** @var \Magento\Framework\ObjectManagerInterface $objectManager */ +$objectManager = \Magento\TestFramework\Helper\Bootstrap::getObjectManager(); + +/** @var \Magento\Framework\Registry $registry */ +$registry = $objectManager->get(\Magento\Framework\Registry::class); +$registry->unregister('isSecureArea'); +$registry->register('isSecureArea', true); + +/** @var \Magento\Store\Model\StoreManager $store */ +$store = $objectManager->get(\Magento\Store\Model\StoreManager::class); + +/** @var $customer \Magento\Customer\Model\Customer*/ +$customer = $objectManager->create(\Magento\Customer\Model\Customer::class); +$customer->setWebsiteId($store->getDefaultStoreView()->getWebsiteId()); +$customer->loadByEmail('john.doe@magento.com'); +if ($customer->getId()) { + $customer->delete(); +} + +$registry->unregister('isSecureArea'); +$registry->register('isSecureArea', false); diff --git a/dev/tests/integration/testsuite/Magento/Customer/_files/five_repository_customers.php b/dev/tests/integration/testsuite/Magento/Customer/_files/five_repository_customers.php new file mode 100644 index 0000000000000..1722e471a5bbc --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/Customer/_files/five_repository_customers.php @@ -0,0 +1,49 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +declare(strict_types=1); + +use Magento\Customer\Api\CustomerRepositoryInterface; +use Magento\Customer\Api\Data\CustomerInterface; +use Magento\Customer\Api\Data\CustomerInterfaceFactory; +use Magento\Customer\Model\Customer; +use Magento\Eav\Model\Config as EavModelConfig; +use Magento\Framework\Indexer\IndexerInterface; +use Magento\Framework\Indexer\IndexerRegistry; +use Magento\TestFramework\Helper\Bootstrap; + +$objectManager = Bootstrap::getObjectManager(); + +/** @var CustomerRepositoryInterface $customerRepository */ +$customerRepository = $objectManager->create(CustomerRepositoryInterface::class); +/** @var CustomerInterfaceFactory $customerFactory */ +$customerFactory = $objectManager->get(CustomerInterfaceFactory::class); + +for ($i = 1; $i <= 5; $i++) { + /** @var CustomerInterface $customer */ + $customer = $customerFactory->create(); + $customer->setFirstname('John') + ->setGroupId(1) + ->setLastname('Smith') + ->setWebsiteId(1) + ->setEmail('customer'.$i.'@example.com'); + try { + $customerRepository->save($customer, 'password'); + } catch (\Exception $e) { + } +} + +/** @var EavModelConfig $eavConfig */ +$eavConfig = $objectManager->get(EavModelConfig::class); +$eavConfig->clear(); + +/** @var IndexerRegistry $indexerRegistry */ +$indexerRegistry = $objectManager->create(IndexerRegistry::class); +/** @var IndexerInterface $indexer */ +$indexer = $indexerRegistry->get(Customer::CUSTOMER_GRID_INDEXER_ID); +try { + $indexer->reindexAll(); +} catch (\Exception $e) { +} diff --git a/dev/tests/integration/testsuite/Magento/Customer/_files/five_repository_customers_rollback.php b/dev/tests/integration/testsuite/Magento/Customer/_files/five_repository_customers_rollback.php new file mode 100644 index 0000000000000..5272d9cdbf06d --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/Customer/_files/five_repository_customers_rollback.php @@ -0,0 +1,29 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +declare(strict_types=1); + +use Magento\Customer\Api\CustomerRepositoryInterface; +use Magento\TestFramework\Helper\Bootstrap; +use Magento\Customer\Api\Data\CustomerInterface; +use Magento\Eav\Model\Config as EavModelConfig; + +$objectManager = Bootstrap::getObjectManager(); + +/** @var CustomerRepositoryInterface $repository */ +$customerRepository = $objectManager->create(CustomerRepositoryInterface::class); + +for ($i = 1; $i <= 5; $i++) { + try { + /** @var CustomerInterface $customer */ + $customer = $customerRepository->get('customer'.$i.'@example.com'); + $customerRepository->delete($customer); + } catch (\Exception $e) { + } +} + +/** @var EavModelConfig $eavConfig */ +$eavConfig = $objectManager->get(EavModelConfig::class); +$eavConfig->clear(); diff --git a/dev/tests/integration/testsuite/Magento/Downloadable/_files/product_downloadable_with_files.php b/dev/tests/integration/testsuite/Magento/Downloadable/_files/product_downloadable_with_files.php index cf0da5599914f..86aa61a99e1e8 100644 --- a/dev/tests/integration/testsuite/Magento/Downloadable/_files/product_downloadable_with_files.php +++ b/dev/tests/integration/testsuite/Magento/Downloadable/_files/product_downloadable_with_files.php @@ -154,3 +154,10 @@ $product->setTypeHasRequiredOptions(false)->setRequiredOptions(false); } $product->save(); + +$stockRegistry = $objectManager->get(\Magento\CatalogInventory\Api\StockRegistryInterface::class); +$stockItem = $stockRegistry->getStockItem($product->getId()); +$stockItem->setUseConfigManageStock(true); +$stockItem->setQty(100); +$stockItem->setIsInStock(true); +$stockRegistry->updateStockItemBySku($product->getSku(), $stockItem); diff --git a/dev/tests/integration/testsuite/Magento/Eav/Model/Entity/AttributeTest.php b/dev/tests/integration/testsuite/Magento/Eav/Model/Entity/AttributeTest.php new file mode 100644 index 0000000000000..2750e2a768aab --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/Eav/Model/Entity/AttributeTest.php @@ -0,0 +1,119 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ + +declare(strict_types=1); + +namespace Magento\Eav\Model\Entity; + +use Magento\TestFramework\Helper\Bootstrap; +use Magento\Framework\Locale\ResolverInterface; + +class AttributeTest extends \PHPUnit\Framework\TestCase +{ + /** + * @var Attribute + */ + private $attribute; + + /** + * @var \Magento\Framework\ObjectManagerInterface + */ + private $objectManager; + + /** + * @var ResolverInterface + */ + private $_localeResolver; + + /** + * {@inheritdoc} + */ + protected function setUp() + { + $this->objectManager = Bootstrap::getObjectManager(); + $this->attribute = $this->objectManager->get(Attribute::class); + $this->_localeResolver = $this->objectManager->get(ResolverInterface::class); + } + + /** + * {@inheritdoc} + */ + protected function tearDown() + { + $this->attribute = null; + $this->objectManager = null; + $this->_localeResolver = null; + } + + /** + * @param string $defaultValue + * @param string $backendType + * @param string $locale + * @param string $expected + * @dataProvider beforeSaveDataProvider + * @throws + */ + public function testBeforeSave($defaultValue, $backendType, $locale, $expected) + { + $this->attribute->setDefaultValue($defaultValue); + $this->attribute->setBackendType($backendType); + $this->_localeResolver->setLocale($locale); + $this->attribute->beforeSave(); + + $this->assertEquals($expected, $this->attribute->getDefaultValue()); + } + + /** + * Data provider for beforeSaveData. + * + * @return array + */ + public function beforeSaveDataProvider() + { + return [ + ['21/07/18', 'datetime', 'en_AU', '2018-07-21 00:00:00'], + ['07/21/18', 'datetime', 'en_US', '2018-07-21 00:00:00'], + ['21/07/18', 'datetime', 'fr_FR', '2018-07-21 00:00:00'], + ['21/07/18', 'datetime', 'de_DE', '2018-07-21 00:00:00'], + ['21/07/18', 'datetime', 'uk_UA', '2018-07-21 00:00:00'], + ['100.50', 'decimal', 'en_US', '100.50'], + ['100,50', 'decimal', 'uk_UA', '100.5'], + ]; + } + + /** + * @param string $defaultValue + * @param string $backendType + * @param string $locale + * @param string $expected + * @dataProvider beforeSaveErrorDataDataProvider + * @expectedException \Magento\Framework\Exception\LocalizedException + */ + public function testBeforeSaveErrorData($defaultValue, $backendType, $locale, $expected) + { + $this->attribute->setDefaultValue($defaultValue); + $this->attribute->setBackendType($backendType); + $this->_localeResolver->setLocale($locale); + $this->attribute->beforeSave(); + + $this->expectExceptionMessage($expected); + } + + /** + * Data provider for beforeSaveData with error result. + * + * @return array + */ + public function beforeSaveErrorDataDataProvider() + { + return [ + 'wrong date for Australia' => ['32/38', 'datetime', 'en_AU', 'Invalid default date'], + 'wrong date for States' => ['32/38', 'datetime', 'en_US', 'Invalid default date'], + 'wrong decimal separator for US' => ['100,50', 'decimal', 'en_US', 'Invalid default decimal value'], + 'wrong decimal separator for UA' => ['100.50', 'decimal', 'uk_UA', 'Invalid default decimal value'], + ]; + } +} diff --git a/dev/tests/integration/testsuite/Magento/Eav/Model/ResourceModel/Entity/Attribute/CollectionTest.php b/dev/tests/integration/testsuite/Magento/Eav/Model/ResourceModel/Entity/Attribute/CollectionTest.php index e39f1e2fd8390..c273e87f6d738 100644 --- a/dev/tests/integration/testsuite/Magento/Eav/Model/ResourceModel/Entity/Attribute/CollectionTest.php +++ b/dev/tests/integration/testsuite/Magento/Eav/Model/ResourceModel/Entity/Attribute/CollectionTest.php @@ -52,6 +52,20 @@ public function testSetAttributeGroupFilter() $this->assertEquals([$includeGroupId], $groups); } + /** + * Test if getAllIds method return results after using setInAllAttributeSetsFilter method + * + * @covers \Magento\Eav\Model\ResourceModel\Entity\Attribute\Collection::setInAllAttributeSetsFilter() + * @covers \Magento\Eav\Model\ResourceModel\Entity\Attribute\Collection::getAllIds() + */ + public function testSetInAllAttributeSetsFilterWithGetAllIds() + { + $sets = [1]; + $this->_model->setInAllAttributeSetsFilter($sets); + $attributeIds = $this->_model->getAllIds(); + $this->assertGreaterThan(0, count($attributeIds)); + } + /** * Returns array of group ids, present in collection attributes * diff --git a/dev/tests/integration/testsuite/Magento/Framework/App/Filesystem/CreatePdfFileTest.php b/dev/tests/integration/testsuite/Magento/Framework/App/Filesystem/CreatePdfFileTest.php new file mode 100644 index 0000000000000..9ac778da91f29 --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/Framework/App/Filesystem/CreatePdfFileTest.php @@ -0,0 +1,56 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + * + */ +declare(strict_types=1); + +namespace Magento\Framework\App\Filesystem; + +use Magento\Framework\App\Filesystem\DirectoryList; +use Magento\Framework\App\Response\Http\FileFactory; +use Magento\Framework\Filesystem; +use Magento\TestFramework\Helper\Bootstrap; +use Zend\Http\Header\ContentType; + +/** + * Class CreatePdfFileTest + * + * Integration test for testing a file creation from string + */ +class CreatePdfFileTest extends \PHPUnit\Framework\TestCase +{ + /** + * @throws \Exception + */ + public function testGenerateFileFromString() + { + $objectManager = Bootstrap::getObjectManager(); + /** @var FileFactory $fileFactory */ + $fileFactory = $objectManager->get(FileFactory::class); + /** @var Filesystem $filesystem */ + $filesystem = $objectManager->get(Filesystem::class); + $filename = 'test.pdf'; + $contentType = 'application/pdf'; + $fileContent = ['type' => 'string', 'value' => '']; + $response = $fileFactory->create($filename, $fileContent, DirectoryList::VAR_DIR, $contentType); + /** @var ContentType $contentTypeHeader */ + $contentTypeHeader = $response->getHeader('Content-type'); + + /* Check the system returns the correct type */ + self::assertEquals("Content-Type: $contentType", $contentTypeHeader->toString()); + + $varDirectory = $filesystem->getDirectoryRead(DirectoryList::VAR_DIR); + $varDirectory->isFile($filename); + + /* Check the file is generated */ + self::assertTrue($varDirectory->isFile($filename)); + + /* Check the file is removed after generation if the corresponding option is set */ + $fileContent = ['type' => 'string', 'value' => '', 'rm' => true]; + $fileFactory->create($filename, $fileContent, DirectoryList::VAR_DIR, $contentType); + + self::assertFalse($varDirectory->isFile($filename)); + } +} diff --git a/dev/tests/integration/testsuite/Magento/Multishipping/Controller/Checkout/CheckItemsTest.php b/dev/tests/integration/testsuite/Magento/Multishipping/Controller/Checkout/CheckItemsTest.php new file mode 100644 index 0000000000000..02f031fae336a --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/Multishipping/Controller/Checkout/CheckItemsTest.php @@ -0,0 +1,176 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +declare(strict_types=1); + +namespace Magento\Multishipping\Controller\Checkout; + +use Magento\Catalog\Model\Product; +use Magento\Catalog\Api\ProductRepositoryInterface; +use Magento\Checkout\Model\Session; +use Magento\Customer\Api\AccountManagementInterface; +use Magento\Customer\Model\Session as CustomerSession; +use Magento\Framework\Exception\LocalizedException; +use Magento\Quote\Model\Quote; +use Magento\Framework\Api\SearchCriteriaBuilder; +use Magento\Quote\Api\CartRepositoryInterface as QuoteRepository; +use Magento\Framework\Serialize\Serializer\Json; + +/** + * Test class for \Magento\Multishipping\Controller\Checkout + * + * @magentoAppArea frontend + * @magentoDataFixture Magento/Sales/_files/quote.php + * @magentoDataFixture Magento/Customer/_files/customer.php + */ +class CheckItemsTest extends \Magento\TestFramework\TestCase\AbstractController +{ + /** + * @var Quote + */ + private $quote; + + /** + * @var Session + */ + private $checkoutSession; + + /** + * @var ProductRepositoryInterface + */ + private $productRepository; + + /** + * @var Json + */ + private $json; + + /** + * @inheritdoc + */ + public function setUp() + { + parent::setUp(); + + $this->checkoutSession = $this->_objectManager->get(Session::class); + $this->productRepository = $this->_objectManager->get(ProductRepositoryInterface::class); + $this->json = $this->_objectManager->get(Json::class); + $this->quote = $this->getQuote('test01'); + $this->checkoutSession->setQuoteId($this->quote->getId()); + $this->checkoutSession->setCartWasUpdated(false); + } + + /** + * Validator of quote items. + * + * @param array $requestQuantity + * @param array $expectedResponse + * + * @magentoConfigFixture current_store multishipping/options/checkout_multiple 1 + * @magentoConfigFixture current_store multishipping/options/checkout_multiple_maximum_qty 200 + * @dataProvider requestDataProvider + */ + public function testExecute($requestQuantity, $expectedResponse) + { + $this->loginCustomer(); + + try { + /** @var $product Product */ + $product = $this->productRepository->get('simple'); + } catch (\Exception $e) { + $this->fail('No such product entity'); + } + + $quoteItem = $this->quote->getItemByProduct($product); + $this->assertNotFalse($quoteItem, 'Cannot get quote item for simple product'); + + $request = []; + if (!empty($requestQuantity) && is_array($requestQuantity)) { + $request= [ + 'ship' => [ + [$quoteItem->getId() => $requestQuantity], + ] + ]; + } + + $this->getRequest()->setPostValue($request); + $this->dispatch('multishipping/checkout/checkItems'); + $response = $this->getResponse()->getBody(); + + $this->assertEquals($expectedResponse, $this->json->unserialize($response)); + } + + /** + * Authenticates customer and creates customer session. + */ + private function loginCustomer() + { + $logger = $this->createMock(\Psr\Log\LoggerInterface::class); + /** @var AccountManagementInterface $service */ + $service = $this->_objectManager->create(AccountManagementInterface::class); + try { + $customer = $service->authenticate('customer@example.com', 'password'); + } catch (LocalizedException $e) { + $this->fail($e->getMessage()); + } + /** @var CustomerSession $customerSession */ + $customerSession = $this->_objectManager->create(CustomerSession::class, [$logger]); + $customerSession->setCustomerDataAsLoggedIn($customer); + } + + /** + * Gets quote by reserved order id. + * + * @param string $reservedOrderId + * @return Quote + */ + private function getQuote($reservedOrderId) + { + /** @var SearchCriteriaBuilder $searchCriteriaBuilder */ + $searchCriteriaBuilder = $this->_objectManager->create(SearchCriteriaBuilder::class); + $searchCriteria = $searchCriteriaBuilder->addFilter('reserved_order_id', $reservedOrderId) + ->create(); + /** @var QuoteRepository $quoteRepository */ + $quoteRepository = $this->_objectManager->get(QuoteRepository::class); + $items = $quoteRepository->getList($searchCriteria) + ->getItems(); + return array_pop($items); + } + + /** + * Variations of request data. + * @returns array + */ + public function requestDataProvider(): array + { + return [ + [ + 'request' => [], + 'response' => [ + 'success' => false, + 'error_message' => 'We are unable to process your request. Please, try again later.' + ] + ], + [ + 'request' => ['qty' => 2], + 'response' => [ + 'success' => true, + ] + ], + [ + 'request' => ['qty' => 101], + 'response' => [ + 'success' => false, + 'error_message' => 'The requested qty is not available'] + ], + [ + 'request' => ['qty' => 230], + 'response' => [ + 'success' => false, + 'error_message' => 'Maximum qty allowed for Shipping to multiple addresses is 200'] + ], + ]; + } +} diff --git a/dev/tests/integration/testsuite/Magento/Newsletter/Controller/ManageTest.php b/dev/tests/integration/testsuite/Magento/Newsletter/Controller/ManageTest.php index 1a27994b607f1..5a094eb05c774 100644 --- a/dev/tests/integration/testsuite/Magento/Newsletter/Controller/ManageTest.php +++ b/dev/tests/integration/testsuite/Magento/Newsletter/Controller/ManageTest.php @@ -21,6 +21,9 @@ class ManageTest extends \Magento\TestFramework\TestCase\AbstractController */ protected $coreSession; + /** + * Test setup + */ protected function setUp() { parent::setUp(); @@ -31,6 +34,9 @@ protected function setUp() $this->coreSession->setData('_form_key', 'formKey'); } + /** + * test tearDown + */ protected function tearDown() { $this->customerSession->setCustomerId(null); @@ -58,7 +64,7 @@ public function testSaveAction() * Check that success message */ $this->assertSessionMessages( - $this->equalTo(['We saved the subscription.']), + $this->equalTo(['We have saved your subscription.']), \Magento\Framework\Message\MessageInterface::TYPE_SUCCESS ); } @@ -68,6 +74,7 @@ public function testSaveAction() */ public function testSaveActionRemoveSubscription() { + $this->getRequest() ->setParam('form_key', 'formKey') ->setParam('is_subscribed', '0'); @@ -84,7 +91,7 @@ public function testSaveActionRemoveSubscription() * Check that success message */ $this->assertSessionMessages( - $this->equalTo(['We removed the subscription.']), + $this->equalTo(['We have updated your subscription.']), \Magento\Framework\Message\MessageInterface::TYPE_SUCCESS ); } diff --git a/dev/tests/integration/testsuite/Magento/Paypal/Model/Config/Structure/Reader/_files/expected/config.xml b/dev/tests/integration/testsuite/Magento/Paypal/Model/Config/Structure/Reader/_files/expected/config.xml index 2552d383bbcc3..2bd346a6e8f7b 100644 --- a/dev/tests/integration/testsuite/Magento/Paypal/Model/Config/Structure/Reader/_files/expected/config.xml +++ b/dev/tests/integration/testsuite/Magento/Paypal/Model/Config/Structure/Reader/_files/expected/config.xml @@ -350,7 +350,7 @@ <field id="enable_express_checkout_bml" extends="payment_all_paypal/express_checkout/express_checkout_required/enable_express_checkout_bml" sortOrder="41"> <comment><![CDATA[Payflow Link lets you give customers access to financing through PayPal Credit® - at no additional cost to you. You get paid up front, even though customers have more time to pay. A pre-integrated payment button lets customers pay quickly with PayPal Credit®. - <a href="https:/www.paypal.com/webapps/mpp/promotional-financing" target="_blank">Learn More</a>]]> + <a href="https://www.paypal.com/webapps/mpp/promotional-financing" target="_blank">Learn More</a>]]> </comment> <config_path>payment/payflow_express_bml/active</config_path> <frontend_model>Magento\Paypal\Block\Adminhtml\System\Config\Field\Enable\Bml</frontend_model> @@ -371,12 +371,12 @@ <group id="payflow_link_advertise_bml" translate="label comment" showInDefault="1" showInWebsite="1" sortOrder="60"> <label>Advertise PayPal Credit</label> <comment> - <![CDATA[<a href="https:/financing.paypal.com/ppfinportal/content/whyUseFinancing" target="_blank">Why Advertise Financing?</a><br/> + <![CDATA[<a href="https://financing.paypal.com/ppfinportal/content/whyUseFinancing" target="_blank">Why Advertise Financing?</a><br/> <strong>Give your sales a boost when you advertise financing.</strong><br/>PayPal helps turn browsers into buyers with financing from PayPal Credit®. Your customers have more time to pay, while you get paid up front – at no additional cost to you. Use PayPal’s free banner ads that let you advertise PayPal Credit® financing as a payment option when your customers check out with PayPal. The PayPal Advertising Program has been shown to generate additional purchases as well as increase consumer's average purchase sizes by 15% - or more. <a href="https:/financing.paypal.com/ppfinportal/content/forrester" target="_blank">See Details</a>.]]> + or more. <a href="https://financing.paypal.com/ppfinportal/content/forrester" target="_blank">See Details</a>.]]> </comment> <field id="bml_publisher_id" extends="payment_all_paypal/express_checkout/express_checkout_required/advertise_bml/bml_publisher_id" /> <field id="bml_wizard" extends="payment_all_paypal/express_checkout/express_checkout_required/advertise_bml/bml_wizard" /> @@ -731,7 +731,7 @@ <label>Enable PayPal Credit</label> <comment><![CDATA[PayPal Express Checkout lets you give customers access to financing through PayPal Credit® - at no additional cost to you. You get paid up front, even though customers have more time to pay. A pre-integrated payment button lets customers pay quickly with PayPal Credit®. - <a href="https:/www.paypal.com/webapps/mpp/promotional-financing" target="_blank">Learn More</a>]]> + <a href="https://www.paypal.com/webapps/mpp/promotional-financing" target="_blank">Learn More</a>]]> </comment> <config_path>payment/paypal_express_bml/active</config_path> <source_model>Magento\Config\Model\Config\Source\Yesno</source_model> @@ -753,12 +753,12 @@ <group id="advertise_bml" translate="label comment" showInDefault="1" showInWebsite="1" sortOrder="30"> <label>Advertise PayPal Credit</label> <comment> - <![CDATA[<a href="https:/financing.paypal.com/ppfinportal/content/whyUseFinancing" target="_blank">Why Advertise Financing?</a><br/> + <![CDATA[<a href="https://financing.paypal.com/ppfinportal/content/whyUseFinancing" target="_blank">Why Advertise Financing?</a><br/> <strong>Give your sales a boost when you advertise financing.</strong><br/>PayPal helps turn browsers into buyers with financing from PayPal Credit®. Your customers have more time to pay, while you get paid up front – at no additional cost to you. Use PayPal’s free banner ads that let you advertise PayPal Credit® financing as a payment option when your customers check out with PayPal. The PayPal Advertising Program has been shown to generate additional purchases as well as increase consumer's average purchase sizes by 15% - or more. <a href="https:/financing.paypal.com/ppfinportal/content/forrester" target="_blank">See Details</a>.]]> + or more. <a href="https://financing.paypal.com/ppfinportal/content/forrester" target="_blank">See Details</a>.]]> </comment> <field id="bml_publisher_id" translate="label comment tooltip" showInDefault="1" showInWebsite="1" sortOrder="10"> <label>Publisher ID</label> @@ -768,7 +768,7 @@ </field> <field id="bml_wizard" translate="button_label" sortOrder="15" showInDefault="1" showInWebsite="1"> <button_label>Get Publisher ID from PayPal</button_label> - <button_url><![CDATA[https:/financing.paypal.com/ppfinportal/cart/index?dcp=4eff8563b9cc505e0b9afaff3256705081553c79]]></button_url> + <button_url><![CDATA[https://financing.paypal.com/ppfinportal/cart/index?dcp=4eff8563b9cc505e0b9afaff3256705081553c79]]></button_url> <frontend_model>Magento\Paypal\Block\Adminhtml\System\Config\BmlApiWizard</frontend_model> </field> <group id="settings_bml_homepage" translate="label" showInDefault="1" showInWebsite="1" showInStore="1" sortOrder="20"> @@ -1261,7 +1261,7 @@ <field id="enable_express_checkout_bml" extends="payment_all_paypal/express_checkout/express_checkout_required/enable_express_checkout_bml" sortOrder="21"> <comment><![CDATA[Payments Pro Hosted Solution lets you give customers access to financing through PayPal Credit® - at no additional cost to you. You get paid up front, even though customers have more time to pay. A pre-integrated payment button lets customers pay quickly with PayPal Credit®. - <a href="https:/www.paypal.com/webapps/mpp/promotional-financing" target="_blank">Learn More</a>]]> + <a href="https://www.paypal.com/webapps/mpp/promotional-financing" target="_blank">Learn More</a>]]> </comment> <requires> <field id="pphs_enable"/> @@ -1270,12 +1270,12 @@ <group id="pphs_advertise_bml" translate="label comment" showInDefault="1" showInWebsite="1" sortOrder="22"> <label>Advertise PayPal Credit</label> <comment> - <![CDATA[<a href="https:/financing.paypal.com/ppfinportal/content/whyUseFinancing" target="_blank">Why Advertise Financing?</a><br/> + <![CDATA[<a href="https://financing.paypal.com/ppfinportal/content/whyUseFinancing" target="_blank">Why Advertise Financing?</a><br/> <strong>Give your sales a boost when you advertise financing.</strong><br/>PayPal helps turn browsers into buyers with financing from PayPal Credit®. Your customers have more time to pay, while you get paid up front – at no additional cost to you. Use PayPal’s free banner ads that let you advertise PayPal Credit® financing as a payment option when your customers check out with PayPal. The PayPal Advertising Program has been shown to generate additional purchases as well as increase consumer's average purchase sizes by 15% - or more. <a href="https:/financing.paypal.com/ppfinportal/content/forrester" target="_blank">See Details</a>.]]> + or more. <a href="https://financing.paypal.com/ppfinportal/content/forrester" target="_blank">See Details</a>.]]> </comment> <field id="bml_publisher_id" extends="payment_all_paypal/express_checkout/express_checkout_required/advertise_bml/bml_publisher_id" /> <field id="bml_wizard" extends="payment_all_paypal/express_checkout/express_checkout_required/advertise_bml/bml_wizard" /> @@ -1536,7 +1536,7 @@ <field id="enable_express_checkout_bml" sortOrder="42" extends="payment_all_paypal/express_checkout/express_checkout_required/enable_express_checkout_bml"> <comment><![CDATA[PayPal Express Checkout Payflow Edition lets you give customers access to financing through PayPal Credit® - at no additional cost to you. You get paid up front, even though customers have more time to pay. A pre-integrated payment button lets customers pay quickly with PayPal Credit®. - <a href="https:/www.paypal.com/webapps/mpp/promotional-financing" target="_blank">Learn More</a>]]> + <a href="https://www.paypal.com/webapps/mpp/promotional-financing" target="_blank">Learn More</a>]]> </comment> <config_path>payment/payflow_express_bml/active</config_path> <frontend_model>Magento\Paypal\Block\Adminhtml\System\Config\Field\Enable\Bml</frontend_model> @@ -1836,7 +1836,7 @@ <label>Enable PayPal Credit</label> <comment><![CDATA[PayPal Express Checkout Payflow Edition lets you give customers access to financing through PayPal Credit® - at no additional cost to you. You get paid up front, even though customers have more time to pay. A pre-integrated payment button lets customers pay quickly with PayPal Credit®. - <a href="https:/www.paypal.com/webapps/mpp/promotional-financing" target="_blank">Learn More</a>]]> + <a href="https://www.paypal.com/webapps/mpp/promotional-financing" target="_blank">Learn More</a>]]> </comment> <config_path>payment/payflow_express_bml/active</config_path> <source_model>Magento\Config\Model\Config\Source\Yesno</source_model> @@ -1855,12 +1855,12 @@ <group id="paypal_payflow_advertise_bml" translate="label comment" showInDefault="1" showInWebsite="1" sortOrder="40"> <label>Advertise PayPal Credit</label> <comment> - <![CDATA[<a href="https:/financing.paypal.com/ppfinportal/content/whyUseFinancing" target="_blank">Why Advertise Financing?</a><br/> + <![CDATA[<a href="https://financing.paypal.com/ppfinportal/content/whyUseFinancing" target="_blank">Why Advertise Financing?</a><br/> <strong>Give your sales a boost when you advertise financing.</strong><br/>PayPal helps turn browsers into buyers with financing from PayPal Credit®. Your customers have more time to pay, while you get paid up front – at no additional cost to you. Use PayPal’s free banner ads that let you advertise PayPal Credit® financing as a payment option when your customers check out with PayPal. The PayPal Advertising Program has been shown to generate additional purchases as well as increase consumer's average purchase sizes by 15% - or more. <a href="https:/financing.paypal.com/ppfinportal/content/forrester" target="_blank">See Details</a>.]]> + or more. <a href="https://financing.paypal.com/ppfinportal/content/forrester" target="_blank">See Details</a>.]]> </comment> <field id="bml_publisher_id" extends="payment_all_paypal/express_checkout/express_checkout_required/advertise_bml/bml_publisher_id" /> <field id="bml_wizard" extends="payment_all_paypal/express_checkout/express_checkout_required/advertise_bml/bml_wizard" /> diff --git a/dev/tests/integration/testsuite/Magento/Quote/Model/Plugin/UpdateQuoteStoreTest.php b/dev/tests/integration/testsuite/Magento/Quote/Model/Plugin/UpdateQuoteStoreTest.php new file mode 100644 index 0000000000000..cbacab1139c10 --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/Quote/Model/Plugin/UpdateQuoteStoreTest.php @@ -0,0 +1,130 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +declare(strict_types=1); + +namespace Magento\Quote\Model\Plugin; + +use Magento\Checkout\Model\Session; +use Magento\Framework\Api\SearchCriteriaBuilder; +use Magento\FunctionalTestingFramework\ObjectManagerInterface; +use Magento\Quote\Api\CartRepositoryInterface; +use Magento\Quote\Model\Quote; +use Magento\Store\Api\Data\StoreInterface; +use Magento\Store\Api\StoreCookieManagerInterface; +use Magento\Store\Model\StoreManagerInterface; +use Magento\Store\Model\StoreRepository; +use Magento\TestFramework\Helper\Bootstrap as BootstrapHelper; + +/** + * @magentoAppArea frontend + * @SuppressWarnings(PHPMD.CouplingBetweenObjects) + */ +class UpdateQuoteStoreTest extends \PHPUnit\Framework\TestCase +{ + /** + * @var ObjectManagerInterface + */ + private $objectManager; + + /** + * @var CartRepositoryInterface + */ + private $quoteRepository; + + protected function setUp() + { + $this->objectManager = BootstrapHelper::getObjectManager(); + $this->quoteRepository = $this->objectManager->create(CartRepositoryInterface::class); + } + + /** + * Tests that active quote store id updates after store cookie change. + * + * @magentoDataFixture Magento/Quote/_files/empty_quote.php + * @magentoDataFixture Magento/Store/_files/second_store.php + * @throws \ReflectionException + * @throws \Magento\Framework\Exception\NoSuchEntityException + */ + public function testUpdateQuoteStoreAfterChangeStoreCookie() + { + $secondStoreCode = 'fixture_second_store'; + $reservedOrderId = 'reserved_order_id'; + + /** @var StoreManagerInterface $storeManager */ + $storeManager = $this->objectManager->get(StoreManagerInterface::class); + $currentStore = $storeManager->getStore(); + + $quote = $this->getQuote($reservedOrderId); + $this->assertEquals( + $currentStore->getId(), + $quote->getStoreId(), + 'Current store id and quote store id are not match' + ); + + /** @var Session $checkoutSession */ + $checkoutSession = $this->objectManager->get(Session::class); + $checkoutSession->setQuoteId($quote->getId()); + + $storeRepository = $this->objectManager->create(StoreRepository::class); + $secondStore = $storeRepository->get($secondStoreCode); + + $storeCookieManager = $this->getStoreCookieManager($currentStore); + $storeCookieManager->setStoreCookie($secondStore); + + $updatedQuote = $this->getQuote($reservedOrderId); + $this->assertEquals( + $secondStore->getId(), + $updatedQuote->getStoreId(), + 'Active quote store id should be equal second store id' + ); + } + + /** + * Retrieves quote by reserved order id. + * + * @param string $reservedOrderId + * @return Quote + */ + private function getQuote(string $reservedOrderId): Quote + { + /** @var SearchCriteriaBuilder $searchCriteriaBuilder */ + $searchCriteriaBuilder = $this->objectManager->get(SearchCriteriaBuilder::class); + $searchCriteria = $searchCriteriaBuilder->addFilter('reserved_order_id', $reservedOrderId) + ->create(); + + $items = $this->quoteRepository->getList($searchCriteria)->getItems(); + + return array_pop($items); + } + + /** + * Returns instance of StoreCookieManagerInterface with mocked cookieManager dependency. + * + * Mock is needed since integration test framework use own cookie manager with + * behavior that differs from real environment. + * + * @param $currentStore + * @return StoreCookieManagerInterface + * @throws \ReflectionException + */ + private function getStoreCookieManager(StoreInterface $currentStore): StoreCookieManagerInterface + { + /** @var StoreCookieManagerInterface $storeCookieManager */ + $storeCookieManager = $this->objectManager->get(StoreCookieManagerInterface::class); + $cookieManagerMock = $this->getMockBuilder(\Magento\Framework\Stdlib\Cookie\PhpCookieManager::class) + ->disableOriginalConstructor() + ->getMock(); + $cookieManagerMock->method('getCookie') + ->willReturn($currentStore->getCode()); + + $reflection = new \ReflectionClass($storeCookieManager); + $cookieManager = $reflection->getProperty('cookieManager'); + $cookieManager->setAccessible(true); + $cookieManager->setValue($storeCookieManager, $cookieManagerMock); + + return $storeCookieManager; + } +} diff --git a/dev/tests/integration/testsuite/Magento/Quote/Model/Quote/AddressTest.php b/dev/tests/integration/testsuite/Magento/Quote/Model/Quote/AddressTest.php index d59c402e22a71..62e417d27c51b 100644 --- a/dev/tests/integration/testsuite/Magento/Quote/Model/Quote/AddressTest.php +++ b/dev/tests/integration/testsuite/Magento/Quote/Model/Quote/AddressTest.php @@ -11,7 +11,7 @@ * @magentoDataFixture Magento/Sales/_files/quote_with_customer.php * @magentoDataFixture Magento/Customer/_files/customer_two_addresses.php */ -class AddressTest extends \PHPUnit\Framework\TestCase +class AddressTest extends \Magento\TestFramework\Indexer\TestCase { /** @var \Magento\Quote\Model\Quote $quote */ protected $_quote; @@ -25,6 +25,19 @@ class AddressTest extends \PHPUnit\Framework\TestCase /**@var \Magento\Customer\Api\CustomerRepositoryInterface $customerRepository */ protected $customerRepository; + public static function setUpBeforeClass() + { + $db = \Magento\TestFramework\Helper\Bootstrap::getInstance()->getBootstrap() + ->getApplication() + ->getDbInstance(); + if (!$db->isDbDumpExists()) { + throw new \LogicException('DB dump does not exist.'); + } + $db->restoreFromDbDump(); + + parent::setUpBeforeClass(); + } + /** * Initialize quote and customer fixtures */ diff --git a/dev/tests/integration/testsuite/Magento/Quote/Model/QuoteRepositoryTest.php b/dev/tests/integration/testsuite/Magento/Quote/Model/QuoteRepositoryTest.php index 88c66fedd10ed..3e093876349d0 100644 --- a/dev/tests/integration/testsuite/Magento/Quote/Model/QuoteRepositoryTest.php +++ b/dev/tests/integration/testsuite/Magento/Quote/Model/QuoteRepositoryTest.php @@ -5,6 +5,7 @@ */ namespace Magento\Quote\Model; +use Magento\Store\Model\StoreRepository; use Magento\TestFramework\Helper\Bootstrap as BootstrapHelper; use Magento\Framework\ObjectManagerInterface; use Magento\Framework\Api\SearchCriteriaBuilder; @@ -50,6 +51,34 @@ protected function setUp() $this->filterBuilder = $this->objectManager->create(FilterBuilder::class); } + /** + * Tests that quote saved with custom store id has same store id after getting via repository. + * + * @magentoDataFixture Magento/Sales/_files/quote.php + * @magentoDataFixture Magento/Store/_files/second_store.php + */ + public function testGetQuoteWithCustomStoreId() + { + $secondStoreCode = 'fixture_second_store'; + $reservedOrderId = 'test01'; + + $storeRepository = $this->objectManager->create(StoreRepository::class); + $secondStore = $storeRepository->get($secondStoreCode); + + // Set store_id in quote to second store_id + $quote = $this->getQuote($reservedOrderId); + $quote->setStoreId($secondStore->getId()); + $this->quoteRepository->save($quote); + + $savedQuote = $this->quoteRepository->get($quote->getId()); + + $this->assertEquals( + $secondStore->getId(), + $savedQuote->getStoreId(), + 'Quote store id should be equal with store id value in DB' + ); + } + /** * @magentoDataFixture Magento/Sales/_files/quote.php */ @@ -126,6 +155,24 @@ public function testSaveWithNotExistingCustomerAddress() ); } + /** + * Returns quote by reserved order id. + * + * @param string $reservedOrderId + * @return CartInterface + */ + private function getQuote(string $reservedOrderId) + { + $searchCriteria = $this->getSearchCriteria($reservedOrderId); + $searchResult = $this->quoteRepository->getList($searchCriteria); + $items = $searchResult->getItems(); + + /** @var CartInterface $quote */ + $quote = array_pop($items); + + return $quote; + } + /** * Get search criteria * diff --git a/dev/tests/integration/testsuite/Magento/Quote/Model/QuoteTest.php b/dev/tests/integration/testsuite/Magento/Quote/Model/QuoteTest.php index 39db5b1572cb7..5df185cad7ac3 100644 --- a/dev/tests/integration/testsuite/Magento/Quote/Model/QuoteTest.php +++ b/dev/tests/integration/testsuite/Magento/Quote/Model/QuoteTest.php @@ -9,15 +9,36 @@ use Magento\Customer\Api\Data\CustomerInterfaceFactory; use Magento\Framework\Exception\LocalizedException; use Magento\TestFramework\Helper\Bootstrap; +use Magento\TestFramework\ObjectManager; +use Magento\Framework\Api\SearchCriteriaBuilder; +use Magento\Quote\Api\CartRepositoryInterface; +use Magento\Framework\Api\ExtensibleDataInterface; /** * @SuppressWarnings(PHPMD.CouplingBetweenObjects) */ class QuoteTest extends \PHPUnit\Framework\TestCase { - private function convertToArray($entity) + /** + * @var ObjectManager + */ + private $objectManager; + + /** + * @inheritdoc + */ + protected function setUp() + { + $this->objectManager = Bootstrap::getObjectManager(); + } + + /** + * @param ExtensibleDataInterface $entity + * @return array + */ + private function convertToArray(ExtensibleDataInterface $entity): array { - return Bootstrap::getObjectManager() + return $this->objectManager ->create(\Magento\Framework\Api\ExtensibleDataObjectConverter::class) ->toFlatArray($entity); } @@ -25,13 +46,14 @@ private function convertToArray($entity) /** * @magentoDataFixture Magento/Catalog/_files/product_virtual.php * @magentoDataFixture Magento/Sales/_files/quote.php + * @return void */ - public function testCollectTotalsWithVirtual() + public function testCollectTotalsWithVirtual(): void { - $quote = Bootstrap::getObjectManager()->create(\Magento\Quote\Model\Quote::class); + $quote = $this->objectManager->create(Quote::class); $quote->load('test01', 'reserved_order_id'); - $productRepository = Bootstrap::getObjectManager()->create( + $productRepository = $this->objectManager->create( \Magento\Catalog\Api\ProductRepositoryInterface::class ); $product = $productRepository->get('virtual-product', false, null, true); @@ -44,16 +66,19 @@ public function testCollectTotalsWithVirtual() $this->assertEquals(20, $quote->getBaseGrandTotal()); } - public function testSetCustomerData() + /** + * @return void + */ + public function testSetCustomerData(): void { - /** @var \Magento\Quote\Model\Quote $quote */ - $quote = Bootstrap::getObjectManager()->create(\Magento\Quote\Model\Quote::class); + /** @var Quote $quote */ + $quote = $this->objectManager->create(Quote::class); /** @var CustomerInterfaceFactory $customerFactory */ - $customerFactory = Bootstrap::getObjectManager()->create( + $customerFactory = $this->objectManager->create( CustomerInterfaceFactory::class ); /** @var \Magento\Framework\Api\DataObjectHelper $dataObjectHelper */ - $dataObjectHelper = Bootstrap::getObjectManager()->create(\Magento\Framework\Api\DataObjectHelper::class); + $dataObjectHelper = $this->objectManager->create(\Magento\Framework\Api\DataObjectHelper::class); $expected = $this->_getCustomerDataArray(); $customer = $customerFactory->create(); $dataObjectHelper->populateWithArray( @@ -70,15 +95,18 @@ public function testSetCustomerData() $this->assertEquals('qa@example.com', $quote->getCustomerEmail()); } - public function testUpdateCustomerData() + /** + * @return void + */ + public function testUpdateCustomerData(): void { - /** @var \Magento\Quote\Model\Quote $quote */ - $quote = Bootstrap::getObjectManager()->create(\Magento\Quote\Model\Quote::class); - $customerFactory = Bootstrap::getObjectManager()->create( + /** @var Quote $quote */ + $quote = $this->objectManager->create(Quote::class); + $customerFactory = $this->objectManager->create( CustomerInterfaceFactory::class ); /** @var \Magento\Framework\Api\DataObjectHelper $dataObjectHelper */ - $dataObjectHelper = Bootstrap::getObjectManager()->create(\Magento\Framework\Api\DataObjectHelper::class); + $dataObjectHelper = $this->objectManager->create(\Magento\Framework\Api\DataObjectHelper::class); $expected = $this->_getCustomerDataArray(); //For save in repository $expected = $this->removeIdFromCustomerData($expected); @@ -92,7 +120,7 @@ public function testUpdateCustomerData() /** * @var \Magento\Customer\Api\CustomerRepositoryInterface $customerRepository */ - $customerRepository = Bootstrap::getObjectManager() + $customerRepository = $this->objectManager ->create(\Magento\Customer\Api\CustomerRepositoryInterface::class); $customerRepository->save($customerDataSet); $quote->setCustomer($customerDataSet); @@ -116,18 +144,20 @@ public function testUpdateCustomerData() /** * Customer data is set to quote (which contains valid group ID). + * + * @return void */ - public function testGetCustomerGroupFromCustomer() + public function testGetCustomerGroupFromCustomer(): void { /** Preconditions */ /** @var CustomerInterfaceFactory $customerFactory */ - $customerFactory = Bootstrap::getObjectManager()->create( + $customerFactory = $this->objectManager->create( CustomerInterfaceFactory::class ); $customerGroupId = 3; $customerData = $customerFactory->create()->setId(1)->setGroupId($customerGroupId); - /** @var \Magento\Quote\Model\Quote $quote */ - $quote = Bootstrap::getObjectManager()->create(\Magento\Quote\Model\Quote::class); + /** @var Quote $quote */ + $quote = $this->objectManager->create(Quote::class); $quote->setCustomer($customerData); $quote->unsetData('customer_group_id'); @@ -137,8 +167,9 @@ public function testGetCustomerGroupFromCustomer() /** * @magentoDataFixture Magento/Customer/_files/customer_group.php + * @return void */ - public function testGetCustomerTaxClassId() + public function testGetCustomerTaxClassId(): void { /** * Preconditions: create quote and assign ID of customer group created in fixture to it. @@ -146,10 +177,10 @@ public function testGetCustomerTaxClassId() $fixtureGroupCode = 'custom_group'; $fixtureTaxClassId = 3; /** @var \Magento\Customer\Model\Group $group */ - $group = Bootstrap::getObjectManager()->create(\Magento\Customer\Model\Group::class); + $group = $this->objectManager->create(\Magento\Customer\Model\Group::class); $fixtureGroupId = $group->load($fixtureGroupCode, 'customer_group_code')->getId(); - /** @var \Magento\Quote\Model\Quote $quote */ - $quote = Bootstrap::getObjectManager()->create(\Magento\Quote\Model\Quote::class); + /** @var Quote $quote */ + $quote = $this->objectManager->create(Quote::class); $quote->setCustomerGroupId($fixtureGroupId); /** Execute SUT */ @@ -162,15 +193,16 @@ public function testGetCustomerTaxClassId() * @magentoDataFixture Magento/Customer/_files/customer.php * @magentoDataFixture Magento/Customer/_files/customer_address.php * @magentoDataFixture Magento/Customer/_files/customer_two_addresses.php + * @return void */ - public function testAssignCustomerWithAddressChangeAddressesNotSpecified() + public function testAssignCustomerWithAddressChangeAddressesNotSpecified(): void { /** Preconditions: * Customer with two addresses created * First address is default billing, second is default shipping. */ - /** @var \Magento\Quote\Model\Quote $quote */ - $quote = Bootstrap::getObjectManager()->create(\Magento\Quote\Model\Quote::class); + /** @var Quote $quote */ + $quote = $this->objectManager->create(Quote::class); $customerData = $this->_prepareQuoteForTestAssignCustomerWithAddressChange($quote); /** Execute SUT */ @@ -227,16 +259,16 @@ public function testAssignCustomerWithAddressChangeAddressesNotSpecified() * @magentoDataFixture Magento/Customer/_files/customer.php * @magentoDataFixture Magento/Customer/_files/customer_address.php * @magentoDataFixture Magento/Customer/_files/customer_two_addresses.php + * @return void */ - public function testAssignCustomerWithAddressChange() + public function testAssignCustomerWithAddressChange(): void { /** Preconditions: * Customer with two addresses created * First address is default billing, second is default shipping. */ - /** @var \Magento\Quote\Model\Quote $quote */ - $objectManager = Bootstrap::getObjectManager(); - $quote = $objectManager->create(\Magento\Quote\Model\Quote::class); + /** @var Quote $quote */ + $quote = $this->objectManager->create(Quote::class); $customerData = $this->_prepareQuoteForTestAssignCustomerWithAddressChange($quote); /** @var \Magento\Quote\Model\Quote\Address $quoteBillingAddress */ $expectedBillingAddressData = [ @@ -249,7 +281,7 @@ public function testAssignCustomerWithAddressChange() 'firstname' => 'FirstBilling', 'region_id' => 1 ]; - $quoteBillingAddress = $objectManager->create(\Magento\Quote\Model\Quote\Address::class); + $quoteBillingAddress = $this->objectManager->create(\Magento\Quote\Model\Quote\Address::class); $quoteBillingAddress->setData($expectedBillingAddressData); $expectedShippingAddressData = [ @@ -262,7 +294,7 @@ public function testAssignCustomerWithAddressChange() 'firstname' => 'FirstShipping', 'region_id' => 1 ]; - $quoteShippingAddress = $objectManager->create(\Magento\Quote\Model\Quote\Address::class); + $quoteShippingAddress = $this->objectManager->create(\Magento\Quote\Model\Quote\Address::class); $quoteShippingAddress->setData($expectedShippingAddressData); /** Execute SUT */ @@ -292,16 +324,17 @@ public function testAssignCustomerWithAddressChange() /** * @magentoDataFixture Magento/Catalog/_files/product_simple_duplicated.php + * @return void */ - public function testAddProductUpdateItem() + public function testAddProductUpdateItem(): void { - /** @var \Magento\Quote\Model\Quote $quote */ - $quote = Bootstrap::getObjectManager()->create(\Magento\Quote\Model\Quote::class); + /** @var Quote $quote */ + $quote = $this->objectManager->create(Quote::class); $quote->load('test01', 'reserved_order_id'); $productStockQty = 100; - $productRepository = Bootstrap::getObjectManager()->create( + $productRepository = $this->objectManager->create( \Magento\Catalog\Api\ProductRepositoryInterface::class ); $product = $productRepository->get('simple-1', false, null, true); @@ -324,7 +357,7 @@ public function testAddProductUpdateItem() $this->assertEquals(1, $quote->getItemsQty()); $this->expectException(\Magento\Framework\Exception\LocalizedException::class); - $this->expectExceptionMessage('We don\'t have as many "Simple Product" as you requested.'); + $this->expectExceptionMessage('The requested qty is not available'); $updateParams['qty'] = $productStockQty + 1; $quote->updateItem($updateParams['id'], $updateParams); } @@ -334,17 +367,19 @@ public function testAddProductUpdateItem() * * Customer with two addresses created. First address is default billing, second is default shipping. * - * @param \Magento\Quote\Model\Quote $quote + * @param Quote $quote * @return \Magento\Customer\Api\Data\CustomerInterface */ - protected function _prepareQuoteForTestAssignCustomerWithAddressChange($quote) - { - $objectManager = Bootstrap::getObjectManager(); + protected function _prepareQuoteForTestAssignCustomerWithAddressChange( + Quote $quote + ): \Magento\Customer\Api\Data\CustomerInterface { /** @var \Magento\Customer\Api\CustomerRepositoryInterface $customerRepository */ - $customerRepository = $objectManager->create(\Magento\Customer\Api\CustomerRepositoryInterface::class); + $customerRepository = $this->objectManager->create( + \Magento\Customer\Api\CustomerRepositoryInterface::class + ); $fixtureCustomerId = 1; /** @var \Magento\Customer\Model\Customer $customer */ - $customer = $objectManager->create(\Magento\Customer\Model\Customer::class); + $customer = $this->objectManager->create(\Magento\Customer\Model\Customer::class); $fixtureSecondAddressId = 2; $customer->load($fixtureCustomerId)->setDefaultShipping($fixtureSecondAddressId)->save(); $customerData = $customerRepository->getById($fixtureCustomerId); @@ -360,11 +395,11 @@ protected function _prepareQuoteForTestAssignCustomerWithAddressChange($quote) } /** - * @param $email + * @param string $email * @param array $customerData * @return array */ - protected function changeEmailInCustomerData($email, array $customerData) + protected function changeEmailInCustomerData(string $email, array $customerData): array { $customerData[\Magento\Customer\Model\Data\Customer::EMAIL] = $email; return $customerData; @@ -374,13 +409,16 @@ protected function changeEmailInCustomerData($email, array $customerData) * @param array $customerData * @return array */ - protected function removeIdFromCustomerData(array $customerData) + protected function removeIdFromCustomerData(array $customerData): array { unset($customerData[\Magento\Customer\Model\Data\Customer::ID]); return $customerData; } - protected function _getCustomerDataArray() + /** + * @return array + */ + protected function _getCustomerDataArray(): array { return [ \Magento\Customer\Model\Data\Customer::CONFIRMATION => 'test', @@ -410,12 +448,12 @@ protected function _getCustomerDataArray() * * @magentoDataFixture Magento/Sales/_files/order.php * @magentoDataFixture Magento/Quote/_files/empty_quote.php + * @return void */ - public function testReserveOrderId() + public function testReserveOrderId(): void { - $objectManager = Bootstrap::getObjectManager(); - /** @var \Magento\Quote\Model\Quote $quote */ - $quote = $objectManager->create(\Magento\Quote\Model\Quote::class); + /** @var Quote $quote */ + $quote = $this->objectManager->create(Quote::class); $quote->load('reserved_order_id', 'reserved_order_id'); $quote->reserveOrderId(); $this->assertEquals('reserved_order_id', $quote->getReservedOrderId()); @@ -427,38 +465,38 @@ public function testReserveOrderId() /** * Test to verify that disabled product cannot be added to cart * @magentoDataFixture Magento/Quote/_files/is_not_salable_product.php + * @return void */ - public function testAddedProductToQuoteIsSalable() + public function testAddedProductToQuoteIsSalable(): void { $productId = 99; - $objectManager = Bootstrap::getObjectManager(); /** @var ProductRepository $productRepository */ - $productRepository = $objectManager->get(ProductRepository::class); + $productRepository = $this->objectManager->get(ProductRepository::class); - /** @var \Magento\Quote\Model\Quote $quote */ + /** @var Quote $quote */ $product = $productRepository->getById($productId, false, null, true); $this->expectException(LocalizedException::class); $this->expectExceptionMessage('Product that you are trying to add is not available.'); - $quote = $objectManager->create(\Magento\Quote\Model\Quote::class); + $quote = $this->objectManager->create(Quote::class); $quote->addProduct($product); } /** * @magentoDataFixture Magento/Sales/_files/quote.php * @magentoDataFixture Magento/Catalog/_files/product_simple.php + * @return void */ - public function testGetItemById() + public function testGetItemById(): void { - $objectManager = Bootstrap::getObjectManager(); - $quote = $objectManager->create(\Magento\Quote\Model\Quote::class); + $quote = $this->objectManager->create(Quote::class); $quote->load('test01', 'reserved_order_id'); - $quoteItem = $objectManager->create(\Magento\Quote\Model\Quote\Item::class); + $quoteItem = $this->objectManager->create(\Magento\Quote\Model\Quote\Item::class); - $productRepository = $objectManager->create(\Magento\Catalog\Api\ProductRepositoryInterface::class); + $productRepository = $this->objectManager->create(\Magento\Catalog\Api\ProductRepositoryInterface::class); $product = $productRepository->get('simple'); $quoteItem->setProduct($product); @@ -468,4 +506,45 @@ public function testGetItemById() $this->assertInstanceOf(\Magento\Quote\Model\Quote\Item::class, $quote->getItemById($quoteItem->getId())); $this->assertEquals($quoteItem->getId(), $quote->getItemById($quoteItem->getId())->getId()); } + + /** + * Tests of quotes merging. + * + * @magentoDataFixture Magento/Sales/_files/quote.php + * @return void + */ + public function testMerge(): void + { + $giftMessageId = 1; + + /** @var Quote $quote */ + $guestQuote = $this->getQuote('test01'); + $guestQuote->setGiftMessageId($giftMessageId); + + /** @var Quote $customerQuote */ + $customerQuote = $this->objectManager->create(Quote::class); + $customerQuote->merge($guestQuote); + + self::assertEquals($giftMessageId, $customerQuote->getGiftMessageId()); + } + + /** + * Gets quote by reserved order id. + * + * @param string $reservedOrderId + * @return Quote + */ + private function getQuote(string $reservedOrderId): Quote + { + /** @var SearchCriteriaBuilder $searchCriteriaBuilder */ + $searchCriteriaBuilder = $this->objectManager->get(SearchCriteriaBuilder::class); + $searchCriteria = $searchCriteriaBuilder->addFilter('reserved_order_id', $reservedOrderId) + ->create(); + + /** @var CartRepositoryInterface $quoteRepository */ + $quoteRepository = $this->objectManager->get(CartRepositoryInterface::class); + $items = $quoteRepository->getList($searchCriteria)->getItems(); + + return array_pop($items); + } } diff --git a/dev/tests/integration/testsuite/Magento/Sales/Block/Adminhtml/Order/Create/Form/AccountTest.php b/dev/tests/integration/testsuite/Magento/Sales/Block/Adminhtml/Order/Create/Form/AccountTest.php index 6b4e9a66f4c6b..999522a49e006 100644 --- a/dev/tests/integration/testsuite/Magento/Sales/Block/Adminhtml/Order/Create/Form/AccountTest.php +++ b/dev/tests/integration/testsuite/Magento/Sales/Block/Adminhtml/Order/Create/Form/AccountTest.php @@ -5,39 +5,50 @@ * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ + +declare(strict_types=1); + namespace Magento\Sales\Block\Adminhtml\Order\Create\Form; +use Magento\Backend\Model\Session\Quote as SessionQuote; +use Magento\Customer\Api\Data\AttributeMetadataInterfaceFactory; +use Magento\Customer\Model\Metadata\Form; +use Magento\Customer\Model\Metadata\FormFactory; +use Magento\Framework\View\LayoutInterface; +use Magento\Quote\Model\Quote; +use Magento\TestFramework\Helper\Bootstrap; + /** * @magentoAppArea adminhtml */ class AccountTest extends \PHPUnit\Framework\TestCase { - /** @var \Magento\Sales\Block\Adminhtml\Order\Create\Form\Account */ - protected $_accountBlock; + /** @var Account */ + private $accountBlock; /** - * @var \Magento\TestFramework\Helper\Bootstrap + * @var Bootstrap */ - protected $_objectManager; + private $objectManager; /** * @magentoDataFixture Magento/Sales/_files/quote.php */ protected function setUp() { - $this->_objectManager = \Magento\TestFramework\Helper\Bootstrap::getObjectManager(); - $quote = $this->_objectManager->create(\Magento\Quote\Model\Quote::class)->load(1); + $this->objectManager = Bootstrap::getObjectManager(); + $quote = $this->objectManager->create(Quote::class)->load(1); $sessionQuoteMock = $this->getMockBuilder( - \Magento\Backend\Model\Session\Quote::class + SessionQuote::class )->disableOriginalConstructor()->setMethods( ['getCustomerId', 'getStore', 'getStoreId', 'getQuote'] )->getMock(); $sessionQuoteMock->expects($this->any())->method('getCustomerId')->will($this->returnValue(1)); $sessionQuoteMock->expects($this->any())->method('getQuote')->will($this->returnValue($quote)); - /** @var \Magento\Framework\View\LayoutInterface $layout */ - $layout = $this->_objectManager->get(\Magento\Framework\View\LayoutInterface::class); - $this->_accountBlock = $layout->createBlock( - \Magento\Sales\Block\Adminhtml\Order\Create\Form\Account::class, + /** @var LayoutInterface $layout */ + $layout = $this->objectManager->get(LayoutInterface::class); + $this->accountBlock = $layout->createBlock( + Account::class, 'address_block' . rand(), ['sessionQuote' => $sessionQuoteMock] ); @@ -50,7 +61,7 @@ protected function setUp() public function testGetForm() { $expectedFields = ['group_id', 'email']; - $form = $this->_accountBlock->getForm(); + $form = $this->accountBlock->getForm(); $this->assertEquals(1, $form->getElements()->count(), "Form has invalid number of fieldsets"); $fieldset = $form->getElements()[0]; @@ -63,4 +74,56 @@ public function testGetForm() ); } } + + /** + * Tests a case when user defined custom attribute has default value. + * + * @magentoDataFixture Magento/Customer/_files/customer.php + */ + public function testGetFormWithUserDefinedAttribute() + { + $formFactory = $this->getFormFactoryMock(); + $this->objectManager->addSharedInstance($formFactory, FormFactory::class); + + /** @var LayoutInterface $layout */ + $layout = $this->objectManager->get(LayoutInterface::class); + $accountBlock = $layout->createBlock(Account::class, 'address_block' . rand()); + + $form = $accountBlock->getForm(); + $form->setUseContainer(true); + + $this->assertContains( + '<option value="1" selected="selected">Yes</option>', + $form->toHtml(), + 'Default value for user defined custom attribute should be selected' + ); + } + + /** + * @return \PHPUnit_Framework_MockObject_MockObject + */ + private function getFormFactoryMock(): \PHPUnit_Framework_MockObject_MockObject + { + /** @var AttributeMetadataInterfaceFactory $attributeMetadataFactory */ + $attributeMetadataFactory = $this->objectManager->create(AttributeMetadataInterfaceFactory::class); + $booleanAttribute = $attributeMetadataFactory->create() + ->setAttributeCode('boolean') + ->setBackendType('boolean') + ->setFrontendInput('boolean') + ->setDefaultValue('1') + ->setFrontendLabel('Yes/No'); + + $form = $this->getMockBuilder(Form::class) + ->disableOriginalConstructor() + ->getMock(); + $form->method('getUserAttributes')->willReturn([$booleanAttribute]); + $form->method('getSystemAttributes')->willReturn([]); + + $formFactory = $this->getMockBuilder(FormFactory::class) + ->disableOriginalConstructor() + ->getMock(); + $formFactory->method('create')->willReturn($form); + + return $formFactory; + } } diff --git a/dev/tests/integration/testsuite/Magento/Sales/Block/Adminhtml/Order/Create/FormTest.php b/dev/tests/integration/testsuite/Magento/Sales/Block/Adminhtml/Order/Create/FormTest.php index b6df7eb05c03d..abdbab2c24d16 100644 --- a/dev/tests/integration/testsuite/Magento/Sales/Block/Adminhtml/Order/Create/FormTest.php +++ b/dev/tests/integration/testsuite/Magento/Sales/Block/Adminhtml/Order/Create/FormTest.php @@ -1,151 +1,201 @@ <?php /** - * Test class for \Magento\Sales\Block\Adminhtml\Order\Create\Form + * Test class for Form * * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ namespace Magento\Sales\Block\Adminhtml\Order\Create; +use Magento\Backend\Model\Session\Quote as QuoteSession; +use Magento\Customer\Api\AddressRepositoryInterface; +use Magento\Customer\Api\Data\AddressInterfaceFactory; +use Magento\Customer\Api\Data\RegionInterfaceFactory; +use Magento\Framework\Api\SearchCriteriaBuilder; +use Magento\Framework\ObjectManagerInterface; +use Magento\Framework\View\LayoutInterface; +use Magento\Quote\Api\CartRepositoryInterface; +use Magento\Quote\Model\Quote; +use Magento\Store\Model\Store; +use Magento\TestFramework\Helper\Bootstrap; +use PHPUnit_Framework_MockObject_MockObject as MockObject; + /** * @magentoAppArea adminhtml + * @SuppressWarnings(PHPMD.CouplingBetweenObjects) */ class FormTest extends \PHPUnit\Framework\TestCase { - /** @var \Magento\Sales\Block\Adminhtml\Order\Create\Form */ - protected $_orderCreateBlock; + /** + * @var Form + */ + private $block; - /** @var \Magento\Framework\ObjectManagerInterface */ - protected $_objectManager; + /** + * @var ObjectManagerInterface + */ + private $objectManager; /** - * @magentoDataFixture Magento/Sales/_files/quote.php + * @var QuoteSession|MockObject */ + private $session; + protected function setUp() { - $this->_objectManager = \Magento\TestFramework\Helper\Bootstrap::getObjectManager(); - - $sessionMock = $this->getMockBuilder( - \Magento\Backend\Model\Session\Quote::class - )->disableOriginalConstructor()->setMethods( - ['getCustomerId', 'getQuote', 'getStoreId', 'getStore'] - )->getMock(); - $sessionMock->expects($this->any())->method('getCustomerId')->will($this->returnValue(1)); - - $quote = $this->_objectManager->create(\Magento\Quote\Model\Quote::class)->load(1); - $sessionMock->expects($this->any())->method('getQuote')->will($this->returnValue($quote)); - - $sessionMock->expects($this->any())->method('getStoreId')->will($this->returnValue(1)); - - $storeMock = $this->getMockBuilder( - \Magento\Store\Model\Store::class - )->disableOriginalConstructor()->setMethods( - ['getCurrentCurrencyCode'] - )->getMock(); - $storeMock->expects($this->any())->method('getCurrentCurrencyCode')->will($this->returnValue('USD')); - $sessionMock->expects($this->any())->method('getStore')->will($this->returnValue($storeMock)); - - /** @var \Magento\Framework\View\LayoutInterface $layout */ - $layout = $this->_objectManager->get(\Magento\Framework\View\LayoutInterface::class); - $this->_orderCreateBlock = $layout->createBlock( - \Magento\Sales\Block\Adminhtml\Order\Create\Form::class, - 'order_create_block' . rand(), - ['sessionQuote' => $sessionMock] + $this->objectManager = Bootstrap::getObjectManager(); + + $this->session = $this->getMockBuilder(QuoteSession::class) + ->disableOriginalConstructor() + ->setMethods(['getCustomerId', 'getQuote', 'getStoreId', 'getStore', 'getQuoteId']) + ->getMock(); + $this->session->method('getCustomerId') + ->willReturn(1); + + $this->session->method('getStoreId') + ->willReturn(1); + + $store = $this->getMockBuilder(Store::class) + ->disableOriginalConstructor() + ->setMethods(['getCurrentCurrencyCode']) + ->getMock(); + $store->method('getCurrentCurrencyCode') + ->willReturn('USD'); + $this->session->method('getStore') + ->willReturn($store); + + /** @var LayoutInterface $layout */ + $layout = $this->objectManager->get(LayoutInterface::class); + $this->block = $layout->createBlock( + Form::class, + 'order_create_block' . mt_rand(), + ['sessionQuote' => $this->session] ); parent::setUp(); } /** + * Checks if all needed order's data is correctly returned to the form. + * * @magentoDataFixture Magento/Customer/_files/customer.php + * @magentoDataFixture Magento/Sales/_files/quote.php */ public function testOrderDataJson() { - /** @var array $addressIds */ - $addressIds = $this->setUpMockAddress(); - $orderDataJson = $this->_orderCreateBlock->getOrderDataJson(); - $expectedOrderDataJson = <<<ORDER_DATA_JSON - { - "customer_id":1, - "addresses": - {"{$addressIds[0]}": - {"firstname":"John","lastname":"Smith","company":false,"street":"Green str, 67","city":"CityM", - "country_id":"US", - "region":"Alabama","region_id":1, - "postcode":"75477","telephone":"3468676","vat_id":false}, - "{$addressIds[1]}": - {"firstname":"John","lastname":"Smith","company":false,"street":"Black str, 48","city":"CityX", - "country_id":"US", - "region":"Alabama","region_id":1, - "postcode":"47676","telephone":"3234676","vat_id":false} - }, - "store_id":1,"currency_symbol":"$","shipping_method_reseted":true,"payment_method":null - } -ORDER_DATA_JSON; - - $this->assertEquals(json_decode($expectedOrderDataJson), json_decode($orderDataJson)); + $customerId = 1; + $quote = $this->getQuote('test01'); + $this->session->method('getQuote') + ->willReturn($quote); + $this->session->method('getQuoteId') + ->willReturn($quote->getId()); + $addressData = $this->getAddressData(); + $addressIds = $this->setUpMockAddress($customerId, $addressData); + $expected = [ + 'customer_id' => $customerId, + 'addresses' => [ + $addressIds[0] => $addressData[0], + $addressIds[1] => $addressData[1] + ], + 'store_id' => 1, + 'currency_symbol' => '$', + 'shipping_method_reseted' => true, + 'payment_method' => 'checkmo', + 'quote_id' => $quote->getId() + ]; + + self::assertEquals($expected, json_decode($this->block->getOrderDataJson(), true)); } - private function setUpMockAddress() + /** + * Saves customer's addresses. + * + * @param int $customerId + * @param array $addressData + * @return array + * @throws \Magento\Framework\Exception\LocalizedException + */ + private function setUpMockAddress(int $customerId, array $addressData) { - /** @var \Magento\Customer\Api\Data\RegionInterfaceFactory $regionFactory */ - $regionFactory = $this->_objectManager->create(\Magento\Customer\Api\Data\RegionInterfaceFactory::class); - - /** @var \Magento\Customer\Api\Data\AddressInterfaceFactory $addressFactory */ - $addressFactory = $this->_objectManager->create(\Magento\Customer\Api\Data\AddressInterfaceFactory::class); - /** @var \Magento\Customer\Api\AddressRepositoryInterface $addressRepository */ - $addressRepository = $this->_objectManager->create(\Magento\Customer\Api\AddressRepositoryInterface::class); - - $addressData1 = $addressFactory->create()->setCountryId( - 'US' - )->setCustomerId( - 1 - )->setIsDefaultBilling( - true - )->setIsDefaultShipping( - true - )->setPostcode( - '75477' - )->setRegion( - $regionFactory->create()->setRegionCode('AL')->setRegion('Alabama')->setRegionId(1) - )->setStreet( - ['Green str, 67'] - )->setTelephone( - '3468676' - )->setCity( - 'CityM' - )->setFirstname( - 'John' - )->setLastname( - 'Smith' - ); - - $addressData2 = $addressFactory->create()->setCountryId( - 'US' - )->setCustomerId( - 1 - )->setIsDefaultBilling( - false - )->setIsDefaultShipping( - false - )->setPostcode( - '47676' - )->setRegion( - $regionFactory->create()->setRegionCode('AL')->setRegion('Alabama')->setRegionId(1) - )->setStreet( - ['Black str, 48'] - )->setCity( - 'CityX' - )->setTelephone( - '3234676' - )->setFirstname( - 'John' - )->setLastname( - 'Smith' - ); + /** @var RegionInterfaceFactory $regionFactory */ + $regionFactory = $this->objectManager->create(RegionInterfaceFactory::class); + /** @var AddressInterfaceFactory $addressFactory */ + $addressFactory = $this->objectManager->create(AddressInterfaceFactory::class); + /** @var AddressRepositoryInterface $addressRepository */ + $addressRepository = $this->objectManager->create(AddressRepositoryInterface::class); + $region = $regionFactory->create() + ->setRegionCode('AL') + ->setRegion('Alabama') + ->setRegionId(1); + + $ids = []; + foreach ($addressData as $data) { + $address = $addressFactory->create(['data' => $data]); + $address->setRegion($region) + ->setCustomerId($customerId) + ->setIsDefaultBilling(true) + ->setIsDefaultShipping(true); + $address = $addressRepository->save($address); + $ids[] = $address->getId(); + } + + return $ids; + } - $savedAddress1 = $addressRepository->save($addressData1); - $savedAddress2 = $addressRepository->save($addressData2); + /** + * Gets test address data. + * + * @return array + */ + private function getAddressData(): array + { + return [ + [ + 'firstname' => 'John', + 'lastname' => 'Smith', + 'company' => false, + 'street' => 'Green str, 67', + 'city' => 'CityM', + 'country_id' => 'US', + 'region' => 'Alabama', + 'region_id' => 1, + 'postcode' => '75477', + 'telephone' => '3468676', + 'vat_id' => false + ], + [ + 'firstname' => 'John', + 'lastname' => 'Smith', + 'company' => false, + 'street' => 'Black str, 48', + 'city' => 'CityX', + 'country_id' => 'US', + 'region' => 'Alabama', + 'region_id' => 1, + 'postcode' => '47676', + 'telephone' => '3234676', + 'vat_id' => false, + ] + ]; + } - return [$savedAddress1->getId(), $savedAddress2->getId()]; + /** + * Gets quote by ID. + * + * @param string $reservedOrderId + * @return Quote + * @throws \Magento\Framework\Exception\NoSuchEntityException + */ + private function getQuote(string $reservedOrderId): Quote + { + /** @var SearchCriteriaBuilder $searchCriteriaBuilder */ + $searchCriteriaBuilder = $this->objectManager->get(SearchCriteriaBuilder::class); + $searchCriteria = $searchCriteriaBuilder->addFilter('reserved_order_id', $reservedOrderId) + ->create(); + /** @var CartRepositoryInterface $repository */ + $repository = $this->objectManager->get(CartRepositoryInterface::class); + $items = $repository->getList($searchCriteria) + ->getItems(); + + return array_pop($items); } } diff --git a/dev/tests/integration/testsuite/Magento/Sales/_files/address_data.php b/dev/tests/integration/testsuite/Magento/Sales/_files/address_data.php index 2d131bf5f57e2..394b13078010a 100644 --- a/dev/tests/integration/testsuite/Magento/Sales/_files/address_data.php +++ b/dev/tests/integration/testsuite/Magento/Sales/_files/address_data.php @@ -6,6 +6,7 @@ return [ 'region' => 'CA', + 'region_id' => '12', 'postcode' => '11111', 'lastname' => 'lastname', 'firstname' => 'firstname', diff --git a/dev/tests/integration/testsuite/Magento/Sales/_files/order_info.php b/dev/tests/integration/testsuite/Magento/Sales/_files/order_info.php index 31aa8aafd94d9..f3e528b9c0d28 100644 --- a/dev/tests/integration/testsuite/Magento/Sales/_files/order_info.php +++ b/dev/tests/integration/testsuite/Magento/Sales/_files/order_info.php @@ -85,6 +85,9 @@ $invoice = $invoiceFactory->prepareInvoice($order, [$item->getId() => 10]); $invoice->register(); $invoice->save(); +$order->save(); + +$invoice = $objectManager->get(\Magento\Sales\Api\InvoiceRepositoryInterface::class)->get($invoice->getId()); /** @var \Magento\Sales\Model\Order\CreditmemoFactory $creditmemoFactory */ $creditmemoFactory = $objectManager->get(\Magento\Sales\Model\Order\CreditmemoFactory::class); diff --git a/dev/tests/integration/testsuite/Magento/SalesRule/Model/Rule/Action/Discount/CartFixedTest.php b/dev/tests/integration/testsuite/Magento/SalesRule/Model/Rule/Action/Discount/CartFixedTest.php index e601e2dd59232..694310f2cbc89 100644 --- a/dev/tests/integration/testsuite/Magento/SalesRule/Model/Rule/Action/Discount/CartFixedTest.php +++ b/dev/tests/integration/testsuite/Magento/SalesRule/Model/Rule/Action/Discount/CartFixedTest.php @@ -93,6 +93,36 @@ public function applyFixedDiscountDataProvider(): array ]; } + /** + * Tests that coupon with wildcard symbols in code can be successfully applied. + * + * @magentoDataFixture Magento/SalesRule/_files/coupon_code_with_wildcard.php + */ + public function testCouponCodeWithWildcard() + { + $expectedDiscount = '-5.00'; + $couponCode = '2?ds5!2d'; + $cartId = $this->cartManagement->createEmptyCart(); + $productPrice = 10; + + $product = $this->createProduct($productPrice); + + /** @var CartItemInterface $quoteItem */ + $quoteItem = Bootstrap::getObjectManager()->create(CartItemInterface::class); + $quoteItem->setQuoteId($cartId); + $quoteItem->setProduct($product); + $quoteItem->setQty(1); + $this->cartItemRepository->save($quoteItem); + + $this->couponManagement->set($cartId, $couponCode); + + /** @var GuestCartTotalRepositoryInterface $cartTotalRepository */ + $cartTotalRepository = Bootstrap::getObjectManager()->get(GuestCartTotalRepositoryInterface::class); + $total = $cartTotalRepository->get($cartId); + + $this->assertEquals($expectedDiscount, $total->getBaseDiscountAmount()); + } + /** * Returns simple product with given price. * diff --git a/dev/tests/integration/testsuite/Magento/SalesRule/Model/Rule/Condition/ProductTest.php b/dev/tests/integration/testsuite/Magento/SalesRule/Model/Rule/Condition/ProductTest.php index 98826adeb2147..00f1b1f451815 100644 --- a/dev/tests/integration/testsuite/Magento/SalesRule/Model/Rule/Condition/ProductTest.php +++ b/dev/tests/integration/testsuite/Magento/SalesRule/Model/Rule/Condition/ProductTest.php @@ -6,6 +6,14 @@ namespace Magento\SalesRule\Model\Rule\Condition; +use Magento\Quote\Api\CartRepositoryInterface; +use Magento\Framework\Api\SearchCriteriaBuilder; +use Magento\Quote\Api\Data\CartInterface; +use Magento\SalesRule\Api\RuleRepositoryInterface; + +/** + * @SuppressWarnings(PHPMD.CouplingBetweenObjects) + */ class ProductTest extends \PHPUnit\Framework\TestCase { /** @@ -98,4 +106,71 @@ public function validateProductConditionDataProvider() ] ]; } + + /** + * Ensure that SalesRules filtering on quote items quantity validates configurable product correctly + * + * 1. Load a quote with a configured product and a sales rule set to filter items with quantity 2. + * 2. Attempt to validate the sales rule against the quote and assert the output is negative. + * + * @magentoDataFixture Magento/ConfigurableProduct/_files/quote_with_configurable_product.php + * @magentoDataFixture Magento/SalesRule/_files/cart_rule_10_percent_off.php + */ + public function testValidateQtySalesRuleWithConfigurable() + { + // Load the quote that contains a child of a configurable product with quantity 1. + $quote = $this->getQuote('test_cart_with_configurable'); + + // Load the SalesRule looking for products with quantity 2. + $rule = $this->getSalesRule('10% Off on orders with two items'); + + $this->assertFalse( + $rule->validate($quote->getBillingAddress()) + ); + } + + /** + * Gets quote by reserved order id. + * + * @param string $reservedOrderId + * @return CartInterface + */ + private function getQuote($reservedOrderId) + { + /** @var SearchCriteriaBuilder $searchCriteriaBuilder */ + $searchCriteriaBuilder = $this->objectManager->get(SearchCriteriaBuilder::class); + $searchCriteria = $searchCriteriaBuilder->addFilter('reserved_order_id', $reservedOrderId) + ->create(); + + /** @var CartRepositoryInterface $quoteRepository */ + $quoteRepository = $this->objectManager->get(CartRepositoryInterface::class); + $items = $quoteRepository->getList($searchCriteria)->getItems(); + return array_pop($items); + } + + /** + * Gets rule by name. + * + * @param string $name + * @return \Magento\SalesRule\Model\Rule + * @throws \Magento\Framework\Exception\InputException + * @throws \Magento\Framework\Exception\NoSuchEntityException + */ + private function getSalesRule(string $name): \Magento\SalesRule\Model\Rule + { + /** @var SearchCriteriaBuilder $searchCriteriaBuilder */ + $searchCriteriaBuilder = $this->objectManager->get(SearchCriteriaBuilder::class); + $searchCriteria = $searchCriteriaBuilder->addFilter('name', $name) + ->create(); + + /** @var CartRepositoryInterface $quoteRepository */ + $ruleRepository = $this->objectManager->get(RuleRepositoryInterface::class); + $items = $ruleRepository->getList($searchCriteria)->getItems(); + + $rule = array_pop($items); + /** @var \Magento\SalesRule\Model\Converter\ToModel $converter */ + $converter = $this->objectManager->get(\Magento\SalesRule\Model\Converter\ToModel::class); + + return $converter->toModel($rule); + } } diff --git a/dev/tests/integration/testsuite/Magento/SalesRule/_files/cart_rule_10_percent_off.php b/dev/tests/integration/testsuite/Magento/SalesRule/_files/cart_rule_10_percent_off.php new file mode 100644 index 0000000000000..0761e5753da75 --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/SalesRule/_files/cart_rule_10_percent_off.php @@ -0,0 +1,64 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +declare(strict_types=1); + +use Magento\Customer\Model\GroupManagement; +use Magento\SalesRule\Model\Rule; +use Magento\Store\Model\StoreManagerInterface; +use Magento\TestFramework\Helper\Bootstrap; + +$objectManager = Bootstrap::getObjectManager(); +$websiteId = Bootstrap::getObjectManager()->get(StoreManagerInterface::class) + ->getWebsite() + ->getId(); + +/** @var Rule $salesRule */ +$salesRule = $objectManager->create(Rule::class); +$salesRule->setData( + [ + 'name' => '10% Off on orders with two items', + 'is_active' => 1, + 'customer_group_ids' => [GroupManagement::NOT_LOGGED_IN_ID], + 'coupon_type' => Rule::COUPON_TYPE_NO_COUPON, + 'simple_action' => 'by_percent', + 'discount_amount' => 10, + 'discount_step' => 0, + 'stop_rules_processing' => 1, + 'website_ids' => [$websiteId] + ] +); + +$salesRule->getConditions()->loadArray([ + 'type' => \Magento\SalesRule\Model\Rule\Condition\Combine::class, + 'attribute' => null, + 'operator' => null, + 'value' => '1', + 'is_value_processed' => null, + 'aggregator' => 'all', + 'conditions' => + [ + [ + 'type' => \Magento\SalesRule\Model\Rule\Condition\Product\Subselect::class, + 'attribute' => 'qty', + 'operator' => '==', + 'value' => '2', + 'is_value_processed' => null, + 'aggregator' => 'all', + 'conditions' => + [ + [ + 'type' => \Magento\SalesRule\Model\Rule\Condition\Product::class, + 'attribute' => 'attribute_set_id', + 'operator' => '==', + 'value' => '4', + 'is_value_processed' => false, + ], + ], + ], + ], +]); + +$salesRule->save(); diff --git a/dev/tests/integration/testsuite/Magento/SalesRule/_files/coupon_code_with_wildcard.php b/dev/tests/integration/testsuite/Magento/SalesRule/_files/coupon_code_with_wildcard.php new file mode 100644 index 0000000000000..9005284f984cf --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/SalesRule/_files/coupon_code_with_wildcard.php @@ -0,0 +1,45 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +declare(strict_types=1); + +use Magento\Customer\Model\GroupManagement; +use Magento\SalesRule\Api\CouponRepositoryInterface; +use Magento\SalesRule\Model\Coupon; +use Magento\SalesRule\Model\Rule; +use Magento\Store\Model\StoreManagerInterface; +use Magento\TestFramework\Helper\Bootstrap; + +$objectManager = Bootstrap::getObjectManager(); + +/** @var Rule $salesRule */ +$salesRule = $objectManager->create(Rule::class); +$salesRule->setData( + [ + 'name' => '5$ fixed discount on whole cart', + 'is_active' => 1, + 'customer_group_ids' => [GroupManagement::NOT_LOGGED_IN_ID], + 'coupon_type' => Rule::COUPON_TYPE_SPECIFIC, + 'conditions' => [], + 'simple_action' => Rule::CART_FIXED_ACTION, + 'discount_amount' => 5, + 'discount_step' => 0, + 'stop_rules_processing' => 1, + 'website_ids' => [ + $objectManager->get(StoreManagerInterface::class)->getWebsite()->getId(), + ], + ] +); +$objectManager->get(\Magento\SalesRule\Model\ResourceModel\Rule::class)->save($salesRule); + +// Create coupon and assign "15$ fixed discount" rule to this coupon. +$coupon = $objectManager->create(Coupon::class); +$coupon->setRuleId($salesRule->getId()) + ->setCode('2?ds5!2d') + ->setType(0); + +/** @var CouponRepositoryInterface $couponRepository */ +$couponRepository = $objectManager->get(CouponRepositoryInterface::class); +$couponRepository->save($coupon); diff --git a/dev/tests/integration/testsuite/Magento/SalesRule/_files/coupon_code_with_wildcard_rollback.php b/dev/tests/integration/testsuite/Magento/SalesRule/_files/coupon_code_with_wildcard_rollback.php new file mode 100644 index 0000000000000..776c302210351 --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/SalesRule/_files/coupon_code_with_wildcard_rollback.php @@ -0,0 +1,46 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +declare(strict_types=1); + +use Magento\Framework\Api\SearchCriteriaBuilder; +use Magento\SalesRule\Api\CouponRepositoryInterface; +use Magento\SalesRule\Api\RuleRepositoryInterface; +use Magento\SalesRule\Model\Coupon; +use Magento\SalesRule\Model\Rule; +use Magento\TestFramework\Helper\Bootstrap; + +$objectManager = Bootstrap::getObjectManager(); + +/** @var Rule $salesRule */ +$salesRule = getSalesRule('5$ fixed discount on whole cart'); +if ($salesRule !== null) { + /** @var RuleRepositoryInterface $ruleRepository */ + $ruleRepository = $objectManager->get(RuleRepositoryInterface::class); + $ruleRepository->deleteById($salesRule->getRuleId()); +} + +$coupon = $objectManager->create(Coupon::class); +$coupon->loadByCode('2?ds5!2d'); +if ($coupon->getCouponId()) { + /** @var CouponRepositoryInterface $couponRepository */ + $couponRepository = $objectManager->get(CouponRepositoryInterface::class); + $couponRepository->deleteById($coupon->getCouponId()); +} + +function getSalesRule(string $name) +{ + /** @var SearchCriteriaBuilder $searchCriteriaBuilder */ + $searchCriteriaBuilder = Bootstrap::getObjectManager()->get(SearchCriteriaBuilder::class); + $searchCriteria = $searchCriteriaBuilder->addFilter('name', $name) + ->create(); + + /** @var RuleRepositoryInterface $ruleRepository */ + $ruleRepository = Bootstrap::getObjectManager()->get(RuleRepositoryInterface::class); + $items = $ruleRepository->getList($searchCriteria) + ->getItems(); + + return array_pop($items); +} diff --git a/dev/tests/integration/testsuite/Magento/Setup/Console/Command/PriceIndexerDimensionsModeSetCommandTest.php b/dev/tests/integration/testsuite/Magento/Setup/Console/Command/PriceIndexerDimensionsModeSetCommandTest.php new file mode 100644 index 0000000000000..79028a159d1aa --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/Setup/Console/Command/PriceIndexerDimensionsModeSetCommandTest.php @@ -0,0 +1,168 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +declare(strict_types=1); + +namespace Magento\Setup\Console\Command; + +use Magento\Catalog\Model\Indexer\Product\Price\DimensionModeConfiguration; +use Symfony\Component\Console\Tester\CommandTester; +use Magento\Framework\Console\Cli; +use Magento\Framework\ObjectManagerInterface; +use Magento\TestFramework\Helper\Bootstrap; +use Magento\Catalog\Console\Command\PriceIndexerDimensionsModeSetCommand; + +/** + * Class PriceIndexerDimensionsModeSetCommand + * @package Magento\Setup\Console\Command + */ +class PriceIndexerDimensionsModeSetCommandTest extends \Magento\TestFramework\Indexer\TestCase +{ + /** @var ObjectManagerInterface */ + private $objectManager; + + /** @var GenerateFixturesCommand */ + private $command; + + /** @var CommandTester */ + private $commandTester; + + /** + * setUp + */ + public function setUp() + { + $this->objectManager = Bootstrap::getObjectManager(); + + $this->objectManager->get(\Magento\TestFramework\App\Config::class)->clean(); + + $this->command = $this->objectManager->create( + \Magento\Catalog\Console\Command\PriceIndexerDimensionsModeSetCommand::class + ); + + $this->commandTester = new CommandTester($this->command); + + parent::setUp(); + } + + /** + * tearDown + */ + public function tearDown() + { + parent::tearDown(); + } + + /** + * setUpBeforeClass + */ + public static function setUpBeforeClass() + { + $db = Bootstrap::getInstance()->getBootstrap() + ->getApplication() + ->getDbInstance(); + if (!$db->isDbDumpExists()) { + throw new \LogicException('DB dump does not exist.'); + } + $db->restoreFromDbDump(); + + parent::setUpBeforeClass(); + } + + /** + * @magentoAppArea adminhtml + * @magentoAppIsolation enabled + * + * @param $previousMode + * @param $currentMode + * @dataProvider modesDataProvider + */ + public function testSwitchMode($previousMode, $currentMode) + { + $this->commandTester->execute( + [ + PriceIndexerDimensionsModeSetCommand::INPUT_KEY_MODE => $currentMode + ] + ); + $expectedOutput = 'Dimensions mode for indexer Product Price was changed from \'' + . $previousMode . '\' to \'' . $currentMode . '\''; + + $actualOutput = $this->commandTester->getDisplay(); + + $this->assertContains($expectedOutput, $actualOutput); + + static::assertEquals( + Cli::RETURN_SUCCESS, + $this->commandTester->getStatusCode(), + $this->commandTester->getDisplay(true) + ); + } + + public function modesDataProvider() + { + return [ + [DimensionModeConfiguration::DIMENSION_NONE, DimensionModeConfiguration::DIMENSION_WEBSITE], + [DimensionModeConfiguration::DIMENSION_WEBSITE, DimensionModeConfiguration::DIMENSION_CUSTOMER_GROUP], + [ + DimensionModeConfiguration::DIMENSION_CUSTOMER_GROUP, + DimensionModeConfiguration::DIMENSION_WEBSITE_AND_CUSTOMER_GROUP + ], + [ + DimensionModeConfiguration::DIMENSION_WEBSITE_AND_CUSTOMER_GROUP, + DimensionModeConfiguration::DIMENSION_NONE + ], + [ + DimensionModeConfiguration::DIMENSION_NONE, + DimensionModeConfiguration::DIMENSION_WEBSITE_AND_CUSTOMER_GROUP + ], + [ + DimensionModeConfiguration::DIMENSION_WEBSITE_AND_CUSTOMER_GROUP, + DimensionModeConfiguration::DIMENSION_CUSTOMER_GROUP + ], + [DimensionModeConfiguration::DIMENSION_CUSTOMER_GROUP, DimensionModeConfiguration::DIMENSION_WEBSITE], + [DimensionModeConfiguration::DIMENSION_WEBSITE, DimensionModeConfiguration::DIMENSION_NONE], + ]; + } + + /** + * @magentoAppArea adminhtml + * @magentoAppIsolation enabled + */ + public function testSwitchModeForSameMode() + { + $this->commandTester->execute( + [ + PriceIndexerDimensionsModeSetCommand::INPUT_KEY_MODE => DimensionModeConfiguration::DIMENSION_NONE + ] + ); + $expectedOutput = 'Dimensions mode for indexer Product Price has not been changed'; + + $actualOutput = $this->commandTester->getDisplay(); + + $this->assertContains($expectedOutput, $actualOutput); + + static::assertEquals( + Cli::RETURN_SUCCESS, + $this->commandTester->getStatusCode(), + $this->commandTester->getDisplay(true) + ); + } + + /** + * @magentoAppArea adminhtml + * @magentoAppIsolation enabled + * + * @expectedException \InvalidArgumentException + */ + public function testSwitchModeWithInvalidArgument() + { + $this->commandTester->execute( + [ + PriceIndexerDimensionsModeSetCommand::INPUT_KEY_MODE => DimensionModeConfiguration::DIMENSION_NONE . + '_not_valid' + ] + ); + } +} diff --git a/dev/tests/integration/testsuite/Magento/Store/Block/SwitcherTest.php b/dev/tests/integration/testsuite/Magento/Store/Block/SwitcherTest.php index b3707fc605017..9d1f584bfcd77 100644 --- a/dev/tests/integration/testsuite/Magento/Store/Block/SwitcherTest.php +++ b/dev/tests/integration/testsuite/Magento/Store/Block/SwitcherTest.php @@ -5,6 +5,11 @@ */ namespace Magento\Store\Block; +use Magento\Framework\App\ActionInterface; +use Magento\TestFramework\Helper\Bootstrap; +use Magento\Framework\Url\DecoderInterface; +use Magento\Framework\App\ScopeInterface; + /** * Integration tests for \Magento\Store\Block\Switcher block. */ @@ -15,6 +20,11 @@ class SwitcherTest extends \PHPUnit\Framework\TestCase */ private $_objectManager; + /** + * @var DecoderInterface + */ + private $decoder; + /** * Set up. * @@ -22,11 +32,12 @@ class SwitcherTest extends \PHPUnit\Framework\TestCase */ protected function setUp() { - $this->_objectManager = \Magento\TestFramework\Helper\Bootstrap::getObjectManager(); + $this->_objectManager = Bootstrap::getObjectManager(); + $this->decoder = Bootstrap::getObjectManager()->create(DecoderInterface::class); } /** - * Test that GetTargetStorePostData() method return correct store URL. + * Test that GetTargetStorePostData() method returns correct data. * * @magentoDataFixture Magento/Store/_files/store.php * @return void @@ -39,8 +50,16 @@ public function testGetTargetStorePostData() /** @var \Magento\Store\Api\StoreRepositoryInterface $storeRepository */ $storeRepository = $this->_objectManager->create(\Magento\Store\Api\StoreRepositoryInterface::class); $store = $storeRepository->get($storeCode); + $result = json_decode($block->getTargetStorePostData($store), true); - - $this->assertContains($storeCode, $result['action']); + $url = parse_url($this->decoder->decode($result['data'][ActionInterface::PARAM_NAME_URL_ENCODED])); + $storeParsedQuery = []; + if (isset($url['query'])) { + parse_str($url['query'], $storeParsedQuery); + } + + $this->assertSame($storeCode, $result['data']['___store']); + $this->assertSame($storeCode, $storeParsedQuery['___store']); + $this->assertSame(ScopeInterface::SCOPE_DEFAULT, $result['data']['___from_store']); } } diff --git a/dev/tests/integration/testsuite/Magento/Store/Model/StoreSwitcherTest.php b/dev/tests/integration/testsuite/Magento/Store/Model/StoreSwitcherTest.php new file mode 100644 index 0000000000000..0e4d129d17aa6 --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/Store/Model/StoreSwitcherTest.php @@ -0,0 +1,59 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +declare(strict_types=1); + +namespace Magento\Store\Model; + +use Magento\Framework\ObjectManagerInterface as ObjectManager; +use Magento\TestFramework\Helper\Bootstrap; + +class StoreSwitcherTest extends \PHPUnit\Framework\TestCase +{ + /** + * @var StoreSwitcher + */ + private $storeSwitcher; + + /** + * @var ObjectManager + */ + private $objectManager; + + /** + * Class dependencies initialization + * + * @return void + */ + protected function setUp() + { + $this->objectManager = Bootstrap::getObjectManager(); + $this->storeSwitcher = $this->objectManager->get(StoreSwitcher::class); + } + + /** + * @magentoDataFixture Magento/Store/_files/store.php + * @magentoDataFixture Magento/Store/_files/second_store.php + * @return void + * @throws StoreSwitcher\CannotSwitchStoreException + * @throws \Magento\Framework\Exception\NoSuchEntityException + */ + public function testSwitch(): void + { + $redirectUrl = "http://domain.com/?SID=e5h3e086dce3ckkqt9ia7avl27&___store=fixture_second_store"; + $expectedUrl = "http://domain.com/"; + $fromStoreCode = 'test'; + /** @var \Magento\Store\Api\StoreRepositoryInterface $storeRepository */ + $storeRepository = $this->objectManager->create(\Magento\Store\Api\StoreRepositoryInterface::class); + $fromStore = $storeRepository->get($fromStoreCode); + + $toStoreCode = 'fixture_second_store'; + /** @var \Magento\Store\Api\StoreRepositoryInterface $storeRepository */ + $storeRepository = $this->objectManager->create(\Magento\Store\Api\StoreRepositoryInterface::class); + $toStore = $storeRepository->get($toStoreCode); + + $this->assertEquals($expectedUrl, $this->storeSwitcher->switch($fromStore, $toStore, $redirectUrl)); + } +} diff --git a/dev/tests/integration/testsuite/Magento/Tax/Model/Sales/Total/Quote/SubtotalTest.php b/dev/tests/integration/testsuite/Magento/Tax/Model/Sales/Total/Quote/SubtotalTest.php index b021040079538..ae1f475d43b71 100644 --- a/dev/tests/integration/testsuite/Magento/Tax/Model/Sales/Total/Quote/SubtotalTest.php +++ b/dev/tests/integration/testsuite/Magento/Tax/Model/Sales/Total/Quote/SubtotalTest.php @@ -4,6 +4,8 @@ * See COPYING.txt for license details. */ +// @codingStandardsIgnoreFile + namespace Magento\Tax\Model\Sales\Total\Quote; use Magento\TestFramework\Helper\Bootstrap; @@ -13,7 +15,7 @@ * * @SuppressWarnings(PHPMD.CouplingBetweenObjects) */ -class SubtotalTest extends \PHPUnit\Framework\TestCase +class SubtotalTest extends \Magento\TestFramework\Indexer\TestCase { /** * Object Manager @@ -27,12 +29,23 @@ class SubtotalTest extends \PHPUnit\Framework\TestCase */ private $productRepository; + public static function setUpBeforeClass() + { + $db = \Magento\TestFramework\Helper\Bootstrap::getInstance()->getBootstrap() + ->getApplication() + ->getDbInstance(); + if (!$db->isDbDumpExists()) { + throw new \LogicException('DB dump does not exist.'); + } + $db->restoreFromDbDump(); + + parent::setUpBeforeClass(); + } + protected function setUp() { $this->objectManager = Bootstrap::getObjectManager(); - $this->productRepository = $this->objectManager->create( - \Magento\Catalog\Api\ProductRepositoryInterface::class - ); + $this->productRepository = $this->objectManager->create(\Magento\Catalog\Api\ProductRepositoryInterface::class); } protected function getCustomerById($id) @@ -46,6 +59,7 @@ protected function getCustomerById($id) /** * @magentoAppIsolation enabled + * @magentoDbIsolation enabled * @magentoDataFixture Magento/Customer/_files/customer.php * @magentoDataFixture Magento/Customer/_files/customer_address.php * @magentoDataFixture Magento/Tax/_files/tax_classes.php @@ -61,8 +75,12 @@ public function testCollectUnitBased($expected) /** @var \Magento\Customer\Model\Customer $customer */ $customer = $this->objectManager->create(\Magento\Customer\Model\Customer::class)->load($fixtureCustomerId); /** @var \Magento\Customer\Model\Group $customerGroup */ - $customerGroup = $this->objectManager->create(\Magento\Customer\Model\Group::class) - ->load('custom_group', 'customer_group_code'); + $customerGroup = $this->objectManager->create( + \Magento\Customer\Model\Group::class + )->load( + 'custom_group', + 'customer_group_code' + ); $customerGroup->setTaxClassId($customerTaxClassId)->save(); $customer->setGroupId($customerGroup->getId())->save(); @@ -160,6 +178,7 @@ public function collectUnitBasedDataProvider() } /** + * @magentoDbIsolation disabled * @magentoDataFixture Magento/Customer/_files/customer.php * @magentoDataFixture Magento/Customer/_files/customer_address.php * @magentoDataFixture Magento/Tax/_files/tax_classes.php @@ -177,7 +196,10 @@ public function testCollectUnitBasedBundleProduct($expected) /** @var \Magento\Customer\Model\Group $customerGroup */ $customerGroup = $this->objectManager->create( \Magento\Customer\Model\Group::class - )->load('custom_group', 'customer_group_code'); + )->load( + 'custom_group', + 'customer_group_code' + ); $customerGroup->setTaxClassId($customerTaxClassId)->save(); $customer->setGroupId($customerGroup->getId())->save(); diff --git a/dev/tests/integration/testsuite/Magento/Tax/Model/Sales/Total/Quote/TaxTest.php b/dev/tests/integration/testsuite/Magento/Tax/Model/Sales/Total/Quote/TaxTest.php index 9b498afc2500d..19343e49192ac 100644 --- a/dev/tests/integration/testsuite/Magento/Tax/Model/Sales/Total/Quote/TaxTest.php +++ b/dev/tests/integration/testsuite/Magento/Tax/Model/Sales/Total/Quote/TaxTest.php @@ -5,17 +5,19 @@ */ namespace Magento\Tax\Model\Sales\Total\Quote; +use Magento\Quote\Model\Quote\TotalsCollector; use Magento\Tax\Model\Calculation; use Magento\TestFramework\Helper\Bootstrap; require_once __DIR__ . '/SetupUtil.php'; require_once __DIR__ . '/../../../../_files/tax_calculation_data_aggregated.php'; +require_once __DIR__ . '/../../../../_files/full_discount_with_tax.php'; /** * Class TaxTest * @SuppressWarnings(PHPMD.CouplingBetweenObjects) */ -class TaxTest extends \PHPUnit\Framework\TestCase +class TaxTest extends \Magento\TestFramework\Indexer\TestCase { /** * Utility object for setting up tax rates, tax classes and tax rules @@ -24,6 +26,24 @@ class TaxTest extends \PHPUnit\Framework\TestCase */ protected $setupUtil = null; + /** + * @var TotalsCollector + */ + private $totalsCollector; + + /** + * test setup + */ + public function setUp() + { + /** @var \Magento\Framework\ObjectManagerInterface $objectManager */ + $objectManager = Bootstrap::getObjectManager(); + $this->totalsCollector = $objectManager->create(TotalsCollector::class); + $this->setupUtil = new SetupUtil($objectManager); + + parent::setUp(); + } + /** * Test taxes collection for quote. * @@ -108,6 +128,40 @@ public function testCollect() ); } + /** + * Test taxes collection with full discount for quote. + * + * Test tax calculation and price when the discount may be bigger than total + * This method will test the collector through $quote->collectTotals() method + * + * @see \Magento\SalesRule\Model\Utility::deltaRoundingFix + * @magentoDataFixture Magento/Tax/_files/full_discount_with_tax.php + * @magentoDbIsolation enabled + * @magentoAppIsolation enabled + */ + public function testFullDiscountWithDeltaRoundingFix() + { + global $fullDiscountIncTax; + $configData = $fullDiscountIncTax['config_data']; + $quoteData = $fullDiscountIncTax['quote_data']; + $expectedResults = $fullDiscountIncTax['expected_result']; + + /** @var \Magento\Framework\ObjectManagerInterface $objectManager */ + $objectManager = Bootstrap::getObjectManager(); + + //Setup tax configurations + $this->setupUtil = new SetupUtil($objectManager); + $this->setupUtil->setupTax($configData); + + $quote = $this->setupUtil->setupQuote($quoteData); + + $quote->collectTotals(); + + $quoteAddress = $quote->getShippingAddress(); + + $this->verifyResult($quoteAddress, $expectedResults); + } + /** * Verify fields in quote item * @@ -227,25 +281,26 @@ protected function verifyResult($quoteAddress, $expectedResults) * @param array $configData * @param array $quoteData * @param array $expectedResults - * @magentoDbIsolation enabled + * @magentoDbIsolation disabled * @magentoAppIsolation enabled * @dataProvider taxDataProvider * @return void */ public function testTaxCalculation($configData, $quoteData, $expectedResults) { - /** @var \Magento\Framework\ObjectManagerInterface $objectManager */ - $objectManager = Bootstrap::getObjectManager(); - /** @var \Magento\Quote\Model\Quote\TotalsCollector $totalsCollector */ - $totalsCollector = $objectManager->create(\Magento\Quote\Model\Quote\TotalsCollector::class); - + $db = \Magento\TestFramework\Helper\Bootstrap::getInstance()->getBootstrap() + ->getApplication() + ->getDbInstance(); + if (!$db->isDbDumpExists()) { + throw new \LogicException('DB dump does not exist.'); + } + $db->restoreFromDbDump(); //Setup tax configurations - $this->setupUtil = new SetupUtil($objectManager); $this->setupUtil->setupTax($configData); $quote = $this->setupUtil->setupQuote($quoteData); $quoteAddress = $quote->getShippingAddress(); - $totalsCollector->collectAddressTotals($quote, $quoteAddress); + $this->totalsCollector->collectAddressTotals($quote, $quoteAddress); $this->verifyResult($quoteAddress, $expectedResults); } diff --git a/dev/tests/integration/testsuite/Magento/Tax/Model/TaxRuleRepositoryTest.php b/dev/tests/integration/testsuite/Magento/Tax/Model/TaxRuleRepositoryTest.php index cb45e1971ecab..0b98b9a519391 100644 --- a/dev/tests/integration/testsuite/Magento/Tax/Model/TaxRuleRepositoryTest.php +++ b/dev/tests/integration/testsuite/Magento/Tax/Model/TaxRuleRepositoryTest.php @@ -109,7 +109,7 @@ public function testSave() * @expectedExceptionMessage No such entity with taxRuleId = 9999 * @magentoDbIsolation enabled */ - public function testSaveThrowsExceptionIdTargetTaxRulDoesNotExist() + public function testSaveThrowsExceptionIdIfTargetTaxRuleDoesNotExist() { $taxRuleDataObject = $this->taxRuleFactory->create(); $taxRuleDataObject->setId(9999) diff --git a/dev/tests/integration/testsuite/Magento/Tax/_files/full_discount_with_tax.php b/dev/tests/integration/testsuite/Magento/Tax/_files/full_discount_with_tax.php new file mode 100644 index 0000000000000..2b5ef07de341a --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/Tax/_files/full_discount_with_tax.php @@ -0,0 +1,120 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +declare(strict_types=1); + +use Magento\Tax\Model\Config; +use Magento\Tax\Model\Sales\Total\Quote\SetupUtil; + +$fullDiscountIncTax = [ + 'config_data' => [ + 'config_overrides' => [ + Config::CONFIG_XML_PATH_APPLY_AFTER_DISCOUNT => 0, + Config::CONFIG_XML_PATH_DISCOUNT_TAX => 1, + Config::XML_PATH_ALGORITHM => 'ROW_BASE_CALCULATION', + Config::CONFIG_XML_PATH_SHIPPING_TAX_CLASS => SetupUtil::SHIPPING_TAX_CLASS, + ], + 'tax_rate_overrides' => [ + SetupUtil::TAX_RATE_TX => 18, + SetupUtil::TAX_RATE_SHIPPING => 0, + ], + 'tax_rule_overrides' => [ + [ + 'code' => 'Product Tax Rule', + 'product_tax_class_ids' => [ + SetupUtil::PRODUCT_TAX_CLASS_1 + ], + ], + [ + 'code' => 'Shipping Tax Rule', + 'product_tax_class_ids' => [ + SetupUtil::SHIPPING_TAX_CLASS + ], + 'tax_rate_ids' => [ + SetupUtil::TAX_RATE_SHIPPING, + ], + ], + ], + ], + 'quote_data' => [ + 'billing_address' => [ + 'region_id' => SetupUtil::REGION_TX, + ], + 'shipping_address' => [ + 'region_id' => SetupUtil::REGION_TX, + ], + 'items' => [ + [ + 'sku' => 'simple1', + 'price' => 2542.37, + 'qty' => 2, + ] + ], + 'shipping_method' => 'free', + 'shopping_cart_rules' => [ + [ + 'discount_amount' => 100 + ], + ], + ], + 'expected_result' => [ + 'address_data' => [ + 'subtotal' => 5084.74, + 'base_subtotal' => 5084.74, + 'subtotal_incl_tax' => 5999.99, + 'base_subtotal_incl_tax' => 5999.99, + 'tax_amount' => 915.25, + 'base_tax_amount' => 915.25, + 'shipping_amount' => 0, + 'base_shipping_amount' => 0, + 'shipping_incl_tax' => 0, + 'base_shipping_incl_tax' => 0, + 'shipping_tax_amount' => 0, + 'base_shipping_tax_amount' => 0, + 'discount_amount' => -5999.99, + 'base_discount_amount' => -5999.99, + 'discount_tax_compensation_amount' => 0, + 'base_discount_tax_compensation_amount' => 0, + 'shipping_discount_tax_compensation_amount' => 0, + 'base_shipping_discount_tax_compensation_amount' => 0, + 'grand_total' => 0, + 'base_grand_total' => 0, + 'applied_taxes' => [ + SetupUtil::TAX_RATE_TX => [ + 'percent' => 18, + 'amount' => 915.25, + 'base_amount' => 915.25, + 'rates' => [ + [ + 'code' => SetupUtil::TAX_RATE_TX, + 'title' => SetupUtil::TAX_RATE_TX, + 'percent' => 18, + ], + ], + ] + ], + ], + 'items_data' => [ + 'simple1' => [ + 'row_total' => 5084.74, + 'base_row_total' => 5084.74, + 'tax_percent' => 18, + 'price' => 2542.37, + 'base_price' => 2542.37, + 'price_incl_tax' => 3000, + 'base_price_incl_tax' => 3000, + 'row_total_incl_tax' => 5999.99, + 'base_row_total_incl_tax' => 5999.99, + 'tax_amount' => 915.25, + 'base_tax_amount' => 915.25, + 'discount_amount' => 5999.99, + 'base_discount_amount' => 5999.99, + 'discount_percent' => 100, + 'discount_tax_compensation_amount' => 0, + 'base_discount_tax_compensation_amount' => 0, + ], + ], + ] +]; diff --git a/dev/tests/integration/testsuite/Magento/Ups/Model/CarrierTest.php b/dev/tests/integration/testsuite/Magento/Ups/Model/CarrierTest.php index a9f6752c9de82..aa301e8d3e423 100644 --- a/dev/tests/integration/testsuite/Magento/Ups/Model/CarrierTest.php +++ b/dev/tests/integration/testsuite/Magento/Ups/Model/CarrierTest.php @@ -5,20 +5,27 @@ */ namespace Magento\Ups\Model; +use Magento\TestFramework\Helper\Bootstrap; +use Magento\Quote\Model\Quote\Address\RateRequestFactory; + class CarrierTest extends \PHPUnit\Framework\TestCase { /** - * @var \Magento\Ups\Model\Carrier + * @var Carrier */ private $carrier; + /** + * @return void + */ protected function setUp() { - $this->carrier = \Magento\TestFramework\Helper\Bootstrap::getObjectManager()->create( - \Magento\Ups\Model\Carrier::class - ); + $this->carrier = Bootstrap::getObjectManager()->create(Carrier::class); } + /** + * @return void + */ public function testGetShipAcceptUrl() { $this->assertEquals('https://wwwcie.ups.com/ups.app/xml/ShipAccept', $this->carrier->getShipAcceptUrl()); @@ -34,6 +41,9 @@ public function testGetShipAcceptUrlLive() $this->assertEquals('https://onlinetools.ups.com/ups.app/xml/ShipAccept', $this->carrier->getShipAcceptUrl()); } + /** + * @return void + */ public function testGetShipConfirmUrl() { $this->assertEquals('https://wwwcie.ups.com/ups.app/xml/ShipConfirm', $this->carrier->getShipConfirmUrl()); @@ -51,4 +61,27 @@ public function testGetShipConfirmUrlLive() $this->carrier->getShipConfirmUrl() ); } + + /** + * @magentoConfigFixture current_store carriers/ups/active 1 + * @magentoConfigFixture current_store carriers/ups/allowed_methods 1DA,GND + * @magentoConfigFixture current_store carriers/ups/free_method GND + */ + public function testCollectFreeRates() + { + $rateRequest = Bootstrap::getObjectManager()->get(RateRequestFactory::class)->create(); + $rateRequest->setDestCountryId('US'); + $rateRequest->setDestRegionId('CA'); + $rateRequest->setDestPostcode('90001'); + $rateRequest->setPackageQty(1); + $rateRequest->setPackageWeight(1); + $rateRequest->setFreeMethodWeight(0); + $rateRequest->setLimitCarrier($this->carrier::CODE); + $rateRequest->setFreeShipping(true); + $rateResult = $this->carrier->collectRates($rateRequest); + $result = $rateResult->asArray(); + $methods = $result[$this->carrier::CODE]['methods']; + $this->assertEquals(0, $methods['GND']['price']); + $this->assertNotEquals(0, $methods['1DA']['price']); + } } diff --git a/dev/tests/integration/testsuite/Magento/UrlRewrite/Controller/UrlRewriteTest.php b/dev/tests/integration/testsuite/Magento/UrlRewrite/Controller/UrlRewriteTest.php index 1ebbb35dd7dc4..5593cecb10d91 100644 --- a/dev/tests/integration/testsuite/Magento/UrlRewrite/Controller/UrlRewriteTest.php +++ b/dev/tests/integration/testsuite/Magento/UrlRewrite/Controller/UrlRewriteTest.php @@ -42,6 +42,9 @@ public function testMatchUrlRewrite( ); } + /** + * @return array + */ public function requestDataProvider() { return [ @@ -69,12 +72,6 @@ public function requestDataProvider() 'request' => '/page-similar/', 'redirect' => '/page-b', ], - 'Use Case #7: Rewrite during stores switching' => [ - 'request' => '/page-c-on-2nd-store' - . '?___store=default&___from_store=fixture_second_store', - 'redirect' => '/page-c-on-1st-store', - 'expectedCode' => 302 - ], ]; } } diff --git a/dev/tests/integration/testsuite/Magento/UrlRewrite/Model/StoreSwitcher/RewriteUrlTest.php b/dev/tests/integration/testsuite/Magento/UrlRewrite/Model/StoreSwitcher/RewriteUrlTest.php new file mode 100644 index 0000000000000..2cb86358667c0 --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/UrlRewrite/Model/StoreSwitcher/RewriteUrlTest.php @@ -0,0 +1,122 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +declare(strict_types=1); + +namespace Magento\UrlRewrite\Model\StoreSwitcher; + +use Magento\Catalog\Api\ProductRepositoryInterface; +use Magento\Framework\App\Config\ReinitableConfigInterface; +use Magento\Framework\App\Config\Value; +use Magento\Store\Api\Data\StoreInterface; +use Magento\Store\Model\ScopeInterface; +use Magento\Store\Model\StoreSwitcher; +use Magento\Framework\ObjectManagerInterface as ObjectManager; +use Magento\TestFramework\Helper\Bootstrap; + +class RewriteUrlTest extends \PHPUnit\Framework\TestCase +{ + /** + * @var StoreSwitcher + */ + private $storeSwitcher; + + /** + * @var ObjectManager + */ + private $objectManager; + + /** + * @var ProductRepositoryInterface + */ + private $productRepository; + + /** + * Class dependencies initialization + * + * @return void + */ + protected function setUp() + { + $this->objectManager = Bootstrap::getObjectManager(); + $this->storeSwitcher = $this->objectManager->get(StoreSwitcher::class); + $this->productRepository = $this->objectManager->create(ProductRepositoryInterface::class); + } + + /** + * @magentoDataFixture Magento/UrlRewrite/_files/url_rewrite.php + * @magentoDataFixture Magento/Catalog/_files/category_product.php + * @return void + * @throws StoreSwitcher\CannotSwitchStoreException + * @throws \Magento\Framework\Exception\NoSuchEntityException + */ + public function testSwitchToNonExistingPage(): void + { + $fromStoreCode = 'default'; + /** @var \Magento\Store\Api\StoreRepositoryInterface $storeRepository */ + $storeRepository = $this->objectManager->create(\Magento\Store\Api\StoreRepositoryInterface::class); + $fromStore = $storeRepository->get($fromStoreCode); + + $toStoreCode = 'fixture_second_store'; + /** @var \Magento\Store\Api\StoreRepositoryInterface $storeRepository */ + $storeRepository = $this->objectManager->create(\Magento\Store\Api\StoreRepositoryInterface::class); + $toStore = $storeRepository->get($toStoreCode); + + $this->setBaseUrl($toStore); + + $product = $this->productRepository->get('simple333'); + + $redirectUrl = "http://domain.com/{$product->getUrlKey()}.html"; + $expectedUrl = $toStore->getBaseUrl(); + + $this->assertEquals($expectedUrl, $this->storeSwitcher->switch($fromStore, $toStore, $redirectUrl)); + } + + /** + * @magentoDataFixture Magento/UrlRewrite/_files/url_rewrite.php + * @return void + * @throws StoreSwitcher\CannotSwitchStoreException + * @throws \Magento\Framework\Exception\NoSuchEntityException + */ + public function testSwitchToExistingPage(): void + { + $fromStoreCode = 'default'; + /** @var \Magento\Store\Api\StoreRepositoryInterface $storeRepository */ + $storeRepository = $this->objectManager->create(\Magento\Store\Api\StoreRepositoryInterface::class); + $fromStore = $storeRepository->get($fromStoreCode); + + $toStoreCode = 'fixture_second_store'; + /** @var \Magento\Store\Api\StoreRepositoryInterface $storeRepository */ + $storeRepository = $this->objectManager->create(\Magento\Store\Api\StoreRepositoryInterface::class); + $toStore = $storeRepository->get($toStoreCode); + + $redirectUrl = $expectedUrl = "http://localhost/page-c"; + + $this->assertEquals($expectedUrl, $this->storeSwitcher->switch($fromStore, $toStore, $redirectUrl)); + } + + /** + * Set base url to store. + * + * @param StoreInterface $targetStore + * @return void + */ + private function setBaseUrl(StoreInterface $targetStore): void + { + $configValue = $this->objectManager->create(Value::class); + $configValue->load('web/unsecure/base_url', 'path'); + $baseUrl = 'http://domain.com/'; + if (!$configValue->getPath()) { + $configValue->setPath('web/unsecure/base_url'); + } + $configValue->setValue($baseUrl); + $configValue->setScope(ScopeInterface::SCOPE_STORES); + $configValue->setScopeId($targetStore->getId()); + $configValue->save(); + + $reinitibleConfig = $this->objectManager->create(ReinitableConfigInterface::class); + $reinitibleConfig->reinit(); + } +} diff --git a/dev/tests/integration/testsuite/Magento/UrlRewrite/_files/url_rewrite_rollback.php b/dev/tests/integration/testsuite/Magento/UrlRewrite/_files/url_rewrite_rollback.php new file mode 100644 index 0000000000000..19cce769b1c19 --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/UrlRewrite/_files/url_rewrite_rollback.php @@ -0,0 +1,29 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +declare(strict_types=1); + +/** @var \Magento\Framework\Registry $registry */ +$registry = \Magento\TestFramework\Helper\Bootstrap::getObjectManager()->get(\Magento\Framework\Registry::class); + +$registry->unregister('isSecureArea'); +$registry->register('isSecureArea', true); + +/** @var \Magento\Catalog\Api\ProductRepositoryInterface $productRepository */ +$productRepository = \Magento\TestFramework\Helper\Bootstrap::getObjectManager() + ->create(\Magento\Catalog\Api\ProductRepositoryInterface::class); + +/** @var \Magento\UrlRewrite\Model\ResourceModel\UrlRewriteCollection $urlRewriteCollection */ +$urlRewriteCollection = \Magento\TestFramework\Helper\Bootstrap::getObjectManager() + ->create(\Magento\UrlRewrite\Model\ResourceModel\UrlRewriteCollection::class); +$collection = $urlRewriteCollection + ->addFieldToFilter('entity_type', 'custom') + ->addFieldToFilter('request_path', ['page-a', 'page-b', 'page-c']) + ->addFieldToFilter('entity_id', '333') + ->load() + ->walk('delete'); + +$registry->unregister('isSecureArea'); +$registry->register('isSecureArea', false); diff --git a/dev/tests/integration/testsuite/Magento/Widget/Setup/LayoutUpdateConverterTest.php b/dev/tests/integration/testsuite/Magento/Widget/Setup/LayoutUpdateConverterTest.php index 083876d7eddb3..43c0bd202cc92 100644 --- a/dev/tests/integration/testsuite/Magento/Widget/Setup/LayoutUpdateConverterTest.php +++ b/dev/tests/integration/testsuite/Magento/Widget/Setup/LayoutUpdateConverterTest.php @@ -32,7 +32,7 @@ public function testConvert($value, $expected) public function convertDataProvider() { // @codingStandardsIgnoreStart - $beginning = '<body><referenceContainer name="content"><block class="Magento\CatalogWidget\Block\Product\ProductsList" name="23e38bbfa7cc6474454570e51aeffcc3" template="product/widget/content/grid.phtml"><action method="setData"><argument name="name" xsi:type="string">show_pager</argument><argument name="value" xsi:type="string">0</argument></action><action method="setData"><argument name="name" xsi:type="string">products_count</argument><argument name="value" xsi:type="string">10</argument></action><action method="setData">'; + $beginning = '<body><referenceContainer name="content"><block class="Magento\CatalogWidget\Block\Product\ProductsList" name="23e38bbfa7cc6474454570e51aeffcc3" template="Magento_CatalogWidget::product/widget/content/grid.phtml"><action method="setData"><argument name="name" xsi:type="string">show_pager</argument><argument name="value" xsi:type="string">0</argument></action><action method="setData"><argument name="name" xsi:type="string">products_count</argument><argument name="value" xsi:type="string">10</argument></action><action method="setData">'; $serializedWidgetXml = '<argument name="name" xsi:type="string">conditions_encoded</argument><argument name="value" xsi:type="string">a:3:[i:1;a:4:[s:4:`type`;s:50:`Magento|CatalogWidget|Model|Rule|Condition|Combine`;s:10:`aggregator`;s:3:`all`;s:5:`value`;s:1:`1`;s:9:`new_child`;s:0:``;]s:4:`1--1`;a:4:[s:4:`type`;s:50:`Magento|CatalogWidget|Model|Rule|Condition|Product`;s:9:`attribute`;s:3:`sku`;s:8:`operator`;s:2:`()`;s:5:`value`;s:15:`simple, simple1`;]s:4:`1--2`;a:4:[s:4:`type`;s:50:`Magento|CatalogWidget|Model|Rule|Condition|Product`;s:9:`attribute`;s:5:`price`;s:8:`operator`;s:2:`<=`;s:5:`value`;s:2:`10`;]]</argument>'; $jsonEncodedWidgetXml = '<argument name="name" xsi:type="string">conditions_encoded</argument><argument name="value" xsi:type="string">^[`1`:^[`type`:`Magento||CatalogWidget||Model||Rule||Condition||Combine`,`aggregator`:`all`,`value`:`1`,`new_child`:``^],`1--1`:^[`type`:`Magento||CatalogWidget||Model||Rule||Condition||Product`,`attribute`:`sku`,`operator`:`()`,`value`:`simple, simple1`^],`1--2`:^[`type`:`Magento||CatalogWidget||Model||Rule||Condition||Product`,`attribute`:`price`,`operator`:`<=`,`value`:`10`^]^]</argument>'; $ending = '</action><action method="setData"><argument name="name" xsi:type="string">page_var_name</argument><argument name="value" xsi:type="string">pobqks</argument></action></block></referenceContainer></body>'; diff --git a/dev/tests/js/jasmine/tests/app/code/Magento/Braintree/frontend/js/view/payment/method-renderer/paypal.test.js b/dev/tests/js/jasmine/tests/app/code/Magento/Braintree/frontend/js/view/payment/method-renderer/paypal.test.js index 596017be9a33c..6fabc513da9af 100644 --- a/dev/tests/js/jasmine/tests/app/code/Magento/Braintree/frontend/js/view/payment/method-renderer/paypal.test.js +++ b/dev/tests/js/jasmine/tests/app/code/Magento/Braintree/frontend/js/view/payment/method-renderer/paypal.test.js @@ -27,7 +27,24 @@ define([ }) }, 'Magento_Braintree/js/view/payment/adapter': { + config: {}, + + /** Stub */ + onReady: function () {}, + + /** Stub */ + setConfig: function (config) { + this.config = config; + }, + + /** Stub */ + setup: function () { + this.config.onReady(this.checkout); + }, + checkout: { + /** Stub */ + teardown: function () {}, paypal: { /** Stub */ initAuthFlow: function () {} diff --git a/dev/tests/js/jasmine/tests/app/code/Magento/Catalog/adminhtml/js/use-parent-settings/toggle-disabled-mixin.test.js b/dev/tests/js/jasmine/tests/app/code/Magento/Catalog/adminhtml/js/use-parent-settings/toggle-disabled-mixin.test.js new file mode 100644 index 0000000000000..f3e53673a4e59 --- /dev/null +++ b/dev/tests/js/jasmine/tests/app/code/Magento/Catalog/adminhtml/js/use-parent-settings/toggle-disabled-mixin.test.js @@ -0,0 +1,141 @@ +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ + +/*eslint max-nested-callbacks: 0*/ +define([ + 'underscore', + 'Magento_Catalog/js/components/use-parent-settings/select', + 'Magento_Catalog/js/components/use-parent-settings/toggle-disabled-mixin' +], function (_, select, mixin) { + 'use strict'; + + var CustomInput = mixin(select), + defaultProperties = { + name: 'uiSelect', + dataScope: '', + provider: 'provider', + service: true + }, + obj; + + describe('toggle-disabled-mixin structure tests', function () { + var defaultContext = require.s.contexts._; + + obj = new CustomInput(defaultProperties); + + it('mixin is present in RequireJs config', function () { + var requireJsConfig = defaultContext.config + .config.mixins['Magento_Catalog/js/components/use-parent-settings/select']; + + expect( + requireJsConfig['Magento_Catalog/js/components/use-parent-settings/toggle-disabled-mixin'] + ).toBe(true); + }); + + it('Check for useParent property', function () { + expect(obj.hasOwnProperty('useParent')).toBeTruthy(); + expect(typeof obj.useParent).toEqual('boolean'); + expect(obj.useParent).toEqual(false); + }); + + it('Check for useDefaults property', function () { + expect(obj.hasOwnProperty('useDefaults')).toBeTruthy(); + expect(typeof obj.useDefaults).toEqual('boolean'); + expect(obj.useDefaults).toEqual(false); + }); + + it('Check for toggleDisabled method', function () { + expect(obj.toggleDisabled).toBeDefined(); + expect(typeof obj.toggleDisabled).toEqual('function'); + }); + + it('Check for saveUseDefaults method', function () { + expect(obj.saveUseDefaults).toBeDefined(); + expect(typeof obj.saveUseDefaults).toEqual('function'); + }); + + it('Check for setInitialValue method', function () { + expect(obj.setInitialValue).toBeDefined(); + expect(typeof obj.setInitialValue).toEqual('function'); + }); + + it('Check for toggleUseDefault method', function () { + expect(obj.toggleUseDefault).toBeDefined(); + expect(typeof obj.toggleUseDefault).toEqual('function'); + }); + }); + + describe('toggle-disabled-mixin functionality', function () { + var dataProvider = [ + { + defaults: { + useParent: false, + useDefaults: false + }, + expected: { + disabled: false + } + }, + { + defaults: { + useParent: true, + useDefaults: false + }, + expected: { + disabled: true + } + }, + { + defaults: { + useParent: false, + useDefaults: true + }, + expected: { + disabled: true + } + }, + { + defaults: { + useParent: true, + useDefaults: true + }, + expected: { + disabled: true + } + } + ]; + + dataProvider.forEach(function (state) { + describe(JSON.stringify(state.defaults), function () { + + beforeEach(function () { + obj = new CustomInput( + _.extend(defaultProperties, state.defaults) + ); + }); + + it('Check disabled state', function () { + expect(obj.disabled()).toEqual(state.expected.disabled); + }); + + it('Check checked state', function () { + expect(obj.isUseDefault()).toEqual(state.defaults.useDefaults); + }); + + it('Check of using parent settings', function () { + obj.toggleDisabled(true); + expect(obj.isUseDefault()).toEqual(state.defaults.useDefaults); + expect(obj.disabled()).toEqual(true); + }); + + it('Check of using self settings', function () { + obj.toggleDisabled(false); + expect(obj.isUseDefault()).toEqual(state.defaults.useDefaults); + expect(obj.disabled()).toEqual(obj.isUseDefault()); + }); + }); + }); + }); +}); diff --git a/dev/tests/js/jasmine/tests/app/code/Magento/Catalog/frontend/js/product/storage/storage-service.test.js b/dev/tests/js/jasmine/tests/app/code/Magento/Catalog/frontend/js/product/storage/storage-service.test.js index 4ef1aa2a98976..1a3a5726080bc 100644 --- a/dev/tests/js/jasmine/tests/app/code/Magento/Catalog/frontend/js/product/storage/storage-service.test.js +++ b/dev/tests/js/jasmine/tests/app/code/Magento/Catalog/frontend/js/product/storage/storage-service.test.js @@ -12,22 +12,11 @@ define([ var injector = new Squire(), mocks = { - 'Magento_Catalog/js/product/storage/ids-storage': { - name: 'IdsStorage', - initialize: jasmine.createSpy().and.returnValue({}) - }, 'Magento_Catalog/js/product/storage/data-storage': {}, 'Magento_Catalog/js/product/storage/ids-storage-compare': {} }, - obj; - - beforeEach(function (done) { - injector.mock(mocks); - injector.require(['Magento_Catalog/js/product/storage/storage-service'], function (insance) { - obj = insance; - done(); - }); - }); + obj, + utils; afterEach(function () { try { @@ -43,6 +32,19 @@ define([ }, storage; + beforeEach(function (done) { + injector.mock(mocks); + injector.require([ + 'Magento_Catalog/js/product/storage/ids-storage', + 'Magento_Catalog/js/product/storage/storage-service', + 'mageUtils' + ], function (IdsStorage, instance, mageUtils) { + obj = instance; + utils = mageUtils; + done(); + }); + }); + describe('"createStorage" method', function () { it('create new storage', function () { obj.processSubscribers = jasmine.createSpy(); @@ -73,5 +75,54 @@ define([ expect(typeof obj.getStorage(config.namespace)).toBe('object'); }); }); + describe('"add" method', function () { + var storageValue; + + beforeEach(function () { + storage = new obj.createStorage(config); + storageValue = { + 'property1': 1 + }; + + storage.set(storageValue); + }); + + it('method exists', function () { + expect(storage.add).toBeDefined(); + expect(typeof storage.add).toEqual('function'); + }); + + it('update value', function () { + spyOn(utils, 'copy').and.callThrough(); + expect(storage.get()).toEqual(storageValue); + + storageValue = { + 'property2': 2 + }; + + storage.add(storageValue); + + expect(utils.copy).toHaveBeenCalled(); + expect(storage.get()).toEqual( + { + 'property1': 1, + 'property2': 2 + } + ); + }); + + it('add empty value', function () { + spyOn(utils, 'copy').and.callThrough(); + + storage.add({}); + + expect(utils.copy).not.toHaveBeenCalled(); + expect(storage.get()).toEqual( + { + 'property1': 1 + } + ); + }); + }); }); }); diff --git a/dev/tests/js/jasmine/tests/app/code/Magento/Checkout/frontend/js/model/cart/totals-processor/default.test.js b/dev/tests/js/jasmine/tests/app/code/Magento/Checkout/frontend/js/model/cart/totals-processor/default.test.js index 47518bef19e56..184118f1d02ec 100644 --- a/dev/tests/js/jasmine/tests/app/code/Magento/Checkout/frontend/js/model/cart/totals-processor/default.test.js +++ b/dev/tests/js/jasmine/tests/app/code/Magento/Checkout/frontend/js/model/cart/totals-processor/default.test.js @@ -113,6 +113,8 @@ define([ }); it('estimateTotals if data wasn\'t cached and request was successfully sent', function () { + var deferral = new $.Deferred(); + spyOn(mocks['Magento_Checkout/js/model/cart/cache'], 'isChanged').and.returnValue(true); spyOn(mocks['Magento_Customer/js/customer-data'], 'get').and.returnValue( ko.observable({ @@ -124,9 +126,9 @@ define([ data.shippingMethodCode = mocks['Magento_Checkout/js/model/quote'].shippingMethod()['method_code']; data.shippingCarrierCode = mocks['Magento_Checkout/js/model/quote'].shippingMethod()['carrier_code']; - return new $.Deferred().resolve(result); + return deferral.resolve(result); }); - expect(defaultProcessor.estimateTotals(address)).toBeUndefined(); + expect(defaultProcessor.estimateTotals(address)).toBe(deferral); expect(mocks['Magento_Checkout/js/model/quote'].setTotals).toHaveBeenCalledWith(totals); expect(mocks['Magento_Checkout/js/model/totals'].isLoading.calls.argsFor(0)[0]).toBe(true); expect(mocks['Magento_Checkout/js/model/totals'].isLoading.calls.argsFor(1)[0]).toBe(false); @@ -136,6 +138,8 @@ define([ }); it('estimateTotals if data wasn\'t cached and request returns error', function () { + var deferral = new $.Deferred(); + spyOn(mocks['Magento_Checkout/js/model/cart/cache'], 'isChanged').and.returnValue(true); spyOn(mocks['Magento_Customer/js/customer-data'], 'get').and.returnValue( ko.observable({ @@ -144,9 +148,9 @@ define([ ); spyOn(mocks['Magento_Checkout/js/model/cart/cache'], 'get'); spyOn(mocks['mage/storage'], 'post').and.callFake(function () { - return new $.Deferred().reject('Error Message'); + return deferral.reject('Error Message'); }); - expect(defaultProcessor.estimateTotals(address)).toBeUndefined(); + expect(defaultProcessor.estimateTotals(address)).toBe(deferral); expect(mocks['Magento_Checkout/js/model/totals'].isLoading.calls.argsFor(0)[0]).toBe(true); expect(mocks['Magento_Checkout/js/model/totals'].isLoading.calls.argsFor(1)[0]).toBe(false); expect(mocks['mage/storage'].post).toHaveBeenCalled(); diff --git a/dev/tests/js/jasmine/tests/app/code/Magento/Checkout/frontend/js/sidebar.test.js b/dev/tests/js/jasmine/tests/app/code/Magento/Checkout/frontend/js/sidebar.test.js new file mode 100644 index 0000000000000..8b4fae5a69461 --- /dev/null +++ b/dev/tests/js/jasmine/tests/app/code/Magento/Checkout/frontend/js/sidebar.test.js @@ -0,0 +1,109 @@ +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +/* eslint-disable max-nested-callbacks */ +/*jscs:disable jsDoc*/ + +define([ + 'squire', + 'jquery', + 'ko' +], function (Squire, $, ko) { + 'use strict'; + + describe('Magento_Checkout/js/sidebar', function () { + var injector = new Squire(), + mocks = { + 'Magento_Customer/js/customer-data': { + get: function () { + return ko.observable(); + } + } + }, + sidebar, + cartData = { + 'items': [ + { + 'item_id': 1, + 'product_sku': 'bundle' + }, + { + 'item_id': 5, + 'product_sku': 'simple' + }, + { + 'item_id': 7, + 'product_sku': 'configurable' + } + ] + }, + cart = ko.observable(cartData); + + beforeEach(function (done) { + injector.mock(mocks); + injector.require(['Magento_Checkout/js/sidebar'], function (Constr) { + sidebar = new Constr; + done(); + }); + }); + + describe('Check remove mini-cart item callback.', function () { + beforeEach(function () { + spyOn(jQuery.fn, 'trigger'); + spyOn(mocks['Magento_Customer/js/customer-data'], 'get').and.returnValue(cart); + }); + + it('Method "_removeItemAfter" is defined', function () { + expect(sidebar._removeItemAfter).toBeDefined(); + }); + + it('Cart item is exists', function () { + var elem = $('<input>').data('cart-item', 5); + + sidebar._removeItemAfter(elem); + expect(mocks['Magento_Customer/js/customer-data'].get).toHaveBeenCalledWith('cart'); + expect(jQuery('body').trigger).toHaveBeenCalledWith('ajax:removeFromCart', 'simple'); + }); + + it('Cart item doesn\'t exists', function () { + var elem = $('<input>').data('cart-item', 100); + + sidebar._removeItemAfter(elem); + expect(jQuery('body').trigger).not.toHaveBeenCalled(); + }); + }); + + describe('Check update item quantity callback.', function () { + beforeEach(function () { + spyOn(jQuery.fn, 'trigger'); + spyOn(mocks['Magento_Customer/js/customer-data'], 'get').and.returnValue(cart); + }); + + it('Method "_updateItemQtyAfter" is defined', function () { + expect(sidebar._updateItemQtyAfter).toBeDefined(); + }); + + it('Cart item is exists', function () { + var elem = $('<input>').data('cart-item', 5); + + spyOn(sidebar, '_hideItemButton'); + + sidebar._updateItemQtyAfter(elem); + expect(mocks['Magento_Customer/js/customer-data'].get).toHaveBeenCalledWith('cart'); + expect(jQuery('body').trigger).toHaveBeenCalledWith('ajax:updateCartItemQty', 'simple'); + expect(sidebar._hideItemButton).toHaveBeenCalledWith(elem); + }); + + it('Cart item doesn\'t exists', function () { + var elem = $('<input>').data('cart-item', 100); + + spyOn(sidebar, '_hideItemButton'); + + sidebar._updateItemQtyAfter(elem); + expect(jQuery('body').trigger).not.toHaveBeenCalled(); + expect(sidebar._hideItemButton).toHaveBeenCalledWith(elem); + }); + }); + }); +}); diff --git a/dev/tests/js/jasmine/tests/app/code/Magento/Ui/base/js/form/element/abstract.test.js b/dev/tests/js/jasmine/tests/app/code/Magento/Ui/base/js/form/element/abstract.test.js index c5b153f7cc100..390c5aa89fcc7 100644 --- a/dev/tests/js/jasmine/tests/app/code/Magento/Ui/base/js/form/element/abstract.test.js +++ b/dev/tests/js/jasmine/tests/app/code/Magento/Ui/base/js/form/element/abstract.test.js @@ -303,5 +303,11 @@ define([ expect(model.validate).toHaveBeenCalled(); }); }); + describe('serviceDisabled property', function () { + it('check property state', function () { + expect(typeof model.serviceDisabled).toEqual('function'); + expect(model.serviceDisabled()).toBeFalsy(); + }); + }); }); }); diff --git a/dev/tests/js/jasmine/tests/app/code/Magento/Ui/base/js/lib/ko/bind/i18n.test.js b/dev/tests/js/jasmine/tests/app/code/Magento/Ui/base/js/lib/ko/bind/i18n.test.js index 0f50cc2b6b9b1..201959a2598fd 100644 --- a/dev/tests/js/jasmine/tests/app/code/Magento/Ui/base/js/lib/ko/bind/i18n.test.js +++ b/dev/tests/js/jasmine/tests/app/code/Magento/Ui/base/js/lib/ko/bind/i18n.test.js @@ -38,14 +38,18 @@ define([ /** Stub */ turnOffInlineTranslation = function () { manageInlineTranslation(false); - }; + }, + + storedConfig; beforeEach(function () { + storedConfig = context.config.config; $(document.body).append(elWithStaticText); $(document.body).append(elWithVariable); }); afterEach(function () { + context.config.config = storedConfig; elWithStaticText.remove(); elWithVariable.remove(); }); diff --git a/dev/tests/js/jasmine/tests/app/code/Magento/Ui/base/js/lib/validation/rules.test.js b/dev/tests/js/jasmine/tests/app/code/Magento/Ui/base/js/lib/validation/rules.test.js index 1dfdfca8b2f50..0703374aaa9d6 100644 --- a/dev/tests/js/jasmine/tests/app/code/Magento/Ui/base/js/lib/validation/rules.test.js +++ b/dev/tests/js/jasmine/tests/app/code/Magento/Ui/base/js/lib/validation/rules.test.js @@ -39,6 +39,37 @@ define([ expect(rules['range-words'].handler(value, params)).toBe(true); }); }); + describe('"validate-number" method', function () { + it('Check on empty value', function () { + var value = ''; + + expect(rules['validate-number'].handler(value)).toBe(true); + }); + + it('Check on integer', function () { + var value = '125'; + + expect(rules['validate-number'].handler(value)).toBe(true); + }); + + it('Check on float', function () { + var value = '1000.50'; + + expect(rules['validate-number'].handler(value)).toBe(true); + }); + + it('Check on formatted float', function () { + var value = '1,000,000.50'; + + expect(rules['validate-number'].handler(value)).toBe(true); + }); + + it('Check on not a number', function () { + var value = 'string'; + + expect(rules['validate-number'].handler(value)).toBe(false); + }); + }); }); describe('validate-color', function () { diff --git a/dev/tests/static/framework/Magento/Sniffs/Annotation/MethodArgumentsSniff.php b/dev/tests/static/framework/Magento/Sniffs/Annotation/MethodArgumentsSniff.php new file mode 100644 index 0000000000000..879334d8c553b --- /dev/null +++ b/dev/tests/static/framework/Magento/Sniffs/Annotation/MethodArgumentsSniff.php @@ -0,0 +1,587 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ + +declare(strict_types=1); + +namespace Magento\Sniffs\Annotation; + +use PHP_CodeSniffer\Sniffs\Sniff; +use PHP_CodeSniffer\Files\File; + +/** + * Sniff to validate method arguments annotations + */ +class MethodArgumentsSniff implements Sniff +{ + /** + * @var array + */ + private $validTokensBeforeClosingCommentTag = [ + 'T_WHITESPACE', + 'T_PUBLIC', + 'T_PRIVATE', + 'T_PROTECTED', + 'T_STATIC', + 'T_ABSTRACT', + 'T_FINAL' + ]; + + /** + * @var array + */ + private $invalidTypes = [ + 'null', + 'false', + 'true', + 'self' + ]; + + /** + * @inheritdoc + */ + public function register() : array + { + return [ + T_FUNCTION + ]; + } + + /** + * Validates whether valid token exists before closing comment tag + * + * @param string $type + * @return bool + */ + private function isTokenBeforeClosingCommentTagValid(string $type) : bool + { + return in_array($type, $this->validTokensBeforeClosingCommentTag); + } + + /** + * Validates whether comment block exists + * + * @param File $phpcsFile + * @param int $previousCommentClosePtr + * @param int $stackPtr + * @return bool + */ + private function validateCommentBlockExists(File $phpcsFile, int $previousCommentClosePtr, int $stackPtr) : bool + { + $tokens = $phpcsFile->getTokens(); + for ($tempPtr = $previousCommentClosePtr + 1; $tempPtr < $stackPtr; $tempPtr++) { + if (!$this->isTokenBeforeClosingCommentTagValid($tokens[$tempPtr]['type'])) { + return false; + } + } + return true; + } + + /** + * Checks whether the parameter type is invalid + * + * @param string $type + * @return bool + */ + private function isInvalidType(string $type) : bool + { + return in_array(strtolower($type), $this->invalidTypes); + } + + /** + * Get arguments from method signature + * + * @param File $phpcsFile + * @param int $openParenthesisPtr + * @param int $closedParenthesisPtr + * @return array + */ + private function getMethodArguments(File $phpcsFile, int $openParenthesisPtr, int $closedParenthesisPtr) : array + { + $tokens = $phpcsFile->getTokens(); + $methodArguments = []; + for ($i = $openParenthesisPtr; $i < $closedParenthesisPtr; $i++) { + $argumentsPtr = $phpcsFile->findNext(T_VARIABLE, $i + 1, $closedParenthesisPtr); + if ($argumentsPtr === false) { + break; + } elseif ($argumentsPtr < $closedParenthesisPtr) { + $arguments = $tokens[$argumentsPtr]['content']; + $methodArguments[] = $arguments; + $i = $argumentsPtr - 1; + } + } + return $methodArguments; + } + + /** + * Get parameters from method annotation + * + * @param array $paramDefinitions + * @return array + */ + private function getMethodParameters(array $paramDefinitions) : array + { + $paramName = []; + for ($i = 0; $i < count($paramDefinitions); $i++) { + if (isset($paramDefinitions[$i]['paramName'])) { + $paramName[] = $paramDefinitions[$i]['paramName']; + } + } + return $paramName; + } + + /** + * Validates whether @inheritdoc without braces [@inheritdoc] exists or not + * + * @param File $phpcsFile + * @param int $previousCommentOpenPtr + * @param int $previousCommentClosePtr + */ + private function validateInheritdocAnnotationWithoutBracesExists( + File $phpcsFile, + int $previousCommentOpenPtr, + int $previousCommentClosePtr + ) : bool { + return $this->validateInheritdocAnnotationExists( + $phpcsFile, + $previousCommentOpenPtr, + $previousCommentClosePtr, + '@inheritdoc' + ); + } + + /** + * Validates whether @inheritdoc with braces [{@inheritdoc}] exists or not + * + * @param File $phpcsFile + * @param int $previousCommentOpenPtr + * @param int $previousCommentClosePtr + */ + private function validateInheritdocAnnotationWithBracesExists( + File $phpcsFile, + int $previousCommentOpenPtr, + int $previousCommentClosePtr + ) : bool { + return $this->validateInheritdocAnnotationExists( + $phpcsFile, + $previousCommentOpenPtr, + $previousCommentClosePtr, + '{@inheritdoc}' + ); + } + + /** + * Validates inheritdoc annotation exists + * + * @param File $phpcsFile + * @param int $previousCommentOpenPtr + * @param int $previousCommentClosePtr + * @param string $inheritdocAnnotation + * @return bool + */ + private function validateInheritdocAnnotationExists( + File $phpcsFile, + int $previousCommentOpenPtr, + int $previousCommentClosePtr, + string $inheritdocAnnotation + ) : bool { + $tokens = $phpcsFile->getTokens(); + for ($ptr = $previousCommentOpenPtr; $ptr < $previousCommentClosePtr; $ptr++) { + if (strtolower($tokens[$ptr]['content']) === $inheritdocAnnotation) { + return true; + } + } + return false; + } + + /** + * Validates if annotation exists for parameter in method annotation + * + * @param File $phpcsFile + * @param int $argumentsCount + * @param int $parametersCount + * @param int $previousCommentOpenPtr + * @param int $previousCommentClosePtr + * @param int $stackPtr + */ + private function validateParameterAnnotationForArgumentExists( + File $phpcsFile, + int $argumentsCount, + int $parametersCount, + int $previousCommentOpenPtr, + int $previousCommentClosePtr, + int $stackPtr + ) : void { + if ($argumentsCount > 0 && $parametersCount === 0) { + $inheritdocAnnotationWithoutBracesExists = $this->validateInheritdocAnnotationWithoutBracesExists( + $phpcsFile, + $previousCommentOpenPtr, + $previousCommentClosePtr + ); + $inheritdocAnnotationWithBracesExists = $this->validateInheritdocAnnotationWithBracesExists( + $phpcsFile, + $previousCommentOpenPtr, + $previousCommentClosePtr + ); + if ($inheritdocAnnotationWithBracesExists) { + $phpcsFile->addFixableError( + '{@inheritdoc} does not import parameter annotation', + $stackPtr, + 'MethodArguments' + ); + } elseif ($this->validateCommentBlockExists($phpcsFile, $previousCommentClosePtr, $stackPtr) + && !$inheritdocAnnotationWithoutBracesExists + ) { + $phpcsFile->addFixableError( + 'Missing @param for argument in method annotation', + $stackPtr, + 'MethodArguments' + ); + } + } + } + + /** + * Validates whether comment block have extra the parameters listed in method annotation + * + * @param File $phpcsFile + * @param int $argumentsCount + * @param int $parametersCount + * @param int $stackPtr + */ + private function validateCommentBlockDoesnotHaveExtraParameterAnnotation( + File $phpcsFile, + int $argumentsCount, + int $parametersCount, + int $stackPtr + ) : void { + if ($argumentsCount < $parametersCount && $argumentsCount > 0) { + $phpcsFile->addFixableError( + 'Extra @param found in method annotation', + $stackPtr, + 'MethodArguments' + ); + } elseif ($argumentsCount > 0 && $argumentsCount != $parametersCount && $parametersCount != 0) { + $phpcsFile->addFixableError( + '@param is not found for one or more params in method annotation', + $stackPtr, + 'MethodArguments' + ); + } + } + + /** + * Validates whether the argument name exists in method parameter annotation + * + * @param int $stackPtr + * @param int $ptr + * @param File $phpcsFile + * @param array $methodArguments + * @param array $paramDefinitions + */ + private function validateArgumentNameInParameterAnnotationExists( + int $stackPtr, + int $ptr, + File $phpcsFile, + array $methodArguments, + array $paramDefinitions + ) : void { + $parameterNames = $this->getMethodParameters($paramDefinitions); + if (!in_array($methodArguments[$ptr], $parameterNames)) { + $error = $methodArguments[$ptr]. ' parameter is missing in method annotation'; + $phpcsFile->addFixableError($error, $stackPtr, 'MethodArguments'); + } + } + + /** + * Validates whether parameter present in method signature + * + * @param int $ptr + * @param int $paramDefinitionsArguments + * @param array $methodArguments + * @param File $phpcsFile + * @param array $paramPointers + */ + private function validateParameterPresentInMethodSignature( + int $ptr, + string $paramDefinitionsArguments, + array $methodArguments, + File $phpcsFile, + array $paramPointers + ) : void { + if (!in_array($paramDefinitionsArguments, $methodArguments)) { + $phpcsFile->addFixableError( + $paramDefinitionsArguments . ' parameter is missing in method arguments signature', + $paramPointers[$ptr], + 'MethodArguments' + ); + } + } + + /** + * Validates whether the parameters are in order or not in method annotation + * + * @param array $paramDefinitions + * @param array $methodArguments + * @param File $phpcsFile + * @param array $paramPointers + */ + private function validateParameterOrderIsCorrect( + array $paramDefinitions, + array $methodArguments, + File $phpcsFile, + array $paramPointers + ) : void { + $parameterNames = $this->getMethodParameters($paramDefinitions); + $paramDefinitionsCount = count($paramDefinitions); + for ($ptr = 0; $ptr < $paramDefinitionsCount; $ptr++) { + if (isset($methodArguments[$ptr]) && isset($parameterNames[$ptr]) + && in_array($methodArguments[$ptr], $parameterNames) + ) { + if ($methodArguments[$ptr] != $parameterNames[$ptr]) { + $phpcsFile->addFixableError( + $methodArguments[$ptr].' parameter is not in order', + $paramPointers[$ptr], + 'MethodArguments' + ); + } + } + } + } + + /** + * Validate whether duplicate annotation present in method annotation + * + * @param int $stackPtr + * @param array $paramDefinitions + * @param array $paramPointers + * @param File $phpcsFile + * @param array $methodArguments + */ + private function validateDuplicateAnnotationDoesnotExists( + int $stackPtr, + array $paramDefinitions, + array $paramPointers, + File $phpcsFile, + array $methodArguments + ) : void { + $argumentsCount = count($methodArguments); + $parametersCount = count($paramPointers); + if ($argumentsCount <= $parametersCount && $argumentsCount > 0) { + $duplicateParameters = []; + for ($i = 0; $i < sizeof($paramDefinitions); $i++) { + if (isset($paramDefinitions[$i]['paramName'])) { + $parameterContent = $paramDefinitions[$i]['paramName']; + for ($j = $i + 1; $j < count($paramDefinitions); $j++) { + if (isset($paramDefinitions[$j]['paramName']) + && $parameterContent === $paramDefinitions[$j]['paramName'] + ) { + $duplicateParameters[] = $parameterContent; + } + } + } + } + foreach ($duplicateParameters as $value) { + $phpcsFile->addFixableError( + $value . ' duplicate found in method annotation', + $stackPtr, + 'MethodArguments' + ); + } + } + } + + /** + * Validate parameter annotation format is correct or not + * + * @param int $ptr + * @param File $phpcsFile + * @param array $methodArguments + * @param array $paramDefinitions + * @param array $paramPointers + */ + private function validateParameterAnnotationFormatIsCorrect( + int $ptr, + File $phpcsFile, + array $methodArguments, + array $paramDefinitions, + array $paramPointers + ) : void { + switch (count($paramDefinitions)) { + case 0: + $phpcsFile->addFixableError( + 'Missing both type and parameter', + $paramPointers[$ptr], + 'MethodArguments' + ); + break; + case 1: + if (preg_match('/^\$.*/', $paramDefinitions[0])) { + $phpcsFile->addError( + 'Type is not specified', + $paramPointers[$ptr], + 'MethodArguments' + ); + } + break; + case 2: + if ($this->isInvalidType($paramDefinitions[0])) { + $phpcsFile->addFixableError( + $paramDefinitions[0].' is not a valid PHP type', + $paramPointers[$ptr], + 'MethodArguments' + ); + } + $this->validateParameterPresentInMethodSignature( + $ptr, + ltrim($paramDefinitions[1], '&'), + $methodArguments, + $phpcsFile, + $paramPointers + ); + break; + default: + if (preg_match('/^\$.*/', $paramDefinitions[0])) { + $phpcsFile->addError( + 'Type is not specified', + $paramPointers[$ptr], + 'MethodArguments' + ); + if ($this->isInvalidType($paramDefinitions[0])) { + $phpcsFile->addFixableError( + $paramDefinitions[0].' is not a valid PHP type', + $paramPointers[$ptr], + 'MethodArguments' + ); + } + } + break; + } + } + + /** + * Validate method parameter annotations + * + * @param int $stackPtr + * @param array $paramDefinitions + * @param array $paramPointers + * @param File $phpcsFile + * @param array $methodArguments + * @param int $previousCommentOpenPtr + * @param int $previousCommentClosePtr + */ + private function validateMethodParameterAnnotations( + int $stackPtr, + array $paramDefinitions, + array $paramPointers, + File $phpcsFile, + array $methodArguments, + int $previousCommentOpenPtr, + int $previousCommentClosePtr + ) : void { + $argumentCount = count($methodArguments); + $paramCount = count($paramPointers); + $this->validateParameterAnnotationForArgumentExists( + $phpcsFile, + $argumentCount, + $paramCount, + $previousCommentOpenPtr, + $previousCommentClosePtr, + $stackPtr + ); + $this->validateCommentBlockDoesnotHaveExtraParameterAnnotation( + $phpcsFile, + $argumentCount, + $paramCount, + $stackPtr + ); + $this->validateDuplicateAnnotationDoesnotExists( + $stackPtr, + $paramDefinitions, + $paramPointers, + $phpcsFile, + $methodArguments + ); + $this->validateParameterOrderIsCorrect( + $paramDefinitions, + $methodArguments, + $phpcsFile, + $paramPointers + ); + for ($ptr = 0; $ptr < count($methodArguments); $ptr++) { + $tokens = $phpcsFile->getTokens(); + if (isset($paramPointers[$ptr])) { + $this->validateArgumentNameInParameterAnnotationExists( + $stackPtr, + $ptr, + $phpcsFile, + $methodArguments, + $paramDefinitions + ); + $paramContent = $tokens[$paramPointers[$ptr]+2]['content']; + $paramContentExplode = explode(' ', $paramContent); + $this->validateParameterAnnotationFormatIsCorrect( + $ptr, + $phpcsFile, + $methodArguments, + $paramContentExplode, + $paramPointers + ); + } + } + } + + /** + * @inheritdoc + */ + public function process(File $phpcsFile, $stackPtr) + { + $tokens = $phpcsFile->getTokens(); + $numTokens = count($tokens); + $previousCommentOpenPtr = $phpcsFile->findPrevious(T_DOC_COMMENT_OPEN_TAG, $stackPtr-1, 0); + $previousCommentClosePtr = $phpcsFile->findPrevious(T_DOC_COMMENT_CLOSE_TAG, $stackPtr-1, 0); + if (!$this->validateCommentBlockExists($phpcsFile, $previousCommentClosePtr, $stackPtr)) { + $phpcsFile->addError('Comment block is missing', $stackPtr, 'MethodArguments'); + return; + } + $openParenthesisPtr = $phpcsFile->findNext(T_OPEN_PARENTHESIS, $stackPtr+1, $numTokens); + $closedParenthesisPtr = $phpcsFile->findNext(T_CLOSE_PARENTHESIS, $stackPtr+1, $numTokens); + $methodArguments = $this->getMethodArguments($phpcsFile, $openParenthesisPtr, $closedParenthesisPtr); + $paramPointers = $paramDefinitions = []; + for ($tempPtr = $previousCommentOpenPtr; $tempPtr < $previousCommentClosePtr; $tempPtr++) { + if (strtolower($tokens[$tempPtr]['content']) === '@param') { + $paramPointers[] = $tempPtr; + $paramAnnotationParts = explode(' ', $tokens[$tempPtr+2]['content']); + if (count($paramAnnotationParts) === 1) { + if ((preg_match('/^\$.*/', $paramAnnotationParts[0]))) { + $paramDefinitions[] = [ + 'type' => null, + 'paramName' => rtrim(ltrim($tokens[$tempPtr+2]['content'], '&'), ',') + ]; + } else { + $paramDefinitions[] = [ + 'type' => $tokens[$tempPtr+2]['content'], + 'paramName' => null + ]; + } + } else { + $paramDefinitions[] = [ + 'type' => $paramAnnotationParts[0], + 'paramName' => rtrim(ltrim($paramAnnotationParts[1], '&'), ',') + ]; + } + } + } + $this->validateMethodParameterAnnotations( + $stackPtr, + $paramDefinitions, + $paramPointers, + $phpcsFile, + $methodArguments, + $previousCommentOpenPtr, + $previousCommentClosePtr + ); + } +} diff --git a/dev/tests/static/framework/Magento/ruleset.xml b/dev/tests/static/framework/Magento/ruleset.xml index 14d05b466b407..f3e4893ba752f 100644 --- a/dev/tests/static/framework/Magento/ruleset.xml +++ b/dev/tests/static/framework/Magento/ruleset.xml @@ -22,6 +22,10 @@ <rule ref="Magento.LiteralNamespaces.LiteralNamespaces"> <exclude-pattern>*/_files/*</exclude-pattern> </rule> + <rule ref="Magento.Annotation.MethodArguments"> + <!--Disabled due to MAGETWO-94083--> + <exclude-pattern>*</exclude-pattern> + </rule> <rule ref="Magento.Functions.OutputBuffering"> <include-pattern>*/(app/code|vendor|setup/src|lib/internal/Magento)/*</include-pattern> <exclude-pattern>*/lib/internal/Magento/Framework/Image/Adapter/Gd2.php</exclude-pattern> diff --git a/dev/tests/static/phpunit-all.xml.dist b/dev/tests/static/phpunit-all.xml.dist index a0d1f2fe75dc9..3020889e6066b 100644 --- a/dev/tests/static/phpunit-all.xml.dist +++ b/dev/tests/static/phpunit-all.xml.dist @@ -21,6 +21,6 @@ <php> <ini name="date.timezone" value="America/Los_Angeles"/> <!-- TESTCODESTYLE_IS_FULL_SCAN - specify if full scan should be performed for test code style test --> - <const name="TESTCODESTYLE_IS_FULL_SCAN" value="1"/> + <const name="TESTCODESTYLE_IS_FULL_SCAN" value="0"/> </php> </phpunit> diff --git a/dev/tests/static/phpunit.xml.dist b/dev/tests/static/phpunit.xml.dist index d9f9dbdfe54cd..ec581ec992f00 100644 --- a/dev/tests/static/phpunit.xml.dist +++ b/dev/tests/static/phpunit.xml.dist @@ -31,7 +31,7 @@ <php> <ini name="date.timezone" value="America/Los_Angeles"/> <!-- TESTCODESTYLE_IS_FULL_SCAN - specify if full scan should be performed for test code style test --> - <const name="TESTCODESTYLE_IS_FULL_SCAN" value="1"/> + <const name="TESTCODESTYLE_IS_FULL_SCAN" value="0"/> <!-- TESTS_COMPOSER_PATH - specify the path to composer binary, if a relative reference cannot be resolved --> <!--<const name="TESTS_COMPOSER_PATH" value="/usr/local/bin/composer"/>--> </php> diff --git a/dev/tests/static/testsuite/Magento/Test/Integrity/Magento/Backend/ControllerAclTest.php b/dev/tests/static/testsuite/Magento/Test/Integrity/Magento/Backend/ControllerAclTest.php index 187cb9087013e..f204019988b79 100644 --- a/dev/tests/static/testsuite/Magento/Test/Integrity/Magento/Backend/ControllerAclTest.php +++ b/dev/tests/static/testsuite/Magento/Test/Integrity/Magento/Backend/ControllerAclTest.php @@ -232,7 +232,7 @@ private function isItTest($relativeFilePath) */ private function getControllerPath($relativeFilePath) { - if (preg_match('~(Magento\/.*Controller\/Adminhtml\/.*)\.php~', $relativeFilePath, $matches)) { + if (preg_match('~(Magento\/[^\/]+\/Controller\/Adminhtml\/.*)\.php~', $relativeFilePath, $matches)) { if (count($matches) === 2) { $partPath = $matches[1]; return $partPath; diff --git a/dev/tests/static/testsuite/Magento/Test/Php/LiveCodeTest.php b/dev/tests/static/testsuite/Magento/Test/Php/LiveCodeTest.php index fa62179ed34f5..21ca0a495dd19 100644 --- a/dev/tests/static/testsuite/Magento/Test/Php/LiveCodeTest.php +++ b/dev/tests/static/testsuite/Magento/Test/Php/LiveCodeTest.php @@ -256,10 +256,16 @@ private function getFullWhitelist() } } + /** + * Test code quality using phpcs + */ public function testCodeStyle() { $isFullScan = defined('TESTCODESTYLE_IS_FULL_SCAN') && TESTCODESTYLE_IS_FULL_SCAN === '1'; $reportFile = self::$reportDir . '/phpcs_report.txt'; + if (!file_exists($reportFile)) { + touch($reportFile); + } $codeSniffer = new CodeSniffer('Magento', $reportFile, new Wrapper()); $result = $codeSniffer->run($isFullScan ? $this->getFullWhitelist() : self::getWhitelist(['php', 'phtml'])); $report = file_get_contents($reportFile); @@ -270,6 +276,9 @@ public function testCodeStyle() ); } + /** + * Test code quality using phpmd + */ public function testCodeMess() { $reportFile = self::$reportDir . '/phpmd_report.txt'; @@ -298,6 +307,9 @@ public function testCodeMess() } } + /** + * Test code quality using phpcpd + */ public function testCopyPaste() { $reportFile = self::$reportDir . '/phpcpd_report.xml'; diff --git a/dev/tools/grunt/configs/autoprefixer.json b/dev/tools/grunt/configs/autoprefixer.json index 78283d030919f..28cd9c8a1255f 100644 --- a/dev/tools/grunt/configs/autoprefixer.json +++ b/dev/tools/grunt/configs/autoprefixer.json @@ -2,7 +2,7 @@ "options": { "browsers": [ "last 2 versions", - "ie 9" + "ie 11" ] }, "setup": { diff --git a/dev/travis/before_script.sh b/dev/travis/before_script.sh index f2ba20dc412b6..1dccc310c7a20 100755 --- a/dev/travis/before_script.sh +++ b/dev/travis/before_script.sh @@ -129,6 +129,7 @@ case $TEST_SUITE in sed -e "s?basic?travis_acceptance?g" --in-place ./phpunit.xml cp ./.htaccess.sample ./.htaccess cd ./utils + php -f generate/moduleSequence.php php -f mtf troubleshooting:check-all cd ../../.. diff --git a/lib/internal/Magento/Framework/Api/AbstractExtensibleObject.php b/lib/internal/Magento/Framework/Api/AbstractExtensibleObject.php index 7b2b94cbd0973..97c24167d47e1 100644 --- a/lib/internal/Magento/Framework/Api/AbstractExtensibleObject.php +++ b/lib/internal/Magento/Framework/Api/AbstractExtensibleObject.php @@ -76,7 +76,7 @@ public function getCustomAttribute($attributeCode) */ public function getCustomAttributes() { - return isset($this->_data[self::CUSTOM_ATTRIBUTES]) ? $this->_data[self::CUSTOM_ATTRIBUTES] : []; + return $this->_data[self::CUSTOM_ATTRIBUTES] ?? []; } /** @@ -131,7 +131,7 @@ public function setCustomAttribute($attributeCode, $attributeValue) */ protected function getCustomAttributesCodes() { - return isset($this->customAttributesCodes) ? $this->customAttributesCodes : []; + return $this->customAttributesCodes ?? []; } /** diff --git a/lib/internal/Magento/Framework/Api/AbstractSimpleObject.php b/lib/internal/Magento/Framework/Api/AbstractSimpleObject.php index b907246139d42..9cc0ddab3bfcb 100644 --- a/lib/internal/Magento/Framework/Api/AbstractSimpleObject.php +++ b/lib/internal/Magento/Framework/Api/AbstractSimpleObject.php @@ -34,7 +34,7 @@ public function __construct(array $data = []) */ protected function _get($key) { - return isset($this->_data[$key]) ? $this->_data[$key] : null; + return $this->_data[$key] ?? null; } /** diff --git a/lib/internal/Magento/Framework/Api/CombinedFilterGroup.php b/lib/internal/Magento/Framework/Api/CombinedFilterGroup.php index 21d95b72fed1c..190085ddcae00 100644 --- a/lib/internal/Magento/Framework/Api/CombinedFilterGroup.php +++ b/lib/internal/Magento/Framework/Api/CombinedFilterGroup.php @@ -7,8 +7,6 @@ namespace Magento\Framework\Api; -use Magento\Framework\Api\AbstractSimpleObject; -use Magento\Framework\DB\Select; use Magento\Framework\Exception\InputException; use Magento\Framework\Phrase; diff --git a/lib/internal/Magento/Framework/Api/ImageProcessor.php b/lib/internal/Magento/Framework/Api/ImageProcessor.php index beadb51bc7796..83390b3853212 100644 --- a/lib/internal/Magento/Framework/Api/ImageProcessor.php +++ b/lib/internal/Magento/Framework/Api/ImageProcessor.php @@ -172,7 +172,7 @@ public function processImageContent($entityType, $imageContent) */ protected function getMimeTypeExtension($mimeType) { - return isset($this->mimeTypeExtensionMap[$mimeType]) ? $this->mimeTypeExtensionMap[$mimeType] : ''; + return $this->mimeTypeExtensionMap[$mimeType] ?? ''; } /** diff --git a/lib/internal/Magento/Framework/Api/Search/Document.php b/lib/internal/Magento/Framework/Api/Search/Document.php index d60458a6e5585..7454fa7974ece 100644 --- a/lib/internal/Magento/Framework/Api/Search/Document.php +++ b/lib/internal/Magento/Framework/Api/Search/Document.php @@ -33,9 +33,7 @@ public function setId($id) */ public function getCustomAttribute($attributeCode) { - return isset($this->_data[self::CUSTOM_ATTRIBUTES][$attributeCode]) - ? $this->_data[self::CUSTOM_ATTRIBUTES][$attributeCode] - : null; + return $this->_data[self::CUSTOM_ATTRIBUTES][$attributeCode] ?? null; } /** diff --git a/lib/internal/Magento/Framework/Api/SearchCriteria/CollectionProcessor/FilterProcessor.php b/lib/internal/Magento/Framework/Api/SearchCriteria/CollectionProcessor/FilterProcessor.php index c9f10c183b50c..024a4d2af3847 100644 --- a/lib/internal/Magento/Framework/Api/SearchCriteria/CollectionProcessor/FilterProcessor.php +++ b/lib/internal/Magento/Framework/Api/SearchCriteria/CollectionProcessor/FilterProcessor.php @@ -123,6 +123,6 @@ private function getCustomFilterForField($field) */ private function getFieldMapping($field) { - return isset($this->fieldMapping[$field]) ? $this->fieldMapping[$field] : $field; + return $this->fieldMapping[$field] ?? $field; } } diff --git a/lib/internal/Magento/Framework/Api/SearchCriteria/CollectionProcessor/JoinProcessor.php b/lib/internal/Magento/Framework/Api/SearchCriteria/CollectionProcessor/JoinProcessor.php index b8e52334bee1f..207325042c737 100644 --- a/lib/internal/Magento/Framework/Api/SearchCriteria/CollectionProcessor/JoinProcessor.php +++ b/lib/internal/Magento/Framework/Api/SearchCriteria/CollectionProcessor/JoinProcessor.php @@ -121,6 +121,6 @@ private function getCustomJoin($field) */ private function getFieldMapping($field) { - return isset($this->fieldMapping[$field]) ? $this->fieldMapping[$field] : $field; + return $this->fieldMapping[$field] ?? $field; } } diff --git a/lib/internal/Magento/Framework/Api/SearchCriteria/CollectionProcessor/SortingProcessor.php b/lib/internal/Magento/Framework/Api/SearchCriteria/CollectionProcessor/SortingProcessor.php index 85a6d6f570d5e..9dda5cd682708 100644 --- a/lib/internal/Magento/Framework/Api/SearchCriteria/CollectionProcessor/SortingProcessor.php +++ b/lib/internal/Magento/Framework/Api/SearchCriteria/CollectionProcessor/SortingProcessor.php @@ -59,7 +59,7 @@ public function process(SearchCriteriaInterface $searchCriteria, AbstractDb $col */ private function getFieldMapping($field) { - return isset($this->fieldMapping[$field]) ? $this->fieldMapping[$field] : $field; + return $this->fieldMapping[$field] ?? $field; } /** diff --git a/lib/internal/Magento/Framework/App/ActionFlag.php b/lib/internal/Magento/Framework/App/ActionFlag.php index 657c2ede9262d..55201504c968f 100644 --- a/lib/internal/Magento/Framework/App/ActionFlag.php +++ b/lib/internal/Magento/Framework/App/ActionFlag.php @@ -65,9 +65,7 @@ public function get($action, $flag = '') $action = $this->_request->getActionName(); } if ('' === $flag) { - return isset( - $this->_flags[$this->_getControllerKey()] - ) ? $this->_flags[$this->_getControllerKey()] : []; + return $this->_flags[$this->_getControllerKey()] ?? []; } elseif (isset($this->_flags[$this->_getControllerKey()][$action][$flag])) { return $this->_flags[$this->_getControllerKey()][$action][$flag]; } else { diff --git a/lib/internal/Magento/Framework/App/AreaList.php b/lib/internal/Magento/Framework/App/AreaList.php index 7c123f7ff9d60..fb28d09d5fe09 100644 --- a/lib/internal/Magento/Framework/App/AreaList.php +++ b/lib/internal/Magento/Framework/App/AreaList.php @@ -88,7 +88,7 @@ public function getCodeByFrontName($frontName) */ public function getFrontName($areaCode) { - return isset($this->_areas[$areaCode]['frontName']) ? $this->_areas[$areaCode]['frontName'] : null; + return $this->_areas[$areaCode]['frontName'] ?? null; } /** @@ -111,7 +111,7 @@ public function getCodes() */ public function getDefaultRouter($areaCode) { - return isset($this->_areas[$areaCode]['router']) ? $this->_areas[$areaCode]['router'] : null; + return $this->_areas[$areaCode]['router'] ?? null; } /** diff --git a/lib/internal/Magento/Framework/App/Cache/Frontend/Factory.php b/lib/internal/Magento/Framework/App/Cache/Frontend/Factory.php index f2bc4eceb507d..f84dd304643da 100644 --- a/lib/internal/Magento/Framework/App/Cache/Frontend/Factory.php +++ b/lib/internal/Magento/Framework/App/Cache/Frontend/Factory.php @@ -10,9 +10,7 @@ namespace Magento\Framework\App\Cache\Frontend; use Magento\Framework\App\Filesystem\DirectoryList; -use Magento\Framework\App\ResourceConnection; use Magento\Framework\Filesystem; -use Magento\Framework\Filesystem\DriverInterface; /** * @SuppressWarnings(PHPMD.CouplingBetweenObjects) diff --git a/lib/internal/Magento/Framework/App/Config/Initial.php b/lib/internal/Magento/Framework/App/Config/Initial.php index 1933682346ad3..b65c9a2f53489 100644 --- a/lib/internal/Magento/Framework/App/Config/Initial.php +++ b/lib/internal/Magento/Framework/App/Config/Initial.php @@ -72,9 +72,9 @@ public function getData($scope) list($scopeType, $scopeCode) = array_pad(explode('|', $scope), 2, null); if (ScopeConfigInterface::SCOPE_TYPE_DEFAULT == $scopeType) { - return isset($this->_data[$scopeType]) ? $this->_data[$scopeType] : []; + return $this->_data[$scopeType] ?? []; } elseif ($scopeCode) { - return isset($this->_data[$scopeType][$scopeCode]) ? $this->_data[$scopeType][$scopeCode] : []; + return $this->_data[$scopeType][$scopeCode] ?? []; } return []; } diff --git a/lib/internal/Magento/Framework/App/DefaultPath/DefaultPath.php b/lib/internal/Magento/Framework/App/DefaultPath/DefaultPath.php index 61d0aa138f9a4..8a4188aed9605 100644 --- a/lib/internal/Magento/Framework/App/DefaultPath/DefaultPath.php +++ b/lib/internal/Magento/Framework/App/DefaultPath/DefaultPath.php @@ -32,6 +32,6 @@ public function __construct(array $parts) */ public function getPart($code) { - return isset($this->_parts[$code]) ? $this->_parts[$code] : null; + return $this->_parts[$code] ?? null; } } diff --git a/lib/internal/Magento/Framework/App/DeploymentConfig.php b/lib/internal/Magento/Framework/App/DeploymentConfig.php index 0fe7703ef81c0..f83f89ee4caeb 100644 --- a/lib/internal/Magento/Framework/App/DeploymentConfig.php +++ b/lib/internal/Magento/Framework/App/DeploymentConfig.php @@ -70,7 +70,7 @@ public function get($key = null, $defaultValue = null) if ($key === null) { return $this->flatData; } - return isset($this->flatData[$key]) ? $this->flatData[$key] : $defaultValue; + return $this->flatData[$key] ?? $defaultValue; } /** diff --git a/lib/internal/Magento/Framework/App/Http/Context.php b/lib/internal/Magento/Framework/App/Http/Context.php index a5eba2753b510..79a15110234cd 100644 --- a/lib/internal/Magento/Framework/App/Http/Context.php +++ b/lib/internal/Magento/Framework/App/Http/Context.php @@ -84,9 +84,7 @@ public function unsValue($name) */ public function getValue($name) { - return isset($this->data[$name]) - ? $this->data[$name] - : (isset($this->default[$name]) ? $this->default[$name] : null); + return $this->data[$name] ?? ($this->default[$name] ?? null); } /** diff --git a/lib/internal/Magento/Framework/App/HttpRequestInterface.php b/lib/internal/Magento/Framework/App/HttpRequestInterface.php new file mode 100644 index 0000000000000..674ccdb07f49f --- /dev/null +++ b/lib/internal/Magento/Framework/App/HttpRequestInterface.php @@ -0,0 +1,53 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +declare(strict_types=1); + +namespace Magento\Framework\App; + +interface HttpRequestInterface +{ + /** + * Returned true if POST request + * + * @return boolean + */ + public function isPost(); + + /** + * Returned true if GET request + * + * @return boolean + */ + public function isGet(); + + /** + * Returned true if PATCH request + * + * @return boolean + */ + public function isPatch(); + + /** + * Returned true if DELETE request + * + * @return boolean + */ + public function isDelete(); + + /** + * Returned true if PUT request + * + * @return boolean + */ + public function isPut(); + + /** + * Returned true if Ajax request + * + * @return boolean + */ + public function isAjax(); +} diff --git a/lib/internal/Magento/Framework/App/Request/Http.php b/lib/internal/Magento/Framework/App/Request/Http.php index 4421903f40c2e..03a7200fbe203 100644 --- a/lib/internal/Magento/Framework/App/Request/Http.php +++ b/lib/internal/Magento/Framework/App/Request/Http.php @@ -5,6 +5,7 @@ */ namespace Magento\Framework\App\Request; +use Magento\Framework\App\HttpRequestInterface; use Magento\Framework\App\RequestContentInterface; use Magento\Framework\App\RequestSafetyInterface; use Magento\Framework\App\Route\ConfigInterface\Proxy as ConfigInterface; @@ -16,7 +17,7 @@ /** * Http request */ -class Http extends Request implements RequestContentInterface, RequestSafetyInterface +class Http extends Request implements RequestContentInterface, RequestSafetyInterface, HttpRequestInterface { /**#@+ * HTTP Ports @@ -99,7 +100,7 @@ class Http extends Request implements RequestContentInterface, RequestSafetyInte * @param StringUtils $converter * @param ConfigInterface $routeConfig * @param PathInfoProcessorInterface $pathInfoProcessor - * @param ObjectManagerInterface $objectManager + * @param ObjectManagerInterface $objectManager * @param \Zend\Uri\UriInterface|string|null $uri * @param array $directFrontNames */ diff --git a/lib/internal/Magento/Framework/App/Response/Http/FileFactory.php b/lib/internal/Magento/Framework/App/Response/Http/FileFactory.php index 979ea1c429590..19a89681a2d5f 100644 --- a/lib/internal/Magento/Framework/App/Response/Http/FileFactory.php +++ b/lib/internal/Magento/Framework/App/Response/Http/FileFactory.php @@ -59,6 +59,7 @@ public function create( $dir = $this->_filesystem->getDirectoryWrite($baseDir); $isFile = false; $file = null; + $fileContent = $this->getFileContent($content); if (is_array($content)) { if (!isset($content['type']) || !isset($content['value'])) { throw new \InvalidArgumentException("Invalid arguments. Keys 'type' and 'value' are required."); @@ -76,7 +77,7 @@ public function create( ->setHeader('Pragma', 'public', true) ->setHeader('Cache-Control', 'must-revalidate, post-check=0, pre-check=0', true) ->setHeader('Content-type', $contentType, true) - ->setHeader('Content-Length', $contentLength === null ? strlen($content) : $contentLength, true) + ->setHeader('Content-Length', $contentLength === null ? strlen($fileContent) : $contentLength, true) ->setHeader('Content-Disposition', 'attachment; filename="' . $fileName . '"', true) ->setHeader('Last-Modified', date('r'), true); @@ -88,7 +89,8 @@ public function create( echo $stream->read(1024); } } else { - $dir->writeFile($fileName, $content); + $dir->writeFile($fileName, $fileContent); + $file = $fileName; $stream = $dir->openFile($fileName, 'r'); while (!$stream->eof()) { echo $stream->read(1024); @@ -102,4 +104,19 @@ public function create( } return $this->_response; } + + /** + * Returns file content for writing. + * + * @param string|array $content + * @return string|array + */ + private function getFileContent($content) + { + if (isset($content['type']) && $content['type'] === 'string') { + return $content['value']; + } + + return $content; + } } diff --git a/lib/internal/Magento/Framework/Archive/Tar.php b/lib/internal/Magento/Framework/Archive/Tar.php index e2a070503f61f..7fe1255e5b859 100644 --- a/lib/internal/Magento/Framework/Archive/Tar.php +++ b/lib/internal/Magento/Framework/Archive/Tar.php @@ -12,7 +12,6 @@ namespace Magento\Framework\Archive; use Magento\Framework\Archive\Helper\File; -use Magento\Framework\Filesystem\DriverInterface; class Tar extends \Magento\Framework\Archive\AbstractArchive implements \Magento\Framework\Archive\ArchiveInterface { diff --git a/lib/internal/Magento/Framework/Component/ComponentRegistrar.php b/lib/internal/Magento/Framework/Component/ComponentRegistrar.php index 0e85cf5260e9b..0a54d770300e8 100644 --- a/lib/internal/Magento/Framework/Component/ComponentRegistrar.php +++ b/lib/internal/Magento/Framework/Component/ComponentRegistrar.php @@ -70,7 +70,7 @@ public function getPaths($type) public function getPath($type, $componentName) { self::validateType($type); - return isset(self::$paths[$type][$componentName]) ? self::$paths[$type][$componentName] : null; + return self::$paths[$type][$componentName] ?? null; } /** diff --git a/lib/internal/Magento/Framework/Composer/Test/Unit/ComposerInformationTest.php b/lib/internal/Magento/Framework/Composer/Test/Unit/ComposerInformationTest.php index 27a222e6bceb9..bf67f73009a08 100644 --- a/lib/internal/Magento/Framework/Composer/Test/Unit/ComposerInformationTest.php +++ b/lib/internal/Magento/Framework/Composer/Test/Unit/ComposerInformationTest.php @@ -7,7 +7,6 @@ use Composer\Composer; use Composer\Package\Locker; -use Magento\Framework\Composer\ComposerInformation; use Magento\Framework\TestFramework\Unit\Helper\ObjectManager; class ComposerInformationTest extends \PHPUnit\Framework\TestCase diff --git a/lib/internal/Magento/Framework/Config/View.php b/lib/internal/Magento/Framework/Config/View.php index ef9c39e221e86..05863caeec2b6 100644 --- a/lib/internal/Magento/Framework/Config/View.php +++ b/lib/internal/Magento/Framework/Config/View.php @@ -71,7 +71,7 @@ public function __construct( public function getVars($module) { $this->initData(); - return isset($this->data['vars'][$module]) ? $this->data['vars'][$module] : []; + return $this->data['vars'][$module] ?? []; } /** @@ -110,7 +110,7 @@ public function getVarValue($module, $var) public function getMediaEntities($module, $mediaType) { $this->initData(); - return isset($this->data['media'][$module][$mediaType]) ? $this->data['media'][$module][$mediaType] : []; + return $this->data['media'][$module][$mediaType] ?? []; } /** @@ -124,9 +124,7 @@ public function getMediaEntities($module, $mediaType) public function getMediaAttributes($module, $mediaType, $mediaId) { $this->initData(); - return isset($this->data['media'][$module][$mediaType][$mediaId]) - ? $this->data['media'][$module][$mediaType][$mediaId] - : []; + return $this->data['media'][$module][$mediaType][$mediaId] ?? []; } /** @@ -163,7 +161,7 @@ protected function getIdAttributes() public function getExcludedFiles() { $items = $this->getItems(); - return isset($items['file']) ? $items['file'] : []; + return $items['file'] ?? []; } /** @@ -174,7 +172,7 @@ public function getExcludedFiles() public function getExcludedDir() { $items = $this->getItems(); - return isset($items['directory']) ? $items['directory'] : []; + return $items['directory'] ?? []; } /** @@ -185,7 +183,7 @@ public function getExcludedDir() protected function getItems() { $this->initData(); - return isset($this->data['exclude']) ? $this->data['exclude'] : []; + return $this->data['exclude'] ?? []; } /** diff --git a/lib/internal/Magento/Framework/Console/Test/Unit/QuestionPerformer/YesNoTest.php b/lib/internal/Magento/Framework/Console/Test/Unit/QuestionPerformer/YesNoTest.php index d8552f2ba5f31..4a951aa2987a8 100644 --- a/lib/internal/Magento/Framework/Console/Test/Unit/QuestionPerformer/YesNoTest.php +++ b/lib/internal/Magento/Framework/Console/Test/Unit/QuestionPerformer/YesNoTest.php @@ -11,8 +11,6 @@ use Symfony\Component\Console\Output\OutputInterface; use Symfony\Component\Console\Question\QuestionFactory; use Symfony\Component\Console\Question\Question; -use Magento\Framework\Exception\LocalizedException; -use Magento\Framework\Phrase; class YesNoTest extends \PHPUnit\Framework\TestCase { diff --git a/lib/internal/Magento/Framework/DB/AbstractMapper.php b/lib/internal/Magento/Framework/DB/AbstractMapper.php index bce53caef8a39..9d043d6de7fbc 100644 --- a/lib/internal/Magento/Framework/DB/AbstractMapper.php +++ b/lib/internal/Magento/Framework/DB/AbstractMapper.php @@ -10,7 +10,6 @@ use Magento\Framework\Data\ObjectFactory; use Magento\Framework\DB\Adapter\AdapterInterface; use Psr\Log\LoggerInterface as Logger; -use Magento\Framework\DataObject; /** * Class AbstractMapper diff --git a/lib/internal/Magento/Framework/DB/Adapter/Pdo/Mysql.php b/lib/internal/Magento/Framework/DB/Adapter/Pdo/Mysql.php index e02c48222ebd4..441da10253a14 100644 --- a/lib/internal/Magento/Framework/DB/Adapter/Pdo/Mysql.php +++ b/lib/internal/Magento/Framework/DB/Adapter/Pdo/Mysql.php @@ -490,7 +490,7 @@ public function rawFetchRow($sql, $field = null) if (empty($field)) { return $row; } else { - return isset($row[$field]) ? $row[$field] : false; + return $row[$field] ?? false; } } diff --git a/lib/internal/Magento/Framework/DB/Select/GroupRenderer.php b/lib/internal/Magento/Framework/DB/Select/GroupRenderer.php index df046c92203c2..692843aaa37e3 100644 --- a/lib/internal/Magento/Framework/DB/Select/GroupRenderer.php +++ b/lib/internal/Magento/Framework/DB/Select/GroupRenderer.php @@ -6,7 +6,6 @@ namespace Magento\Framework\DB\Select; use Magento\Framework\DB\Select; -use Magento\Framework\DB\Platform; use Magento\Framework\DB\Platform\Quote; /** diff --git a/lib/internal/Magento/Framework/DB/SelectFactory.php b/lib/internal/Magento/Framework/DB/SelectFactory.php index bdbc35b395af7..3c64e78839c4d 100644 --- a/lib/internal/Magento/Framework/DB/SelectFactory.php +++ b/lib/internal/Magento/Framework/DB/SelectFactory.php @@ -6,7 +6,6 @@ namespace Magento\Framework\DB; -use Magento\Framework\DB\Select; use Magento\Framework\DB\Select\SelectRenderer; use Magento\Framework\DB\Adapter\AdapterInterface; diff --git a/lib/internal/Magento/Framework/DB/TemporaryTableService.php b/lib/internal/Magento/Framework/DB/TemporaryTableService.php index 03c1a9b9aa7f6..881ebbe5c85ad 100644 --- a/lib/internal/Magento/Framework/DB/TemporaryTableService.php +++ b/lib/internal/Magento/Framework/DB/TemporaryTableService.php @@ -6,7 +6,6 @@ namespace Magento\Framework\DB; use Magento\Framework\DB\Adapter\AdapterInterface; -use Magento\Framework\DB\Select; /** * Class TemporaryTableService creates a temporary table in mysql from a Magento\Framework\DB\Select. diff --git a/lib/internal/Magento/Framework/DB/Test/Unit/SelectTest.php b/lib/internal/Magento/Framework/DB/Test/Unit/SelectTest.php index 7ce0ba4e4eb45..2be211a6c3da0 100644 --- a/lib/internal/Magento/Framework/DB/Test/Unit/SelectTest.php +++ b/lib/internal/Magento/Framework/DB/Test/Unit/SelectTest.php @@ -7,8 +7,6 @@ use \Magento\Framework\DB\Select; -use Magento\Framework\TestFramework\Unit\Helper\ObjectManager; - /** * Class SelectTest * @SuppressWarnings(PHPMD.CouplingBetweenObjects) diff --git a/lib/internal/Magento/Framework/Data/AbstractCriteria.php b/lib/internal/Magento/Framework/Data/AbstractCriteria.php index c90ed2b03bf3d..d4811b79980a9 100644 --- a/lib/internal/Magento/Framework/Data/AbstractCriteria.php +++ b/lib/internal/Magento/Framework/Data/AbstractCriteria.php @@ -274,7 +274,7 @@ public function getLimit() */ public function getPart($name, $default = null) { - return isset($this->data[$name]) ? $this->data[$name] : $default; + return $this->data[$name] ?? $default; } /** diff --git a/lib/internal/Magento/Framework/Data/AbstractDataObject.php b/lib/internal/Magento/Framework/Data/AbstractDataObject.php index 5916100ffbbfa..da04fecc447cc 100644 --- a/lib/internal/Magento/Framework/Data/AbstractDataObject.php +++ b/lib/internal/Magento/Framework/Data/AbstractDataObject.php @@ -50,6 +50,6 @@ public function toArray() */ protected function get($key) { - return isset($this->data[$key]) ? $this->data[$key] : null; + return $this->data[$key] ?? null; } } diff --git a/lib/internal/Magento/Framework/Data/Collection.php b/lib/internal/Magento/Framework/Data/Collection.php index f8b82d3122234..71ec8c1aa8379 100644 --- a/lib/internal/Magento/Framework/Data/Collection.php +++ b/lib/internal/Magento/Framework/Data/Collection.php @@ -851,7 +851,7 @@ public function count() */ public function getFlag($flag) { - return isset($this->_flags[$flag]) ? $this->_flags[$flag] : null; + return $this->_flags[$flag] ?? null; } /** diff --git a/lib/internal/Magento/Framework/Data/Form/Element/Checkboxes.php b/lib/internal/Magento/Framework/Data/Form/Element/Checkboxes.php index 76bc4fce5f95c..3048be4d5dc1b 100644 --- a/lib/internal/Magento/Framework/Data/Form/Element/Checkboxes.php +++ b/lib/internal/Magento/Framework/Data/Form/Element/Checkboxes.php @@ -178,14 +178,6 @@ public function getOnchange($value) return; } - // public function getName($value) - // { - // if ($name = $this->getData('name')) { - // return str_replace('$value', $value, $name); - // } - // return ; - // } - /** * @param array $option * @return string diff --git a/lib/internal/Magento/Framework/Data/Form/Element/Date.php b/lib/internal/Magento/Framework/Data/Form/Element/Date.php index c4661c92e8c49..ed5457edc7f3f 100644 --- a/lib/internal/Magento/Framework/Data/Form/Element/Date.php +++ b/lib/internal/Magento/Framework/Data/Form/Element/Date.php @@ -12,7 +12,6 @@ namespace Magento\Framework\Data\Form\Element; use Magento\Framework\Escaper; -use Magento\Framework\Stdlib\DateTime; use Magento\Framework\Stdlib\DateTime\TimezoneInterface; class Date extends AbstractElement diff --git a/lib/internal/Magento/Framework/Data/Form/FilterFactory.php b/lib/internal/Magento/Framework/Data/Form/FilterFactory.php index 2763e8bd17cce..22dfabb8fb565 100644 --- a/lib/internal/Magento/Framework/Data/Form/FilterFactory.php +++ b/lib/internal/Magento/Framework/Data/Form/FilterFactory.php @@ -7,7 +7,6 @@ use Magento\Framework\Data\Form\Filter\FilterInterface; use Magento\Framework\ObjectManagerInterface; -use Magento\Framework\Phrase; class FilterFactory { diff --git a/lib/internal/Magento/Framework/Data/Structure.php b/lib/internal/Magento/Framework/Data/Structure.php index f2c45fa160cc2..b22395f1ba835 100644 --- a/lib/internal/Magento/Framework/Data/Structure.php +++ b/lib/internal/Magento/Framework/Data/Structure.php @@ -172,7 +172,7 @@ public function createElement($elementId, array $data) */ public function getElement($elementId) { - return isset($this->_elements[$elementId]) ? $this->_elements[$elementId] : false; + return $this->_elements[$elementId] ?? false; } /** @@ -466,9 +466,7 @@ public function getChildId($parentId, $alias) */ public function getChildren($parentId) { - return isset( - $this->_elements[$parentId][self::CHILDREN] - ) ? $this->_elements[$parentId][self::CHILDREN] : []; + return $this->_elements[$parentId][self::CHILDREN] ?? []; } /** @@ -479,7 +477,7 @@ public function getChildren($parentId) */ public function getParentId($childId) { - return isset($this->_elements[$childId][self::PARENT]) ? $this->_elements[$childId][self::PARENT] : false; + return $this->_elements[$childId][self::PARENT] ?? false; } /** diff --git a/lib/internal/Magento/Framework/DataObject/Test/Unit/Copy/Config/SchemaLocatorTest.php b/lib/internal/Magento/Framework/DataObject/Test/Unit/Copy/Config/SchemaLocatorTest.php index c7417439bac1f..0d35b3a4264e0 100644 --- a/lib/internal/Magento/Framework/DataObject/Test/Unit/Copy/Config/SchemaLocatorTest.php +++ b/lib/internal/Magento/Framework/DataObject/Test/Unit/Copy/Config/SchemaLocatorTest.php @@ -6,8 +6,6 @@ namespace Magento\Framework\DataObject\Test\Unit\Copy\Config; -use Magento\Framework\App\Filesystem\DirectoryList; - class SchemaLocatorTest extends \PHPUnit\Framework\TestCase { /** diff --git a/lib/internal/Magento/Framework/Encryption/Test/Unit/EncryptorTest.php b/lib/internal/Magento/Framework/Encryption/Test/Unit/EncryptorTest.php index f4381a42775d7..74f2db9b05f2d 100644 --- a/lib/internal/Magento/Framework/Encryption/Test/Unit/EncryptorTest.php +++ b/lib/internal/Magento/Framework/Encryption/Test/Unit/EncryptorTest.php @@ -7,7 +7,6 @@ use Magento\Framework\Encryption\Encryptor; use Magento\Framework\Encryption\Crypt; -use Magento\Framework\App\DeploymentConfig; class EncryptorTest extends \PHPUnit\Framework\TestCase { diff --git a/lib/internal/Magento/Framework/EntityManager/AbstractModelHydrator.php b/lib/internal/Magento/Framework/EntityManager/AbstractModelHydrator.php index ce35e72baea1f..9b31fcce10b9d 100644 --- a/lib/internal/Magento/Framework/EntityManager/AbstractModelHydrator.php +++ b/lib/internal/Magento/Framework/EntityManager/AbstractModelHydrator.php @@ -5,8 +5,6 @@ */ namespace Magento\Framework\EntityManager; -use Magento\Framework\Model\AbstractModel; - /** * Class AbstractModelHydrator */ diff --git a/lib/internal/Magento/Framework/EntityManager/Hydrator.php b/lib/internal/Magento/Framework/EntityManager/Hydrator.php index ccf5b0c8557ab..0ea4eb3cedcd9 100644 --- a/lib/internal/Magento/Framework/EntityManager/Hydrator.php +++ b/lib/internal/Magento/Framework/EntityManager/Hydrator.php @@ -5,10 +5,8 @@ */ namespace Magento\Framework\EntityManager; -use Magento\Framework\EntityManager\MapperPool; use Magento\Framework\Reflection\DataObjectProcessor; use Magento\Framework\Api\DataObjectHelper; -use Magento\Framework\EntityManager\TypeResolver; /** * Class Hydrator diff --git a/lib/internal/Magento/Framework/EntityManager/Observer/BeforeEntityDelete.php b/lib/internal/Magento/Framework/EntityManager/Observer/BeforeEntityDelete.php index 5480b1c4feba9..6bc144929fb60 100644 --- a/lib/internal/Magento/Framework/EntityManager/Observer/BeforeEntityDelete.php +++ b/lib/internal/Magento/Framework/EntityManager/Observer/BeforeEntityDelete.php @@ -9,7 +9,6 @@ use Magento\Framework\Event\ObserverInterface; use Magento\Framework\Event\Observer; use Magento\Framework\Model\AbstractModel; -use Magento\Framework\Model\ResourceModel\Db\AbstractDb; /** * Class BeforeEntityDelete diff --git a/lib/internal/Magento/Framework/EntityManager/Operation/ExtensionPool.php b/lib/internal/Magento/Framework/EntityManager/Operation/ExtensionPool.php index 703ed96ece4b9..5d3d37bb830d5 100644 --- a/lib/internal/Magento/Framework/EntityManager/Operation/ExtensionPool.php +++ b/lib/internal/Magento/Framework/EntityManager/Operation/ExtensionPool.php @@ -7,7 +7,6 @@ namespace Magento\Framework\EntityManager\Operation; use Magento\Framework\ObjectManagerInterface; -use Magento\Framework\EntityManager\Operation\ExtensionInterface; /** * Class ExtensionPool diff --git a/lib/internal/Magento/Framework/EntityManager/OperationPool.php b/lib/internal/Magento/Framework/EntityManager/OperationPool.php index 97d580e328b1b..90a5acb8b8a03 100644 --- a/lib/internal/Magento/Framework/EntityManager/OperationPool.php +++ b/lib/internal/Magento/Framework/EntityManager/OperationPool.php @@ -7,7 +7,6 @@ namespace Magento\Framework\EntityManager; use Magento\Framework\ObjectManagerInterface as ObjectManager; -use Magento\Framework\EntityManager\OperationInterface; use Magento\Framework\EntityManager\Operation\CheckIfExists; use Magento\Framework\EntityManager\Operation\Read; use Magento\Framework\EntityManager\Operation\Create; diff --git a/lib/internal/Magento/Framework/EntityManager/Sequence/SequenceManager.php b/lib/internal/Magento/Framework/EntityManager/Sequence/SequenceManager.php index 25af4743ac9b8..7d92c05d6c830 100644 --- a/lib/internal/Magento/Framework/EntityManager/Sequence/SequenceManager.php +++ b/lib/internal/Magento/Framework/EntityManager/Sequence/SequenceManager.php @@ -68,7 +68,7 @@ public function force($entityType, $identifier) if (!isset($sequenceInfo['sequenceTable'])) { throw new \Exception( - 'TODO: use correct Exception class' . PHP_EOL . ' Sequence table doesnt exists' + 'TODO: use correct Exception class' . PHP_EOL . ' Sequence table doesn\'t exists' ); } @@ -101,7 +101,7 @@ public function delete($entityType, $identifier) $metadata = $this->metadataPool->getMetadata($entityType); $sequenceInfo = $this->sequenceRegistry->retrieve($entityType); if (!isset($sequenceInfo['sequenceTable'])) { - throw new \Exception('TODO: use correct Exception class' . PHP_EOL . ' Sequence table doesnt exists'); + throw new \Exception('TODO: use correct Exception class' . PHP_EOL . ' Sequence table doesn\'t exists'); } try { $connection = $this->appResource->getConnectionByName($metadata->getEntityConnectionName()); diff --git a/lib/internal/Magento/Framework/Event.php b/lib/internal/Magento/Framework/Event.php index 4c116d0a33629..c7b15a8eb0722 100644 --- a/lib/internal/Magento/Framework/Event.php +++ b/lib/internal/Magento/Framework/Event.php @@ -88,7 +88,7 @@ public function dispatch() */ public function getName() { - return isset($this->_data['name']) ? $this->_data['name'] : null; + return $this->_data['name'] ?? null; } /** diff --git a/lib/internal/Magento/Framework/Event/Test/Unit/ObserverTest.php b/lib/internal/Magento/Framework/Event/Test/Unit/ObserverTest.php index 5e5c60e149837..378de874974c6 100644 --- a/lib/internal/Magento/Framework/Event/Test/Unit/ObserverTest.php +++ b/lib/internal/Magento/Framework/Event/Test/Unit/ObserverTest.php @@ -8,8 +8,6 @@ use \Magento\Framework\Event\Observer; -use Magento\Framework\Event; - /** * Class ConfigTest * diff --git a/lib/internal/Magento/Framework/File/Uploader.php b/lib/internal/Magento/Framework/File/Uploader.php index c86f98c4e413a..33f458d2082e1 100644 --- a/lib/internal/Magento/Framework/File/Uploader.php +++ b/lib/internal/Magento/Framework/File/Uploader.php @@ -5,8 +5,6 @@ */ namespace Magento\Framework\File; -use Magento\Framework\Filesystem\DriverInterface; - /** * File upload class * diff --git a/lib/internal/Magento/Framework/Filesystem/Io/File.php b/lib/internal/Magento/Framework/Filesystem/Io/File.php index c1cfebc7a0ac1..8fec7f7630257 100644 --- a/lib/internal/Magento/Framework/Filesystem/Io/File.php +++ b/lib/internal/Magento/Framework/Filesystem/Io/File.php @@ -233,7 +233,7 @@ public function streamStat($part = null, $default = null) } $stat = @fstat($this->_streamHandler); if ($part !== null) { - return isset($stat[$part]) ? $stat[$part] : $default; + return $stat[$part] ?? $default; } return $stat; } diff --git a/lib/internal/Magento/Framework/Filesystem/Io/Ftp.php b/lib/internal/Magento/Framework/Filesystem/Io/Ftp.php index 1aa9d61f8865a..04df5fd3f3a6c 100644 --- a/lib/internal/Magento/Framework/Filesystem/Io/Ftp.php +++ b/lib/internal/Magento/Framework/Filesystem/Io/Ftp.php @@ -6,7 +6,6 @@ namespace Magento\Framework\Filesystem\Io; -use Magento\Framework\Filesystem\DriverInterface; use Magento\Framework\Phrase; use Magento\Framework\Exception\LocalizedException; diff --git a/lib/internal/Magento/Framework/Filesystem/Io/IoInterface.php b/lib/internal/Magento/Framework/Filesystem/Io/IoInterface.php index c31d3ff9e52ba..93c85ebafe727 100644 --- a/lib/internal/Magento/Framework/Filesystem/Io/IoInterface.php +++ b/lib/internal/Magento/Framework/Filesystem/Io/IoInterface.php @@ -5,10 +5,9 @@ */ namespace Magento\Framework\Filesystem\Io; -use Magento\Framework\Filesystem\DriverInterface; - /** * Input/output client interface + * @api */ interface IoInterface { diff --git a/lib/internal/Magento/Framework/Filesystem/Test/Unit/File/ReadFactoryTest.php b/lib/internal/Magento/Framework/Filesystem/Test/Unit/File/ReadFactoryTest.php index c2115205e6bd2..93b12f8d56ff8 100644 --- a/lib/internal/Magento/Framework/Filesystem/Test/Unit/File/ReadFactoryTest.php +++ b/lib/internal/Magento/Framework/Filesystem/Test/Unit/File/ReadFactoryTest.php @@ -7,8 +7,6 @@ use \Magento\Framework\Filesystem\File\ReadFactory; -use Magento\Framework\Filesystem\DriverPool; - /** * Class ReadFactoryTest */ diff --git a/lib/internal/Magento/Framework/Filter/AbstractFactory.php b/lib/internal/Magento/Framework/Filter/AbstractFactory.php index 2a0ae0ba15e42..c30b07aa09061 100644 --- a/lib/internal/Magento/Framework/Filter/AbstractFactory.php +++ b/lib/internal/Magento/Framework/Filter/AbstractFactory.php @@ -68,7 +68,7 @@ public function canCreateFilter($alias) */ public function isShared($class) { - return isset($this->shared[$class]) ? $this->shared[$class] : $this->shareByDefault; + return $this->shared[$class] ?? $this->shareByDefault; } /** diff --git a/lib/internal/Magento/Framework/Filter/DataObject/Grid.php b/lib/internal/Magento/Framework/Filter/DataObject/Grid.php index 7676558a927b0..54dccc8ae5b82 100644 --- a/lib/internal/Magento/Framework/Filter/DataObject/Grid.php +++ b/lib/internal/Magento/Framework/Filter/DataObject/Grid.php @@ -5,8 +5,6 @@ */ namespace Magento\Framework\Filter\DataObject; -use Magento\Framework\DataObject; - class Grid extends \Magento\Framework\Filter\DataObject { /** diff --git a/lib/internal/Magento/Framework/Filter/Input.php b/lib/internal/Magento/Framework/Filter/Input.php index 39c7a54786edb..6da748fcbeb9f 100644 --- a/lib/internal/Magento/Framework/Filter/Input.php +++ b/lib/internal/Magento/Framework/Filter/Input.php @@ -183,7 +183,7 @@ public function getFilters($name = null) if (null === $name) { return $this->_filters; } else { - return isset($this->_filters[$name]) ? $this->_filters[$name] : null; + return $this->_filters[$name] ?? null; } } diff --git a/lib/internal/Magento/Framework/Indexer/CacheContext.php b/lib/internal/Magento/Framework/Indexer/CacheContext.php index 7a56b320859e9..4a6964477ebd5 100644 --- a/lib/internal/Magento/Framework/Indexer/CacheContext.php +++ b/lib/internal/Magento/Framework/Indexer/CacheContext.php @@ -30,7 +30,6 @@ class CacheContext implements \Magento\Framework\DataObject\IdentityInterface public function registerEntities($cacheTag, $ids) { $this->entities[$cacheTag] = array_merge($this->getRegisteredEntity($cacheTag), $ids); - return $this; } @@ -40,7 +39,7 @@ public function registerEntities($cacheTag, $ids) * @param array $cacheTags * @return $this */ - public function registerTags(array $cacheTags) + public function registerTags($cacheTags) { $this->tags = array_merge($this->tags, $cacheTags); return $this; diff --git a/lib/internal/Magento/Framework/Indexer/Config/Reader.php b/lib/internal/Magento/Framework/Indexer/Config/Reader.php index 6ef22b3b7f796..9ed35ef0e9af5 100644 --- a/lib/internal/Magento/Framework/Indexer/Config/Reader.php +++ b/lib/internal/Magento/Framework/Indexer/Config/Reader.php @@ -18,6 +18,7 @@ class Reader extends \Magento\Framework\Config\Reader\Filesystem '/config/indexer/source' => 'name', '/config/indexer/fieldset' => 'name', '/config/indexer/fieldset/field' => 'name', + '/config/indexer/dependencies/indexer' => 'id', ]; /** diff --git a/lib/internal/Magento/Framework/Indexer/Dimension.php b/lib/internal/Magento/Framework/Indexer/Dimension.php index 4cb74003c46fc..dacc8d7f524f5 100644 --- a/lib/internal/Magento/Framework/Indexer/Dimension.php +++ b/lib/internal/Magento/Framework/Indexer/Dimension.php @@ -14,6 +14,16 @@ */ class Dimension { + /** + * @var string + */ + private $name; + + /** + * @var string + */ + private $value; + /** * @param string $name * @param string $value diff --git a/lib/internal/Magento/Framework/Indexer/DimensionFactory.php b/lib/internal/Magento/Framework/Indexer/DimensionFactory.php index a137e2d0e94a6..8eaeff5628d60 100644 --- a/lib/internal/Magento/Framework/Indexer/DimensionFactory.php +++ b/lib/internal/Magento/Framework/Indexer/DimensionFactory.php @@ -34,11 +34,14 @@ public function __construct(ObjectManagerInterface $objectManager) * @param string $value * @return Dimension */ - public function create(string $name, $value): Dimension + public function create(string $name, string $value): Dimension { - return $this->objectManager->create(Dimension::class, [ - 'name' => $name, - 'value' => (string) $value, - ]); + return $this->objectManager->create( + Dimension::class, + [ + 'name' => $name, + 'value' => $value, + ] + ); } } diff --git a/lib/internal/Magento/Framework/Indexer/Dimension/DimensionProviderInterface.php b/lib/internal/Magento/Framework/Indexer/DimensionProviderInterface.php similarity index 90% rename from lib/internal/Magento/Framework/Indexer/Dimension/DimensionProviderInterface.php rename to lib/internal/Magento/Framework/Indexer/DimensionProviderInterface.php index e2d05b2ae038f..ea4f56eb48d41 100644 --- a/lib/internal/Magento/Framework/Indexer/Dimension/DimensionProviderInterface.php +++ b/lib/internal/Magento/Framework/Indexer/DimensionProviderInterface.php @@ -5,7 +5,7 @@ */ declare(strict_types=1); -namespace Magento\Framework\Indexer\Dimension; +namespace Magento\Framework\Indexer; /** * @api diff --git a/lib/internal/Magento/Framework/Indexer/Dimension/DimensionalIndexerInterface.php b/lib/internal/Magento/Framework/Indexer/DimensionalIndexerInterface.php similarity index 55% rename from lib/internal/Magento/Framework/Indexer/Dimension/DimensionalIndexerInterface.php rename to lib/internal/Magento/Framework/Indexer/DimensionalIndexerInterface.php index e2f68272565a6..43c4e7a7fd70b 100644 --- a/lib/internal/Magento/Framework/Indexer/Dimension/DimensionalIndexerInterface.php +++ b/lib/internal/Magento/Framework/Indexer/DimensionalIndexerInterface.php @@ -5,11 +5,11 @@ */ declare(strict_types=1); -namespace Magento\Framework\Indexer\Dimension; +namespace Magento\Framework\Indexer; /** * @api - * Run indexer by specific dimension + * Run indexer by dimensions */ interface DimensionalIndexerInterface { @@ -17,9 +17,9 @@ interface DimensionalIndexerInterface * Execute indexer by specified dimension. * Accept array of dimensions DTO that represent indexer dimension * - * @param \Magento\Framework\Indexer\Dimension[] $dimension - * @param \Traversable|null $entityIds + * @param \Magento\Framework\Indexer\Dimension[] $dimensions + * @param \Traversable $entityIds * @return void */ - public function executeByDimension(array $dimension, \Traversable $entityIds = null); + public function executeByDimensions(array $dimensions, \Traversable $entityIds); } diff --git a/lib/internal/Magento/Framework/Indexer/MultiDimensionProvider.php b/lib/internal/Magento/Framework/Indexer/MultiDimensionProvider.php new file mode 100644 index 0000000000000..a02637f755b89 --- /dev/null +++ b/lib/internal/Magento/Framework/Indexer/MultiDimensionProvider.php @@ -0,0 +1,156 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +declare(strict_types=1); + +namespace Magento\Framework\Indexer; + +/** + * Multiply dimensions from provided DimensionProviderInterface + */ +class MultiDimensionProvider implements \IteratorAggregate +{ + /** + * @var array + */ + private $dimensionsIterators = []; + + /** + * @var array + */ + private $dimensionsDataProviders = []; + + /** + * @var int + */ + private $dimensionsProvidersCount = 0; + + /** + * @param DimensionProviderInterface[] $dimensionProviders + */ + public function __construct(array $dimensionProviders = []) + { + foreach ($dimensionProviders as $dimensionDataProvider) { + $this->addDimensionDataProvider($dimensionDataProvider); + } + } + + /** + * Returns generator that will return multiplied dimensions on each iteration + * + * @return \Traversable|Dimension[][] + * @throws \LogicException + */ + public function getIterator(): \Traversable + { + // just return empty array if we have no dimension providers to iterate over + if ($this->dimensionsProvidersCount === 0) { + yield []; + return; + } + + // this recreates iterators for dimension so we can iterate over them + $this->rewind(); + + // if at leas one dimension provider has no dimensions to return we can't multiple dimension at all + if (!$this->hasCurrentDimension()) { + throw new \LogicException('Can`t multiple dimensions because some of them are empty.'); + } + + // return dimensions until all iterators become invalid + while ($this->hasCurrentDimension()) { + yield $this->getCurrentDimension(); + $this->setNextDimension(); + } + } + + /** + * Return all dimensions for current state of each dimension provider + * + * @return array + */ + private function getCurrentDimension(): array + { + $dimensions = []; + + foreach ($this->dimensionsIterators as $dimensionIterator) { + /** @var Dimension $dimension */ + $dimension = $dimensionIterator->current(); + $dimensions[$dimension->getName()] = $dimension; + } + + return $dimensions; + } + + /** + * Iterates over dimension iterators one by one starting from right to left + * This approach emulates iterations over X nested foreach loops e.g.: + * + * @return void + */ + private function setNextDimension() + { + $this->dimensionsIterators[$this->dimensionsProvidersCount - 1]->next(); + + for ($i = ($this->dimensionsProvidersCount - 1); $i > 0; $i--) { + if (!$this->dimensionsIterators[$i]->valid()) { + $this->dimensionsIterators[$i] = $this->dimensionsDataProviders[$i]->getIterator(); + $this->dimensionsIterators[$i-1]->next(); + } + } + } + + /** + * Recreates iterators so all MultiDimensionProvider can be iterated again + * + * @return void + */ + private function rewind() + { + $this->dimensionsIterators = []; + + foreach ($this->dimensionsDataProviders as $dimensionDataProvider) { + $this->dimensionsIterators[] = $dimensionDataProvider->getIterator(); + } + } + + /** + * Check if all dimension iterators are in valid state + * + * If at least one of dimension iterators is invalid before very first iteration - we assume + * that dimension provider has no dimensions at all, which means we can't multiple all dimensions + * + * If all dimension iterators became invalid - we assume that multiplication is already done + * + * @return bool + */ + private function hasCurrentDimension(): bool + { + $valid = true; + + foreach ($this->dimensionsIterators as $dimensionsIterator) { + // if at least one data provider is invalid at this stage - all generator is invalid + if (!$dimensionsIterator->valid()) { + return false; + } + } + + // generator is valid only when all data providers are valid + return $valid; + } + + /** + * Collects dimension data providers + * This was done via separate method to ensure that each provider has required interface + * + * @param DimensionProviderInterface $dimensionDataProvider + * @return void + */ + private function addDimensionDataProvider(DimensionProviderInterface $dimensionDataProvider) + { + $this->dimensionsDataProviders[] = $dimensionDataProvider; + $this->dimensionsProvidersCount++; + } +} diff --git a/lib/internal/Magento/Framework/Indexer/SaveHandler/IndexerHandler.php b/lib/internal/Magento/Framework/Indexer/SaveHandler/IndexerHandler.php index 3908cf1e98762..c3ab971c992e6 100644 --- a/lib/internal/Magento/Framework/Indexer/SaveHandler/IndexerHandler.php +++ b/lib/internal/Magento/Framework/Indexer/SaveHandler/IndexerHandler.php @@ -12,7 +12,6 @@ use Magento\Framework\Indexer\IndexStructureInterface; use Magento\Framework\Indexer\ScopeResolver\FlatScopeResolver; use Magento\Framework\Indexer\ScopeResolver\IndexScopeResolver; -use Magento\Framework\Indexer\SaveHandler\Batch; class IndexerHandler implements IndexerInterface { diff --git a/lib/internal/Magento/Framework/Indexer/SaveHandlerFactory.php b/lib/internal/Magento/Framework/Indexer/SaveHandlerFactory.php index 82e8a26553b89..80231dd7aa290 100644 --- a/lib/internal/Magento/Framework/Indexer/SaveHandlerFactory.php +++ b/lib/internal/Magento/Framework/Indexer/SaveHandlerFactory.php @@ -5,7 +5,6 @@ */ namespace Magento\Framework\Indexer; -use Magento\Framework\Indexer\IndexerInterface; use Magento\Framework\ObjectManagerInterface; use Magento\Framework\Indexer\SaveHandler\IndexerInterface as SaveHandlerInterface; diff --git a/lib/internal/Magento/Framework/Indexer/ScopeResolver/IndexScopeResolver.php b/lib/internal/Magento/Framework/Indexer/ScopeResolver/IndexScopeResolver.php index 891a6cd1efe12..a68de6ad36f9a 100644 --- a/lib/internal/Magento/Framework/Indexer/ScopeResolver/IndexScopeResolver.php +++ b/lib/internal/Magento/Framework/Indexer/ScopeResolver/IndexScopeResolver.php @@ -42,16 +42,18 @@ public function __construct( */ public function resolve($index, array $dimensions) { - $tableNameParts = [$index]; + $tableNameParts = []; foreach ($dimensions as $dimension) { switch ($dimension->getName()) { case 'scope': - $tableNameParts[] = $dimension->getName() . $this->getScopeId($dimension); + $tableNameParts[$dimension->getName()] = $dimension->getName() . $this->getScopeId($dimension); break; default: - $tableNameParts[] = $dimension->getName() . $dimension->getValue(); + $tableNameParts[$dimension->getName()] = $dimension->getName() . $dimension->getValue(); } } + ksort($tableNameParts); + array_unshift($tableNameParts, $index); return $this->resource->getTableName(implode('_', $tableNameParts)); } diff --git a/lib/internal/Magento/Framework/Indexer/StructureFactory.php b/lib/internal/Magento/Framework/Indexer/StructureFactory.php index f9b7eafdfc436..1b6729e4603ec 100644 --- a/lib/internal/Magento/Framework/Indexer/StructureFactory.php +++ b/lib/internal/Magento/Framework/Indexer/StructureFactory.php @@ -5,8 +5,6 @@ */ namespace Magento\Framework\Indexer; -use Magento\Framework\Indexer\IndexStructureInterface; - class StructureFactory { /** diff --git a/lib/internal/Magento/Framework/Indexer/Test/Unit/IndexStructureTest.php b/lib/internal/Magento/Framework/Indexer/Test/Unit/IndexStructureTest.php index 514bd673f8525..2c0d9124b9603 100644 --- a/lib/internal/Magento/Framework/Indexer/Test/Unit/IndexStructureTest.php +++ b/lib/internal/Magento/Framework/Indexer/Test/Unit/IndexStructureTest.php @@ -6,7 +6,6 @@ namespace Magento\Framework\Indexer\Test\Unit; -use Magento\Framework\App\ResourceConnection; use Magento\Framework\DB\Adapter\AdapterInterface; use Magento\Framework\DB\Ddl\Table; use \Magento\Framework\TestFramework\Unit\Helper\ObjectManager; diff --git a/lib/internal/Magento/Framework/Indexer/Test/Unit/MultiDimensionProviderTest.php b/lib/internal/Magento/Framework/Indexer/Test/Unit/MultiDimensionProviderTest.php new file mode 100644 index 0000000000000..b55ace9bdec3d --- /dev/null +++ b/lib/internal/Magento/Framework/Indexer/Test/Unit/MultiDimensionProviderTest.php @@ -0,0 +1,256 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +declare(strict_types=1); + +namespace Magento\Framework\Indexer\Test\Unit; + +use \Magento\Framework\Indexer\MultiDimensionProvider; +use \Magento\Framework\Indexer\DimensionProviderInterface; +use \Magento\Framework\Indexer\Dimension; + +class MultiDimensionProviderTest extends \PHPUnit\Framework\TestCase +{ + /** + * tests that MultiDimensionProvider will return [[]] in case it has no dimension providers + */ + public function testWithNoDataProviders() + { + // prepare expected dimensions + $expectedDimensions = [[]]; + + // collect actual dimensions + $multiDimensionProvider = new MultiDimensionProvider([]); + + $actualDimensions = []; + foreach ($multiDimensionProvider as $dimension) { + $actualDimensions[] = $dimension; + } + + $this->assertSame($expectedDimensions, $actualDimensions); + } + + /** + * tests multiplication of dimensions from different providers + * + * e.g we have three dimensions: + * - dimension X with values (x1, x2) + * - dimension Y with values (y1, y2, y3) + * - dimension Z with values (z1, z2) + * + * the multiplication result set will be: + * x1-y1-z1 + * x1-y1-z2 + * x1-y2-z1 + * x1-y2-z2 + * x1-y3-z1 + * x1-y3-z2 + * x2-y1-z1 + * x2-y1-z2 + * x2-y2-z1 + * x2-y2-z2 + * x2-y3-z1 + * x2-y3-z2 + */ + public function testWithMultipleDataProviders() + { + // prepare expected dimensions + $dimensionXData = [ + $this->getDimensionMock('x', '1'), + $this->getDimensionMock('x', '2'), + $this->getDimensionMock('x', '3'), + ]; + + $dimensionYData = [ + $this->getDimensionMock('y', '1'), + $this->getDimensionMock('y', '2'), + $this->getDimensionMock('y', '3'), + $this->getDimensionMock('y', '4'), + $this->getDimensionMock('y', '5'), + ]; + + $dimensionZData = [ + $this->getDimensionMock('z', '1'), + $this->getDimensionMock('z', '2'), + ]; + + $expectedDimensions = []; + + foreach ($dimensionXData as $dimensionX) { + foreach ($dimensionYData as $dimensionY) { + foreach ($dimensionZData as $dimensionZ) { + $expectedDimensions[] = [ + $dimensionX->getName() => $dimensionX, + $dimensionY->getName() => $dimensionY, + $dimensionZ->getName() => $dimensionZ, + ]; + } + } + } + + // collect actual dimensions + $multiDimensionProvider = new MultiDimensionProvider( + [ + $this->getDimensionProviderMock($dimensionXData), + $this->getDimensionProviderMock($dimensionYData), + $this->getDimensionProviderMock($dimensionZData), + ] + ); + + $actualDimensions = []; + foreach ($multiDimensionProvider as $dimension) { + $actualDimensions[] = $dimension; + } + + $this->assertSame($expectedDimensions, $actualDimensions); + } + + /** + * tests that the same MultiDimensionProvider can be used in foreach multiple times without creating again + */ + public function testMultiDimensionProviderIsReIterable() + { + // prepare expected dimensions + $dimensionXData = [ + $this->getDimensionMock('x', '1'), + $this->getDimensionMock('x', '2'), + $this->getDimensionMock('x', '3'), + ]; + + $dimensionZData = [ + $this->getDimensionMock('z', '1'), + $this->getDimensionMock('z', '2'), + ]; + + // collect actual dimensions + $multiDimensionProvider = new MultiDimensionProvider( + [ + $this->getDimensionProviderMock($dimensionXData), + $this->getDimensionProviderMock($dimensionZData), + ] + ); + + // first iteration + $actualDimensions1st = []; + foreach ($multiDimensionProvider as $dimension) { + $actualDimensions1st[] = $dimension; + } + + // second iteration + $actualDimensions2nd = []; + foreach ($multiDimensionProvider as $dimension) { + $actualDimensions2nd[] = $dimension; + } + + $this->assertSame($actualDimensions1st, $actualDimensions2nd); + } + + /** + * tests that MultiDimensionProvider will throw exception when all dimension providers has nothing to return + * + * @expectedException \LogicException + * @expectedExceptionMessage Can`t multiple dimensions because some of them are empty. + */ + public function testMultiDimensionProviderWithEmptyDataProvider() + { + // collect actual dimensions + $multiDimensionProvider = new MultiDimensionProvider( + [ + $this->getDimensionProviderMock([]), + $this->getDimensionProviderMock([]), + ] + ); + + $actualDimensions = []; + foreach ($multiDimensionProvider as $dimension) { + $actualDimensions[] = $dimension; + } + } + + /** + * tests that MultiDimensionProvider will throw exception when one dimension providers has nothing to return + * + * @expectedException \LogicException + * @expectedExceptionMessage Can`t multiple dimensions because some of them are empty. + */ + public function testMultiDimensionProviderWithMixedDataProvider() + { + + // prepare expected dimensions + $dimensionXData = [ + $this->getDimensionMock('x', '1'), + $this->getDimensionMock('x', '2'), + $this->getDimensionMock('x', '3'), + ]; + + $dimensionYData = [ + $this->getDimensionMock('y', '1'), + $this->getDimensionMock('y', '2'), + $this->getDimensionMock('y', '3'), + $this->getDimensionMock('y', '4'), + $this->getDimensionMock('y', '5'), + ]; + + $dimensionZData = []; + + // collect actual dimensions + $multiDimensionProvider = new MultiDimensionProvider( + [ + $this->getDimensionProviderMock($dimensionXData), + $this->getDimensionProviderMock($dimensionYData), + $this->getDimensionProviderMock($dimensionZData), + ] + ); + + $actualDimensions = []; + foreach ($multiDimensionProvider as $dimension) { + $actualDimensions[] = $dimension; + } + } + + private function getDimensionProviderMock($dimensions) + { + $dimensionProviderMock = $this->getMockBuilder(DimensionProviderInterface::class) + ->disableOriginalConstructor() + ->disableOriginalClone() + ->disableArgumentCloning() + ->disallowMockingUnknownTypes() + ->setMethods(['getIterator']) + ->getMockForAbstractClass(); + + $dimensionProviderMock->expects($this->any()) + ->method('getIterator') + ->will( + $this->returnCallback( + function () use ($dimensions) { + return \SplFixedArray::fromArray($dimensions); + } + ) + ); + + return $dimensionProviderMock; + } + + private function getDimensionMock(string $name, string $value) + { + $dimensionMock = $this->getMockBuilder(Dimension::class) + ->disableOriginalConstructor() + ->disableOriginalClone() + ->disableArgumentCloning() + ->disallowMockingUnknownTypes() + ->setMethods(['getName', 'getValue']) + ->getMock(); + + $dimensionMock->expects($this->any()) + ->method('getName') + ->willReturn($name); + + $dimensionMock->expects($this->any()) + ->method('getValue') + ->willReturn($value); + + return $dimensionMock; + } +} diff --git a/lib/internal/Magento/Framework/Indexer/Test/Unit/ScopeResolver/IndexScopeResolverTest.php b/lib/internal/Magento/Framework/Indexer/Test/Unit/ScopeResolver/IndexScopeResolverTest.php index ae898657ccecf..b193a3eecdd98 100644 --- a/lib/internal/Magento/Framework/Indexer/Test/Unit/ScopeResolver/IndexScopeResolverTest.php +++ b/lib/internal/Magento/Framework/Indexer/Test/Unit/ScopeResolver/IndexScopeResolverTest.php @@ -103,9 +103,19 @@ public function resolveDataProvider() ], [ 'index' => 'index_name', - 'dimensions' => [['dimension', 10], ['dimension', 20]], + 'dimensions' => [['first', 10], ['second', 20]], // actually you will get exception here thrown in ScopeResolverInterface - 'expected' => 'index_name_dimension10_dimension20' + 'expected' => 'index_name_first10_second20' + ], + [ + 'index' => 'index_name', + 'dimensions' => [['second', 10], ['first', 20]], + 'expected' => 'index_name_first20_second10' + ], + [ + 'index' => 'index_name', + 'dimensions' => [[-1, 10], ['first', 20]], + 'expected' => 'index_name_-110_first20' ] ]; } diff --git a/lib/internal/Magento/Framework/Interception/PluginList/PluginList.php b/lib/internal/Magento/Framework/Interception/PluginList/PluginList.php index 82738a30266d8..e21841b48bc13 100644 --- a/lib/internal/Magento/Framework/Interception/PluginList/PluginList.php +++ b/lib/internal/Magento/Framework/Interception/PluginList/PluginList.php @@ -268,7 +268,7 @@ public function getNext($type, $method, $code = '__self') $this->_inheritPlugins($type); } $key = $type . '_' . lcfirst($method) . '_' . $code; - return isset($this->_processed[$key]) ? $this->_processed[$key] : null; + return $this->_processed[$key] ?? null; } /** diff --git a/lib/internal/Magento/Framework/Locale/Format.php b/lib/internal/Magento/Framework/Locale/Format.php index 89f6957011876..ca50cdb2440f4 100644 --- a/lib/internal/Magento/Framework/Locale/Format.php +++ b/lib/internal/Magento/Framework/Locale/Format.php @@ -65,7 +65,7 @@ public function getNumber($value) } //trim spaces and apostrophes - $value = str_replace(['\'', ' '], '', $value); + $value = preg_replace('/[^0-9^\^.,-]/m', '', $value); $separatorComa = strpos($value, ','); $separatorDot = strpos($value, '.'); diff --git a/lib/internal/Magento/Framework/Locale/Test/Unit/CurrencyTest.php b/lib/internal/Magento/Framework/Locale/Test/Unit/CurrencyTest.php index 5ef1a3097402b..3e917425c31e0 100644 --- a/lib/internal/Magento/Framework/Locale/Test/Unit/CurrencyTest.php +++ b/lib/internal/Magento/Framework/Locale/Test/Unit/CurrencyTest.php @@ -7,7 +7,6 @@ namespace Magento\Framework\Locale\Test\Unit; use Magento\Framework\Locale\Currency; -use Magento\Framework\Locale\CurrencyInterface; class CurrencyTest extends \PHPUnit\Framework\TestCase { diff --git a/lib/internal/Magento/Framework/Locale/Test/Unit/FormatTest.php b/lib/internal/Magento/Framework/Locale/Test/Unit/FormatTest.php index 41583fd1383a5..1141f451c13a5 100644 --- a/lib/internal/Magento/Framework/Locale/Test/Unit/FormatTest.php +++ b/lib/internal/Magento/Framework/Locale/Test/Unit/FormatTest.php @@ -33,6 +33,9 @@ class FormatTest extends \PHPUnit\Framework\TestCase */ protected $currency; + /** + * {@inheritDoc} + */ protected function setUp() { $this->currency = $this->getMockBuilder(\Magento\Directory\Model\Currency::class) @@ -41,9 +44,7 @@ protected function setUp() $this->scope = $this->getMockBuilder(\Magento\Framework\App\ScopeInterface::class) ->setMethods(['getCurrentCurrency']) ->getMockForAbstractClass(); - $this->scope->expects($this->once()) - ->method('getCurrentCurrency') - ->willReturn($this->currency); + $this->scopeResolver = $this->getMockBuilder(\Magento\Framework\App\ScopeResolverInterface::class) ->setMethods(['getScope']) ->getMockForAbstractClass(); @@ -52,7 +53,10 @@ protected function setUp() ->willReturn($this->scope); $this->localeResolver = $this->getMockBuilder(\Magento\Framework\Locale\ResolverInterface::class) ->getMock(); + + /** @var \Magento\Directory\Model\CurrencyFactory|\PHPUnit_Framework_MockObject_MockObject $currencyFactory */ $currencyFactory = $this->getMockBuilder(\Magento\Directory\Model\CurrencyFactory::class) + ->disableOriginalConstructor() ->getMock(); $this->formatModel = new \Magento\Framework\Locale\Format( @@ -63,21 +67,26 @@ protected function setUp() } /** - * @param $localeCode - * @param $expectedResult + * @param string $localeCode + * @param array $expectedResult * @dataProvider getPriceFormatDataProvider */ - public function testGetPriceFormat($localeCode, $expectedResult) + public function testGetPriceFormat($localeCode, array $expectedResult): void { + $this->scope->expects($this->once()) + ->method('getCurrentCurrency') + ->willReturn($this->currency); + $result = $this->formatModel->getPriceFormat($localeCode); $intersection = array_intersect_assoc($result, $expectedResult); $this->assertCount(count($expectedResult), $intersection); } /** + * * @return array */ - public function getPriceFormatDataProvider() + public function getPriceFormatDataProvider(): array { return [ ['en_US', ['decimalSymbol' => '.', 'groupSymbol' => ',']], @@ -86,4 +95,35 @@ public function getPriceFormatDataProvider() ['uk_UA', ['decimalSymbol' => ',', 'groupSymbol' => ' ']] ]; } + + /** + * + * @param mixed $value + * @param float $expected + * @dataProvider provideNumbers + */ + public function testGetNumber($value, $expected): void + { + $this->assertEquals($expected, $this->formatModel->getNumber($value)); + } + + /** + * + * @return array + */ + public function provideNumbers(): array + { + return [ + [' 2345.4356,1234', 23454356.1234], + ['+23,3452.123', 233452.123], + ['12343', 12343], + ['-9456km', -9456], + ['0', 0], + ['2 054,10', 2054.1], + ['2046,45', 2046.45], + ['2 054.52', 2054.52], + ['2,46 GB', 2.46], + ['2,054.00', 2054], + ]; + } } diff --git a/lib/internal/Magento/Framework/Message/Collection.php b/lib/internal/Magento/Framework/Message/Collection.php index 8805d433f4ffb..32e84fc28f5a0 100644 --- a/lib/internal/Magento/Framework/Message/Collection.php +++ b/lib/internal/Magento/Framework/Message/Collection.php @@ -136,7 +136,7 @@ public function getItems() */ public function getItemsByType($type) { - return isset($this->messages[$type]) ? $this->messages[$type] : []; + return $this->messages[$type] ?? []; } /** diff --git a/lib/internal/Magento/Framework/Message/Test/Unit/AbstractMessageTest.php b/lib/internal/Magento/Framework/Message/Test/Unit/AbstractMessageTest.php index 550f135ddc545..f4b73bdd2f293 100644 --- a/lib/internal/Magento/Framework/Message/Test/Unit/AbstractMessageTest.php +++ b/lib/internal/Magento/Framework/Message/Test/Unit/AbstractMessageTest.php @@ -5,8 +5,6 @@ */ namespace Magento\Framework\Message\Test\Unit; -use Magento\Framework\Message\MessageInterface; - /** * \Magento\Framework\Message\AbstractMessage test case */ diff --git a/lib/internal/Magento/Framework/Model/AbstractExtensibleModel.php b/lib/internal/Magento/Framework/Model/AbstractExtensibleModel.php index e7ffcde03ff64..1cffba2543b0b 100644 --- a/lib/internal/Magento/Framework/Model/AbstractExtensibleModel.php +++ b/lib/internal/Magento/Framework/Model/AbstractExtensibleModel.php @@ -154,9 +154,7 @@ public function getCustomAttributes() public function getCustomAttribute($attributeCode) { $this->initializeCustomAttributes(); - return isset($this->_data[self::CUSTOM_ATTRIBUTES][$attributeCode]) - ? $this->_data[self::CUSTOM_ATTRIBUTES][$attributeCode] - : null; + return $this->_data[self::CUSTOM_ATTRIBUTES][$attributeCode] ?? null; } /** diff --git a/lib/internal/Magento/Framework/Model/ResourceModel/Db/DeleteEntityRow.php b/lib/internal/Magento/Framework/Model/ResourceModel/Db/DeleteEntityRow.php index 7ec43220dc85c..d7d63232c1191 100755 --- a/lib/internal/Magento/Framework/Model/ResourceModel/Db/DeleteEntityRow.php +++ b/lib/internal/Magento/Framework/Model/ResourceModel/Db/DeleteEntityRow.php @@ -6,7 +6,6 @@ namespace Magento\Framework\Model\ResourceModel\Db; use Magento\Framework\EntityManager\MetadataPool; -use Magento\Framework\EntityManager\EntityMetadata; class DeleteEntityRow { diff --git a/lib/internal/Magento/Framework/Model/ResourceModel/Db/Relation/ActionPool.php b/lib/internal/Magento/Framework/Model/ResourceModel/Db/Relation/ActionPool.php index 433762556693d..f3ac5ed5ee1f8 100644 --- a/lib/internal/Magento/Framework/Model/ResourceModel/Db/Relation/ActionPool.php +++ b/lib/internal/Magento/Framework/Model/ResourceModel/Db/Relation/ActionPool.php @@ -7,7 +7,6 @@ namespace Magento\Framework\Model\ResourceModel\Db\Relation; use Magento\Framework\ObjectManagerInterface as ObjectManager; -use Magento\Framework\Model\ResourceModel\Db\ProcessEntityRelationInterface; /** * Class ActionPool @@ -50,9 +49,6 @@ public function getActions($entityType, $actionName) } foreach ($this->relationActions[$entityType][$actionName] as $actionClassName) { $action = $this->objectManager->get($actionClassName); - //if (!$action instanceof ProcessEntityRelationInterface) { - // throw new \Exception('Not compliant with action interface'); - //} $actions[] = $action; } return $actions; diff --git a/lib/internal/Magento/Framework/Model/Test/Unit/AbstractExtensibleModelTest.php b/lib/internal/Magento/Framework/Model/Test/Unit/AbstractExtensibleModelTest.php index 1b16427040709..7e68b8daf2aef 100644 --- a/lib/internal/Magento/Framework/Model/Test/Unit/AbstractExtensibleModelTest.php +++ b/lib/internal/Magento/Framework/Model/Test/Unit/AbstractExtensibleModelTest.php @@ -7,7 +7,6 @@ namespace Magento\Framework\Model\Test\Unit; use Magento\Framework\Api\AttributeValue; -use Magento\Framework\TestFramework\Unit\Helper\ObjectManager as ObjectManagerHelper; /** * @SuppressWarnings(PHPMD.CouplingBetweenObjects) diff --git a/lib/internal/Magento/Framework/Model/Test/Unit/ResourceModel/Db/Collection/AbstractCollectionTest.php b/lib/internal/Magento/Framework/Model/Test/Unit/ResourceModel/Db/Collection/AbstractCollectionTest.php index 147cac47d3829..4f27f083509d7 100644 --- a/lib/internal/Magento/Framework/Model/Test/Unit/ResourceModel/Db/Collection/AbstractCollectionTest.php +++ b/lib/internal/Magento/Framework/Model/Test/Unit/ResourceModel/Db/Collection/AbstractCollectionTest.php @@ -7,7 +7,6 @@ namespace Magento\Framework\Model\Test\Unit\ResourceModel\Db\Collection; use Magento\Framework\DB\Select; -use Magento\Framework\DataObject as MagentoObject; use Magento\Framework\TestFramework\Unit\Helper\ObjectManager as ObjectManagerHelper; use Magento\Framework\ObjectManagerInterface; diff --git a/lib/internal/Magento/Framework/Module/Dir.php b/lib/internal/Magento/Framework/Module/Dir.php index 77174bb51305d..e6b60453b9577 100644 --- a/lib/internal/Magento/Framework/Module/Dir.php +++ b/lib/internal/Magento/Framework/Module/Dir.php @@ -9,7 +9,6 @@ use Magento\Framework\Component\ComponentRegistrar; use Magento\Framework\Component\ComponentRegistrarInterface; -use Magento\Framework\Filesystem; class Dir { diff --git a/lib/internal/Magento/Framework/Module/FullModuleList.php b/lib/internal/Magento/Framework/Module/FullModuleList.php index 5ad5b05a413ef..c6e403dee0898 100644 --- a/lib/internal/Magento/Framework/Module/FullModuleList.php +++ b/lib/internal/Magento/Framework/Module/FullModuleList.php @@ -55,7 +55,7 @@ public function getAll() public function getOne($name) { $data = $this->getAll(); - return isset($data[$name]) ? $data[$name] : null; + return $data[$name] ?? null; } /** diff --git a/lib/internal/Magento/Framework/Module/ModuleList.php b/lib/internal/Magento/Framework/Module/ModuleList.php index 406aa9efd31a0..6ee061cffb3d0 100644 --- a/lib/internal/Magento/Framework/Module/ModuleList.php +++ b/lib/internal/Magento/Framework/Module/ModuleList.php @@ -90,7 +90,7 @@ public function getAll() public function getOne($name) { $enabled = $this->getAll(); - return isset($enabled[$name]) ? $enabled[$name] : null; + return $enabled[$name] ?? null; } /** diff --git a/lib/internal/Magento/Framework/Module/ModuleResource.php b/lib/internal/Magento/Framework/Module/ModuleResource.php index 427f8a6f8e959..b453ea4cba095 100644 --- a/lib/internal/Magento/Framework/Module/ModuleResource.php +++ b/lib/internal/Magento/Framework/Module/ModuleResource.php @@ -87,7 +87,7 @@ public function getDbVersion($moduleName) return false; } $this->_loadVersion('db'); - return isset(self::$schemaVersions[$moduleName]) ? self::$schemaVersions[$moduleName] : false; + return self::$schemaVersions[$moduleName] ?? false; } /** @@ -119,7 +119,7 @@ public function getDataVersion($moduleName) return false; } $this->_loadVersion('data'); - return isset(self::$dataVersions[$moduleName]) ? self::$dataVersions[$moduleName] : false; + return self::$dataVersions[$moduleName] ?? false; } /** diff --git a/lib/internal/Magento/Framework/Module/PackageInfo.php b/lib/internal/Magento/Framework/Module/PackageInfo.php index 7edb0c04ebf98..0dce507ba26f4 100644 --- a/lib/internal/Magento/Framework/Module/PackageInfo.php +++ b/lib/internal/Magento/Framework/Module/PackageInfo.php @@ -283,6 +283,6 @@ public function getConflict($moduleName) public function getVersion($moduleName) { $this->load(); - return isset($this->modulePackageVersionMap[$moduleName]) ? $this->modulePackageVersionMap[$moduleName] : ''; + return $this->modulePackageVersionMap[$moduleName] ?? ''; } } diff --git a/lib/internal/Magento/Framework/Module/Test/Unit/Dir/ReaderTest.php b/lib/internal/Magento/Framework/Module/Test/Unit/Dir/ReaderTest.php index f41f9bbd0d239..59249e3b92ae9 100644 --- a/lib/internal/Magento/Framework/Module/Test/Unit/Dir/ReaderTest.php +++ b/lib/internal/Magento/Framework/Module/Test/Unit/Dir/ReaderTest.php @@ -11,7 +11,6 @@ namespace Magento\Framework\Module\Test\Unit\Dir; use Magento\Framework\Config\FileIteratorFactory; -use Magento\Framework\Filesystem; use Magento\Framework\Module\Dir; class ReaderTest extends \PHPUnit\Framework\TestCase diff --git a/lib/internal/Magento/Framework/Module/Test/Unit/ManagerTest.php b/lib/internal/Magento/Framework/Module/Test/Unit/ManagerTest.php index 12ddfea8c83d1..255f5783dbc60 100644 --- a/lib/internal/Magento/Framework/Module/Test/Unit/ManagerTest.php +++ b/lib/internal/Magento/Framework/Module/Test/Unit/ManagerTest.php @@ -5,8 +5,6 @@ */ namespace Magento\Framework\Module\Test\Unit; -use Magento\Framework\Module\Plugin\DbStatusValidator; - class ManagerTest extends \PHPUnit\Framework\TestCase { /** diff --git a/lib/internal/Magento/Framework/Mview/Config/Converter.php b/lib/internal/Magento/Framework/Mview/Config/Converter.php index 55b2f1da21cb9..5c33ac150d00a 100644 --- a/lib/internal/Magento/Framework/Mview/Config/Converter.php +++ b/lib/internal/Magento/Framework/Mview/Config/Converter.php @@ -5,7 +5,6 @@ */ namespace Magento\Framework\Mview\Config; -use Magento\Framework\Exception\LocalizedException; use Magento\Framework\Mview\View\SubscriptionInterface; class Converter implements \Magento\Framework\Config\ConverterInterface diff --git a/lib/internal/Magento/Framework/Mview/Config/SchemaLocator.php b/lib/internal/Magento/Framework/Mview/Config/SchemaLocator.php index 7cafc35ba1451..7eeea70ffe337 100644 --- a/lib/internal/Magento/Framework/Mview/Config/SchemaLocator.php +++ b/lib/internal/Magento/Framework/Mview/Config/SchemaLocator.php @@ -5,8 +5,6 @@ */ namespace Magento\Framework\Mview\Config; -use Magento\Framework\App\Filesystem\DirectoryList; - class SchemaLocator implements \Magento\Framework\Config\SchemaLocatorInterface { /** diff --git a/lib/internal/Magento/Framework/Mview/Test/Unit/Config/ReaderTest.php b/lib/internal/Magento/Framework/Mview/Test/Unit/Config/ReaderTest.php index ea8b7cfc068ac..4830c5e140917 100644 --- a/lib/internal/Magento/Framework/Mview/Test/Unit/Config/ReaderTest.php +++ b/lib/internal/Magento/Framework/Mview/Test/Unit/Config/ReaderTest.php @@ -5,8 +5,6 @@ */ namespace Magento\Framework\Mview\Test\Unit\Config; -use Magento\Framework\App\Filesystem\DirectoryList; - class ReaderTest extends \PHPUnit\Framework\TestCase { /** diff --git a/lib/internal/Magento/Framework/Mview/View/Changelog.php b/lib/internal/Magento/Framework/Mview/View/Changelog.php index 0f441b7728fce..4fb06ce3f06fd 100644 --- a/lib/internal/Magento/Framework/Mview/View/Changelog.php +++ b/lib/internal/Magento/Framework/Mview/View/Changelog.php @@ -6,7 +6,6 @@ namespace Magento\Framework\Mview\View; -use Magento\Framework\App\ResourceConnection; use Magento\Framework\Phrase; class Changelog implements ChangelogInterface diff --git a/lib/internal/Magento/Framework/Notification/MessageList.php b/lib/internal/Magento/Framework/Notification/MessageList.php index 8fb91890b2ff0..ac753b48c8944 100644 --- a/lib/internal/Magento/Framework/Notification/MessageList.php +++ b/lib/internal/Magento/Framework/Notification/MessageList.php @@ -72,7 +72,7 @@ protected function _loadMessages() public function getMessageByIdentity($identity) { $this->_loadMessages(); - return isset($this->_messages[$identity]) ? $this->_messages[$identity] : null; + return $this->_messages[$identity] ?? null; } /** diff --git a/lib/internal/Magento/Framework/ObjectManager/DefinitionFactory.php b/lib/internal/Magento/Framework/ObjectManager/DefinitionFactory.php index e4e82fc1ac7b3..492af22815311 100644 --- a/lib/internal/Magento/Framework/ObjectManager/DefinitionFactory.php +++ b/lib/internal/Magento/Framework/ObjectManager/DefinitionFactory.php @@ -6,10 +6,7 @@ namespace Magento\Framework\ObjectManager; use Magento\Framework\Filesystem\DriverInterface; -use Magento\Framework\Interception\Code\Generator as InterceptionGenerator; use Magento\Framework\ObjectManager\Definition\Runtime; -use Magento\Framework\ObjectManager\Profiler\Code\Generator as ProfilerGenerator; -use Magento\Framework\Serialize\SerializerInterface; use Magento\Framework\Code\Generator\Autoloader; /** diff --git a/lib/internal/Magento/Framework/ObjectManager/Test/Unit/Code/Generator/RepositoryTest.php b/lib/internal/Magento/Framework/ObjectManager/Test/Unit/Code/Generator/RepositoryTest.php index 1ca755b1281ec..72eccbc5e7dea 100644 --- a/lib/internal/Magento/Framework/ObjectManager/Test/Unit/Code/Generator/RepositoryTest.php +++ b/lib/internal/Magento/Framework/ObjectManager/Test/Unit/Code/Generator/RepositoryTest.php @@ -6,7 +6,6 @@ namespace Magento\Framework\ObjectManager\Test\Unit\Code\Generator; use Magento\Framework\Api\Test\Unit\Code\Generator\EntityChildTestAbstract; -use Magento\Framework\TestFramework\Unit\Helper\ObjectManager; /** * Class RepositoryTest diff --git a/lib/internal/Magento/Framework/ObjectManager/Test/Unit/Factory/Fixture/Polymorphous.php b/lib/internal/Magento/Framework/ObjectManager/Test/Unit/Factory/Fixture/Polymorphous.php index ebb7d76dcb63c..0c1a2128560f8 100644 --- a/lib/internal/Magento/Framework/ObjectManager/Test/Unit/Factory/Fixture/Polymorphous.php +++ b/lib/internal/Magento/Framework/ObjectManager/Test/Unit/Factory/Fixture/Polymorphous.php @@ -26,6 +26,6 @@ public function __construct() */ public function getArg($key) { - return isset($this->args[$key]) ? $this->args[$key] : null; + return $this->args[$key] ?? null; } } diff --git a/lib/internal/Magento/Framework/ObjectManager/Test/Unit/Helper/CompositeTest.php b/lib/internal/Magento/Framework/ObjectManager/Test/Unit/Helper/CompositeTest.php index 14a40c76bc470..8e3681cab611f 100644 --- a/lib/internal/Magento/Framework/ObjectManager/Test/Unit/Helper/CompositeTest.php +++ b/lib/internal/Magento/Framework/ObjectManager/Test/Unit/Helper/CompositeTest.php @@ -9,7 +9,6 @@ use \Magento\Framework\ObjectManager\Helper\Composite; use Magento\Framework\ObjectManager\Helper\Composite as CompositeHelper; -use Magento\Framework\TestFramework\Unit\Helper\ObjectManager; class CompositeTest extends \PHPUnit\Framework\TestCase { diff --git a/lib/internal/Magento/Framework/Pricing/Amount/Base.php b/lib/internal/Magento/Framework/Pricing/Amount/Base.php index 2664ccc54944c..d055819a4a126 100644 --- a/lib/internal/Magento/Framework/Pricing/Amount/Base.php +++ b/lib/internal/Magento/Framework/Pricing/Amount/Base.php @@ -105,9 +105,7 @@ public function getBaseAmount() */ public function getAdjustmentAmount($adjustmentCode) { - return isset($this->adjustmentAmounts[$adjustmentCode]) - ? $this->adjustmentAmounts[$adjustmentCode] - : false; + return $this->adjustmentAmounts[$adjustmentCode] ?? false; } /** diff --git a/lib/internal/Magento/Framework/Pricing/Price/Pool.php b/lib/internal/Magento/Framework/Pricing/Price/Pool.php index b460113fc32c8..dfdd0c52681e1 100644 --- a/lib/internal/Magento/Framework/Pricing/Price/Pool.php +++ b/lib/internal/Magento/Framework/Pricing/Price/Pool.php @@ -141,6 +141,6 @@ public function offsetUnset($offset) */ public function offsetGet($offset) { - return isset($this->prices[$offset]) ? $this->prices[$offset] : null; + return $this->prices[$offset] ?? null; } } diff --git a/lib/internal/Magento/Framework/Reflection/CustomAttributesProcessor.php b/lib/internal/Magento/Framework/Reflection/CustomAttributesProcessor.php index 4fd3a17fb6c6a..18308724c0226 100644 --- a/lib/internal/Magento/Framework/Reflection/CustomAttributesProcessor.php +++ b/lib/internal/Magento/Framework/Reflection/CustomAttributesProcessor.php @@ -6,11 +6,8 @@ namespace Magento\Framework\Reflection; -use Magento\Framework\Phrase; use Magento\Framework\Api\AttributeInterface; use Magento\Framework\Api\AttributeValue; -use Magento\Framework\Api\SimpleDataObjectConverter; -use Zend\Code\Reflection\MethodReflection; use Magento\Framework\Api\CustomAttributesDataInterface; use Magento\Framework\Api\AttributeTypeResolverInterface; diff --git a/lib/internal/Magento/Framework/Reflection/ExtensionAttributesProcessor.php b/lib/internal/Magento/Framework/Reflection/ExtensionAttributesProcessor.php index 3e9eef4fd7b15..aa978e7f337cc 100644 --- a/lib/internal/Magento/Framework/Reflection/ExtensionAttributesProcessor.php +++ b/lib/internal/Magento/Framework/Reflection/ExtensionAttributesProcessor.php @@ -11,7 +11,6 @@ use Magento\Framework\AuthorizationInterface; use Magento\Framework\Phrase; use Magento\Framework\Api\ExtensionAttributesInterface; -use Magento\Framework\Reflection\MethodsMap; use Zend\Code\Reflection\MethodReflection; /** diff --git a/lib/internal/Magento/Framework/Reflection/FieldNamer.php b/lib/internal/Magento/Framework/Reflection/FieldNamer.php index 8e4d077c52e08..a208764352f58 100644 --- a/lib/internal/Magento/Framework/Reflection/FieldNamer.php +++ b/lib/internal/Magento/Framework/Reflection/FieldNamer.php @@ -6,12 +6,7 @@ namespace Magento\Framework\Reflection; -use Magento\Framework\Phrase; -use Magento\Framework\Api\AttributeValue; -use Magento\Framework\Api\CustomAttributesDataInterface; use Magento\Framework\Api\SimpleDataObjectConverter; -use Zend\Code\Reflection\ClassReflection; -use Zend\Code\Reflection\MethodReflection; /** * Determines the name to use for fields in a data output array given method metadata. diff --git a/lib/internal/Magento/Framework/Reflection/Test/Unit/NameFinderTest.php b/lib/internal/Magento/Framework/Reflection/Test/Unit/NameFinderTest.php index a467c4b7b5aad..e4c0294c0cfb5 100644 --- a/lib/internal/Magento/Framework/Reflection/Test/Unit/NameFinderTest.php +++ b/lib/internal/Magento/Framework/Reflection/Test/Unit/NameFinderTest.php @@ -7,7 +7,6 @@ namespace Magento\Framework\Reflection\Test\Unit; use Zend\Code\Reflection\ClassReflection; -use Magento\Framework\Exception\SerializationException; /** * NameFinder Unit Test diff --git a/lib/internal/Magento/Framework/Search/Adapter/Mysql/Adapter.php b/lib/internal/Magento/Framework/Search/Adapter/Mysql/Adapter.php index 098782b4e814e..11bd746eb71e5 100644 --- a/lib/internal/Magento/Framework/Search/Adapter/Mysql/Adapter.php +++ b/lib/internal/Magento/Framework/Search/Adapter/Mysql/Adapter.php @@ -7,7 +7,6 @@ use Magento\Framework\App\ResourceConnection; use Magento\Framework\DB\Ddl\Table; -use Magento\Framework\DB\Select; use Magento\Framework\Search\Adapter\Mysql\Aggregation\Builder as AggregationBuilder; use Magento\Framework\Search\AdapterInterface; use Magento\Framework\Search\RequestInterface; @@ -70,7 +69,7 @@ public function __construct( } /** - * {@inheritdoc} + * @inheritdoc * @throws \LogicException */ public function query(RequestInterface $request) diff --git a/lib/internal/Magento/Framework/Search/Adapter/Mysql/Aggregation/Builder/Term.php b/lib/internal/Magento/Framework/Search/Adapter/Mysql/Aggregation/Builder/Term.php index ed3018756cdd6..78ff7b04fd39c 100644 --- a/lib/internal/Magento/Framework/Search/Adapter/Mysql/Aggregation/Builder/Term.php +++ b/lib/internal/Magento/Framework/Search/Adapter/Mysql/Aggregation/Builder/Term.php @@ -6,7 +6,6 @@ namespace Magento\Framework\Search\Adapter\Mysql\Aggregation\Builder; use Magento\Framework\DB\Ddl\Table; -use Magento\Framework\DB\Select; use Magento\Framework\Search\Adapter\Mysql\Aggregation\DataProviderInterface; use Magento\Framework\Search\Request\BucketInterface as RequestBucketInterface; diff --git a/lib/internal/Magento/Framework/Search/Request/IndexScopeResolverInterface.php b/lib/internal/Magento/Framework/Search/Request/IndexScopeResolverInterface.php index d9412cb8517fa..9e907883bb2b9 100644 --- a/lib/internal/Magento/Framework/Search/Request/IndexScopeResolverInterface.php +++ b/lib/internal/Magento/Framework/Search/Request/IndexScopeResolverInterface.php @@ -6,8 +6,8 @@ namespace Magento\Framework\Search\Request; /** - * Interface \Magento\Framework\Search\Request\IndexScopeResolverInterface - * + * Resolve table name by provided dimensions. Scope Resolver must accept all dimensions that potentially can be used to + * resolve table name, but certain implementation can filter them if needed */ interface IndexScopeResolverInterface { diff --git a/lib/internal/Magento/Framework/Search/Response/Aggregation.php b/lib/internal/Magento/Framework/Search/Response/Aggregation.php index 9cb7a364ff21c..ea72597c53034 100644 --- a/lib/internal/Magento/Framework/Search/Response/Aggregation.php +++ b/lib/internal/Magento/Framework/Search/Response/Aggregation.php @@ -47,7 +47,7 @@ public function getIterator() */ public function getBucket($bucketName) { - return isset($this->buckets[$bucketName]) ? $this->buckets[$bucketName] : null; + return $this->buckets[$bucketName] ?? null; } /** diff --git a/lib/internal/Magento/Framework/Search/Test/Unit/Adapter/Mysql/AdapterTest.php b/lib/internal/Magento/Framework/Search/Test/Unit/Adapter/Mysql/AdapterTest.php index ef4a4d62322ed..55d26493ca379 100644 --- a/lib/internal/Magento/Framework/Search/Test/Unit/Adapter/Mysql/AdapterTest.php +++ b/lib/internal/Magento/Framework/Search/Test/Unit/Adapter/Mysql/AdapterTest.php @@ -6,7 +6,6 @@ namespace Magento\Framework\Search\Test\Unit\Adapter\Mysql; -use Magento\Framework\App\ResourceConnection; use Magento\Framework\Search\Request\BucketInterface; use Magento\Framework\TestFramework\Unit\Helper\ObjectManager; diff --git a/lib/internal/Magento/Framework/Serialize/Test/Unit/Serializer/SerializeTest.php b/lib/internal/Magento/Framework/Serialize/Test/Unit/Serializer/SerializeTest.php index 1f8e7cf9d0bc3..aac25400cec85 100644 --- a/lib/internal/Magento/Framework/Serialize/Test/Unit/Serializer/SerializeTest.php +++ b/lib/internal/Magento/Framework/Serialize/Test/Unit/Serializer/SerializeTest.php @@ -7,7 +7,6 @@ use Magento\Framework\Serialize\Serializer\Serialize; use Magento\Framework\Serialize\Signer; -use Psr\Log\LoggerInterface; use Magento\Framework\Serialize\InvalidSignatureException; class SerializeTest extends \PHPUnit\Framework\TestCase diff --git a/lib/internal/Magento/Framework/Session/SaveHandler/DbTable.php b/lib/internal/Magento/Framework/Session/SaveHandler/DbTable.php index 6f5937e08455d..cf3449a8c3fcf 100644 --- a/lib/internal/Magento/Framework/Session/SaveHandler/DbTable.php +++ b/lib/internal/Magento/Framework/Session/SaveHandler/DbTable.php @@ -6,7 +6,6 @@ namespace Magento\Framework\Session\SaveHandler; -use Magento\Framework\App\ResourceConnection; use Magento\Framework\Exception\SessionException; use Magento\Framework\Phrase; diff --git a/lib/internal/Magento/Framework/Session/SaveHandler/Redis.php b/lib/internal/Magento/Framework/Session/SaveHandler/Redis.php index 53af1847d1012..cd1cef5da6ddd 100644 --- a/lib/internal/Magento/Framework/Session/SaveHandler/Redis.php +++ b/lib/internal/Magento/Framework/Session/SaveHandler/Redis.php @@ -14,13 +14,28 @@ use Magento\Framework\Filesystem; use Magento\Framework\App\Filesystem\DirectoryList; -class Redis extends \Cm\RedisSession\Handler +class Redis implements \SessionHandlerInterface { + /** + * @var ConfigInterface + */ + private $config; + + /** + * @var LoggerInterface + */ + private $logger; + /** * @var Filesystem */ private $filesystem; + /** + * @var \Cm\RedisSession\Handler[] + */ + private $connection; + /** * @param ConfigInterface $config * @param LoggerInterface $logger @@ -29,23 +44,117 @@ class Redis extends \Cm\RedisSession\Handler */ public function __construct(ConfigInterface $config, LoggerInterface $logger, Filesystem $filesystem) { + $this->config = $config; + $this->logger = $logger; $this->filesystem = $filesystem; - try { - parent::__construct($config, $logger); - } catch (ConnectionFailedException $e) { - throw new SessionException(new Phrase($e->getMessage())); + } + + /** + * Get connection + * + * @return \Cm\RedisSession\Handler + * @throws SessionException + */ + private function getConnection() + { + $pid = getmypid(); + if (!isset($this->connection[$pid])) { + try { + $this->connection[$pid] = new \Cm\RedisSession\Handler($this->config, $this->logger); + } catch (ConnectionFailedException $e) { + throw new SessionException(new Phrase($e->getMessage())); + } } + return $this->connection[$pid]; } /** - * {@inheritdoc} + * Open session + * + * @param string $savePath ignored + * @param string $sessionName ignored + * @return bool + * @throws SessionException + */ + public function open($savePath, $sessionName) + { + return $this->getConnection()->open($savePath, $sessionName); + } + + /** + * Fetch session data + * + * @param string $sessionId + * @return string + * @throws ConcurrentConnectionsExceededException + * @throws SessionException */ public function read($sessionId) { try { - return parent::read($sessionId); + return $this->getConnection()->read($sessionId); } catch (ConcurrentConnectionsExceededException $e) { require $this->filesystem->getDirectoryRead(DirectoryList::PUB)->getAbsolutePath('errors/503.php'); } } + + /** + * Update session + * + * @param string $sessionId + * @param string $sessionData + * @return boolean + * @throws SessionException + */ + public function write($sessionId, $sessionData) + { + return $this->getConnection()->write($sessionId, $sessionData); + } + + /** + * Destroy session + * + * @param string $sessionId + * @return boolean + * @throws SessionException + */ + public function destroy($sessionId) + { + return $this->getConnection()->destroy($sessionId); + } + + /** + * Overridden to prevent calling getLifeTime at shutdown + * + * @return bool + * @throws SessionException + */ + public function close() + { + return $this->getConnection()->close(); + } + + /** + * Garbage collection + * + * @param int $maxLifeTime ignored + * @return boolean + * @throws SessionException + * @SuppressWarnings(PHPMD.ShortMethodName) + */ + public function gc($maxLifeTime) + { + return $this->getConnection()->gc($maxLifeTime); + } + + /** + * Get the number of failed lock attempts + * + * @return int + * @throws SessionException + */ + public function getFailedLockAttempts() + { + return $this->getConnection()->getFailedLockAttempts(); + } } diff --git a/lib/internal/Magento/Framework/Session/SessionManager.php b/lib/internal/Magento/Framework/Session/SessionManager.php index e4130147a5da0..662173ad4a09a 100644 --- a/lib/internal/Magento/Framework/Session/SessionManager.php +++ b/lib/internal/Magento/Framework/Session/SessionManager.php @@ -473,7 +473,7 @@ protected function _addHost() */ protected function _getHosts() { - return isset($_SESSION[self::HOST_KEY]) ? $_SESSION[self::HOST_KEY] : []; + return $_SESSION[self::HOST_KEY] ?? []; } /** diff --git a/lib/internal/Magento/Framework/Session/Test/Unit/SaveHandler/Redis/LoggerTest.php b/lib/internal/Magento/Framework/Session/Test/Unit/SaveHandler/Redis/LoggerTest.php index 4594a471e008d..a604178bc36cc 100644 --- a/lib/internal/Magento/Framework/Session/Test/Unit/SaveHandler/Redis/LoggerTest.php +++ b/lib/internal/Magento/Framework/Session/Test/Unit/SaveHandler/Redis/LoggerTest.php @@ -6,7 +6,6 @@ namespace Magento\Framework\Session\Test\Unit\SaveHandler\Redis; use Cm\RedisSession\Handler\LoggerInterface; -use Magento\Framework\Session\SaveHandler\Redis\Logger; class LoggerTest extends \PHPUnit\Framework\TestCase { diff --git a/lib/internal/Magento/Framework/Stdlib/Test/Unit/Cookie/_files/setcookie_mock.php b/lib/internal/Magento/Framework/Stdlib/Test/Unit/Cookie/_files/setcookie_mock.php index e97dfab795c59..f89144f9753db 100644 --- a/lib/internal/Magento/Framework/Stdlib/Test/Unit/Cookie/_files/setcookie_mock.php +++ b/lib/internal/Magento/Framework/Stdlib/Test/Unit/Cookie/_files/setcookie_mock.php @@ -6,7 +6,6 @@ namespace Magento\Framework\Stdlib\Cookie; -use \Magento\Framework\Stdlib\Cookie\PhpCookieManager; use \Magento\Framework\Stdlib\Test\Unit\Cookie\PhpCookieManagerTest; /** diff --git a/lib/internal/Magento/Framework/System/Dirs.php b/lib/internal/Magento/Framework/System/Dirs.php index 1bab4c90b3bec..6328921d40bb0 100644 --- a/lib/internal/Magento/Framework/System/Dirs.php +++ b/lib/internal/Magento/Framework/System/Dirs.php @@ -5,8 +5,6 @@ */ namespace Magento\Framework\System; -use Magento\Framework\Filesystem\DriverInterface; - class Dirs { /** diff --git a/lib/internal/Magento/Framework/System/Ftp.php b/lib/internal/Magento/Framework/System/Ftp.php index 827e524a62464..8bf898965cbc3 100644 --- a/lib/internal/Magento/Framework/System/Ftp.php +++ b/lib/internal/Magento/Framework/System/Ftp.php @@ -6,8 +6,6 @@ namespace Magento\Framework\System; -use Magento\Framework\Filesystem\DriverInterface; - /** * Class to work with remote FTP server */ diff --git a/lib/internal/Magento/Framework/Url.php b/lib/internal/Magento/Framework/Url.php index 11f828370d441..11aeb1c0c79b8 100644 --- a/lib/internal/Magento/Framework/Url.php +++ b/lib/internal/Magento/Framework/Url.php @@ -1074,7 +1074,7 @@ function ($match) { if ($match[1] == '?') { return isset($match[3]) ? '?' : ''; } elseif ($match[1] == '&' || $match[1] == '&') { - return isset($match[3]) ? $match[3] : ''; + return $match[3] ?? ''; } } }, diff --git a/lib/internal/Magento/Framework/Validator/Exception.php b/lib/internal/Magento/Framework/Validator/Exception.php index c70ecfabb52af..370f66c424b01 100644 --- a/lib/internal/Magento/Framework/Validator/Exception.php +++ b/lib/internal/Magento/Framework/Validator/Exception.php @@ -84,6 +84,6 @@ public function getMessages($type = '') } return $allMessages; } - return isset($this->messages[$type]) ? $this->messages[$type] : []; + return $this->messages[$type] ?? []; } } diff --git a/lib/internal/Magento/Framework/View/Asset/PreProcessor/AlternativeSource.php b/lib/internal/Magento/Framework/View/Asset/PreProcessor/AlternativeSource.php index 38f2b220dee6f..7016bbdb08ab2 100644 --- a/lib/internal/Magento/Framework/View/Asset/PreProcessor/AlternativeSource.php +++ b/lib/internal/Magento/Framework/View/Asset/PreProcessor/AlternativeSource.php @@ -5,7 +5,6 @@ */ namespace Magento\Framework\View\Asset\PreProcessor; -use Magento\Framework\Filesystem; use Magento\Framework\ObjectManagerInterface; use Magento\Framework\View\Asset\File\FallbackContext; use Magento\Framework\View\Asset\LockerProcessInterface; diff --git a/lib/internal/Magento/Framework/View/Asset/PropertyGroup.php b/lib/internal/Magento/Framework/View/Asset/PropertyGroup.php index ad86dfca47a25..4fe8f48d6b723 100644 --- a/lib/internal/Magento/Framework/View/Asset/PropertyGroup.php +++ b/lib/internal/Magento/Framework/View/Asset/PropertyGroup.php @@ -45,6 +45,6 @@ public function getProperties() */ public function getProperty($name) { - return isset($this->properties[$name]) ? $this->properties[$name] : null; + return $this->properties[$name] ?? null; } } diff --git a/lib/internal/Magento/Framework/View/BlockPool.php b/lib/internal/Magento/Framework/View/BlockPool.php index c50af9d5bbc5f..dff280057fdaf 100644 --- a/lib/internal/Magento/Framework/View/BlockPool.php +++ b/lib/internal/Magento/Framework/View/BlockPool.php @@ -72,6 +72,6 @@ public function get($name = null) return $this->blocks; } - return isset($this->blocks[$name]) ? $this->blocks[$name] : null; + return $this->blocks[$name] ?? null; } } diff --git a/lib/internal/Magento/Framework/View/DataSourcePool.php b/lib/internal/Magento/Framework/View/DataSourcePool.php index 24bdb6639981b..94f4f1dceae97 100644 --- a/lib/internal/Magento/Framework/View/DataSourcePool.php +++ b/lib/internal/Magento/Framework/View/DataSourcePool.php @@ -80,7 +80,7 @@ public function get($name = null) return $this->dataSources; } - return isset($this->dataSources[$name]) ? $this->dataSources[$name] : null; + return $this->dataSources[$name] ?? null; } /** @@ -107,6 +107,6 @@ public function assign($dataName, $namespace, $alias) */ public function getNamespaceData($namespace) { - return isset($this->assignments[$namespace]) ? $this->assignments[$namespace] : []; + return $this->assignments[$namespace] ?? []; } } diff --git a/lib/internal/Magento/Framework/View/Design/Theme/Validator.php b/lib/internal/Magento/Framework/View/Design/Theme/Validator.php index 06c78e7125040..04e775d730b56 100644 --- a/lib/internal/Magento/Framework/View/Design/Theme/Validator.php +++ b/lib/internal/Magento/Framework/View/Design/Theme/Validator.php @@ -118,7 +118,7 @@ public function addDataValidators($dataKey, $validators) public function getErrorMessages($dataKey = null) { if ($dataKey) { - return isset($this->_errorMessages[$dataKey]) ? $this->_errorMessages[$dataKey] : []; + return $this->_errorMessages[$dataKey] ?? []; } return $this->_errorMessages; } diff --git a/lib/internal/Magento/Framework/View/Element/AbstractBlock.php b/lib/internal/Magento/Framework/View/Element/AbstractBlock.php index 0ffa9dce7f730..b2f857bf29f45 100644 --- a/lib/internal/Magento/Framework/View/Element/AbstractBlock.php +++ b/lib/internal/Magento/Framework/View/Element/AbstractBlock.php @@ -1074,7 +1074,7 @@ protected function getCacheLifetime() $cacheLifetime = $this->getData('cache_lifetime'); if (false === $cacheLifetime || null === $cacheLifetime) { - return $cacheLifetime; + return null; } return (int)$cacheLifetime; diff --git a/lib/internal/Magento/Framework/View/Element/UiComponent/Context.php b/lib/internal/Magento/Framework/View/Element/UiComponent/Context.php index 73f125be77c79..48a66b429ebd5 100644 --- a/lib/internal/Magento/Framework/View/Element/UiComponent/Context.php +++ b/lib/internal/Magento/Framework/View/Element/UiComponent/Context.php @@ -213,7 +213,7 @@ public function getFiltersParams() public function getFilterParam($key, $defaultValue = null) { $filter = $this->getFiltersParams(); - return isset($filter[$key]) ? $filter[$key] : $defaultValue; + return $filter[$key] ?? $defaultValue; } /** diff --git a/lib/internal/Magento/Framework/View/Element/UiComponent/DataProvider/DataProvider.php b/lib/internal/Magento/Framework/View/Element/UiComponent/DataProvider/DataProvider.php index b2288a47f8f83..baa4e94eed978 100644 --- a/lib/internal/Magento/Framework/View/Element/UiComponent/DataProvider/DataProvider.php +++ b/lib/internal/Magento/Framework/View/Element/UiComponent/DataProvider/DataProvider.php @@ -181,7 +181,7 @@ public function getMeta() */ public function getFieldSetMetaInfo($fieldSetName) { - return isset($this->meta[$fieldSetName]) ? $this->meta[$fieldSetName] : []; + return $this->meta[$fieldSetName] ?? []; } /** @@ -190,7 +190,7 @@ public function getFieldSetMetaInfo($fieldSetName) */ public function getFieldsMetaInfo($fieldSetName) { - return isset($this->meta[$fieldSetName]['children']) ? $this->meta[$fieldSetName]['children'] : []; + return $this->meta[$fieldSetName]['children'] ?? []; } /** @@ -200,9 +200,7 @@ public function getFieldsMetaInfo($fieldSetName) */ public function getFieldMetaInfo($fieldSetName, $fieldName) { - return isset($this->meta[$fieldSetName]['children'][$fieldName]) - ? $this->meta[$fieldSetName]['children'][$fieldName] - : []; + return $this->meta[$fieldSetName]['children'][$fieldName] ?? []; } /** @@ -291,7 +289,7 @@ public function getData() */ public function getConfigData() { - return isset($this->data['config']) ? $this->data['config'] : []; + return $this->data['config'] ?? []; } /** diff --git a/lib/internal/Magento/Framework/View/Layout.php b/lib/internal/Magento/Framework/View/Layout.php index bd94491537efe..5cd7591098207 100755 --- a/lib/internal/Magento/Framework/View/Layout.php +++ b/lib/internal/Magento/Framework/View/Layout.php @@ -13,7 +13,6 @@ use Magento\Framework\Message\ManagerInterface as MessageManagerInterface; use Magento\Framework\Serialize\SerializerInterface; use Magento\Framework\View\Layout\Element; -use Magento\Framework\View\Layout\ScheduledStructure; use Psr\Log\LoggerInterface as Logger; /** diff --git a/lib/internal/Magento/Framework/View/Layout/Generic.php b/lib/internal/Magento/Framework/View/Layout/Generic.php index b83545ff3c439..b527d1a817a96 100644 --- a/lib/internal/Magento/Framework/View/Layout/Generic.php +++ b/lib/internal/Magento/Framework/View/Layout/Generic.php @@ -200,6 +200,6 @@ protected function createChildFormComponent(UiComponentInterface $childComponent */ protected function getConfig($name) { - return isset($this->data['config'][$name]) ? $this->data['config'][$name] : null; + return $this->data['config'][$name] ?? null; } } diff --git a/lib/internal/Magento/Framework/View/Layout/ScheduledStructure.php b/lib/internal/Magento/Framework/View/Layout/ScheduledStructure.php index 25a04845a0728..3193e10282fd4 100644 --- a/lib/internal/Magento/Framework/View/Layout/ScheduledStructure.php +++ b/lib/internal/Magento/Framework/View/Layout/ScheduledStructure.php @@ -146,7 +146,7 @@ public function unsetElementToSort($elementName) */ public function getElementToSort($elementName, array $default = []) { - return isset($this->elementsToSort[$elementName]) ? $this->elementsToSort[$elementName] : $default; + return $this->elementsToSort[$elementName] ?? $default; } /** @@ -257,7 +257,7 @@ public function unsetElement($elementName) */ public function getElementToMove($elementName, $default = null) { - return isset($this->scheduledMoves[$elementName]) ? $this->scheduledMoves[$elementName] : $default; + return $this->scheduledMoves[$elementName] ?? $default; } /** @@ -370,7 +370,7 @@ public function unsetStructureElement($elementName) */ public function getStructureElementData($elementName, $default = null) { - return isset($this->scheduledData[$elementName]) ? $this->scheduledData[$elementName] : $default; + return $this->scheduledData[$elementName] ?? $default; } /** @@ -524,6 +524,6 @@ public function populateWithArray(array $data) */ private function getArrayValueByKey($key, array $array) { - return isset($array[$key]) ? $array[$key] : []; + return $array[$key] ?? []; } } diff --git a/lib/internal/Magento/Framework/View/Page/Config.php b/lib/internal/Magento/Framework/View/Page/Config.php index d42d30e35cc5b..1a21e61f867d8 100644 --- a/lib/internal/Magento/Framework/View/Page/Config.php +++ b/lib/internal/Magento/Framework/View/Page/Config.php @@ -508,7 +508,7 @@ public function setElementAttribute($elementType, $attribute, $value) public function getElementAttribute($elementType, $attribute) { $this->build(); - return isset($this->elements[$elementType][$attribute]) ? $this->elements[$elementType][$attribute] : null; + return $this->elements[$elementType][$attribute] ?? null; } /** @@ -518,7 +518,7 @@ public function getElementAttribute($elementType, $attribute) public function getElementAttributes($elementType) { $this->build(); - return isset($this->elements[$elementType]) ? $this->elements[$elementType] : []; + return $this->elements[$elementType] ?? []; } /** diff --git a/lib/internal/Magento/Framework/View/Test/Unit/Element/AbstractBlockTest.php b/lib/internal/Magento/Framework/View/Test/Unit/Element/AbstractBlockTest.php index 70233c0196dc5..5f7508438a6ed 100644 --- a/lib/internal/Magento/Framework/View/Test/Unit/Element/AbstractBlockTest.php +++ b/lib/internal/Magento/Framework/View/Test/Unit/Element/AbstractBlockTest.php @@ -290,9 +290,9 @@ public function getCacheLifetimeDataProvider() 'dataFromCache' => 'dataFromCache', 'dataForSaveCache' => '', 'expectsDispatchEvent' => $this->exactly(2), - 'expectsCacheLoad' => $this->once(), + 'expectsCacheLoad' => $this->never(), 'expectsCacheSave' => $this->never(), - 'expectedResult' => 'dataFromCache', + 'expectedResult' => '', ], [ 'cacheLifetime' => 120, diff --git a/lib/internal/Magento/Framework/View/Test/Unit/Url/_files/sourceImport.css b/lib/internal/Magento/Framework/View/Test/Unit/Url/_files/sourceImport.css index d7ce9e81258db..420083613705f 100644 --- a/lib/internal/Magento/Framework/View/Test/Unit/Url/_files/sourceImport.css +++ b/lib/internal/Magento/Framework/View/Test/Unit/Url/_files/sourceImport.css @@ -2,8 +2,8 @@ * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ -body {background: url(body.gif);} @import url(../recursive.css); -p {background: url(1.gif?param);} @import url("deep/recursive.css"); +body {background: url(body.gif);} +p {background: url(1.gif?param);} h1 {background: url('../h1.gif#param');} h2 {background: url(../images/h2.gif?test);} diff --git a/lib/internal/Magento/Framework/Webapi/ServiceOutputProcessor.php b/lib/internal/Magento/Framework/Webapi/ServiceOutputProcessor.php index d8e1a3de3670a..cdb6ed799aade 100644 --- a/lib/internal/Magento/Framework/Webapi/ServiceOutputProcessor.php +++ b/lib/internal/Magento/Framework/Webapi/ServiceOutputProcessor.php @@ -9,7 +9,6 @@ use Magento\Framework\Api\ExtensibleDataObjectConverter; use Magento\Framework\Reflection\DataObjectProcessor; use Magento\Framework\Reflection\MethodsMap; -use Magento\Framework\Webapi\ServicePayloadConverterInterface; /** * Data object converter diff --git a/lib/internal/Magento/Framework/Xml/Generator.php b/lib/internal/Magento/Framework/Xml/Generator.php index 975073e443d0e..f165793c2e2a4 100644 --- a/lib/internal/Magento/Framework/Xml/Generator.php +++ b/lib/internal/Magento/Framework/Xml/Generator.php @@ -146,8 +146,6 @@ public function setIndexedArrayItemName($name) */ protected function _getIndexedArrayItemName() { - return isset($this->_defaultIndexedArrayItemName) - ? $this->_defaultIndexedArrayItemName - : self::DEFAULT_ENTITY_ITEM_NAME; + return $this->_defaultIndexedArrayItemName ?? self::DEFAULT_ENTITY_ITEM_NAME; } } diff --git a/lib/internal/Magento/Framework/Xml/Security.php b/lib/internal/Magento/Framework/Xml/Security.php index e502429e4511a..ec901a63ea862 100644 --- a/lib/internal/Magento/Framework/Xml/Security.php +++ b/lib/internal/Magento/Framework/Xml/Security.php @@ -6,7 +6,6 @@ namespace Magento\Framework\Xml; use DOMDocument; -use Magento\Framework\Phrase; /** * Class Security diff --git a/lib/web/css/docs/actions-toolbar.html b/lib/web/css/docs/actions-toolbar.html index 4a3fbe515ca95..0c2186bf0458c 100644 --- a/lib/web/css/docs/actions-toolbar.html +++ b/lib/web/css/docs/actions-toolbar.html @@ -301,4 +301,4 @@ .example-actions-toolbar-12 { .lib-actions-toolbar-clear-floats(); } -}</code></pre></div></article></section><div class="bar bottom"><div hidden class="settings container"><!-- Icons from http://iconmonstr.com--><button title="Desktop (1280)" data-width='1280'><svg viewBox="0 0 412 386" height="24" width="26" class="icon"><path d="m147.6,343.9c-4.5,15.9-26.2,37.6-42.1,42.1h201c-15.3,-4-38.1,-26.8-42.1,-42.1H147.6zM387,0.5H25c-13.8,0-25,11.2-25,25V294c0,13.8 11.2,25 25,25h362c13.8,0 25,-11.2 25,-25V25.5C412,11.7 400.8,0.5 387,0.5zM369.9,238.2H42.1L42.1,42.6 369.9,42.6V238.2z"></path></svg></button><button title="Laptop (1024)" data-width='1024'><svg viewBox="0 0 384 312" height="23" width="28" class="icon"><path d="m349.2,20.5c0,-11-9,-20-20,-20H53.6c-11,0-20,9-20,20v194H349.2v-194zm-27,167H60.6V27.5H322.2v160zm28,42H32.6L2.6,282.1c-3.5,6.2-3.5,13.8 0.1,19.9 3.6,6.2 10.2,9.9 17.3,9.9H363.1c7.1,0 13.7,-3.8 17.3,-10 3.6,-6.2 3.6,-13.8 0,-20l-30.2,-52.5zm-196.9,54 8,-23.5h60.5l8,23.5h-76.5z"></path></svg></button><button title="Tablet (768)" data-width='768'><svg viewBox="0 0 317 412" height="24" width="18" class="icon"><path d="M 316.5,380 V 32 c 0,-17.7 -14.3,-32 -32,-32 H 32 C 14.3,0 0,14.3 0,32 v 348 c 0,17.7 14.3,32 32,32 h 252.5 c 17.7,0 32,-14.3 32,-32 z M 40,367 V 45 H 276.5 V 367 H 40 z m 109.8,22.7 c 0,-4.7 3.8,-8.5 8.5,-8.5 4.7,0 8.5,3.8 8.5,8.5 0,4.7 -3.8,8.5 -8.5,8.5 -4.7,0 -8.5,-3.8 -8.5,-8.5 z"></path></svg></button><button title="Smart phone (320)" data-width='320'><svg viewBox="0 0 224 412" height="24" width="13" class="icon"><path d="M 190.7,0 H 33 C 14.8,0 0,14.8 0,33 v 346 c 0,18.2 14.8,33 33,33 h 157.7 c 18.2,0 33,-14.8 33,-33 V 33 c 0,-18.2 -14.8,-33 -33,-33 z M 94.3,30.2 h 37 c 2.2,0 4,1.8 4,4 0,2.2 -1.8,4 -4,4 h -37 c -2.2,0 -4,-1.8 -4,-4 0,-2.2 1.8,-4 4,-4 z m 18.5,362.8 c -8.8,0 -16,-7.2 -16,-16 0,-8.8 7.2,-16 16,-16 8.8,0 16,7.2 16,16 0,8.8 -7.2,16 -16,16 z M 198.6,343.8 H 25.1 V 68.2 h 173.5 v 275.5 z"></path></svg></button><button title="Feature phone (240)" data-width='240'><svg viewBox="0 0 201 412" height="24" width="12" class="icon"><path d="M 165.5,0.2 V 45 H 25 c -13.8,0 -25,11.2 -25,25 V 387 c 0,13.8 11.2,25 25,25 h 150.5 c 13.8,0 25,-11.2 25,-25 V 0.2 h -35 z M 65.2,366.5 H 34.2 v -24.5 h 31 v 24.5 z m 0,-44.3 H 34.2 v -24.5 h 31 v 24.5 z m 50.5,44.3 H 84.7 v -24.5 h 31 v 24.5 z m 0,-44.3 H 84.7 v -24.5 h 31 v 24.5 z m 50.5,44.3 h -31 v -24.5 h 31 v 24.5 z m 0,-44.3 h -31 v -24.5 h 31 v 24.5 z m 0,-59.3 h -132 V 95.4 h 132 V 262.9 z"></path></svg></button><button title="Auto (100%)" data-width="auto" class="auto is-active">Auto</button></div></div><script>(function(){var a=[{title:"actions-toolbar",filename:"actions-toolbar",url:"actions-toolbar.html"},{title:"Actions toolbar",filename:"actions-toolbar",url:"actions-toolbar.html#actions-toolbar"},{title:"Actions toolbar mixin variables",filename:"actions-toolbar",url:"actions-toolbar.html#actions-toolbar-mixin-variables"},{title:"Actions toolbar alignment",filename:"actions-toolbar",url:"actions-toolbar.html#actions-toolbar-alignment"},{title:"Reverse primary and secondary blocks",filename:"actions-toolbar",url:"actions-toolbar.html#reverse-primary-and-secondary-blocks"},{title:"Actions toolbar indents customizations",filename:"actions-toolbar",url:"actions-toolbar.html#actions-toolbar-indents-customizations"},{title:"Responsive actions toolbar",filename:"actions-toolbar",url:"actions-toolbar.html#responsive-actions-toolbar"},{title:"breadcrumbs",filename:"breadcrumbs",url:"breadcrumbs.html"},{title:"Breadcrumbs",filename:"breadcrumbs",url:"breadcrumbs.html#breadcrumbs"},{title:"Breadcrumbs variables",filename:"breadcrumbs",url:"breadcrumbs.html#breadcrumbs-variables"},{title:"Button-styled breadcrumbs with gradient background, border, and no separating symbol",filename:"breadcrumbs",url:"breadcrumbs.html#buttonstyled-breadcrumbs-with-gradient-background-border-and-no-separating-symbol"},{title:"Breadcrumbs with solid background",filename:"breadcrumbs",url:"breadcrumbs.html#breadcrumbs-with-solid-background"},{title:"buttons",filename:"buttons",url:"buttons.html"},{title:"Default button",filename:"buttons",url:"buttons.html#default-button"},{title:"Button variables",filename:"buttons",url:"buttons.html#button-variables"},{title:"Button as an icon",filename:"buttons",url:"buttons.html#button-as-an-icon"},{title:"Button with an icon on the left or right side of the text",filename:"buttons",url:"buttons.html#button-with-an-icon-on-the-left-or-right-side-of-the-text"},{title:"Button with fixed width",filename:"buttons",url:"buttons.html#button-with-fixed-width"},{title:"Primary button",filename:"buttons",url:"buttons.html#primary-button"},{title:"Primary button variables",filename:"buttons",url:"buttons.html#primary-button-variables"},{title:"Button with gradient background",filename:"buttons",url:"buttons.html#button-with-gradient-background"},{title:"Button as a link",filename:"buttons",url:"buttons.html#button-as-a-link"},{title:"Button as a link variables",filename:"buttons",url:"buttons.html#button-as-a-link-variables"},{title:"Link as a button",filename:"buttons",url:"buttons.html#link-as-a-button"},{title:"Button reset",filename:"buttons",url:"buttons.html#button-reset"},{title:"Button revert secondary color",filename:"buttons",url:"buttons.html#button-revert-secondary-color"},{title:"Button revert secondary color variables",filename:"buttons",url:"buttons.html#button-revert-secondary-color-variables"},{title:"Button revert secondary size",filename:"buttons",url:"buttons.html#button-revert-secondary-size"},{title:"Button revert secondary size variables",filename:"buttons",url:"buttons.html#button-revert-secondary-size-variables"},{title:"components",filename:"components",url:"components.html"},{title:"Components",filename:"components",url:"components.html#components"},{title:"Components Variables",filename:"components",url:"components.html#components-variables"},{title:"dropdowns",filename:"dropdowns",url:"dropdowns.html"},{title:"Drop-down and split buttons mixins",filename:"dropdowns",url:"dropdowns.html#dropdown-and-split-buttons-mixins"},{title:"Drop-down",filename:"dropdowns",url:"dropdowns.html#dropdown"},{title:"Drop-down variables",filename:"dropdowns",url:"dropdowns.html#dropdown-variables"},{title:"Drop-down with icon customization",filename:"dropdowns",url:"dropdowns.html#dropdown-with-icon-customization"},{title:"Modify dropdown list styles",filename:"dropdowns",url:"dropdowns.html#modify-dropdown-list-styles"},{title:"Split button",filename:"dropdowns",url:"dropdowns.html#split-button"},{title:"Split button variables",filename:"dropdowns",url:"dropdowns.html#split-button-variables"},{title:"Split button - button styling",filename:"dropdowns",url:"dropdowns.html#split-button-button-styling"},{title:"Split button icon customization",filename:"dropdowns",url:"dropdowns.html#split-button-icon-customization"},{title:"Split button drop-down list customization",filename:"dropdowns",url:"dropdowns.html#split-button-dropdown-list-customization"},{title:"forms",filename:"forms",url:"forms.html"},{title:"Forms mixins",filename:"forms",url:"forms.html#forms-mixins"},{title:"Global forms elements customization",filename:"forms",url:"forms.html#global-forms-elements-customization"},{title:"Fieldsets & fields customization",filename:"forms",url:"forms.html#fieldsets-fields-customization"},{title:"Fieldset and legend customization variables",filename:"forms",url:"forms.html#fieldset-and-legend-customization-variables"},{title:"Fields customization variables",filename:"forms",url:"forms.html#fields-customization-variables"},{title:"Required fields message customization variables",filename:"forms",url:"forms.html#required-fields-message-customization-variables"},{title:"Form element inputs customization",filename:"forms",url:"forms.html#form-element-inputs-customization"},{title:"Form element inputs customization variables",filename:"forms",url:"forms.html#form-element-inputs-customization-variables"},{title:"Form element choice",filename:"forms",url:"forms.html#form-element-choice"},{title:"Form element choice variables",filename:"forms",url:"forms.html#form-element-choice-variables"},{title:"Custom color",filename:"forms",url:"forms.html#custom-color"},{title:"Input number - input-text view",filename:"forms",url:"forms.html#input-number-inputtext-view"},{title:"Input search - input-text view",filename:"forms",url:"forms.html#input-search-inputtext-view"},{title:"Form validation",filename:"forms",url:"forms.html#form-validation"},{title:"Form validation variables",filename:"forms",url:"forms.html#form-validation-variables"},{title:"icons",filename:"icons",url:"icons.html"},{title:"Icons",filename:"icons",url:"icons.html#icons"},{title:"Icon with image or sprite",filename:"icons",url:"icons.html#icon-with-image-or-sprite"},{title:"Icon with image or sprite variables",filename:"icons",url:"icons.html#icon-with-image-or-sprite-variables"},{title:"Icon position for an icon with image or sprite",filename:"icons",url:"icons.html#icon-position-for-an-icon-with-image-or-sprite"},{title:"Position for icon with image or sprite mixin variables",filename:"icons",url:"icons.html#position-for-icon-with-image-or-sprite-mixin-variables"},{title:"Icon sprite position (with grid)",filename:"icons",url:"icons.html#icon-sprite-position-with-grid"},{title:"Icon sprite position variables",filename:"icons",url:"icons.html#icon-sprite-position-variables"},{title:"Image/sprite icon size",filename:"icons",url:"icons.html#imagesprite-icon-size"},{title:"Image/sprite icon size variables",filename:"icons",url:"icons.html#imagesprite-icon-size-variables"},{title:"Font icon",filename:"icons",url:"icons.html#font-icon"},{title:"Font icon variables",filename:"icons",url:"icons.html#font-icon-variables"},{title:"Change the size of font icon",filename:"icons",url:"icons.html#change-the-size-of-font-icon"},{title:"Change the size of font icon variables",filename:"icons",url:"icons.html#change-the-size-of-font-icon-variables"},{title:"Hide icon text",filename:"icons",url:"icons.html#hide-icon-text"},{title:"Sprite and font icons for Blank theme",filename:"icons",url:"icons.html#sprite-and-font-icons-for-blank-theme"},{title:"layout",filename:"layout",url:"layout.html"},{title:"Layout",filename:"layout",url:"layout.html#layout"},{title:"Layout global variables",filename:"layout",url:"layout.html#layout-global-variables"},{title:"Page layouts",filename:"layout",url:"layout.html#page-layouts"},{title:"Layout column",filename:"layout",url:"layout.html#layout-column"},{title:"Layout column variables",filename:"layout",url:"layout.html#layout-column-variables"},{title:"Layout width",filename:"layout",url:"layout.html#layout-width"},{title:"Layout width variables",filename:"layout",url:"layout.html#layout-width-variables"},{title:"lib",filename:"lib",url:"lib.html"},{title:"Including Magento UI library to your theme",filename:"lib",url:"lib.html#including-magento-ui-library-to-your-theme"},{title:"loaders",filename:"loaders",url:"loaders.html"},{title:"Loaders",filename:"loaders",url:"loaders.html#loaders"},{title:"Default loader variables",filename:"loaders",url:"loaders.html#default-loader-variables"},{title:"Loading",filename:"loaders",url:"loaders.html#loading"},{title:"Loading default variables",filename:"loaders",url:"loaders.html#loading-default-variables"},{title:"messages",filename:"messages",url:"messages.html"},{title:"Messages",filename:"messages",url:"messages.html#messages"},{title:"Information message",filename:"messages",url:"messages.html#information-message"},{title:"Warning message",filename:"messages",url:"messages.html#warning-message"},{title:"Error message",filename:"messages",url:"messages.html#error-message"},{title:"Success message",filename:"messages",url:"messages.html#success-message"},{title:"Notice message",filename:"messages",url:"messages.html#notice-message"},{title:"Message with inner icon",filename:"messages",url:"messages.html#message-with-inner-icon"},{title:"Message with lateral icon",filename:"messages",url:"messages.html#message-with-lateral-icon"},{title:"Custom message style",filename:"messages",url:"messages.html#custom-message-style"},{title:"Messages global variables",filename:"messages",url:"messages.html#messages-global-variables"},{title:"pages",filename:"pages",url:"pages.html"},{title:"Pagination HTML markup",filename:"pages",url:"pages.html#pagination-html-markup"},{title:"Pagination variables",filename:"pages",url:"pages.html#pagination-variables"},{title:"Pagination with label and gradient background on links",filename:"pages",url:"pages.html#pagination-with-label-and-gradient-background-on-links"},{title:'Pagination with "previous"..."next" text links and label',filename:"pages",url:"pages.html#pagination-with-previousnext-text-links-and-label"},{title:"Pagination without label, with solid background",filename:"pages",url:"pages.html#pagination-without-label-with-solid-background"},{title:"popups",filename:"popups",url:"popups.html"},{title:"Popups",filename:"popups",url:"popups.html#popups"},{title:"Popup variables",filename:"popups",url:"popups.html#popup-variables"},{title:"Window overlay mixin variables",filename:"popups",url:"popups.html#window-overlay-mixin-variables"},{title:"Fixed height popup",filename:"popups",url:"popups.html#fixed-height-popup"},{title:"Fixed content height popup",filename:"popups",url:"popups.html#fixed-content-height-popup"},{title:"Margins for header, content and footer block in popup",filename:"popups",url:"popups.html#margins-for-header-content-and-footer-block-in-popup"},{title:"Popup titles styled as theme headings",filename:"popups",url:"popups.html#popup-titles-styled-as-theme-headings"},{title:"Popup action toolbar",filename:"popups",url:"popups.html#popup-action-toolbar"},{title:"Popup Close button without an icon",filename:"popups",url:"popups.html#popup-close-button-without-an-icon"},{title:"Modify the icon of popup Close button",filename:"popups",url:"popups.html#modify-the-icon-of-popup-close-button"},{title:"Modify overlay styles",filename:"popups",url:"popups.html#modify-overlay-styles"},{title:"rating",filename:"rating",url:"rating.html"},{title:"Ratings",filename:"rating",url:"rating.html#ratings"},{title:"Global rating variables",filename:"rating",url:"rating.html#global-rating-variables"},{title:"Rating with vote",filename:"rating",url:"rating.html#rating-with-vote"},{title:"Rating with vote icons number customization",filename:"rating",url:"rating.html#rating-with-vote-icons-number-customization"},{title:"Rating with vote icons colors customization",filename:"rating",url:"rating.html#rating-with-vote-icons-colors-customization"},{title:"Rating with vote icons symbol customization",filename:"rating",url:"rating.html#rating-with-vote-icons-symbol-customization"},{title:"Accessible rating with vote",filename:"rating",url:"rating.html#accessible-rating-with-vote"},{title:"Rating summary",filename:"rating",url:"rating.html#rating-summary"},{title:"Rating summary icons number customization",filename:"rating",url:"rating.html#rating-summary-icons-number-customization"},{title:"Rating summary icons color customization",filename:"rating",url:"rating.html#rating-summary-icons-color-customization"},{title:"Rating summary icons symbol customization",filename:"rating",url:"rating.html#rating-summary-icons-symbol-customization"},{title:"Rating summary hide label",filename:"rating",url:"rating.html#rating-summary-hide-label"},{title:"Rating summary multiple ratings",filename:"rating",url:"rating.html#rating-summary-multiple-ratings"},{title:"Rating hide label mixin",filename:"rating",url:"rating.html#rating-hide-label-mixin"},{title:"resets",filename:"resets",url:"resets.html"},{title:"Resets",filename:"resets",url:"resets.html#resets"},{title:"responsive",filename:"responsive",url:"responsive.html"},{title:"Responsive",filename:"responsive",url:"responsive.html#responsive"},{title:"Responsive mixins usage",filename:"responsive",url:"responsive.html#responsive-mixins-usage"},{title:"Media query style groups separation variables",filename:"responsive",url:"responsive.html#media-query-style-groups-separation-variables"},{title:"Responsive breakpoints",filename:"responsive",url:"responsive.html#responsive-breakpoints"},{title:"sections",filename:"sections",url:"sections.html"},{title:"Tabs and accordions",filename:"sections",url:"sections.html#tabs-and-accordions"},{title:"Tabs",filename:"sections",url:"sections.html#tabs"},{title:"Tabs mixin variables",filename:"sections",url:"sections.html#tabs-mixin-variables"},{title:"Tabs with content top border",filename:"sections",url:"sections.html#tabs-with-content-top-border"},{title:"Accordion",filename:"sections",url:"sections.html#accordion"},{title:"Accordion mixin variables",filename:"sections",url:"sections.html#accordion-mixin-variables"},{title:"Responsive tabs",filename:"sections",url:"sections.html#responsive-tabs"},{title:"Tabs Base",filename:"sections",url:"sections.html#tabs-base"},{title:"Accordion Base",filename:"sections",url:"sections.html#accordion-base"},{title:"tables",filename:"tables",url:"tables.html"},{title:"Tables",filename:"tables",url:"tables.html#tables"},{title:"Table mixin variables",filename:"tables",url:"tables.html#table-mixin-variables"},{title:"Table typography",filename:"tables",url:"tables.html#table-typography"},{title:"Table typography mixin variables",filename:"tables",url:"tables.html#table-typography-mixin-variables"},{title:"Table caption",filename:"tables",url:"tables.html#table-caption"},{title:"Table caption mixin variables",filename:"tables",url:"tables.html#table-caption-mixin-variables"},{title:"Table cells resize",filename:"tables",url:"tables.html#table-cells-resize"},{title:"Table cells resize variables",filename:"tables",url:"tables.html#table-cells-resize-variables"},{title:"Table background customization",filename:"tables",url:"tables.html#table-background-customization"},{title:"Table background mixin variables",filename:"tables",url:"tables.html#table-background-mixin-variables"},{title:"Table borders customization",filename:"tables",url:"tables.html#table-borders-customization"},{title:"Table borders mixin variables",filename:"tables",url:"tables.html#table-borders-mixin-variables"},{title:"Table with horizontal borders",filename:"tables",url:"tables.html#table-with-horizontal-borders"},{title:"Table with vertical borders",filename:"tables",url:"tables.html#table-with-vertical-borders"},{title:"Table with light borders",filename:"tables",url:"tables.html#table-with-light-borders"},{title:"Table without borders",filename:"tables",url:"tables.html#table-without-borders"},{title:"Striped table",filename:"tables",url:"tables.html#striped-table"},{title:"Striped table mixin variables",filename:"tables",url:"tables.html#striped-table-mixin-variables"},{title:"Table with rows hover",filename:"tables",url:"tables.html#table-with-rows-hover"},{title:"Table with rows hover mixin variables",filename:"tables",url:"tables.html#table-with-rows-hover-mixin-variables"},{title:"Responsive table technics #1",filename:"tables",url:"tables.html#responsive-table-technics-1"},{title:"Responsive table technics #2",filename:"tables",url:"tables.html#responsive-table-technics-2"},{title:"Responsive table technics #2 mixin variables",filename:"tables",url:"tables.html#responsive-table-technics-2-mixin-variables"},{title:"tooltips",filename:"tooltips",url:"tooltips.html"},{title:"Tooltips",filename:"tooltips",url:"tooltips.html#tooltips"},{title:"Tooltips variables",filename:"tooltips",url:"tooltips.html#tooltips-variables"},{title:"typography",filename:"typography",url:"typography.html"},{title:"Typogrphy",filename:"typography",url:"typography.html#typogrphy"},{title:"Typography variables",filename:"typography",url:"typography.html#typography-variables"},{title:"Font-size mixin",filename:"typography",url:"typography.html#fontsize-mixin"},{title:"Line-height mixin",filename:"typography",url:"typography.html#lineheight-mixin"},{title:"Word breaking mixin",filename:"typography",url:"typography.html#word-breaking-mixin"},{title:"Font face mixin",filename:"typography",url:"typography.html#font-face-mixin"},{title:"Text overflow mixin",filename:"typography",url:"typography.html#text-overflow-mixin"},{title:"Text hide",filename:"typography",url:"typography.html#text-hide"},{title:"Hyphens",filename:"typography",url:"typography.html#hyphens"},{title:"Font style and color",filename:"typography",url:"typography.html#font-style-and-color"},{title:"Font style mixin variables",filename:"typography",url:"typography.html#font-style-mixin-variables"},{title:"Reset list styles",filename:"typography",url:"typography.html#reset-list-styles"},{title:"Reset list styles variables",filename:"typography",url:"typography.html#reset-list-styles-variables"},{title:"Inline-block list item styling",filename:"typography",url:"typography.html#inlineblock-list-item-styling"},{title:"Link styling mixin",filename:"typography",url:"typography.html#link-styling-mixin"},{title:"Link styling mixin variables",filename:"typography",url:"typography.html#link-styling-mixin-variables"},{title:"Heading styling mixin",filename:"typography",url:"typography.html#heading-styling-mixin"},{title:"Base typography mixins",filename:"typography",url:"typography.html#base-typography-mixins"},{title:"Base typography mixin variables",filename:"typography",url:"typography.html#base-typography-mixin-variables"},{title:"Headings typography mixin",filename:"typography",url:"typography.html#headings-typography-mixin"},{title:"Headings typography mixin variables",filename:"typography",url:"typography.html#headings-typography-mixin-variables"},{title:"Typography links mixin",filename:"typography",url:"typography.html#typography-links-mixin"},{title:"Typography lists mixin",filename:"typography",url:"typography.html#typography-lists-mixin"},{title:"Typography lists mixin variables",filename:"typography",url:"typography.html#typography-lists-mixin-variables"},{title:"Typography code elements mixin",filename:"typography",url:"typography.html#typography-code-elements-mixin"},{title:"Typography code mixin variables",filename:"typography",url:"typography.html#typography-code-mixin-variables"},{title:"Typography blockquote",filename:"typography",url:"typography.html#typography-blockquote"},{title:"Typography blockquote mixin variables",filename:"typography",url:"typography.html#typography-blockquote-mixin-variables"},{title:"utilities",filename:"utilities",url:"utilities.html"},{title:"Utilities",filename:"utilities",url:"utilities.html#utilities"},{title:".lib-clearfix()",filename:"utilities",url:"utilities.html#libclearfix"},{title:".lib-visibility-hidden()",filename:"utilities",url:"utilities.html#libvisibilityhidden"},{title:".lib-visually-hidden()",filename:"utilities",url:"utilities.html#libvisuallyhidden"},{title:".lib-visually-hidden-reset()",filename:"utilities",url:"utilities.html#libvisuallyhiddenreset"},{title:".lib-css()",filename:"utilities",url:"utilities.html#libcss"},{title:".lib-css() variables",filename:"utilities",url:"utilities.html#libcss-variables"},{title:".lib-rotate()",filename:"utilities",url:"utilities.html#librotate"},{title:".lib-rotate() variables",filename:"utilities",url:"utilities.html#librotate-variables"},{title:".lib-input-placeholder()",filename:"utilities",url:"utilities.html#libinputplaceholder"},{title:".lib-input-placeholder() variables",filename:"utilities",url:"utilities.html#libinputplaceholder-variables"},{title:".lib-background-gradient()",filename:"utilities",url:"utilities.html#libbackgroundgradient"},{title:".lib-background-gradient() variables",filename:"utilities",url:"utilities.html#libbackgroundgradient-variables"},{title:".lib-url-check()",filename:"utilities",url:"utilities.html#liburlcheck"},{title:".lib-url-check() variables",filename:"utilities",url:"utilities.html#liburlcheck-variables"},{title:"variables",filename:"variables",url:"variables.html"},{title:"List of Global Variables",filename:"variables",url:"variables.html#list-of-global-variables"},{title:"Table with rows hover mixin variables",filename:"variables",url:"variables.html#table-with-rows-hover-mixin-variables"},{title:"docs",filename:"docs",url:"docs.html"},{title:"Documentation",filename:"docs",url:"docs.html#documentation"}];(function(){"use strict";var b=function(a,b){return Array.prototype.indexOf.call(a,b)!==-1},c=function(a,b){return Array.prototype.filter.call(a,b)},d=function(a,b){return Array.prototype.forEach.call(a,b)},e=document.getElementsByTagName("body")[0];e.addEventListener("click",function(a){var b=a.target;b.tagName.toLowerCase()==="svg"&&(b=b.parentNode);var c=!1;b.dataset.toggle!=null&&(a.preventDefault(),b.classList.contains("is-active")||(c=!0)),d(e.querySelectorAll("[data-toggle]"),function(a){a.classList.remove("is-active"),document.getElementById(a.dataset.toggle).hidden=!0}),c&&(b.classList.add("is-active"),document.getElementById(b.dataset.toggle).hidden=!1)}),function(){var f=e.getElementsByClassName("nav")[0];if(!f)return;var g=document.createElement("ul");g.className="nav-results",g.id="nav-search",g.hidden=!0,d(a,function(a){var b,c,d;b=document.createElement("li"),b._title=a.title.toLowerCase(),b.hidden=!0,b.appendChild(c=document.createElement("a")),c.href=a.url,c.innerHTML=a.title,c.appendChild(d=document.createElement("span")),d.innerHTML=a.filename,d.className="nav-results-filename",g.appendChild(b)}),f.appendChild(g);var h=g.children,i=function(a){d(h,function(a){a.hidden=!0});var b=this.value.toLowerCase(),e=[];b!==""&&(e=c(h,function(a){return a._title.indexOf(b)!==-1})),e.length>0?(d(e,function(a){a.hidden=!1}),g.hidden=!1):g.hidden=!0},j=f.querySelector('input[type="search"]');j.addEventListener("keyup",i),j.addEventListener("focus",i),e.addEventListener("click",function(a){if(a.target.classList&&a.target.classList.contains("search"))return;g.hidden=!0}),g.addEventListener("click",function(a){j.value=""});var k=document.createElement("ul");k.id="nav-toc",k.hidden=!0,k.className="nav-results toc-list",c(e.getElementsByTagName("*"),function(a){return b(["h1","h2","h3"],a.tagName.toLowerCase())}).map(function(a){var b=document.createElement("li"),c=document.createElement("a"),d=a.tagName.toLowerCase()[1];c.classList.add("level-"+d),b.appendChild(c),c.href="#"+a.id,c.innerHTML=a.innerHTML,k.appendChild(b)}),f.appendChild(k)}()})(),function(){"use strict";if(location.hash==="#__preview__"||location.protocol==="data:")return;var a=function(a,b){return Array.prototype.forEach.call(a,b)},b=function(a,b){var e=Array.prototype.slice.call(arguments,2);return d(a,function(a){return(c(b)?b||a:a[b]).apply(a,e)})},c=function(a){return Object.prototype.toString.call(a)==="[object Function]"},d=function(a,b){return Array.prototype.map.call(a,b)},e=function(a,b){return d(a,function(a){return a[b]})},f=function(a){var b={},c=a.split(";");for(var d=0;c.length>d;d++){var e=c[d].trim().split("=");b[e[0]]=e[1]}return b},g=function(a,c){return b(e(a,"classList"),"remove",c)},h=function(a,b){a.contentDocument.defaultView.postMessage(b,"*")},i=document.getElementsByTagName("head")[0],j=document.getElementsByTagName("body")[0],k=e(i.querySelectorAll('style[type="text/preview"]'),"innerHTML").join(""),l=e(i.querySelectorAll('script[type="text/preview"]'),"innerHTML").join(""),m=location.href.split("#")[0]+"#__preview__",n=document.createElement("iframe");n.src="data:text/html,",j.appendChild(n),n.addEventListener("load",function(){var b={sameOriginDataUri:!0};try{this.contentDocument,this.contentDocument||(b.sameOriginDataUri=!1)}catch(c){b.sameOriginDataUri=!1}this.parentNode.removeChild(this),a(j.getElementsByTagName("textarea"),function(a,c){o(a,b,c),q(),p(a)})});var o=function(a,b,c){var d,e,f;d=document.createElement("div"),d.appendChild(e=document.createElement("div")),d.className="preview",e.appendChild(f=document.createElement("iframe")),e.className="resizeable",f.setAttribute("scrolling","no"),f.name="iframe"+c++,f.addEventListener("load",function(){var c,d,e,f,g,i,j;j=this.contentDocument;if(!b.sameOriginDataUri&&this.src!==m)return;this.src===m&&(c=j.createElement("html"),c.appendChild(j.createElement("head")),c.appendChild(d=j.createElement("body")),d.innerHTML=a.textContent,j.replaceChild(c,j.documentElement)),g=j.createElement("head"),g.appendChild(f=j.createElement("style")),g.appendChild(e=j.createElement("script")),e.textContent=l,f.textContent=k,i=j.getElementsByTagName("head")[0],i.parentNode.replaceChild(g,i),h(this,"getHeight")});var g;b.sameOriginDataUri?g="data:text/html;charset=utf-8,"+encodeURIComponent("<!doctype html><html><head></head></body>"+a.textContent):g=m,f.setAttribute("src",g);var i=function(){f.contentDocument.body.innerHTML=this.value,h(f,"getHeight")};a.addEventListener("keypress",i),a.addEventListener("keyup",i),a.parentNode.insertBefore(d,a)},p=function(a){var b=document.createElement("div");b.className="preview-code",b.style.position="absolute",b.style.left="-9999px",j.appendChild(b);var c=parseInt(window.getComputedStyle(a).getPropertyValue("max-height"),10),d=function(a){b.textContent=this.value+"\n";var d=b.offsetHeight+2;d>=c?this.style.overflow="auto":this.style.overflow="hidden",this.style.height=b.offsetHeight+2+"px"};a.addEventListener("keypress",d),a.addEventListener("keyup",d),d.call(a)},q=function(){var b=j.getElementsByClassName("settings")[0],c=j.getElementsByClassName("resizeable"),d=30,e=function(b){document.cookie="preview-width="+b,a(c,function(a){b==="auto"&&(b=a.parentNode.offsetWidth),a.style.width=b+"px",h(a.getElementsByTagName("iframe")[0],"getHeight")})},i=f(document.cookie)["preview-width"];if(i){e(i),g(b.getElementsByClassName("is-active"),"is-active");var k=b.querySelector('button[data-width="'+i+'"]');k&&k.classList.add("is-active")}window.addEventListener("message",function(a){if(a.data==null||!a.source)return;var b=a.data,c=document.getElementsByName(a.source.name)[0];b.height!=null&&c&&(c.parentNode.style.height=b.height+d+"px")},!1),b&&c.length>0&&(b.hidden=!1,b.addEventListener("click",function(a){var c=a.target.tagName.toLowerCase(),d;if(c==="button")d=a.target;else{if(c!=="svg")return;d=a.target.parentNode}a.preventDefault(),g(b.getElementsByClassName("is-active"),"is-active"),d.classList.add("is-active");var f=d.dataset.width;e(f)}))}}()})()</script></body></html><!-- Generated with StyleDocco (http://jacobrask.github.com/styledocco). --> +}</code></pre></div></article></section><div class="bar bottom"><div hidden class="settings container"><!-- Icons from http://iconmonstr.com--><button title="Desktop (1280)" data-width='1280'><svg viewBox="0 0 412 386" height="24" width="26" class="icon"><path d="m147.6,343.9c-4.5,15.9-26.2,37.6-42.1,42.1h201c-15.3,-4-38.1,-26.8-42.1,-42.1H147.6zM387,0.5H25c-13.8,0-25,11.2-25,25V294c0,13.8 11.2,25 25,25h362c13.8,0 25,-11.2 25,-25V25.5C412,11.7 400.8,0.5 387,0.5zM369.9,238.2H42.1L42.1,42.6 369.9,42.6V238.2z"></path></svg></button><button title="Laptop (1024)" data-width='1024'><svg viewBox="0 0 384 312" height="23" width="28" class="icon"><path d="m349.2,20.5c0,-11-9,-20-20,-20H53.6c-11,0-20,9-20,20v194H349.2v-194zm-27,167H60.6V27.5H322.2v160zm28,42H32.6L2.6,282.1c-3.5,6.2-3.5,13.8 0.1,19.9 3.6,6.2 10.2,9.9 17.3,9.9H363.1c7.1,0 13.7,-3.8 17.3,-10 3.6,-6.2 3.6,-13.8 0,-20l-30.2,-52.5zm-196.9,54 8,-23.5h60.5l8,23.5h-76.5z"></path></svg></button><button title="Tablet (768)" data-width='768'><svg viewBox="0 0 317 412" height="24" width="18" class="icon"><path d="M 316.5,380 V 32 c 0,-17.7 -14.3,-32 -32,-32 H 32 C 14.3,0 0,14.3 0,32 v 348 c 0,17.7 14.3,32 32,32 h 252.5 c 17.7,0 32,-14.3 32,-32 z M 40,367 V 45 H 276.5 V 367 H 40 z m 109.8,22.7 c 0,-4.7 3.8,-8.5 8.5,-8.5 4.7,0 8.5,3.8 8.5,8.5 0,4.7 -3.8,8.5 -8.5,8.5 -4.7,0 -8.5,-3.8 -8.5,-8.5 z"></path></svg></button><button title="Smart phone (320)" data-width='320'><svg viewBox="0 0 224 412" height="24" width="13" class="icon"><path d="M 190.7,0 H 33 C 14.8,0 0,14.8 0,33 v 346 c 0,18.2 14.8,33 33,33 h 157.7 c 18.2,0 33,-14.8 33,-33 V 33 c 0,-18.2 -14.8,-33 -33,-33 z M 94.3,30.2 h 37 c 2.2,0 4,1.8 4,4 0,2.2 -1.8,4 -4,4 h -37 c -2.2,0 -4,-1.8 -4,-4 0,-2.2 1.8,-4 4,-4 z m 18.5,362.8 c -8.8,0 -16,-7.2 -16,-16 0,-8.8 7.2,-16 16,-16 8.8,0 16,7.2 16,16 0,8.8 -7.2,16 -16,16 z M 198.6,343.8 H 25.1 V 68.2 h 173.5 v 275.5 z"></path></svg></button><button title="Feature phone (240)" data-width='240'><svg viewBox="0 0 201 412" height="24" width="12" class="icon"><path d="M 165.5,0.2 V 45 H 25 c -13.8,0 -25,11.2 -25,25 V 387 c 0,13.8 11.2,25 25,25 h 150.5 c 13.8,0 25,-11.2 25,-25 V 0.2 h -35 z M 65.2,366.5 H 34.2 v -24.5 h 31 v 24.5 z m 0,-44.3 H 34.2 v -24.5 h 31 v 24.5 z m 50.5,44.3 H 84.7 v -24.5 h 31 v 24.5 z m 0,-44.3 H 84.7 v -24.5 h 31 v 24.5 z m 50.5,44.3 h -31 v -24.5 h 31 v 24.5 z m 0,-44.3 h -31 v -24.5 h 31 v 24.5 z m 0,-59.3 h -132 V 95.4 h 132 V 262.9 z"></path></svg></button><button title="Auto (100%)" data-width="auto" class="auto is-active">Auto</button></div></div><script>(function(){var a=[{title:"actions-toolbar",filename:"actions-toolbar",url:"actions-toolbar.html"},{title:"Actions toolbar",filename:"actions-toolbar",url:"actions-toolbar.html#actions-toolbar"},{title:"Actions toolbar mixin variables",filename:"actions-toolbar",url:"actions-toolbar.html#actions-toolbar-mixin-variables"},{title:"Actions toolbar alignment",filename:"actions-toolbar",url:"actions-toolbar.html#actions-toolbar-alignment"},{title:"Reverse primary and secondary blocks",filename:"actions-toolbar",url:"actions-toolbar.html#reverse-primary-and-secondary-blocks"},{title:"Actions toolbar indents customizations",filename:"actions-toolbar",url:"actions-toolbar.html#actions-toolbar-indents-customizations"},{title:"Responsive actions toolbar",filename:"actions-toolbar",url:"actions-toolbar.html#responsive-actions-toolbar"},{title:"breadcrumbs",filename:"breadcrumbs",url:"breadcrumbs.html"},{title:"Breadcrumbs",filename:"breadcrumbs",url:"breadcrumbs.html#breadcrumbs"},{title:"Breadcrumbs variables",filename:"breadcrumbs",url:"breadcrumbs.html#breadcrumbs-variables"},{title:"Button-styled breadcrumbs with gradient background, border, and no separating symbol",filename:"breadcrumbs",url:"breadcrumbs.html#buttonstyled-breadcrumbs-with-gradient-background-border-and-no-separating-symbol"},{title:"Breadcrumbs with solid background",filename:"breadcrumbs",url:"breadcrumbs.html#breadcrumbs-with-solid-background"},{title:"buttons",filename:"buttons",url:"buttons.html"},{title:"Default button",filename:"buttons",url:"buttons.html#default-button"},{title:"Button variables",filename:"buttons",url:"buttons.html#button-variables"},{title:"Button as an icon",filename:"buttons",url:"buttons.html#button-as-an-icon"},{title:"Button with an icon on the left or right side of the text",filename:"buttons",url:"buttons.html#button-with-an-icon-on-the-left-or-right-side-of-the-text"},{title:"Button with fixed width",filename:"buttons",url:"buttons.html#button-with-fixed-width"},{title:"Primary button",filename:"buttons",url:"buttons.html#primary-button"},{title:"Primary button variables",filename:"buttons",url:"buttons.html#primary-button-variables"},{title:"Button with gradient background",filename:"buttons",url:"buttons.html#button-with-gradient-background"},{title:"Button as a link",filename:"buttons",url:"buttons.html#button-as-a-link"},{title:"Button as a link variables",filename:"buttons",url:"buttons.html#button-as-a-link-variables"},{title:"Link as a button",filename:"buttons",url:"buttons.html#link-as-a-button"},{title:"Button reset",filename:"buttons",url:"buttons.html#button-reset"},{title:"Button revert secondary color",filename:"buttons",url:"buttons.html#button-revert-secondary-color"},{title:"Button revert secondary color variables",filename:"buttons",url:"buttons.html#button-revert-secondary-color-variables"},{title:"Button revert secondary size",filename:"buttons",url:"buttons.html#button-revert-secondary-size"},{title:"Button revert secondary size variables",filename:"buttons",url:"buttons.html#button-revert-secondary-size-variables"},{title:"components",filename:"components",url:"components.html"},{title:"Components",filename:"components",url:"components.html#components"},{title:"Components Variables",filename:"components",url:"components.html#components-variables"},{title:"dropdowns",filename:"dropdowns",url:"dropdowns.html"},{title:"Drop-down and split buttons mixins",filename:"dropdowns",url:"dropdowns.html#dropdown-and-split-buttons-mixins"},{title:"Drop-down",filename:"dropdowns",url:"dropdowns.html#dropdown"},{title:"Drop-down variables",filename:"dropdowns",url:"dropdowns.html#dropdown-variables"},{title:"Drop-down with icon customization",filename:"dropdowns",url:"dropdowns.html#dropdown-with-icon-customization"},{title:"Modify dropdown list styles",filename:"dropdowns",url:"dropdowns.html#modify-dropdown-list-styles"},{title:"Split button",filename:"dropdowns",url:"dropdowns.html#split-button"},{title:"Split button variables",filename:"dropdowns",url:"dropdowns.html#split-button-variables"},{title:"Split button - button styling",filename:"dropdowns",url:"dropdowns.html#split-button-button-styling"},{title:"Split button icon customization",filename:"dropdowns",url:"dropdowns.html#split-button-icon-customization"},{title:"Split button drop-down list customization",filename:"dropdowns",url:"dropdowns.html#split-button-dropdown-list-customization"},{title:"forms",filename:"forms",url:"forms.html"},{title:"Forms mixins",filename:"forms",url:"forms.html#forms-mixins"},{title:"Global forms elements customization",filename:"forms",url:"forms.html#global-forms-elements-customization"},{title:"Fieldsets & fields customization",filename:"forms",url:"forms.html#fieldsets-fields-customization"},{title:"Fieldset and legend customization variables",filename:"forms",url:"forms.html#fieldset-and-legend-customization-variables"},{title:"Fields customization variables",filename:"forms",url:"forms.html#fields-customization-variables"},{title:"Required fields message customization variables",filename:"forms",url:"forms.html#required-fields-message-customization-variables"},{title:"Form element inputs customization",filename:"forms",url:"forms.html#form-element-inputs-customization"},{title:"Form element inputs customization variables",filename:"forms",url:"forms.html#form-element-inputs-customization-variables"},{title:"Form element choice",filename:"forms",url:"forms.html#form-element-choice"},{title:"Form element choice variables",filename:"forms",url:"forms.html#form-element-choice-variables"},{title:"Custom color",filename:"forms",url:"forms.html#custom-color"},{title:"Input number - input-text view",filename:"forms",url:"forms.html#input-number-inputtext-view"},{title:"Input search - input-text view",filename:"forms",url:"forms.html#input-search-inputtext-view"},{title:"Form validation",filename:"forms",url:"forms.html#form-validation"},{title:"Form validation variables",filename:"forms",url:"forms.html#form-validation-variables"},{title:"icons",filename:"icons",url:"icons.html"},{title:"Icons",filename:"icons",url:"icons.html#icons"},{title:"Icon with image or sprite",filename:"icons",url:"icons.html#icon-with-image-or-sprite"},{title:"Icon with image or sprite variables",filename:"icons",url:"icons.html#icon-with-image-or-sprite-variables"},{title:"Icon position for an icon with image or sprite",filename:"icons",url:"icons.html#icon-position-for-an-icon-with-image-or-sprite"},{title:"Position for icon with image or sprite mixin variables",filename:"icons",url:"icons.html#position-for-icon-with-image-or-sprite-mixin-variables"},{title:"Icon sprite position (with grid)",filename:"icons",url:"icons.html#icon-sprite-position-with-grid"},{title:"Icon sprite position variables",filename:"icons",url:"icons.html#icon-sprite-position-variables"},{title:"Image/sprite icon size",filename:"icons",url:"icons.html#imagesprite-icon-size"},{title:"Image/sprite icon size variables",filename:"icons",url:"icons.html#imagesprite-icon-size-variables"},{title:"Font icon",filename:"icons",url:"icons.html#font-icon"},{title:"Font icon variables",filename:"icons",url:"icons.html#font-icon-variables"},{title:"Change the size of font icon",filename:"icons",url:"icons.html#change-the-size-of-font-icon"},{title:"Change the size of font icon variables",filename:"icons",url:"icons.html#change-the-size-of-font-icon-variables"},{title:"Hide icon text",filename:"icons",url:"icons.html#hide-icon-text"},{title:"Sprite and font icons for Blank theme",filename:"icons",url:"icons.html#sprite-and-font-icons-for-blank-theme"},{title:"layout",filename:"layout",url:"layout.html"},{title:"Layout",filename:"layout",url:"layout.html#layout"},{title:"Layout global variables",filename:"layout",url:"layout.html#layout-global-variables"},{title:"Page layouts",filename:"layout",url:"layout.html#page-layouts"},{title:"Layout column",filename:"layout",url:"layout.html#layout-column"},{title:"Layout column variables",filename:"layout",url:"layout.html#layout-column-variables"},{title:"Layout width",filename:"layout",url:"layout.html#layout-width"},{title:"Layout width variables",filename:"layout",url:"layout.html#layout-width-variables"},{title:"lib",filename:"lib",url:"lib.html"},{title:"Including Magento UI library to your theme",filename:"lib",url:"lib.html#including-magento-ui-library-to-your-theme"},{title:"loaders",filename:"loaders",url:"loaders.html"},{title:"Loaders",filename:"loaders",url:"loaders.html#loaders"},{title:"Default loader variables",filename:"loaders",url:"loaders.html#default-loader-variables"},{title:"Loading",filename:"loaders",url:"loaders.html#loading"},{title:"Loading default variables",filename:"loaders",url:"loaders.html#loading-default-variables"},{title:"messages",filename:"messages",url:"messages.html"},{title:"Messages",filename:"messages",url:"messages.html#messages"},{title:"Information message",filename:"messages",url:"messages.html#information-message"},{title:"Warning message",filename:"messages",url:"messages.html#warning-message"},{title:"Error message",filename:"messages",url:"messages.html#error-message"},{title:"Success message",filename:"messages",url:"messages.html#success-message"},{title:"Notice message",filename:"messages",url:"messages.html#notice-message"},{title:"Message with inner icon",filename:"messages",url:"messages.html#message-with-inner-icon"},{title:"Message with lateral icon",filename:"messages",url:"messages.html#message-with-lateral-icon"},{title:"Custom message style",filename:"messages",url:"messages.html#custom-message-style"},{title:"Messages global variables",filename:"messages",url:"messages.html#messages-global-variables"},{title:"pages",filename:"pages",url:"pages.html"},{title:"Pagination HTML markup",filename:"pages",url:"pages.html#pagination-html-markup"},{title:"Pagination variables",filename:"pages",url:"pages.html#pagination-variables"},{title:"Pagination with label and gradient background on links",filename:"pages",url:"pages.html#pagination-with-label-and-gradient-background-on-links"},{title:'Pagination with "previous"..."next" text links and label',filename:"pages",url:"pages.html#pagination-with-previousnext-text-links-and-label"},{title:"Pagination without label, with solid background",filename:"pages",url:"pages.html#pagination-without-label-with-solid-background"},{title:"popups",filename:"popups",url:"popups.html"},{title:"Popups",filename:"popups",url:"popups.html#popups"},{title:"Popup variables",filename:"popups",url:"popups.html#popup-variables"},{title:"Window overlay mixin variables",filename:"popups",url:"popups.html#window-overlay-mixin-variables"},{title:"Fixed height popup",filename:"popups",url:"popups.html#fixed-height-popup"},{title:"Fixed content height popup",filename:"popups",url:"popups.html#fixed-content-height-popup"},{title:"Margins for header, content and footer block in popup",filename:"popups",url:"popups.html#margins-for-header-content-and-footer-block-in-popup"},{title:"Popup titles styled as theme headings",filename:"popups",url:"popups.html#popup-titles-styled-as-theme-headings"},{title:"Popup action toolbar",filename:"popups",url:"popups.html#popup-action-toolbar"},{title:"Popup Close button without an icon",filename:"popups",url:"popups.html#popup-close-button-without-an-icon"},{title:"Modify the icon of popup Close button",filename:"popups",url:"popups.html#modify-the-icon-of-popup-close-button"},{title:"Modify overlay styles",filename:"popups",url:"popups.html#modify-overlay-styles"},{title:"rating",filename:"rating",url:"rating.html"},{title:"Ratings",filename:"rating",url:"rating.html#ratings"},{title:"Global rating variables",filename:"rating",url:"rating.html#global-rating-variables"},{title:"Rating with vote",filename:"rating",url:"rating.html#rating-with-vote"},{title:"Rating with vote icons number customization",filename:"rating",url:"rating.html#rating-with-vote-icons-number-customization"},{title:"Rating with vote icons colors customization",filename:"rating",url:"rating.html#rating-with-vote-icons-colors-customization"},{title:"Rating with vote icons symbol customization",filename:"rating",url:"rating.html#rating-with-vote-icons-symbol-customization"},{title:"Accessible rating with vote",filename:"rating",url:"rating.html#accessible-rating-with-vote"},{title:"Rating summary",filename:"rating",url:"rating.html#rating-summary"},{title:"Rating summary icons number customization",filename:"rating",url:"rating.html#rating-summary-icons-number-customization"},{title:"Rating summary icons color customization",filename:"rating",url:"rating.html#rating-summary-icons-color-customization"},{title:"Rating summary icons symbol customization",filename:"rating",url:"rating.html#rating-summary-icons-symbol-customization"},{title:"Rating summary hide label",filename:"rating",url:"rating.html#rating-summary-hide-label"},{title:"Rating summary multiple ratings",filename:"rating",url:"rating.html#rating-summary-multiple-ratings"},{title:"Rating hide label mixin",filename:"rating",url:"rating.html#rating-hide-label-mixin"},{title:"resets",filename:"resets",url:"resets.html"},{title:"Resets",filename:"resets",url:"resets.html#resets"},{title:"responsive",filename:"responsive",url:"responsive.html"},{title:"Responsive",filename:"responsive",url:"responsive.html#responsive"},{title:"Responsive mixins usage",filename:"responsive",url:"responsive.html#responsive-mixins-usage"},{title:"Media query style groups separation variables",filename:"responsive",url:"responsive.html#media-query-style-groups-separation-variables"},{title:"Responsive breakpoints",filename:"responsive",url:"responsive.html#responsive-breakpoints"},{title:"sections",filename:"sections",url:"sections.html"},{title:"Tabs and accordions",filename:"sections",url:"sections.html#tabs-and-accordions"},{title:"Tabs",filename:"sections",url:"sections.html#tabs"},{title:"Tabs mixin variables",filename:"sections",url:"sections.html#tabs-mixin-variables"},{title:"Tabs with content top border",filename:"sections",url:"sections.html#tabs-with-content-top-border"},{title:"Accordion",filename:"sections",url:"sections.html#accordion"},{title:"Accordion mixin variables",filename:"sections",url:"sections.html#accordion-mixin-variables"},{title:"Responsive tabs",filename:"sections",url:"sections.html#responsive-tabs"},{title:"Tabs Base",filename:"sections",url:"sections.html#tabs-base"},{title:"Accordion Base",filename:"sections",url:"sections.html#accordion-base"},{title:"tables",filename:"tables",url:"tables.html"},{title:"Tables",filename:"tables",url:"tables.html#tables"},{title:"Table mixin variables",filename:"tables",url:"tables.html#table-mixin-variables"},{title:"Table typography",filename:"tables",url:"tables.html#table-typography"},{title:"Table typography mixin variables",filename:"tables",url:"tables.html#table-typography-mixin-variables"},{title:"Table caption",filename:"tables",url:"tables.html#table-caption"},{title:"Table caption mixin variables",filename:"tables",url:"tables.html#table-caption-mixin-variables"},{title:"Table cells resize",filename:"tables",url:"tables.html#table-cells-resize"},{title:"Table cells resize variables",filename:"tables",url:"tables.html#table-cells-resize-variables"},{title:"Table background customization",filename:"tables",url:"tables.html#table-background-customization"},{title:"Table background mixin variables",filename:"tables",url:"tables.html#table-background-mixin-variables"},{title:"Table borders customization",filename:"tables",url:"tables.html#table-borders-customization"},{title:"Table borders mixin variables",filename:"tables",url:"tables.html#table-borders-mixin-variables"},{title:"Table with horizontal borders",filename:"tables",url:"tables.html#table-with-horizontal-borders"},{title:"Table with vertical borders",filename:"tables",url:"tables.html#table-with-vertical-borders"},{title:"Table with light borders",filename:"tables",url:"tables.html#table-with-light-borders"},{title:"Table without borders",filename:"tables",url:"tables.html#table-without-borders"},{title:"Striped table",filename:"tables",url:"tables.html#striped-table"},{title:"Striped table mixin variables",filename:"tables",url:"tables.html#striped-table-mixin-variables"},{title:"Table with rows hover",filename:"tables",url:"tables.html#table-with-rows-hover"},{title:"Table with rows hover mixin variables",filename:"tables",url:"tables.html#table-with-rows-hover-mixin-variables"},{title:"Responsive table technics #1",filename:"tables",url:"tables.html#responsive-table-technics-1"},{title:"Responsive table technics #2",filename:"tables",url:"tables.html#responsive-table-technics-2"},{title:"Responsive table technics #2 mixin variables",filename:"tables",url:"tables.html#responsive-table-technics-2-mixin-variables"},{title:"tooltips",filename:"tooltips",url:"tooltips.html"},{title:"Tooltips",filename:"tooltips",url:"tooltips.html#tooltips"},{title:"Tooltips variables",filename:"tooltips",url:"tooltips.html#tooltips-variables"},{title:"typography",filename:"typography",url:"typography.html"},{title:"Typogrphy",filename:"typography",url:"typography.html#typogrphy"},{title:"Typography variables",filename:"typography",url:"typography.html#typography-variables"},{title:"Font-size mixin",filename:"typography",url:"typography.html#fontsize-mixin"},{title:"Line-height mixin",filename:"typography",url:"typography.html#lineheight-mixin"},{title:"Word breaking mixin",filename:"typography",url:"typography.html#word-breaking-mixin"},{title:"Font face mixin",filename:"typography",url:"typography.html#font-face-mixin"},{title:"Text overflow mixin",filename:"typography",url:"typography.html#text-overflow-mixin"},{title:"Text hide",filename:"typography",url:"typography.html#text-hide"},{title:"Hyphens",filename:"typography",url:"typography.html#hyphens"},{title:"Font style and color",filename:"typography",url:"typography.html#font-style-and-color"},{title:"Font style mixin variables",filename:"typography",url:"typography.html#font-style-mixin-variables"},{title:"Reset list styles",filename:"typography",url:"typography.html#reset-list-styles"},{title:"Reset list styles variables",filename:"typography",url:"typography.html#reset-list-styles-variables"},{title:"Inline-block list item styling",filename:"typography",url:"typography.html#inlineblock-list-item-styling"},{title:"Link styling mixin",filename:"typography",url:"typography.html#link-styling-mixin"},{title:"Link styling mixin variables",filename:"typography",url:"typography.html#link-styling-mixin-variables"},{title:"Heading styling mixin",filename:"typography",url:"typography.html#heading-styling-mixin"},{title:"Base typography mixins",filename:"typography",url:"typography.html#base-typography-mixins"},{title:"Base typography mixin variables",filename:"typography",url:"typography.html#base-typography-mixin-variables"},{title:"Headings typography mixin",filename:"typography",url:"typography.html#headings-typography-mixin"},{title:"Headings typography mixin variables",filename:"typography",url:"typography.html#headings-typography-mixin-variables"},{title:"Typography links mixin",filename:"typography",url:"typography.html#typography-links-mixin"},{title:"Typography lists mixin",filename:"typography",url:"typography.html#typography-lists-mixin"},{title:"Typography lists mixin variables",filename:"typography",url:"typography.html#typography-lists-mixin-variables"},{title:"Typography code elements mixin",filename:"typography",url:"typography.html#typography-code-elements-mixin"},{title:"Typography code mixin variables",filename:"typography",url:"typography.html#typography-code-mixin-variables"},{title:"Typography blockquote",filename:"typography",url:"typography.html#typography-blockquote"},{title:"Typography blockquote mixin variables",filename:"typography",url:"typography.html#typography-blockquote-mixin-variables"},{title:"utilities",filename:"utilities",url:"utilities.html"},{title:"Utilities",filename:"utilities",url:"utilities.html#utilities"},{title:".lib-clearfix()",filename:"utilities",url:"utilities.html#libclearfix"},{title:".lib-visibility-hidden()",filename:"utilities",url:"utilities.html#libvisibilityhidden"},{title:".lib-visually-hidden()",filename:"utilities",url:"utilities.html#libvisuallyhidden"},{title:".lib-visually-hidden-reset()",filename:"utilities",url:"utilities.html#libvisuallyhiddenreset"},{title:".lib-css()",filename:"utilities",url:"utilities.html#libcss"},{title:".lib-css() variables",filename:"utilities",url:"utilities.html#libcss-variables"},{title:".lib-rotate()",filename:"utilities",url:"utilities.html#librotate"},{title:".lib-rotate() variables",filename:"utilities",url:"utilities.html#librotate-variables"},{title:".lib-input-placeholder()",filename:"utilities",url:"utilities.html#libinputplaceholder"},{title:".lib-input-placeholder() variables",filename:"utilities",url:"utilities.html#libinputplaceholder-variables"},{title:".lib-background-gradient()",filename:"utilities",url:"utilities.html#libbackgroundgradient"},{title:".lib-background-gradient() variables",filename:"utilities",url:"utilities.html#libbackgroundgradient-variables"},{title:"variables",filename:"variables",url:"variables.html"},{title:"List of Global Variables",filename:"variables",url:"variables.html#list-of-global-variables"},{title:"Table with rows hover mixin variables",filename:"variables",url:"variables.html#table-with-rows-hover-mixin-variables"},{title:"docs",filename:"docs",url:"docs.html"},{title:"Documentation",filename:"docs",url:"docs.html#documentation"}];(function(){"use strict";var b=function(a,b){return Array.prototype.indexOf.call(a,b)!==-1},c=function(a,b){return Array.prototype.filter.call(a,b)},d=function(a,b){return Array.prototype.forEach.call(a,b)},e=document.getElementsByTagName("body")[0];e.addEventListener("click",function(a){var b=a.target;b.tagName.toLowerCase()==="svg"&&(b=b.parentNode);var c=!1;b.dataset.toggle!=null&&(a.preventDefault(),b.classList.contains("is-active")||(c=!0)),d(e.querySelectorAll("[data-toggle]"),function(a){a.classList.remove("is-active"),document.getElementById(a.dataset.toggle).hidden=!0}),c&&(b.classList.add("is-active"),document.getElementById(b.dataset.toggle).hidden=!1)}),function(){var f=e.getElementsByClassName("nav")[0];if(!f)return;var g=document.createElement("ul");g.className="nav-results",g.id="nav-search",g.hidden=!0,d(a,function(a){var b,c,d;b=document.createElement("li"),b._title=a.title.toLowerCase(),b.hidden=!0,b.appendChild(c=document.createElement("a")),c.href=a.url,c.innerHTML=a.title,c.appendChild(d=document.createElement("span")),d.innerHTML=a.filename,d.className="nav-results-filename",g.appendChild(b)}),f.appendChild(g);var h=g.children,i=function(a){d(h,function(a){a.hidden=!0});var b=this.value.toLowerCase(),e=[];b!==""&&(e=c(h,function(a){return a._title.indexOf(b)!==-1})),e.length>0?(d(e,function(a){a.hidden=!1}),g.hidden=!1):g.hidden=!0},j=f.querySelector('input[type="search"]');j.addEventListener("keyup",i),j.addEventListener("focus",i),e.addEventListener("click",function(a){if(a.target.classList&&a.target.classList.contains("search"))return;g.hidden=!0}),g.addEventListener("click",function(a){j.value=""});var k=document.createElement("ul");k.id="nav-toc",k.hidden=!0,k.className="nav-results toc-list",c(e.getElementsByTagName("*"),function(a){return b(["h1","h2","h3"],a.tagName.toLowerCase())}).map(function(a){var b=document.createElement("li"),c=document.createElement("a"),d=a.tagName.toLowerCase()[1];c.classList.add("level-"+d),b.appendChild(c),c.href="#"+a.id,c.innerHTML=a.innerHTML,k.appendChild(b)}),f.appendChild(k)}()})(),function(){"use strict";if(location.hash==="#__preview__"||location.protocol==="data:")return;var a=function(a,b){return Array.prototype.forEach.call(a,b)},b=function(a,b){var e=Array.prototype.slice.call(arguments,2);return d(a,function(a){return(c(b)?b||a:a[b]).apply(a,e)})},c=function(a){return Object.prototype.toString.call(a)==="[object Function]"},d=function(a,b){return Array.prototype.map.call(a,b)},e=function(a,b){return d(a,function(a){return a[b]})},f=function(a){var b={},c=a.split(";");for(var d=0;c.length>d;d++){var e=c[d].trim().split("=");b[e[0]]=e[1]}return b},g=function(a,c){return b(e(a,"classList"),"remove",c)},h=function(a,b){a.contentDocument.defaultView.postMessage(b,"*")},i=document.getElementsByTagName("head")[0],j=document.getElementsByTagName("body")[0],k=e(i.querySelectorAll('style[type="text/preview"]'),"innerHTML").join(""),l=e(i.querySelectorAll('script[type="text/preview"]'),"innerHTML").join(""),m=location.href.split("#")[0]+"#__preview__",n=document.createElement("iframe");n.src="data:text/html,",j.appendChild(n),n.addEventListener("load",function(){var b={sameOriginDataUri:!0};try{this.contentDocument,this.contentDocument||(b.sameOriginDataUri=!1)}catch(c){b.sameOriginDataUri=!1}this.parentNode.removeChild(this),a(j.getElementsByTagName("textarea"),function(a,c){o(a,b,c),q(),p(a)})});var o=function(a,b,c){var d,e,f;d=document.createElement("div"),d.appendChild(e=document.createElement("div")),d.className="preview",e.appendChild(f=document.createElement("iframe")),e.className="resizeable",f.setAttribute("scrolling","no"),f.name="iframe"+c++,f.addEventListener("load",function(){var c,d,e,f,g,i,j;j=this.contentDocument;if(!b.sameOriginDataUri&&this.src!==m)return;this.src===m&&(c=j.createElement("html"),c.appendChild(j.createElement("head")),c.appendChild(d=j.createElement("body")),d.innerHTML=a.textContent,j.replaceChild(c,j.documentElement)),g=j.createElement("head"),g.appendChild(f=j.createElement("style")),g.appendChild(e=j.createElement("script")),e.textContent=l,f.textContent=k,i=j.getElementsByTagName("head")[0],i.parentNode.replaceChild(g,i),h(this,"getHeight")});var g;b.sameOriginDataUri?g="data:text/html;charset=utf-8,"+encodeURIComponent("<!doctype html><html><head></head></body>"+a.textContent):g=m,f.setAttribute("src",g);var i=function(){f.contentDocument.body.innerHTML=this.value,h(f,"getHeight")};a.addEventListener("keypress",i),a.addEventListener("keyup",i),a.parentNode.insertBefore(d,a)},p=function(a){var b=document.createElement("div");b.className="preview-code",b.style.position="absolute",b.style.left="-9999px",j.appendChild(b);var c=parseInt(window.getComputedStyle(a).getPropertyValue("max-height"),10),d=function(a){b.textContent=this.value+"\n";var d=b.offsetHeight+2;d>=c?this.style.overflow="auto":this.style.overflow="hidden",this.style.height=b.offsetHeight+2+"px"};a.addEventListener("keypress",d),a.addEventListener("keyup",d),d.call(a)},q=function(){var b=j.getElementsByClassName("settings")[0],c=j.getElementsByClassName("resizeable"),d=30,e=function(b){document.cookie="preview-width="+b,a(c,function(a){b==="auto"&&(b=a.parentNode.offsetWidth),a.style.width=b+"px",h(a.getElementsByTagName("iframe")[0],"getHeight")})},i=f(document.cookie)["preview-width"];if(i){e(i),g(b.getElementsByClassName("is-active"),"is-active");var k=b.querySelector('button[data-width="'+i+'"]');k&&k.classList.add("is-active")}window.addEventListener("message",function(a){if(a.data==null||!a.source)return;var b=a.data,c=document.getElementsByName(a.source.name)[0];b.height!=null&&c&&(c.parentNode.style.height=b.height+d+"px")},!1),b&&c.length>0&&(b.hidden=!1,b.addEventListener("click",function(a){var c=a.target.tagName.toLowerCase(),d;if(c==="button")d=a.target;else{if(c!=="svg")return;d=a.target.parentNode}a.preventDefault(),g(b.getElementsByClassName("is-active"),"is-active"),d.classList.add("is-active");var f=d.dataset.width;e(f)}))}}()})()</script></body></html><!-- Generated with StyleDocco (http://jacobrask.github.com/styledocco). --> diff --git a/lib/web/css/docs/breadcrumbs.html b/lib/web/css/docs/breadcrumbs.html index 9ada940b4c0de..e4bfc3a973aa1 100644 --- a/lib/web/css/docs/breadcrumbs.html +++ b/lib/web/css/docs/breadcrumbs.html @@ -502,4 +502,4 @@ border-color: transparent transparent transparent #ccc; } } -}</code></pre></div></article></section><div class="bar bottom"><div hidden class="settings container"><!-- Icons from http://iconmonstr.com--><button title="Desktop (1280)" data-width='1280'><svg viewBox="0 0 412 386" height="24" width="26" class="icon"><path d="m147.6,343.9c-4.5,15.9-26.2,37.6-42.1,42.1h201c-15.3,-4-38.1,-26.8-42.1,-42.1H147.6zM387,0.5H25c-13.8,0-25,11.2-25,25V294c0,13.8 11.2,25 25,25h362c13.8,0 25,-11.2 25,-25V25.5C412,11.7 400.8,0.5 387,0.5zM369.9,238.2H42.1L42.1,42.6 369.9,42.6V238.2z"></path></svg></button><button title="Laptop (1024)" data-width='1024'><svg viewBox="0 0 384 312" height="23" width="28" class="icon"><path d="m349.2,20.5c0,-11-9,-20-20,-20H53.6c-11,0-20,9-20,20v194H349.2v-194zm-27,167H60.6V27.5H322.2v160zm28,42H32.6L2.6,282.1c-3.5,6.2-3.5,13.8 0.1,19.9 3.6,6.2 10.2,9.9 17.3,9.9H363.1c7.1,0 13.7,-3.8 17.3,-10 3.6,-6.2 3.6,-13.8 0,-20l-30.2,-52.5zm-196.9,54 8,-23.5h60.5l8,23.5h-76.5z"></path></svg></button><button title="Tablet (768)" data-width='768'><svg viewBox="0 0 317 412" height="24" width="18" class="icon"><path d="M 316.5,380 V 32 c 0,-17.7 -14.3,-32 -32,-32 H 32 C 14.3,0 0,14.3 0,32 v 348 c 0,17.7 14.3,32 32,32 h 252.5 c 17.7,0 32,-14.3 32,-32 z M 40,367 V 45 H 276.5 V 367 H 40 z m 109.8,22.7 c 0,-4.7 3.8,-8.5 8.5,-8.5 4.7,0 8.5,3.8 8.5,8.5 0,4.7 -3.8,8.5 -8.5,8.5 -4.7,0 -8.5,-3.8 -8.5,-8.5 z"></path></svg></button><button title="Smart phone (320)" data-width='320'><svg viewBox="0 0 224 412" height="24" width="13" class="icon"><path d="M 190.7,0 H 33 C 14.8,0 0,14.8 0,33 v 346 c 0,18.2 14.8,33 33,33 h 157.7 c 18.2,0 33,-14.8 33,-33 V 33 c 0,-18.2 -14.8,-33 -33,-33 z M 94.3,30.2 h 37 c 2.2,0 4,1.8 4,4 0,2.2 -1.8,4 -4,4 h -37 c -2.2,0 -4,-1.8 -4,-4 0,-2.2 1.8,-4 4,-4 z m 18.5,362.8 c -8.8,0 -16,-7.2 -16,-16 0,-8.8 7.2,-16 16,-16 8.8,0 16,7.2 16,16 0,8.8 -7.2,16 -16,16 z M 198.6,343.8 H 25.1 V 68.2 h 173.5 v 275.5 z"></path></svg></button><button title="Feature phone (240)" data-width='240'><svg viewBox="0 0 201 412" height="24" width="12" class="icon"><path d="M 165.5,0.2 V 45 H 25 c -13.8,0 -25,11.2 -25,25 V 387 c 0,13.8 11.2,25 25,25 h 150.5 c 13.8,0 25,-11.2 25,-25 V 0.2 h -35 z M 65.2,366.5 H 34.2 v -24.5 h 31 v 24.5 z m 0,-44.3 H 34.2 v -24.5 h 31 v 24.5 z m 50.5,44.3 H 84.7 v -24.5 h 31 v 24.5 z m 0,-44.3 H 84.7 v -24.5 h 31 v 24.5 z m 50.5,44.3 h -31 v -24.5 h 31 v 24.5 z m 0,-44.3 h -31 v -24.5 h 31 v 24.5 z m 0,-59.3 h -132 V 95.4 h 132 V 262.9 z"></path></svg></button><button title="Auto (100%)" data-width="auto" class="auto is-active">Auto</button></div></div><script>(function(){var a=[{title:"actions-toolbar",filename:"actions-toolbar",url:"actions-toolbar.html"},{title:"Actions toolbar",filename:"actions-toolbar",url:"actions-toolbar.html#actions-toolbar"},{title:"Actions toolbar mixin variables",filename:"actions-toolbar",url:"actions-toolbar.html#actions-toolbar-mixin-variables"},{title:"Actions toolbar alignment",filename:"actions-toolbar",url:"actions-toolbar.html#actions-toolbar-alignment"},{title:"Reverse primary and secondary blocks",filename:"actions-toolbar",url:"actions-toolbar.html#reverse-primary-and-secondary-blocks"},{title:"Actions toolbar indents customizations",filename:"actions-toolbar",url:"actions-toolbar.html#actions-toolbar-indents-customizations"},{title:"Responsive actions toolbar",filename:"actions-toolbar",url:"actions-toolbar.html#responsive-actions-toolbar"},{title:"breadcrumbs",filename:"breadcrumbs",url:"breadcrumbs.html"},{title:"Breadcrumbs",filename:"breadcrumbs",url:"breadcrumbs.html#breadcrumbs"},{title:"Breadcrumbs variables",filename:"breadcrumbs",url:"breadcrumbs.html#breadcrumbs-variables"},{title:"Button-styled breadcrumbs with gradient background, border, and no separating symbol",filename:"breadcrumbs",url:"breadcrumbs.html#buttonstyled-breadcrumbs-with-gradient-background-border-and-no-separating-symbol"},{title:"Breadcrumbs with solid background",filename:"breadcrumbs",url:"breadcrumbs.html#breadcrumbs-with-solid-background"},{title:"buttons",filename:"buttons",url:"buttons.html"},{title:"Default button",filename:"buttons",url:"buttons.html#default-button"},{title:"Button variables",filename:"buttons",url:"buttons.html#button-variables"},{title:"Button as an icon",filename:"buttons",url:"buttons.html#button-as-an-icon"},{title:"Button with an icon on the left or right side of the text",filename:"buttons",url:"buttons.html#button-with-an-icon-on-the-left-or-right-side-of-the-text"},{title:"Button with fixed width",filename:"buttons",url:"buttons.html#button-with-fixed-width"},{title:"Primary button",filename:"buttons",url:"buttons.html#primary-button"},{title:"Primary button variables",filename:"buttons",url:"buttons.html#primary-button-variables"},{title:"Button with gradient background",filename:"buttons",url:"buttons.html#button-with-gradient-background"},{title:"Button as a link",filename:"buttons",url:"buttons.html#button-as-a-link"},{title:"Button as a link variables",filename:"buttons",url:"buttons.html#button-as-a-link-variables"},{title:"Link as a button",filename:"buttons",url:"buttons.html#link-as-a-button"},{title:"Button reset",filename:"buttons",url:"buttons.html#button-reset"},{title:"Button revert secondary color",filename:"buttons",url:"buttons.html#button-revert-secondary-color"},{title:"Button revert secondary color variables",filename:"buttons",url:"buttons.html#button-revert-secondary-color-variables"},{title:"Button revert secondary size",filename:"buttons",url:"buttons.html#button-revert-secondary-size"},{title:"Button revert secondary size variables",filename:"buttons",url:"buttons.html#button-revert-secondary-size-variables"},{title:"components",filename:"components",url:"components.html"},{title:"Components",filename:"components",url:"components.html#components"},{title:"Components Variables",filename:"components",url:"components.html#components-variables"},{title:"dropdowns",filename:"dropdowns",url:"dropdowns.html"},{title:"Drop-down and split buttons mixins",filename:"dropdowns",url:"dropdowns.html#dropdown-and-split-buttons-mixins"},{title:"Drop-down",filename:"dropdowns",url:"dropdowns.html#dropdown"},{title:"Drop-down variables",filename:"dropdowns",url:"dropdowns.html#dropdown-variables"},{title:"Drop-down with icon customization",filename:"dropdowns",url:"dropdowns.html#dropdown-with-icon-customization"},{title:"Modify dropdown list styles",filename:"dropdowns",url:"dropdowns.html#modify-dropdown-list-styles"},{title:"Split button",filename:"dropdowns",url:"dropdowns.html#split-button"},{title:"Split button variables",filename:"dropdowns",url:"dropdowns.html#split-button-variables"},{title:"Split button - button styling",filename:"dropdowns",url:"dropdowns.html#split-button-button-styling"},{title:"Split button icon customization",filename:"dropdowns",url:"dropdowns.html#split-button-icon-customization"},{title:"Split button drop-down list customization",filename:"dropdowns",url:"dropdowns.html#split-button-dropdown-list-customization"},{title:"forms",filename:"forms",url:"forms.html"},{title:"Forms mixins",filename:"forms",url:"forms.html#forms-mixins"},{title:"Global forms elements customization",filename:"forms",url:"forms.html#global-forms-elements-customization"},{title:"Fieldsets & fields customization",filename:"forms",url:"forms.html#fieldsets-fields-customization"},{title:"Fieldset and legend customization variables",filename:"forms",url:"forms.html#fieldset-and-legend-customization-variables"},{title:"Fields customization variables",filename:"forms",url:"forms.html#fields-customization-variables"},{title:"Required fields message customization variables",filename:"forms",url:"forms.html#required-fields-message-customization-variables"},{title:"Form element inputs customization",filename:"forms",url:"forms.html#form-element-inputs-customization"},{title:"Form element inputs customization variables",filename:"forms",url:"forms.html#form-element-inputs-customization-variables"},{title:"Form element choice",filename:"forms",url:"forms.html#form-element-choice"},{title:"Form element choice variables",filename:"forms",url:"forms.html#form-element-choice-variables"},{title:"Custom color",filename:"forms",url:"forms.html#custom-color"},{title:"Input number - input-text view",filename:"forms",url:"forms.html#input-number-inputtext-view"},{title:"Input search - input-text view",filename:"forms",url:"forms.html#input-search-inputtext-view"},{title:"Form validation",filename:"forms",url:"forms.html#form-validation"},{title:"Form validation variables",filename:"forms",url:"forms.html#form-validation-variables"},{title:"icons",filename:"icons",url:"icons.html"},{title:"Icons",filename:"icons",url:"icons.html#icons"},{title:"Icon with image or sprite",filename:"icons",url:"icons.html#icon-with-image-or-sprite"},{title:"Icon with image or sprite variables",filename:"icons",url:"icons.html#icon-with-image-or-sprite-variables"},{title:"Icon position for an icon with image or sprite",filename:"icons",url:"icons.html#icon-position-for-an-icon-with-image-or-sprite"},{title:"Position for icon with image or sprite mixin variables",filename:"icons",url:"icons.html#position-for-icon-with-image-or-sprite-mixin-variables"},{title:"Icon sprite position (with grid)",filename:"icons",url:"icons.html#icon-sprite-position-with-grid"},{title:"Icon sprite position variables",filename:"icons",url:"icons.html#icon-sprite-position-variables"},{title:"Image/sprite icon size",filename:"icons",url:"icons.html#imagesprite-icon-size"},{title:"Image/sprite icon size variables",filename:"icons",url:"icons.html#imagesprite-icon-size-variables"},{title:"Font icon",filename:"icons",url:"icons.html#font-icon"},{title:"Font icon variables",filename:"icons",url:"icons.html#font-icon-variables"},{title:"Change the size of font icon",filename:"icons",url:"icons.html#change-the-size-of-font-icon"},{title:"Change the size of font icon variables",filename:"icons",url:"icons.html#change-the-size-of-font-icon-variables"},{title:"Hide icon text",filename:"icons",url:"icons.html#hide-icon-text"},{title:"Sprite and font icons for Blank theme",filename:"icons",url:"icons.html#sprite-and-font-icons-for-blank-theme"},{title:"layout",filename:"layout",url:"layout.html"},{title:"Layout",filename:"layout",url:"layout.html#layout"},{title:"Layout global variables",filename:"layout",url:"layout.html#layout-global-variables"},{title:"Page layouts",filename:"layout",url:"layout.html#page-layouts"},{title:"Layout column",filename:"layout",url:"layout.html#layout-column"},{title:"Layout column variables",filename:"layout",url:"layout.html#layout-column-variables"},{title:"Layout width",filename:"layout",url:"layout.html#layout-width"},{title:"Layout width variables",filename:"layout",url:"layout.html#layout-width-variables"},{title:"lib",filename:"lib",url:"lib.html"},{title:"Including Magento UI library to your theme",filename:"lib",url:"lib.html#including-magento-ui-library-to-your-theme"},{title:"loaders",filename:"loaders",url:"loaders.html"},{title:"Loaders",filename:"loaders",url:"loaders.html#loaders"},{title:"Default loader variables",filename:"loaders",url:"loaders.html#default-loader-variables"},{title:"Loading",filename:"loaders",url:"loaders.html#loading"},{title:"Loading default variables",filename:"loaders",url:"loaders.html#loading-default-variables"},{title:"messages",filename:"messages",url:"messages.html"},{title:"Messages",filename:"messages",url:"messages.html#messages"},{title:"Information message",filename:"messages",url:"messages.html#information-message"},{title:"Warning message",filename:"messages",url:"messages.html#warning-message"},{title:"Error message",filename:"messages",url:"messages.html#error-message"},{title:"Success message",filename:"messages",url:"messages.html#success-message"},{title:"Notice message",filename:"messages",url:"messages.html#notice-message"},{title:"Message with inner icon",filename:"messages",url:"messages.html#message-with-inner-icon"},{title:"Message with lateral icon",filename:"messages",url:"messages.html#message-with-lateral-icon"},{title:"Custom message style",filename:"messages",url:"messages.html#custom-message-style"},{title:"Messages global variables",filename:"messages",url:"messages.html#messages-global-variables"},{title:"pages",filename:"pages",url:"pages.html"},{title:"Pagination HTML markup",filename:"pages",url:"pages.html#pagination-html-markup"},{title:"Pagination variables",filename:"pages",url:"pages.html#pagination-variables"},{title:"Pagination with label and gradient background on links",filename:"pages",url:"pages.html#pagination-with-label-and-gradient-background-on-links"},{title:'Pagination with "previous"..."next" text links and label',filename:"pages",url:"pages.html#pagination-with-previousnext-text-links-and-label"},{title:"Pagination without label, with solid background",filename:"pages",url:"pages.html#pagination-without-label-with-solid-background"},{title:"popups",filename:"popups",url:"popups.html"},{title:"Popups",filename:"popups",url:"popups.html#popups"},{title:"Popup variables",filename:"popups",url:"popups.html#popup-variables"},{title:"Window overlay mixin variables",filename:"popups",url:"popups.html#window-overlay-mixin-variables"},{title:"Fixed height popup",filename:"popups",url:"popups.html#fixed-height-popup"},{title:"Fixed content height popup",filename:"popups",url:"popups.html#fixed-content-height-popup"},{title:"Margins for header, content and footer block in popup",filename:"popups",url:"popups.html#margins-for-header-content-and-footer-block-in-popup"},{title:"Popup titles styled as theme headings",filename:"popups",url:"popups.html#popup-titles-styled-as-theme-headings"},{title:"Popup action toolbar",filename:"popups",url:"popups.html#popup-action-toolbar"},{title:"Popup Close button without an icon",filename:"popups",url:"popups.html#popup-close-button-without-an-icon"},{title:"Modify the icon of popup Close button",filename:"popups",url:"popups.html#modify-the-icon-of-popup-close-button"},{title:"Modify overlay styles",filename:"popups",url:"popups.html#modify-overlay-styles"},{title:"rating",filename:"rating",url:"rating.html"},{title:"Ratings",filename:"rating",url:"rating.html#ratings"},{title:"Global rating variables",filename:"rating",url:"rating.html#global-rating-variables"},{title:"Rating with vote",filename:"rating",url:"rating.html#rating-with-vote"},{title:"Rating with vote icons number customization",filename:"rating",url:"rating.html#rating-with-vote-icons-number-customization"},{title:"Rating with vote icons colors customization",filename:"rating",url:"rating.html#rating-with-vote-icons-colors-customization"},{title:"Rating with vote icons symbol customization",filename:"rating",url:"rating.html#rating-with-vote-icons-symbol-customization"},{title:"Accessible rating with vote",filename:"rating",url:"rating.html#accessible-rating-with-vote"},{title:"Rating summary",filename:"rating",url:"rating.html#rating-summary"},{title:"Rating summary icons number customization",filename:"rating",url:"rating.html#rating-summary-icons-number-customization"},{title:"Rating summary icons color customization",filename:"rating",url:"rating.html#rating-summary-icons-color-customization"},{title:"Rating summary icons symbol customization",filename:"rating",url:"rating.html#rating-summary-icons-symbol-customization"},{title:"Rating summary hide label",filename:"rating",url:"rating.html#rating-summary-hide-label"},{title:"Rating summary multiple ratings",filename:"rating",url:"rating.html#rating-summary-multiple-ratings"},{title:"Rating hide label mixin",filename:"rating",url:"rating.html#rating-hide-label-mixin"},{title:"resets",filename:"resets",url:"resets.html"},{title:"Resets",filename:"resets",url:"resets.html#resets"},{title:"responsive",filename:"responsive",url:"responsive.html"},{title:"Responsive",filename:"responsive",url:"responsive.html#responsive"},{title:"Responsive mixins usage",filename:"responsive",url:"responsive.html#responsive-mixins-usage"},{title:"Media query style groups separation variables",filename:"responsive",url:"responsive.html#media-query-style-groups-separation-variables"},{title:"Responsive breakpoints",filename:"responsive",url:"responsive.html#responsive-breakpoints"},{title:"sections",filename:"sections",url:"sections.html"},{title:"Tabs and accordions",filename:"sections",url:"sections.html#tabs-and-accordions"},{title:"Tabs",filename:"sections",url:"sections.html#tabs"},{title:"Tabs mixin variables",filename:"sections",url:"sections.html#tabs-mixin-variables"},{title:"Tabs with content top border",filename:"sections",url:"sections.html#tabs-with-content-top-border"},{title:"Accordion",filename:"sections",url:"sections.html#accordion"},{title:"Accordion mixin variables",filename:"sections",url:"sections.html#accordion-mixin-variables"},{title:"Responsive tabs",filename:"sections",url:"sections.html#responsive-tabs"},{title:"Tabs Base",filename:"sections",url:"sections.html#tabs-base"},{title:"Accordion Base",filename:"sections",url:"sections.html#accordion-base"},{title:"tables",filename:"tables",url:"tables.html"},{title:"Tables",filename:"tables",url:"tables.html#tables"},{title:"Table mixin variables",filename:"tables",url:"tables.html#table-mixin-variables"},{title:"Table typography",filename:"tables",url:"tables.html#table-typography"},{title:"Table typography mixin variables",filename:"tables",url:"tables.html#table-typography-mixin-variables"},{title:"Table caption",filename:"tables",url:"tables.html#table-caption"},{title:"Table caption mixin variables",filename:"tables",url:"tables.html#table-caption-mixin-variables"},{title:"Table cells resize",filename:"tables",url:"tables.html#table-cells-resize"},{title:"Table cells resize variables",filename:"tables",url:"tables.html#table-cells-resize-variables"},{title:"Table background customization",filename:"tables",url:"tables.html#table-background-customization"},{title:"Table background mixin variables",filename:"tables",url:"tables.html#table-background-mixin-variables"},{title:"Table borders customization",filename:"tables",url:"tables.html#table-borders-customization"},{title:"Table borders mixin variables",filename:"tables",url:"tables.html#table-borders-mixin-variables"},{title:"Table with horizontal borders",filename:"tables",url:"tables.html#table-with-horizontal-borders"},{title:"Table with vertical borders",filename:"tables",url:"tables.html#table-with-vertical-borders"},{title:"Table with light borders",filename:"tables",url:"tables.html#table-with-light-borders"},{title:"Table without borders",filename:"tables",url:"tables.html#table-without-borders"},{title:"Striped table",filename:"tables",url:"tables.html#striped-table"},{title:"Striped table mixin variables",filename:"tables",url:"tables.html#striped-table-mixin-variables"},{title:"Table with rows hover",filename:"tables",url:"tables.html#table-with-rows-hover"},{title:"Table with rows hover mixin variables",filename:"tables",url:"tables.html#table-with-rows-hover-mixin-variables"},{title:"Responsive table technics #1",filename:"tables",url:"tables.html#responsive-table-technics-1"},{title:"Responsive table technics #2",filename:"tables",url:"tables.html#responsive-table-technics-2"},{title:"Responsive table technics #2 mixin variables",filename:"tables",url:"tables.html#responsive-table-technics-2-mixin-variables"},{title:"tooltips",filename:"tooltips",url:"tooltips.html"},{title:"Tooltips",filename:"tooltips",url:"tooltips.html#tooltips"},{title:"Tooltips variables",filename:"tooltips",url:"tooltips.html#tooltips-variables"},{title:"typography",filename:"typography",url:"typography.html"},{title:"Typogrphy",filename:"typography",url:"typography.html#typogrphy"},{title:"Typography variables",filename:"typography",url:"typography.html#typography-variables"},{title:"Font-size mixin",filename:"typography",url:"typography.html#fontsize-mixin"},{title:"Line-height mixin",filename:"typography",url:"typography.html#lineheight-mixin"},{title:"Word breaking mixin",filename:"typography",url:"typography.html#word-breaking-mixin"},{title:"Font face mixin",filename:"typography",url:"typography.html#font-face-mixin"},{title:"Text overflow mixin",filename:"typography",url:"typography.html#text-overflow-mixin"},{title:"Text hide",filename:"typography",url:"typography.html#text-hide"},{title:"Hyphens",filename:"typography",url:"typography.html#hyphens"},{title:"Font style and color",filename:"typography",url:"typography.html#font-style-and-color"},{title:"Font style mixin variables",filename:"typography",url:"typography.html#font-style-mixin-variables"},{title:"Reset list styles",filename:"typography",url:"typography.html#reset-list-styles"},{title:"Reset list styles variables",filename:"typography",url:"typography.html#reset-list-styles-variables"},{title:"Inline-block list item styling",filename:"typography",url:"typography.html#inlineblock-list-item-styling"},{title:"Link styling mixin",filename:"typography",url:"typography.html#link-styling-mixin"},{title:"Link styling mixin variables",filename:"typography",url:"typography.html#link-styling-mixin-variables"},{title:"Heading styling mixin",filename:"typography",url:"typography.html#heading-styling-mixin"},{title:"Base typography mixins",filename:"typography",url:"typography.html#base-typography-mixins"},{title:"Base typography mixin variables",filename:"typography",url:"typography.html#base-typography-mixin-variables"},{title:"Headings typography mixin",filename:"typography",url:"typography.html#headings-typography-mixin"},{title:"Headings typography mixin variables",filename:"typography",url:"typography.html#headings-typography-mixin-variables"},{title:"Typography links mixin",filename:"typography",url:"typography.html#typography-links-mixin"},{title:"Typography lists mixin",filename:"typography",url:"typography.html#typography-lists-mixin"},{title:"Typography lists mixin variables",filename:"typography",url:"typography.html#typography-lists-mixin-variables"},{title:"Typography code elements mixin",filename:"typography",url:"typography.html#typography-code-elements-mixin"},{title:"Typography code mixin variables",filename:"typography",url:"typography.html#typography-code-mixin-variables"},{title:"Typography blockquote",filename:"typography",url:"typography.html#typography-blockquote"},{title:"Typography blockquote mixin variables",filename:"typography",url:"typography.html#typography-blockquote-mixin-variables"},{title:"utilities",filename:"utilities",url:"utilities.html"},{title:"Utilities",filename:"utilities",url:"utilities.html#utilities"},{title:".lib-clearfix()",filename:"utilities",url:"utilities.html#libclearfix"},{title:".lib-visibility-hidden()",filename:"utilities",url:"utilities.html#libvisibilityhidden"},{title:".lib-visually-hidden()",filename:"utilities",url:"utilities.html#libvisuallyhidden"},{title:".lib-visually-hidden-reset()",filename:"utilities",url:"utilities.html#libvisuallyhiddenreset"},{title:".lib-css()",filename:"utilities",url:"utilities.html#libcss"},{title:".lib-css() variables",filename:"utilities",url:"utilities.html#libcss-variables"},{title:".lib-rotate()",filename:"utilities",url:"utilities.html#librotate"},{title:".lib-rotate() variables",filename:"utilities",url:"utilities.html#librotate-variables"},{title:".lib-input-placeholder()",filename:"utilities",url:"utilities.html#libinputplaceholder"},{title:".lib-input-placeholder() variables",filename:"utilities",url:"utilities.html#libinputplaceholder-variables"},{title:".lib-background-gradient()",filename:"utilities",url:"utilities.html#libbackgroundgradient"},{title:".lib-background-gradient() variables",filename:"utilities",url:"utilities.html#libbackgroundgradient-variables"},{title:".lib-url-check()",filename:"utilities",url:"utilities.html#liburlcheck"},{title:".lib-url-check() variables",filename:"utilities",url:"utilities.html#liburlcheck-variables"},{title:"variables",filename:"variables",url:"variables.html"},{title:"List of Global Variables",filename:"variables",url:"variables.html#list-of-global-variables"},{title:"Table with rows hover mixin variables",filename:"variables",url:"variables.html#table-with-rows-hover-mixin-variables"},{title:"docs",filename:"docs",url:"docs.html"},{title:"Documentation",filename:"docs",url:"docs.html#documentation"}];(function(){"use strict";var b=function(a,b){return Array.prototype.indexOf.call(a,b)!==-1},c=function(a,b){return Array.prototype.filter.call(a,b)},d=function(a,b){return Array.prototype.forEach.call(a,b)},e=document.getElementsByTagName("body")[0];e.addEventListener("click",function(a){var b=a.target;b.tagName.toLowerCase()==="svg"&&(b=b.parentNode);var c=!1;b.dataset.toggle!=null&&(a.preventDefault(),b.classList.contains("is-active")||(c=!0)),d(e.querySelectorAll("[data-toggle]"),function(a){a.classList.remove("is-active"),document.getElementById(a.dataset.toggle).hidden=!0}),c&&(b.classList.add("is-active"),document.getElementById(b.dataset.toggle).hidden=!1)}),function(){var f=e.getElementsByClassName("nav")[0];if(!f)return;var g=document.createElement("ul");g.className="nav-results",g.id="nav-search",g.hidden=!0,d(a,function(a){var b,c,d;b=document.createElement("li"),b._title=a.title.toLowerCase(),b.hidden=!0,b.appendChild(c=document.createElement("a")),c.href=a.url,c.innerHTML=a.title,c.appendChild(d=document.createElement("span")),d.innerHTML=a.filename,d.className="nav-results-filename",g.appendChild(b)}),f.appendChild(g);var h=g.children,i=function(a){d(h,function(a){a.hidden=!0});var b=this.value.toLowerCase(),e=[];b!==""&&(e=c(h,function(a){return a._title.indexOf(b)!==-1})),e.length>0?(d(e,function(a){a.hidden=!1}),g.hidden=!1):g.hidden=!0},j=f.querySelector('input[type="search"]');j.addEventListener("keyup",i),j.addEventListener("focus",i),e.addEventListener("click",function(a){if(a.target.classList&&a.target.classList.contains("search"))return;g.hidden=!0}),g.addEventListener("click",function(a){j.value=""});var k=document.createElement("ul");k.id="nav-toc",k.hidden=!0,k.className="nav-results toc-list",c(e.getElementsByTagName("*"),function(a){return b(["h1","h2","h3"],a.tagName.toLowerCase())}).map(function(a){var b=document.createElement("li"),c=document.createElement("a"),d=a.tagName.toLowerCase()[1];c.classList.add("level-"+d),b.appendChild(c),c.href="#"+a.id,c.innerHTML=a.innerHTML,k.appendChild(b)}),f.appendChild(k)}()})(),function(){"use strict";if(location.hash==="#__preview__"||location.protocol==="data:")return;var a=function(a,b){return Array.prototype.forEach.call(a,b)},b=function(a,b){var e=Array.prototype.slice.call(arguments,2);return d(a,function(a){return(c(b)?b||a:a[b]).apply(a,e)})},c=function(a){return Object.prototype.toString.call(a)==="[object Function]"},d=function(a,b){return Array.prototype.map.call(a,b)},e=function(a,b){return d(a,function(a){return a[b]})},f=function(a){var b={},c=a.split(";");for(var d=0;c.length>d;d++){var e=c[d].trim().split("=");b[e[0]]=e[1]}return b},g=function(a,c){return b(e(a,"classList"),"remove",c)},h=function(a,b){a.contentDocument.defaultView.postMessage(b,"*")},i=document.getElementsByTagName("head")[0],j=document.getElementsByTagName("body")[0],k=e(i.querySelectorAll('style[type="text/preview"]'),"innerHTML").join(""),l=e(i.querySelectorAll('script[type="text/preview"]'),"innerHTML").join(""),m=location.href.split("#")[0]+"#__preview__",n=document.createElement("iframe");n.src="data:text/html,",j.appendChild(n),n.addEventListener("load",function(){var b={sameOriginDataUri:!0};try{this.contentDocument,this.contentDocument||(b.sameOriginDataUri=!1)}catch(c){b.sameOriginDataUri=!1}this.parentNode.removeChild(this),a(j.getElementsByTagName("textarea"),function(a,c){o(a,b,c),q(),p(a)})});var o=function(a,b,c){var d,e,f;d=document.createElement("div"),d.appendChild(e=document.createElement("div")),d.className="preview",e.appendChild(f=document.createElement("iframe")),e.className="resizeable",f.setAttribute("scrolling","no"),f.name="iframe"+c++,f.addEventListener("load",function(){var c,d,e,f,g,i,j;j=this.contentDocument;if(!b.sameOriginDataUri&&this.src!==m)return;this.src===m&&(c=j.createElement("html"),c.appendChild(j.createElement("head")),c.appendChild(d=j.createElement("body")),d.innerHTML=a.textContent,j.replaceChild(c,j.documentElement)),g=j.createElement("head"),g.appendChild(f=j.createElement("style")),g.appendChild(e=j.createElement("script")),e.textContent=l,f.textContent=k,i=j.getElementsByTagName("head")[0],i.parentNode.replaceChild(g,i),h(this,"getHeight")});var g;b.sameOriginDataUri?g="data:text/html;charset=utf-8,"+encodeURIComponent("<!doctype html><html><head></head></body>"+a.textContent):g=m,f.setAttribute("src",g);var i=function(){f.contentDocument.body.innerHTML=this.value,h(f,"getHeight")};a.addEventListener("keypress",i),a.addEventListener("keyup",i),a.parentNode.insertBefore(d,a)},p=function(a){var b=document.createElement("div");b.className="preview-code",b.style.position="absolute",b.style.left="-9999px",j.appendChild(b);var c=parseInt(window.getComputedStyle(a).getPropertyValue("max-height"),10),d=function(a){b.textContent=this.value+"\n";var d=b.offsetHeight+2;d>=c?this.style.overflow="auto":this.style.overflow="hidden",this.style.height=b.offsetHeight+2+"px"};a.addEventListener("keypress",d),a.addEventListener("keyup",d),d.call(a)},q=function(){var b=j.getElementsByClassName("settings")[0],c=j.getElementsByClassName("resizeable"),d=30,e=function(b){document.cookie="preview-width="+b,a(c,function(a){b==="auto"&&(b=a.parentNode.offsetWidth),a.style.width=b+"px",h(a.getElementsByTagName("iframe")[0],"getHeight")})},i=f(document.cookie)["preview-width"];if(i){e(i),g(b.getElementsByClassName("is-active"),"is-active");var k=b.querySelector('button[data-width="'+i+'"]');k&&k.classList.add("is-active")}window.addEventListener("message",function(a){if(a.data==null||!a.source)return;var b=a.data,c=document.getElementsByName(a.source.name)[0];b.height!=null&&c&&(c.parentNode.style.height=b.height+d+"px")},!1),b&&c.length>0&&(b.hidden=!1,b.addEventListener("click",function(a){var c=a.target.tagName.toLowerCase(),d;if(c==="button")d=a.target;else{if(c!=="svg")return;d=a.target.parentNode}a.preventDefault(),g(b.getElementsByClassName("is-active"),"is-active"),d.classList.add("is-active");var f=d.dataset.width;e(f)}))}}()})()</script></body></html><!-- Generated with StyleDocco (http://jacobrask.github.com/styledocco). --> +}</code></pre></div></article></section><div class="bar bottom"><div hidden class="settings container"><!-- Icons from http://iconmonstr.com--><button title="Desktop (1280)" data-width='1280'><svg viewBox="0 0 412 386" height="24" width="26" class="icon"><path d="m147.6,343.9c-4.5,15.9-26.2,37.6-42.1,42.1h201c-15.3,-4-38.1,-26.8-42.1,-42.1H147.6zM387,0.5H25c-13.8,0-25,11.2-25,25V294c0,13.8 11.2,25 25,25h362c13.8,0 25,-11.2 25,-25V25.5C412,11.7 400.8,0.5 387,0.5zM369.9,238.2H42.1L42.1,42.6 369.9,42.6V238.2z"></path></svg></button><button title="Laptop (1024)" data-width='1024'><svg viewBox="0 0 384 312" height="23" width="28" class="icon"><path d="m349.2,20.5c0,-11-9,-20-20,-20H53.6c-11,0-20,9-20,20v194H349.2v-194zm-27,167H60.6V27.5H322.2v160zm28,42H32.6L2.6,282.1c-3.5,6.2-3.5,13.8 0.1,19.9 3.6,6.2 10.2,9.9 17.3,9.9H363.1c7.1,0 13.7,-3.8 17.3,-10 3.6,-6.2 3.6,-13.8 0,-20l-30.2,-52.5zm-196.9,54 8,-23.5h60.5l8,23.5h-76.5z"></path></svg></button><button title="Tablet (768)" data-width='768'><svg viewBox="0 0 317 412" height="24" width="18" class="icon"><path d="M 316.5,380 V 32 c 0,-17.7 -14.3,-32 -32,-32 H 32 C 14.3,0 0,14.3 0,32 v 348 c 0,17.7 14.3,32 32,32 h 252.5 c 17.7,0 32,-14.3 32,-32 z M 40,367 V 45 H 276.5 V 367 H 40 z m 109.8,22.7 c 0,-4.7 3.8,-8.5 8.5,-8.5 4.7,0 8.5,3.8 8.5,8.5 0,4.7 -3.8,8.5 -8.5,8.5 -4.7,0 -8.5,-3.8 -8.5,-8.5 z"></path></svg></button><button title="Smart phone (320)" data-width='320'><svg viewBox="0 0 224 412" height="24" width="13" class="icon"><path d="M 190.7,0 H 33 C 14.8,0 0,14.8 0,33 v 346 c 0,18.2 14.8,33 33,33 h 157.7 c 18.2,0 33,-14.8 33,-33 V 33 c 0,-18.2 -14.8,-33 -33,-33 z M 94.3,30.2 h 37 c 2.2,0 4,1.8 4,4 0,2.2 -1.8,4 -4,4 h -37 c -2.2,0 -4,-1.8 -4,-4 0,-2.2 1.8,-4 4,-4 z m 18.5,362.8 c -8.8,0 -16,-7.2 -16,-16 0,-8.8 7.2,-16 16,-16 8.8,0 16,7.2 16,16 0,8.8 -7.2,16 -16,16 z M 198.6,343.8 H 25.1 V 68.2 h 173.5 v 275.5 z"></path></svg></button><button title="Feature phone (240)" data-width='240'><svg viewBox="0 0 201 412" height="24" width="12" class="icon"><path d="M 165.5,0.2 V 45 H 25 c -13.8,0 -25,11.2 -25,25 V 387 c 0,13.8 11.2,25 25,25 h 150.5 c 13.8,0 25,-11.2 25,-25 V 0.2 h -35 z M 65.2,366.5 H 34.2 v -24.5 h 31 v 24.5 z m 0,-44.3 H 34.2 v -24.5 h 31 v 24.5 z m 50.5,44.3 H 84.7 v -24.5 h 31 v 24.5 z m 0,-44.3 H 84.7 v -24.5 h 31 v 24.5 z m 50.5,44.3 h -31 v -24.5 h 31 v 24.5 z m 0,-44.3 h -31 v -24.5 h 31 v 24.5 z m 0,-59.3 h -132 V 95.4 h 132 V 262.9 z"></path></svg></button><button title="Auto (100%)" data-width="auto" class="auto is-active">Auto</button></div></div><script>(function(){var a=[{title:"actions-toolbar",filename:"actions-toolbar",url:"actions-toolbar.html"},{title:"Actions toolbar",filename:"actions-toolbar",url:"actions-toolbar.html#actions-toolbar"},{title:"Actions toolbar mixin variables",filename:"actions-toolbar",url:"actions-toolbar.html#actions-toolbar-mixin-variables"},{title:"Actions toolbar alignment",filename:"actions-toolbar",url:"actions-toolbar.html#actions-toolbar-alignment"},{title:"Reverse primary and secondary blocks",filename:"actions-toolbar",url:"actions-toolbar.html#reverse-primary-and-secondary-blocks"},{title:"Actions toolbar indents customizations",filename:"actions-toolbar",url:"actions-toolbar.html#actions-toolbar-indents-customizations"},{title:"Responsive actions toolbar",filename:"actions-toolbar",url:"actions-toolbar.html#responsive-actions-toolbar"},{title:"breadcrumbs",filename:"breadcrumbs",url:"breadcrumbs.html"},{title:"Breadcrumbs",filename:"breadcrumbs",url:"breadcrumbs.html#breadcrumbs"},{title:"Breadcrumbs variables",filename:"breadcrumbs",url:"breadcrumbs.html#breadcrumbs-variables"},{title:"Button-styled breadcrumbs with gradient background, border, and no separating symbol",filename:"breadcrumbs",url:"breadcrumbs.html#buttonstyled-breadcrumbs-with-gradient-background-border-and-no-separating-symbol"},{title:"Breadcrumbs with solid background",filename:"breadcrumbs",url:"breadcrumbs.html#breadcrumbs-with-solid-background"},{title:"buttons",filename:"buttons",url:"buttons.html"},{title:"Default button",filename:"buttons",url:"buttons.html#default-button"},{title:"Button variables",filename:"buttons",url:"buttons.html#button-variables"},{title:"Button as an icon",filename:"buttons",url:"buttons.html#button-as-an-icon"},{title:"Button with an icon on the left or right side of the text",filename:"buttons",url:"buttons.html#button-with-an-icon-on-the-left-or-right-side-of-the-text"},{title:"Button with fixed width",filename:"buttons",url:"buttons.html#button-with-fixed-width"},{title:"Primary button",filename:"buttons",url:"buttons.html#primary-button"},{title:"Primary button variables",filename:"buttons",url:"buttons.html#primary-button-variables"},{title:"Button with gradient background",filename:"buttons",url:"buttons.html#button-with-gradient-background"},{title:"Button as a link",filename:"buttons",url:"buttons.html#button-as-a-link"},{title:"Button as a link variables",filename:"buttons",url:"buttons.html#button-as-a-link-variables"},{title:"Link as a button",filename:"buttons",url:"buttons.html#link-as-a-button"},{title:"Button reset",filename:"buttons",url:"buttons.html#button-reset"},{title:"Button revert secondary color",filename:"buttons",url:"buttons.html#button-revert-secondary-color"},{title:"Button revert secondary color variables",filename:"buttons",url:"buttons.html#button-revert-secondary-color-variables"},{title:"Button revert secondary size",filename:"buttons",url:"buttons.html#button-revert-secondary-size"},{title:"Button revert secondary size variables",filename:"buttons",url:"buttons.html#button-revert-secondary-size-variables"},{title:"components",filename:"components",url:"components.html"},{title:"Components",filename:"components",url:"components.html#components"},{title:"Components Variables",filename:"components",url:"components.html#components-variables"},{title:"dropdowns",filename:"dropdowns",url:"dropdowns.html"},{title:"Drop-down and split buttons mixins",filename:"dropdowns",url:"dropdowns.html#dropdown-and-split-buttons-mixins"},{title:"Drop-down",filename:"dropdowns",url:"dropdowns.html#dropdown"},{title:"Drop-down variables",filename:"dropdowns",url:"dropdowns.html#dropdown-variables"},{title:"Drop-down with icon customization",filename:"dropdowns",url:"dropdowns.html#dropdown-with-icon-customization"},{title:"Modify dropdown list styles",filename:"dropdowns",url:"dropdowns.html#modify-dropdown-list-styles"},{title:"Split button",filename:"dropdowns",url:"dropdowns.html#split-button"},{title:"Split button variables",filename:"dropdowns",url:"dropdowns.html#split-button-variables"},{title:"Split button - button styling",filename:"dropdowns",url:"dropdowns.html#split-button-button-styling"},{title:"Split button icon customization",filename:"dropdowns",url:"dropdowns.html#split-button-icon-customization"},{title:"Split button drop-down list customization",filename:"dropdowns",url:"dropdowns.html#split-button-dropdown-list-customization"},{title:"forms",filename:"forms",url:"forms.html"},{title:"Forms mixins",filename:"forms",url:"forms.html#forms-mixins"},{title:"Global forms elements customization",filename:"forms",url:"forms.html#global-forms-elements-customization"},{title:"Fieldsets & fields customization",filename:"forms",url:"forms.html#fieldsets-fields-customization"},{title:"Fieldset and legend customization variables",filename:"forms",url:"forms.html#fieldset-and-legend-customization-variables"},{title:"Fields customization variables",filename:"forms",url:"forms.html#fields-customization-variables"},{title:"Required fields message customization variables",filename:"forms",url:"forms.html#required-fields-message-customization-variables"},{title:"Form element inputs customization",filename:"forms",url:"forms.html#form-element-inputs-customization"},{title:"Form element inputs customization variables",filename:"forms",url:"forms.html#form-element-inputs-customization-variables"},{title:"Form element choice",filename:"forms",url:"forms.html#form-element-choice"},{title:"Form element choice variables",filename:"forms",url:"forms.html#form-element-choice-variables"},{title:"Custom color",filename:"forms",url:"forms.html#custom-color"},{title:"Input number - input-text view",filename:"forms",url:"forms.html#input-number-inputtext-view"},{title:"Input search - input-text view",filename:"forms",url:"forms.html#input-search-inputtext-view"},{title:"Form validation",filename:"forms",url:"forms.html#form-validation"},{title:"Form validation variables",filename:"forms",url:"forms.html#form-validation-variables"},{title:"icons",filename:"icons",url:"icons.html"},{title:"Icons",filename:"icons",url:"icons.html#icons"},{title:"Icon with image or sprite",filename:"icons",url:"icons.html#icon-with-image-or-sprite"},{title:"Icon with image or sprite variables",filename:"icons",url:"icons.html#icon-with-image-or-sprite-variables"},{title:"Icon position for an icon with image or sprite",filename:"icons",url:"icons.html#icon-position-for-an-icon-with-image-or-sprite"},{title:"Position for icon with image or sprite mixin variables",filename:"icons",url:"icons.html#position-for-icon-with-image-or-sprite-mixin-variables"},{title:"Icon sprite position (with grid)",filename:"icons",url:"icons.html#icon-sprite-position-with-grid"},{title:"Icon sprite position variables",filename:"icons",url:"icons.html#icon-sprite-position-variables"},{title:"Image/sprite icon size",filename:"icons",url:"icons.html#imagesprite-icon-size"},{title:"Image/sprite icon size variables",filename:"icons",url:"icons.html#imagesprite-icon-size-variables"},{title:"Font icon",filename:"icons",url:"icons.html#font-icon"},{title:"Font icon variables",filename:"icons",url:"icons.html#font-icon-variables"},{title:"Change the size of font icon",filename:"icons",url:"icons.html#change-the-size-of-font-icon"},{title:"Change the size of font icon variables",filename:"icons",url:"icons.html#change-the-size-of-font-icon-variables"},{title:"Hide icon text",filename:"icons",url:"icons.html#hide-icon-text"},{title:"Sprite and font icons for Blank theme",filename:"icons",url:"icons.html#sprite-and-font-icons-for-blank-theme"},{title:"layout",filename:"layout",url:"layout.html"},{title:"Layout",filename:"layout",url:"layout.html#layout"},{title:"Layout global variables",filename:"layout",url:"layout.html#layout-global-variables"},{title:"Page layouts",filename:"layout",url:"layout.html#page-layouts"},{title:"Layout column",filename:"layout",url:"layout.html#layout-column"},{title:"Layout column variables",filename:"layout",url:"layout.html#layout-column-variables"},{title:"Layout width",filename:"layout",url:"layout.html#layout-width"},{title:"Layout width variables",filename:"layout",url:"layout.html#layout-width-variables"},{title:"lib",filename:"lib",url:"lib.html"},{title:"Including Magento UI library to your theme",filename:"lib",url:"lib.html#including-magento-ui-library-to-your-theme"},{title:"loaders",filename:"loaders",url:"loaders.html"},{title:"Loaders",filename:"loaders",url:"loaders.html#loaders"},{title:"Default loader variables",filename:"loaders",url:"loaders.html#default-loader-variables"},{title:"Loading",filename:"loaders",url:"loaders.html#loading"},{title:"Loading default variables",filename:"loaders",url:"loaders.html#loading-default-variables"},{title:"messages",filename:"messages",url:"messages.html"},{title:"Messages",filename:"messages",url:"messages.html#messages"},{title:"Information message",filename:"messages",url:"messages.html#information-message"},{title:"Warning message",filename:"messages",url:"messages.html#warning-message"},{title:"Error message",filename:"messages",url:"messages.html#error-message"},{title:"Success message",filename:"messages",url:"messages.html#success-message"},{title:"Notice message",filename:"messages",url:"messages.html#notice-message"},{title:"Message with inner icon",filename:"messages",url:"messages.html#message-with-inner-icon"},{title:"Message with lateral icon",filename:"messages",url:"messages.html#message-with-lateral-icon"},{title:"Custom message style",filename:"messages",url:"messages.html#custom-message-style"},{title:"Messages global variables",filename:"messages",url:"messages.html#messages-global-variables"},{title:"pages",filename:"pages",url:"pages.html"},{title:"Pagination HTML markup",filename:"pages",url:"pages.html#pagination-html-markup"},{title:"Pagination variables",filename:"pages",url:"pages.html#pagination-variables"},{title:"Pagination with label and gradient background on links",filename:"pages",url:"pages.html#pagination-with-label-and-gradient-background-on-links"},{title:'Pagination with "previous"..."next" text links and label',filename:"pages",url:"pages.html#pagination-with-previousnext-text-links-and-label"},{title:"Pagination without label, with solid background",filename:"pages",url:"pages.html#pagination-without-label-with-solid-background"},{title:"popups",filename:"popups",url:"popups.html"},{title:"Popups",filename:"popups",url:"popups.html#popups"},{title:"Popup variables",filename:"popups",url:"popups.html#popup-variables"},{title:"Window overlay mixin variables",filename:"popups",url:"popups.html#window-overlay-mixin-variables"},{title:"Fixed height popup",filename:"popups",url:"popups.html#fixed-height-popup"},{title:"Fixed content height popup",filename:"popups",url:"popups.html#fixed-content-height-popup"},{title:"Margins for header, content and footer block in popup",filename:"popups",url:"popups.html#margins-for-header-content-and-footer-block-in-popup"},{title:"Popup titles styled as theme headings",filename:"popups",url:"popups.html#popup-titles-styled-as-theme-headings"},{title:"Popup action toolbar",filename:"popups",url:"popups.html#popup-action-toolbar"},{title:"Popup Close button without an icon",filename:"popups",url:"popups.html#popup-close-button-without-an-icon"},{title:"Modify the icon of popup Close button",filename:"popups",url:"popups.html#modify-the-icon-of-popup-close-button"},{title:"Modify overlay styles",filename:"popups",url:"popups.html#modify-overlay-styles"},{title:"rating",filename:"rating",url:"rating.html"},{title:"Ratings",filename:"rating",url:"rating.html#ratings"},{title:"Global rating variables",filename:"rating",url:"rating.html#global-rating-variables"},{title:"Rating with vote",filename:"rating",url:"rating.html#rating-with-vote"},{title:"Rating with vote icons number customization",filename:"rating",url:"rating.html#rating-with-vote-icons-number-customization"},{title:"Rating with vote icons colors customization",filename:"rating",url:"rating.html#rating-with-vote-icons-colors-customization"},{title:"Rating with vote icons symbol customization",filename:"rating",url:"rating.html#rating-with-vote-icons-symbol-customization"},{title:"Accessible rating with vote",filename:"rating",url:"rating.html#accessible-rating-with-vote"},{title:"Rating summary",filename:"rating",url:"rating.html#rating-summary"},{title:"Rating summary icons number customization",filename:"rating",url:"rating.html#rating-summary-icons-number-customization"},{title:"Rating summary icons color customization",filename:"rating",url:"rating.html#rating-summary-icons-color-customization"},{title:"Rating summary icons symbol customization",filename:"rating",url:"rating.html#rating-summary-icons-symbol-customization"},{title:"Rating summary hide label",filename:"rating",url:"rating.html#rating-summary-hide-label"},{title:"Rating summary multiple ratings",filename:"rating",url:"rating.html#rating-summary-multiple-ratings"},{title:"Rating hide label mixin",filename:"rating",url:"rating.html#rating-hide-label-mixin"},{title:"resets",filename:"resets",url:"resets.html"},{title:"Resets",filename:"resets",url:"resets.html#resets"},{title:"responsive",filename:"responsive",url:"responsive.html"},{title:"Responsive",filename:"responsive",url:"responsive.html#responsive"},{title:"Responsive mixins usage",filename:"responsive",url:"responsive.html#responsive-mixins-usage"},{title:"Media query style groups separation variables",filename:"responsive",url:"responsive.html#media-query-style-groups-separation-variables"},{title:"Responsive breakpoints",filename:"responsive",url:"responsive.html#responsive-breakpoints"},{title:"sections",filename:"sections",url:"sections.html"},{title:"Tabs and accordions",filename:"sections",url:"sections.html#tabs-and-accordions"},{title:"Tabs",filename:"sections",url:"sections.html#tabs"},{title:"Tabs mixin variables",filename:"sections",url:"sections.html#tabs-mixin-variables"},{title:"Tabs with content top border",filename:"sections",url:"sections.html#tabs-with-content-top-border"},{title:"Accordion",filename:"sections",url:"sections.html#accordion"},{title:"Accordion mixin variables",filename:"sections",url:"sections.html#accordion-mixin-variables"},{title:"Responsive tabs",filename:"sections",url:"sections.html#responsive-tabs"},{title:"Tabs Base",filename:"sections",url:"sections.html#tabs-base"},{title:"Accordion Base",filename:"sections",url:"sections.html#accordion-base"},{title:"tables",filename:"tables",url:"tables.html"},{title:"Tables",filename:"tables",url:"tables.html#tables"},{title:"Table mixin variables",filename:"tables",url:"tables.html#table-mixin-variables"},{title:"Table typography",filename:"tables",url:"tables.html#table-typography"},{title:"Table typography mixin variables",filename:"tables",url:"tables.html#table-typography-mixin-variables"},{title:"Table caption",filename:"tables",url:"tables.html#table-caption"},{title:"Table caption mixin variables",filename:"tables",url:"tables.html#table-caption-mixin-variables"},{title:"Table cells resize",filename:"tables",url:"tables.html#table-cells-resize"},{title:"Table cells resize variables",filename:"tables",url:"tables.html#table-cells-resize-variables"},{title:"Table background customization",filename:"tables",url:"tables.html#table-background-customization"},{title:"Table background mixin variables",filename:"tables",url:"tables.html#table-background-mixin-variables"},{title:"Table borders customization",filename:"tables",url:"tables.html#table-borders-customization"},{title:"Table borders mixin variables",filename:"tables",url:"tables.html#table-borders-mixin-variables"},{title:"Table with horizontal borders",filename:"tables",url:"tables.html#table-with-horizontal-borders"},{title:"Table with vertical borders",filename:"tables",url:"tables.html#table-with-vertical-borders"},{title:"Table with light borders",filename:"tables",url:"tables.html#table-with-light-borders"},{title:"Table without borders",filename:"tables",url:"tables.html#table-without-borders"},{title:"Striped table",filename:"tables",url:"tables.html#striped-table"},{title:"Striped table mixin variables",filename:"tables",url:"tables.html#striped-table-mixin-variables"},{title:"Table with rows hover",filename:"tables",url:"tables.html#table-with-rows-hover"},{title:"Table with rows hover mixin variables",filename:"tables",url:"tables.html#table-with-rows-hover-mixin-variables"},{title:"Responsive table technics #1",filename:"tables",url:"tables.html#responsive-table-technics-1"},{title:"Responsive table technics #2",filename:"tables",url:"tables.html#responsive-table-technics-2"},{title:"Responsive table technics #2 mixin variables",filename:"tables",url:"tables.html#responsive-table-technics-2-mixin-variables"},{title:"tooltips",filename:"tooltips",url:"tooltips.html"},{title:"Tooltips",filename:"tooltips",url:"tooltips.html#tooltips"},{title:"Tooltips variables",filename:"tooltips",url:"tooltips.html#tooltips-variables"},{title:"typography",filename:"typography",url:"typography.html"},{title:"Typogrphy",filename:"typography",url:"typography.html#typogrphy"},{title:"Typography variables",filename:"typography",url:"typography.html#typography-variables"},{title:"Font-size mixin",filename:"typography",url:"typography.html#fontsize-mixin"},{title:"Line-height mixin",filename:"typography",url:"typography.html#lineheight-mixin"},{title:"Word breaking mixin",filename:"typography",url:"typography.html#word-breaking-mixin"},{title:"Font face mixin",filename:"typography",url:"typography.html#font-face-mixin"},{title:"Text overflow mixin",filename:"typography",url:"typography.html#text-overflow-mixin"},{title:"Text hide",filename:"typography",url:"typography.html#text-hide"},{title:"Hyphens",filename:"typography",url:"typography.html#hyphens"},{title:"Font style and color",filename:"typography",url:"typography.html#font-style-and-color"},{title:"Font style mixin variables",filename:"typography",url:"typography.html#font-style-mixin-variables"},{title:"Reset list styles",filename:"typography",url:"typography.html#reset-list-styles"},{title:"Reset list styles variables",filename:"typography",url:"typography.html#reset-list-styles-variables"},{title:"Inline-block list item styling",filename:"typography",url:"typography.html#inlineblock-list-item-styling"},{title:"Link styling mixin",filename:"typography",url:"typography.html#link-styling-mixin"},{title:"Link styling mixin variables",filename:"typography",url:"typography.html#link-styling-mixin-variables"},{title:"Heading styling mixin",filename:"typography",url:"typography.html#heading-styling-mixin"},{title:"Base typography mixins",filename:"typography",url:"typography.html#base-typography-mixins"},{title:"Base typography mixin variables",filename:"typography",url:"typography.html#base-typography-mixin-variables"},{title:"Headings typography mixin",filename:"typography",url:"typography.html#headings-typography-mixin"},{title:"Headings typography mixin variables",filename:"typography",url:"typography.html#headings-typography-mixin-variables"},{title:"Typography links mixin",filename:"typography",url:"typography.html#typography-links-mixin"},{title:"Typography lists mixin",filename:"typography",url:"typography.html#typography-lists-mixin"},{title:"Typography lists mixin variables",filename:"typography",url:"typography.html#typography-lists-mixin-variables"},{title:"Typography code elements mixin",filename:"typography",url:"typography.html#typography-code-elements-mixin"},{title:"Typography code mixin variables",filename:"typography",url:"typography.html#typography-code-mixin-variables"},{title:"Typography blockquote",filename:"typography",url:"typography.html#typography-blockquote"},{title:"Typography blockquote mixin variables",filename:"typography",url:"typography.html#typography-blockquote-mixin-variables"},{title:"utilities",filename:"utilities",url:"utilities.html"},{title:"Utilities",filename:"utilities",url:"utilities.html#utilities"},{title:".lib-clearfix()",filename:"utilities",url:"utilities.html#libclearfix"},{title:".lib-visibility-hidden()",filename:"utilities",url:"utilities.html#libvisibilityhidden"},{title:".lib-visually-hidden()",filename:"utilities",url:"utilities.html#libvisuallyhidden"},{title:".lib-visually-hidden-reset()",filename:"utilities",url:"utilities.html#libvisuallyhiddenreset"},{title:".lib-css()",filename:"utilities",url:"utilities.html#libcss"},{title:".lib-css() variables",filename:"utilities",url:"utilities.html#libcss-variables"},{title:".lib-rotate()",filename:"utilities",url:"utilities.html#librotate"},{title:".lib-rotate() variables",filename:"utilities",url:"utilities.html#librotate-variables"},{title:".lib-input-placeholder()",filename:"utilities",url:"utilities.html#libinputplaceholder"},{title:".lib-input-placeholder() variables",filename:"utilities",url:"utilities.html#libinputplaceholder-variables"},{title:".lib-background-gradient()",filename:"utilities",url:"utilities.html#libbackgroundgradient"},{title:".lib-background-gradient() variables",filename:"utilities",url:"utilities.html#libbackgroundgradient-variables"},{title:"variables",filename:"variables",url:"variables.html"},{title:"List of Global Variables",filename:"variables",url:"variables.html#list-of-global-variables"},{title:"Table with rows hover mixin variables",filename:"variables",url:"variables.html#table-with-rows-hover-mixin-variables"},{title:"docs",filename:"docs",url:"docs.html"},{title:"Documentation",filename:"docs",url:"docs.html#documentation"}];(function(){"use strict";var b=function(a,b){return Array.prototype.indexOf.call(a,b)!==-1},c=function(a,b){return Array.prototype.filter.call(a,b)},d=function(a,b){return Array.prototype.forEach.call(a,b)},e=document.getElementsByTagName("body")[0];e.addEventListener("click",function(a){var b=a.target;b.tagName.toLowerCase()==="svg"&&(b=b.parentNode);var c=!1;b.dataset.toggle!=null&&(a.preventDefault(),b.classList.contains("is-active")||(c=!0)),d(e.querySelectorAll("[data-toggle]"),function(a){a.classList.remove("is-active"),document.getElementById(a.dataset.toggle).hidden=!0}),c&&(b.classList.add("is-active"),document.getElementById(b.dataset.toggle).hidden=!1)}),function(){var f=e.getElementsByClassName("nav")[0];if(!f)return;var g=document.createElement("ul");g.className="nav-results",g.id="nav-search",g.hidden=!0,d(a,function(a){var b,c,d;b=document.createElement("li"),b._title=a.title.toLowerCase(),b.hidden=!0,b.appendChild(c=document.createElement("a")),c.href=a.url,c.innerHTML=a.title,c.appendChild(d=document.createElement("span")),d.innerHTML=a.filename,d.className="nav-results-filename",g.appendChild(b)}),f.appendChild(g);var h=g.children,i=function(a){d(h,function(a){a.hidden=!0});var b=this.value.toLowerCase(),e=[];b!==""&&(e=c(h,function(a){return a._title.indexOf(b)!==-1})),e.length>0?(d(e,function(a){a.hidden=!1}),g.hidden=!1):g.hidden=!0},j=f.querySelector('input[type="search"]');j.addEventListener("keyup",i),j.addEventListener("focus",i),e.addEventListener("click",function(a){if(a.target.classList&&a.target.classList.contains("search"))return;g.hidden=!0}),g.addEventListener("click",function(a){j.value=""});var k=document.createElement("ul");k.id="nav-toc",k.hidden=!0,k.className="nav-results toc-list",c(e.getElementsByTagName("*"),function(a){return b(["h1","h2","h3"],a.tagName.toLowerCase())}).map(function(a){var b=document.createElement("li"),c=document.createElement("a"),d=a.tagName.toLowerCase()[1];c.classList.add("level-"+d),b.appendChild(c),c.href="#"+a.id,c.innerHTML=a.innerHTML,k.appendChild(b)}),f.appendChild(k)}()})(),function(){"use strict";if(location.hash==="#__preview__"||location.protocol==="data:")return;var a=function(a,b){return Array.prototype.forEach.call(a,b)},b=function(a,b){var e=Array.prototype.slice.call(arguments,2);return d(a,function(a){return(c(b)?b||a:a[b]).apply(a,e)})},c=function(a){return Object.prototype.toString.call(a)==="[object Function]"},d=function(a,b){return Array.prototype.map.call(a,b)},e=function(a,b){return d(a,function(a){return a[b]})},f=function(a){var b={},c=a.split(";");for(var d=0;c.length>d;d++){var e=c[d].trim().split("=");b[e[0]]=e[1]}return b},g=function(a,c){return b(e(a,"classList"),"remove",c)},h=function(a,b){a.contentDocument.defaultView.postMessage(b,"*")},i=document.getElementsByTagName("head")[0],j=document.getElementsByTagName("body")[0],k=e(i.querySelectorAll('style[type="text/preview"]'),"innerHTML").join(""),l=e(i.querySelectorAll('script[type="text/preview"]'),"innerHTML").join(""),m=location.href.split("#")[0]+"#__preview__",n=document.createElement("iframe");n.src="data:text/html,",j.appendChild(n),n.addEventListener("load",function(){var b={sameOriginDataUri:!0};try{this.contentDocument,this.contentDocument||(b.sameOriginDataUri=!1)}catch(c){b.sameOriginDataUri=!1}this.parentNode.removeChild(this),a(j.getElementsByTagName("textarea"),function(a,c){o(a,b,c),q(),p(a)})});var o=function(a,b,c){var d,e,f;d=document.createElement("div"),d.appendChild(e=document.createElement("div")),d.className="preview",e.appendChild(f=document.createElement("iframe")),e.className="resizeable",f.setAttribute("scrolling","no"),f.name="iframe"+c++,f.addEventListener("load",function(){var c,d,e,f,g,i,j;j=this.contentDocument;if(!b.sameOriginDataUri&&this.src!==m)return;this.src===m&&(c=j.createElement("html"),c.appendChild(j.createElement("head")),c.appendChild(d=j.createElement("body")),d.innerHTML=a.textContent,j.replaceChild(c,j.documentElement)),g=j.createElement("head"),g.appendChild(f=j.createElement("style")),g.appendChild(e=j.createElement("script")),e.textContent=l,f.textContent=k,i=j.getElementsByTagName("head")[0],i.parentNode.replaceChild(g,i),h(this,"getHeight")});var g;b.sameOriginDataUri?g="data:text/html;charset=utf-8,"+encodeURIComponent("<!doctype html><html><head></head></body>"+a.textContent):g=m,f.setAttribute("src",g);var i=function(){f.contentDocument.body.innerHTML=this.value,h(f,"getHeight")};a.addEventListener("keypress",i),a.addEventListener("keyup",i),a.parentNode.insertBefore(d,a)},p=function(a){var b=document.createElement("div");b.className="preview-code",b.style.position="absolute",b.style.left="-9999px",j.appendChild(b);var c=parseInt(window.getComputedStyle(a).getPropertyValue("max-height"),10),d=function(a){b.textContent=this.value+"\n";var d=b.offsetHeight+2;d>=c?this.style.overflow="auto":this.style.overflow="hidden",this.style.height=b.offsetHeight+2+"px"};a.addEventListener("keypress",d),a.addEventListener("keyup",d),d.call(a)},q=function(){var b=j.getElementsByClassName("settings")[0],c=j.getElementsByClassName("resizeable"),d=30,e=function(b){document.cookie="preview-width="+b,a(c,function(a){b==="auto"&&(b=a.parentNode.offsetWidth),a.style.width=b+"px",h(a.getElementsByTagName("iframe")[0],"getHeight")})},i=f(document.cookie)["preview-width"];if(i){e(i),g(b.getElementsByClassName("is-active"),"is-active");var k=b.querySelector('button[data-width="'+i+'"]');k&&k.classList.add("is-active")}window.addEventListener("message",function(a){if(a.data==null||!a.source)return;var b=a.data,c=document.getElementsByName(a.source.name)[0];b.height!=null&&c&&(c.parentNode.style.height=b.height+d+"px")},!1),b&&c.length>0&&(b.hidden=!1,b.addEventListener("click",function(a){var c=a.target.tagName.toLowerCase(),d;if(c==="button")d=a.target;else{if(c!=="svg")return;d=a.target.parentNode}a.preventDefault(),g(b.getElementsByClassName("is-active"),"is-active"),d.classList.add("is-active");var f=d.dataset.width;e(f)}))}}()})()</script></body></html><!-- Generated with StyleDocco (http://jacobrask.github.com/styledocco). --> diff --git a/lib/web/css/docs/buttons.html b/lib/web/css/docs/buttons.html index 0890701226d3c..502d35da59a99 100644 --- a/lib/web/css/docs/buttons.html +++ b/lib/web/css/docs/buttons.html @@ -875,4 +875,4 @@ <h2 id="primary-button-big">Primary button big</h2> </tr> </table> </pre> -</div></article></section><div class="bar bottom"><div hidden class="settings container"><!-- Icons from http://iconmonstr.com--><button title="Desktop (1280)" data-width='1280'><svg viewBox="0 0 412 386" height="24" width="26" class="icon"><path d="m147.6,343.9c-4.5,15.9-26.2,37.6-42.1,42.1h201c-15.3,-4-38.1,-26.8-42.1,-42.1H147.6zM387,0.5H25c-13.8,0-25,11.2-25,25V294c0,13.8 11.2,25 25,25h362c13.8,0 25,-11.2 25,-25V25.5C412,11.7 400.8,0.5 387,0.5zM369.9,238.2H42.1L42.1,42.6 369.9,42.6V238.2z"></path></svg></button><button title="Laptop (1024)" data-width='1024'><svg viewBox="0 0 384 312" height="23" width="28" class="icon"><path d="m349.2,20.5c0,-11-9,-20-20,-20H53.6c-11,0-20,9-20,20v194H349.2v-194zm-27,167H60.6V27.5H322.2v160zm28,42H32.6L2.6,282.1c-3.5,6.2-3.5,13.8 0.1,19.9 3.6,6.2 10.2,9.9 17.3,9.9H363.1c7.1,0 13.7,-3.8 17.3,-10 3.6,-6.2 3.6,-13.8 0,-20l-30.2,-52.5zm-196.9,54 8,-23.5h60.5l8,23.5h-76.5z"></path></svg></button><button title="Tablet (768)" data-width='768'><svg viewBox="0 0 317 412" height="24" width="18" class="icon"><path d="M 316.5,380 V 32 c 0,-17.7 -14.3,-32 -32,-32 H 32 C 14.3,0 0,14.3 0,32 v 348 c 0,17.7 14.3,32 32,32 h 252.5 c 17.7,0 32,-14.3 32,-32 z M 40,367 V 45 H 276.5 V 367 H 40 z m 109.8,22.7 c 0,-4.7 3.8,-8.5 8.5,-8.5 4.7,0 8.5,3.8 8.5,8.5 0,4.7 -3.8,8.5 -8.5,8.5 -4.7,0 -8.5,-3.8 -8.5,-8.5 z"></path></svg></button><button title="Smart phone (320)" data-width='320'><svg viewBox="0 0 224 412" height="24" width="13" class="icon"><path d="M 190.7,0 H 33 C 14.8,0 0,14.8 0,33 v 346 c 0,18.2 14.8,33 33,33 h 157.7 c 18.2,0 33,-14.8 33,-33 V 33 c 0,-18.2 -14.8,-33 -33,-33 z M 94.3,30.2 h 37 c 2.2,0 4,1.8 4,4 0,2.2 -1.8,4 -4,4 h -37 c -2.2,0 -4,-1.8 -4,-4 0,-2.2 1.8,-4 4,-4 z m 18.5,362.8 c -8.8,0 -16,-7.2 -16,-16 0,-8.8 7.2,-16 16,-16 8.8,0 16,7.2 16,16 0,8.8 -7.2,16 -16,16 z M 198.6,343.8 H 25.1 V 68.2 h 173.5 v 275.5 z"></path></svg></button><button title="Feature phone (240)" data-width='240'><svg viewBox="0 0 201 412" height="24" width="12" class="icon"><path d="M 165.5,0.2 V 45 H 25 c -13.8,0 -25,11.2 -25,25 V 387 c 0,13.8 11.2,25 25,25 h 150.5 c 13.8,0 25,-11.2 25,-25 V 0.2 h -35 z M 65.2,366.5 H 34.2 v -24.5 h 31 v 24.5 z m 0,-44.3 H 34.2 v -24.5 h 31 v 24.5 z m 50.5,44.3 H 84.7 v -24.5 h 31 v 24.5 z m 0,-44.3 H 84.7 v -24.5 h 31 v 24.5 z m 50.5,44.3 h -31 v -24.5 h 31 v 24.5 z m 0,-44.3 h -31 v -24.5 h 31 v 24.5 z m 0,-59.3 h -132 V 95.4 h 132 V 262.9 z"></path></svg></button><button title="Auto (100%)" data-width="auto" class="auto is-active">Auto</button></div></div><script>(function(){var a=[{title:"actions-toolbar",filename:"actions-toolbar",url:"actions-toolbar.html"},{title:"Actions toolbar",filename:"actions-toolbar",url:"actions-toolbar.html#actions-toolbar"},{title:"Actions toolbar mixin variables",filename:"actions-toolbar",url:"actions-toolbar.html#actions-toolbar-mixin-variables"},{title:"Actions toolbar alignment",filename:"actions-toolbar",url:"actions-toolbar.html#actions-toolbar-alignment"},{title:"Reverse primary and secondary blocks",filename:"actions-toolbar",url:"actions-toolbar.html#reverse-primary-and-secondary-blocks"},{title:"Actions toolbar indents customizations",filename:"actions-toolbar",url:"actions-toolbar.html#actions-toolbar-indents-customizations"},{title:"Responsive actions toolbar",filename:"actions-toolbar",url:"actions-toolbar.html#responsive-actions-toolbar"},{title:"breadcrumbs",filename:"breadcrumbs",url:"breadcrumbs.html"},{title:"Breadcrumbs",filename:"breadcrumbs",url:"breadcrumbs.html#breadcrumbs"},{title:"Breadcrumbs variables",filename:"breadcrumbs",url:"breadcrumbs.html#breadcrumbs-variables"},{title:"Button-styled breadcrumbs with gradient background, border, and no separating symbol",filename:"breadcrumbs",url:"breadcrumbs.html#buttonstyled-breadcrumbs-with-gradient-background-border-and-no-separating-symbol"},{title:"Breadcrumbs with solid background",filename:"breadcrumbs",url:"breadcrumbs.html#breadcrumbs-with-solid-background"},{title:"buttons",filename:"buttons",url:"buttons.html"},{title:"Default button",filename:"buttons",url:"buttons.html#default-button"},{title:"Button variables",filename:"buttons",url:"buttons.html#button-variables"},{title:"Button as an icon",filename:"buttons",url:"buttons.html#button-as-an-icon"},{title:"Button with an icon on the left or right side of the text",filename:"buttons",url:"buttons.html#button-with-an-icon-on-the-left-or-right-side-of-the-text"},{title:"Button with fixed width",filename:"buttons",url:"buttons.html#button-with-fixed-width"},{title:"Primary button",filename:"buttons",url:"buttons.html#primary-button"},{title:"Primary button variables",filename:"buttons",url:"buttons.html#primary-button-variables"},{title:"Button with gradient background",filename:"buttons",url:"buttons.html#button-with-gradient-background"},{title:"Button as a link",filename:"buttons",url:"buttons.html#button-as-a-link"},{title:"Button as a link variables",filename:"buttons",url:"buttons.html#button-as-a-link-variables"},{title:"Link as a button",filename:"buttons",url:"buttons.html#link-as-a-button"},{title:"Button reset",filename:"buttons",url:"buttons.html#button-reset"},{title:"Button revert secondary color",filename:"buttons",url:"buttons.html#button-revert-secondary-color"},{title:"Button revert secondary color variables",filename:"buttons",url:"buttons.html#button-revert-secondary-color-variables"},{title:"Button revert secondary size",filename:"buttons",url:"buttons.html#button-revert-secondary-size"},{title:"Button revert secondary size variables",filename:"buttons",url:"buttons.html#button-revert-secondary-size-variables"},{title:"components",filename:"components",url:"components.html"},{title:"Components",filename:"components",url:"components.html#components"},{title:"Components Variables",filename:"components",url:"components.html#components-variables"},{title:"dropdowns",filename:"dropdowns",url:"dropdowns.html"},{title:"Drop-down and split buttons mixins",filename:"dropdowns",url:"dropdowns.html#dropdown-and-split-buttons-mixins"},{title:"Drop-down",filename:"dropdowns",url:"dropdowns.html#dropdown"},{title:"Drop-down variables",filename:"dropdowns",url:"dropdowns.html#dropdown-variables"},{title:"Drop-down with icon customization",filename:"dropdowns",url:"dropdowns.html#dropdown-with-icon-customization"},{title:"Modify dropdown list styles",filename:"dropdowns",url:"dropdowns.html#modify-dropdown-list-styles"},{title:"Split button",filename:"dropdowns",url:"dropdowns.html#split-button"},{title:"Split button variables",filename:"dropdowns",url:"dropdowns.html#split-button-variables"},{title:"Split button - button styling",filename:"dropdowns",url:"dropdowns.html#split-button-button-styling"},{title:"Split button icon customization",filename:"dropdowns",url:"dropdowns.html#split-button-icon-customization"},{title:"Split button drop-down list customization",filename:"dropdowns",url:"dropdowns.html#split-button-dropdown-list-customization"},{title:"forms",filename:"forms",url:"forms.html"},{title:"Forms mixins",filename:"forms",url:"forms.html#forms-mixins"},{title:"Global forms elements customization",filename:"forms",url:"forms.html#global-forms-elements-customization"},{title:"Fieldsets & fields customization",filename:"forms",url:"forms.html#fieldsets-fields-customization"},{title:"Fieldset and legend customization variables",filename:"forms",url:"forms.html#fieldset-and-legend-customization-variables"},{title:"Fields customization variables",filename:"forms",url:"forms.html#fields-customization-variables"},{title:"Required fields message customization variables",filename:"forms",url:"forms.html#required-fields-message-customization-variables"},{title:"Form element inputs customization",filename:"forms",url:"forms.html#form-element-inputs-customization"},{title:"Form element inputs customization variables",filename:"forms",url:"forms.html#form-element-inputs-customization-variables"},{title:"Form element choice",filename:"forms",url:"forms.html#form-element-choice"},{title:"Form element choice variables",filename:"forms",url:"forms.html#form-element-choice-variables"},{title:"Custom color",filename:"forms",url:"forms.html#custom-color"},{title:"Input number - input-text view",filename:"forms",url:"forms.html#input-number-inputtext-view"},{title:"Input search - input-text view",filename:"forms",url:"forms.html#input-search-inputtext-view"},{title:"Form validation",filename:"forms",url:"forms.html#form-validation"},{title:"Form validation variables",filename:"forms",url:"forms.html#form-validation-variables"},{title:"icons",filename:"icons",url:"icons.html"},{title:"Icons",filename:"icons",url:"icons.html#icons"},{title:"Icon with image or sprite",filename:"icons",url:"icons.html#icon-with-image-or-sprite"},{title:"Icon with image or sprite variables",filename:"icons",url:"icons.html#icon-with-image-or-sprite-variables"},{title:"Icon position for an icon with image or sprite",filename:"icons",url:"icons.html#icon-position-for-an-icon-with-image-or-sprite"},{title:"Position for icon with image or sprite mixin variables",filename:"icons",url:"icons.html#position-for-icon-with-image-or-sprite-mixin-variables"},{title:"Icon sprite position (with grid)",filename:"icons",url:"icons.html#icon-sprite-position-with-grid"},{title:"Icon sprite position variables",filename:"icons",url:"icons.html#icon-sprite-position-variables"},{title:"Image/sprite icon size",filename:"icons",url:"icons.html#imagesprite-icon-size"},{title:"Image/sprite icon size variables",filename:"icons",url:"icons.html#imagesprite-icon-size-variables"},{title:"Font icon",filename:"icons",url:"icons.html#font-icon"},{title:"Font icon variables",filename:"icons",url:"icons.html#font-icon-variables"},{title:"Change the size of font icon",filename:"icons",url:"icons.html#change-the-size-of-font-icon"},{title:"Change the size of font icon variables",filename:"icons",url:"icons.html#change-the-size-of-font-icon-variables"},{title:"Hide icon text",filename:"icons",url:"icons.html#hide-icon-text"},{title:"Sprite and font icons for Blank theme",filename:"icons",url:"icons.html#sprite-and-font-icons-for-blank-theme"},{title:"layout",filename:"layout",url:"layout.html"},{title:"Layout",filename:"layout",url:"layout.html#layout"},{title:"Layout global variables",filename:"layout",url:"layout.html#layout-global-variables"},{title:"Page layouts",filename:"layout",url:"layout.html#page-layouts"},{title:"Layout column",filename:"layout",url:"layout.html#layout-column"},{title:"Layout column variables",filename:"layout",url:"layout.html#layout-column-variables"},{title:"Layout width",filename:"layout",url:"layout.html#layout-width"},{title:"Layout width variables",filename:"layout",url:"layout.html#layout-width-variables"},{title:"lib",filename:"lib",url:"lib.html"},{title:"Including Magento UI library to your theme",filename:"lib",url:"lib.html#including-magento-ui-library-to-your-theme"},{title:"loaders",filename:"loaders",url:"loaders.html"},{title:"Loaders",filename:"loaders",url:"loaders.html#loaders"},{title:"Default loader variables",filename:"loaders",url:"loaders.html#default-loader-variables"},{title:"Loading",filename:"loaders",url:"loaders.html#loading"},{title:"Loading default variables",filename:"loaders",url:"loaders.html#loading-default-variables"},{title:"messages",filename:"messages",url:"messages.html"},{title:"Messages",filename:"messages",url:"messages.html#messages"},{title:"Information message",filename:"messages",url:"messages.html#information-message"},{title:"Warning message",filename:"messages",url:"messages.html#warning-message"},{title:"Error message",filename:"messages",url:"messages.html#error-message"},{title:"Success message",filename:"messages",url:"messages.html#success-message"},{title:"Notice message",filename:"messages",url:"messages.html#notice-message"},{title:"Message with inner icon",filename:"messages",url:"messages.html#message-with-inner-icon"},{title:"Message with lateral icon",filename:"messages",url:"messages.html#message-with-lateral-icon"},{title:"Custom message style",filename:"messages",url:"messages.html#custom-message-style"},{title:"Messages global variables",filename:"messages",url:"messages.html#messages-global-variables"},{title:"pages",filename:"pages",url:"pages.html"},{title:"Pagination HTML markup",filename:"pages",url:"pages.html#pagination-html-markup"},{title:"Pagination variables",filename:"pages",url:"pages.html#pagination-variables"},{title:"Pagination with label and gradient background on links",filename:"pages",url:"pages.html#pagination-with-label-and-gradient-background-on-links"},{title:'Pagination with "previous"..."next" text links and label',filename:"pages",url:"pages.html#pagination-with-previousnext-text-links-and-label"},{title:"Pagination without label, with solid background",filename:"pages",url:"pages.html#pagination-without-label-with-solid-background"},{title:"popups",filename:"popups",url:"popups.html"},{title:"Popups",filename:"popups",url:"popups.html#popups"},{title:"Popup variables",filename:"popups",url:"popups.html#popup-variables"},{title:"Window overlay mixin variables",filename:"popups",url:"popups.html#window-overlay-mixin-variables"},{title:"Fixed height popup",filename:"popups",url:"popups.html#fixed-height-popup"},{title:"Fixed content height popup",filename:"popups",url:"popups.html#fixed-content-height-popup"},{title:"Margins for header, content and footer block in popup",filename:"popups",url:"popups.html#margins-for-header-content-and-footer-block-in-popup"},{title:"Popup titles styled as theme headings",filename:"popups",url:"popups.html#popup-titles-styled-as-theme-headings"},{title:"Popup action toolbar",filename:"popups",url:"popups.html#popup-action-toolbar"},{title:"Popup Close button without an icon",filename:"popups",url:"popups.html#popup-close-button-without-an-icon"},{title:"Modify the icon of popup Close button",filename:"popups",url:"popups.html#modify-the-icon-of-popup-close-button"},{title:"Modify overlay styles",filename:"popups",url:"popups.html#modify-overlay-styles"},{title:"rating",filename:"rating",url:"rating.html"},{title:"Ratings",filename:"rating",url:"rating.html#ratings"},{title:"Global rating variables",filename:"rating",url:"rating.html#global-rating-variables"},{title:"Rating with vote",filename:"rating",url:"rating.html#rating-with-vote"},{title:"Rating with vote icons number customization",filename:"rating",url:"rating.html#rating-with-vote-icons-number-customization"},{title:"Rating with vote icons colors customization",filename:"rating",url:"rating.html#rating-with-vote-icons-colors-customization"},{title:"Rating with vote icons symbol customization",filename:"rating",url:"rating.html#rating-with-vote-icons-symbol-customization"},{title:"Accessible rating with vote",filename:"rating",url:"rating.html#accessible-rating-with-vote"},{title:"Rating summary",filename:"rating",url:"rating.html#rating-summary"},{title:"Rating summary icons number customization",filename:"rating",url:"rating.html#rating-summary-icons-number-customization"},{title:"Rating summary icons color customization",filename:"rating",url:"rating.html#rating-summary-icons-color-customization"},{title:"Rating summary icons symbol customization",filename:"rating",url:"rating.html#rating-summary-icons-symbol-customization"},{title:"Rating summary hide label",filename:"rating",url:"rating.html#rating-summary-hide-label"},{title:"Rating summary multiple ratings",filename:"rating",url:"rating.html#rating-summary-multiple-ratings"},{title:"Rating hide label mixin",filename:"rating",url:"rating.html#rating-hide-label-mixin"},{title:"resets",filename:"resets",url:"resets.html"},{title:"Resets",filename:"resets",url:"resets.html#resets"},{title:"responsive",filename:"responsive",url:"responsive.html"},{title:"Responsive",filename:"responsive",url:"responsive.html#responsive"},{title:"Responsive mixins usage",filename:"responsive",url:"responsive.html#responsive-mixins-usage"},{title:"Media query style groups separation variables",filename:"responsive",url:"responsive.html#media-query-style-groups-separation-variables"},{title:"Responsive breakpoints",filename:"responsive",url:"responsive.html#responsive-breakpoints"},{title:"sections",filename:"sections",url:"sections.html"},{title:"Tabs and accordions",filename:"sections",url:"sections.html#tabs-and-accordions"},{title:"Tabs",filename:"sections",url:"sections.html#tabs"},{title:"Tabs mixin variables",filename:"sections",url:"sections.html#tabs-mixin-variables"},{title:"Tabs with content top border",filename:"sections",url:"sections.html#tabs-with-content-top-border"},{title:"Accordion",filename:"sections",url:"sections.html#accordion"},{title:"Accordion mixin variables",filename:"sections",url:"sections.html#accordion-mixin-variables"},{title:"Responsive tabs",filename:"sections",url:"sections.html#responsive-tabs"},{title:"Tabs Base",filename:"sections",url:"sections.html#tabs-base"},{title:"Accordion Base",filename:"sections",url:"sections.html#accordion-base"},{title:"tables",filename:"tables",url:"tables.html"},{title:"Tables",filename:"tables",url:"tables.html#tables"},{title:"Table mixin variables",filename:"tables",url:"tables.html#table-mixin-variables"},{title:"Table typography",filename:"tables",url:"tables.html#table-typography"},{title:"Table typography mixin variables",filename:"tables",url:"tables.html#table-typography-mixin-variables"},{title:"Table caption",filename:"tables",url:"tables.html#table-caption"},{title:"Table caption mixin variables",filename:"tables",url:"tables.html#table-caption-mixin-variables"},{title:"Table cells resize",filename:"tables",url:"tables.html#table-cells-resize"},{title:"Table cells resize variables",filename:"tables",url:"tables.html#table-cells-resize-variables"},{title:"Table background customization",filename:"tables",url:"tables.html#table-background-customization"},{title:"Table background mixin variables",filename:"tables",url:"tables.html#table-background-mixin-variables"},{title:"Table borders customization",filename:"tables",url:"tables.html#table-borders-customization"},{title:"Table borders mixin variables",filename:"tables",url:"tables.html#table-borders-mixin-variables"},{title:"Table with horizontal borders",filename:"tables",url:"tables.html#table-with-horizontal-borders"},{title:"Table with vertical borders",filename:"tables",url:"tables.html#table-with-vertical-borders"},{title:"Table with light borders",filename:"tables",url:"tables.html#table-with-light-borders"},{title:"Table without borders",filename:"tables",url:"tables.html#table-without-borders"},{title:"Striped table",filename:"tables",url:"tables.html#striped-table"},{title:"Striped table mixin variables",filename:"tables",url:"tables.html#striped-table-mixin-variables"},{title:"Table with rows hover",filename:"tables",url:"tables.html#table-with-rows-hover"},{title:"Table with rows hover mixin variables",filename:"tables",url:"tables.html#table-with-rows-hover-mixin-variables"},{title:"Responsive table technics #1",filename:"tables",url:"tables.html#responsive-table-technics-1"},{title:"Responsive table technics #2",filename:"tables",url:"tables.html#responsive-table-technics-2"},{title:"Responsive table technics #2 mixin variables",filename:"tables",url:"tables.html#responsive-table-technics-2-mixin-variables"},{title:"tooltips",filename:"tooltips",url:"tooltips.html"},{title:"Tooltips",filename:"tooltips",url:"tooltips.html#tooltips"},{title:"Tooltips variables",filename:"tooltips",url:"tooltips.html#tooltips-variables"},{title:"typography",filename:"typography",url:"typography.html"},{title:"Typogrphy",filename:"typography",url:"typography.html#typogrphy"},{title:"Typography variables",filename:"typography",url:"typography.html#typography-variables"},{title:"Font-size mixin",filename:"typography",url:"typography.html#fontsize-mixin"},{title:"Line-height mixin",filename:"typography",url:"typography.html#lineheight-mixin"},{title:"Word breaking mixin",filename:"typography",url:"typography.html#word-breaking-mixin"},{title:"Font face mixin",filename:"typography",url:"typography.html#font-face-mixin"},{title:"Text overflow mixin",filename:"typography",url:"typography.html#text-overflow-mixin"},{title:"Text hide",filename:"typography",url:"typography.html#text-hide"},{title:"Hyphens",filename:"typography",url:"typography.html#hyphens"},{title:"Font style and color",filename:"typography",url:"typography.html#font-style-and-color"},{title:"Font style mixin variables",filename:"typography",url:"typography.html#font-style-mixin-variables"},{title:"Reset list styles",filename:"typography",url:"typography.html#reset-list-styles"},{title:"Reset list styles variables",filename:"typography",url:"typography.html#reset-list-styles-variables"},{title:"Inline-block list item styling",filename:"typography",url:"typography.html#inlineblock-list-item-styling"},{title:"Link styling mixin",filename:"typography",url:"typography.html#link-styling-mixin"},{title:"Link styling mixin variables",filename:"typography",url:"typography.html#link-styling-mixin-variables"},{title:"Heading styling mixin",filename:"typography",url:"typography.html#heading-styling-mixin"},{title:"Base typography mixins",filename:"typography",url:"typography.html#base-typography-mixins"},{title:"Base typography mixin variables",filename:"typography",url:"typography.html#base-typography-mixin-variables"},{title:"Headings typography mixin",filename:"typography",url:"typography.html#headings-typography-mixin"},{title:"Headings typography mixin variables",filename:"typography",url:"typography.html#headings-typography-mixin-variables"},{title:"Typography links mixin",filename:"typography",url:"typography.html#typography-links-mixin"},{title:"Typography lists mixin",filename:"typography",url:"typography.html#typography-lists-mixin"},{title:"Typography lists mixin variables",filename:"typography",url:"typography.html#typography-lists-mixin-variables"},{title:"Typography code elements mixin",filename:"typography",url:"typography.html#typography-code-elements-mixin"},{title:"Typography code mixin variables",filename:"typography",url:"typography.html#typography-code-mixin-variables"},{title:"Typography blockquote",filename:"typography",url:"typography.html#typography-blockquote"},{title:"Typography blockquote mixin variables",filename:"typography",url:"typography.html#typography-blockquote-mixin-variables"},{title:"utilities",filename:"utilities",url:"utilities.html"},{title:"Utilities",filename:"utilities",url:"utilities.html#utilities"},{title:".lib-clearfix()",filename:"utilities",url:"utilities.html#libclearfix"},{title:".lib-visibility-hidden()",filename:"utilities",url:"utilities.html#libvisibilityhidden"},{title:".lib-visually-hidden()",filename:"utilities",url:"utilities.html#libvisuallyhidden"},{title:".lib-visually-hidden-reset()",filename:"utilities",url:"utilities.html#libvisuallyhiddenreset"},{title:".lib-css()",filename:"utilities",url:"utilities.html#libcss"},{title:".lib-css() variables",filename:"utilities",url:"utilities.html#libcss-variables"},{title:".lib-rotate()",filename:"utilities",url:"utilities.html#librotate"},{title:".lib-rotate() variables",filename:"utilities",url:"utilities.html#librotate-variables"},{title:".lib-input-placeholder()",filename:"utilities",url:"utilities.html#libinputplaceholder"},{title:".lib-input-placeholder() variables",filename:"utilities",url:"utilities.html#libinputplaceholder-variables"},{title:".lib-background-gradient()",filename:"utilities",url:"utilities.html#libbackgroundgradient"},{title:".lib-background-gradient() variables",filename:"utilities",url:"utilities.html#libbackgroundgradient-variables"},{title:".lib-url-check()",filename:"utilities",url:"utilities.html#liburlcheck"},{title:".lib-url-check() variables",filename:"utilities",url:"utilities.html#liburlcheck-variables"},{title:"variables",filename:"variables",url:"variables.html"},{title:"List of Global Variables",filename:"variables",url:"variables.html#list-of-global-variables"},{title:"Table with rows hover mixin variables",filename:"variables",url:"variables.html#table-with-rows-hover-mixin-variables"},{title:"docs",filename:"docs",url:"docs.html"},{title:"Documentation",filename:"docs",url:"docs.html#documentation"}];(function(){"use strict";var b=function(a,b){return Array.prototype.indexOf.call(a,b)!==-1},c=function(a,b){return Array.prototype.filter.call(a,b)},d=function(a,b){return Array.prototype.forEach.call(a,b)},e=document.getElementsByTagName("body")[0];e.addEventListener("click",function(a){var b=a.target;b.tagName.toLowerCase()==="svg"&&(b=b.parentNode);var c=!1;b.dataset.toggle!=null&&(a.preventDefault(),b.classList.contains("is-active")||(c=!0)),d(e.querySelectorAll("[data-toggle]"),function(a){a.classList.remove("is-active"),document.getElementById(a.dataset.toggle).hidden=!0}),c&&(b.classList.add("is-active"),document.getElementById(b.dataset.toggle).hidden=!1)}),function(){var f=e.getElementsByClassName("nav")[0];if(!f)return;var g=document.createElement("ul");g.className="nav-results",g.id="nav-search",g.hidden=!0,d(a,function(a){var b,c,d;b=document.createElement("li"),b._title=a.title.toLowerCase(),b.hidden=!0,b.appendChild(c=document.createElement("a")),c.href=a.url,c.innerHTML=a.title,c.appendChild(d=document.createElement("span")),d.innerHTML=a.filename,d.className="nav-results-filename",g.appendChild(b)}),f.appendChild(g);var h=g.children,i=function(a){d(h,function(a){a.hidden=!0});var b=this.value.toLowerCase(),e=[];b!==""&&(e=c(h,function(a){return a._title.indexOf(b)!==-1})),e.length>0?(d(e,function(a){a.hidden=!1}),g.hidden=!1):g.hidden=!0},j=f.querySelector('input[type="search"]');j.addEventListener("keyup",i),j.addEventListener("focus",i),e.addEventListener("click",function(a){if(a.target.classList&&a.target.classList.contains("search"))return;g.hidden=!0}),g.addEventListener("click",function(a){j.value=""});var k=document.createElement("ul");k.id="nav-toc",k.hidden=!0,k.className="nav-results toc-list",c(e.getElementsByTagName("*"),function(a){return b(["h1","h2","h3"],a.tagName.toLowerCase())}).map(function(a){var b=document.createElement("li"),c=document.createElement("a"),d=a.tagName.toLowerCase()[1];c.classList.add("level-"+d),b.appendChild(c),c.href="#"+a.id,c.innerHTML=a.innerHTML,k.appendChild(b)}),f.appendChild(k)}()})(),function(){"use strict";if(location.hash==="#__preview__"||location.protocol==="data:")return;var a=function(a,b){return Array.prototype.forEach.call(a,b)},b=function(a,b){var e=Array.prototype.slice.call(arguments,2);return d(a,function(a){return(c(b)?b||a:a[b]).apply(a,e)})},c=function(a){return Object.prototype.toString.call(a)==="[object Function]"},d=function(a,b){return Array.prototype.map.call(a,b)},e=function(a,b){return d(a,function(a){return a[b]})},f=function(a){var b={},c=a.split(";");for(var d=0;c.length>d;d++){var e=c[d].trim().split("=");b[e[0]]=e[1]}return b},g=function(a,c){return b(e(a,"classList"),"remove",c)},h=function(a,b){a.contentDocument.defaultView.postMessage(b,"*")},i=document.getElementsByTagName("head")[0],j=document.getElementsByTagName("body")[0],k=e(i.querySelectorAll('style[type="text/preview"]'),"innerHTML").join(""),l=e(i.querySelectorAll('script[type="text/preview"]'),"innerHTML").join(""),m=location.href.split("#")[0]+"#__preview__",n=document.createElement("iframe");n.src="data:text/html,",j.appendChild(n),n.addEventListener("load",function(){var b={sameOriginDataUri:!0};try{this.contentDocument,this.contentDocument||(b.sameOriginDataUri=!1)}catch(c){b.sameOriginDataUri=!1}this.parentNode.removeChild(this),a(j.getElementsByTagName("textarea"),function(a,c){o(a,b,c),q(),p(a)})});var o=function(a,b,c){var d,e,f;d=document.createElement("div"),d.appendChild(e=document.createElement("div")),d.className="preview",e.appendChild(f=document.createElement("iframe")),e.className="resizeable",f.setAttribute("scrolling","no"),f.name="iframe"+c++,f.addEventListener("load",function(){var c,d,e,f,g,i,j;j=this.contentDocument;if(!b.sameOriginDataUri&&this.src!==m)return;this.src===m&&(c=j.createElement("html"),c.appendChild(j.createElement("head")),c.appendChild(d=j.createElement("body")),d.innerHTML=a.textContent,j.replaceChild(c,j.documentElement)),g=j.createElement("head"),g.appendChild(f=j.createElement("style")),g.appendChild(e=j.createElement("script")),e.textContent=l,f.textContent=k,i=j.getElementsByTagName("head")[0],i.parentNode.replaceChild(g,i),h(this,"getHeight")});var g;b.sameOriginDataUri?g="data:text/html;charset=utf-8,"+encodeURIComponent("<!doctype html><html><head></head></body>"+a.textContent):g=m,f.setAttribute("src",g);var i=function(){f.contentDocument.body.innerHTML=this.value,h(f,"getHeight")};a.addEventListener("keypress",i),a.addEventListener("keyup",i),a.parentNode.insertBefore(d,a)},p=function(a){var b=document.createElement("div");b.className="preview-code",b.style.position="absolute",b.style.left="-9999px",j.appendChild(b);var c=parseInt(window.getComputedStyle(a).getPropertyValue("max-height"),10),d=function(a){b.textContent=this.value+"\n";var d=b.offsetHeight+2;d>=c?this.style.overflow="auto":this.style.overflow="hidden",this.style.height=b.offsetHeight+2+"px"};a.addEventListener("keypress",d),a.addEventListener("keyup",d),d.call(a)},q=function(){var b=j.getElementsByClassName("settings")[0],c=j.getElementsByClassName("resizeable"),d=30,e=function(b){document.cookie="preview-width="+b,a(c,function(a){b==="auto"&&(b=a.parentNode.offsetWidth),a.style.width=b+"px",h(a.getElementsByTagName("iframe")[0],"getHeight")})},i=f(document.cookie)["preview-width"];if(i){e(i),g(b.getElementsByClassName("is-active"),"is-active");var k=b.querySelector('button[data-width="'+i+'"]');k&&k.classList.add("is-active")}window.addEventListener("message",function(a){if(a.data==null||!a.source)return;var b=a.data,c=document.getElementsByName(a.source.name)[0];b.height!=null&&c&&(c.parentNode.style.height=b.height+d+"px")},!1),b&&c.length>0&&(b.hidden=!1,b.addEventListener("click",function(a){var c=a.target.tagName.toLowerCase(),d;if(c==="button")d=a.target;else{if(c!=="svg")return;d=a.target.parentNode}a.preventDefault(),g(b.getElementsByClassName("is-active"),"is-active"),d.classList.add("is-active");var f=d.dataset.width;e(f)}))}}()})()</script></body></html><!-- Generated with StyleDocco (http://jacobrask.github.com/styledocco). --> +</div></article></section><div class="bar bottom"><div hidden class="settings container"><!-- Icons from http://iconmonstr.com--><button title="Desktop (1280)" data-width='1280'><svg viewBox="0 0 412 386" height="24" width="26" class="icon"><path d="m147.6,343.9c-4.5,15.9-26.2,37.6-42.1,42.1h201c-15.3,-4-38.1,-26.8-42.1,-42.1H147.6zM387,0.5H25c-13.8,0-25,11.2-25,25V294c0,13.8 11.2,25 25,25h362c13.8,0 25,-11.2 25,-25V25.5C412,11.7 400.8,0.5 387,0.5zM369.9,238.2H42.1L42.1,42.6 369.9,42.6V238.2z"></path></svg></button><button title="Laptop (1024)" data-width='1024'><svg viewBox="0 0 384 312" height="23" width="28" class="icon"><path d="m349.2,20.5c0,-11-9,-20-20,-20H53.6c-11,0-20,9-20,20v194H349.2v-194zm-27,167H60.6V27.5H322.2v160zm28,42H32.6L2.6,282.1c-3.5,6.2-3.5,13.8 0.1,19.9 3.6,6.2 10.2,9.9 17.3,9.9H363.1c7.1,0 13.7,-3.8 17.3,-10 3.6,-6.2 3.6,-13.8 0,-20l-30.2,-52.5zm-196.9,54 8,-23.5h60.5l8,23.5h-76.5z"></path></svg></button><button title="Tablet (768)" data-width='768'><svg viewBox="0 0 317 412" height="24" width="18" class="icon"><path d="M 316.5,380 V 32 c 0,-17.7 -14.3,-32 -32,-32 H 32 C 14.3,0 0,14.3 0,32 v 348 c 0,17.7 14.3,32 32,32 h 252.5 c 17.7,0 32,-14.3 32,-32 z M 40,367 V 45 H 276.5 V 367 H 40 z m 109.8,22.7 c 0,-4.7 3.8,-8.5 8.5,-8.5 4.7,0 8.5,3.8 8.5,8.5 0,4.7 -3.8,8.5 -8.5,8.5 -4.7,0 -8.5,-3.8 -8.5,-8.5 z"></path></svg></button><button title="Smart phone (320)" data-width='320'><svg viewBox="0 0 224 412" height="24" width="13" class="icon"><path d="M 190.7,0 H 33 C 14.8,0 0,14.8 0,33 v 346 c 0,18.2 14.8,33 33,33 h 157.7 c 18.2,0 33,-14.8 33,-33 V 33 c 0,-18.2 -14.8,-33 -33,-33 z M 94.3,30.2 h 37 c 2.2,0 4,1.8 4,4 0,2.2 -1.8,4 -4,4 h -37 c -2.2,0 -4,-1.8 -4,-4 0,-2.2 1.8,-4 4,-4 z m 18.5,362.8 c -8.8,0 -16,-7.2 -16,-16 0,-8.8 7.2,-16 16,-16 8.8,0 16,7.2 16,16 0,8.8 -7.2,16 -16,16 z M 198.6,343.8 H 25.1 V 68.2 h 173.5 v 275.5 z"></path></svg></button><button title="Feature phone (240)" data-width='240'><svg viewBox="0 0 201 412" height="24" width="12" class="icon"><path d="M 165.5,0.2 V 45 H 25 c -13.8,0 -25,11.2 -25,25 V 387 c 0,13.8 11.2,25 25,25 h 150.5 c 13.8,0 25,-11.2 25,-25 V 0.2 h -35 z M 65.2,366.5 H 34.2 v -24.5 h 31 v 24.5 z m 0,-44.3 H 34.2 v -24.5 h 31 v 24.5 z m 50.5,44.3 H 84.7 v -24.5 h 31 v 24.5 z m 0,-44.3 H 84.7 v -24.5 h 31 v 24.5 z m 50.5,44.3 h -31 v -24.5 h 31 v 24.5 z m 0,-44.3 h -31 v -24.5 h 31 v 24.5 z m 0,-59.3 h -132 V 95.4 h 132 V 262.9 z"></path></svg></button><button title="Auto (100%)" data-width="auto" class="auto is-active">Auto</button></div></div><script>(function(){var a=[{title:"actions-toolbar",filename:"actions-toolbar",url:"actions-toolbar.html"},{title:"Actions toolbar",filename:"actions-toolbar",url:"actions-toolbar.html#actions-toolbar"},{title:"Actions toolbar mixin variables",filename:"actions-toolbar",url:"actions-toolbar.html#actions-toolbar-mixin-variables"},{title:"Actions toolbar alignment",filename:"actions-toolbar",url:"actions-toolbar.html#actions-toolbar-alignment"},{title:"Reverse primary and secondary blocks",filename:"actions-toolbar",url:"actions-toolbar.html#reverse-primary-and-secondary-blocks"},{title:"Actions toolbar indents customizations",filename:"actions-toolbar",url:"actions-toolbar.html#actions-toolbar-indents-customizations"},{title:"Responsive actions toolbar",filename:"actions-toolbar",url:"actions-toolbar.html#responsive-actions-toolbar"},{title:"breadcrumbs",filename:"breadcrumbs",url:"breadcrumbs.html"},{title:"Breadcrumbs",filename:"breadcrumbs",url:"breadcrumbs.html#breadcrumbs"},{title:"Breadcrumbs variables",filename:"breadcrumbs",url:"breadcrumbs.html#breadcrumbs-variables"},{title:"Button-styled breadcrumbs with gradient background, border, and no separating symbol",filename:"breadcrumbs",url:"breadcrumbs.html#buttonstyled-breadcrumbs-with-gradient-background-border-and-no-separating-symbol"},{title:"Breadcrumbs with solid background",filename:"breadcrumbs",url:"breadcrumbs.html#breadcrumbs-with-solid-background"},{title:"buttons",filename:"buttons",url:"buttons.html"},{title:"Default button",filename:"buttons",url:"buttons.html#default-button"},{title:"Button variables",filename:"buttons",url:"buttons.html#button-variables"},{title:"Button as an icon",filename:"buttons",url:"buttons.html#button-as-an-icon"},{title:"Button with an icon on the left or right side of the text",filename:"buttons",url:"buttons.html#button-with-an-icon-on-the-left-or-right-side-of-the-text"},{title:"Button with fixed width",filename:"buttons",url:"buttons.html#button-with-fixed-width"},{title:"Primary button",filename:"buttons",url:"buttons.html#primary-button"},{title:"Primary button variables",filename:"buttons",url:"buttons.html#primary-button-variables"},{title:"Button with gradient background",filename:"buttons",url:"buttons.html#button-with-gradient-background"},{title:"Button as a link",filename:"buttons",url:"buttons.html#button-as-a-link"},{title:"Button as a link variables",filename:"buttons",url:"buttons.html#button-as-a-link-variables"},{title:"Link as a button",filename:"buttons",url:"buttons.html#link-as-a-button"},{title:"Button reset",filename:"buttons",url:"buttons.html#button-reset"},{title:"Button revert secondary color",filename:"buttons",url:"buttons.html#button-revert-secondary-color"},{title:"Button revert secondary color variables",filename:"buttons",url:"buttons.html#button-revert-secondary-color-variables"},{title:"Button revert secondary size",filename:"buttons",url:"buttons.html#button-revert-secondary-size"},{title:"Button revert secondary size variables",filename:"buttons",url:"buttons.html#button-revert-secondary-size-variables"},{title:"components",filename:"components",url:"components.html"},{title:"Components",filename:"components",url:"components.html#components"},{title:"Components Variables",filename:"components",url:"components.html#components-variables"},{title:"dropdowns",filename:"dropdowns",url:"dropdowns.html"},{title:"Drop-down and split buttons mixins",filename:"dropdowns",url:"dropdowns.html#dropdown-and-split-buttons-mixins"},{title:"Drop-down",filename:"dropdowns",url:"dropdowns.html#dropdown"},{title:"Drop-down variables",filename:"dropdowns",url:"dropdowns.html#dropdown-variables"},{title:"Drop-down with icon customization",filename:"dropdowns",url:"dropdowns.html#dropdown-with-icon-customization"},{title:"Modify dropdown list styles",filename:"dropdowns",url:"dropdowns.html#modify-dropdown-list-styles"},{title:"Split button",filename:"dropdowns",url:"dropdowns.html#split-button"},{title:"Split button variables",filename:"dropdowns",url:"dropdowns.html#split-button-variables"},{title:"Split button - button styling",filename:"dropdowns",url:"dropdowns.html#split-button-button-styling"},{title:"Split button icon customization",filename:"dropdowns",url:"dropdowns.html#split-button-icon-customization"},{title:"Split button drop-down list customization",filename:"dropdowns",url:"dropdowns.html#split-button-dropdown-list-customization"},{title:"forms",filename:"forms",url:"forms.html"},{title:"Forms mixins",filename:"forms",url:"forms.html#forms-mixins"},{title:"Global forms elements customization",filename:"forms",url:"forms.html#global-forms-elements-customization"},{title:"Fieldsets & fields customization",filename:"forms",url:"forms.html#fieldsets-fields-customization"},{title:"Fieldset and legend customization variables",filename:"forms",url:"forms.html#fieldset-and-legend-customization-variables"},{title:"Fields customization variables",filename:"forms",url:"forms.html#fields-customization-variables"},{title:"Required fields message customization variables",filename:"forms",url:"forms.html#required-fields-message-customization-variables"},{title:"Form element inputs customization",filename:"forms",url:"forms.html#form-element-inputs-customization"},{title:"Form element inputs customization variables",filename:"forms",url:"forms.html#form-element-inputs-customization-variables"},{title:"Form element choice",filename:"forms",url:"forms.html#form-element-choice"},{title:"Form element choice variables",filename:"forms",url:"forms.html#form-element-choice-variables"},{title:"Custom color",filename:"forms",url:"forms.html#custom-color"},{title:"Input number - input-text view",filename:"forms",url:"forms.html#input-number-inputtext-view"},{title:"Input search - input-text view",filename:"forms",url:"forms.html#input-search-inputtext-view"},{title:"Form validation",filename:"forms",url:"forms.html#form-validation"},{title:"Form validation variables",filename:"forms",url:"forms.html#form-validation-variables"},{title:"icons",filename:"icons",url:"icons.html"},{title:"Icons",filename:"icons",url:"icons.html#icons"},{title:"Icon with image or sprite",filename:"icons",url:"icons.html#icon-with-image-or-sprite"},{title:"Icon with image or sprite variables",filename:"icons",url:"icons.html#icon-with-image-or-sprite-variables"},{title:"Icon position for an icon with image or sprite",filename:"icons",url:"icons.html#icon-position-for-an-icon-with-image-or-sprite"},{title:"Position for icon with image or sprite mixin variables",filename:"icons",url:"icons.html#position-for-icon-with-image-or-sprite-mixin-variables"},{title:"Icon sprite position (with grid)",filename:"icons",url:"icons.html#icon-sprite-position-with-grid"},{title:"Icon sprite position variables",filename:"icons",url:"icons.html#icon-sprite-position-variables"},{title:"Image/sprite icon size",filename:"icons",url:"icons.html#imagesprite-icon-size"},{title:"Image/sprite icon size variables",filename:"icons",url:"icons.html#imagesprite-icon-size-variables"},{title:"Font icon",filename:"icons",url:"icons.html#font-icon"},{title:"Font icon variables",filename:"icons",url:"icons.html#font-icon-variables"},{title:"Change the size of font icon",filename:"icons",url:"icons.html#change-the-size-of-font-icon"},{title:"Change the size of font icon variables",filename:"icons",url:"icons.html#change-the-size-of-font-icon-variables"},{title:"Hide icon text",filename:"icons",url:"icons.html#hide-icon-text"},{title:"Sprite and font icons for Blank theme",filename:"icons",url:"icons.html#sprite-and-font-icons-for-blank-theme"},{title:"layout",filename:"layout",url:"layout.html"},{title:"Layout",filename:"layout",url:"layout.html#layout"},{title:"Layout global variables",filename:"layout",url:"layout.html#layout-global-variables"},{title:"Page layouts",filename:"layout",url:"layout.html#page-layouts"},{title:"Layout column",filename:"layout",url:"layout.html#layout-column"},{title:"Layout column variables",filename:"layout",url:"layout.html#layout-column-variables"},{title:"Layout width",filename:"layout",url:"layout.html#layout-width"},{title:"Layout width variables",filename:"layout",url:"layout.html#layout-width-variables"},{title:"lib",filename:"lib",url:"lib.html"},{title:"Including Magento UI library to your theme",filename:"lib",url:"lib.html#including-magento-ui-library-to-your-theme"},{title:"loaders",filename:"loaders",url:"loaders.html"},{title:"Loaders",filename:"loaders",url:"loaders.html#loaders"},{title:"Default loader variables",filename:"loaders",url:"loaders.html#default-loader-variables"},{title:"Loading",filename:"loaders",url:"loaders.html#loading"},{title:"Loading default variables",filename:"loaders",url:"loaders.html#loading-default-variables"},{title:"messages",filename:"messages",url:"messages.html"},{title:"Messages",filename:"messages",url:"messages.html#messages"},{title:"Information message",filename:"messages",url:"messages.html#information-message"},{title:"Warning message",filename:"messages",url:"messages.html#warning-message"},{title:"Error message",filename:"messages",url:"messages.html#error-message"},{title:"Success message",filename:"messages",url:"messages.html#success-message"},{title:"Notice message",filename:"messages",url:"messages.html#notice-message"},{title:"Message with inner icon",filename:"messages",url:"messages.html#message-with-inner-icon"},{title:"Message with lateral icon",filename:"messages",url:"messages.html#message-with-lateral-icon"},{title:"Custom message style",filename:"messages",url:"messages.html#custom-message-style"},{title:"Messages global variables",filename:"messages",url:"messages.html#messages-global-variables"},{title:"pages",filename:"pages",url:"pages.html"},{title:"Pagination HTML markup",filename:"pages",url:"pages.html#pagination-html-markup"},{title:"Pagination variables",filename:"pages",url:"pages.html#pagination-variables"},{title:"Pagination with label and gradient background on links",filename:"pages",url:"pages.html#pagination-with-label-and-gradient-background-on-links"},{title:'Pagination with "previous"..."next" text links and label',filename:"pages",url:"pages.html#pagination-with-previousnext-text-links-and-label"},{title:"Pagination without label, with solid background",filename:"pages",url:"pages.html#pagination-without-label-with-solid-background"},{title:"popups",filename:"popups",url:"popups.html"},{title:"Popups",filename:"popups",url:"popups.html#popups"},{title:"Popup variables",filename:"popups",url:"popups.html#popup-variables"},{title:"Window overlay mixin variables",filename:"popups",url:"popups.html#window-overlay-mixin-variables"},{title:"Fixed height popup",filename:"popups",url:"popups.html#fixed-height-popup"},{title:"Fixed content height popup",filename:"popups",url:"popups.html#fixed-content-height-popup"},{title:"Margins for header, content and footer block in popup",filename:"popups",url:"popups.html#margins-for-header-content-and-footer-block-in-popup"},{title:"Popup titles styled as theme headings",filename:"popups",url:"popups.html#popup-titles-styled-as-theme-headings"},{title:"Popup action toolbar",filename:"popups",url:"popups.html#popup-action-toolbar"},{title:"Popup Close button without an icon",filename:"popups",url:"popups.html#popup-close-button-without-an-icon"},{title:"Modify the icon of popup Close button",filename:"popups",url:"popups.html#modify-the-icon-of-popup-close-button"},{title:"Modify overlay styles",filename:"popups",url:"popups.html#modify-overlay-styles"},{title:"rating",filename:"rating",url:"rating.html"},{title:"Ratings",filename:"rating",url:"rating.html#ratings"},{title:"Global rating variables",filename:"rating",url:"rating.html#global-rating-variables"},{title:"Rating with vote",filename:"rating",url:"rating.html#rating-with-vote"},{title:"Rating with vote icons number customization",filename:"rating",url:"rating.html#rating-with-vote-icons-number-customization"},{title:"Rating with vote icons colors customization",filename:"rating",url:"rating.html#rating-with-vote-icons-colors-customization"},{title:"Rating with vote icons symbol customization",filename:"rating",url:"rating.html#rating-with-vote-icons-symbol-customization"},{title:"Accessible rating with vote",filename:"rating",url:"rating.html#accessible-rating-with-vote"},{title:"Rating summary",filename:"rating",url:"rating.html#rating-summary"},{title:"Rating summary icons number customization",filename:"rating",url:"rating.html#rating-summary-icons-number-customization"},{title:"Rating summary icons color customization",filename:"rating",url:"rating.html#rating-summary-icons-color-customization"},{title:"Rating summary icons symbol customization",filename:"rating",url:"rating.html#rating-summary-icons-symbol-customization"},{title:"Rating summary hide label",filename:"rating",url:"rating.html#rating-summary-hide-label"},{title:"Rating summary multiple ratings",filename:"rating",url:"rating.html#rating-summary-multiple-ratings"},{title:"Rating hide label mixin",filename:"rating",url:"rating.html#rating-hide-label-mixin"},{title:"resets",filename:"resets",url:"resets.html"},{title:"Resets",filename:"resets",url:"resets.html#resets"},{title:"responsive",filename:"responsive",url:"responsive.html"},{title:"Responsive",filename:"responsive",url:"responsive.html#responsive"},{title:"Responsive mixins usage",filename:"responsive",url:"responsive.html#responsive-mixins-usage"},{title:"Media query style groups separation variables",filename:"responsive",url:"responsive.html#media-query-style-groups-separation-variables"},{title:"Responsive breakpoints",filename:"responsive",url:"responsive.html#responsive-breakpoints"},{title:"sections",filename:"sections",url:"sections.html"},{title:"Tabs and accordions",filename:"sections",url:"sections.html#tabs-and-accordions"},{title:"Tabs",filename:"sections",url:"sections.html#tabs"},{title:"Tabs mixin variables",filename:"sections",url:"sections.html#tabs-mixin-variables"},{title:"Tabs with content top border",filename:"sections",url:"sections.html#tabs-with-content-top-border"},{title:"Accordion",filename:"sections",url:"sections.html#accordion"},{title:"Accordion mixin variables",filename:"sections",url:"sections.html#accordion-mixin-variables"},{title:"Responsive tabs",filename:"sections",url:"sections.html#responsive-tabs"},{title:"Tabs Base",filename:"sections",url:"sections.html#tabs-base"},{title:"Accordion Base",filename:"sections",url:"sections.html#accordion-base"},{title:"tables",filename:"tables",url:"tables.html"},{title:"Tables",filename:"tables",url:"tables.html#tables"},{title:"Table mixin variables",filename:"tables",url:"tables.html#table-mixin-variables"},{title:"Table typography",filename:"tables",url:"tables.html#table-typography"},{title:"Table typography mixin variables",filename:"tables",url:"tables.html#table-typography-mixin-variables"},{title:"Table caption",filename:"tables",url:"tables.html#table-caption"},{title:"Table caption mixin variables",filename:"tables",url:"tables.html#table-caption-mixin-variables"},{title:"Table cells resize",filename:"tables",url:"tables.html#table-cells-resize"},{title:"Table cells resize variables",filename:"tables",url:"tables.html#table-cells-resize-variables"},{title:"Table background customization",filename:"tables",url:"tables.html#table-background-customization"},{title:"Table background mixin variables",filename:"tables",url:"tables.html#table-background-mixin-variables"},{title:"Table borders customization",filename:"tables",url:"tables.html#table-borders-customization"},{title:"Table borders mixin variables",filename:"tables",url:"tables.html#table-borders-mixin-variables"},{title:"Table with horizontal borders",filename:"tables",url:"tables.html#table-with-horizontal-borders"},{title:"Table with vertical borders",filename:"tables",url:"tables.html#table-with-vertical-borders"},{title:"Table with light borders",filename:"tables",url:"tables.html#table-with-light-borders"},{title:"Table without borders",filename:"tables",url:"tables.html#table-without-borders"},{title:"Striped table",filename:"tables",url:"tables.html#striped-table"},{title:"Striped table mixin variables",filename:"tables",url:"tables.html#striped-table-mixin-variables"},{title:"Table with rows hover",filename:"tables",url:"tables.html#table-with-rows-hover"},{title:"Table with rows hover mixin variables",filename:"tables",url:"tables.html#table-with-rows-hover-mixin-variables"},{title:"Responsive table technics #1",filename:"tables",url:"tables.html#responsive-table-technics-1"},{title:"Responsive table technics #2",filename:"tables",url:"tables.html#responsive-table-technics-2"},{title:"Responsive table technics #2 mixin variables",filename:"tables",url:"tables.html#responsive-table-technics-2-mixin-variables"},{title:"tooltips",filename:"tooltips",url:"tooltips.html"},{title:"Tooltips",filename:"tooltips",url:"tooltips.html#tooltips"},{title:"Tooltips variables",filename:"tooltips",url:"tooltips.html#tooltips-variables"},{title:"typography",filename:"typography",url:"typography.html"},{title:"Typogrphy",filename:"typography",url:"typography.html#typogrphy"},{title:"Typography variables",filename:"typography",url:"typography.html#typography-variables"},{title:"Font-size mixin",filename:"typography",url:"typography.html#fontsize-mixin"},{title:"Line-height mixin",filename:"typography",url:"typography.html#lineheight-mixin"},{title:"Word breaking mixin",filename:"typography",url:"typography.html#word-breaking-mixin"},{title:"Font face mixin",filename:"typography",url:"typography.html#font-face-mixin"},{title:"Text overflow mixin",filename:"typography",url:"typography.html#text-overflow-mixin"},{title:"Text hide",filename:"typography",url:"typography.html#text-hide"},{title:"Hyphens",filename:"typography",url:"typography.html#hyphens"},{title:"Font style and color",filename:"typography",url:"typography.html#font-style-and-color"},{title:"Font style mixin variables",filename:"typography",url:"typography.html#font-style-mixin-variables"},{title:"Reset list styles",filename:"typography",url:"typography.html#reset-list-styles"},{title:"Reset list styles variables",filename:"typography",url:"typography.html#reset-list-styles-variables"},{title:"Inline-block list item styling",filename:"typography",url:"typography.html#inlineblock-list-item-styling"},{title:"Link styling mixin",filename:"typography",url:"typography.html#link-styling-mixin"},{title:"Link styling mixin variables",filename:"typography",url:"typography.html#link-styling-mixin-variables"},{title:"Heading styling mixin",filename:"typography",url:"typography.html#heading-styling-mixin"},{title:"Base typography mixins",filename:"typography",url:"typography.html#base-typography-mixins"},{title:"Base typography mixin variables",filename:"typography",url:"typography.html#base-typography-mixin-variables"},{title:"Headings typography mixin",filename:"typography",url:"typography.html#headings-typography-mixin"},{title:"Headings typography mixin variables",filename:"typography",url:"typography.html#headings-typography-mixin-variables"},{title:"Typography links mixin",filename:"typography",url:"typography.html#typography-links-mixin"},{title:"Typography lists mixin",filename:"typography",url:"typography.html#typography-lists-mixin"},{title:"Typography lists mixin variables",filename:"typography",url:"typography.html#typography-lists-mixin-variables"},{title:"Typography code elements mixin",filename:"typography",url:"typography.html#typography-code-elements-mixin"},{title:"Typography code mixin variables",filename:"typography",url:"typography.html#typography-code-mixin-variables"},{title:"Typography blockquote",filename:"typography",url:"typography.html#typography-blockquote"},{title:"Typography blockquote mixin variables",filename:"typography",url:"typography.html#typography-blockquote-mixin-variables"},{title:"utilities",filename:"utilities",url:"utilities.html"},{title:"Utilities",filename:"utilities",url:"utilities.html#utilities"},{title:".lib-clearfix()",filename:"utilities",url:"utilities.html#libclearfix"},{title:".lib-visibility-hidden()",filename:"utilities",url:"utilities.html#libvisibilityhidden"},{title:".lib-visually-hidden()",filename:"utilities",url:"utilities.html#libvisuallyhidden"},{title:".lib-visually-hidden-reset()",filename:"utilities",url:"utilities.html#libvisuallyhiddenreset"},{title:".lib-css()",filename:"utilities",url:"utilities.html#libcss"},{title:".lib-css() variables",filename:"utilities",url:"utilities.html#libcss-variables"},{title:".lib-rotate()",filename:"utilities",url:"utilities.html#librotate"},{title:".lib-rotate() variables",filename:"utilities",url:"utilities.html#librotate-variables"},{title:".lib-input-placeholder()",filename:"utilities",url:"utilities.html#libinputplaceholder"},{title:".lib-input-placeholder() variables",filename:"utilities",url:"utilities.html#libinputplaceholder-variables"},{title:".lib-background-gradient()",filename:"utilities",url:"utilities.html#libbackgroundgradient"},{title:".lib-background-gradient() variables",filename:"utilities",url:"utilities.html#libbackgroundgradient-variables"},{title:"variables",filename:"variables",url:"variables.html"},{title:"List of Global Variables",filename:"variables",url:"variables.html#list-of-global-variables"},{title:"Table with rows hover mixin variables",filename:"variables",url:"variables.html#table-with-rows-hover-mixin-variables"},{title:"docs",filename:"docs",url:"docs.html"},{title:"Documentation",filename:"docs",url:"docs.html#documentation"}];(function(){"use strict";var b=function(a,b){return Array.prototype.indexOf.call(a,b)!==-1},c=function(a,b){return Array.prototype.filter.call(a,b)},d=function(a,b){return Array.prototype.forEach.call(a,b)},e=document.getElementsByTagName("body")[0];e.addEventListener("click",function(a){var b=a.target;b.tagName.toLowerCase()==="svg"&&(b=b.parentNode);var c=!1;b.dataset.toggle!=null&&(a.preventDefault(),b.classList.contains("is-active")||(c=!0)),d(e.querySelectorAll("[data-toggle]"),function(a){a.classList.remove("is-active"),document.getElementById(a.dataset.toggle).hidden=!0}),c&&(b.classList.add("is-active"),document.getElementById(b.dataset.toggle).hidden=!1)}),function(){var f=e.getElementsByClassName("nav")[0];if(!f)return;var g=document.createElement("ul");g.className="nav-results",g.id="nav-search",g.hidden=!0,d(a,function(a){var b,c,d;b=document.createElement("li"),b._title=a.title.toLowerCase(),b.hidden=!0,b.appendChild(c=document.createElement("a")),c.href=a.url,c.innerHTML=a.title,c.appendChild(d=document.createElement("span")),d.innerHTML=a.filename,d.className="nav-results-filename",g.appendChild(b)}),f.appendChild(g);var h=g.children,i=function(a){d(h,function(a){a.hidden=!0});var b=this.value.toLowerCase(),e=[];b!==""&&(e=c(h,function(a){return a._title.indexOf(b)!==-1})),e.length>0?(d(e,function(a){a.hidden=!1}),g.hidden=!1):g.hidden=!0},j=f.querySelector('input[type="search"]');j.addEventListener("keyup",i),j.addEventListener("focus",i),e.addEventListener("click",function(a){if(a.target.classList&&a.target.classList.contains("search"))return;g.hidden=!0}),g.addEventListener("click",function(a){j.value=""});var k=document.createElement("ul");k.id="nav-toc",k.hidden=!0,k.className="nav-results toc-list",c(e.getElementsByTagName("*"),function(a){return b(["h1","h2","h3"],a.tagName.toLowerCase())}).map(function(a){var b=document.createElement("li"),c=document.createElement("a"),d=a.tagName.toLowerCase()[1];c.classList.add("level-"+d),b.appendChild(c),c.href="#"+a.id,c.innerHTML=a.innerHTML,k.appendChild(b)}),f.appendChild(k)}()})(),function(){"use strict";if(location.hash==="#__preview__"||location.protocol==="data:")return;var a=function(a,b){return Array.prototype.forEach.call(a,b)},b=function(a,b){var e=Array.prototype.slice.call(arguments,2);return d(a,function(a){return(c(b)?b||a:a[b]).apply(a,e)})},c=function(a){return Object.prototype.toString.call(a)==="[object Function]"},d=function(a,b){return Array.prototype.map.call(a,b)},e=function(a,b){return d(a,function(a){return a[b]})},f=function(a){var b={},c=a.split(";");for(var d=0;c.length>d;d++){var e=c[d].trim().split("=");b[e[0]]=e[1]}return b},g=function(a,c){return b(e(a,"classList"),"remove",c)},h=function(a,b){a.contentDocument.defaultView.postMessage(b,"*")},i=document.getElementsByTagName("head")[0],j=document.getElementsByTagName("body")[0],k=e(i.querySelectorAll('style[type="text/preview"]'),"innerHTML").join(""),l=e(i.querySelectorAll('script[type="text/preview"]'),"innerHTML").join(""),m=location.href.split("#")[0]+"#__preview__",n=document.createElement("iframe");n.src="data:text/html,",j.appendChild(n),n.addEventListener("load",function(){var b={sameOriginDataUri:!0};try{this.contentDocument,this.contentDocument||(b.sameOriginDataUri=!1)}catch(c){b.sameOriginDataUri=!1}this.parentNode.removeChild(this),a(j.getElementsByTagName("textarea"),function(a,c){o(a,b,c),q(),p(a)})});var o=function(a,b,c){var d,e,f;d=document.createElement("div"),d.appendChild(e=document.createElement("div")),d.className="preview",e.appendChild(f=document.createElement("iframe")),e.className="resizeable",f.setAttribute("scrolling","no"),f.name="iframe"+c++,f.addEventListener("load",function(){var c,d,e,f,g,i,j;j=this.contentDocument;if(!b.sameOriginDataUri&&this.src!==m)return;this.src===m&&(c=j.createElement("html"),c.appendChild(j.createElement("head")),c.appendChild(d=j.createElement("body")),d.innerHTML=a.textContent,j.replaceChild(c,j.documentElement)),g=j.createElement("head"),g.appendChild(f=j.createElement("style")),g.appendChild(e=j.createElement("script")),e.textContent=l,f.textContent=k,i=j.getElementsByTagName("head")[0],i.parentNode.replaceChild(g,i),h(this,"getHeight")});var g;b.sameOriginDataUri?g="data:text/html;charset=utf-8,"+encodeURIComponent("<!doctype html><html><head></head></body>"+a.textContent):g=m,f.setAttribute("src",g);var i=function(){f.contentDocument.body.innerHTML=this.value,h(f,"getHeight")};a.addEventListener("keypress",i),a.addEventListener("keyup",i),a.parentNode.insertBefore(d,a)},p=function(a){var b=document.createElement("div");b.className="preview-code",b.style.position="absolute",b.style.left="-9999px",j.appendChild(b);var c=parseInt(window.getComputedStyle(a).getPropertyValue("max-height"),10),d=function(a){b.textContent=this.value+"\n";var d=b.offsetHeight+2;d>=c?this.style.overflow="auto":this.style.overflow="hidden",this.style.height=b.offsetHeight+2+"px"};a.addEventListener("keypress",d),a.addEventListener("keyup",d),d.call(a)},q=function(){var b=j.getElementsByClassName("settings")[0],c=j.getElementsByClassName("resizeable"),d=30,e=function(b){document.cookie="preview-width="+b,a(c,function(a){b==="auto"&&(b=a.parentNode.offsetWidth),a.style.width=b+"px",h(a.getElementsByTagName("iframe")[0],"getHeight")})},i=f(document.cookie)["preview-width"];if(i){e(i),g(b.getElementsByClassName("is-active"),"is-active");var k=b.querySelector('button[data-width="'+i+'"]');k&&k.classList.add("is-active")}window.addEventListener("message",function(a){if(a.data==null||!a.source)return;var b=a.data,c=document.getElementsByName(a.source.name)[0];b.height!=null&&c&&(c.parentNode.style.height=b.height+d+"px")},!1),b&&c.length>0&&(b.hidden=!1,b.addEventListener("click",function(a){var c=a.target.tagName.toLowerCase(),d;if(c==="button")d=a.target;else{if(c!=="svg")return;d=a.target.parentNode}a.preventDefault(),g(b.getElementsByClassName("is-active"),"is-active"),d.classList.add("is-active");var f=d.dataset.width;e(f)}))}}()})()</script></body></html><!-- Generated with StyleDocco (http://jacobrask.github.com/styledocco). --> diff --git a/lib/web/css/docs/components.html b/lib/web/css/docs/components.html index 609bd4d3ffa00..9e0b149c989a9 100644 --- a/lib/web/css/docs/components.html +++ b/lib/web/css/docs/components.html @@ -147,4 +147,4 @@ <h1 class="modal-title" data-role="title">Modal Slide</h1> </tr> </table> </pre> -</div></article></section><div class="bar bottom"><div hidden class="settings container"><!-- Icons from http://iconmonstr.com--><button title="Desktop (1280)" data-width='1280'><svg viewBox="0 0 412 386" height="24" width="26" class="icon"><path d="m147.6,343.9c-4.5,15.9-26.2,37.6-42.1,42.1h201c-15.3,-4-38.1,-26.8-42.1,-42.1H147.6zM387,0.5H25c-13.8,0-25,11.2-25,25V294c0,13.8 11.2,25 25,25h362c13.8,0 25,-11.2 25,-25V25.5C412,11.7 400.8,0.5 387,0.5zM369.9,238.2H42.1L42.1,42.6 369.9,42.6V238.2z"></path></svg></button><button title="Laptop (1024)" data-width='1024'><svg viewBox="0 0 384 312" height="23" width="28" class="icon"><path d="m349.2,20.5c0,-11-9,-20-20,-20H53.6c-11,0-20,9-20,20v194H349.2v-194zm-27,167H60.6V27.5H322.2v160zm28,42H32.6L2.6,282.1c-3.5,6.2-3.5,13.8 0.1,19.9 3.6,6.2 10.2,9.9 17.3,9.9H363.1c7.1,0 13.7,-3.8 17.3,-10 3.6,-6.2 3.6,-13.8 0,-20l-30.2,-52.5zm-196.9,54 8,-23.5h60.5l8,23.5h-76.5z"></path></svg></button><button title="Tablet (768)" data-width='768'><svg viewBox="0 0 317 412" height="24" width="18" class="icon"><path d="M 316.5,380 V 32 c 0,-17.7 -14.3,-32 -32,-32 H 32 C 14.3,0 0,14.3 0,32 v 348 c 0,17.7 14.3,32 32,32 h 252.5 c 17.7,0 32,-14.3 32,-32 z M 40,367 V 45 H 276.5 V 367 H 40 z m 109.8,22.7 c 0,-4.7 3.8,-8.5 8.5,-8.5 4.7,0 8.5,3.8 8.5,8.5 0,4.7 -3.8,8.5 -8.5,8.5 -4.7,0 -8.5,-3.8 -8.5,-8.5 z"></path></svg></button><button title="Smart phone (320)" data-width='320'><svg viewBox="0 0 224 412" height="24" width="13" class="icon"><path d="M 190.7,0 H 33 C 14.8,0 0,14.8 0,33 v 346 c 0,18.2 14.8,33 33,33 h 157.7 c 18.2,0 33,-14.8 33,-33 V 33 c 0,-18.2 -14.8,-33 -33,-33 z M 94.3,30.2 h 37 c 2.2,0 4,1.8 4,4 0,2.2 -1.8,4 -4,4 h -37 c -2.2,0 -4,-1.8 -4,-4 0,-2.2 1.8,-4 4,-4 z m 18.5,362.8 c -8.8,0 -16,-7.2 -16,-16 0,-8.8 7.2,-16 16,-16 8.8,0 16,7.2 16,16 0,8.8 -7.2,16 -16,16 z M 198.6,343.8 H 25.1 V 68.2 h 173.5 v 275.5 z"></path></svg></button><button title="Feature phone (240)" data-width='240'><svg viewBox="0 0 201 412" height="24" width="12" class="icon"><path d="M 165.5,0.2 V 45 H 25 c -13.8,0 -25,11.2 -25,25 V 387 c 0,13.8 11.2,25 25,25 h 150.5 c 13.8,0 25,-11.2 25,-25 V 0.2 h -35 z M 65.2,366.5 H 34.2 v -24.5 h 31 v 24.5 z m 0,-44.3 H 34.2 v -24.5 h 31 v 24.5 z m 50.5,44.3 H 84.7 v -24.5 h 31 v 24.5 z m 0,-44.3 H 84.7 v -24.5 h 31 v 24.5 z m 50.5,44.3 h -31 v -24.5 h 31 v 24.5 z m 0,-44.3 h -31 v -24.5 h 31 v 24.5 z m 0,-59.3 h -132 V 95.4 h 132 V 262.9 z"></path></svg></button><button title="Auto (100%)" data-width="auto" class="auto is-active">Auto</button></div></div><script>(function(){var a=[{title:"actions-toolbar",filename:"actions-toolbar",url:"actions-toolbar.html"},{title:"Actions toolbar",filename:"actions-toolbar",url:"actions-toolbar.html#actions-toolbar"},{title:"Actions toolbar mixin variables",filename:"actions-toolbar",url:"actions-toolbar.html#actions-toolbar-mixin-variables"},{title:"Actions toolbar alignment",filename:"actions-toolbar",url:"actions-toolbar.html#actions-toolbar-alignment"},{title:"Reverse primary and secondary blocks",filename:"actions-toolbar",url:"actions-toolbar.html#reverse-primary-and-secondary-blocks"},{title:"Actions toolbar indents customizations",filename:"actions-toolbar",url:"actions-toolbar.html#actions-toolbar-indents-customizations"},{title:"Responsive actions toolbar",filename:"actions-toolbar",url:"actions-toolbar.html#responsive-actions-toolbar"},{title:"breadcrumbs",filename:"breadcrumbs",url:"breadcrumbs.html"},{title:"Breadcrumbs",filename:"breadcrumbs",url:"breadcrumbs.html#breadcrumbs"},{title:"Breadcrumbs variables",filename:"breadcrumbs",url:"breadcrumbs.html#breadcrumbs-variables"},{title:"Button-styled breadcrumbs with gradient background, border, and no separating symbol",filename:"breadcrumbs",url:"breadcrumbs.html#buttonstyled-breadcrumbs-with-gradient-background-border-and-no-separating-symbol"},{title:"Breadcrumbs with solid background",filename:"breadcrumbs",url:"breadcrumbs.html#breadcrumbs-with-solid-background"},{title:"buttons",filename:"buttons",url:"buttons.html"},{title:"Default button",filename:"buttons",url:"buttons.html#default-button"},{title:"Button variables",filename:"buttons",url:"buttons.html#button-variables"},{title:"Button as an icon",filename:"buttons",url:"buttons.html#button-as-an-icon"},{title:"Button with an icon on the left or right side of the text",filename:"buttons",url:"buttons.html#button-with-an-icon-on-the-left-or-right-side-of-the-text"},{title:"Button with fixed width",filename:"buttons",url:"buttons.html#button-with-fixed-width"},{title:"Primary button",filename:"buttons",url:"buttons.html#primary-button"},{title:"Primary button variables",filename:"buttons",url:"buttons.html#primary-button-variables"},{title:"Button with gradient background",filename:"buttons",url:"buttons.html#button-with-gradient-background"},{title:"Button as a link",filename:"buttons",url:"buttons.html#button-as-a-link"},{title:"Button as a link variables",filename:"buttons",url:"buttons.html#button-as-a-link-variables"},{title:"Link as a button",filename:"buttons",url:"buttons.html#link-as-a-button"},{title:"Button reset",filename:"buttons",url:"buttons.html#button-reset"},{title:"Button revert secondary color",filename:"buttons",url:"buttons.html#button-revert-secondary-color"},{title:"Button revert secondary color variables",filename:"buttons",url:"buttons.html#button-revert-secondary-color-variables"},{title:"Button revert secondary size",filename:"buttons",url:"buttons.html#button-revert-secondary-size"},{title:"Button revert secondary size variables",filename:"buttons",url:"buttons.html#button-revert-secondary-size-variables"},{title:"components",filename:"components",url:"components.html"},{title:"Components",filename:"components",url:"components.html#components"},{title:"Components Variables",filename:"components",url:"components.html#components-variables"},{title:"dropdowns",filename:"dropdowns",url:"dropdowns.html"},{title:"Drop-down and split buttons mixins",filename:"dropdowns",url:"dropdowns.html#dropdown-and-split-buttons-mixins"},{title:"Drop-down",filename:"dropdowns",url:"dropdowns.html#dropdown"},{title:"Drop-down variables",filename:"dropdowns",url:"dropdowns.html#dropdown-variables"},{title:"Drop-down with icon customization",filename:"dropdowns",url:"dropdowns.html#dropdown-with-icon-customization"},{title:"Modify dropdown list styles",filename:"dropdowns",url:"dropdowns.html#modify-dropdown-list-styles"},{title:"Split button",filename:"dropdowns",url:"dropdowns.html#split-button"},{title:"Split button variables",filename:"dropdowns",url:"dropdowns.html#split-button-variables"},{title:"Split button - button styling",filename:"dropdowns",url:"dropdowns.html#split-button-button-styling"},{title:"Split button icon customization",filename:"dropdowns",url:"dropdowns.html#split-button-icon-customization"},{title:"Split button drop-down list customization",filename:"dropdowns",url:"dropdowns.html#split-button-dropdown-list-customization"},{title:"forms",filename:"forms",url:"forms.html"},{title:"Forms mixins",filename:"forms",url:"forms.html#forms-mixins"},{title:"Global forms elements customization",filename:"forms",url:"forms.html#global-forms-elements-customization"},{title:"Fieldsets & fields customization",filename:"forms",url:"forms.html#fieldsets-fields-customization"},{title:"Fieldset and legend customization variables",filename:"forms",url:"forms.html#fieldset-and-legend-customization-variables"},{title:"Fields customization variables",filename:"forms",url:"forms.html#fields-customization-variables"},{title:"Required fields message customization variables",filename:"forms",url:"forms.html#required-fields-message-customization-variables"},{title:"Form element inputs customization",filename:"forms",url:"forms.html#form-element-inputs-customization"},{title:"Form element inputs customization variables",filename:"forms",url:"forms.html#form-element-inputs-customization-variables"},{title:"Form element choice",filename:"forms",url:"forms.html#form-element-choice"},{title:"Form element choice variables",filename:"forms",url:"forms.html#form-element-choice-variables"},{title:"Custom color",filename:"forms",url:"forms.html#custom-color"},{title:"Input number - input-text view",filename:"forms",url:"forms.html#input-number-inputtext-view"},{title:"Input search - input-text view",filename:"forms",url:"forms.html#input-search-inputtext-view"},{title:"Form validation",filename:"forms",url:"forms.html#form-validation"},{title:"Form validation variables",filename:"forms",url:"forms.html#form-validation-variables"},{title:"icons",filename:"icons",url:"icons.html"},{title:"Icons",filename:"icons",url:"icons.html#icons"},{title:"Icon with image or sprite",filename:"icons",url:"icons.html#icon-with-image-or-sprite"},{title:"Icon with image or sprite variables",filename:"icons",url:"icons.html#icon-with-image-or-sprite-variables"},{title:"Icon position for an icon with image or sprite",filename:"icons",url:"icons.html#icon-position-for-an-icon-with-image-or-sprite"},{title:"Position for icon with image or sprite mixin variables",filename:"icons",url:"icons.html#position-for-icon-with-image-or-sprite-mixin-variables"},{title:"Icon sprite position (with grid)",filename:"icons",url:"icons.html#icon-sprite-position-with-grid"},{title:"Icon sprite position variables",filename:"icons",url:"icons.html#icon-sprite-position-variables"},{title:"Image/sprite icon size",filename:"icons",url:"icons.html#imagesprite-icon-size"},{title:"Image/sprite icon size variables",filename:"icons",url:"icons.html#imagesprite-icon-size-variables"},{title:"Font icon",filename:"icons",url:"icons.html#font-icon"},{title:"Font icon variables",filename:"icons",url:"icons.html#font-icon-variables"},{title:"Change the size of font icon",filename:"icons",url:"icons.html#change-the-size-of-font-icon"},{title:"Change the size of font icon variables",filename:"icons",url:"icons.html#change-the-size-of-font-icon-variables"},{title:"Hide icon text",filename:"icons",url:"icons.html#hide-icon-text"},{title:"Sprite and font icons for Blank theme",filename:"icons",url:"icons.html#sprite-and-font-icons-for-blank-theme"},{title:"layout",filename:"layout",url:"layout.html"},{title:"Layout",filename:"layout",url:"layout.html#layout"},{title:"Layout global variables",filename:"layout",url:"layout.html#layout-global-variables"},{title:"Page layouts",filename:"layout",url:"layout.html#page-layouts"},{title:"Layout column",filename:"layout",url:"layout.html#layout-column"},{title:"Layout column variables",filename:"layout",url:"layout.html#layout-column-variables"},{title:"Layout width",filename:"layout",url:"layout.html#layout-width"},{title:"Layout width variables",filename:"layout",url:"layout.html#layout-width-variables"},{title:"lib",filename:"lib",url:"lib.html"},{title:"Including Magento UI library to your theme",filename:"lib",url:"lib.html#including-magento-ui-library-to-your-theme"},{title:"loaders",filename:"loaders",url:"loaders.html"},{title:"Loaders",filename:"loaders",url:"loaders.html#loaders"},{title:"Default loader variables",filename:"loaders",url:"loaders.html#default-loader-variables"},{title:"Loading",filename:"loaders",url:"loaders.html#loading"},{title:"Loading default variables",filename:"loaders",url:"loaders.html#loading-default-variables"},{title:"messages",filename:"messages",url:"messages.html"},{title:"Messages",filename:"messages",url:"messages.html#messages"},{title:"Information message",filename:"messages",url:"messages.html#information-message"},{title:"Warning message",filename:"messages",url:"messages.html#warning-message"},{title:"Error message",filename:"messages",url:"messages.html#error-message"},{title:"Success message",filename:"messages",url:"messages.html#success-message"},{title:"Notice message",filename:"messages",url:"messages.html#notice-message"},{title:"Message with inner icon",filename:"messages",url:"messages.html#message-with-inner-icon"},{title:"Message with lateral icon",filename:"messages",url:"messages.html#message-with-lateral-icon"},{title:"Custom message style",filename:"messages",url:"messages.html#custom-message-style"},{title:"Messages global variables",filename:"messages",url:"messages.html#messages-global-variables"},{title:"pages",filename:"pages",url:"pages.html"},{title:"Pagination HTML markup",filename:"pages",url:"pages.html#pagination-html-markup"},{title:"Pagination variables",filename:"pages",url:"pages.html#pagination-variables"},{title:"Pagination with label and gradient background on links",filename:"pages",url:"pages.html#pagination-with-label-and-gradient-background-on-links"},{title:'Pagination with "previous"..."next" text links and label',filename:"pages",url:"pages.html#pagination-with-previousnext-text-links-and-label"},{title:"Pagination without label, with solid background",filename:"pages",url:"pages.html#pagination-without-label-with-solid-background"},{title:"popups",filename:"popups",url:"popups.html"},{title:"Popups",filename:"popups",url:"popups.html#popups"},{title:"Popup variables",filename:"popups",url:"popups.html#popup-variables"},{title:"Window overlay mixin variables",filename:"popups",url:"popups.html#window-overlay-mixin-variables"},{title:"Fixed height popup",filename:"popups",url:"popups.html#fixed-height-popup"},{title:"Fixed content height popup",filename:"popups",url:"popups.html#fixed-content-height-popup"},{title:"Margins for header, content and footer block in popup",filename:"popups",url:"popups.html#margins-for-header-content-and-footer-block-in-popup"},{title:"Popup titles styled as theme headings",filename:"popups",url:"popups.html#popup-titles-styled-as-theme-headings"},{title:"Popup action toolbar",filename:"popups",url:"popups.html#popup-action-toolbar"},{title:"Popup Close button without an icon",filename:"popups",url:"popups.html#popup-close-button-without-an-icon"},{title:"Modify the icon of popup Close button",filename:"popups",url:"popups.html#modify-the-icon-of-popup-close-button"},{title:"Modify overlay styles",filename:"popups",url:"popups.html#modify-overlay-styles"},{title:"rating",filename:"rating",url:"rating.html"},{title:"Ratings",filename:"rating",url:"rating.html#ratings"},{title:"Global rating variables",filename:"rating",url:"rating.html#global-rating-variables"},{title:"Rating with vote",filename:"rating",url:"rating.html#rating-with-vote"},{title:"Rating with vote icons number customization",filename:"rating",url:"rating.html#rating-with-vote-icons-number-customization"},{title:"Rating with vote icons colors customization",filename:"rating",url:"rating.html#rating-with-vote-icons-colors-customization"},{title:"Rating with vote icons symbol customization",filename:"rating",url:"rating.html#rating-with-vote-icons-symbol-customization"},{title:"Accessible rating with vote",filename:"rating",url:"rating.html#accessible-rating-with-vote"},{title:"Rating summary",filename:"rating",url:"rating.html#rating-summary"},{title:"Rating summary icons number customization",filename:"rating",url:"rating.html#rating-summary-icons-number-customization"},{title:"Rating summary icons color customization",filename:"rating",url:"rating.html#rating-summary-icons-color-customization"},{title:"Rating summary icons symbol customization",filename:"rating",url:"rating.html#rating-summary-icons-symbol-customization"},{title:"Rating summary hide label",filename:"rating",url:"rating.html#rating-summary-hide-label"},{title:"Rating summary multiple ratings",filename:"rating",url:"rating.html#rating-summary-multiple-ratings"},{title:"Rating hide label mixin",filename:"rating",url:"rating.html#rating-hide-label-mixin"},{title:"resets",filename:"resets",url:"resets.html"},{title:"Resets",filename:"resets",url:"resets.html#resets"},{title:"responsive",filename:"responsive",url:"responsive.html"},{title:"Responsive",filename:"responsive",url:"responsive.html#responsive"},{title:"Responsive mixins usage",filename:"responsive",url:"responsive.html#responsive-mixins-usage"},{title:"Media query style groups separation variables",filename:"responsive",url:"responsive.html#media-query-style-groups-separation-variables"},{title:"Responsive breakpoints",filename:"responsive",url:"responsive.html#responsive-breakpoints"},{title:"sections",filename:"sections",url:"sections.html"},{title:"Tabs and accordions",filename:"sections",url:"sections.html#tabs-and-accordions"},{title:"Tabs",filename:"sections",url:"sections.html#tabs"},{title:"Tabs mixin variables",filename:"sections",url:"sections.html#tabs-mixin-variables"},{title:"Tabs with content top border",filename:"sections",url:"sections.html#tabs-with-content-top-border"},{title:"Accordion",filename:"sections",url:"sections.html#accordion"},{title:"Accordion mixin variables",filename:"sections",url:"sections.html#accordion-mixin-variables"},{title:"Responsive tabs",filename:"sections",url:"sections.html#responsive-tabs"},{title:"Tabs Base",filename:"sections",url:"sections.html#tabs-base"},{title:"Accordion Base",filename:"sections",url:"sections.html#accordion-base"},{title:"tables",filename:"tables",url:"tables.html"},{title:"Tables",filename:"tables",url:"tables.html#tables"},{title:"Table mixin variables",filename:"tables",url:"tables.html#table-mixin-variables"},{title:"Table typography",filename:"tables",url:"tables.html#table-typography"},{title:"Table typography mixin variables",filename:"tables",url:"tables.html#table-typography-mixin-variables"},{title:"Table caption",filename:"tables",url:"tables.html#table-caption"},{title:"Table caption mixin variables",filename:"tables",url:"tables.html#table-caption-mixin-variables"},{title:"Table cells resize",filename:"tables",url:"tables.html#table-cells-resize"},{title:"Table cells resize variables",filename:"tables",url:"tables.html#table-cells-resize-variables"},{title:"Table background customization",filename:"tables",url:"tables.html#table-background-customization"},{title:"Table background mixin variables",filename:"tables",url:"tables.html#table-background-mixin-variables"},{title:"Table borders customization",filename:"tables",url:"tables.html#table-borders-customization"},{title:"Table borders mixin variables",filename:"tables",url:"tables.html#table-borders-mixin-variables"},{title:"Table with horizontal borders",filename:"tables",url:"tables.html#table-with-horizontal-borders"},{title:"Table with vertical borders",filename:"tables",url:"tables.html#table-with-vertical-borders"},{title:"Table with light borders",filename:"tables",url:"tables.html#table-with-light-borders"},{title:"Table without borders",filename:"tables",url:"tables.html#table-without-borders"},{title:"Striped table",filename:"tables",url:"tables.html#striped-table"},{title:"Striped table mixin variables",filename:"tables",url:"tables.html#striped-table-mixin-variables"},{title:"Table with rows hover",filename:"tables",url:"tables.html#table-with-rows-hover"},{title:"Table with rows hover mixin variables",filename:"tables",url:"tables.html#table-with-rows-hover-mixin-variables"},{title:"Responsive table technics #1",filename:"tables",url:"tables.html#responsive-table-technics-1"},{title:"Responsive table technics #2",filename:"tables",url:"tables.html#responsive-table-technics-2"},{title:"Responsive table technics #2 mixin variables",filename:"tables",url:"tables.html#responsive-table-technics-2-mixin-variables"},{title:"tooltips",filename:"tooltips",url:"tooltips.html"},{title:"Tooltips",filename:"tooltips",url:"tooltips.html#tooltips"},{title:"Tooltips variables",filename:"tooltips",url:"tooltips.html#tooltips-variables"},{title:"typography",filename:"typography",url:"typography.html"},{title:"Typogrphy",filename:"typography",url:"typography.html#typogrphy"},{title:"Typography variables",filename:"typography",url:"typography.html#typography-variables"},{title:"Font-size mixin",filename:"typography",url:"typography.html#fontsize-mixin"},{title:"Line-height mixin",filename:"typography",url:"typography.html#lineheight-mixin"},{title:"Word breaking mixin",filename:"typography",url:"typography.html#word-breaking-mixin"},{title:"Font face mixin",filename:"typography",url:"typography.html#font-face-mixin"},{title:"Text overflow mixin",filename:"typography",url:"typography.html#text-overflow-mixin"},{title:"Text hide",filename:"typography",url:"typography.html#text-hide"},{title:"Hyphens",filename:"typography",url:"typography.html#hyphens"},{title:"Font style and color",filename:"typography",url:"typography.html#font-style-and-color"},{title:"Font style mixin variables",filename:"typography",url:"typography.html#font-style-mixin-variables"},{title:"Reset list styles",filename:"typography",url:"typography.html#reset-list-styles"},{title:"Reset list styles variables",filename:"typography",url:"typography.html#reset-list-styles-variables"},{title:"Inline-block list item styling",filename:"typography",url:"typography.html#inlineblock-list-item-styling"},{title:"Link styling mixin",filename:"typography",url:"typography.html#link-styling-mixin"},{title:"Link styling mixin variables",filename:"typography",url:"typography.html#link-styling-mixin-variables"},{title:"Heading styling mixin",filename:"typography",url:"typography.html#heading-styling-mixin"},{title:"Base typography mixins",filename:"typography",url:"typography.html#base-typography-mixins"},{title:"Base typography mixin variables",filename:"typography",url:"typography.html#base-typography-mixin-variables"},{title:"Headings typography mixin",filename:"typography",url:"typography.html#headings-typography-mixin"},{title:"Headings typography mixin variables",filename:"typography",url:"typography.html#headings-typography-mixin-variables"},{title:"Typography links mixin",filename:"typography",url:"typography.html#typography-links-mixin"},{title:"Typography lists mixin",filename:"typography",url:"typography.html#typography-lists-mixin"},{title:"Typography lists mixin variables",filename:"typography",url:"typography.html#typography-lists-mixin-variables"},{title:"Typography code elements mixin",filename:"typography",url:"typography.html#typography-code-elements-mixin"},{title:"Typography code mixin variables",filename:"typography",url:"typography.html#typography-code-mixin-variables"},{title:"Typography blockquote",filename:"typography",url:"typography.html#typography-blockquote"},{title:"Typography blockquote mixin variables",filename:"typography",url:"typography.html#typography-blockquote-mixin-variables"},{title:"utilities",filename:"utilities",url:"utilities.html"},{title:"Utilities",filename:"utilities",url:"utilities.html#utilities"},{title:".lib-clearfix()",filename:"utilities",url:"utilities.html#libclearfix"},{title:".lib-visibility-hidden()",filename:"utilities",url:"utilities.html#libvisibilityhidden"},{title:".lib-visually-hidden()",filename:"utilities",url:"utilities.html#libvisuallyhidden"},{title:".lib-visually-hidden-reset()",filename:"utilities",url:"utilities.html#libvisuallyhiddenreset"},{title:".lib-css()",filename:"utilities",url:"utilities.html#libcss"},{title:".lib-css() variables",filename:"utilities",url:"utilities.html#libcss-variables"},{title:".lib-rotate()",filename:"utilities",url:"utilities.html#librotate"},{title:".lib-rotate() variables",filename:"utilities",url:"utilities.html#librotate-variables"},{title:".lib-input-placeholder()",filename:"utilities",url:"utilities.html#libinputplaceholder"},{title:".lib-input-placeholder() variables",filename:"utilities",url:"utilities.html#libinputplaceholder-variables"},{title:".lib-background-gradient()",filename:"utilities",url:"utilities.html#libbackgroundgradient"},{title:".lib-background-gradient() variables",filename:"utilities",url:"utilities.html#libbackgroundgradient-variables"},{title:".lib-url-check()",filename:"utilities",url:"utilities.html#liburlcheck"},{title:".lib-url-check() variables",filename:"utilities",url:"utilities.html#liburlcheck-variables"},{title:"variables",filename:"variables",url:"variables.html"},{title:"List of Global Variables",filename:"variables",url:"variables.html#list-of-global-variables"},{title:"Table with rows hover mixin variables",filename:"variables",url:"variables.html#table-with-rows-hover-mixin-variables"},{title:"docs",filename:"docs",url:"docs.html"},{title:"Documentation",filename:"docs",url:"docs.html#documentation"}];(function(){"use strict";var b=function(a,b){return Array.prototype.indexOf.call(a,b)!==-1},c=function(a,b){return Array.prototype.filter.call(a,b)},d=function(a,b){return Array.prototype.forEach.call(a,b)},e=document.getElementsByTagName("body")[0];e.addEventListener("click",function(a){var b=a.target;b.tagName.toLowerCase()==="svg"&&(b=b.parentNode);var c=!1;b.dataset.toggle!=null&&(a.preventDefault(),b.classList.contains("is-active")||(c=!0)),d(e.querySelectorAll("[data-toggle]"),function(a){a.classList.remove("is-active"),document.getElementById(a.dataset.toggle).hidden=!0}),c&&(b.classList.add("is-active"),document.getElementById(b.dataset.toggle).hidden=!1)}),function(){var f=e.getElementsByClassName("nav")[0];if(!f)return;var g=document.createElement("ul");g.className="nav-results",g.id="nav-search",g.hidden=!0,d(a,function(a){var b,c,d;b=document.createElement("li"),b._title=a.title.toLowerCase(),b.hidden=!0,b.appendChild(c=document.createElement("a")),c.href=a.url,c.innerHTML=a.title,c.appendChild(d=document.createElement("span")),d.innerHTML=a.filename,d.className="nav-results-filename",g.appendChild(b)}),f.appendChild(g);var h=g.children,i=function(a){d(h,function(a){a.hidden=!0});var b=this.value.toLowerCase(),e=[];b!==""&&(e=c(h,function(a){return a._title.indexOf(b)!==-1})),e.length>0?(d(e,function(a){a.hidden=!1}),g.hidden=!1):g.hidden=!0},j=f.querySelector('input[type="search"]');j.addEventListener("keyup",i),j.addEventListener("focus",i),e.addEventListener("click",function(a){if(a.target.classList&&a.target.classList.contains("search"))return;g.hidden=!0}),g.addEventListener("click",function(a){j.value=""});var k=document.createElement("ul");k.id="nav-toc",k.hidden=!0,k.className="nav-results toc-list",c(e.getElementsByTagName("*"),function(a){return b(["h1","h2","h3"],a.tagName.toLowerCase())}).map(function(a){var b=document.createElement("li"),c=document.createElement("a"),d=a.tagName.toLowerCase()[1];c.classList.add("level-"+d),b.appendChild(c),c.href="#"+a.id,c.innerHTML=a.innerHTML,k.appendChild(b)}),f.appendChild(k)}()})(),function(){"use strict";if(location.hash==="#__preview__"||location.protocol==="data:")return;var a=function(a,b){return Array.prototype.forEach.call(a,b)},b=function(a,b){var e=Array.prototype.slice.call(arguments,2);return d(a,function(a){return(c(b)?b||a:a[b]).apply(a,e)})},c=function(a){return Object.prototype.toString.call(a)==="[object Function]"},d=function(a,b){return Array.prototype.map.call(a,b)},e=function(a,b){return d(a,function(a){return a[b]})},f=function(a){var b={},c=a.split(";");for(var d=0;c.length>d;d++){var e=c[d].trim().split("=");b[e[0]]=e[1]}return b},g=function(a,c){return b(e(a,"classList"),"remove",c)},h=function(a,b){a.contentDocument.defaultView.postMessage(b,"*")},i=document.getElementsByTagName("head")[0],j=document.getElementsByTagName("body")[0],k=e(i.querySelectorAll('style[type="text/preview"]'),"innerHTML").join(""),l=e(i.querySelectorAll('script[type="text/preview"]'),"innerHTML").join(""),m=location.href.split("#")[0]+"#__preview__",n=document.createElement("iframe");n.src="data:text/html,",j.appendChild(n),n.addEventListener("load",function(){var b={sameOriginDataUri:!0};try{this.contentDocument,this.contentDocument||(b.sameOriginDataUri=!1)}catch(c){b.sameOriginDataUri=!1}this.parentNode.removeChild(this),a(j.getElementsByTagName("textarea"),function(a,c){o(a,b,c),q(),p(a)})});var o=function(a,b,c){var d,e,f;d=document.createElement("div"),d.appendChild(e=document.createElement("div")),d.className="preview",e.appendChild(f=document.createElement("iframe")),e.className="resizeable",f.setAttribute("scrolling","no"),f.name="iframe"+c++,f.addEventListener("load",function(){var c,d,e,f,g,i,j;j=this.contentDocument;if(!b.sameOriginDataUri&&this.src!==m)return;this.src===m&&(c=j.createElement("html"),c.appendChild(j.createElement("head")),c.appendChild(d=j.createElement("body")),d.innerHTML=a.textContent,j.replaceChild(c,j.documentElement)),g=j.createElement("head"),g.appendChild(f=j.createElement("style")),g.appendChild(e=j.createElement("script")),e.textContent=l,f.textContent=k,i=j.getElementsByTagName("head")[0],i.parentNode.replaceChild(g,i),h(this,"getHeight")});var g;b.sameOriginDataUri?g="data:text/html;charset=utf-8,"+encodeURIComponent("<!doctype html><html><head></head></body>"+a.textContent):g=m,f.setAttribute("src",g);var i=function(){f.contentDocument.body.innerHTML=this.value,h(f,"getHeight")};a.addEventListener("keypress",i),a.addEventListener("keyup",i),a.parentNode.insertBefore(d,a)},p=function(a){var b=document.createElement("div");b.className="preview-code",b.style.position="absolute",b.style.left="-9999px",j.appendChild(b);var c=parseInt(window.getComputedStyle(a).getPropertyValue("max-height"),10),d=function(a){b.textContent=this.value+"\n";var d=b.offsetHeight+2;d>=c?this.style.overflow="auto":this.style.overflow="hidden",this.style.height=b.offsetHeight+2+"px"};a.addEventListener("keypress",d),a.addEventListener("keyup",d),d.call(a)},q=function(){var b=j.getElementsByClassName("settings")[0],c=j.getElementsByClassName("resizeable"),d=30,e=function(b){document.cookie="preview-width="+b,a(c,function(a){b==="auto"&&(b=a.parentNode.offsetWidth),a.style.width=b+"px",h(a.getElementsByTagName("iframe")[0],"getHeight")})},i=f(document.cookie)["preview-width"];if(i){e(i),g(b.getElementsByClassName("is-active"),"is-active");var k=b.querySelector('button[data-width="'+i+'"]');k&&k.classList.add("is-active")}window.addEventListener("message",function(a){if(a.data==null||!a.source)return;var b=a.data,c=document.getElementsByName(a.source.name)[0];b.height!=null&&c&&(c.parentNode.style.height=b.height+d+"px")},!1),b&&c.length>0&&(b.hidden=!1,b.addEventListener("click",function(a){var c=a.target.tagName.toLowerCase(),d;if(c==="button")d=a.target;else{if(c!=="svg")return;d=a.target.parentNode}a.preventDefault(),g(b.getElementsByClassName("is-active"),"is-active"),d.classList.add("is-active");var f=d.dataset.width;e(f)}))}}()})()</script></body></html><!-- Generated with StyleDocco (http://jacobrask.github.com/styledocco). --> +</div></article></section><div class="bar bottom"><div hidden class="settings container"><!-- Icons from http://iconmonstr.com--><button title="Desktop (1280)" data-width='1280'><svg viewBox="0 0 412 386" height="24" width="26" class="icon"><path d="m147.6,343.9c-4.5,15.9-26.2,37.6-42.1,42.1h201c-15.3,-4-38.1,-26.8-42.1,-42.1H147.6zM387,0.5H25c-13.8,0-25,11.2-25,25V294c0,13.8 11.2,25 25,25h362c13.8,0 25,-11.2 25,-25V25.5C412,11.7 400.8,0.5 387,0.5zM369.9,238.2H42.1L42.1,42.6 369.9,42.6V238.2z"></path></svg></button><button title="Laptop (1024)" data-width='1024'><svg viewBox="0 0 384 312" height="23" width="28" class="icon"><path d="m349.2,20.5c0,-11-9,-20-20,-20H53.6c-11,0-20,9-20,20v194H349.2v-194zm-27,167H60.6V27.5H322.2v160zm28,42H32.6L2.6,282.1c-3.5,6.2-3.5,13.8 0.1,19.9 3.6,6.2 10.2,9.9 17.3,9.9H363.1c7.1,0 13.7,-3.8 17.3,-10 3.6,-6.2 3.6,-13.8 0,-20l-30.2,-52.5zm-196.9,54 8,-23.5h60.5l8,23.5h-76.5z"></path></svg></button><button title="Tablet (768)" data-width='768'><svg viewBox="0 0 317 412" height="24" width="18" class="icon"><path d="M 316.5,380 V 32 c 0,-17.7 -14.3,-32 -32,-32 H 32 C 14.3,0 0,14.3 0,32 v 348 c 0,17.7 14.3,32 32,32 h 252.5 c 17.7,0 32,-14.3 32,-32 z M 40,367 V 45 H 276.5 V 367 H 40 z m 109.8,22.7 c 0,-4.7 3.8,-8.5 8.5,-8.5 4.7,0 8.5,3.8 8.5,8.5 0,4.7 -3.8,8.5 -8.5,8.5 -4.7,0 -8.5,-3.8 -8.5,-8.5 z"></path></svg></button><button title="Smart phone (320)" data-width='320'><svg viewBox="0 0 224 412" height="24" width="13" class="icon"><path d="M 190.7,0 H 33 C 14.8,0 0,14.8 0,33 v 346 c 0,18.2 14.8,33 33,33 h 157.7 c 18.2,0 33,-14.8 33,-33 V 33 c 0,-18.2 -14.8,-33 -33,-33 z M 94.3,30.2 h 37 c 2.2,0 4,1.8 4,4 0,2.2 -1.8,4 -4,4 h -37 c -2.2,0 -4,-1.8 -4,-4 0,-2.2 1.8,-4 4,-4 z m 18.5,362.8 c -8.8,0 -16,-7.2 -16,-16 0,-8.8 7.2,-16 16,-16 8.8,0 16,7.2 16,16 0,8.8 -7.2,16 -16,16 z M 198.6,343.8 H 25.1 V 68.2 h 173.5 v 275.5 z"></path></svg></button><button title="Feature phone (240)" data-width='240'><svg viewBox="0 0 201 412" height="24" width="12" class="icon"><path d="M 165.5,0.2 V 45 H 25 c -13.8,0 -25,11.2 -25,25 V 387 c 0,13.8 11.2,25 25,25 h 150.5 c 13.8,0 25,-11.2 25,-25 V 0.2 h -35 z M 65.2,366.5 H 34.2 v -24.5 h 31 v 24.5 z m 0,-44.3 H 34.2 v -24.5 h 31 v 24.5 z m 50.5,44.3 H 84.7 v -24.5 h 31 v 24.5 z m 0,-44.3 H 84.7 v -24.5 h 31 v 24.5 z m 50.5,44.3 h -31 v -24.5 h 31 v 24.5 z m 0,-44.3 h -31 v -24.5 h 31 v 24.5 z m 0,-59.3 h -132 V 95.4 h 132 V 262.9 z"></path></svg></button><button title="Auto (100%)" data-width="auto" class="auto is-active">Auto</button></div></div><script>(function(){var a=[{title:"actions-toolbar",filename:"actions-toolbar",url:"actions-toolbar.html"},{title:"Actions toolbar",filename:"actions-toolbar",url:"actions-toolbar.html#actions-toolbar"},{title:"Actions toolbar mixin variables",filename:"actions-toolbar",url:"actions-toolbar.html#actions-toolbar-mixin-variables"},{title:"Actions toolbar alignment",filename:"actions-toolbar",url:"actions-toolbar.html#actions-toolbar-alignment"},{title:"Reverse primary and secondary blocks",filename:"actions-toolbar",url:"actions-toolbar.html#reverse-primary-and-secondary-blocks"},{title:"Actions toolbar indents customizations",filename:"actions-toolbar",url:"actions-toolbar.html#actions-toolbar-indents-customizations"},{title:"Responsive actions toolbar",filename:"actions-toolbar",url:"actions-toolbar.html#responsive-actions-toolbar"},{title:"breadcrumbs",filename:"breadcrumbs",url:"breadcrumbs.html"},{title:"Breadcrumbs",filename:"breadcrumbs",url:"breadcrumbs.html#breadcrumbs"},{title:"Breadcrumbs variables",filename:"breadcrumbs",url:"breadcrumbs.html#breadcrumbs-variables"},{title:"Button-styled breadcrumbs with gradient background, border, and no separating symbol",filename:"breadcrumbs",url:"breadcrumbs.html#buttonstyled-breadcrumbs-with-gradient-background-border-and-no-separating-symbol"},{title:"Breadcrumbs with solid background",filename:"breadcrumbs",url:"breadcrumbs.html#breadcrumbs-with-solid-background"},{title:"buttons",filename:"buttons",url:"buttons.html"},{title:"Default button",filename:"buttons",url:"buttons.html#default-button"},{title:"Button variables",filename:"buttons",url:"buttons.html#button-variables"},{title:"Button as an icon",filename:"buttons",url:"buttons.html#button-as-an-icon"},{title:"Button with an icon on the left or right side of the text",filename:"buttons",url:"buttons.html#button-with-an-icon-on-the-left-or-right-side-of-the-text"},{title:"Button with fixed width",filename:"buttons",url:"buttons.html#button-with-fixed-width"},{title:"Primary button",filename:"buttons",url:"buttons.html#primary-button"},{title:"Primary button variables",filename:"buttons",url:"buttons.html#primary-button-variables"},{title:"Button with gradient background",filename:"buttons",url:"buttons.html#button-with-gradient-background"},{title:"Button as a link",filename:"buttons",url:"buttons.html#button-as-a-link"},{title:"Button as a link variables",filename:"buttons",url:"buttons.html#button-as-a-link-variables"},{title:"Link as a button",filename:"buttons",url:"buttons.html#link-as-a-button"},{title:"Button reset",filename:"buttons",url:"buttons.html#button-reset"},{title:"Button revert secondary color",filename:"buttons",url:"buttons.html#button-revert-secondary-color"},{title:"Button revert secondary color variables",filename:"buttons",url:"buttons.html#button-revert-secondary-color-variables"},{title:"Button revert secondary size",filename:"buttons",url:"buttons.html#button-revert-secondary-size"},{title:"Button revert secondary size variables",filename:"buttons",url:"buttons.html#button-revert-secondary-size-variables"},{title:"components",filename:"components",url:"components.html"},{title:"Components",filename:"components",url:"components.html#components"},{title:"Components Variables",filename:"components",url:"components.html#components-variables"},{title:"dropdowns",filename:"dropdowns",url:"dropdowns.html"},{title:"Drop-down and split buttons mixins",filename:"dropdowns",url:"dropdowns.html#dropdown-and-split-buttons-mixins"},{title:"Drop-down",filename:"dropdowns",url:"dropdowns.html#dropdown"},{title:"Drop-down variables",filename:"dropdowns",url:"dropdowns.html#dropdown-variables"},{title:"Drop-down with icon customization",filename:"dropdowns",url:"dropdowns.html#dropdown-with-icon-customization"},{title:"Modify dropdown list styles",filename:"dropdowns",url:"dropdowns.html#modify-dropdown-list-styles"},{title:"Split button",filename:"dropdowns",url:"dropdowns.html#split-button"},{title:"Split button variables",filename:"dropdowns",url:"dropdowns.html#split-button-variables"},{title:"Split button - button styling",filename:"dropdowns",url:"dropdowns.html#split-button-button-styling"},{title:"Split button icon customization",filename:"dropdowns",url:"dropdowns.html#split-button-icon-customization"},{title:"Split button drop-down list customization",filename:"dropdowns",url:"dropdowns.html#split-button-dropdown-list-customization"},{title:"forms",filename:"forms",url:"forms.html"},{title:"Forms mixins",filename:"forms",url:"forms.html#forms-mixins"},{title:"Global forms elements customization",filename:"forms",url:"forms.html#global-forms-elements-customization"},{title:"Fieldsets & fields customization",filename:"forms",url:"forms.html#fieldsets-fields-customization"},{title:"Fieldset and legend customization variables",filename:"forms",url:"forms.html#fieldset-and-legend-customization-variables"},{title:"Fields customization variables",filename:"forms",url:"forms.html#fields-customization-variables"},{title:"Required fields message customization variables",filename:"forms",url:"forms.html#required-fields-message-customization-variables"},{title:"Form element inputs customization",filename:"forms",url:"forms.html#form-element-inputs-customization"},{title:"Form element inputs customization variables",filename:"forms",url:"forms.html#form-element-inputs-customization-variables"},{title:"Form element choice",filename:"forms",url:"forms.html#form-element-choice"},{title:"Form element choice variables",filename:"forms",url:"forms.html#form-element-choice-variables"},{title:"Custom color",filename:"forms",url:"forms.html#custom-color"},{title:"Input number - input-text view",filename:"forms",url:"forms.html#input-number-inputtext-view"},{title:"Input search - input-text view",filename:"forms",url:"forms.html#input-search-inputtext-view"},{title:"Form validation",filename:"forms",url:"forms.html#form-validation"},{title:"Form validation variables",filename:"forms",url:"forms.html#form-validation-variables"},{title:"icons",filename:"icons",url:"icons.html"},{title:"Icons",filename:"icons",url:"icons.html#icons"},{title:"Icon with image or sprite",filename:"icons",url:"icons.html#icon-with-image-or-sprite"},{title:"Icon with image or sprite variables",filename:"icons",url:"icons.html#icon-with-image-or-sprite-variables"},{title:"Icon position for an icon with image or sprite",filename:"icons",url:"icons.html#icon-position-for-an-icon-with-image-or-sprite"},{title:"Position for icon with image or sprite mixin variables",filename:"icons",url:"icons.html#position-for-icon-with-image-or-sprite-mixin-variables"},{title:"Icon sprite position (with grid)",filename:"icons",url:"icons.html#icon-sprite-position-with-grid"},{title:"Icon sprite position variables",filename:"icons",url:"icons.html#icon-sprite-position-variables"},{title:"Image/sprite icon size",filename:"icons",url:"icons.html#imagesprite-icon-size"},{title:"Image/sprite icon size variables",filename:"icons",url:"icons.html#imagesprite-icon-size-variables"},{title:"Font icon",filename:"icons",url:"icons.html#font-icon"},{title:"Font icon variables",filename:"icons",url:"icons.html#font-icon-variables"},{title:"Change the size of font icon",filename:"icons",url:"icons.html#change-the-size-of-font-icon"},{title:"Change the size of font icon variables",filename:"icons",url:"icons.html#change-the-size-of-font-icon-variables"},{title:"Hide icon text",filename:"icons",url:"icons.html#hide-icon-text"},{title:"Sprite and font icons for Blank theme",filename:"icons",url:"icons.html#sprite-and-font-icons-for-blank-theme"},{title:"layout",filename:"layout",url:"layout.html"},{title:"Layout",filename:"layout",url:"layout.html#layout"},{title:"Layout global variables",filename:"layout",url:"layout.html#layout-global-variables"},{title:"Page layouts",filename:"layout",url:"layout.html#page-layouts"},{title:"Layout column",filename:"layout",url:"layout.html#layout-column"},{title:"Layout column variables",filename:"layout",url:"layout.html#layout-column-variables"},{title:"Layout width",filename:"layout",url:"layout.html#layout-width"},{title:"Layout width variables",filename:"layout",url:"layout.html#layout-width-variables"},{title:"lib",filename:"lib",url:"lib.html"},{title:"Including Magento UI library to your theme",filename:"lib",url:"lib.html#including-magento-ui-library-to-your-theme"},{title:"loaders",filename:"loaders",url:"loaders.html"},{title:"Loaders",filename:"loaders",url:"loaders.html#loaders"},{title:"Default loader variables",filename:"loaders",url:"loaders.html#default-loader-variables"},{title:"Loading",filename:"loaders",url:"loaders.html#loading"},{title:"Loading default variables",filename:"loaders",url:"loaders.html#loading-default-variables"},{title:"messages",filename:"messages",url:"messages.html"},{title:"Messages",filename:"messages",url:"messages.html#messages"},{title:"Information message",filename:"messages",url:"messages.html#information-message"},{title:"Warning message",filename:"messages",url:"messages.html#warning-message"},{title:"Error message",filename:"messages",url:"messages.html#error-message"},{title:"Success message",filename:"messages",url:"messages.html#success-message"},{title:"Notice message",filename:"messages",url:"messages.html#notice-message"},{title:"Message with inner icon",filename:"messages",url:"messages.html#message-with-inner-icon"},{title:"Message with lateral icon",filename:"messages",url:"messages.html#message-with-lateral-icon"},{title:"Custom message style",filename:"messages",url:"messages.html#custom-message-style"},{title:"Messages global variables",filename:"messages",url:"messages.html#messages-global-variables"},{title:"pages",filename:"pages",url:"pages.html"},{title:"Pagination HTML markup",filename:"pages",url:"pages.html#pagination-html-markup"},{title:"Pagination variables",filename:"pages",url:"pages.html#pagination-variables"},{title:"Pagination with label and gradient background on links",filename:"pages",url:"pages.html#pagination-with-label-and-gradient-background-on-links"},{title:'Pagination with "previous"..."next" text links and label',filename:"pages",url:"pages.html#pagination-with-previousnext-text-links-and-label"},{title:"Pagination without label, with solid background",filename:"pages",url:"pages.html#pagination-without-label-with-solid-background"},{title:"popups",filename:"popups",url:"popups.html"},{title:"Popups",filename:"popups",url:"popups.html#popups"},{title:"Popup variables",filename:"popups",url:"popups.html#popup-variables"},{title:"Window overlay mixin variables",filename:"popups",url:"popups.html#window-overlay-mixin-variables"},{title:"Fixed height popup",filename:"popups",url:"popups.html#fixed-height-popup"},{title:"Fixed content height popup",filename:"popups",url:"popups.html#fixed-content-height-popup"},{title:"Margins for header, content and footer block in popup",filename:"popups",url:"popups.html#margins-for-header-content-and-footer-block-in-popup"},{title:"Popup titles styled as theme headings",filename:"popups",url:"popups.html#popup-titles-styled-as-theme-headings"},{title:"Popup action toolbar",filename:"popups",url:"popups.html#popup-action-toolbar"},{title:"Popup Close button without an icon",filename:"popups",url:"popups.html#popup-close-button-without-an-icon"},{title:"Modify the icon of popup Close button",filename:"popups",url:"popups.html#modify-the-icon-of-popup-close-button"},{title:"Modify overlay styles",filename:"popups",url:"popups.html#modify-overlay-styles"},{title:"rating",filename:"rating",url:"rating.html"},{title:"Ratings",filename:"rating",url:"rating.html#ratings"},{title:"Global rating variables",filename:"rating",url:"rating.html#global-rating-variables"},{title:"Rating with vote",filename:"rating",url:"rating.html#rating-with-vote"},{title:"Rating with vote icons number customization",filename:"rating",url:"rating.html#rating-with-vote-icons-number-customization"},{title:"Rating with vote icons colors customization",filename:"rating",url:"rating.html#rating-with-vote-icons-colors-customization"},{title:"Rating with vote icons symbol customization",filename:"rating",url:"rating.html#rating-with-vote-icons-symbol-customization"},{title:"Accessible rating with vote",filename:"rating",url:"rating.html#accessible-rating-with-vote"},{title:"Rating summary",filename:"rating",url:"rating.html#rating-summary"},{title:"Rating summary icons number customization",filename:"rating",url:"rating.html#rating-summary-icons-number-customization"},{title:"Rating summary icons color customization",filename:"rating",url:"rating.html#rating-summary-icons-color-customization"},{title:"Rating summary icons symbol customization",filename:"rating",url:"rating.html#rating-summary-icons-symbol-customization"},{title:"Rating summary hide label",filename:"rating",url:"rating.html#rating-summary-hide-label"},{title:"Rating summary multiple ratings",filename:"rating",url:"rating.html#rating-summary-multiple-ratings"},{title:"Rating hide label mixin",filename:"rating",url:"rating.html#rating-hide-label-mixin"},{title:"resets",filename:"resets",url:"resets.html"},{title:"Resets",filename:"resets",url:"resets.html#resets"},{title:"responsive",filename:"responsive",url:"responsive.html"},{title:"Responsive",filename:"responsive",url:"responsive.html#responsive"},{title:"Responsive mixins usage",filename:"responsive",url:"responsive.html#responsive-mixins-usage"},{title:"Media query style groups separation variables",filename:"responsive",url:"responsive.html#media-query-style-groups-separation-variables"},{title:"Responsive breakpoints",filename:"responsive",url:"responsive.html#responsive-breakpoints"},{title:"sections",filename:"sections",url:"sections.html"},{title:"Tabs and accordions",filename:"sections",url:"sections.html#tabs-and-accordions"},{title:"Tabs",filename:"sections",url:"sections.html#tabs"},{title:"Tabs mixin variables",filename:"sections",url:"sections.html#tabs-mixin-variables"},{title:"Tabs with content top border",filename:"sections",url:"sections.html#tabs-with-content-top-border"},{title:"Accordion",filename:"sections",url:"sections.html#accordion"},{title:"Accordion mixin variables",filename:"sections",url:"sections.html#accordion-mixin-variables"},{title:"Responsive tabs",filename:"sections",url:"sections.html#responsive-tabs"},{title:"Tabs Base",filename:"sections",url:"sections.html#tabs-base"},{title:"Accordion Base",filename:"sections",url:"sections.html#accordion-base"},{title:"tables",filename:"tables",url:"tables.html"},{title:"Tables",filename:"tables",url:"tables.html#tables"},{title:"Table mixin variables",filename:"tables",url:"tables.html#table-mixin-variables"},{title:"Table typography",filename:"tables",url:"tables.html#table-typography"},{title:"Table typography mixin variables",filename:"tables",url:"tables.html#table-typography-mixin-variables"},{title:"Table caption",filename:"tables",url:"tables.html#table-caption"},{title:"Table caption mixin variables",filename:"tables",url:"tables.html#table-caption-mixin-variables"},{title:"Table cells resize",filename:"tables",url:"tables.html#table-cells-resize"},{title:"Table cells resize variables",filename:"tables",url:"tables.html#table-cells-resize-variables"},{title:"Table background customization",filename:"tables",url:"tables.html#table-background-customization"},{title:"Table background mixin variables",filename:"tables",url:"tables.html#table-background-mixin-variables"},{title:"Table borders customization",filename:"tables",url:"tables.html#table-borders-customization"},{title:"Table borders mixin variables",filename:"tables",url:"tables.html#table-borders-mixin-variables"},{title:"Table with horizontal borders",filename:"tables",url:"tables.html#table-with-horizontal-borders"},{title:"Table with vertical borders",filename:"tables",url:"tables.html#table-with-vertical-borders"},{title:"Table with light borders",filename:"tables",url:"tables.html#table-with-light-borders"},{title:"Table without borders",filename:"tables",url:"tables.html#table-without-borders"},{title:"Striped table",filename:"tables",url:"tables.html#striped-table"},{title:"Striped table mixin variables",filename:"tables",url:"tables.html#striped-table-mixin-variables"},{title:"Table with rows hover",filename:"tables",url:"tables.html#table-with-rows-hover"},{title:"Table with rows hover mixin variables",filename:"tables",url:"tables.html#table-with-rows-hover-mixin-variables"},{title:"Responsive table technics #1",filename:"tables",url:"tables.html#responsive-table-technics-1"},{title:"Responsive table technics #2",filename:"tables",url:"tables.html#responsive-table-technics-2"},{title:"Responsive table technics #2 mixin variables",filename:"tables",url:"tables.html#responsive-table-technics-2-mixin-variables"},{title:"tooltips",filename:"tooltips",url:"tooltips.html"},{title:"Tooltips",filename:"tooltips",url:"tooltips.html#tooltips"},{title:"Tooltips variables",filename:"tooltips",url:"tooltips.html#tooltips-variables"},{title:"typography",filename:"typography",url:"typography.html"},{title:"Typogrphy",filename:"typography",url:"typography.html#typogrphy"},{title:"Typography variables",filename:"typography",url:"typography.html#typography-variables"},{title:"Font-size mixin",filename:"typography",url:"typography.html#fontsize-mixin"},{title:"Line-height mixin",filename:"typography",url:"typography.html#lineheight-mixin"},{title:"Word breaking mixin",filename:"typography",url:"typography.html#word-breaking-mixin"},{title:"Font face mixin",filename:"typography",url:"typography.html#font-face-mixin"},{title:"Text overflow mixin",filename:"typography",url:"typography.html#text-overflow-mixin"},{title:"Text hide",filename:"typography",url:"typography.html#text-hide"},{title:"Hyphens",filename:"typography",url:"typography.html#hyphens"},{title:"Font style and color",filename:"typography",url:"typography.html#font-style-and-color"},{title:"Font style mixin variables",filename:"typography",url:"typography.html#font-style-mixin-variables"},{title:"Reset list styles",filename:"typography",url:"typography.html#reset-list-styles"},{title:"Reset list styles variables",filename:"typography",url:"typography.html#reset-list-styles-variables"},{title:"Inline-block list item styling",filename:"typography",url:"typography.html#inlineblock-list-item-styling"},{title:"Link styling mixin",filename:"typography",url:"typography.html#link-styling-mixin"},{title:"Link styling mixin variables",filename:"typography",url:"typography.html#link-styling-mixin-variables"},{title:"Heading styling mixin",filename:"typography",url:"typography.html#heading-styling-mixin"},{title:"Base typography mixins",filename:"typography",url:"typography.html#base-typography-mixins"},{title:"Base typography mixin variables",filename:"typography",url:"typography.html#base-typography-mixin-variables"},{title:"Headings typography mixin",filename:"typography",url:"typography.html#headings-typography-mixin"},{title:"Headings typography mixin variables",filename:"typography",url:"typography.html#headings-typography-mixin-variables"},{title:"Typography links mixin",filename:"typography",url:"typography.html#typography-links-mixin"},{title:"Typography lists mixin",filename:"typography",url:"typography.html#typography-lists-mixin"},{title:"Typography lists mixin variables",filename:"typography",url:"typography.html#typography-lists-mixin-variables"},{title:"Typography code elements mixin",filename:"typography",url:"typography.html#typography-code-elements-mixin"},{title:"Typography code mixin variables",filename:"typography",url:"typography.html#typography-code-mixin-variables"},{title:"Typography blockquote",filename:"typography",url:"typography.html#typography-blockquote"},{title:"Typography blockquote mixin variables",filename:"typography",url:"typography.html#typography-blockquote-mixin-variables"},{title:"utilities",filename:"utilities",url:"utilities.html"},{title:"Utilities",filename:"utilities",url:"utilities.html#utilities"},{title:".lib-clearfix()",filename:"utilities",url:"utilities.html#libclearfix"},{title:".lib-visibility-hidden()",filename:"utilities",url:"utilities.html#libvisibilityhidden"},{title:".lib-visually-hidden()",filename:"utilities",url:"utilities.html#libvisuallyhidden"},{title:".lib-visually-hidden-reset()",filename:"utilities",url:"utilities.html#libvisuallyhiddenreset"},{title:".lib-css()",filename:"utilities",url:"utilities.html#libcss"},{title:".lib-css() variables",filename:"utilities",url:"utilities.html#libcss-variables"},{title:".lib-rotate()",filename:"utilities",url:"utilities.html#librotate"},{title:".lib-rotate() variables",filename:"utilities",url:"utilities.html#librotate-variables"},{title:".lib-input-placeholder()",filename:"utilities",url:"utilities.html#libinputplaceholder"},{title:".lib-input-placeholder() variables",filename:"utilities",url:"utilities.html#libinputplaceholder-variables"},{title:".lib-background-gradient()",filename:"utilities",url:"utilities.html#libbackgroundgradient"},{title:".lib-background-gradient() variables",filename:"utilities",url:"utilities.html#libbackgroundgradient-variables"},{title:"variables",filename:"variables",url:"variables.html"},{title:"List of Global Variables",filename:"variables",url:"variables.html#list-of-global-variables"},{title:"Table with rows hover mixin variables",filename:"variables",url:"variables.html#table-with-rows-hover-mixin-variables"},{title:"docs",filename:"docs",url:"docs.html"},{title:"Documentation",filename:"docs",url:"docs.html#documentation"}];(function(){"use strict";var b=function(a,b){return Array.prototype.indexOf.call(a,b)!==-1},c=function(a,b){return Array.prototype.filter.call(a,b)},d=function(a,b){return Array.prototype.forEach.call(a,b)},e=document.getElementsByTagName("body")[0];e.addEventListener("click",function(a){var b=a.target;b.tagName.toLowerCase()==="svg"&&(b=b.parentNode);var c=!1;b.dataset.toggle!=null&&(a.preventDefault(),b.classList.contains("is-active")||(c=!0)),d(e.querySelectorAll("[data-toggle]"),function(a){a.classList.remove("is-active"),document.getElementById(a.dataset.toggle).hidden=!0}),c&&(b.classList.add("is-active"),document.getElementById(b.dataset.toggle).hidden=!1)}),function(){var f=e.getElementsByClassName("nav")[0];if(!f)return;var g=document.createElement("ul");g.className="nav-results",g.id="nav-search",g.hidden=!0,d(a,function(a){var b,c,d;b=document.createElement("li"),b._title=a.title.toLowerCase(),b.hidden=!0,b.appendChild(c=document.createElement("a")),c.href=a.url,c.innerHTML=a.title,c.appendChild(d=document.createElement("span")),d.innerHTML=a.filename,d.className="nav-results-filename",g.appendChild(b)}),f.appendChild(g);var h=g.children,i=function(a){d(h,function(a){a.hidden=!0});var b=this.value.toLowerCase(),e=[];b!==""&&(e=c(h,function(a){return a._title.indexOf(b)!==-1})),e.length>0?(d(e,function(a){a.hidden=!1}),g.hidden=!1):g.hidden=!0},j=f.querySelector('input[type="search"]');j.addEventListener("keyup",i),j.addEventListener("focus",i),e.addEventListener("click",function(a){if(a.target.classList&&a.target.classList.contains("search"))return;g.hidden=!0}),g.addEventListener("click",function(a){j.value=""});var k=document.createElement("ul");k.id="nav-toc",k.hidden=!0,k.className="nav-results toc-list",c(e.getElementsByTagName("*"),function(a){return b(["h1","h2","h3"],a.tagName.toLowerCase())}).map(function(a){var b=document.createElement("li"),c=document.createElement("a"),d=a.tagName.toLowerCase()[1];c.classList.add("level-"+d),b.appendChild(c),c.href="#"+a.id,c.innerHTML=a.innerHTML,k.appendChild(b)}),f.appendChild(k)}()})(),function(){"use strict";if(location.hash==="#__preview__"||location.protocol==="data:")return;var a=function(a,b){return Array.prototype.forEach.call(a,b)},b=function(a,b){var e=Array.prototype.slice.call(arguments,2);return d(a,function(a){return(c(b)?b||a:a[b]).apply(a,e)})},c=function(a){return Object.prototype.toString.call(a)==="[object Function]"},d=function(a,b){return Array.prototype.map.call(a,b)},e=function(a,b){return d(a,function(a){return a[b]})},f=function(a){var b={},c=a.split(";");for(var d=0;c.length>d;d++){var e=c[d].trim().split("=");b[e[0]]=e[1]}return b},g=function(a,c){return b(e(a,"classList"),"remove",c)},h=function(a,b){a.contentDocument.defaultView.postMessage(b,"*")},i=document.getElementsByTagName("head")[0],j=document.getElementsByTagName("body")[0],k=e(i.querySelectorAll('style[type="text/preview"]'),"innerHTML").join(""),l=e(i.querySelectorAll('script[type="text/preview"]'),"innerHTML").join(""),m=location.href.split("#")[0]+"#__preview__",n=document.createElement("iframe");n.src="data:text/html,",j.appendChild(n),n.addEventListener("load",function(){var b={sameOriginDataUri:!0};try{this.contentDocument,this.contentDocument||(b.sameOriginDataUri=!1)}catch(c){b.sameOriginDataUri=!1}this.parentNode.removeChild(this),a(j.getElementsByTagName("textarea"),function(a,c){o(a,b,c),q(),p(a)})});var o=function(a,b,c){var d,e,f;d=document.createElement("div"),d.appendChild(e=document.createElement("div")),d.className="preview",e.appendChild(f=document.createElement("iframe")),e.className="resizeable",f.setAttribute("scrolling","no"),f.name="iframe"+c++,f.addEventListener("load",function(){var c,d,e,f,g,i,j;j=this.contentDocument;if(!b.sameOriginDataUri&&this.src!==m)return;this.src===m&&(c=j.createElement("html"),c.appendChild(j.createElement("head")),c.appendChild(d=j.createElement("body")),d.innerHTML=a.textContent,j.replaceChild(c,j.documentElement)),g=j.createElement("head"),g.appendChild(f=j.createElement("style")),g.appendChild(e=j.createElement("script")),e.textContent=l,f.textContent=k,i=j.getElementsByTagName("head")[0],i.parentNode.replaceChild(g,i),h(this,"getHeight")});var g;b.sameOriginDataUri?g="data:text/html;charset=utf-8,"+encodeURIComponent("<!doctype html><html><head></head></body>"+a.textContent):g=m,f.setAttribute("src",g);var i=function(){f.contentDocument.body.innerHTML=this.value,h(f,"getHeight")};a.addEventListener("keypress",i),a.addEventListener("keyup",i),a.parentNode.insertBefore(d,a)},p=function(a){var b=document.createElement("div");b.className="preview-code",b.style.position="absolute",b.style.left="-9999px",j.appendChild(b);var c=parseInt(window.getComputedStyle(a).getPropertyValue("max-height"),10),d=function(a){b.textContent=this.value+"\n";var d=b.offsetHeight+2;d>=c?this.style.overflow="auto":this.style.overflow="hidden",this.style.height=b.offsetHeight+2+"px"};a.addEventListener("keypress",d),a.addEventListener("keyup",d),d.call(a)},q=function(){var b=j.getElementsByClassName("settings")[0],c=j.getElementsByClassName("resizeable"),d=30,e=function(b){document.cookie="preview-width="+b,a(c,function(a){b==="auto"&&(b=a.parentNode.offsetWidth),a.style.width=b+"px",h(a.getElementsByTagName("iframe")[0],"getHeight")})},i=f(document.cookie)["preview-width"];if(i){e(i),g(b.getElementsByClassName("is-active"),"is-active");var k=b.querySelector('button[data-width="'+i+'"]');k&&k.classList.add("is-active")}window.addEventListener("message",function(a){if(a.data==null||!a.source)return;var b=a.data,c=document.getElementsByName(a.source.name)[0];b.height!=null&&c&&(c.parentNode.style.height=b.height+d+"px")},!1),b&&c.length>0&&(b.hidden=!1,b.addEventListener("click",function(a){var c=a.target.tagName.toLowerCase(),d;if(c==="button")d=a.target;else{if(c!=="svg")return;d=a.target.parentNode}a.preventDefault(),g(b.getElementsByClassName("is-active"),"is-active"),d.classList.add("is-active");var f=d.dataset.width;e(f)}))}}()})()</script></body></html><!-- Generated with StyleDocco (http://jacobrask.github.com/styledocco). --> diff --git a/lib/web/css/docs/docs.css b/lib/web/css/docs/docs.css index beb18b8b2194a..a3a372ad4eeb9 100644 --- a/lib/web/css/docs/docs.css +++ b/lib/web/css/docs/docs.css @@ -4187,7 +4187,7 @@ select { color: #000066; } .example-message-4:before { - background: #green; + background: green; width: 30px; content: ''; display: block; @@ -4230,7 +4230,7 @@ select { border: 5px solid transparent; height: 0; width: 0; - border-left-color: #green; + border-left-color: green; left: 30px; } .example-message-4 > *:first-child:after { diff --git a/lib/web/css/docs/docs.html b/lib/web/css/docs/docs.html index 164e5a1dfdc21..68e9d98eb2def 100644 --- a/lib/web/css/docs/docs.html +++ b/lib/web/css/docs/docs.html @@ -40,4 +40,4 @@ body { padding: 15px; background-image: none; -}</code></pre></div></article></section><div class="bar bottom"><div hidden class="settings container"><!-- Icons from http://iconmonstr.com--><button title="Desktop (1280)" data-width='1280'><svg viewBox="0 0 412 386" height="24" width="26" class="icon"><path d="m147.6,343.9c-4.5,15.9-26.2,37.6-42.1,42.1h201c-15.3,-4-38.1,-26.8-42.1,-42.1H147.6zM387,0.5H25c-13.8,0-25,11.2-25,25V294c0,13.8 11.2,25 25,25h362c13.8,0 25,-11.2 25,-25V25.5C412,11.7 400.8,0.5 387,0.5zM369.9,238.2H42.1L42.1,42.6 369.9,42.6V238.2z"></path></svg></button><button title="Laptop (1024)" data-width='1024'><svg viewBox="0 0 384 312" height="23" width="28" class="icon"><path d="m349.2,20.5c0,-11-9,-20-20,-20H53.6c-11,0-20,9-20,20v194H349.2v-194zm-27,167H60.6V27.5H322.2v160zm28,42H32.6L2.6,282.1c-3.5,6.2-3.5,13.8 0.1,19.9 3.6,6.2 10.2,9.9 17.3,9.9H363.1c7.1,0 13.7,-3.8 17.3,-10 3.6,-6.2 3.6,-13.8 0,-20l-30.2,-52.5zm-196.9,54 8,-23.5h60.5l8,23.5h-76.5z"></path></svg></button><button title="Tablet (768)" data-width='768'><svg viewBox="0 0 317 412" height="24" width="18" class="icon"><path d="M 316.5,380 V 32 c 0,-17.7 -14.3,-32 -32,-32 H 32 C 14.3,0 0,14.3 0,32 v 348 c 0,17.7 14.3,32 32,32 h 252.5 c 17.7,0 32,-14.3 32,-32 z M 40,367 V 45 H 276.5 V 367 H 40 z m 109.8,22.7 c 0,-4.7 3.8,-8.5 8.5,-8.5 4.7,0 8.5,3.8 8.5,8.5 0,4.7 -3.8,8.5 -8.5,8.5 -4.7,0 -8.5,-3.8 -8.5,-8.5 z"></path></svg></button><button title="Smart phone (320)" data-width='320'><svg viewBox="0 0 224 412" height="24" width="13" class="icon"><path d="M 190.7,0 H 33 C 14.8,0 0,14.8 0,33 v 346 c 0,18.2 14.8,33 33,33 h 157.7 c 18.2,0 33,-14.8 33,-33 V 33 c 0,-18.2 -14.8,-33 -33,-33 z M 94.3,30.2 h 37 c 2.2,0 4,1.8 4,4 0,2.2 -1.8,4 -4,4 h -37 c -2.2,0 -4,-1.8 -4,-4 0,-2.2 1.8,-4 4,-4 z m 18.5,362.8 c -8.8,0 -16,-7.2 -16,-16 0,-8.8 7.2,-16 16,-16 8.8,0 16,7.2 16,16 0,8.8 -7.2,16 -16,16 z M 198.6,343.8 H 25.1 V 68.2 h 173.5 v 275.5 z"></path></svg></button><button title="Feature phone (240)" data-width='240'><svg viewBox="0 0 201 412" height="24" width="12" class="icon"><path d="M 165.5,0.2 V 45 H 25 c -13.8,0 -25,11.2 -25,25 V 387 c 0,13.8 11.2,25 25,25 h 150.5 c 13.8,0 25,-11.2 25,-25 V 0.2 h -35 z M 65.2,366.5 H 34.2 v -24.5 h 31 v 24.5 z m 0,-44.3 H 34.2 v -24.5 h 31 v 24.5 z m 50.5,44.3 H 84.7 v -24.5 h 31 v 24.5 z m 0,-44.3 H 84.7 v -24.5 h 31 v 24.5 z m 50.5,44.3 h -31 v -24.5 h 31 v 24.5 z m 0,-44.3 h -31 v -24.5 h 31 v 24.5 z m 0,-59.3 h -132 V 95.4 h 132 V 262.9 z"></path></svg></button><button title="Auto (100%)" data-width="auto" class="auto is-active">Auto</button></div></div><script>(function(){var a=[{title:"actions-toolbar",filename:"actions-toolbar",url:"actions-toolbar.html"},{title:"Actions toolbar",filename:"actions-toolbar",url:"actions-toolbar.html#actions-toolbar"},{title:"Actions toolbar mixin variables",filename:"actions-toolbar",url:"actions-toolbar.html#actions-toolbar-mixin-variables"},{title:"Actions toolbar alignment",filename:"actions-toolbar",url:"actions-toolbar.html#actions-toolbar-alignment"},{title:"Reverse primary and secondary blocks",filename:"actions-toolbar",url:"actions-toolbar.html#reverse-primary-and-secondary-blocks"},{title:"Actions toolbar indents customizations",filename:"actions-toolbar",url:"actions-toolbar.html#actions-toolbar-indents-customizations"},{title:"Responsive actions toolbar",filename:"actions-toolbar",url:"actions-toolbar.html#responsive-actions-toolbar"},{title:"breadcrumbs",filename:"breadcrumbs",url:"breadcrumbs.html"},{title:"Breadcrumbs",filename:"breadcrumbs",url:"breadcrumbs.html#breadcrumbs"},{title:"Breadcrumbs variables",filename:"breadcrumbs",url:"breadcrumbs.html#breadcrumbs-variables"},{title:"Button-styled breadcrumbs with gradient background, border, and no separating symbol",filename:"breadcrumbs",url:"breadcrumbs.html#buttonstyled-breadcrumbs-with-gradient-background-border-and-no-separating-symbol"},{title:"Breadcrumbs with solid background",filename:"breadcrumbs",url:"breadcrumbs.html#breadcrumbs-with-solid-background"},{title:"buttons",filename:"buttons",url:"buttons.html"},{title:"Default button",filename:"buttons",url:"buttons.html#default-button"},{title:"Button variables",filename:"buttons",url:"buttons.html#button-variables"},{title:"Button as an icon",filename:"buttons",url:"buttons.html#button-as-an-icon"},{title:"Button with an icon on the left or right side of the text",filename:"buttons",url:"buttons.html#button-with-an-icon-on-the-left-or-right-side-of-the-text"},{title:"Button with fixed width",filename:"buttons",url:"buttons.html#button-with-fixed-width"},{title:"Primary button",filename:"buttons",url:"buttons.html#primary-button"},{title:"Primary button variables",filename:"buttons",url:"buttons.html#primary-button-variables"},{title:"Button with gradient background",filename:"buttons",url:"buttons.html#button-with-gradient-background"},{title:"Button as a link",filename:"buttons",url:"buttons.html#button-as-a-link"},{title:"Button as a link variables",filename:"buttons",url:"buttons.html#button-as-a-link-variables"},{title:"Link as a button",filename:"buttons",url:"buttons.html#link-as-a-button"},{title:"Button reset",filename:"buttons",url:"buttons.html#button-reset"},{title:"Button revert secondary color",filename:"buttons",url:"buttons.html#button-revert-secondary-color"},{title:"Button revert secondary color variables",filename:"buttons",url:"buttons.html#button-revert-secondary-color-variables"},{title:"Button revert secondary size",filename:"buttons",url:"buttons.html#button-revert-secondary-size"},{title:"Button revert secondary size variables",filename:"buttons",url:"buttons.html#button-revert-secondary-size-variables"},{title:"components",filename:"components",url:"components.html"},{title:"Components",filename:"components",url:"components.html#components"},{title:"Components Variables",filename:"components",url:"components.html#components-variables"},{title:"dropdowns",filename:"dropdowns",url:"dropdowns.html"},{title:"Drop-down and split buttons mixins",filename:"dropdowns",url:"dropdowns.html#dropdown-and-split-buttons-mixins"},{title:"Drop-down",filename:"dropdowns",url:"dropdowns.html#dropdown"},{title:"Drop-down variables",filename:"dropdowns",url:"dropdowns.html#dropdown-variables"},{title:"Drop-down with icon customization",filename:"dropdowns",url:"dropdowns.html#dropdown-with-icon-customization"},{title:"Modify dropdown list styles",filename:"dropdowns",url:"dropdowns.html#modify-dropdown-list-styles"},{title:"Split button",filename:"dropdowns",url:"dropdowns.html#split-button"},{title:"Split button variables",filename:"dropdowns",url:"dropdowns.html#split-button-variables"},{title:"Split button - button styling",filename:"dropdowns",url:"dropdowns.html#split-button-button-styling"},{title:"Split button icon customization",filename:"dropdowns",url:"dropdowns.html#split-button-icon-customization"},{title:"Split button drop-down list customization",filename:"dropdowns",url:"dropdowns.html#split-button-dropdown-list-customization"},{title:"forms",filename:"forms",url:"forms.html"},{title:"Forms mixins",filename:"forms",url:"forms.html#forms-mixins"},{title:"Global forms elements customization",filename:"forms",url:"forms.html#global-forms-elements-customization"},{title:"Fieldsets & fields customization",filename:"forms",url:"forms.html#fieldsets-fields-customization"},{title:"Fieldset and legend customization variables",filename:"forms",url:"forms.html#fieldset-and-legend-customization-variables"},{title:"Fields customization variables",filename:"forms",url:"forms.html#fields-customization-variables"},{title:"Required fields message customization variables",filename:"forms",url:"forms.html#required-fields-message-customization-variables"},{title:"Form element inputs customization",filename:"forms",url:"forms.html#form-element-inputs-customization"},{title:"Form element inputs customization variables",filename:"forms",url:"forms.html#form-element-inputs-customization-variables"},{title:"Form element choice",filename:"forms",url:"forms.html#form-element-choice"},{title:"Form element choice variables",filename:"forms",url:"forms.html#form-element-choice-variables"},{title:"Custom color",filename:"forms",url:"forms.html#custom-color"},{title:"Input number - input-text view",filename:"forms",url:"forms.html#input-number-inputtext-view"},{title:"Input search - input-text view",filename:"forms",url:"forms.html#input-search-inputtext-view"},{title:"Form validation",filename:"forms",url:"forms.html#form-validation"},{title:"Form validation variables",filename:"forms",url:"forms.html#form-validation-variables"},{title:"icons",filename:"icons",url:"icons.html"},{title:"Icons",filename:"icons",url:"icons.html#icons"},{title:"Icon with image or sprite",filename:"icons",url:"icons.html#icon-with-image-or-sprite"},{title:"Icon with image or sprite variables",filename:"icons",url:"icons.html#icon-with-image-or-sprite-variables"},{title:"Icon position for an icon with image or sprite",filename:"icons",url:"icons.html#icon-position-for-an-icon-with-image-or-sprite"},{title:"Position for icon with image or sprite mixin variables",filename:"icons",url:"icons.html#position-for-icon-with-image-or-sprite-mixin-variables"},{title:"Icon sprite position (with grid)",filename:"icons",url:"icons.html#icon-sprite-position-with-grid"},{title:"Icon sprite position variables",filename:"icons",url:"icons.html#icon-sprite-position-variables"},{title:"Image/sprite icon size",filename:"icons",url:"icons.html#imagesprite-icon-size"},{title:"Image/sprite icon size variables",filename:"icons",url:"icons.html#imagesprite-icon-size-variables"},{title:"Font icon",filename:"icons",url:"icons.html#font-icon"},{title:"Font icon variables",filename:"icons",url:"icons.html#font-icon-variables"},{title:"Change the size of font icon",filename:"icons",url:"icons.html#change-the-size-of-font-icon"},{title:"Change the size of font icon variables",filename:"icons",url:"icons.html#change-the-size-of-font-icon-variables"},{title:"Hide icon text",filename:"icons",url:"icons.html#hide-icon-text"},{title:"Sprite and font icons for Blank theme",filename:"icons",url:"icons.html#sprite-and-font-icons-for-blank-theme"},{title:"layout",filename:"layout",url:"layout.html"},{title:"Layout",filename:"layout",url:"layout.html#layout"},{title:"Layout global variables",filename:"layout",url:"layout.html#layout-global-variables"},{title:"Page layouts",filename:"layout",url:"layout.html#page-layouts"},{title:"Layout column",filename:"layout",url:"layout.html#layout-column"},{title:"Layout column variables",filename:"layout",url:"layout.html#layout-column-variables"},{title:"Layout width",filename:"layout",url:"layout.html#layout-width"},{title:"Layout width variables",filename:"layout",url:"layout.html#layout-width-variables"},{title:"lib",filename:"lib",url:"lib.html"},{title:"Including Magento UI library to your theme",filename:"lib",url:"lib.html#including-magento-ui-library-to-your-theme"},{title:"loaders",filename:"loaders",url:"loaders.html"},{title:"Loaders",filename:"loaders",url:"loaders.html#loaders"},{title:"Default loader variables",filename:"loaders",url:"loaders.html#default-loader-variables"},{title:"Loading",filename:"loaders",url:"loaders.html#loading"},{title:"Loading default variables",filename:"loaders",url:"loaders.html#loading-default-variables"},{title:"messages",filename:"messages",url:"messages.html"},{title:"Messages",filename:"messages",url:"messages.html#messages"},{title:"Information message",filename:"messages",url:"messages.html#information-message"},{title:"Warning message",filename:"messages",url:"messages.html#warning-message"},{title:"Error message",filename:"messages",url:"messages.html#error-message"},{title:"Success message",filename:"messages",url:"messages.html#success-message"},{title:"Notice message",filename:"messages",url:"messages.html#notice-message"},{title:"Message with inner icon",filename:"messages",url:"messages.html#message-with-inner-icon"},{title:"Message with lateral icon",filename:"messages",url:"messages.html#message-with-lateral-icon"},{title:"Custom message style",filename:"messages",url:"messages.html#custom-message-style"},{title:"Messages global variables",filename:"messages",url:"messages.html#messages-global-variables"},{title:"pages",filename:"pages",url:"pages.html"},{title:"Pagination HTML markup",filename:"pages",url:"pages.html#pagination-html-markup"},{title:"Pagination variables",filename:"pages",url:"pages.html#pagination-variables"},{title:"Pagination with label and gradient background on links",filename:"pages",url:"pages.html#pagination-with-label-and-gradient-background-on-links"},{title:'Pagination with "previous"..."next" text links and label',filename:"pages",url:"pages.html#pagination-with-previousnext-text-links-and-label"},{title:"Pagination without label, with solid background",filename:"pages",url:"pages.html#pagination-without-label-with-solid-background"},{title:"popups",filename:"popups",url:"popups.html"},{title:"Popups",filename:"popups",url:"popups.html#popups"},{title:"Popup variables",filename:"popups",url:"popups.html#popup-variables"},{title:"Window overlay mixin variables",filename:"popups",url:"popups.html#window-overlay-mixin-variables"},{title:"Fixed height popup",filename:"popups",url:"popups.html#fixed-height-popup"},{title:"Fixed content height popup",filename:"popups",url:"popups.html#fixed-content-height-popup"},{title:"Margins for header, content and footer block in popup",filename:"popups",url:"popups.html#margins-for-header-content-and-footer-block-in-popup"},{title:"Popup titles styled as theme headings",filename:"popups",url:"popups.html#popup-titles-styled-as-theme-headings"},{title:"Popup action toolbar",filename:"popups",url:"popups.html#popup-action-toolbar"},{title:"Popup Close button without an icon",filename:"popups",url:"popups.html#popup-close-button-without-an-icon"},{title:"Modify the icon of popup Close button",filename:"popups",url:"popups.html#modify-the-icon-of-popup-close-button"},{title:"Modify overlay styles",filename:"popups",url:"popups.html#modify-overlay-styles"},{title:"rating",filename:"rating",url:"rating.html"},{title:"Ratings",filename:"rating",url:"rating.html#ratings"},{title:"Global rating variables",filename:"rating",url:"rating.html#global-rating-variables"},{title:"Rating with vote",filename:"rating",url:"rating.html#rating-with-vote"},{title:"Rating with vote icons number customization",filename:"rating",url:"rating.html#rating-with-vote-icons-number-customization"},{title:"Rating with vote icons colors customization",filename:"rating",url:"rating.html#rating-with-vote-icons-colors-customization"},{title:"Rating with vote icons symbol customization",filename:"rating",url:"rating.html#rating-with-vote-icons-symbol-customization"},{title:"Accessible rating with vote",filename:"rating",url:"rating.html#accessible-rating-with-vote"},{title:"Rating summary",filename:"rating",url:"rating.html#rating-summary"},{title:"Rating summary icons number customization",filename:"rating",url:"rating.html#rating-summary-icons-number-customization"},{title:"Rating summary icons color customization",filename:"rating",url:"rating.html#rating-summary-icons-color-customization"},{title:"Rating summary icons symbol customization",filename:"rating",url:"rating.html#rating-summary-icons-symbol-customization"},{title:"Rating summary hide label",filename:"rating",url:"rating.html#rating-summary-hide-label"},{title:"Rating summary multiple ratings",filename:"rating",url:"rating.html#rating-summary-multiple-ratings"},{title:"Rating hide label mixin",filename:"rating",url:"rating.html#rating-hide-label-mixin"},{title:"resets",filename:"resets",url:"resets.html"},{title:"Resets",filename:"resets",url:"resets.html#resets"},{title:"responsive",filename:"responsive",url:"responsive.html"},{title:"Responsive",filename:"responsive",url:"responsive.html#responsive"},{title:"Responsive mixins usage",filename:"responsive",url:"responsive.html#responsive-mixins-usage"},{title:"Media query style groups separation variables",filename:"responsive",url:"responsive.html#media-query-style-groups-separation-variables"},{title:"Responsive breakpoints",filename:"responsive",url:"responsive.html#responsive-breakpoints"},{title:"sections",filename:"sections",url:"sections.html"},{title:"Tabs and accordions",filename:"sections",url:"sections.html#tabs-and-accordions"},{title:"Tabs",filename:"sections",url:"sections.html#tabs"},{title:"Tabs mixin variables",filename:"sections",url:"sections.html#tabs-mixin-variables"},{title:"Tabs with content top border",filename:"sections",url:"sections.html#tabs-with-content-top-border"},{title:"Accordion",filename:"sections",url:"sections.html#accordion"},{title:"Accordion mixin variables",filename:"sections",url:"sections.html#accordion-mixin-variables"},{title:"Responsive tabs",filename:"sections",url:"sections.html#responsive-tabs"},{title:"Tabs Base",filename:"sections",url:"sections.html#tabs-base"},{title:"Accordion Base",filename:"sections",url:"sections.html#accordion-base"},{title:"tables",filename:"tables",url:"tables.html"},{title:"Tables",filename:"tables",url:"tables.html#tables"},{title:"Table mixin variables",filename:"tables",url:"tables.html#table-mixin-variables"},{title:"Table typography",filename:"tables",url:"tables.html#table-typography"},{title:"Table typography mixin variables",filename:"tables",url:"tables.html#table-typography-mixin-variables"},{title:"Table caption",filename:"tables",url:"tables.html#table-caption"},{title:"Table caption mixin variables",filename:"tables",url:"tables.html#table-caption-mixin-variables"},{title:"Table cells resize",filename:"tables",url:"tables.html#table-cells-resize"},{title:"Table cells resize variables",filename:"tables",url:"tables.html#table-cells-resize-variables"},{title:"Table background customization",filename:"tables",url:"tables.html#table-background-customization"},{title:"Table background mixin variables",filename:"tables",url:"tables.html#table-background-mixin-variables"},{title:"Table borders customization",filename:"tables",url:"tables.html#table-borders-customization"},{title:"Table borders mixin variables",filename:"tables",url:"tables.html#table-borders-mixin-variables"},{title:"Table with horizontal borders",filename:"tables",url:"tables.html#table-with-horizontal-borders"},{title:"Table with vertical borders",filename:"tables",url:"tables.html#table-with-vertical-borders"},{title:"Table with light borders",filename:"tables",url:"tables.html#table-with-light-borders"},{title:"Table without borders",filename:"tables",url:"tables.html#table-without-borders"},{title:"Striped table",filename:"tables",url:"tables.html#striped-table"},{title:"Striped table mixin variables",filename:"tables",url:"tables.html#striped-table-mixin-variables"},{title:"Table with rows hover",filename:"tables",url:"tables.html#table-with-rows-hover"},{title:"Table with rows hover mixin variables",filename:"tables",url:"tables.html#table-with-rows-hover-mixin-variables"},{title:"Responsive table technics #1",filename:"tables",url:"tables.html#responsive-table-technics-1"},{title:"Responsive table technics #2",filename:"tables",url:"tables.html#responsive-table-technics-2"},{title:"Responsive table technics #2 mixin variables",filename:"tables",url:"tables.html#responsive-table-technics-2-mixin-variables"},{title:"tooltips",filename:"tooltips",url:"tooltips.html"},{title:"Tooltips",filename:"tooltips",url:"tooltips.html#tooltips"},{title:"Tooltips variables",filename:"tooltips",url:"tooltips.html#tooltips-variables"},{title:"typography",filename:"typography",url:"typography.html"},{title:"Typogrphy",filename:"typography",url:"typography.html#typogrphy"},{title:"Typography variables",filename:"typography",url:"typography.html#typography-variables"},{title:"Font-size mixin",filename:"typography",url:"typography.html#fontsize-mixin"},{title:"Line-height mixin",filename:"typography",url:"typography.html#lineheight-mixin"},{title:"Word breaking mixin",filename:"typography",url:"typography.html#word-breaking-mixin"},{title:"Font face mixin",filename:"typography",url:"typography.html#font-face-mixin"},{title:"Text overflow mixin",filename:"typography",url:"typography.html#text-overflow-mixin"},{title:"Text hide",filename:"typography",url:"typography.html#text-hide"},{title:"Hyphens",filename:"typography",url:"typography.html#hyphens"},{title:"Font style and color",filename:"typography",url:"typography.html#font-style-and-color"},{title:"Font style mixin variables",filename:"typography",url:"typography.html#font-style-mixin-variables"},{title:"Reset list styles",filename:"typography",url:"typography.html#reset-list-styles"},{title:"Reset list styles variables",filename:"typography",url:"typography.html#reset-list-styles-variables"},{title:"Inline-block list item styling",filename:"typography",url:"typography.html#inlineblock-list-item-styling"},{title:"Link styling mixin",filename:"typography",url:"typography.html#link-styling-mixin"},{title:"Link styling mixin variables",filename:"typography",url:"typography.html#link-styling-mixin-variables"},{title:"Heading styling mixin",filename:"typography",url:"typography.html#heading-styling-mixin"},{title:"Base typography mixins",filename:"typography",url:"typography.html#base-typography-mixins"},{title:"Base typography mixin variables",filename:"typography",url:"typography.html#base-typography-mixin-variables"},{title:"Headings typography mixin",filename:"typography",url:"typography.html#headings-typography-mixin"},{title:"Headings typography mixin variables",filename:"typography",url:"typography.html#headings-typography-mixin-variables"},{title:"Typography links mixin",filename:"typography",url:"typography.html#typography-links-mixin"},{title:"Typography lists mixin",filename:"typography",url:"typography.html#typography-lists-mixin"},{title:"Typography lists mixin variables",filename:"typography",url:"typography.html#typography-lists-mixin-variables"},{title:"Typography code elements mixin",filename:"typography",url:"typography.html#typography-code-elements-mixin"},{title:"Typography code mixin variables",filename:"typography",url:"typography.html#typography-code-mixin-variables"},{title:"Typography blockquote",filename:"typography",url:"typography.html#typography-blockquote"},{title:"Typography blockquote mixin variables",filename:"typography",url:"typography.html#typography-blockquote-mixin-variables"},{title:"utilities",filename:"utilities",url:"utilities.html"},{title:"Utilities",filename:"utilities",url:"utilities.html#utilities"},{title:".lib-clearfix()",filename:"utilities",url:"utilities.html#libclearfix"},{title:".lib-visibility-hidden()",filename:"utilities",url:"utilities.html#libvisibilityhidden"},{title:".lib-visually-hidden()",filename:"utilities",url:"utilities.html#libvisuallyhidden"},{title:".lib-visually-hidden-reset()",filename:"utilities",url:"utilities.html#libvisuallyhiddenreset"},{title:".lib-css()",filename:"utilities",url:"utilities.html#libcss"},{title:".lib-css() variables",filename:"utilities",url:"utilities.html#libcss-variables"},{title:".lib-rotate()",filename:"utilities",url:"utilities.html#librotate"},{title:".lib-rotate() variables",filename:"utilities",url:"utilities.html#librotate-variables"},{title:".lib-input-placeholder()",filename:"utilities",url:"utilities.html#libinputplaceholder"},{title:".lib-input-placeholder() variables",filename:"utilities",url:"utilities.html#libinputplaceholder-variables"},{title:".lib-background-gradient()",filename:"utilities",url:"utilities.html#libbackgroundgradient"},{title:".lib-background-gradient() variables",filename:"utilities",url:"utilities.html#libbackgroundgradient-variables"},{title:".lib-url-check()",filename:"utilities",url:"utilities.html#liburlcheck"},{title:".lib-url-check() variables",filename:"utilities",url:"utilities.html#liburlcheck-variables"},{title:"variables",filename:"variables",url:"variables.html"},{title:"List of Global Variables",filename:"variables",url:"variables.html#list-of-global-variables"},{title:"Table with rows hover mixin variables",filename:"variables",url:"variables.html#table-with-rows-hover-mixin-variables"},{title:"docs",filename:"docs",url:"docs.html"},{title:"Documentation",filename:"docs",url:"docs.html#documentation"}];(function(){"use strict";var b=function(a,b){return Array.prototype.indexOf.call(a,b)!==-1},c=function(a,b){return Array.prototype.filter.call(a,b)},d=function(a,b){return Array.prototype.forEach.call(a,b)},e=document.getElementsByTagName("body")[0];e.addEventListener("click",function(a){var b=a.target;b.tagName.toLowerCase()==="svg"&&(b=b.parentNode);var c=!1;b.dataset.toggle!=null&&(a.preventDefault(),b.classList.contains("is-active")||(c=!0)),d(e.querySelectorAll("[data-toggle]"),function(a){a.classList.remove("is-active"),document.getElementById(a.dataset.toggle).hidden=!0}),c&&(b.classList.add("is-active"),document.getElementById(b.dataset.toggle).hidden=!1)}),function(){var f=e.getElementsByClassName("nav")[0];if(!f)return;var g=document.createElement("ul");g.className="nav-results",g.id="nav-search",g.hidden=!0,d(a,function(a){var b,c,d;b=document.createElement("li"),b._title=a.title.toLowerCase(),b.hidden=!0,b.appendChild(c=document.createElement("a")),c.href=a.url,c.innerHTML=a.title,c.appendChild(d=document.createElement("span")),d.innerHTML=a.filename,d.className="nav-results-filename",g.appendChild(b)}),f.appendChild(g);var h=g.children,i=function(a){d(h,function(a){a.hidden=!0});var b=this.value.toLowerCase(),e=[];b!==""&&(e=c(h,function(a){return a._title.indexOf(b)!==-1})),e.length>0?(d(e,function(a){a.hidden=!1}),g.hidden=!1):g.hidden=!0},j=f.querySelector('input[type="search"]');j.addEventListener("keyup",i),j.addEventListener("focus",i),e.addEventListener("click",function(a){if(a.target.classList&&a.target.classList.contains("search"))return;g.hidden=!0}),g.addEventListener("click",function(a){j.value=""});var k=document.createElement("ul");k.id="nav-toc",k.hidden=!0,k.className="nav-results toc-list",c(e.getElementsByTagName("*"),function(a){return b(["h1","h2","h3"],a.tagName.toLowerCase())}).map(function(a){var b=document.createElement("li"),c=document.createElement("a"),d=a.tagName.toLowerCase()[1];c.classList.add("level-"+d),b.appendChild(c),c.href="#"+a.id,c.innerHTML=a.innerHTML,k.appendChild(b)}),f.appendChild(k)}()})(),function(){"use strict";if(location.hash==="#__preview__"||location.protocol==="data:")return;var a=function(a,b){return Array.prototype.forEach.call(a,b)},b=function(a,b){var e=Array.prototype.slice.call(arguments,2);return d(a,function(a){return(c(b)?b||a:a[b]).apply(a,e)})},c=function(a){return Object.prototype.toString.call(a)==="[object Function]"},d=function(a,b){return Array.prototype.map.call(a,b)},e=function(a,b){return d(a,function(a){return a[b]})},f=function(a){var b={},c=a.split(";");for(var d=0;c.length>d;d++){var e=c[d].trim().split("=");b[e[0]]=e[1]}return b},g=function(a,c){return b(e(a,"classList"),"remove",c)},h=function(a,b){a.contentDocument.defaultView.postMessage(b,"*")},i=document.getElementsByTagName("head")[0],j=document.getElementsByTagName("body")[0],k=e(i.querySelectorAll('style[type="text/preview"]'),"innerHTML").join(""),l=e(i.querySelectorAll('script[type="text/preview"]'),"innerHTML").join(""),m=location.href.split("#")[0]+"#__preview__",n=document.createElement("iframe");n.src="data:text/html,",j.appendChild(n),n.addEventListener("load",function(){var b={sameOriginDataUri:!0};try{this.contentDocument,this.contentDocument||(b.sameOriginDataUri=!1)}catch(c){b.sameOriginDataUri=!1}this.parentNode.removeChild(this),a(j.getElementsByTagName("textarea"),function(a,c){o(a,b,c),q(),p(a)})});var o=function(a,b,c){var d,e,f;d=document.createElement("div"),d.appendChild(e=document.createElement("div")),d.className="preview",e.appendChild(f=document.createElement("iframe")),e.className="resizeable",f.setAttribute("scrolling","no"),f.name="iframe"+c++,f.addEventListener("load",function(){var c,d,e,f,g,i,j;j=this.contentDocument;if(!b.sameOriginDataUri&&this.src!==m)return;this.src===m&&(c=j.createElement("html"),c.appendChild(j.createElement("head")),c.appendChild(d=j.createElement("body")),d.innerHTML=a.textContent,j.replaceChild(c,j.documentElement)),g=j.createElement("head"),g.appendChild(f=j.createElement("style")),g.appendChild(e=j.createElement("script")),e.textContent=l,f.textContent=k,i=j.getElementsByTagName("head")[0],i.parentNode.replaceChild(g,i),h(this,"getHeight")});var g;b.sameOriginDataUri?g="data:text/html;charset=utf-8,"+encodeURIComponent("<!doctype html><html><head></head></body>"+a.textContent):g=m,f.setAttribute("src",g);var i=function(){f.contentDocument.body.innerHTML=this.value,h(f,"getHeight")};a.addEventListener("keypress",i),a.addEventListener("keyup",i),a.parentNode.insertBefore(d,a)},p=function(a){var b=document.createElement("div");b.className="preview-code",b.style.position="absolute",b.style.left="-9999px",j.appendChild(b);var c=parseInt(window.getComputedStyle(a).getPropertyValue("max-height"),10),d=function(a){b.textContent=this.value+"\n";var d=b.offsetHeight+2;d>=c?this.style.overflow="auto":this.style.overflow="hidden",this.style.height=b.offsetHeight+2+"px"};a.addEventListener("keypress",d),a.addEventListener("keyup",d),d.call(a)},q=function(){var b=j.getElementsByClassName("settings")[0],c=j.getElementsByClassName("resizeable"),d=30,e=function(b){document.cookie="preview-width="+b,a(c,function(a){b==="auto"&&(b=a.parentNode.offsetWidth),a.style.width=b+"px",h(a.getElementsByTagName("iframe")[0],"getHeight")})},i=f(document.cookie)["preview-width"];if(i){e(i),g(b.getElementsByClassName("is-active"),"is-active");var k=b.querySelector('button[data-width="'+i+'"]');k&&k.classList.add("is-active")}window.addEventListener("message",function(a){if(a.data==null||!a.source)return;var b=a.data,c=document.getElementsByName(a.source.name)[0];b.height!=null&&c&&(c.parentNode.style.height=b.height+d+"px")},!1),b&&c.length>0&&(b.hidden=!1,b.addEventListener("click",function(a){var c=a.target.tagName.toLowerCase(),d;if(c==="button")d=a.target;else{if(c!=="svg")return;d=a.target.parentNode}a.preventDefault(),g(b.getElementsByClassName("is-active"),"is-active"),d.classList.add("is-active");var f=d.dataset.width;e(f)}))}}()})()</script></body></html><!-- Generated with StyleDocco (http://jacobrask.github.com/styledocco). --> +}</code></pre></div></article></section><div class="bar bottom"><div hidden class="settings container"><!-- Icons from http://iconmonstr.com--><button title="Desktop (1280)" data-width='1280'><svg viewBox="0 0 412 386" height="24" width="26" class="icon"><path d="m147.6,343.9c-4.5,15.9-26.2,37.6-42.1,42.1h201c-15.3,-4-38.1,-26.8-42.1,-42.1H147.6zM387,0.5H25c-13.8,0-25,11.2-25,25V294c0,13.8 11.2,25 25,25h362c13.8,0 25,-11.2 25,-25V25.5C412,11.7 400.8,0.5 387,0.5zM369.9,238.2H42.1L42.1,42.6 369.9,42.6V238.2z"></path></svg></button><button title="Laptop (1024)" data-width='1024'><svg viewBox="0 0 384 312" height="23" width="28" class="icon"><path d="m349.2,20.5c0,-11-9,-20-20,-20H53.6c-11,0-20,9-20,20v194H349.2v-194zm-27,167H60.6V27.5H322.2v160zm28,42H32.6L2.6,282.1c-3.5,6.2-3.5,13.8 0.1,19.9 3.6,6.2 10.2,9.9 17.3,9.9H363.1c7.1,0 13.7,-3.8 17.3,-10 3.6,-6.2 3.6,-13.8 0,-20l-30.2,-52.5zm-196.9,54 8,-23.5h60.5l8,23.5h-76.5z"></path></svg></button><button title="Tablet (768)" data-width='768'><svg viewBox="0 0 317 412" height="24" width="18" class="icon"><path d="M 316.5,380 V 32 c 0,-17.7 -14.3,-32 -32,-32 H 32 C 14.3,0 0,14.3 0,32 v 348 c 0,17.7 14.3,32 32,32 h 252.5 c 17.7,0 32,-14.3 32,-32 z M 40,367 V 45 H 276.5 V 367 H 40 z m 109.8,22.7 c 0,-4.7 3.8,-8.5 8.5,-8.5 4.7,0 8.5,3.8 8.5,8.5 0,4.7 -3.8,8.5 -8.5,8.5 -4.7,0 -8.5,-3.8 -8.5,-8.5 z"></path></svg></button><button title="Smart phone (320)" data-width='320'><svg viewBox="0 0 224 412" height="24" width="13" class="icon"><path d="M 190.7,0 H 33 C 14.8,0 0,14.8 0,33 v 346 c 0,18.2 14.8,33 33,33 h 157.7 c 18.2,0 33,-14.8 33,-33 V 33 c 0,-18.2 -14.8,-33 -33,-33 z M 94.3,30.2 h 37 c 2.2,0 4,1.8 4,4 0,2.2 -1.8,4 -4,4 h -37 c -2.2,0 -4,-1.8 -4,-4 0,-2.2 1.8,-4 4,-4 z m 18.5,362.8 c -8.8,0 -16,-7.2 -16,-16 0,-8.8 7.2,-16 16,-16 8.8,0 16,7.2 16,16 0,8.8 -7.2,16 -16,16 z M 198.6,343.8 H 25.1 V 68.2 h 173.5 v 275.5 z"></path></svg></button><button title="Feature phone (240)" data-width='240'><svg viewBox="0 0 201 412" height="24" width="12" class="icon"><path d="M 165.5,0.2 V 45 H 25 c -13.8,0 -25,11.2 -25,25 V 387 c 0,13.8 11.2,25 25,25 h 150.5 c 13.8,0 25,-11.2 25,-25 V 0.2 h -35 z M 65.2,366.5 H 34.2 v -24.5 h 31 v 24.5 z m 0,-44.3 H 34.2 v -24.5 h 31 v 24.5 z m 50.5,44.3 H 84.7 v -24.5 h 31 v 24.5 z m 0,-44.3 H 84.7 v -24.5 h 31 v 24.5 z m 50.5,44.3 h -31 v -24.5 h 31 v 24.5 z m 0,-44.3 h -31 v -24.5 h 31 v 24.5 z m 0,-59.3 h -132 V 95.4 h 132 V 262.9 z"></path></svg></button><button title="Auto (100%)" data-width="auto" class="auto is-active">Auto</button></div></div><script>(function(){var a=[{title:"actions-toolbar",filename:"actions-toolbar",url:"actions-toolbar.html"},{title:"Actions toolbar",filename:"actions-toolbar",url:"actions-toolbar.html#actions-toolbar"},{title:"Actions toolbar mixin variables",filename:"actions-toolbar",url:"actions-toolbar.html#actions-toolbar-mixin-variables"},{title:"Actions toolbar alignment",filename:"actions-toolbar",url:"actions-toolbar.html#actions-toolbar-alignment"},{title:"Reverse primary and secondary blocks",filename:"actions-toolbar",url:"actions-toolbar.html#reverse-primary-and-secondary-blocks"},{title:"Actions toolbar indents customizations",filename:"actions-toolbar",url:"actions-toolbar.html#actions-toolbar-indents-customizations"},{title:"Responsive actions toolbar",filename:"actions-toolbar",url:"actions-toolbar.html#responsive-actions-toolbar"},{title:"breadcrumbs",filename:"breadcrumbs",url:"breadcrumbs.html"},{title:"Breadcrumbs",filename:"breadcrumbs",url:"breadcrumbs.html#breadcrumbs"},{title:"Breadcrumbs variables",filename:"breadcrumbs",url:"breadcrumbs.html#breadcrumbs-variables"},{title:"Button-styled breadcrumbs with gradient background, border, and no separating symbol",filename:"breadcrumbs",url:"breadcrumbs.html#buttonstyled-breadcrumbs-with-gradient-background-border-and-no-separating-symbol"},{title:"Breadcrumbs with solid background",filename:"breadcrumbs",url:"breadcrumbs.html#breadcrumbs-with-solid-background"},{title:"buttons",filename:"buttons",url:"buttons.html"},{title:"Default button",filename:"buttons",url:"buttons.html#default-button"},{title:"Button variables",filename:"buttons",url:"buttons.html#button-variables"},{title:"Button as an icon",filename:"buttons",url:"buttons.html#button-as-an-icon"},{title:"Button with an icon on the left or right side of the text",filename:"buttons",url:"buttons.html#button-with-an-icon-on-the-left-or-right-side-of-the-text"},{title:"Button with fixed width",filename:"buttons",url:"buttons.html#button-with-fixed-width"},{title:"Primary button",filename:"buttons",url:"buttons.html#primary-button"},{title:"Primary button variables",filename:"buttons",url:"buttons.html#primary-button-variables"},{title:"Button with gradient background",filename:"buttons",url:"buttons.html#button-with-gradient-background"},{title:"Button as a link",filename:"buttons",url:"buttons.html#button-as-a-link"},{title:"Button as a link variables",filename:"buttons",url:"buttons.html#button-as-a-link-variables"},{title:"Link as a button",filename:"buttons",url:"buttons.html#link-as-a-button"},{title:"Button reset",filename:"buttons",url:"buttons.html#button-reset"},{title:"Button revert secondary color",filename:"buttons",url:"buttons.html#button-revert-secondary-color"},{title:"Button revert secondary color variables",filename:"buttons",url:"buttons.html#button-revert-secondary-color-variables"},{title:"Button revert secondary size",filename:"buttons",url:"buttons.html#button-revert-secondary-size"},{title:"Button revert secondary size variables",filename:"buttons",url:"buttons.html#button-revert-secondary-size-variables"},{title:"components",filename:"components",url:"components.html"},{title:"Components",filename:"components",url:"components.html#components"},{title:"Components Variables",filename:"components",url:"components.html#components-variables"},{title:"dropdowns",filename:"dropdowns",url:"dropdowns.html"},{title:"Drop-down and split buttons mixins",filename:"dropdowns",url:"dropdowns.html#dropdown-and-split-buttons-mixins"},{title:"Drop-down",filename:"dropdowns",url:"dropdowns.html#dropdown"},{title:"Drop-down variables",filename:"dropdowns",url:"dropdowns.html#dropdown-variables"},{title:"Drop-down with icon customization",filename:"dropdowns",url:"dropdowns.html#dropdown-with-icon-customization"},{title:"Modify dropdown list styles",filename:"dropdowns",url:"dropdowns.html#modify-dropdown-list-styles"},{title:"Split button",filename:"dropdowns",url:"dropdowns.html#split-button"},{title:"Split button variables",filename:"dropdowns",url:"dropdowns.html#split-button-variables"},{title:"Split button - button styling",filename:"dropdowns",url:"dropdowns.html#split-button-button-styling"},{title:"Split button icon customization",filename:"dropdowns",url:"dropdowns.html#split-button-icon-customization"},{title:"Split button drop-down list customization",filename:"dropdowns",url:"dropdowns.html#split-button-dropdown-list-customization"},{title:"forms",filename:"forms",url:"forms.html"},{title:"Forms mixins",filename:"forms",url:"forms.html#forms-mixins"},{title:"Global forms elements customization",filename:"forms",url:"forms.html#global-forms-elements-customization"},{title:"Fieldsets & fields customization",filename:"forms",url:"forms.html#fieldsets-fields-customization"},{title:"Fieldset and legend customization variables",filename:"forms",url:"forms.html#fieldset-and-legend-customization-variables"},{title:"Fields customization variables",filename:"forms",url:"forms.html#fields-customization-variables"},{title:"Required fields message customization variables",filename:"forms",url:"forms.html#required-fields-message-customization-variables"},{title:"Form element inputs customization",filename:"forms",url:"forms.html#form-element-inputs-customization"},{title:"Form element inputs customization variables",filename:"forms",url:"forms.html#form-element-inputs-customization-variables"},{title:"Form element choice",filename:"forms",url:"forms.html#form-element-choice"},{title:"Form element choice variables",filename:"forms",url:"forms.html#form-element-choice-variables"},{title:"Custom color",filename:"forms",url:"forms.html#custom-color"},{title:"Input number - input-text view",filename:"forms",url:"forms.html#input-number-inputtext-view"},{title:"Input search - input-text view",filename:"forms",url:"forms.html#input-search-inputtext-view"},{title:"Form validation",filename:"forms",url:"forms.html#form-validation"},{title:"Form validation variables",filename:"forms",url:"forms.html#form-validation-variables"},{title:"icons",filename:"icons",url:"icons.html"},{title:"Icons",filename:"icons",url:"icons.html#icons"},{title:"Icon with image or sprite",filename:"icons",url:"icons.html#icon-with-image-or-sprite"},{title:"Icon with image or sprite variables",filename:"icons",url:"icons.html#icon-with-image-or-sprite-variables"},{title:"Icon position for an icon with image or sprite",filename:"icons",url:"icons.html#icon-position-for-an-icon-with-image-or-sprite"},{title:"Position for icon with image or sprite mixin variables",filename:"icons",url:"icons.html#position-for-icon-with-image-or-sprite-mixin-variables"},{title:"Icon sprite position (with grid)",filename:"icons",url:"icons.html#icon-sprite-position-with-grid"},{title:"Icon sprite position variables",filename:"icons",url:"icons.html#icon-sprite-position-variables"},{title:"Image/sprite icon size",filename:"icons",url:"icons.html#imagesprite-icon-size"},{title:"Image/sprite icon size variables",filename:"icons",url:"icons.html#imagesprite-icon-size-variables"},{title:"Font icon",filename:"icons",url:"icons.html#font-icon"},{title:"Font icon variables",filename:"icons",url:"icons.html#font-icon-variables"},{title:"Change the size of font icon",filename:"icons",url:"icons.html#change-the-size-of-font-icon"},{title:"Change the size of font icon variables",filename:"icons",url:"icons.html#change-the-size-of-font-icon-variables"},{title:"Hide icon text",filename:"icons",url:"icons.html#hide-icon-text"},{title:"Sprite and font icons for Blank theme",filename:"icons",url:"icons.html#sprite-and-font-icons-for-blank-theme"},{title:"layout",filename:"layout",url:"layout.html"},{title:"Layout",filename:"layout",url:"layout.html#layout"},{title:"Layout global variables",filename:"layout",url:"layout.html#layout-global-variables"},{title:"Page layouts",filename:"layout",url:"layout.html#page-layouts"},{title:"Layout column",filename:"layout",url:"layout.html#layout-column"},{title:"Layout column variables",filename:"layout",url:"layout.html#layout-column-variables"},{title:"Layout width",filename:"layout",url:"layout.html#layout-width"},{title:"Layout width variables",filename:"layout",url:"layout.html#layout-width-variables"},{title:"lib",filename:"lib",url:"lib.html"},{title:"Including Magento UI library to your theme",filename:"lib",url:"lib.html#including-magento-ui-library-to-your-theme"},{title:"loaders",filename:"loaders",url:"loaders.html"},{title:"Loaders",filename:"loaders",url:"loaders.html#loaders"},{title:"Default loader variables",filename:"loaders",url:"loaders.html#default-loader-variables"},{title:"Loading",filename:"loaders",url:"loaders.html#loading"},{title:"Loading default variables",filename:"loaders",url:"loaders.html#loading-default-variables"},{title:"messages",filename:"messages",url:"messages.html"},{title:"Messages",filename:"messages",url:"messages.html#messages"},{title:"Information message",filename:"messages",url:"messages.html#information-message"},{title:"Warning message",filename:"messages",url:"messages.html#warning-message"},{title:"Error message",filename:"messages",url:"messages.html#error-message"},{title:"Success message",filename:"messages",url:"messages.html#success-message"},{title:"Notice message",filename:"messages",url:"messages.html#notice-message"},{title:"Message with inner icon",filename:"messages",url:"messages.html#message-with-inner-icon"},{title:"Message with lateral icon",filename:"messages",url:"messages.html#message-with-lateral-icon"},{title:"Custom message style",filename:"messages",url:"messages.html#custom-message-style"},{title:"Messages global variables",filename:"messages",url:"messages.html#messages-global-variables"},{title:"pages",filename:"pages",url:"pages.html"},{title:"Pagination HTML markup",filename:"pages",url:"pages.html#pagination-html-markup"},{title:"Pagination variables",filename:"pages",url:"pages.html#pagination-variables"},{title:"Pagination with label and gradient background on links",filename:"pages",url:"pages.html#pagination-with-label-and-gradient-background-on-links"},{title:'Pagination with "previous"..."next" text links and label',filename:"pages",url:"pages.html#pagination-with-previousnext-text-links-and-label"},{title:"Pagination without label, with solid background",filename:"pages",url:"pages.html#pagination-without-label-with-solid-background"},{title:"popups",filename:"popups",url:"popups.html"},{title:"Popups",filename:"popups",url:"popups.html#popups"},{title:"Popup variables",filename:"popups",url:"popups.html#popup-variables"},{title:"Window overlay mixin variables",filename:"popups",url:"popups.html#window-overlay-mixin-variables"},{title:"Fixed height popup",filename:"popups",url:"popups.html#fixed-height-popup"},{title:"Fixed content height popup",filename:"popups",url:"popups.html#fixed-content-height-popup"},{title:"Margins for header, content and footer block in popup",filename:"popups",url:"popups.html#margins-for-header-content-and-footer-block-in-popup"},{title:"Popup titles styled as theme headings",filename:"popups",url:"popups.html#popup-titles-styled-as-theme-headings"},{title:"Popup action toolbar",filename:"popups",url:"popups.html#popup-action-toolbar"},{title:"Popup Close button without an icon",filename:"popups",url:"popups.html#popup-close-button-without-an-icon"},{title:"Modify the icon of popup Close button",filename:"popups",url:"popups.html#modify-the-icon-of-popup-close-button"},{title:"Modify overlay styles",filename:"popups",url:"popups.html#modify-overlay-styles"},{title:"rating",filename:"rating",url:"rating.html"},{title:"Ratings",filename:"rating",url:"rating.html#ratings"},{title:"Global rating variables",filename:"rating",url:"rating.html#global-rating-variables"},{title:"Rating with vote",filename:"rating",url:"rating.html#rating-with-vote"},{title:"Rating with vote icons number customization",filename:"rating",url:"rating.html#rating-with-vote-icons-number-customization"},{title:"Rating with vote icons colors customization",filename:"rating",url:"rating.html#rating-with-vote-icons-colors-customization"},{title:"Rating with vote icons symbol customization",filename:"rating",url:"rating.html#rating-with-vote-icons-symbol-customization"},{title:"Accessible rating with vote",filename:"rating",url:"rating.html#accessible-rating-with-vote"},{title:"Rating summary",filename:"rating",url:"rating.html#rating-summary"},{title:"Rating summary icons number customization",filename:"rating",url:"rating.html#rating-summary-icons-number-customization"},{title:"Rating summary icons color customization",filename:"rating",url:"rating.html#rating-summary-icons-color-customization"},{title:"Rating summary icons symbol customization",filename:"rating",url:"rating.html#rating-summary-icons-symbol-customization"},{title:"Rating summary hide label",filename:"rating",url:"rating.html#rating-summary-hide-label"},{title:"Rating summary multiple ratings",filename:"rating",url:"rating.html#rating-summary-multiple-ratings"},{title:"Rating hide label mixin",filename:"rating",url:"rating.html#rating-hide-label-mixin"},{title:"resets",filename:"resets",url:"resets.html"},{title:"Resets",filename:"resets",url:"resets.html#resets"},{title:"responsive",filename:"responsive",url:"responsive.html"},{title:"Responsive",filename:"responsive",url:"responsive.html#responsive"},{title:"Responsive mixins usage",filename:"responsive",url:"responsive.html#responsive-mixins-usage"},{title:"Media query style groups separation variables",filename:"responsive",url:"responsive.html#media-query-style-groups-separation-variables"},{title:"Responsive breakpoints",filename:"responsive",url:"responsive.html#responsive-breakpoints"},{title:"sections",filename:"sections",url:"sections.html"},{title:"Tabs and accordions",filename:"sections",url:"sections.html#tabs-and-accordions"},{title:"Tabs",filename:"sections",url:"sections.html#tabs"},{title:"Tabs mixin variables",filename:"sections",url:"sections.html#tabs-mixin-variables"},{title:"Tabs with content top border",filename:"sections",url:"sections.html#tabs-with-content-top-border"},{title:"Accordion",filename:"sections",url:"sections.html#accordion"},{title:"Accordion mixin variables",filename:"sections",url:"sections.html#accordion-mixin-variables"},{title:"Responsive tabs",filename:"sections",url:"sections.html#responsive-tabs"},{title:"Tabs Base",filename:"sections",url:"sections.html#tabs-base"},{title:"Accordion Base",filename:"sections",url:"sections.html#accordion-base"},{title:"tables",filename:"tables",url:"tables.html"},{title:"Tables",filename:"tables",url:"tables.html#tables"},{title:"Table mixin variables",filename:"tables",url:"tables.html#table-mixin-variables"},{title:"Table typography",filename:"tables",url:"tables.html#table-typography"},{title:"Table typography mixin variables",filename:"tables",url:"tables.html#table-typography-mixin-variables"},{title:"Table caption",filename:"tables",url:"tables.html#table-caption"},{title:"Table caption mixin variables",filename:"tables",url:"tables.html#table-caption-mixin-variables"},{title:"Table cells resize",filename:"tables",url:"tables.html#table-cells-resize"},{title:"Table cells resize variables",filename:"tables",url:"tables.html#table-cells-resize-variables"},{title:"Table background customization",filename:"tables",url:"tables.html#table-background-customization"},{title:"Table background mixin variables",filename:"tables",url:"tables.html#table-background-mixin-variables"},{title:"Table borders customization",filename:"tables",url:"tables.html#table-borders-customization"},{title:"Table borders mixin variables",filename:"tables",url:"tables.html#table-borders-mixin-variables"},{title:"Table with horizontal borders",filename:"tables",url:"tables.html#table-with-horizontal-borders"},{title:"Table with vertical borders",filename:"tables",url:"tables.html#table-with-vertical-borders"},{title:"Table with light borders",filename:"tables",url:"tables.html#table-with-light-borders"},{title:"Table without borders",filename:"tables",url:"tables.html#table-without-borders"},{title:"Striped table",filename:"tables",url:"tables.html#striped-table"},{title:"Striped table mixin variables",filename:"tables",url:"tables.html#striped-table-mixin-variables"},{title:"Table with rows hover",filename:"tables",url:"tables.html#table-with-rows-hover"},{title:"Table with rows hover mixin variables",filename:"tables",url:"tables.html#table-with-rows-hover-mixin-variables"},{title:"Responsive table technics #1",filename:"tables",url:"tables.html#responsive-table-technics-1"},{title:"Responsive table technics #2",filename:"tables",url:"tables.html#responsive-table-technics-2"},{title:"Responsive table technics #2 mixin variables",filename:"tables",url:"tables.html#responsive-table-technics-2-mixin-variables"},{title:"tooltips",filename:"tooltips",url:"tooltips.html"},{title:"Tooltips",filename:"tooltips",url:"tooltips.html#tooltips"},{title:"Tooltips variables",filename:"tooltips",url:"tooltips.html#tooltips-variables"},{title:"typography",filename:"typography",url:"typography.html"},{title:"Typogrphy",filename:"typography",url:"typography.html#typogrphy"},{title:"Typography variables",filename:"typography",url:"typography.html#typography-variables"},{title:"Font-size mixin",filename:"typography",url:"typography.html#fontsize-mixin"},{title:"Line-height mixin",filename:"typography",url:"typography.html#lineheight-mixin"},{title:"Word breaking mixin",filename:"typography",url:"typography.html#word-breaking-mixin"},{title:"Font face mixin",filename:"typography",url:"typography.html#font-face-mixin"},{title:"Text overflow mixin",filename:"typography",url:"typography.html#text-overflow-mixin"},{title:"Text hide",filename:"typography",url:"typography.html#text-hide"},{title:"Hyphens",filename:"typography",url:"typography.html#hyphens"},{title:"Font style and color",filename:"typography",url:"typography.html#font-style-and-color"},{title:"Font style mixin variables",filename:"typography",url:"typography.html#font-style-mixin-variables"},{title:"Reset list styles",filename:"typography",url:"typography.html#reset-list-styles"},{title:"Reset list styles variables",filename:"typography",url:"typography.html#reset-list-styles-variables"},{title:"Inline-block list item styling",filename:"typography",url:"typography.html#inlineblock-list-item-styling"},{title:"Link styling mixin",filename:"typography",url:"typography.html#link-styling-mixin"},{title:"Link styling mixin variables",filename:"typography",url:"typography.html#link-styling-mixin-variables"},{title:"Heading styling mixin",filename:"typography",url:"typography.html#heading-styling-mixin"},{title:"Base typography mixins",filename:"typography",url:"typography.html#base-typography-mixins"},{title:"Base typography mixin variables",filename:"typography",url:"typography.html#base-typography-mixin-variables"},{title:"Headings typography mixin",filename:"typography",url:"typography.html#headings-typography-mixin"},{title:"Headings typography mixin variables",filename:"typography",url:"typography.html#headings-typography-mixin-variables"},{title:"Typography links mixin",filename:"typography",url:"typography.html#typography-links-mixin"},{title:"Typography lists mixin",filename:"typography",url:"typography.html#typography-lists-mixin"},{title:"Typography lists mixin variables",filename:"typography",url:"typography.html#typography-lists-mixin-variables"},{title:"Typography code elements mixin",filename:"typography",url:"typography.html#typography-code-elements-mixin"},{title:"Typography code mixin variables",filename:"typography",url:"typography.html#typography-code-mixin-variables"},{title:"Typography blockquote",filename:"typography",url:"typography.html#typography-blockquote"},{title:"Typography blockquote mixin variables",filename:"typography",url:"typography.html#typography-blockquote-mixin-variables"},{title:"utilities",filename:"utilities",url:"utilities.html"},{title:"Utilities",filename:"utilities",url:"utilities.html#utilities"},{title:".lib-clearfix()",filename:"utilities",url:"utilities.html#libclearfix"},{title:".lib-visibility-hidden()",filename:"utilities",url:"utilities.html#libvisibilityhidden"},{title:".lib-visually-hidden()",filename:"utilities",url:"utilities.html#libvisuallyhidden"},{title:".lib-visually-hidden-reset()",filename:"utilities",url:"utilities.html#libvisuallyhiddenreset"},{title:".lib-css()",filename:"utilities",url:"utilities.html#libcss"},{title:".lib-css() variables",filename:"utilities",url:"utilities.html#libcss-variables"},{title:".lib-rotate()",filename:"utilities",url:"utilities.html#librotate"},{title:".lib-rotate() variables",filename:"utilities",url:"utilities.html#librotate-variables"},{title:".lib-input-placeholder()",filename:"utilities",url:"utilities.html#libinputplaceholder"},{title:".lib-input-placeholder() variables",filename:"utilities",url:"utilities.html#libinputplaceholder-variables"},{title:".lib-background-gradient()",filename:"utilities",url:"utilities.html#libbackgroundgradient"},{title:".lib-background-gradient() variables",filename:"utilities",url:"utilities.html#libbackgroundgradient-variables"},{title:"variables",filename:"variables",url:"variables.html"},{title:"List of Global Variables",filename:"variables",url:"variables.html#list-of-global-variables"},{title:"Table with rows hover mixin variables",filename:"variables",url:"variables.html#table-with-rows-hover-mixin-variables"},{title:"docs",filename:"docs",url:"docs.html"},{title:"Documentation",filename:"docs",url:"docs.html#documentation"}];(function(){"use strict";var b=function(a,b){return Array.prototype.indexOf.call(a,b)!==-1},c=function(a,b){return Array.prototype.filter.call(a,b)},d=function(a,b){return Array.prototype.forEach.call(a,b)},e=document.getElementsByTagName("body")[0];e.addEventListener("click",function(a){var b=a.target;b.tagName.toLowerCase()==="svg"&&(b=b.parentNode);var c=!1;b.dataset.toggle!=null&&(a.preventDefault(),b.classList.contains("is-active")||(c=!0)),d(e.querySelectorAll("[data-toggle]"),function(a){a.classList.remove("is-active"),document.getElementById(a.dataset.toggle).hidden=!0}),c&&(b.classList.add("is-active"),document.getElementById(b.dataset.toggle).hidden=!1)}),function(){var f=e.getElementsByClassName("nav")[0];if(!f)return;var g=document.createElement("ul");g.className="nav-results",g.id="nav-search",g.hidden=!0,d(a,function(a){var b,c,d;b=document.createElement("li"),b._title=a.title.toLowerCase(),b.hidden=!0,b.appendChild(c=document.createElement("a")),c.href=a.url,c.innerHTML=a.title,c.appendChild(d=document.createElement("span")),d.innerHTML=a.filename,d.className="nav-results-filename",g.appendChild(b)}),f.appendChild(g);var h=g.children,i=function(a){d(h,function(a){a.hidden=!0});var b=this.value.toLowerCase(),e=[];b!==""&&(e=c(h,function(a){return a._title.indexOf(b)!==-1})),e.length>0?(d(e,function(a){a.hidden=!1}),g.hidden=!1):g.hidden=!0},j=f.querySelector('input[type="search"]');j.addEventListener("keyup",i),j.addEventListener("focus",i),e.addEventListener("click",function(a){if(a.target.classList&&a.target.classList.contains("search"))return;g.hidden=!0}),g.addEventListener("click",function(a){j.value=""});var k=document.createElement("ul");k.id="nav-toc",k.hidden=!0,k.className="nav-results toc-list",c(e.getElementsByTagName("*"),function(a){return b(["h1","h2","h3"],a.tagName.toLowerCase())}).map(function(a){var b=document.createElement("li"),c=document.createElement("a"),d=a.tagName.toLowerCase()[1];c.classList.add("level-"+d),b.appendChild(c),c.href="#"+a.id,c.innerHTML=a.innerHTML,k.appendChild(b)}),f.appendChild(k)}()})(),function(){"use strict";if(location.hash==="#__preview__"||location.protocol==="data:")return;var a=function(a,b){return Array.prototype.forEach.call(a,b)},b=function(a,b){var e=Array.prototype.slice.call(arguments,2);return d(a,function(a){return(c(b)?b||a:a[b]).apply(a,e)})},c=function(a){return Object.prototype.toString.call(a)==="[object Function]"},d=function(a,b){return Array.prototype.map.call(a,b)},e=function(a,b){return d(a,function(a){return a[b]})},f=function(a){var b={},c=a.split(";");for(var d=0;c.length>d;d++){var e=c[d].trim().split("=");b[e[0]]=e[1]}return b},g=function(a,c){return b(e(a,"classList"),"remove",c)},h=function(a,b){a.contentDocument.defaultView.postMessage(b,"*")},i=document.getElementsByTagName("head")[0],j=document.getElementsByTagName("body")[0],k=e(i.querySelectorAll('style[type="text/preview"]'),"innerHTML").join(""),l=e(i.querySelectorAll('script[type="text/preview"]'),"innerHTML").join(""),m=location.href.split("#")[0]+"#__preview__",n=document.createElement("iframe");n.src="data:text/html,",j.appendChild(n),n.addEventListener("load",function(){var b={sameOriginDataUri:!0};try{this.contentDocument,this.contentDocument||(b.sameOriginDataUri=!1)}catch(c){b.sameOriginDataUri=!1}this.parentNode.removeChild(this),a(j.getElementsByTagName("textarea"),function(a,c){o(a,b,c),q(),p(a)})});var o=function(a,b,c){var d,e,f;d=document.createElement("div"),d.appendChild(e=document.createElement("div")),d.className="preview",e.appendChild(f=document.createElement("iframe")),e.className="resizeable",f.setAttribute("scrolling","no"),f.name="iframe"+c++,f.addEventListener("load",function(){var c,d,e,f,g,i,j;j=this.contentDocument;if(!b.sameOriginDataUri&&this.src!==m)return;this.src===m&&(c=j.createElement("html"),c.appendChild(j.createElement("head")),c.appendChild(d=j.createElement("body")),d.innerHTML=a.textContent,j.replaceChild(c,j.documentElement)),g=j.createElement("head"),g.appendChild(f=j.createElement("style")),g.appendChild(e=j.createElement("script")),e.textContent=l,f.textContent=k,i=j.getElementsByTagName("head")[0],i.parentNode.replaceChild(g,i),h(this,"getHeight")});var g;b.sameOriginDataUri?g="data:text/html;charset=utf-8,"+encodeURIComponent("<!doctype html><html><head></head></body>"+a.textContent):g=m,f.setAttribute("src",g);var i=function(){f.contentDocument.body.innerHTML=this.value,h(f,"getHeight")};a.addEventListener("keypress",i),a.addEventListener("keyup",i),a.parentNode.insertBefore(d,a)},p=function(a){var b=document.createElement("div");b.className="preview-code",b.style.position="absolute",b.style.left="-9999px",j.appendChild(b);var c=parseInt(window.getComputedStyle(a).getPropertyValue("max-height"),10),d=function(a){b.textContent=this.value+"\n";var d=b.offsetHeight+2;d>=c?this.style.overflow="auto":this.style.overflow="hidden",this.style.height=b.offsetHeight+2+"px"};a.addEventListener("keypress",d),a.addEventListener("keyup",d),d.call(a)},q=function(){var b=j.getElementsByClassName("settings")[0],c=j.getElementsByClassName("resizeable"),d=30,e=function(b){document.cookie="preview-width="+b,a(c,function(a){b==="auto"&&(b=a.parentNode.offsetWidth),a.style.width=b+"px",h(a.getElementsByTagName("iframe")[0],"getHeight")})},i=f(document.cookie)["preview-width"];if(i){e(i),g(b.getElementsByClassName("is-active"),"is-active");var k=b.querySelector('button[data-width="'+i+'"]');k&&k.classList.add("is-active")}window.addEventListener("message",function(a){if(a.data==null||!a.source)return;var b=a.data,c=document.getElementsByName(a.source.name)[0];b.height!=null&&c&&(c.parentNode.style.height=b.height+d+"px")},!1),b&&c.length>0&&(b.hidden=!1,b.addEventListener("click",function(a){var c=a.target.tagName.toLowerCase(),d;if(c==="button")d=a.target;else{if(c!=="svg")return;d=a.target.parentNode}a.preventDefault(),g(b.getElementsByClassName("is-active"),"is-active"),d.classList.add("is-active");var f=d.dataset.width;e(f)}))}}()})()</script></body></html><!-- Generated with StyleDocco (http://jacobrask.github.com/styledocco). --> diff --git a/lib/web/css/docs/dropdowns.html b/lib/web/css/docs/dropdowns.html index 6f0c95a723beb..eb9efc9a65078 100644 --- a/lib/web/css/docs/dropdowns.html +++ b/lib/web/css/docs/dropdowns.html @@ -876,4 +876,4 @@ <h2 id="split-button-buttonbutton">Split button: button+button</h2> @_dropdown-split-list-shadow: none, @_dropdown-split-button-border-radius-fix: true ); -}</code></pre></div></article></section><div class="bar bottom"><div hidden class="settings container"><!-- Icons from http://iconmonstr.com--><button title="Desktop (1280)" data-width='1280'><svg viewBox="0 0 412 386" height="24" width="26" class="icon"><path d="m147.6,343.9c-4.5,15.9-26.2,37.6-42.1,42.1h201c-15.3,-4-38.1,-26.8-42.1,-42.1H147.6zM387,0.5H25c-13.8,0-25,11.2-25,25V294c0,13.8 11.2,25 25,25h362c13.8,0 25,-11.2 25,-25V25.5C412,11.7 400.8,0.5 387,0.5zM369.9,238.2H42.1L42.1,42.6 369.9,42.6V238.2z"></path></svg></button><button title="Laptop (1024)" data-width='1024'><svg viewBox="0 0 384 312" height="23" width="28" class="icon"><path d="m349.2,20.5c0,-11-9,-20-20,-20H53.6c-11,0-20,9-20,20v194H349.2v-194zm-27,167H60.6V27.5H322.2v160zm28,42H32.6L2.6,282.1c-3.5,6.2-3.5,13.8 0.1,19.9 3.6,6.2 10.2,9.9 17.3,9.9H363.1c7.1,0 13.7,-3.8 17.3,-10 3.6,-6.2 3.6,-13.8 0,-20l-30.2,-52.5zm-196.9,54 8,-23.5h60.5l8,23.5h-76.5z"></path></svg></button><button title="Tablet (768)" data-width='768'><svg viewBox="0 0 317 412" height="24" width="18" class="icon"><path d="M 316.5,380 V 32 c 0,-17.7 -14.3,-32 -32,-32 H 32 C 14.3,0 0,14.3 0,32 v 348 c 0,17.7 14.3,32 32,32 h 252.5 c 17.7,0 32,-14.3 32,-32 z M 40,367 V 45 H 276.5 V 367 H 40 z m 109.8,22.7 c 0,-4.7 3.8,-8.5 8.5,-8.5 4.7,0 8.5,3.8 8.5,8.5 0,4.7 -3.8,8.5 -8.5,8.5 -4.7,0 -8.5,-3.8 -8.5,-8.5 z"></path></svg></button><button title="Smart phone (320)" data-width='320'><svg viewBox="0 0 224 412" height="24" width="13" class="icon"><path d="M 190.7,0 H 33 C 14.8,0 0,14.8 0,33 v 346 c 0,18.2 14.8,33 33,33 h 157.7 c 18.2,0 33,-14.8 33,-33 V 33 c 0,-18.2 -14.8,-33 -33,-33 z M 94.3,30.2 h 37 c 2.2,0 4,1.8 4,4 0,2.2 -1.8,4 -4,4 h -37 c -2.2,0 -4,-1.8 -4,-4 0,-2.2 1.8,-4 4,-4 z m 18.5,362.8 c -8.8,0 -16,-7.2 -16,-16 0,-8.8 7.2,-16 16,-16 8.8,0 16,7.2 16,16 0,8.8 -7.2,16 -16,16 z M 198.6,343.8 H 25.1 V 68.2 h 173.5 v 275.5 z"></path></svg></button><button title="Feature phone (240)" data-width='240'><svg viewBox="0 0 201 412" height="24" width="12" class="icon"><path d="M 165.5,0.2 V 45 H 25 c -13.8,0 -25,11.2 -25,25 V 387 c 0,13.8 11.2,25 25,25 h 150.5 c 13.8,0 25,-11.2 25,-25 V 0.2 h -35 z M 65.2,366.5 H 34.2 v -24.5 h 31 v 24.5 z m 0,-44.3 H 34.2 v -24.5 h 31 v 24.5 z m 50.5,44.3 H 84.7 v -24.5 h 31 v 24.5 z m 0,-44.3 H 84.7 v -24.5 h 31 v 24.5 z m 50.5,44.3 h -31 v -24.5 h 31 v 24.5 z m 0,-44.3 h -31 v -24.5 h 31 v 24.5 z m 0,-59.3 h -132 V 95.4 h 132 V 262.9 z"></path></svg></button><button title="Auto (100%)" data-width="auto" class="auto is-active">Auto</button></div></div><script>(function(){var a=[{title:"actions-toolbar",filename:"actions-toolbar",url:"actions-toolbar.html"},{title:"Actions toolbar",filename:"actions-toolbar",url:"actions-toolbar.html#actions-toolbar"},{title:"Actions toolbar mixin variables",filename:"actions-toolbar",url:"actions-toolbar.html#actions-toolbar-mixin-variables"},{title:"Actions toolbar alignment",filename:"actions-toolbar",url:"actions-toolbar.html#actions-toolbar-alignment"},{title:"Reverse primary and secondary blocks",filename:"actions-toolbar",url:"actions-toolbar.html#reverse-primary-and-secondary-blocks"},{title:"Actions toolbar indents customizations",filename:"actions-toolbar",url:"actions-toolbar.html#actions-toolbar-indents-customizations"},{title:"Responsive actions toolbar",filename:"actions-toolbar",url:"actions-toolbar.html#responsive-actions-toolbar"},{title:"breadcrumbs",filename:"breadcrumbs",url:"breadcrumbs.html"},{title:"Breadcrumbs",filename:"breadcrumbs",url:"breadcrumbs.html#breadcrumbs"},{title:"Breadcrumbs variables",filename:"breadcrumbs",url:"breadcrumbs.html#breadcrumbs-variables"},{title:"Button-styled breadcrumbs with gradient background, border, and no separating symbol",filename:"breadcrumbs",url:"breadcrumbs.html#buttonstyled-breadcrumbs-with-gradient-background-border-and-no-separating-symbol"},{title:"Breadcrumbs with solid background",filename:"breadcrumbs",url:"breadcrumbs.html#breadcrumbs-with-solid-background"},{title:"buttons",filename:"buttons",url:"buttons.html"},{title:"Default button",filename:"buttons",url:"buttons.html#default-button"},{title:"Button variables",filename:"buttons",url:"buttons.html#button-variables"},{title:"Button as an icon",filename:"buttons",url:"buttons.html#button-as-an-icon"},{title:"Button with an icon on the left or right side of the text",filename:"buttons",url:"buttons.html#button-with-an-icon-on-the-left-or-right-side-of-the-text"},{title:"Button with fixed width",filename:"buttons",url:"buttons.html#button-with-fixed-width"},{title:"Primary button",filename:"buttons",url:"buttons.html#primary-button"},{title:"Primary button variables",filename:"buttons",url:"buttons.html#primary-button-variables"},{title:"Button with gradient background",filename:"buttons",url:"buttons.html#button-with-gradient-background"},{title:"Button as a link",filename:"buttons",url:"buttons.html#button-as-a-link"},{title:"Button as a link variables",filename:"buttons",url:"buttons.html#button-as-a-link-variables"},{title:"Link as a button",filename:"buttons",url:"buttons.html#link-as-a-button"},{title:"Button reset",filename:"buttons",url:"buttons.html#button-reset"},{title:"Button revert secondary color",filename:"buttons",url:"buttons.html#button-revert-secondary-color"},{title:"Button revert secondary color variables",filename:"buttons",url:"buttons.html#button-revert-secondary-color-variables"},{title:"Button revert secondary size",filename:"buttons",url:"buttons.html#button-revert-secondary-size"},{title:"Button revert secondary size variables",filename:"buttons",url:"buttons.html#button-revert-secondary-size-variables"},{title:"components",filename:"components",url:"components.html"},{title:"Components",filename:"components",url:"components.html#components"},{title:"Components Variables",filename:"components",url:"components.html#components-variables"},{title:"dropdowns",filename:"dropdowns",url:"dropdowns.html"},{title:"Drop-down and split buttons mixins",filename:"dropdowns",url:"dropdowns.html#dropdown-and-split-buttons-mixins"},{title:"Drop-down",filename:"dropdowns",url:"dropdowns.html#dropdown"},{title:"Drop-down variables",filename:"dropdowns",url:"dropdowns.html#dropdown-variables"},{title:"Drop-down with icon customization",filename:"dropdowns",url:"dropdowns.html#dropdown-with-icon-customization"},{title:"Modify dropdown list styles",filename:"dropdowns",url:"dropdowns.html#modify-dropdown-list-styles"},{title:"Split button",filename:"dropdowns",url:"dropdowns.html#split-button"},{title:"Split button variables",filename:"dropdowns",url:"dropdowns.html#split-button-variables"},{title:"Split button - button styling",filename:"dropdowns",url:"dropdowns.html#split-button-button-styling"},{title:"Split button icon customization",filename:"dropdowns",url:"dropdowns.html#split-button-icon-customization"},{title:"Split button drop-down list customization",filename:"dropdowns",url:"dropdowns.html#split-button-dropdown-list-customization"},{title:"forms",filename:"forms",url:"forms.html"},{title:"Forms mixins",filename:"forms",url:"forms.html#forms-mixins"},{title:"Global forms elements customization",filename:"forms",url:"forms.html#global-forms-elements-customization"},{title:"Fieldsets & fields customization",filename:"forms",url:"forms.html#fieldsets-fields-customization"},{title:"Fieldset and legend customization variables",filename:"forms",url:"forms.html#fieldset-and-legend-customization-variables"},{title:"Fields customization variables",filename:"forms",url:"forms.html#fields-customization-variables"},{title:"Required fields message customization variables",filename:"forms",url:"forms.html#required-fields-message-customization-variables"},{title:"Form element inputs customization",filename:"forms",url:"forms.html#form-element-inputs-customization"},{title:"Form element inputs customization variables",filename:"forms",url:"forms.html#form-element-inputs-customization-variables"},{title:"Form element choice",filename:"forms",url:"forms.html#form-element-choice"},{title:"Form element choice variables",filename:"forms",url:"forms.html#form-element-choice-variables"},{title:"Custom color",filename:"forms",url:"forms.html#custom-color"},{title:"Input number - input-text view",filename:"forms",url:"forms.html#input-number-inputtext-view"},{title:"Input search - input-text view",filename:"forms",url:"forms.html#input-search-inputtext-view"},{title:"Form validation",filename:"forms",url:"forms.html#form-validation"},{title:"Form validation variables",filename:"forms",url:"forms.html#form-validation-variables"},{title:"icons",filename:"icons",url:"icons.html"},{title:"Icons",filename:"icons",url:"icons.html#icons"},{title:"Icon with image or sprite",filename:"icons",url:"icons.html#icon-with-image-or-sprite"},{title:"Icon with image or sprite variables",filename:"icons",url:"icons.html#icon-with-image-or-sprite-variables"},{title:"Icon position for an icon with image or sprite",filename:"icons",url:"icons.html#icon-position-for-an-icon-with-image-or-sprite"},{title:"Position for icon with image or sprite mixin variables",filename:"icons",url:"icons.html#position-for-icon-with-image-or-sprite-mixin-variables"},{title:"Icon sprite position (with grid)",filename:"icons",url:"icons.html#icon-sprite-position-with-grid"},{title:"Icon sprite position variables",filename:"icons",url:"icons.html#icon-sprite-position-variables"},{title:"Image/sprite icon size",filename:"icons",url:"icons.html#imagesprite-icon-size"},{title:"Image/sprite icon size variables",filename:"icons",url:"icons.html#imagesprite-icon-size-variables"},{title:"Font icon",filename:"icons",url:"icons.html#font-icon"},{title:"Font icon variables",filename:"icons",url:"icons.html#font-icon-variables"},{title:"Change the size of font icon",filename:"icons",url:"icons.html#change-the-size-of-font-icon"},{title:"Change the size of font icon variables",filename:"icons",url:"icons.html#change-the-size-of-font-icon-variables"},{title:"Hide icon text",filename:"icons",url:"icons.html#hide-icon-text"},{title:"Sprite and font icons for Blank theme",filename:"icons",url:"icons.html#sprite-and-font-icons-for-blank-theme"},{title:"layout",filename:"layout",url:"layout.html"},{title:"Layout",filename:"layout",url:"layout.html#layout"},{title:"Layout global variables",filename:"layout",url:"layout.html#layout-global-variables"},{title:"Page layouts",filename:"layout",url:"layout.html#page-layouts"},{title:"Layout column",filename:"layout",url:"layout.html#layout-column"},{title:"Layout column variables",filename:"layout",url:"layout.html#layout-column-variables"},{title:"Layout width",filename:"layout",url:"layout.html#layout-width"},{title:"Layout width variables",filename:"layout",url:"layout.html#layout-width-variables"},{title:"lib",filename:"lib",url:"lib.html"},{title:"Including Magento UI library to your theme",filename:"lib",url:"lib.html#including-magento-ui-library-to-your-theme"},{title:"loaders",filename:"loaders",url:"loaders.html"},{title:"Loaders",filename:"loaders",url:"loaders.html#loaders"},{title:"Default loader variables",filename:"loaders",url:"loaders.html#default-loader-variables"},{title:"Loading",filename:"loaders",url:"loaders.html#loading"},{title:"Loading default variables",filename:"loaders",url:"loaders.html#loading-default-variables"},{title:"messages",filename:"messages",url:"messages.html"},{title:"Messages",filename:"messages",url:"messages.html#messages"},{title:"Information message",filename:"messages",url:"messages.html#information-message"},{title:"Warning message",filename:"messages",url:"messages.html#warning-message"},{title:"Error message",filename:"messages",url:"messages.html#error-message"},{title:"Success message",filename:"messages",url:"messages.html#success-message"},{title:"Notice message",filename:"messages",url:"messages.html#notice-message"},{title:"Message with inner icon",filename:"messages",url:"messages.html#message-with-inner-icon"},{title:"Message with lateral icon",filename:"messages",url:"messages.html#message-with-lateral-icon"},{title:"Custom message style",filename:"messages",url:"messages.html#custom-message-style"},{title:"Messages global variables",filename:"messages",url:"messages.html#messages-global-variables"},{title:"pages",filename:"pages",url:"pages.html"},{title:"Pagination HTML markup",filename:"pages",url:"pages.html#pagination-html-markup"},{title:"Pagination variables",filename:"pages",url:"pages.html#pagination-variables"},{title:"Pagination with label and gradient background on links",filename:"pages",url:"pages.html#pagination-with-label-and-gradient-background-on-links"},{title:'Pagination with "previous"..."next" text links and label',filename:"pages",url:"pages.html#pagination-with-previousnext-text-links-and-label"},{title:"Pagination without label, with solid background",filename:"pages",url:"pages.html#pagination-without-label-with-solid-background"},{title:"popups",filename:"popups",url:"popups.html"},{title:"Popups",filename:"popups",url:"popups.html#popups"},{title:"Popup variables",filename:"popups",url:"popups.html#popup-variables"},{title:"Window overlay mixin variables",filename:"popups",url:"popups.html#window-overlay-mixin-variables"},{title:"Fixed height popup",filename:"popups",url:"popups.html#fixed-height-popup"},{title:"Fixed content height popup",filename:"popups",url:"popups.html#fixed-content-height-popup"},{title:"Margins for header, content and footer block in popup",filename:"popups",url:"popups.html#margins-for-header-content-and-footer-block-in-popup"},{title:"Popup titles styled as theme headings",filename:"popups",url:"popups.html#popup-titles-styled-as-theme-headings"},{title:"Popup action toolbar",filename:"popups",url:"popups.html#popup-action-toolbar"},{title:"Popup Close button without an icon",filename:"popups",url:"popups.html#popup-close-button-without-an-icon"},{title:"Modify the icon of popup Close button",filename:"popups",url:"popups.html#modify-the-icon-of-popup-close-button"},{title:"Modify overlay styles",filename:"popups",url:"popups.html#modify-overlay-styles"},{title:"rating",filename:"rating",url:"rating.html"},{title:"Ratings",filename:"rating",url:"rating.html#ratings"},{title:"Global rating variables",filename:"rating",url:"rating.html#global-rating-variables"},{title:"Rating with vote",filename:"rating",url:"rating.html#rating-with-vote"},{title:"Rating with vote icons number customization",filename:"rating",url:"rating.html#rating-with-vote-icons-number-customization"},{title:"Rating with vote icons colors customization",filename:"rating",url:"rating.html#rating-with-vote-icons-colors-customization"},{title:"Rating with vote icons symbol customization",filename:"rating",url:"rating.html#rating-with-vote-icons-symbol-customization"},{title:"Accessible rating with vote",filename:"rating",url:"rating.html#accessible-rating-with-vote"},{title:"Rating summary",filename:"rating",url:"rating.html#rating-summary"},{title:"Rating summary icons number customization",filename:"rating",url:"rating.html#rating-summary-icons-number-customization"},{title:"Rating summary icons color customization",filename:"rating",url:"rating.html#rating-summary-icons-color-customization"},{title:"Rating summary icons symbol customization",filename:"rating",url:"rating.html#rating-summary-icons-symbol-customization"},{title:"Rating summary hide label",filename:"rating",url:"rating.html#rating-summary-hide-label"},{title:"Rating summary multiple ratings",filename:"rating",url:"rating.html#rating-summary-multiple-ratings"},{title:"Rating hide label mixin",filename:"rating",url:"rating.html#rating-hide-label-mixin"},{title:"resets",filename:"resets",url:"resets.html"},{title:"Resets",filename:"resets",url:"resets.html#resets"},{title:"responsive",filename:"responsive",url:"responsive.html"},{title:"Responsive",filename:"responsive",url:"responsive.html#responsive"},{title:"Responsive mixins usage",filename:"responsive",url:"responsive.html#responsive-mixins-usage"},{title:"Media query style groups separation variables",filename:"responsive",url:"responsive.html#media-query-style-groups-separation-variables"},{title:"Responsive breakpoints",filename:"responsive",url:"responsive.html#responsive-breakpoints"},{title:"sections",filename:"sections",url:"sections.html"},{title:"Tabs and accordions",filename:"sections",url:"sections.html#tabs-and-accordions"},{title:"Tabs",filename:"sections",url:"sections.html#tabs"},{title:"Tabs mixin variables",filename:"sections",url:"sections.html#tabs-mixin-variables"},{title:"Tabs with content top border",filename:"sections",url:"sections.html#tabs-with-content-top-border"},{title:"Accordion",filename:"sections",url:"sections.html#accordion"},{title:"Accordion mixin variables",filename:"sections",url:"sections.html#accordion-mixin-variables"},{title:"Responsive tabs",filename:"sections",url:"sections.html#responsive-tabs"},{title:"Tabs Base",filename:"sections",url:"sections.html#tabs-base"},{title:"Accordion Base",filename:"sections",url:"sections.html#accordion-base"},{title:"tables",filename:"tables",url:"tables.html"},{title:"Tables",filename:"tables",url:"tables.html#tables"},{title:"Table mixin variables",filename:"tables",url:"tables.html#table-mixin-variables"},{title:"Table typography",filename:"tables",url:"tables.html#table-typography"},{title:"Table typography mixin variables",filename:"tables",url:"tables.html#table-typography-mixin-variables"},{title:"Table caption",filename:"tables",url:"tables.html#table-caption"},{title:"Table caption mixin variables",filename:"tables",url:"tables.html#table-caption-mixin-variables"},{title:"Table cells resize",filename:"tables",url:"tables.html#table-cells-resize"},{title:"Table cells resize variables",filename:"tables",url:"tables.html#table-cells-resize-variables"},{title:"Table background customization",filename:"tables",url:"tables.html#table-background-customization"},{title:"Table background mixin variables",filename:"tables",url:"tables.html#table-background-mixin-variables"},{title:"Table borders customization",filename:"tables",url:"tables.html#table-borders-customization"},{title:"Table borders mixin variables",filename:"tables",url:"tables.html#table-borders-mixin-variables"},{title:"Table with horizontal borders",filename:"tables",url:"tables.html#table-with-horizontal-borders"},{title:"Table with vertical borders",filename:"tables",url:"tables.html#table-with-vertical-borders"},{title:"Table with light borders",filename:"tables",url:"tables.html#table-with-light-borders"},{title:"Table without borders",filename:"tables",url:"tables.html#table-without-borders"},{title:"Striped table",filename:"tables",url:"tables.html#striped-table"},{title:"Striped table mixin variables",filename:"tables",url:"tables.html#striped-table-mixin-variables"},{title:"Table with rows hover",filename:"tables",url:"tables.html#table-with-rows-hover"},{title:"Table with rows hover mixin variables",filename:"tables",url:"tables.html#table-with-rows-hover-mixin-variables"},{title:"Responsive table technics #1",filename:"tables",url:"tables.html#responsive-table-technics-1"},{title:"Responsive table technics #2",filename:"tables",url:"tables.html#responsive-table-technics-2"},{title:"Responsive table technics #2 mixin variables",filename:"tables",url:"tables.html#responsive-table-technics-2-mixin-variables"},{title:"tooltips",filename:"tooltips",url:"tooltips.html"},{title:"Tooltips",filename:"tooltips",url:"tooltips.html#tooltips"},{title:"Tooltips variables",filename:"tooltips",url:"tooltips.html#tooltips-variables"},{title:"typography",filename:"typography",url:"typography.html"},{title:"Typogrphy",filename:"typography",url:"typography.html#typogrphy"},{title:"Typography variables",filename:"typography",url:"typography.html#typography-variables"},{title:"Font-size mixin",filename:"typography",url:"typography.html#fontsize-mixin"},{title:"Line-height mixin",filename:"typography",url:"typography.html#lineheight-mixin"},{title:"Word breaking mixin",filename:"typography",url:"typography.html#word-breaking-mixin"},{title:"Font face mixin",filename:"typography",url:"typography.html#font-face-mixin"},{title:"Text overflow mixin",filename:"typography",url:"typography.html#text-overflow-mixin"},{title:"Text hide",filename:"typography",url:"typography.html#text-hide"},{title:"Hyphens",filename:"typography",url:"typography.html#hyphens"},{title:"Font style and color",filename:"typography",url:"typography.html#font-style-and-color"},{title:"Font style mixin variables",filename:"typography",url:"typography.html#font-style-mixin-variables"},{title:"Reset list styles",filename:"typography",url:"typography.html#reset-list-styles"},{title:"Reset list styles variables",filename:"typography",url:"typography.html#reset-list-styles-variables"},{title:"Inline-block list item styling",filename:"typography",url:"typography.html#inlineblock-list-item-styling"},{title:"Link styling mixin",filename:"typography",url:"typography.html#link-styling-mixin"},{title:"Link styling mixin variables",filename:"typography",url:"typography.html#link-styling-mixin-variables"},{title:"Heading styling mixin",filename:"typography",url:"typography.html#heading-styling-mixin"},{title:"Base typography mixins",filename:"typography",url:"typography.html#base-typography-mixins"},{title:"Base typography mixin variables",filename:"typography",url:"typography.html#base-typography-mixin-variables"},{title:"Headings typography mixin",filename:"typography",url:"typography.html#headings-typography-mixin"},{title:"Headings typography mixin variables",filename:"typography",url:"typography.html#headings-typography-mixin-variables"},{title:"Typography links mixin",filename:"typography",url:"typography.html#typography-links-mixin"},{title:"Typography lists mixin",filename:"typography",url:"typography.html#typography-lists-mixin"},{title:"Typography lists mixin variables",filename:"typography",url:"typography.html#typography-lists-mixin-variables"},{title:"Typography code elements mixin",filename:"typography",url:"typography.html#typography-code-elements-mixin"},{title:"Typography code mixin variables",filename:"typography",url:"typography.html#typography-code-mixin-variables"},{title:"Typography blockquote",filename:"typography",url:"typography.html#typography-blockquote"},{title:"Typography blockquote mixin variables",filename:"typography",url:"typography.html#typography-blockquote-mixin-variables"},{title:"utilities",filename:"utilities",url:"utilities.html"},{title:"Utilities",filename:"utilities",url:"utilities.html#utilities"},{title:".lib-clearfix()",filename:"utilities",url:"utilities.html#libclearfix"},{title:".lib-visibility-hidden()",filename:"utilities",url:"utilities.html#libvisibilityhidden"},{title:".lib-visually-hidden()",filename:"utilities",url:"utilities.html#libvisuallyhidden"},{title:".lib-visually-hidden-reset()",filename:"utilities",url:"utilities.html#libvisuallyhiddenreset"},{title:".lib-css()",filename:"utilities",url:"utilities.html#libcss"},{title:".lib-css() variables",filename:"utilities",url:"utilities.html#libcss-variables"},{title:".lib-rotate()",filename:"utilities",url:"utilities.html#librotate"},{title:".lib-rotate() variables",filename:"utilities",url:"utilities.html#librotate-variables"},{title:".lib-input-placeholder()",filename:"utilities",url:"utilities.html#libinputplaceholder"},{title:".lib-input-placeholder() variables",filename:"utilities",url:"utilities.html#libinputplaceholder-variables"},{title:".lib-background-gradient()",filename:"utilities",url:"utilities.html#libbackgroundgradient"},{title:".lib-background-gradient() variables",filename:"utilities",url:"utilities.html#libbackgroundgradient-variables"},{title:".lib-url-check()",filename:"utilities",url:"utilities.html#liburlcheck"},{title:".lib-url-check() variables",filename:"utilities",url:"utilities.html#liburlcheck-variables"},{title:"variables",filename:"variables",url:"variables.html"},{title:"List of Global Variables",filename:"variables",url:"variables.html#list-of-global-variables"},{title:"Table with rows hover mixin variables",filename:"variables",url:"variables.html#table-with-rows-hover-mixin-variables"},{title:"docs",filename:"docs",url:"docs.html"},{title:"Documentation",filename:"docs",url:"docs.html#documentation"}];(function(){"use strict";var b=function(a,b){return Array.prototype.indexOf.call(a,b)!==-1},c=function(a,b){return Array.prototype.filter.call(a,b)},d=function(a,b){return Array.prototype.forEach.call(a,b)},e=document.getElementsByTagName("body")[0];e.addEventListener("click",function(a){var b=a.target;b.tagName.toLowerCase()==="svg"&&(b=b.parentNode);var c=!1;b.dataset.toggle!=null&&(a.preventDefault(),b.classList.contains("is-active")||(c=!0)),d(e.querySelectorAll("[data-toggle]"),function(a){a.classList.remove("is-active"),document.getElementById(a.dataset.toggle).hidden=!0}),c&&(b.classList.add("is-active"),document.getElementById(b.dataset.toggle).hidden=!1)}),function(){var f=e.getElementsByClassName("nav")[0];if(!f)return;var g=document.createElement("ul");g.className="nav-results",g.id="nav-search",g.hidden=!0,d(a,function(a){var b,c,d;b=document.createElement("li"),b._title=a.title.toLowerCase(),b.hidden=!0,b.appendChild(c=document.createElement("a")),c.href=a.url,c.innerHTML=a.title,c.appendChild(d=document.createElement("span")),d.innerHTML=a.filename,d.className="nav-results-filename",g.appendChild(b)}),f.appendChild(g);var h=g.children,i=function(a){d(h,function(a){a.hidden=!0});var b=this.value.toLowerCase(),e=[];b!==""&&(e=c(h,function(a){return a._title.indexOf(b)!==-1})),e.length>0?(d(e,function(a){a.hidden=!1}),g.hidden=!1):g.hidden=!0},j=f.querySelector('input[type="search"]');j.addEventListener("keyup",i),j.addEventListener("focus",i),e.addEventListener("click",function(a){if(a.target.classList&&a.target.classList.contains("search"))return;g.hidden=!0}),g.addEventListener("click",function(a){j.value=""});var k=document.createElement("ul");k.id="nav-toc",k.hidden=!0,k.className="nav-results toc-list",c(e.getElementsByTagName("*"),function(a){return b(["h1","h2","h3"],a.tagName.toLowerCase())}).map(function(a){var b=document.createElement("li"),c=document.createElement("a"),d=a.tagName.toLowerCase()[1];c.classList.add("level-"+d),b.appendChild(c),c.href="#"+a.id,c.innerHTML=a.innerHTML,k.appendChild(b)}),f.appendChild(k)}()})(),function(){"use strict";if(location.hash==="#__preview__"||location.protocol==="data:")return;var a=function(a,b){return Array.prototype.forEach.call(a,b)},b=function(a,b){var e=Array.prototype.slice.call(arguments,2);return d(a,function(a){return(c(b)?b||a:a[b]).apply(a,e)})},c=function(a){return Object.prototype.toString.call(a)==="[object Function]"},d=function(a,b){return Array.prototype.map.call(a,b)},e=function(a,b){return d(a,function(a){return a[b]})},f=function(a){var b={},c=a.split(";");for(var d=0;c.length>d;d++){var e=c[d].trim().split("=");b[e[0]]=e[1]}return b},g=function(a,c){return b(e(a,"classList"),"remove",c)},h=function(a,b){a.contentDocument.defaultView.postMessage(b,"*")},i=document.getElementsByTagName("head")[0],j=document.getElementsByTagName("body")[0],k=e(i.querySelectorAll('style[type="text/preview"]'),"innerHTML").join(""),l=e(i.querySelectorAll('script[type="text/preview"]'),"innerHTML").join(""),m=location.href.split("#")[0]+"#__preview__",n=document.createElement("iframe");n.src="data:text/html,",j.appendChild(n),n.addEventListener("load",function(){var b={sameOriginDataUri:!0};try{this.contentDocument,this.contentDocument||(b.sameOriginDataUri=!1)}catch(c){b.sameOriginDataUri=!1}this.parentNode.removeChild(this),a(j.getElementsByTagName("textarea"),function(a,c){o(a,b,c),q(),p(a)})});var o=function(a,b,c){var d,e,f;d=document.createElement("div"),d.appendChild(e=document.createElement("div")),d.className="preview",e.appendChild(f=document.createElement("iframe")),e.className="resizeable",f.setAttribute("scrolling","no"),f.name="iframe"+c++,f.addEventListener("load",function(){var c,d,e,f,g,i,j;j=this.contentDocument;if(!b.sameOriginDataUri&&this.src!==m)return;this.src===m&&(c=j.createElement("html"),c.appendChild(j.createElement("head")),c.appendChild(d=j.createElement("body")),d.innerHTML=a.textContent,j.replaceChild(c,j.documentElement)),g=j.createElement("head"),g.appendChild(f=j.createElement("style")),g.appendChild(e=j.createElement("script")),e.textContent=l,f.textContent=k,i=j.getElementsByTagName("head")[0],i.parentNode.replaceChild(g,i),h(this,"getHeight")});var g;b.sameOriginDataUri?g="data:text/html;charset=utf-8,"+encodeURIComponent("<!doctype html><html><head></head></body>"+a.textContent):g=m,f.setAttribute("src",g);var i=function(){f.contentDocument.body.innerHTML=this.value,h(f,"getHeight")};a.addEventListener("keypress",i),a.addEventListener("keyup",i),a.parentNode.insertBefore(d,a)},p=function(a){var b=document.createElement("div");b.className="preview-code",b.style.position="absolute",b.style.left="-9999px",j.appendChild(b);var c=parseInt(window.getComputedStyle(a).getPropertyValue("max-height"),10),d=function(a){b.textContent=this.value+"\n";var d=b.offsetHeight+2;d>=c?this.style.overflow="auto":this.style.overflow="hidden",this.style.height=b.offsetHeight+2+"px"};a.addEventListener("keypress",d),a.addEventListener("keyup",d),d.call(a)},q=function(){var b=j.getElementsByClassName("settings")[0],c=j.getElementsByClassName("resizeable"),d=30,e=function(b){document.cookie="preview-width="+b,a(c,function(a){b==="auto"&&(b=a.parentNode.offsetWidth),a.style.width=b+"px",h(a.getElementsByTagName("iframe")[0],"getHeight")})},i=f(document.cookie)["preview-width"];if(i){e(i),g(b.getElementsByClassName("is-active"),"is-active");var k=b.querySelector('button[data-width="'+i+'"]');k&&k.classList.add("is-active")}window.addEventListener("message",function(a){if(a.data==null||!a.source)return;var b=a.data,c=document.getElementsByName(a.source.name)[0];b.height!=null&&c&&(c.parentNode.style.height=b.height+d+"px")},!1),b&&c.length>0&&(b.hidden=!1,b.addEventListener("click",function(a){var c=a.target.tagName.toLowerCase(),d;if(c==="button")d=a.target;else{if(c!=="svg")return;d=a.target.parentNode}a.preventDefault(),g(b.getElementsByClassName("is-active"),"is-active"),d.classList.add("is-active");var f=d.dataset.width;e(f)}))}}()})()</script></body></html><!-- Generated with StyleDocco (http://jacobrask.github.com/styledocco). --> +}</code></pre></div></article></section><div class="bar bottom"><div hidden class="settings container"><!-- Icons from http://iconmonstr.com--><button title="Desktop (1280)" data-width='1280'><svg viewBox="0 0 412 386" height="24" width="26" class="icon"><path d="m147.6,343.9c-4.5,15.9-26.2,37.6-42.1,42.1h201c-15.3,-4-38.1,-26.8-42.1,-42.1H147.6zM387,0.5H25c-13.8,0-25,11.2-25,25V294c0,13.8 11.2,25 25,25h362c13.8,0 25,-11.2 25,-25V25.5C412,11.7 400.8,0.5 387,0.5zM369.9,238.2H42.1L42.1,42.6 369.9,42.6V238.2z"></path></svg></button><button title="Laptop (1024)" data-width='1024'><svg viewBox="0 0 384 312" height="23" width="28" class="icon"><path d="m349.2,20.5c0,-11-9,-20-20,-20H53.6c-11,0-20,9-20,20v194H349.2v-194zm-27,167H60.6V27.5H322.2v160zm28,42H32.6L2.6,282.1c-3.5,6.2-3.5,13.8 0.1,19.9 3.6,6.2 10.2,9.9 17.3,9.9H363.1c7.1,0 13.7,-3.8 17.3,-10 3.6,-6.2 3.6,-13.8 0,-20l-30.2,-52.5zm-196.9,54 8,-23.5h60.5l8,23.5h-76.5z"></path></svg></button><button title="Tablet (768)" data-width='768'><svg viewBox="0 0 317 412" height="24" width="18" class="icon"><path d="M 316.5,380 V 32 c 0,-17.7 -14.3,-32 -32,-32 H 32 C 14.3,0 0,14.3 0,32 v 348 c 0,17.7 14.3,32 32,32 h 252.5 c 17.7,0 32,-14.3 32,-32 z M 40,367 V 45 H 276.5 V 367 H 40 z m 109.8,22.7 c 0,-4.7 3.8,-8.5 8.5,-8.5 4.7,0 8.5,3.8 8.5,8.5 0,4.7 -3.8,8.5 -8.5,8.5 -4.7,0 -8.5,-3.8 -8.5,-8.5 z"></path></svg></button><button title="Smart phone (320)" data-width='320'><svg viewBox="0 0 224 412" height="24" width="13" class="icon"><path d="M 190.7,0 H 33 C 14.8,0 0,14.8 0,33 v 346 c 0,18.2 14.8,33 33,33 h 157.7 c 18.2,0 33,-14.8 33,-33 V 33 c 0,-18.2 -14.8,-33 -33,-33 z M 94.3,30.2 h 37 c 2.2,0 4,1.8 4,4 0,2.2 -1.8,4 -4,4 h -37 c -2.2,0 -4,-1.8 -4,-4 0,-2.2 1.8,-4 4,-4 z m 18.5,362.8 c -8.8,0 -16,-7.2 -16,-16 0,-8.8 7.2,-16 16,-16 8.8,0 16,7.2 16,16 0,8.8 -7.2,16 -16,16 z M 198.6,343.8 H 25.1 V 68.2 h 173.5 v 275.5 z"></path></svg></button><button title="Feature phone (240)" data-width='240'><svg viewBox="0 0 201 412" height="24" width="12" class="icon"><path d="M 165.5,0.2 V 45 H 25 c -13.8,0 -25,11.2 -25,25 V 387 c 0,13.8 11.2,25 25,25 h 150.5 c 13.8,0 25,-11.2 25,-25 V 0.2 h -35 z M 65.2,366.5 H 34.2 v -24.5 h 31 v 24.5 z m 0,-44.3 H 34.2 v -24.5 h 31 v 24.5 z m 50.5,44.3 H 84.7 v -24.5 h 31 v 24.5 z m 0,-44.3 H 84.7 v -24.5 h 31 v 24.5 z m 50.5,44.3 h -31 v -24.5 h 31 v 24.5 z m 0,-44.3 h -31 v -24.5 h 31 v 24.5 z m 0,-59.3 h -132 V 95.4 h 132 V 262.9 z"></path></svg></button><button title="Auto (100%)" data-width="auto" class="auto is-active">Auto</button></div></div><script>(function(){var a=[{title:"actions-toolbar",filename:"actions-toolbar",url:"actions-toolbar.html"},{title:"Actions toolbar",filename:"actions-toolbar",url:"actions-toolbar.html#actions-toolbar"},{title:"Actions toolbar mixin variables",filename:"actions-toolbar",url:"actions-toolbar.html#actions-toolbar-mixin-variables"},{title:"Actions toolbar alignment",filename:"actions-toolbar",url:"actions-toolbar.html#actions-toolbar-alignment"},{title:"Reverse primary and secondary blocks",filename:"actions-toolbar",url:"actions-toolbar.html#reverse-primary-and-secondary-blocks"},{title:"Actions toolbar indents customizations",filename:"actions-toolbar",url:"actions-toolbar.html#actions-toolbar-indents-customizations"},{title:"Responsive actions toolbar",filename:"actions-toolbar",url:"actions-toolbar.html#responsive-actions-toolbar"},{title:"breadcrumbs",filename:"breadcrumbs",url:"breadcrumbs.html"},{title:"Breadcrumbs",filename:"breadcrumbs",url:"breadcrumbs.html#breadcrumbs"},{title:"Breadcrumbs variables",filename:"breadcrumbs",url:"breadcrumbs.html#breadcrumbs-variables"},{title:"Button-styled breadcrumbs with gradient background, border, and no separating symbol",filename:"breadcrumbs",url:"breadcrumbs.html#buttonstyled-breadcrumbs-with-gradient-background-border-and-no-separating-symbol"},{title:"Breadcrumbs with solid background",filename:"breadcrumbs",url:"breadcrumbs.html#breadcrumbs-with-solid-background"},{title:"buttons",filename:"buttons",url:"buttons.html"},{title:"Default button",filename:"buttons",url:"buttons.html#default-button"},{title:"Button variables",filename:"buttons",url:"buttons.html#button-variables"},{title:"Button as an icon",filename:"buttons",url:"buttons.html#button-as-an-icon"},{title:"Button with an icon on the left or right side of the text",filename:"buttons",url:"buttons.html#button-with-an-icon-on-the-left-or-right-side-of-the-text"},{title:"Button with fixed width",filename:"buttons",url:"buttons.html#button-with-fixed-width"},{title:"Primary button",filename:"buttons",url:"buttons.html#primary-button"},{title:"Primary button variables",filename:"buttons",url:"buttons.html#primary-button-variables"},{title:"Button with gradient background",filename:"buttons",url:"buttons.html#button-with-gradient-background"},{title:"Button as a link",filename:"buttons",url:"buttons.html#button-as-a-link"},{title:"Button as a link variables",filename:"buttons",url:"buttons.html#button-as-a-link-variables"},{title:"Link as a button",filename:"buttons",url:"buttons.html#link-as-a-button"},{title:"Button reset",filename:"buttons",url:"buttons.html#button-reset"},{title:"Button revert secondary color",filename:"buttons",url:"buttons.html#button-revert-secondary-color"},{title:"Button revert secondary color variables",filename:"buttons",url:"buttons.html#button-revert-secondary-color-variables"},{title:"Button revert secondary size",filename:"buttons",url:"buttons.html#button-revert-secondary-size"},{title:"Button revert secondary size variables",filename:"buttons",url:"buttons.html#button-revert-secondary-size-variables"},{title:"components",filename:"components",url:"components.html"},{title:"Components",filename:"components",url:"components.html#components"},{title:"Components Variables",filename:"components",url:"components.html#components-variables"},{title:"dropdowns",filename:"dropdowns",url:"dropdowns.html"},{title:"Drop-down and split buttons mixins",filename:"dropdowns",url:"dropdowns.html#dropdown-and-split-buttons-mixins"},{title:"Drop-down",filename:"dropdowns",url:"dropdowns.html#dropdown"},{title:"Drop-down variables",filename:"dropdowns",url:"dropdowns.html#dropdown-variables"},{title:"Drop-down with icon customization",filename:"dropdowns",url:"dropdowns.html#dropdown-with-icon-customization"},{title:"Modify dropdown list styles",filename:"dropdowns",url:"dropdowns.html#modify-dropdown-list-styles"},{title:"Split button",filename:"dropdowns",url:"dropdowns.html#split-button"},{title:"Split button variables",filename:"dropdowns",url:"dropdowns.html#split-button-variables"},{title:"Split button - button styling",filename:"dropdowns",url:"dropdowns.html#split-button-button-styling"},{title:"Split button icon customization",filename:"dropdowns",url:"dropdowns.html#split-button-icon-customization"},{title:"Split button drop-down list customization",filename:"dropdowns",url:"dropdowns.html#split-button-dropdown-list-customization"},{title:"forms",filename:"forms",url:"forms.html"},{title:"Forms mixins",filename:"forms",url:"forms.html#forms-mixins"},{title:"Global forms elements customization",filename:"forms",url:"forms.html#global-forms-elements-customization"},{title:"Fieldsets & fields customization",filename:"forms",url:"forms.html#fieldsets-fields-customization"},{title:"Fieldset and legend customization variables",filename:"forms",url:"forms.html#fieldset-and-legend-customization-variables"},{title:"Fields customization variables",filename:"forms",url:"forms.html#fields-customization-variables"},{title:"Required fields message customization variables",filename:"forms",url:"forms.html#required-fields-message-customization-variables"},{title:"Form element inputs customization",filename:"forms",url:"forms.html#form-element-inputs-customization"},{title:"Form element inputs customization variables",filename:"forms",url:"forms.html#form-element-inputs-customization-variables"},{title:"Form element choice",filename:"forms",url:"forms.html#form-element-choice"},{title:"Form element choice variables",filename:"forms",url:"forms.html#form-element-choice-variables"},{title:"Custom color",filename:"forms",url:"forms.html#custom-color"},{title:"Input number - input-text view",filename:"forms",url:"forms.html#input-number-inputtext-view"},{title:"Input search - input-text view",filename:"forms",url:"forms.html#input-search-inputtext-view"},{title:"Form validation",filename:"forms",url:"forms.html#form-validation"},{title:"Form validation variables",filename:"forms",url:"forms.html#form-validation-variables"},{title:"icons",filename:"icons",url:"icons.html"},{title:"Icons",filename:"icons",url:"icons.html#icons"},{title:"Icon with image or sprite",filename:"icons",url:"icons.html#icon-with-image-or-sprite"},{title:"Icon with image or sprite variables",filename:"icons",url:"icons.html#icon-with-image-or-sprite-variables"},{title:"Icon position for an icon with image or sprite",filename:"icons",url:"icons.html#icon-position-for-an-icon-with-image-or-sprite"},{title:"Position for icon with image or sprite mixin variables",filename:"icons",url:"icons.html#position-for-icon-with-image-or-sprite-mixin-variables"},{title:"Icon sprite position (with grid)",filename:"icons",url:"icons.html#icon-sprite-position-with-grid"},{title:"Icon sprite position variables",filename:"icons",url:"icons.html#icon-sprite-position-variables"},{title:"Image/sprite icon size",filename:"icons",url:"icons.html#imagesprite-icon-size"},{title:"Image/sprite icon size variables",filename:"icons",url:"icons.html#imagesprite-icon-size-variables"},{title:"Font icon",filename:"icons",url:"icons.html#font-icon"},{title:"Font icon variables",filename:"icons",url:"icons.html#font-icon-variables"},{title:"Change the size of font icon",filename:"icons",url:"icons.html#change-the-size-of-font-icon"},{title:"Change the size of font icon variables",filename:"icons",url:"icons.html#change-the-size-of-font-icon-variables"},{title:"Hide icon text",filename:"icons",url:"icons.html#hide-icon-text"},{title:"Sprite and font icons for Blank theme",filename:"icons",url:"icons.html#sprite-and-font-icons-for-blank-theme"},{title:"layout",filename:"layout",url:"layout.html"},{title:"Layout",filename:"layout",url:"layout.html#layout"},{title:"Layout global variables",filename:"layout",url:"layout.html#layout-global-variables"},{title:"Page layouts",filename:"layout",url:"layout.html#page-layouts"},{title:"Layout column",filename:"layout",url:"layout.html#layout-column"},{title:"Layout column variables",filename:"layout",url:"layout.html#layout-column-variables"},{title:"Layout width",filename:"layout",url:"layout.html#layout-width"},{title:"Layout width variables",filename:"layout",url:"layout.html#layout-width-variables"},{title:"lib",filename:"lib",url:"lib.html"},{title:"Including Magento UI library to your theme",filename:"lib",url:"lib.html#including-magento-ui-library-to-your-theme"},{title:"loaders",filename:"loaders",url:"loaders.html"},{title:"Loaders",filename:"loaders",url:"loaders.html#loaders"},{title:"Default loader variables",filename:"loaders",url:"loaders.html#default-loader-variables"},{title:"Loading",filename:"loaders",url:"loaders.html#loading"},{title:"Loading default variables",filename:"loaders",url:"loaders.html#loading-default-variables"},{title:"messages",filename:"messages",url:"messages.html"},{title:"Messages",filename:"messages",url:"messages.html#messages"},{title:"Information message",filename:"messages",url:"messages.html#information-message"},{title:"Warning message",filename:"messages",url:"messages.html#warning-message"},{title:"Error message",filename:"messages",url:"messages.html#error-message"},{title:"Success message",filename:"messages",url:"messages.html#success-message"},{title:"Notice message",filename:"messages",url:"messages.html#notice-message"},{title:"Message with inner icon",filename:"messages",url:"messages.html#message-with-inner-icon"},{title:"Message with lateral icon",filename:"messages",url:"messages.html#message-with-lateral-icon"},{title:"Custom message style",filename:"messages",url:"messages.html#custom-message-style"},{title:"Messages global variables",filename:"messages",url:"messages.html#messages-global-variables"},{title:"pages",filename:"pages",url:"pages.html"},{title:"Pagination HTML markup",filename:"pages",url:"pages.html#pagination-html-markup"},{title:"Pagination variables",filename:"pages",url:"pages.html#pagination-variables"},{title:"Pagination with label and gradient background on links",filename:"pages",url:"pages.html#pagination-with-label-and-gradient-background-on-links"},{title:'Pagination with "previous"..."next" text links and label',filename:"pages",url:"pages.html#pagination-with-previousnext-text-links-and-label"},{title:"Pagination without label, with solid background",filename:"pages",url:"pages.html#pagination-without-label-with-solid-background"},{title:"popups",filename:"popups",url:"popups.html"},{title:"Popups",filename:"popups",url:"popups.html#popups"},{title:"Popup variables",filename:"popups",url:"popups.html#popup-variables"},{title:"Window overlay mixin variables",filename:"popups",url:"popups.html#window-overlay-mixin-variables"},{title:"Fixed height popup",filename:"popups",url:"popups.html#fixed-height-popup"},{title:"Fixed content height popup",filename:"popups",url:"popups.html#fixed-content-height-popup"},{title:"Margins for header, content and footer block in popup",filename:"popups",url:"popups.html#margins-for-header-content-and-footer-block-in-popup"},{title:"Popup titles styled as theme headings",filename:"popups",url:"popups.html#popup-titles-styled-as-theme-headings"},{title:"Popup action toolbar",filename:"popups",url:"popups.html#popup-action-toolbar"},{title:"Popup Close button without an icon",filename:"popups",url:"popups.html#popup-close-button-without-an-icon"},{title:"Modify the icon of popup Close button",filename:"popups",url:"popups.html#modify-the-icon-of-popup-close-button"},{title:"Modify overlay styles",filename:"popups",url:"popups.html#modify-overlay-styles"},{title:"rating",filename:"rating",url:"rating.html"},{title:"Ratings",filename:"rating",url:"rating.html#ratings"},{title:"Global rating variables",filename:"rating",url:"rating.html#global-rating-variables"},{title:"Rating with vote",filename:"rating",url:"rating.html#rating-with-vote"},{title:"Rating with vote icons number customization",filename:"rating",url:"rating.html#rating-with-vote-icons-number-customization"},{title:"Rating with vote icons colors customization",filename:"rating",url:"rating.html#rating-with-vote-icons-colors-customization"},{title:"Rating with vote icons symbol customization",filename:"rating",url:"rating.html#rating-with-vote-icons-symbol-customization"},{title:"Accessible rating with vote",filename:"rating",url:"rating.html#accessible-rating-with-vote"},{title:"Rating summary",filename:"rating",url:"rating.html#rating-summary"},{title:"Rating summary icons number customization",filename:"rating",url:"rating.html#rating-summary-icons-number-customization"},{title:"Rating summary icons color customization",filename:"rating",url:"rating.html#rating-summary-icons-color-customization"},{title:"Rating summary icons symbol customization",filename:"rating",url:"rating.html#rating-summary-icons-symbol-customization"},{title:"Rating summary hide label",filename:"rating",url:"rating.html#rating-summary-hide-label"},{title:"Rating summary multiple ratings",filename:"rating",url:"rating.html#rating-summary-multiple-ratings"},{title:"Rating hide label mixin",filename:"rating",url:"rating.html#rating-hide-label-mixin"},{title:"resets",filename:"resets",url:"resets.html"},{title:"Resets",filename:"resets",url:"resets.html#resets"},{title:"responsive",filename:"responsive",url:"responsive.html"},{title:"Responsive",filename:"responsive",url:"responsive.html#responsive"},{title:"Responsive mixins usage",filename:"responsive",url:"responsive.html#responsive-mixins-usage"},{title:"Media query style groups separation variables",filename:"responsive",url:"responsive.html#media-query-style-groups-separation-variables"},{title:"Responsive breakpoints",filename:"responsive",url:"responsive.html#responsive-breakpoints"},{title:"sections",filename:"sections",url:"sections.html"},{title:"Tabs and accordions",filename:"sections",url:"sections.html#tabs-and-accordions"},{title:"Tabs",filename:"sections",url:"sections.html#tabs"},{title:"Tabs mixin variables",filename:"sections",url:"sections.html#tabs-mixin-variables"},{title:"Tabs with content top border",filename:"sections",url:"sections.html#tabs-with-content-top-border"},{title:"Accordion",filename:"sections",url:"sections.html#accordion"},{title:"Accordion mixin variables",filename:"sections",url:"sections.html#accordion-mixin-variables"},{title:"Responsive tabs",filename:"sections",url:"sections.html#responsive-tabs"},{title:"Tabs Base",filename:"sections",url:"sections.html#tabs-base"},{title:"Accordion Base",filename:"sections",url:"sections.html#accordion-base"},{title:"tables",filename:"tables",url:"tables.html"},{title:"Tables",filename:"tables",url:"tables.html#tables"},{title:"Table mixin variables",filename:"tables",url:"tables.html#table-mixin-variables"},{title:"Table typography",filename:"tables",url:"tables.html#table-typography"},{title:"Table typography mixin variables",filename:"tables",url:"tables.html#table-typography-mixin-variables"},{title:"Table caption",filename:"tables",url:"tables.html#table-caption"},{title:"Table caption mixin variables",filename:"tables",url:"tables.html#table-caption-mixin-variables"},{title:"Table cells resize",filename:"tables",url:"tables.html#table-cells-resize"},{title:"Table cells resize variables",filename:"tables",url:"tables.html#table-cells-resize-variables"},{title:"Table background customization",filename:"tables",url:"tables.html#table-background-customization"},{title:"Table background mixin variables",filename:"tables",url:"tables.html#table-background-mixin-variables"},{title:"Table borders customization",filename:"tables",url:"tables.html#table-borders-customization"},{title:"Table borders mixin variables",filename:"tables",url:"tables.html#table-borders-mixin-variables"},{title:"Table with horizontal borders",filename:"tables",url:"tables.html#table-with-horizontal-borders"},{title:"Table with vertical borders",filename:"tables",url:"tables.html#table-with-vertical-borders"},{title:"Table with light borders",filename:"tables",url:"tables.html#table-with-light-borders"},{title:"Table without borders",filename:"tables",url:"tables.html#table-without-borders"},{title:"Striped table",filename:"tables",url:"tables.html#striped-table"},{title:"Striped table mixin variables",filename:"tables",url:"tables.html#striped-table-mixin-variables"},{title:"Table with rows hover",filename:"tables",url:"tables.html#table-with-rows-hover"},{title:"Table with rows hover mixin variables",filename:"tables",url:"tables.html#table-with-rows-hover-mixin-variables"},{title:"Responsive table technics #1",filename:"tables",url:"tables.html#responsive-table-technics-1"},{title:"Responsive table technics #2",filename:"tables",url:"tables.html#responsive-table-technics-2"},{title:"Responsive table technics #2 mixin variables",filename:"tables",url:"tables.html#responsive-table-technics-2-mixin-variables"},{title:"tooltips",filename:"tooltips",url:"tooltips.html"},{title:"Tooltips",filename:"tooltips",url:"tooltips.html#tooltips"},{title:"Tooltips variables",filename:"tooltips",url:"tooltips.html#tooltips-variables"},{title:"typography",filename:"typography",url:"typography.html"},{title:"Typogrphy",filename:"typography",url:"typography.html#typogrphy"},{title:"Typography variables",filename:"typography",url:"typography.html#typography-variables"},{title:"Font-size mixin",filename:"typography",url:"typography.html#fontsize-mixin"},{title:"Line-height mixin",filename:"typography",url:"typography.html#lineheight-mixin"},{title:"Word breaking mixin",filename:"typography",url:"typography.html#word-breaking-mixin"},{title:"Font face mixin",filename:"typography",url:"typography.html#font-face-mixin"},{title:"Text overflow mixin",filename:"typography",url:"typography.html#text-overflow-mixin"},{title:"Text hide",filename:"typography",url:"typography.html#text-hide"},{title:"Hyphens",filename:"typography",url:"typography.html#hyphens"},{title:"Font style and color",filename:"typography",url:"typography.html#font-style-and-color"},{title:"Font style mixin variables",filename:"typography",url:"typography.html#font-style-mixin-variables"},{title:"Reset list styles",filename:"typography",url:"typography.html#reset-list-styles"},{title:"Reset list styles variables",filename:"typography",url:"typography.html#reset-list-styles-variables"},{title:"Inline-block list item styling",filename:"typography",url:"typography.html#inlineblock-list-item-styling"},{title:"Link styling mixin",filename:"typography",url:"typography.html#link-styling-mixin"},{title:"Link styling mixin variables",filename:"typography",url:"typography.html#link-styling-mixin-variables"},{title:"Heading styling mixin",filename:"typography",url:"typography.html#heading-styling-mixin"},{title:"Base typography mixins",filename:"typography",url:"typography.html#base-typography-mixins"},{title:"Base typography mixin variables",filename:"typography",url:"typography.html#base-typography-mixin-variables"},{title:"Headings typography mixin",filename:"typography",url:"typography.html#headings-typography-mixin"},{title:"Headings typography mixin variables",filename:"typography",url:"typography.html#headings-typography-mixin-variables"},{title:"Typography links mixin",filename:"typography",url:"typography.html#typography-links-mixin"},{title:"Typography lists mixin",filename:"typography",url:"typography.html#typography-lists-mixin"},{title:"Typography lists mixin variables",filename:"typography",url:"typography.html#typography-lists-mixin-variables"},{title:"Typography code elements mixin",filename:"typography",url:"typography.html#typography-code-elements-mixin"},{title:"Typography code mixin variables",filename:"typography",url:"typography.html#typography-code-mixin-variables"},{title:"Typography blockquote",filename:"typography",url:"typography.html#typography-blockquote"},{title:"Typography blockquote mixin variables",filename:"typography",url:"typography.html#typography-blockquote-mixin-variables"},{title:"utilities",filename:"utilities",url:"utilities.html"},{title:"Utilities",filename:"utilities",url:"utilities.html#utilities"},{title:".lib-clearfix()",filename:"utilities",url:"utilities.html#libclearfix"},{title:".lib-visibility-hidden()",filename:"utilities",url:"utilities.html#libvisibilityhidden"},{title:".lib-visually-hidden()",filename:"utilities",url:"utilities.html#libvisuallyhidden"},{title:".lib-visually-hidden-reset()",filename:"utilities",url:"utilities.html#libvisuallyhiddenreset"},{title:".lib-css()",filename:"utilities",url:"utilities.html#libcss"},{title:".lib-css() variables",filename:"utilities",url:"utilities.html#libcss-variables"},{title:".lib-rotate()",filename:"utilities",url:"utilities.html#librotate"},{title:".lib-rotate() variables",filename:"utilities",url:"utilities.html#librotate-variables"},{title:".lib-input-placeholder()",filename:"utilities",url:"utilities.html#libinputplaceholder"},{title:".lib-input-placeholder() variables",filename:"utilities",url:"utilities.html#libinputplaceholder-variables"},{title:".lib-background-gradient()",filename:"utilities",url:"utilities.html#libbackgroundgradient"},{title:".lib-background-gradient() variables",filename:"utilities",url:"utilities.html#libbackgroundgradient-variables"},{title:"variables",filename:"variables",url:"variables.html"},{title:"List of Global Variables",filename:"variables",url:"variables.html#list-of-global-variables"},{title:"Table with rows hover mixin variables",filename:"variables",url:"variables.html#table-with-rows-hover-mixin-variables"},{title:"docs",filename:"docs",url:"docs.html"},{title:"Documentation",filename:"docs",url:"docs.html#documentation"}];(function(){"use strict";var b=function(a,b){return Array.prototype.indexOf.call(a,b)!==-1},c=function(a,b){return Array.prototype.filter.call(a,b)},d=function(a,b){return Array.prototype.forEach.call(a,b)},e=document.getElementsByTagName("body")[0];e.addEventListener("click",function(a){var b=a.target;b.tagName.toLowerCase()==="svg"&&(b=b.parentNode);var c=!1;b.dataset.toggle!=null&&(a.preventDefault(),b.classList.contains("is-active")||(c=!0)),d(e.querySelectorAll("[data-toggle]"),function(a){a.classList.remove("is-active"),document.getElementById(a.dataset.toggle).hidden=!0}),c&&(b.classList.add("is-active"),document.getElementById(b.dataset.toggle).hidden=!1)}),function(){var f=e.getElementsByClassName("nav")[0];if(!f)return;var g=document.createElement("ul");g.className="nav-results",g.id="nav-search",g.hidden=!0,d(a,function(a){var b,c,d;b=document.createElement("li"),b._title=a.title.toLowerCase(),b.hidden=!0,b.appendChild(c=document.createElement("a")),c.href=a.url,c.innerHTML=a.title,c.appendChild(d=document.createElement("span")),d.innerHTML=a.filename,d.className="nav-results-filename",g.appendChild(b)}),f.appendChild(g);var h=g.children,i=function(a){d(h,function(a){a.hidden=!0});var b=this.value.toLowerCase(),e=[];b!==""&&(e=c(h,function(a){return a._title.indexOf(b)!==-1})),e.length>0?(d(e,function(a){a.hidden=!1}),g.hidden=!1):g.hidden=!0},j=f.querySelector('input[type="search"]');j.addEventListener("keyup",i),j.addEventListener("focus",i),e.addEventListener("click",function(a){if(a.target.classList&&a.target.classList.contains("search"))return;g.hidden=!0}),g.addEventListener("click",function(a){j.value=""});var k=document.createElement("ul");k.id="nav-toc",k.hidden=!0,k.className="nav-results toc-list",c(e.getElementsByTagName("*"),function(a){return b(["h1","h2","h3"],a.tagName.toLowerCase())}).map(function(a){var b=document.createElement("li"),c=document.createElement("a"),d=a.tagName.toLowerCase()[1];c.classList.add("level-"+d),b.appendChild(c),c.href="#"+a.id,c.innerHTML=a.innerHTML,k.appendChild(b)}),f.appendChild(k)}()})(),function(){"use strict";if(location.hash==="#__preview__"||location.protocol==="data:")return;var a=function(a,b){return Array.prototype.forEach.call(a,b)},b=function(a,b){var e=Array.prototype.slice.call(arguments,2);return d(a,function(a){return(c(b)?b||a:a[b]).apply(a,e)})},c=function(a){return Object.prototype.toString.call(a)==="[object Function]"},d=function(a,b){return Array.prototype.map.call(a,b)},e=function(a,b){return d(a,function(a){return a[b]})},f=function(a){var b={},c=a.split(";");for(var d=0;c.length>d;d++){var e=c[d].trim().split("=");b[e[0]]=e[1]}return b},g=function(a,c){return b(e(a,"classList"),"remove",c)},h=function(a,b){a.contentDocument.defaultView.postMessage(b,"*")},i=document.getElementsByTagName("head")[0],j=document.getElementsByTagName("body")[0],k=e(i.querySelectorAll('style[type="text/preview"]'),"innerHTML").join(""),l=e(i.querySelectorAll('script[type="text/preview"]'),"innerHTML").join(""),m=location.href.split("#")[0]+"#__preview__",n=document.createElement("iframe");n.src="data:text/html,",j.appendChild(n),n.addEventListener("load",function(){var b={sameOriginDataUri:!0};try{this.contentDocument,this.contentDocument||(b.sameOriginDataUri=!1)}catch(c){b.sameOriginDataUri=!1}this.parentNode.removeChild(this),a(j.getElementsByTagName("textarea"),function(a,c){o(a,b,c),q(),p(a)})});var o=function(a,b,c){var d,e,f;d=document.createElement("div"),d.appendChild(e=document.createElement("div")),d.className="preview",e.appendChild(f=document.createElement("iframe")),e.className="resizeable",f.setAttribute("scrolling","no"),f.name="iframe"+c++,f.addEventListener("load",function(){var c,d,e,f,g,i,j;j=this.contentDocument;if(!b.sameOriginDataUri&&this.src!==m)return;this.src===m&&(c=j.createElement("html"),c.appendChild(j.createElement("head")),c.appendChild(d=j.createElement("body")),d.innerHTML=a.textContent,j.replaceChild(c,j.documentElement)),g=j.createElement("head"),g.appendChild(f=j.createElement("style")),g.appendChild(e=j.createElement("script")),e.textContent=l,f.textContent=k,i=j.getElementsByTagName("head")[0],i.parentNode.replaceChild(g,i),h(this,"getHeight")});var g;b.sameOriginDataUri?g="data:text/html;charset=utf-8,"+encodeURIComponent("<!doctype html><html><head></head></body>"+a.textContent):g=m,f.setAttribute("src",g);var i=function(){f.contentDocument.body.innerHTML=this.value,h(f,"getHeight")};a.addEventListener("keypress",i),a.addEventListener("keyup",i),a.parentNode.insertBefore(d,a)},p=function(a){var b=document.createElement("div");b.className="preview-code",b.style.position="absolute",b.style.left="-9999px",j.appendChild(b);var c=parseInt(window.getComputedStyle(a).getPropertyValue("max-height"),10),d=function(a){b.textContent=this.value+"\n";var d=b.offsetHeight+2;d>=c?this.style.overflow="auto":this.style.overflow="hidden",this.style.height=b.offsetHeight+2+"px"};a.addEventListener("keypress",d),a.addEventListener("keyup",d),d.call(a)},q=function(){var b=j.getElementsByClassName("settings")[0],c=j.getElementsByClassName("resizeable"),d=30,e=function(b){document.cookie="preview-width="+b,a(c,function(a){b==="auto"&&(b=a.parentNode.offsetWidth),a.style.width=b+"px",h(a.getElementsByTagName("iframe")[0],"getHeight")})},i=f(document.cookie)["preview-width"];if(i){e(i),g(b.getElementsByClassName("is-active"),"is-active");var k=b.querySelector('button[data-width="'+i+'"]');k&&k.classList.add("is-active")}window.addEventListener("message",function(a){if(a.data==null||!a.source)return;var b=a.data,c=document.getElementsByName(a.source.name)[0];b.height!=null&&c&&(c.parentNode.style.height=b.height+d+"px")},!1),b&&c.length>0&&(b.hidden=!1,b.addEventListener("click",function(a){var c=a.target.tagName.toLowerCase(),d;if(c==="button")d=a.target;else{if(c!=="svg")return;d=a.target.parentNode}a.preventDefault(),g(b.getElementsByClassName("is-active"),"is-active"),d.classList.add("is-active");var f=d.dataset.width;e(f)}))}}()})()</script></body></html><!-- Generated with StyleDocco (http://jacobrask.github.com/styledocco). --> diff --git a/lib/web/css/docs/forms.html b/lib/web/css/docs/forms.html index ca3e2e6184677..211a9bd650ba0 100644 --- a/lib/web/css/docs/forms.html +++ b/lib/web/css/docs/forms.html @@ -1133,4 +1133,4 @@ <h2 id="simple-form-with-required-fields-message">Simple form with "require </tr> </table> </pre> -</div></article></section><div class="bar bottom"><div hidden class="settings container"><!-- Icons from http://iconmonstr.com--><button title="Desktop (1280)" data-width='1280'><svg viewBox="0 0 412 386" height="24" width="26" class="icon"><path d="m147.6,343.9c-4.5,15.9-26.2,37.6-42.1,42.1h201c-15.3,-4-38.1,-26.8-42.1,-42.1H147.6zM387,0.5H25c-13.8,0-25,11.2-25,25V294c0,13.8 11.2,25 25,25h362c13.8,0 25,-11.2 25,-25V25.5C412,11.7 400.8,0.5 387,0.5zM369.9,238.2H42.1L42.1,42.6 369.9,42.6V238.2z"></path></svg></button><button title="Laptop (1024)" data-width='1024'><svg viewBox="0 0 384 312" height="23" width="28" class="icon"><path d="m349.2,20.5c0,-11-9,-20-20,-20H53.6c-11,0-20,9-20,20v194H349.2v-194zm-27,167H60.6V27.5H322.2v160zm28,42H32.6L2.6,282.1c-3.5,6.2-3.5,13.8 0.1,19.9 3.6,6.2 10.2,9.9 17.3,9.9H363.1c7.1,0 13.7,-3.8 17.3,-10 3.6,-6.2 3.6,-13.8 0,-20l-30.2,-52.5zm-196.9,54 8,-23.5h60.5l8,23.5h-76.5z"></path></svg></button><button title="Tablet (768)" data-width='768'><svg viewBox="0 0 317 412" height="24" width="18" class="icon"><path d="M 316.5,380 V 32 c 0,-17.7 -14.3,-32 -32,-32 H 32 C 14.3,0 0,14.3 0,32 v 348 c 0,17.7 14.3,32 32,32 h 252.5 c 17.7,0 32,-14.3 32,-32 z M 40,367 V 45 H 276.5 V 367 H 40 z m 109.8,22.7 c 0,-4.7 3.8,-8.5 8.5,-8.5 4.7,0 8.5,3.8 8.5,8.5 0,4.7 -3.8,8.5 -8.5,8.5 -4.7,0 -8.5,-3.8 -8.5,-8.5 z"></path></svg></button><button title="Smart phone (320)" data-width='320'><svg viewBox="0 0 224 412" height="24" width="13" class="icon"><path d="M 190.7,0 H 33 C 14.8,0 0,14.8 0,33 v 346 c 0,18.2 14.8,33 33,33 h 157.7 c 18.2,0 33,-14.8 33,-33 V 33 c 0,-18.2 -14.8,-33 -33,-33 z M 94.3,30.2 h 37 c 2.2,0 4,1.8 4,4 0,2.2 -1.8,4 -4,4 h -37 c -2.2,0 -4,-1.8 -4,-4 0,-2.2 1.8,-4 4,-4 z m 18.5,362.8 c -8.8,0 -16,-7.2 -16,-16 0,-8.8 7.2,-16 16,-16 8.8,0 16,7.2 16,16 0,8.8 -7.2,16 -16,16 z M 198.6,343.8 H 25.1 V 68.2 h 173.5 v 275.5 z"></path></svg></button><button title="Feature phone (240)" data-width='240'><svg viewBox="0 0 201 412" height="24" width="12" class="icon"><path d="M 165.5,0.2 V 45 H 25 c -13.8,0 -25,11.2 -25,25 V 387 c 0,13.8 11.2,25 25,25 h 150.5 c 13.8,0 25,-11.2 25,-25 V 0.2 h -35 z M 65.2,366.5 H 34.2 v -24.5 h 31 v 24.5 z m 0,-44.3 H 34.2 v -24.5 h 31 v 24.5 z m 50.5,44.3 H 84.7 v -24.5 h 31 v 24.5 z m 0,-44.3 H 84.7 v -24.5 h 31 v 24.5 z m 50.5,44.3 h -31 v -24.5 h 31 v 24.5 z m 0,-44.3 h -31 v -24.5 h 31 v 24.5 z m 0,-59.3 h -132 V 95.4 h 132 V 262.9 z"></path></svg></button><button title="Auto (100%)" data-width="auto" class="auto is-active">Auto</button></div></div><script>(function(){var a=[{title:"actions-toolbar",filename:"actions-toolbar",url:"actions-toolbar.html"},{title:"Actions toolbar",filename:"actions-toolbar",url:"actions-toolbar.html#actions-toolbar"},{title:"Actions toolbar mixin variables",filename:"actions-toolbar",url:"actions-toolbar.html#actions-toolbar-mixin-variables"},{title:"Actions toolbar alignment",filename:"actions-toolbar",url:"actions-toolbar.html#actions-toolbar-alignment"},{title:"Reverse primary and secondary blocks",filename:"actions-toolbar",url:"actions-toolbar.html#reverse-primary-and-secondary-blocks"},{title:"Actions toolbar indents customizations",filename:"actions-toolbar",url:"actions-toolbar.html#actions-toolbar-indents-customizations"},{title:"Responsive actions toolbar",filename:"actions-toolbar",url:"actions-toolbar.html#responsive-actions-toolbar"},{title:"breadcrumbs",filename:"breadcrumbs",url:"breadcrumbs.html"},{title:"Breadcrumbs",filename:"breadcrumbs",url:"breadcrumbs.html#breadcrumbs"},{title:"Breadcrumbs variables",filename:"breadcrumbs",url:"breadcrumbs.html#breadcrumbs-variables"},{title:"Button-styled breadcrumbs with gradient background, border, and no separating symbol",filename:"breadcrumbs",url:"breadcrumbs.html#buttonstyled-breadcrumbs-with-gradient-background-border-and-no-separating-symbol"},{title:"Breadcrumbs with solid background",filename:"breadcrumbs",url:"breadcrumbs.html#breadcrumbs-with-solid-background"},{title:"buttons",filename:"buttons",url:"buttons.html"},{title:"Default button",filename:"buttons",url:"buttons.html#default-button"},{title:"Button variables",filename:"buttons",url:"buttons.html#button-variables"},{title:"Button as an icon",filename:"buttons",url:"buttons.html#button-as-an-icon"},{title:"Button with an icon on the left or right side of the text",filename:"buttons",url:"buttons.html#button-with-an-icon-on-the-left-or-right-side-of-the-text"},{title:"Button with fixed width",filename:"buttons",url:"buttons.html#button-with-fixed-width"},{title:"Primary button",filename:"buttons",url:"buttons.html#primary-button"},{title:"Primary button variables",filename:"buttons",url:"buttons.html#primary-button-variables"},{title:"Button with gradient background",filename:"buttons",url:"buttons.html#button-with-gradient-background"},{title:"Button as a link",filename:"buttons",url:"buttons.html#button-as-a-link"},{title:"Button as a link variables",filename:"buttons",url:"buttons.html#button-as-a-link-variables"},{title:"Link as a button",filename:"buttons",url:"buttons.html#link-as-a-button"},{title:"Button reset",filename:"buttons",url:"buttons.html#button-reset"},{title:"Button revert secondary color",filename:"buttons",url:"buttons.html#button-revert-secondary-color"},{title:"Button revert secondary color variables",filename:"buttons",url:"buttons.html#button-revert-secondary-color-variables"},{title:"Button revert secondary size",filename:"buttons",url:"buttons.html#button-revert-secondary-size"},{title:"Button revert secondary size variables",filename:"buttons",url:"buttons.html#button-revert-secondary-size-variables"},{title:"components",filename:"components",url:"components.html"},{title:"Components",filename:"components",url:"components.html#components"},{title:"Components Variables",filename:"components",url:"components.html#components-variables"},{title:"dropdowns",filename:"dropdowns",url:"dropdowns.html"},{title:"Drop-down and split buttons mixins",filename:"dropdowns",url:"dropdowns.html#dropdown-and-split-buttons-mixins"},{title:"Drop-down",filename:"dropdowns",url:"dropdowns.html#dropdown"},{title:"Drop-down variables",filename:"dropdowns",url:"dropdowns.html#dropdown-variables"},{title:"Drop-down with icon customization",filename:"dropdowns",url:"dropdowns.html#dropdown-with-icon-customization"},{title:"Modify dropdown list styles",filename:"dropdowns",url:"dropdowns.html#modify-dropdown-list-styles"},{title:"Split button",filename:"dropdowns",url:"dropdowns.html#split-button"},{title:"Split button variables",filename:"dropdowns",url:"dropdowns.html#split-button-variables"},{title:"Split button - button styling",filename:"dropdowns",url:"dropdowns.html#split-button-button-styling"},{title:"Split button icon customization",filename:"dropdowns",url:"dropdowns.html#split-button-icon-customization"},{title:"Split button drop-down list customization",filename:"dropdowns",url:"dropdowns.html#split-button-dropdown-list-customization"},{title:"forms",filename:"forms",url:"forms.html"},{title:"Forms mixins",filename:"forms",url:"forms.html#forms-mixins"},{title:"Global forms elements customization",filename:"forms",url:"forms.html#global-forms-elements-customization"},{title:"Fieldsets & fields customization",filename:"forms",url:"forms.html#fieldsets-fields-customization"},{title:"Fieldset and legend customization variables",filename:"forms",url:"forms.html#fieldset-and-legend-customization-variables"},{title:"Fields customization variables",filename:"forms",url:"forms.html#fields-customization-variables"},{title:"Required fields message customization variables",filename:"forms",url:"forms.html#required-fields-message-customization-variables"},{title:"Form element inputs customization",filename:"forms",url:"forms.html#form-element-inputs-customization"},{title:"Form element inputs customization variables",filename:"forms",url:"forms.html#form-element-inputs-customization-variables"},{title:"Form element choice",filename:"forms",url:"forms.html#form-element-choice"},{title:"Form element choice variables",filename:"forms",url:"forms.html#form-element-choice-variables"},{title:"Custom color",filename:"forms",url:"forms.html#custom-color"},{title:"Input number - input-text view",filename:"forms",url:"forms.html#input-number-inputtext-view"},{title:"Input search - input-text view",filename:"forms",url:"forms.html#input-search-inputtext-view"},{title:"Form validation",filename:"forms",url:"forms.html#form-validation"},{title:"Form validation variables",filename:"forms",url:"forms.html#form-validation-variables"},{title:"icons",filename:"icons",url:"icons.html"},{title:"Icons",filename:"icons",url:"icons.html#icons"},{title:"Icon with image or sprite",filename:"icons",url:"icons.html#icon-with-image-or-sprite"},{title:"Icon with image or sprite variables",filename:"icons",url:"icons.html#icon-with-image-or-sprite-variables"},{title:"Icon position for an icon with image or sprite",filename:"icons",url:"icons.html#icon-position-for-an-icon-with-image-or-sprite"},{title:"Position for icon with image or sprite mixin variables",filename:"icons",url:"icons.html#position-for-icon-with-image-or-sprite-mixin-variables"},{title:"Icon sprite position (with grid)",filename:"icons",url:"icons.html#icon-sprite-position-with-grid"},{title:"Icon sprite position variables",filename:"icons",url:"icons.html#icon-sprite-position-variables"},{title:"Image/sprite icon size",filename:"icons",url:"icons.html#imagesprite-icon-size"},{title:"Image/sprite icon size variables",filename:"icons",url:"icons.html#imagesprite-icon-size-variables"},{title:"Font icon",filename:"icons",url:"icons.html#font-icon"},{title:"Font icon variables",filename:"icons",url:"icons.html#font-icon-variables"},{title:"Change the size of font icon",filename:"icons",url:"icons.html#change-the-size-of-font-icon"},{title:"Change the size of font icon variables",filename:"icons",url:"icons.html#change-the-size-of-font-icon-variables"},{title:"Hide icon text",filename:"icons",url:"icons.html#hide-icon-text"},{title:"Sprite and font icons for Blank theme",filename:"icons",url:"icons.html#sprite-and-font-icons-for-blank-theme"},{title:"layout",filename:"layout",url:"layout.html"},{title:"Layout",filename:"layout",url:"layout.html#layout"},{title:"Layout global variables",filename:"layout",url:"layout.html#layout-global-variables"},{title:"Page layouts",filename:"layout",url:"layout.html#page-layouts"},{title:"Layout column",filename:"layout",url:"layout.html#layout-column"},{title:"Layout column variables",filename:"layout",url:"layout.html#layout-column-variables"},{title:"Layout width",filename:"layout",url:"layout.html#layout-width"},{title:"Layout width variables",filename:"layout",url:"layout.html#layout-width-variables"},{title:"lib",filename:"lib",url:"lib.html"},{title:"Including Magento UI library to your theme",filename:"lib",url:"lib.html#including-magento-ui-library-to-your-theme"},{title:"loaders",filename:"loaders",url:"loaders.html"},{title:"Loaders",filename:"loaders",url:"loaders.html#loaders"},{title:"Default loader variables",filename:"loaders",url:"loaders.html#default-loader-variables"},{title:"Loading",filename:"loaders",url:"loaders.html#loading"},{title:"Loading default variables",filename:"loaders",url:"loaders.html#loading-default-variables"},{title:"messages",filename:"messages",url:"messages.html"},{title:"Messages",filename:"messages",url:"messages.html#messages"},{title:"Information message",filename:"messages",url:"messages.html#information-message"},{title:"Warning message",filename:"messages",url:"messages.html#warning-message"},{title:"Error message",filename:"messages",url:"messages.html#error-message"},{title:"Success message",filename:"messages",url:"messages.html#success-message"},{title:"Notice message",filename:"messages",url:"messages.html#notice-message"},{title:"Message with inner icon",filename:"messages",url:"messages.html#message-with-inner-icon"},{title:"Message with lateral icon",filename:"messages",url:"messages.html#message-with-lateral-icon"},{title:"Custom message style",filename:"messages",url:"messages.html#custom-message-style"},{title:"Messages global variables",filename:"messages",url:"messages.html#messages-global-variables"},{title:"pages",filename:"pages",url:"pages.html"},{title:"Pagination HTML markup",filename:"pages",url:"pages.html#pagination-html-markup"},{title:"Pagination variables",filename:"pages",url:"pages.html#pagination-variables"},{title:"Pagination with label and gradient background on links",filename:"pages",url:"pages.html#pagination-with-label-and-gradient-background-on-links"},{title:'Pagination with "previous"..."next" text links and label',filename:"pages",url:"pages.html#pagination-with-previousnext-text-links-and-label"},{title:"Pagination without label, with solid background",filename:"pages",url:"pages.html#pagination-without-label-with-solid-background"},{title:"popups",filename:"popups",url:"popups.html"},{title:"Popups",filename:"popups",url:"popups.html#popups"},{title:"Popup variables",filename:"popups",url:"popups.html#popup-variables"},{title:"Window overlay mixin variables",filename:"popups",url:"popups.html#window-overlay-mixin-variables"},{title:"Fixed height popup",filename:"popups",url:"popups.html#fixed-height-popup"},{title:"Fixed content height popup",filename:"popups",url:"popups.html#fixed-content-height-popup"},{title:"Margins for header, content and footer block in popup",filename:"popups",url:"popups.html#margins-for-header-content-and-footer-block-in-popup"},{title:"Popup titles styled as theme headings",filename:"popups",url:"popups.html#popup-titles-styled-as-theme-headings"},{title:"Popup action toolbar",filename:"popups",url:"popups.html#popup-action-toolbar"},{title:"Popup Close button without an icon",filename:"popups",url:"popups.html#popup-close-button-without-an-icon"},{title:"Modify the icon of popup Close button",filename:"popups",url:"popups.html#modify-the-icon-of-popup-close-button"},{title:"Modify overlay styles",filename:"popups",url:"popups.html#modify-overlay-styles"},{title:"rating",filename:"rating",url:"rating.html"},{title:"Ratings",filename:"rating",url:"rating.html#ratings"},{title:"Global rating variables",filename:"rating",url:"rating.html#global-rating-variables"},{title:"Rating with vote",filename:"rating",url:"rating.html#rating-with-vote"},{title:"Rating with vote icons number customization",filename:"rating",url:"rating.html#rating-with-vote-icons-number-customization"},{title:"Rating with vote icons colors customization",filename:"rating",url:"rating.html#rating-with-vote-icons-colors-customization"},{title:"Rating with vote icons symbol customization",filename:"rating",url:"rating.html#rating-with-vote-icons-symbol-customization"},{title:"Accessible rating with vote",filename:"rating",url:"rating.html#accessible-rating-with-vote"},{title:"Rating summary",filename:"rating",url:"rating.html#rating-summary"},{title:"Rating summary icons number customization",filename:"rating",url:"rating.html#rating-summary-icons-number-customization"},{title:"Rating summary icons color customization",filename:"rating",url:"rating.html#rating-summary-icons-color-customization"},{title:"Rating summary icons symbol customization",filename:"rating",url:"rating.html#rating-summary-icons-symbol-customization"},{title:"Rating summary hide label",filename:"rating",url:"rating.html#rating-summary-hide-label"},{title:"Rating summary multiple ratings",filename:"rating",url:"rating.html#rating-summary-multiple-ratings"},{title:"Rating hide label mixin",filename:"rating",url:"rating.html#rating-hide-label-mixin"},{title:"resets",filename:"resets",url:"resets.html"},{title:"Resets",filename:"resets",url:"resets.html#resets"},{title:"responsive",filename:"responsive",url:"responsive.html"},{title:"Responsive",filename:"responsive",url:"responsive.html#responsive"},{title:"Responsive mixins usage",filename:"responsive",url:"responsive.html#responsive-mixins-usage"},{title:"Media query style groups separation variables",filename:"responsive",url:"responsive.html#media-query-style-groups-separation-variables"},{title:"Responsive breakpoints",filename:"responsive",url:"responsive.html#responsive-breakpoints"},{title:"sections",filename:"sections",url:"sections.html"},{title:"Tabs and accordions",filename:"sections",url:"sections.html#tabs-and-accordions"},{title:"Tabs",filename:"sections",url:"sections.html#tabs"},{title:"Tabs mixin variables",filename:"sections",url:"sections.html#tabs-mixin-variables"},{title:"Tabs with content top border",filename:"sections",url:"sections.html#tabs-with-content-top-border"},{title:"Accordion",filename:"sections",url:"sections.html#accordion"},{title:"Accordion mixin variables",filename:"sections",url:"sections.html#accordion-mixin-variables"},{title:"Responsive tabs",filename:"sections",url:"sections.html#responsive-tabs"},{title:"Tabs Base",filename:"sections",url:"sections.html#tabs-base"},{title:"Accordion Base",filename:"sections",url:"sections.html#accordion-base"},{title:"tables",filename:"tables",url:"tables.html"},{title:"Tables",filename:"tables",url:"tables.html#tables"},{title:"Table mixin variables",filename:"tables",url:"tables.html#table-mixin-variables"},{title:"Table typography",filename:"tables",url:"tables.html#table-typography"},{title:"Table typography mixin variables",filename:"tables",url:"tables.html#table-typography-mixin-variables"},{title:"Table caption",filename:"tables",url:"tables.html#table-caption"},{title:"Table caption mixin variables",filename:"tables",url:"tables.html#table-caption-mixin-variables"},{title:"Table cells resize",filename:"tables",url:"tables.html#table-cells-resize"},{title:"Table cells resize variables",filename:"tables",url:"tables.html#table-cells-resize-variables"},{title:"Table background customization",filename:"tables",url:"tables.html#table-background-customization"},{title:"Table background mixin variables",filename:"tables",url:"tables.html#table-background-mixin-variables"},{title:"Table borders customization",filename:"tables",url:"tables.html#table-borders-customization"},{title:"Table borders mixin variables",filename:"tables",url:"tables.html#table-borders-mixin-variables"},{title:"Table with horizontal borders",filename:"tables",url:"tables.html#table-with-horizontal-borders"},{title:"Table with vertical borders",filename:"tables",url:"tables.html#table-with-vertical-borders"},{title:"Table with light borders",filename:"tables",url:"tables.html#table-with-light-borders"},{title:"Table without borders",filename:"tables",url:"tables.html#table-without-borders"},{title:"Striped table",filename:"tables",url:"tables.html#striped-table"},{title:"Striped table mixin variables",filename:"tables",url:"tables.html#striped-table-mixin-variables"},{title:"Table with rows hover",filename:"tables",url:"tables.html#table-with-rows-hover"},{title:"Table with rows hover mixin variables",filename:"tables",url:"tables.html#table-with-rows-hover-mixin-variables"},{title:"Responsive table technics #1",filename:"tables",url:"tables.html#responsive-table-technics-1"},{title:"Responsive table technics #2",filename:"tables",url:"tables.html#responsive-table-technics-2"},{title:"Responsive table technics #2 mixin variables",filename:"tables",url:"tables.html#responsive-table-technics-2-mixin-variables"},{title:"tooltips",filename:"tooltips",url:"tooltips.html"},{title:"Tooltips",filename:"tooltips",url:"tooltips.html#tooltips"},{title:"Tooltips variables",filename:"tooltips",url:"tooltips.html#tooltips-variables"},{title:"typography",filename:"typography",url:"typography.html"},{title:"Typogrphy",filename:"typography",url:"typography.html#typogrphy"},{title:"Typography variables",filename:"typography",url:"typography.html#typography-variables"},{title:"Font-size mixin",filename:"typography",url:"typography.html#fontsize-mixin"},{title:"Line-height mixin",filename:"typography",url:"typography.html#lineheight-mixin"},{title:"Word breaking mixin",filename:"typography",url:"typography.html#word-breaking-mixin"},{title:"Font face mixin",filename:"typography",url:"typography.html#font-face-mixin"},{title:"Text overflow mixin",filename:"typography",url:"typography.html#text-overflow-mixin"},{title:"Text hide",filename:"typography",url:"typography.html#text-hide"},{title:"Hyphens",filename:"typography",url:"typography.html#hyphens"},{title:"Font style and color",filename:"typography",url:"typography.html#font-style-and-color"},{title:"Font style mixin variables",filename:"typography",url:"typography.html#font-style-mixin-variables"},{title:"Reset list styles",filename:"typography",url:"typography.html#reset-list-styles"},{title:"Reset list styles variables",filename:"typography",url:"typography.html#reset-list-styles-variables"},{title:"Inline-block list item styling",filename:"typography",url:"typography.html#inlineblock-list-item-styling"},{title:"Link styling mixin",filename:"typography",url:"typography.html#link-styling-mixin"},{title:"Link styling mixin variables",filename:"typography",url:"typography.html#link-styling-mixin-variables"},{title:"Heading styling mixin",filename:"typography",url:"typography.html#heading-styling-mixin"},{title:"Base typography mixins",filename:"typography",url:"typography.html#base-typography-mixins"},{title:"Base typography mixin variables",filename:"typography",url:"typography.html#base-typography-mixin-variables"},{title:"Headings typography mixin",filename:"typography",url:"typography.html#headings-typography-mixin"},{title:"Headings typography mixin variables",filename:"typography",url:"typography.html#headings-typography-mixin-variables"},{title:"Typography links mixin",filename:"typography",url:"typography.html#typography-links-mixin"},{title:"Typography lists mixin",filename:"typography",url:"typography.html#typography-lists-mixin"},{title:"Typography lists mixin variables",filename:"typography",url:"typography.html#typography-lists-mixin-variables"},{title:"Typography code elements mixin",filename:"typography",url:"typography.html#typography-code-elements-mixin"},{title:"Typography code mixin variables",filename:"typography",url:"typography.html#typography-code-mixin-variables"},{title:"Typography blockquote",filename:"typography",url:"typography.html#typography-blockquote"},{title:"Typography blockquote mixin variables",filename:"typography",url:"typography.html#typography-blockquote-mixin-variables"},{title:"utilities",filename:"utilities",url:"utilities.html"},{title:"Utilities",filename:"utilities",url:"utilities.html#utilities"},{title:".lib-clearfix()",filename:"utilities",url:"utilities.html#libclearfix"},{title:".lib-visibility-hidden()",filename:"utilities",url:"utilities.html#libvisibilityhidden"},{title:".lib-visually-hidden()",filename:"utilities",url:"utilities.html#libvisuallyhidden"},{title:".lib-visually-hidden-reset()",filename:"utilities",url:"utilities.html#libvisuallyhiddenreset"},{title:".lib-css()",filename:"utilities",url:"utilities.html#libcss"},{title:".lib-css() variables",filename:"utilities",url:"utilities.html#libcss-variables"},{title:".lib-rotate()",filename:"utilities",url:"utilities.html#librotate"},{title:".lib-rotate() variables",filename:"utilities",url:"utilities.html#librotate-variables"},{title:".lib-input-placeholder()",filename:"utilities",url:"utilities.html#libinputplaceholder"},{title:".lib-input-placeholder() variables",filename:"utilities",url:"utilities.html#libinputplaceholder-variables"},{title:".lib-background-gradient()",filename:"utilities",url:"utilities.html#libbackgroundgradient"},{title:".lib-background-gradient() variables",filename:"utilities",url:"utilities.html#libbackgroundgradient-variables"},{title:".lib-url-check()",filename:"utilities",url:"utilities.html#liburlcheck"},{title:".lib-url-check() variables",filename:"utilities",url:"utilities.html#liburlcheck-variables"},{title:"variables",filename:"variables",url:"variables.html"},{title:"List of Global Variables",filename:"variables",url:"variables.html#list-of-global-variables"},{title:"Table with rows hover mixin variables",filename:"variables",url:"variables.html#table-with-rows-hover-mixin-variables"},{title:"docs",filename:"docs",url:"docs.html"},{title:"Documentation",filename:"docs",url:"docs.html#documentation"}];(function(){"use strict";var b=function(a,b){return Array.prototype.indexOf.call(a,b)!==-1},c=function(a,b){return Array.prototype.filter.call(a,b)},d=function(a,b){return Array.prototype.forEach.call(a,b)},e=document.getElementsByTagName("body")[0];e.addEventListener("click",function(a){var b=a.target;b.tagName.toLowerCase()==="svg"&&(b=b.parentNode);var c=!1;b.dataset.toggle!=null&&(a.preventDefault(),b.classList.contains("is-active")||(c=!0)),d(e.querySelectorAll("[data-toggle]"),function(a){a.classList.remove("is-active"),document.getElementById(a.dataset.toggle).hidden=!0}),c&&(b.classList.add("is-active"),document.getElementById(b.dataset.toggle).hidden=!1)}),function(){var f=e.getElementsByClassName("nav")[0];if(!f)return;var g=document.createElement("ul");g.className="nav-results",g.id="nav-search",g.hidden=!0,d(a,function(a){var b,c,d;b=document.createElement("li"),b._title=a.title.toLowerCase(),b.hidden=!0,b.appendChild(c=document.createElement("a")),c.href=a.url,c.innerHTML=a.title,c.appendChild(d=document.createElement("span")),d.innerHTML=a.filename,d.className="nav-results-filename",g.appendChild(b)}),f.appendChild(g);var h=g.children,i=function(a){d(h,function(a){a.hidden=!0});var b=this.value.toLowerCase(),e=[];b!==""&&(e=c(h,function(a){return a._title.indexOf(b)!==-1})),e.length>0?(d(e,function(a){a.hidden=!1}),g.hidden=!1):g.hidden=!0},j=f.querySelector('input[type="search"]');j.addEventListener("keyup",i),j.addEventListener("focus",i),e.addEventListener("click",function(a){if(a.target.classList&&a.target.classList.contains("search"))return;g.hidden=!0}),g.addEventListener("click",function(a){j.value=""});var k=document.createElement("ul");k.id="nav-toc",k.hidden=!0,k.className="nav-results toc-list",c(e.getElementsByTagName("*"),function(a){return b(["h1","h2","h3"],a.tagName.toLowerCase())}).map(function(a){var b=document.createElement("li"),c=document.createElement("a"),d=a.tagName.toLowerCase()[1];c.classList.add("level-"+d),b.appendChild(c),c.href="#"+a.id,c.innerHTML=a.innerHTML,k.appendChild(b)}),f.appendChild(k)}()})(),function(){"use strict";if(location.hash==="#__preview__"||location.protocol==="data:")return;var a=function(a,b){return Array.prototype.forEach.call(a,b)},b=function(a,b){var e=Array.prototype.slice.call(arguments,2);return d(a,function(a){return(c(b)?b||a:a[b]).apply(a,e)})},c=function(a){return Object.prototype.toString.call(a)==="[object Function]"},d=function(a,b){return Array.prototype.map.call(a,b)},e=function(a,b){return d(a,function(a){return a[b]})},f=function(a){var b={},c=a.split(";");for(var d=0;c.length>d;d++){var e=c[d].trim().split("=");b[e[0]]=e[1]}return b},g=function(a,c){return b(e(a,"classList"),"remove",c)},h=function(a,b){a.contentDocument.defaultView.postMessage(b,"*")},i=document.getElementsByTagName("head")[0],j=document.getElementsByTagName("body")[0],k=e(i.querySelectorAll('style[type="text/preview"]'),"innerHTML").join(""),l=e(i.querySelectorAll('script[type="text/preview"]'),"innerHTML").join(""),m=location.href.split("#")[0]+"#__preview__",n=document.createElement("iframe");n.src="data:text/html,",j.appendChild(n),n.addEventListener("load",function(){var b={sameOriginDataUri:!0};try{this.contentDocument,this.contentDocument||(b.sameOriginDataUri=!1)}catch(c){b.sameOriginDataUri=!1}this.parentNode.removeChild(this),a(j.getElementsByTagName("textarea"),function(a,c){o(a,b,c),q(),p(a)})});var o=function(a,b,c){var d,e,f;d=document.createElement("div"),d.appendChild(e=document.createElement("div")),d.className="preview",e.appendChild(f=document.createElement("iframe")),e.className="resizeable",f.setAttribute("scrolling","no"),f.name="iframe"+c++,f.addEventListener("load",function(){var c,d,e,f,g,i,j;j=this.contentDocument;if(!b.sameOriginDataUri&&this.src!==m)return;this.src===m&&(c=j.createElement("html"),c.appendChild(j.createElement("head")),c.appendChild(d=j.createElement("body")),d.innerHTML=a.textContent,j.replaceChild(c,j.documentElement)),g=j.createElement("head"),g.appendChild(f=j.createElement("style")),g.appendChild(e=j.createElement("script")),e.textContent=l,f.textContent=k,i=j.getElementsByTagName("head")[0],i.parentNode.replaceChild(g,i),h(this,"getHeight")});var g;b.sameOriginDataUri?g="data:text/html;charset=utf-8,"+encodeURIComponent("<!doctype html><html><head></head></body>"+a.textContent):g=m,f.setAttribute("src",g);var i=function(){f.contentDocument.body.innerHTML=this.value,h(f,"getHeight")};a.addEventListener("keypress",i),a.addEventListener("keyup",i),a.parentNode.insertBefore(d,a)},p=function(a){var b=document.createElement("div");b.className="preview-code",b.style.position="absolute",b.style.left="-9999px",j.appendChild(b);var c=parseInt(window.getComputedStyle(a).getPropertyValue("max-height"),10),d=function(a){b.textContent=this.value+"\n";var d=b.offsetHeight+2;d>=c?this.style.overflow="auto":this.style.overflow="hidden",this.style.height=b.offsetHeight+2+"px"};a.addEventListener("keypress",d),a.addEventListener("keyup",d),d.call(a)},q=function(){var b=j.getElementsByClassName("settings")[0],c=j.getElementsByClassName("resizeable"),d=30,e=function(b){document.cookie="preview-width="+b,a(c,function(a){b==="auto"&&(b=a.parentNode.offsetWidth),a.style.width=b+"px",h(a.getElementsByTagName("iframe")[0],"getHeight")})},i=f(document.cookie)["preview-width"];if(i){e(i),g(b.getElementsByClassName("is-active"),"is-active");var k=b.querySelector('button[data-width="'+i+'"]');k&&k.classList.add("is-active")}window.addEventListener("message",function(a){if(a.data==null||!a.source)return;var b=a.data,c=document.getElementsByName(a.source.name)[0];b.height!=null&&c&&(c.parentNode.style.height=b.height+d+"px")},!1),b&&c.length>0&&(b.hidden=!1,b.addEventListener("click",function(a){var c=a.target.tagName.toLowerCase(),d;if(c==="button")d=a.target;else{if(c!=="svg")return;d=a.target.parentNode}a.preventDefault(),g(b.getElementsByClassName("is-active"),"is-active"),d.classList.add("is-active");var f=d.dataset.width;e(f)}))}}()})()</script></body></html><!-- Generated with StyleDocco (http://jacobrask.github.com/styledocco). --> +</div></article></section><div class="bar bottom"><div hidden class="settings container"><!-- Icons from http://iconmonstr.com--><button title="Desktop (1280)" data-width='1280'><svg viewBox="0 0 412 386" height="24" width="26" class="icon"><path d="m147.6,343.9c-4.5,15.9-26.2,37.6-42.1,42.1h201c-15.3,-4-38.1,-26.8-42.1,-42.1H147.6zM387,0.5H25c-13.8,0-25,11.2-25,25V294c0,13.8 11.2,25 25,25h362c13.8,0 25,-11.2 25,-25V25.5C412,11.7 400.8,0.5 387,0.5zM369.9,238.2H42.1L42.1,42.6 369.9,42.6V238.2z"></path></svg></button><button title="Laptop (1024)" data-width='1024'><svg viewBox="0 0 384 312" height="23" width="28" class="icon"><path d="m349.2,20.5c0,-11-9,-20-20,-20H53.6c-11,0-20,9-20,20v194H349.2v-194zm-27,167H60.6V27.5H322.2v160zm28,42H32.6L2.6,282.1c-3.5,6.2-3.5,13.8 0.1,19.9 3.6,6.2 10.2,9.9 17.3,9.9H363.1c7.1,0 13.7,-3.8 17.3,-10 3.6,-6.2 3.6,-13.8 0,-20l-30.2,-52.5zm-196.9,54 8,-23.5h60.5l8,23.5h-76.5z"></path></svg></button><button title="Tablet (768)" data-width='768'><svg viewBox="0 0 317 412" height="24" width="18" class="icon"><path d="M 316.5,380 V 32 c 0,-17.7 -14.3,-32 -32,-32 H 32 C 14.3,0 0,14.3 0,32 v 348 c 0,17.7 14.3,32 32,32 h 252.5 c 17.7,0 32,-14.3 32,-32 z M 40,367 V 45 H 276.5 V 367 H 40 z m 109.8,22.7 c 0,-4.7 3.8,-8.5 8.5,-8.5 4.7,0 8.5,3.8 8.5,8.5 0,4.7 -3.8,8.5 -8.5,8.5 -4.7,0 -8.5,-3.8 -8.5,-8.5 z"></path></svg></button><button title="Smart phone (320)" data-width='320'><svg viewBox="0 0 224 412" height="24" width="13" class="icon"><path d="M 190.7,0 H 33 C 14.8,0 0,14.8 0,33 v 346 c 0,18.2 14.8,33 33,33 h 157.7 c 18.2,0 33,-14.8 33,-33 V 33 c 0,-18.2 -14.8,-33 -33,-33 z M 94.3,30.2 h 37 c 2.2,0 4,1.8 4,4 0,2.2 -1.8,4 -4,4 h -37 c -2.2,0 -4,-1.8 -4,-4 0,-2.2 1.8,-4 4,-4 z m 18.5,362.8 c -8.8,0 -16,-7.2 -16,-16 0,-8.8 7.2,-16 16,-16 8.8,0 16,7.2 16,16 0,8.8 -7.2,16 -16,16 z M 198.6,343.8 H 25.1 V 68.2 h 173.5 v 275.5 z"></path></svg></button><button title="Feature phone (240)" data-width='240'><svg viewBox="0 0 201 412" height="24" width="12" class="icon"><path d="M 165.5,0.2 V 45 H 25 c -13.8,0 -25,11.2 -25,25 V 387 c 0,13.8 11.2,25 25,25 h 150.5 c 13.8,0 25,-11.2 25,-25 V 0.2 h -35 z M 65.2,366.5 H 34.2 v -24.5 h 31 v 24.5 z m 0,-44.3 H 34.2 v -24.5 h 31 v 24.5 z m 50.5,44.3 H 84.7 v -24.5 h 31 v 24.5 z m 0,-44.3 H 84.7 v -24.5 h 31 v 24.5 z m 50.5,44.3 h -31 v -24.5 h 31 v 24.5 z m 0,-44.3 h -31 v -24.5 h 31 v 24.5 z m 0,-59.3 h -132 V 95.4 h 132 V 262.9 z"></path></svg></button><button title="Auto (100%)" data-width="auto" class="auto is-active">Auto</button></div></div><script>(function(){var a=[{title:"actions-toolbar",filename:"actions-toolbar",url:"actions-toolbar.html"},{title:"Actions toolbar",filename:"actions-toolbar",url:"actions-toolbar.html#actions-toolbar"},{title:"Actions toolbar mixin variables",filename:"actions-toolbar",url:"actions-toolbar.html#actions-toolbar-mixin-variables"},{title:"Actions toolbar alignment",filename:"actions-toolbar",url:"actions-toolbar.html#actions-toolbar-alignment"},{title:"Reverse primary and secondary blocks",filename:"actions-toolbar",url:"actions-toolbar.html#reverse-primary-and-secondary-blocks"},{title:"Actions toolbar indents customizations",filename:"actions-toolbar",url:"actions-toolbar.html#actions-toolbar-indents-customizations"},{title:"Responsive actions toolbar",filename:"actions-toolbar",url:"actions-toolbar.html#responsive-actions-toolbar"},{title:"breadcrumbs",filename:"breadcrumbs",url:"breadcrumbs.html"},{title:"Breadcrumbs",filename:"breadcrumbs",url:"breadcrumbs.html#breadcrumbs"},{title:"Breadcrumbs variables",filename:"breadcrumbs",url:"breadcrumbs.html#breadcrumbs-variables"},{title:"Button-styled breadcrumbs with gradient background, border, and no separating symbol",filename:"breadcrumbs",url:"breadcrumbs.html#buttonstyled-breadcrumbs-with-gradient-background-border-and-no-separating-symbol"},{title:"Breadcrumbs with solid background",filename:"breadcrumbs",url:"breadcrumbs.html#breadcrumbs-with-solid-background"},{title:"buttons",filename:"buttons",url:"buttons.html"},{title:"Default button",filename:"buttons",url:"buttons.html#default-button"},{title:"Button variables",filename:"buttons",url:"buttons.html#button-variables"},{title:"Button as an icon",filename:"buttons",url:"buttons.html#button-as-an-icon"},{title:"Button with an icon on the left or right side of the text",filename:"buttons",url:"buttons.html#button-with-an-icon-on-the-left-or-right-side-of-the-text"},{title:"Button with fixed width",filename:"buttons",url:"buttons.html#button-with-fixed-width"},{title:"Primary button",filename:"buttons",url:"buttons.html#primary-button"},{title:"Primary button variables",filename:"buttons",url:"buttons.html#primary-button-variables"},{title:"Button with gradient background",filename:"buttons",url:"buttons.html#button-with-gradient-background"},{title:"Button as a link",filename:"buttons",url:"buttons.html#button-as-a-link"},{title:"Button as a link variables",filename:"buttons",url:"buttons.html#button-as-a-link-variables"},{title:"Link as a button",filename:"buttons",url:"buttons.html#link-as-a-button"},{title:"Button reset",filename:"buttons",url:"buttons.html#button-reset"},{title:"Button revert secondary color",filename:"buttons",url:"buttons.html#button-revert-secondary-color"},{title:"Button revert secondary color variables",filename:"buttons",url:"buttons.html#button-revert-secondary-color-variables"},{title:"Button revert secondary size",filename:"buttons",url:"buttons.html#button-revert-secondary-size"},{title:"Button revert secondary size variables",filename:"buttons",url:"buttons.html#button-revert-secondary-size-variables"},{title:"components",filename:"components",url:"components.html"},{title:"Components",filename:"components",url:"components.html#components"},{title:"Components Variables",filename:"components",url:"components.html#components-variables"},{title:"dropdowns",filename:"dropdowns",url:"dropdowns.html"},{title:"Drop-down and split buttons mixins",filename:"dropdowns",url:"dropdowns.html#dropdown-and-split-buttons-mixins"},{title:"Drop-down",filename:"dropdowns",url:"dropdowns.html#dropdown"},{title:"Drop-down variables",filename:"dropdowns",url:"dropdowns.html#dropdown-variables"},{title:"Drop-down with icon customization",filename:"dropdowns",url:"dropdowns.html#dropdown-with-icon-customization"},{title:"Modify dropdown list styles",filename:"dropdowns",url:"dropdowns.html#modify-dropdown-list-styles"},{title:"Split button",filename:"dropdowns",url:"dropdowns.html#split-button"},{title:"Split button variables",filename:"dropdowns",url:"dropdowns.html#split-button-variables"},{title:"Split button - button styling",filename:"dropdowns",url:"dropdowns.html#split-button-button-styling"},{title:"Split button icon customization",filename:"dropdowns",url:"dropdowns.html#split-button-icon-customization"},{title:"Split button drop-down list customization",filename:"dropdowns",url:"dropdowns.html#split-button-dropdown-list-customization"},{title:"forms",filename:"forms",url:"forms.html"},{title:"Forms mixins",filename:"forms",url:"forms.html#forms-mixins"},{title:"Global forms elements customization",filename:"forms",url:"forms.html#global-forms-elements-customization"},{title:"Fieldsets & fields customization",filename:"forms",url:"forms.html#fieldsets-fields-customization"},{title:"Fieldset and legend customization variables",filename:"forms",url:"forms.html#fieldset-and-legend-customization-variables"},{title:"Fields customization variables",filename:"forms",url:"forms.html#fields-customization-variables"},{title:"Required fields message customization variables",filename:"forms",url:"forms.html#required-fields-message-customization-variables"},{title:"Form element inputs customization",filename:"forms",url:"forms.html#form-element-inputs-customization"},{title:"Form element inputs customization variables",filename:"forms",url:"forms.html#form-element-inputs-customization-variables"},{title:"Form element choice",filename:"forms",url:"forms.html#form-element-choice"},{title:"Form element choice variables",filename:"forms",url:"forms.html#form-element-choice-variables"},{title:"Custom color",filename:"forms",url:"forms.html#custom-color"},{title:"Input number - input-text view",filename:"forms",url:"forms.html#input-number-inputtext-view"},{title:"Input search - input-text view",filename:"forms",url:"forms.html#input-search-inputtext-view"},{title:"Form validation",filename:"forms",url:"forms.html#form-validation"},{title:"Form validation variables",filename:"forms",url:"forms.html#form-validation-variables"},{title:"icons",filename:"icons",url:"icons.html"},{title:"Icons",filename:"icons",url:"icons.html#icons"},{title:"Icon with image or sprite",filename:"icons",url:"icons.html#icon-with-image-or-sprite"},{title:"Icon with image or sprite variables",filename:"icons",url:"icons.html#icon-with-image-or-sprite-variables"},{title:"Icon position for an icon with image or sprite",filename:"icons",url:"icons.html#icon-position-for-an-icon-with-image-or-sprite"},{title:"Position for icon with image or sprite mixin variables",filename:"icons",url:"icons.html#position-for-icon-with-image-or-sprite-mixin-variables"},{title:"Icon sprite position (with grid)",filename:"icons",url:"icons.html#icon-sprite-position-with-grid"},{title:"Icon sprite position variables",filename:"icons",url:"icons.html#icon-sprite-position-variables"},{title:"Image/sprite icon size",filename:"icons",url:"icons.html#imagesprite-icon-size"},{title:"Image/sprite icon size variables",filename:"icons",url:"icons.html#imagesprite-icon-size-variables"},{title:"Font icon",filename:"icons",url:"icons.html#font-icon"},{title:"Font icon variables",filename:"icons",url:"icons.html#font-icon-variables"},{title:"Change the size of font icon",filename:"icons",url:"icons.html#change-the-size-of-font-icon"},{title:"Change the size of font icon variables",filename:"icons",url:"icons.html#change-the-size-of-font-icon-variables"},{title:"Hide icon text",filename:"icons",url:"icons.html#hide-icon-text"},{title:"Sprite and font icons for Blank theme",filename:"icons",url:"icons.html#sprite-and-font-icons-for-blank-theme"},{title:"layout",filename:"layout",url:"layout.html"},{title:"Layout",filename:"layout",url:"layout.html#layout"},{title:"Layout global variables",filename:"layout",url:"layout.html#layout-global-variables"},{title:"Page layouts",filename:"layout",url:"layout.html#page-layouts"},{title:"Layout column",filename:"layout",url:"layout.html#layout-column"},{title:"Layout column variables",filename:"layout",url:"layout.html#layout-column-variables"},{title:"Layout width",filename:"layout",url:"layout.html#layout-width"},{title:"Layout width variables",filename:"layout",url:"layout.html#layout-width-variables"},{title:"lib",filename:"lib",url:"lib.html"},{title:"Including Magento UI library to your theme",filename:"lib",url:"lib.html#including-magento-ui-library-to-your-theme"},{title:"loaders",filename:"loaders",url:"loaders.html"},{title:"Loaders",filename:"loaders",url:"loaders.html#loaders"},{title:"Default loader variables",filename:"loaders",url:"loaders.html#default-loader-variables"},{title:"Loading",filename:"loaders",url:"loaders.html#loading"},{title:"Loading default variables",filename:"loaders",url:"loaders.html#loading-default-variables"},{title:"messages",filename:"messages",url:"messages.html"},{title:"Messages",filename:"messages",url:"messages.html#messages"},{title:"Information message",filename:"messages",url:"messages.html#information-message"},{title:"Warning message",filename:"messages",url:"messages.html#warning-message"},{title:"Error message",filename:"messages",url:"messages.html#error-message"},{title:"Success message",filename:"messages",url:"messages.html#success-message"},{title:"Notice message",filename:"messages",url:"messages.html#notice-message"},{title:"Message with inner icon",filename:"messages",url:"messages.html#message-with-inner-icon"},{title:"Message with lateral icon",filename:"messages",url:"messages.html#message-with-lateral-icon"},{title:"Custom message style",filename:"messages",url:"messages.html#custom-message-style"},{title:"Messages global variables",filename:"messages",url:"messages.html#messages-global-variables"},{title:"pages",filename:"pages",url:"pages.html"},{title:"Pagination HTML markup",filename:"pages",url:"pages.html#pagination-html-markup"},{title:"Pagination variables",filename:"pages",url:"pages.html#pagination-variables"},{title:"Pagination with label and gradient background on links",filename:"pages",url:"pages.html#pagination-with-label-and-gradient-background-on-links"},{title:'Pagination with "previous"..."next" text links and label',filename:"pages",url:"pages.html#pagination-with-previousnext-text-links-and-label"},{title:"Pagination without label, with solid background",filename:"pages",url:"pages.html#pagination-without-label-with-solid-background"},{title:"popups",filename:"popups",url:"popups.html"},{title:"Popups",filename:"popups",url:"popups.html#popups"},{title:"Popup variables",filename:"popups",url:"popups.html#popup-variables"},{title:"Window overlay mixin variables",filename:"popups",url:"popups.html#window-overlay-mixin-variables"},{title:"Fixed height popup",filename:"popups",url:"popups.html#fixed-height-popup"},{title:"Fixed content height popup",filename:"popups",url:"popups.html#fixed-content-height-popup"},{title:"Margins for header, content and footer block in popup",filename:"popups",url:"popups.html#margins-for-header-content-and-footer-block-in-popup"},{title:"Popup titles styled as theme headings",filename:"popups",url:"popups.html#popup-titles-styled-as-theme-headings"},{title:"Popup action toolbar",filename:"popups",url:"popups.html#popup-action-toolbar"},{title:"Popup Close button without an icon",filename:"popups",url:"popups.html#popup-close-button-without-an-icon"},{title:"Modify the icon of popup Close button",filename:"popups",url:"popups.html#modify-the-icon-of-popup-close-button"},{title:"Modify overlay styles",filename:"popups",url:"popups.html#modify-overlay-styles"},{title:"rating",filename:"rating",url:"rating.html"},{title:"Ratings",filename:"rating",url:"rating.html#ratings"},{title:"Global rating variables",filename:"rating",url:"rating.html#global-rating-variables"},{title:"Rating with vote",filename:"rating",url:"rating.html#rating-with-vote"},{title:"Rating with vote icons number customization",filename:"rating",url:"rating.html#rating-with-vote-icons-number-customization"},{title:"Rating with vote icons colors customization",filename:"rating",url:"rating.html#rating-with-vote-icons-colors-customization"},{title:"Rating with vote icons symbol customization",filename:"rating",url:"rating.html#rating-with-vote-icons-symbol-customization"},{title:"Accessible rating with vote",filename:"rating",url:"rating.html#accessible-rating-with-vote"},{title:"Rating summary",filename:"rating",url:"rating.html#rating-summary"},{title:"Rating summary icons number customization",filename:"rating",url:"rating.html#rating-summary-icons-number-customization"},{title:"Rating summary icons color customization",filename:"rating",url:"rating.html#rating-summary-icons-color-customization"},{title:"Rating summary icons symbol customization",filename:"rating",url:"rating.html#rating-summary-icons-symbol-customization"},{title:"Rating summary hide label",filename:"rating",url:"rating.html#rating-summary-hide-label"},{title:"Rating summary multiple ratings",filename:"rating",url:"rating.html#rating-summary-multiple-ratings"},{title:"Rating hide label mixin",filename:"rating",url:"rating.html#rating-hide-label-mixin"},{title:"resets",filename:"resets",url:"resets.html"},{title:"Resets",filename:"resets",url:"resets.html#resets"},{title:"responsive",filename:"responsive",url:"responsive.html"},{title:"Responsive",filename:"responsive",url:"responsive.html#responsive"},{title:"Responsive mixins usage",filename:"responsive",url:"responsive.html#responsive-mixins-usage"},{title:"Media query style groups separation variables",filename:"responsive",url:"responsive.html#media-query-style-groups-separation-variables"},{title:"Responsive breakpoints",filename:"responsive",url:"responsive.html#responsive-breakpoints"},{title:"sections",filename:"sections",url:"sections.html"},{title:"Tabs and accordions",filename:"sections",url:"sections.html#tabs-and-accordions"},{title:"Tabs",filename:"sections",url:"sections.html#tabs"},{title:"Tabs mixin variables",filename:"sections",url:"sections.html#tabs-mixin-variables"},{title:"Tabs with content top border",filename:"sections",url:"sections.html#tabs-with-content-top-border"},{title:"Accordion",filename:"sections",url:"sections.html#accordion"},{title:"Accordion mixin variables",filename:"sections",url:"sections.html#accordion-mixin-variables"},{title:"Responsive tabs",filename:"sections",url:"sections.html#responsive-tabs"},{title:"Tabs Base",filename:"sections",url:"sections.html#tabs-base"},{title:"Accordion Base",filename:"sections",url:"sections.html#accordion-base"},{title:"tables",filename:"tables",url:"tables.html"},{title:"Tables",filename:"tables",url:"tables.html#tables"},{title:"Table mixin variables",filename:"tables",url:"tables.html#table-mixin-variables"},{title:"Table typography",filename:"tables",url:"tables.html#table-typography"},{title:"Table typography mixin variables",filename:"tables",url:"tables.html#table-typography-mixin-variables"},{title:"Table caption",filename:"tables",url:"tables.html#table-caption"},{title:"Table caption mixin variables",filename:"tables",url:"tables.html#table-caption-mixin-variables"},{title:"Table cells resize",filename:"tables",url:"tables.html#table-cells-resize"},{title:"Table cells resize variables",filename:"tables",url:"tables.html#table-cells-resize-variables"},{title:"Table background customization",filename:"tables",url:"tables.html#table-background-customization"},{title:"Table background mixin variables",filename:"tables",url:"tables.html#table-background-mixin-variables"},{title:"Table borders customization",filename:"tables",url:"tables.html#table-borders-customization"},{title:"Table borders mixin variables",filename:"tables",url:"tables.html#table-borders-mixin-variables"},{title:"Table with horizontal borders",filename:"tables",url:"tables.html#table-with-horizontal-borders"},{title:"Table with vertical borders",filename:"tables",url:"tables.html#table-with-vertical-borders"},{title:"Table with light borders",filename:"tables",url:"tables.html#table-with-light-borders"},{title:"Table without borders",filename:"tables",url:"tables.html#table-without-borders"},{title:"Striped table",filename:"tables",url:"tables.html#striped-table"},{title:"Striped table mixin variables",filename:"tables",url:"tables.html#striped-table-mixin-variables"},{title:"Table with rows hover",filename:"tables",url:"tables.html#table-with-rows-hover"},{title:"Table with rows hover mixin variables",filename:"tables",url:"tables.html#table-with-rows-hover-mixin-variables"},{title:"Responsive table technics #1",filename:"tables",url:"tables.html#responsive-table-technics-1"},{title:"Responsive table technics #2",filename:"tables",url:"tables.html#responsive-table-technics-2"},{title:"Responsive table technics #2 mixin variables",filename:"tables",url:"tables.html#responsive-table-technics-2-mixin-variables"},{title:"tooltips",filename:"tooltips",url:"tooltips.html"},{title:"Tooltips",filename:"tooltips",url:"tooltips.html#tooltips"},{title:"Tooltips variables",filename:"tooltips",url:"tooltips.html#tooltips-variables"},{title:"typography",filename:"typography",url:"typography.html"},{title:"Typogrphy",filename:"typography",url:"typography.html#typogrphy"},{title:"Typography variables",filename:"typography",url:"typography.html#typography-variables"},{title:"Font-size mixin",filename:"typography",url:"typography.html#fontsize-mixin"},{title:"Line-height mixin",filename:"typography",url:"typography.html#lineheight-mixin"},{title:"Word breaking mixin",filename:"typography",url:"typography.html#word-breaking-mixin"},{title:"Font face mixin",filename:"typography",url:"typography.html#font-face-mixin"},{title:"Text overflow mixin",filename:"typography",url:"typography.html#text-overflow-mixin"},{title:"Text hide",filename:"typography",url:"typography.html#text-hide"},{title:"Hyphens",filename:"typography",url:"typography.html#hyphens"},{title:"Font style and color",filename:"typography",url:"typography.html#font-style-and-color"},{title:"Font style mixin variables",filename:"typography",url:"typography.html#font-style-mixin-variables"},{title:"Reset list styles",filename:"typography",url:"typography.html#reset-list-styles"},{title:"Reset list styles variables",filename:"typography",url:"typography.html#reset-list-styles-variables"},{title:"Inline-block list item styling",filename:"typography",url:"typography.html#inlineblock-list-item-styling"},{title:"Link styling mixin",filename:"typography",url:"typography.html#link-styling-mixin"},{title:"Link styling mixin variables",filename:"typography",url:"typography.html#link-styling-mixin-variables"},{title:"Heading styling mixin",filename:"typography",url:"typography.html#heading-styling-mixin"},{title:"Base typography mixins",filename:"typography",url:"typography.html#base-typography-mixins"},{title:"Base typography mixin variables",filename:"typography",url:"typography.html#base-typography-mixin-variables"},{title:"Headings typography mixin",filename:"typography",url:"typography.html#headings-typography-mixin"},{title:"Headings typography mixin variables",filename:"typography",url:"typography.html#headings-typography-mixin-variables"},{title:"Typography links mixin",filename:"typography",url:"typography.html#typography-links-mixin"},{title:"Typography lists mixin",filename:"typography",url:"typography.html#typography-lists-mixin"},{title:"Typography lists mixin variables",filename:"typography",url:"typography.html#typography-lists-mixin-variables"},{title:"Typography code elements mixin",filename:"typography",url:"typography.html#typography-code-elements-mixin"},{title:"Typography code mixin variables",filename:"typography",url:"typography.html#typography-code-mixin-variables"},{title:"Typography blockquote",filename:"typography",url:"typography.html#typography-blockquote"},{title:"Typography blockquote mixin variables",filename:"typography",url:"typography.html#typography-blockquote-mixin-variables"},{title:"utilities",filename:"utilities",url:"utilities.html"},{title:"Utilities",filename:"utilities",url:"utilities.html#utilities"},{title:".lib-clearfix()",filename:"utilities",url:"utilities.html#libclearfix"},{title:".lib-visibility-hidden()",filename:"utilities",url:"utilities.html#libvisibilityhidden"},{title:".lib-visually-hidden()",filename:"utilities",url:"utilities.html#libvisuallyhidden"},{title:".lib-visually-hidden-reset()",filename:"utilities",url:"utilities.html#libvisuallyhiddenreset"},{title:".lib-css()",filename:"utilities",url:"utilities.html#libcss"},{title:".lib-css() variables",filename:"utilities",url:"utilities.html#libcss-variables"},{title:".lib-rotate()",filename:"utilities",url:"utilities.html#librotate"},{title:".lib-rotate() variables",filename:"utilities",url:"utilities.html#librotate-variables"},{title:".lib-input-placeholder()",filename:"utilities",url:"utilities.html#libinputplaceholder"},{title:".lib-input-placeholder() variables",filename:"utilities",url:"utilities.html#libinputplaceholder-variables"},{title:".lib-background-gradient()",filename:"utilities",url:"utilities.html#libbackgroundgradient"},{title:".lib-background-gradient() variables",filename:"utilities",url:"utilities.html#libbackgroundgradient-variables"},{title:"variables",filename:"variables",url:"variables.html"},{title:"List of Global Variables",filename:"variables",url:"variables.html#list-of-global-variables"},{title:"Table with rows hover mixin variables",filename:"variables",url:"variables.html#table-with-rows-hover-mixin-variables"},{title:"docs",filename:"docs",url:"docs.html"},{title:"Documentation",filename:"docs",url:"docs.html#documentation"}];(function(){"use strict";var b=function(a,b){return Array.prototype.indexOf.call(a,b)!==-1},c=function(a,b){return Array.prototype.filter.call(a,b)},d=function(a,b){return Array.prototype.forEach.call(a,b)},e=document.getElementsByTagName("body")[0];e.addEventListener("click",function(a){var b=a.target;b.tagName.toLowerCase()==="svg"&&(b=b.parentNode);var c=!1;b.dataset.toggle!=null&&(a.preventDefault(),b.classList.contains("is-active")||(c=!0)),d(e.querySelectorAll("[data-toggle]"),function(a){a.classList.remove("is-active"),document.getElementById(a.dataset.toggle).hidden=!0}),c&&(b.classList.add("is-active"),document.getElementById(b.dataset.toggle).hidden=!1)}),function(){var f=e.getElementsByClassName("nav")[0];if(!f)return;var g=document.createElement("ul");g.className="nav-results",g.id="nav-search",g.hidden=!0,d(a,function(a){var b,c,d;b=document.createElement("li"),b._title=a.title.toLowerCase(),b.hidden=!0,b.appendChild(c=document.createElement("a")),c.href=a.url,c.innerHTML=a.title,c.appendChild(d=document.createElement("span")),d.innerHTML=a.filename,d.className="nav-results-filename",g.appendChild(b)}),f.appendChild(g);var h=g.children,i=function(a){d(h,function(a){a.hidden=!0});var b=this.value.toLowerCase(),e=[];b!==""&&(e=c(h,function(a){return a._title.indexOf(b)!==-1})),e.length>0?(d(e,function(a){a.hidden=!1}),g.hidden=!1):g.hidden=!0},j=f.querySelector('input[type="search"]');j.addEventListener("keyup",i),j.addEventListener("focus",i),e.addEventListener("click",function(a){if(a.target.classList&&a.target.classList.contains("search"))return;g.hidden=!0}),g.addEventListener("click",function(a){j.value=""});var k=document.createElement("ul");k.id="nav-toc",k.hidden=!0,k.className="nav-results toc-list",c(e.getElementsByTagName("*"),function(a){return b(["h1","h2","h3"],a.tagName.toLowerCase())}).map(function(a){var b=document.createElement("li"),c=document.createElement("a"),d=a.tagName.toLowerCase()[1];c.classList.add("level-"+d),b.appendChild(c),c.href="#"+a.id,c.innerHTML=a.innerHTML,k.appendChild(b)}),f.appendChild(k)}()})(),function(){"use strict";if(location.hash==="#__preview__"||location.protocol==="data:")return;var a=function(a,b){return Array.prototype.forEach.call(a,b)},b=function(a,b){var e=Array.prototype.slice.call(arguments,2);return d(a,function(a){return(c(b)?b||a:a[b]).apply(a,e)})},c=function(a){return Object.prototype.toString.call(a)==="[object Function]"},d=function(a,b){return Array.prototype.map.call(a,b)},e=function(a,b){return d(a,function(a){return a[b]})},f=function(a){var b={},c=a.split(";");for(var d=0;c.length>d;d++){var e=c[d].trim().split("=");b[e[0]]=e[1]}return b},g=function(a,c){return b(e(a,"classList"),"remove",c)},h=function(a,b){a.contentDocument.defaultView.postMessage(b,"*")},i=document.getElementsByTagName("head")[0],j=document.getElementsByTagName("body")[0],k=e(i.querySelectorAll('style[type="text/preview"]'),"innerHTML").join(""),l=e(i.querySelectorAll('script[type="text/preview"]'),"innerHTML").join(""),m=location.href.split("#")[0]+"#__preview__",n=document.createElement("iframe");n.src="data:text/html,",j.appendChild(n),n.addEventListener("load",function(){var b={sameOriginDataUri:!0};try{this.contentDocument,this.contentDocument||(b.sameOriginDataUri=!1)}catch(c){b.sameOriginDataUri=!1}this.parentNode.removeChild(this),a(j.getElementsByTagName("textarea"),function(a,c){o(a,b,c),q(),p(a)})});var o=function(a,b,c){var d,e,f;d=document.createElement("div"),d.appendChild(e=document.createElement("div")),d.className="preview",e.appendChild(f=document.createElement("iframe")),e.className="resizeable",f.setAttribute("scrolling","no"),f.name="iframe"+c++,f.addEventListener("load",function(){var c,d,e,f,g,i,j;j=this.contentDocument;if(!b.sameOriginDataUri&&this.src!==m)return;this.src===m&&(c=j.createElement("html"),c.appendChild(j.createElement("head")),c.appendChild(d=j.createElement("body")),d.innerHTML=a.textContent,j.replaceChild(c,j.documentElement)),g=j.createElement("head"),g.appendChild(f=j.createElement("style")),g.appendChild(e=j.createElement("script")),e.textContent=l,f.textContent=k,i=j.getElementsByTagName("head")[0],i.parentNode.replaceChild(g,i),h(this,"getHeight")});var g;b.sameOriginDataUri?g="data:text/html;charset=utf-8,"+encodeURIComponent("<!doctype html><html><head></head></body>"+a.textContent):g=m,f.setAttribute("src",g);var i=function(){f.contentDocument.body.innerHTML=this.value,h(f,"getHeight")};a.addEventListener("keypress",i),a.addEventListener("keyup",i),a.parentNode.insertBefore(d,a)},p=function(a){var b=document.createElement("div");b.className="preview-code",b.style.position="absolute",b.style.left="-9999px",j.appendChild(b);var c=parseInt(window.getComputedStyle(a).getPropertyValue("max-height"),10),d=function(a){b.textContent=this.value+"\n";var d=b.offsetHeight+2;d>=c?this.style.overflow="auto":this.style.overflow="hidden",this.style.height=b.offsetHeight+2+"px"};a.addEventListener("keypress",d),a.addEventListener("keyup",d),d.call(a)},q=function(){var b=j.getElementsByClassName("settings")[0],c=j.getElementsByClassName("resizeable"),d=30,e=function(b){document.cookie="preview-width="+b,a(c,function(a){b==="auto"&&(b=a.parentNode.offsetWidth),a.style.width=b+"px",h(a.getElementsByTagName("iframe")[0],"getHeight")})},i=f(document.cookie)["preview-width"];if(i){e(i),g(b.getElementsByClassName("is-active"),"is-active");var k=b.querySelector('button[data-width="'+i+'"]');k&&k.classList.add("is-active")}window.addEventListener("message",function(a){if(a.data==null||!a.source)return;var b=a.data,c=document.getElementsByName(a.source.name)[0];b.height!=null&&c&&(c.parentNode.style.height=b.height+d+"px")},!1),b&&c.length>0&&(b.hidden=!1,b.addEventListener("click",function(a){var c=a.target.tagName.toLowerCase(),d;if(c==="button")d=a.target;else{if(c!=="svg")return;d=a.target.parentNode}a.preventDefault(),g(b.getElementsByClassName("is-active"),"is-active"),d.classList.add("is-active");var f=d.dataset.width;e(f)}))}}()})()</script></body></html><!-- Generated with StyleDocco (http://jacobrask.github.com/styledocco). --> diff --git a/lib/web/css/docs/icons.html b/lib/web/css/docs/icons.html index 1dca9797fc560..d7eeff7f802ca 100644 --- a/lib/web/css/docs/icons.html +++ b/lib/web/css/docs/icons.html @@ -847,4 +847,4 @@ <h2 id="icons-using-sprite">Icons using sprite</h2> } } } -}</code></pre></div></article></section><div class="bar bottom"><div hidden class="settings container"><!-- Icons from http://iconmonstr.com--><button title="Desktop (1280)" data-width='1280'><svg viewBox="0 0 412 386" height="24" width="26" class="icon"><path d="m147.6,343.9c-4.5,15.9-26.2,37.6-42.1,42.1h201c-15.3,-4-38.1,-26.8-42.1,-42.1H147.6zM387,0.5H25c-13.8,0-25,11.2-25,25V294c0,13.8 11.2,25 25,25h362c13.8,0 25,-11.2 25,-25V25.5C412,11.7 400.8,0.5 387,0.5zM369.9,238.2H42.1L42.1,42.6 369.9,42.6V238.2z"></path></svg></button><button title="Laptop (1024)" data-width='1024'><svg viewBox="0 0 384 312" height="23" width="28" class="icon"><path d="m349.2,20.5c0,-11-9,-20-20,-20H53.6c-11,0-20,9-20,20v194H349.2v-194zm-27,167H60.6V27.5H322.2v160zm28,42H32.6L2.6,282.1c-3.5,6.2-3.5,13.8 0.1,19.9 3.6,6.2 10.2,9.9 17.3,9.9H363.1c7.1,0 13.7,-3.8 17.3,-10 3.6,-6.2 3.6,-13.8 0,-20l-30.2,-52.5zm-196.9,54 8,-23.5h60.5l8,23.5h-76.5z"></path></svg></button><button title="Tablet (768)" data-width='768'><svg viewBox="0 0 317 412" height="24" width="18" class="icon"><path d="M 316.5,380 V 32 c 0,-17.7 -14.3,-32 -32,-32 H 32 C 14.3,0 0,14.3 0,32 v 348 c 0,17.7 14.3,32 32,32 h 252.5 c 17.7,0 32,-14.3 32,-32 z M 40,367 V 45 H 276.5 V 367 H 40 z m 109.8,22.7 c 0,-4.7 3.8,-8.5 8.5,-8.5 4.7,0 8.5,3.8 8.5,8.5 0,4.7 -3.8,8.5 -8.5,8.5 -4.7,0 -8.5,-3.8 -8.5,-8.5 z"></path></svg></button><button title="Smart phone (320)" data-width='320'><svg viewBox="0 0 224 412" height="24" width="13" class="icon"><path d="M 190.7,0 H 33 C 14.8,0 0,14.8 0,33 v 346 c 0,18.2 14.8,33 33,33 h 157.7 c 18.2,0 33,-14.8 33,-33 V 33 c 0,-18.2 -14.8,-33 -33,-33 z M 94.3,30.2 h 37 c 2.2,0 4,1.8 4,4 0,2.2 -1.8,4 -4,4 h -37 c -2.2,0 -4,-1.8 -4,-4 0,-2.2 1.8,-4 4,-4 z m 18.5,362.8 c -8.8,0 -16,-7.2 -16,-16 0,-8.8 7.2,-16 16,-16 8.8,0 16,7.2 16,16 0,8.8 -7.2,16 -16,16 z M 198.6,343.8 H 25.1 V 68.2 h 173.5 v 275.5 z"></path></svg></button><button title="Feature phone (240)" data-width='240'><svg viewBox="0 0 201 412" height="24" width="12" class="icon"><path d="M 165.5,0.2 V 45 H 25 c -13.8,0 -25,11.2 -25,25 V 387 c 0,13.8 11.2,25 25,25 h 150.5 c 13.8,0 25,-11.2 25,-25 V 0.2 h -35 z M 65.2,366.5 H 34.2 v -24.5 h 31 v 24.5 z m 0,-44.3 H 34.2 v -24.5 h 31 v 24.5 z m 50.5,44.3 H 84.7 v -24.5 h 31 v 24.5 z m 0,-44.3 H 84.7 v -24.5 h 31 v 24.5 z m 50.5,44.3 h -31 v -24.5 h 31 v 24.5 z m 0,-44.3 h -31 v -24.5 h 31 v 24.5 z m 0,-59.3 h -132 V 95.4 h 132 V 262.9 z"></path></svg></button><button title="Auto (100%)" data-width="auto" class="auto is-active">Auto</button></div></div><script>(function(){var a=[{title:"actions-toolbar",filename:"actions-toolbar",url:"actions-toolbar.html"},{title:"Actions toolbar",filename:"actions-toolbar",url:"actions-toolbar.html#actions-toolbar"},{title:"Actions toolbar mixin variables",filename:"actions-toolbar",url:"actions-toolbar.html#actions-toolbar-mixin-variables"},{title:"Actions toolbar alignment",filename:"actions-toolbar",url:"actions-toolbar.html#actions-toolbar-alignment"},{title:"Reverse primary and secondary blocks",filename:"actions-toolbar",url:"actions-toolbar.html#reverse-primary-and-secondary-blocks"},{title:"Actions toolbar indents customizations",filename:"actions-toolbar",url:"actions-toolbar.html#actions-toolbar-indents-customizations"},{title:"Responsive actions toolbar",filename:"actions-toolbar",url:"actions-toolbar.html#responsive-actions-toolbar"},{title:"breadcrumbs",filename:"breadcrumbs",url:"breadcrumbs.html"},{title:"Breadcrumbs",filename:"breadcrumbs",url:"breadcrumbs.html#breadcrumbs"},{title:"Breadcrumbs variables",filename:"breadcrumbs",url:"breadcrumbs.html#breadcrumbs-variables"},{title:"Button-styled breadcrumbs with gradient background, border, and no separating symbol",filename:"breadcrumbs",url:"breadcrumbs.html#buttonstyled-breadcrumbs-with-gradient-background-border-and-no-separating-symbol"},{title:"Breadcrumbs with solid background",filename:"breadcrumbs",url:"breadcrumbs.html#breadcrumbs-with-solid-background"},{title:"buttons",filename:"buttons",url:"buttons.html"},{title:"Default button",filename:"buttons",url:"buttons.html#default-button"},{title:"Button variables",filename:"buttons",url:"buttons.html#button-variables"},{title:"Button as an icon",filename:"buttons",url:"buttons.html#button-as-an-icon"},{title:"Button with an icon on the left or right side of the text",filename:"buttons",url:"buttons.html#button-with-an-icon-on-the-left-or-right-side-of-the-text"},{title:"Button with fixed width",filename:"buttons",url:"buttons.html#button-with-fixed-width"},{title:"Primary button",filename:"buttons",url:"buttons.html#primary-button"},{title:"Primary button variables",filename:"buttons",url:"buttons.html#primary-button-variables"},{title:"Button with gradient background",filename:"buttons",url:"buttons.html#button-with-gradient-background"},{title:"Button as a link",filename:"buttons",url:"buttons.html#button-as-a-link"},{title:"Button as a link variables",filename:"buttons",url:"buttons.html#button-as-a-link-variables"},{title:"Link as a button",filename:"buttons",url:"buttons.html#link-as-a-button"},{title:"Button reset",filename:"buttons",url:"buttons.html#button-reset"},{title:"Button revert secondary color",filename:"buttons",url:"buttons.html#button-revert-secondary-color"},{title:"Button revert secondary color variables",filename:"buttons",url:"buttons.html#button-revert-secondary-color-variables"},{title:"Button revert secondary size",filename:"buttons",url:"buttons.html#button-revert-secondary-size"},{title:"Button revert secondary size variables",filename:"buttons",url:"buttons.html#button-revert-secondary-size-variables"},{title:"components",filename:"components",url:"components.html"},{title:"Components",filename:"components",url:"components.html#components"},{title:"Components Variables",filename:"components",url:"components.html#components-variables"},{title:"dropdowns",filename:"dropdowns",url:"dropdowns.html"},{title:"Drop-down and split buttons mixins",filename:"dropdowns",url:"dropdowns.html#dropdown-and-split-buttons-mixins"},{title:"Drop-down",filename:"dropdowns",url:"dropdowns.html#dropdown"},{title:"Drop-down variables",filename:"dropdowns",url:"dropdowns.html#dropdown-variables"},{title:"Drop-down with icon customization",filename:"dropdowns",url:"dropdowns.html#dropdown-with-icon-customization"},{title:"Modify dropdown list styles",filename:"dropdowns",url:"dropdowns.html#modify-dropdown-list-styles"},{title:"Split button",filename:"dropdowns",url:"dropdowns.html#split-button"},{title:"Split button variables",filename:"dropdowns",url:"dropdowns.html#split-button-variables"},{title:"Split button - button styling",filename:"dropdowns",url:"dropdowns.html#split-button-button-styling"},{title:"Split button icon customization",filename:"dropdowns",url:"dropdowns.html#split-button-icon-customization"},{title:"Split button drop-down list customization",filename:"dropdowns",url:"dropdowns.html#split-button-dropdown-list-customization"},{title:"forms",filename:"forms",url:"forms.html"},{title:"Forms mixins",filename:"forms",url:"forms.html#forms-mixins"},{title:"Global forms elements customization",filename:"forms",url:"forms.html#global-forms-elements-customization"},{title:"Fieldsets & fields customization",filename:"forms",url:"forms.html#fieldsets-fields-customization"},{title:"Fieldset and legend customization variables",filename:"forms",url:"forms.html#fieldset-and-legend-customization-variables"},{title:"Fields customization variables",filename:"forms",url:"forms.html#fields-customization-variables"},{title:"Required fields message customization variables",filename:"forms",url:"forms.html#required-fields-message-customization-variables"},{title:"Form element inputs customization",filename:"forms",url:"forms.html#form-element-inputs-customization"},{title:"Form element inputs customization variables",filename:"forms",url:"forms.html#form-element-inputs-customization-variables"},{title:"Form element choice",filename:"forms",url:"forms.html#form-element-choice"},{title:"Form element choice variables",filename:"forms",url:"forms.html#form-element-choice-variables"},{title:"Custom color",filename:"forms",url:"forms.html#custom-color"},{title:"Input number - input-text view",filename:"forms",url:"forms.html#input-number-inputtext-view"},{title:"Input search - input-text view",filename:"forms",url:"forms.html#input-search-inputtext-view"},{title:"Form validation",filename:"forms",url:"forms.html#form-validation"},{title:"Form validation variables",filename:"forms",url:"forms.html#form-validation-variables"},{title:"icons",filename:"icons",url:"icons.html"},{title:"Icons",filename:"icons",url:"icons.html#icons"},{title:"Icon with image or sprite",filename:"icons",url:"icons.html#icon-with-image-or-sprite"},{title:"Icon with image or sprite variables",filename:"icons",url:"icons.html#icon-with-image-or-sprite-variables"},{title:"Icon position for an icon with image or sprite",filename:"icons",url:"icons.html#icon-position-for-an-icon-with-image-or-sprite"},{title:"Position for icon with image or sprite mixin variables",filename:"icons",url:"icons.html#position-for-icon-with-image-or-sprite-mixin-variables"},{title:"Icon sprite position (with grid)",filename:"icons",url:"icons.html#icon-sprite-position-with-grid"},{title:"Icon sprite position variables",filename:"icons",url:"icons.html#icon-sprite-position-variables"},{title:"Image/sprite icon size",filename:"icons",url:"icons.html#imagesprite-icon-size"},{title:"Image/sprite icon size variables",filename:"icons",url:"icons.html#imagesprite-icon-size-variables"},{title:"Font icon",filename:"icons",url:"icons.html#font-icon"},{title:"Font icon variables",filename:"icons",url:"icons.html#font-icon-variables"},{title:"Change the size of font icon",filename:"icons",url:"icons.html#change-the-size-of-font-icon"},{title:"Change the size of font icon variables",filename:"icons",url:"icons.html#change-the-size-of-font-icon-variables"},{title:"Hide icon text",filename:"icons",url:"icons.html#hide-icon-text"},{title:"Sprite and font icons for Blank theme",filename:"icons",url:"icons.html#sprite-and-font-icons-for-blank-theme"},{title:"layout",filename:"layout",url:"layout.html"},{title:"Layout",filename:"layout",url:"layout.html#layout"},{title:"Layout global variables",filename:"layout",url:"layout.html#layout-global-variables"},{title:"Page layouts",filename:"layout",url:"layout.html#page-layouts"},{title:"Layout column",filename:"layout",url:"layout.html#layout-column"},{title:"Layout column variables",filename:"layout",url:"layout.html#layout-column-variables"},{title:"Layout width",filename:"layout",url:"layout.html#layout-width"},{title:"Layout width variables",filename:"layout",url:"layout.html#layout-width-variables"},{title:"lib",filename:"lib",url:"lib.html"},{title:"Including Magento UI library to your theme",filename:"lib",url:"lib.html#including-magento-ui-library-to-your-theme"},{title:"loaders",filename:"loaders",url:"loaders.html"},{title:"Loaders",filename:"loaders",url:"loaders.html#loaders"},{title:"Default loader variables",filename:"loaders",url:"loaders.html#default-loader-variables"},{title:"Loading",filename:"loaders",url:"loaders.html#loading"},{title:"Loading default variables",filename:"loaders",url:"loaders.html#loading-default-variables"},{title:"messages",filename:"messages",url:"messages.html"},{title:"Messages",filename:"messages",url:"messages.html#messages"},{title:"Information message",filename:"messages",url:"messages.html#information-message"},{title:"Warning message",filename:"messages",url:"messages.html#warning-message"},{title:"Error message",filename:"messages",url:"messages.html#error-message"},{title:"Success message",filename:"messages",url:"messages.html#success-message"},{title:"Notice message",filename:"messages",url:"messages.html#notice-message"},{title:"Message with inner icon",filename:"messages",url:"messages.html#message-with-inner-icon"},{title:"Message with lateral icon",filename:"messages",url:"messages.html#message-with-lateral-icon"},{title:"Custom message style",filename:"messages",url:"messages.html#custom-message-style"},{title:"Messages global variables",filename:"messages",url:"messages.html#messages-global-variables"},{title:"pages",filename:"pages",url:"pages.html"},{title:"Pagination HTML markup",filename:"pages",url:"pages.html#pagination-html-markup"},{title:"Pagination variables",filename:"pages",url:"pages.html#pagination-variables"},{title:"Pagination with label and gradient background on links",filename:"pages",url:"pages.html#pagination-with-label-and-gradient-background-on-links"},{title:'Pagination with "previous"..."next" text links and label',filename:"pages",url:"pages.html#pagination-with-previousnext-text-links-and-label"},{title:"Pagination without label, with solid background",filename:"pages",url:"pages.html#pagination-without-label-with-solid-background"},{title:"popups",filename:"popups",url:"popups.html"},{title:"Popups",filename:"popups",url:"popups.html#popups"},{title:"Popup variables",filename:"popups",url:"popups.html#popup-variables"},{title:"Window overlay mixin variables",filename:"popups",url:"popups.html#window-overlay-mixin-variables"},{title:"Fixed height popup",filename:"popups",url:"popups.html#fixed-height-popup"},{title:"Fixed content height popup",filename:"popups",url:"popups.html#fixed-content-height-popup"},{title:"Margins for header, content and footer block in popup",filename:"popups",url:"popups.html#margins-for-header-content-and-footer-block-in-popup"},{title:"Popup titles styled as theme headings",filename:"popups",url:"popups.html#popup-titles-styled-as-theme-headings"},{title:"Popup action toolbar",filename:"popups",url:"popups.html#popup-action-toolbar"},{title:"Popup Close button without an icon",filename:"popups",url:"popups.html#popup-close-button-without-an-icon"},{title:"Modify the icon of popup Close button",filename:"popups",url:"popups.html#modify-the-icon-of-popup-close-button"},{title:"Modify overlay styles",filename:"popups",url:"popups.html#modify-overlay-styles"},{title:"rating",filename:"rating",url:"rating.html"},{title:"Ratings",filename:"rating",url:"rating.html#ratings"},{title:"Global rating variables",filename:"rating",url:"rating.html#global-rating-variables"},{title:"Rating with vote",filename:"rating",url:"rating.html#rating-with-vote"},{title:"Rating with vote icons number customization",filename:"rating",url:"rating.html#rating-with-vote-icons-number-customization"},{title:"Rating with vote icons colors customization",filename:"rating",url:"rating.html#rating-with-vote-icons-colors-customization"},{title:"Rating with vote icons symbol customization",filename:"rating",url:"rating.html#rating-with-vote-icons-symbol-customization"},{title:"Accessible rating with vote",filename:"rating",url:"rating.html#accessible-rating-with-vote"},{title:"Rating summary",filename:"rating",url:"rating.html#rating-summary"},{title:"Rating summary icons number customization",filename:"rating",url:"rating.html#rating-summary-icons-number-customization"},{title:"Rating summary icons color customization",filename:"rating",url:"rating.html#rating-summary-icons-color-customization"},{title:"Rating summary icons symbol customization",filename:"rating",url:"rating.html#rating-summary-icons-symbol-customization"},{title:"Rating summary hide label",filename:"rating",url:"rating.html#rating-summary-hide-label"},{title:"Rating summary multiple ratings",filename:"rating",url:"rating.html#rating-summary-multiple-ratings"},{title:"Rating hide label mixin",filename:"rating",url:"rating.html#rating-hide-label-mixin"},{title:"resets",filename:"resets",url:"resets.html"},{title:"Resets",filename:"resets",url:"resets.html#resets"},{title:"responsive",filename:"responsive",url:"responsive.html"},{title:"Responsive",filename:"responsive",url:"responsive.html#responsive"},{title:"Responsive mixins usage",filename:"responsive",url:"responsive.html#responsive-mixins-usage"},{title:"Media query style groups separation variables",filename:"responsive",url:"responsive.html#media-query-style-groups-separation-variables"},{title:"Responsive breakpoints",filename:"responsive",url:"responsive.html#responsive-breakpoints"},{title:"sections",filename:"sections",url:"sections.html"},{title:"Tabs and accordions",filename:"sections",url:"sections.html#tabs-and-accordions"},{title:"Tabs",filename:"sections",url:"sections.html#tabs"},{title:"Tabs mixin variables",filename:"sections",url:"sections.html#tabs-mixin-variables"},{title:"Tabs with content top border",filename:"sections",url:"sections.html#tabs-with-content-top-border"},{title:"Accordion",filename:"sections",url:"sections.html#accordion"},{title:"Accordion mixin variables",filename:"sections",url:"sections.html#accordion-mixin-variables"},{title:"Responsive tabs",filename:"sections",url:"sections.html#responsive-tabs"},{title:"Tabs Base",filename:"sections",url:"sections.html#tabs-base"},{title:"Accordion Base",filename:"sections",url:"sections.html#accordion-base"},{title:"tables",filename:"tables",url:"tables.html"},{title:"Tables",filename:"tables",url:"tables.html#tables"},{title:"Table mixin variables",filename:"tables",url:"tables.html#table-mixin-variables"},{title:"Table typography",filename:"tables",url:"tables.html#table-typography"},{title:"Table typography mixin variables",filename:"tables",url:"tables.html#table-typography-mixin-variables"},{title:"Table caption",filename:"tables",url:"tables.html#table-caption"},{title:"Table caption mixin variables",filename:"tables",url:"tables.html#table-caption-mixin-variables"},{title:"Table cells resize",filename:"tables",url:"tables.html#table-cells-resize"},{title:"Table cells resize variables",filename:"tables",url:"tables.html#table-cells-resize-variables"},{title:"Table background customization",filename:"tables",url:"tables.html#table-background-customization"},{title:"Table background mixin variables",filename:"tables",url:"tables.html#table-background-mixin-variables"},{title:"Table borders customization",filename:"tables",url:"tables.html#table-borders-customization"},{title:"Table borders mixin variables",filename:"tables",url:"tables.html#table-borders-mixin-variables"},{title:"Table with horizontal borders",filename:"tables",url:"tables.html#table-with-horizontal-borders"},{title:"Table with vertical borders",filename:"tables",url:"tables.html#table-with-vertical-borders"},{title:"Table with light borders",filename:"tables",url:"tables.html#table-with-light-borders"},{title:"Table without borders",filename:"tables",url:"tables.html#table-without-borders"},{title:"Striped table",filename:"tables",url:"tables.html#striped-table"},{title:"Striped table mixin variables",filename:"tables",url:"tables.html#striped-table-mixin-variables"},{title:"Table with rows hover",filename:"tables",url:"tables.html#table-with-rows-hover"},{title:"Table with rows hover mixin variables",filename:"tables",url:"tables.html#table-with-rows-hover-mixin-variables"},{title:"Responsive table technics #1",filename:"tables",url:"tables.html#responsive-table-technics-1"},{title:"Responsive table technics #2",filename:"tables",url:"tables.html#responsive-table-technics-2"},{title:"Responsive table technics #2 mixin variables",filename:"tables",url:"tables.html#responsive-table-technics-2-mixin-variables"},{title:"tooltips",filename:"tooltips",url:"tooltips.html"},{title:"Tooltips",filename:"tooltips",url:"tooltips.html#tooltips"},{title:"Tooltips variables",filename:"tooltips",url:"tooltips.html#tooltips-variables"},{title:"typography",filename:"typography",url:"typography.html"},{title:"Typogrphy",filename:"typography",url:"typography.html#typogrphy"},{title:"Typography variables",filename:"typography",url:"typography.html#typography-variables"},{title:"Font-size mixin",filename:"typography",url:"typography.html#fontsize-mixin"},{title:"Line-height mixin",filename:"typography",url:"typography.html#lineheight-mixin"},{title:"Word breaking mixin",filename:"typography",url:"typography.html#word-breaking-mixin"},{title:"Font face mixin",filename:"typography",url:"typography.html#font-face-mixin"},{title:"Text overflow mixin",filename:"typography",url:"typography.html#text-overflow-mixin"},{title:"Text hide",filename:"typography",url:"typography.html#text-hide"},{title:"Hyphens",filename:"typography",url:"typography.html#hyphens"},{title:"Font style and color",filename:"typography",url:"typography.html#font-style-and-color"},{title:"Font style mixin variables",filename:"typography",url:"typography.html#font-style-mixin-variables"},{title:"Reset list styles",filename:"typography",url:"typography.html#reset-list-styles"},{title:"Reset list styles variables",filename:"typography",url:"typography.html#reset-list-styles-variables"},{title:"Inline-block list item styling",filename:"typography",url:"typography.html#inlineblock-list-item-styling"},{title:"Link styling mixin",filename:"typography",url:"typography.html#link-styling-mixin"},{title:"Link styling mixin variables",filename:"typography",url:"typography.html#link-styling-mixin-variables"},{title:"Heading styling mixin",filename:"typography",url:"typography.html#heading-styling-mixin"},{title:"Base typography mixins",filename:"typography",url:"typography.html#base-typography-mixins"},{title:"Base typography mixin variables",filename:"typography",url:"typography.html#base-typography-mixin-variables"},{title:"Headings typography mixin",filename:"typography",url:"typography.html#headings-typography-mixin"},{title:"Headings typography mixin variables",filename:"typography",url:"typography.html#headings-typography-mixin-variables"},{title:"Typography links mixin",filename:"typography",url:"typography.html#typography-links-mixin"},{title:"Typography lists mixin",filename:"typography",url:"typography.html#typography-lists-mixin"},{title:"Typography lists mixin variables",filename:"typography",url:"typography.html#typography-lists-mixin-variables"},{title:"Typography code elements mixin",filename:"typography",url:"typography.html#typography-code-elements-mixin"},{title:"Typography code mixin variables",filename:"typography",url:"typography.html#typography-code-mixin-variables"},{title:"Typography blockquote",filename:"typography",url:"typography.html#typography-blockquote"},{title:"Typography blockquote mixin variables",filename:"typography",url:"typography.html#typography-blockquote-mixin-variables"},{title:"utilities",filename:"utilities",url:"utilities.html"},{title:"Utilities",filename:"utilities",url:"utilities.html#utilities"},{title:".lib-clearfix()",filename:"utilities",url:"utilities.html#libclearfix"},{title:".lib-visibility-hidden()",filename:"utilities",url:"utilities.html#libvisibilityhidden"},{title:".lib-visually-hidden()",filename:"utilities",url:"utilities.html#libvisuallyhidden"},{title:".lib-visually-hidden-reset()",filename:"utilities",url:"utilities.html#libvisuallyhiddenreset"},{title:".lib-css()",filename:"utilities",url:"utilities.html#libcss"},{title:".lib-css() variables",filename:"utilities",url:"utilities.html#libcss-variables"},{title:".lib-rotate()",filename:"utilities",url:"utilities.html#librotate"},{title:".lib-rotate() variables",filename:"utilities",url:"utilities.html#librotate-variables"},{title:".lib-input-placeholder()",filename:"utilities",url:"utilities.html#libinputplaceholder"},{title:".lib-input-placeholder() variables",filename:"utilities",url:"utilities.html#libinputplaceholder-variables"},{title:".lib-background-gradient()",filename:"utilities",url:"utilities.html#libbackgroundgradient"},{title:".lib-background-gradient() variables",filename:"utilities",url:"utilities.html#libbackgroundgradient-variables"},{title:".lib-url-check()",filename:"utilities",url:"utilities.html#liburlcheck"},{title:".lib-url-check() variables",filename:"utilities",url:"utilities.html#liburlcheck-variables"},{title:"variables",filename:"variables",url:"variables.html"},{title:"List of Global Variables",filename:"variables",url:"variables.html#list-of-global-variables"},{title:"Table with rows hover mixin variables",filename:"variables",url:"variables.html#table-with-rows-hover-mixin-variables"},{title:"docs",filename:"docs",url:"docs.html"},{title:"Documentation",filename:"docs",url:"docs.html#documentation"}];(function(){"use strict";var b=function(a,b){return Array.prototype.indexOf.call(a,b)!==-1},c=function(a,b){return Array.prototype.filter.call(a,b)},d=function(a,b){return Array.prototype.forEach.call(a,b)},e=document.getElementsByTagName("body")[0];e.addEventListener("click",function(a){var b=a.target;b.tagName.toLowerCase()==="svg"&&(b=b.parentNode);var c=!1;b.dataset.toggle!=null&&(a.preventDefault(),b.classList.contains("is-active")||(c=!0)),d(e.querySelectorAll("[data-toggle]"),function(a){a.classList.remove("is-active"),document.getElementById(a.dataset.toggle).hidden=!0}),c&&(b.classList.add("is-active"),document.getElementById(b.dataset.toggle).hidden=!1)}),function(){var f=e.getElementsByClassName("nav")[0];if(!f)return;var g=document.createElement("ul");g.className="nav-results",g.id="nav-search",g.hidden=!0,d(a,function(a){var b,c,d;b=document.createElement("li"),b._title=a.title.toLowerCase(),b.hidden=!0,b.appendChild(c=document.createElement("a")),c.href=a.url,c.innerHTML=a.title,c.appendChild(d=document.createElement("span")),d.innerHTML=a.filename,d.className="nav-results-filename",g.appendChild(b)}),f.appendChild(g);var h=g.children,i=function(a){d(h,function(a){a.hidden=!0});var b=this.value.toLowerCase(),e=[];b!==""&&(e=c(h,function(a){return a._title.indexOf(b)!==-1})),e.length>0?(d(e,function(a){a.hidden=!1}),g.hidden=!1):g.hidden=!0},j=f.querySelector('input[type="search"]');j.addEventListener("keyup",i),j.addEventListener("focus",i),e.addEventListener("click",function(a){if(a.target.classList&&a.target.classList.contains("search"))return;g.hidden=!0}),g.addEventListener("click",function(a){j.value=""});var k=document.createElement("ul");k.id="nav-toc",k.hidden=!0,k.className="nav-results toc-list",c(e.getElementsByTagName("*"),function(a){return b(["h1","h2","h3"],a.tagName.toLowerCase())}).map(function(a){var b=document.createElement("li"),c=document.createElement("a"),d=a.tagName.toLowerCase()[1];c.classList.add("level-"+d),b.appendChild(c),c.href="#"+a.id,c.innerHTML=a.innerHTML,k.appendChild(b)}),f.appendChild(k)}()})(),function(){"use strict";if(location.hash==="#__preview__"||location.protocol==="data:")return;var a=function(a,b){return Array.prototype.forEach.call(a,b)},b=function(a,b){var e=Array.prototype.slice.call(arguments,2);return d(a,function(a){return(c(b)?b||a:a[b]).apply(a,e)})},c=function(a){return Object.prototype.toString.call(a)==="[object Function]"},d=function(a,b){return Array.prototype.map.call(a,b)},e=function(a,b){return d(a,function(a){return a[b]})},f=function(a){var b={},c=a.split(";");for(var d=0;c.length>d;d++){var e=c[d].trim().split("=");b[e[0]]=e[1]}return b},g=function(a,c){return b(e(a,"classList"),"remove",c)},h=function(a,b){a.contentDocument.defaultView.postMessage(b,"*")},i=document.getElementsByTagName("head")[0],j=document.getElementsByTagName("body")[0],k=e(i.querySelectorAll('style[type="text/preview"]'),"innerHTML").join(""),l=e(i.querySelectorAll('script[type="text/preview"]'),"innerHTML").join(""),m=location.href.split("#")[0]+"#__preview__",n=document.createElement("iframe");n.src="data:text/html,",j.appendChild(n),n.addEventListener("load",function(){var b={sameOriginDataUri:!0};try{this.contentDocument,this.contentDocument||(b.sameOriginDataUri=!1)}catch(c){b.sameOriginDataUri=!1}this.parentNode.removeChild(this),a(j.getElementsByTagName("textarea"),function(a,c){o(a,b,c),q(),p(a)})});var o=function(a,b,c){var d,e,f;d=document.createElement("div"),d.appendChild(e=document.createElement("div")),d.className="preview",e.appendChild(f=document.createElement("iframe")),e.className="resizeable",f.setAttribute("scrolling","no"),f.name="iframe"+c++,f.addEventListener("load",function(){var c,d,e,f,g,i,j;j=this.contentDocument;if(!b.sameOriginDataUri&&this.src!==m)return;this.src===m&&(c=j.createElement("html"),c.appendChild(j.createElement("head")),c.appendChild(d=j.createElement("body")),d.innerHTML=a.textContent,j.replaceChild(c,j.documentElement)),g=j.createElement("head"),g.appendChild(f=j.createElement("style")),g.appendChild(e=j.createElement("script")),e.textContent=l,f.textContent=k,i=j.getElementsByTagName("head")[0],i.parentNode.replaceChild(g,i),h(this,"getHeight")});var g;b.sameOriginDataUri?g="data:text/html;charset=utf-8,"+encodeURIComponent("<!doctype html><html><head></head></body>"+a.textContent):g=m,f.setAttribute("src",g);var i=function(){f.contentDocument.body.innerHTML=this.value,h(f,"getHeight")};a.addEventListener("keypress",i),a.addEventListener("keyup",i),a.parentNode.insertBefore(d,a)},p=function(a){var b=document.createElement("div");b.className="preview-code",b.style.position="absolute",b.style.left="-9999px",j.appendChild(b);var c=parseInt(window.getComputedStyle(a).getPropertyValue("max-height"),10),d=function(a){b.textContent=this.value+"\n";var d=b.offsetHeight+2;d>=c?this.style.overflow="auto":this.style.overflow="hidden",this.style.height=b.offsetHeight+2+"px"};a.addEventListener("keypress",d),a.addEventListener("keyup",d),d.call(a)},q=function(){var b=j.getElementsByClassName("settings")[0],c=j.getElementsByClassName("resizeable"),d=30,e=function(b){document.cookie="preview-width="+b,a(c,function(a){b==="auto"&&(b=a.parentNode.offsetWidth),a.style.width=b+"px",h(a.getElementsByTagName("iframe")[0],"getHeight")})},i=f(document.cookie)["preview-width"];if(i){e(i),g(b.getElementsByClassName("is-active"),"is-active");var k=b.querySelector('button[data-width="'+i+'"]');k&&k.classList.add("is-active")}window.addEventListener("message",function(a){if(a.data==null||!a.source)return;var b=a.data,c=document.getElementsByName(a.source.name)[0];b.height!=null&&c&&(c.parentNode.style.height=b.height+d+"px")},!1),b&&c.length>0&&(b.hidden=!1,b.addEventListener("click",function(a){var c=a.target.tagName.toLowerCase(),d;if(c==="button")d=a.target;else{if(c!=="svg")return;d=a.target.parentNode}a.preventDefault(),g(b.getElementsByClassName("is-active"),"is-active"),d.classList.add("is-active");var f=d.dataset.width;e(f)}))}}()})()</script></body></html><!-- Generated with StyleDocco (http://jacobrask.github.com/styledocco). --> +}</code></pre></div></article></section><div class="bar bottom"><div hidden class="settings container"><!-- Icons from http://iconmonstr.com--><button title="Desktop (1280)" data-width='1280'><svg viewBox="0 0 412 386" height="24" width="26" class="icon"><path d="m147.6,343.9c-4.5,15.9-26.2,37.6-42.1,42.1h201c-15.3,-4-38.1,-26.8-42.1,-42.1H147.6zM387,0.5H25c-13.8,0-25,11.2-25,25V294c0,13.8 11.2,25 25,25h362c13.8,0 25,-11.2 25,-25V25.5C412,11.7 400.8,0.5 387,0.5zM369.9,238.2H42.1L42.1,42.6 369.9,42.6V238.2z"></path></svg></button><button title="Laptop (1024)" data-width='1024'><svg viewBox="0 0 384 312" height="23" width="28" class="icon"><path d="m349.2,20.5c0,-11-9,-20-20,-20H53.6c-11,0-20,9-20,20v194H349.2v-194zm-27,167H60.6V27.5H322.2v160zm28,42H32.6L2.6,282.1c-3.5,6.2-3.5,13.8 0.1,19.9 3.6,6.2 10.2,9.9 17.3,9.9H363.1c7.1,0 13.7,-3.8 17.3,-10 3.6,-6.2 3.6,-13.8 0,-20l-30.2,-52.5zm-196.9,54 8,-23.5h60.5l8,23.5h-76.5z"></path></svg></button><button title="Tablet (768)" data-width='768'><svg viewBox="0 0 317 412" height="24" width="18" class="icon"><path d="M 316.5,380 V 32 c 0,-17.7 -14.3,-32 -32,-32 H 32 C 14.3,0 0,14.3 0,32 v 348 c 0,17.7 14.3,32 32,32 h 252.5 c 17.7,0 32,-14.3 32,-32 z M 40,367 V 45 H 276.5 V 367 H 40 z m 109.8,22.7 c 0,-4.7 3.8,-8.5 8.5,-8.5 4.7,0 8.5,3.8 8.5,8.5 0,4.7 -3.8,8.5 -8.5,8.5 -4.7,0 -8.5,-3.8 -8.5,-8.5 z"></path></svg></button><button title="Smart phone (320)" data-width='320'><svg viewBox="0 0 224 412" height="24" width="13" class="icon"><path d="M 190.7,0 H 33 C 14.8,0 0,14.8 0,33 v 346 c 0,18.2 14.8,33 33,33 h 157.7 c 18.2,0 33,-14.8 33,-33 V 33 c 0,-18.2 -14.8,-33 -33,-33 z M 94.3,30.2 h 37 c 2.2,0 4,1.8 4,4 0,2.2 -1.8,4 -4,4 h -37 c -2.2,0 -4,-1.8 -4,-4 0,-2.2 1.8,-4 4,-4 z m 18.5,362.8 c -8.8,0 -16,-7.2 -16,-16 0,-8.8 7.2,-16 16,-16 8.8,0 16,7.2 16,16 0,8.8 -7.2,16 -16,16 z M 198.6,343.8 H 25.1 V 68.2 h 173.5 v 275.5 z"></path></svg></button><button title="Feature phone (240)" data-width='240'><svg viewBox="0 0 201 412" height="24" width="12" class="icon"><path d="M 165.5,0.2 V 45 H 25 c -13.8,0 -25,11.2 -25,25 V 387 c 0,13.8 11.2,25 25,25 h 150.5 c 13.8,0 25,-11.2 25,-25 V 0.2 h -35 z M 65.2,366.5 H 34.2 v -24.5 h 31 v 24.5 z m 0,-44.3 H 34.2 v -24.5 h 31 v 24.5 z m 50.5,44.3 H 84.7 v -24.5 h 31 v 24.5 z m 0,-44.3 H 84.7 v -24.5 h 31 v 24.5 z m 50.5,44.3 h -31 v -24.5 h 31 v 24.5 z m 0,-44.3 h -31 v -24.5 h 31 v 24.5 z m 0,-59.3 h -132 V 95.4 h 132 V 262.9 z"></path></svg></button><button title="Auto (100%)" data-width="auto" class="auto is-active">Auto</button></div></div><script>(function(){var a=[{title:"actions-toolbar",filename:"actions-toolbar",url:"actions-toolbar.html"},{title:"Actions toolbar",filename:"actions-toolbar",url:"actions-toolbar.html#actions-toolbar"},{title:"Actions toolbar mixin variables",filename:"actions-toolbar",url:"actions-toolbar.html#actions-toolbar-mixin-variables"},{title:"Actions toolbar alignment",filename:"actions-toolbar",url:"actions-toolbar.html#actions-toolbar-alignment"},{title:"Reverse primary and secondary blocks",filename:"actions-toolbar",url:"actions-toolbar.html#reverse-primary-and-secondary-blocks"},{title:"Actions toolbar indents customizations",filename:"actions-toolbar",url:"actions-toolbar.html#actions-toolbar-indents-customizations"},{title:"Responsive actions toolbar",filename:"actions-toolbar",url:"actions-toolbar.html#responsive-actions-toolbar"},{title:"breadcrumbs",filename:"breadcrumbs",url:"breadcrumbs.html"},{title:"Breadcrumbs",filename:"breadcrumbs",url:"breadcrumbs.html#breadcrumbs"},{title:"Breadcrumbs variables",filename:"breadcrumbs",url:"breadcrumbs.html#breadcrumbs-variables"},{title:"Button-styled breadcrumbs with gradient background, border, and no separating symbol",filename:"breadcrumbs",url:"breadcrumbs.html#buttonstyled-breadcrumbs-with-gradient-background-border-and-no-separating-symbol"},{title:"Breadcrumbs with solid background",filename:"breadcrumbs",url:"breadcrumbs.html#breadcrumbs-with-solid-background"},{title:"buttons",filename:"buttons",url:"buttons.html"},{title:"Default button",filename:"buttons",url:"buttons.html#default-button"},{title:"Button variables",filename:"buttons",url:"buttons.html#button-variables"},{title:"Button as an icon",filename:"buttons",url:"buttons.html#button-as-an-icon"},{title:"Button with an icon on the left or right side of the text",filename:"buttons",url:"buttons.html#button-with-an-icon-on-the-left-or-right-side-of-the-text"},{title:"Button with fixed width",filename:"buttons",url:"buttons.html#button-with-fixed-width"},{title:"Primary button",filename:"buttons",url:"buttons.html#primary-button"},{title:"Primary button variables",filename:"buttons",url:"buttons.html#primary-button-variables"},{title:"Button with gradient background",filename:"buttons",url:"buttons.html#button-with-gradient-background"},{title:"Button as a link",filename:"buttons",url:"buttons.html#button-as-a-link"},{title:"Button as a link variables",filename:"buttons",url:"buttons.html#button-as-a-link-variables"},{title:"Link as a button",filename:"buttons",url:"buttons.html#link-as-a-button"},{title:"Button reset",filename:"buttons",url:"buttons.html#button-reset"},{title:"Button revert secondary color",filename:"buttons",url:"buttons.html#button-revert-secondary-color"},{title:"Button revert secondary color variables",filename:"buttons",url:"buttons.html#button-revert-secondary-color-variables"},{title:"Button revert secondary size",filename:"buttons",url:"buttons.html#button-revert-secondary-size"},{title:"Button revert secondary size variables",filename:"buttons",url:"buttons.html#button-revert-secondary-size-variables"},{title:"components",filename:"components",url:"components.html"},{title:"Components",filename:"components",url:"components.html#components"},{title:"Components Variables",filename:"components",url:"components.html#components-variables"},{title:"dropdowns",filename:"dropdowns",url:"dropdowns.html"},{title:"Drop-down and split buttons mixins",filename:"dropdowns",url:"dropdowns.html#dropdown-and-split-buttons-mixins"},{title:"Drop-down",filename:"dropdowns",url:"dropdowns.html#dropdown"},{title:"Drop-down variables",filename:"dropdowns",url:"dropdowns.html#dropdown-variables"},{title:"Drop-down with icon customization",filename:"dropdowns",url:"dropdowns.html#dropdown-with-icon-customization"},{title:"Modify dropdown list styles",filename:"dropdowns",url:"dropdowns.html#modify-dropdown-list-styles"},{title:"Split button",filename:"dropdowns",url:"dropdowns.html#split-button"},{title:"Split button variables",filename:"dropdowns",url:"dropdowns.html#split-button-variables"},{title:"Split button - button styling",filename:"dropdowns",url:"dropdowns.html#split-button-button-styling"},{title:"Split button icon customization",filename:"dropdowns",url:"dropdowns.html#split-button-icon-customization"},{title:"Split button drop-down list customization",filename:"dropdowns",url:"dropdowns.html#split-button-dropdown-list-customization"},{title:"forms",filename:"forms",url:"forms.html"},{title:"Forms mixins",filename:"forms",url:"forms.html#forms-mixins"},{title:"Global forms elements customization",filename:"forms",url:"forms.html#global-forms-elements-customization"},{title:"Fieldsets & fields customization",filename:"forms",url:"forms.html#fieldsets-fields-customization"},{title:"Fieldset and legend customization variables",filename:"forms",url:"forms.html#fieldset-and-legend-customization-variables"},{title:"Fields customization variables",filename:"forms",url:"forms.html#fields-customization-variables"},{title:"Required fields message customization variables",filename:"forms",url:"forms.html#required-fields-message-customization-variables"},{title:"Form element inputs customization",filename:"forms",url:"forms.html#form-element-inputs-customization"},{title:"Form element inputs customization variables",filename:"forms",url:"forms.html#form-element-inputs-customization-variables"},{title:"Form element choice",filename:"forms",url:"forms.html#form-element-choice"},{title:"Form element choice variables",filename:"forms",url:"forms.html#form-element-choice-variables"},{title:"Custom color",filename:"forms",url:"forms.html#custom-color"},{title:"Input number - input-text view",filename:"forms",url:"forms.html#input-number-inputtext-view"},{title:"Input search - input-text view",filename:"forms",url:"forms.html#input-search-inputtext-view"},{title:"Form validation",filename:"forms",url:"forms.html#form-validation"},{title:"Form validation variables",filename:"forms",url:"forms.html#form-validation-variables"},{title:"icons",filename:"icons",url:"icons.html"},{title:"Icons",filename:"icons",url:"icons.html#icons"},{title:"Icon with image or sprite",filename:"icons",url:"icons.html#icon-with-image-or-sprite"},{title:"Icon with image or sprite variables",filename:"icons",url:"icons.html#icon-with-image-or-sprite-variables"},{title:"Icon position for an icon with image or sprite",filename:"icons",url:"icons.html#icon-position-for-an-icon-with-image-or-sprite"},{title:"Position for icon with image or sprite mixin variables",filename:"icons",url:"icons.html#position-for-icon-with-image-or-sprite-mixin-variables"},{title:"Icon sprite position (with grid)",filename:"icons",url:"icons.html#icon-sprite-position-with-grid"},{title:"Icon sprite position variables",filename:"icons",url:"icons.html#icon-sprite-position-variables"},{title:"Image/sprite icon size",filename:"icons",url:"icons.html#imagesprite-icon-size"},{title:"Image/sprite icon size variables",filename:"icons",url:"icons.html#imagesprite-icon-size-variables"},{title:"Font icon",filename:"icons",url:"icons.html#font-icon"},{title:"Font icon variables",filename:"icons",url:"icons.html#font-icon-variables"},{title:"Change the size of font icon",filename:"icons",url:"icons.html#change-the-size-of-font-icon"},{title:"Change the size of font icon variables",filename:"icons",url:"icons.html#change-the-size-of-font-icon-variables"},{title:"Hide icon text",filename:"icons",url:"icons.html#hide-icon-text"},{title:"Sprite and font icons for Blank theme",filename:"icons",url:"icons.html#sprite-and-font-icons-for-blank-theme"},{title:"layout",filename:"layout",url:"layout.html"},{title:"Layout",filename:"layout",url:"layout.html#layout"},{title:"Layout global variables",filename:"layout",url:"layout.html#layout-global-variables"},{title:"Page layouts",filename:"layout",url:"layout.html#page-layouts"},{title:"Layout column",filename:"layout",url:"layout.html#layout-column"},{title:"Layout column variables",filename:"layout",url:"layout.html#layout-column-variables"},{title:"Layout width",filename:"layout",url:"layout.html#layout-width"},{title:"Layout width variables",filename:"layout",url:"layout.html#layout-width-variables"},{title:"lib",filename:"lib",url:"lib.html"},{title:"Including Magento UI library to your theme",filename:"lib",url:"lib.html#including-magento-ui-library-to-your-theme"},{title:"loaders",filename:"loaders",url:"loaders.html"},{title:"Loaders",filename:"loaders",url:"loaders.html#loaders"},{title:"Default loader variables",filename:"loaders",url:"loaders.html#default-loader-variables"},{title:"Loading",filename:"loaders",url:"loaders.html#loading"},{title:"Loading default variables",filename:"loaders",url:"loaders.html#loading-default-variables"},{title:"messages",filename:"messages",url:"messages.html"},{title:"Messages",filename:"messages",url:"messages.html#messages"},{title:"Information message",filename:"messages",url:"messages.html#information-message"},{title:"Warning message",filename:"messages",url:"messages.html#warning-message"},{title:"Error message",filename:"messages",url:"messages.html#error-message"},{title:"Success message",filename:"messages",url:"messages.html#success-message"},{title:"Notice message",filename:"messages",url:"messages.html#notice-message"},{title:"Message with inner icon",filename:"messages",url:"messages.html#message-with-inner-icon"},{title:"Message with lateral icon",filename:"messages",url:"messages.html#message-with-lateral-icon"},{title:"Custom message style",filename:"messages",url:"messages.html#custom-message-style"},{title:"Messages global variables",filename:"messages",url:"messages.html#messages-global-variables"},{title:"pages",filename:"pages",url:"pages.html"},{title:"Pagination HTML markup",filename:"pages",url:"pages.html#pagination-html-markup"},{title:"Pagination variables",filename:"pages",url:"pages.html#pagination-variables"},{title:"Pagination with label and gradient background on links",filename:"pages",url:"pages.html#pagination-with-label-and-gradient-background-on-links"},{title:'Pagination with "previous"..."next" text links and label',filename:"pages",url:"pages.html#pagination-with-previousnext-text-links-and-label"},{title:"Pagination without label, with solid background",filename:"pages",url:"pages.html#pagination-without-label-with-solid-background"},{title:"popups",filename:"popups",url:"popups.html"},{title:"Popups",filename:"popups",url:"popups.html#popups"},{title:"Popup variables",filename:"popups",url:"popups.html#popup-variables"},{title:"Window overlay mixin variables",filename:"popups",url:"popups.html#window-overlay-mixin-variables"},{title:"Fixed height popup",filename:"popups",url:"popups.html#fixed-height-popup"},{title:"Fixed content height popup",filename:"popups",url:"popups.html#fixed-content-height-popup"},{title:"Margins for header, content and footer block in popup",filename:"popups",url:"popups.html#margins-for-header-content-and-footer-block-in-popup"},{title:"Popup titles styled as theme headings",filename:"popups",url:"popups.html#popup-titles-styled-as-theme-headings"},{title:"Popup action toolbar",filename:"popups",url:"popups.html#popup-action-toolbar"},{title:"Popup Close button without an icon",filename:"popups",url:"popups.html#popup-close-button-without-an-icon"},{title:"Modify the icon of popup Close button",filename:"popups",url:"popups.html#modify-the-icon-of-popup-close-button"},{title:"Modify overlay styles",filename:"popups",url:"popups.html#modify-overlay-styles"},{title:"rating",filename:"rating",url:"rating.html"},{title:"Ratings",filename:"rating",url:"rating.html#ratings"},{title:"Global rating variables",filename:"rating",url:"rating.html#global-rating-variables"},{title:"Rating with vote",filename:"rating",url:"rating.html#rating-with-vote"},{title:"Rating with vote icons number customization",filename:"rating",url:"rating.html#rating-with-vote-icons-number-customization"},{title:"Rating with vote icons colors customization",filename:"rating",url:"rating.html#rating-with-vote-icons-colors-customization"},{title:"Rating with vote icons symbol customization",filename:"rating",url:"rating.html#rating-with-vote-icons-symbol-customization"},{title:"Accessible rating with vote",filename:"rating",url:"rating.html#accessible-rating-with-vote"},{title:"Rating summary",filename:"rating",url:"rating.html#rating-summary"},{title:"Rating summary icons number customization",filename:"rating",url:"rating.html#rating-summary-icons-number-customization"},{title:"Rating summary icons color customization",filename:"rating",url:"rating.html#rating-summary-icons-color-customization"},{title:"Rating summary icons symbol customization",filename:"rating",url:"rating.html#rating-summary-icons-symbol-customization"},{title:"Rating summary hide label",filename:"rating",url:"rating.html#rating-summary-hide-label"},{title:"Rating summary multiple ratings",filename:"rating",url:"rating.html#rating-summary-multiple-ratings"},{title:"Rating hide label mixin",filename:"rating",url:"rating.html#rating-hide-label-mixin"},{title:"resets",filename:"resets",url:"resets.html"},{title:"Resets",filename:"resets",url:"resets.html#resets"},{title:"responsive",filename:"responsive",url:"responsive.html"},{title:"Responsive",filename:"responsive",url:"responsive.html#responsive"},{title:"Responsive mixins usage",filename:"responsive",url:"responsive.html#responsive-mixins-usage"},{title:"Media query style groups separation variables",filename:"responsive",url:"responsive.html#media-query-style-groups-separation-variables"},{title:"Responsive breakpoints",filename:"responsive",url:"responsive.html#responsive-breakpoints"},{title:"sections",filename:"sections",url:"sections.html"},{title:"Tabs and accordions",filename:"sections",url:"sections.html#tabs-and-accordions"},{title:"Tabs",filename:"sections",url:"sections.html#tabs"},{title:"Tabs mixin variables",filename:"sections",url:"sections.html#tabs-mixin-variables"},{title:"Tabs with content top border",filename:"sections",url:"sections.html#tabs-with-content-top-border"},{title:"Accordion",filename:"sections",url:"sections.html#accordion"},{title:"Accordion mixin variables",filename:"sections",url:"sections.html#accordion-mixin-variables"},{title:"Responsive tabs",filename:"sections",url:"sections.html#responsive-tabs"},{title:"Tabs Base",filename:"sections",url:"sections.html#tabs-base"},{title:"Accordion Base",filename:"sections",url:"sections.html#accordion-base"},{title:"tables",filename:"tables",url:"tables.html"},{title:"Tables",filename:"tables",url:"tables.html#tables"},{title:"Table mixin variables",filename:"tables",url:"tables.html#table-mixin-variables"},{title:"Table typography",filename:"tables",url:"tables.html#table-typography"},{title:"Table typography mixin variables",filename:"tables",url:"tables.html#table-typography-mixin-variables"},{title:"Table caption",filename:"tables",url:"tables.html#table-caption"},{title:"Table caption mixin variables",filename:"tables",url:"tables.html#table-caption-mixin-variables"},{title:"Table cells resize",filename:"tables",url:"tables.html#table-cells-resize"},{title:"Table cells resize variables",filename:"tables",url:"tables.html#table-cells-resize-variables"},{title:"Table background customization",filename:"tables",url:"tables.html#table-background-customization"},{title:"Table background mixin variables",filename:"tables",url:"tables.html#table-background-mixin-variables"},{title:"Table borders customization",filename:"tables",url:"tables.html#table-borders-customization"},{title:"Table borders mixin variables",filename:"tables",url:"tables.html#table-borders-mixin-variables"},{title:"Table with horizontal borders",filename:"tables",url:"tables.html#table-with-horizontal-borders"},{title:"Table with vertical borders",filename:"tables",url:"tables.html#table-with-vertical-borders"},{title:"Table with light borders",filename:"tables",url:"tables.html#table-with-light-borders"},{title:"Table without borders",filename:"tables",url:"tables.html#table-without-borders"},{title:"Striped table",filename:"tables",url:"tables.html#striped-table"},{title:"Striped table mixin variables",filename:"tables",url:"tables.html#striped-table-mixin-variables"},{title:"Table with rows hover",filename:"tables",url:"tables.html#table-with-rows-hover"},{title:"Table with rows hover mixin variables",filename:"tables",url:"tables.html#table-with-rows-hover-mixin-variables"},{title:"Responsive table technics #1",filename:"tables",url:"tables.html#responsive-table-technics-1"},{title:"Responsive table technics #2",filename:"tables",url:"tables.html#responsive-table-technics-2"},{title:"Responsive table technics #2 mixin variables",filename:"tables",url:"tables.html#responsive-table-technics-2-mixin-variables"},{title:"tooltips",filename:"tooltips",url:"tooltips.html"},{title:"Tooltips",filename:"tooltips",url:"tooltips.html#tooltips"},{title:"Tooltips variables",filename:"tooltips",url:"tooltips.html#tooltips-variables"},{title:"typography",filename:"typography",url:"typography.html"},{title:"Typogrphy",filename:"typography",url:"typography.html#typogrphy"},{title:"Typography variables",filename:"typography",url:"typography.html#typography-variables"},{title:"Font-size mixin",filename:"typography",url:"typography.html#fontsize-mixin"},{title:"Line-height mixin",filename:"typography",url:"typography.html#lineheight-mixin"},{title:"Word breaking mixin",filename:"typography",url:"typography.html#word-breaking-mixin"},{title:"Font face mixin",filename:"typography",url:"typography.html#font-face-mixin"},{title:"Text overflow mixin",filename:"typography",url:"typography.html#text-overflow-mixin"},{title:"Text hide",filename:"typography",url:"typography.html#text-hide"},{title:"Hyphens",filename:"typography",url:"typography.html#hyphens"},{title:"Font style and color",filename:"typography",url:"typography.html#font-style-and-color"},{title:"Font style mixin variables",filename:"typography",url:"typography.html#font-style-mixin-variables"},{title:"Reset list styles",filename:"typography",url:"typography.html#reset-list-styles"},{title:"Reset list styles variables",filename:"typography",url:"typography.html#reset-list-styles-variables"},{title:"Inline-block list item styling",filename:"typography",url:"typography.html#inlineblock-list-item-styling"},{title:"Link styling mixin",filename:"typography",url:"typography.html#link-styling-mixin"},{title:"Link styling mixin variables",filename:"typography",url:"typography.html#link-styling-mixin-variables"},{title:"Heading styling mixin",filename:"typography",url:"typography.html#heading-styling-mixin"},{title:"Base typography mixins",filename:"typography",url:"typography.html#base-typography-mixins"},{title:"Base typography mixin variables",filename:"typography",url:"typography.html#base-typography-mixin-variables"},{title:"Headings typography mixin",filename:"typography",url:"typography.html#headings-typography-mixin"},{title:"Headings typography mixin variables",filename:"typography",url:"typography.html#headings-typography-mixin-variables"},{title:"Typography links mixin",filename:"typography",url:"typography.html#typography-links-mixin"},{title:"Typography lists mixin",filename:"typography",url:"typography.html#typography-lists-mixin"},{title:"Typography lists mixin variables",filename:"typography",url:"typography.html#typography-lists-mixin-variables"},{title:"Typography code elements mixin",filename:"typography",url:"typography.html#typography-code-elements-mixin"},{title:"Typography code mixin variables",filename:"typography",url:"typography.html#typography-code-mixin-variables"},{title:"Typography blockquote",filename:"typography",url:"typography.html#typography-blockquote"},{title:"Typography blockquote mixin variables",filename:"typography",url:"typography.html#typography-blockquote-mixin-variables"},{title:"utilities",filename:"utilities",url:"utilities.html"},{title:"Utilities",filename:"utilities",url:"utilities.html#utilities"},{title:".lib-clearfix()",filename:"utilities",url:"utilities.html#libclearfix"},{title:".lib-visibility-hidden()",filename:"utilities",url:"utilities.html#libvisibilityhidden"},{title:".lib-visually-hidden()",filename:"utilities",url:"utilities.html#libvisuallyhidden"},{title:".lib-visually-hidden-reset()",filename:"utilities",url:"utilities.html#libvisuallyhiddenreset"},{title:".lib-css()",filename:"utilities",url:"utilities.html#libcss"},{title:".lib-css() variables",filename:"utilities",url:"utilities.html#libcss-variables"},{title:".lib-rotate()",filename:"utilities",url:"utilities.html#librotate"},{title:".lib-rotate() variables",filename:"utilities",url:"utilities.html#librotate-variables"},{title:".lib-input-placeholder()",filename:"utilities",url:"utilities.html#libinputplaceholder"},{title:".lib-input-placeholder() variables",filename:"utilities",url:"utilities.html#libinputplaceholder-variables"},{title:".lib-background-gradient()",filename:"utilities",url:"utilities.html#libbackgroundgradient"},{title:".lib-background-gradient() variables",filename:"utilities",url:"utilities.html#libbackgroundgradient-variables"},{title:"variables",filename:"variables",url:"variables.html"},{title:"List of Global Variables",filename:"variables",url:"variables.html#list-of-global-variables"},{title:"Table with rows hover mixin variables",filename:"variables",url:"variables.html#table-with-rows-hover-mixin-variables"},{title:"docs",filename:"docs",url:"docs.html"},{title:"Documentation",filename:"docs",url:"docs.html#documentation"}];(function(){"use strict";var b=function(a,b){return Array.prototype.indexOf.call(a,b)!==-1},c=function(a,b){return Array.prototype.filter.call(a,b)},d=function(a,b){return Array.prototype.forEach.call(a,b)},e=document.getElementsByTagName("body")[0];e.addEventListener("click",function(a){var b=a.target;b.tagName.toLowerCase()==="svg"&&(b=b.parentNode);var c=!1;b.dataset.toggle!=null&&(a.preventDefault(),b.classList.contains("is-active")||(c=!0)),d(e.querySelectorAll("[data-toggle]"),function(a){a.classList.remove("is-active"),document.getElementById(a.dataset.toggle).hidden=!0}),c&&(b.classList.add("is-active"),document.getElementById(b.dataset.toggle).hidden=!1)}),function(){var f=e.getElementsByClassName("nav")[0];if(!f)return;var g=document.createElement("ul");g.className="nav-results",g.id="nav-search",g.hidden=!0,d(a,function(a){var b,c,d;b=document.createElement("li"),b._title=a.title.toLowerCase(),b.hidden=!0,b.appendChild(c=document.createElement("a")),c.href=a.url,c.innerHTML=a.title,c.appendChild(d=document.createElement("span")),d.innerHTML=a.filename,d.className="nav-results-filename",g.appendChild(b)}),f.appendChild(g);var h=g.children,i=function(a){d(h,function(a){a.hidden=!0});var b=this.value.toLowerCase(),e=[];b!==""&&(e=c(h,function(a){return a._title.indexOf(b)!==-1})),e.length>0?(d(e,function(a){a.hidden=!1}),g.hidden=!1):g.hidden=!0},j=f.querySelector('input[type="search"]');j.addEventListener("keyup",i),j.addEventListener("focus",i),e.addEventListener("click",function(a){if(a.target.classList&&a.target.classList.contains("search"))return;g.hidden=!0}),g.addEventListener("click",function(a){j.value=""});var k=document.createElement("ul");k.id="nav-toc",k.hidden=!0,k.className="nav-results toc-list",c(e.getElementsByTagName("*"),function(a){return b(["h1","h2","h3"],a.tagName.toLowerCase())}).map(function(a){var b=document.createElement("li"),c=document.createElement("a"),d=a.tagName.toLowerCase()[1];c.classList.add("level-"+d),b.appendChild(c),c.href="#"+a.id,c.innerHTML=a.innerHTML,k.appendChild(b)}),f.appendChild(k)}()})(),function(){"use strict";if(location.hash==="#__preview__"||location.protocol==="data:")return;var a=function(a,b){return Array.prototype.forEach.call(a,b)},b=function(a,b){var e=Array.prototype.slice.call(arguments,2);return d(a,function(a){return(c(b)?b||a:a[b]).apply(a,e)})},c=function(a){return Object.prototype.toString.call(a)==="[object Function]"},d=function(a,b){return Array.prototype.map.call(a,b)},e=function(a,b){return d(a,function(a){return a[b]})},f=function(a){var b={},c=a.split(";");for(var d=0;c.length>d;d++){var e=c[d].trim().split("=");b[e[0]]=e[1]}return b},g=function(a,c){return b(e(a,"classList"),"remove",c)},h=function(a,b){a.contentDocument.defaultView.postMessage(b,"*")},i=document.getElementsByTagName("head")[0],j=document.getElementsByTagName("body")[0],k=e(i.querySelectorAll('style[type="text/preview"]'),"innerHTML").join(""),l=e(i.querySelectorAll('script[type="text/preview"]'),"innerHTML").join(""),m=location.href.split("#")[0]+"#__preview__",n=document.createElement("iframe");n.src="data:text/html,",j.appendChild(n),n.addEventListener("load",function(){var b={sameOriginDataUri:!0};try{this.contentDocument,this.contentDocument||(b.sameOriginDataUri=!1)}catch(c){b.sameOriginDataUri=!1}this.parentNode.removeChild(this),a(j.getElementsByTagName("textarea"),function(a,c){o(a,b,c),q(),p(a)})});var o=function(a,b,c){var d,e,f;d=document.createElement("div"),d.appendChild(e=document.createElement("div")),d.className="preview",e.appendChild(f=document.createElement("iframe")),e.className="resizeable",f.setAttribute("scrolling","no"),f.name="iframe"+c++,f.addEventListener("load",function(){var c,d,e,f,g,i,j;j=this.contentDocument;if(!b.sameOriginDataUri&&this.src!==m)return;this.src===m&&(c=j.createElement("html"),c.appendChild(j.createElement("head")),c.appendChild(d=j.createElement("body")),d.innerHTML=a.textContent,j.replaceChild(c,j.documentElement)),g=j.createElement("head"),g.appendChild(f=j.createElement("style")),g.appendChild(e=j.createElement("script")),e.textContent=l,f.textContent=k,i=j.getElementsByTagName("head")[0],i.parentNode.replaceChild(g,i),h(this,"getHeight")});var g;b.sameOriginDataUri?g="data:text/html;charset=utf-8,"+encodeURIComponent("<!doctype html><html><head></head></body>"+a.textContent):g=m,f.setAttribute("src",g);var i=function(){f.contentDocument.body.innerHTML=this.value,h(f,"getHeight")};a.addEventListener("keypress",i),a.addEventListener("keyup",i),a.parentNode.insertBefore(d,a)},p=function(a){var b=document.createElement("div");b.className="preview-code",b.style.position="absolute",b.style.left="-9999px",j.appendChild(b);var c=parseInt(window.getComputedStyle(a).getPropertyValue("max-height"),10),d=function(a){b.textContent=this.value+"\n";var d=b.offsetHeight+2;d>=c?this.style.overflow="auto":this.style.overflow="hidden",this.style.height=b.offsetHeight+2+"px"};a.addEventListener("keypress",d),a.addEventListener("keyup",d),d.call(a)},q=function(){var b=j.getElementsByClassName("settings")[0],c=j.getElementsByClassName("resizeable"),d=30,e=function(b){document.cookie="preview-width="+b,a(c,function(a){b==="auto"&&(b=a.parentNode.offsetWidth),a.style.width=b+"px",h(a.getElementsByTagName("iframe")[0],"getHeight")})},i=f(document.cookie)["preview-width"];if(i){e(i),g(b.getElementsByClassName("is-active"),"is-active");var k=b.querySelector('button[data-width="'+i+'"]');k&&k.classList.add("is-active")}window.addEventListener("message",function(a){if(a.data==null||!a.source)return;var b=a.data,c=document.getElementsByName(a.source.name)[0];b.height!=null&&c&&(c.parentNode.style.height=b.height+d+"px")},!1),b&&c.length>0&&(b.hidden=!1,b.addEventListener("click",function(a){var c=a.target.tagName.toLowerCase(),d;if(c==="button")d=a.target;else{if(c!=="svg")return;d=a.target.parentNode}a.preventDefault(),g(b.getElementsByClassName("is-active"),"is-active"),d.classList.add("is-active");var f=d.dataset.width;e(f)}))}}()})()</script></body></html><!-- Generated with StyleDocco (http://jacobrask.github.com/styledocco). --> diff --git a/lib/web/css/docs/index.html b/lib/web/css/docs/index.html index cbf3de48cdfc7..07cd72e6f823f 100644 --- a/lib/web/css/docs/index.html +++ b/lib/web/css/docs/index.html @@ -608,4 +608,4 @@ <h3 id="location">Location</h3> Extends that used in more than one theme should be saved in lib <strong>lib/source/_abstract.less</strong> (will be renamed to _extend.less)</p> <h3 id="naming">Naming</h3> <p>Extend class names should have prefix <strong>.abs-</strong> (from abstract)</p> -</div></article></section><div class="bar bottom"><div hidden class="settings container"><!-- Icons from http://iconmonstr.com--><button title="Desktop (1280)" data-width='1280'><svg viewBox="0 0 412 386" height="24" width="26" class="icon"><path d="m147.6,343.9c-4.5,15.9-26.2,37.6-42.1,42.1h201c-15.3,-4-38.1,-26.8-42.1,-42.1H147.6zM387,0.5H25c-13.8,0-25,11.2-25,25V294c0,13.8 11.2,25 25,25h362c13.8,0 25,-11.2 25,-25V25.5C412,11.7 400.8,0.5 387,0.5zM369.9,238.2H42.1L42.1,42.6 369.9,42.6V238.2z"></path></svg></button><button title="Laptop (1024)" data-width='1024'><svg viewBox="0 0 384 312" height="23" width="28" class="icon"><path d="m349.2,20.5c0,-11-9,-20-20,-20H53.6c-11,0-20,9-20,20v194H349.2v-194zm-27,167H60.6V27.5H322.2v160zm28,42H32.6L2.6,282.1c-3.5,6.2-3.5,13.8 0.1,19.9 3.6,6.2 10.2,9.9 17.3,9.9H363.1c7.1,0 13.7,-3.8 17.3,-10 3.6,-6.2 3.6,-13.8 0,-20l-30.2,-52.5zm-196.9,54 8,-23.5h60.5l8,23.5h-76.5z"></path></svg></button><button title="Tablet (768)" data-width='768'><svg viewBox="0 0 317 412" height="24" width="18" class="icon"><path d="M 316.5,380 V 32 c 0,-17.7 -14.3,-32 -32,-32 H 32 C 14.3,0 0,14.3 0,32 v 348 c 0,17.7 14.3,32 32,32 h 252.5 c 17.7,0 32,-14.3 32,-32 z M 40,367 V 45 H 276.5 V 367 H 40 z m 109.8,22.7 c 0,-4.7 3.8,-8.5 8.5,-8.5 4.7,0 8.5,3.8 8.5,8.5 0,4.7 -3.8,8.5 -8.5,8.5 -4.7,0 -8.5,-3.8 -8.5,-8.5 z"></path></svg></button><button title="Smart phone (320)" data-width='320'><svg viewBox="0 0 224 412" height="24" width="13" class="icon"><path d="M 190.7,0 H 33 C 14.8,0 0,14.8 0,33 v 346 c 0,18.2 14.8,33 33,33 h 157.7 c 18.2,0 33,-14.8 33,-33 V 33 c 0,-18.2 -14.8,-33 -33,-33 z M 94.3,30.2 h 37 c 2.2,0 4,1.8 4,4 0,2.2 -1.8,4 -4,4 h -37 c -2.2,0 -4,-1.8 -4,-4 0,-2.2 1.8,-4 4,-4 z m 18.5,362.8 c -8.8,0 -16,-7.2 -16,-16 0,-8.8 7.2,-16 16,-16 8.8,0 16,7.2 16,16 0,8.8 -7.2,16 -16,16 z M 198.6,343.8 H 25.1 V 68.2 h 173.5 v 275.5 z"></path></svg></button><button title="Feature phone (240)" data-width='240'><svg viewBox="0 0 201 412" height="24" width="12" class="icon"><path d="M 165.5,0.2 V 45 H 25 c -13.8,0 -25,11.2 -25,25 V 387 c 0,13.8 11.2,25 25,25 h 150.5 c 13.8,0 25,-11.2 25,-25 V 0.2 h -35 z M 65.2,366.5 H 34.2 v -24.5 h 31 v 24.5 z m 0,-44.3 H 34.2 v -24.5 h 31 v 24.5 z m 50.5,44.3 H 84.7 v -24.5 h 31 v 24.5 z m 0,-44.3 H 84.7 v -24.5 h 31 v 24.5 z m 50.5,44.3 h -31 v -24.5 h 31 v 24.5 z m 0,-44.3 h -31 v -24.5 h 31 v 24.5 z m 0,-59.3 h -132 V 95.4 h 132 V 262.9 z"></path></svg></button><button title="Auto (100%)" data-width="auto" class="auto is-active">Auto</button></div></div><script>(function(){var a=[{title:"actions-toolbar",filename:"actions-toolbar",url:"actions-toolbar.html"},{title:"Actions toolbar",filename:"actions-toolbar",url:"actions-toolbar.html#actions-toolbar"},{title:"Actions toolbar mixin variables",filename:"actions-toolbar",url:"actions-toolbar.html#actions-toolbar-mixin-variables"},{title:"Actions toolbar alignment",filename:"actions-toolbar",url:"actions-toolbar.html#actions-toolbar-alignment"},{title:"Reverse primary and secondary blocks",filename:"actions-toolbar",url:"actions-toolbar.html#reverse-primary-and-secondary-blocks"},{title:"Actions toolbar indents customizations",filename:"actions-toolbar",url:"actions-toolbar.html#actions-toolbar-indents-customizations"},{title:"Responsive actions toolbar",filename:"actions-toolbar",url:"actions-toolbar.html#responsive-actions-toolbar"},{title:"breadcrumbs",filename:"breadcrumbs",url:"breadcrumbs.html"},{title:"Breadcrumbs",filename:"breadcrumbs",url:"breadcrumbs.html#breadcrumbs"},{title:"Breadcrumbs variables",filename:"breadcrumbs",url:"breadcrumbs.html#breadcrumbs-variables"},{title:"Button-styled breadcrumbs with gradient background, border, and no separating symbol",filename:"breadcrumbs",url:"breadcrumbs.html#buttonstyled-breadcrumbs-with-gradient-background-border-and-no-separating-symbol"},{title:"Breadcrumbs with solid background",filename:"breadcrumbs",url:"breadcrumbs.html#breadcrumbs-with-solid-background"},{title:"buttons",filename:"buttons",url:"buttons.html"},{title:"Default button",filename:"buttons",url:"buttons.html#default-button"},{title:"Button variables",filename:"buttons",url:"buttons.html#button-variables"},{title:"Button as an icon",filename:"buttons",url:"buttons.html#button-as-an-icon"},{title:"Button with an icon on the left or right side of the text",filename:"buttons",url:"buttons.html#button-with-an-icon-on-the-left-or-right-side-of-the-text"},{title:"Button with fixed width",filename:"buttons",url:"buttons.html#button-with-fixed-width"},{title:"Primary button",filename:"buttons",url:"buttons.html#primary-button"},{title:"Primary button variables",filename:"buttons",url:"buttons.html#primary-button-variables"},{title:"Button with gradient background",filename:"buttons",url:"buttons.html#button-with-gradient-background"},{title:"Button as a link",filename:"buttons",url:"buttons.html#button-as-a-link"},{title:"Button as a link variables",filename:"buttons",url:"buttons.html#button-as-a-link-variables"},{title:"Link as a button",filename:"buttons",url:"buttons.html#link-as-a-button"},{title:"Button reset",filename:"buttons",url:"buttons.html#button-reset"},{title:"Button revert secondary color",filename:"buttons",url:"buttons.html#button-revert-secondary-color"},{title:"Button revert secondary color variables",filename:"buttons",url:"buttons.html#button-revert-secondary-color-variables"},{title:"Button revert secondary size",filename:"buttons",url:"buttons.html#button-revert-secondary-size"},{title:"Button revert secondary size variables",filename:"buttons",url:"buttons.html#button-revert-secondary-size-variables"},{title:"components",filename:"components",url:"components.html"},{title:"Components",filename:"components",url:"components.html#components"},{title:"Components Variables",filename:"components",url:"components.html#components-variables"},{title:"dropdowns",filename:"dropdowns",url:"dropdowns.html"},{title:"Drop-down and split buttons mixins",filename:"dropdowns",url:"dropdowns.html#dropdown-and-split-buttons-mixins"},{title:"Drop-down",filename:"dropdowns",url:"dropdowns.html#dropdown"},{title:"Drop-down variables",filename:"dropdowns",url:"dropdowns.html#dropdown-variables"},{title:"Drop-down with icon customization",filename:"dropdowns",url:"dropdowns.html#dropdown-with-icon-customization"},{title:"Modify dropdown list styles",filename:"dropdowns",url:"dropdowns.html#modify-dropdown-list-styles"},{title:"Split button",filename:"dropdowns",url:"dropdowns.html#split-button"},{title:"Split button variables",filename:"dropdowns",url:"dropdowns.html#split-button-variables"},{title:"Split button - button styling",filename:"dropdowns",url:"dropdowns.html#split-button-button-styling"},{title:"Split button icon customization",filename:"dropdowns",url:"dropdowns.html#split-button-icon-customization"},{title:"Split button drop-down list customization",filename:"dropdowns",url:"dropdowns.html#split-button-dropdown-list-customization"},{title:"forms",filename:"forms",url:"forms.html"},{title:"Forms mixins",filename:"forms",url:"forms.html#forms-mixins"},{title:"Global forms elements customization",filename:"forms",url:"forms.html#global-forms-elements-customization"},{title:"Fieldsets & fields customization",filename:"forms",url:"forms.html#fieldsets-fields-customization"},{title:"Fieldset and legend customization variables",filename:"forms",url:"forms.html#fieldset-and-legend-customization-variables"},{title:"Fields customization variables",filename:"forms",url:"forms.html#fields-customization-variables"},{title:"Required fields message customization variables",filename:"forms",url:"forms.html#required-fields-message-customization-variables"},{title:"Form element inputs customization",filename:"forms",url:"forms.html#form-element-inputs-customization"},{title:"Form element inputs customization variables",filename:"forms",url:"forms.html#form-element-inputs-customization-variables"},{title:"Form element choice",filename:"forms",url:"forms.html#form-element-choice"},{title:"Form element choice variables",filename:"forms",url:"forms.html#form-element-choice-variables"},{title:"Custom color",filename:"forms",url:"forms.html#custom-color"},{title:"Input number - input-text view",filename:"forms",url:"forms.html#input-number-inputtext-view"},{title:"Input search - input-text view",filename:"forms",url:"forms.html#input-search-inputtext-view"},{title:"Form validation",filename:"forms",url:"forms.html#form-validation"},{title:"Form validation variables",filename:"forms",url:"forms.html#form-validation-variables"},{title:"icons",filename:"icons",url:"icons.html"},{title:"Icons",filename:"icons",url:"icons.html#icons"},{title:"Icon with image or sprite",filename:"icons",url:"icons.html#icon-with-image-or-sprite"},{title:"Icon with image or sprite variables",filename:"icons",url:"icons.html#icon-with-image-or-sprite-variables"},{title:"Icon position for an icon with image or sprite",filename:"icons",url:"icons.html#icon-position-for-an-icon-with-image-or-sprite"},{title:"Position for icon with image or sprite mixin variables",filename:"icons",url:"icons.html#position-for-icon-with-image-or-sprite-mixin-variables"},{title:"Icon sprite position (with grid)",filename:"icons",url:"icons.html#icon-sprite-position-with-grid"},{title:"Icon sprite position variables",filename:"icons",url:"icons.html#icon-sprite-position-variables"},{title:"Image/sprite icon size",filename:"icons",url:"icons.html#imagesprite-icon-size"},{title:"Image/sprite icon size variables",filename:"icons",url:"icons.html#imagesprite-icon-size-variables"},{title:"Font icon",filename:"icons",url:"icons.html#font-icon"},{title:"Font icon variables",filename:"icons",url:"icons.html#font-icon-variables"},{title:"Change the size of font icon",filename:"icons",url:"icons.html#change-the-size-of-font-icon"},{title:"Change the size of font icon variables",filename:"icons",url:"icons.html#change-the-size-of-font-icon-variables"},{title:"Hide icon text",filename:"icons",url:"icons.html#hide-icon-text"},{title:"Sprite and font icons for Blank theme",filename:"icons",url:"icons.html#sprite-and-font-icons-for-blank-theme"},{title:"layout",filename:"layout",url:"layout.html"},{title:"Layout",filename:"layout",url:"layout.html#layout"},{title:"Layout global variables",filename:"layout",url:"layout.html#layout-global-variables"},{title:"Page layouts",filename:"layout",url:"layout.html#page-layouts"},{title:"Layout column",filename:"layout",url:"layout.html#layout-column"},{title:"Layout column variables",filename:"layout",url:"layout.html#layout-column-variables"},{title:"Layout width",filename:"layout",url:"layout.html#layout-width"},{title:"Layout width variables",filename:"layout",url:"layout.html#layout-width-variables"},{title:"lib",filename:"lib",url:"lib.html"},{title:"Including Magento UI library to your theme",filename:"lib",url:"lib.html#including-magento-ui-library-to-your-theme"},{title:"loaders",filename:"loaders",url:"loaders.html"},{title:"Loaders",filename:"loaders",url:"loaders.html#loaders"},{title:"Default loader variables",filename:"loaders",url:"loaders.html#default-loader-variables"},{title:"Loading",filename:"loaders",url:"loaders.html#loading"},{title:"Loading default variables",filename:"loaders",url:"loaders.html#loading-default-variables"},{title:"messages",filename:"messages",url:"messages.html"},{title:"Messages",filename:"messages",url:"messages.html#messages"},{title:"Information message",filename:"messages",url:"messages.html#information-message"},{title:"Warning message",filename:"messages",url:"messages.html#warning-message"},{title:"Error message",filename:"messages",url:"messages.html#error-message"},{title:"Success message",filename:"messages",url:"messages.html#success-message"},{title:"Notice message",filename:"messages",url:"messages.html#notice-message"},{title:"Message with inner icon",filename:"messages",url:"messages.html#message-with-inner-icon"},{title:"Message with lateral icon",filename:"messages",url:"messages.html#message-with-lateral-icon"},{title:"Custom message style",filename:"messages",url:"messages.html#custom-message-style"},{title:"Messages global variables",filename:"messages",url:"messages.html#messages-global-variables"},{title:"pages",filename:"pages",url:"pages.html"},{title:"Pagination HTML markup",filename:"pages",url:"pages.html#pagination-html-markup"},{title:"Pagination variables",filename:"pages",url:"pages.html#pagination-variables"},{title:"Pagination with label and gradient background on links",filename:"pages",url:"pages.html#pagination-with-label-and-gradient-background-on-links"},{title:'Pagination with "previous"..."next" text links and label',filename:"pages",url:"pages.html#pagination-with-previousnext-text-links-and-label"},{title:"Pagination without label, with solid background",filename:"pages",url:"pages.html#pagination-without-label-with-solid-background"},{title:"popups",filename:"popups",url:"popups.html"},{title:"Popups",filename:"popups",url:"popups.html#popups"},{title:"Popup variables",filename:"popups",url:"popups.html#popup-variables"},{title:"Window overlay mixin variables",filename:"popups",url:"popups.html#window-overlay-mixin-variables"},{title:"Fixed height popup",filename:"popups",url:"popups.html#fixed-height-popup"},{title:"Fixed content height popup",filename:"popups",url:"popups.html#fixed-content-height-popup"},{title:"Margins for header, content and footer block in popup",filename:"popups",url:"popups.html#margins-for-header-content-and-footer-block-in-popup"},{title:"Popup titles styled as theme headings",filename:"popups",url:"popups.html#popup-titles-styled-as-theme-headings"},{title:"Popup action toolbar",filename:"popups",url:"popups.html#popup-action-toolbar"},{title:"Popup Close button without an icon",filename:"popups",url:"popups.html#popup-close-button-without-an-icon"},{title:"Modify the icon of popup Close button",filename:"popups",url:"popups.html#modify-the-icon-of-popup-close-button"},{title:"Modify overlay styles",filename:"popups",url:"popups.html#modify-overlay-styles"},{title:"rating",filename:"rating",url:"rating.html"},{title:"Ratings",filename:"rating",url:"rating.html#ratings"},{title:"Global rating variables",filename:"rating",url:"rating.html#global-rating-variables"},{title:"Rating with vote",filename:"rating",url:"rating.html#rating-with-vote"},{title:"Rating with vote icons number customization",filename:"rating",url:"rating.html#rating-with-vote-icons-number-customization"},{title:"Rating with vote icons colors customization",filename:"rating",url:"rating.html#rating-with-vote-icons-colors-customization"},{title:"Rating with vote icons symbol customization",filename:"rating",url:"rating.html#rating-with-vote-icons-symbol-customization"},{title:"Accessible rating with vote",filename:"rating",url:"rating.html#accessible-rating-with-vote"},{title:"Rating summary",filename:"rating",url:"rating.html#rating-summary"},{title:"Rating summary icons number customization",filename:"rating",url:"rating.html#rating-summary-icons-number-customization"},{title:"Rating summary icons color customization",filename:"rating",url:"rating.html#rating-summary-icons-color-customization"},{title:"Rating summary icons symbol customization",filename:"rating",url:"rating.html#rating-summary-icons-symbol-customization"},{title:"Rating summary hide label",filename:"rating",url:"rating.html#rating-summary-hide-label"},{title:"Rating summary multiple ratings",filename:"rating",url:"rating.html#rating-summary-multiple-ratings"},{title:"Rating hide label mixin",filename:"rating",url:"rating.html#rating-hide-label-mixin"},{title:"resets",filename:"resets",url:"resets.html"},{title:"Resets",filename:"resets",url:"resets.html#resets"},{title:"responsive",filename:"responsive",url:"responsive.html"},{title:"Responsive",filename:"responsive",url:"responsive.html#responsive"},{title:"Responsive mixins usage",filename:"responsive",url:"responsive.html#responsive-mixins-usage"},{title:"Media query style groups separation variables",filename:"responsive",url:"responsive.html#media-query-style-groups-separation-variables"},{title:"Responsive breakpoints",filename:"responsive",url:"responsive.html#responsive-breakpoints"},{title:"sections",filename:"sections",url:"sections.html"},{title:"Tabs and accordions",filename:"sections",url:"sections.html#tabs-and-accordions"},{title:"Tabs",filename:"sections",url:"sections.html#tabs"},{title:"Tabs mixin variables",filename:"sections",url:"sections.html#tabs-mixin-variables"},{title:"Tabs with content top border",filename:"sections",url:"sections.html#tabs-with-content-top-border"},{title:"Accordion",filename:"sections",url:"sections.html#accordion"},{title:"Accordion mixin variables",filename:"sections",url:"sections.html#accordion-mixin-variables"},{title:"Responsive tabs",filename:"sections",url:"sections.html#responsive-tabs"},{title:"Tabs Base",filename:"sections",url:"sections.html#tabs-base"},{title:"Accordion Base",filename:"sections",url:"sections.html#accordion-base"},{title:"tables",filename:"tables",url:"tables.html"},{title:"Tables",filename:"tables",url:"tables.html#tables"},{title:"Table mixin variables",filename:"tables",url:"tables.html#table-mixin-variables"},{title:"Table typography",filename:"tables",url:"tables.html#table-typography"},{title:"Table typography mixin variables",filename:"tables",url:"tables.html#table-typography-mixin-variables"},{title:"Table caption",filename:"tables",url:"tables.html#table-caption"},{title:"Table caption mixin variables",filename:"tables",url:"tables.html#table-caption-mixin-variables"},{title:"Table cells resize",filename:"tables",url:"tables.html#table-cells-resize"},{title:"Table cells resize variables",filename:"tables",url:"tables.html#table-cells-resize-variables"},{title:"Table background customization",filename:"tables",url:"tables.html#table-background-customization"},{title:"Table background mixin variables",filename:"tables",url:"tables.html#table-background-mixin-variables"},{title:"Table borders customization",filename:"tables",url:"tables.html#table-borders-customization"},{title:"Table borders mixin variables",filename:"tables",url:"tables.html#table-borders-mixin-variables"},{title:"Table with horizontal borders",filename:"tables",url:"tables.html#table-with-horizontal-borders"},{title:"Table with vertical borders",filename:"tables",url:"tables.html#table-with-vertical-borders"},{title:"Table with light borders",filename:"tables",url:"tables.html#table-with-light-borders"},{title:"Table without borders",filename:"tables",url:"tables.html#table-without-borders"},{title:"Striped table",filename:"tables",url:"tables.html#striped-table"},{title:"Striped table mixin variables",filename:"tables",url:"tables.html#striped-table-mixin-variables"},{title:"Table with rows hover",filename:"tables",url:"tables.html#table-with-rows-hover"},{title:"Table with rows hover mixin variables",filename:"tables",url:"tables.html#table-with-rows-hover-mixin-variables"},{title:"Responsive table technics #1",filename:"tables",url:"tables.html#responsive-table-technics-1"},{title:"Responsive table technics #2",filename:"tables",url:"tables.html#responsive-table-technics-2"},{title:"Responsive table technics #2 mixin variables",filename:"tables",url:"tables.html#responsive-table-technics-2-mixin-variables"},{title:"tooltips",filename:"tooltips",url:"tooltips.html"},{title:"Tooltips",filename:"tooltips",url:"tooltips.html#tooltips"},{title:"Tooltips variables",filename:"tooltips",url:"tooltips.html#tooltips-variables"},{title:"typography",filename:"typography",url:"typography.html"},{title:"Typogrphy",filename:"typography",url:"typography.html#typogrphy"},{title:"Typography variables",filename:"typography",url:"typography.html#typography-variables"},{title:"Font-size mixin",filename:"typography",url:"typography.html#fontsize-mixin"},{title:"Line-height mixin",filename:"typography",url:"typography.html#lineheight-mixin"},{title:"Word breaking mixin",filename:"typography",url:"typography.html#word-breaking-mixin"},{title:"Font face mixin",filename:"typography",url:"typography.html#font-face-mixin"},{title:"Text overflow mixin",filename:"typography",url:"typography.html#text-overflow-mixin"},{title:"Text hide",filename:"typography",url:"typography.html#text-hide"},{title:"Hyphens",filename:"typography",url:"typography.html#hyphens"},{title:"Font style and color",filename:"typography",url:"typography.html#font-style-and-color"},{title:"Font style mixin variables",filename:"typography",url:"typography.html#font-style-mixin-variables"},{title:"Reset list styles",filename:"typography",url:"typography.html#reset-list-styles"},{title:"Reset list styles variables",filename:"typography",url:"typography.html#reset-list-styles-variables"},{title:"Inline-block list item styling",filename:"typography",url:"typography.html#inlineblock-list-item-styling"},{title:"Link styling mixin",filename:"typography",url:"typography.html#link-styling-mixin"},{title:"Link styling mixin variables",filename:"typography",url:"typography.html#link-styling-mixin-variables"},{title:"Heading styling mixin",filename:"typography",url:"typography.html#heading-styling-mixin"},{title:"Base typography mixins",filename:"typography",url:"typography.html#base-typography-mixins"},{title:"Base typography mixin variables",filename:"typography",url:"typography.html#base-typography-mixin-variables"},{title:"Headings typography mixin",filename:"typography",url:"typography.html#headings-typography-mixin"},{title:"Headings typography mixin variables",filename:"typography",url:"typography.html#headings-typography-mixin-variables"},{title:"Typography links mixin",filename:"typography",url:"typography.html#typography-links-mixin"},{title:"Typography lists mixin",filename:"typography",url:"typography.html#typography-lists-mixin"},{title:"Typography lists mixin variables",filename:"typography",url:"typography.html#typography-lists-mixin-variables"},{title:"Typography code elements mixin",filename:"typography",url:"typography.html#typography-code-elements-mixin"},{title:"Typography code mixin variables",filename:"typography",url:"typography.html#typography-code-mixin-variables"},{title:"Typography blockquote",filename:"typography",url:"typography.html#typography-blockquote"},{title:"Typography blockquote mixin variables",filename:"typography",url:"typography.html#typography-blockquote-mixin-variables"},{title:"utilities",filename:"utilities",url:"utilities.html"},{title:"Utilities",filename:"utilities",url:"utilities.html#utilities"},{title:".lib-clearfix()",filename:"utilities",url:"utilities.html#libclearfix"},{title:".lib-visibility-hidden()",filename:"utilities",url:"utilities.html#libvisibilityhidden"},{title:".lib-visually-hidden()",filename:"utilities",url:"utilities.html#libvisuallyhidden"},{title:".lib-visually-hidden-reset()",filename:"utilities",url:"utilities.html#libvisuallyhiddenreset"},{title:".lib-css()",filename:"utilities",url:"utilities.html#libcss"},{title:".lib-css() variables",filename:"utilities",url:"utilities.html#libcss-variables"},{title:".lib-rotate()",filename:"utilities",url:"utilities.html#librotate"},{title:".lib-rotate() variables",filename:"utilities",url:"utilities.html#librotate-variables"},{title:".lib-input-placeholder()",filename:"utilities",url:"utilities.html#libinputplaceholder"},{title:".lib-input-placeholder() variables",filename:"utilities",url:"utilities.html#libinputplaceholder-variables"},{title:".lib-background-gradient()",filename:"utilities",url:"utilities.html#libbackgroundgradient"},{title:".lib-background-gradient() variables",filename:"utilities",url:"utilities.html#libbackgroundgradient-variables"},{title:".lib-url-check()",filename:"utilities",url:"utilities.html#liburlcheck"},{title:".lib-url-check() variables",filename:"utilities",url:"utilities.html#liburlcheck-variables"},{title:"variables",filename:"variables",url:"variables.html"},{title:"List of Global Variables",filename:"variables",url:"variables.html#list-of-global-variables"},{title:"Table with rows hover mixin variables",filename:"variables",url:"variables.html#table-with-rows-hover-mixin-variables"},{title:"docs",filename:"docs",url:"docs.html"},{title:"Documentation",filename:"docs",url:"docs.html#documentation"}];(function(){"use strict";var b=function(a,b){return Array.prototype.indexOf.call(a,b)!==-1},c=function(a,b){return Array.prototype.filter.call(a,b)},d=function(a,b){return Array.prototype.forEach.call(a,b)},e=document.getElementsByTagName("body")[0];e.addEventListener("click",function(a){var b=a.target;b.tagName.toLowerCase()==="svg"&&(b=b.parentNode);var c=!1;b.dataset.toggle!=null&&(a.preventDefault(),b.classList.contains("is-active")||(c=!0)),d(e.querySelectorAll("[data-toggle]"),function(a){a.classList.remove("is-active"),document.getElementById(a.dataset.toggle).hidden=!0}),c&&(b.classList.add("is-active"),document.getElementById(b.dataset.toggle).hidden=!1)}),function(){var f=e.getElementsByClassName("nav")[0];if(!f)return;var g=document.createElement("ul");g.className="nav-results",g.id="nav-search",g.hidden=!0,d(a,function(a){var b,c,d;b=document.createElement("li"),b._title=a.title.toLowerCase(),b.hidden=!0,b.appendChild(c=document.createElement("a")),c.href=a.url,c.innerHTML=a.title,c.appendChild(d=document.createElement("span")),d.innerHTML=a.filename,d.className="nav-results-filename",g.appendChild(b)}),f.appendChild(g);var h=g.children,i=function(a){d(h,function(a){a.hidden=!0});var b=this.value.toLowerCase(),e=[];b!==""&&(e=c(h,function(a){return a._title.indexOf(b)!==-1})),e.length>0?(d(e,function(a){a.hidden=!1}),g.hidden=!1):g.hidden=!0},j=f.querySelector('input[type="search"]');j.addEventListener("keyup",i),j.addEventListener("focus",i),e.addEventListener("click",function(a){if(a.target.classList&&a.target.classList.contains("search"))return;g.hidden=!0}),g.addEventListener("click",function(a){j.value=""});var k=document.createElement("ul");k.id="nav-toc",k.hidden=!0,k.className="nav-results toc-list",c(e.getElementsByTagName("*"),function(a){return b(["h1","h2","h3"],a.tagName.toLowerCase())}).map(function(a){var b=document.createElement("li"),c=document.createElement("a"),d=a.tagName.toLowerCase()[1];c.classList.add("level-"+d),b.appendChild(c),c.href="#"+a.id,c.innerHTML=a.innerHTML,k.appendChild(b)}),f.appendChild(k)}()})(),function(){"use strict";if(location.hash==="#__preview__"||location.protocol==="data:")return;var a=function(a,b){return Array.prototype.forEach.call(a,b)},b=function(a,b){var e=Array.prototype.slice.call(arguments,2);return d(a,function(a){return(c(b)?b||a:a[b]).apply(a,e)})},c=function(a){return Object.prototype.toString.call(a)==="[object Function]"},d=function(a,b){return Array.prototype.map.call(a,b)},e=function(a,b){return d(a,function(a){return a[b]})},f=function(a){var b={},c=a.split(";");for(var d=0;c.length>d;d++){var e=c[d].trim().split("=");b[e[0]]=e[1]}return b},g=function(a,c){return b(e(a,"classList"),"remove",c)},h=function(a,b){a.contentDocument.defaultView.postMessage(b,"*")},i=document.getElementsByTagName("head")[0],j=document.getElementsByTagName("body")[0],k=e(i.querySelectorAll('style[type="text/preview"]'),"innerHTML").join(""),l=e(i.querySelectorAll('script[type="text/preview"]'),"innerHTML").join(""),m=location.href.split("#")[0]+"#__preview__",n=document.createElement("iframe");n.src="data:text/html,",j.appendChild(n),n.addEventListener("load",function(){var b={sameOriginDataUri:!0};try{this.contentDocument,this.contentDocument||(b.sameOriginDataUri=!1)}catch(c){b.sameOriginDataUri=!1}this.parentNode.removeChild(this),a(j.getElementsByTagName("textarea"),function(a,c){o(a,b,c),q(),p(a)})});var o=function(a,b,c){var d,e,f;d=document.createElement("div"),d.appendChild(e=document.createElement("div")),d.className="preview",e.appendChild(f=document.createElement("iframe")),e.className="resizeable",f.setAttribute("scrolling","no"),f.name="iframe"+c++,f.addEventListener("load",function(){var c,d,e,f,g,i,j;j=this.contentDocument;if(!b.sameOriginDataUri&&this.src!==m)return;this.src===m&&(c=j.createElement("html"),c.appendChild(j.createElement("head")),c.appendChild(d=j.createElement("body")),d.innerHTML=a.textContent,j.replaceChild(c,j.documentElement)),g=j.createElement("head"),g.appendChild(f=j.createElement("style")),g.appendChild(e=j.createElement("script")),e.textContent=l,f.textContent=k,i=j.getElementsByTagName("head")[0],i.parentNode.replaceChild(g,i),h(this,"getHeight")});var g;b.sameOriginDataUri?g="data:text/html;charset=utf-8,"+encodeURIComponent("<!doctype html><html><head></head></body>"+a.textContent):g=m,f.setAttribute("src",g);var i=function(){f.contentDocument.body.innerHTML=this.value,h(f,"getHeight")};a.addEventListener("keypress",i),a.addEventListener("keyup",i),a.parentNode.insertBefore(d,a)},p=function(a){var b=document.createElement("div");b.className="preview-code",b.style.position="absolute",b.style.left="-9999px",j.appendChild(b);var c=parseInt(window.getComputedStyle(a).getPropertyValue("max-height"),10),d=function(a){b.textContent=this.value+"\n";var d=b.offsetHeight+2;d>=c?this.style.overflow="auto":this.style.overflow="hidden",this.style.height=b.offsetHeight+2+"px"};a.addEventListener("keypress",d),a.addEventListener("keyup",d),d.call(a)},q=function(){var b=j.getElementsByClassName("settings")[0],c=j.getElementsByClassName("resizeable"),d=30,e=function(b){document.cookie="preview-width="+b,a(c,function(a){b==="auto"&&(b=a.parentNode.offsetWidth),a.style.width=b+"px",h(a.getElementsByTagName("iframe")[0],"getHeight")})},i=f(document.cookie)["preview-width"];if(i){e(i),g(b.getElementsByClassName("is-active"),"is-active");var k=b.querySelector('button[data-width="'+i+'"]');k&&k.classList.add("is-active")}window.addEventListener("message",function(a){if(a.data==null||!a.source)return;var b=a.data,c=document.getElementsByName(a.source.name)[0];b.height!=null&&c&&(c.parentNode.style.height=b.height+d+"px")},!1),b&&c.length>0&&(b.hidden=!1,b.addEventListener("click",function(a){var c=a.target.tagName.toLowerCase(),d;if(c==="button")d=a.target;else{if(c!=="svg")return;d=a.target.parentNode}a.preventDefault(),g(b.getElementsByClassName("is-active"),"is-active"),d.classList.add("is-active");var f=d.dataset.width;e(f)}))}}()})()</script></body></html><!-- Generated with StyleDocco (http://jacobrask.github.com/styledocco). --> +</div></article></section><div class="bar bottom"><div hidden class="settings container"><!-- Icons from http://iconmonstr.com--><button title="Desktop (1280)" data-width='1280'><svg viewBox="0 0 412 386" height="24" width="26" class="icon"><path d="m147.6,343.9c-4.5,15.9-26.2,37.6-42.1,42.1h201c-15.3,-4-38.1,-26.8-42.1,-42.1H147.6zM387,0.5H25c-13.8,0-25,11.2-25,25V294c0,13.8 11.2,25 25,25h362c13.8,0 25,-11.2 25,-25V25.5C412,11.7 400.8,0.5 387,0.5zM369.9,238.2H42.1L42.1,42.6 369.9,42.6V238.2z"></path></svg></button><button title="Laptop (1024)" data-width='1024'><svg viewBox="0 0 384 312" height="23" width="28" class="icon"><path d="m349.2,20.5c0,-11-9,-20-20,-20H53.6c-11,0-20,9-20,20v194H349.2v-194zm-27,167H60.6V27.5H322.2v160zm28,42H32.6L2.6,282.1c-3.5,6.2-3.5,13.8 0.1,19.9 3.6,6.2 10.2,9.9 17.3,9.9H363.1c7.1,0 13.7,-3.8 17.3,-10 3.6,-6.2 3.6,-13.8 0,-20l-30.2,-52.5zm-196.9,54 8,-23.5h60.5l8,23.5h-76.5z"></path></svg></button><button title="Tablet (768)" data-width='768'><svg viewBox="0 0 317 412" height="24" width="18" class="icon"><path d="M 316.5,380 V 32 c 0,-17.7 -14.3,-32 -32,-32 H 32 C 14.3,0 0,14.3 0,32 v 348 c 0,17.7 14.3,32 32,32 h 252.5 c 17.7,0 32,-14.3 32,-32 z M 40,367 V 45 H 276.5 V 367 H 40 z m 109.8,22.7 c 0,-4.7 3.8,-8.5 8.5,-8.5 4.7,0 8.5,3.8 8.5,8.5 0,4.7 -3.8,8.5 -8.5,8.5 -4.7,0 -8.5,-3.8 -8.5,-8.5 z"></path></svg></button><button title="Smart phone (320)" data-width='320'><svg viewBox="0 0 224 412" height="24" width="13" class="icon"><path d="M 190.7,0 H 33 C 14.8,0 0,14.8 0,33 v 346 c 0,18.2 14.8,33 33,33 h 157.7 c 18.2,0 33,-14.8 33,-33 V 33 c 0,-18.2 -14.8,-33 -33,-33 z M 94.3,30.2 h 37 c 2.2,0 4,1.8 4,4 0,2.2 -1.8,4 -4,4 h -37 c -2.2,0 -4,-1.8 -4,-4 0,-2.2 1.8,-4 4,-4 z m 18.5,362.8 c -8.8,0 -16,-7.2 -16,-16 0,-8.8 7.2,-16 16,-16 8.8,0 16,7.2 16,16 0,8.8 -7.2,16 -16,16 z M 198.6,343.8 H 25.1 V 68.2 h 173.5 v 275.5 z"></path></svg></button><button title="Feature phone (240)" data-width='240'><svg viewBox="0 0 201 412" height="24" width="12" class="icon"><path d="M 165.5,0.2 V 45 H 25 c -13.8,0 -25,11.2 -25,25 V 387 c 0,13.8 11.2,25 25,25 h 150.5 c 13.8,0 25,-11.2 25,-25 V 0.2 h -35 z M 65.2,366.5 H 34.2 v -24.5 h 31 v 24.5 z m 0,-44.3 H 34.2 v -24.5 h 31 v 24.5 z m 50.5,44.3 H 84.7 v -24.5 h 31 v 24.5 z m 0,-44.3 H 84.7 v -24.5 h 31 v 24.5 z m 50.5,44.3 h -31 v -24.5 h 31 v 24.5 z m 0,-44.3 h -31 v -24.5 h 31 v 24.5 z m 0,-59.3 h -132 V 95.4 h 132 V 262.9 z"></path></svg></button><button title="Auto (100%)" data-width="auto" class="auto is-active">Auto</button></div></div><script>(function(){var a=[{title:"actions-toolbar",filename:"actions-toolbar",url:"actions-toolbar.html"},{title:"Actions toolbar",filename:"actions-toolbar",url:"actions-toolbar.html#actions-toolbar"},{title:"Actions toolbar mixin variables",filename:"actions-toolbar",url:"actions-toolbar.html#actions-toolbar-mixin-variables"},{title:"Actions toolbar alignment",filename:"actions-toolbar",url:"actions-toolbar.html#actions-toolbar-alignment"},{title:"Reverse primary and secondary blocks",filename:"actions-toolbar",url:"actions-toolbar.html#reverse-primary-and-secondary-blocks"},{title:"Actions toolbar indents customizations",filename:"actions-toolbar",url:"actions-toolbar.html#actions-toolbar-indents-customizations"},{title:"Responsive actions toolbar",filename:"actions-toolbar",url:"actions-toolbar.html#responsive-actions-toolbar"},{title:"breadcrumbs",filename:"breadcrumbs",url:"breadcrumbs.html"},{title:"Breadcrumbs",filename:"breadcrumbs",url:"breadcrumbs.html#breadcrumbs"},{title:"Breadcrumbs variables",filename:"breadcrumbs",url:"breadcrumbs.html#breadcrumbs-variables"},{title:"Button-styled breadcrumbs with gradient background, border, and no separating symbol",filename:"breadcrumbs",url:"breadcrumbs.html#buttonstyled-breadcrumbs-with-gradient-background-border-and-no-separating-symbol"},{title:"Breadcrumbs with solid background",filename:"breadcrumbs",url:"breadcrumbs.html#breadcrumbs-with-solid-background"},{title:"buttons",filename:"buttons",url:"buttons.html"},{title:"Default button",filename:"buttons",url:"buttons.html#default-button"},{title:"Button variables",filename:"buttons",url:"buttons.html#button-variables"},{title:"Button as an icon",filename:"buttons",url:"buttons.html#button-as-an-icon"},{title:"Button with an icon on the left or right side of the text",filename:"buttons",url:"buttons.html#button-with-an-icon-on-the-left-or-right-side-of-the-text"},{title:"Button with fixed width",filename:"buttons",url:"buttons.html#button-with-fixed-width"},{title:"Primary button",filename:"buttons",url:"buttons.html#primary-button"},{title:"Primary button variables",filename:"buttons",url:"buttons.html#primary-button-variables"},{title:"Button with gradient background",filename:"buttons",url:"buttons.html#button-with-gradient-background"},{title:"Button as a link",filename:"buttons",url:"buttons.html#button-as-a-link"},{title:"Button as a link variables",filename:"buttons",url:"buttons.html#button-as-a-link-variables"},{title:"Link as a button",filename:"buttons",url:"buttons.html#link-as-a-button"},{title:"Button reset",filename:"buttons",url:"buttons.html#button-reset"},{title:"Button revert secondary color",filename:"buttons",url:"buttons.html#button-revert-secondary-color"},{title:"Button revert secondary color variables",filename:"buttons",url:"buttons.html#button-revert-secondary-color-variables"},{title:"Button revert secondary size",filename:"buttons",url:"buttons.html#button-revert-secondary-size"},{title:"Button revert secondary size variables",filename:"buttons",url:"buttons.html#button-revert-secondary-size-variables"},{title:"components",filename:"components",url:"components.html"},{title:"Components",filename:"components",url:"components.html#components"},{title:"Components Variables",filename:"components",url:"components.html#components-variables"},{title:"dropdowns",filename:"dropdowns",url:"dropdowns.html"},{title:"Drop-down and split buttons mixins",filename:"dropdowns",url:"dropdowns.html#dropdown-and-split-buttons-mixins"},{title:"Drop-down",filename:"dropdowns",url:"dropdowns.html#dropdown"},{title:"Drop-down variables",filename:"dropdowns",url:"dropdowns.html#dropdown-variables"},{title:"Drop-down with icon customization",filename:"dropdowns",url:"dropdowns.html#dropdown-with-icon-customization"},{title:"Modify dropdown list styles",filename:"dropdowns",url:"dropdowns.html#modify-dropdown-list-styles"},{title:"Split button",filename:"dropdowns",url:"dropdowns.html#split-button"},{title:"Split button variables",filename:"dropdowns",url:"dropdowns.html#split-button-variables"},{title:"Split button - button styling",filename:"dropdowns",url:"dropdowns.html#split-button-button-styling"},{title:"Split button icon customization",filename:"dropdowns",url:"dropdowns.html#split-button-icon-customization"},{title:"Split button drop-down list customization",filename:"dropdowns",url:"dropdowns.html#split-button-dropdown-list-customization"},{title:"forms",filename:"forms",url:"forms.html"},{title:"Forms mixins",filename:"forms",url:"forms.html#forms-mixins"},{title:"Global forms elements customization",filename:"forms",url:"forms.html#global-forms-elements-customization"},{title:"Fieldsets & fields customization",filename:"forms",url:"forms.html#fieldsets-fields-customization"},{title:"Fieldset and legend customization variables",filename:"forms",url:"forms.html#fieldset-and-legend-customization-variables"},{title:"Fields customization variables",filename:"forms",url:"forms.html#fields-customization-variables"},{title:"Required fields message customization variables",filename:"forms",url:"forms.html#required-fields-message-customization-variables"},{title:"Form element inputs customization",filename:"forms",url:"forms.html#form-element-inputs-customization"},{title:"Form element inputs customization variables",filename:"forms",url:"forms.html#form-element-inputs-customization-variables"},{title:"Form element choice",filename:"forms",url:"forms.html#form-element-choice"},{title:"Form element choice variables",filename:"forms",url:"forms.html#form-element-choice-variables"},{title:"Custom color",filename:"forms",url:"forms.html#custom-color"},{title:"Input number - input-text view",filename:"forms",url:"forms.html#input-number-inputtext-view"},{title:"Input search - input-text view",filename:"forms",url:"forms.html#input-search-inputtext-view"},{title:"Form validation",filename:"forms",url:"forms.html#form-validation"},{title:"Form validation variables",filename:"forms",url:"forms.html#form-validation-variables"},{title:"icons",filename:"icons",url:"icons.html"},{title:"Icons",filename:"icons",url:"icons.html#icons"},{title:"Icon with image or sprite",filename:"icons",url:"icons.html#icon-with-image-or-sprite"},{title:"Icon with image or sprite variables",filename:"icons",url:"icons.html#icon-with-image-or-sprite-variables"},{title:"Icon position for an icon with image or sprite",filename:"icons",url:"icons.html#icon-position-for-an-icon-with-image-or-sprite"},{title:"Position for icon with image or sprite mixin variables",filename:"icons",url:"icons.html#position-for-icon-with-image-or-sprite-mixin-variables"},{title:"Icon sprite position (with grid)",filename:"icons",url:"icons.html#icon-sprite-position-with-grid"},{title:"Icon sprite position variables",filename:"icons",url:"icons.html#icon-sprite-position-variables"},{title:"Image/sprite icon size",filename:"icons",url:"icons.html#imagesprite-icon-size"},{title:"Image/sprite icon size variables",filename:"icons",url:"icons.html#imagesprite-icon-size-variables"},{title:"Font icon",filename:"icons",url:"icons.html#font-icon"},{title:"Font icon variables",filename:"icons",url:"icons.html#font-icon-variables"},{title:"Change the size of font icon",filename:"icons",url:"icons.html#change-the-size-of-font-icon"},{title:"Change the size of font icon variables",filename:"icons",url:"icons.html#change-the-size-of-font-icon-variables"},{title:"Hide icon text",filename:"icons",url:"icons.html#hide-icon-text"},{title:"Sprite and font icons for Blank theme",filename:"icons",url:"icons.html#sprite-and-font-icons-for-blank-theme"},{title:"layout",filename:"layout",url:"layout.html"},{title:"Layout",filename:"layout",url:"layout.html#layout"},{title:"Layout global variables",filename:"layout",url:"layout.html#layout-global-variables"},{title:"Page layouts",filename:"layout",url:"layout.html#page-layouts"},{title:"Layout column",filename:"layout",url:"layout.html#layout-column"},{title:"Layout column variables",filename:"layout",url:"layout.html#layout-column-variables"},{title:"Layout width",filename:"layout",url:"layout.html#layout-width"},{title:"Layout width variables",filename:"layout",url:"layout.html#layout-width-variables"},{title:"lib",filename:"lib",url:"lib.html"},{title:"Including Magento UI library to your theme",filename:"lib",url:"lib.html#including-magento-ui-library-to-your-theme"},{title:"loaders",filename:"loaders",url:"loaders.html"},{title:"Loaders",filename:"loaders",url:"loaders.html#loaders"},{title:"Default loader variables",filename:"loaders",url:"loaders.html#default-loader-variables"},{title:"Loading",filename:"loaders",url:"loaders.html#loading"},{title:"Loading default variables",filename:"loaders",url:"loaders.html#loading-default-variables"},{title:"messages",filename:"messages",url:"messages.html"},{title:"Messages",filename:"messages",url:"messages.html#messages"},{title:"Information message",filename:"messages",url:"messages.html#information-message"},{title:"Warning message",filename:"messages",url:"messages.html#warning-message"},{title:"Error message",filename:"messages",url:"messages.html#error-message"},{title:"Success message",filename:"messages",url:"messages.html#success-message"},{title:"Notice message",filename:"messages",url:"messages.html#notice-message"},{title:"Message with inner icon",filename:"messages",url:"messages.html#message-with-inner-icon"},{title:"Message with lateral icon",filename:"messages",url:"messages.html#message-with-lateral-icon"},{title:"Custom message style",filename:"messages",url:"messages.html#custom-message-style"},{title:"Messages global variables",filename:"messages",url:"messages.html#messages-global-variables"},{title:"pages",filename:"pages",url:"pages.html"},{title:"Pagination HTML markup",filename:"pages",url:"pages.html#pagination-html-markup"},{title:"Pagination variables",filename:"pages",url:"pages.html#pagination-variables"},{title:"Pagination with label and gradient background on links",filename:"pages",url:"pages.html#pagination-with-label-and-gradient-background-on-links"},{title:'Pagination with "previous"..."next" text links and label',filename:"pages",url:"pages.html#pagination-with-previousnext-text-links-and-label"},{title:"Pagination without label, with solid background",filename:"pages",url:"pages.html#pagination-without-label-with-solid-background"},{title:"popups",filename:"popups",url:"popups.html"},{title:"Popups",filename:"popups",url:"popups.html#popups"},{title:"Popup variables",filename:"popups",url:"popups.html#popup-variables"},{title:"Window overlay mixin variables",filename:"popups",url:"popups.html#window-overlay-mixin-variables"},{title:"Fixed height popup",filename:"popups",url:"popups.html#fixed-height-popup"},{title:"Fixed content height popup",filename:"popups",url:"popups.html#fixed-content-height-popup"},{title:"Margins for header, content and footer block in popup",filename:"popups",url:"popups.html#margins-for-header-content-and-footer-block-in-popup"},{title:"Popup titles styled as theme headings",filename:"popups",url:"popups.html#popup-titles-styled-as-theme-headings"},{title:"Popup action toolbar",filename:"popups",url:"popups.html#popup-action-toolbar"},{title:"Popup Close button without an icon",filename:"popups",url:"popups.html#popup-close-button-without-an-icon"},{title:"Modify the icon of popup Close button",filename:"popups",url:"popups.html#modify-the-icon-of-popup-close-button"},{title:"Modify overlay styles",filename:"popups",url:"popups.html#modify-overlay-styles"},{title:"rating",filename:"rating",url:"rating.html"},{title:"Ratings",filename:"rating",url:"rating.html#ratings"},{title:"Global rating variables",filename:"rating",url:"rating.html#global-rating-variables"},{title:"Rating with vote",filename:"rating",url:"rating.html#rating-with-vote"},{title:"Rating with vote icons number customization",filename:"rating",url:"rating.html#rating-with-vote-icons-number-customization"},{title:"Rating with vote icons colors customization",filename:"rating",url:"rating.html#rating-with-vote-icons-colors-customization"},{title:"Rating with vote icons symbol customization",filename:"rating",url:"rating.html#rating-with-vote-icons-symbol-customization"},{title:"Accessible rating with vote",filename:"rating",url:"rating.html#accessible-rating-with-vote"},{title:"Rating summary",filename:"rating",url:"rating.html#rating-summary"},{title:"Rating summary icons number customization",filename:"rating",url:"rating.html#rating-summary-icons-number-customization"},{title:"Rating summary icons color customization",filename:"rating",url:"rating.html#rating-summary-icons-color-customization"},{title:"Rating summary icons symbol customization",filename:"rating",url:"rating.html#rating-summary-icons-symbol-customization"},{title:"Rating summary hide label",filename:"rating",url:"rating.html#rating-summary-hide-label"},{title:"Rating summary multiple ratings",filename:"rating",url:"rating.html#rating-summary-multiple-ratings"},{title:"Rating hide label mixin",filename:"rating",url:"rating.html#rating-hide-label-mixin"},{title:"resets",filename:"resets",url:"resets.html"},{title:"Resets",filename:"resets",url:"resets.html#resets"},{title:"responsive",filename:"responsive",url:"responsive.html"},{title:"Responsive",filename:"responsive",url:"responsive.html#responsive"},{title:"Responsive mixins usage",filename:"responsive",url:"responsive.html#responsive-mixins-usage"},{title:"Media query style groups separation variables",filename:"responsive",url:"responsive.html#media-query-style-groups-separation-variables"},{title:"Responsive breakpoints",filename:"responsive",url:"responsive.html#responsive-breakpoints"},{title:"sections",filename:"sections",url:"sections.html"},{title:"Tabs and accordions",filename:"sections",url:"sections.html#tabs-and-accordions"},{title:"Tabs",filename:"sections",url:"sections.html#tabs"},{title:"Tabs mixin variables",filename:"sections",url:"sections.html#tabs-mixin-variables"},{title:"Tabs with content top border",filename:"sections",url:"sections.html#tabs-with-content-top-border"},{title:"Accordion",filename:"sections",url:"sections.html#accordion"},{title:"Accordion mixin variables",filename:"sections",url:"sections.html#accordion-mixin-variables"},{title:"Responsive tabs",filename:"sections",url:"sections.html#responsive-tabs"},{title:"Tabs Base",filename:"sections",url:"sections.html#tabs-base"},{title:"Accordion Base",filename:"sections",url:"sections.html#accordion-base"},{title:"tables",filename:"tables",url:"tables.html"},{title:"Tables",filename:"tables",url:"tables.html#tables"},{title:"Table mixin variables",filename:"tables",url:"tables.html#table-mixin-variables"},{title:"Table typography",filename:"tables",url:"tables.html#table-typography"},{title:"Table typography mixin variables",filename:"tables",url:"tables.html#table-typography-mixin-variables"},{title:"Table caption",filename:"tables",url:"tables.html#table-caption"},{title:"Table caption mixin variables",filename:"tables",url:"tables.html#table-caption-mixin-variables"},{title:"Table cells resize",filename:"tables",url:"tables.html#table-cells-resize"},{title:"Table cells resize variables",filename:"tables",url:"tables.html#table-cells-resize-variables"},{title:"Table background customization",filename:"tables",url:"tables.html#table-background-customization"},{title:"Table background mixin variables",filename:"tables",url:"tables.html#table-background-mixin-variables"},{title:"Table borders customization",filename:"tables",url:"tables.html#table-borders-customization"},{title:"Table borders mixin variables",filename:"tables",url:"tables.html#table-borders-mixin-variables"},{title:"Table with horizontal borders",filename:"tables",url:"tables.html#table-with-horizontal-borders"},{title:"Table with vertical borders",filename:"tables",url:"tables.html#table-with-vertical-borders"},{title:"Table with light borders",filename:"tables",url:"tables.html#table-with-light-borders"},{title:"Table without borders",filename:"tables",url:"tables.html#table-without-borders"},{title:"Striped table",filename:"tables",url:"tables.html#striped-table"},{title:"Striped table mixin variables",filename:"tables",url:"tables.html#striped-table-mixin-variables"},{title:"Table with rows hover",filename:"tables",url:"tables.html#table-with-rows-hover"},{title:"Table with rows hover mixin variables",filename:"tables",url:"tables.html#table-with-rows-hover-mixin-variables"},{title:"Responsive table technics #1",filename:"tables",url:"tables.html#responsive-table-technics-1"},{title:"Responsive table technics #2",filename:"tables",url:"tables.html#responsive-table-technics-2"},{title:"Responsive table technics #2 mixin variables",filename:"tables",url:"tables.html#responsive-table-technics-2-mixin-variables"},{title:"tooltips",filename:"tooltips",url:"tooltips.html"},{title:"Tooltips",filename:"tooltips",url:"tooltips.html#tooltips"},{title:"Tooltips variables",filename:"tooltips",url:"tooltips.html#tooltips-variables"},{title:"typography",filename:"typography",url:"typography.html"},{title:"Typogrphy",filename:"typography",url:"typography.html#typogrphy"},{title:"Typography variables",filename:"typography",url:"typography.html#typography-variables"},{title:"Font-size mixin",filename:"typography",url:"typography.html#fontsize-mixin"},{title:"Line-height mixin",filename:"typography",url:"typography.html#lineheight-mixin"},{title:"Word breaking mixin",filename:"typography",url:"typography.html#word-breaking-mixin"},{title:"Font face mixin",filename:"typography",url:"typography.html#font-face-mixin"},{title:"Text overflow mixin",filename:"typography",url:"typography.html#text-overflow-mixin"},{title:"Text hide",filename:"typography",url:"typography.html#text-hide"},{title:"Hyphens",filename:"typography",url:"typography.html#hyphens"},{title:"Font style and color",filename:"typography",url:"typography.html#font-style-and-color"},{title:"Font style mixin variables",filename:"typography",url:"typography.html#font-style-mixin-variables"},{title:"Reset list styles",filename:"typography",url:"typography.html#reset-list-styles"},{title:"Reset list styles variables",filename:"typography",url:"typography.html#reset-list-styles-variables"},{title:"Inline-block list item styling",filename:"typography",url:"typography.html#inlineblock-list-item-styling"},{title:"Link styling mixin",filename:"typography",url:"typography.html#link-styling-mixin"},{title:"Link styling mixin variables",filename:"typography",url:"typography.html#link-styling-mixin-variables"},{title:"Heading styling mixin",filename:"typography",url:"typography.html#heading-styling-mixin"},{title:"Base typography mixins",filename:"typography",url:"typography.html#base-typography-mixins"},{title:"Base typography mixin variables",filename:"typography",url:"typography.html#base-typography-mixin-variables"},{title:"Headings typography mixin",filename:"typography",url:"typography.html#headings-typography-mixin"},{title:"Headings typography mixin variables",filename:"typography",url:"typography.html#headings-typography-mixin-variables"},{title:"Typography links mixin",filename:"typography",url:"typography.html#typography-links-mixin"},{title:"Typography lists mixin",filename:"typography",url:"typography.html#typography-lists-mixin"},{title:"Typography lists mixin variables",filename:"typography",url:"typography.html#typography-lists-mixin-variables"},{title:"Typography code elements mixin",filename:"typography",url:"typography.html#typography-code-elements-mixin"},{title:"Typography code mixin variables",filename:"typography",url:"typography.html#typography-code-mixin-variables"},{title:"Typography blockquote",filename:"typography",url:"typography.html#typography-blockquote"},{title:"Typography blockquote mixin variables",filename:"typography",url:"typography.html#typography-blockquote-mixin-variables"},{title:"utilities",filename:"utilities",url:"utilities.html"},{title:"Utilities",filename:"utilities",url:"utilities.html#utilities"},{title:".lib-clearfix()",filename:"utilities",url:"utilities.html#libclearfix"},{title:".lib-visibility-hidden()",filename:"utilities",url:"utilities.html#libvisibilityhidden"},{title:".lib-visually-hidden()",filename:"utilities",url:"utilities.html#libvisuallyhidden"},{title:".lib-visually-hidden-reset()",filename:"utilities",url:"utilities.html#libvisuallyhiddenreset"},{title:".lib-css()",filename:"utilities",url:"utilities.html#libcss"},{title:".lib-css() variables",filename:"utilities",url:"utilities.html#libcss-variables"},{title:".lib-rotate()",filename:"utilities",url:"utilities.html#librotate"},{title:".lib-rotate() variables",filename:"utilities",url:"utilities.html#librotate-variables"},{title:".lib-input-placeholder()",filename:"utilities",url:"utilities.html#libinputplaceholder"},{title:".lib-input-placeholder() variables",filename:"utilities",url:"utilities.html#libinputplaceholder-variables"},{title:".lib-background-gradient()",filename:"utilities",url:"utilities.html#libbackgroundgradient"},{title:".lib-background-gradient() variables",filename:"utilities",url:"utilities.html#libbackgroundgradient-variables"},{title:"variables",filename:"variables",url:"variables.html"},{title:"List of Global Variables",filename:"variables",url:"variables.html#list-of-global-variables"},{title:"Table with rows hover mixin variables",filename:"variables",url:"variables.html#table-with-rows-hover-mixin-variables"},{title:"docs",filename:"docs",url:"docs.html"},{title:"Documentation",filename:"docs",url:"docs.html#documentation"}];(function(){"use strict";var b=function(a,b){return Array.prototype.indexOf.call(a,b)!==-1},c=function(a,b){return Array.prototype.filter.call(a,b)},d=function(a,b){return Array.prototype.forEach.call(a,b)},e=document.getElementsByTagName("body")[0];e.addEventListener("click",function(a){var b=a.target;b.tagName.toLowerCase()==="svg"&&(b=b.parentNode);var c=!1;b.dataset.toggle!=null&&(a.preventDefault(),b.classList.contains("is-active")||(c=!0)),d(e.querySelectorAll("[data-toggle]"),function(a){a.classList.remove("is-active"),document.getElementById(a.dataset.toggle).hidden=!0}),c&&(b.classList.add("is-active"),document.getElementById(b.dataset.toggle).hidden=!1)}),function(){var f=e.getElementsByClassName("nav")[0];if(!f)return;var g=document.createElement("ul");g.className="nav-results",g.id="nav-search",g.hidden=!0,d(a,function(a){var b,c,d;b=document.createElement("li"),b._title=a.title.toLowerCase(),b.hidden=!0,b.appendChild(c=document.createElement("a")),c.href=a.url,c.innerHTML=a.title,c.appendChild(d=document.createElement("span")),d.innerHTML=a.filename,d.className="nav-results-filename",g.appendChild(b)}),f.appendChild(g);var h=g.children,i=function(a){d(h,function(a){a.hidden=!0});var b=this.value.toLowerCase(),e=[];b!==""&&(e=c(h,function(a){return a._title.indexOf(b)!==-1})),e.length>0?(d(e,function(a){a.hidden=!1}),g.hidden=!1):g.hidden=!0},j=f.querySelector('input[type="search"]');j.addEventListener("keyup",i),j.addEventListener("focus",i),e.addEventListener("click",function(a){if(a.target.classList&&a.target.classList.contains("search"))return;g.hidden=!0}),g.addEventListener("click",function(a){j.value=""});var k=document.createElement("ul");k.id="nav-toc",k.hidden=!0,k.className="nav-results toc-list",c(e.getElementsByTagName("*"),function(a){return b(["h1","h2","h3"],a.tagName.toLowerCase())}).map(function(a){var b=document.createElement("li"),c=document.createElement("a"),d=a.tagName.toLowerCase()[1];c.classList.add("level-"+d),b.appendChild(c),c.href="#"+a.id,c.innerHTML=a.innerHTML,k.appendChild(b)}),f.appendChild(k)}()})(),function(){"use strict";if(location.hash==="#__preview__"||location.protocol==="data:")return;var a=function(a,b){return Array.prototype.forEach.call(a,b)},b=function(a,b){var e=Array.prototype.slice.call(arguments,2);return d(a,function(a){return(c(b)?b||a:a[b]).apply(a,e)})},c=function(a){return Object.prototype.toString.call(a)==="[object Function]"},d=function(a,b){return Array.prototype.map.call(a,b)},e=function(a,b){return d(a,function(a){return a[b]})},f=function(a){var b={},c=a.split(";");for(var d=0;c.length>d;d++){var e=c[d].trim().split("=");b[e[0]]=e[1]}return b},g=function(a,c){return b(e(a,"classList"),"remove",c)},h=function(a,b){a.contentDocument.defaultView.postMessage(b,"*")},i=document.getElementsByTagName("head")[0],j=document.getElementsByTagName("body")[0],k=e(i.querySelectorAll('style[type="text/preview"]'),"innerHTML").join(""),l=e(i.querySelectorAll('script[type="text/preview"]'),"innerHTML").join(""),m=location.href.split("#")[0]+"#__preview__",n=document.createElement("iframe");n.src="data:text/html,",j.appendChild(n),n.addEventListener("load",function(){var b={sameOriginDataUri:!0};try{this.contentDocument,this.contentDocument||(b.sameOriginDataUri=!1)}catch(c){b.sameOriginDataUri=!1}this.parentNode.removeChild(this),a(j.getElementsByTagName("textarea"),function(a,c){o(a,b,c),q(),p(a)})});var o=function(a,b,c){var d,e,f;d=document.createElement("div"),d.appendChild(e=document.createElement("div")),d.className="preview",e.appendChild(f=document.createElement("iframe")),e.className="resizeable",f.setAttribute("scrolling","no"),f.name="iframe"+c++,f.addEventListener("load",function(){var c,d,e,f,g,i,j;j=this.contentDocument;if(!b.sameOriginDataUri&&this.src!==m)return;this.src===m&&(c=j.createElement("html"),c.appendChild(j.createElement("head")),c.appendChild(d=j.createElement("body")),d.innerHTML=a.textContent,j.replaceChild(c,j.documentElement)),g=j.createElement("head"),g.appendChild(f=j.createElement("style")),g.appendChild(e=j.createElement("script")),e.textContent=l,f.textContent=k,i=j.getElementsByTagName("head")[0],i.parentNode.replaceChild(g,i),h(this,"getHeight")});var g;b.sameOriginDataUri?g="data:text/html;charset=utf-8,"+encodeURIComponent("<!doctype html><html><head></head></body>"+a.textContent):g=m,f.setAttribute("src",g);var i=function(){f.contentDocument.body.innerHTML=this.value,h(f,"getHeight")};a.addEventListener("keypress",i),a.addEventListener("keyup",i),a.parentNode.insertBefore(d,a)},p=function(a){var b=document.createElement("div");b.className="preview-code",b.style.position="absolute",b.style.left="-9999px",j.appendChild(b);var c=parseInt(window.getComputedStyle(a).getPropertyValue("max-height"),10),d=function(a){b.textContent=this.value+"\n";var d=b.offsetHeight+2;d>=c?this.style.overflow="auto":this.style.overflow="hidden",this.style.height=b.offsetHeight+2+"px"};a.addEventListener("keypress",d),a.addEventListener("keyup",d),d.call(a)},q=function(){var b=j.getElementsByClassName("settings")[0],c=j.getElementsByClassName("resizeable"),d=30,e=function(b){document.cookie="preview-width="+b,a(c,function(a){b==="auto"&&(b=a.parentNode.offsetWidth),a.style.width=b+"px",h(a.getElementsByTagName("iframe")[0],"getHeight")})},i=f(document.cookie)["preview-width"];if(i){e(i),g(b.getElementsByClassName("is-active"),"is-active");var k=b.querySelector('button[data-width="'+i+'"]');k&&k.classList.add("is-active")}window.addEventListener("message",function(a){if(a.data==null||!a.source)return;var b=a.data,c=document.getElementsByName(a.source.name)[0];b.height!=null&&c&&(c.parentNode.style.height=b.height+d+"px")},!1),b&&c.length>0&&(b.hidden=!1,b.addEventListener("click",function(a){var c=a.target.tagName.toLowerCase(),d;if(c==="button")d=a.target;else{if(c!=="svg")return;d=a.target.parentNode}a.preventDefault(),g(b.getElementsByClassName("is-active"),"is-active"),d.classList.add("is-active");var f=d.dataset.width;e(f)}))}}()})()</script></body></html><!-- Generated with StyleDocco (http://jacobrask.github.com/styledocco). --> diff --git a/lib/web/css/docs/layout.html b/lib/web/css/docs/layout.html index a75e366f621ad..77ed0597f0748 100644 --- a/lib/web/css/docs/layout.html +++ b/lib/web/css/docs/layout.html @@ -340,4 +340,4 @@ <h2 id="three-columns-page-layout">Three columns page layout</h2> </tr> </table> </pre> -</div></article></section><div class="bar bottom"><div hidden class="settings container"><!-- Icons from http://iconmonstr.com--><button title="Desktop (1280)" data-width='1280'><svg viewBox="0 0 412 386" height="24" width="26" class="icon"><path d="m147.6,343.9c-4.5,15.9-26.2,37.6-42.1,42.1h201c-15.3,-4-38.1,-26.8-42.1,-42.1H147.6zM387,0.5H25c-13.8,0-25,11.2-25,25V294c0,13.8 11.2,25 25,25h362c13.8,0 25,-11.2 25,-25V25.5C412,11.7 400.8,0.5 387,0.5zM369.9,238.2H42.1L42.1,42.6 369.9,42.6V238.2z"></path></svg></button><button title="Laptop (1024)" data-width='1024'><svg viewBox="0 0 384 312" height="23" width="28" class="icon"><path d="m349.2,20.5c0,-11-9,-20-20,-20H53.6c-11,0-20,9-20,20v194H349.2v-194zm-27,167H60.6V27.5H322.2v160zm28,42H32.6L2.6,282.1c-3.5,6.2-3.5,13.8 0.1,19.9 3.6,6.2 10.2,9.9 17.3,9.9H363.1c7.1,0 13.7,-3.8 17.3,-10 3.6,-6.2 3.6,-13.8 0,-20l-30.2,-52.5zm-196.9,54 8,-23.5h60.5l8,23.5h-76.5z"></path></svg></button><button title="Tablet (768)" data-width='768'><svg viewBox="0 0 317 412" height="24" width="18" class="icon"><path d="M 316.5,380 V 32 c 0,-17.7 -14.3,-32 -32,-32 H 32 C 14.3,0 0,14.3 0,32 v 348 c 0,17.7 14.3,32 32,32 h 252.5 c 17.7,0 32,-14.3 32,-32 z M 40,367 V 45 H 276.5 V 367 H 40 z m 109.8,22.7 c 0,-4.7 3.8,-8.5 8.5,-8.5 4.7,0 8.5,3.8 8.5,8.5 0,4.7 -3.8,8.5 -8.5,8.5 -4.7,0 -8.5,-3.8 -8.5,-8.5 z"></path></svg></button><button title="Smart phone (320)" data-width='320'><svg viewBox="0 0 224 412" height="24" width="13" class="icon"><path d="M 190.7,0 H 33 C 14.8,0 0,14.8 0,33 v 346 c 0,18.2 14.8,33 33,33 h 157.7 c 18.2,0 33,-14.8 33,-33 V 33 c 0,-18.2 -14.8,-33 -33,-33 z M 94.3,30.2 h 37 c 2.2,0 4,1.8 4,4 0,2.2 -1.8,4 -4,4 h -37 c -2.2,0 -4,-1.8 -4,-4 0,-2.2 1.8,-4 4,-4 z m 18.5,362.8 c -8.8,0 -16,-7.2 -16,-16 0,-8.8 7.2,-16 16,-16 8.8,0 16,7.2 16,16 0,8.8 -7.2,16 -16,16 z M 198.6,343.8 H 25.1 V 68.2 h 173.5 v 275.5 z"></path></svg></button><button title="Feature phone (240)" data-width='240'><svg viewBox="0 0 201 412" height="24" width="12" class="icon"><path d="M 165.5,0.2 V 45 H 25 c -13.8,0 -25,11.2 -25,25 V 387 c 0,13.8 11.2,25 25,25 h 150.5 c 13.8,0 25,-11.2 25,-25 V 0.2 h -35 z M 65.2,366.5 H 34.2 v -24.5 h 31 v 24.5 z m 0,-44.3 H 34.2 v -24.5 h 31 v 24.5 z m 50.5,44.3 H 84.7 v -24.5 h 31 v 24.5 z m 0,-44.3 H 84.7 v -24.5 h 31 v 24.5 z m 50.5,44.3 h -31 v -24.5 h 31 v 24.5 z m 0,-44.3 h -31 v -24.5 h 31 v 24.5 z m 0,-59.3 h -132 V 95.4 h 132 V 262.9 z"></path></svg></button><button title="Auto (100%)" data-width="auto" class="auto is-active">Auto</button></div></div><script>(function(){var a=[{title:"actions-toolbar",filename:"actions-toolbar",url:"actions-toolbar.html"},{title:"Actions toolbar",filename:"actions-toolbar",url:"actions-toolbar.html#actions-toolbar"},{title:"Actions toolbar mixin variables",filename:"actions-toolbar",url:"actions-toolbar.html#actions-toolbar-mixin-variables"},{title:"Actions toolbar alignment",filename:"actions-toolbar",url:"actions-toolbar.html#actions-toolbar-alignment"},{title:"Reverse primary and secondary blocks",filename:"actions-toolbar",url:"actions-toolbar.html#reverse-primary-and-secondary-blocks"},{title:"Actions toolbar indents customizations",filename:"actions-toolbar",url:"actions-toolbar.html#actions-toolbar-indents-customizations"},{title:"Responsive actions toolbar",filename:"actions-toolbar",url:"actions-toolbar.html#responsive-actions-toolbar"},{title:"breadcrumbs",filename:"breadcrumbs",url:"breadcrumbs.html"},{title:"Breadcrumbs",filename:"breadcrumbs",url:"breadcrumbs.html#breadcrumbs"},{title:"Breadcrumbs variables",filename:"breadcrumbs",url:"breadcrumbs.html#breadcrumbs-variables"},{title:"Button-styled breadcrumbs with gradient background, border, and no separating symbol",filename:"breadcrumbs",url:"breadcrumbs.html#buttonstyled-breadcrumbs-with-gradient-background-border-and-no-separating-symbol"},{title:"Breadcrumbs with solid background",filename:"breadcrumbs",url:"breadcrumbs.html#breadcrumbs-with-solid-background"},{title:"buttons",filename:"buttons",url:"buttons.html"},{title:"Default button",filename:"buttons",url:"buttons.html#default-button"},{title:"Button variables",filename:"buttons",url:"buttons.html#button-variables"},{title:"Button as an icon",filename:"buttons",url:"buttons.html#button-as-an-icon"},{title:"Button with an icon on the left or right side of the text",filename:"buttons",url:"buttons.html#button-with-an-icon-on-the-left-or-right-side-of-the-text"},{title:"Button with fixed width",filename:"buttons",url:"buttons.html#button-with-fixed-width"},{title:"Primary button",filename:"buttons",url:"buttons.html#primary-button"},{title:"Primary button variables",filename:"buttons",url:"buttons.html#primary-button-variables"},{title:"Button with gradient background",filename:"buttons",url:"buttons.html#button-with-gradient-background"},{title:"Button as a link",filename:"buttons",url:"buttons.html#button-as-a-link"},{title:"Button as a link variables",filename:"buttons",url:"buttons.html#button-as-a-link-variables"},{title:"Link as a button",filename:"buttons",url:"buttons.html#link-as-a-button"},{title:"Button reset",filename:"buttons",url:"buttons.html#button-reset"},{title:"Button revert secondary color",filename:"buttons",url:"buttons.html#button-revert-secondary-color"},{title:"Button revert secondary color variables",filename:"buttons",url:"buttons.html#button-revert-secondary-color-variables"},{title:"Button revert secondary size",filename:"buttons",url:"buttons.html#button-revert-secondary-size"},{title:"Button revert secondary size variables",filename:"buttons",url:"buttons.html#button-revert-secondary-size-variables"},{title:"components",filename:"components",url:"components.html"},{title:"Components",filename:"components",url:"components.html#components"},{title:"Components Variables",filename:"components",url:"components.html#components-variables"},{title:"dropdowns",filename:"dropdowns",url:"dropdowns.html"},{title:"Drop-down and split buttons mixins",filename:"dropdowns",url:"dropdowns.html#dropdown-and-split-buttons-mixins"},{title:"Drop-down",filename:"dropdowns",url:"dropdowns.html#dropdown"},{title:"Drop-down variables",filename:"dropdowns",url:"dropdowns.html#dropdown-variables"},{title:"Drop-down with icon customization",filename:"dropdowns",url:"dropdowns.html#dropdown-with-icon-customization"},{title:"Modify dropdown list styles",filename:"dropdowns",url:"dropdowns.html#modify-dropdown-list-styles"},{title:"Split button",filename:"dropdowns",url:"dropdowns.html#split-button"},{title:"Split button variables",filename:"dropdowns",url:"dropdowns.html#split-button-variables"},{title:"Split button - button styling",filename:"dropdowns",url:"dropdowns.html#split-button-button-styling"},{title:"Split button icon customization",filename:"dropdowns",url:"dropdowns.html#split-button-icon-customization"},{title:"Split button drop-down list customization",filename:"dropdowns",url:"dropdowns.html#split-button-dropdown-list-customization"},{title:"forms",filename:"forms",url:"forms.html"},{title:"Forms mixins",filename:"forms",url:"forms.html#forms-mixins"},{title:"Global forms elements customization",filename:"forms",url:"forms.html#global-forms-elements-customization"},{title:"Fieldsets & fields customization",filename:"forms",url:"forms.html#fieldsets-fields-customization"},{title:"Fieldset and legend customization variables",filename:"forms",url:"forms.html#fieldset-and-legend-customization-variables"},{title:"Fields customization variables",filename:"forms",url:"forms.html#fields-customization-variables"},{title:"Required fields message customization variables",filename:"forms",url:"forms.html#required-fields-message-customization-variables"},{title:"Form element inputs customization",filename:"forms",url:"forms.html#form-element-inputs-customization"},{title:"Form element inputs customization variables",filename:"forms",url:"forms.html#form-element-inputs-customization-variables"},{title:"Form element choice",filename:"forms",url:"forms.html#form-element-choice"},{title:"Form element choice variables",filename:"forms",url:"forms.html#form-element-choice-variables"},{title:"Custom color",filename:"forms",url:"forms.html#custom-color"},{title:"Input number - input-text view",filename:"forms",url:"forms.html#input-number-inputtext-view"},{title:"Input search - input-text view",filename:"forms",url:"forms.html#input-search-inputtext-view"},{title:"Form validation",filename:"forms",url:"forms.html#form-validation"},{title:"Form validation variables",filename:"forms",url:"forms.html#form-validation-variables"},{title:"icons",filename:"icons",url:"icons.html"},{title:"Icons",filename:"icons",url:"icons.html#icons"},{title:"Icon with image or sprite",filename:"icons",url:"icons.html#icon-with-image-or-sprite"},{title:"Icon with image or sprite variables",filename:"icons",url:"icons.html#icon-with-image-or-sprite-variables"},{title:"Icon position for an icon with image or sprite",filename:"icons",url:"icons.html#icon-position-for-an-icon-with-image-or-sprite"},{title:"Position for icon with image or sprite mixin variables",filename:"icons",url:"icons.html#position-for-icon-with-image-or-sprite-mixin-variables"},{title:"Icon sprite position (with grid)",filename:"icons",url:"icons.html#icon-sprite-position-with-grid"},{title:"Icon sprite position variables",filename:"icons",url:"icons.html#icon-sprite-position-variables"},{title:"Image/sprite icon size",filename:"icons",url:"icons.html#imagesprite-icon-size"},{title:"Image/sprite icon size variables",filename:"icons",url:"icons.html#imagesprite-icon-size-variables"},{title:"Font icon",filename:"icons",url:"icons.html#font-icon"},{title:"Font icon variables",filename:"icons",url:"icons.html#font-icon-variables"},{title:"Change the size of font icon",filename:"icons",url:"icons.html#change-the-size-of-font-icon"},{title:"Change the size of font icon variables",filename:"icons",url:"icons.html#change-the-size-of-font-icon-variables"},{title:"Hide icon text",filename:"icons",url:"icons.html#hide-icon-text"},{title:"Sprite and font icons for Blank theme",filename:"icons",url:"icons.html#sprite-and-font-icons-for-blank-theme"},{title:"layout",filename:"layout",url:"layout.html"},{title:"Layout",filename:"layout",url:"layout.html#layout"},{title:"Layout global variables",filename:"layout",url:"layout.html#layout-global-variables"},{title:"Page layouts",filename:"layout",url:"layout.html#page-layouts"},{title:"Layout column",filename:"layout",url:"layout.html#layout-column"},{title:"Layout column variables",filename:"layout",url:"layout.html#layout-column-variables"},{title:"Layout width",filename:"layout",url:"layout.html#layout-width"},{title:"Layout width variables",filename:"layout",url:"layout.html#layout-width-variables"},{title:"lib",filename:"lib",url:"lib.html"},{title:"Including Magento UI library to your theme",filename:"lib",url:"lib.html#including-magento-ui-library-to-your-theme"},{title:"loaders",filename:"loaders",url:"loaders.html"},{title:"Loaders",filename:"loaders",url:"loaders.html#loaders"},{title:"Default loader variables",filename:"loaders",url:"loaders.html#default-loader-variables"},{title:"Loading",filename:"loaders",url:"loaders.html#loading"},{title:"Loading default variables",filename:"loaders",url:"loaders.html#loading-default-variables"},{title:"messages",filename:"messages",url:"messages.html"},{title:"Messages",filename:"messages",url:"messages.html#messages"},{title:"Information message",filename:"messages",url:"messages.html#information-message"},{title:"Warning message",filename:"messages",url:"messages.html#warning-message"},{title:"Error message",filename:"messages",url:"messages.html#error-message"},{title:"Success message",filename:"messages",url:"messages.html#success-message"},{title:"Notice message",filename:"messages",url:"messages.html#notice-message"},{title:"Message with inner icon",filename:"messages",url:"messages.html#message-with-inner-icon"},{title:"Message with lateral icon",filename:"messages",url:"messages.html#message-with-lateral-icon"},{title:"Custom message style",filename:"messages",url:"messages.html#custom-message-style"},{title:"Messages global variables",filename:"messages",url:"messages.html#messages-global-variables"},{title:"pages",filename:"pages",url:"pages.html"},{title:"Pagination HTML markup",filename:"pages",url:"pages.html#pagination-html-markup"},{title:"Pagination variables",filename:"pages",url:"pages.html#pagination-variables"},{title:"Pagination with label and gradient background on links",filename:"pages",url:"pages.html#pagination-with-label-and-gradient-background-on-links"},{title:'Pagination with "previous"..."next" text links and label',filename:"pages",url:"pages.html#pagination-with-previousnext-text-links-and-label"},{title:"Pagination without label, with solid background",filename:"pages",url:"pages.html#pagination-without-label-with-solid-background"},{title:"popups",filename:"popups",url:"popups.html"},{title:"Popups",filename:"popups",url:"popups.html#popups"},{title:"Popup variables",filename:"popups",url:"popups.html#popup-variables"},{title:"Window overlay mixin variables",filename:"popups",url:"popups.html#window-overlay-mixin-variables"},{title:"Fixed height popup",filename:"popups",url:"popups.html#fixed-height-popup"},{title:"Fixed content height popup",filename:"popups",url:"popups.html#fixed-content-height-popup"},{title:"Margins for header, content and footer block in popup",filename:"popups",url:"popups.html#margins-for-header-content-and-footer-block-in-popup"},{title:"Popup titles styled as theme headings",filename:"popups",url:"popups.html#popup-titles-styled-as-theme-headings"},{title:"Popup action toolbar",filename:"popups",url:"popups.html#popup-action-toolbar"},{title:"Popup Close button without an icon",filename:"popups",url:"popups.html#popup-close-button-without-an-icon"},{title:"Modify the icon of popup Close button",filename:"popups",url:"popups.html#modify-the-icon-of-popup-close-button"},{title:"Modify overlay styles",filename:"popups",url:"popups.html#modify-overlay-styles"},{title:"rating",filename:"rating",url:"rating.html"},{title:"Ratings",filename:"rating",url:"rating.html#ratings"},{title:"Global rating variables",filename:"rating",url:"rating.html#global-rating-variables"},{title:"Rating with vote",filename:"rating",url:"rating.html#rating-with-vote"},{title:"Rating with vote icons number customization",filename:"rating",url:"rating.html#rating-with-vote-icons-number-customization"},{title:"Rating with vote icons colors customization",filename:"rating",url:"rating.html#rating-with-vote-icons-colors-customization"},{title:"Rating with vote icons symbol customization",filename:"rating",url:"rating.html#rating-with-vote-icons-symbol-customization"},{title:"Accessible rating with vote",filename:"rating",url:"rating.html#accessible-rating-with-vote"},{title:"Rating summary",filename:"rating",url:"rating.html#rating-summary"},{title:"Rating summary icons number customization",filename:"rating",url:"rating.html#rating-summary-icons-number-customization"},{title:"Rating summary icons color customization",filename:"rating",url:"rating.html#rating-summary-icons-color-customization"},{title:"Rating summary icons symbol customization",filename:"rating",url:"rating.html#rating-summary-icons-symbol-customization"},{title:"Rating summary hide label",filename:"rating",url:"rating.html#rating-summary-hide-label"},{title:"Rating summary multiple ratings",filename:"rating",url:"rating.html#rating-summary-multiple-ratings"},{title:"Rating hide label mixin",filename:"rating",url:"rating.html#rating-hide-label-mixin"},{title:"resets",filename:"resets",url:"resets.html"},{title:"Resets",filename:"resets",url:"resets.html#resets"},{title:"responsive",filename:"responsive",url:"responsive.html"},{title:"Responsive",filename:"responsive",url:"responsive.html#responsive"},{title:"Responsive mixins usage",filename:"responsive",url:"responsive.html#responsive-mixins-usage"},{title:"Media query style groups separation variables",filename:"responsive",url:"responsive.html#media-query-style-groups-separation-variables"},{title:"Responsive breakpoints",filename:"responsive",url:"responsive.html#responsive-breakpoints"},{title:"sections",filename:"sections",url:"sections.html"},{title:"Tabs and accordions",filename:"sections",url:"sections.html#tabs-and-accordions"},{title:"Tabs",filename:"sections",url:"sections.html#tabs"},{title:"Tabs mixin variables",filename:"sections",url:"sections.html#tabs-mixin-variables"},{title:"Tabs with content top border",filename:"sections",url:"sections.html#tabs-with-content-top-border"},{title:"Accordion",filename:"sections",url:"sections.html#accordion"},{title:"Accordion mixin variables",filename:"sections",url:"sections.html#accordion-mixin-variables"},{title:"Responsive tabs",filename:"sections",url:"sections.html#responsive-tabs"},{title:"Tabs Base",filename:"sections",url:"sections.html#tabs-base"},{title:"Accordion Base",filename:"sections",url:"sections.html#accordion-base"},{title:"tables",filename:"tables",url:"tables.html"},{title:"Tables",filename:"tables",url:"tables.html#tables"},{title:"Table mixin variables",filename:"tables",url:"tables.html#table-mixin-variables"},{title:"Table typography",filename:"tables",url:"tables.html#table-typography"},{title:"Table typography mixin variables",filename:"tables",url:"tables.html#table-typography-mixin-variables"},{title:"Table caption",filename:"tables",url:"tables.html#table-caption"},{title:"Table caption mixin variables",filename:"tables",url:"tables.html#table-caption-mixin-variables"},{title:"Table cells resize",filename:"tables",url:"tables.html#table-cells-resize"},{title:"Table cells resize variables",filename:"tables",url:"tables.html#table-cells-resize-variables"},{title:"Table background customization",filename:"tables",url:"tables.html#table-background-customization"},{title:"Table background mixin variables",filename:"tables",url:"tables.html#table-background-mixin-variables"},{title:"Table borders customization",filename:"tables",url:"tables.html#table-borders-customization"},{title:"Table borders mixin variables",filename:"tables",url:"tables.html#table-borders-mixin-variables"},{title:"Table with horizontal borders",filename:"tables",url:"tables.html#table-with-horizontal-borders"},{title:"Table with vertical borders",filename:"tables",url:"tables.html#table-with-vertical-borders"},{title:"Table with light borders",filename:"tables",url:"tables.html#table-with-light-borders"},{title:"Table without borders",filename:"tables",url:"tables.html#table-without-borders"},{title:"Striped table",filename:"tables",url:"tables.html#striped-table"},{title:"Striped table mixin variables",filename:"tables",url:"tables.html#striped-table-mixin-variables"},{title:"Table with rows hover",filename:"tables",url:"tables.html#table-with-rows-hover"},{title:"Table with rows hover mixin variables",filename:"tables",url:"tables.html#table-with-rows-hover-mixin-variables"},{title:"Responsive table technics #1",filename:"tables",url:"tables.html#responsive-table-technics-1"},{title:"Responsive table technics #2",filename:"tables",url:"tables.html#responsive-table-technics-2"},{title:"Responsive table technics #2 mixin variables",filename:"tables",url:"tables.html#responsive-table-technics-2-mixin-variables"},{title:"tooltips",filename:"tooltips",url:"tooltips.html"},{title:"Tooltips",filename:"tooltips",url:"tooltips.html#tooltips"},{title:"Tooltips variables",filename:"tooltips",url:"tooltips.html#tooltips-variables"},{title:"typography",filename:"typography",url:"typography.html"},{title:"Typogrphy",filename:"typography",url:"typography.html#typogrphy"},{title:"Typography variables",filename:"typography",url:"typography.html#typography-variables"},{title:"Font-size mixin",filename:"typography",url:"typography.html#fontsize-mixin"},{title:"Line-height mixin",filename:"typography",url:"typography.html#lineheight-mixin"},{title:"Word breaking mixin",filename:"typography",url:"typography.html#word-breaking-mixin"},{title:"Font face mixin",filename:"typography",url:"typography.html#font-face-mixin"},{title:"Text overflow mixin",filename:"typography",url:"typography.html#text-overflow-mixin"},{title:"Text hide",filename:"typography",url:"typography.html#text-hide"},{title:"Hyphens",filename:"typography",url:"typography.html#hyphens"},{title:"Font style and color",filename:"typography",url:"typography.html#font-style-and-color"},{title:"Font style mixin variables",filename:"typography",url:"typography.html#font-style-mixin-variables"},{title:"Reset list styles",filename:"typography",url:"typography.html#reset-list-styles"},{title:"Reset list styles variables",filename:"typography",url:"typography.html#reset-list-styles-variables"},{title:"Inline-block list item styling",filename:"typography",url:"typography.html#inlineblock-list-item-styling"},{title:"Link styling mixin",filename:"typography",url:"typography.html#link-styling-mixin"},{title:"Link styling mixin variables",filename:"typography",url:"typography.html#link-styling-mixin-variables"},{title:"Heading styling mixin",filename:"typography",url:"typography.html#heading-styling-mixin"},{title:"Base typography mixins",filename:"typography",url:"typography.html#base-typography-mixins"},{title:"Base typography mixin variables",filename:"typography",url:"typography.html#base-typography-mixin-variables"},{title:"Headings typography mixin",filename:"typography",url:"typography.html#headings-typography-mixin"},{title:"Headings typography mixin variables",filename:"typography",url:"typography.html#headings-typography-mixin-variables"},{title:"Typography links mixin",filename:"typography",url:"typography.html#typography-links-mixin"},{title:"Typography lists mixin",filename:"typography",url:"typography.html#typography-lists-mixin"},{title:"Typography lists mixin variables",filename:"typography",url:"typography.html#typography-lists-mixin-variables"},{title:"Typography code elements mixin",filename:"typography",url:"typography.html#typography-code-elements-mixin"},{title:"Typography code mixin variables",filename:"typography",url:"typography.html#typography-code-mixin-variables"},{title:"Typography blockquote",filename:"typography",url:"typography.html#typography-blockquote"},{title:"Typography blockquote mixin variables",filename:"typography",url:"typography.html#typography-blockquote-mixin-variables"},{title:"utilities",filename:"utilities",url:"utilities.html"},{title:"Utilities",filename:"utilities",url:"utilities.html#utilities"},{title:".lib-clearfix()",filename:"utilities",url:"utilities.html#libclearfix"},{title:".lib-visibility-hidden()",filename:"utilities",url:"utilities.html#libvisibilityhidden"},{title:".lib-visually-hidden()",filename:"utilities",url:"utilities.html#libvisuallyhidden"},{title:".lib-visually-hidden-reset()",filename:"utilities",url:"utilities.html#libvisuallyhiddenreset"},{title:".lib-css()",filename:"utilities",url:"utilities.html#libcss"},{title:".lib-css() variables",filename:"utilities",url:"utilities.html#libcss-variables"},{title:".lib-rotate()",filename:"utilities",url:"utilities.html#librotate"},{title:".lib-rotate() variables",filename:"utilities",url:"utilities.html#librotate-variables"},{title:".lib-input-placeholder()",filename:"utilities",url:"utilities.html#libinputplaceholder"},{title:".lib-input-placeholder() variables",filename:"utilities",url:"utilities.html#libinputplaceholder-variables"},{title:".lib-background-gradient()",filename:"utilities",url:"utilities.html#libbackgroundgradient"},{title:".lib-background-gradient() variables",filename:"utilities",url:"utilities.html#libbackgroundgradient-variables"},{title:".lib-url-check()",filename:"utilities",url:"utilities.html#liburlcheck"},{title:".lib-url-check() variables",filename:"utilities",url:"utilities.html#liburlcheck-variables"},{title:"variables",filename:"variables",url:"variables.html"},{title:"List of Global Variables",filename:"variables",url:"variables.html#list-of-global-variables"},{title:"Table with rows hover mixin variables",filename:"variables",url:"variables.html#table-with-rows-hover-mixin-variables"},{title:"docs",filename:"docs",url:"docs.html"},{title:"Documentation",filename:"docs",url:"docs.html#documentation"}];(function(){"use strict";var b=function(a,b){return Array.prototype.indexOf.call(a,b)!==-1},c=function(a,b){return Array.prototype.filter.call(a,b)},d=function(a,b){return Array.prototype.forEach.call(a,b)},e=document.getElementsByTagName("body")[0];e.addEventListener("click",function(a){var b=a.target;b.tagName.toLowerCase()==="svg"&&(b=b.parentNode);var c=!1;b.dataset.toggle!=null&&(a.preventDefault(),b.classList.contains("is-active")||(c=!0)),d(e.querySelectorAll("[data-toggle]"),function(a){a.classList.remove("is-active"),document.getElementById(a.dataset.toggle).hidden=!0}),c&&(b.classList.add("is-active"),document.getElementById(b.dataset.toggle).hidden=!1)}),function(){var f=e.getElementsByClassName("nav")[0];if(!f)return;var g=document.createElement("ul");g.className="nav-results",g.id="nav-search",g.hidden=!0,d(a,function(a){var b,c,d;b=document.createElement("li"),b._title=a.title.toLowerCase(),b.hidden=!0,b.appendChild(c=document.createElement("a")),c.href=a.url,c.innerHTML=a.title,c.appendChild(d=document.createElement("span")),d.innerHTML=a.filename,d.className="nav-results-filename",g.appendChild(b)}),f.appendChild(g);var h=g.children,i=function(a){d(h,function(a){a.hidden=!0});var b=this.value.toLowerCase(),e=[];b!==""&&(e=c(h,function(a){return a._title.indexOf(b)!==-1})),e.length>0?(d(e,function(a){a.hidden=!1}),g.hidden=!1):g.hidden=!0},j=f.querySelector('input[type="search"]');j.addEventListener("keyup",i),j.addEventListener("focus",i),e.addEventListener("click",function(a){if(a.target.classList&&a.target.classList.contains("search"))return;g.hidden=!0}),g.addEventListener("click",function(a){j.value=""});var k=document.createElement("ul");k.id="nav-toc",k.hidden=!0,k.className="nav-results toc-list",c(e.getElementsByTagName("*"),function(a){return b(["h1","h2","h3"],a.tagName.toLowerCase())}).map(function(a){var b=document.createElement("li"),c=document.createElement("a"),d=a.tagName.toLowerCase()[1];c.classList.add("level-"+d),b.appendChild(c),c.href="#"+a.id,c.innerHTML=a.innerHTML,k.appendChild(b)}),f.appendChild(k)}()})(),function(){"use strict";if(location.hash==="#__preview__"||location.protocol==="data:")return;var a=function(a,b){return Array.prototype.forEach.call(a,b)},b=function(a,b){var e=Array.prototype.slice.call(arguments,2);return d(a,function(a){return(c(b)?b||a:a[b]).apply(a,e)})},c=function(a){return Object.prototype.toString.call(a)==="[object Function]"},d=function(a,b){return Array.prototype.map.call(a,b)},e=function(a,b){return d(a,function(a){return a[b]})},f=function(a){var b={},c=a.split(";");for(var d=0;c.length>d;d++){var e=c[d].trim().split("=");b[e[0]]=e[1]}return b},g=function(a,c){return b(e(a,"classList"),"remove",c)},h=function(a,b){a.contentDocument.defaultView.postMessage(b,"*")},i=document.getElementsByTagName("head")[0],j=document.getElementsByTagName("body")[0],k=e(i.querySelectorAll('style[type="text/preview"]'),"innerHTML").join(""),l=e(i.querySelectorAll('script[type="text/preview"]'),"innerHTML").join(""),m=location.href.split("#")[0]+"#__preview__",n=document.createElement("iframe");n.src="data:text/html,",j.appendChild(n),n.addEventListener("load",function(){var b={sameOriginDataUri:!0};try{this.contentDocument,this.contentDocument||(b.sameOriginDataUri=!1)}catch(c){b.sameOriginDataUri=!1}this.parentNode.removeChild(this),a(j.getElementsByTagName("textarea"),function(a,c){o(a,b,c),q(),p(a)})});var o=function(a,b,c){var d,e,f;d=document.createElement("div"),d.appendChild(e=document.createElement("div")),d.className="preview",e.appendChild(f=document.createElement("iframe")),e.className="resizeable",f.setAttribute("scrolling","no"),f.name="iframe"+c++,f.addEventListener("load",function(){var c,d,e,f,g,i,j;j=this.contentDocument;if(!b.sameOriginDataUri&&this.src!==m)return;this.src===m&&(c=j.createElement("html"),c.appendChild(j.createElement("head")),c.appendChild(d=j.createElement("body")),d.innerHTML=a.textContent,j.replaceChild(c,j.documentElement)),g=j.createElement("head"),g.appendChild(f=j.createElement("style")),g.appendChild(e=j.createElement("script")),e.textContent=l,f.textContent=k,i=j.getElementsByTagName("head")[0],i.parentNode.replaceChild(g,i),h(this,"getHeight")});var g;b.sameOriginDataUri?g="data:text/html;charset=utf-8,"+encodeURIComponent("<!doctype html><html><head></head></body>"+a.textContent):g=m,f.setAttribute("src",g);var i=function(){f.contentDocument.body.innerHTML=this.value,h(f,"getHeight")};a.addEventListener("keypress",i),a.addEventListener("keyup",i),a.parentNode.insertBefore(d,a)},p=function(a){var b=document.createElement("div");b.className="preview-code",b.style.position="absolute",b.style.left="-9999px",j.appendChild(b);var c=parseInt(window.getComputedStyle(a).getPropertyValue("max-height"),10),d=function(a){b.textContent=this.value+"\n";var d=b.offsetHeight+2;d>=c?this.style.overflow="auto":this.style.overflow="hidden",this.style.height=b.offsetHeight+2+"px"};a.addEventListener("keypress",d),a.addEventListener("keyup",d),d.call(a)},q=function(){var b=j.getElementsByClassName("settings")[0],c=j.getElementsByClassName("resizeable"),d=30,e=function(b){document.cookie="preview-width="+b,a(c,function(a){b==="auto"&&(b=a.parentNode.offsetWidth),a.style.width=b+"px",h(a.getElementsByTagName("iframe")[0],"getHeight")})},i=f(document.cookie)["preview-width"];if(i){e(i),g(b.getElementsByClassName("is-active"),"is-active");var k=b.querySelector('button[data-width="'+i+'"]');k&&k.classList.add("is-active")}window.addEventListener("message",function(a){if(a.data==null||!a.source)return;var b=a.data,c=document.getElementsByName(a.source.name)[0];b.height!=null&&c&&(c.parentNode.style.height=b.height+d+"px")},!1),b&&c.length>0&&(b.hidden=!1,b.addEventListener("click",function(a){var c=a.target.tagName.toLowerCase(),d;if(c==="button")d=a.target;else{if(c!=="svg")return;d=a.target.parentNode}a.preventDefault(),g(b.getElementsByClassName("is-active"),"is-active"),d.classList.add("is-active");var f=d.dataset.width;e(f)}))}}()})()</script></body></html><!-- Generated with StyleDocco (http://jacobrask.github.com/styledocco). --> +</div></article></section><div class="bar bottom"><div hidden class="settings container"><!-- Icons from http://iconmonstr.com--><button title="Desktop (1280)" data-width='1280'><svg viewBox="0 0 412 386" height="24" width="26" class="icon"><path d="m147.6,343.9c-4.5,15.9-26.2,37.6-42.1,42.1h201c-15.3,-4-38.1,-26.8-42.1,-42.1H147.6zM387,0.5H25c-13.8,0-25,11.2-25,25V294c0,13.8 11.2,25 25,25h362c13.8,0 25,-11.2 25,-25V25.5C412,11.7 400.8,0.5 387,0.5zM369.9,238.2H42.1L42.1,42.6 369.9,42.6V238.2z"></path></svg></button><button title="Laptop (1024)" data-width='1024'><svg viewBox="0 0 384 312" height="23" width="28" class="icon"><path d="m349.2,20.5c0,-11-9,-20-20,-20H53.6c-11,0-20,9-20,20v194H349.2v-194zm-27,167H60.6V27.5H322.2v160zm28,42H32.6L2.6,282.1c-3.5,6.2-3.5,13.8 0.1,19.9 3.6,6.2 10.2,9.9 17.3,9.9H363.1c7.1,0 13.7,-3.8 17.3,-10 3.6,-6.2 3.6,-13.8 0,-20l-30.2,-52.5zm-196.9,54 8,-23.5h60.5l8,23.5h-76.5z"></path></svg></button><button title="Tablet (768)" data-width='768'><svg viewBox="0 0 317 412" height="24" width="18" class="icon"><path d="M 316.5,380 V 32 c 0,-17.7 -14.3,-32 -32,-32 H 32 C 14.3,0 0,14.3 0,32 v 348 c 0,17.7 14.3,32 32,32 h 252.5 c 17.7,0 32,-14.3 32,-32 z M 40,367 V 45 H 276.5 V 367 H 40 z m 109.8,22.7 c 0,-4.7 3.8,-8.5 8.5,-8.5 4.7,0 8.5,3.8 8.5,8.5 0,4.7 -3.8,8.5 -8.5,8.5 -4.7,0 -8.5,-3.8 -8.5,-8.5 z"></path></svg></button><button title="Smart phone (320)" data-width='320'><svg viewBox="0 0 224 412" height="24" width="13" class="icon"><path d="M 190.7,0 H 33 C 14.8,0 0,14.8 0,33 v 346 c 0,18.2 14.8,33 33,33 h 157.7 c 18.2,0 33,-14.8 33,-33 V 33 c 0,-18.2 -14.8,-33 -33,-33 z M 94.3,30.2 h 37 c 2.2,0 4,1.8 4,4 0,2.2 -1.8,4 -4,4 h -37 c -2.2,0 -4,-1.8 -4,-4 0,-2.2 1.8,-4 4,-4 z m 18.5,362.8 c -8.8,0 -16,-7.2 -16,-16 0,-8.8 7.2,-16 16,-16 8.8,0 16,7.2 16,16 0,8.8 -7.2,16 -16,16 z M 198.6,343.8 H 25.1 V 68.2 h 173.5 v 275.5 z"></path></svg></button><button title="Feature phone (240)" data-width='240'><svg viewBox="0 0 201 412" height="24" width="12" class="icon"><path d="M 165.5,0.2 V 45 H 25 c -13.8,0 -25,11.2 -25,25 V 387 c 0,13.8 11.2,25 25,25 h 150.5 c 13.8,0 25,-11.2 25,-25 V 0.2 h -35 z M 65.2,366.5 H 34.2 v -24.5 h 31 v 24.5 z m 0,-44.3 H 34.2 v -24.5 h 31 v 24.5 z m 50.5,44.3 H 84.7 v -24.5 h 31 v 24.5 z m 0,-44.3 H 84.7 v -24.5 h 31 v 24.5 z m 50.5,44.3 h -31 v -24.5 h 31 v 24.5 z m 0,-44.3 h -31 v -24.5 h 31 v 24.5 z m 0,-59.3 h -132 V 95.4 h 132 V 262.9 z"></path></svg></button><button title="Auto (100%)" data-width="auto" class="auto is-active">Auto</button></div></div><script>(function(){var a=[{title:"actions-toolbar",filename:"actions-toolbar",url:"actions-toolbar.html"},{title:"Actions toolbar",filename:"actions-toolbar",url:"actions-toolbar.html#actions-toolbar"},{title:"Actions toolbar mixin variables",filename:"actions-toolbar",url:"actions-toolbar.html#actions-toolbar-mixin-variables"},{title:"Actions toolbar alignment",filename:"actions-toolbar",url:"actions-toolbar.html#actions-toolbar-alignment"},{title:"Reverse primary and secondary blocks",filename:"actions-toolbar",url:"actions-toolbar.html#reverse-primary-and-secondary-blocks"},{title:"Actions toolbar indents customizations",filename:"actions-toolbar",url:"actions-toolbar.html#actions-toolbar-indents-customizations"},{title:"Responsive actions toolbar",filename:"actions-toolbar",url:"actions-toolbar.html#responsive-actions-toolbar"},{title:"breadcrumbs",filename:"breadcrumbs",url:"breadcrumbs.html"},{title:"Breadcrumbs",filename:"breadcrumbs",url:"breadcrumbs.html#breadcrumbs"},{title:"Breadcrumbs variables",filename:"breadcrumbs",url:"breadcrumbs.html#breadcrumbs-variables"},{title:"Button-styled breadcrumbs with gradient background, border, and no separating symbol",filename:"breadcrumbs",url:"breadcrumbs.html#buttonstyled-breadcrumbs-with-gradient-background-border-and-no-separating-symbol"},{title:"Breadcrumbs with solid background",filename:"breadcrumbs",url:"breadcrumbs.html#breadcrumbs-with-solid-background"},{title:"buttons",filename:"buttons",url:"buttons.html"},{title:"Default button",filename:"buttons",url:"buttons.html#default-button"},{title:"Button variables",filename:"buttons",url:"buttons.html#button-variables"},{title:"Button as an icon",filename:"buttons",url:"buttons.html#button-as-an-icon"},{title:"Button with an icon on the left or right side of the text",filename:"buttons",url:"buttons.html#button-with-an-icon-on-the-left-or-right-side-of-the-text"},{title:"Button with fixed width",filename:"buttons",url:"buttons.html#button-with-fixed-width"},{title:"Primary button",filename:"buttons",url:"buttons.html#primary-button"},{title:"Primary button variables",filename:"buttons",url:"buttons.html#primary-button-variables"},{title:"Button with gradient background",filename:"buttons",url:"buttons.html#button-with-gradient-background"},{title:"Button as a link",filename:"buttons",url:"buttons.html#button-as-a-link"},{title:"Button as a link variables",filename:"buttons",url:"buttons.html#button-as-a-link-variables"},{title:"Link as a button",filename:"buttons",url:"buttons.html#link-as-a-button"},{title:"Button reset",filename:"buttons",url:"buttons.html#button-reset"},{title:"Button revert secondary color",filename:"buttons",url:"buttons.html#button-revert-secondary-color"},{title:"Button revert secondary color variables",filename:"buttons",url:"buttons.html#button-revert-secondary-color-variables"},{title:"Button revert secondary size",filename:"buttons",url:"buttons.html#button-revert-secondary-size"},{title:"Button revert secondary size variables",filename:"buttons",url:"buttons.html#button-revert-secondary-size-variables"},{title:"components",filename:"components",url:"components.html"},{title:"Components",filename:"components",url:"components.html#components"},{title:"Components Variables",filename:"components",url:"components.html#components-variables"},{title:"dropdowns",filename:"dropdowns",url:"dropdowns.html"},{title:"Drop-down and split buttons mixins",filename:"dropdowns",url:"dropdowns.html#dropdown-and-split-buttons-mixins"},{title:"Drop-down",filename:"dropdowns",url:"dropdowns.html#dropdown"},{title:"Drop-down variables",filename:"dropdowns",url:"dropdowns.html#dropdown-variables"},{title:"Drop-down with icon customization",filename:"dropdowns",url:"dropdowns.html#dropdown-with-icon-customization"},{title:"Modify dropdown list styles",filename:"dropdowns",url:"dropdowns.html#modify-dropdown-list-styles"},{title:"Split button",filename:"dropdowns",url:"dropdowns.html#split-button"},{title:"Split button variables",filename:"dropdowns",url:"dropdowns.html#split-button-variables"},{title:"Split button - button styling",filename:"dropdowns",url:"dropdowns.html#split-button-button-styling"},{title:"Split button icon customization",filename:"dropdowns",url:"dropdowns.html#split-button-icon-customization"},{title:"Split button drop-down list customization",filename:"dropdowns",url:"dropdowns.html#split-button-dropdown-list-customization"},{title:"forms",filename:"forms",url:"forms.html"},{title:"Forms mixins",filename:"forms",url:"forms.html#forms-mixins"},{title:"Global forms elements customization",filename:"forms",url:"forms.html#global-forms-elements-customization"},{title:"Fieldsets & fields customization",filename:"forms",url:"forms.html#fieldsets-fields-customization"},{title:"Fieldset and legend customization variables",filename:"forms",url:"forms.html#fieldset-and-legend-customization-variables"},{title:"Fields customization variables",filename:"forms",url:"forms.html#fields-customization-variables"},{title:"Required fields message customization variables",filename:"forms",url:"forms.html#required-fields-message-customization-variables"},{title:"Form element inputs customization",filename:"forms",url:"forms.html#form-element-inputs-customization"},{title:"Form element inputs customization variables",filename:"forms",url:"forms.html#form-element-inputs-customization-variables"},{title:"Form element choice",filename:"forms",url:"forms.html#form-element-choice"},{title:"Form element choice variables",filename:"forms",url:"forms.html#form-element-choice-variables"},{title:"Custom color",filename:"forms",url:"forms.html#custom-color"},{title:"Input number - input-text view",filename:"forms",url:"forms.html#input-number-inputtext-view"},{title:"Input search - input-text view",filename:"forms",url:"forms.html#input-search-inputtext-view"},{title:"Form validation",filename:"forms",url:"forms.html#form-validation"},{title:"Form validation variables",filename:"forms",url:"forms.html#form-validation-variables"},{title:"icons",filename:"icons",url:"icons.html"},{title:"Icons",filename:"icons",url:"icons.html#icons"},{title:"Icon with image or sprite",filename:"icons",url:"icons.html#icon-with-image-or-sprite"},{title:"Icon with image or sprite variables",filename:"icons",url:"icons.html#icon-with-image-or-sprite-variables"},{title:"Icon position for an icon with image or sprite",filename:"icons",url:"icons.html#icon-position-for-an-icon-with-image-or-sprite"},{title:"Position for icon with image or sprite mixin variables",filename:"icons",url:"icons.html#position-for-icon-with-image-or-sprite-mixin-variables"},{title:"Icon sprite position (with grid)",filename:"icons",url:"icons.html#icon-sprite-position-with-grid"},{title:"Icon sprite position variables",filename:"icons",url:"icons.html#icon-sprite-position-variables"},{title:"Image/sprite icon size",filename:"icons",url:"icons.html#imagesprite-icon-size"},{title:"Image/sprite icon size variables",filename:"icons",url:"icons.html#imagesprite-icon-size-variables"},{title:"Font icon",filename:"icons",url:"icons.html#font-icon"},{title:"Font icon variables",filename:"icons",url:"icons.html#font-icon-variables"},{title:"Change the size of font icon",filename:"icons",url:"icons.html#change-the-size-of-font-icon"},{title:"Change the size of font icon variables",filename:"icons",url:"icons.html#change-the-size-of-font-icon-variables"},{title:"Hide icon text",filename:"icons",url:"icons.html#hide-icon-text"},{title:"Sprite and font icons for Blank theme",filename:"icons",url:"icons.html#sprite-and-font-icons-for-blank-theme"},{title:"layout",filename:"layout",url:"layout.html"},{title:"Layout",filename:"layout",url:"layout.html#layout"},{title:"Layout global variables",filename:"layout",url:"layout.html#layout-global-variables"},{title:"Page layouts",filename:"layout",url:"layout.html#page-layouts"},{title:"Layout column",filename:"layout",url:"layout.html#layout-column"},{title:"Layout column variables",filename:"layout",url:"layout.html#layout-column-variables"},{title:"Layout width",filename:"layout",url:"layout.html#layout-width"},{title:"Layout width variables",filename:"layout",url:"layout.html#layout-width-variables"},{title:"lib",filename:"lib",url:"lib.html"},{title:"Including Magento UI library to your theme",filename:"lib",url:"lib.html#including-magento-ui-library-to-your-theme"},{title:"loaders",filename:"loaders",url:"loaders.html"},{title:"Loaders",filename:"loaders",url:"loaders.html#loaders"},{title:"Default loader variables",filename:"loaders",url:"loaders.html#default-loader-variables"},{title:"Loading",filename:"loaders",url:"loaders.html#loading"},{title:"Loading default variables",filename:"loaders",url:"loaders.html#loading-default-variables"},{title:"messages",filename:"messages",url:"messages.html"},{title:"Messages",filename:"messages",url:"messages.html#messages"},{title:"Information message",filename:"messages",url:"messages.html#information-message"},{title:"Warning message",filename:"messages",url:"messages.html#warning-message"},{title:"Error message",filename:"messages",url:"messages.html#error-message"},{title:"Success message",filename:"messages",url:"messages.html#success-message"},{title:"Notice message",filename:"messages",url:"messages.html#notice-message"},{title:"Message with inner icon",filename:"messages",url:"messages.html#message-with-inner-icon"},{title:"Message with lateral icon",filename:"messages",url:"messages.html#message-with-lateral-icon"},{title:"Custom message style",filename:"messages",url:"messages.html#custom-message-style"},{title:"Messages global variables",filename:"messages",url:"messages.html#messages-global-variables"},{title:"pages",filename:"pages",url:"pages.html"},{title:"Pagination HTML markup",filename:"pages",url:"pages.html#pagination-html-markup"},{title:"Pagination variables",filename:"pages",url:"pages.html#pagination-variables"},{title:"Pagination with label and gradient background on links",filename:"pages",url:"pages.html#pagination-with-label-and-gradient-background-on-links"},{title:'Pagination with "previous"..."next" text links and label',filename:"pages",url:"pages.html#pagination-with-previousnext-text-links-and-label"},{title:"Pagination without label, with solid background",filename:"pages",url:"pages.html#pagination-without-label-with-solid-background"},{title:"popups",filename:"popups",url:"popups.html"},{title:"Popups",filename:"popups",url:"popups.html#popups"},{title:"Popup variables",filename:"popups",url:"popups.html#popup-variables"},{title:"Window overlay mixin variables",filename:"popups",url:"popups.html#window-overlay-mixin-variables"},{title:"Fixed height popup",filename:"popups",url:"popups.html#fixed-height-popup"},{title:"Fixed content height popup",filename:"popups",url:"popups.html#fixed-content-height-popup"},{title:"Margins for header, content and footer block in popup",filename:"popups",url:"popups.html#margins-for-header-content-and-footer-block-in-popup"},{title:"Popup titles styled as theme headings",filename:"popups",url:"popups.html#popup-titles-styled-as-theme-headings"},{title:"Popup action toolbar",filename:"popups",url:"popups.html#popup-action-toolbar"},{title:"Popup Close button without an icon",filename:"popups",url:"popups.html#popup-close-button-without-an-icon"},{title:"Modify the icon of popup Close button",filename:"popups",url:"popups.html#modify-the-icon-of-popup-close-button"},{title:"Modify overlay styles",filename:"popups",url:"popups.html#modify-overlay-styles"},{title:"rating",filename:"rating",url:"rating.html"},{title:"Ratings",filename:"rating",url:"rating.html#ratings"},{title:"Global rating variables",filename:"rating",url:"rating.html#global-rating-variables"},{title:"Rating with vote",filename:"rating",url:"rating.html#rating-with-vote"},{title:"Rating with vote icons number customization",filename:"rating",url:"rating.html#rating-with-vote-icons-number-customization"},{title:"Rating with vote icons colors customization",filename:"rating",url:"rating.html#rating-with-vote-icons-colors-customization"},{title:"Rating with vote icons symbol customization",filename:"rating",url:"rating.html#rating-with-vote-icons-symbol-customization"},{title:"Accessible rating with vote",filename:"rating",url:"rating.html#accessible-rating-with-vote"},{title:"Rating summary",filename:"rating",url:"rating.html#rating-summary"},{title:"Rating summary icons number customization",filename:"rating",url:"rating.html#rating-summary-icons-number-customization"},{title:"Rating summary icons color customization",filename:"rating",url:"rating.html#rating-summary-icons-color-customization"},{title:"Rating summary icons symbol customization",filename:"rating",url:"rating.html#rating-summary-icons-symbol-customization"},{title:"Rating summary hide label",filename:"rating",url:"rating.html#rating-summary-hide-label"},{title:"Rating summary multiple ratings",filename:"rating",url:"rating.html#rating-summary-multiple-ratings"},{title:"Rating hide label mixin",filename:"rating",url:"rating.html#rating-hide-label-mixin"},{title:"resets",filename:"resets",url:"resets.html"},{title:"Resets",filename:"resets",url:"resets.html#resets"},{title:"responsive",filename:"responsive",url:"responsive.html"},{title:"Responsive",filename:"responsive",url:"responsive.html#responsive"},{title:"Responsive mixins usage",filename:"responsive",url:"responsive.html#responsive-mixins-usage"},{title:"Media query style groups separation variables",filename:"responsive",url:"responsive.html#media-query-style-groups-separation-variables"},{title:"Responsive breakpoints",filename:"responsive",url:"responsive.html#responsive-breakpoints"},{title:"sections",filename:"sections",url:"sections.html"},{title:"Tabs and accordions",filename:"sections",url:"sections.html#tabs-and-accordions"},{title:"Tabs",filename:"sections",url:"sections.html#tabs"},{title:"Tabs mixin variables",filename:"sections",url:"sections.html#tabs-mixin-variables"},{title:"Tabs with content top border",filename:"sections",url:"sections.html#tabs-with-content-top-border"},{title:"Accordion",filename:"sections",url:"sections.html#accordion"},{title:"Accordion mixin variables",filename:"sections",url:"sections.html#accordion-mixin-variables"},{title:"Responsive tabs",filename:"sections",url:"sections.html#responsive-tabs"},{title:"Tabs Base",filename:"sections",url:"sections.html#tabs-base"},{title:"Accordion Base",filename:"sections",url:"sections.html#accordion-base"},{title:"tables",filename:"tables",url:"tables.html"},{title:"Tables",filename:"tables",url:"tables.html#tables"},{title:"Table mixin variables",filename:"tables",url:"tables.html#table-mixin-variables"},{title:"Table typography",filename:"tables",url:"tables.html#table-typography"},{title:"Table typography mixin variables",filename:"tables",url:"tables.html#table-typography-mixin-variables"},{title:"Table caption",filename:"tables",url:"tables.html#table-caption"},{title:"Table caption mixin variables",filename:"tables",url:"tables.html#table-caption-mixin-variables"},{title:"Table cells resize",filename:"tables",url:"tables.html#table-cells-resize"},{title:"Table cells resize variables",filename:"tables",url:"tables.html#table-cells-resize-variables"},{title:"Table background customization",filename:"tables",url:"tables.html#table-background-customization"},{title:"Table background mixin variables",filename:"tables",url:"tables.html#table-background-mixin-variables"},{title:"Table borders customization",filename:"tables",url:"tables.html#table-borders-customization"},{title:"Table borders mixin variables",filename:"tables",url:"tables.html#table-borders-mixin-variables"},{title:"Table with horizontal borders",filename:"tables",url:"tables.html#table-with-horizontal-borders"},{title:"Table with vertical borders",filename:"tables",url:"tables.html#table-with-vertical-borders"},{title:"Table with light borders",filename:"tables",url:"tables.html#table-with-light-borders"},{title:"Table without borders",filename:"tables",url:"tables.html#table-without-borders"},{title:"Striped table",filename:"tables",url:"tables.html#striped-table"},{title:"Striped table mixin variables",filename:"tables",url:"tables.html#striped-table-mixin-variables"},{title:"Table with rows hover",filename:"tables",url:"tables.html#table-with-rows-hover"},{title:"Table with rows hover mixin variables",filename:"tables",url:"tables.html#table-with-rows-hover-mixin-variables"},{title:"Responsive table technics #1",filename:"tables",url:"tables.html#responsive-table-technics-1"},{title:"Responsive table technics #2",filename:"tables",url:"tables.html#responsive-table-technics-2"},{title:"Responsive table technics #2 mixin variables",filename:"tables",url:"tables.html#responsive-table-technics-2-mixin-variables"},{title:"tooltips",filename:"tooltips",url:"tooltips.html"},{title:"Tooltips",filename:"tooltips",url:"tooltips.html#tooltips"},{title:"Tooltips variables",filename:"tooltips",url:"tooltips.html#tooltips-variables"},{title:"typography",filename:"typography",url:"typography.html"},{title:"Typogrphy",filename:"typography",url:"typography.html#typogrphy"},{title:"Typography variables",filename:"typography",url:"typography.html#typography-variables"},{title:"Font-size mixin",filename:"typography",url:"typography.html#fontsize-mixin"},{title:"Line-height mixin",filename:"typography",url:"typography.html#lineheight-mixin"},{title:"Word breaking mixin",filename:"typography",url:"typography.html#word-breaking-mixin"},{title:"Font face mixin",filename:"typography",url:"typography.html#font-face-mixin"},{title:"Text overflow mixin",filename:"typography",url:"typography.html#text-overflow-mixin"},{title:"Text hide",filename:"typography",url:"typography.html#text-hide"},{title:"Hyphens",filename:"typography",url:"typography.html#hyphens"},{title:"Font style and color",filename:"typography",url:"typography.html#font-style-and-color"},{title:"Font style mixin variables",filename:"typography",url:"typography.html#font-style-mixin-variables"},{title:"Reset list styles",filename:"typography",url:"typography.html#reset-list-styles"},{title:"Reset list styles variables",filename:"typography",url:"typography.html#reset-list-styles-variables"},{title:"Inline-block list item styling",filename:"typography",url:"typography.html#inlineblock-list-item-styling"},{title:"Link styling mixin",filename:"typography",url:"typography.html#link-styling-mixin"},{title:"Link styling mixin variables",filename:"typography",url:"typography.html#link-styling-mixin-variables"},{title:"Heading styling mixin",filename:"typography",url:"typography.html#heading-styling-mixin"},{title:"Base typography mixins",filename:"typography",url:"typography.html#base-typography-mixins"},{title:"Base typography mixin variables",filename:"typography",url:"typography.html#base-typography-mixin-variables"},{title:"Headings typography mixin",filename:"typography",url:"typography.html#headings-typography-mixin"},{title:"Headings typography mixin variables",filename:"typography",url:"typography.html#headings-typography-mixin-variables"},{title:"Typography links mixin",filename:"typography",url:"typography.html#typography-links-mixin"},{title:"Typography lists mixin",filename:"typography",url:"typography.html#typography-lists-mixin"},{title:"Typography lists mixin variables",filename:"typography",url:"typography.html#typography-lists-mixin-variables"},{title:"Typography code elements mixin",filename:"typography",url:"typography.html#typography-code-elements-mixin"},{title:"Typography code mixin variables",filename:"typography",url:"typography.html#typography-code-mixin-variables"},{title:"Typography blockquote",filename:"typography",url:"typography.html#typography-blockquote"},{title:"Typography blockquote mixin variables",filename:"typography",url:"typography.html#typography-blockquote-mixin-variables"},{title:"utilities",filename:"utilities",url:"utilities.html"},{title:"Utilities",filename:"utilities",url:"utilities.html#utilities"},{title:".lib-clearfix()",filename:"utilities",url:"utilities.html#libclearfix"},{title:".lib-visibility-hidden()",filename:"utilities",url:"utilities.html#libvisibilityhidden"},{title:".lib-visually-hidden()",filename:"utilities",url:"utilities.html#libvisuallyhidden"},{title:".lib-visually-hidden-reset()",filename:"utilities",url:"utilities.html#libvisuallyhiddenreset"},{title:".lib-css()",filename:"utilities",url:"utilities.html#libcss"},{title:".lib-css() variables",filename:"utilities",url:"utilities.html#libcss-variables"},{title:".lib-rotate()",filename:"utilities",url:"utilities.html#librotate"},{title:".lib-rotate() variables",filename:"utilities",url:"utilities.html#librotate-variables"},{title:".lib-input-placeholder()",filename:"utilities",url:"utilities.html#libinputplaceholder"},{title:".lib-input-placeholder() variables",filename:"utilities",url:"utilities.html#libinputplaceholder-variables"},{title:".lib-background-gradient()",filename:"utilities",url:"utilities.html#libbackgroundgradient"},{title:".lib-background-gradient() variables",filename:"utilities",url:"utilities.html#libbackgroundgradient-variables"},{title:"variables",filename:"variables",url:"variables.html"},{title:"List of Global Variables",filename:"variables",url:"variables.html#list-of-global-variables"},{title:"Table with rows hover mixin variables",filename:"variables",url:"variables.html#table-with-rows-hover-mixin-variables"},{title:"docs",filename:"docs",url:"docs.html"},{title:"Documentation",filename:"docs",url:"docs.html#documentation"}];(function(){"use strict";var b=function(a,b){return Array.prototype.indexOf.call(a,b)!==-1},c=function(a,b){return Array.prototype.filter.call(a,b)},d=function(a,b){return Array.prototype.forEach.call(a,b)},e=document.getElementsByTagName("body")[0];e.addEventListener("click",function(a){var b=a.target;b.tagName.toLowerCase()==="svg"&&(b=b.parentNode);var c=!1;b.dataset.toggle!=null&&(a.preventDefault(),b.classList.contains("is-active")||(c=!0)),d(e.querySelectorAll("[data-toggle]"),function(a){a.classList.remove("is-active"),document.getElementById(a.dataset.toggle).hidden=!0}),c&&(b.classList.add("is-active"),document.getElementById(b.dataset.toggle).hidden=!1)}),function(){var f=e.getElementsByClassName("nav")[0];if(!f)return;var g=document.createElement("ul");g.className="nav-results",g.id="nav-search",g.hidden=!0,d(a,function(a){var b,c,d;b=document.createElement("li"),b._title=a.title.toLowerCase(),b.hidden=!0,b.appendChild(c=document.createElement("a")),c.href=a.url,c.innerHTML=a.title,c.appendChild(d=document.createElement("span")),d.innerHTML=a.filename,d.className="nav-results-filename",g.appendChild(b)}),f.appendChild(g);var h=g.children,i=function(a){d(h,function(a){a.hidden=!0});var b=this.value.toLowerCase(),e=[];b!==""&&(e=c(h,function(a){return a._title.indexOf(b)!==-1})),e.length>0?(d(e,function(a){a.hidden=!1}),g.hidden=!1):g.hidden=!0},j=f.querySelector('input[type="search"]');j.addEventListener("keyup",i),j.addEventListener("focus",i),e.addEventListener("click",function(a){if(a.target.classList&&a.target.classList.contains("search"))return;g.hidden=!0}),g.addEventListener("click",function(a){j.value=""});var k=document.createElement("ul");k.id="nav-toc",k.hidden=!0,k.className="nav-results toc-list",c(e.getElementsByTagName("*"),function(a){return b(["h1","h2","h3"],a.tagName.toLowerCase())}).map(function(a){var b=document.createElement("li"),c=document.createElement("a"),d=a.tagName.toLowerCase()[1];c.classList.add("level-"+d),b.appendChild(c),c.href="#"+a.id,c.innerHTML=a.innerHTML,k.appendChild(b)}),f.appendChild(k)}()})(),function(){"use strict";if(location.hash==="#__preview__"||location.protocol==="data:")return;var a=function(a,b){return Array.prototype.forEach.call(a,b)},b=function(a,b){var e=Array.prototype.slice.call(arguments,2);return d(a,function(a){return(c(b)?b||a:a[b]).apply(a,e)})},c=function(a){return Object.prototype.toString.call(a)==="[object Function]"},d=function(a,b){return Array.prototype.map.call(a,b)},e=function(a,b){return d(a,function(a){return a[b]})},f=function(a){var b={},c=a.split(";");for(var d=0;c.length>d;d++){var e=c[d].trim().split("=");b[e[0]]=e[1]}return b},g=function(a,c){return b(e(a,"classList"),"remove",c)},h=function(a,b){a.contentDocument.defaultView.postMessage(b,"*")},i=document.getElementsByTagName("head")[0],j=document.getElementsByTagName("body")[0],k=e(i.querySelectorAll('style[type="text/preview"]'),"innerHTML").join(""),l=e(i.querySelectorAll('script[type="text/preview"]'),"innerHTML").join(""),m=location.href.split("#")[0]+"#__preview__",n=document.createElement("iframe");n.src="data:text/html,",j.appendChild(n),n.addEventListener("load",function(){var b={sameOriginDataUri:!0};try{this.contentDocument,this.contentDocument||(b.sameOriginDataUri=!1)}catch(c){b.sameOriginDataUri=!1}this.parentNode.removeChild(this),a(j.getElementsByTagName("textarea"),function(a,c){o(a,b,c),q(),p(a)})});var o=function(a,b,c){var d,e,f;d=document.createElement("div"),d.appendChild(e=document.createElement("div")),d.className="preview",e.appendChild(f=document.createElement("iframe")),e.className="resizeable",f.setAttribute("scrolling","no"),f.name="iframe"+c++,f.addEventListener("load",function(){var c,d,e,f,g,i,j;j=this.contentDocument;if(!b.sameOriginDataUri&&this.src!==m)return;this.src===m&&(c=j.createElement("html"),c.appendChild(j.createElement("head")),c.appendChild(d=j.createElement("body")),d.innerHTML=a.textContent,j.replaceChild(c,j.documentElement)),g=j.createElement("head"),g.appendChild(f=j.createElement("style")),g.appendChild(e=j.createElement("script")),e.textContent=l,f.textContent=k,i=j.getElementsByTagName("head")[0],i.parentNode.replaceChild(g,i),h(this,"getHeight")});var g;b.sameOriginDataUri?g="data:text/html;charset=utf-8,"+encodeURIComponent("<!doctype html><html><head></head></body>"+a.textContent):g=m,f.setAttribute("src",g);var i=function(){f.contentDocument.body.innerHTML=this.value,h(f,"getHeight")};a.addEventListener("keypress",i),a.addEventListener("keyup",i),a.parentNode.insertBefore(d,a)},p=function(a){var b=document.createElement("div");b.className="preview-code",b.style.position="absolute",b.style.left="-9999px",j.appendChild(b);var c=parseInt(window.getComputedStyle(a).getPropertyValue("max-height"),10),d=function(a){b.textContent=this.value+"\n";var d=b.offsetHeight+2;d>=c?this.style.overflow="auto":this.style.overflow="hidden",this.style.height=b.offsetHeight+2+"px"};a.addEventListener("keypress",d),a.addEventListener("keyup",d),d.call(a)},q=function(){var b=j.getElementsByClassName("settings")[0],c=j.getElementsByClassName("resizeable"),d=30,e=function(b){document.cookie="preview-width="+b,a(c,function(a){b==="auto"&&(b=a.parentNode.offsetWidth),a.style.width=b+"px",h(a.getElementsByTagName("iframe")[0],"getHeight")})},i=f(document.cookie)["preview-width"];if(i){e(i),g(b.getElementsByClassName("is-active"),"is-active");var k=b.querySelector('button[data-width="'+i+'"]');k&&k.classList.add("is-active")}window.addEventListener("message",function(a){if(a.data==null||!a.source)return;var b=a.data,c=document.getElementsByName(a.source.name)[0];b.height!=null&&c&&(c.parentNode.style.height=b.height+d+"px")},!1),b&&c.length>0&&(b.hidden=!1,b.addEventListener("click",function(a){var c=a.target.tagName.toLowerCase(),d;if(c==="button")d=a.target;else{if(c!=="svg")return;d=a.target.parentNode}a.preventDefault(),g(b.getElementsByClassName("is-active"),"is-active"),d.classList.add("is-active");var f=d.dataset.width;e(f)}))}}()})()</script></body></html><!-- Generated with StyleDocco (http://jacobrask.github.com/styledocco). --> diff --git a/lib/web/css/docs/lib.html b/lib/web/css/docs/lib.html index ccd5873e94303..001e8aeecd308 100644 --- a/lib/web/css/docs/lib.html +++ b/lib/web/css/docs/lib.html @@ -10,4 +10,4 @@ <p> The _lib.less file contains the includes of all Magento UI library files. To use Magento UI library in your theme add the following directive to the theme’s styles.less:</p> <pre><code class="lang-css"> @import 'source/lib/_lib';</code></pre> <p> The lib.less file is designed to avoid manual adding of each Magento UI library file import instruction to your theme.</p> -</div></article></section><div class="bar bottom"><div hidden class="settings container"><!-- Icons from http://iconmonstr.com--><button title="Desktop (1280)" data-width='1280'><svg viewBox="0 0 412 386" height="24" width="26" class="icon"><path d="m147.6,343.9c-4.5,15.9-26.2,37.6-42.1,42.1h201c-15.3,-4-38.1,-26.8-42.1,-42.1H147.6zM387,0.5H25c-13.8,0-25,11.2-25,25V294c0,13.8 11.2,25 25,25h362c13.8,0 25,-11.2 25,-25V25.5C412,11.7 400.8,0.5 387,0.5zM369.9,238.2H42.1L42.1,42.6 369.9,42.6V238.2z"></path></svg></button><button title="Laptop (1024)" data-width='1024'><svg viewBox="0 0 384 312" height="23" width="28" class="icon"><path d="m349.2,20.5c0,-11-9,-20-20,-20H53.6c-11,0-20,9-20,20v194H349.2v-194zm-27,167H60.6V27.5H322.2v160zm28,42H32.6L2.6,282.1c-3.5,6.2-3.5,13.8 0.1,19.9 3.6,6.2 10.2,9.9 17.3,9.9H363.1c7.1,0 13.7,-3.8 17.3,-10 3.6,-6.2 3.6,-13.8 0,-20l-30.2,-52.5zm-196.9,54 8,-23.5h60.5l8,23.5h-76.5z"></path></svg></button><button title="Tablet (768)" data-width='768'><svg viewBox="0 0 317 412" height="24" width="18" class="icon"><path d="M 316.5,380 V 32 c 0,-17.7 -14.3,-32 -32,-32 H 32 C 14.3,0 0,14.3 0,32 v 348 c 0,17.7 14.3,32 32,32 h 252.5 c 17.7,0 32,-14.3 32,-32 z M 40,367 V 45 H 276.5 V 367 H 40 z m 109.8,22.7 c 0,-4.7 3.8,-8.5 8.5,-8.5 4.7,0 8.5,3.8 8.5,8.5 0,4.7 -3.8,8.5 -8.5,8.5 -4.7,0 -8.5,-3.8 -8.5,-8.5 z"></path></svg></button><button title="Smart phone (320)" data-width='320'><svg viewBox="0 0 224 412" height="24" width="13" class="icon"><path d="M 190.7,0 H 33 C 14.8,0 0,14.8 0,33 v 346 c 0,18.2 14.8,33 33,33 h 157.7 c 18.2,0 33,-14.8 33,-33 V 33 c 0,-18.2 -14.8,-33 -33,-33 z M 94.3,30.2 h 37 c 2.2,0 4,1.8 4,4 0,2.2 -1.8,4 -4,4 h -37 c -2.2,0 -4,-1.8 -4,-4 0,-2.2 1.8,-4 4,-4 z m 18.5,362.8 c -8.8,0 -16,-7.2 -16,-16 0,-8.8 7.2,-16 16,-16 8.8,0 16,7.2 16,16 0,8.8 -7.2,16 -16,16 z M 198.6,343.8 H 25.1 V 68.2 h 173.5 v 275.5 z"></path></svg></button><button title="Feature phone (240)" data-width='240'><svg viewBox="0 0 201 412" height="24" width="12" class="icon"><path d="M 165.5,0.2 V 45 H 25 c -13.8,0 -25,11.2 -25,25 V 387 c 0,13.8 11.2,25 25,25 h 150.5 c 13.8,0 25,-11.2 25,-25 V 0.2 h -35 z M 65.2,366.5 H 34.2 v -24.5 h 31 v 24.5 z m 0,-44.3 H 34.2 v -24.5 h 31 v 24.5 z m 50.5,44.3 H 84.7 v -24.5 h 31 v 24.5 z m 0,-44.3 H 84.7 v -24.5 h 31 v 24.5 z m 50.5,44.3 h -31 v -24.5 h 31 v 24.5 z m 0,-44.3 h -31 v -24.5 h 31 v 24.5 z m 0,-59.3 h -132 V 95.4 h 132 V 262.9 z"></path></svg></button><button title="Auto (100%)" data-width="auto" class="auto is-active">Auto</button></div></div><script>(function(){var a=[{title:"actions-toolbar",filename:"actions-toolbar",url:"actions-toolbar.html"},{title:"Actions toolbar",filename:"actions-toolbar",url:"actions-toolbar.html#actions-toolbar"},{title:"Actions toolbar mixin variables",filename:"actions-toolbar",url:"actions-toolbar.html#actions-toolbar-mixin-variables"},{title:"Actions toolbar alignment",filename:"actions-toolbar",url:"actions-toolbar.html#actions-toolbar-alignment"},{title:"Reverse primary and secondary blocks",filename:"actions-toolbar",url:"actions-toolbar.html#reverse-primary-and-secondary-blocks"},{title:"Actions toolbar indents customizations",filename:"actions-toolbar",url:"actions-toolbar.html#actions-toolbar-indents-customizations"},{title:"Responsive actions toolbar",filename:"actions-toolbar",url:"actions-toolbar.html#responsive-actions-toolbar"},{title:"breadcrumbs",filename:"breadcrumbs",url:"breadcrumbs.html"},{title:"Breadcrumbs",filename:"breadcrumbs",url:"breadcrumbs.html#breadcrumbs"},{title:"Breadcrumbs variables",filename:"breadcrumbs",url:"breadcrumbs.html#breadcrumbs-variables"},{title:"Button-styled breadcrumbs with gradient background, border, and no separating symbol",filename:"breadcrumbs",url:"breadcrumbs.html#buttonstyled-breadcrumbs-with-gradient-background-border-and-no-separating-symbol"},{title:"Breadcrumbs with solid background",filename:"breadcrumbs",url:"breadcrumbs.html#breadcrumbs-with-solid-background"},{title:"buttons",filename:"buttons",url:"buttons.html"},{title:"Default button",filename:"buttons",url:"buttons.html#default-button"},{title:"Button variables",filename:"buttons",url:"buttons.html#button-variables"},{title:"Button as an icon",filename:"buttons",url:"buttons.html#button-as-an-icon"},{title:"Button with an icon on the left or right side of the text",filename:"buttons",url:"buttons.html#button-with-an-icon-on-the-left-or-right-side-of-the-text"},{title:"Button with fixed width",filename:"buttons",url:"buttons.html#button-with-fixed-width"},{title:"Primary button",filename:"buttons",url:"buttons.html#primary-button"},{title:"Primary button variables",filename:"buttons",url:"buttons.html#primary-button-variables"},{title:"Button with gradient background",filename:"buttons",url:"buttons.html#button-with-gradient-background"},{title:"Button as a link",filename:"buttons",url:"buttons.html#button-as-a-link"},{title:"Button as a link variables",filename:"buttons",url:"buttons.html#button-as-a-link-variables"},{title:"Link as a button",filename:"buttons",url:"buttons.html#link-as-a-button"},{title:"Button reset",filename:"buttons",url:"buttons.html#button-reset"},{title:"Button revert secondary color",filename:"buttons",url:"buttons.html#button-revert-secondary-color"},{title:"Button revert secondary color variables",filename:"buttons",url:"buttons.html#button-revert-secondary-color-variables"},{title:"Button revert secondary size",filename:"buttons",url:"buttons.html#button-revert-secondary-size"},{title:"Button revert secondary size variables",filename:"buttons",url:"buttons.html#button-revert-secondary-size-variables"},{title:"components",filename:"components",url:"components.html"},{title:"Components",filename:"components",url:"components.html#components"},{title:"Components Variables",filename:"components",url:"components.html#components-variables"},{title:"dropdowns",filename:"dropdowns",url:"dropdowns.html"},{title:"Drop-down and split buttons mixins",filename:"dropdowns",url:"dropdowns.html#dropdown-and-split-buttons-mixins"},{title:"Drop-down",filename:"dropdowns",url:"dropdowns.html#dropdown"},{title:"Drop-down variables",filename:"dropdowns",url:"dropdowns.html#dropdown-variables"},{title:"Drop-down with icon customization",filename:"dropdowns",url:"dropdowns.html#dropdown-with-icon-customization"},{title:"Modify dropdown list styles",filename:"dropdowns",url:"dropdowns.html#modify-dropdown-list-styles"},{title:"Split button",filename:"dropdowns",url:"dropdowns.html#split-button"},{title:"Split button variables",filename:"dropdowns",url:"dropdowns.html#split-button-variables"},{title:"Split button - button styling",filename:"dropdowns",url:"dropdowns.html#split-button-button-styling"},{title:"Split button icon customization",filename:"dropdowns",url:"dropdowns.html#split-button-icon-customization"},{title:"Split button drop-down list customization",filename:"dropdowns",url:"dropdowns.html#split-button-dropdown-list-customization"},{title:"forms",filename:"forms",url:"forms.html"},{title:"Forms mixins",filename:"forms",url:"forms.html#forms-mixins"},{title:"Global forms elements customization",filename:"forms",url:"forms.html#global-forms-elements-customization"},{title:"Fieldsets & fields customization",filename:"forms",url:"forms.html#fieldsets-fields-customization"},{title:"Fieldset and legend customization variables",filename:"forms",url:"forms.html#fieldset-and-legend-customization-variables"},{title:"Fields customization variables",filename:"forms",url:"forms.html#fields-customization-variables"},{title:"Required fields message customization variables",filename:"forms",url:"forms.html#required-fields-message-customization-variables"},{title:"Form element inputs customization",filename:"forms",url:"forms.html#form-element-inputs-customization"},{title:"Form element inputs customization variables",filename:"forms",url:"forms.html#form-element-inputs-customization-variables"},{title:"Form element choice",filename:"forms",url:"forms.html#form-element-choice"},{title:"Form element choice variables",filename:"forms",url:"forms.html#form-element-choice-variables"},{title:"Custom color",filename:"forms",url:"forms.html#custom-color"},{title:"Input number - input-text view",filename:"forms",url:"forms.html#input-number-inputtext-view"},{title:"Input search - input-text view",filename:"forms",url:"forms.html#input-search-inputtext-view"},{title:"Form validation",filename:"forms",url:"forms.html#form-validation"},{title:"Form validation variables",filename:"forms",url:"forms.html#form-validation-variables"},{title:"icons",filename:"icons",url:"icons.html"},{title:"Icons",filename:"icons",url:"icons.html#icons"},{title:"Icon with image or sprite",filename:"icons",url:"icons.html#icon-with-image-or-sprite"},{title:"Icon with image or sprite variables",filename:"icons",url:"icons.html#icon-with-image-or-sprite-variables"},{title:"Icon position for an icon with image or sprite",filename:"icons",url:"icons.html#icon-position-for-an-icon-with-image-or-sprite"},{title:"Position for icon with image or sprite mixin variables",filename:"icons",url:"icons.html#position-for-icon-with-image-or-sprite-mixin-variables"},{title:"Icon sprite position (with grid)",filename:"icons",url:"icons.html#icon-sprite-position-with-grid"},{title:"Icon sprite position variables",filename:"icons",url:"icons.html#icon-sprite-position-variables"},{title:"Image/sprite icon size",filename:"icons",url:"icons.html#imagesprite-icon-size"},{title:"Image/sprite icon size variables",filename:"icons",url:"icons.html#imagesprite-icon-size-variables"},{title:"Font icon",filename:"icons",url:"icons.html#font-icon"},{title:"Font icon variables",filename:"icons",url:"icons.html#font-icon-variables"},{title:"Change the size of font icon",filename:"icons",url:"icons.html#change-the-size-of-font-icon"},{title:"Change the size of font icon variables",filename:"icons",url:"icons.html#change-the-size-of-font-icon-variables"},{title:"Hide icon text",filename:"icons",url:"icons.html#hide-icon-text"},{title:"Sprite and font icons for Blank theme",filename:"icons",url:"icons.html#sprite-and-font-icons-for-blank-theme"},{title:"layout",filename:"layout",url:"layout.html"},{title:"Layout",filename:"layout",url:"layout.html#layout"},{title:"Layout global variables",filename:"layout",url:"layout.html#layout-global-variables"},{title:"Page layouts",filename:"layout",url:"layout.html#page-layouts"},{title:"Layout column",filename:"layout",url:"layout.html#layout-column"},{title:"Layout column variables",filename:"layout",url:"layout.html#layout-column-variables"},{title:"Layout width",filename:"layout",url:"layout.html#layout-width"},{title:"Layout width variables",filename:"layout",url:"layout.html#layout-width-variables"},{title:"lib",filename:"lib",url:"lib.html"},{title:"Including Magento UI library to your theme",filename:"lib",url:"lib.html#including-magento-ui-library-to-your-theme"},{title:"loaders",filename:"loaders",url:"loaders.html"},{title:"Loaders",filename:"loaders",url:"loaders.html#loaders"},{title:"Default loader variables",filename:"loaders",url:"loaders.html#default-loader-variables"},{title:"Loading",filename:"loaders",url:"loaders.html#loading"},{title:"Loading default variables",filename:"loaders",url:"loaders.html#loading-default-variables"},{title:"messages",filename:"messages",url:"messages.html"},{title:"Messages",filename:"messages",url:"messages.html#messages"},{title:"Information message",filename:"messages",url:"messages.html#information-message"},{title:"Warning message",filename:"messages",url:"messages.html#warning-message"},{title:"Error message",filename:"messages",url:"messages.html#error-message"},{title:"Success message",filename:"messages",url:"messages.html#success-message"},{title:"Notice message",filename:"messages",url:"messages.html#notice-message"},{title:"Message with inner icon",filename:"messages",url:"messages.html#message-with-inner-icon"},{title:"Message with lateral icon",filename:"messages",url:"messages.html#message-with-lateral-icon"},{title:"Custom message style",filename:"messages",url:"messages.html#custom-message-style"},{title:"Messages global variables",filename:"messages",url:"messages.html#messages-global-variables"},{title:"pages",filename:"pages",url:"pages.html"},{title:"Pagination HTML markup",filename:"pages",url:"pages.html#pagination-html-markup"},{title:"Pagination variables",filename:"pages",url:"pages.html#pagination-variables"},{title:"Pagination with label and gradient background on links",filename:"pages",url:"pages.html#pagination-with-label-and-gradient-background-on-links"},{title:'Pagination with "previous"..."next" text links and label',filename:"pages",url:"pages.html#pagination-with-previousnext-text-links-and-label"},{title:"Pagination without label, with solid background",filename:"pages",url:"pages.html#pagination-without-label-with-solid-background"},{title:"popups",filename:"popups",url:"popups.html"},{title:"Popups",filename:"popups",url:"popups.html#popups"},{title:"Popup variables",filename:"popups",url:"popups.html#popup-variables"},{title:"Window overlay mixin variables",filename:"popups",url:"popups.html#window-overlay-mixin-variables"},{title:"Fixed height popup",filename:"popups",url:"popups.html#fixed-height-popup"},{title:"Fixed content height popup",filename:"popups",url:"popups.html#fixed-content-height-popup"},{title:"Margins for header, content and footer block in popup",filename:"popups",url:"popups.html#margins-for-header-content-and-footer-block-in-popup"},{title:"Popup titles styled as theme headings",filename:"popups",url:"popups.html#popup-titles-styled-as-theme-headings"},{title:"Popup action toolbar",filename:"popups",url:"popups.html#popup-action-toolbar"},{title:"Popup Close button without an icon",filename:"popups",url:"popups.html#popup-close-button-without-an-icon"},{title:"Modify the icon of popup Close button",filename:"popups",url:"popups.html#modify-the-icon-of-popup-close-button"},{title:"Modify overlay styles",filename:"popups",url:"popups.html#modify-overlay-styles"},{title:"rating",filename:"rating",url:"rating.html"},{title:"Ratings",filename:"rating",url:"rating.html#ratings"},{title:"Global rating variables",filename:"rating",url:"rating.html#global-rating-variables"},{title:"Rating with vote",filename:"rating",url:"rating.html#rating-with-vote"},{title:"Rating with vote icons number customization",filename:"rating",url:"rating.html#rating-with-vote-icons-number-customization"},{title:"Rating with vote icons colors customization",filename:"rating",url:"rating.html#rating-with-vote-icons-colors-customization"},{title:"Rating with vote icons symbol customization",filename:"rating",url:"rating.html#rating-with-vote-icons-symbol-customization"},{title:"Accessible rating with vote",filename:"rating",url:"rating.html#accessible-rating-with-vote"},{title:"Rating summary",filename:"rating",url:"rating.html#rating-summary"},{title:"Rating summary icons number customization",filename:"rating",url:"rating.html#rating-summary-icons-number-customization"},{title:"Rating summary icons color customization",filename:"rating",url:"rating.html#rating-summary-icons-color-customization"},{title:"Rating summary icons symbol customization",filename:"rating",url:"rating.html#rating-summary-icons-symbol-customization"},{title:"Rating summary hide label",filename:"rating",url:"rating.html#rating-summary-hide-label"},{title:"Rating summary multiple ratings",filename:"rating",url:"rating.html#rating-summary-multiple-ratings"},{title:"Rating hide label mixin",filename:"rating",url:"rating.html#rating-hide-label-mixin"},{title:"resets",filename:"resets",url:"resets.html"},{title:"Resets",filename:"resets",url:"resets.html#resets"},{title:"responsive",filename:"responsive",url:"responsive.html"},{title:"Responsive",filename:"responsive",url:"responsive.html#responsive"},{title:"Responsive mixins usage",filename:"responsive",url:"responsive.html#responsive-mixins-usage"},{title:"Media query style groups separation variables",filename:"responsive",url:"responsive.html#media-query-style-groups-separation-variables"},{title:"Responsive breakpoints",filename:"responsive",url:"responsive.html#responsive-breakpoints"},{title:"sections",filename:"sections",url:"sections.html"},{title:"Tabs and accordions",filename:"sections",url:"sections.html#tabs-and-accordions"},{title:"Tabs",filename:"sections",url:"sections.html#tabs"},{title:"Tabs mixin variables",filename:"sections",url:"sections.html#tabs-mixin-variables"},{title:"Tabs with content top border",filename:"sections",url:"sections.html#tabs-with-content-top-border"},{title:"Accordion",filename:"sections",url:"sections.html#accordion"},{title:"Accordion mixin variables",filename:"sections",url:"sections.html#accordion-mixin-variables"},{title:"Responsive tabs",filename:"sections",url:"sections.html#responsive-tabs"},{title:"Tabs Base",filename:"sections",url:"sections.html#tabs-base"},{title:"Accordion Base",filename:"sections",url:"sections.html#accordion-base"},{title:"tables",filename:"tables",url:"tables.html"},{title:"Tables",filename:"tables",url:"tables.html#tables"},{title:"Table mixin variables",filename:"tables",url:"tables.html#table-mixin-variables"},{title:"Table typography",filename:"tables",url:"tables.html#table-typography"},{title:"Table typography mixin variables",filename:"tables",url:"tables.html#table-typography-mixin-variables"},{title:"Table caption",filename:"tables",url:"tables.html#table-caption"},{title:"Table caption mixin variables",filename:"tables",url:"tables.html#table-caption-mixin-variables"},{title:"Table cells resize",filename:"tables",url:"tables.html#table-cells-resize"},{title:"Table cells resize variables",filename:"tables",url:"tables.html#table-cells-resize-variables"},{title:"Table background customization",filename:"tables",url:"tables.html#table-background-customization"},{title:"Table background mixin variables",filename:"tables",url:"tables.html#table-background-mixin-variables"},{title:"Table borders customization",filename:"tables",url:"tables.html#table-borders-customization"},{title:"Table borders mixin variables",filename:"tables",url:"tables.html#table-borders-mixin-variables"},{title:"Table with horizontal borders",filename:"tables",url:"tables.html#table-with-horizontal-borders"},{title:"Table with vertical borders",filename:"tables",url:"tables.html#table-with-vertical-borders"},{title:"Table with light borders",filename:"tables",url:"tables.html#table-with-light-borders"},{title:"Table without borders",filename:"tables",url:"tables.html#table-without-borders"},{title:"Striped table",filename:"tables",url:"tables.html#striped-table"},{title:"Striped table mixin variables",filename:"tables",url:"tables.html#striped-table-mixin-variables"},{title:"Table with rows hover",filename:"tables",url:"tables.html#table-with-rows-hover"},{title:"Table with rows hover mixin variables",filename:"tables",url:"tables.html#table-with-rows-hover-mixin-variables"},{title:"Responsive table technics #1",filename:"tables",url:"tables.html#responsive-table-technics-1"},{title:"Responsive table technics #2",filename:"tables",url:"tables.html#responsive-table-technics-2"},{title:"Responsive table technics #2 mixin variables",filename:"tables",url:"tables.html#responsive-table-technics-2-mixin-variables"},{title:"tooltips",filename:"tooltips",url:"tooltips.html"},{title:"Tooltips",filename:"tooltips",url:"tooltips.html#tooltips"},{title:"Tooltips variables",filename:"tooltips",url:"tooltips.html#tooltips-variables"},{title:"typography",filename:"typography",url:"typography.html"},{title:"Typogrphy",filename:"typography",url:"typography.html#typogrphy"},{title:"Typography variables",filename:"typography",url:"typography.html#typography-variables"},{title:"Font-size mixin",filename:"typography",url:"typography.html#fontsize-mixin"},{title:"Line-height mixin",filename:"typography",url:"typography.html#lineheight-mixin"},{title:"Word breaking mixin",filename:"typography",url:"typography.html#word-breaking-mixin"},{title:"Font face mixin",filename:"typography",url:"typography.html#font-face-mixin"},{title:"Text overflow mixin",filename:"typography",url:"typography.html#text-overflow-mixin"},{title:"Text hide",filename:"typography",url:"typography.html#text-hide"},{title:"Hyphens",filename:"typography",url:"typography.html#hyphens"},{title:"Font style and color",filename:"typography",url:"typography.html#font-style-and-color"},{title:"Font style mixin variables",filename:"typography",url:"typography.html#font-style-mixin-variables"},{title:"Reset list styles",filename:"typography",url:"typography.html#reset-list-styles"},{title:"Reset list styles variables",filename:"typography",url:"typography.html#reset-list-styles-variables"},{title:"Inline-block list item styling",filename:"typography",url:"typography.html#inlineblock-list-item-styling"},{title:"Link styling mixin",filename:"typography",url:"typography.html#link-styling-mixin"},{title:"Link styling mixin variables",filename:"typography",url:"typography.html#link-styling-mixin-variables"},{title:"Heading styling mixin",filename:"typography",url:"typography.html#heading-styling-mixin"},{title:"Base typography mixins",filename:"typography",url:"typography.html#base-typography-mixins"},{title:"Base typography mixin variables",filename:"typography",url:"typography.html#base-typography-mixin-variables"},{title:"Headings typography mixin",filename:"typography",url:"typography.html#headings-typography-mixin"},{title:"Headings typography mixin variables",filename:"typography",url:"typography.html#headings-typography-mixin-variables"},{title:"Typography links mixin",filename:"typography",url:"typography.html#typography-links-mixin"},{title:"Typography lists mixin",filename:"typography",url:"typography.html#typography-lists-mixin"},{title:"Typography lists mixin variables",filename:"typography",url:"typography.html#typography-lists-mixin-variables"},{title:"Typography code elements mixin",filename:"typography",url:"typography.html#typography-code-elements-mixin"},{title:"Typography code mixin variables",filename:"typography",url:"typography.html#typography-code-mixin-variables"},{title:"Typography blockquote",filename:"typography",url:"typography.html#typography-blockquote"},{title:"Typography blockquote mixin variables",filename:"typography",url:"typography.html#typography-blockquote-mixin-variables"},{title:"utilities",filename:"utilities",url:"utilities.html"},{title:"Utilities",filename:"utilities",url:"utilities.html#utilities"},{title:".lib-clearfix()",filename:"utilities",url:"utilities.html#libclearfix"},{title:".lib-visibility-hidden()",filename:"utilities",url:"utilities.html#libvisibilityhidden"},{title:".lib-visually-hidden()",filename:"utilities",url:"utilities.html#libvisuallyhidden"},{title:".lib-visually-hidden-reset()",filename:"utilities",url:"utilities.html#libvisuallyhiddenreset"},{title:".lib-css()",filename:"utilities",url:"utilities.html#libcss"},{title:".lib-css() variables",filename:"utilities",url:"utilities.html#libcss-variables"},{title:".lib-rotate()",filename:"utilities",url:"utilities.html#librotate"},{title:".lib-rotate() variables",filename:"utilities",url:"utilities.html#librotate-variables"},{title:".lib-input-placeholder()",filename:"utilities",url:"utilities.html#libinputplaceholder"},{title:".lib-input-placeholder() variables",filename:"utilities",url:"utilities.html#libinputplaceholder-variables"},{title:".lib-background-gradient()",filename:"utilities",url:"utilities.html#libbackgroundgradient"},{title:".lib-background-gradient() variables",filename:"utilities",url:"utilities.html#libbackgroundgradient-variables"},{title:".lib-url-check()",filename:"utilities",url:"utilities.html#liburlcheck"},{title:".lib-url-check() variables",filename:"utilities",url:"utilities.html#liburlcheck-variables"},{title:"variables",filename:"variables",url:"variables.html"},{title:"List of Global Variables",filename:"variables",url:"variables.html#list-of-global-variables"},{title:"Table with rows hover mixin variables",filename:"variables",url:"variables.html#table-with-rows-hover-mixin-variables"},{title:"docs",filename:"docs",url:"docs.html"},{title:"Documentation",filename:"docs",url:"docs.html#documentation"}];(function(){"use strict";var b=function(a,b){return Array.prototype.indexOf.call(a,b)!==-1},c=function(a,b){return Array.prototype.filter.call(a,b)},d=function(a,b){return Array.prototype.forEach.call(a,b)},e=document.getElementsByTagName("body")[0];e.addEventListener("click",function(a){var b=a.target;b.tagName.toLowerCase()==="svg"&&(b=b.parentNode);var c=!1;b.dataset.toggle!=null&&(a.preventDefault(),b.classList.contains("is-active")||(c=!0)),d(e.querySelectorAll("[data-toggle]"),function(a){a.classList.remove("is-active"),document.getElementById(a.dataset.toggle).hidden=!0}),c&&(b.classList.add("is-active"),document.getElementById(b.dataset.toggle).hidden=!1)}),function(){var f=e.getElementsByClassName("nav")[0];if(!f)return;var g=document.createElement("ul");g.className="nav-results",g.id="nav-search",g.hidden=!0,d(a,function(a){var b,c,d;b=document.createElement("li"),b._title=a.title.toLowerCase(),b.hidden=!0,b.appendChild(c=document.createElement("a")),c.href=a.url,c.innerHTML=a.title,c.appendChild(d=document.createElement("span")),d.innerHTML=a.filename,d.className="nav-results-filename",g.appendChild(b)}),f.appendChild(g);var h=g.children,i=function(a){d(h,function(a){a.hidden=!0});var b=this.value.toLowerCase(),e=[];b!==""&&(e=c(h,function(a){return a._title.indexOf(b)!==-1})),e.length>0?(d(e,function(a){a.hidden=!1}),g.hidden=!1):g.hidden=!0},j=f.querySelector('input[type="search"]');j.addEventListener("keyup",i),j.addEventListener("focus",i),e.addEventListener("click",function(a){if(a.target.classList&&a.target.classList.contains("search"))return;g.hidden=!0}),g.addEventListener("click",function(a){j.value=""});var k=document.createElement("ul");k.id="nav-toc",k.hidden=!0,k.className="nav-results toc-list",c(e.getElementsByTagName("*"),function(a){return b(["h1","h2","h3"],a.tagName.toLowerCase())}).map(function(a){var b=document.createElement("li"),c=document.createElement("a"),d=a.tagName.toLowerCase()[1];c.classList.add("level-"+d),b.appendChild(c),c.href="#"+a.id,c.innerHTML=a.innerHTML,k.appendChild(b)}),f.appendChild(k)}()})(),function(){"use strict";if(location.hash==="#__preview__"||location.protocol==="data:")return;var a=function(a,b){return Array.prototype.forEach.call(a,b)},b=function(a,b){var e=Array.prototype.slice.call(arguments,2);return d(a,function(a){return(c(b)?b||a:a[b]).apply(a,e)})},c=function(a){return Object.prototype.toString.call(a)==="[object Function]"},d=function(a,b){return Array.prototype.map.call(a,b)},e=function(a,b){return d(a,function(a){return a[b]})},f=function(a){var b={},c=a.split(";");for(var d=0;c.length>d;d++){var e=c[d].trim().split("=");b[e[0]]=e[1]}return b},g=function(a,c){return b(e(a,"classList"),"remove",c)},h=function(a,b){a.contentDocument.defaultView.postMessage(b,"*")},i=document.getElementsByTagName("head")[0],j=document.getElementsByTagName("body")[0],k=e(i.querySelectorAll('style[type="text/preview"]'),"innerHTML").join(""),l=e(i.querySelectorAll('script[type="text/preview"]'),"innerHTML").join(""),m=location.href.split("#")[0]+"#__preview__",n=document.createElement("iframe");n.src="data:text/html,",j.appendChild(n),n.addEventListener("load",function(){var b={sameOriginDataUri:!0};try{this.contentDocument,this.contentDocument||(b.sameOriginDataUri=!1)}catch(c){b.sameOriginDataUri=!1}this.parentNode.removeChild(this),a(j.getElementsByTagName("textarea"),function(a,c){o(a,b,c),q(),p(a)})});var o=function(a,b,c){var d,e,f;d=document.createElement("div"),d.appendChild(e=document.createElement("div")),d.className="preview",e.appendChild(f=document.createElement("iframe")),e.className="resizeable",f.setAttribute("scrolling","no"),f.name="iframe"+c++,f.addEventListener("load",function(){var c,d,e,f,g,i,j;j=this.contentDocument;if(!b.sameOriginDataUri&&this.src!==m)return;this.src===m&&(c=j.createElement("html"),c.appendChild(j.createElement("head")),c.appendChild(d=j.createElement("body")),d.innerHTML=a.textContent,j.replaceChild(c,j.documentElement)),g=j.createElement("head"),g.appendChild(f=j.createElement("style")),g.appendChild(e=j.createElement("script")),e.textContent=l,f.textContent=k,i=j.getElementsByTagName("head")[0],i.parentNode.replaceChild(g,i),h(this,"getHeight")});var g;b.sameOriginDataUri?g="data:text/html;charset=utf-8,"+encodeURIComponent("<!doctype html><html><head></head></body>"+a.textContent):g=m,f.setAttribute("src",g);var i=function(){f.contentDocument.body.innerHTML=this.value,h(f,"getHeight")};a.addEventListener("keypress",i),a.addEventListener("keyup",i),a.parentNode.insertBefore(d,a)},p=function(a){var b=document.createElement("div");b.className="preview-code",b.style.position="absolute",b.style.left="-9999px",j.appendChild(b);var c=parseInt(window.getComputedStyle(a).getPropertyValue("max-height"),10),d=function(a){b.textContent=this.value+"\n";var d=b.offsetHeight+2;d>=c?this.style.overflow="auto":this.style.overflow="hidden",this.style.height=b.offsetHeight+2+"px"};a.addEventListener("keypress",d),a.addEventListener("keyup",d),d.call(a)},q=function(){var b=j.getElementsByClassName("settings")[0],c=j.getElementsByClassName("resizeable"),d=30,e=function(b){document.cookie="preview-width="+b,a(c,function(a){b==="auto"&&(b=a.parentNode.offsetWidth),a.style.width=b+"px",h(a.getElementsByTagName("iframe")[0],"getHeight")})},i=f(document.cookie)["preview-width"];if(i){e(i),g(b.getElementsByClassName("is-active"),"is-active");var k=b.querySelector('button[data-width="'+i+'"]');k&&k.classList.add("is-active")}window.addEventListener("message",function(a){if(a.data==null||!a.source)return;var b=a.data,c=document.getElementsByName(a.source.name)[0];b.height!=null&&c&&(c.parentNode.style.height=b.height+d+"px")},!1),b&&c.length>0&&(b.hidden=!1,b.addEventListener("click",function(a){var c=a.target.tagName.toLowerCase(),d;if(c==="button")d=a.target;else{if(c!=="svg")return;d=a.target.parentNode}a.preventDefault(),g(b.getElementsByClassName("is-active"),"is-active"),d.classList.add("is-active");var f=d.dataset.width;e(f)}))}}()})()</script></body></html><!-- Generated with StyleDocco (http://jacobrask.github.com/styledocco). --> +</div></article></section><div class="bar bottom"><div hidden class="settings container"><!-- Icons from http://iconmonstr.com--><button title="Desktop (1280)" data-width='1280'><svg viewBox="0 0 412 386" height="24" width="26" class="icon"><path d="m147.6,343.9c-4.5,15.9-26.2,37.6-42.1,42.1h201c-15.3,-4-38.1,-26.8-42.1,-42.1H147.6zM387,0.5H25c-13.8,0-25,11.2-25,25V294c0,13.8 11.2,25 25,25h362c13.8,0 25,-11.2 25,-25V25.5C412,11.7 400.8,0.5 387,0.5zM369.9,238.2H42.1L42.1,42.6 369.9,42.6V238.2z"></path></svg></button><button title="Laptop (1024)" data-width='1024'><svg viewBox="0 0 384 312" height="23" width="28" class="icon"><path d="m349.2,20.5c0,-11-9,-20-20,-20H53.6c-11,0-20,9-20,20v194H349.2v-194zm-27,167H60.6V27.5H322.2v160zm28,42H32.6L2.6,282.1c-3.5,6.2-3.5,13.8 0.1,19.9 3.6,6.2 10.2,9.9 17.3,9.9H363.1c7.1,0 13.7,-3.8 17.3,-10 3.6,-6.2 3.6,-13.8 0,-20l-30.2,-52.5zm-196.9,54 8,-23.5h60.5l8,23.5h-76.5z"></path></svg></button><button title="Tablet (768)" data-width='768'><svg viewBox="0 0 317 412" height="24" width="18" class="icon"><path d="M 316.5,380 V 32 c 0,-17.7 -14.3,-32 -32,-32 H 32 C 14.3,0 0,14.3 0,32 v 348 c 0,17.7 14.3,32 32,32 h 252.5 c 17.7,0 32,-14.3 32,-32 z M 40,367 V 45 H 276.5 V 367 H 40 z m 109.8,22.7 c 0,-4.7 3.8,-8.5 8.5,-8.5 4.7,0 8.5,3.8 8.5,8.5 0,4.7 -3.8,8.5 -8.5,8.5 -4.7,0 -8.5,-3.8 -8.5,-8.5 z"></path></svg></button><button title="Smart phone (320)" data-width='320'><svg viewBox="0 0 224 412" height="24" width="13" class="icon"><path d="M 190.7,0 H 33 C 14.8,0 0,14.8 0,33 v 346 c 0,18.2 14.8,33 33,33 h 157.7 c 18.2,0 33,-14.8 33,-33 V 33 c 0,-18.2 -14.8,-33 -33,-33 z M 94.3,30.2 h 37 c 2.2,0 4,1.8 4,4 0,2.2 -1.8,4 -4,4 h -37 c -2.2,0 -4,-1.8 -4,-4 0,-2.2 1.8,-4 4,-4 z m 18.5,362.8 c -8.8,0 -16,-7.2 -16,-16 0,-8.8 7.2,-16 16,-16 8.8,0 16,7.2 16,16 0,8.8 -7.2,16 -16,16 z M 198.6,343.8 H 25.1 V 68.2 h 173.5 v 275.5 z"></path></svg></button><button title="Feature phone (240)" data-width='240'><svg viewBox="0 0 201 412" height="24" width="12" class="icon"><path d="M 165.5,0.2 V 45 H 25 c -13.8,0 -25,11.2 -25,25 V 387 c 0,13.8 11.2,25 25,25 h 150.5 c 13.8,0 25,-11.2 25,-25 V 0.2 h -35 z M 65.2,366.5 H 34.2 v -24.5 h 31 v 24.5 z m 0,-44.3 H 34.2 v -24.5 h 31 v 24.5 z m 50.5,44.3 H 84.7 v -24.5 h 31 v 24.5 z m 0,-44.3 H 84.7 v -24.5 h 31 v 24.5 z m 50.5,44.3 h -31 v -24.5 h 31 v 24.5 z m 0,-44.3 h -31 v -24.5 h 31 v 24.5 z m 0,-59.3 h -132 V 95.4 h 132 V 262.9 z"></path></svg></button><button title="Auto (100%)" data-width="auto" class="auto is-active">Auto</button></div></div><script>(function(){var a=[{title:"actions-toolbar",filename:"actions-toolbar",url:"actions-toolbar.html"},{title:"Actions toolbar",filename:"actions-toolbar",url:"actions-toolbar.html#actions-toolbar"},{title:"Actions toolbar mixin variables",filename:"actions-toolbar",url:"actions-toolbar.html#actions-toolbar-mixin-variables"},{title:"Actions toolbar alignment",filename:"actions-toolbar",url:"actions-toolbar.html#actions-toolbar-alignment"},{title:"Reverse primary and secondary blocks",filename:"actions-toolbar",url:"actions-toolbar.html#reverse-primary-and-secondary-blocks"},{title:"Actions toolbar indents customizations",filename:"actions-toolbar",url:"actions-toolbar.html#actions-toolbar-indents-customizations"},{title:"Responsive actions toolbar",filename:"actions-toolbar",url:"actions-toolbar.html#responsive-actions-toolbar"},{title:"breadcrumbs",filename:"breadcrumbs",url:"breadcrumbs.html"},{title:"Breadcrumbs",filename:"breadcrumbs",url:"breadcrumbs.html#breadcrumbs"},{title:"Breadcrumbs variables",filename:"breadcrumbs",url:"breadcrumbs.html#breadcrumbs-variables"},{title:"Button-styled breadcrumbs with gradient background, border, and no separating symbol",filename:"breadcrumbs",url:"breadcrumbs.html#buttonstyled-breadcrumbs-with-gradient-background-border-and-no-separating-symbol"},{title:"Breadcrumbs with solid background",filename:"breadcrumbs",url:"breadcrumbs.html#breadcrumbs-with-solid-background"},{title:"buttons",filename:"buttons",url:"buttons.html"},{title:"Default button",filename:"buttons",url:"buttons.html#default-button"},{title:"Button variables",filename:"buttons",url:"buttons.html#button-variables"},{title:"Button as an icon",filename:"buttons",url:"buttons.html#button-as-an-icon"},{title:"Button with an icon on the left or right side of the text",filename:"buttons",url:"buttons.html#button-with-an-icon-on-the-left-or-right-side-of-the-text"},{title:"Button with fixed width",filename:"buttons",url:"buttons.html#button-with-fixed-width"},{title:"Primary button",filename:"buttons",url:"buttons.html#primary-button"},{title:"Primary button variables",filename:"buttons",url:"buttons.html#primary-button-variables"},{title:"Button with gradient background",filename:"buttons",url:"buttons.html#button-with-gradient-background"},{title:"Button as a link",filename:"buttons",url:"buttons.html#button-as-a-link"},{title:"Button as a link variables",filename:"buttons",url:"buttons.html#button-as-a-link-variables"},{title:"Link as a button",filename:"buttons",url:"buttons.html#link-as-a-button"},{title:"Button reset",filename:"buttons",url:"buttons.html#button-reset"},{title:"Button revert secondary color",filename:"buttons",url:"buttons.html#button-revert-secondary-color"},{title:"Button revert secondary color variables",filename:"buttons",url:"buttons.html#button-revert-secondary-color-variables"},{title:"Button revert secondary size",filename:"buttons",url:"buttons.html#button-revert-secondary-size"},{title:"Button revert secondary size variables",filename:"buttons",url:"buttons.html#button-revert-secondary-size-variables"},{title:"components",filename:"components",url:"components.html"},{title:"Components",filename:"components",url:"components.html#components"},{title:"Components Variables",filename:"components",url:"components.html#components-variables"},{title:"dropdowns",filename:"dropdowns",url:"dropdowns.html"},{title:"Drop-down and split buttons mixins",filename:"dropdowns",url:"dropdowns.html#dropdown-and-split-buttons-mixins"},{title:"Drop-down",filename:"dropdowns",url:"dropdowns.html#dropdown"},{title:"Drop-down variables",filename:"dropdowns",url:"dropdowns.html#dropdown-variables"},{title:"Drop-down with icon customization",filename:"dropdowns",url:"dropdowns.html#dropdown-with-icon-customization"},{title:"Modify dropdown list styles",filename:"dropdowns",url:"dropdowns.html#modify-dropdown-list-styles"},{title:"Split button",filename:"dropdowns",url:"dropdowns.html#split-button"},{title:"Split button variables",filename:"dropdowns",url:"dropdowns.html#split-button-variables"},{title:"Split button - button styling",filename:"dropdowns",url:"dropdowns.html#split-button-button-styling"},{title:"Split button icon customization",filename:"dropdowns",url:"dropdowns.html#split-button-icon-customization"},{title:"Split button drop-down list customization",filename:"dropdowns",url:"dropdowns.html#split-button-dropdown-list-customization"},{title:"forms",filename:"forms",url:"forms.html"},{title:"Forms mixins",filename:"forms",url:"forms.html#forms-mixins"},{title:"Global forms elements customization",filename:"forms",url:"forms.html#global-forms-elements-customization"},{title:"Fieldsets & fields customization",filename:"forms",url:"forms.html#fieldsets-fields-customization"},{title:"Fieldset and legend customization variables",filename:"forms",url:"forms.html#fieldset-and-legend-customization-variables"},{title:"Fields customization variables",filename:"forms",url:"forms.html#fields-customization-variables"},{title:"Required fields message customization variables",filename:"forms",url:"forms.html#required-fields-message-customization-variables"},{title:"Form element inputs customization",filename:"forms",url:"forms.html#form-element-inputs-customization"},{title:"Form element inputs customization variables",filename:"forms",url:"forms.html#form-element-inputs-customization-variables"},{title:"Form element choice",filename:"forms",url:"forms.html#form-element-choice"},{title:"Form element choice variables",filename:"forms",url:"forms.html#form-element-choice-variables"},{title:"Custom color",filename:"forms",url:"forms.html#custom-color"},{title:"Input number - input-text view",filename:"forms",url:"forms.html#input-number-inputtext-view"},{title:"Input search - input-text view",filename:"forms",url:"forms.html#input-search-inputtext-view"},{title:"Form validation",filename:"forms",url:"forms.html#form-validation"},{title:"Form validation variables",filename:"forms",url:"forms.html#form-validation-variables"},{title:"icons",filename:"icons",url:"icons.html"},{title:"Icons",filename:"icons",url:"icons.html#icons"},{title:"Icon with image or sprite",filename:"icons",url:"icons.html#icon-with-image-or-sprite"},{title:"Icon with image or sprite variables",filename:"icons",url:"icons.html#icon-with-image-or-sprite-variables"},{title:"Icon position for an icon with image or sprite",filename:"icons",url:"icons.html#icon-position-for-an-icon-with-image-or-sprite"},{title:"Position for icon with image or sprite mixin variables",filename:"icons",url:"icons.html#position-for-icon-with-image-or-sprite-mixin-variables"},{title:"Icon sprite position (with grid)",filename:"icons",url:"icons.html#icon-sprite-position-with-grid"},{title:"Icon sprite position variables",filename:"icons",url:"icons.html#icon-sprite-position-variables"},{title:"Image/sprite icon size",filename:"icons",url:"icons.html#imagesprite-icon-size"},{title:"Image/sprite icon size variables",filename:"icons",url:"icons.html#imagesprite-icon-size-variables"},{title:"Font icon",filename:"icons",url:"icons.html#font-icon"},{title:"Font icon variables",filename:"icons",url:"icons.html#font-icon-variables"},{title:"Change the size of font icon",filename:"icons",url:"icons.html#change-the-size-of-font-icon"},{title:"Change the size of font icon variables",filename:"icons",url:"icons.html#change-the-size-of-font-icon-variables"},{title:"Hide icon text",filename:"icons",url:"icons.html#hide-icon-text"},{title:"Sprite and font icons for Blank theme",filename:"icons",url:"icons.html#sprite-and-font-icons-for-blank-theme"},{title:"layout",filename:"layout",url:"layout.html"},{title:"Layout",filename:"layout",url:"layout.html#layout"},{title:"Layout global variables",filename:"layout",url:"layout.html#layout-global-variables"},{title:"Page layouts",filename:"layout",url:"layout.html#page-layouts"},{title:"Layout column",filename:"layout",url:"layout.html#layout-column"},{title:"Layout column variables",filename:"layout",url:"layout.html#layout-column-variables"},{title:"Layout width",filename:"layout",url:"layout.html#layout-width"},{title:"Layout width variables",filename:"layout",url:"layout.html#layout-width-variables"},{title:"lib",filename:"lib",url:"lib.html"},{title:"Including Magento UI library to your theme",filename:"lib",url:"lib.html#including-magento-ui-library-to-your-theme"},{title:"loaders",filename:"loaders",url:"loaders.html"},{title:"Loaders",filename:"loaders",url:"loaders.html#loaders"},{title:"Default loader variables",filename:"loaders",url:"loaders.html#default-loader-variables"},{title:"Loading",filename:"loaders",url:"loaders.html#loading"},{title:"Loading default variables",filename:"loaders",url:"loaders.html#loading-default-variables"},{title:"messages",filename:"messages",url:"messages.html"},{title:"Messages",filename:"messages",url:"messages.html#messages"},{title:"Information message",filename:"messages",url:"messages.html#information-message"},{title:"Warning message",filename:"messages",url:"messages.html#warning-message"},{title:"Error message",filename:"messages",url:"messages.html#error-message"},{title:"Success message",filename:"messages",url:"messages.html#success-message"},{title:"Notice message",filename:"messages",url:"messages.html#notice-message"},{title:"Message with inner icon",filename:"messages",url:"messages.html#message-with-inner-icon"},{title:"Message with lateral icon",filename:"messages",url:"messages.html#message-with-lateral-icon"},{title:"Custom message style",filename:"messages",url:"messages.html#custom-message-style"},{title:"Messages global variables",filename:"messages",url:"messages.html#messages-global-variables"},{title:"pages",filename:"pages",url:"pages.html"},{title:"Pagination HTML markup",filename:"pages",url:"pages.html#pagination-html-markup"},{title:"Pagination variables",filename:"pages",url:"pages.html#pagination-variables"},{title:"Pagination with label and gradient background on links",filename:"pages",url:"pages.html#pagination-with-label-and-gradient-background-on-links"},{title:'Pagination with "previous"..."next" text links and label',filename:"pages",url:"pages.html#pagination-with-previousnext-text-links-and-label"},{title:"Pagination without label, with solid background",filename:"pages",url:"pages.html#pagination-without-label-with-solid-background"},{title:"popups",filename:"popups",url:"popups.html"},{title:"Popups",filename:"popups",url:"popups.html#popups"},{title:"Popup variables",filename:"popups",url:"popups.html#popup-variables"},{title:"Window overlay mixin variables",filename:"popups",url:"popups.html#window-overlay-mixin-variables"},{title:"Fixed height popup",filename:"popups",url:"popups.html#fixed-height-popup"},{title:"Fixed content height popup",filename:"popups",url:"popups.html#fixed-content-height-popup"},{title:"Margins for header, content and footer block in popup",filename:"popups",url:"popups.html#margins-for-header-content-and-footer-block-in-popup"},{title:"Popup titles styled as theme headings",filename:"popups",url:"popups.html#popup-titles-styled-as-theme-headings"},{title:"Popup action toolbar",filename:"popups",url:"popups.html#popup-action-toolbar"},{title:"Popup Close button without an icon",filename:"popups",url:"popups.html#popup-close-button-without-an-icon"},{title:"Modify the icon of popup Close button",filename:"popups",url:"popups.html#modify-the-icon-of-popup-close-button"},{title:"Modify overlay styles",filename:"popups",url:"popups.html#modify-overlay-styles"},{title:"rating",filename:"rating",url:"rating.html"},{title:"Ratings",filename:"rating",url:"rating.html#ratings"},{title:"Global rating variables",filename:"rating",url:"rating.html#global-rating-variables"},{title:"Rating with vote",filename:"rating",url:"rating.html#rating-with-vote"},{title:"Rating with vote icons number customization",filename:"rating",url:"rating.html#rating-with-vote-icons-number-customization"},{title:"Rating with vote icons colors customization",filename:"rating",url:"rating.html#rating-with-vote-icons-colors-customization"},{title:"Rating with vote icons symbol customization",filename:"rating",url:"rating.html#rating-with-vote-icons-symbol-customization"},{title:"Accessible rating with vote",filename:"rating",url:"rating.html#accessible-rating-with-vote"},{title:"Rating summary",filename:"rating",url:"rating.html#rating-summary"},{title:"Rating summary icons number customization",filename:"rating",url:"rating.html#rating-summary-icons-number-customization"},{title:"Rating summary icons color customization",filename:"rating",url:"rating.html#rating-summary-icons-color-customization"},{title:"Rating summary icons symbol customization",filename:"rating",url:"rating.html#rating-summary-icons-symbol-customization"},{title:"Rating summary hide label",filename:"rating",url:"rating.html#rating-summary-hide-label"},{title:"Rating summary multiple ratings",filename:"rating",url:"rating.html#rating-summary-multiple-ratings"},{title:"Rating hide label mixin",filename:"rating",url:"rating.html#rating-hide-label-mixin"},{title:"resets",filename:"resets",url:"resets.html"},{title:"Resets",filename:"resets",url:"resets.html#resets"},{title:"responsive",filename:"responsive",url:"responsive.html"},{title:"Responsive",filename:"responsive",url:"responsive.html#responsive"},{title:"Responsive mixins usage",filename:"responsive",url:"responsive.html#responsive-mixins-usage"},{title:"Media query style groups separation variables",filename:"responsive",url:"responsive.html#media-query-style-groups-separation-variables"},{title:"Responsive breakpoints",filename:"responsive",url:"responsive.html#responsive-breakpoints"},{title:"sections",filename:"sections",url:"sections.html"},{title:"Tabs and accordions",filename:"sections",url:"sections.html#tabs-and-accordions"},{title:"Tabs",filename:"sections",url:"sections.html#tabs"},{title:"Tabs mixin variables",filename:"sections",url:"sections.html#tabs-mixin-variables"},{title:"Tabs with content top border",filename:"sections",url:"sections.html#tabs-with-content-top-border"},{title:"Accordion",filename:"sections",url:"sections.html#accordion"},{title:"Accordion mixin variables",filename:"sections",url:"sections.html#accordion-mixin-variables"},{title:"Responsive tabs",filename:"sections",url:"sections.html#responsive-tabs"},{title:"Tabs Base",filename:"sections",url:"sections.html#tabs-base"},{title:"Accordion Base",filename:"sections",url:"sections.html#accordion-base"},{title:"tables",filename:"tables",url:"tables.html"},{title:"Tables",filename:"tables",url:"tables.html#tables"},{title:"Table mixin variables",filename:"tables",url:"tables.html#table-mixin-variables"},{title:"Table typography",filename:"tables",url:"tables.html#table-typography"},{title:"Table typography mixin variables",filename:"tables",url:"tables.html#table-typography-mixin-variables"},{title:"Table caption",filename:"tables",url:"tables.html#table-caption"},{title:"Table caption mixin variables",filename:"tables",url:"tables.html#table-caption-mixin-variables"},{title:"Table cells resize",filename:"tables",url:"tables.html#table-cells-resize"},{title:"Table cells resize variables",filename:"tables",url:"tables.html#table-cells-resize-variables"},{title:"Table background customization",filename:"tables",url:"tables.html#table-background-customization"},{title:"Table background mixin variables",filename:"tables",url:"tables.html#table-background-mixin-variables"},{title:"Table borders customization",filename:"tables",url:"tables.html#table-borders-customization"},{title:"Table borders mixin variables",filename:"tables",url:"tables.html#table-borders-mixin-variables"},{title:"Table with horizontal borders",filename:"tables",url:"tables.html#table-with-horizontal-borders"},{title:"Table with vertical borders",filename:"tables",url:"tables.html#table-with-vertical-borders"},{title:"Table with light borders",filename:"tables",url:"tables.html#table-with-light-borders"},{title:"Table without borders",filename:"tables",url:"tables.html#table-without-borders"},{title:"Striped table",filename:"tables",url:"tables.html#striped-table"},{title:"Striped table mixin variables",filename:"tables",url:"tables.html#striped-table-mixin-variables"},{title:"Table with rows hover",filename:"tables",url:"tables.html#table-with-rows-hover"},{title:"Table with rows hover mixin variables",filename:"tables",url:"tables.html#table-with-rows-hover-mixin-variables"},{title:"Responsive table technics #1",filename:"tables",url:"tables.html#responsive-table-technics-1"},{title:"Responsive table technics #2",filename:"tables",url:"tables.html#responsive-table-technics-2"},{title:"Responsive table technics #2 mixin variables",filename:"tables",url:"tables.html#responsive-table-technics-2-mixin-variables"},{title:"tooltips",filename:"tooltips",url:"tooltips.html"},{title:"Tooltips",filename:"tooltips",url:"tooltips.html#tooltips"},{title:"Tooltips variables",filename:"tooltips",url:"tooltips.html#tooltips-variables"},{title:"typography",filename:"typography",url:"typography.html"},{title:"Typogrphy",filename:"typography",url:"typography.html#typogrphy"},{title:"Typography variables",filename:"typography",url:"typography.html#typography-variables"},{title:"Font-size mixin",filename:"typography",url:"typography.html#fontsize-mixin"},{title:"Line-height mixin",filename:"typography",url:"typography.html#lineheight-mixin"},{title:"Word breaking mixin",filename:"typography",url:"typography.html#word-breaking-mixin"},{title:"Font face mixin",filename:"typography",url:"typography.html#font-face-mixin"},{title:"Text overflow mixin",filename:"typography",url:"typography.html#text-overflow-mixin"},{title:"Text hide",filename:"typography",url:"typography.html#text-hide"},{title:"Hyphens",filename:"typography",url:"typography.html#hyphens"},{title:"Font style and color",filename:"typography",url:"typography.html#font-style-and-color"},{title:"Font style mixin variables",filename:"typography",url:"typography.html#font-style-mixin-variables"},{title:"Reset list styles",filename:"typography",url:"typography.html#reset-list-styles"},{title:"Reset list styles variables",filename:"typography",url:"typography.html#reset-list-styles-variables"},{title:"Inline-block list item styling",filename:"typography",url:"typography.html#inlineblock-list-item-styling"},{title:"Link styling mixin",filename:"typography",url:"typography.html#link-styling-mixin"},{title:"Link styling mixin variables",filename:"typography",url:"typography.html#link-styling-mixin-variables"},{title:"Heading styling mixin",filename:"typography",url:"typography.html#heading-styling-mixin"},{title:"Base typography mixins",filename:"typography",url:"typography.html#base-typography-mixins"},{title:"Base typography mixin variables",filename:"typography",url:"typography.html#base-typography-mixin-variables"},{title:"Headings typography mixin",filename:"typography",url:"typography.html#headings-typography-mixin"},{title:"Headings typography mixin variables",filename:"typography",url:"typography.html#headings-typography-mixin-variables"},{title:"Typography links mixin",filename:"typography",url:"typography.html#typography-links-mixin"},{title:"Typography lists mixin",filename:"typography",url:"typography.html#typography-lists-mixin"},{title:"Typography lists mixin variables",filename:"typography",url:"typography.html#typography-lists-mixin-variables"},{title:"Typography code elements mixin",filename:"typography",url:"typography.html#typography-code-elements-mixin"},{title:"Typography code mixin variables",filename:"typography",url:"typography.html#typography-code-mixin-variables"},{title:"Typography blockquote",filename:"typography",url:"typography.html#typography-blockquote"},{title:"Typography blockquote mixin variables",filename:"typography",url:"typography.html#typography-blockquote-mixin-variables"},{title:"utilities",filename:"utilities",url:"utilities.html"},{title:"Utilities",filename:"utilities",url:"utilities.html#utilities"},{title:".lib-clearfix()",filename:"utilities",url:"utilities.html#libclearfix"},{title:".lib-visibility-hidden()",filename:"utilities",url:"utilities.html#libvisibilityhidden"},{title:".lib-visually-hidden()",filename:"utilities",url:"utilities.html#libvisuallyhidden"},{title:".lib-visually-hidden-reset()",filename:"utilities",url:"utilities.html#libvisuallyhiddenreset"},{title:".lib-css()",filename:"utilities",url:"utilities.html#libcss"},{title:".lib-css() variables",filename:"utilities",url:"utilities.html#libcss-variables"},{title:".lib-rotate()",filename:"utilities",url:"utilities.html#librotate"},{title:".lib-rotate() variables",filename:"utilities",url:"utilities.html#librotate-variables"},{title:".lib-input-placeholder()",filename:"utilities",url:"utilities.html#libinputplaceholder"},{title:".lib-input-placeholder() variables",filename:"utilities",url:"utilities.html#libinputplaceholder-variables"},{title:".lib-background-gradient()",filename:"utilities",url:"utilities.html#libbackgroundgradient"},{title:".lib-background-gradient() variables",filename:"utilities",url:"utilities.html#libbackgroundgradient-variables"},{title:"variables",filename:"variables",url:"variables.html"},{title:"List of Global Variables",filename:"variables",url:"variables.html#list-of-global-variables"},{title:"Table with rows hover mixin variables",filename:"variables",url:"variables.html#table-with-rows-hover-mixin-variables"},{title:"docs",filename:"docs",url:"docs.html"},{title:"Documentation",filename:"docs",url:"docs.html#documentation"}];(function(){"use strict";var b=function(a,b){return Array.prototype.indexOf.call(a,b)!==-1},c=function(a,b){return Array.prototype.filter.call(a,b)},d=function(a,b){return Array.prototype.forEach.call(a,b)},e=document.getElementsByTagName("body")[0];e.addEventListener("click",function(a){var b=a.target;b.tagName.toLowerCase()==="svg"&&(b=b.parentNode);var c=!1;b.dataset.toggle!=null&&(a.preventDefault(),b.classList.contains("is-active")||(c=!0)),d(e.querySelectorAll("[data-toggle]"),function(a){a.classList.remove("is-active"),document.getElementById(a.dataset.toggle).hidden=!0}),c&&(b.classList.add("is-active"),document.getElementById(b.dataset.toggle).hidden=!1)}),function(){var f=e.getElementsByClassName("nav")[0];if(!f)return;var g=document.createElement("ul");g.className="nav-results",g.id="nav-search",g.hidden=!0,d(a,function(a){var b,c,d;b=document.createElement("li"),b._title=a.title.toLowerCase(),b.hidden=!0,b.appendChild(c=document.createElement("a")),c.href=a.url,c.innerHTML=a.title,c.appendChild(d=document.createElement("span")),d.innerHTML=a.filename,d.className="nav-results-filename",g.appendChild(b)}),f.appendChild(g);var h=g.children,i=function(a){d(h,function(a){a.hidden=!0});var b=this.value.toLowerCase(),e=[];b!==""&&(e=c(h,function(a){return a._title.indexOf(b)!==-1})),e.length>0?(d(e,function(a){a.hidden=!1}),g.hidden=!1):g.hidden=!0},j=f.querySelector('input[type="search"]');j.addEventListener("keyup",i),j.addEventListener("focus",i),e.addEventListener("click",function(a){if(a.target.classList&&a.target.classList.contains("search"))return;g.hidden=!0}),g.addEventListener("click",function(a){j.value=""});var k=document.createElement("ul");k.id="nav-toc",k.hidden=!0,k.className="nav-results toc-list",c(e.getElementsByTagName("*"),function(a){return b(["h1","h2","h3"],a.tagName.toLowerCase())}).map(function(a){var b=document.createElement("li"),c=document.createElement("a"),d=a.tagName.toLowerCase()[1];c.classList.add("level-"+d),b.appendChild(c),c.href="#"+a.id,c.innerHTML=a.innerHTML,k.appendChild(b)}),f.appendChild(k)}()})(),function(){"use strict";if(location.hash==="#__preview__"||location.protocol==="data:")return;var a=function(a,b){return Array.prototype.forEach.call(a,b)},b=function(a,b){var e=Array.prototype.slice.call(arguments,2);return d(a,function(a){return(c(b)?b||a:a[b]).apply(a,e)})},c=function(a){return Object.prototype.toString.call(a)==="[object Function]"},d=function(a,b){return Array.prototype.map.call(a,b)},e=function(a,b){return d(a,function(a){return a[b]})},f=function(a){var b={},c=a.split(";");for(var d=0;c.length>d;d++){var e=c[d].trim().split("=");b[e[0]]=e[1]}return b},g=function(a,c){return b(e(a,"classList"),"remove",c)},h=function(a,b){a.contentDocument.defaultView.postMessage(b,"*")},i=document.getElementsByTagName("head")[0],j=document.getElementsByTagName("body")[0],k=e(i.querySelectorAll('style[type="text/preview"]'),"innerHTML").join(""),l=e(i.querySelectorAll('script[type="text/preview"]'),"innerHTML").join(""),m=location.href.split("#")[0]+"#__preview__",n=document.createElement("iframe");n.src="data:text/html,",j.appendChild(n),n.addEventListener("load",function(){var b={sameOriginDataUri:!0};try{this.contentDocument,this.contentDocument||(b.sameOriginDataUri=!1)}catch(c){b.sameOriginDataUri=!1}this.parentNode.removeChild(this),a(j.getElementsByTagName("textarea"),function(a,c){o(a,b,c),q(),p(a)})});var o=function(a,b,c){var d,e,f;d=document.createElement("div"),d.appendChild(e=document.createElement("div")),d.className="preview",e.appendChild(f=document.createElement("iframe")),e.className="resizeable",f.setAttribute("scrolling","no"),f.name="iframe"+c++,f.addEventListener("load",function(){var c,d,e,f,g,i,j;j=this.contentDocument;if(!b.sameOriginDataUri&&this.src!==m)return;this.src===m&&(c=j.createElement("html"),c.appendChild(j.createElement("head")),c.appendChild(d=j.createElement("body")),d.innerHTML=a.textContent,j.replaceChild(c,j.documentElement)),g=j.createElement("head"),g.appendChild(f=j.createElement("style")),g.appendChild(e=j.createElement("script")),e.textContent=l,f.textContent=k,i=j.getElementsByTagName("head")[0],i.parentNode.replaceChild(g,i),h(this,"getHeight")});var g;b.sameOriginDataUri?g="data:text/html;charset=utf-8,"+encodeURIComponent("<!doctype html><html><head></head></body>"+a.textContent):g=m,f.setAttribute("src",g);var i=function(){f.contentDocument.body.innerHTML=this.value,h(f,"getHeight")};a.addEventListener("keypress",i),a.addEventListener("keyup",i),a.parentNode.insertBefore(d,a)},p=function(a){var b=document.createElement("div");b.className="preview-code",b.style.position="absolute",b.style.left="-9999px",j.appendChild(b);var c=parseInt(window.getComputedStyle(a).getPropertyValue("max-height"),10),d=function(a){b.textContent=this.value+"\n";var d=b.offsetHeight+2;d>=c?this.style.overflow="auto":this.style.overflow="hidden",this.style.height=b.offsetHeight+2+"px"};a.addEventListener("keypress",d),a.addEventListener("keyup",d),d.call(a)},q=function(){var b=j.getElementsByClassName("settings")[0],c=j.getElementsByClassName("resizeable"),d=30,e=function(b){document.cookie="preview-width="+b,a(c,function(a){b==="auto"&&(b=a.parentNode.offsetWidth),a.style.width=b+"px",h(a.getElementsByTagName("iframe")[0],"getHeight")})},i=f(document.cookie)["preview-width"];if(i){e(i),g(b.getElementsByClassName("is-active"),"is-active");var k=b.querySelector('button[data-width="'+i+'"]');k&&k.classList.add("is-active")}window.addEventListener("message",function(a){if(a.data==null||!a.source)return;var b=a.data,c=document.getElementsByName(a.source.name)[0];b.height!=null&&c&&(c.parentNode.style.height=b.height+d+"px")},!1),b&&c.length>0&&(b.hidden=!1,b.addEventListener("click",function(a){var c=a.target.tagName.toLowerCase(),d;if(c==="button")d=a.target;else{if(c!=="svg")return;d=a.target.parentNode}a.preventDefault(),g(b.getElementsByClassName("is-active"),"is-active"),d.classList.add("is-active");var f=d.dataset.width;e(f)}))}}()})()</script></body></html><!-- Generated with StyleDocco (http://jacobrask.github.com/styledocco). --> diff --git a/lib/web/css/docs/loaders.html b/lib/web/css/docs/loaders.html index 6d63110cfafea..884b71c782905 100644 --- a/lib/web/css/docs/loaders.html +++ b/lib/web/css/docs/loaders.html @@ -182,4 +182,4 @@ </tr> </table> </pre> -</div></article></section><div class="bar bottom"><div hidden class="settings container"><!-- Icons from http://iconmonstr.com--><button title="Desktop (1280)" data-width='1280'><svg viewBox="0 0 412 386" height="24" width="26" class="icon"><path d="m147.6,343.9c-4.5,15.9-26.2,37.6-42.1,42.1h201c-15.3,-4-38.1,-26.8-42.1,-42.1H147.6zM387,0.5H25c-13.8,0-25,11.2-25,25V294c0,13.8 11.2,25 25,25h362c13.8,0 25,-11.2 25,-25V25.5C412,11.7 400.8,0.5 387,0.5zM369.9,238.2H42.1L42.1,42.6 369.9,42.6V238.2z"></path></svg></button><button title="Laptop (1024)" data-width='1024'><svg viewBox="0 0 384 312" height="23" width="28" class="icon"><path d="m349.2,20.5c0,-11-9,-20-20,-20H53.6c-11,0-20,9-20,20v194H349.2v-194zm-27,167H60.6V27.5H322.2v160zm28,42H32.6L2.6,282.1c-3.5,6.2-3.5,13.8 0.1,19.9 3.6,6.2 10.2,9.9 17.3,9.9H363.1c7.1,0 13.7,-3.8 17.3,-10 3.6,-6.2 3.6,-13.8 0,-20l-30.2,-52.5zm-196.9,54 8,-23.5h60.5l8,23.5h-76.5z"></path></svg></button><button title="Tablet (768)" data-width='768'><svg viewBox="0 0 317 412" height="24" width="18" class="icon"><path d="M 316.5,380 V 32 c 0,-17.7 -14.3,-32 -32,-32 H 32 C 14.3,0 0,14.3 0,32 v 348 c 0,17.7 14.3,32 32,32 h 252.5 c 17.7,0 32,-14.3 32,-32 z M 40,367 V 45 H 276.5 V 367 H 40 z m 109.8,22.7 c 0,-4.7 3.8,-8.5 8.5,-8.5 4.7,0 8.5,3.8 8.5,8.5 0,4.7 -3.8,8.5 -8.5,8.5 -4.7,0 -8.5,-3.8 -8.5,-8.5 z"></path></svg></button><button title="Smart phone (320)" data-width='320'><svg viewBox="0 0 224 412" height="24" width="13" class="icon"><path d="M 190.7,0 H 33 C 14.8,0 0,14.8 0,33 v 346 c 0,18.2 14.8,33 33,33 h 157.7 c 18.2,0 33,-14.8 33,-33 V 33 c 0,-18.2 -14.8,-33 -33,-33 z M 94.3,30.2 h 37 c 2.2,0 4,1.8 4,4 0,2.2 -1.8,4 -4,4 h -37 c -2.2,0 -4,-1.8 -4,-4 0,-2.2 1.8,-4 4,-4 z m 18.5,362.8 c -8.8,0 -16,-7.2 -16,-16 0,-8.8 7.2,-16 16,-16 8.8,0 16,7.2 16,16 0,8.8 -7.2,16 -16,16 z M 198.6,343.8 H 25.1 V 68.2 h 173.5 v 275.5 z"></path></svg></button><button title="Feature phone (240)" data-width='240'><svg viewBox="0 0 201 412" height="24" width="12" class="icon"><path d="M 165.5,0.2 V 45 H 25 c -13.8,0 -25,11.2 -25,25 V 387 c 0,13.8 11.2,25 25,25 h 150.5 c 13.8,0 25,-11.2 25,-25 V 0.2 h -35 z M 65.2,366.5 H 34.2 v -24.5 h 31 v 24.5 z m 0,-44.3 H 34.2 v -24.5 h 31 v 24.5 z m 50.5,44.3 H 84.7 v -24.5 h 31 v 24.5 z m 0,-44.3 H 84.7 v -24.5 h 31 v 24.5 z m 50.5,44.3 h -31 v -24.5 h 31 v 24.5 z m 0,-44.3 h -31 v -24.5 h 31 v 24.5 z m 0,-59.3 h -132 V 95.4 h 132 V 262.9 z"></path></svg></button><button title="Auto (100%)" data-width="auto" class="auto is-active">Auto</button></div></div><script>(function(){var a=[{title:"actions-toolbar",filename:"actions-toolbar",url:"actions-toolbar.html"},{title:"Actions toolbar",filename:"actions-toolbar",url:"actions-toolbar.html#actions-toolbar"},{title:"Actions toolbar mixin variables",filename:"actions-toolbar",url:"actions-toolbar.html#actions-toolbar-mixin-variables"},{title:"Actions toolbar alignment",filename:"actions-toolbar",url:"actions-toolbar.html#actions-toolbar-alignment"},{title:"Reverse primary and secondary blocks",filename:"actions-toolbar",url:"actions-toolbar.html#reverse-primary-and-secondary-blocks"},{title:"Actions toolbar indents customizations",filename:"actions-toolbar",url:"actions-toolbar.html#actions-toolbar-indents-customizations"},{title:"Responsive actions toolbar",filename:"actions-toolbar",url:"actions-toolbar.html#responsive-actions-toolbar"},{title:"breadcrumbs",filename:"breadcrumbs",url:"breadcrumbs.html"},{title:"Breadcrumbs",filename:"breadcrumbs",url:"breadcrumbs.html#breadcrumbs"},{title:"Breadcrumbs variables",filename:"breadcrumbs",url:"breadcrumbs.html#breadcrumbs-variables"},{title:"Button-styled breadcrumbs with gradient background, border, and no separating symbol",filename:"breadcrumbs",url:"breadcrumbs.html#buttonstyled-breadcrumbs-with-gradient-background-border-and-no-separating-symbol"},{title:"Breadcrumbs with solid background",filename:"breadcrumbs",url:"breadcrumbs.html#breadcrumbs-with-solid-background"},{title:"buttons",filename:"buttons",url:"buttons.html"},{title:"Default button",filename:"buttons",url:"buttons.html#default-button"},{title:"Button variables",filename:"buttons",url:"buttons.html#button-variables"},{title:"Button as an icon",filename:"buttons",url:"buttons.html#button-as-an-icon"},{title:"Button with an icon on the left or right side of the text",filename:"buttons",url:"buttons.html#button-with-an-icon-on-the-left-or-right-side-of-the-text"},{title:"Button with fixed width",filename:"buttons",url:"buttons.html#button-with-fixed-width"},{title:"Primary button",filename:"buttons",url:"buttons.html#primary-button"},{title:"Primary button variables",filename:"buttons",url:"buttons.html#primary-button-variables"},{title:"Button with gradient background",filename:"buttons",url:"buttons.html#button-with-gradient-background"},{title:"Button as a link",filename:"buttons",url:"buttons.html#button-as-a-link"},{title:"Button as a link variables",filename:"buttons",url:"buttons.html#button-as-a-link-variables"},{title:"Link as a button",filename:"buttons",url:"buttons.html#link-as-a-button"},{title:"Button reset",filename:"buttons",url:"buttons.html#button-reset"},{title:"Button revert secondary color",filename:"buttons",url:"buttons.html#button-revert-secondary-color"},{title:"Button revert secondary color variables",filename:"buttons",url:"buttons.html#button-revert-secondary-color-variables"},{title:"Button revert secondary size",filename:"buttons",url:"buttons.html#button-revert-secondary-size"},{title:"Button revert secondary size variables",filename:"buttons",url:"buttons.html#button-revert-secondary-size-variables"},{title:"components",filename:"components",url:"components.html"},{title:"Components",filename:"components",url:"components.html#components"},{title:"Components Variables",filename:"components",url:"components.html#components-variables"},{title:"dropdowns",filename:"dropdowns",url:"dropdowns.html"},{title:"Drop-down and split buttons mixins",filename:"dropdowns",url:"dropdowns.html#dropdown-and-split-buttons-mixins"},{title:"Drop-down",filename:"dropdowns",url:"dropdowns.html#dropdown"},{title:"Drop-down variables",filename:"dropdowns",url:"dropdowns.html#dropdown-variables"},{title:"Drop-down with icon customization",filename:"dropdowns",url:"dropdowns.html#dropdown-with-icon-customization"},{title:"Modify dropdown list styles",filename:"dropdowns",url:"dropdowns.html#modify-dropdown-list-styles"},{title:"Split button",filename:"dropdowns",url:"dropdowns.html#split-button"},{title:"Split button variables",filename:"dropdowns",url:"dropdowns.html#split-button-variables"},{title:"Split button - button styling",filename:"dropdowns",url:"dropdowns.html#split-button-button-styling"},{title:"Split button icon customization",filename:"dropdowns",url:"dropdowns.html#split-button-icon-customization"},{title:"Split button drop-down list customization",filename:"dropdowns",url:"dropdowns.html#split-button-dropdown-list-customization"},{title:"forms",filename:"forms",url:"forms.html"},{title:"Forms mixins",filename:"forms",url:"forms.html#forms-mixins"},{title:"Global forms elements customization",filename:"forms",url:"forms.html#global-forms-elements-customization"},{title:"Fieldsets & fields customization",filename:"forms",url:"forms.html#fieldsets-fields-customization"},{title:"Fieldset and legend customization variables",filename:"forms",url:"forms.html#fieldset-and-legend-customization-variables"},{title:"Fields customization variables",filename:"forms",url:"forms.html#fields-customization-variables"},{title:"Required fields message customization variables",filename:"forms",url:"forms.html#required-fields-message-customization-variables"},{title:"Form element inputs customization",filename:"forms",url:"forms.html#form-element-inputs-customization"},{title:"Form element inputs customization variables",filename:"forms",url:"forms.html#form-element-inputs-customization-variables"},{title:"Form element choice",filename:"forms",url:"forms.html#form-element-choice"},{title:"Form element choice variables",filename:"forms",url:"forms.html#form-element-choice-variables"},{title:"Custom color",filename:"forms",url:"forms.html#custom-color"},{title:"Input number - input-text view",filename:"forms",url:"forms.html#input-number-inputtext-view"},{title:"Input search - input-text view",filename:"forms",url:"forms.html#input-search-inputtext-view"},{title:"Form validation",filename:"forms",url:"forms.html#form-validation"},{title:"Form validation variables",filename:"forms",url:"forms.html#form-validation-variables"},{title:"icons",filename:"icons",url:"icons.html"},{title:"Icons",filename:"icons",url:"icons.html#icons"},{title:"Icon with image or sprite",filename:"icons",url:"icons.html#icon-with-image-or-sprite"},{title:"Icon with image or sprite variables",filename:"icons",url:"icons.html#icon-with-image-or-sprite-variables"},{title:"Icon position for an icon with image or sprite",filename:"icons",url:"icons.html#icon-position-for-an-icon-with-image-or-sprite"},{title:"Position for icon with image or sprite mixin variables",filename:"icons",url:"icons.html#position-for-icon-with-image-or-sprite-mixin-variables"},{title:"Icon sprite position (with grid)",filename:"icons",url:"icons.html#icon-sprite-position-with-grid"},{title:"Icon sprite position variables",filename:"icons",url:"icons.html#icon-sprite-position-variables"},{title:"Image/sprite icon size",filename:"icons",url:"icons.html#imagesprite-icon-size"},{title:"Image/sprite icon size variables",filename:"icons",url:"icons.html#imagesprite-icon-size-variables"},{title:"Font icon",filename:"icons",url:"icons.html#font-icon"},{title:"Font icon variables",filename:"icons",url:"icons.html#font-icon-variables"},{title:"Change the size of font icon",filename:"icons",url:"icons.html#change-the-size-of-font-icon"},{title:"Change the size of font icon variables",filename:"icons",url:"icons.html#change-the-size-of-font-icon-variables"},{title:"Hide icon text",filename:"icons",url:"icons.html#hide-icon-text"},{title:"Sprite and font icons for Blank theme",filename:"icons",url:"icons.html#sprite-and-font-icons-for-blank-theme"},{title:"layout",filename:"layout",url:"layout.html"},{title:"Layout",filename:"layout",url:"layout.html#layout"},{title:"Layout global variables",filename:"layout",url:"layout.html#layout-global-variables"},{title:"Page layouts",filename:"layout",url:"layout.html#page-layouts"},{title:"Layout column",filename:"layout",url:"layout.html#layout-column"},{title:"Layout column variables",filename:"layout",url:"layout.html#layout-column-variables"},{title:"Layout width",filename:"layout",url:"layout.html#layout-width"},{title:"Layout width variables",filename:"layout",url:"layout.html#layout-width-variables"},{title:"lib",filename:"lib",url:"lib.html"},{title:"Including Magento UI library to your theme",filename:"lib",url:"lib.html#including-magento-ui-library-to-your-theme"},{title:"loaders",filename:"loaders",url:"loaders.html"},{title:"Loaders",filename:"loaders",url:"loaders.html#loaders"},{title:"Default loader variables",filename:"loaders",url:"loaders.html#default-loader-variables"},{title:"Loading",filename:"loaders",url:"loaders.html#loading"},{title:"Loading default variables",filename:"loaders",url:"loaders.html#loading-default-variables"},{title:"messages",filename:"messages",url:"messages.html"},{title:"Messages",filename:"messages",url:"messages.html#messages"},{title:"Information message",filename:"messages",url:"messages.html#information-message"},{title:"Warning message",filename:"messages",url:"messages.html#warning-message"},{title:"Error message",filename:"messages",url:"messages.html#error-message"},{title:"Success message",filename:"messages",url:"messages.html#success-message"},{title:"Notice message",filename:"messages",url:"messages.html#notice-message"},{title:"Message with inner icon",filename:"messages",url:"messages.html#message-with-inner-icon"},{title:"Message with lateral icon",filename:"messages",url:"messages.html#message-with-lateral-icon"},{title:"Custom message style",filename:"messages",url:"messages.html#custom-message-style"},{title:"Messages global variables",filename:"messages",url:"messages.html#messages-global-variables"},{title:"pages",filename:"pages",url:"pages.html"},{title:"Pagination HTML markup",filename:"pages",url:"pages.html#pagination-html-markup"},{title:"Pagination variables",filename:"pages",url:"pages.html#pagination-variables"},{title:"Pagination with label and gradient background on links",filename:"pages",url:"pages.html#pagination-with-label-and-gradient-background-on-links"},{title:'Pagination with "previous"..."next" text links and label',filename:"pages",url:"pages.html#pagination-with-previousnext-text-links-and-label"},{title:"Pagination without label, with solid background",filename:"pages",url:"pages.html#pagination-without-label-with-solid-background"},{title:"popups",filename:"popups",url:"popups.html"},{title:"Popups",filename:"popups",url:"popups.html#popups"},{title:"Popup variables",filename:"popups",url:"popups.html#popup-variables"},{title:"Window overlay mixin variables",filename:"popups",url:"popups.html#window-overlay-mixin-variables"},{title:"Fixed height popup",filename:"popups",url:"popups.html#fixed-height-popup"},{title:"Fixed content height popup",filename:"popups",url:"popups.html#fixed-content-height-popup"},{title:"Margins for header, content and footer block in popup",filename:"popups",url:"popups.html#margins-for-header-content-and-footer-block-in-popup"},{title:"Popup titles styled as theme headings",filename:"popups",url:"popups.html#popup-titles-styled-as-theme-headings"},{title:"Popup action toolbar",filename:"popups",url:"popups.html#popup-action-toolbar"},{title:"Popup Close button without an icon",filename:"popups",url:"popups.html#popup-close-button-without-an-icon"},{title:"Modify the icon of popup Close button",filename:"popups",url:"popups.html#modify-the-icon-of-popup-close-button"},{title:"Modify overlay styles",filename:"popups",url:"popups.html#modify-overlay-styles"},{title:"rating",filename:"rating",url:"rating.html"},{title:"Ratings",filename:"rating",url:"rating.html#ratings"},{title:"Global rating variables",filename:"rating",url:"rating.html#global-rating-variables"},{title:"Rating with vote",filename:"rating",url:"rating.html#rating-with-vote"},{title:"Rating with vote icons number customization",filename:"rating",url:"rating.html#rating-with-vote-icons-number-customization"},{title:"Rating with vote icons colors customization",filename:"rating",url:"rating.html#rating-with-vote-icons-colors-customization"},{title:"Rating with vote icons symbol customization",filename:"rating",url:"rating.html#rating-with-vote-icons-symbol-customization"},{title:"Accessible rating with vote",filename:"rating",url:"rating.html#accessible-rating-with-vote"},{title:"Rating summary",filename:"rating",url:"rating.html#rating-summary"},{title:"Rating summary icons number customization",filename:"rating",url:"rating.html#rating-summary-icons-number-customization"},{title:"Rating summary icons color customization",filename:"rating",url:"rating.html#rating-summary-icons-color-customization"},{title:"Rating summary icons symbol customization",filename:"rating",url:"rating.html#rating-summary-icons-symbol-customization"},{title:"Rating summary hide label",filename:"rating",url:"rating.html#rating-summary-hide-label"},{title:"Rating summary multiple ratings",filename:"rating",url:"rating.html#rating-summary-multiple-ratings"},{title:"Rating hide label mixin",filename:"rating",url:"rating.html#rating-hide-label-mixin"},{title:"resets",filename:"resets",url:"resets.html"},{title:"Resets",filename:"resets",url:"resets.html#resets"},{title:"responsive",filename:"responsive",url:"responsive.html"},{title:"Responsive",filename:"responsive",url:"responsive.html#responsive"},{title:"Responsive mixins usage",filename:"responsive",url:"responsive.html#responsive-mixins-usage"},{title:"Media query style groups separation variables",filename:"responsive",url:"responsive.html#media-query-style-groups-separation-variables"},{title:"Responsive breakpoints",filename:"responsive",url:"responsive.html#responsive-breakpoints"},{title:"sections",filename:"sections",url:"sections.html"},{title:"Tabs and accordions",filename:"sections",url:"sections.html#tabs-and-accordions"},{title:"Tabs",filename:"sections",url:"sections.html#tabs"},{title:"Tabs mixin variables",filename:"sections",url:"sections.html#tabs-mixin-variables"},{title:"Tabs with content top border",filename:"sections",url:"sections.html#tabs-with-content-top-border"},{title:"Accordion",filename:"sections",url:"sections.html#accordion"},{title:"Accordion mixin variables",filename:"sections",url:"sections.html#accordion-mixin-variables"},{title:"Responsive tabs",filename:"sections",url:"sections.html#responsive-tabs"},{title:"Tabs Base",filename:"sections",url:"sections.html#tabs-base"},{title:"Accordion Base",filename:"sections",url:"sections.html#accordion-base"},{title:"tables",filename:"tables",url:"tables.html"},{title:"Tables",filename:"tables",url:"tables.html#tables"},{title:"Table mixin variables",filename:"tables",url:"tables.html#table-mixin-variables"},{title:"Table typography",filename:"tables",url:"tables.html#table-typography"},{title:"Table typography mixin variables",filename:"tables",url:"tables.html#table-typography-mixin-variables"},{title:"Table caption",filename:"tables",url:"tables.html#table-caption"},{title:"Table caption mixin variables",filename:"tables",url:"tables.html#table-caption-mixin-variables"},{title:"Table cells resize",filename:"tables",url:"tables.html#table-cells-resize"},{title:"Table cells resize variables",filename:"tables",url:"tables.html#table-cells-resize-variables"},{title:"Table background customization",filename:"tables",url:"tables.html#table-background-customization"},{title:"Table background mixin variables",filename:"tables",url:"tables.html#table-background-mixin-variables"},{title:"Table borders customization",filename:"tables",url:"tables.html#table-borders-customization"},{title:"Table borders mixin variables",filename:"tables",url:"tables.html#table-borders-mixin-variables"},{title:"Table with horizontal borders",filename:"tables",url:"tables.html#table-with-horizontal-borders"},{title:"Table with vertical borders",filename:"tables",url:"tables.html#table-with-vertical-borders"},{title:"Table with light borders",filename:"tables",url:"tables.html#table-with-light-borders"},{title:"Table without borders",filename:"tables",url:"tables.html#table-without-borders"},{title:"Striped table",filename:"tables",url:"tables.html#striped-table"},{title:"Striped table mixin variables",filename:"tables",url:"tables.html#striped-table-mixin-variables"},{title:"Table with rows hover",filename:"tables",url:"tables.html#table-with-rows-hover"},{title:"Table with rows hover mixin variables",filename:"tables",url:"tables.html#table-with-rows-hover-mixin-variables"},{title:"Responsive table technics #1",filename:"tables",url:"tables.html#responsive-table-technics-1"},{title:"Responsive table technics #2",filename:"tables",url:"tables.html#responsive-table-technics-2"},{title:"Responsive table technics #2 mixin variables",filename:"tables",url:"tables.html#responsive-table-technics-2-mixin-variables"},{title:"tooltips",filename:"tooltips",url:"tooltips.html"},{title:"Tooltips",filename:"tooltips",url:"tooltips.html#tooltips"},{title:"Tooltips variables",filename:"tooltips",url:"tooltips.html#tooltips-variables"},{title:"typography",filename:"typography",url:"typography.html"},{title:"Typogrphy",filename:"typography",url:"typography.html#typogrphy"},{title:"Typography variables",filename:"typography",url:"typography.html#typography-variables"},{title:"Font-size mixin",filename:"typography",url:"typography.html#fontsize-mixin"},{title:"Line-height mixin",filename:"typography",url:"typography.html#lineheight-mixin"},{title:"Word breaking mixin",filename:"typography",url:"typography.html#word-breaking-mixin"},{title:"Font face mixin",filename:"typography",url:"typography.html#font-face-mixin"},{title:"Text overflow mixin",filename:"typography",url:"typography.html#text-overflow-mixin"},{title:"Text hide",filename:"typography",url:"typography.html#text-hide"},{title:"Hyphens",filename:"typography",url:"typography.html#hyphens"},{title:"Font style and color",filename:"typography",url:"typography.html#font-style-and-color"},{title:"Font style mixin variables",filename:"typography",url:"typography.html#font-style-mixin-variables"},{title:"Reset list styles",filename:"typography",url:"typography.html#reset-list-styles"},{title:"Reset list styles variables",filename:"typography",url:"typography.html#reset-list-styles-variables"},{title:"Inline-block list item styling",filename:"typography",url:"typography.html#inlineblock-list-item-styling"},{title:"Link styling mixin",filename:"typography",url:"typography.html#link-styling-mixin"},{title:"Link styling mixin variables",filename:"typography",url:"typography.html#link-styling-mixin-variables"},{title:"Heading styling mixin",filename:"typography",url:"typography.html#heading-styling-mixin"},{title:"Base typography mixins",filename:"typography",url:"typography.html#base-typography-mixins"},{title:"Base typography mixin variables",filename:"typography",url:"typography.html#base-typography-mixin-variables"},{title:"Headings typography mixin",filename:"typography",url:"typography.html#headings-typography-mixin"},{title:"Headings typography mixin variables",filename:"typography",url:"typography.html#headings-typography-mixin-variables"},{title:"Typography links mixin",filename:"typography",url:"typography.html#typography-links-mixin"},{title:"Typography lists mixin",filename:"typography",url:"typography.html#typography-lists-mixin"},{title:"Typography lists mixin variables",filename:"typography",url:"typography.html#typography-lists-mixin-variables"},{title:"Typography code elements mixin",filename:"typography",url:"typography.html#typography-code-elements-mixin"},{title:"Typography code mixin variables",filename:"typography",url:"typography.html#typography-code-mixin-variables"},{title:"Typography blockquote",filename:"typography",url:"typography.html#typography-blockquote"},{title:"Typography blockquote mixin variables",filename:"typography",url:"typography.html#typography-blockquote-mixin-variables"},{title:"utilities",filename:"utilities",url:"utilities.html"},{title:"Utilities",filename:"utilities",url:"utilities.html#utilities"},{title:".lib-clearfix()",filename:"utilities",url:"utilities.html#libclearfix"},{title:".lib-visibility-hidden()",filename:"utilities",url:"utilities.html#libvisibilityhidden"},{title:".lib-visually-hidden()",filename:"utilities",url:"utilities.html#libvisuallyhidden"},{title:".lib-visually-hidden-reset()",filename:"utilities",url:"utilities.html#libvisuallyhiddenreset"},{title:".lib-css()",filename:"utilities",url:"utilities.html#libcss"},{title:".lib-css() variables",filename:"utilities",url:"utilities.html#libcss-variables"},{title:".lib-rotate()",filename:"utilities",url:"utilities.html#librotate"},{title:".lib-rotate() variables",filename:"utilities",url:"utilities.html#librotate-variables"},{title:".lib-input-placeholder()",filename:"utilities",url:"utilities.html#libinputplaceholder"},{title:".lib-input-placeholder() variables",filename:"utilities",url:"utilities.html#libinputplaceholder-variables"},{title:".lib-background-gradient()",filename:"utilities",url:"utilities.html#libbackgroundgradient"},{title:".lib-background-gradient() variables",filename:"utilities",url:"utilities.html#libbackgroundgradient-variables"},{title:".lib-url-check()",filename:"utilities",url:"utilities.html#liburlcheck"},{title:".lib-url-check() variables",filename:"utilities",url:"utilities.html#liburlcheck-variables"},{title:"variables",filename:"variables",url:"variables.html"},{title:"List of Global Variables",filename:"variables",url:"variables.html#list-of-global-variables"},{title:"Table with rows hover mixin variables",filename:"variables",url:"variables.html#table-with-rows-hover-mixin-variables"},{title:"docs",filename:"docs",url:"docs.html"},{title:"Documentation",filename:"docs",url:"docs.html#documentation"}];(function(){"use strict";var b=function(a,b){return Array.prototype.indexOf.call(a,b)!==-1},c=function(a,b){return Array.prototype.filter.call(a,b)},d=function(a,b){return Array.prototype.forEach.call(a,b)},e=document.getElementsByTagName("body")[0];e.addEventListener("click",function(a){var b=a.target;b.tagName.toLowerCase()==="svg"&&(b=b.parentNode);var c=!1;b.dataset.toggle!=null&&(a.preventDefault(),b.classList.contains("is-active")||(c=!0)),d(e.querySelectorAll("[data-toggle]"),function(a){a.classList.remove("is-active"),document.getElementById(a.dataset.toggle).hidden=!0}),c&&(b.classList.add("is-active"),document.getElementById(b.dataset.toggle).hidden=!1)}),function(){var f=e.getElementsByClassName("nav")[0];if(!f)return;var g=document.createElement("ul");g.className="nav-results",g.id="nav-search",g.hidden=!0,d(a,function(a){var b,c,d;b=document.createElement("li"),b._title=a.title.toLowerCase(),b.hidden=!0,b.appendChild(c=document.createElement("a")),c.href=a.url,c.innerHTML=a.title,c.appendChild(d=document.createElement("span")),d.innerHTML=a.filename,d.className="nav-results-filename",g.appendChild(b)}),f.appendChild(g);var h=g.children,i=function(a){d(h,function(a){a.hidden=!0});var b=this.value.toLowerCase(),e=[];b!==""&&(e=c(h,function(a){return a._title.indexOf(b)!==-1})),e.length>0?(d(e,function(a){a.hidden=!1}),g.hidden=!1):g.hidden=!0},j=f.querySelector('input[type="search"]');j.addEventListener("keyup",i),j.addEventListener("focus",i),e.addEventListener("click",function(a){if(a.target.classList&&a.target.classList.contains("search"))return;g.hidden=!0}),g.addEventListener("click",function(a){j.value=""});var k=document.createElement("ul");k.id="nav-toc",k.hidden=!0,k.className="nav-results toc-list",c(e.getElementsByTagName("*"),function(a){return b(["h1","h2","h3"],a.tagName.toLowerCase())}).map(function(a){var b=document.createElement("li"),c=document.createElement("a"),d=a.tagName.toLowerCase()[1];c.classList.add("level-"+d),b.appendChild(c),c.href="#"+a.id,c.innerHTML=a.innerHTML,k.appendChild(b)}),f.appendChild(k)}()})(),function(){"use strict";if(location.hash==="#__preview__"||location.protocol==="data:")return;var a=function(a,b){return Array.prototype.forEach.call(a,b)},b=function(a,b){var e=Array.prototype.slice.call(arguments,2);return d(a,function(a){return(c(b)?b||a:a[b]).apply(a,e)})},c=function(a){return Object.prototype.toString.call(a)==="[object Function]"},d=function(a,b){return Array.prototype.map.call(a,b)},e=function(a,b){return d(a,function(a){return a[b]})},f=function(a){var b={},c=a.split(";");for(var d=0;c.length>d;d++){var e=c[d].trim().split("=");b[e[0]]=e[1]}return b},g=function(a,c){return b(e(a,"classList"),"remove",c)},h=function(a,b){a.contentDocument.defaultView.postMessage(b,"*")},i=document.getElementsByTagName("head")[0],j=document.getElementsByTagName("body")[0],k=e(i.querySelectorAll('style[type="text/preview"]'),"innerHTML").join(""),l=e(i.querySelectorAll('script[type="text/preview"]'),"innerHTML").join(""),m=location.href.split("#")[0]+"#__preview__",n=document.createElement("iframe");n.src="data:text/html,",j.appendChild(n),n.addEventListener("load",function(){var b={sameOriginDataUri:!0};try{this.contentDocument,this.contentDocument||(b.sameOriginDataUri=!1)}catch(c){b.sameOriginDataUri=!1}this.parentNode.removeChild(this),a(j.getElementsByTagName("textarea"),function(a,c){o(a,b,c),q(),p(a)})});var o=function(a,b,c){var d,e,f;d=document.createElement("div"),d.appendChild(e=document.createElement("div")),d.className="preview",e.appendChild(f=document.createElement("iframe")),e.className="resizeable",f.setAttribute("scrolling","no"),f.name="iframe"+c++,f.addEventListener("load",function(){var c,d,e,f,g,i,j;j=this.contentDocument;if(!b.sameOriginDataUri&&this.src!==m)return;this.src===m&&(c=j.createElement("html"),c.appendChild(j.createElement("head")),c.appendChild(d=j.createElement("body")),d.innerHTML=a.textContent,j.replaceChild(c,j.documentElement)),g=j.createElement("head"),g.appendChild(f=j.createElement("style")),g.appendChild(e=j.createElement("script")),e.textContent=l,f.textContent=k,i=j.getElementsByTagName("head")[0],i.parentNode.replaceChild(g,i),h(this,"getHeight")});var g;b.sameOriginDataUri?g="data:text/html;charset=utf-8,"+encodeURIComponent("<!doctype html><html><head></head></body>"+a.textContent):g=m,f.setAttribute("src",g);var i=function(){f.contentDocument.body.innerHTML=this.value,h(f,"getHeight")};a.addEventListener("keypress",i),a.addEventListener("keyup",i),a.parentNode.insertBefore(d,a)},p=function(a){var b=document.createElement("div");b.className="preview-code",b.style.position="absolute",b.style.left="-9999px",j.appendChild(b);var c=parseInt(window.getComputedStyle(a).getPropertyValue("max-height"),10),d=function(a){b.textContent=this.value+"\n";var d=b.offsetHeight+2;d>=c?this.style.overflow="auto":this.style.overflow="hidden",this.style.height=b.offsetHeight+2+"px"};a.addEventListener("keypress",d),a.addEventListener("keyup",d),d.call(a)},q=function(){var b=j.getElementsByClassName("settings")[0],c=j.getElementsByClassName("resizeable"),d=30,e=function(b){document.cookie="preview-width="+b,a(c,function(a){b==="auto"&&(b=a.parentNode.offsetWidth),a.style.width=b+"px",h(a.getElementsByTagName("iframe")[0],"getHeight")})},i=f(document.cookie)["preview-width"];if(i){e(i),g(b.getElementsByClassName("is-active"),"is-active");var k=b.querySelector('button[data-width="'+i+'"]');k&&k.classList.add("is-active")}window.addEventListener("message",function(a){if(a.data==null||!a.source)return;var b=a.data,c=document.getElementsByName(a.source.name)[0];b.height!=null&&c&&(c.parentNode.style.height=b.height+d+"px")},!1),b&&c.length>0&&(b.hidden=!1,b.addEventListener("click",function(a){var c=a.target.tagName.toLowerCase(),d;if(c==="button")d=a.target;else{if(c!=="svg")return;d=a.target.parentNode}a.preventDefault(),g(b.getElementsByClassName("is-active"),"is-active"),d.classList.add("is-active");var f=d.dataset.width;e(f)}))}}()})()</script></body></html><!-- Generated with StyleDocco (http://jacobrask.github.com/styledocco). --> +</div></article></section><div class="bar bottom"><div hidden class="settings container"><!-- Icons from http://iconmonstr.com--><button title="Desktop (1280)" data-width='1280'><svg viewBox="0 0 412 386" height="24" width="26" class="icon"><path d="m147.6,343.9c-4.5,15.9-26.2,37.6-42.1,42.1h201c-15.3,-4-38.1,-26.8-42.1,-42.1H147.6zM387,0.5H25c-13.8,0-25,11.2-25,25V294c0,13.8 11.2,25 25,25h362c13.8,0 25,-11.2 25,-25V25.5C412,11.7 400.8,0.5 387,0.5zM369.9,238.2H42.1L42.1,42.6 369.9,42.6V238.2z"></path></svg></button><button title="Laptop (1024)" data-width='1024'><svg viewBox="0 0 384 312" height="23" width="28" class="icon"><path d="m349.2,20.5c0,-11-9,-20-20,-20H53.6c-11,0-20,9-20,20v194H349.2v-194zm-27,167H60.6V27.5H322.2v160zm28,42H32.6L2.6,282.1c-3.5,6.2-3.5,13.8 0.1,19.9 3.6,6.2 10.2,9.9 17.3,9.9H363.1c7.1,0 13.7,-3.8 17.3,-10 3.6,-6.2 3.6,-13.8 0,-20l-30.2,-52.5zm-196.9,54 8,-23.5h60.5l8,23.5h-76.5z"></path></svg></button><button title="Tablet (768)" data-width='768'><svg viewBox="0 0 317 412" height="24" width="18" class="icon"><path d="M 316.5,380 V 32 c 0,-17.7 -14.3,-32 -32,-32 H 32 C 14.3,0 0,14.3 0,32 v 348 c 0,17.7 14.3,32 32,32 h 252.5 c 17.7,0 32,-14.3 32,-32 z M 40,367 V 45 H 276.5 V 367 H 40 z m 109.8,22.7 c 0,-4.7 3.8,-8.5 8.5,-8.5 4.7,0 8.5,3.8 8.5,8.5 0,4.7 -3.8,8.5 -8.5,8.5 -4.7,0 -8.5,-3.8 -8.5,-8.5 z"></path></svg></button><button title="Smart phone (320)" data-width='320'><svg viewBox="0 0 224 412" height="24" width="13" class="icon"><path d="M 190.7,0 H 33 C 14.8,0 0,14.8 0,33 v 346 c 0,18.2 14.8,33 33,33 h 157.7 c 18.2,0 33,-14.8 33,-33 V 33 c 0,-18.2 -14.8,-33 -33,-33 z M 94.3,30.2 h 37 c 2.2,0 4,1.8 4,4 0,2.2 -1.8,4 -4,4 h -37 c -2.2,0 -4,-1.8 -4,-4 0,-2.2 1.8,-4 4,-4 z m 18.5,362.8 c -8.8,0 -16,-7.2 -16,-16 0,-8.8 7.2,-16 16,-16 8.8,0 16,7.2 16,16 0,8.8 -7.2,16 -16,16 z M 198.6,343.8 H 25.1 V 68.2 h 173.5 v 275.5 z"></path></svg></button><button title="Feature phone (240)" data-width='240'><svg viewBox="0 0 201 412" height="24" width="12" class="icon"><path d="M 165.5,0.2 V 45 H 25 c -13.8,0 -25,11.2 -25,25 V 387 c 0,13.8 11.2,25 25,25 h 150.5 c 13.8,0 25,-11.2 25,-25 V 0.2 h -35 z M 65.2,366.5 H 34.2 v -24.5 h 31 v 24.5 z m 0,-44.3 H 34.2 v -24.5 h 31 v 24.5 z m 50.5,44.3 H 84.7 v -24.5 h 31 v 24.5 z m 0,-44.3 H 84.7 v -24.5 h 31 v 24.5 z m 50.5,44.3 h -31 v -24.5 h 31 v 24.5 z m 0,-44.3 h -31 v -24.5 h 31 v 24.5 z m 0,-59.3 h -132 V 95.4 h 132 V 262.9 z"></path></svg></button><button title="Auto (100%)" data-width="auto" class="auto is-active">Auto</button></div></div><script>(function(){var a=[{title:"actions-toolbar",filename:"actions-toolbar",url:"actions-toolbar.html"},{title:"Actions toolbar",filename:"actions-toolbar",url:"actions-toolbar.html#actions-toolbar"},{title:"Actions toolbar mixin variables",filename:"actions-toolbar",url:"actions-toolbar.html#actions-toolbar-mixin-variables"},{title:"Actions toolbar alignment",filename:"actions-toolbar",url:"actions-toolbar.html#actions-toolbar-alignment"},{title:"Reverse primary and secondary blocks",filename:"actions-toolbar",url:"actions-toolbar.html#reverse-primary-and-secondary-blocks"},{title:"Actions toolbar indents customizations",filename:"actions-toolbar",url:"actions-toolbar.html#actions-toolbar-indents-customizations"},{title:"Responsive actions toolbar",filename:"actions-toolbar",url:"actions-toolbar.html#responsive-actions-toolbar"},{title:"breadcrumbs",filename:"breadcrumbs",url:"breadcrumbs.html"},{title:"Breadcrumbs",filename:"breadcrumbs",url:"breadcrumbs.html#breadcrumbs"},{title:"Breadcrumbs variables",filename:"breadcrumbs",url:"breadcrumbs.html#breadcrumbs-variables"},{title:"Button-styled breadcrumbs with gradient background, border, and no separating symbol",filename:"breadcrumbs",url:"breadcrumbs.html#buttonstyled-breadcrumbs-with-gradient-background-border-and-no-separating-symbol"},{title:"Breadcrumbs with solid background",filename:"breadcrumbs",url:"breadcrumbs.html#breadcrumbs-with-solid-background"},{title:"buttons",filename:"buttons",url:"buttons.html"},{title:"Default button",filename:"buttons",url:"buttons.html#default-button"},{title:"Button variables",filename:"buttons",url:"buttons.html#button-variables"},{title:"Button as an icon",filename:"buttons",url:"buttons.html#button-as-an-icon"},{title:"Button with an icon on the left or right side of the text",filename:"buttons",url:"buttons.html#button-with-an-icon-on-the-left-or-right-side-of-the-text"},{title:"Button with fixed width",filename:"buttons",url:"buttons.html#button-with-fixed-width"},{title:"Primary button",filename:"buttons",url:"buttons.html#primary-button"},{title:"Primary button variables",filename:"buttons",url:"buttons.html#primary-button-variables"},{title:"Button with gradient background",filename:"buttons",url:"buttons.html#button-with-gradient-background"},{title:"Button as a link",filename:"buttons",url:"buttons.html#button-as-a-link"},{title:"Button as a link variables",filename:"buttons",url:"buttons.html#button-as-a-link-variables"},{title:"Link as a button",filename:"buttons",url:"buttons.html#link-as-a-button"},{title:"Button reset",filename:"buttons",url:"buttons.html#button-reset"},{title:"Button revert secondary color",filename:"buttons",url:"buttons.html#button-revert-secondary-color"},{title:"Button revert secondary color variables",filename:"buttons",url:"buttons.html#button-revert-secondary-color-variables"},{title:"Button revert secondary size",filename:"buttons",url:"buttons.html#button-revert-secondary-size"},{title:"Button revert secondary size variables",filename:"buttons",url:"buttons.html#button-revert-secondary-size-variables"},{title:"components",filename:"components",url:"components.html"},{title:"Components",filename:"components",url:"components.html#components"},{title:"Components Variables",filename:"components",url:"components.html#components-variables"},{title:"dropdowns",filename:"dropdowns",url:"dropdowns.html"},{title:"Drop-down and split buttons mixins",filename:"dropdowns",url:"dropdowns.html#dropdown-and-split-buttons-mixins"},{title:"Drop-down",filename:"dropdowns",url:"dropdowns.html#dropdown"},{title:"Drop-down variables",filename:"dropdowns",url:"dropdowns.html#dropdown-variables"},{title:"Drop-down with icon customization",filename:"dropdowns",url:"dropdowns.html#dropdown-with-icon-customization"},{title:"Modify dropdown list styles",filename:"dropdowns",url:"dropdowns.html#modify-dropdown-list-styles"},{title:"Split button",filename:"dropdowns",url:"dropdowns.html#split-button"},{title:"Split button variables",filename:"dropdowns",url:"dropdowns.html#split-button-variables"},{title:"Split button - button styling",filename:"dropdowns",url:"dropdowns.html#split-button-button-styling"},{title:"Split button icon customization",filename:"dropdowns",url:"dropdowns.html#split-button-icon-customization"},{title:"Split button drop-down list customization",filename:"dropdowns",url:"dropdowns.html#split-button-dropdown-list-customization"},{title:"forms",filename:"forms",url:"forms.html"},{title:"Forms mixins",filename:"forms",url:"forms.html#forms-mixins"},{title:"Global forms elements customization",filename:"forms",url:"forms.html#global-forms-elements-customization"},{title:"Fieldsets & fields customization",filename:"forms",url:"forms.html#fieldsets-fields-customization"},{title:"Fieldset and legend customization variables",filename:"forms",url:"forms.html#fieldset-and-legend-customization-variables"},{title:"Fields customization variables",filename:"forms",url:"forms.html#fields-customization-variables"},{title:"Required fields message customization variables",filename:"forms",url:"forms.html#required-fields-message-customization-variables"},{title:"Form element inputs customization",filename:"forms",url:"forms.html#form-element-inputs-customization"},{title:"Form element inputs customization variables",filename:"forms",url:"forms.html#form-element-inputs-customization-variables"},{title:"Form element choice",filename:"forms",url:"forms.html#form-element-choice"},{title:"Form element choice variables",filename:"forms",url:"forms.html#form-element-choice-variables"},{title:"Custom color",filename:"forms",url:"forms.html#custom-color"},{title:"Input number - input-text view",filename:"forms",url:"forms.html#input-number-inputtext-view"},{title:"Input search - input-text view",filename:"forms",url:"forms.html#input-search-inputtext-view"},{title:"Form validation",filename:"forms",url:"forms.html#form-validation"},{title:"Form validation variables",filename:"forms",url:"forms.html#form-validation-variables"},{title:"icons",filename:"icons",url:"icons.html"},{title:"Icons",filename:"icons",url:"icons.html#icons"},{title:"Icon with image or sprite",filename:"icons",url:"icons.html#icon-with-image-or-sprite"},{title:"Icon with image or sprite variables",filename:"icons",url:"icons.html#icon-with-image-or-sprite-variables"},{title:"Icon position for an icon with image or sprite",filename:"icons",url:"icons.html#icon-position-for-an-icon-with-image-or-sprite"},{title:"Position for icon with image or sprite mixin variables",filename:"icons",url:"icons.html#position-for-icon-with-image-or-sprite-mixin-variables"},{title:"Icon sprite position (with grid)",filename:"icons",url:"icons.html#icon-sprite-position-with-grid"},{title:"Icon sprite position variables",filename:"icons",url:"icons.html#icon-sprite-position-variables"},{title:"Image/sprite icon size",filename:"icons",url:"icons.html#imagesprite-icon-size"},{title:"Image/sprite icon size variables",filename:"icons",url:"icons.html#imagesprite-icon-size-variables"},{title:"Font icon",filename:"icons",url:"icons.html#font-icon"},{title:"Font icon variables",filename:"icons",url:"icons.html#font-icon-variables"},{title:"Change the size of font icon",filename:"icons",url:"icons.html#change-the-size-of-font-icon"},{title:"Change the size of font icon variables",filename:"icons",url:"icons.html#change-the-size-of-font-icon-variables"},{title:"Hide icon text",filename:"icons",url:"icons.html#hide-icon-text"},{title:"Sprite and font icons for Blank theme",filename:"icons",url:"icons.html#sprite-and-font-icons-for-blank-theme"},{title:"layout",filename:"layout",url:"layout.html"},{title:"Layout",filename:"layout",url:"layout.html#layout"},{title:"Layout global variables",filename:"layout",url:"layout.html#layout-global-variables"},{title:"Page layouts",filename:"layout",url:"layout.html#page-layouts"},{title:"Layout column",filename:"layout",url:"layout.html#layout-column"},{title:"Layout column variables",filename:"layout",url:"layout.html#layout-column-variables"},{title:"Layout width",filename:"layout",url:"layout.html#layout-width"},{title:"Layout width variables",filename:"layout",url:"layout.html#layout-width-variables"},{title:"lib",filename:"lib",url:"lib.html"},{title:"Including Magento UI library to your theme",filename:"lib",url:"lib.html#including-magento-ui-library-to-your-theme"},{title:"loaders",filename:"loaders",url:"loaders.html"},{title:"Loaders",filename:"loaders",url:"loaders.html#loaders"},{title:"Default loader variables",filename:"loaders",url:"loaders.html#default-loader-variables"},{title:"Loading",filename:"loaders",url:"loaders.html#loading"},{title:"Loading default variables",filename:"loaders",url:"loaders.html#loading-default-variables"},{title:"messages",filename:"messages",url:"messages.html"},{title:"Messages",filename:"messages",url:"messages.html#messages"},{title:"Information message",filename:"messages",url:"messages.html#information-message"},{title:"Warning message",filename:"messages",url:"messages.html#warning-message"},{title:"Error message",filename:"messages",url:"messages.html#error-message"},{title:"Success message",filename:"messages",url:"messages.html#success-message"},{title:"Notice message",filename:"messages",url:"messages.html#notice-message"},{title:"Message with inner icon",filename:"messages",url:"messages.html#message-with-inner-icon"},{title:"Message with lateral icon",filename:"messages",url:"messages.html#message-with-lateral-icon"},{title:"Custom message style",filename:"messages",url:"messages.html#custom-message-style"},{title:"Messages global variables",filename:"messages",url:"messages.html#messages-global-variables"},{title:"pages",filename:"pages",url:"pages.html"},{title:"Pagination HTML markup",filename:"pages",url:"pages.html#pagination-html-markup"},{title:"Pagination variables",filename:"pages",url:"pages.html#pagination-variables"},{title:"Pagination with label and gradient background on links",filename:"pages",url:"pages.html#pagination-with-label-and-gradient-background-on-links"},{title:'Pagination with "previous"..."next" text links and label',filename:"pages",url:"pages.html#pagination-with-previousnext-text-links-and-label"},{title:"Pagination without label, with solid background",filename:"pages",url:"pages.html#pagination-without-label-with-solid-background"},{title:"popups",filename:"popups",url:"popups.html"},{title:"Popups",filename:"popups",url:"popups.html#popups"},{title:"Popup variables",filename:"popups",url:"popups.html#popup-variables"},{title:"Window overlay mixin variables",filename:"popups",url:"popups.html#window-overlay-mixin-variables"},{title:"Fixed height popup",filename:"popups",url:"popups.html#fixed-height-popup"},{title:"Fixed content height popup",filename:"popups",url:"popups.html#fixed-content-height-popup"},{title:"Margins for header, content and footer block in popup",filename:"popups",url:"popups.html#margins-for-header-content-and-footer-block-in-popup"},{title:"Popup titles styled as theme headings",filename:"popups",url:"popups.html#popup-titles-styled-as-theme-headings"},{title:"Popup action toolbar",filename:"popups",url:"popups.html#popup-action-toolbar"},{title:"Popup Close button without an icon",filename:"popups",url:"popups.html#popup-close-button-without-an-icon"},{title:"Modify the icon of popup Close button",filename:"popups",url:"popups.html#modify-the-icon-of-popup-close-button"},{title:"Modify overlay styles",filename:"popups",url:"popups.html#modify-overlay-styles"},{title:"rating",filename:"rating",url:"rating.html"},{title:"Ratings",filename:"rating",url:"rating.html#ratings"},{title:"Global rating variables",filename:"rating",url:"rating.html#global-rating-variables"},{title:"Rating with vote",filename:"rating",url:"rating.html#rating-with-vote"},{title:"Rating with vote icons number customization",filename:"rating",url:"rating.html#rating-with-vote-icons-number-customization"},{title:"Rating with vote icons colors customization",filename:"rating",url:"rating.html#rating-with-vote-icons-colors-customization"},{title:"Rating with vote icons symbol customization",filename:"rating",url:"rating.html#rating-with-vote-icons-symbol-customization"},{title:"Accessible rating with vote",filename:"rating",url:"rating.html#accessible-rating-with-vote"},{title:"Rating summary",filename:"rating",url:"rating.html#rating-summary"},{title:"Rating summary icons number customization",filename:"rating",url:"rating.html#rating-summary-icons-number-customization"},{title:"Rating summary icons color customization",filename:"rating",url:"rating.html#rating-summary-icons-color-customization"},{title:"Rating summary icons symbol customization",filename:"rating",url:"rating.html#rating-summary-icons-symbol-customization"},{title:"Rating summary hide label",filename:"rating",url:"rating.html#rating-summary-hide-label"},{title:"Rating summary multiple ratings",filename:"rating",url:"rating.html#rating-summary-multiple-ratings"},{title:"Rating hide label mixin",filename:"rating",url:"rating.html#rating-hide-label-mixin"},{title:"resets",filename:"resets",url:"resets.html"},{title:"Resets",filename:"resets",url:"resets.html#resets"},{title:"responsive",filename:"responsive",url:"responsive.html"},{title:"Responsive",filename:"responsive",url:"responsive.html#responsive"},{title:"Responsive mixins usage",filename:"responsive",url:"responsive.html#responsive-mixins-usage"},{title:"Media query style groups separation variables",filename:"responsive",url:"responsive.html#media-query-style-groups-separation-variables"},{title:"Responsive breakpoints",filename:"responsive",url:"responsive.html#responsive-breakpoints"},{title:"sections",filename:"sections",url:"sections.html"},{title:"Tabs and accordions",filename:"sections",url:"sections.html#tabs-and-accordions"},{title:"Tabs",filename:"sections",url:"sections.html#tabs"},{title:"Tabs mixin variables",filename:"sections",url:"sections.html#tabs-mixin-variables"},{title:"Tabs with content top border",filename:"sections",url:"sections.html#tabs-with-content-top-border"},{title:"Accordion",filename:"sections",url:"sections.html#accordion"},{title:"Accordion mixin variables",filename:"sections",url:"sections.html#accordion-mixin-variables"},{title:"Responsive tabs",filename:"sections",url:"sections.html#responsive-tabs"},{title:"Tabs Base",filename:"sections",url:"sections.html#tabs-base"},{title:"Accordion Base",filename:"sections",url:"sections.html#accordion-base"},{title:"tables",filename:"tables",url:"tables.html"},{title:"Tables",filename:"tables",url:"tables.html#tables"},{title:"Table mixin variables",filename:"tables",url:"tables.html#table-mixin-variables"},{title:"Table typography",filename:"tables",url:"tables.html#table-typography"},{title:"Table typography mixin variables",filename:"tables",url:"tables.html#table-typography-mixin-variables"},{title:"Table caption",filename:"tables",url:"tables.html#table-caption"},{title:"Table caption mixin variables",filename:"tables",url:"tables.html#table-caption-mixin-variables"},{title:"Table cells resize",filename:"tables",url:"tables.html#table-cells-resize"},{title:"Table cells resize variables",filename:"tables",url:"tables.html#table-cells-resize-variables"},{title:"Table background customization",filename:"tables",url:"tables.html#table-background-customization"},{title:"Table background mixin variables",filename:"tables",url:"tables.html#table-background-mixin-variables"},{title:"Table borders customization",filename:"tables",url:"tables.html#table-borders-customization"},{title:"Table borders mixin variables",filename:"tables",url:"tables.html#table-borders-mixin-variables"},{title:"Table with horizontal borders",filename:"tables",url:"tables.html#table-with-horizontal-borders"},{title:"Table with vertical borders",filename:"tables",url:"tables.html#table-with-vertical-borders"},{title:"Table with light borders",filename:"tables",url:"tables.html#table-with-light-borders"},{title:"Table without borders",filename:"tables",url:"tables.html#table-without-borders"},{title:"Striped table",filename:"tables",url:"tables.html#striped-table"},{title:"Striped table mixin variables",filename:"tables",url:"tables.html#striped-table-mixin-variables"},{title:"Table with rows hover",filename:"tables",url:"tables.html#table-with-rows-hover"},{title:"Table with rows hover mixin variables",filename:"tables",url:"tables.html#table-with-rows-hover-mixin-variables"},{title:"Responsive table technics #1",filename:"tables",url:"tables.html#responsive-table-technics-1"},{title:"Responsive table technics #2",filename:"tables",url:"tables.html#responsive-table-technics-2"},{title:"Responsive table technics #2 mixin variables",filename:"tables",url:"tables.html#responsive-table-technics-2-mixin-variables"},{title:"tooltips",filename:"tooltips",url:"tooltips.html"},{title:"Tooltips",filename:"tooltips",url:"tooltips.html#tooltips"},{title:"Tooltips variables",filename:"tooltips",url:"tooltips.html#tooltips-variables"},{title:"typography",filename:"typography",url:"typography.html"},{title:"Typogrphy",filename:"typography",url:"typography.html#typogrphy"},{title:"Typography variables",filename:"typography",url:"typography.html#typography-variables"},{title:"Font-size mixin",filename:"typography",url:"typography.html#fontsize-mixin"},{title:"Line-height mixin",filename:"typography",url:"typography.html#lineheight-mixin"},{title:"Word breaking mixin",filename:"typography",url:"typography.html#word-breaking-mixin"},{title:"Font face mixin",filename:"typography",url:"typography.html#font-face-mixin"},{title:"Text overflow mixin",filename:"typography",url:"typography.html#text-overflow-mixin"},{title:"Text hide",filename:"typography",url:"typography.html#text-hide"},{title:"Hyphens",filename:"typography",url:"typography.html#hyphens"},{title:"Font style and color",filename:"typography",url:"typography.html#font-style-and-color"},{title:"Font style mixin variables",filename:"typography",url:"typography.html#font-style-mixin-variables"},{title:"Reset list styles",filename:"typography",url:"typography.html#reset-list-styles"},{title:"Reset list styles variables",filename:"typography",url:"typography.html#reset-list-styles-variables"},{title:"Inline-block list item styling",filename:"typography",url:"typography.html#inlineblock-list-item-styling"},{title:"Link styling mixin",filename:"typography",url:"typography.html#link-styling-mixin"},{title:"Link styling mixin variables",filename:"typography",url:"typography.html#link-styling-mixin-variables"},{title:"Heading styling mixin",filename:"typography",url:"typography.html#heading-styling-mixin"},{title:"Base typography mixins",filename:"typography",url:"typography.html#base-typography-mixins"},{title:"Base typography mixin variables",filename:"typography",url:"typography.html#base-typography-mixin-variables"},{title:"Headings typography mixin",filename:"typography",url:"typography.html#headings-typography-mixin"},{title:"Headings typography mixin variables",filename:"typography",url:"typography.html#headings-typography-mixin-variables"},{title:"Typography links mixin",filename:"typography",url:"typography.html#typography-links-mixin"},{title:"Typography lists mixin",filename:"typography",url:"typography.html#typography-lists-mixin"},{title:"Typography lists mixin variables",filename:"typography",url:"typography.html#typography-lists-mixin-variables"},{title:"Typography code elements mixin",filename:"typography",url:"typography.html#typography-code-elements-mixin"},{title:"Typography code mixin variables",filename:"typography",url:"typography.html#typography-code-mixin-variables"},{title:"Typography blockquote",filename:"typography",url:"typography.html#typography-blockquote"},{title:"Typography blockquote mixin variables",filename:"typography",url:"typography.html#typography-blockquote-mixin-variables"},{title:"utilities",filename:"utilities",url:"utilities.html"},{title:"Utilities",filename:"utilities",url:"utilities.html#utilities"},{title:".lib-clearfix()",filename:"utilities",url:"utilities.html#libclearfix"},{title:".lib-visibility-hidden()",filename:"utilities",url:"utilities.html#libvisibilityhidden"},{title:".lib-visually-hidden()",filename:"utilities",url:"utilities.html#libvisuallyhidden"},{title:".lib-visually-hidden-reset()",filename:"utilities",url:"utilities.html#libvisuallyhiddenreset"},{title:".lib-css()",filename:"utilities",url:"utilities.html#libcss"},{title:".lib-css() variables",filename:"utilities",url:"utilities.html#libcss-variables"},{title:".lib-rotate()",filename:"utilities",url:"utilities.html#librotate"},{title:".lib-rotate() variables",filename:"utilities",url:"utilities.html#librotate-variables"},{title:".lib-input-placeholder()",filename:"utilities",url:"utilities.html#libinputplaceholder"},{title:".lib-input-placeholder() variables",filename:"utilities",url:"utilities.html#libinputplaceholder-variables"},{title:".lib-background-gradient()",filename:"utilities",url:"utilities.html#libbackgroundgradient"},{title:".lib-background-gradient() variables",filename:"utilities",url:"utilities.html#libbackgroundgradient-variables"},{title:"variables",filename:"variables",url:"variables.html"},{title:"List of Global Variables",filename:"variables",url:"variables.html#list-of-global-variables"},{title:"Table with rows hover mixin variables",filename:"variables",url:"variables.html#table-with-rows-hover-mixin-variables"},{title:"docs",filename:"docs",url:"docs.html"},{title:"Documentation",filename:"docs",url:"docs.html#documentation"}];(function(){"use strict";var b=function(a,b){return Array.prototype.indexOf.call(a,b)!==-1},c=function(a,b){return Array.prototype.filter.call(a,b)},d=function(a,b){return Array.prototype.forEach.call(a,b)},e=document.getElementsByTagName("body")[0];e.addEventListener("click",function(a){var b=a.target;b.tagName.toLowerCase()==="svg"&&(b=b.parentNode);var c=!1;b.dataset.toggle!=null&&(a.preventDefault(),b.classList.contains("is-active")||(c=!0)),d(e.querySelectorAll("[data-toggle]"),function(a){a.classList.remove("is-active"),document.getElementById(a.dataset.toggle).hidden=!0}),c&&(b.classList.add("is-active"),document.getElementById(b.dataset.toggle).hidden=!1)}),function(){var f=e.getElementsByClassName("nav")[0];if(!f)return;var g=document.createElement("ul");g.className="nav-results",g.id="nav-search",g.hidden=!0,d(a,function(a){var b,c,d;b=document.createElement("li"),b._title=a.title.toLowerCase(),b.hidden=!0,b.appendChild(c=document.createElement("a")),c.href=a.url,c.innerHTML=a.title,c.appendChild(d=document.createElement("span")),d.innerHTML=a.filename,d.className="nav-results-filename",g.appendChild(b)}),f.appendChild(g);var h=g.children,i=function(a){d(h,function(a){a.hidden=!0});var b=this.value.toLowerCase(),e=[];b!==""&&(e=c(h,function(a){return a._title.indexOf(b)!==-1})),e.length>0?(d(e,function(a){a.hidden=!1}),g.hidden=!1):g.hidden=!0},j=f.querySelector('input[type="search"]');j.addEventListener("keyup",i),j.addEventListener("focus",i),e.addEventListener("click",function(a){if(a.target.classList&&a.target.classList.contains("search"))return;g.hidden=!0}),g.addEventListener("click",function(a){j.value=""});var k=document.createElement("ul");k.id="nav-toc",k.hidden=!0,k.className="nav-results toc-list",c(e.getElementsByTagName("*"),function(a){return b(["h1","h2","h3"],a.tagName.toLowerCase())}).map(function(a){var b=document.createElement("li"),c=document.createElement("a"),d=a.tagName.toLowerCase()[1];c.classList.add("level-"+d),b.appendChild(c),c.href="#"+a.id,c.innerHTML=a.innerHTML,k.appendChild(b)}),f.appendChild(k)}()})(),function(){"use strict";if(location.hash==="#__preview__"||location.protocol==="data:")return;var a=function(a,b){return Array.prototype.forEach.call(a,b)},b=function(a,b){var e=Array.prototype.slice.call(arguments,2);return d(a,function(a){return(c(b)?b||a:a[b]).apply(a,e)})},c=function(a){return Object.prototype.toString.call(a)==="[object Function]"},d=function(a,b){return Array.prototype.map.call(a,b)},e=function(a,b){return d(a,function(a){return a[b]})},f=function(a){var b={},c=a.split(";");for(var d=0;c.length>d;d++){var e=c[d].trim().split("=");b[e[0]]=e[1]}return b},g=function(a,c){return b(e(a,"classList"),"remove",c)},h=function(a,b){a.contentDocument.defaultView.postMessage(b,"*")},i=document.getElementsByTagName("head")[0],j=document.getElementsByTagName("body")[0],k=e(i.querySelectorAll('style[type="text/preview"]'),"innerHTML").join(""),l=e(i.querySelectorAll('script[type="text/preview"]'),"innerHTML").join(""),m=location.href.split("#")[0]+"#__preview__",n=document.createElement("iframe");n.src="data:text/html,",j.appendChild(n),n.addEventListener("load",function(){var b={sameOriginDataUri:!0};try{this.contentDocument,this.contentDocument||(b.sameOriginDataUri=!1)}catch(c){b.sameOriginDataUri=!1}this.parentNode.removeChild(this),a(j.getElementsByTagName("textarea"),function(a,c){o(a,b,c),q(),p(a)})});var o=function(a,b,c){var d,e,f;d=document.createElement("div"),d.appendChild(e=document.createElement("div")),d.className="preview",e.appendChild(f=document.createElement("iframe")),e.className="resizeable",f.setAttribute("scrolling","no"),f.name="iframe"+c++,f.addEventListener("load",function(){var c,d,e,f,g,i,j;j=this.contentDocument;if(!b.sameOriginDataUri&&this.src!==m)return;this.src===m&&(c=j.createElement("html"),c.appendChild(j.createElement("head")),c.appendChild(d=j.createElement("body")),d.innerHTML=a.textContent,j.replaceChild(c,j.documentElement)),g=j.createElement("head"),g.appendChild(f=j.createElement("style")),g.appendChild(e=j.createElement("script")),e.textContent=l,f.textContent=k,i=j.getElementsByTagName("head")[0],i.parentNode.replaceChild(g,i),h(this,"getHeight")});var g;b.sameOriginDataUri?g="data:text/html;charset=utf-8,"+encodeURIComponent("<!doctype html><html><head></head></body>"+a.textContent):g=m,f.setAttribute("src",g);var i=function(){f.contentDocument.body.innerHTML=this.value,h(f,"getHeight")};a.addEventListener("keypress",i),a.addEventListener("keyup",i),a.parentNode.insertBefore(d,a)},p=function(a){var b=document.createElement("div");b.className="preview-code",b.style.position="absolute",b.style.left="-9999px",j.appendChild(b);var c=parseInt(window.getComputedStyle(a).getPropertyValue("max-height"),10),d=function(a){b.textContent=this.value+"\n";var d=b.offsetHeight+2;d>=c?this.style.overflow="auto":this.style.overflow="hidden",this.style.height=b.offsetHeight+2+"px"};a.addEventListener("keypress",d),a.addEventListener("keyup",d),d.call(a)},q=function(){var b=j.getElementsByClassName("settings")[0],c=j.getElementsByClassName("resizeable"),d=30,e=function(b){document.cookie="preview-width="+b,a(c,function(a){b==="auto"&&(b=a.parentNode.offsetWidth),a.style.width=b+"px",h(a.getElementsByTagName("iframe")[0],"getHeight")})},i=f(document.cookie)["preview-width"];if(i){e(i),g(b.getElementsByClassName("is-active"),"is-active");var k=b.querySelector('button[data-width="'+i+'"]');k&&k.classList.add("is-active")}window.addEventListener("message",function(a){if(a.data==null||!a.source)return;var b=a.data,c=document.getElementsByName(a.source.name)[0];b.height!=null&&c&&(c.parentNode.style.height=b.height+d+"px")},!1),b&&c.length>0&&(b.hidden=!1,b.addEventListener("click",function(a){var c=a.target.tagName.toLowerCase(),d;if(c==="button")d=a.target;else{if(c!=="svg")return;d=a.target.parentNode}a.preventDefault(),g(b.getElementsByClassName("is-active"),"is-active"),d.classList.add("is-active");var f=d.dataset.width;e(f)}))}}()})()</script></body></html><!-- Generated with StyleDocco (http://jacobrask.github.com/styledocco). --> diff --git a/lib/web/css/docs/messages.html b/lib/web/css/docs/messages.html index 305266906e3d0..287bf1b0d3aa4 100644 --- a/lib/web/css/docs/messages.html +++ b/lib/web/css/docs/messages.html @@ -711,4 +711,4 @@ </tr> </table> </pre> -</div></article></section><div class="bar bottom"><div hidden class="settings container"><!-- Icons from http://iconmonstr.com--><button title="Desktop (1280)" data-width='1280'><svg viewBox="0 0 412 386" height="24" width="26" class="icon"><path d="m147.6,343.9c-4.5,15.9-26.2,37.6-42.1,42.1h201c-15.3,-4-38.1,-26.8-42.1,-42.1H147.6zM387,0.5H25c-13.8,0-25,11.2-25,25V294c0,13.8 11.2,25 25,25h362c13.8,0 25,-11.2 25,-25V25.5C412,11.7 400.8,0.5 387,0.5zM369.9,238.2H42.1L42.1,42.6 369.9,42.6V238.2z"></path></svg></button><button title="Laptop (1024)" data-width='1024'><svg viewBox="0 0 384 312" height="23" width="28" class="icon"><path d="m349.2,20.5c0,-11-9,-20-20,-20H53.6c-11,0-20,9-20,20v194H349.2v-194zm-27,167H60.6V27.5H322.2v160zm28,42H32.6L2.6,282.1c-3.5,6.2-3.5,13.8 0.1,19.9 3.6,6.2 10.2,9.9 17.3,9.9H363.1c7.1,0 13.7,-3.8 17.3,-10 3.6,-6.2 3.6,-13.8 0,-20l-30.2,-52.5zm-196.9,54 8,-23.5h60.5l8,23.5h-76.5z"></path></svg></button><button title="Tablet (768)" data-width='768'><svg viewBox="0 0 317 412" height="24" width="18" class="icon"><path d="M 316.5,380 V 32 c 0,-17.7 -14.3,-32 -32,-32 H 32 C 14.3,0 0,14.3 0,32 v 348 c 0,17.7 14.3,32 32,32 h 252.5 c 17.7,0 32,-14.3 32,-32 z M 40,367 V 45 H 276.5 V 367 H 40 z m 109.8,22.7 c 0,-4.7 3.8,-8.5 8.5,-8.5 4.7,0 8.5,3.8 8.5,8.5 0,4.7 -3.8,8.5 -8.5,8.5 -4.7,0 -8.5,-3.8 -8.5,-8.5 z"></path></svg></button><button title="Smart phone (320)" data-width='320'><svg viewBox="0 0 224 412" height="24" width="13" class="icon"><path d="M 190.7,0 H 33 C 14.8,0 0,14.8 0,33 v 346 c 0,18.2 14.8,33 33,33 h 157.7 c 18.2,0 33,-14.8 33,-33 V 33 c 0,-18.2 -14.8,-33 -33,-33 z M 94.3,30.2 h 37 c 2.2,0 4,1.8 4,4 0,2.2 -1.8,4 -4,4 h -37 c -2.2,0 -4,-1.8 -4,-4 0,-2.2 1.8,-4 4,-4 z m 18.5,362.8 c -8.8,0 -16,-7.2 -16,-16 0,-8.8 7.2,-16 16,-16 8.8,0 16,7.2 16,16 0,8.8 -7.2,16 -16,16 z M 198.6,343.8 H 25.1 V 68.2 h 173.5 v 275.5 z"></path></svg></button><button title="Feature phone (240)" data-width='240'><svg viewBox="0 0 201 412" height="24" width="12" class="icon"><path d="M 165.5,0.2 V 45 H 25 c -13.8,0 -25,11.2 -25,25 V 387 c 0,13.8 11.2,25 25,25 h 150.5 c 13.8,0 25,-11.2 25,-25 V 0.2 h -35 z M 65.2,366.5 H 34.2 v -24.5 h 31 v 24.5 z m 0,-44.3 H 34.2 v -24.5 h 31 v 24.5 z m 50.5,44.3 H 84.7 v -24.5 h 31 v 24.5 z m 0,-44.3 H 84.7 v -24.5 h 31 v 24.5 z m 50.5,44.3 h -31 v -24.5 h 31 v 24.5 z m 0,-44.3 h -31 v -24.5 h 31 v 24.5 z m 0,-59.3 h -132 V 95.4 h 132 V 262.9 z"></path></svg></button><button title="Auto (100%)" data-width="auto" class="auto is-active">Auto</button></div></div><script>(function(){var a=[{title:"actions-toolbar",filename:"actions-toolbar",url:"actions-toolbar.html"},{title:"Actions toolbar",filename:"actions-toolbar",url:"actions-toolbar.html#actions-toolbar"},{title:"Actions toolbar mixin variables",filename:"actions-toolbar",url:"actions-toolbar.html#actions-toolbar-mixin-variables"},{title:"Actions toolbar alignment",filename:"actions-toolbar",url:"actions-toolbar.html#actions-toolbar-alignment"},{title:"Reverse primary and secondary blocks",filename:"actions-toolbar",url:"actions-toolbar.html#reverse-primary-and-secondary-blocks"},{title:"Actions toolbar indents customizations",filename:"actions-toolbar",url:"actions-toolbar.html#actions-toolbar-indents-customizations"},{title:"Responsive actions toolbar",filename:"actions-toolbar",url:"actions-toolbar.html#responsive-actions-toolbar"},{title:"breadcrumbs",filename:"breadcrumbs",url:"breadcrumbs.html"},{title:"Breadcrumbs",filename:"breadcrumbs",url:"breadcrumbs.html#breadcrumbs"},{title:"Breadcrumbs variables",filename:"breadcrumbs",url:"breadcrumbs.html#breadcrumbs-variables"},{title:"Button-styled breadcrumbs with gradient background, border, and no separating symbol",filename:"breadcrumbs",url:"breadcrumbs.html#buttonstyled-breadcrumbs-with-gradient-background-border-and-no-separating-symbol"},{title:"Breadcrumbs with solid background",filename:"breadcrumbs",url:"breadcrumbs.html#breadcrumbs-with-solid-background"},{title:"buttons",filename:"buttons",url:"buttons.html"},{title:"Default button",filename:"buttons",url:"buttons.html#default-button"},{title:"Button variables",filename:"buttons",url:"buttons.html#button-variables"},{title:"Button as an icon",filename:"buttons",url:"buttons.html#button-as-an-icon"},{title:"Button with an icon on the left or right side of the text",filename:"buttons",url:"buttons.html#button-with-an-icon-on-the-left-or-right-side-of-the-text"},{title:"Button with fixed width",filename:"buttons",url:"buttons.html#button-with-fixed-width"},{title:"Primary button",filename:"buttons",url:"buttons.html#primary-button"},{title:"Primary button variables",filename:"buttons",url:"buttons.html#primary-button-variables"},{title:"Button with gradient background",filename:"buttons",url:"buttons.html#button-with-gradient-background"},{title:"Button as a link",filename:"buttons",url:"buttons.html#button-as-a-link"},{title:"Button as a link variables",filename:"buttons",url:"buttons.html#button-as-a-link-variables"},{title:"Link as a button",filename:"buttons",url:"buttons.html#link-as-a-button"},{title:"Button reset",filename:"buttons",url:"buttons.html#button-reset"},{title:"Button revert secondary color",filename:"buttons",url:"buttons.html#button-revert-secondary-color"},{title:"Button revert secondary color variables",filename:"buttons",url:"buttons.html#button-revert-secondary-color-variables"},{title:"Button revert secondary size",filename:"buttons",url:"buttons.html#button-revert-secondary-size"},{title:"Button revert secondary size variables",filename:"buttons",url:"buttons.html#button-revert-secondary-size-variables"},{title:"components",filename:"components",url:"components.html"},{title:"Components",filename:"components",url:"components.html#components"},{title:"Components Variables",filename:"components",url:"components.html#components-variables"},{title:"dropdowns",filename:"dropdowns",url:"dropdowns.html"},{title:"Drop-down and split buttons mixins",filename:"dropdowns",url:"dropdowns.html#dropdown-and-split-buttons-mixins"},{title:"Drop-down",filename:"dropdowns",url:"dropdowns.html#dropdown"},{title:"Drop-down variables",filename:"dropdowns",url:"dropdowns.html#dropdown-variables"},{title:"Drop-down with icon customization",filename:"dropdowns",url:"dropdowns.html#dropdown-with-icon-customization"},{title:"Modify dropdown list styles",filename:"dropdowns",url:"dropdowns.html#modify-dropdown-list-styles"},{title:"Split button",filename:"dropdowns",url:"dropdowns.html#split-button"},{title:"Split button variables",filename:"dropdowns",url:"dropdowns.html#split-button-variables"},{title:"Split button - button styling",filename:"dropdowns",url:"dropdowns.html#split-button-button-styling"},{title:"Split button icon customization",filename:"dropdowns",url:"dropdowns.html#split-button-icon-customization"},{title:"Split button drop-down list customization",filename:"dropdowns",url:"dropdowns.html#split-button-dropdown-list-customization"},{title:"forms",filename:"forms",url:"forms.html"},{title:"Forms mixins",filename:"forms",url:"forms.html#forms-mixins"},{title:"Global forms elements customization",filename:"forms",url:"forms.html#global-forms-elements-customization"},{title:"Fieldsets & fields customization",filename:"forms",url:"forms.html#fieldsets-fields-customization"},{title:"Fieldset and legend customization variables",filename:"forms",url:"forms.html#fieldset-and-legend-customization-variables"},{title:"Fields customization variables",filename:"forms",url:"forms.html#fields-customization-variables"},{title:"Required fields message customization variables",filename:"forms",url:"forms.html#required-fields-message-customization-variables"},{title:"Form element inputs customization",filename:"forms",url:"forms.html#form-element-inputs-customization"},{title:"Form element inputs customization variables",filename:"forms",url:"forms.html#form-element-inputs-customization-variables"},{title:"Form element choice",filename:"forms",url:"forms.html#form-element-choice"},{title:"Form element choice variables",filename:"forms",url:"forms.html#form-element-choice-variables"},{title:"Custom color",filename:"forms",url:"forms.html#custom-color"},{title:"Input number - input-text view",filename:"forms",url:"forms.html#input-number-inputtext-view"},{title:"Input search - input-text view",filename:"forms",url:"forms.html#input-search-inputtext-view"},{title:"Form validation",filename:"forms",url:"forms.html#form-validation"},{title:"Form validation variables",filename:"forms",url:"forms.html#form-validation-variables"},{title:"icons",filename:"icons",url:"icons.html"},{title:"Icons",filename:"icons",url:"icons.html#icons"},{title:"Icon with image or sprite",filename:"icons",url:"icons.html#icon-with-image-or-sprite"},{title:"Icon with image or sprite variables",filename:"icons",url:"icons.html#icon-with-image-or-sprite-variables"},{title:"Icon position for an icon with image or sprite",filename:"icons",url:"icons.html#icon-position-for-an-icon-with-image-or-sprite"},{title:"Position for icon with image or sprite mixin variables",filename:"icons",url:"icons.html#position-for-icon-with-image-or-sprite-mixin-variables"},{title:"Icon sprite position (with grid)",filename:"icons",url:"icons.html#icon-sprite-position-with-grid"},{title:"Icon sprite position variables",filename:"icons",url:"icons.html#icon-sprite-position-variables"},{title:"Image/sprite icon size",filename:"icons",url:"icons.html#imagesprite-icon-size"},{title:"Image/sprite icon size variables",filename:"icons",url:"icons.html#imagesprite-icon-size-variables"},{title:"Font icon",filename:"icons",url:"icons.html#font-icon"},{title:"Font icon variables",filename:"icons",url:"icons.html#font-icon-variables"},{title:"Change the size of font icon",filename:"icons",url:"icons.html#change-the-size-of-font-icon"},{title:"Change the size of font icon variables",filename:"icons",url:"icons.html#change-the-size-of-font-icon-variables"},{title:"Hide icon text",filename:"icons",url:"icons.html#hide-icon-text"},{title:"Sprite and font icons for Blank theme",filename:"icons",url:"icons.html#sprite-and-font-icons-for-blank-theme"},{title:"layout",filename:"layout",url:"layout.html"},{title:"Layout",filename:"layout",url:"layout.html#layout"},{title:"Layout global variables",filename:"layout",url:"layout.html#layout-global-variables"},{title:"Page layouts",filename:"layout",url:"layout.html#page-layouts"},{title:"Layout column",filename:"layout",url:"layout.html#layout-column"},{title:"Layout column variables",filename:"layout",url:"layout.html#layout-column-variables"},{title:"Layout width",filename:"layout",url:"layout.html#layout-width"},{title:"Layout width variables",filename:"layout",url:"layout.html#layout-width-variables"},{title:"lib",filename:"lib",url:"lib.html"},{title:"Including Magento UI library to your theme",filename:"lib",url:"lib.html#including-magento-ui-library-to-your-theme"},{title:"loaders",filename:"loaders",url:"loaders.html"},{title:"Loaders",filename:"loaders",url:"loaders.html#loaders"},{title:"Default loader variables",filename:"loaders",url:"loaders.html#default-loader-variables"},{title:"Loading",filename:"loaders",url:"loaders.html#loading"},{title:"Loading default variables",filename:"loaders",url:"loaders.html#loading-default-variables"},{title:"messages",filename:"messages",url:"messages.html"},{title:"Messages",filename:"messages",url:"messages.html#messages"},{title:"Information message",filename:"messages",url:"messages.html#information-message"},{title:"Warning message",filename:"messages",url:"messages.html#warning-message"},{title:"Error message",filename:"messages",url:"messages.html#error-message"},{title:"Success message",filename:"messages",url:"messages.html#success-message"},{title:"Notice message",filename:"messages",url:"messages.html#notice-message"},{title:"Message with inner icon",filename:"messages",url:"messages.html#message-with-inner-icon"},{title:"Message with lateral icon",filename:"messages",url:"messages.html#message-with-lateral-icon"},{title:"Custom message style",filename:"messages",url:"messages.html#custom-message-style"},{title:"Messages global variables",filename:"messages",url:"messages.html#messages-global-variables"},{title:"pages",filename:"pages",url:"pages.html"},{title:"Pagination HTML markup",filename:"pages",url:"pages.html#pagination-html-markup"},{title:"Pagination variables",filename:"pages",url:"pages.html#pagination-variables"},{title:"Pagination with label and gradient background on links",filename:"pages",url:"pages.html#pagination-with-label-and-gradient-background-on-links"},{title:'Pagination with "previous"..."next" text links and label',filename:"pages",url:"pages.html#pagination-with-previousnext-text-links-and-label"},{title:"Pagination without label, with solid background",filename:"pages",url:"pages.html#pagination-without-label-with-solid-background"},{title:"popups",filename:"popups",url:"popups.html"},{title:"Popups",filename:"popups",url:"popups.html#popups"},{title:"Popup variables",filename:"popups",url:"popups.html#popup-variables"},{title:"Window overlay mixin variables",filename:"popups",url:"popups.html#window-overlay-mixin-variables"},{title:"Fixed height popup",filename:"popups",url:"popups.html#fixed-height-popup"},{title:"Fixed content height popup",filename:"popups",url:"popups.html#fixed-content-height-popup"},{title:"Margins for header, content and footer block in popup",filename:"popups",url:"popups.html#margins-for-header-content-and-footer-block-in-popup"},{title:"Popup titles styled as theme headings",filename:"popups",url:"popups.html#popup-titles-styled-as-theme-headings"},{title:"Popup action toolbar",filename:"popups",url:"popups.html#popup-action-toolbar"},{title:"Popup Close button without an icon",filename:"popups",url:"popups.html#popup-close-button-without-an-icon"},{title:"Modify the icon of popup Close button",filename:"popups",url:"popups.html#modify-the-icon-of-popup-close-button"},{title:"Modify overlay styles",filename:"popups",url:"popups.html#modify-overlay-styles"},{title:"rating",filename:"rating",url:"rating.html"},{title:"Ratings",filename:"rating",url:"rating.html#ratings"},{title:"Global rating variables",filename:"rating",url:"rating.html#global-rating-variables"},{title:"Rating with vote",filename:"rating",url:"rating.html#rating-with-vote"},{title:"Rating with vote icons number customization",filename:"rating",url:"rating.html#rating-with-vote-icons-number-customization"},{title:"Rating with vote icons colors customization",filename:"rating",url:"rating.html#rating-with-vote-icons-colors-customization"},{title:"Rating with vote icons symbol customization",filename:"rating",url:"rating.html#rating-with-vote-icons-symbol-customization"},{title:"Accessible rating with vote",filename:"rating",url:"rating.html#accessible-rating-with-vote"},{title:"Rating summary",filename:"rating",url:"rating.html#rating-summary"},{title:"Rating summary icons number customization",filename:"rating",url:"rating.html#rating-summary-icons-number-customization"},{title:"Rating summary icons color customization",filename:"rating",url:"rating.html#rating-summary-icons-color-customization"},{title:"Rating summary icons symbol customization",filename:"rating",url:"rating.html#rating-summary-icons-symbol-customization"},{title:"Rating summary hide label",filename:"rating",url:"rating.html#rating-summary-hide-label"},{title:"Rating summary multiple ratings",filename:"rating",url:"rating.html#rating-summary-multiple-ratings"},{title:"Rating hide label mixin",filename:"rating",url:"rating.html#rating-hide-label-mixin"},{title:"resets",filename:"resets",url:"resets.html"},{title:"Resets",filename:"resets",url:"resets.html#resets"},{title:"responsive",filename:"responsive",url:"responsive.html"},{title:"Responsive",filename:"responsive",url:"responsive.html#responsive"},{title:"Responsive mixins usage",filename:"responsive",url:"responsive.html#responsive-mixins-usage"},{title:"Media query style groups separation variables",filename:"responsive",url:"responsive.html#media-query-style-groups-separation-variables"},{title:"Responsive breakpoints",filename:"responsive",url:"responsive.html#responsive-breakpoints"},{title:"sections",filename:"sections",url:"sections.html"},{title:"Tabs and accordions",filename:"sections",url:"sections.html#tabs-and-accordions"},{title:"Tabs",filename:"sections",url:"sections.html#tabs"},{title:"Tabs mixin variables",filename:"sections",url:"sections.html#tabs-mixin-variables"},{title:"Tabs with content top border",filename:"sections",url:"sections.html#tabs-with-content-top-border"},{title:"Accordion",filename:"sections",url:"sections.html#accordion"},{title:"Accordion mixin variables",filename:"sections",url:"sections.html#accordion-mixin-variables"},{title:"Responsive tabs",filename:"sections",url:"sections.html#responsive-tabs"},{title:"Tabs Base",filename:"sections",url:"sections.html#tabs-base"},{title:"Accordion Base",filename:"sections",url:"sections.html#accordion-base"},{title:"tables",filename:"tables",url:"tables.html"},{title:"Tables",filename:"tables",url:"tables.html#tables"},{title:"Table mixin variables",filename:"tables",url:"tables.html#table-mixin-variables"},{title:"Table typography",filename:"tables",url:"tables.html#table-typography"},{title:"Table typography mixin variables",filename:"tables",url:"tables.html#table-typography-mixin-variables"},{title:"Table caption",filename:"tables",url:"tables.html#table-caption"},{title:"Table caption mixin variables",filename:"tables",url:"tables.html#table-caption-mixin-variables"},{title:"Table cells resize",filename:"tables",url:"tables.html#table-cells-resize"},{title:"Table cells resize variables",filename:"tables",url:"tables.html#table-cells-resize-variables"},{title:"Table background customization",filename:"tables",url:"tables.html#table-background-customization"},{title:"Table background mixin variables",filename:"tables",url:"tables.html#table-background-mixin-variables"},{title:"Table borders customization",filename:"tables",url:"tables.html#table-borders-customization"},{title:"Table borders mixin variables",filename:"tables",url:"tables.html#table-borders-mixin-variables"},{title:"Table with horizontal borders",filename:"tables",url:"tables.html#table-with-horizontal-borders"},{title:"Table with vertical borders",filename:"tables",url:"tables.html#table-with-vertical-borders"},{title:"Table with light borders",filename:"tables",url:"tables.html#table-with-light-borders"},{title:"Table without borders",filename:"tables",url:"tables.html#table-without-borders"},{title:"Striped table",filename:"tables",url:"tables.html#striped-table"},{title:"Striped table mixin variables",filename:"tables",url:"tables.html#striped-table-mixin-variables"},{title:"Table with rows hover",filename:"tables",url:"tables.html#table-with-rows-hover"},{title:"Table with rows hover mixin variables",filename:"tables",url:"tables.html#table-with-rows-hover-mixin-variables"},{title:"Responsive table technics #1",filename:"tables",url:"tables.html#responsive-table-technics-1"},{title:"Responsive table technics #2",filename:"tables",url:"tables.html#responsive-table-technics-2"},{title:"Responsive table technics #2 mixin variables",filename:"tables",url:"tables.html#responsive-table-technics-2-mixin-variables"},{title:"tooltips",filename:"tooltips",url:"tooltips.html"},{title:"Tooltips",filename:"tooltips",url:"tooltips.html#tooltips"},{title:"Tooltips variables",filename:"tooltips",url:"tooltips.html#tooltips-variables"},{title:"typography",filename:"typography",url:"typography.html"},{title:"Typogrphy",filename:"typography",url:"typography.html#typogrphy"},{title:"Typography variables",filename:"typography",url:"typography.html#typography-variables"},{title:"Font-size mixin",filename:"typography",url:"typography.html#fontsize-mixin"},{title:"Line-height mixin",filename:"typography",url:"typography.html#lineheight-mixin"},{title:"Word breaking mixin",filename:"typography",url:"typography.html#word-breaking-mixin"},{title:"Font face mixin",filename:"typography",url:"typography.html#font-face-mixin"},{title:"Text overflow mixin",filename:"typography",url:"typography.html#text-overflow-mixin"},{title:"Text hide",filename:"typography",url:"typography.html#text-hide"},{title:"Hyphens",filename:"typography",url:"typography.html#hyphens"},{title:"Font style and color",filename:"typography",url:"typography.html#font-style-and-color"},{title:"Font style mixin variables",filename:"typography",url:"typography.html#font-style-mixin-variables"},{title:"Reset list styles",filename:"typography",url:"typography.html#reset-list-styles"},{title:"Reset list styles variables",filename:"typography",url:"typography.html#reset-list-styles-variables"},{title:"Inline-block list item styling",filename:"typography",url:"typography.html#inlineblock-list-item-styling"},{title:"Link styling mixin",filename:"typography",url:"typography.html#link-styling-mixin"},{title:"Link styling mixin variables",filename:"typography",url:"typography.html#link-styling-mixin-variables"},{title:"Heading styling mixin",filename:"typography",url:"typography.html#heading-styling-mixin"},{title:"Base typography mixins",filename:"typography",url:"typography.html#base-typography-mixins"},{title:"Base typography mixin variables",filename:"typography",url:"typography.html#base-typography-mixin-variables"},{title:"Headings typography mixin",filename:"typography",url:"typography.html#headings-typography-mixin"},{title:"Headings typography mixin variables",filename:"typography",url:"typography.html#headings-typography-mixin-variables"},{title:"Typography links mixin",filename:"typography",url:"typography.html#typography-links-mixin"},{title:"Typography lists mixin",filename:"typography",url:"typography.html#typography-lists-mixin"},{title:"Typography lists mixin variables",filename:"typography",url:"typography.html#typography-lists-mixin-variables"},{title:"Typography code elements mixin",filename:"typography",url:"typography.html#typography-code-elements-mixin"},{title:"Typography code mixin variables",filename:"typography",url:"typography.html#typography-code-mixin-variables"},{title:"Typography blockquote",filename:"typography",url:"typography.html#typography-blockquote"},{title:"Typography blockquote mixin variables",filename:"typography",url:"typography.html#typography-blockquote-mixin-variables"},{title:"utilities",filename:"utilities",url:"utilities.html"},{title:"Utilities",filename:"utilities",url:"utilities.html#utilities"},{title:".lib-clearfix()",filename:"utilities",url:"utilities.html#libclearfix"},{title:".lib-visibility-hidden()",filename:"utilities",url:"utilities.html#libvisibilityhidden"},{title:".lib-visually-hidden()",filename:"utilities",url:"utilities.html#libvisuallyhidden"},{title:".lib-visually-hidden-reset()",filename:"utilities",url:"utilities.html#libvisuallyhiddenreset"},{title:".lib-css()",filename:"utilities",url:"utilities.html#libcss"},{title:".lib-css() variables",filename:"utilities",url:"utilities.html#libcss-variables"},{title:".lib-rotate()",filename:"utilities",url:"utilities.html#librotate"},{title:".lib-rotate() variables",filename:"utilities",url:"utilities.html#librotate-variables"},{title:".lib-input-placeholder()",filename:"utilities",url:"utilities.html#libinputplaceholder"},{title:".lib-input-placeholder() variables",filename:"utilities",url:"utilities.html#libinputplaceholder-variables"},{title:".lib-background-gradient()",filename:"utilities",url:"utilities.html#libbackgroundgradient"},{title:".lib-background-gradient() variables",filename:"utilities",url:"utilities.html#libbackgroundgradient-variables"},{title:".lib-url-check()",filename:"utilities",url:"utilities.html#liburlcheck"},{title:".lib-url-check() variables",filename:"utilities",url:"utilities.html#liburlcheck-variables"},{title:"variables",filename:"variables",url:"variables.html"},{title:"List of Global Variables",filename:"variables",url:"variables.html#list-of-global-variables"},{title:"Table with rows hover mixin variables",filename:"variables",url:"variables.html#table-with-rows-hover-mixin-variables"},{title:"docs",filename:"docs",url:"docs.html"},{title:"Documentation",filename:"docs",url:"docs.html#documentation"}];(function(){"use strict";var b=function(a,b){return Array.prototype.indexOf.call(a,b)!==-1},c=function(a,b){return Array.prototype.filter.call(a,b)},d=function(a,b){return Array.prototype.forEach.call(a,b)},e=document.getElementsByTagName("body")[0];e.addEventListener("click",function(a){var b=a.target;b.tagName.toLowerCase()==="svg"&&(b=b.parentNode);var c=!1;b.dataset.toggle!=null&&(a.preventDefault(),b.classList.contains("is-active")||(c=!0)),d(e.querySelectorAll("[data-toggle]"),function(a){a.classList.remove("is-active"),document.getElementById(a.dataset.toggle).hidden=!0}),c&&(b.classList.add("is-active"),document.getElementById(b.dataset.toggle).hidden=!1)}),function(){var f=e.getElementsByClassName("nav")[0];if(!f)return;var g=document.createElement("ul");g.className="nav-results",g.id="nav-search",g.hidden=!0,d(a,function(a){var b,c,d;b=document.createElement("li"),b._title=a.title.toLowerCase(),b.hidden=!0,b.appendChild(c=document.createElement("a")),c.href=a.url,c.innerHTML=a.title,c.appendChild(d=document.createElement("span")),d.innerHTML=a.filename,d.className="nav-results-filename",g.appendChild(b)}),f.appendChild(g);var h=g.children,i=function(a){d(h,function(a){a.hidden=!0});var b=this.value.toLowerCase(),e=[];b!==""&&(e=c(h,function(a){return a._title.indexOf(b)!==-1})),e.length>0?(d(e,function(a){a.hidden=!1}),g.hidden=!1):g.hidden=!0},j=f.querySelector('input[type="search"]');j.addEventListener("keyup",i),j.addEventListener("focus",i),e.addEventListener("click",function(a){if(a.target.classList&&a.target.classList.contains("search"))return;g.hidden=!0}),g.addEventListener("click",function(a){j.value=""});var k=document.createElement("ul");k.id="nav-toc",k.hidden=!0,k.className="nav-results toc-list",c(e.getElementsByTagName("*"),function(a){return b(["h1","h2","h3"],a.tagName.toLowerCase())}).map(function(a){var b=document.createElement("li"),c=document.createElement("a"),d=a.tagName.toLowerCase()[1];c.classList.add("level-"+d),b.appendChild(c),c.href="#"+a.id,c.innerHTML=a.innerHTML,k.appendChild(b)}),f.appendChild(k)}()})(),function(){"use strict";if(location.hash==="#__preview__"||location.protocol==="data:")return;var a=function(a,b){return Array.prototype.forEach.call(a,b)},b=function(a,b){var e=Array.prototype.slice.call(arguments,2);return d(a,function(a){return(c(b)?b||a:a[b]).apply(a,e)})},c=function(a){return Object.prototype.toString.call(a)==="[object Function]"},d=function(a,b){return Array.prototype.map.call(a,b)},e=function(a,b){return d(a,function(a){return a[b]})},f=function(a){var b={},c=a.split(";");for(var d=0;c.length>d;d++){var e=c[d].trim().split("=");b[e[0]]=e[1]}return b},g=function(a,c){return b(e(a,"classList"),"remove",c)},h=function(a,b){a.contentDocument.defaultView.postMessage(b,"*")},i=document.getElementsByTagName("head")[0],j=document.getElementsByTagName("body")[0],k=e(i.querySelectorAll('style[type="text/preview"]'),"innerHTML").join(""),l=e(i.querySelectorAll('script[type="text/preview"]'),"innerHTML").join(""),m=location.href.split("#")[0]+"#__preview__",n=document.createElement("iframe");n.src="data:text/html,",j.appendChild(n),n.addEventListener("load",function(){var b={sameOriginDataUri:!0};try{this.contentDocument,this.contentDocument||(b.sameOriginDataUri=!1)}catch(c){b.sameOriginDataUri=!1}this.parentNode.removeChild(this),a(j.getElementsByTagName("textarea"),function(a,c){o(a,b,c),q(),p(a)})});var o=function(a,b,c){var d,e,f;d=document.createElement("div"),d.appendChild(e=document.createElement("div")),d.className="preview",e.appendChild(f=document.createElement("iframe")),e.className="resizeable",f.setAttribute("scrolling","no"),f.name="iframe"+c++,f.addEventListener("load",function(){var c,d,e,f,g,i,j;j=this.contentDocument;if(!b.sameOriginDataUri&&this.src!==m)return;this.src===m&&(c=j.createElement("html"),c.appendChild(j.createElement("head")),c.appendChild(d=j.createElement("body")),d.innerHTML=a.textContent,j.replaceChild(c,j.documentElement)),g=j.createElement("head"),g.appendChild(f=j.createElement("style")),g.appendChild(e=j.createElement("script")),e.textContent=l,f.textContent=k,i=j.getElementsByTagName("head")[0],i.parentNode.replaceChild(g,i),h(this,"getHeight")});var g;b.sameOriginDataUri?g="data:text/html;charset=utf-8,"+encodeURIComponent("<!doctype html><html><head></head></body>"+a.textContent):g=m,f.setAttribute("src",g);var i=function(){f.contentDocument.body.innerHTML=this.value,h(f,"getHeight")};a.addEventListener("keypress",i),a.addEventListener("keyup",i),a.parentNode.insertBefore(d,a)},p=function(a){var b=document.createElement("div");b.className="preview-code",b.style.position="absolute",b.style.left="-9999px",j.appendChild(b);var c=parseInt(window.getComputedStyle(a).getPropertyValue("max-height"),10),d=function(a){b.textContent=this.value+"\n";var d=b.offsetHeight+2;d>=c?this.style.overflow="auto":this.style.overflow="hidden",this.style.height=b.offsetHeight+2+"px"};a.addEventListener("keypress",d),a.addEventListener("keyup",d),d.call(a)},q=function(){var b=j.getElementsByClassName("settings")[0],c=j.getElementsByClassName("resizeable"),d=30,e=function(b){document.cookie="preview-width="+b,a(c,function(a){b==="auto"&&(b=a.parentNode.offsetWidth),a.style.width=b+"px",h(a.getElementsByTagName("iframe")[0],"getHeight")})},i=f(document.cookie)["preview-width"];if(i){e(i),g(b.getElementsByClassName("is-active"),"is-active");var k=b.querySelector('button[data-width="'+i+'"]');k&&k.classList.add("is-active")}window.addEventListener("message",function(a){if(a.data==null||!a.source)return;var b=a.data,c=document.getElementsByName(a.source.name)[0];b.height!=null&&c&&(c.parentNode.style.height=b.height+d+"px")},!1),b&&c.length>0&&(b.hidden=!1,b.addEventListener("click",function(a){var c=a.target.tagName.toLowerCase(),d;if(c==="button")d=a.target;else{if(c!=="svg")return;d=a.target.parentNode}a.preventDefault(),g(b.getElementsByClassName("is-active"),"is-active"),d.classList.add("is-active");var f=d.dataset.width;e(f)}))}}()})()</script></body></html><!-- Generated with StyleDocco (http://jacobrask.github.com/styledocco). --> +</div></article></section><div class="bar bottom"><div hidden class="settings container"><!-- Icons from http://iconmonstr.com--><button title="Desktop (1280)" data-width='1280'><svg viewBox="0 0 412 386" height="24" width="26" class="icon"><path d="m147.6,343.9c-4.5,15.9-26.2,37.6-42.1,42.1h201c-15.3,-4-38.1,-26.8-42.1,-42.1H147.6zM387,0.5H25c-13.8,0-25,11.2-25,25V294c0,13.8 11.2,25 25,25h362c13.8,0 25,-11.2 25,-25V25.5C412,11.7 400.8,0.5 387,0.5zM369.9,238.2H42.1L42.1,42.6 369.9,42.6V238.2z"></path></svg></button><button title="Laptop (1024)" data-width='1024'><svg viewBox="0 0 384 312" height="23" width="28" class="icon"><path d="m349.2,20.5c0,-11-9,-20-20,-20H53.6c-11,0-20,9-20,20v194H349.2v-194zm-27,167H60.6V27.5H322.2v160zm28,42H32.6L2.6,282.1c-3.5,6.2-3.5,13.8 0.1,19.9 3.6,6.2 10.2,9.9 17.3,9.9H363.1c7.1,0 13.7,-3.8 17.3,-10 3.6,-6.2 3.6,-13.8 0,-20l-30.2,-52.5zm-196.9,54 8,-23.5h60.5l8,23.5h-76.5z"></path></svg></button><button title="Tablet (768)" data-width='768'><svg viewBox="0 0 317 412" height="24" width="18" class="icon"><path d="M 316.5,380 V 32 c 0,-17.7 -14.3,-32 -32,-32 H 32 C 14.3,0 0,14.3 0,32 v 348 c 0,17.7 14.3,32 32,32 h 252.5 c 17.7,0 32,-14.3 32,-32 z M 40,367 V 45 H 276.5 V 367 H 40 z m 109.8,22.7 c 0,-4.7 3.8,-8.5 8.5,-8.5 4.7,0 8.5,3.8 8.5,8.5 0,4.7 -3.8,8.5 -8.5,8.5 -4.7,0 -8.5,-3.8 -8.5,-8.5 z"></path></svg></button><button title="Smart phone (320)" data-width='320'><svg viewBox="0 0 224 412" height="24" width="13" class="icon"><path d="M 190.7,0 H 33 C 14.8,0 0,14.8 0,33 v 346 c 0,18.2 14.8,33 33,33 h 157.7 c 18.2,0 33,-14.8 33,-33 V 33 c 0,-18.2 -14.8,-33 -33,-33 z M 94.3,30.2 h 37 c 2.2,0 4,1.8 4,4 0,2.2 -1.8,4 -4,4 h -37 c -2.2,0 -4,-1.8 -4,-4 0,-2.2 1.8,-4 4,-4 z m 18.5,362.8 c -8.8,0 -16,-7.2 -16,-16 0,-8.8 7.2,-16 16,-16 8.8,0 16,7.2 16,16 0,8.8 -7.2,16 -16,16 z M 198.6,343.8 H 25.1 V 68.2 h 173.5 v 275.5 z"></path></svg></button><button title="Feature phone (240)" data-width='240'><svg viewBox="0 0 201 412" height="24" width="12" class="icon"><path d="M 165.5,0.2 V 45 H 25 c -13.8,0 -25,11.2 -25,25 V 387 c 0,13.8 11.2,25 25,25 h 150.5 c 13.8,0 25,-11.2 25,-25 V 0.2 h -35 z M 65.2,366.5 H 34.2 v -24.5 h 31 v 24.5 z m 0,-44.3 H 34.2 v -24.5 h 31 v 24.5 z m 50.5,44.3 H 84.7 v -24.5 h 31 v 24.5 z m 0,-44.3 H 84.7 v -24.5 h 31 v 24.5 z m 50.5,44.3 h -31 v -24.5 h 31 v 24.5 z m 0,-44.3 h -31 v -24.5 h 31 v 24.5 z m 0,-59.3 h -132 V 95.4 h 132 V 262.9 z"></path></svg></button><button title="Auto (100%)" data-width="auto" class="auto is-active">Auto</button></div></div><script>(function(){var a=[{title:"actions-toolbar",filename:"actions-toolbar",url:"actions-toolbar.html"},{title:"Actions toolbar",filename:"actions-toolbar",url:"actions-toolbar.html#actions-toolbar"},{title:"Actions toolbar mixin variables",filename:"actions-toolbar",url:"actions-toolbar.html#actions-toolbar-mixin-variables"},{title:"Actions toolbar alignment",filename:"actions-toolbar",url:"actions-toolbar.html#actions-toolbar-alignment"},{title:"Reverse primary and secondary blocks",filename:"actions-toolbar",url:"actions-toolbar.html#reverse-primary-and-secondary-blocks"},{title:"Actions toolbar indents customizations",filename:"actions-toolbar",url:"actions-toolbar.html#actions-toolbar-indents-customizations"},{title:"Responsive actions toolbar",filename:"actions-toolbar",url:"actions-toolbar.html#responsive-actions-toolbar"},{title:"breadcrumbs",filename:"breadcrumbs",url:"breadcrumbs.html"},{title:"Breadcrumbs",filename:"breadcrumbs",url:"breadcrumbs.html#breadcrumbs"},{title:"Breadcrumbs variables",filename:"breadcrumbs",url:"breadcrumbs.html#breadcrumbs-variables"},{title:"Button-styled breadcrumbs with gradient background, border, and no separating symbol",filename:"breadcrumbs",url:"breadcrumbs.html#buttonstyled-breadcrumbs-with-gradient-background-border-and-no-separating-symbol"},{title:"Breadcrumbs with solid background",filename:"breadcrumbs",url:"breadcrumbs.html#breadcrumbs-with-solid-background"},{title:"buttons",filename:"buttons",url:"buttons.html"},{title:"Default button",filename:"buttons",url:"buttons.html#default-button"},{title:"Button variables",filename:"buttons",url:"buttons.html#button-variables"},{title:"Button as an icon",filename:"buttons",url:"buttons.html#button-as-an-icon"},{title:"Button with an icon on the left or right side of the text",filename:"buttons",url:"buttons.html#button-with-an-icon-on-the-left-or-right-side-of-the-text"},{title:"Button with fixed width",filename:"buttons",url:"buttons.html#button-with-fixed-width"},{title:"Primary button",filename:"buttons",url:"buttons.html#primary-button"},{title:"Primary button variables",filename:"buttons",url:"buttons.html#primary-button-variables"},{title:"Button with gradient background",filename:"buttons",url:"buttons.html#button-with-gradient-background"},{title:"Button as a link",filename:"buttons",url:"buttons.html#button-as-a-link"},{title:"Button as a link variables",filename:"buttons",url:"buttons.html#button-as-a-link-variables"},{title:"Link as a button",filename:"buttons",url:"buttons.html#link-as-a-button"},{title:"Button reset",filename:"buttons",url:"buttons.html#button-reset"},{title:"Button revert secondary color",filename:"buttons",url:"buttons.html#button-revert-secondary-color"},{title:"Button revert secondary color variables",filename:"buttons",url:"buttons.html#button-revert-secondary-color-variables"},{title:"Button revert secondary size",filename:"buttons",url:"buttons.html#button-revert-secondary-size"},{title:"Button revert secondary size variables",filename:"buttons",url:"buttons.html#button-revert-secondary-size-variables"},{title:"components",filename:"components",url:"components.html"},{title:"Components",filename:"components",url:"components.html#components"},{title:"Components Variables",filename:"components",url:"components.html#components-variables"},{title:"dropdowns",filename:"dropdowns",url:"dropdowns.html"},{title:"Drop-down and split buttons mixins",filename:"dropdowns",url:"dropdowns.html#dropdown-and-split-buttons-mixins"},{title:"Drop-down",filename:"dropdowns",url:"dropdowns.html#dropdown"},{title:"Drop-down variables",filename:"dropdowns",url:"dropdowns.html#dropdown-variables"},{title:"Drop-down with icon customization",filename:"dropdowns",url:"dropdowns.html#dropdown-with-icon-customization"},{title:"Modify dropdown list styles",filename:"dropdowns",url:"dropdowns.html#modify-dropdown-list-styles"},{title:"Split button",filename:"dropdowns",url:"dropdowns.html#split-button"},{title:"Split button variables",filename:"dropdowns",url:"dropdowns.html#split-button-variables"},{title:"Split button - button styling",filename:"dropdowns",url:"dropdowns.html#split-button-button-styling"},{title:"Split button icon customization",filename:"dropdowns",url:"dropdowns.html#split-button-icon-customization"},{title:"Split button drop-down list customization",filename:"dropdowns",url:"dropdowns.html#split-button-dropdown-list-customization"},{title:"forms",filename:"forms",url:"forms.html"},{title:"Forms mixins",filename:"forms",url:"forms.html#forms-mixins"},{title:"Global forms elements customization",filename:"forms",url:"forms.html#global-forms-elements-customization"},{title:"Fieldsets & fields customization",filename:"forms",url:"forms.html#fieldsets-fields-customization"},{title:"Fieldset and legend customization variables",filename:"forms",url:"forms.html#fieldset-and-legend-customization-variables"},{title:"Fields customization variables",filename:"forms",url:"forms.html#fields-customization-variables"},{title:"Required fields message customization variables",filename:"forms",url:"forms.html#required-fields-message-customization-variables"},{title:"Form element inputs customization",filename:"forms",url:"forms.html#form-element-inputs-customization"},{title:"Form element inputs customization variables",filename:"forms",url:"forms.html#form-element-inputs-customization-variables"},{title:"Form element choice",filename:"forms",url:"forms.html#form-element-choice"},{title:"Form element choice variables",filename:"forms",url:"forms.html#form-element-choice-variables"},{title:"Custom color",filename:"forms",url:"forms.html#custom-color"},{title:"Input number - input-text view",filename:"forms",url:"forms.html#input-number-inputtext-view"},{title:"Input search - input-text view",filename:"forms",url:"forms.html#input-search-inputtext-view"},{title:"Form validation",filename:"forms",url:"forms.html#form-validation"},{title:"Form validation variables",filename:"forms",url:"forms.html#form-validation-variables"},{title:"icons",filename:"icons",url:"icons.html"},{title:"Icons",filename:"icons",url:"icons.html#icons"},{title:"Icon with image or sprite",filename:"icons",url:"icons.html#icon-with-image-or-sprite"},{title:"Icon with image or sprite variables",filename:"icons",url:"icons.html#icon-with-image-or-sprite-variables"},{title:"Icon position for an icon with image or sprite",filename:"icons",url:"icons.html#icon-position-for-an-icon-with-image-or-sprite"},{title:"Position for icon with image or sprite mixin variables",filename:"icons",url:"icons.html#position-for-icon-with-image-or-sprite-mixin-variables"},{title:"Icon sprite position (with grid)",filename:"icons",url:"icons.html#icon-sprite-position-with-grid"},{title:"Icon sprite position variables",filename:"icons",url:"icons.html#icon-sprite-position-variables"},{title:"Image/sprite icon size",filename:"icons",url:"icons.html#imagesprite-icon-size"},{title:"Image/sprite icon size variables",filename:"icons",url:"icons.html#imagesprite-icon-size-variables"},{title:"Font icon",filename:"icons",url:"icons.html#font-icon"},{title:"Font icon variables",filename:"icons",url:"icons.html#font-icon-variables"},{title:"Change the size of font icon",filename:"icons",url:"icons.html#change-the-size-of-font-icon"},{title:"Change the size of font icon variables",filename:"icons",url:"icons.html#change-the-size-of-font-icon-variables"},{title:"Hide icon text",filename:"icons",url:"icons.html#hide-icon-text"},{title:"Sprite and font icons for Blank theme",filename:"icons",url:"icons.html#sprite-and-font-icons-for-blank-theme"},{title:"layout",filename:"layout",url:"layout.html"},{title:"Layout",filename:"layout",url:"layout.html#layout"},{title:"Layout global variables",filename:"layout",url:"layout.html#layout-global-variables"},{title:"Page layouts",filename:"layout",url:"layout.html#page-layouts"},{title:"Layout column",filename:"layout",url:"layout.html#layout-column"},{title:"Layout column variables",filename:"layout",url:"layout.html#layout-column-variables"},{title:"Layout width",filename:"layout",url:"layout.html#layout-width"},{title:"Layout width variables",filename:"layout",url:"layout.html#layout-width-variables"},{title:"lib",filename:"lib",url:"lib.html"},{title:"Including Magento UI library to your theme",filename:"lib",url:"lib.html#including-magento-ui-library-to-your-theme"},{title:"loaders",filename:"loaders",url:"loaders.html"},{title:"Loaders",filename:"loaders",url:"loaders.html#loaders"},{title:"Default loader variables",filename:"loaders",url:"loaders.html#default-loader-variables"},{title:"Loading",filename:"loaders",url:"loaders.html#loading"},{title:"Loading default variables",filename:"loaders",url:"loaders.html#loading-default-variables"},{title:"messages",filename:"messages",url:"messages.html"},{title:"Messages",filename:"messages",url:"messages.html#messages"},{title:"Information message",filename:"messages",url:"messages.html#information-message"},{title:"Warning message",filename:"messages",url:"messages.html#warning-message"},{title:"Error message",filename:"messages",url:"messages.html#error-message"},{title:"Success message",filename:"messages",url:"messages.html#success-message"},{title:"Notice message",filename:"messages",url:"messages.html#notice-message"},{title:"Message with inner icon",filename:"messages",url:"messages.html#message-with-inner-icon"},{title:"Message with lateral icon",filename:"messages",url:"messages.html#message-with-lateral-icon"},{title:"Custom message style",filename:"messages",url:"messages.html#custom-message-style"},{title:"Messages global variables",filename:"messages",url:"messages.html#messages-global-variables"},{title:"pages",filename:"pages",url:"pages.html"},{title:"Pagination HTML markup",filename:"pages",url:"pages.html#pagination-html-markup"},{title:"Pagination variables",filename:"pages",url:"pages.html#pagination-variables"},{title:"Pagination with label and gradient background on links",filename:"pages",url:"pages.html#pagination-with-label-and-gradient-background-on-links"},{title:'Pagination with "previous"..."next" text links and label',filename:"pages",url:"pages.html#pagination-with-previousnext-text-links-and-label"},{title:"Pagination without label, with solid background",filename:"pages",url:"pages.html#pagination-without-label-with-solid-background"},{title:"popups",filename:"popups",url:"popups.html"},{title:"Popups",filename:"popups",url:"popups.html#popups"},{title:"Popup variables",filename:"popups",url:"popups.html#popup-variables"},{title:"Window overlay mixin variables",filename:"popups",url:"popups.html#window-overlay-mixin-variables"},{title:"Fixed height popup",filename:"popups",url:"popups.html#fixed-height-popup"},{title:"Fixed content height popup",filename:"popups",url:"popups.html#fixed-content-height-popup"},{title:"Margins for header, content and footer block in popup",filename:"popups",url:"popups.html#margins-for-header-content-and-footer-block-in-popup"},{title:"Popup titles styled as theme headings",filename:"popups",url:"popups.html#popup-titles-styled-as-theme-headings"},{title:"Popup action toolbar",filename:"popups",url:"popups.html#popup-action-toolbar"},{title:"Popup Close button without an icon",filename:"popups",url:"popups.html#popup-close-button-without-an-icon"},{title:"Modify the icon of popup Close button",filename:"popups",url:"popups.html#modify-the-icon-of-popup-close-button"},{title:"Modify overlay styles",filename:"popups",url:"popups.html#modify-overlay-styles"},{title:"rating",filename:"rating",url:"rating.html"},{title:"Ratings",filename:"rating",url:"rating.html#ratings"},{title:"Global rating variables",filename:"rating",url:"rating.html#global-rating-variables"},{title:"Rating with vote",filename:"rating",url:"rating.html#rating-with-vote"},{title:"Rating with vote icons number customization",filename:"rating",url:"rating.html#rating-with-vote-icons-number-customization"},{title:"Rating with vote icons colors customization",filename:"rating",url:"rating.html#rating-with-vote-icons-colors-customization"},{title:"Rating with vote icons symbol customization",filename:"rating",url:"rating.html#rating-with-vote-icons-symbol-customization"},{title:"Accessible rating with vote",filename:"rating",url:"rating.html#accessible-rating-with-vote"},{title:"Rating summary",filename:"rating",url:"rating.html#rating-summary"},{title:"Rating summary icons number customization",filename:"rating",url:"rating.html#rating-summary-icons-number-customization"},{title:"Rating summary icons color customization",filename:"rating",url:"rating.html#rating-summary-icons-color-customization"},{title:"Rating summary icons symbol customization",filename:"rating",url:"rating.html#rating-summary-icons-symbol-customization"},{title:"Rating summary hide label",filename:"rating",url:"rating.html#rating-summary-hide-label"},{title:"Rating summary multiple ratings",filename:"rating",url:"rating.html#rating-summary-multiple-ratings"},{title:"Rating hide label mixin",filename:"rating",url:"rating.html#rating-hide-label-mixin"},{title:"resets",filename:"resets",url:"resets.html"},{title:"Resets",filename:"resets",url:"resets.html#resets"},{title:"responsive",filename:"responsive",url:"responsive.html"},{title:"Responsive",filename:"responsive",url:"responsive.html#responsive"},{title:"Responsive mixins usage",filename:"responsive",url:"responsive.html#responsive-mixins-usage"},{title:"Media query style groups separation variables",filename:"responsive",url:"responsive.html#media-query-style-groups-separation-variables"},{title:"Responsive breakpoints",filename:"responsive",url:"responsive.html#responsive-breakpoints"},{title:"sections",filename:"sections",url:"sections.html"},{title:"Tabs and accordions",filename:"sections",url:"sections.html#tabs-and-accordions"},{title:"Tabs",filename:"sections",url:"sections.html#tabs"},{title:"Tabs mixin variables",filename:"sections",url:"sections.html#tabs-mixin-variables"},{title:"Tabs with content top border",filename:"sections",url:"sections.html#tabs-with-content-top-border"},{title:"Accordion",filename:"sections",url:"sections.html#accordion"},{title:"Accordion mixin variables",filename:"sections",url:"sections.html#accordion-mixin-variables"},{title:"Responsive tabs",filename:"sections",url:"sections.html#responsive-tabs"},{title:"Tabs Base",filename:"sections",url:"sections.html#tabs-base"},{title:"Accordion Base",filename:"sections",url:"sections.html#accordion-base"},{title:"tables",filename:"tables",url:"tables.html"},{title:"Tables",filename:"tables",url:"tables.html#tables"},{title:"Table mixin variables",filename:"tables",url:"tables.html#table-mixin-variables"},{title:"Table typography",filename:"tables",url:"tables.html#table-typography"},{title:"Table typography mixin variables",filename:"tables",url:"tables.html#table-typography-mixin-variables"},{title:"Table caption",filename:"tables",url:"tables.html#table-caption"},{title:"Table caption mixin variables",filename:"tables",url:"tables.html#table-caption-mixin-variables"},{title:"Table cells resize",filename:"tables",url:"tables.html#table-cells-resize"},{title:"Table cells resize variables",filename:"tables",url:"tables.html#table-cells-resize-variables"},{title:"Table background customization",filename:"tables",url:"tables.html#table-background-customization"},{title:"Table background mixin variables",filename:"tables",url:"tables.html#table-background-mixin-variables"},{title:"Table borders customization",filename:"tables",url:"tables.html#table-borders-customization"},{title:"Table borders mixin variables",filename:"tables",url:"tables.html#table-borders-mixin-variables"},{title:"Table with horizontal borders",filename:"tables",url:"tables.html#table-with-horizontal-borders"},{title:"Table with vertical borders",filename:"tables",url:"tables.html#table-with-vertical-borders"},{title:"Table with light borders",filename:"tables",url:"tables.html#table-with-light-borders"},{title:"Table without borders",filename:"tables",url:"tables.html#table-without-borders"},{title:"Striped table",filename:"tables",url:"tables.html#striped-table"},{title:"Striped table mixin variables",filename:"tables",url:"tables.html#striped-table-mixin-variables"},{title:"Table with rows hover",filename:"tables",url:"tables.html#table-with-rows-hover"},{title:"Table with rows hover mixin variables",filename:"tables",url:"tables.html#table-with-rows-hover-mixin-variables"},{title:"Responsive table technics #1",filename:"tables",url:"tables.html#responsive-table-technics-1"},{title:"Responsive table technics #2",filename:"tables",url:"tables.html#responsive-table-technics-2"},{title:"Responsive table technics #2 mixin variables",filename:"tables",url:"tables.html#responsive-table-technics-2-mixin-variables"},{title:"tooltips",filename:"tooltips",url:"tooltips.html"},{title:"Tooltips",filename:"tooltips",url:"tooltips.html#tooltips"},{title:"Tooltips variables",filename:"tooltips",url:"tooltips.html#tooltips-variables"},{title:"typography",filename:"typography",url:"typography.html"},{title:"Typogrphy",filename:"typography",url:"typography.html#typogrphy"},{title:"Typography variables",filename:"typography",url:"typography.html#typography-variables"},{title:"Font-size mixin",filename:"typography",url:"typography.html#fontsize-mixin"},{title:"Line-height mixin",filename:"typography",url:"typography.html#lineheight-mixin"},{title:"Word breaking mixin",filename:"typography",url:"typography.html#word-breaking-mixin"},{title:"Font face mixin",filename:"typography",url:"typography.html#font-face-mixin"},{title:"Text overflow mixin",filename:"typography",url:"typography.html#text-overflow-mixin"},{title:"Text hide",filename:"typography",url:"typography.html#text-hide"},{title:"Hyphens",filename:"typography",url:"typography.html#hyphens"},{title:"Font style and color",filename:"typography",url:"typography.html#font-style-and-color"},{title:"Font style mixin variables",filename:"typography",url:"typography.html#font-style-mixin-variables"},{title:"Reset list styles",filename:"typography",url:"typography.html#reset-list-styles"},{title:"Reset list styles variables",filename:"typography",url:"typography.html#reset-list-styles-variables"},{title:"Inline-block list item styling",filename:"typography",url:"typography.html#inlineblock-list-item-styling"},{title:"Link styling mixin",filename:"typography",url:"typography.html#link-styling-mixin"},{title:"Link styling mixin variables",filename:"typography",url:"typography.html#link-styling-mixin-variables"},{title:"Heading styling mixin",filename:"typography",url:"typography.html#heading-styling-mixin"},{title:"Base typography mixins",filename:"typography",url:"typography.html#base-typography-mixins"},{title:"Base typography mixin variables",filename:"typography",url:"typography.html#base-typography-mixin-variables"},{title:"Headings typography mixin",filename:"typography",url:"typography.html#headings-typography-mixin"},{title:"Headings typography mixin variables",filename:"typography",url:"typography.html#headings-typography-mixin-variables"},{title:"Typography links mixin",filename:"typography",url:"typography.html#typography-links-mixin"},{title:"Typography lists mixin",filename:"typography",url:"typography.html#typography-lists-mixin"},{title:"Typography lists mixin variables",filename:"typography",url:"typography.html#typography-lists-mixin-variables"},{title:"Typography code elements mixin",filename:"typography",url:"typography.html#typography-code-elements-mixin"},{title:"Typography code mixin variables",filename:"typography",url:"typography.html#typography-code-mixin-variables"},{title:"Typography blockquote",filename:"typography",url:"typography.html#typography-blockquote"},{title:"Typography blockquote mixin variables",filename:"typography",url:"typography.html#typography-blockquote-mixin-variables"},{title:"utilities",filename:"utilities",url:"utilities.html"},{title:"Utilities",filename:"utilities",url:"utilities.html#utilities"},{title:".lib-clearfix()",filename:"utilities",url:"utilities.html#libclearfix"},{title:".lib-visibility-hidden()",filename:"utilities",url:"utilities.html#libvisibilityhidden"},{title:".lib-visually-hidden()",filename:"utilities",url:"utilities.html#libvisuallyhidden"},{title:".lib-visually-hidden-reset()",filename:"utilities",url:"utilities.html#libvisuallyhiddenreset"},{title:".lib-css()",filename:"utilities",url:"utilities.html#libcss"},{title:".lib-css() variables",filename:"utilities",url:"utilities.html#libcss-variables"},{title:".lib-rotate()",filename:"utilities",url:"utilities.html#librotate"},{title:".lib-rotate() variables",filename:"utilities",url:"utilities.html#librotate-variables"},{title:".lib-input-placeholder()",filename:"utilities",url:"utilities.html#libinputplaceholder"},{title:".lib-input-placeholder() variables",filename:"utilities",url:"utilities.html#libinputplaceholder-variables"},{title:".lib-background-gradient()",filename:"utilities",url:"utilities.html#libbackgroundgradient"},{title:".lib-background-gradient() variables",filename:"utilities",url:"utilities.html#libbackgroundgradient-variables"},{title:"variables",filename:"variables",url:"variables.html"},{title:"List of Global Variables",filename:"variables",url:"variables.html#list-of-global-variables"},{title:"Table with rows hover mixin variables",filename:"variables",url:"variables.html#table-with-rows-hover-mixin-variables"},{title:"docs",filename:"docs",url:"docs.html"},{title:"Documentation",filename:"docs",url:"docs.html#documentation"}];(function(){"use strict";var b=function(a,b){return Array.prototype.indexOf.call(a,b)!==-1},c=function(a,b){return Array.prototype.filter.call(a,b)},d=function(a,b){return Array.prototype.forEach.call(a,b)},e=document.getElementsByTagName("body")[0];e.addEventListener("click",function(a){var b=a.target;b.tagName.toLowerCase()==="svg"&&(b=b.parentNode);var c=!1;b.dataset.toggle!=null&&(a.preventDefault(),b.classList.contains("is-active")||(c=!0)),d(e.querySelectorAll("[data-toggle]"),function(a){a.classList.remove("is-active"),document.getElementById(a.dataset.toggle).hidden=!0}),c&&(b.classList.add("is-active"),document.getElementById(b.dataset.toggle).hidden=!1)}),function(){var f=e.getElementsByClassName("nav")[0];if(!f)return;var g=document.createElement("ul");g.className="nav-results",g.id="nav-search",g.hidden=!0,d(a,function(a){var b,c,d;b=document.createElement("li"),b._title=a.title.toLowerCase(),b.hidden=!0,b.appendChild(c=document.createElement("a")),c.href=a.url,c.innerHTML=a.title,c.appendChild(d=document.createElement("span")),d.innerHTML=a.filename,d.className="nav-results-filename",g.appendChild(b)}),f.appendChild(g);var h=g.children,i=function(a){d(h,function(a){a.hidden=!0});var b=this.value.toLowerCase(),e=[];b!==""&&(e=c(h,function(a){return a._title.indexOf(b)!==-1})),e.length>0?(d(e,function(a){a.hidden=!1}),g.hidden=!1):g.hidden=!0},j=f.querySelector('input[type="search"]');j.addEventListener("keyup",i),j.addEventListener("focus",i),e.addEventListener("click",function(a){if(a.target.classList&&a.target.classList.contains("search"))return;g.hidden=!0}),g.addEventListener("click",function(a){j.value=""});var k=document.createElement("ul");k.id="nav-toc",k.hidden=!0,k.className="nav-results toc-list",c(e.getElementsByTagName("*"),function(a){return b(["h1","h2","h3"],a.tagName.toLowerCase())}).map(function(a){var b=document.createElement("li"),c=document.createElement("a"),d=a.tagName.toLowerCase()[1];c.classList.add("level-"+d),b.appendChild(c),c.href="#"+a.id,c.innerHTML=a.innerHTML,k.appendChild(b)}),f.appendChild(k)}()})(),function(){"use strict";if(location.hash==="#__preview__"||location.protocol==="data:")return;var a=function(a,b){return Array.prototype.forEach.call(a,b)},b=function(a,b){var e=Array.prototype.slice.call(arguments,2);return d(a,function(a){return(c(b)?b||a:a[b]).apply(a,e)})},c=function(a){return Object.prototype.toString.call(a)==="[object Function]"},d=function(a,b){return Array.prototype.map.call(a,b)},e=function(a,b){return d(a,function(a){return a[b]})},f=function(a){var b={},c=a.split(";");for(var d=0;c.length>d;d++){var e=c[d].trim().split("=");b[e[0]]=e[1]}return b},g=function(a,c){return b(e(a,"classList"),"remove",c)},h=function(a,b){a.contentDocument.defaultView.postMessage(b,"*")},i=document.getElementsByTagName("head")[0],j=document.getElementsByTagName("body")[0],k=e(i.querySelectorAll('style[type="text/preview"]'),"innerHTML").join(""),l=e(i.querySelectorAll('script[type="text/preview"]'),"innerHTML").join(""),m=location.href.split("#")[0]+"#__preview__",n=document.createElement("iframe");n.src="data:text/html,",j.appendChild(n),n.addEventListener("load",function(){var b={sameOriginDataUri:!0};try{this.contentDocument,this.contentDocument||(b.sameOriginDataUri=!1)}catch(c){b.sameOriginDataUri=!1}this.parentNode.removeChild(this),a(j.getElementsByTagName("textarea"),function(a,c){o(a,b,c),q(),p(a)})});var o=function(a,b,c){var d,e,f;d=document.createElement("div"),d.appendChild(e=document.createElement("div")),d.className="preview",e.appendChild(f=document.createElement("iframe")),e.className="resizeable",f.setAttribute("scrolling","no"),f.name="iframe"+c++,f.addEventListener("load",function(){var c,d,e,f,g,i,j;j=this.contentDocument;if(!b.sameOriginDataUri&&this.src!==m)return;this.src===m&&(c=j.createElement("html"),c.appendChild(j.createElement("head")),c.appendChild(d=j.createElement("body")),d.innerHTML=a.textContent,j.replaceChild(c,j.documentElement)),g=j.createElement("head"),g.appendChild(f=j.createElement("style")),g.appendChild(e=j.createElement("script")),e.textContent=l,f.textContent=k,i=j.getElementsByTagName("head")[0],i.parentNode.replaceChild(g,i),h(this,"getHeight")});var g;b.sameOriginDataUri?g="data:text/html;charset=utf-8,"+encodeURIComponent("<!doctype html><html><head></head></body>"+a.textContent):g=m,f.setAttribute("src",g);var i=function(){f.contentDocument.body.innerHTML=this.value,h(f,"getHeight")};a.addEventListener("keypress",i),a.addEventListener("keyup",i),a.parentNode.insertBefore(d,a)},p=function(a){var b=document.createElement("div");b.className="preview-code",b.style.position="absolute",b.style.left="-9999px",j.appendChild(b);var c=parseInt(window.getComputedStyle(a).getPropertyValue("max-height"),10),d=function(a){b.textContent=this.value+"\n";var d=b.offsetHeight+2;d>=c?this.style.overflow="auto":this.style.overflow="hidden",this.style.height=b.offsetHeight+2+"px"};a.addEventListener("keypress",d),a.addEventListener("keyup",d),d.call(a)},q=function(){var b=j.getElementsByClassName("settings")[0],c=j.getElementsByClassName("resizeable"),d=30,e=function(b){document.cookie="preview-width="+b,a(c,function(a){b==="auto"&&(b=a.parentNode.offsetWidth),a.style.width=b+"px",h(a.getElementsByTagName("iframe")[0],"getHeight")})},i=f(document.cookie)["preview-width"];if(i){e(i),g(b.getElementsByClassName("is-active"),"is-active");var k=b.querySelector('button[data-width="'+i+'"]');k&&k.classList.add("is-active")}window.addEventListener("message",function(a){if(a.data==null||!a.source)return;var b=a.data,c=document.getElementsByName(a.source.name)[0];b.height!=null&&c&&(c.parentNode.style.height=b.height+d+"px")},!1),b&&c.length>0&&(b.hidden=!1,b.addEventListener("click",function(a){var c=a.target.tagName.toLowerCase(),d;if(c==="button")d=a.target;else{if(c!=="svg")return;d=a.target.parentNode}a.preventDefault(),g(b.getElementsByClassName("is-active"),"is-active"),d.classList.add("is-active");var f=d.dataset.width;e(f)}))}}()})()</script></body></html><!-- Generated with StyleDocco (http://jacobrask.github.com/styledocco). --> diff --git a/lib/web/css/docs/pages.html b/lib/web/css/docs/pages.html index 8b7335d86b8da..1bbcac94c56f8 100644 --- a/lib/web/css/docs/pages.html +++ b/lib/web/css/docs/pages.html @@ -826,4 +826,4 @@ @_pager-action-color-hover: #fff, @_pager-action-color-active: #fff ); -}</code></pre></div></article></section><div class="bar bottom"><div hidden class="settings container"><!-- Icons from http://iconmonstr.com--><button title="Desktop (1280)" data-width='1280'><svg viewBox="0 0 412 386" height="24" width="26" class="icon"><path d="m147.6,343.9c-4.5,15.9-26.2,37.6-42.1,42.1h201c-15.3,-4-38.1,-26.8-42.1,-42.1H147.6zM387,0.5H25c-13.8,0-25,11.2-25,25V294c0,13.8 11.2,25 25,25h362c13.8,0 25,-11.2 25,-25V25.5C412,11.7 400.8,0.5 387,0.5zM369.9,238.2H42.1L42.1,42.6 369.9,42.6V238.2z"></path></svg></button><button title="Laptop (1024)" data-width='1024'><svg viewBox="0 0 384 312" height="23" width="28" class="icon"><path d="m349.2,20.5c0,-11-9,-20-20,-20H53.6c-11,0-20,9-20,20v194H349.2v-194zm-27,167H60.6V27.5H322.2v160zm28,42H32.6L2.6,282.1c-3.5,6.2-3.5,13.8 0.1,19.9 3.6,6.2 10.2,9.9 17.3,9.9H363.1c7.1,0 13.7,-3.8 17.3,-10 3.6,-6.2 3.6,-13.8 0,-20l-30.2,-52.5zm-196.9,54 8,-23.5h60.5l8,23.5h-76.5z"></path></svg></button><button title="Tablet (768)" data-width='768'><svg viewBox="0 0 317 412" height="24" width="18" class="icon"><path d="M 316.5,380 V 32 c 0,-17.7 -14.3,-32 -32,-32 H 32 C 14.3,0 0,14.3 0,32 v 348 c 0,17.7 14.3,32 32,32 h 252.5 c 17.7,0 32,-14.3 32,-32 z M 40,367 V 45 H 276.5 V 367 H 40 z m 109.8,22.7 c 0,-4.7 3.8,-8.5 8.5,-8.5 4.7,0 8.5,3.8 8.5,8.5 0,4.7 -3.8,8.5 -8.5,8.5 -4.7,0 -8.5,-3.8 -8.5,-8.5 z"></path></svg></button><button title="Smart phone (320)" data-width='320'><svg viewBox="0 0 224 412" height="24" width="13" class="icon"><path d="M 190.7,0 H 33 C 14.8,0 0,14.8 0,33 v 346 c 0,18.2 14.8,33 33,33 h 157.7 c 18.2,0 33,-14.8 33,-33 V 33 c 0,-18.2 -14.8,-33 -33,-33 z M 94.3,30.2 h 37 c 2.2,0 4,1.8 4,4 0,2.2 -1.8,4 -4,4 h -37 c -2.2,0 -4,-1.8 -4,-4 0,-2.2 1.8,-4 4,-4 z m 18.5,362.8 c -8.8,0 -16,-7.2 -16,-16 0,-8.8 7.2,-16 16,-16 8.8,0 16,7.2 16,16 0,8.8 -7.2,16 -16,16 z M 198.6,343.8 H 25.1 V 68.2 h 173.5 v 275.5 z"></path></svg></button><button title="Feature phone (240)" data-width='240'><svg viewBox="0 0 201 412" height="24" width="12" class="icon"><path d="M 165.5,0.2 V 45 H 25 c -13.8,0 -25,11.2 -25,25 V 387 c 0,13.8 11.2,25 25,25 h 150.5 c 13.8,0 25,-11.2 25,-25 V 0.2 h -35 z M 65.2,366.5 H 34.2 v -24.5 h 31 v 24.5 z m 0,-44.3 H 34.2 v -24.5 h 31 v 24.5 z m 50.5,44.3 H 84.7 v -24.5 h 31 v 24.5 z m 0,-44.3 H 84.7 v -24.5 h 31 v 24.5 z m 50.5,44.3 h -31 v -24.5 h 31 v 24.5 z m 0,-44.3 h -31 v -24.5 h 31 v 24.5 z m 0,-59.3 h -132 V 95.4 h 132 V 262.9 z"></path></svg></button><button title="Auto (100%)" data-width="auto" class="auto is-active">Auto</button></div></div><script>(function(){var a=[{title:"actions-toolbar",filename:"actions-toolbar",url:"actions-toolbar.html"},{title:"Actions toolbar",filename:"actions-toolbar",url:"actions-toolbar.html#actions-toolbar"},{title:"Actions toolbar mixin variables",filename:"actions-toolbar",url:"actions-toolbar.html#actions-toolbar-mixin-variables"},{title:"Actions toolbar alignment",filename:"actions-toolbar",url:"actions-toolbar.html#actions-toolbar-alignment"},{title:"Reverse primary and secondary blocks",filename:"actions-toolbar",url:"actions-toolbar.html#reverse-primary-and-secondary-blocks"},{title:"Actions toolbar indents customizations",filename:"actions-toolbar",url:"actions-toolbar.html#actions-toolbar-indents-customizations"},{title:"Responsive actions toolbar",filename:"actions-toolbar",url:"actions-toolbar.html#responsive-actions-toolbar"},{title:"breadcrumbs",filename:"breadcrumbs",url:"breadcrumbs.html"},{title:"Breadcrumbs",filename:"breadcrumbs",url:"breadcrumbs.html#breadcrumbs"},{title:"Breadcrumbs variables",filename:"breadcrumbs",url:"breadcrumbs.html#breadcrumbs-variables"},{title:"Button-styled breadcrumbs with gradient background, border, and no separating symbol",filename:"breadcrumbs",url:"breadcrumbs.html#buttonstyled-breadcrumbs-with-gradient-background-border-and-no-separating-symbol"},{title:"Breadcrumbs with solid background",filename:"breadcrumbs",url:"breadcrumbs.html#breadcrumbs-with-solid-background"},{title:"buttons",filename:"buttons",url:"buttons.html"},{title:"Default button",filename:"buttons",url:"buttons.html#default-button"},{title:"Button variables",filename:"buttons",url:"buttons.html#button-variables"},{title:"Button as an icon",filename:"buttons",url:"buttons.html#button-as-an-icon"},{title:"Button with an icon on the left or right side of the text",filename:"buttons",url:"buttons.html#button-with-an-icon-on-the-left-or-right-side-of-the-text"},{title:"Button with fixed width",filename:"buttons",url:"buttons.html#button-with-fixed-width"},{title:"Primary button",filename:"buttons",url:"buttons.html#primary-button"},{title:"Primary button variables",filename:"buttons",url:"buttons.html#primary-button-variables"},{title:"Button with gradient background",filename:"buttons",url:"buttons.html#button-with-gradient-background"},{title:"Button as a link",filename:"buttons",url:"buttons.html#button-as-a-link"},{title:"Button as a link variables",filename:"buttons",url:"buttons.html#button-as-a-link-variables"},{title:"Link as a button",filename:"buttons",url:"buttons.html#link-as-a-button"},{title:"Button reset",filename:"buttons",url:"buttons.html#button-reset"},{title:"Button revert secondary color",filename:"buttons",url:"buttons.html#button-revert-secondary-color"},{title:"Button revert secondary color variables",filename:"buttons",url:"buttons.html#button-revert-secondary-color-variables"},{title:"Button revert secondary size",filename:"buttons",url:"buttons.html#button-revert-secondary-size"},{title:"Button revert secondary size variables",filename:"buttons",url:"buttons.html#button-revert-secondary-size-variables"},{title:"components",filename:"components",url:"components.html"},{title:"Components",filename:"components",url:"components.html#components"},{title:"Components Variables",filename:"components",url:"components.html#components-variables"},{title:"dropdowns",filename:"dropdowns",url:"dropdowns.html"},{title:"Drop-down and split buttons mixins",filename:"dropdowns",url:"dropdowns.html#dropdown-and-split-buttons-mixins"},{title:"Drop-down",filename:"dropdowns",url:"dropdowns.html#dropdown"},{title:"Drop-down variables",filename:"dropdowns",url:"dropdowns.html#dropdown-variables"},{title:"Drop-down with icon customization",filename:"dropdowns",url:"dropdowns.html#dropdown-with-icon-customization"},{title:"Modify dropdown list styles",filename:"dropdowns",url:"dropdowns.html#modify-dropdown-list-styles"},{title:"Split button",filename:"dropdowns",url:"dropdowns.html#split-button"},{title:"Split button variables",filename:"dropdowns",url:"dropdowns.html#split-button-variables"},{title:"Split button - button styling",filename:"dropdowns",url:"dropdowns.html#split-button-button-styling"},{title:"Split button icon customization",filename:"dropdowns",url:"dropdowns.html#split-button-icon-customization"},{title:"Split button drop-down list customization",filename:"dropdowns",url:"dropdowns.html#split-button-dropdown-list-customization"},{title:"forms",filename:"forms",url:"forms.html"},{title:"Forms mixins",filename:"forms",url:"forms.html#forms-mixins"},{title:"Global forms elements customization",filename:"forms",url:"forms.html#global-forms-elements-customization"},{title:"Fieldsets & fields customization",filename:"forms",url:"forms.html#fieldsets-fields-customization"},{title:"Fieldset and legend customization variables",filename:"forms",url:"forms.html#fieldset-and-legend-customization-variables"},{title:"Fields customization variables",filename:"forms",url:"forms.html#fields-customization-variables"},{title:"Required fields message customization variables",filename:"forms",url:"forms.html#required-fields-message-customization-variables"},{title:"Form element inputs customization",filename:"forms",url:"forms.html#form-element-inputs-customization"},{title:"Form element inputs customization variables",filename:"forms",url:"forms.html#form-element-inputs-customization-variables"},{title:"Form element choice",filename:"forms",url:"forms.html#form-element-choice"},{title:"Form element choice variables",filename:"forms",url:"forms.html#form-element-choice-variables"},{title:"Custom color",filename:"forms",url:"forms.html#custom-color"},{title:"Input number - input-text view",filename:"forms",url:"forms.html#input-number-inputtext-view"},{title:"Input search - input-text view",filename:"forms",url:"forms.html#input-search-inputtext-view"},{title:"Form validation",filename:"forms",url:"forms.html#form-validation"},{title:"Form validation variables",filename:"forms",url:"forms.html#form-validation-variables"},{title:"icons",filename:"icons",url:"icons.html"},{title:"Icons",filename:"icons",url:"icons.html#icons"},{title:"Icon with image or sprite",filename:"icons",url:"icons.html#icon-with-image-or-sprite"},{title:"Icon with image or sprite variables",filename:"icons",url:"icons.html#icon-with-image-or-sprite-variables"},{title:"Icon position for an icon with image or sprite",filename:"icons",url:"icons.html#icon-position-for-an-icon-with-image-or-sprite"},{title:"Position for icon with image or sprite mixin variables",filename:"icons",url:"icons.html#position-for-icon-with-image-or-sprite-mixin-variables"},{title:"Icon sprite position (with grid)",filename:"icons",url:"icons.html#icon-sprite-position-with-grid"},{title:"Icon sprite position variables",filename:"icons",url:"icons.html#icon-sprite-position-variables"},{title:"Image/sprite icon size",filename:"icons",url:"icons.html#imagesprite-icon-size"},{title:"Image/sprite icon size variables",filename:"icons",url:"icons.html#imagesprite-icon-size-variables"},{title:"Font icon",filename:"icons",url:"icons.html#font-icon"},{title:"Font icon variables",filename:"icons",url:"icons.html#font-icon-variables"},{title:"Change the size of font icon",filename:"icons",url:"icons.html#change-the-size-of-font-icon"},{title:"Change the size of font icon variables",filename:"icons",url:"icons.html#change-the-size-of-font-icon-variables"},{title:"Hide icon text",filename:"icons",url:"icons.html#hide-icon-text"},{title:"Sprite and font icons for Blank theme",filename:"icons",url:"icons.html#sprite-and-font-icons-for-blank-theme"},{title:"layout",filename:"layout",url:"layout.html"},{title:"Layout",filename:"layout",url:"layout.html#layout"},{title:"Layout global variables",filename:"layout",url:"layout.html#layout-global-variables"},{title:"Page layouts",filename:"layout",url:"layout.html#page-layouts"},{title:"Layout column",filename:"layout",url:"layout.html#layout-column"},{title:"Layout column variables",filename:"layout",url:"layout.html#layout-column-variables"},{title:"Layout width",filename:"layout",url:"layout.html#layout-width"},{title:"Layout width variables",filename:"layout",url:"layout.html#layout-width-variables"},{title:"lib",filename:"lib",url:"lib.html"},{title:"Including Magento UI library to your theme",filename:"lib",url:"lib.html#including-magento-ui-library-to-your-theme"},{title:"loaders",filename:"loaders",url:"loaders.html"},{title:"Loaders",filename:"loaders",url:"loaders.html#loaders"},{title:"Default loader variables",filename:"loaders",url:"loaders.html#default-loader-variables"},{title:"Loading",filename:"loaders",url:"loaders.html#loading"},{title:"Loading default variables",filename:"loaders",url:"loaders.html#loading-default-variables"},{title:"messages",filename:"messages",url:"messages.html"},{title:"Messages",filename:"messages",url:"messages.html#messages"},{title:"Information message",filename:"messages",url:"messages.html#information-message"},{title:"Warning message",filename:"messages",url:"messages.html#warning-message"},{title:"Error message",filename:"messages",url:"messages.html#error-message"},{title:"Success message",filename:"messages",url:"messages.html#success-message"},{title:"Notice message",filename:"messages",url:"messages.html#notice-message"},{title:"Message with inner icon",filename:"messages",url:"messages.html#message-with-inner-icon"},{title:"Message with lateral icon",filename:"messages",url:"messages.html#message-with-lateral-icon"},{title:"Custom message style",filename:"messages",url:"messages.html#custom-message-style"},{title:"Messages global variables",filename:"messages",url:"messages.html#messages-global-variables"},{title:"pages",filename:"pages",url:"pages.html"},{title:"Pagination HTML markup",filename:"pages",url:"pages.html#pagination-html-markup"},{title:"Pagination variables",filename:"pages",url:"pages.html#pagination-variables"},{title:"Pagination with label and gradient background on links",filename:"pages",url:"pages.html#pagination-with-label-and-gradient-background-on-links"},{title:'Pagination with "previous"..."next" text links and label',filename:"pages",url:"pages.html#pagination-with-previousnext-text-links-and-label"},{title:"Pagination without label, with solid background",filename:"pages",url:"pages.html#pagination-without-label-with-solid-background"},{title:"popups",filename:"popups",url:"popups.html"},{title:"Popups",filename:"popups",url:"popups.html#popups"},{title:"Popup variables",filename:"popups",url:"popups.html#popup-variables"},{title:"Window overlay mixin variables",filename:"popups",url:"popups.html#window-overlay-mixin-variables"},{title:"Fixed height popup",filename:"popups",url:"popups.html#fixed-height-popup"},{title:"Fixed content height popup",filename:"popups",url:"popups.html#fixed-content-height-popup"},{title:"Margins for header, content and footer block in popup",filename:"popups",url:"popups.html#margins-for-header-content-and-footer-block-in-popup"},{title:"Popup titles styled as theme headings",filename:"popups",url:"popups.html#popup-titles-styled-as-theme-headings"},{title:"Popup action toolbar",filename:"popups",url:"popups.html#popup-action-toolbar"},{title:"Popup Close button without an icon",filename:"popups",url:"popups.html#popup-close-button-without-an-icon"},{title:"Modify the icon of popup Close button",filename:"popups",url:"popups.html#modify-the-icon-of-popup-close-button"},{title:"Modify overlay styles",filename:"popups",url:"popups.html#modify-overlay-styles"},{title:"rating",filename:"rating",url:"rating.html"},{title:"Ratings",filename:"rating",url:"rating.html#ratings"},{title:"Global rating variables",filename:"rating",url:"rating.html#global-rating-variables"},{title:"Rating with vote",filename:"rating",url:"rating.html#rating-with-vote"},{title:"Rating with vote icons number customization",filename:"rating",url:"rating.html#rating-with-vote-icons-number-customization"},{title:"Rating with vote icons colors customization",filename:"rating",url:"rating.html#rating-with-vote-icons-colors-customization"},{title:"Rating with vote icons symbol customization",filename:"rating",url:"rating.html#rating-with-vote-icons-symbol-customization"},{title:"Accessible rating with vote",filename:"rating",url:"rating.html#accessible-rating-with-vote"},{title:"Rating summary",filename:"rating",url:"rating.html#rating-summary"},{title:"Rating summary icons number customization",filename:"rating",url:"rating.html#rating-summary-icons-number-customization"},{title:"Rating summary icons color customization",filename:"rating",url:"rating.html#rating-summary-icons-color-customization"},{title:"Rating summary icons symbol customization",filename:"rating",url:"rating.html#rating-summary-icons-symbol-customization"},{title:"Rating summary hide label",filename:"rating",url:"rating.html#rating-summary-hide-label"},{title:"Rating summary multiple ratings",filename:"rating",url:"rating.html#rating-summary-multiple-ratings"},{title:"Rating hide label mixin",filename:"rating",url:"rating.html#rating-hide-label-mixin"},{title:"resets",filename:"resets",url:"resets.html"},{title:"Resets",filename:"resets",url:"resets.html#resets"},{title:"responsive",filename:"responsive",url:"responsive.html"},{title:"Responsive",filename:"responsive",url:"responsive.html#responsive"},{title:"Responsive mixins usage",filename:"responsive",url:"responsive.html#responsive-mixins-usage"},{title:"Media query style groups separation variables",filename:"responsive",url:"responsive.html#media-query-style-groups-separation-variables"},{title:"Responsive breakpoints",filename:"responsive",url:"responsive.html#responsive-breakpoints"},{title:"sections",filename:"sections",url:"sections.html"},{title:"Tabs and accordions",filename:"sections",url:"sections.html#tabs-and-accordions"},{title:"Tabs",filename:"sections",url:"sections.html#tabs"},{title:"Tabs mixin variables",filename:"sections",url:"sections.html#tabs-mixin-variables"},{title:"Tabs with content top border",filename:"sections",url:"sections.html#tabs-with-content-top-border"},{title:"Accordion",filename:"sections",url:"sections.html#accordion"},{title:"Accordion mixin variables",filename:"sections",url:"sections.html#accordion-mixin-variables"},{title:"Responsive tabs",filename:"sections",url:"sections.html#responsive-tabs"},{title:"Tabs Base",filename:"sections",url:"sections.html#tabs-base"},{title:"Accordion Base",filename:"sections",url:"sections.html#accordion-base"},{title:"tables",filename:"tables",url:"tables.html"},{title:"Tables",filename:"tables",url:"tables.html#tables"},{title:"Table mixin variables",filename:"tables",url:"tables.html#table-mixin-variables"},{title:"Table typography",filename:"tables",url:"tables.html#table-typography"},{title:"Table typography mixin variables",filename:"tables",url:"tables.html#table-typography-mixin-variables"},{title:"Table caption",filename:"tables",url:"tables.html#table-caption"},{title:"Table caption mixin variables",filename:"tables",url:"tables.html#table-caption-mixin-variables"},{title:"Table cells resize",filename:"tables",url:"tables.html#table-cells-resize"},{title:"Table cells resize variables",filename:"tables",url:"tables.html#table-cells-resize-variables"},{title:"Table background customization",filename:"tables",url:"tables.html#table-background-customization"},{title:"Table background mixin variables",filename:"tables",url:"tables.html#table-background-mixin-variables"},{title:"Table borders customization",filename:"tables",url:"tables.html#table-borders-customization"},{title:"Table borders mixin variables",filename:"tables",url:"tables.html#table-borders-mixin-variables"},{title:"Table with horizontal borders",filename:"tables",url:"tables.html#table-with-horizontal-borders"},{title:"Table with vertical borders",filename:"tables",url:"tables.html#table-with-vertical-borders"},{title:"Table with light borders",filename:"tables",url:"tables.html#table-with-light-borders"},{title:"Table without borders",filename:"tables",url:"tables.html#table-without-borders"},{title:"Striped table",filename:"tables",url:"tables.html#striped-table"},{title:"Striped table mixin variables",filename:"tables",url:"tables.html#striped-table-mixin-variables"},{title:"Table with rows hover",filename:"tables",url:"tables.html#table-with-rows-hover"},{title:"Table with rows hover mixin variables",filename:"tables",url:"tables.html#table-with-rows-hover-mixin-variables"},{title:"Responsive table technics #1",filename:"tables",url:"tables.html#responsive-table-technics-1"},{title:"Responsive table technics #2",filename:"tables",url:"tables.html#responsive-table-technics-2"},{title:"Responsive table technics #2 mixin variables",filename:"tables",url:"tables.html#responsive-table-technics-2-mixin-variables"},{title:"tooltips",filename:"tooltips",url:"tooltips.html"},{title:"Tooltips",filename:"tooltips",url:"tooltips.html#tooltips"},{title:"Tooltips variables",filename:"tooltips",url:"tooltips.html#tooltips-variables"},{title:"typography",filename:"typography",url:"typography.html"},{title:"Typogrphy",filename:"typography",url:"typography.html#typogrphy"},{title:"Typography variables",filename:"typography",url:"typography.html#typography-variables"},{title:"Font-size mixin",filename:"typography",url:"typography.html#fontsize-mixin"},{title:"Line-height mixin",filename:"typography",url:"typography.html#lineheight-mixin"},{title:"Word breaking mixin",filename:"typography",url:"typography.html#word-breaking-mixin"},{title:"Font face mixin",filename:"typography",url:"typography.html#font-face-mixin"},{title:"Text overflow mixin",filename:"typography",url:"typography.html#text-overflow-mixin"},{title:"Text hide",filename:"typography",url:"typography.html#text-hide"},{title:"Hyphens",filename:"typography",url:"typography.html#hyphens"},{title:"Font style and color",filename:"typography",url:"typography.html#font-style-and-color"},{title:"Font style mixin variables",filename:"typography",url:"typography.html#font-style-mixin-variables"},{title:"Reset list styles",filename:"typography",url:"typography.html#reset-list-styles"},{title:"Reset list styles variables",filename:"typography",url:"typography.html#reset-list-styles-variables"},{title:"Inline-block list item styling",filename:"typography",url:"typography.html#inlineblock-list-item-styling"},{title:"Link styling mixin",filename:"typography",url:"typography.html#link-styling-mixin"},{title:"Link styling mixin variables",filename:"typography",url:"typography.html#link-styling-mixin-variables"},{title:"Heading styling mixin",filename:"typography",url:"typography.html#heading-styling-mixin"},{title:"Base typography mixins",filename:"typography",url:"typography.html#base-typography-mixins"},{title:"Base typography mixin variables",filename:"typography",url:"typography.html#base-typography-mixin-variables"},{title:"Headings typography mixin",filename:"typography",url:"typography.html#headings-typography-mixin"},{title:"Headings typography mixin variables",filename:"typography",url:"typography.html#headings-typography-mixin-variables"},{title:"Typography links mixin",filename:"typography",url:"typography.html#typography-links-mixin"},{title:"Typography lists mixin",filename:"typography",url:"typography.html#typography-lists-mixin"},{title:"Typography lists mixin variables",filename:"typography",url:"typography.html#typography-lists-mixin-variables"},{title:"Typography code elements mixin",filename:"typography",url:"typography.html#typography-code-elements-mixin"},{title:"Typography code mixin variables",filename:"typography",url:"typography.html#typography-code-mixin-variables"},{title:"Typography blockquote",filename:"typography",url:"typography.html#typography-blockquote"},{title:"Typography blockquote mixin variables",filename:"typography",url:"typography.html#typography-blockquote-mixin-variables"},{title:"utilities",filename:"utilities",url:"utilities.html"},{title:"Utilities",filename:"utilities",url:"utilities.html#utilities"},{title:".lib-clearfix()",filename:"utilities",url:"utilities.html#libclearfix"},{title:".lib-visibility-hidden()",filename:"utilities",url:"utilities.html#libvisibilityhidden"},{title:".lib-visually-hidden()",filename:"utilities",url:"utilities.html#libvisuallyhidden"},{title:".lib-visually-hidden-reset()",filename:"utilities",url:"utilities.html#libvisuallyhiddenreset"},{title:".lib-css()",filename:"utilities",url:"utilities.html#libcss"},{title:".lib-css() variables",filename:"utilities",url:"utilities.html#libcss-variables"},{title:".lib-rotate()",filename:"utilities",url:"utilities.html#librotate"},{title:".lib-rotate() variables",filename:"utilities",url:"utilities.html#librotate-variables"},{title:".lib-input-placeholder()",filename:"utilities",url:"utilities.html#libinputplaceholder"},{title:".lib-input-placeholder() variables",filename:"utilities",url:"utilities.html#libinputplaceholder-variables"},{title:".lib-background-gradient()",filename:"utilities",url:"utilities.html#libbackgroundgradient"},{title:".lib-background-gradient() variables",filename:"utilities",url:"utilities.html#libbackgroundgradient-variables"},{title:".lib-url-check()",filename:"utilities",url:"utilities.html#liburlcheck"},{title:".lib-url-check() variables",filename:"utilities",url:"utilities.html#liburlcheck-variables"},{title:"variables",filename:"variables",url:"variables.html"},{title:"List of Global Variables",filename:"variables",url:"variables.html#list-of-global-variables"},{title:"Table with rows hover mixin variables",filename:"variables",url:"variables.html#table-with-rows-hover-mixin-variables"},{title:"docs",filename:"docs",url:"docs.html"},{title:"Documentation",filename:"docs",url:"docs.html#documentation"}];(function(){"use strict";var b=function(a,b){return Array.prototype.indexOf.call(a,b)!==-1},c=function(a,b){return Array.prototype.filter.call(a,b)},d=function(a,b){return Array.prototype.forEach.call(a,b)},e=document.getElementsByTagName("body")[0];e.addEventListener("click",function(a){var b=a.target;b.tagName.toLowerCase()==="svg"&&(b=b.parentNode);var c=!1;b.dataset.toggle!=null&&(a.preventDefault(),b.classList.contains("is-active")||(c=!0)),d(e.querySelectorAll("[data-toggle]"),function(a){a.classList.remove("is-active"),document.getElementById(a.dataset.toggle).hidden=!0}),c&&(b.classList.add("is-active"),document.getElementById(b.dataset.toggle).hidden=!1)}),function(){var f=e.getElementsByClassName("nav")[0];if(!f)return;var g=document.createElement("ul");g.className="nav-results",g.id="nav-search",g.hidden=!0,d(a,function(a){var b,c,d;b=document.createElement("li"),b._title=a.title.toLowerCase(),b.hidden=!0,b.appendChild(c=document.createElement("a")),c.href=a.url,c.innerHTML=a.title,c.appendChild(d=document.createElement("span")),d.innerHTML=a.filename,d.className="nav-results-filename",g.appendChild(b)}),f.appendChild(g);var h=g.children,i=function(a){d(h,function(a){a.hidden=!0});var b=this.value.toLowerCase(),e=[];b!==""&&(e=c(h,function(a){return a._title.indexOf(b)!==-1})),e.length>0?(d(e,function(a){a.hidden=!1}),g.hidden=!1):g.hidden=!0},j=f.querySelector('input[type="search"]');j.addEventListener("keyup",i),j.addEventListener("focus",i),e.addEventListener("click",function(a){if(a.target.classList&&a.target.classList.contains("search"))return;g.hidden=!0}),g.addEventListener("click",function(a){j.value=""});var k=document.createElement("ul");k.id="nav-toc",k.hidden=!0,k.className="nav-results toc-list",c(e.getElementsByTagName("*"),function(a){return b(["h1","h2","h3"],a.tagName.toLowerCase())}).map(function(a){var b=document.createElement("li"),c=document.createElement("a"),d=a.tagName.toLowerCase()[1];c.classList.add("level-"+d),b.appendChild(c),c.href="#"+a.id,c.innerHTML=a.innerHTML,k.appendChild(b)}),f.appendChild(k)}()})(),function(){"use strict";if(location.hash==="#__preview__"||location.protocol==="data:")return;var a=function(a,b){return Array.prototype.forEach.call(a,b)},b=function(a,b){var e=Array.prototype.slice.call(arguments,2);return d(a,function(a){return(c(b)?b||a:a[b]).apply(a,e)})},c=function(a){return Object.prototype.toString.call(a)==="[object Function]"},d=function(a,b){return Array.prototype.map.call(a,b)},e=function(a,b){return d(a,function(a){return a[b]})},f=function(a){var b={},c=a.split(";");for(var d=0;c.length>d;d++){var e=c[d].trim().split("=");b[e[0]]=e[1]}return b},g=function(a,c){return b(e(a,"classList"),"remove",c)},h=function(a,b){a.contentDocument.defaultView.postMessage(b,"*")},i=document.getElementsByTagName("head")[0],j=document.getElementsByTagName("body")[0],k=e(i.querySelectorAll('style[type="text/preview"]'),"innerHTML").join(""),l=e(i.querySelectorAll('script[type="text/preview"]'),"innerHTML").join(""),m=location.href.split("#")[0]+"#__preview__",n=document.createElement("iframe");n.src="data:text/html,",j.appendChild(n),n.addEventListener("load",function(){var b={sameOriginDataUri:!0};try{this.contentDocument,this.contentDocument||(b.sameOriginDataUri=!1)}catch(c){b.sameOriginDataUri=!1}this.parentNode.removeChild(this),a(j.getElementsByTagName("textarea"),function(a,c){o(a,b,c),q(),p(a)})});var o=function(a,b,c){var d,e,f;d=document.createElement("div"),d.appendChild(e=document.createElement("div")),d.className="preview",e.appendChild(f=document.createElement("iframe")),e.className="resizeable",f.setAttribute("scrolling","no"),f.name="iframe"+c++,f.addEventListener("load",function(){var c,d,e,f,g,i,j;j=this.contentDocument;if(!b.sameOriginDataUri&&this.src!==m)return;this.src===m&&(c=j.createElement("html"),c.appendChild(j.createElement("head")),c.appendChild(d=j.createElement("body")),d.innerHTML=a.textContent,j.replaceChild(c,j.documentElement)),g=j.createElement("head"),g.appendChild(f=j.createElement("style")),g.appendChild(e=j.createElement("script")),e.textContent=l,f.textContent=k,i=j.getElementsByTagName("head")[0],i.parentNode.replaceChild(g,i),h(this,"getHeight")});var g;b.sameOriginDataUri?g="data:text/html;charset=utf-8,"+encodeURIComponent("<!doctype html><html><head></head></body>"+a.textContent):g=m,f.setAttribute("src",g);var i=function(){f.contentDocument.body.innerHTML=this.value,h(f,"getHeight")};a.addEventListener("keypress",i),a.addEventListener("keyup",i),a.parentNode.insertBefore(d,a)},p=function(a){var b=document.createElement("div");b.className="preview-code",b.style.position="absolute",b.style.left="-9999px",j.appendChild(b);var c=parseInt(window.getComputedStyle(a).getPropertyValue("max-height"),10),d=function(a){b.textContent=this.value+"\n";var d=b.offsetHeight+2;d>=c?this.style.overflow="auto":this.style.overflow="hidden",this.style.height=b.offsetHeight+2+"px"};a.addEventListener("keypress",d),a.addEventListener("keyup",d),d.call(a)},q=function(){var b=j.getElementsByClassName("settings")[0],c=j.getElementsByClassName("resizeable"),d=30,e=function(b){document.cookie="preview-width="+b,a(c,function(a){b==="auto"&&(b=a.parentNode.offsetWidth),a.style.width=b+"px",h(a.getElementsByTagName("iframe")[0],"getHeight")})},i=f(document.cookie)["preview-width"];if(i){e(i),g(b.getElementsByClassName("is-active"),"is-active");var k=b.querySelector('button[data-width="'+i+'"]');k&&k.classList.add("is-active")}window.addEventListener("message",function(a){if(a.data==null||!a.source)return;var b=a.data,c=document.getElementsByName(a.source.name)[0];b.height!=null&&c&&(c.parentNode.style.height=b.height+d+"px")},!1),b&&c.length>0&&(b.hidden=!1,b.addEventListener("click",function(a){var c=a.target.tagName.toLowerCase(),d;if(c==="button")d=a.target;else{if(c!=="svg")return;d=a.target.parentNode}a.preventDefault(),g(b.getElementsByClassName("is-active"),"is-active"),d.classList.add("is-active");var f=d.dataset.width;e(f)}))}}()})()</script></body></html><!-- Generated with StyleDocco (http://jacobrask.github.com/styledocco). --> +}</code></pre></div></article></section><div class="bar bottom"><div hidden class="settings container"><!-- Icons from http://iconmonstr.com--><button title="Desktop (1280)" data-width='1280'><svg viewBox="0 0 412 386" height="24" width="26" class="icon"><path d="m147.6,343.9c-4.5,15.9-26.2,37.6-42.1,42.1h201c-15.3,-4-38.1,-26.8-42.1,-42.1H147.6zM387,0.5H25c-13.8,0-25,11.2-25,25V294c0,13.8 11.2,25 25,25h362c13.8,0 25,-11.2 25,-25V25.5C412,11.7 400.8,0.5 387,0.5zM369.9,238.2H42.1L42.1,42.6 369.9,42.6V238.2z"></path></svg></button><button title="Laptop (1024)" data-width='1024'><svg viewBox="0 0 384 312" height="23" width="28" class="icon"><path d="m349.2,20.5c0,-11-9,-20-20,-20H53.6c-11,0-20,9-20,20v194H349.2v-194zm-27,167H60.6V27.5H322.2v160zm28,42H32.6L2.6,282.1c-3.5,6.2-3.5,13.8 0.1,19.9 3.6,6.2 10.2,9.9 17.3,9.9H363.1c7.1,0 13.7,-3.8 17.3,-10 3.6,-6.2 3.6,-13.8 0,-20l-30.2,-52.5zm-196.9,54 8,-23.5h60.5l8,23.5h-76.5z"></path></svg></button><button title="Tablet (768)" data-width='768'><svg viewBox="0 0 317 412" height="24" width="18" class="icon"><path d="M 316.5,380 V 32 c 0,-17.7 -14.3,-32 -32,-32 H 32 C 14.3,0 0,14.3 0,32 v 348 c 0,17.7 14.3,32 32,32 h 252.5 c 17.7,0 32,-14.3 32,-32 z M 40,367 V 45 H 276.5 V 367 H 40 z m 109.8,22.7 c 0,-4.7 3.8,-8.5 8.5,-8.5 4.7,0 8.5,3.8 8.5,8.5 0,4.7 -3.8,8.5 -8.5,8.5 -4.7,0 -8.5,-3.8 -8.5,-8.5 z"></path></svg></button><button title="Smart phone (320)" data-width='320'><svg viewBox="0 0 224 412" height="24" width="13" class="icon"><path d="M 190.7,0 H 33 C 14.8,0 0,14.8 0,33 v 346 c 0,18.2 14.8,33 33,33 h 157.7 c 18.2,0 33,-14.8 33,-33 V 33 c 0,-18.2 -14.8,-33 -33,-33 z M 94.3,30.2 h 37 c 2.2,0 4,1.8 4,4 0,2.2 -1.8,4 -4,4 h -37 c -2.2,0 -4,-1.8 -4,-4 0,-2.2 1.8,-4 4,-4 z m 18.5,362.8 c -8.8,0 -16,-7.2 -16,-16 0,-8.8 7.2,-16 16,-16 8.8,0 16,7.2 16,16 0,8.8 -7.2,16 -16,16 z M 198.6,343.8 H 25.1 V 68.2 h 173.5 v 275.5 z"></path></svg></button><button title="Feature phone (240)" data-width='240'><svg viewBox="0 0 201 412" height="24" width="12" class="icon"><path d="M 165.5,0.2 V 45 H 25 c -13.8,0 -25,11.2 -25,25 V 387 c 0,13.8 11.2,25 25,25 h 150.5 c 13.8,0 25,-11.2 25,-25 V 0.2 h -35 z M 65.2,366.5 H 34.2 v -24.5 h 31 v 24.5 z m 0,-44.3 H 34.2 v -24.5 h 31 v 24.5 z m 50.5,44.3 H 84.7 v -24.5 h 31 v 24.5 z m 0,-44.3 H 84.7 v -24.5 h 31 v 24.5 z m 50.5,44.3 h -31 v -24.5 h 31 v 24.5 z m 0,-44.3 h -31 v -24.5 h 31 v 24.5 z m 0,-59.3 h -132 V 95.4 h 132 V 262.9 z"></path></svg></button><button title="Auto (100%)" data-width="auto" class="auto is-active">Auto</button></div></div><script>(function(){var a=[{title:"actions-toolbar",filename:"actions-toolbar",url:"actions-toolbar.html"},{title:"Actions toolbar",filename:"actions-toolbar",url:"actions-toolbar.html#actions-toolbar"},{title:"Actions toolbar mixin variables",filename:"actions-toolbar",url:"actions-toolbar.html#actions-toolbar-mixin-variables"},{title:"Actions toolbar alignment",filename:"actions-toolbar",url:"actions-toolbar.html#actions-toolbar-alignment"},{title:"Reverse primary and secondary blocks",filename:"actions-toolbar",url:"actions-toolbar.html#reverse-primary-and-secondary-blocks"},{title:"Actions toolbar indents customizations",filename:"actions-toolbar",url:"actions-toolbar.html#actions-toolbar-indents-customizations"},{title:"Responsive actions toolbar",filename:"actions-toolbar",url:"actions-toolbar.html#responsive-actions-toolbar"},{title:"breadcrumbs",filename:"breadcrumbs",url:"breadcrumbs.html"},{title:"Breadcrumbs",filename:"breadcrumbs",url:"breadcrumbs.html#breadcrumbs"},{title:"Breadcrumbs variables",filename:"breadcrumbs",url:"breadcrumbs.html#breadcrumbs-variables"},{title:"Button-styled breadcrumbs with gradient background, border, and no separating symbol",filename:"breadcrumbs",url:"breadcrumbs.html#buttonstyled-breadcrumbs-with-gradient-background-border-and-no-separating-symbol"},{title:"Breadcrumbs with solid background",filename:"breadcrumbs",url:"breadcrumbs.html#breadcrumbs-with-solid-background"},{title:"buttons",filename:"buttons",url:"buttons.html"},{title:"Default button",filename:"buttons",url:"buttons.html#default-button"},{title:"Button variables",filename:"buttons",url:"buttons.html#button-variables"},{title:"Button as an icon",filename:"buttons",url:"buttons.html#button-as-an-icon"},{title:"Button with an icon on the left or right side of the text",filename:"buttons",url:"buttons.html#button-with-an-icon-on-the-left-or-right-side-of-the-text"},{title:"Button with fixed width",filename:"buttons",url:"buttons.html#button-with-fixed-width"},{title:"Primary button",filename:"buttons",url:"buttons.html#primary-button"},{title:"Primary button variables",filename:"buttons",url:"buttons.html#primary-button-variables"},{title:"Button with gradient background",filename:"buttons",url:"buttons.html#button-with-gradient-background"},{title:"Button as a link",filename:"buttons",url:"buttons.html#button-as-a-link"},{title:"Button as a link variables",filename:"buttons",url:"buttons.html#button-as-a-link-variables"},{title:"Link as a button",filename:"buttons",url:"buttons.html#link-as-a-button"},{title:"Button reset",filename:"buttons",url:"buttons.html#button-reset"},{title:"Button revert secondary color",filename:"buttons",url:"buttons.html#button-revert-secondary-color"},{title:"Button revert secondary color variables",filename:"buttons",url:"buttons.html#button-revert-secondary-color-variables"},{title:"Button revert secondary size",filename:"buttons",url:"buttons.html#button-revert-secondary-size"},{title:"Button revert secondary size variables",filename:"buttons",url:"buttons.html#button-revert-secondary-size-variables"},{title:"components",filename:"components",url:"components.html"},{title:"Components",filename:"components",url:"components.html#components"},{title:"Components Variables",filename:"components",url:"components.html#components-variables"},{title:"dropdowns",filename:"dropdowns",url:"dropdowns.html"},{title:"Drop-down and split buttons mixins",filename:"dropdowns",url:"dropdowns.html#dropdown-and-split-buttons-mixins"},{title:"Drop-down",filename:"dropdowns",url:"dropdowns.html#dropdown"},{title:"Drop-down variables",filename:"dropdowns",url:"dropdowns.html#dropdown-variables"},{title:"Drop-down with icon customization",filename:"dropdowns",url:"dropdowns.html#dropdown-with-icon-customization"},{title:"Modify dropdown list styles",filename:"dropdowns",url:"dropdowns.html#modify-dropdown-list-styles"},{title:"Split button",filename:"dropdowns",url:"dropdowns.html#split-button"},{title:"Split button variables",filename:"dropdowns",url:"dropdowns.html#split-button-variables"},{title:"Split button - button styling",filename:"dropdowns",url:"dropdowns.html#split-button-button-styling"},{title:"Split button icon customization",filename:"dropdowns",url:"dropdowns.html#split-button-icon-customization"},{title:"Split button drop-down list customization",filename:"dropdowns",url:"dropdowns.html#split-button-dropdown-list-customization"},{title:"forms",filename:"forms",url:"forms.html"},{title:"Forms mixins",filename:"forms",url:"forms.html#forms-mixins"},{title:"Global forms elements customization",filename:"forms",url:"forms.html#global-forms-elements-customization"},{title:"Fieldsets & fields customization",filename:"forms",url:"forms.html#fieldsets-fields-customization"},{title:"Fieldset and legend customization variables",filename:"forms",url:"forms.html#fieldset-and-legend-customization-variables"},{title:"Fields customization variables",filename:"forms",url:"forms.html#fields-customization-variables"},{title:"Required fields message customization variables",filename:"forms",url:"forms.html#required-fields-message-customization-variables"},{title:"Form element inputs customization",filename:"forms",url:"forms.html#form-element-inputs-customization"},{title:"Form element inputs customization variables",filename:"forms",url:"forms.html#form-element-inputs-customization-variables"},{title:"Form element choice",filename:"forms",url:"forms.html#form-element-choice"},{title:"Form element choice variables",filename:"forms",url:"forms.html#form-element-choice-variables"},{title:"Custom color",filename:"forms",url:"forms.html#custom-color"},{title:"Input number - input-text view",filename:"forms",url:"forms.html#input-number-inputtext-view"},{title:"Input search - input-text view",filename:"forms",url:"forms.html#input-search-inputtext-view"},{title:"Form validation",filename:"forms",url:"forms.html#form-validation"},{title:"Form validation variables",filename:"forms",url:"forms.html#form-validation-variables"},{title:"icons",filename:"icons",url:"icons.html"},{title:"Icons",filename:"icons",url:"icons.html#icons"},{title:"Icon with image or sprite",filename:"icons",url:"icons.html#icon-with-image-or-sprite"},{title:"Icon with image or sprite variables",filename:"icons",url:"icons.html#icon-with-image-or-sprite-variables"},{title:"Icon position for an icon with image or sprite",filename:"icons",url:"icons.html#icon-position-for-an-icon-with-image-or-sprite"},{title:"Position for icon with image or sprite mixin variables",filename:"icons",url:"icons.html#position-for-icon-with-image-or-sprite-mixin-variables"},{title:"Icon sprite position (with grid)",filename:"icons",url:"icons.html#icon-sprite-position-with-grid"},{title:"Icon sprite position variables",filename:"icons",url:"icons.html#icon-sprite-position-variables"},{title:"Image/sprite icon size",filename:"icons",url:"icons.html#imagesprite-icon-size"},{title:"Image/sprite icon size variables",filename:"icons",url:"icons.html#imagesprite-icon-size-variables"},{title:"Font icon",filename:"icons",url:"icons.html#font-icon"},{title:"Font icon variables",filename:"icons",url:"icons.html#font-icon-variables"},{title:"Change the size of font icon",filename:"icons",url:"icons.html#change-the-size-of-font-icon"},{title:"Change the size of font icon variables",filename:"icons",url:"icons.html#change-the-size-of-font-icon-variables"},{title:"Hide icon text",filename:"icons",url:"icons.html#hide-icon-text"},{title:"Sprite and font icons for Blank theme",filename:"icons",url:"icons.html#sprite-and-font-icons-for-blank-theme"},{title:"layout",filename:"layout",url:"layout.html"},{title:"Layout",filename:"layout",url:"layout.html#layout"},{title:"Layout global variables",filename:"layout",url:"layout.html#layout-global-variables"},{title:"Page layouts",filename:"layout",url:"layout.html#page-layouts"},{title:"Layout column",filename:"layout",url:"layout.html#layout-column"},{title:"Layout column variables",filename:"layout",url:"layout.html#layout-column-variables"},{title:"Layout width",filename:"layout",url:"layout.html#layout-width"},{title:"Layout width variables",filename:"layout",url:"layout.html#layout-width-variables"},{title:"lib",filename:"lib",url:"lib.html"},{title:"Including Magento UI library to your theme",filename:"lib",url:"lib.html#including-magento-ui-library-to-your-theme"},{title:"loaders",filename:"loaders",url:"loaders.html"},{title:"Loaders",filename:"loaders",url:"loaders.html#loaders"},{title:"Default loader variables",filename:"loaders",url:"loaders.html#default-loader-variables"},{title:"Loading",filename:"loaders",url:"loaders.html#loading"},{title:"Loading default variables",filename:"loaders",url:"loaders.html#loading-default-variables"},{title:"messages",filename:"messages",url:"messages.html"},{title:"Messages",filename:"messages",url:"messages.html#messages"},{title:"Information message",filename:"messages",url:"messages.html#information-message"},{title:"Warning message",filename:"messages",url:"messages.html#warning-message"},{title:"Error message",filename:"messages",url:"messages.html#error-message"},{title:"Success message",filename:"messages",url:"messages.html#success-message"},{title:"Notice message",filename:"messages",url:"messages.html#notice-message"},{title:"Message with inner icon",filename:"messages",url:"messages.html#message-with-inner-icon"},{title:"Message with lateral icon",filename:"messages",url:"messages.html#message-with-lateral-icon"},{title:"Custom message style",filename:"messages",url:"messages.html#custom-message-style"},{title:"Messages global variables",filename:"messages",url:"messages.html#messages-global-variables"},{title:"pages",filename:"pages",url:"pages.html"},{title:"Pagination HTML markup",filename:"pages",url:"pages.html#pagination-html-markup"},{title:"Pagination variables",filename:"pages",url:"pages.html#pagination-variables"},{title:"Pagination with label and gradient background on links",filename:"pages",url:"pages.html#pagination-with-label-and-gradient-background-on-links"},{title:'Pagination with "previous"..."next" text links and label',filename:"pages",url:"pages.html#pagination-with-previousnext-text-links-and-label"},{title:"Pagination without label, with solid background",filename:"pages",url:"pages.html#pagination-without-label-with-solid-background"},{title:"popups",filename:"popups",url:"popups.html"},{title:"Popups",filename:"popups",url:"popups.html#popups"},{title:"Popup variables",filename:"popups",url:"popups.html#popup-variables"},{title:"Window overlay mixin variables",filename:"popups",url:"popups.html#window-overlay-mixin-variables"},{title:"Fixed height popup",filename:"popups",url:"popups.html#fixed-height-popup"},{title:"Fixed content height popup",filename:"popups",url:"popups.html#fixed-content-height-popup"},{title:"Margins for header, content and footer block in popup",filename:"popups",url:"popups.html#margins-for-header-content-and-footer-block-in-popup"},{title:"Popup titles styled as theme headings",filename:"popups",url:"popups.html#popup-titles-styled-as-theme-headings"},{title:"Popup action toolbar",filename:"popups",url:"popups.html#popup-action-toolbar"},{title:"Popup Close button without an icon",filename:"popups",url:"popups.html#popup-close-button-without-an-icon"},{title:"Modify the icon of popup Close button",filename:"popups",url:"popups.html#modify-the-icon-of-popup-close-button"},{title:"Modify overlay styles",filename:"popups",url:"popups.html#modify-overlay-styles"},{title:"rating",filename:"rating",url:"rating.html"},{title:"Ratings",filename:"rating",url:"rating.html#ratings"},{title:"Global rating variables",filename:"rating",url:"rating.html#global-rating-variables"},{title:"Rating with vote",filename:"rating",url:"rating.html#rating-with-vote"},{title:"Rating with vote icons number customization",filename:"rating",url:"rating.html#rating-with-vote-icons-number-customization"},{title:"Rating with vote icons colors customization",filename:"rating",url:"rating.html#rating-with-vote-icons-colors-customization"},{title:"Rating with vote icons symbol customization",filename:"rating",url:"rating.html#rating-with-vote-icons-symbol-customization"},{title:"Accessible rating with vote",filename:"rating",url:"rating.html#accessible-rating-with-vote"},{title:"Rating summary",filename:"rating",url:"rating.html#rating-summary"},{title:"Rating summary icons number customization",filename:"rating",url:"rating.html#rating-summary-icons-number-customization"},{title:"Rating summary icons color customization",filename:"rating",url:"rating.html#rating-summary-icons-color-customization"},{title:"Rating summary icons symbol customization",filename:"rating",url:"rating.html#rating-summary-icons-symbol-customization"},{title:"Rating summary hide label",filename:"rating",url:"rating.html#rating-summary-hide-label"},{title:"Rating summary multiple ratings",filename:"rating",url:"rating.html#rating-summary-multiple-ratings"},{title:"Rating hide label mixin",filename:"rating",url:"rating.html#rating-hide-label-mixin"},{title:"resets",filename:"resets",url:"resets.html"},{title:"Resets",filename:"resets",url:"resets.html#resets"},{title:"responsive",filename:"responsive",url:"responsive.html"},{title:"Responsive",filename:"responsive",url:"responsive.html#responsive"},{title:"Responsive mixins usage",filename:"responsive",url:"responsive.html#responsive-mixins-usage"},{title:"Media query style groups separation variables",filename:"responsive",url:"responsive.html#media-query-style-groups-separation-variables"},{title:"Responsive breakpoints",filename:"responsive",url:"responsive.html#responsive-breakpoints"},{title:"sections",filename:"sections",url:"sections.html"},{title:"Tabs and accordions",filename:"sections",url:"sections.html#tabs-and-accordions"},{title:"Tabs",filename:"sections",url:"sections.html#tabs"},{title:"Tabs mixin variables",filename:"sections",url:"sections.html#tabs-mixin-variables"},{title:"Tabs with content top border",filename:"sections",url:"sections.html#tabs-with-content-top-border"},{title:"Accordion",filename:"sections",url:"sections.html#accordion"},{title:"Accordion mixin variables",filename:"sections",url:"sections.html#accordion-mixin-variables"},{title:"Responsive tabs",filename:"sections",url:"sections.html#responsive-tabs"},{title:"Tabs Base",filename:"sections",url:"sections.html#tabs-base"},{title:"Accordion Base",filename:"sections",url:"sections.html#accordion-base"},{title:"tables",filename:"tables",url:"tables.html"},{title:"Tables",filename:"tables",url:"tables.html#tables"},{title:"Table mixin variables",filename:"tables",url:"tables.html#table-mixin-variables"},{title:"Table typography",filename:"tables",url:"tables.html#table-typography"},{title:"Table typography mixin variables",filename:"tables",url:"tables.html#table-typography-mixin-variables"},{title:"Table caption",filename:"tables",url:"tables.html#table-caption"},{title:"Table caption mixin variables",filename:"tables",url:"tables.html#table-caption-mixin-variables"},{title:"Table cells resize",filename:"tables",url:"tables.html#table-cells-resize"},{title:"Table cells resize variables",filename:"tables",url:"tables.html#table-cells-resize-variables"},{title:"Table background customization",filename:"tables",url:"tables.html#table-background-customization"},{title:"Table background mixin variables",filename:"tables",url:"tables.html#table-background-mixin-variables"},{title:"Table borders customization",filename:"tables",url:"tables.html#table-borders-customization"},{title:"Table borders mixin variables",filename:"tables",url:"tables.html#table-borders-mixin-variables"},{title:"Table with horizontal borders",filename:"tables",url:"tables.html#table-with-horizontal-borders"},{title:"Table with vertical borders",filename:"tables",url:"tables.html#table-with-vertical-borders"},{title:"Table with light borders",filename:"tables",url:"tables.html#table-with-light-borders"},{title:"Table without borders",filename:"tables",url:"tables.html#table-without-borders"},{title:"Striped table",filename:"tables",url:"tables.html#striped-table"},{title:"Striped table mixin variables",filename:"tables",url:"tables.html#striped-table-mixin-variables"},{title:"Table with rows hover",filename:"tables",url:"tables.html#table-with-rows-hover"},{title:"Table with rows hover mixin variables",filename:"tables",url:"tables.html#table-with-rows-hover-mixin-variables"},{title:"Responsive table technics #1",filename:"tables",url:"tables.html#responsive-table-technics-1"},{title:"Responsive table technics #2",filename:"tables",url:"tables.html#responsive-table-technics-2"},{title:"Responsive table technics #2 mixin variables",filename:"tables",url:"tables.html#responsive-table-technics-2-mixin-variables"},{title:"tooltips",filename:"tooltips",url:"tooltips.html"},{title:"Tooltips",filename:"tooltips",url:"tooltips.html#tooltips"},{title:"Tooltips variables",filename:"tooltips",url:"tooltips.html#tooltips-variables"},{title:"typography",filename:"typography",url:"typography.html"},{title:"Typogrphy",filename:"typography",url:"typography.html#typogrphy"},{title:"Typography variables",filename:"typography",url:"typography.html#typography-variables"},{title:"Font-size mixin",filename:"typography",url:"typography.html#fontsize-mixin"},{title:"Line-height mixin",filename:"typography",url:"typography.html#lineheight-mixin"},{title:"Word breaking mixin",filename:"typography",url:"typography.html#word-breaking-mixin"},{title:"Font face mixin",filename:"typography",url:"typography.html#font-face-mixin"},{title:"Text overflow mixin",filename:"typography",url:"typography.html#text-overflow-mixin"},{title:"Text hide",filename:"typography",url:"typography.html#text-hide"},{title:"Hyphens",filename:"typography",url:"typography.html#hyphens"},{title:"Font style and color",filename:"typography",url:"typography.html#font-style-and-color"},{title:"Font style mixin variables",filename:"typography",url:"typography.html#font-style-mixin-variables"},{title:"Reset list styles",filename:"typography",url:"typography.html#reset-list-styles"},{title:"Reset list styles variables",filename:"typography",url:"typography.html#reset-list-styles-variables"},{title:"Inline-block list item styling",filename:"typography",url:"typography.html#inlineblock-list-item-styling"},{title:"Link styling mixin",filename:"typography",url:"typography.html#link-styling-mixin"},{title:"Link styling mixin variables",filename:"typography",url:"typography.html#link-styling-mixin-variables"},{title:"Heading styling mixin",filename:"typography",url:"typography.html#heading-styling-mixin"},{title:"Base typography mixins",filename:"typography",url:"typography.html#base-typography-mixins"},{title:"Base typography mixin variables",filename:"typography",url:"typography.html#base-typography-mixin-variables"},{title:"Headings typography mixin",filename:"typography",url:"typography.html#headings-typography-mixin"},{title:"Headings typography mixin variables",filename:"typography",url:"typography.html#headings-typography-mixin-variables"},{title:"Typography links mixin",filename:"typography",url:"typography.html#typography-links-mixin"},{title:"Typography lists mixin",filename:"typography",url:"typography.html#typography-lists-mixin"},{title:"Typography lists mixin variables",filename:"typography",url:"typography.html#typography-lists-mixin-variables"},{title:"Typography code elements mixin",filename:"typography",url:"typography.html#typography-code-elements-mixin"},{title:"Typography code mixin variables",filename:"typography",url:"typography.html#typography-code-mixin-variables"},{title:"Typography blockquote",filename:"typography",url:"typography.html#typography-blockquote"},{title:"Typography blockquote mixin variables",filename:"typography",url:"typography.html#typography-blockquote-mixin-variables"},{title:"utilities",filename:"utilities",url:"utilities.html"},{title:"Utilities",filename:"utilities",url:"utilities.html#utilities"},{title:".lib-clearfix()",filename:"utilities",url:"utilities.html#libclearfix"},{title:".lib-visibility-hidden()",filename:"utilities",url:"utilities.html#libvisibilityhidden"},{title:".lib-visually-hidden()",filename:"utilities",url:"utilities.html#libvisuallyhidden"},{title:".lib-visually-hidden-reset()",filename:"utilities",url:"utilities.html#libvisuallyhiddenreset"},{title:".lib-css()",filename:"utilities",url:"utilities.html#libcss"},{title:".lib-css() variables",filename:"utilities",url:"utilities.html#libcss-variables"},{title:".lib-rotate()",filename:"utilities",url:"utilities.html#librotate"},{title:".lib-rotate() variables",filename:"utilities",url:"utilities.html#librotate-variables"},{title:".lib-input-placeholder()",filename:"utilities",url:"utilities.html#libinputplaceholder"},{title:".lib-input-placeholder() variables",filename:"utilities",url:"utilities.html#libinputplaceholder-variables"},{title:".lib-background-gradient()",filename:"utilities",url:"utilities.html#libbackgroundgradient"},{title:".lib-background-gradient() variables",filename:"utilities",url:"utilities.html#libbackgroundgradient-variables"},{title:"variables",filename:"variables",url:"variables.html"},{title:"List of Global Variables",filename:"variables",url:"variables.html#list-of-global-variables"},{title:"Table with rows hover mixin variables",filename:"variables",url:"variables.html#table-with-rows-hover-mixin-variables"},{title:"docs",filename:"docs",url:"docs.html"},{title:"Documentation",filename:"docs",url:"docs.html#documentation"}];(function(){"use strict";var b=function(a,b){return Array.prototype.indexOf.call(a,b)!==-1},c=function(a,b){return Array.prototype.filter.call(a,b)},d=function(a,b){return Array.prototype.forEach.call(a,b)},e=document.getElementsByTagName("body")[0];e.addEventListener("click",function(a){var b=a.target;b.tagName.toLowerCase()==="svg"&&(b=b.parentNode);var c=!1;b.dataset.toggle!=null&&(a.preventDefault(),b.classList.contains("is-active")||(c=!0)),d(e.querySelectorAll("[data-toggle]"),function(a){a.classList.remove("is-active"),document.getElementById(a.dataset.toggle).hidden=!0}),c&&(b.classList.add("is-active"),document.getElementById(b.dataset.toggle).hidden=!1)}),function(){var f=e.getElementsByClassName("nav")[0];if(!f)return;var g=document.createElement("ul");g.className="nav-results",g.id="nav-search",g.hidden=!0,d(a,function(a){var b,c,d;b=document.createElement("li"),b._title=a.title.toLowerCase(),b.hidden=!0,b.appendChild(c=document.createElement("a")),c.href=a.url,c.innerHTML=a.title,c.appendChild(d=document.createElement("span")),d.innerHTML=a.filename,d.className="nav-results-filename",g.appendChild(b)}),f.appendChild(g);var h=g.children,i=function(a){d(h,function(a){a.hidden=!0});var b=this.value.toLowerCase(),e=[];b!==""&&(e=c(h,function(a){return a._title.indexOf(b)!==-1})),e.length>0?(d(e,function(a){a.hidden=!1}),g.hidden=!1):g.hidden=!0},j=f.querySelector('input[type="search"]');j.addEventListener("keyup",i),j.addEventListener("focus",i),e.addEventListener("click",function(a){if(a.target.classList&&a.target.classList.contains("search"))return;g.hidden=!0}),g.addEventListener("click",function(a){j.value=""});var k=document.createElement("ul");k.id="nav-toc",k.hidden=!0,k.className="nav-results toc-list",c(e.getElementsByTagName("*"),function(a){return b(["h1","h2","h3"],a.tagName.toLowerCase())}).map(function(a){var b=document.createElement("li"),c=document.createElement("a"),d=a.tagName.toLowerCase()[1];c.classList.add("level-"+d),b.appendChild(c),c.href="#"+a.id,c.innerHTML=a.innerHTML,k.appendChild(b)}),f.appendChild(k)}()})(),function(){"use strict";if(location.hash==="#__preview__"||location.protocol==="data:")return;var a=function(a,b){return Array.prototype.forEach.call(a,b)},b=function(a,b){var e=Array.prototype.slice.call(arguments,2);return d(a,function(a){return(c(b)?b||a:a[b]).apply(a,e)})},c=function(a){return Object.prototype.toString.call(a)==="[object Function]"},d=function(a,b){return Array.prototype.map.call(a,b)},e=function(a,b){return d(a,function(a){return a[b]})},f=function(a){var b={},c=a.split(";");for(var d=0;c.length>d;d++){var e=c[d].trim().split("=");b[e[0]]=e[1]}return b},g=function(a,c){return b(e(a,"classList"),"remove",c)},h=function(a,b){a.contentDocument.defaultView.postMessage(b,"*")},i=document.getElementsByTagName("head")[0],j=document.getElementsByTagName("body")[0],k=e(i.querySelectorAll('style[type="text/preview"]'),"innerHTML").join(""),l=e(i.querySelectorAll('script[type="text/preview"]'),"innerHTML").join(""),m=location.href.split("#")[0]+"#__preview__",n=document.createElement("iframe");n.src="data:text/html,",j.appendChild(n),n.addEventListener("load",function(){var b={sameOriginDataUri:!0};try{this.contentDocument,this.contentDocument||(b.sameOriginDataUri=!1)}catch(c){b.sameOriginDataUri=!1}this.parentNode.removeChild(this),a(j.getElementsByTagName("textarea"),function(a,c){o(a,b,c),q(),p(a)})});var o=function(a,b,c){var d,e,f;d=document.createElement("div"),d.appendChild(e=document.createElement("div")),d.className="preview",e.appendChild(f=document.createElement("iframe")),e.className="resizeable",f.setAttribute("scrolling","no"),f.name="iframe"+c++,f.addEventListener("load",function(){var c,d,e,f,g,i,j;j=this.contentDocument;if(!b.sameOriginDataUri&&this.src!==m)return;this.src===m&&(c=j.createElement("html"),c.appendChild(j.createElement("head")),c.appendChild(d=j.createElement("body")),d.innerHTML=a.textContent,j.replaceChild(c,j.documentElement)),g=j.createElement("head"),g.appendChild(f=j.createElement("style")),g.appendChild(e=j.createElement("script")),e.textContent=l,f.textContent=k,i=j.getElementsByTagName("head")[0],i.parentNode.replaceChild(g,i),h(this,"getHeight")});var g;b.sameOriginDataUri?g="data:text/html;charset=utf-8,"+encodeURIComponent("<!doctype html><html><head></head></body>"+a.textContent):g=m,f.setAttribute("src",g);var i=function(){f.contentDocument.body.innerHTML=this.value,h(f,"getHeight")};a.addEventListener("keypress",i),a.addEventListener("keyup",i),a.parentNode.insertBefore(d,a)},p=function(a){var b=document.createElement("div");b.className="preview-code",b.style.position="absolute",b.style.left="-9999px",j.appendChild(b);var c=parseInt(window.getComputedStyle(a).getPropertyValue("max-height"),10),d=function(a){b.textContent=this.value+"\n";var d=b.offsetHeight+2;d>=c?this.style.overflow="auto":this.style.overflow="hidden",this.style.height=b.offsetHeight+2+"px"};a.addEventListener("keypress",d),a.addEventListener("keyup",d),d.call(a)},q=function(){var b=j.getElementsByClassName("settings")[0],c=j.getElementsByClassName("resizeable"),d=30,e=function(b){document.cookie="preview-width="+b,a(c,function(a){b==="auto"&&(b=a.parentNode.offsetWidth),a.style.width=b+"px",h(a.getElementsByTagName("iframe")[0],"getHeight")})},i=f(document.cookie)["preview-width"];if(i){e(i),g(b.getElementsByClassName("is-active"),"is-active");var k=b.querySelector('button[data-width="'+i+'"]');k&&k.classList.add("is-active")}window.addEventListener("message",function(a){if(a.data==null||!a.source)return;var b=a.data,c=document.getElementsByName(a.source.name)[0];b.height!=null&&c&&(c.parentNode.style.height=b.height+d+"px")},!1),b&&c.length>0&&(b.hidden=!1,b.addEventListener("click",function(a){var c=a.target.tagName.toLowerCase(),d;if(c==="button")d=a.target;else{if(c!=="svg")return;d=a.target.parentNode}a.preventDefault(),g(b.getElementsByClassName("is-active"),"is-active"),d.classList.add("is-active");var f=d.dataset.width;e(f)}))}}()})()</script></body></html><!-- Generated with StyleDocco (http://jacobrask.github.com/styledocco). --> diff --git a/lib/web/css/docs/popups.html b/lib/web/css/docs/popups.html index d31d50f6ed7c6..9f7aff4c6569b 100644 --- a/lib/web/css/docs/popups.html +++ b/lib/web/css/docs/popups.html @@ -750,4 +750,4 @@ <h2 id="simple-popup">Simple popup</h2> @_overlay-opacity: .8, @_overlay-opacity-old: 80 ); -}</code></pre></div></article></section><div class="bar bottom"><div hidden class="settings container"><!-- Icons from http://iconmonstr.com--><button title="Desktop (1280)" data-width='1280'><svg viewBox="0 0 412 386" height="24" width="26" class="icon"><path d="m147.6,343.9c-4.5,15.9-26.2,37.6-42.1,42.1h201c-15.3,-4-38.1,-26.8-42.1,-42.1H147.6zM387,0.5H25c-13.8,0-25,11.2-25,25V294c0,13.8 11.2,25 25,25h362c13.8,0 25,-11.2 25,-25V25.5C412,11.7 400.8,0.5 387,0.5zM369.9,238.2H42.1L42.1,42.6 369.9,42.6V238.2z"></path></svg></button><button title="Laptop (1024)" data-width='1024'><svg viewBox="0 0 384 312" height="23" width="28" class="icon"><path d="m349.2,20.5c0,-11-9,-20-20,-20H53.6c-11,0-20,9-20,20v194H349.2v-194zm-27,167H60.6V27.5H322.2v160zm28,42H32.6L2.6,282.1c-3.5,6.2-3.5,13.8 0.1,19.9 3.6,6.2 10.2,9.9 17.3,9.9H363.1c7.1,0 13.7,-3.8 17.3,-10 3.6,-6.2 3.6,-13.8 0,-20l-30.2,-52.5zm-196.9,54 8,-23.5h60.5l8,23.5h-76.5z"></path></svg></button><button title="Tablet (768)" data-width='768'><svg viewBox="0 0 317 412" height="24" width="18" class="icon"><path d="M 316.5,380 V 32 c 0,-17.7 -14.3,-32 -32,-32 H 32 C 14.3,0 0,14.3 0,32 v 348 c 0,17.7 14.3,32 32,32 h 252.5 c 17.7,0 32,-14.3 32,-32 z M 40,367 V 45 H 276.5 V 367 H 40 z m 109.8,22.7 c 0,-4.7 3.8,-8.5 8.5,-8.5 4.7,0 8.5,3.8 8.5,8.5 0,4.7 -3.8,8.5 -8.5,8.5 -4.7,0 -8.5,-3.8 -8.5,-8.5 z"></path></svg></button><button title="Smart phone (320)" data-width='320'><svg viewBox="0 0 224 412" height="24" width="13" class="icon"><path d="M 190.7,0 H 33 C 14.8,0 0,14.8 0,33 v 346 c 0,18.2 14.8,33 33,33 h 157.7 c 18.2,0 33,-14.8 33,-33 V 33 c 0,-18.2 -14.8,-33 -33,-33 z M 94.3,30.2 h 37 c 2.2,0 4,1.8 4,4 0,2.2 -1.8,4 -4,4 h -37 c -2.2,0 -4,-1.8 -4,-4 0,-2.2 1.8,-4 4,-4 z m 18.5,362.8 c -8.8,0 -16,-7.2 -16,-16 0,-8.8 7.2,-16 16,-16 8.8,0 16,7.2 16,16 0,8.8 -7.2,16 -16,16 z M 198.6,343.8 H 25.1 V 68.2 h 173.5 v 275.5 z"></path></svg></button><button title="Feature phone (240)" data-width='240'><svg viewBox="0 0 201 412" height="24" width="12" class="icon"><path d="M 165.5,0.2 V 45 H 25 c -13.8,0 -25,11.2 -25,25 V 387 c 0,13.8 11.2,25 25,25 h 150.5 c 13.8,0 25,-11.2 25,-25 V 0.2 h -35 z M 65.2,366.5 H 34.2 v -24.5 h 31 v 24.5 z m 0,-44.3 H 34.2 v -24.5 h 31 v 24.5 z m 50.5,44.3 H 84.7 v -24.5 h 31 v 24.5 z m 0,-44.3 H 84.7 v -24.5 h 31 v 24.5 z m 50.5,44.3 h -31 v -24.5 h 31 v 24.5 z m 0,-44.3 h -31 v -24.5 h 31 v 24.5 z m 0,-59.3 h -132 V 95.4 h 132 V 262.9 z"></path></svg></button><button title="Auto (100%)" data-width="auto" class="auto is-active">Auto</button></div></div><script>(function(){var a=[{title:"actions-toolbar",filename:"actions-toolbar",url:"actions-toolbar.html"},{title:"Actions toolbar",filename:"actions-toolbar",url:"actions-toolbar.html#actions-toolbar"},{title:"Actions toolbar mixin variables",filename:"actions-toolbar",url:"actions-toolbar.html#actions-toolbar-mixin-variables"},{title:"Actions toolbar alignment",filename:"actions-toolbar",url:"actions-toolbar.html#actions-toolbar-alignment"},{title:"Reverse primary and secondary blocks",filename:"actions-toolbar",url:"actions-toolbar.html#reverse-primary-and-secondary-blocks"},{title:"Actions toolbar indents customizations",filename:"actions-toolbar",url:"actions-toolbar.html#actions-toolbar-indents-customizations"},{title:"Responsive actions toolbar",filename:"actions-toolbar",url:"actions-toolbar.html#responsive-actions-toolbar"},{title:"breadcrumbs",filename:"breadcrumbs",url:"breadcrumbs.html"},{title:"Breadcrumbs",filename:"breadcrumbs",url:"breadcrumbs.html#breadcrumbs"},{title:"Breadcrumbs variables",filename:"breadcrumbs",url:"breadcrumbs.html#breadcrumbs-variables"},{title:"Button-styled breadcrumbs with gradient background, border, and no separating symbol",filename:"breadcrumbs",url:"breadcrumbs.html#buttonstyled-breadcrumbs-with-gradient-background-border-and-no-separating-symbol"},{title:"Breadcrumbs with solid background",filename:"breadcrumbs",url:"breadcrumbs.html#breadcrumbs-with-solid-background"},{title:"buttons",filename:"buttons",url:"buttons.html"},{title:"Default button",filename:"buttons",url:"buttons.html#default-button"},{title:"Button variables",filename:"buttons",url:"buttons.html#button-variables"},{title:"Button as an icon",filename:"buttons",url:"buttons.html#button-as-an-icon"},{title:"Button with an icon on the left or right side of the text",filename:"buttons",url:"buttons.html#button-with-an-icon-on-the-left-or-right-side-of-the-text"},{title:"Button with fixed width",filename:"buttons",url:"buttons.html#button-with-fixed-width"},{title:"Primary button",filename:"buttons",url:"buttons.html#primary-button"},{title:"Primary button variables",filename:"buttons",url:"buttons.html#primary-button-variables"},{title:"Button with gradient background",filename:"buttons",url:"buttons.html#button-with-gradient-background"},{title:"Button as a link",filename:"buttons",url:"buttons.html#button-as-a-link"},{title:"Button as a link variables",filename:"buttons",url:"buttons.html#button-as-a-link-variables"},{title:"Link as a button",filename:"buttons",url:"buttons.html#link-as-a-button"},{title:"Button reset",filename:"buttons",url:"buttons.html#button-reset"},{title:"Button revert secondary color",filename:"buttons",url:"buttons.html#button-revert-secondary-color"},{title:"Button revert secondary color variables",filename:"buttons",url:"buttons.html#button-revert-secondary-color-variables"},{title:"Button revert secondary size",filename:"buttons",url:"buttons.html#button-revert-secondary-size"},{title:"Button revert secondary size variables",filename:"buttons",url:"buttons.html#button-revert-secondary-size-variables"},{title:"components",filename:"components",url:"components.html"},{title:"Components",filename:"components",url:"components.html#components"},{title:"Components Variables",filename:"components",url:"components.html#components-variables"},{title:"dropdowns",filename:"dropdowns",url:"dropdowns.html"},{title:"Drop-down and split buttons mixins",filename:"dropdowns",url:"dropdowns.html#dropdown-and-split-buttons-mixins"},{title:"Drop-down",filename:"dropdowns",url:"dropdowns.html#dropdown"},{title:"Drop-down variables",filename:"dropdowns",url:"dropdowns.html#dropdown-variables"},{title:"Drop-down with icon customization",filename:"dropdowns",url:"dropdowns.html#dropdown-with-icon-customization"},{title:"Modify dropdown list styles",filename:"dropdowns",url:"dropdowns.html#modify-dropdown-list-styles"},{title:"Split button",filename:"dropdowns",url:"dropdowns.html#split-button"},{title:"Split button variables",filename:"dropdowns",url:"dropdowns.html#split-button-variables"},{title:"Split button - button styling",filename:"dropdowns",url:"dropdowns.html#split-button-button-styling"},{title:"Split button icon customization",filename:"dropdowns",url:"dropdowns.html#split-button-icon-customization"},{title:"Split button drop-down list customization",filename:"dropdowns",url:"dropdowns.html#split-button-dropdown-list-customization"},{title:"forms",filename:"forms",url:"forms.html"},{title:"Forms mixins",filename:"forms",url:"forms.html#forms-mixins"},{title:"Global forms elements customization",filename:"forms",url:"forms.html#global-forms-elements-customization"},{title:"Fieldsets & fields customization",filename:"forms",url:"forms.html#fieldsets-fields-customization"},{title:"Fieldset and legend customization variables",filename:"forms",url:"forms.html#fieldset-and-legend-customization-variables"},{title:"Fields customization variables",filename:"forms",url:"forms.html#fields-customization-variables"},{title:"Required fields message customization variables",filename:"forms",url:"forms.html#required-fields-message-customization-variables"},{title:"Form element inputs customization",filename:"forms",url:"forms.html#form-element-inputs-customization"},{title:"Form element inputs customization variables",filename:"forms",url:"forms.html#form-element-inputs-customization-variables"},{title:"Form element choice",filename:"forms",url:"forms.html#form-element-choice"},{title:"Form element choice variables",filename:"forms",url:"forms.html#form-element-choice-variables"},{title:"Custom color",filename:"forms",url:"forms.html#custom-color"},{title:"Input number - input-text view",filename:"forms",url:"forms.html#input-number-inputtext-view"},{title:"Input search - input-text view",filename:"forms",url:"forms.html#input-search-inputtext-view"},{title:"Form validation",filename:"forms",url:"forms.html#form-validation"},{title:"Form validation variables",filename:"forms",url:"forms.html#form-validation-variables"},{title:"icons",filename:"icons",url:"icons.html"},{title:"Icons",filename:"icons",url:"icons.html#icons"},{title:"Icon with image or sprite",filename:"icons",url:"icons.html#icon-with-image-or-sprite"},{title:"Icon with image or sprite variables",filename:"icons",url:"icons.html#icon-with-image-or-sprite-variables"},{title:"Icon position for an icon with image or sprite",filename:"icons",url:"icons.html#icon-position-for-an-icon-with-image-or-sprite"},{title:"Position for icon with image or sprite mixin variables",filename:"icons",url:"icons.html#position-for-icon-with-image-or-sprite-mixin-variables"},{title:"Icon sprite position (with grid)",filename:"icons",url:"icons.html#icon-sprite-position-with-grid"},{title:"Icon sprite position variables",filename:"icons",url:"icons.html#icon-sprite-position-variables"},{title:"Image/sprite icon size",filename:"icons",url:"icons.html#imagesprite-icon-size"},{title:"Image/sprite icon size variables",filename:"icons",url:"icons.html#imagesprite-icon-size-variables"},{title:"Font icon",filename:"icons",url:"icons.html#font-icon"},{title:"Font icon variables",filename:"icons",url:"icons.html#font-icon-variables"},{title:"Change the size of font icon",filename:"icons",url:"icons.html#change-the-size-of-font-icon"},{title:"Change the size of font icon variables",filename:"icons",url:"icons.html#change-the-size-of-font-icon-variables"},{title:"Hide icon text",filename:"icons",url:"icons.html#hide-icon-text"},{title:"Sprite and font icons for Blank theme",filename:"icons",url:"icons.html#sprite-and-font-icons-for-blank-theme"},{title:"layout",filename:"layout",url:"layout.html"},{title:"Layout",filename:"layout",url:"layout.html#layout"},{title:"Layout global variables",filename:"layout",url:"layout.html#layout-global-variables"},{title:"Page layouts",filename:"layout",url:"layout.html#page-layouts"},{title:"Layout column",filename:"layout",url:"layout.html#layout-column"},{title:"Layout column variables",filename:"layout",url:"layout.html#layout-column-variables"},{title:"Layout width",filename:"layout",url:"layout.html#layout-width"},{title:"Layout width variables",filename:"layout",url:"layout.html#layout-width-variables"},{title:"lib",filename:"lib",url:"lib.html"},{title:"Including Magento UI library to your theme",filename:"lib",url:"lib.html#including-magento-ui-library-to-your-theme"},{title:"loaders",filename:"loaders",url:"loaders.html"},{title:"Loaders",filename:"loaders",url:"loaders.html#loaders"},{title:"Default loader variables",filename:"loaders",url:"loaders.html#default-loader-variables"},{title:"Loading",filename:"loaders",url:"loaders.html#loading"},{title:"Loading default variables",filename:"loaders",url:"loaders.html#loading-default-variables"},{title:"messages",filename:"messages",url:"messages.html"},{title:"Messages",filename:"messages",url:"messages.html#messages"},{title:"Information message",filename:"messages",url:"messages.html#information-message"},{title:"Warning message",filename:"messages",url:"messages.html#warning-message"},{title:"Error message",filename:"messages",url:"messages.html#error-message"},{title:"Success message",filename:"messages",url:"messages.html#success-message"},{title:"Notice message",filename:"messages",url:"messages.html#notice-message"},{title:"Message with inner icon",filename:"messages",url:"messages.html#message-with-inner-icon"},{title:"Message with lateral icon",filename:"messages",url:"messages.html#message-with-lateral-icon"},{title:"Custom message style",filename:"messages",url:"messages.html#custom-message-style"},{title:"Messages global variables",filename:"messages",url:"messages.html#messages-global-variables"},{title:"pages",filename:"pages",url:"pages.html"},{title:"Pagination HTML markup",filename:"pages",url:"pages.html#pagination-html-markup"},{title:"Pagination variables",filename:"pages",url:"pages.html#pagination-variables"},{title:"Pagination with label and gradient background on links",filename:"pages",url:"pages.html#pagination-with-label-and-gradient-background-on-links"},{title:'Pagination with "previous"..."next" text links and label',filename:"pages",url:"pages.html#pagination-with-previousnext-text-links-and-label"},{title:"Pagination without label, with solid background",filename:"pages",url:"pages.html#pagination-without-label-with-solid-background"},{title:"popups",filename:"popups",url:"popups.html"},{title:"Popups",filename:"popups",url:"popups.html#popups"},{title:"Popup variables",filename:"popups",url:"popups.html#popup-variables"},{title:"Window overlay mixin variables",filename:"popups",url:"popups.html#window-overlay-mixin-variables"},{title:"Fixed height popup",filename:"popups",url:"popups.html#fixed-height-popup"},{title:"Fixed content height popup",filename:"popups",url:"popups.html#fixed-content-height-popup"},{title:"Margins for header, content and footer block in popup",filename:"popups",url:"popups.html#margins-for-header-content-and-footer-block-in-popup"},{title:"Popup titles styled as theme headings",filename:"popups",url:"popups.html#popup-titles-styled-as-theme-headings"},{title:"Popup action toolbar",filename:"popups",url:"popups.html#popup-action-toolbar"},{title:"Popup Close button without an icon",filename:"popups",url:"popups.html#popup-close-button-without-an-icon"},{title:"Modify the icon of popup Close button",filename:"popups",url:"popups.html#modify-the-icon-of-popup-close-button"},{title:"Modify overlay styles",filename:"popups",url:"popups.html#modify-overlay-styles"},{title:"rating",filename:"rating",url:"rating.html"},{title:"Ratings",filename:"rating",url:"rating.html#ratings"},{title:"Global rating variables",filename:"rating",url:"rating.html#global-rating-variables"},{title:"Rating with vote",filename:"rating",url:"rating.html#rating-with-vote"},{title:"Rating with vote icons number customization",filename:"rating",url:"rating.html#rating-with-vote-icons-number-customization"},{title:"Rating with vote icons colors customization",filename:"rating",url:"rating.html#rating-with-vote-icons-colors-customization"},{title:"Rating with vote icons symbol customization",filename:"rating",url:"rating.html#rating-with-vote-icons-symbol-customization"},{title:"Accessible rating with vote",filename:"rating",url:"rating.html#accessible-rating-with-vote"},{title:"Rating summary",filename:"rating",url:"rating.html#rating-summary"},{title:"Rating summary icons number customization",filename:"rating",url:"rating.html#rating-summary-icons-number-customization"},{title:"Rating summary icons color customization",filename:"rating",url:"rating.html#rating-summary-icons-color-customization"},{title:"Rating summary icons symbol customization",filename:"rating",url:"rating.html#rating-summary-icons-symbol-customization"},{title:"Rating summary hide label",filename:"rating",url:"rating.html#rating-summary-hide-label"},{title:"Rating summary multiple ratings",filename:"rating",url:"rating.html#rating-summary-multiple-ratings"},{title:"Rating hide label mixin",filename:"rating",url:"rating.html#rating-hide-label-mixin"},{title:"resets",filename:"resets",url:"resets.html"},{title:"Resets",filename:"resets",url:"resets.html#resets"},{title:"responsive",filename:"responsive",url:"responsive.html"},{title:"Responsive",filename:"responsive",url:"responsive.html#responsive"},{title:"Responsive mixins usage",filename:"responsive",url:"responsive.html#responsive-mixins-usage"},{title:"Media query style groups separation variables",filename:"responsive",url:"responsive.html#media-query-style-groups-separation-variables"},{title:"Responsive breakpoints",filename:"responsive",url:"responsive.html#responsive-breakpoints"},{title:"sections",filename:"sections",url:"sections.html"},{title:"Tabs and accordions",filename:"sections",url:"sections.html#tabs-and-accordions"},{title:"Tabs",filename:"sections",url:"sections.html#tabs"},{title:"Tabs mixin variables",filename:"sections",url:"sections.html#tabs-mixin-variables"},{title:"Tabs with content top border",filename:"sections",url:"sections.html#tabs-with-content-top-border"},{title:"Accordion",filename:"sections",url:"sections.html#accordion"},{title:"Accordion mixin variables",filename:"sections",url:"sections.html#accordion-mixin-variables"},{title:"Responsive tabs",filename:"sections",url:"sections.html#responsive-tabs"},{title:"Tabs Base",filename:"sections",url:"sections.html#tabs-base"},{title:"Accordion Base",filename:"sections",url:"sections.html#accordion-base"},{title:"tables",filename:"tables",url:"tables.html"},{title:"Tables",filename:"tables",url:"tables.html#tables"},{title:"Table mixin variables",filename:"tables",url:"tables.html#table-mixin-variables"},{title:"Table typography",filename:"tables",url:"tables.html#table-typography"},{title:"Table typography mixin variables",filename:"tables",url:"tables.html#table-typography-mixin-variables"},{title:"Table caption",filename:"tables",url:"tables.html#table-caption"},{title:"Table caption mixin variables",filename:"tables",url:"tables.html#table-caption-mixin-variables"},{title:"Table cells resize",filename:"tables",url:"tables.html#table-cells-resize"},{title:"Table cells resize variables",filename:"tables",url:"tables.html#table-cells-resize-variables"},{title:"Table background customization",filename:"tables",url:"tables.html#table-background-customization"},{title:"Table background mixin variables",filename:"tables",url:"tables.html#table-background-mixin-variables"},{title:"Table borders customization",filename:"tables",url:"tables.html#table-borders-customization"},{title:"Table borders mixin variables",filename:"tables",url:"tables.html#table-borders-mixin-variables"},{title:"Table with horizontal borders",filename:"tables",url:"tables.html#table-with-horizontal-borders"},{title:"Table with vertical borders",filename:"tables",url:"tables.html#table-with-vertical-borders"},{title:"Table with light borders",filename:"tables",url:"tables.html#table-with-light-borders"},{title:"Table without borders",filename:"tables",url:"tables.html#table-without-borders"},{title:"Striped table",filename:"tables",url:"tables.html#striped-table"},{title:"Striped table mixin variables",filename:"tables",url:"tables.html#striped-table-mixin-variables"},{title:"Table with rows hover",filename:"tables",url:"tables.html#table-with-rows-hover"},{title:"Table with rows hover mixin variables",filename:"tables",url:"tables.html#table-with-rows-hover-mixin-variables"},{title:"Responsive table technics #1",filename:"tables",url:"tables.html#responsive-table-technics-1"},{title:"Responsive table technics #2",filename:"tables",url:"tables.html#responsive-table-technics-2"},{title:"Responsive table technics #2 mixin variables",filename:"tables",url:"tables.html#responsive-table-technics-2-mixin-variables"},{title:"tooltips",filename:"tooltips",url:"tooltips.html"},{title:"Tooltips",filename:"tooltips",url:"tooltips.html#tooltips"},{title:"Tooltips variables",filename:"tooltips",url:"tooltips.html#tooltips-variables"},{title:"typography",filename:"typography",url:"typography.html"},{title:"Typogrphy",filename:"typography",url:"typography.html#typogrphy"},{title:"Typography variables",filename:"typography",url:"typography.html#typography-variables"},{title:"Font-size mixin",filename:"typography",url:"typography.html#fontsize-mixin"},{title:"Line-height mixin",filename:"typography",url:"typography.html#lineheight-mixin"},{title:"Word breaking mixin",filename:"typography",url:"typography.html#word-breaking-mixin"},{title:"Font face mixin",filename:"typography",url:"typography.html#font-face-mixin"},{title:"Text overflow mixin",filename:"typography",url:"typography.html#text-overflow-mixin"},{title:"Text hide",filename:"typography",url:"typography.html#text-hide"},{title:"Hyphens",filename:"typography",url:"typography.html#hyphens"},{title:"Font style and color",filename:"typography",url:"typography.html#font-style-and-color"},{title:"Font style mixin variables",filename:"typography",url:"typography.html#font-style-mixin-variables"},{title:"Reset list styles",filename:"typography",url:"typography.html#reset-list-styles"},{title:"Reset list styles variables",filename:"typography",url:"typography.html#reset-list-styles-variables"},{title:"Inline-block list item styling",filename:"typography",url:"typography.html#inlineblock-list-item-styling"},{title:"Link styling mixin",filename:"typography",url:"typography.html#link-styling-mixin"},{title:"Link styling mixin variables",filename:"typography",url:"typography.html#link-styling-mixin-variables"},{title:"Heading styling mixin",filename:"typography",url:"typography.html#heading-styling-mixin"},{title:"Base typography mixins",filename:"typography",url:"typography.html#base-typography-mixins"},{title:"Base typography mixin variables",filename:"typography",url:"typography.html#base-typography-mixin-variables"},{title:"Headings typography mixin",filename:"typography",url:"typography.html#headings-typography-mixin"},{title:"Headings typography mixin variables",filename:"typography",url:"typography.html#headings-typography-mixin-variables"},{title:"Typography links mixin",filename:"typography",url:"typography.html#typography-links-mixin"},{title:"Typography lists mixin",filename:"typography",url:"typography.html#typography-lists-mixin"},{title:"Typography lists mixin variables",filename:"typography",url:"typography.html#typography-lists-mixin-variables"},{title:"Typography code elements mixin",filename:"typography",url:"typography.html#typography-code-elements-mixin"},{title:"Typography code mixin variables",filename:"typography",url:"typography.html#typography-code-mixin-variables"},{title:"Typography blockquote",filename:"typography",url:"typography.html#typography-blockquote"},{title:"Typography blockquote mixin variables",filename:"typography",url:"typography.html#typography-blockquote-mixin-variables"},{title:"utilities",filename:"utilities",url:"utilities.html"},{title:"Utilities",filename:"utilities",url:"utilities.html#utilities"},{title:".lib-clearfix()",filename:"utilities",url:"utilities.html#libclearfix"},{title:".lib-visibility-hidden()",filename:"utilities",url:"utilities.html#libvisibilityhidden"},{title:".lib-visually-hidden()",filename:"utilities",url:"utilities.html#libvisuallyhidden"},{title:".lib-visually-hidden-reset()",filename:"utilities",url:"utilities.html#libvisuallyhiddenreset"},{title:".lib-css()",filename:"utilities",url:"utilities.html#libcss"},{title:".lib-css() variables",filename:"utilities",url:"utilities.html#libcss-variables"},{title:".lib-rotate()",filename:"utilities",url:"utilities.html#librotate"},{title:".lib-rotate() variables",filename:"utilities",url:"utilities.html#librotate-variables"},{title:".lib-input-placeholder()",filename:"utilities",url:"utilities.html#libinputplaceholder"},{title:".lib-input-placeholder() variables",filename:"utilities",url:"utilities.html#libinputplaceholder-variables"},{title:".lib-background-gradient()",filename:"utilities",url:"utilities.html#libbackgroundgradient"},{title:".lib-background-gradient() variables",filename:"utilities",url:"utilities.html#libbackgroundgradient-variables"},{title:".lib-url-check()",filename:"utilities",url:"utilities.html#liburlcheck"},{title:".lib-url-check() variables",filename:"utilities",url:"utilities.html#liburlcheck-variables"},{title:"variables",filename:"variables",url:"variables.html"},{title:"List of Global Variables",filename:"variables",url:"variables.html#list-of-global-variables"},{title:"Table with rows hover mixin variables",filename:"variables",url:"variables.html#table-with-rows-hover-mixin-variables"},{title:"docs",filename:"docs",url:"docs.html"},{title:"Documentation",filename:"docs",url:"docs.html#documentation"}];(function(){"use strict";var b=function(a,b){return Array.prototype.indexOf.call(a,b)!==-1},c=function(a,b){return Array.prototype.filter.call(a,b)},d=function(a,b){return Array.prototype.forEach.call(a,b)},e=document.getElementsByTagName("body")[0];e.addEventListener("click",function(a){var b=a.target;b.tagName.toLowerCase()==="svg"&&(b=b.parentNode);var c=!1;b.dataset.toggle!=null&&(a.preventDefault(),b.classList.contains("is-active")||(c=!0)),d(e.querySelectorAll("[data-toggle]"),function(a){a.classList.remove("is-active"),document.getElementById(a.dataset.toggle).hidden=!0}),c&&(b.classList.add("is-active"),document.getElementById(b.dataset.toggle).hidden=!1)}),function(){var f=e.getElementsByClassName("nav")[0];if(!f)return;var g=document.createElement("ul");g.className="nav-results",g.id="nav-search",g.hidden=!0,d(a,function(a){var b,c,d;b=document.createElement("li"),b._title=a.title.toLowerCase(),b.hidden=!0,b.appendChild(c=document.createElement("a")),c.href=a.url,c.innerHTML=a.title,c.appendChild(d=document.createElement("span")),d.innerHTML=a.filename,d.className="nav-results-filename",g.appendChild(b)}),f.appendChild(g);var h=g.children,i=function(a){d(h,function(a){a.hidden=!0});var b=this.value.toLowerCase(),e=[];b!==""&&(e=c(h,function(a){return a._title.indexOf(b)!==-1})),e.length>0?(d(e,function(a){a.hidden=!1}),g.hidden=!1):g.hidden=!0},j=f.querySelector('input[type="search"]');j.addEventListener("keyup",i),j.addEventListener("focus",i),e.addEventListener("click",function(a){if(a.target.classList&&a.target.classList.contains("search"))return;g.hidden=!0}),g.addEventListener("click",function(a){j.value=""});var k=document.createElement("ul");k.id="nav-toc",k.hidden=!0,k.className="nav-results toc-list",c(e.getElementsByTagName("*"),function(a){return b(["h1","h2","h3"],a.tagName.toLowerCase())}).map(function(a){var b=document.createElement("li"),c=document.createElement("a"),d=a.tagName.toLowerCase()[1];c.classList.add("level-"+d),b.appendChild(c),c.href="#"+a.id,c.innerHTML=a.innerHTML,k.appendChild(b)}),f.appendChild(k)}()})(),function(){"use strict";if(location.hash==="#__preview__"||location.protocol==="data:")return;var a=function(a,b){return Array.prototype.forEach.call(a,b)},b=function(a,b){var e=Array.prototype.slice.call(arguments,2);return d(a,function(a){return(c(b)?b||a:a[b]).apply(a,e)})},c=function(a){return Object.prototype.toString.call(a)==="[object Function]"},d=function(a,b){return Array.prototype.map.call(a,b)},e=function(a,b){return d(a,function(a){return a[b]})},f=function(a){var b={},c=a.split(";");for(var d=0;c.length>d;d++){var e=c[d].trim().split("=");b[e[0]]=e[1]}return b},g=function(a,c){return b(e(a,"classList"),"remove",c)},h=function(a,b){a.contentDocument.defaultView.postMessage(b,"*")},i=document.getElementsByTagName("head")[0],j=document.getElementsByTagName("body")[0],k=e(i.querySelectorAll('style[type="text/preview"]'),"innerHTML").join(""),l=e(i.querySelectorAll('script[type="text/preview"]'),"innerHTML").join(""),m=location.href.split("#")[0]+"#__preview__",n=document.createElement("iframe");n.src="data:text/html,",j.appendChild(n),n.addEventListener("load",function(){var b={sameOriginDataUri:!0};try{this.contentDocument,this.contentDocument||(b.sameOriginDataUri=!1)}catch(c){b.sameOriginDataUri=!1}this.parentNode.removeChild(this),a(j.getElementsByTagName("textarea"),function(a,c){o(a,b,c),q(),p(a)})});var o=function(a,b,c){var d,e,f;d=document.createElement("div"),d.appendChild(e=document.createElement("div")),d.className="preview",e.appendChild(f=document.createElement("iframe")),e.className="resizeable",f.setAttribute("scrolling","no"),f.name="iframe"+c++,f.addEventListener("load",function(){var c,d,e,f,g,i,j;j=this.contentDocument;if(!b.sameOriginDataUri&&this.src!==m)return;this.src===m&&(c=j.createElement("html"),c.appendChild(j.createElement("head")),c.appendChild(d=j.createElement("body")),d.innerHTML=a.textContent,j.replaceChild(c,j.documentElement)),g=j.createElement("head"),g.appendChild(f=j.createElement("style")),g.appendChild(e=j.createElement("script")),e.textContent=l,f.textContent=k,i=j.getElementsByTagName("head")[0],i.parentNode.replaceChild(g,i),h(this,"getHeight")});var g;b.sameOriginDataUri?g="data:text/html;charset=utf-8,"+encodeURIComponent("<!doctype html><html><head></head></body>"+a.textContent):g=m,f.setAttribute("src",g);var i=function(){f.contentDocument.body.innerHTML=this.value,h(f,"getHeight")};a.addEventListener("keypress",i),a.addEventListener("keyup",i),a.parentNode.insertBefore(d,a)},p=function(a){var b=document.createElement("div");b.className="preview-code",b.style.position="absolute",b.style.left="-9999px",j.appendChild(b);var c=parseInt(window.getComputedStyle(a).getPropertyValue("max-height"),10),d=function(a){b.textContent=this.value+"\n";var d=b.offsetHeight+2;d>=c?this.style.overflow="auto":this.style.overflow="hidden",this.style.height=b.offsetHeight+2+"px"};a.addEventListener("keypress",d),a.addEventListener("keyup",d),d.call(a)},q=function(){var b=j.getElementsByClassName("settings")[0],c=j.getElementsByClassName("resizeable"),d=30,e=function(b){document.cookie="preview-width="+b,a(c,function(a){b==="auto"&&(b=a.parentNode.offsetWidth),a.style.width=b+"px",h(a.getElementsByTagName("iframe")[0],"getHeight")})},i=f(document.cookie)["preview-width"];if(i){e(i),g(b.getElementsByClassName("is-active"),"is-active");var k=b.querySelector('button[data-width="'+i+'"]');k&&k.classList.add("is-active")}window.addEventListener("message",function(a){if(a.data==null||!a.source)return;var b=a.data,c=document.getElementsByName(a.source.name)[0];b.height!=null&&c&&(c.parentNode.style.height=b.height+d+"px")},!1),b&&c.length>0&&(b.hidden=!1,b.addEventListener("click",function(a){var c=a.target.tagName.toLowerCase(),d;if(c==="button")d=a.target;else{if(c!=="svg")return;d=a.target.parentNode}a.preventDefault(),g(b.getElementsByClassName("is-active"),"is-active"),d.classList.add("is-active");var f=d.dataset.width;e(f)}))}}()})()</script></body></html><!-- Generated with StyleDocco (http://jacobrask.github.com/styledocco). --> +}</code></pre></div></article></section><div class="bar bottom"><div hidden class="settings container"><!-- Icons from http://iconmonstr.com--><button title="Desktop (1280)" data-width='1280'><svg viewBox="0 0 412 386" height="24" width="26" class="icon"><path d="m147.6,343.9c-4.5,15.9-26.2,37.6-42.1,42.1h201c-15.3,-4-38.1,-26.8-42.1,-42.1H147.6zM387,0.5H25c-13.8,0-25,11.2-25,25V294c0,13.8 11.2,25 25,25h362c13.8,0 25,-11.2 25,-25V25.5C412,11.7 400.8,0.5 387,0.5zM369.9,238.2H42.1L42.1,42.6 369.9,42.6V238.2z"></path></svg></button><button title="Laptop (1024)" data-width='1024'><svg viewBox="0 0 384 312" height="23" width="28" class="icon"><path d="m349.2,20.5c0,-11-9,-20-20,-20H53.6c-11,0-20,9-20,20v194H349.2v-194zm-27,167H60.6V27.5H322.2v160zm28,42H32.6L2.6,282.1c-3.5,6.2-3.5,13.8 0.1,19.9 3.6,6.2 10.2,9.9 17.3,9.9H363.1c7.1,0 13.7,-3.8 17.3,-10 3.6,-6.2 3.6,-13.8 0,-20l-30.2,-52.5zm-196.9,54 8,-23.5h60.5l8,23.5h-76.5z"></path></svg></button><button title="Tablet (768)" data-width='768'><svg viewBox="0 0 317 412" height="24" width="18" class="icon"><path d="M 316.5,380 V 32 c 0,-17.7 -14.3,-32 -32,-32 H 32 C 14.3,0 0,14.3 0,32 v 348 c 0,17.7 14.3,32 32,32 h 252.5 c 17.7,0 32,-14.3 32,-32 z M 40,367 V 45 H 276.5 V 367 H 40 z m 109.8,22.7 c 0,-4.7 3.8,-8.5 8.5,-8.5 4.7,0 8.5,3.8 8.5,8.5 0,4.7 -3.8,8.5 -8.5,8.5 -4.7,0 -8.5,-3.8 -8.5,-8.5 z"></path></svg></button><button title="Smart phone (320)" data-width='320'><svg viewBox="0 0 224 412" height="24" width="13" class="icon"><path d="M 190.7,0 H 33 C 14.8,0 0,14.8 0,33 v 346 c 0,18.2 14.8,33 33,33 h 157.7 c 18.2,0 33,-14.8 33,-33 V 33 c 0,-18.2 -14.8,-33 -33,-33 z M 94.3,30.2 h 37 c 2.2,0 4,1.8 4,4 0,2.2 -1.8,4 -4,4 h -37 c -2.2,0 -4,-1.8 -4,-4 0,-2.2 1.8,-4 4,-4 z m 18.5,362.8 c -8.8,0 -16,-7.2 -16,-16 0,-8.8 7.2,-16 16,-16 8.8,0 16,7.2 16,16 0,8.8 -7.2,16 -16,16 z M 198.6,343.8 H 25.1 V 68.2 h 173.5 v 275.5 z"></path></svg></button><button title="Feature phone (240)" data-width='240'><svg viewBox="0 0 201 412" height="24" width="12" class="icon"><path d="M 165.5,0.2 V 45 H 25 c -13.8,0 -25,11.2 -25,25 V 387 c 0,13.8 11.2,25 25,25 h 150.5 c 13.8,0 25,-11.2 25,-25 V 0.2 h -35 z M 65.2,366.5 H 34.2 v -24.5 h 31 v 24.5 z m 0,-44.3 H 34.2 v -24.5 h 31 v 24.5 z m 50.5,44.3 H 84.7 v -24.5 h 31 v 24.5 z m 0,-44.3 H 84.7 v -24.5 h 31 v 24.5 z m 50.5,44.3 h -31 v -24.5 h 31 v 24.5 z m 0,-44.3 h -31 v -24.5 h 31 v 24.5 z m 0,-59.3 h -132 V 95.4 h 132 V 262.9 z"></path></svg></button><button title="Auto (100%)" data-width="auto" class="auto is-active">Auto</button></div></div><script>(function(){var a=[{title:"actions-toolbar",filename:"actions-toolbar",url:"actions-toolbar.html"},{title:"Actions toolbar",filename:"actions-toolbar",url:"actions-toolbar.html#actions-toolbar"},{title:"Actions toolbar mixin variables",filename:"actions-toolbar",url:"actions-toolbar.html#actions-toolbar-mixin-variables"},{title:"Actions toolbar alignment",filename:"actions-toolbar",url:"actions-toolbar.html#actions-toolbar-alignment"},{title:"Reverse primary and secondary blocks",filename:"actions-toolbar",url:"actions-toolbar.html#reverse-primary-and-secondary-blocks"},{title:"Actions toolbar indents customizations",filename:"actions-toolbar",url:"actions-toolbar.html#actions-toolbar-indents-customizations"},{title:"Responsive actions toolbar",filename:"actions-toolbar",url:"actions-toolbar.html#responsive-actions-toolbar"},{title:"breadcrumbs",filename:"breadcrumbs",url:"breadcrumbs.html"},{title:"Breadcrumbs",filename:"breadcrumbs",url:"breadcrumbs.html#breadcrumbs"},{title:"Breadcrumbs variables",filename:"breadcrumbs",url:"breadcrumbs.html#breadcrumbs-variables"},{title:"Button-styled breadcrumbs with gradient background, border, and no separating symbol",filename:"breadcrumbs",url:"breadcrumbs.html#buttonstyled-breadcrumbs-with-gradient-background-border-and-no-separating-symbol"},{title:"Breadcrumbs with solid background",filename:"breadcrumbs",url:"breadcrumbs.html#breadcrumbs-with-solid-background"},{title:"buttons",filename:"buttons",url:"buttons.html"},{title:"Default button",filename:"buttons",url:"buttons.html#default-button"},{title:"Button variables",filename:"buttons",url:"buttons.html#button-variables"},{title:"Button as an icon",filename:"buttons",url:"buttons.html#button-as-an-icon"},{title:"Button with an icon on the left or right side of the text",filename:"buttons",url:"buttons.html#button-with-an-icon-on-the-left-or-right-side-of-the-text"},{title:"Button with fixed width",filename:"buttons",url:"buttons.html#button-with-fixed-width"},{title:"Primary button",filename:"buttons",url:"buttons.html#primary-button"},{title:"Primary button variables",filename:"buttons",url:"buttons.html#primary-button-variables"},{title:"Button with gradient background",filename:"buttons",url:"buttons.html#button-with-gradient-background"},{title:"Button as a link",filename:"buttons",url:"buttons.html#button-as-a-link"},{title:"Button as a link variables",filename:"buttons",url:"buttons.html#button-as-a-link-variables"},{title:"Link as a button",filename:"buttons",url:"buttons.html#link-as-a-button"},{title:"Button reset",filename:"buttons",url:"buttons.html#button-reset"},{title:"Button revert secondary color",filename:"buttons",url:"buttons.html#button-revert-secondary-color"},{title:"Button revert secondary color variables",filename:"buttons",url:"buttons.html#button-revert-secondary-color-variables"},{title:"Button revert secondary size",filename:"buttons",url:"buttons.html#button-revert-secondary-size"},{title:"Button revert secondary size variables",filename:"buttons",url:"buttons.html#button-revert-secondary-size-variables"},{title:"components",filename:"components",url:"components.html"},{title:"Components",filename:"components",url:"components.html#components"},{title:"Components Variables",filename:"components",url:"components.html#components-variables"},{title:"dropdowns",filename:"dropdowns",url:"dropdowns.html"},{title:"Drop-down and split buttons mixins",filename:"dropdowns",url:"dropdowns.html#dropdown-and-split-buttons-mixins"},{title:"Drop-down",filename:"dropdowns",url:"dropdowns.html#dropdown"},{title:"Drop-down variables",filename:"dropdowns",url:"dropdowns.html#dropdown-variables"},{title:"Drop-down with icon customization",filename:"dropdowns",url:"dropdowns.html#dropdown-with-icon-customization"},{title:"Modify dropdown list styles",filename:"dropdowns",url:"dropdowns.html#modify-dropdown-list-styles"},{title:"Split button",filename:"dropdowns",url:"dropdowns.html#split-button"},{title:"Split button variables",filename:"dropdowns",url:"dropdowns.html#split-button-variables"},{title:"Split button - button styling",filename:"dropdowns",url:"dropdowns.html#split-button-button-styling"},{title:"Split button icon customization",filename:"dropdowns",url:"dropdowns.html#split-button-icon-customization"},{title:"Split button drop-down list customization",filename:"dropdowns",url:"dropdowns.html#split-button-dropdown-list-customization"},{title:"forms",filename:"forms",url:"forms.html"},{title:"Forms mixins",filename:"forms",url:"forms.html#forms-mixins"},{title:"Global forms elements customization",filename:"forms",url:"forms.html#global-forms-elements-customization"},{title:"Fieldsets & fields customization",filename:"forms",url:"forms.html#fieldsets-fields-customization"},{title:"Fieldset and legend customization variables",filename:"forms",url:"forms.html#fieldset-and-legend-customization-variables"},{title:"Fields customization variables",filename:"forms",url:"forms.html#fields-customization-variables"},{title:"Required fields message customization variables",filename:"forms",url:"forms.html#required-fields-message-customization-variables"},{title:"Form element inputs customization",filename:"forms",url:"forms.html#form-element-inputs-customization"},{title:"Form element inputs customization variables",filename:"forms",url:"forms.html#form-element-inputs-customization-variables"},{title:"Form element choice",filename:"forms",url:"forms.html#form-element-choice"},{title:"Form element choice variables",filename:"forms",url:"forms.html#form-element-choice-variables"},{title:"Custom color",filename:"forms",url:"forms.html#custom-color"},{title:"Input number - input-text view",filename:"forms",url:"forms.html#input-number-inputtext-view"},{title:"Input search - input-text view",filename:"forms",url:"forms.html#input-search-inputtext-view"},{title:"Form validation",filename:"forms",url:"forms.html#form-validation"},{title:"Form validation variables",filename:"forms",url:"forms.html#form-validation-variables"},{title:"icons",filename:"icons",url:"icons.html"},{title:"Icons",filename:"icons",url:"icons.html#icons"},{title:"Icon with image or sprite",filename:"icons",url:"icons.html#icon-with-image-or-sprite"},{title:"Icon with image or sprite variables",filename:"icons",url:"icons.html#icon-with-image-or-sprite-variables"},{title:"Icon position for an icon with image or sprite",filename:"icons",url:"icons.html#icon-position-for-an-icon-with-image-or-sprite"},{title:"Position for icon with image or sprite mixin variables",filename:"icons",url:"icons.html#position-for-icon-with-image-or-sprite-mixin-variables"},{title:"Icon sprite position (with grid)",filename:"icons",url:"icons.html#icon-sprite-position-with-grid"},{title:"Icon sprite position variables",filename:"icons",url:"icons.html#icon-sprite-position-variables"},{title:"Image/sprite icon size",filename:"icons",url:"icons.html#imagesprite-icon-size"},{title:"Image/sprite icon size variables",filename:"icons",url:"icons.html#imagesprite-icon-size-variables"},{title:"Font icon",filename:"icons",url:"icons.html#font-icon"},{title:"Font icon variables",filename:"icons",url:"icons.html#font-icon-variables"},{title:"Change the size of font icon",filename:"icons",url:"icons.html#change-the-size-of-font-icon"},{title:"Change the size of font icon variables",filename:"icons",url:"icons.html#change-the-size-of-font-icon-variables"},{title:"Hide icon text",filename:"icons",url:"icons.html#hide-icon-text"},{title:"Sprite and font icons for Blank theme",filename:"icons",url:"icons.html#sprite-and-font-icons-for-blank-theme"},{title:"layout",filename:"layout",url:"layout.html"},{title:"Layout",filename:"layout",url:"layout.html#layout"},{title:"Layout global variables",filename:"layout",url:"layout.html#layout-global-variables"},{title:"Page layouts",filename:"layout",url:"layout.html#page-layouts"},{title:"Layout column",filename:"layout",url:"layout.html#layout-column"},{title:"Layout column variables",filename:"layout",url:"layout.html#layout-column-variables"},{title:"Layout width",filename:"layout",url:"layout.html#layout-width"},{title:"Layout width variables",filename:"layout",url:"layout.html#layout-width-variables"},{title:"lib",filename:"lib",url:"lib.html"},{title:"Including Magento UI library to your theme",filename:"lib",url:"lib.html#including-magento-ui-library-to-your-theme"},{title:"loaders",filename:"loaders",url:"loaders.html"},{title:"Loaders",filename:"loaders",url:"loaders.html#loaders"},{title:"Default loader variables",filename:"loaders",url:"loaders.html#default-loader-variables"},{title:"Loading",filename:"loaders",url:"loaders.html#loading"},{title:"Loading default variables",filename:"loaders",url:"loaders.html#loading-default-variables"},{title:"messages",filename:"messages",url:"messages.html"},{title:"Messages",filename:"messages",url:"messages.html#messages"},{title:"Information message",filename:"messages",url:"messages.html#information-message"},{title:"Warning message",filename:"messages",url:"messages.html#warning-message"},{title:"Error message",filename:"messages",url:"messages.html#error-message"},{title:"Success message",filename:"messages",url:"messages.html#success-message"},{title:"Notice message",filename:"messages",url:"messages.html#notice-message"},{title:"Message with inner icon",filename:"messages",url:"messages.html#message-with-inner-icon"},{title:"Message with lateral icon",filename:"messages",url:"messages.html#message-with-lateral-icon"},{title:"Custom message style",filename:"messages",url:"messages.html#custom-message-style"},{title:"Messages global variables",filename:"messages",url:"messages.html#messages-global-variables"},{title:"pages",filename:"pages",url:"pages.html"},{title:"Pagination HTML markup",filename:"pages",url:"pages.html#pagination-html-markup"},{title:"Pagination variables",filename:"pages",url:"pages.html#pagination-variables"},{title:"Pagination with label and gradient background on links",filename:"pages",url:"pages.html#pagination-with-label-and-gradient-background-on-links"},{title:'Pagination with "previous"..."next" text links and label',filename:"pages",url:"pages.html#pagination-with-previousnext-text-links-and-label"},{title:"Pagination without label, with solid background",filename:"pages",url:"pages.html#pagination-without-label-with-solid-background"},{title:"popups",filename:"popups",url:"popups.html"},{title:"Popups",filename:"popups",url:"popups.html#popups"},{title:"Popup variables",filename:"popups",url:"popups.html#popup-variables"},{title:"Window overlay mixin variables",filename:"popups",url:"popups.html#window-overlay-mixin-variables"},{title:"Fixed height popup",filename:"popups",url:"popups.html#fixed-height-popup"},{title:"Fixed content height popup",filename:"popups",url:"popups.html#fixed-content-height-popup"},{title:"Margins for header, content and footer block in popup",filename:"popups",url:"popups.html#margins-for-header-content-and-footer-block-in-popup"},{title:"Popup titles styled as theme headings",filename:"popups",url:"popups.html#popup-titles-styled-as-theme-headings"},{title:"Popup action toolbar",filename:"popups",url:"popups.html#popup-action-toolbar"},{title:"Popup Close button without an icon",filename:"popups",url:"popups.html#popup-close-button-without-an-icon"},{title:"Modify the icon of popup Close button",filename:"popups",url:"popups.html#modify-the-icon-of-popup-close-button"},{title:"Modify overlay styles",filename:"popups",url:"popups.html#modify-overlay-styles"},{title:"rating",filename:"rating",url:"rating.html"},{title:"Ratings",filename:"rating",url:"rating.html#ratings"},{title:"Global rating variables",filename:"rating",url:"rating.html#global-rating-variables"},{title:"Rating with vote",filename:"rating",url:"rating.html#rating-with-vote"},{title:"Rating with vote icons number customization",filename:"rating",url:"rating.html#rating-with-vote-icons-number-customization"},{title:"Rating with vote icons colors customization",filename:"rating",url:"rating.html#rating-with-vote-icons-colors-customization"},{title:"Rating with vote icons symbol customization",filename:"rating",url:"rating.html#rating-with-vote-icons-symbol-customization"},{title:"Accessible rating with vote",filename:"rating",url:"rating.html#accessible-rating-with-vote"},{title:"Rating summary",filename:"rating",url:"rating.html#rating-summary"},{title:"Rating summary icons number customization",filename:"rating",url:"rating.html#rating-summary-icons-number-customization"},{title:"Rating summary icons color customization",filename:"rating",url:"rating.html#rating-summary-icons-color-customization"},{title:"Rating summary icons symbol customization",filename:"rating",url:"rating.html#rating-summary-icons-symbol-customization"},{title:"Rating summary hide label",filename:"rating",url:"rating.html#rating-summary-hide-label"},{title:"Rating summary multiple ratings",filename:"rating",url:"rating.html#rating-summary-multiple-ratings"},{title:"Rating hide label mixin",filename:"rating",url:"rating.html#rating-hide-label-mixin"},{title:"resets",filename:"resets",url:"resets.html"},{title:"Resets",filename:"resets",url:"resets.html#resets"},{title:"responsive",filename:"responsive",url:"responsive.html"},{title:"Responsive",filename:"responsive",url:"responsive.html#responsive"},{title:"Responsive mixins usage",filename:"responsive",url:"responsive.html#responsive-mixins-usage"},{title:"Media query style groups separation variables",filename:"responsive",url:"responsive.html#media-query-style-groups-separation-variables"},{title:"Responsive breakpoints",filename:"responsive",url:"responsive.html#responsive-breakpoints"},{title:"sections",filename:"sections",url:"sections.html"},{title:"Tabs and accordions",filename:"sections",url:"sections.html#tabs-and-accordions"},{title:"Tabs",filename:"sections",url:"sections.html#tabs"},{title:"Tabs mixin variables",filename:"sections",url:"sections.html#tabs-mixin-variables"},{title:"Tabs with content top border",filename:"sections",url:"sections.html#tabs-with-content-top-border"},{title:"Accordion",filename:"sections",url:"sections.html#accordion"},{title:"Accordion mixin variables",filename:"sections",url:"sections.html#accordion-mixin-variables"},{title:"Responsive tabs",filename:"sections",url:"sections.html#responsive-tabs"},{title:"Tabs Base",filename:"sections",url:"sections.html#tabs-base"},{title:"Accordion Base",filename:"sections",url:"sections.html#accordion-base"},{title:"tables",filename:"tables",url:"tables.html"},{title:"Tables",filename:"tables",url:"tables.html#tables"},{title:"Table mixin variables",filename:"tables",url:"tables.html#table-mixin-variables"},{title:"Table typography",filename:"tables",url:"tables.html#table-typography"},{title:"Table typography mixin variables",filename:"tables",url:"tables.html#table-typography-mixin-variables"},{title:"Table caption",filename:"tables",url:"tables.html#table-caption"},{title:"Table caption mixin variables",filename:"tables",url:"tables.html#table-caption-mixin-variables"},{title:"Table cells resize",filename:"tables",url:"tables.html#table-cells-resize"},{title:"Table cells resize variables",filename:"tables",url:"tables.html#table-cells-resize-variables"},{title:"Table background customization",filename:"tables",url:"tables.html#table-background-customization"},{title:"Table background mixin variables",filename:"tables",url:"tables.html#table-background-mixin-variables"},{title:"Table borders customization",filename:"tables",url:"tables.html#table-borders-customization"},{title:"Table borders mixin variables",filename:"tables",url:"tables.html#table-borders-mixin-variables"},{title:"Table with horizontal borders",filename:"tables",url:"tables.html#table-with-horizontal-borders"},{title:"Table with vertical borders",filename:"tables",url:"tables.html#table-with-vertical-borders"},{title:"Table with light borders",filename:"tables",url:"tables.html#table-with-light-borders"},{title:"Table without borders",filename:"tables",url:"tables.html#table-without-borders"},{title:"Striped table",filename:"tables",url:"tables.html#striped-table"},{title:"Striped table mixin variables",filename:"tables",url:"tables.html#striped-table-mixin-variables"},{title:"Table with rows hover",filename:"tables",url:"tables.html#table-with-rows-hover"},{title:"Table with rows hover mixin variables",filename:"tables",url:"tables.html#table-with-rows-hover-mixin-variables"},{title:"Responsive table technics #1",filename:"tables",url:"tables.html#responsive-table-technics-1"},{title:"Responsive table technics #2",filename:"tables",url:"tables.html#responsive-table-technics-2"},{title:"Responsive table technics #2 mixin variables",filename:"tables",url:"tables.html#responsive-table-technics-2-mixin-variables"},{title:"tooltips",filename:"tooltips",url:"tooltips.html"},{title:"Tooltips",filename:"tooltips",url:"tooltips.html#tooltips"},{title:"Tooltips variables",filename:"tooltips",url:"tooltips.html#tooltips-variables"},{title:"typography",filename:"typography",url:"typography.html"},{title:"Typogrphy",filename:"typography",url:"typography.html#typogrphy"},{title:"Typography variables",filename:"typography",url:"typography.html#typography-variables"},{title:"Font-size mixin",filename:"typography",url:"typography.html#fontsize-mixin"},{title:"Line-height mixin",filename:"typography",url:"typography.html#lineheight-mixin"},{title:"Word breaking mixin",filename:"typography",url:"typography.html#word-breaking-mixin"},{title:"Font face mixin",filename:"typography",url:"typography.html#font-face-mixin"},{title:"Text overflow mixin",filename:"typography",url:"typography.html#text-overflow-mixin"},{title:"Text hide",filename:"typography",url:"typography.html#text-hide"},{title:"Hyphens",filename:"typography",url:"typography.html#hyphens"},{title:"Font style and color",filename:"typography",url:"typography.html#font-style-and-color"},{title:"Font style mixin variables",filename:"typography",url:"typography.html#font-style-mixin-variables"},{title:"Reset list styles",filename:"typography",url:"typography.html#reset-list-styles"},{title:"Reset list styles variables",filename:"typography",url:"typography.html#reset-list-styles-variables"},{title:"Inline-block list item styling",filename:"typography",url:"typography.html#inlineblock-list-item-styling"},{title:"Link styling mixin",filename:"typography",url:"typography.html#link-styling-mixin"},{title:"Link styling mixin variables",filename:"typography",url:"typography.html#link-styling-mixin-variables"},{title:"Heading styling mixin",filename:"typography",url:"typography.html#heading-styling-mixin"},{title:"Base typography mixins",filename:"typography",url:"typography.html#base-typography-mixins"},{title:"Base typography mixin variables",filename:"typography",url:"typography.html#base-typography-mixin-variables"},{title:"Headings typography mixin",filename:"typography",url:"typography.html#headings-typography-mixin"},{title:"Headings typography mixin variables",filename:"typography",url:"typography.html#headings-typography-mixin-variables"},{title:"Typography links mixin",filename:"typography",url:"typography.html#typography-links-mixin"},{title:"Typography lists mixin",filename:"typography",url:"typography.html#typography-lists-mixin"},{title:"Typography lists mixin variables",filename:"typography",url:"typography.html#typography-lists-mixin-variables"},{title:"Typography code elements mixin",filename:"typography",url:"typography.html#typography-code-elements-mixin"},{title:"Typography code mixin variables",filename:"typography",url:"typography.html#typography-code-mixin-variables"},{title:"Typography blockquote",filename:"typography",url:"typography.html#typography-blockquote"},{title:"Typography blockquote mixin variables",filename:"typography",url:"typography.html#typography-blockquote-mixin-variables"},{title:"utilities",filename:"utilities",url:"utilities.html"},{title:"Utilities",filename:"utilities",url:"utilities.html#utilities"},{title:".lib-clearfix()",filename:"utilities",url:"utilities.html#libclearfix"},{title:".lib-visibility-hidden()",filename:"utilities",url:"utilities.html#libvisibilityhidden"},{title:".lib-visually-hidden()",filename:"utilities",url:"utilities.html#libvisuallyhidden"},{title:".lib-visually-hidden-reset()",filename:"utilities",url:"utilities.html#libvisuallyhiddenreset"},{title:".lib-css()",filename:"utilities",url:"utilities.html#libcss"},{title:".lib-css() variables",filename:"utilities",url:"utilities.html#libcss-variables"},{title:".lib-rotate()",filename:"utilities",url:"utilities.html#librotate"},{title:".lib-rotate() variables",filename:"utilities",url:"utilities.html#librotate-variables"},{title:".lib-input-placeholder()",filename:"utilities",url:"utilities.html#libinputplaceholder"},{title:".lib-input-placeholder() variables",filename:"utilities",url:"utilities.html#libinputplaceholder-variables"},{title:".lib-background-gradient()",filename:"utilities",url:"utilities.html#libbackgroundgradient"},{title:".lib-background-gradient() variables",filename:"utilities",url:"utilities.html#libbackgroundgradient-variables"},{title:"variables",filename:"variables",url:"variables.html"},{title:"List of Global Variables",filename:"variables",url:"variables.html#list-of-global-variables"},{title:"Table with rows hover mixin variables",filename:"variables",url:"variables.html#table-with-rows-hover-mixin-variables"},{title:"docs",filename:"docs",url:"docs.html"},{title:"Documentation",filename:"docs",url:"docs.html#documentation"}];(function(){"use strict";var b=function(a,b){return Array.prototype.indexOf.call(a,b)!==-1},c=function(a,b){return Array.prototype.filter.call(a,b)},d=function(a,b){return Array.prototype.forEach.call(a,b)},e=document.getElementsByTagName("body")[0];e.addEventListener("click",function(a){var b=a.target;b.tagName.toLowerCase()==="svg"&&(b=b.parentNode);var c=!1;b.dataset.toggle!=null&&(a.preventDefault(),b.classList.contains("is-active")||(c=!0)),d(e.querySelectorAll("[data-toggle]"),function(a){a.classList.remove("is-active"),document.getElementById(a.dataset.toggle).hidden=!0}),c&&(b.classList.add("is-active"),document.getElementById(b.dataset.toggle).hidden=!1)}),function(){var f=e.getElementsByClassName("nav")[0];if(!f)return;var g=document.createElement("ul");g.className="nav-results",g.id="nav-search",g.hidden=!0,d(a,function(a){var b,c,d;b=document.createElement("li"),b._title=a.title.toLowerCase(),b.hidden=!0,b.appendChild(c=document.createElement("a")),c.href=a.url,c.innerHTML=a.title,c.appendChild(d=document.createElement("span")),d.innerHTML=a.filename,d.className="nav-results-filename",g.appendChild(b)}),f.appendChild(g);var h=g.children,i=function(a){d(h,function(a){a.hidden=!0});var b=this.value.toLowerCase(),e=[];b!==""&&(e=c(h,function(a){return a._title.indexOf(b)!==-1})),e.length>0?(d(e,function(a){a.hidden=!1}),g.hidden=!1):g.hidden=!0},j=f.querySelector('input[type="search"]');j.addEventListener("keyup",i),j.addEventListener("focus",i),e.addEventListener("click",function(a){if(a.target.classList&&a.target.classList.contains("search"))return;g.hidden=!0}),g.addEventListener("click",function(a){j.value=""});var k=document.createElement("ul");k.id="nav-toc",k.hidden=!0,k.className="nav-results toc-list",c(e.getElementsByTagName("*"),function(a){return b(["h1","h2","h3"],a.tagName.toLowerCase())}).map(function(a){var b=document.createElement("li"),c=document.createElement("a"),d=a.tagName.toLowerCase()[1];c.classList.add("level-"+d),b.appendChild(c),c.href="#"+a.id,c.innerHTML=a.innerHTML,k.appendChild(b)}),f.appendChild(k)}()})(),function(){"use strict";if(location.hash==="#__preview__"||location.protocol==="data:")return;var a=function(a,b){return Array.prototype.forEach.call(a,b)},b=function(a,b){var e=Array.prototype.slice.call(arguments,2);return d(a,function(a){return(c(b)?b||a:a[b]).apply(a,e)})},c=function(a){return Object.prototype.toString.call(a)==="[object Function]"},d=function(a,b){return Array.prototype.map.call(a,b)},e=function(a,b){return d(a,function(a){return a[b]})},f=function(a){var b={},c=a.split(";");for(var d=0;c.length>d;d++){var e=c[d].trim().split("=");b[e[0]]=e[1]}return b},g=function(a,c){return b(e(a,"classList"),"remove",c)},h=function(a,b){a.contentDocument.defaultView.postMessage(b,"*")},i=document.getElementsByTagName("head")[0],j=document.getElementsByTagName("body")[0],k=e(i.querySelectorAll('style[type="text/preview"]'),"innerHTML").join(""),l=e(i.querySelectorAll('script[type="text/preview"]'),"innerHTML").join(""),m=location.href.split("#")[0]+"#__preview__",n=document.createElement("iframe");n.src="data:text/html,",j.appendChild(n),n.addEventListener("load",function(){var b={sameOriginDataUri:!0};try{this.contentDocument,this.contentDocument||(b.sameOriginDataUri=!1)}catch(c){b.sameOriginDataUri=!1}this.parentNode.removeChild(this),a(j.getElementsByTagName("textarea"),function(a,c){o(a,b,c),q(),p(a)})});var o=function(a,b,c){var d,e,f;d=document.createElement("div"),d.appendChild(e=document.createElement("div")),d.className="preview",e.appendChild(f=document.createElement("iframe")),e.className="resizeable",f.setAttribute("scrolling","no"),f.name="iframe"+c++,f.addEventListener("load",function(){var c,d,e,f,g,i,j;j=this.contentDocument;if(!b.sameOriginDataUri&&this.src!==m)return;this.src===m&&(c=j.createElement("html"),c.appendChild(j.createElement("head")),c.appendChild(d=j.createElement("body")),d.innerHTML=a.textContent,j.replaceChild(c,j.documentElement)),g=j.createElement("head"),g.appendChild(f=j.createElement("style")),g.appendChild(e=j.createElement("script")),e.textContent=l,f.textContent=k,i=j.getElementsByTagName("head")[0],i.parentNode.replaceChild(g,i),h(this,"getHeight")});var g;b.sameOriginDataUri?g="data:text/html;charset=utf-8,"+encodeURIComponent("<!doctype html><html><head></head></body>"+a.textContent):g=m,f.setAttribute("src",g);var i=function(){f.contentDocument.body.innerHTML=this.value,h(f,"getHeight")};a.addEventListener("keypress",i),a.addEventListener("keyup",i),a.parentNode.insertBefore(d,a)},p=function(a){var b=document.createElement("div");b.className="preview-code",b.style.position="absolute",b.style.left="-9999px",j.appendChild(b);var c=parseInt(window.getComputedStyle(a).getPropertyValue("max-height"),10),d=function(a){b.textContent=this.value+"\n";var d=b.offsetHeight+2;d>=c?this.style.overflow="auto":this.style.overflow="hidden",this.style.height=b.offsetHeight+2+"px"};a.addEventListener("keypress",d),a.addEventListener("keyup",d),d.call(a)},q=function(){var b=j.getElementsByClassName("settings")[0],c=j.getElementsByClassName("resizeable"),d=30,e=function(b){document.cookie="preview-width="+b,a(c,function(a){b==="auto"&&(b=a.parentNode.offsetWidth),a.style.width=b+"px",h(a.getElementsByTagName("iframe")[0],"getHeight")})},i=f(document.cookie)["preview-width"];if(i){e(i),g(b.getElementsByClassName("is-active"),"is-active");var k=b.querySelector('button[data-width="'+i+'"]');k&&k.classList.add("is-active")}window.addEventListener("message",function(a){if(a.data==null||!a.source)return;var b=a.data,c=document.getElementsByName(a.source.name)[0];b.height!=null&&c&&(c.parentNode.style.height=b.height+d+"px")},!1),b&&c.length>0&&(b.hidden=!1,b.addEventListener("click",function(a){var c=a.target.tagName.toLowerCase(),d;if(c==="button")d=a.target;else{if(c!=="svg")return;d=a.target.parentNode}a.preventDefault(),g(b.getElementsByClassName("is-active"),"is-active"),d.classList.add("is-active");var f=d.dataset.width;e(f)}))}}()})()</script></body></html><!-- Generated with StyleDocco (http://jacobrask.github.com/styledocco). --> diff --git a/lib/web/css/docs/rating.html b/lib/web/css/docs/rating.html index bf74c47c22f11..3cfe1a864dd98 100644 --- a/lib/web/css/docs/rating.html +++ b/lib/web/css/docs/rating.html @@ -343,4 +343,4 @@ </div><div class="code"><pre><code>.example-rating-summary-7 { .lib-rating-summary(); .lib-rating-summary-label-hide(); -}</code></pre></div></article></section><div class="bar bottom"><div hidden class="settings container"><!-- Icons from http://iconmonstr.com--><button title="Desktop (1280)" data-width='1280'><svg viewBox="0 0 412 386" height="24" width="26" class="icon"><path d="m147.6,343.9c-4.5,15.9-26.2,37.6-42.1,42.1h201c-15.3,-4-38.1,-26.8-42.1,-42.1H147.6zM387,0.5H25c-13.8,0-25,11.2-25,25V294c0,13.8 11.2,25 25,25h362c13.8,0 25,-11.2 25,-25V25.5C412,11.7 400.8,0.5 387,0.5zM369.9,238.2H42.1L42.1,42.6 369.9,42.6V238.2z"></path></svg></button><button title="Laptop (1024)" data-width='1024'><svg viewBox="0 0 384 312" height="23" width="28" class="icon"><path d="m349.2,20.5c0,-11-9,-20-20,-20H53.6c-11,0-20,9-20,20v194H349.2v-194zm-27,167H60.6V27.5H322.2v160zm28,42H32.6L2.6,282.1c-3.5,6.2-3.5,13.8 0.1,19.9 3.6,6.2 10.2,9.9 17.3,9.9H363.1c7.1,0 13.7,-3.8 17.3,-10 3.6,-6.2 3.6,-13.8 0,-20l-30.2,-52.5zm-196.9,54 8,-23.5h60.5l8,23.5h-76.5z"></path></svg></button><button title="Tablet (768)" data-width='768'><svg viewBox="0 0 317 412" height="24" width="18" class="icon"><path d="M 316.5,380 V 32 c 0,-17.7 -14.3,-32 -32,-32 H 32 C 14.3,0 0,14.3 0,32 v 348 c 0,17.7 14.3,32 32,32 h 252.5 c 17.7,0 32,-14.3 32,-32 z M 40,367 V 45 H 276.5 V 367 H 40 z m 109.8,22.7 c 0,-4.7 3.8,-8.5 8.5,-8.5 4.7,0 8.5,3.8 8.5,8.5 0,4.7 -3.8,8.5 -8.5,8.5 -4.7,0 -8.5,-3.8 -8.5,-8.5 z"></path></svg></button><button title="Smart phone (320)" data-width='320'><svg viewBox="0 0 224 412" height="24" width="13" class="icon"><path d="M 190.7,0 H 33 C 14.8,0 0,14.8 0,33 v 346 c 0,18.2 14.8,33 33,33 h 157.7 c 18.2,0 33,-14.8 33,-33 V 33 c 0,-18.2 -14.8,-33 -33,-33 z M 94.3,30.2 h 37 c 2.2,0 4,1.8 4,4 0,2.2 -1.8,4 -4,4 h -37 c -2.2,0 -4,-1.8 -4,-4 0,-2.2 1.8,-4 4,-4 z m 18.5,362.8 c -8.8,0 -16,-7.2 -16,-16 0,-8.8 7.2,-16 16,-16 8.8,0 16,7.2 16,16 0,8.8 -7.2,16 -16,16 z M 198.6,343.8 H 25.1 V 68.2 h 173.5 v 275.5 z"></path></svg></button><button title="Feature phone (240)" data-width='240'><svg viewBox="0 0 201 412" height="24" width="12" class="icon"><path d="M 165.5,0.2 V 45 H 25 c -13.8,0 -25,11.2 -25,25 V 387 c 0,13.8 11.2,25 25,25 h 150.5 c 13.8,0 25,-11.2 25,-25 V 0.2 h -35 z M 65.2,366.5 H 34.2 v -24.5 h 31 v 24.5 z m 0,-44.3 H 34.2 v -24.5 h 31 v 24.5 z m 50.5,44.3 H 84.7 v -24.5 h 31 v 24.5 z m 0,-44.3 H 84.7 v -24.5 h 31 v 24.5 z m 50.5,44.3 h -31 v -24.5 h 31 v 24.5 z m 0,-44.3 h -31 v -24.5 h 31 v 24.5 z m 0,-59.3 h -132 V 95.4 h 132 V 262.9 z"></path></svg></button><button title="Auto (100%)" data-width="auto" class="auto is-active">Auto</button></div></div><script>(function(){var a=[{title:"actions-toolbar",filename:"actions-toolbar",url:"actions-toolbar.html"},{title:"Actions toolbar",filename:"actions-toolbar",url:"actions-toolbar.html#actions-toolbar"},{title:"Actions toolbar mixin variables",filename:"actions-toolbar",url:"actions-toolbar.html#actions-toolbar-mixin-variables"},{title:"Actions toolbar alignment",filename:"actions-toolbar",url:"actions-toolbar.html#actions-toolbar-alignment"},{title:"Reverse primary and secondary blocks",filename:"actions-toolbar",url:"actions-toolbar.html#reverse-primary-and-secondary-blocks"},{title:"Actions toolbar indents customizations",filename:"actions-toolbar",url:"actions-toolbar.html#actions-toolbar-indents-customizations"},{title:"Responsive actions toolbar",filename:"actions-toolbar",url:"actions-toolbar.html#responsive-actions-toolbar"},{title:"breadcrumbs",filename:"breadcrumbs",url:"breadcrumbs.html"},{title:"Breadcrumbs",filename:"breadcrumbs",url:"breadcrumbs.html#breadcrumbs"},{title:"Breadcrumbs variables",filename:"breadcrumbs",url:"breadcrumbs.html#breadcrumbs-variables"},{title:"Button-styled breadcrumbs with gradient background, border, and no separating symbol",filename:"breadcrumbs",url:"breadcrumbs.html#buttonstyled-breadcrumbs-with-gradient-background-border-and-no-separating-symbol"},{title:"Breadcrumbs with solid background",filename:"breadcrumbs",url:"breadcrumbs.html#breadcrumbs-with-solid-background"},{title:"buttons",filename:"buttons",url:"buttons.html"},{title:"Default button",filename:"buttons",url:"buttons.html#default-button"},{title:"Button variables",filename:"buttons",url:"buttons.html#button-variables"},{title:"Button as an icon",filename:"buttons",url:"buttons.html#button-as-an-icon"},{title:"Button with an icon on the left or right side of the text",filename:"buttons",url:"buttons.html#button-with-an-icon-on-the-left-or-right-side-of-the-text"},{title:"Button with fixed width",filename:"buttons",url:"buttons.html#button-with-fixed-width"},{title:"Primary button",filename:"buttons",url:"buttons.html#primary-button"},{title:"Primary button variables",filename:"buttons",url:"buttons.html#primary-button-variables"},{title:"Button with gradient background",filename:"buttons",url:"buttons.html#button-with-gradient-background"},{title:"Button as a link",filename:"buttons",url:"buttons.html#button-as-a-link"},{title:"Button as a link variables",filename:"buttons",url:"buttons.html#button-as-a-link-variables"},{title:"Link as a button",filename:"buttons",url:"buttons.html#link-as-a-button"},{title:"Button reset",filename:"buttons",url:"buttons.html#button-reset"},{title:"Button revert secondary color",filename:"buttons",url:"buttons.html#button-revert-secondary-color"},{title:"Button revert secondary color variables",filename:"buttons",url:"buttons.html#button-revert-secondary-color-variables"},{title:"Button revert secondary size",filename:"buttons",url:"buttons.html#button-revert-secondary-size"},{title:"Button revert secondary size variables",filename:"buttons",url:"buttons.html#button-revert-secondary-size-variables"},{title:"components",filename:"components",url:"components.html"},{title:"Components",filename:"components",url:"components.html#components"},{title:"Components Variables",filename:"components",url:"components.html#components-variables"},{title:"dropdowns",filename:"dropdowns",url:"dropdowns.html"},{title:"Drop-down and split buttons mixins",filename:"dropdowns",url:"dropdowns.html#dropdown-and-split-buttons-mixins"},{title:"Drop-down",filename:"dropdowns",url:"dropdowns.html#dropdown"},{title:"Drop-down variables",filename:"dropdowns",url:"dropdowns.html#dropdown-variables"},{title:"Drop-down with icon customization",filename:"dropdowns",url:"dropdowns.html#dropdown-with-icon-customization"},{title:"Modify dropdown list styles",filename:"dropdowns",url:"dropdowns.html#modify-dropdown-list-styles"},{title:"Split button",filename:"dropdowns",url:"dropdowns.html#split-button"},{title:"Split button variables",filename:"dropdowns",url:"dropdowns.html#split-button-variables"},{title:"Split button - button styling",filename:"dropdowns",url:"dropdowns.html#split-button-button-styling"},{title:"Split button icon customization",filename:"dropdowns",url:"dropdowns.html#split-button-icon-customization"},{title:"Split button drop-down list customization",filename:"dropdowns",url:"dropdowns.html#split-button-dropdown-list-customization"},{title:"forms",filename:"forms",url:"forms.html"},{title:"Forms mixins",filename:"forms",url:"forms.html#forms-mixins"},{title:"Global forms elements customization",filename:"forms",url:"forms.html#global-forms-elements-customization"},{title:"Fieldsets & fields customization",filename:"forms",url:"forms.html#fieldsets-fields-customization"},{title:"Fieldset and legend customization variables",filename:"forms",url:"forms.html#fieldset-and-legend-customization-variables"},{title:"Fields customization variables",filename:"forms",url:"forms.html#fields-customization-variables"},{title:"Required fields message customization variables",filename:"forms",url:"forms.html#required-fields-message-customization-variables"},{title:"Form element inputs customization",filename:"forms",url:"forms.html#form-element-inputs-customization"},{title:"Form element inputs customization variables",filename:"forms",url:"forms.html#form-element-inputs-customization-variables"},{title:"Form element choice",filename:"forms",url:"forms.html#form-element-choice"},{title:"Form element choice variables",filename:"forms",url:"forms.html#form-element-choice-variables"},{title:"Custom color",filename:"forms",url:"forms.html#custom-color"},{title:"Input number - input-text view",filename:"forms",url:"forms.html#input-number-inputtext-view"},{title:"Input search - input-text view",filename:"forms",url:"forms.html#input-search-inputtext-view"},{title:"Form validation",filename:"forms",url:"forms.html#form-validation"},{title:"Form validation variables",filename:"forms",url:"forms.html#form-validation-variables"},{title:"icons",filename:"icons",url:"icons.html"},{title:"Icons",filename:"icons",url:"icons.html#icons"},{title:"Icon with image or sprite",filename:"icons",url:"icons.html#icon-with-image-or-sprite"},{title:"Icon with image or sprite variables",filename:"icons",url:"icons.html#icon-with-image-or-sprite-variables"},{title:"Icon position for an icon with image or sprite",filename:"icons",url:"icons.html#icon-position-for-an-icon-with-image-or-sprite"},{title:"Position for icon with image or sprite mixin variables",filename:"icons",url:"icons.html#position-for-icon-with-image-or-sprite-mixin-variables"},{title:"Icon sprite position (with grid)",filename:"icons",url:"icons.html#icon-sprite-position-with-grid"},{title:"Icon sprite position variables",filename:"icons",url:"icons.html#icon-sprite-position-variables"},{title:"Image/sprite icon size",filename:"icons",url:"icons.html#imagesprite-icon-size"},{title:"Image/sprite icon size variables",filename:"icons",url:"icons.html#imagesprite-icon-size-variables"},{title:"Font icon",filename:"icons",url:"icons.html#font-icon"},{title:"Font icon variables",filename:"icons",url:"icons.html#font-icon-variables"},{title:"Change the size of font icon",filename:"icons",url:"icons.html#change-the-size-of-font-icon"},{title:"Change the size of font icon variables",filename:"icons",url:"icons.html#change-the-size-of-font-icon-variables"},{title:"Hide icon text",filename:"icons",url:"icons.html#hide-icon-text"},{title:"Sprite and font icons for Blank theme",filename:"icons",url:"icons.html#sprite-and-font-icons-for-blank-theme"},{title:"layout",filename:"layout",url:"layout.html"},{title:"Layout",filename:"layout",url:"layout.html#layout"},{title:"Layout global variables",filename:"layout",url:"layout.html#layout-global-variables"},{title:"Page layouts",filename:"layout",url:"layout.html#page-layouts"},{title:"Layout column",filename:"layout",url:"layout.html#layout-column"},{title:"Layout column variables",filename:"layout",url:"layout.html#layout-column-variables"},{title:"Layout width",filename:"layout",url:"layout.html#layout-width"},{title:"Layout width variables",filename:"layout",url:"layout.html#layout-width-variables"},{title:"lib",filename:"lib",url:"lib.html"},{title:"Including Magento UI library to your theme",filename:"lib",url:"lib.html#including-magento-ui-library-to-your-theme"},{title:"loaders",filename:"loaders",url:"loaders.html"},{title:"Loaders",filename:"loaders",url:"loaders.html#loaders"},{title:"Default loader variables",filename:"loaders",url:"loaders.html#default-loader-variables"},{title:"Loading",filename:"loaders",url:"loaders.html#loading"},{title:"Loading default variables",filename:"loaders",url:"loaders.html#loading-default-variables"},{title:"messages",filename:"messages",url:"messages.html"},{title:"Messages",filename:"messages",url:"messages.html#messages"},{title:"Information message",filename:"messages",url:"messages.html#information-message"},{title:"Warning message",filename:"messages",url:"messages.html#warning-message"},{title:"Error message",filename:"messages",url:"messages.html#error-message"},{title:"Success message",filename:"messages",url:"messages.html#success-message"},{title:"Notice message",filename:"messages",url:"messages.html#notice-message"},{title:"Message with inner icon",filename:"messages",url:"messages.html#message-with-inner-icon"},{title:"Message with lateral icon",filename:"messages",url:"messages.html#message-with-lateral-icon"},{title:"Custom message style",filename:"messages",url:"messages.html#custom-message-style"},{title:"Messages global variables",filename:"messages",url:"messages.html#messages-global-variables"},{title:"pages",filename:"pages",url:"pages.html"},{title:"Pagination HTML markup",filename:"pages",url:"pages.html#pagination-html-markup"},{title:"Pagination variables",filename:"pages",url:"pages.html#pagination-variables"},{title:"Pagination with label and gradient background on links",filename:"pages",url:"pages.html#pagination-with-label-and-gradient-background-on-links"},{title:'Pagination with "previous"..."next" text links and label',filename:"pages",url:"pages.html#pagination-with-previousnext-text-links-and-label"},{title:"Pagination without label, with solid background",filename:"pages",url:"pages.html#pagination-without-label-with-solid-background"},{title:"popups",filename:"popups",url:"popups.html"},{title:"Popups",filename:"popups",url:"popups.html#popups"},{title:"Popup variables",filename:"popups",url:"popups.html#popup-variables"},{title:"Window overlay mixin variables",filename:"popups",url:"popups.html#window-overlay-mixin-variables"},{title:"Fixed height popup",filename:"popups",url:"popups.html#fixed-height-popup"},{title:"Fixed content height popup",filename:"popups",url:"popups.html#fixed-content-height-popup"},{title:"Margins for header, content and footer block in popup",filename:"popups",url:"popups.html#margins-for-header-content-and-footer-block-in-popup"},{title:"Popup titles styled as theme headings",filename:"popups",url:"popups.html#popup-titles-styled-as-theme-headings"},{title:"Popup action toolbar",filename:"popups",url:"popups.html#popup-action-toolbar"},{title:"Popup Close button without an icon",filename:"popups",url:"popups.html#popup-close-button-without-an-icon"},{title:"Modify the icon of popup Close button",filename:"popups",url:"popups.html#modify-the-icon-of-popup-close-button"},{title:"Modify overlay styles",filename:"popups",url:"popups.html#modify-overlay-styles"},{title:"rating",filename:"rating",url:"rating.html"},{title:"Ratings",filename:"rating",url:"rating.html#ratings"},{title:"Global rating variables",filename:"rating",url:"rating.html#global-rating-variables"},{title:"Rating with vote",filename:"rating",url:"rating.html#rating-with-vote"},{title:"Rating with vote icons number customization",filename:"rating",url:"rating.html#rating-with-vote-icons-number-customization"},{title:"Rating with vote icons colors customization",filename:"rating",url:"rating.html#rating-with-vote-icons-colors-customization"},{title:"Rating with vote icons symbol customization",filename:"rating",url:"rating.html#rating-with-vote-icons-symbol-customization"},{title:"Accessible rating with vote",filename:"rating",url:"rating.html#accessible-rating-with-vote"},{title:"Rating summary",filename:"rating",url:"rating.html#rating-summary"},{title:"Rating summary icons number customization",filename:"rating",url:"rating.html#rating-summary-icons-number-customization"},{title:"Rating summary icons color customization",filename:"rating",url:"rating.html#rating-summary-icons-color-customization"},{title:"Rating summary icons symbol customization",filename:"rating",url:"rating.html#rating-summary-icons-symbol-customization"},{title:"Rating summary hide label",filename:"rating",url:"rating.html#rating-summary-hide-label"},{title:"Rating summary multiple ratings",filename:"rating",url:"rating.html#rating-summary-multiple-ratings"},{title:"Rating hide label mixin",filename:"rating",url:"rating.html#rating-hide-label-mixin"},{title:"resets",filename:"resets",url:"resets.html"},{title:"Resets",filename:"resets",url:"resets.html#resets"},{title:"responsive",filename:"responsive",url:"responsive.html"},{title:"Responsive",filename:"responsive",url:"responsive.html#responsive"},{title:"Responsive mixins usage",filename:"responsive",url:"responsive.html#responsive-mixins-usage"},{title:"Media query style groups separation variables",filename:"responsive",url:"responsive.html#media-query-style-groups-separation-variables"},{title:"Responsive breakpoints",filename:"responsive",url:"responsive.html#responsive-breakpoints"},{title:"sections",filename:"sections",url:"sections.html"},{title:"Tabs and accordions",filename:"sections",url:"sections.html#tabs-and-accordions"},{title:"Tabs",filename:"sections",url:"sections.html#tabs"},{title:"Tabs mixin variables",filename:"sections",url:"sections.html#tabs-mixin-variables"},{title:"Tabs with content top border",filename:"sections",url:"sections.html#tabs-with-content-top-border"},{title:"Accordion",filename:"sections",url:"sections.html#accordion"},{title:"Accordion mixin variables",filename:"sections",url:"sections.html#accordion-mixin-variables"},{title:"Responsive tabs",filename:"sections",url:"sections.html#responsive-tabs"},{title:"Tabs Base",filename:"sections",url:"sections.html#tabs-base"},{title:"Accordion Base",filename:"sections",url:"sections.html#accordion-base"},{title:"tables",filename:"tables",url:"tables.html"},{title:"Tables",filename:"tables",url:"tables.html#tables"},{title:"Table mixin variables",filename:"tables",url:"tables.html#table-mixin-variables"},{title:"Table typography",filename:"tables",url:"tables.html#table-typography"},{title:"Table typography mixin variables",filename:"tables",url:"tables.html#table-typography-mixin-variables"},{title:"Table caption",filename:"tables",url:"tables.html#table-caption"},{title:"Table caption mixin variables",filename:"tables",url:"tables.html#table-caption-mixin-variables"},{title:"Table cells resize",filename:"tables",url:"tables.html#table-cells-resize"},{title:"Table cells resize variables",filename:"tables",url:"tables.html#table-cells-resize-variables"},{title:"Table background customization",filename:"tables",url:"tables.html#table-background-customization"},{title:"Table background mixin variables",filename:"tables",url:"tables.html#table-background-mixin-variables"},{title:"Table borders customization",filename:"tables",url:"tables.html#table-borders-customization"},{title:"Table borders mixin variables",filename:"tables",url:"tables.html#table-borders-mixin-variables"},{title:"Table with horizontal borders",filename:"tables",url:"tables.html#table-with-horizontal-borders"},{title:"Table with vertical borders",filename:"tables",url:"tables.html#table-with-vertical-borders"},{title:"Table with light borders",filename:"tables",url:"tables.html#table-with-light-borders"},{title:"Table without borders",filename:"tables",url:"tables.html#table-without-borders"},{title:"Striped table",filename:"tables",url:"tables.html#striped-table"},{title:"Striped table mixin variables",filename:"tables",url:"tables.html#striped-table-mixin-variables"},{title:"Table with rows hover",filename:"tables",url:"tables.html#table-with-rows-hover"},{title:"Table with rows hover mixin variables",filename:"tables",url:"tables.html#table-with-rows-hover-mixin-variables"},{title:"Responsive table technics #1",filename:"tables",url:"tables.html#responsive-table-technics-1"},{title:"Responsive table technics #2",filename:"tables",url:"tables.html#responsive-table-technics-2"},{title:"Responsive table technics #2 mixin variables",filename:"tables",url:"tables.html#responsive-table-technics-2-mixin-variables"},{title:"tooltips",filename:"tooltips",url:"tooltips.html"},{title:"Tooltips",filename:"tooltips",url:"tooltips.html#tooltips"},{title:"Tooltips variables",filename:"tooltips",url:"tooltips.html#tooltips-variables"},{title:"typography",filename:"typography",url:"typography.html"},{title:"Typogrphy",filename:"typography",url:"typography.html#typogrphy"},{title:"Typography variables",filename:"typography",url:"typography.html#typography-variables"},{title:"Font-size mixin",filename:"typography",url:"typography.html#fontsize-mixin"},{title:"Line-height mixin",filename:"typography",url:"typography.html#lineheight-mixin"},{title:"Word breaking mixin",filename:"typography",url:"typography.html#word-breaking-mixin"},{title:"Font face mixin",filename:"typography",url:"typography.html#font-face-mixin"},{title:"Text overflow mixin",filename:"typography",url:"typography.html#text-overflow-mixin"},{title:"Text hide",filename:"typography",url:"typography.html#text-hide"},{title:"Hyphens",filename:"typography",url:"typography.html#hyphens"},{title:"Font style and color",filename:"typography",url:"typography.html#font-style-and-color"},{title:"Font style mixin variables",filename:"typography",url:"typography.html#font-style-mixin-variables"},{title:"Reset list styles",filename:"typography",url:"typography.html#reset-list-styles"},{title:"Reset list styles variables",filename:"typography",url:"typography.html#reset-list-styles-variables"},{title:"Inline-block list item styling",filename:"typography",url:"typography.html#inlineblock-list-item-styling"},{title:"Link styling mixin",filename:"typography",url:"typography.html#link-styling-mixin"},{title:"Link styling mixin variables",filename:"typography",url:"typography.html#link-styling-mixin-variables"},{title:"Heading styling mixin",filename:"typography",url:"typography.html#heading-styling-mixin"},{title:"Base typography mixins",filename:"typography",url:"typography.html#base-typography-mixins"},{title:"Base typography mixin variables",filename:"typography",url:"typography.html#base-typography-mixin-variables"},{title:"Headings typography mixin",filename:"typography",url:"typography.html#headings-typography-mixin"},{title:"Headings typography mixin variables",filename:"typography",url:"typography.html#headings-typography-mixin-variables"},{title:"Typography links mixin",filename:"typography",url:"typography.html#typography-links-mixin"},{title:"Typography lists mixin",filename:"typography",url:"typography.html#typography-lists-mixin"},{title:"Typography lists mixin variables",filename:"typography",url:"typography.html#typography-lists-mixin-variables"},{title:"Typography code elements mixin",filename:"typography",url:"typography.html#typography-code-elements-mixin"},{title:"Typography code mixin variables",filename:"typography",url:"typography.html#typography-code-mixin-variables"},{title:"Typography blockquote",filename:"typography",url:"typography.html#typography-blockquote"},{title:"Typography blockquote mixin variables",filename:"typography",url:"typography.html#typography-blockquote-mixin-variables"},{title:"utilities",filename:"utilities",url:"utilities.html"},{title:"Utilities",filename:"utilities",url:"utilities.html#utilities"},{title:".lib-clearfix()",filename:"utilities",url:"utilities.html#libclearfix"},{title:".lib-visibility-hidden()",filename:"utilities",url:"utilities.html#libvisibilityhidden"},{title:".lib-visually-hidden()",filename:"utilities",url:"utilities.html#libvisuallyhidden"},{title:".lib-visually-hidden-reset()",filename:"utilities",url:"utilities.html#libvisuallyhiddenreset"},{title:".lib-css()",filename:"utilities",url:"utilities.html#libcss"},{title:".lib-css() variables",filename:"utilities",url:"utilities.html#libcss-variables"},{title:".lib-rotate()",filename:"utilities",url:"utilities.html#librotate"},{title:".lib-rotate() variables",filename:"utilities",url:"utilities.html#librotate-variables"},{title:".lib-input-placeholder()",filename:"utilities",url:"utilities.html#libinputplaceholder"},{title:".lib-input-placeholder() variables",filename:"utilities",url:"utilities.html#libinputplaceholder-variables"},{title:".lib-background-gradient()",filename:"utilities",url:"utilities.html#libbackgroundgradient"},{title:".lib-background-gradient() variables",filename:"utilities",url:"utilities.html#libbackgroundgradient-variables"},{title:".lib-url-check()",filename:"utilities",url:"utilities.html#liburlcheck"},{title:".lib-url-check() variables",filename:"utilities",url:"utilities.html#liburlcheck-variables"},{title:"variables",filename:"variables",url:"variables.html"},{title:"List of Global Variables",filename:"variables",url:"variables.html#list-of-global-variables"},{title:"Table with rows hover mixin variables",filename:"variables",url:"variables.html#table-with-rows-hover-mixin-variables"},{title:"docs",filename:"docs",url:"docs.html"},{title:"Documentation",filename:"docs",url:"docs.html#documentation"}];(function(){"use strict";var b=function(a,b){return Array.prototype.indexOf.call(a,b)!==-1},c=function(a,b){return Array.prototype.filter.call(a,b)},d=function(a,b){return Array.prototype.forEach.call(a,b)},e=document.getElementsByTagName("body")[0];e.addEventListener("click",function(a){var b=a.target;b.tagName.toLowerCase()==="svg"&&(b=b.parentNode);var c=!1;b.dataset.toggle!=null&&(a.preventDefault(),b.classList.contains("is-active")||(c=!0)),d(e.querySelectorAll("[data-toggle]"),function(a){a.classList.remove("is-active"),document.getElementById(a.dataset.toggle).hidden=!0}),c&&(b.classList.add("is-active"),document.getElementById(b.dataset.toggle).hidden=!1)}),function(){var f=e.getElementsByClassName("nav")[0];if(!f)return;var g=document.createElement("ul");g.className="nav-results",g.id="nav-search",g.hidden=!0,d(a,function(a){var b,c,d;b=document.createElement("li"),b._title=a.title.toLowerCase(),b.hidden=!0,b.appendChild(c=document.createElement("a")),c.href=a.url,c.innerHTML=a.title,c.appendChild(d=document.createElement("span")),d.innerHTML=a.filename,d.className="nav-results-filename",g.appendChild(b)}),f.appendChild(g);var h=g.children,i=function(a){d(h,function(a){a.hidden=!0});var b=this.value.toLowerCase(),e=[];b!==""&&(e=c(h,function(a){return a._title.indexOf(b)!==-1})),e.length>0?(d(e,function(a){a.hidden=!1}),g.hidden=!1):g.hidden=!0},j=f.querySelector('input[type="search"]');j.addEventListener("keyup",i),j.addEventListener("focus",i),e.addEventListener("click",function(a){if(a.target.classList&&a.target.classList.contains("search"))return;g.hidden=!0}),g.addEventListener("click",function(a){j.value=""});var k=document.createElement("ul");k.id="nav-toc",k.hidden=!0,k.className="nav-results toc-list",c(e.getElementsByTagName("*"),function(a){return b(["h1","h2","h3"],a.tagName.toLowerCase())}).map(function(a){var b=document.createElement("li"),c=document.createElement("a"),d=a.tagName.toLowerCase()[1];c.classList.add("level-"+d),b.appendChild(c),c.href="#"+a.id,c.innerHTML=a.innerHTML,k.appendChild(b)}),f.appendChild(k)}()})(),function(){"use strict";if(location.hash==="#__preview__"||location.protocol==="data:")return;var a=function(a,b){return Array.prototype.forEach.call(a,b)},b=function(a,b){var e=Array.prototype.slice.call(arguments,2);return d(a,function(a){return(c(b)?b||a:a[b]).apply(a,e)})},c=function(a){return Object.prototype.toString.call(a)==="[object Function]"},d=function(a,b){return Array.prototype.map.call(a,b)},e=function(a,b){return d(a,function(a){return a[b]})},f=function(a){var b={},c=a.split(";");for(var d=0;c.length>d;d++){var e=c[d].trim().split("=");b[e[0]]=e[1]}return b},g=function(a,c){return b(e(a,"classList"),"remove",c)},h=function(a,b){a.contentDocument.defaultView.postMessage(b,"*")},i=document.getElementsByTagName("head")[0],j=document.getElementsByTagName("body")[0],k=e(i.querySelectorAll('style[type="text/preview"]'),"innerHTML").join(""),l=e(i.querySelectorAll('script[type="text/preview"]'),"innerHTML").join(""),m=location.href.split("#")[0]+"#__preview__",n=document.createElement("iframe");n.src="data:text/html,",j.appendChild(n),n.addEventListener("load",function(){var b={sameOriginDataUri:!0};try{this.contentDocument,this.contentDocument||(b.sameOriginDataUri=!1)}catch(c){b.sameOriginDataUri=!1}this.parentNode.removeChild(this),a(j.getElementsByTagName("textarea"),function(a,c){o(a,b,c),q(),p(a)})});var o=function(a,b,c){var d,e,f;d=document.createElement("div"),d.appendChild(e=document.createElement("div")),d.className="preview",e.appendChild(f=document.createElement("iframe")),e.className="resizeable",f.setAttribute("scrolling","no"),f.name="iframe"+c++,f.addEventListener("load",function(){var c,d,e,f,g,i,j;j=this.contentDocument;if(!b.sameOriginDataUri&&this.src!==m)return;this.src===m&&(c=j.createElement("html"),c.appendChild(j.createElement("head")),c.appendChild(d=j.createElement("body")),d.innerHTML=a.textContent,j.replaceChild(c,j.documentElement)),g=j.createElement("head"),g.appendChild(f=j.createElement("style")),g.appendChild(e=j.createElement("script")),e.textContent=l,f.textContent=k,i=j.getElementsByTagName("head")[0],i.parentNode.replaceChild(g,i),h(this,"getHeight")});var g;b.sameOriginDataUri?g="data:text/html;charset=utf-8,"+encodeURIComponent("<!doctype html><html><head></head></body>"+a.textContent):g=m,f.setAttribute("src",g);var i=function(){f.contentDocument.body.innerHTML=this.value,h(f,"getHeight")};a.addEventListener("keypress",i),a.addEventListener("keyup",i),a.parentNode.insertBefore(d,a)},p=function(a){var b=document.createElement("div");b.className="preview-code",b.style.position="absolute",b.style.left="-9999px",j.appendChild(b);var c=parseInt(window.getComputedStyle(a).getPropertyValue("max-height"),10),d=function(a){b.textContent=this.value+"\n";var d=b.offsetHeight+2;d>=c?this.style.overflow="auto":this.style.overflow="hidden",this.style.height=b.offsetHeight+2+"px"};a.addEventListener("keypress",d),a.addEventListener("keyup",d),d.call(a)},q=function(){var b=j.getElementsByClassName("settings")[0],c=j.getElementsByClassName("resizeable"),d=30,e=function(b){document.cookie="preview-width="+b,a(c,function(a){b==="auto"&&(b=a.parentNode.offsetWidth),a.style.width=b+"px",h(a.getElementsByTagName("iframe")[0],"getHeight")})},i=f(document.cookie)["preview-width"];if(i){e(i),g(b.getElementsByClassName("is-active"),"is-active");var k=b.querySelector('button[data-width="'+i+'"]');k&&k.classList.add("is-active")}window.addEventListener("message",function(a){if(a.data==null||!a.source)return;var b=a.data,c=document.getElementsByName(a.source.name)[0];b.height!=null&&c&&(c.parentNode.style.height=b.height+d+"px")},!1),b&&c.length>0&&(b.hidden=!1,b.addEventListener("click",function(a){var c=a.target.tagName.toLowerCase(),d;if(c==="button")d=a.target;else{if(c!=="svg")return;d=a.target.parentNode}a.preventDefault(),g(b.getElementsByClassName("is-active"),"is-active"),d.classList.add("is-active");var f=d.dataset.width;e(f)}))}}()})()</script></body></html><!-- Generated with StyleDocco (http://jacobrask.github.com/styledocco). --> +}</code></pre></div></article></section><div class="bar bottom"><div hidden class="settings container"><!-- Icons from http://iconmonstr.com--><button title="Desktop (1280)" data-width='1280'><svg viewBox="0 0 412 386" height="24" width="26" class="icon"><path d="m147.6,343.9c-4.5,15.9-26.2,37.6-42.1,42.1h201c-15.3,-4-38.1,-26.8-42.1,-42.1H147.6zM387,0.5H25c-13.8,0-25,11.2-25,25V294c0,13.8 11.2,25 25,25h362c13.8,0 25,-11.2 25,-25V25.5C412,11.7 400.8,0.5 387,0.5zM369.9,238.2H42.1L42.1,42.6 369.9,42.6V238.2z"></path></svg></button><button title="Laptop (1024)" data-width='1024'><svg viewBox="0 0 384 312" height="23" width="28" class="icon"><path d="m349.2,20.5c0,-11-9,-20-20,-20H53.6c-11,0-20,9-20,20v194H349.2v-194zm-27,167H60.6V27.5H322.2v160zm28,42H32.6L2.6,282.1c-3.5,6.2-3.5,13.8 0.1,19.9 3.6,6.2 10.2,9.9 17.3,9.9H363.1c7.1,0 13.7,-3.8 17.3,-10 3.6,-6.2 3.6,-13.8 0,-20l-30.2,-52.5zm-196.9,54 8,-23.5h60.5l8,23.5h-76.5z"></path></svg></button><button title="Tablet (768)" data-width='768'><svg viewBox="0 0 317 412" height="24" width="18" class="icon"><path d="M 316.5,380 V 32 c 0,-17.7 -14.3,-32 -32,-32 H 32 C 14.3,0 0,14.3 0,32 v 348 c 0,17.7 14.3,32 32,32 h 252.5 c 17.7,0 32,-14.3 32,-32 z M 40,367 V 45 H 276.5 V 367 H 40 z m 109.8,22.7 c 0,-4.7 3.8,-8.5 8.5,-8.5 4.7,0 8.5,3.8 8.5,8.5 0,4.7 -3.8,8.5 -8.5,8.5 -4.7,0 -8.5,-3.8 -8.5,-8.5 z"></path></svg></button><button title="Smart phone (320)" data-width='320'><svg viewBox="0 0 224 412" height="24" width="13" class="icon"><path d="M 190.7,0 H 33 C 14.8,0 0,14.8 0,33 v 346 c 0,18.2 14.8,33 33,33 h 157.7 c 18.2,0 33,-14.8 33,-33 V 33 c 0,-18.2 -14.8,-33 -33,-33 z M 94.3,30.2 h 37 c 2.2,0 4,1.8 4,4 0,2.2 -1.8,4 -4,4 h -37 c -2.2,0 -4,-1.8 -4,-4 0,-2.2 1.8,-4 4,-4 z m 18.5,362.8 c -8.8,0 -16,-7.2 -16,-16 0,-8.8 7.2,-16 16,-16 8.8,0 16,7.2 16,16 0,8.8 -7.2,16 -16,16 z M 198.6,343.8 H 25.1 V 68.2 h 173.5 v 275.5 z"></path></svg></button><button title="Feature phone (240)" data-width='240'><svg viewBox="0 0 201 412" height="24" width="12" class="icon"><path d="M 165.5,0.2 V 45 H 25 c -13.8,0 -25,11.2 -25,25 V 387 c 0,13.8 11.2,25 25,25 h 150.5 c 13.8,0 25,-11.2 25,-25 V 0.2 h -35 z M 65.2,366.5 H 34.2 v -24.5 h 31 v 24.5 z m 0,-44.3 H 34.2 v -24.5 h 31 v 24.5 z m 50.5,44.3 H 84.7 v -24.5 h 31 v 24.5 z m 0,-44.3 H 84.7 v -24.5 h 31 v 24.5 z m 50.5,44.3 h -31 v -24.5 h 31 v 24.5 z m 0,-44.3 h -31 v -24.5 h 31 v 24.5 z m 0,-59.3 h -132 V 95.4 h 132 V 262.9 z"></path></svg></button><button title="Auto (100%)" data-width="auto" class="auto is-active">Auto</button></div></div><script>(function(){var a=[{title:"actions-toolbar",filename:"actions-toolbar",url:"actions-toolbar.html"},{title:"Actions toolbar",filename:"actions-toolbar",url:"actions-toolbar.html#actions-toolbar"},{title:"Actions toolbar mixin variables",filename:"actions-toolbar",url:"actions-toolbar.html#actions-toolbar-mixin-variables"},{title:"Actions toolbar alignment",filename:"actions-toolbar",url:"actions-toolbar.html#actions-toolbar-alignment"},{title:"Reverse primary and secondary blocks",filename:"actions-toolbar",url:"actions-toolbar.html#reverse-primary-and-secondary-blocks"},{title:"Actions toolbar indents customizations",filename:"actions-toolbar",url:"actions-toolbar.html#actions-toolbar-indents-customizations"},{title:"Responsive actions toolbar",filename:"actions-toolbar",url:"actions-toolbar.html#responsive-actions-toolbar"},{title:"breadcrumbs",filename:"breadcrumbs",url:"breadcrumbs.html"},{title:"Breadcrumbs",filename:"breadcrumbs",url:"breadcrumbs.html#breadcrumbs"},{title:"Breadcrumbs variables",filename:"breadcrumbs",url:"breadcrumbs.html#breadcrumbs-variables"},{title:"Button-styled breadcrumbs with gradient background, border, and no separating symbol",filename:"breadcrumbs",url:"breadcrumbs.html#buttonstyled-breadcrumbs-with-gradient-background-border-and-no-separating-symbol"},{title:"Breadcrumbs with solid background",filename:"breadcrumbs",url:"breadcrumbs.html#breadcrumbs-with-solid-background"},{title:"buttons",filename:"buttons",url:"buttons.html"},{title:"Default button",filename:"buttons",url:"buttons.html#default-button"},{title:"Button variables",filename:"buttons",url:"buttons.html#button-variables"},{title:"Button as an icon",filename:"buttons",url:"buttons.html#button-as-an-icon"},{title:"Button with an icon on the left or right side of the text",filename:"buttons",url:"buttons.html#button-with-an-icon-on-the-left-or-right-side-of-the-text"},{title:"Button with fixed width",filename:"buttons",url:"buttons.html#button-with-fixed-width"},{title:"Primary button",filename:"buttons",url:"buttons.html#primary-button"},{title:"Primary button variables",filename:"buttons",url:"buttons.html#primary-button-variables"},{title:"Button with gradient background",filename:"buttons",url:"buttons.html#button-with-gradient-background"},{title:"Button as a link",filename:"buttons",url:"buttons.html#button-as-a-link"},{title:"Button as a link variables",filename:"buttons",url:"buttons.html#button-as-a-link-variables"},{title:"Link as a button",filename:"buttons",url:"buttons.html#link-as-a-button"},{title:"Button reset",filename:"buttons",url:"buttons.html#button-reset"},{title:"Button revert secondary color",filename:"buttons",url:"buttons.html#button-revert-secondary-color"},{title:"Button revert secondary color variables",filename:"buttons",url:"buttons.html#button-revert-secondary-color-variables"},{title:"Button revert secondary size",filename:"buttons",url:"buttons.html#button-revert-secondary-size"},{title:"Button revert secondary size variables",filename:"buttons",url:"buttons.html#button-revert-secondary-size-variables"},{title:"components",filename:"components",url:"components.html"},{title:"Components",filename:"components",url:"components.html#components"},{title:"Components Variables",filename:"components",url:"components.html#components-variables"},{title:"dropdowns",filename:"dropdowns",url:"dropdowns.html"},{title:"Drop-down and split buttons mixins",filename:"dropdowns",url:"dropdowns.html#dropdown-and-split-buttons-mixins"},{title:"Drop-down",filename:"dropdowns",url:"dropdowns.html#dropdown"},{title:"Drop-down variables",filename:"dropdowns",url:"dropdowns.html#dropdown-variables"},{title:"Drop-down with icon customization",filename:"dropdowns",url:"dropdowns.html#dropdown-with-icon-customization"},{title:"Modify dropdown list styles",filename:"dropdowns",url:"dropdowns.html#modify-dropdown-list-styles"},{title:"Split button",filename:"dropdowns",url:"dropdowns.html#split-button"},{title:"Split button variables",filename:"dropdowns",url:"dropdowns.html#split-button-variables"},{title:"Split button - button styling",filename:"dropdowns",url:"dropdowns.html#split-button-button-styling"},{title:"Split button icon customization",filename:"dropdowns",url:"dropdowns.html#split-button-icon-customization"},{title:"Split button drop-down list customization",filename:"dropdowns",url:"dropdowns.html#split-button-dropdown-list-customization"},{title:"forms",filename:"forms",url:"forms.html"},{title:"Forms mixins",filename:"forms",url:"forms.html#forms-mixins"},{title:"Global forms elements customization",filename:"forms",url:"forms.html#global-forms-elements-customization"},{title:"Fieldsets & fields customization",filename:"forms",url:"forms.html#fieldsets-fields-customization"},{title:"Fieldset and legend customization variables",filename:"forms",url:"forms.html#fieldset-and-legend-customization-variables"},{title:"Fields customization variables",filename:"forms",url:"forms.html#fields-customization-variables"},{title:"Required fields message customization variables",filename:"forms",url:"forms.html#required-fields-message-customization-variables"},{title:"Form element inputs customization",filename:"forms",url:"forms.html#form-element-inputs-customization"},{title:"Form element inputs customization variables",filename:"forms",url:"forms.html#form-element-inputs-customization-variables"},{title:"Form element choice",filename:"forms",url:"forms.html#form-element-choice"},{title:"Form element choice variables",filename:"forms",url:"forms.html#form-element-choice-variables"},{title:"Custom color",filename:"forms",url:"forms.html#custom-color"},{title:"Input number - input-text view",filename:"forms",url:"forms.html#input-number-inputtext-view"},{title:"Input search - input-text view",filename:"forms",url:"forms.html#input-search-inputtext-view"},{title:"Form validation",filename:"forms",url:"forms.html#form-validation"},{title:"Form validation variables",filename:"forms",url:"forms.html#form-validation-variables"},{title:"icons",filename:"icons",url:"icons.html"},{title:"Icons",filename:"icons",url:"icons.html#icons"},{title:"Icon with image or sprite",filename:"icons",url:"icons.html#icon-with-image-or-sprite"},{title:"Icon with image or sprite variables",filename:"icons",url:"icons.html#icon-with-image-or-sprite-variables"},{title:"Icon position for an icon with image or sprite",filename:"icons",url:"icons.html#icon-position-for-an-icon-with-image-or-sprite"},{title:"Position for icon with image or sprite mixin variables",filename:"icons",url:"icons.html#position-for-icon-with-image-or-sprite-mixin-variables"},{title:"Icon sprite position (with grid)",filename:"icons",url:"icons.html#icon-sprite-position-with-grid"},{title:"Icon sprite position variables",filename:"icons",url:"icons.html#icon-sprite-position-variables"},{title:"Image/sprite icon size",filename:"icons",url:"icons.html#imagesprite-icon-size"},{title:"Image/sprite icon size variables",filename:"icons",url:"icons.html#imagesprite-icon-size-variables"},{title:"Font icon",filename:"icons",url:"icons.html#font-icon"},{title:"Font icon variables",filename:"icons",url:"icons.html#font-icon-variables"},{title:"Change the size of font icon",filename:"icons",url:"icons.html#change-the-size-of-font-icon"},{title:"Change the size of font icon variables",filename:"icons",url:"icons.html#change-the-size-of-font-icon-variables"},{title:"Hide icon text",filename:"icons",url:"icons.html#hide-icon-text"},{title:"Sprite and font icons for Blank theme",filename:"icons",url:"icons.html#sprite-and-font-icons-for-blank-theme"},{title:"layout",filename:"layout",url:"layout.html"},{title:"Layout",filename:"layout",url:"layout.html#layout"},{title:"Layout global variables",filename:"layout",url:"layout.html#layout-global-variables"},{title:"Page layouts",filename:"layout",url:"layout.html#page-layouts"},{title:"Layout column",filename:"layout",url:"layout.html#layout-column"},{title:"Layout column variables",filename:"layout",url:"layout.html#layout-column-variables"},{title:"Layout width",filename:"layout",url:"layout.html#layout-width"},{title:"Layout width variables",filename:"layout",url:"layout.html#layout-width-variables"},{title:"lib",filename:"lib",url:"lib.html"},{title:"Including Magento UI library to your theme",filename:"lib",url:"lib.html#including-magento-ui-library-to-your-theme"},{title:"loaders",filename:"loaders",url:"loaders.html"},{title:"Loaders",filename:"loaders",url:"loaders.html#loaders"},{title:"Default loader variables",filename:"loaders",url:"loaders.html#default-loader-variables"},{title:"Loading",filename:"loaders",url:"loaders.html#loading"},{title:"Loading default variables",filename:"loaders",url:"loaders.html#loading-default-variables"},{title:"messages",filename:"messages",url:"messages.html"},{title:"Messages",filename:"messages",url:"messages.html#messages"},{title:"Information message",filename:"messages",url:"messages.html#information-message"},{title:"Warning message",filename:"messages",url:"messages.html#warning-message"},{title:"Error message",filename:"messages",url:"messages.html#error-message"},{title:"Success message",filename:"messages",url:"messages.html#success-message"},{title:"Notice message",filename:"messages",url:"messages.html#notice-message"},{title:"Message with inner icon",filename:"messages",url:"messages.html#message-with-inner-icon"},{title:"Message with lateral icon",filename:"messages",url:"messages.html#message-with-lateral-icon"},{title:"Custom message style",filename:"messages",url:"messages.html#custom-message-style"},{title:"Messages global variables",filename:"messages",url:"messages.html#messages-global-variables"},{title:"pages",filename:"pages",url:"pages.html"},{title:"Pagination HTML markup",filename:"pages",url:"pages.html#pagination-html-markup"},{title:"Pagination variables",filename:"pages",url:"pages.html#pagination-variables"},{title:"Pagination with label and gradient background on links",filename:"pages",url:"pages.html#pagination-with-label-and-gradient-background-on-links"},{title:'Pagination with "previous"..."next" text links and label',filename:"pages",url:"pages.html#pagination-with-previousnext-text-links-and-label"},{title:"Pagination without label, with solid background",filename:"pages",url:"pages.html#pagination-without-label-with-solid-background"},{title:"popups",filename:"popups",url:"popups.html"},{title:"Popups",filename:"popups",url:"popups.html#popups"},{title:"Popup variables",filename:"popups",url:"popups.html#popup-variables"},{title:"Window overlay mixin variables",filename:"popups",url:"popups.html#window-overlay-mixin-variables"},{title:"Fixed height popup",filename:"popups",url:"popups.html#fixed-height-popup"},{title:"Fixed content height popup",filename:"popups",url:"popups.html#fixed-content-height-popup"},{title:"Margins for header, content and footer block in popup",filename:"popups",url:"popups.html#margins-for-header-content-and-footer-block-in-popup"},{title:"Popup titles styled as theme headings",filename:"popups",url:"popups.html#popup-titles-styled-as-theme-headings"},{title:"Popup action toolbar",filename:"popups",url:"popups.html#popup-action-toolbar"},{title:"Popup Close button without an icon",filename:"popups",url:"popups.html#popup-close-button-without-an-icon"},{title:"Modify the icon of popup Close button",filename:"popups",url:"popups.html#modify-the-icon-of-popup-close-button"},{title:"Modify overlay styles",filename:"popups",url:"popups.html#modify-overlay-styles"},{title:"rating",filename:"rating",url:"rating.html"},{title:"Ratings",filename:"rating",url:"rating.html#ratings"},{title:"Global rating variables",filename:"rating",url:"rating.html#global-rating-variables"},{title:"Rating with vote",filename:"rating",url:"rating.html#rating-with-vote"},{title:"Rating with vote icons number customization",filename:"rating",url:"rating.html#rating-with-vote-icons-number-customization"},{title:"Rating with vote icons colors customization",filename:"rating",url:"rating.html#rating-with-vote-icons-colors-customization"},{title:"Rating with vote icons symbol customization",filename:"rating",url:"rating.html#rating-with-vote-icons-symbol-customization"},{title:"Accessible rating with vote",filename:"rating",url:"rating.html#accessible-rating-with-vote"},{title:"Rating summary",filename:"rating",url:"rating.html#rating-summary"},{title:"Rating summary icons number customization",filename:"rating",url:"rating.html#rating-summary-icons-number-customization"},{title:"Rating summary icons color customization",filename:"rating",url:"rating.html#rating-summary-icons-color-customization"},{title:"Rating summary icons symbol customization",filename:"rating",url:"rating.html#rating-summary-icons-symbol-customization"},{title:"Rating summary hide label",filename:"rating",url:"rating.html#rating-summary-hide-label"},{title:"Rating summary multiple ratings",filename:"rating",url:"rating.html#rating-summary-multiple-ratings"},{title:"Rating hide label mixin",filename:"rating",url:"rating.html#rating-hide-label-mixin"},{title:"resets",filename:"resets",url:"resets.html"},{title:"Resets",filename:"resets",url:"resets.html#resets"},{title:"responsive",filename:"responsive",url:"responsive.html"},{title:"Responsive",filename:"responsive",url:"responsive.html#responsive"},{title:"Responsive mixins usage",filename:"responsive",url:"responsive.html#responsive-mixins-usage"},{title:"Media query style groups separation variables",filename:"responsive",url:"responsive.html#media-query-style-groups-separation-variables"},{title:"Responsive breakpoints",filename:"responsive",url:"responsive.html#responsive-breakpoints"},{title:"sections",filename:"sections",url:"sections.html"},{title:"Tabs and accordions",filename:"sections",url:"sections.html#tabs-and-accordions"},{title:"Tabs",filename:"sections",url:"sections.html#tabs"},{title:"Tabs mixin variables",filename:"sections",url:"sections.html#tabs-mixin-variables"},{title:"Tabs with content top border",filename:"sections",url:"sections.html#tabs-with-content-top-border"},{title:"Accordion",filename:"sections",url:"sections.html#accordion"},{title:"Accordion mixin variables",filename:"sections",url:"sections.html#accordion-mixin-variables"},{title:"Responsive tabs",filename:"sections",url:"sections.html#responsive-tabs"},{title:"Tabs Base",filename:"sections",url:"sections.html#tabs-base"},{title:"Accordion Base",filename:"sections",url:"sections.html#accordion-base"},{title:"tables",filename:"tables",url:"tables.html"},{title:"Tables",filename:"tables",url:"tables.html#tables"},{title:"Table mixin variables",filename:"tables",url:"tables.html#table-mixin-variables"},{title:"Table typography",filename:"tables",url:"tables.html#table-typography"},{title:"Table typography mixin variables",filename:"tables",url:"tables.html#table-typography-mixin-variables"},{title:"Table caption",filename:"tables",url:"tables.html#table-caption"},{title:"Table caption mixin variables",filename:"tables",url:"tables.html#table-caption-mixin-variables"},{title:"Table cells resize",filename:"tables",url:"tables.html#table-cells-resize"},{title:"Table cells resize variables",filename:"tables",url:"tables.html#table-cells-resize-variables"},{title:"Table background customization",filename:"tables",url:"tables.html#table-background-customization"},{title:"Table background mixin variables",filename:"tables",url:"tables.html#table-background-mixin-variables"},{title:"Table borders customization",filename:"tables",url:"tables.html#table-borders-customization"},{title:"Table borders mixin variables",filename:"tables",url:"tables.html#table-borders-mixin-variables"},{title:"Table with horizontal borders",filename:"tables",url:"tables.html#table-with-horizontal-borders"},{title:"Table with vertical borders",filename:"tables",url:"tables.html#table-with-vertical-borders"},{title:"Table with light borders",filename:"tables",url:"tables.html#table-with-light-borders"},{title:"Table without borders",filename:"tables",url:"tables.html#table-without-borders"},{title:"Striped table",filename:"tables",url:"tables.html#striped-table"},{title:"Striped table mixin variables",filename:"tables",url:"tables.html#striped-table-mixin-variables"},{title:"Table with rows hover",filename:"tables",url:"tables.html#table-with-rows-hover"},{title:"Table with rows hover mixin variables",filename:"tables",url:"tables.html#table-with-rows-hover-mixin-variables"},{title:"Responsive table technics #1",filename:"tables",url:"tables.html#responsive-table-technics-1"},{title:"Responsive table technics #2",filename:"tables",url:"tables.html#responsive-table-technics-2"},{title:"Responsive table technics #2 mixin variables",filename:"tables",url:"tables.html#responsive-table-technics-2-mixin-variables"},{title:"tooltips",filename:"tooltips",url:"tooltips.html"},{title:"Tooltips",filename:"tooltips",url:"tooltips.html#tooltips"},{title:"Tooltips variables",filename:"tooltips",url:"tooltips.html#tooltips-variables"},{title:"typography",filename:"typography",url:"typography.html"},{title:"Typogrphy",filename:"typography",url:"typography.html#typogrphy"},{title:"Typography variables",filename:"typography",url:"typography.html#typography-variables"},{title:"Font-size mixin",filename:"typography",url:"typography.html#fontsize-mixin"},{title:"Line-height mixin",filename:"typography",url:"typography.html#lineheight-mixin"},{title:"Word breaking mixin",filename:"typography",url:"typography.html#word-breaking-mixin"},{title:"Font face mixin",filename:"typography",url:"typography.html#font-face-mixin"},{title:"Text overflow mixin",filename:"typography",url:"typography.html#text-overflow-mixin"},{title:"Text hide",filename:"typography",url:"typography.html#text-hide"},{title:"Hyphens",filename:"typography",url:"typography.html#hyphens"},{title:"Font style and color",filename:"typography",url:"typography.html#font-style-and-color"},{title:"Font style mixin variables",filename:"typography",url:"typography.html#font-style-mixin-variables"},{title:"Reset list styles",filename:"typography",url:"typography.html#reset-list-styles"},{title:"Reset list styles variables",filename:"typography",url:"typography.html#reset-list-styles-variables"},{title:"Inline-block list item styling",filename:"typography",url:"typography.html#inlineblock-list-item-styling"},{title:"Link styling mixin",filename:"typography",url:"typography.html#link-styling-mixin"},{title:"Link styling mixin variables",filename:"typography",url:"typography.html#link-styling-mixin-variables"},{title:"Heading styling mixin",filename:"typography",url:"typography.html#heading-styling-mixin"},{title:"Base typography mixins",filename:"typography",url:"typography.html#base-typography-mixins"},{title:"Base typography mixin variables",filename:"typography",url:"typography.html#base-typography-mixin-variables"},{title:"Headings typography mixin",filename:"typography",url:"typography.html#headings-typography-mixin"},{title:"Headings typography mixin variables",filename:"typography",url:"typography.html#headings-typography-mixin-variables"},{title:"Typography links mixin",filename:"typography",url:"typography.html#typography-links-mixin"},{title:"Typography lists mixin",filename:"typography",url:"typography.html#typography-lists-mixin"},{title:"Typography lists mixin variables",filename:"typography",url:"typography.html#typography-lists-mixin-variables"},{title:"Typography code elements mixin",filename:"typography",url:"typography.html#typography-code-elements-mixin"},{title:"Typography code mixin variables",filename:"typography",url:"typography.html#typography-code-mixin-variables"},{title:"Typography blockquote",filename:"typography",url:"typography.html#typography-blockquote"},{title:"Typography blockquote mixin variables",filename:"typography",url:"typography.html#typography-blockquote-mixin-variables"},{title:"utilities",filename:"utilities",url:"utilities.html"},{title:"Utilities",filename:"utilities",url:"utilities.html#utilities"},{title:".lib-clearfix()",filename:"utilities",url:"utilities.html#libclearfix"},{title:".lib-visibility-hidden()",filename:"utilities",url:"utilities.html#libvisibilityhidden"},{title:".lib-visually-hidden()",filename:"utilities",url:"utilities.html#libvisuallyhidden"},{title:".lib-visually-hidden-reset()",filename:"utilities",url:"utilities.html#libvisuallyhiddenreset"},{title:".lib-css()",filename:"utilities",url:"utilities.html#libcss"},{title:".lib-css() variables",filename:"utilities",url:"utilities.html#libcss-variables"},{title:".lib-rotate()",filename:"utilities",url:"utilities.html#librotate"},{title:".lib-rotate() variables",filename:"utilities",url:"utilities.html#librotate-variables"},{title:".lib-input-placeholder()",filename:"utilities",url:"utilities.html#libinputplaceholder"},{title:".lib-input-placeholder() variables",filename:"utilities",url:"utilities.html#libinputplaceholder-variables"},{title:".lib-background-gradient()",filename:"utilities",url:"utilities.html#libbackgroundgradient"},{title:".lib-background-gradient() variables",filename:"utilities",url:"utilities.html#libbackgroundgradient-variables"},{title:"variables",filename:"variables",url:"variables.html"},{title:"List of Global Variables",filename:"variables",url:"variables.html#list-of-global-variables"},{title:"Table with rows hover mixin variables",filename:"variables",url:"variables.html#table-with-rows-hover-mixin-variables"},{title:"docs",filename:"docs",url:"docs.html"},{title:"Documentation",filename:"docs",url:"docs.html#documentation"}];(function(){"use strict";var b=function(a,b){return Array.prototype.indexOf.call(a,b)!==-1},c=function(a,b){return Array.prototype.filter.call(a,b)},d=function(a,b){return Array.prototype.forEach.call(a,b)},e=document.getElementsByTagName("body")[0];e.addEventListener("click",function(a){var b=a.target;b.tagName.toLowerCase()==="svg"&&(b=b.parentNode);var c=!1;b.dataset.toggle!=null&&(a.preventDefault(),b.classList.contains("is-active")||(c=!0)),d(e.querySelectorAll("[data-toggle]"),function(a){a.classList.remove("is-active"),document.getElementById(a.dataset.toggle).hidden=!0}),c&&(b.classList.add("is-active"),document.getElementById(b.dataset.toggle).hidden=!1)}),function(){var f=e.getElementsByClassName("nav")[0];if(!f)return;var g=document.createElement("ul");g.className="nav-results",g.id="nav-search",g.hidden=!0,d(a,function(a){var b,c,d;b=document.createElement("li"),b._title=a.title.toLowerCase(),b.hidden=!0,b.appendChild(c=document.createElement("a")),c.href=a.url,c.innerHTML=a.title,c.appendChild(d=document.createElement("span")),d.innerHTML=a.filename,d.className="nav-results-filename",g.appendChild(b)}),f.appendChild(g);var h=g.children,i=function(a){d(h,function(a){a.hidden=!0});var b=this.value.toLowerCase(),e=[];b!==""&&(e=c(h,function(a){return a._title.indexOf(b)!==-1})),e.length>0?(d(e,function(a){a.hidden=!1}),g.hidden=!1):g.hidden=!0},j=f.querySelector('input[type="search"]');j.addEventListener("keyup",i),j.addEventListener("focus",i),e.addEventListener("click",function(a){if(a.target.classList&&a.target.classList.contains("search"))return;g.hidden=!0}),g.addEventListener("click",function(a){j.value=""});var k=document.createElement("ul");k.id="nav-toc",k.hidden=!0,k.className="nav-results toc-list",c(e.getElementsByTagName("*"),function(a){return b(["h1","h2","h3"],a.tagName.toLowerCase())}).map(function(a){var b=document.createElement("li"),c=document.createElement("a"),d=a.tagName.toLowerCase()[1];c.classList.add("level-"+d),b.appendChild(c),c.href="#"+a.id,c.innerHTML=a.innerHTML,k.appendChild(b)}),f.appendChild(k)}()})(),function(){"use strict";if(location.hash==="#__preview__"||location.protocol==="data:")return;var a=function(a,b){return Array.prototype.forEach.call(a,b)},b=function(a,b){var e=Array.prototype.slice.call(arguments,2);return d(a,function(a){return(c(b)?b||a:a[b]).apply(a,e)})},c=function(a){return Object.prototype.toString.call(a)==="[object Function]"},d=function(a,b){return Array.prototype.map.call(a,b)},e=function(a,b){return d(a,function(a){return a[b]})},f=function(a){var b={},c=a.split(";");for(var d=0;c.length>d;d++){var e=c[d].trim().split("=");b[e[0]]=e[1]}return b},g=function(a,c){return b(e(a,"classList"),"remove",c)},h=function(a,b){a.contentDocument.defaultView.postMessage(b,"*")},i=document.getElementsByTagName("head")[0],j=document.getElementsByTagName("body")[0],k=e(i.querySelectorAll('style[type="text/preview"]'),"innerHTML").join(""),l=e(i.querySelectorAll('script[type="text/preview"]'),"innerHTML").join(""),m=location.href.split("#")[0]+"#__preview__",n=document.createElement("iframe");n.src="data:text/html,",j.appendChild(n),n.addEventListener("load",function(){var b={sameOriginDataUri:!0};try{this.contentDocument,this.contentDocument||(b.sameOriginDataUri=!1)}catch(c){b.sameOriginDataUri=!1}this.parentNode.removeChild(this),a(j.getElementsByTagName("textarea"),function(a,c){o(a,b,c),q(),p(a)})});var o=function(a,b,c){var d,e,f;d=document.createElement("div"),d.appendChild(e=document.createElement("div")),d.className="preview",e.appendChild(f=document.createElement("iframe")),e.className="resizeable",f.setAttribute("scrolling","no"),f.name="iframe"+c++,f.addEventListener("load",function(){var c,d,e,f,g,i,j;j=this.contentDocument;if(!b.sameOriginDataUri&&this.src!==m)return;this.src===m&&(c=j.createElement("html"),c.appendChild(j.createElement("head")),c.appendChild(d=j.createElement("body")),d.innerHTML=a.textContent,j.replaceChild(c,j.documentElement)),g=j.createElement("head"),g.appendChild(f=j.createElement("style")),g.appendChild(e=j.createElement("script")),e.textContent=l,f.textContent=k,i=j.getElementsByTagName("head")[0],i.parentNode.replaceChild(g,i),h(this,"getHeight")});var g;b.sameOriginDataUri?g="data:text/html;charset=utf-8,"+encodeURIComponent("<!doctype html><html><head></head></body>"+a.textContent):g=m,f.setAttribute("src",g);var i=function(){f.contentDocument.body.innerHTML=this.value,h(f,"getHeight")};a.addEventListener("keypress",i),a.addEventListener("keyup",i),a.parentNode.insertBefore(d,a)},p=function(a){var b=document.createElement("div");b.className="preview-code",b.style.position="absolute",b.style.left="-9999px",j.appendChild(b);var c=parseInt(window.getComputedStyle(a).getPropertyValue("max-height"),10),d=function(a){b.textContent=this.value+"\n";var d=b.offsetHeight+2;d>=c?this.style.overflow="auto":this.style.overflow="hidden",this.style.height=b.offsetHeight+2+"px"};a.addEventListener("keypress",d),a.addEventListener("keyup",d),d.call(a)},q=function(){var b=j.getElementsByClassName("settings")[0],c=j.getElementsByClassName("resizeable"),d=30,e=function(b){document.cookie="preview-width="+b,a(c,function(a){b==="auto"&&(b=a.parentNode.offsetWidth),a.style.width=b+"px",h(a.getElementsByTagName("iframe")[0],"getHeight")})},i=f(document.cookie)["preview-width"];if(i){e(i),g(b.getElementsByClassName("is-active"),"is-active");var k=b.querySelector('button[data-width="'+i+'"]');k&&k.classList.add("is-active")}window.addEventListener("message",function(a){if(a.data==null||!a.source)return;var b=a.data,c=document.getElementsByName(a.source.name)[0];b.height!=null&&c&&(c.parentNode.style.height=b.height+d+"px")},!1),b&&c.length>0&&(b.hidden=!1,b.addEventListener("click",function(a){var c=a.target.tagName.toLowerCase(),d;if(c==="button")d=a.target;else{if(c!=="svg")return;d=a.target.parentNode}a.preventDefault(),g(b.getElementsByClassName("is-active"),"is-active"),d.classList.add("is-active");var f=d.dataset.width;e(f)}))}}()})()</script></body></html><!-- Generated with StyleDocco (http://jacobrask.github.com/styledocco). --> diff --git a/lib/web/css/docs/resets.html b/lib/web/css/docs/resets.html index f2eb5ee9b48db..fc1cb092422c0 100644 --- a/lib/web/css/docs/resets.html +++ b/lib/web/css/docs/resets.html @@ -34,4 +34,4 @@ <h2 id="global-borderbox">Global border-box</h2> <p> To set <code>box-sizing: border-box</code> globally, use mixin:</p> <pre><code class="lang-CSS"> .lib-set-default-border-box();</code></pre> <p>  </p> -</div></article></section><div class="bar bottom"><div hidden class="settings container"><!-- Icons from http://iconmonstr.com--><button title="Desktop (1280)" data-width='1280'><svg viewBox="0 0 412 386" height="24" width="26" class="icon"><path d="m147.6,343.9c-4.5,15.9-26.2,37.6-42.1,42.1h201c-15.3,-4-38.1,-26.8-42.1,-42.1H147.6zM387,0.5H25c-13.8,0-25,11.2-25,25V294c0,13.8 11.2,25 25,25h362c13.8,0 25,-11.2 25,-25V25.5C412,11.7 400.8,0.5 387,0.5zM369.9,238.2H42.1L42.1,42.6 369.9,42.6V238.2z"></path></svg></button><button title="Laptop (1024)" data-width='1024'><svg viewBox="0 0 384 312" height="23" width="28" class="icon"><path d="m349.2,20.5c0,-11-9,-20-20,-20H53.6c-11,0-20,9-20,20v194H349.2v-194zm-27,167H60.6V27.5H322.2v160zm28,42H32.6L2.6,282.1c-3.5,6.2-3.5,13.8 0.1,19.9 3.6,6.2 10.2,9.9 17.3,9.9H363.1c7.1,0 13.7,-3.8 17.3,-10 3.6,-6.2 3.6,-13.8 0,-20l-30.2,-52.5zm-196.9,54 8,-23.5h60.5l8,23.5h-76.5z"></path></svg></button><button title="Tablet (768)" data-width='768'><svg viewBox="0 0 317 412" height="24" width="18" class="icon"><path d="M 316.5,380 V 32 c 0,-17.7 -14.3,-32 -32,-32 H 32 C 14.3,0 0,14.3 0,32 v 348 c 0,17.7 14.3,32 32,32 h 252.5 c 17.7,0 32,-14.3 32,-32 z M 40,367 V 45 H 276.5 V 367 H 40 z m 109.8,22.7 c 0,-4.7 3.8,-8.5 8.5,-8.5 4.7,0 8.5,3.8 8.5,8.5 0,4.7 -3.8,8.5 -8.5,8.5 -4.7,0 -8.5,-3.8 -8.5,-8.5 z"></path></svg></button><button title="Smart phone (320)" data-width='320'><svg viewBox="0 0 224 412" height="24" width="13" class="icon"><path d="M 190.7,0 H 33 C 14.8,0 0,14.8 0,33 v 346 c 0,18.2 14.8,33 33,33 h 157.7 c 18.2,0 33,-14.8 33,-33 V 33 c 0,-18.2 -14.8,-33 -33,-33 z M 94.3,30.2 h 37 c 2.2,0 4,1.8 4,4 0,2.2 -1.8,4 -4,4 h -37 c -2.2,0 -4,-1.8 -4,-4 0,-2.2 1.8,-4 4,-4 z m 18.5,362.8 c -8.8,0 -16,-7.2 -16,-16 0,-8.8 7.2,-16 16,-16 8.8,0 16,7.2 16,16 0,8.8 -7.2,16 -16,16 z M 198.6,343.8 H 25.1 V 68.2 h 173.5 v 275.5 z"></path></svg></button><button title="Feature phone (240)" data-width='240'><svg viewBox="0 0 201 412" height="24" width="12" class="icon"><path d="M 165.5,0.2 V 45 H 25 c -13.8,0 -25,11.2 -25,25 V 387 c 0,13.8 11.2,25 25,25 h 150.5 c 13.8,0 25,-11.2 25,-25 V 0.2 h -35 z M 65.2,366.5 H 34.2 v -24.5 h 31 v 24.5 z m 0,-44.3 H 34.2 v -24.5 h 31 v 24.5 z m 50.5,44.3 H 84.7 v -24.5 h 31 v 24.5 z m 0,-44.3 H 84.7 v -24.5 h 31 v 24.5 z m 50.5,44.3 h -31 v -24.5 h 31 v 24.5 z m 0,-44.3 h -31 v -24.5 h 31 v 24.5 z m 0,-59.3 h -132 V 95.4 h 132 V 262.9 z"></path></svg></button><button title="Auto (100%)" data-width="auto" class="auto is-active">Auto</button></div></div><script>(function(){var a=[{title:"actions-toolbar",filename:"actions-toolbar",url:"actions-toolbar.html"},{title:"Actions toolbar",filename:"actions-toolbar",url:"actions-toolbar.html#actions-toolbar"},{title:"Actions toolbar mixin variables",filename:"actions-toolbar",url:"actions-toolbar.html#actions-toolbar-mixin-variables"},{title:"Actions toolbar alignment",filename:"actions-toolbar",url:"actions-toolbar.html#actions-toolbar-alignment"},{title:"Reverse primary and secondary blocks",filename:"actions-toolbar",url:"actions-toolbar.html#reverse-primary-and-secondary-blocks"},{title:"Actions toolbar indents customizations",filename:"actions-toolbar",url:"actions-toolbar.html#actions-toolbar-indents-customizations"},{title:"Responsive actions toolbar",filename:"actions-toolbar",url:"actions-toolbar.html#responsive-actions-toolbar"},{title:"breadcrumbs",filename:"breadcrumbs",url:"breadcrumbs.html"},{title:"Breadcrumbs",filename:"breadcrumbs",url:"breadcrumbs.html#breadcrumbs"},{title:"Breadcrumbs variables",filename:"breadcrumbs",url:"breadcrumbs.html#breadcrumbs-variables"},{title:"Button-styled breadcrumbs with gradient background, border, and no separating symbol",filename:"breadcrumbs",url:"breadcrumbs.html#buttonstyled-breadcrumbs-with-gradient-background-border-and-no-separating-symbol"},{title:"Breadcrumbs with solid background",filename:"breadcrumbs",url:"breadcrumbs.html#breadcrumbs-with-solid-background"},{title:"buttons",filename:"buttons",url:"buttons.html"},{title:"Default button",filename:"buttons",url:"buttons.html#default-button"},{title:"Button variables",filename:"buttons",url:"buttons.html#button-variables"},{title:"Button as an icon",filename:"buttons",url:"buttons.html#button-as-an-icon"},{title:"Button with an icon on the left or right side of the text",filename:"buttons",url:"buttons.html#button-with-an-icon-on-the-left-or-right-side-of-the-text"},{title:"Button with fixed width",filename:"buttons",url:"buttons.html#button-with-fixed-width"},{title:"Primary button",filename:"buttons",url:"buttons.html#primary-button"},{title:"Primary button variables",filename:"buttons",url:"buttons.html#primary-button-variables"},{title:"Button with gradient background",filename:"buttons",url:"buttons.html#button-with-gradient-background"},{title:"Button as a link",filename:"buttons",url:"buttons.html#button-as-a-link"},{title:"Button as a link variables",filename:"buttons",url:"buttons.html#button-as-a-link-variables"},{title:"Link as a button",filename:"buttons",url:"buttons.html#link-as-a-button"},{title:"Button reset",filename:"buttons",url:"buttons.html#button-reset"},{title:"Button revert secondary color",filename:"buttons",url:"buttons.html#button-revert-secondary-color"},{title:"Button revert secondary color variables",filename:"buttons",url:"buttons.html#button-revert-secondary-color-variables"},{title:"Button revert secondary size",filename:"buttons",url:"buttons.html#button-revert-secondary-size"},{title:"Button revert secondary size variables",filename:"buttons",url:"buttons.html#button-revert-secondary-size-variables"},{title:"components",filename:"components",url:"components.html"},{title:"Components",filename:"components",url:"components.html#components"},{title:"Components Variables",filename:"components",url:"components.html#components-variables"},{title:"dropdowns",filename:"dropdowns",url:"dropdowns.html"},{title:"Drop-down and split buttons mixins",filename:"dropdowns",url:"dropdowns.html#dropdown-and-split-buttons-mixins"},{title:"Drop-down",filename:"dropdowns",url:"dropdowns.html#dropdown"},{title:"Drop-down variables",filename:"dropdowns",url:"dropdowns.html#dropdown-variables"},{title:"Drop-down with icon customization",filename:"dropdowns",url:"dropdowns.html#dropdown-with-icon-customization"},{title:"Modify dropdown list styles",filename:"dropdowns",url:"dropdowns.html#modify-dropdown-list-styles"},{title:"Split button",filename:"dropdowns",url:"dropdowns.html#split-button"},{title:"Split button variables",filename:"dropdowns",url:"dropdowns.html#split-button-variables"},{title:"Split button - button styling",filename:"dropdowns",url:"dropdowns.html#split-button-button-styling"},{title:"Split button icon customization",filename:"dropdowns",url:"dropdowns.html#split-button-icon-customization"},{title:"Split button drop-down list customization",filename:"dropdowns",url:"dropdowns.html#split-button-dropdown-list-customization"},{title:"forms",filename:"forms",url:"forms.html"},{title:"Forms mixins",filename:"forms",url:"forms.html#forms-mixins"},{title:"Global forms elements customization",filename:"forms",url:"forms.html#global-forms-elements-customization"},{title:"Fieldsets & fields customization",filename:"forms",url:"forms.html#fieldsets-fields-customization"},{title:"Fieldset and legend customization variables",filename:"forms",url:"forms.html#fieldset-and-legend-customization-variables"},{title:"Fields customization variables",filename:"forms",url:"forms.html#fields-customization-variables"},{title:"Required fields message customization variables",filename:"forms",url:"forms.html#required-fields-message-customization-variables"},{title:"Form element inputs customization",filename:"forms",url:"forms.html#form-element-inputs-customization"},{title:"Form element inputs customization variables",filename:"forms",url:"forms.html#form-element-inputs-customization-variables"},{title:"Form element choice",filename:"forms",url:"forms.html#form-element-choice"},{title:"Form element choice variables",filename:"forms",url:"forms.html#form-element-choice-variables"},{title:"Custom color",filename:"forms",url:"forms.html#custom-color"},{title:"Input number - input-text view",filename:"forms",url:"forms.html#input-number-inputtext-view"},{title:"Input search - input-text view",filename:"forms",url:"forms.html#input-search-inputtext-view"},{title:"Form validation",filename:"forms",url:"forms.html#form-validation"},{title:"Form validation variables",filename:"forms",url:"forms.html#form-validation-variables"},{title:"icons",filename:"icons",url:"icons.html"},{title:"Icons",filename:"icons",url:"icons.html#icons"},{title:"Icon with image or sprite",filename:"icons",url:"icons.html#icon-with-image-or-sprite"},{title:"Icon with image or sprite variables",filename:"icons",url:"icons.html#icon-with-image-or-sprite-variables"},{title:"Icon position for an icon with image or sprite",filename:"icons",url:"icons.html#icon-position-for-an-icon-with-image-or-sprite"},{title:"Position for icon with image or sprite mixin variables",filename:"icons",url:"icons.html#position-for-icon-with-image-or-sprite-mixin-variables"},{title:"Icon sprite position (with grid)",filename:"icons",url:"icons.html#icon-sprite-position-with-grid"},{title:"Icon sprite position variables",filename:"icons",url:"icons.html#icon-sprite-position-variables"},{title:"Image/sprite icon size",filename:"icons",url:"icons.html#imagesprite-icon-size"},{title:"Image/sprite icon size variables",filename:"icons",url:"icons.html#imagesprite-icon-size-variables"},{title:"Font icon",filename:"icons",url:"icons.html#font-icon"},{title:"Font icon variables",filename:"icons",url:"icons.html#font-icon-variables"},{title:"Change the size of font icon",filename:"icons",url:"icons.html#change-the-size-of-font-icon"},{title:"Change the size of font icon variables",filename:"icons",url:"icons.html#change-the-size-of-font-icon-variables"},{title:"Hide icon text",filename:"icons",url:"icons.html#hide-icon-text"},{title:"Sprite and font icons for Blank theme",filename:"icons",url:"icons.html#sprite-and-font-icons-for-blank-theme"},{title:"layout",filename:"layout",url:"layout.html"},{title:"Layout",filename:"layout",url:"layout.html#layout"},{title:"Layout global variables",filename:"layout",url:"layout.html#layout-global-variables"},{title:"Page layouts",filename:"layout",url:"layout.html#page-layouts"},{title:"Layout column",filename:"layout",url:"layout.html#layout-column"},{title:"Layout column variables",filename:"layout",url:"layout.html#layout-column-variables"},{title:"Layout width",filename:"layout",url:"layout.html#layout-width"},{title:"Layout width variables",filename:"layout",url:"layout.html#layout-width-variables"},{title:"lib",filename:"lib",url:"lib.html"},{title:"Including Magento UI library to your theme",filename:"lib",url:"lib.html#including-magento-ui-library-to-your-theme"},{title:"loaders",filename:"loaders",url:"loaders.html"},{title:"Loaders",filename:"loaders",url:"loaders.html#loaders"},{title:"Default loader variables",filename:"loaders",url:"loaders.html#default-loader-variables"},{title:"Loading",filename:"loaders",url:"loaders.html#loading"},{title:"Loading default variables",filename:"loaders",url:"loaders.html#loading-default-variables"},{title:"messages",filename:"messages",url:"messages.html"},{title:"Messages",filename:"messages",url:"messages.html#messages"},{title:"Information message",filename:"messages",url:"messages.html#information-message"},{title:"Warning message",filename:"messages",url:"messages.html#warning-message"},{title:"Error message",filename:"messages",url:"messages.html#error-message"},{title:"Success message",filename:"messages",url:"messages.html#success-message"},{title:"Notice message",filename:"messages",url:"messages.html#notice-message"},{title:"Message with inner icon",filename:"messages",url:"messages.html#message-with-inner-icon"},{title:"Message with lateral icon",filename:"messages",url:"messages.html#message-with-lateral-icon"},{title:"Custom message style",filename:"messages",url:"messages.html#custom-message-style"},{title:"Messages global variables",filename:"messages",url:"messages.html#messages-global-variables"},{title:"pages",filename:"pages",url:"pages.html"},{title:"Pagination HTML markup",filename:"pages",url:"pages.html#pagination-html-markup"},{title:"Pagination variables",filename:"pages",url:"pages.html#pagination-variables"},{title:"Pagination with label and gradient background on links",filename:"pages",url:"pages.html#pagination-with-label-and-gradient-background-on-links"},{title:'Pagination with "previous"..."next" text links and label',filename:"pages",url:"pages.html#pagination-with-previousnext-text-links-and-label"},{title:"Pagination without label, with solid background",filename:"pages",url:"pages.html#pagination-without-label-with-solid-background"},{title:"popups",filename:"popups",url:"popups.html"},{title:"Popups",filename:"popups",url:"popups.html#popups"},{title:"Popup variables",filename:"popups",url:"popups.html#popup-variables"},{title:"Window overlay mixin variables",filename:"popups",url:"popups.html#window-overlay-mixin-variables"},{title:"Fixed height popup",filename:"popups",url:"popups.html#fixed-height-popup"},{title:"Fixed content height popup",filename:"popups",url:"popups.html#fixed-content-height-popup"},{title:"Margins for header, content and footer block in popup",filename:"popups",url:"popups.html#margins-for-header-content-and-footer-block-in-popup"},{title:"Popup titles styled as theme headings",filename:"popups",url:"popups.html#popup-titles-styled-as-theme-headings"},{title:"Popup action toolbar",filename:"popups",url:"popups.html#popup-action-toolbar"},{title:"Popup Close button without an icon",filename:"popups",url:"popups.html#popup-close-button-without-an-icon"},{title:"Modify the icon of popup Close button",filename:"popups",url:"popups.html#modify-the-icon-of-popup-close-button"},{title:"Modify overlay styles",filename:"popups",url:"popups.html#modify-overlay-styles"},{title:"rating",filename:"rating",url:"rating.html"},{title:"Ratings",filename:"rating",url:"rating.html#ratings"},{title:"Global rating variables",filename:"rating",url:"rating.html#global-rating-variables"},{title:"Rating with vote",filename:"rating",url:"rating.html#rating-with-vote"},{title:"Rating with vote icons number customization",filename:"rating",url:"rating.html#rating-with-vote-icons-number-customization"},{title:"Rating with vote icons colors customization",filename:"rating",url:"rating.html#rating-with-vote-icons-colors-customization"},{title:"Rating with vote icons symbol customization",filename:"rating",url:"rating.html#rating-with-vote-icons-symbol-customization"},{title:"Accessible rating with vote",filename:"rating",url:"rating.html#accessible-rating-with-vote"},{title:"Rating summary",filename:"rating",url:"rating.html#rating-summary"},{title:"Rating summary icons number customization",filename:"rating",url:"rating.html#rating-summary-icons-number-customization"},{title:"Rating summary icons color customization",filename:"rating",url:"rating.html#rating-summary-icons-color-customization"},{title:"Rating summary icons symbol customization",filename:"rating",url:"rating.html#rating-summary-icons-symbol-customization"},{title:"Rating summary hide label",filename:"rating",url:"rating.html#rating-summary-hide-label"},{title:"Rating summary multiple ratings",filename:"rating",url:"rating.html#rating-summary-multiple-ratings"},{title:"Rating hide label mixin",filename:"rating",url:"rating.html#rating-hide-label-mixin"},{title:"resets",filename:"resets",url:"resets.html"},{title:"Resets",filename:"resets",url:"resets.html#resets"},{title:"responsive",filename:"responsive",url:"responsive.html"},{title:"Responsive",filename:"responsive",url:"responsive.html#responsive"},{title:"Responsive mixins usage",filename:"responsive",url:"responsive.html#responsive-mixins-usage"},{title:"Media query style groups separation variables",filename:"responsive",url:"responsive.html#media-query-style-groups-separation-variables"},{title:"Responsive breakpoints",filename:"responsive",url:"responsive.html#responsive-breakpoints"},{title:"sections",filename:"sections",url:"sections.html"},{title:"Tabs and accordions",filename:"sections",url:"sections.html#tabs-and-accordions"},{title:"Tabs",filename:"sections",url:"sections.html#tabs"},{title:"Tabs mixin variables",filename:"sections",url:"sections.html#tabs-mixin-variables"},{title:"Tabs with content top border",filename:"sections",url:"sections.html#tabs-with-content-top-border"},{title:"Accordion",filename:"sections",url:"sections.html#accordion"},{title:"Accordion mixin variables",filename:"sections",url:"sections.html#accordion-mixin-variables"},{title:"Responsive tabs",filename:"sections",url:"sections.html#responsive-tabs"},{title:"Tabs Base",filename:"sections",url:"sections.html#tabs-base"},{title:"Accordion Base",filename:"sections",url:"sections.html#accordion-base"},{title:"tables",filename:"tables",url:"tables.html"},{title:"Tables",filename:"tables",url:"tables.html#tables"},{title:"Table mixin variables",filename:"tables",url:"tables.html#table-mixin-variables"},{title:"Table typography",filename:"tables",url:"tables.html#table-typography"},{title:"Table typography mixin variables",filename:"tables",url:"tables.html#table-typography-mixin-variables"},{title:"Table caption",filename:"tables",url:"tables.html#table-caption"},{title:"Table caption mixin variables",filename:"tables",url:"tables.html#table-caption-mixin-variables"},{title:"Table cells resize",filename:"tables",url:"tables.html#table-cells-resize"},{title:"Table cells resize variables",filename:"tables",url:"tables.html#table-cells-resize-variables"},{title:"Table background customization",filename:"tables",url:"tables.html#table-background-customization"},{title:"Table background mixin variables",filename:"tables",url:"tables.html#table-background-mixin-variables"},{title:"Table borders customization",filename:"tables",url:"tables.html#table-borders-customization"},{title:"Table borders mixin variables",filename:"tables",url:"tables.html#table-borders-mixin-variables"},{title:"Table with horizontal borders",filename:"tables",url:"tables.html#table-with-horizontal-borders"},{title:"Table with vertical borders",filename:"tables",url:"tables.html#table-with-vertical-borders"},{title:"Table with light borders",filename:"tables",url:"tables.html#table-with-light-borders"},{title:"Table without borders",filename:"tables",url:"tables.html#table-without-borders"},{title:"Striped table",filename:"tables",url:"tables.html#striped-table"},{title:"Striped table mixin variables",filename:"tables",url:"tables.html#striped-table-mixin-variables"},{title:"Table with rows hover",filename:"tables",url:"tables.html#table-with-rows-hover"},{title:"Table with rows hover mixin variables",filename:"tables",url:"tables.html#table-with-rows-hover-mixin-variables"},{title:"Responsive table technics #1",filename:"tables",url:"tables.html#responsive-table-technics-1"},{title:"Responsive table technics #2",filename:"tables",url:"tables.html#responsive-table-technics-2"},{title:"Responsive table technics #2 mixin variables",filename:"tables",url:"tables.html#responsive-table-technics-2-mixin-variables"},{title:"tooltips",filename:"tooltips",url:"tooltips.html"},{title:"Tooltips",filename:"tooltips",url:"tooltips.html#tooltips"},{title:"Tooltips variables",filename:"tooltips",url:"tooltips.html#tooltips-variables"},{title:"typography",filename:"typography",url:"typography.html"},{title:"Typogrphy",filename:"typography",url:"typography.html#typogrphy"},{title:"Typography variables",filename:"typography",url:"typography.html#typography-variables"},{title:"Font-size mixin",filename:"typography",url:"typography.html#fontsize-mixin"},{title:"Line-height mixin",filename:"typography",url:"typography.html#lineheight-mixin"},{title:"Word breaking mixin",filename:"typography",url:"typography.html#word-breaking-mixin"},{title:"Font face mixin",filename:"typography",url:"typography.html#font-face-mixin"},{title:"Text overflow mixin",filename:"typography",url:"typography.html#text-overflow-mixin"},{title:"Text hide",filename:"typography",url:"typography.html#text-hide"},{title:"Hyphens",filename:"typography",url:"typography.html#hyphens"},{title:"Font style and color",filename:"typography",url:"typography.html#font-style-and-color"},{title:"Font style mixin variables",filename:"typography",url:"typography.html#font-style-mixin-variables"},{title:"Reset list styles",filename:"typography",url:"typography.html#reset-list-styles"},{title:"Reset list styles variables",filename:"typography",url:"typography.html#reset-list-styles-variables"},{title:"Inline-block list item styling",filename:"typography",url:"typography.html#inlineblock-list-item-styling"},{title:"Link styling mixin",filename:"typography",url:"typography.html#link-styling-mixin"},{title:"Link styling mixin variables",filename:"typography",url:"typography.html#link-styling-mixin-variables"},{title:"Heading styling mixin",filename:"typography",url:"typography.html#heading-styling-mixin"},{title:"Base typography mixins",filename:"typography",url:"typography.html#base-typography-mixins"},{title:"Base typography mixin variables",filename:"typography",url:"typography.html#base-typography-mixin-variables"},{title:"Headings typography mixin",filename:"typography",url:"typography.html#headings-typography-mixin"},{title:"Headings typography mixin variables",filename:"typography",url:"typography.html#headings-typography-mixin-variables"},{title:"Typography links mixin",filename:"typography",url:"typography.html#typography-links-mixin"},{title:"Typography lists mixin",filename:"typography",url:"typography.html#typography-lists-mixin"},{title:"Typography lists mixin variables",filename:"typography",url:"typography.html#typography-lists-mixin-variables"},{title:"Typography code elements mixin",filename:"typography",url:"typography.html#typography-code-elements-mixin"},{title:"Typography code mixin variables",filename:"typography",url:"typography.html#typography-code-mixin-variables"},{title:"Typography blockquote",filename:"typography",url:"typography.html#typography-blockquote"},{title:"Typography blockquote mixin variables",filename:"typography",url:"typography.html#typography-blockquote-mixin-variables"},{title:"utilities",filename:"utilities",url:"utilities.html"},{title:"Utilities",filename:"utilities",url:"utilities.html#utilities"},{title:".lib-clearfix()",filename:"utilities",url:"utilities.html#libclearfix"},{title:".lib-visibility-hidden()",filename:"utilities",url:"utilities.html#libvisibilityhidden"},{title:".lib-visually-hidden()",filename:"utilities",url:"utilities.html#libvisuallyhidden"},{title:".lib-visually-hidden-reset()",filename:"utilities",url:"utilities.html#libvisuallyhiddenreset"},{title:".lib-css()",filename:"utilities",url:"utilities.html#libcss"},{title:".lib-css() variables",filename:"utilities",url:"utilities.html#libcss-variables"},{title:".lib-rotate()",filename:"utilities",url:"utilities.html#librotate"},{title:".lib-rotate() variables",filename:"utilities",url:"utilities.html#librotate-variables"},{title:".lib-input-placeholder()",filename:"utilities",url:"utilities.html#libinputplaceholder"},{title:".lib-input-placeholder() variables",filename:"utilities",url:"utilities.html#libinputplaceholder-variables"},{title:".lib-background-gradient()",filename:"utilities",url:"utilities.html#libbackgroundgradient"},{title:".lib-background-gradient() variables",filename:"utilities",url:"utilities.html#libbackgroundgradient-variables"},{title:".lib-url-check()",filename:"utilities",url:"utilities.html#liburlcheck"},{title:".lib-url-check() variables",filename:"utilities",url:"utilities.html#liburlcheck-variables"},{title:"variables",filename:"variables",url:"variables.html"},{title:"List of Global Variables",filename:"variables",url:"variables.html#list-of-global-variables"},{title:"Table with rows hover mixin variables",filename:"variables",url:"variables.html#table-with-rows-hover-mixin-variables"},{title:"docs",filename:"docs",url:"docs.html"},{title:"Documentation",filename:"docs",url:"docs.html#documentation"}];(function(){"use strict";var b=function(a,b){return Array.prototype.indexOf.call(a,b)!==-1},c=function(a,b){return Array.prototype.filter.call(a,b)},d=function(a,b){return Array.prototype.forEach.call(a,b)},e=document.getElementsByTagName("body")[0];e.addEventListener("click",function(a){var b=a.target;b.tagName.toLowerCase()==="svg"&&(b=b.parentNode);var c=!1;b.dataset.toggle!=null&&(a.preventDefault(),b.classList.contains("is-active")||(c=!0)),d(e.querySelectorAll("[data-toggle]"),function(a){a.classList.remove("is-active"),document.getElementById(a.dataset.toggle).hidden=!0}),c&&(b.classList.add("is-active"),document.getElementById(b.dataset.toggle).hidden=!1)}),function(){var f=e.getElementsByClassName("nav")[0];if(!f)return;var g=document.createElement("ul");g.className="nav-results",g.id="nav-search",g.hidden=!0,d(a,function(a){var b,c,d;b=document.createElement("li"),b._title=a.title.toLowerCase(),b.hidden=!0,b.appendChild(c=document.createElement("a")),c.href=a.url,c.innerHTML=a.title,c.appendChild(d=document.createElement("span")),d.innerHTML=a.filename,d.className="nav-results-filename",g.appendChild(b)}),f.appendChild(g);var h=g.children,i=function(a){d(h,function(a){a.hidden=!0});var b=this.value.toLowerCase(),e=[];b!==""&&(e=c(h,function(a){return a._title.indexOf(b)!==-1})),e.length>0?(d(e,function(a){a.hidden=!1}),g.hidden=!1):g.hidden=!0},j=f.querySelector('input[type="search"]');j.addEventListener("keyup",i),j.addEventListener("focus",i),e.addEventListener("click",function(a){if(a.target.classList&&a.target.classList.contains("search"))return;g.hidden=!0}),g.addEventListener("click",function(a){j.value=""});var k=document.createElement("ul");k.id="nav-toc",k.hidden=!0,k.className="nav-results toc-list",c(e.getElementsByTagName("*"),function(a){return b(["h1","h2","h3"],a.tagName.toLowerCase())}).map(function(a){var b=document.createElement("li"),c=document.createElement("a"),d=a.tagName.toLowerCase()[1];c.classList.add("level-"+d),b.appendChild(c),c.href="#"+a.id,c.innerHTML=a.innerHTML,k.appendChild(b)}),f.appendChild(k)}()})(),function(){"use strict";if(location.hash==="#__preview__"||location.protocol==="data:")return;var a=function(a,b){return Array.prototype.forEach.call(a,b)},b=function(a,b){var e=Array.prototype.slice.call(arguments,2);return d(a,function(a){return(c(b)?b||a:a[b]).apply(a,e)})},c=function(a){return Object.prototype.toString.call(a)==="[object Function]"},d=function(a,b){return Array.prototype.map.call(a,b)},e=function(a,b){return d(a,function(a){return a[b]})},f=function(a){var b={},c=a.split(";");for(var d=0;c.length>d;d++){var e=c[d].trim().split("=");b[e[0]]=e[1]}return b},g=function(a,c){return b(e(a,"classList"),"remove",c)},h=function(a,b){a.contentDocument.defaultView.postMessage(b,"*")},i=document.getElementsByTagName("head")[0],j=document.getElementsByTagName("body")[0],k=e(i.querySelectorAll('style[type="text/preview"]'),"innerHTML").join(""),l=e(i.querySelectorAll('script[type="text/preview"]'),"innerHTML").join(""),m=location.href.split("#")[0]+"#__preview__",n=document.createElement("iframe");n.src="data:text/html,",j.appendChild(n),n.addEventListener("load",function(){var b={sameOriginDataUri:!0};try{this.contentDocument,this.contentDocument||(b.sameOriginDataUri=!1)}catch(c){b.sameOriginDataUri=!1}this.parentNode.removeChild(this),a(j.getElementsByTagName("textarea"),function(a,c){o(a,b,c),q(),p(a)})});var o=function(a,b,c){var d,e,f;d=document.createElement("div"),d.appendChild(e=document.createElement("div")),d.className="preview",e.appendChild(f=document.createElement("iframe")),e.className="resizeable",f.setAttribute("scrolling","no"),f.name="iframe"+c++,f.addEventListener("load",function(){var c,d,e,f,g,i,j;j=this.contentDocument;if(!b.sameOriginDataUri&&this.src!==m)return;this.src===m&&(c=j.createElement("html"),c.appendChild(j.createElement("head")),c.appendChild(d=j.createElement("body")),d.innerHTML=a.textContent,j.replaceChild(c,j.documentElement)),g=j.createElement("head"),g.appendChild(f=j.createElement("style")),g.appendChild(e=j.createElement("script")),e.textContent=l,f.textContent=k,i=j.getElementsByTagName("head")[0],i.parentNode.replaceChild(g,i),h(this,"getHeight")});var g;b.sameOriginDataUri?g="data:text/html;charset=utf-8,"+encodeURIComponent("<!doctype html><html><head></head></body>"+a.textContent):g=m,f.setAttribute("src",g);var i=function(){f.contentDocument.body.innerHTML=this.value,h(f,"getHeight")};a.addEventListener("keypress",i),a.addEventListener("keyup",i),a.parentNode.insertBefore(d,a)},p=function(a){var b=document.createElement("div");b.className="preview-code",b.style.position="absolute",b.style.left="-9999px",j.appendChild(b);var c=parseInt(window.getComputedStyle(a).getPropertyValue("max-height"),10),d=function(a){b.textContent=this.value+"\n";var d=b.offsetHeight+2;d>=c?this.style.overflow="auto":this.style.overflow="hidden",this.style.height=b.offsetHeight+2+"px"};a.addEventListener("keypress",d),a.addEventListener("keyup",d),d.call(a)},q=function(){var b=j.getElementsByClassName("settings")[0],c=j.getElementsByClassName("resizeable"),d=30,e=function(b){document.cookie="preview-width="+b,a(c,function(a){b==="auto"&&(b=a.parentNode.offsetWidth),a.style.width=b+"px",h(a.getElementsByTagName("iframe")[0],"getHeight")})},i=f(document.cookie)["preview-width"];if(i){e(i),g(b.getElementsByClassName("is-active"),"is-active");var k=b.querySelector('button[data-width="'+i+'"]');k&&k.classList.add("is-active")}window.addEventListener("message",function(a){if(a.data==null||!a.source)return;var b=a.data,c=document.getElementsByName(a.source.name)[0];b.height!=null&&c&&(c.parentNode.style.height=b.height+d+"px")},!1),b&&c.length>0&&(b.hidden=!1,b.addEventListener("click",function(a){var c=a.target.tagName.toLowerCase(),d;if(c==="button")d=a.target;else{if(c!=="svg")return;d=a.target.parentNode}a.preventDefault(),g(b.getElementsByClassName("is-active"),"is-active"),d.classList.add("is-active");var f=d.dataset.width;e(f)}))}}()})()</script></body></html><!-- Generated with StyleDocco (http://jacobrask.github.com/styledocco). --> +</div></article></section><div class="bar bottom"><div hidden class="settings container"><!-- Icons from http://iconmonstr.com--><button title="Desktop (1280)" data-width='1280'><svg viewBox="0 0 412 386" height="24" width="26" class="icon"><path d="m147.6,343.9c-4.5,15.9-26.2,37.6-42.1,42.1h201c-15.3,-4-38.1,-26.8-42.1,-42.1H147.6zM387,0.5H25c-13.8,0-25,11.2-25,25V294c0,13.8 11.2,25 25,25h362c13.8,0 25,-11.2 25,-25V25.5C412,11.7 400.8,0.5 387,0.5zM369.9,238.2H42.1L42.1,42.6 369.9,42.6V238.2z"></path></svg></button><button title="Laptop (1024)" data-width='1024'><svg viewBox="0 0 384 312" height="23" width="28" class="icon"><path d="m349.2,20.5c0,-11-9,-20-20,-20H53.6c-11,0-20,9-20,20v194H349.2v-194zm-27,167H60.6V27.5H322.2v160zm28,42H32.6L2.6,282.1c-3.5,6.2-3.5,13.8 0.1,19.9 3.6,6.2 10.2,9.9 17.3,9.9H363.1c7.1,0 13.7,-3.8 17.3,-10 3.6,-6.2 3.6,-13.8 0,-20l-30.2,-52.5zm-196.9,54 8,-23.5h60.5l8,23.5h-76.5z"></path></svg></button><button title="Tablet (768)" data-width='768'><svg viewBox="0 0 317 412" height="24" width="18" class="icon"><path d="M 316.5,380 V 32 c 0,-17.7 -14.3,-32 -32,-32 H 32 C 14.3,0 0,14.3 0,32 v 348 c 0,17.7 14.3,32 32,32 h 252.5 c 17.7,0 32,-14.3 32,-32 z M 40,367 V 45 H 276.5 V 367 H 40 z m 109.8,22.7 c 0,-4.7 3.8,-8.5 8.5,-8.5 4.7,0 8.5,3.8 8.5,8.5 0,4.7 -3.8,8.5 -8.5,8.5 -4.7,0 -8.5,-3.8 -8.5,-8.5 z"></path></svg></button><button title="Smart phone (320)" data-width='320'><svg viewBox="0 0 224 412" height="24" width="13" class="icon"><path d="M 190.7,0 H 33 C 14.8,0 0,14.8 0,33 v 346 c 0,18.2 14.8,33 33,33 h 157.7 c 18.2,0 33,-14.8 33,-33 V 33 c 0,-18.2 -14.8,-33 -33,-33 z M 94.3,30.2 h 37 c 2.2,0 4,1.8 4,4 0,2.2 -1.8,4 -4,4 h -37 c -2.2,0 -4,-1.8 -4,-4 0,-2.2 1.8,-4 4,-4 z m 18.5,362.8 c -8.8,0 -16,-7.2 -16,-16 0,-8.8 7.2,-16 16,-16 8.8,0 16,7.2 16,16 0,8.8 -7.2,16 -16,16 z M 198.6,343.8 H 25.1 V 68.2 h 173.5 v 275.5 z"></path></svg></button><button title="Feature phone (240)" data-width='240'><svg viewBox="0 0 201 412" height="24" width="12" class="icon"><path d="M 165.5,0.2 V 45 H 25 c -13.8,0 -25,11.2 -25,25 V 387 c 0,13.8 11.2,25 25,25 h 150.5 c 13.8,0 25,-11.2 25,-25 V 0.2 h -35 z M 65.2,366.5 H 34.2 v -24.5 h 31 v 24.5 z m 0,-44.3 H 34.2 v -24.5 h 31 v 24.5 z m 50.5,44.3 H 84.7 v -24.5 h 31 v 24.5 z m 0,-44.3 H 84.7 v -24.5 h 31 v 24.5 z m 50.5,44.3 h -31 v -24.5 h 31 v 24.5 z m 0,-44.3 h -31 v -24.5 h 31 v 24.5 z m 0,-59.3 h -132 V 95.4 h 132 V 262.9 z"></path></svg></button><button title="Auto (100%)" data-width="auto" class="auto is-active">Auto</button></div></div><script>(function(){var a=[{title:"actions-toolbar",filename:"actions-toolbar",url:"actions-toolbar.html"},{title:"Actions toolbar",filename:"actions-toolbar",url:"actions-toolbar.html#actions-toolbar"},{title:"Actions toolbar mixin variables",filename:"actions-toolbar",url:"actions-toolbar.html#actions-toolbar-mixin-variables"},{title:"Actions toolbar alignment",filename:"actions-toolbar",url:"actions-toolbar.html#actions-toolbar-alignment"},{title:"Reverse primary and secondary blocks",filename:"actions-toolbar",url:"actions-toolbar.html#reverse-primary-and-secondary-blocks"},{title:"Actions toolbar indents customizations",filename:"actions-toolbar",url:"actions-toolbar.html#actions-toolbar-indents-customizations"},{title:"Responsive actions toolbar",filename:"actions-toolbar",url:"actions-toolbar.html#responsive-actions-toolbar"},{title:"breadcrumbs",filename:"breadcrumbs",url:"breadcrumbs.html"},{title:"Breadcrumbs",filename:"breadcrumbs",url:"breadcrumbs.html#breadcrumbs"},{title:"Breadcrumbs variables",filename:"breadcrumbs",url:"breadcrumbs.html#breadcrumbs-variables"},{title:"Button-styled breadcrumbs with gradient background, border, and no separating symbol",filename:"breadcrumbs",url:"breadcrumbs.html#buttonstyled-breadcrumbs-with-gradient-background-border-and-no-separating-symbol"},{title:"Breadcrumbs with solid background",filename:"breadcrumbs",url:"breadcrumbs.html#breadcrumbs-with-solid-background"},{title:"buttons",filename:"buttons",url:"buttons.html"},{title:"Default button",filename:"buttons",url:"buttons.html#default-button"},{title:"Button variables",filename:"buttons",url:"buttons.html#button-variables"},{title:"Button as an icon",filename:"buttons",url:"buttons.html#button-as-an-icon"},{title:"Button with an icon on the left or right side of the text",filename:"buttons",url:"buttons.html#button-with-an-icon-on-the-left-or-right-side-of-the-text"},{title:"Button with fixed width",filename:"buttons",url:"buttons.html#button-with-fixed-width"},{title:"Primary button",filename:"buttons",url:"buttons.html#primary-button"},{title:"Primary button variables",filename:"buttons",url:"buttons.html#primary-button-variables"},{title:"Button with gradient background",filename:"buttons",url:"buttons.html#button-with-gradient-background"},{title:"Button as a link",filename:"buttons",url:"buttons.html#button-as-a-link"},{title:"Button as a link variables",filename:"buttons",url:"buttons.html#button-as-a-link-variables"},{title:"Link as a button",filename:"buttons",url:"buttons.html#link-as-a-button"},{title:"Button reset",filename:"buttons",url:"buttons.html#button-reset"},{title:"Button revert secondary color",filename:"buttons",url:"buttons.html#button-revert-secondary-color"},{title:"Button revert secondary color variables",filename:"buttons",url:"buttons.html#button-revert-secondary-color-variables"},{title:"Button revert secondary size",filename:"buttons",url:"buttons.html#button-revert-secondary-size"},{title:"Button revert secondary size variables",filename:"buttons",url:"buttons.html#button-revert-secondary-size-variables"},{title:"components",filename:"components",url:"components.html"},{title:"Components",filename:"components",url:"components.html#components"},{title:"Components Variables",filename:"components",url:"components.html#components-variables"},{title:"dropdowns",filename:"dropdowns",url:"dropdowns.html"},{title:"Drop-down and split buttons mixins",filename:"dropdowns",url:"dropdowns.html#dropdown-and-split-buttons-mixins"},{title:"Drop-down",filename:"dropdowns",url:"dropdowns.html#dropdown"},{title:"Drop-down variables",filename:"dropdowns",url:"dropdowns.html#dropdown-variables"},{title:"Drop-down with icon customization",filename:"dropdowns",url:"dropdowns.html#dropdown-with-icon-customization"},{title:"Modify dropdown list styles",filename:"dropdowns",url:"dropdowns.html#modify-dropdown-list-styles"},{title:"Split button",filename:"dropdowns",url:"dropdowns.html#split-button"},{title:"Split button variables",filename:"dropdowns",url:"dropdowns.html#split-button-variables"},{title:"Split button - button styling",filename:"dropdowns",url:"dropdowns.html#split-button-button-styling"},{title:"Split button icon customization",filename:"dropdowns",url:"dropdowns.html#split-button-icon-customization"},{title:"Split button drop-down list customization",filename:"dropdowns",url:"dropdowns.html#split-button-dropdown-list-customization"},{title:"forms",filename:"forms",url:"forms.html"},{title:"Forms mixins",filename:"forms",url:"forms.html#forms-mixins"},{title:"Global forms elements customization",filename:"forms",url:"forms.html#global-forms-elements-customization"},{title:"Fieldsets & fields customization",filename:"forms",url:"forms.html#fieldsets-fields-customization"},{title:"Fieldset and legend customization variables",filename:"forms",url:"forms.html#fieldset-and-legend-customization-variables"},{title:"Fields customization variables",filename:"forms",url:"forms.html#fields-customization-variables"},{title:"Required fields message customization variables",filename:"forms",url:"forms.html#required-fields-message-customization-variables"},{title:"Form element inputs customization",filename:"forms",url:"forms.html#form-element-inputs-customization"},{title:"Form element inputs customization variables",filename:"forms",url:"forms.html#form-element-inputs-customization-variables"},{title:"Form element choice",filename:"forms",url:"forms.html#form-element-choice"},{title:"Form element choice variables",filename:"forms",url:"forms.html#form-element-choice-variables"},{title:"Custom color",filename:"forms",url:"forms.html#custom-color"},{title:"Input number - input-text view",filename:"forms",url:"forms.html#input-number-inputtext-view"},{title:"Input search - input-text view",filename:"forms",url:"forms.html#input-search-inputtext-view"},{title:"Form validation",filename:"forms",url:"forms.html#form-validation"},{title:"Form validation variables",filename:"forms",url:"forms.html#form-validation-variables"},{title:"icons",filename:"icons",url:"icons.html"},{title:"Icons",filename:"icons",url:"icons.html#icons"},{title:"Icon with image or sprite",filename:"icons",url:"icons.html#icon-with-image-or-sprite"},{title:"Icon with image or sprite variables",filename:"icons",url:"icons.html#icon-with-image-or-sprite-variables"},{title:"Icon position for an icon with image or sprite",filename:"icons",url:"icons.html#icon-position-for-an-icon-with-image-or-sprite"},{title:"Position for icon with image or sprite mixin variables",filename:"icons",url:"icons.html#position-for-icon-with-image-or-sprite-mixin-variables"},{title:"Icon sprite position (with grid)",filename:"icons",url:"icons.html#icon-sprite-position-with-grid"},{title:"Icon sprite position variables",filename:"icons",url:"icons.html#icon-sprite-position-variables"},{title:"Image/sprite icon size",filename:"icons",url:"icons.html#imagesprite-icon-size"},{title:"Image/sprite icon size variables",filename:"icons",url:"icons.html#imagesprite-icon-size-variables"},{title:"Font icon",filename:"icons",url:"icons.html#font-icon"},{title:"Font icon variables",filename:"icons",url:"icons.html#font-icon-variables"},{title:"Change the size of font icon",filename:"icons",url:"icons.html#change-the-size-of-font-icon"},{title:"Change the size of font icon variables",filename:"icons",url:"icons.html#change-the-size-of-font-icon-variables"},{title:"Hide icon text",filename:"icons",url:"icons.html#hide-icon-text"},{title:"Sprite and font icons for Blank theme",filename:"icons",url:"icons.html#sprite-and-font-icons-for-blank-theme"},{title:"layout",filename:"layout",url:"layout.html"},{title:"Layout",filename:"layout",url:"layout.html#layout"},{title:"Layout global variables",filename:"layout",url:"layout.html#layout-global-variables"},{title:"Page layouts",filename:"layout",url:"layout.html#page-layouts"},{title:"Layout column",filename:"layout",url:"layout.html#layout-column"},{title:"Layout column variables",filename:"layout",url:"layout.html#layout-column-variables"},{title:"Layout width",filename:"layout",url:"layout.html#layout-width"},{title:"Layout width variables",filename:"layout",url:"layout.html#layout-width-variables"},{title:"lib",filename:"lib",url:"lib.html"},{title:"Including Magento UI library to your theme",filename:"lib",url:"lib.html#including-magento-ui-library-to-your-theme"},{title:"loaders",filename:"loaders",url:"loaders.html"},{title:"Loaders",filename:"loaders",url:"loaders.html#loaders"},{title:"Default loader variables",filename:"loaders",url:"loaders.html#default-loader-variables"},{title:"Loading",filename:"loaders",url:"loaders.html#loading"},{title:"Loading default variables",filename:"loaders",url:"loaders.html#loading-default-variables"},{title:"messages",filename:"messages",url:"messages.html"},{title:"Messages",filename:"messages",url:"messages.html#messages"},{title:"Information message",filename:"messages",url:"messages.html#information-message"},{title:"Warning message",filename:"messages",url:"messages.html#warning-message"},{title:"Error message",filename:"messages",url:"messages.html#error-message"},{title:"Success message",filename:"messages",url:"messages.html#success-message"},{title:"Notice message",filename:"messages",url:"messages.html#notice-message"},{title:"Message with inner icon",filename:"messages",url:"messages.html#message-with-inner-icon"},{title:"Message with lateral icon",filename:"messages",url:"messages.html#message-with-lateral-icon"},{title:"Custom message style",filename:"messages",url:"messages.html#custom-message-style"},{title:"Messages global variables",filename:"messages",url:"messages.html#messages-global-variables"},{title:"pages",filename:"pages",url:"pages.html"},{title:"Pagination HTML markup",filename:"pages",url:"pages.html#pagination-html-markup"},{title:"Pagination variables",filename:"pages",url:"pages.html#pagination-variables"},{title:"Pagination with label and gradient background on links",filename:"pages",url:"pages.html#pagination-with-label-and-gradient-background-on-links"},{title:'Pagination with "previous"..."next" text links and label',filename:"pages",url:"pages.html#pagination-with-previousnext-text-links-and-label"},{title:"Pagination without label, with solid background",filename:"pages",url:"pages.html#pagination-without-label-with-solid-background"},{title:"popups",filename:"popups",url:"popups.html"},{title:"Popups",filename:"popups",url:"popups.html#popups"},{title:"Popup variables",filename:"popups",url:"popups.html#popup-variables"},{title:"Window overlay mixin variables",filename:"popups",url:"popups.html#window-overlay-mixin-variables"},{title:"Fixed height popup",filename:"popups",url:"popups.html#fixed-height-popup"},{title:"Fixed content height popup",filename:"popups",url:"popups.html#fixed-content-height-popup"},{title:"Margins for header, content and footer block in popup",filename:"popups",url:"popups.html#margins-for-header-content-and-footer-block-in-popup"},{title:"Popup titles styled as theme headings",filename:"popups",url:"popups.html#popup-titles-styled-as-theme-headings"},{title:"Popup action toolbar",filename:"popups",url:"popups.html#popup-action-toolbar"},{title:"Popup Close button without an icon",filename:"popups",url:"popups.html#popup-close-button-without-an-icon"},{title:"Modify the icon of popup Close button",filename:"popups",url:"popups.html#modify-the-icon-of-popup-close-button"},{title:"Modify overlay styles",filename:"popups",url:"popups.html#modify-overlay-styles"},{title:"rating",filename:"rating",url:"rating.html"},{title:"Ratings",filename:"rating",url:"rating.html#ratings"},{title:"Global rating variables",filename:"rating",url:"rating.html#global-rating-variables"},{title:"Rating with vote",filename:"rating",url:"rating.html#rating-with-vote"},{title:"Rating with vote icons number customization",filename:"rating",url:"rating.html#rating-with-vote-icons-number-customization"},{title:"Rating with vote icons colors customization",filename:"rating",url:"rating.html#rating-with-vote-icons-colors-customization"},{title:"Rating with vote icons symbol customization",filename:"rating",url:"rating.html#rating-with-vote-icons-symbol-customization"},{title:"Accessible rating with vote",filename:"rating",url:"rating.html#accessible-rating-with-vote"},{title:"Rating summary",filename:"rating",url:"rating.html#rating-summary"},{title:"Rating summary icons number customization",filename:"rating",url:"rating.html#rating-summary-icons-number-customization"},{title:"Rating summary icons color customization",filename:"rating",url:"rating.html#rating-summary-icons-color-customization"},{title:"Rating summary icons symbol customization",filename:"rating",url:"rating.html#rating-summary-icons-symbol-customization"},{title:"Rating summary hide label",filename:"rating",url:"rating.html#rating-summary-hide-label"},{title:"Rating summary multiple ratings",filename:"rating",url:"rating.html#rating-summary-multiple-ratings"},{title:"Rating hide label mixin",filename:"rating",url:"rating.html#rating-hide-label-mixin"},{title:"resets",filename:"resets",url:"resets.html"},{title:"Resets",filename:"resets",url:"resets.html#resets"},{title:"responsive",filename:"responsive",url:"responsive.html"},{title:"Responsive",filename:"responsive",url:"responsive.html#responsive"},{title:"Responsive mixins usage",filename:"responsive",url:"responsive.html#responsive-mixins-usage"},{title:"Media query style groups separation variables",filename:"responsive",url:"responsive.html#media-query-style-groups-separation-variables"},{title:"Responsive breakpoints",filename:"responsive",url:"responsive.html#responsive-breakpoints"},{title:"sections",filename:"sections",url:"sections.html"},{title:"Tabs and accordions",filename:"sections",url:"sections.html#tabs-and-accordions"},{title:"Tabs",filename:"sections",url:"sections.html#tabs"},{title:"Tabs mixin variables",filename:"sections",url:"sections.html#tabs-mixin-variables"},{title:"Tabs with content top border",filename:"sections",url:"sections.html#tabs-with-content-top-border"},{title:"Accordion",filename:"sections",url:"sections.html#accordion"},{title:"Accordion mixin variables",filename:"sections",url:"sections.html#accordion-mixin-variables"},{title:"Responsive tabs",filename:"sections",url:"sections.html#responsive-tabs"},{title:"Tabs Base",filename:"sections",url:"sections.html#tabs-base"},{title:"Accordion Base",filename:"sections",url:"sections.html#accordion-base"},{title:"tables",filename:"tables",url:"tables.html"},{title:"Tables",filename:"tables",url:"tables.html#tables"},{title:"Table mixin variables",filename:"tables",url:"tables.html#table-mixin-variables"},{title:"Table typography",filename:"tables",url:"tables.html#table-typography"},{title:"Table typography mixin variables",filename:"tables",url:"tables.html#table-typography-mixin-variables"},{title:"Table caption",filename:"tables",url:"tables.html#table-caption"},{title:"Table caption mixin variables",filename:"tables",url:"tables.html#table-caption-mixin-variables"},{title:"Table cells resize",filename:"tables",url:"tables.html#table-cells-resize"},{title:"Table cells resize variables",filename:"tables",url:"tables.html#table-cells-resize-variables"},{title:"Table background customization",filename:"tables",url:"tables.html#table-background-customization"},{title:"Table background mixin variables",filename:"tables",url:"tables.html#table-background-mixin-variables"},{title:"Table borders customization",filename:"tables",url:"tables.html#table-borders-customization"},{title:"Table borders mixin variables",filename:"tables",url:"tables.html#table-borders-mixin-variables"},{title:"Table with horizontal borders",filename:"tables",url:"tables.html#table-with-horizontal-borders"},{title:"Table with vertical borders",filename:"tables",url:"tables.html#table-with-vertical-borders"},{title:"Table with light borders",filename:"tables",url:"tables.html#table-with-light-borders"},{title:"Table without borders",filename:"tables",url:"tables.html#table-without-borders"},{title:"Striped table",filename:"tables",url:"tables.html#striped-table"},{title:"Striped table mixin variables",filename:"tables",url:"tables.html#striped-table-mixin-variables"},{title:"Table with rows hover",filename:"tables",url:"tables.html#table-with-rows-hover"},{title:"Table with rows hover mixin variables",filename:"tables",url:"tables.html#table-with-rows-hover-mixin-variables"},{title:"Responsive table technics #1",filename:"tables",url:"tables.html#responsive-table-technics-1"},{title:"Responsive table technics #2",filename:"tables",url:"tables.html#responsive-table-technics-2"},{title:"Responsive table technics #2 mixin variables",filename:"tables",url:"tables.html#responsive-table-technics-2-mixin-variables"},{title:"tooltips",filename:"tooltips",url:"tooltips.html"},{title:"Tooltips",filename:"tooltips",url:"tooltips.html#tooltips"},{title:"Tooltips variables",filename:"tooltips",url:"tooltips.html#tooltips-variables"},{title:"typography",filename:"typography",url:"typography.html"},{title:"Typogrphy",filename:"typography",url:"typography.html#typogrphy"},{title:"Typography variables",filename:"typography",url:"typography.html#typography-variables"},{title:"Font-size mixin",filename:"typography",url:"typography.html#fontsize-mixin"},{title:"Line-height mixin",filename:"typography",url:"typography.html#lineheight-mixin"},{title:"Word breaking mixin",filename:"typography",url:"typography.html#word-breaking-mixin"},{title:"Font face mixin",filename:"typography",url:"typography.html#font-face-mixin"},{title:"Text overflow mixin",filename:"typography",url:"typography.html#text-overflow-mixin"},{title:"Text hide",filename:"typography",url:"typography.html#text-hide"},{title:"Hyphens",filename:"typography",url:"typography.html#hyphens"},{title:"Font style and color",filename:"typography",url:"typography.html#font-style-and-color"},{title:"Font style mixin variables",filename:"typography",url:"typography.html#font-style-mixin-variables"},{title:"Reset list styles",filename:"typography",url:"typography.html#reset-list-styles"},{title:"Reset list styles variables",filename:"typography",url:"typography.html#reset-list-styles-variables"},{title:"Inline-block list item styling",filename:"typography",url:"typography.html#inlineblock-list-item-styling"},{title:"Link styling mixin",filename:"typography",url:"typography.html#link-styling-mixin"},{title:"Link styling mixin variables",filename:"typography",url:"typography.html#link-styling-mixin-variables"},{title:"Heading styling mixin",filename:"typography",url:"typography.html#heading-styling-mixin"},{title:"Base typography mixins",filename:"typography",url:"typography.html#base-typography-mixins"},{title:"Base typography mixin variables",filename:"typography",url:"typography.html#base-typography-mixin-variables"},{title:"Headings typography mixin",filename:"typography",url:"typography.html#headings-typography-mixin"},{title:"Headings typography mixin variables",filename:"typography",url:"typography.html#headings-typography-mixin-variables"},{title:"Typography links mixin",filename:"typography",url:"typography.html#typography-links-mixin"},{title:"Typography lists mixin",filename:"typography",url:"typography.html#typography-lists-mixin"},{title:"Typography lists mixin variables",filename:"typography",url:"typography.html#typography-lists-mixin-variables"},{title:"Typography code elements mixin",filename:"typography",url:"typography.html#typography-code-elements-mixin"},{title:"Typography code mixin variables",filename:"typography",url:"typography.html#typography-code-mixin-variables"},{title:"Typography blockquote",filename:"typography",url:"typography.html#typography-blockquote"},{title:"Typography blockquote mixin variables",filename:"typography",url:"typography.html#typography-blockquote-mixin-variables"},{title:"utilities",filename:"utilities",url:"utilities.html"},{title:"Utilities",filename:"utilities",url:"utilities.html#utilities"},{title:".lib-clearfix()",filename:"utilities",url:"utilities.html#libclearfix"},{title:".lib-visibility-hidden()",filename:"utilities",url:"utilities.html#libvisibilityhidden"},{title:".lib-visually-hidden()",filename:"utilities",url:"utilities.html#libvisuallyhidden"},{title:".lib-visually-hidden-reset()",filename:"utilities",url:"utilities.html#libvisuallyhiddenreset"},{title:".lib-css()",filename:"utilities",url:"utilities.html#libcss"},{title:".lib-css() variables",filename:"utilities",url:"utilities.html#libcss-variables"},{title:".lib-rotate()",filename:"utilities",url:"utilities.html#librotate"},{title:".lib-rotate() variables",filename:"utilities",url:"utilities.html#librotate-variables"},{title:".lib-input-placeholder()",filename:"utilities",url:"utilities.html#libinputplaceholder"},{title:".lib-input-placeholder() variables",filename:"utilities",url:"utilities.html#libinputplaceholder-variables"},{title:".lib-background-gradient()",filename:"utilities",url:"utilities.html#libbackgroundgradient"},{title:".lib-background-gradient() variables",filename:"utilities",url:"utilities.html#libbackgroundgradient-variables"},{title:"variables",filename:"variables",url:"variables.html"},{title:"List of Global Variables",filename:"variables",url:"variables.html#list-of-global-variables"},{title:"Table with rows hover mixin variables",filename:"variables",url:"variables.html#table-with-rows-hover-mixin-variables"},{title:"docs",filename:"docs",url:"docs.html"},{title:"Documentation",filename:"docs",url:"docs.html#documentation"}];(function(){"use strict";var b=function(a,b){return Array.prototype.indexOf.call(a,b)!==-1},c=function(a,b){return Array.prototype.filter.call(a,b)},d=function(a,b){return Array.prototype.forEach.call(a,b)},e=document.getElementsByTagName("body")[0];e.addEventListener("click",function(a){var b=a.target;b.tagName.toLowerCase()==="svg"&&(b=b.parentNode);var c=!1;b.dataset.toggle!=null&&(a.preventDefault(),b.classList.contains("is-active")||(c=!0)),d(e.querySelectorAll("[data-toggle]"),function(a){a.classList.remove("is-active"),document.getElementById(a.dataset.toggle).hidden=!0}),c&&(b.classList.add("is-active"),document.getElementById(b.dataset.toggle).hidden=!1)}),function(){var f=e.getElementsByClassName("nav")[0];if(!f)return;var g=document.createElement("ul");g.className="nav-results",g.id="nav-search",g.hidden=!0,d(a,function(a){var b,c,d;b=document.createElement("li"),b._title=a.title.toLowerCase(),b.hidden=!0,b.appendChild(c=document.createElement("a")),c.href=a.url,c.innerHTML=a.title,c.appendChild(d=document.createElement("span")),d.innerHTML=a.filename,d.className="nav-results-filename",g.appendChild(b)}),f.appendChild(g);var h=g.children,i=function(a){d(h,function(a){a.hidden=!0});var b=this.value.toLowerCase(),e=[];b!==""&&(e=c(h,function(a){return a._title.indexOf(b)!==-1})),e.length>0?(d(e,function(a){a.hidden=!1}),g.hidden=!1):g.hidden=!0},j=f.querySelector('input[type="search"]');j.addEventListener("keyup",i),j.addEventListener("focus",i),e.addEventListener("click",function(a){if(a.target.classList&&a.target.classList.contains("search"))return;g.hidden=!0}),g.addEventListener("click",function(a){j.value=""});var k=document.createElement("ul");k.id="nav-toc",k.hidden=!0,k.className="nav-results toc-list",c(e.getElementsByTagName("*"),function(a){return b(["h1","h2","h3"],a.tagName.toLowerCase())}).map(function(a){var b=document.createElement("li"),c=document.createElement("a"),d=a.tagName.toLowerCase()[1];c.classList.add("level-"+d),b.appendChild(c),c.href="#"+a.id,c.innerHTML=a.innerHTML,k.appendChild(b)}),f.appendChild(k)}()})(),function(){"use strict";if(location.hash==="#__preview__"||location.protocol==="data:")return;var a=function(a,b){return Array.prototype.forEach.call(a,b)},b=function(a,b){var e=Array.prototype.slice.call(arguments,2);return d(a,function(a){return(c(b)?b||a:a[b]).apply(a,e)})},c=function(a){return Object.prototype.toString.call(a)==="[object Function]"},d=function(a,b){return Array.prototype.map.call(a,b)},e=function(a,b){return d(a,function(a){return a[b]})},f=function(a){var b={},c=a.split(";");for(var d=0;c.length>d;d++){var e=c[d].trim().split("=");b[e[0]]=e[1]}return b},g=function(a,c){return b(e(a,"classList"),"remove",c)},h=function(a,b){a.contentDocument.defaultView.postMessage(b,"*")},i=document.getElementsByTagName("head")[0],j=document.getElementsByTagName("body")[0],k=e(i.querySelectorAll('style[type="text/preview"]'),"innerHTML").join(""),l=e(i.querySelectorAll('script[type="text/preview"]'),"innerHTML").join(""),m=location.href.split("#")[0]+"#__preview__",n=document.createElement("iframe");n.src="data:text/html,",j.appendChild(n),n.addEventListener("load",function(){var b={sameOriginDataUri:!0};try{this.contentDocument,this.contentDocument||(b.sameOriginDataUri=!1)}catch(c){b.sameOriginDataUri=!1}this.parentNode.removeChild(this),a(j.getElementsByTagName("textarea"),function(a,c){o(a,b,c),q(),p(a)})});var o=function(a,b,c){var d,e,f;d=document.createElement("div"),d.appendChild(e=document.createElement("div")),d.className="preview",e.appendChild(f=document.createElement("iframe")),e.className="resizeable",f.setAttribute("scrolling","no"),f.name="iframe"+c++,f.addEventListener("load",function(){var c,d,e,f,g,i,j;j=this.contentDocument;if(!b.sameOriginDataUri&&this.src!==m)return;this.src===m&&(c=j.createElement("html"),c.appendChild(j.createElement("head")),c.appendChild(d=j.createElement("body")),d.innerHTML=a.textContent,j.replaceChild(c,j.documentElement)),g=j.createElement("head"),g.appendChild(f=j.createElement("style")),g.appendChild(e=j.createElement("script")),e.textContent=l,f.textContent=k,i=j.getElementsByTagName("head")[0],i.parentNode.replaceChild(g,i),h(this,"getHeight")});var g;b.sameOriginDataUri?g="data:text/html;charset=utf-8,"+encodeURIComponent("<!doctype html><html><head></head></body>"+a.textContent):g=m,f.setAttribute("src",g);var i=function(){f.contentDocument.body.innerHTML=this.value,h(f,"getHeight")};a.addEventListener("keypress",i),a.addEventListener("keyup",i),a.parentNode.insertBefore(d,a)},p=function(a){var b=document.createElement("div");b.className="preview-code",b.style.position="absolute",b.style.left="-9999px",j.appendChild(b);var c=parseInt(window.getComputedStyle(a).getPropertyValue("max-height"),10),d=function(a){b.textContent=this.value+"\n";var d=b.offsetHeight+2;d>=c?this.style.overflow="auto":this.style.overflow="hidden",this.style.height=b.offsetHeight+2+"px"};a.addEventListener("keypress",d),a.addEventListener("keyup",d),d.call(a)},q=function(){var b=j.getElementsByClassName("settings")[0],c=j.getElementsByClassName("resizeable"),d=30,e=function(b){document.cookie="preview-width="+b,a(c,function(a){b==="auto"&&(b=a.parentNode.offsetWidth),a.style.width=b+"px",h(a.getElementsByTagName("iframe")[0],"getHeight")})},i=f(document.cookie)["preview-width"];if(i){e(i),g(b.getElementsByClassName("is-active"),"is-active");var k=b.querySelector('button[data-width="'+i+'"]');k&&k.classList.add("is-active")}window.addEventListener("message",function(a){if(a.data==null||!a.source)return;var b=a.data,c=document.getElementsByName(a.source.name)[0];b.height!=null&&c&&(c.parentNode.style.height=b.height+d+"px")},!1),b&&c.length>0&&(b.hidden=!1,b.addEventListener("click",function(a){var c=a.target.tagName.toLowerCase(),d;if(c==="button")d=a.target;else{if(c!=="svg")return;d=a.target.parentNode}a.preventDefault(),g(b.getElementsByClassName("is-active"),"is-active"),d.classList.add("is-active");var f=d.dataset.width;e(f)}))}}()})()</script></body></html><!-- Generated with StyleDocco (http://jacobrask.github.com/styledocco). --> diff --git a/lib/web/css/docs/responsive.html b/lib/web/css/docs/responsive.html index 5e9d3b38eddd0..48d0bd551bd92 100644 --- a/lib/web/css/docs/responsive.html +++ b/lib/web/css/docs/responsive.html @@ -80,4 +80,4 @@ <h2 id="gathering">Gathering</h2> @screen__l: 1024px; @screen__xl: 1440px;</code></pre> <p>  </p> -</div></article></section><div class="bar bottom"><div hidden class="settings container"><!-- Icons from http://iconmonstr.com--><button title="Desktop (1280)" data-width='1280'><svg viewBox="0 0 412 386" height="24" width="26" class="icon"><path d="m147.6,343.9c-4.5,15.9-26.2,37.6-42.1,42.1h201c-15.3,-4-38.1,-26.8-42.1,-42.1H147.6zM387,0.5H25c-13.8,0-25,11.2-25,25V294c0,13.8 11.2,25 25,25h362c13.8,0 25,-11.2 25,-25V25.5C412,11.7 400.8,0.5 387,0.5zM369.9,238.2H42.1L42.1,42.6 369.9,42.6V238.2z"></path></svg></button><button title="Laptop (1024)" data-width='1024'><svg viewBox="0 0 384 312" height="23" width="28" class="icon"><path d="m349.2,20.5c0,-11-9,-20-20,-20H53.6c-11,0-20,9-20,20v194H349.2v-194zm-27,167H60.6V27.5H322.2v160zm28,42H32.6L2.6,282.1c-3.5,6.2-3.5,13.8 0.1,19.9 3.6,6.2 10.2,9.9 17.3,9.9H363.1c7.1,0 13.7,-3.8 17.3,-10 3.6,-6.2 3.6,-13.8 0,-20l-30.2,-52.5zm-196.9,54 8,-23.5h60.5l8,23.5h-76.5z"></path></svg></button><button title="Tablet (768)" data-width='768'><svg viewBox="0 0 317 412" height="24" width="18" class="icon"><path d="M 316.5,380 V 32 c 0,-17.7 -14.3,-32 -32,-32 H 32 C 14.3,0 0,14.3 0,32 v 348 c 0,17.7 14.3,32 32,32 h 252.5 c 17.7,0 32,-14.3 32,-32 z M 40,367 V 45 H 276.5 V 367 H 40 z m 109.8,22.7 c 0,-4.7 3.8,-8.5 8.5,-8.5 4.7,0 8.5,3.8 8.5,8.5 0,4.7 -3.8,8.5 -8.5,8.5 -4.7,0 -8.5,-3.8 -8.5,-8.5 z"></path></svg></button><button title="Smart phone (320)" data-width='320'><svg viewBox="0 0 224 412" height="24" width="13" class="icon"><path d="M 190.7,0 H 33 C 14.8,0 0,14.8 0,33 v 346 c 0,18.2 14.8,33 33,33 h 157.7 c 18.2,0 33,-14.8 33,-33 V 33 c 0,-18.2 -14.8,-33 -33,-33 z M 94.3,30.2 h 37 c 2.2,0 4,1.8 4,4 0,2.2 -1.8,4 -4,4 h -37 c -2.2,0 -4,-1.8 -4,-4 0,-2.2 1.8,-4 4,-4 z m 18.5,362.8 c -8.8,0 -16,-7.2 -16,-16 0,-8.8 7.2,-16 16,-16 8.8,0 16,7.2 16,16 0,8.8 -7.2,16 -16,16 z M 198.6,343.8 H 25.1 V 68.2 h 173.5 v 275.5 z"></path></svg></button><button title="Feature phone (240)" data-width='240'><svg viewBox="0 0 201 412" height="24" width="12" class="icon"><path d="M 165.5,0.2 V 45 H 25 c -13.8,0 -25,11.2 -25,25 V 387 c 0,13.8 11.2,25 25,25 h 150.5 c 13.8,0 25,-11.2 25,-25 V 0.2 h -35 z M 65.2,366.5 H 34.2 v -24.5 h 31 v 24.5 z m 0,-44.3 H 34.2 v -24.5 h 31 v 24.5 z m 50.5,44.3 H 84.7 v -24.5 h 31 v 24.5 z m 0,-44.3 H 84.7 v -24.5 h 31 v 24.5 z m 50.5,44.3 h -31 v -24.5 h 31 v 24.5 z m 0,-44.3 h -31 v -24.5 h 31 v 24.5 z m 0,-59.3 h -132 V 95.4 h 132 V 262.9 z"></path></svg></button><button title="Auto (100%)" data-width="auto" class="auto is-active">Auto</button></div></div><script>(function(){var a=[{title:"actions-toolbar",filename:"actions-toolbar",url:"actions-toolbar.html"},{title:"Actions toolbar",filename:"actions-toolbar",url:"actions-toolbar.html#actions-toolbar"},{title:"Actions toolbar mixin variables",filename:"actions-toolbar",url:"actions-toolbar.html#actions-toolbar-mixin-variables"},{title:"Actions toolbar alignment",filename:"actions-toolbar",url:"actions-toolbar.html#actions-toolbar-alignment"},{title:"Reverse primary and secondary blocks",filename:"actions-toolbar",url:"actions-toolbar.html#reverse-primary-and-secondary-blocks"},{title:"Actions toolbar indents customizations",filename:"actions-toolbar",url:"actions-toolbar.html#actions-toolbar-indents-customizations"},{title:"Responsive actions toolbar",filename:"actions-toolbar",url:"actions-toolbar.html#responsive-actions-toolbar"},{title:"breadcrumbs",filename:"breadcrumbs",url:"breadcrumbs.html"},{title:"Breadcrumbs",filename:"breadcrumbs",url:"breadcrumbs.html#breadcrumbs"},{title:"Breadcrumbs variables",filename:"breadcrumbs",url:"breadcrumbs.html#breadcrumbs-variables"},{title:"Button-styled breadcrumbs with gradient background, border, and no separating symbol",filename:"breadcrumbs",url:"breadcrumbs.html#buttonstyled-breadcrumbs-with-gradient-background-border-and-no-separating-symbol"},{title:"Breadcrumbs with solid background",filename:"breadcrumbs",url:"breadcrumbs.html#breadcrumbs-with-solid-background"},{title:"buttons",filename:"buttons",url:"buttons.html"},{title:"Default button",filename:"buttons",url:"buttons.html#default-button"},{title:"Button variables",filename:"buttons",url:"buttons.html#button-variables"},{title:"Button as an icon",filename:"buttons",url:"buttons.html#button-as-an-icon"},{title:"Button with an icon on the left or right side of the text",filename:"buttons",url:"buttons.html#button-with-an-icon-on-the-left-or-right-side-of-the-text"},{title:"Button with fixed width",filename:"buttons",url:"buttons.html#button-with-fixed-width"},{title:"Primary button",filename:"buttons",url:"buttons.html#primary-button"},{title:"Primary button variables",filename:"buttons",url:"buttons.html#primary-button-variables"},{title:"Button with gradient background",filename:"buttons",url:"buttons.html#button-with-gradient-background"},{title:"Button as a link",filename:"buttons",url:"buttons.html#button-as-a-link"},{title:"Button as a link variables",filename:"buttons",url:"buttons.html#button-as-a-link-variables"},{title:"Link as a button",filename:"buttons",url:"buttons.html#link-as-a-button"},{title:"Button reset",filename:"buttons",url:"buttons.html#button-reset"},{title:"Button revert secondary color",filename:"buttons",url:"buttons.html#button-revert-secondary-color"},{title:"Button revert secondary color variables",filename:"buttons",url:"buttons.html#button-revert-secondary-color-variables"},{title:"Button revert secondary size",filename:"buttons",url:"buttons.html#button-revert-secondary-size"},{title:"Button revert secondary size variables",filename:"buttons",url:"buttons.html#button-revert-secondary-size-variables"},{title:"components",filename:"components",url:"components.html"},{title:"Components",filename:"components",url:"components.html#components"},{title:"Components Variables",filename:"components",url:"components.html#components-variables"},{title:"dropdowns",filename:"dropdowns",url:"dropdowns.html"},{title:"Drop-down and split buttons mixins",filename:"dropdowns",url:"dropdowns.html#dropdown-and-split-buttons-mixins"},{title:"Drop-down",filename:"dropdowns",url:"dropdowns.html#dropdown"},{title:"Drop-down variables",filename:"dropdowns",url:"dropdowns.html#dropdown-variables"},{title:"Drop-down with icon customization",filename:"dropdowns",url:"dropdowns.html#dropdown-with-icon-customization"},{title:"Modify dropdown list styles",filename:"dropdowns",url:"dropdowns.html#modify-dropdown-list-styles"},{title:"Split button",filename:"dropdowns",url:"dropdowns.html#split-button"},{title:"Split button variables",filename:"dropdowns",url:"dropdowns.html#split-button-variables"},{title:"Split button - button styling",filename:"dropdowns",url:"dropdowns.html#split-button-button-styling"},{title:"Split button icon customization",filename:"dropdowns",url:"dropdowns.html#split-button-icon-customization"},{title:"Split button drop-down list customization",filename:"dropdowns",url:"dropdowns.html#split-button-dropdown-list-customization"},{title:"forms",filename:"forms",url:"forms.html"},{title:"Forms mixins",filename:"forms",url:"forms.html#forms-mixins"},{title:"Global forms elements customization",filename:"forms",url:"forms.html#global-forms-elements-customization"},{title:"Fieldsets & fields customization",filename:"forms",url:"forms.html#fieldsets-fields-customization"},{title:"Fieldset and legend customization variables",filename:"forms",url:"forms.html#fieldset-and-legend-customization-variables"},{title:"Fields customization variables",filename:"forms",url:"forms.html#fields-customization-variables"},{title:"Required fields message customization variables",filename:"forms",url:"forms.html#required-fields-message-customization-variables"},{title:"Form element inputs customization",filename:"forms",url:"forms.html#form-element-inputs-customization"},{title:"Form element inputs customization variables",filename:"forms",url:"forms.html#form-element-inputs-customization-variables"},{title:"Form element choice",filename:"forms",url:"forms.html#form-element-choice"},{title:"Form element choice variables",filename:"forms",url:"forms.html#form-element-choice-variables"},{title:"Custom color",filename:"forms",url:"forms.html#custom-color"},{title:"Input number - input-text view",filename:"forms",url:"forms.html#input-number-inputtext-view"},{title:"Input search - input-text view",filename:"forms",url:"forms.html#input-search-inputtext-view"},{title:"Form validation",filename:"forms",url:"forms.html#form-validation"},{title:"Form validation variables",filename:"forms",url:"forms.html#form-validation-variables"},{title:"icons",filename:"icons",url:"icons.html"},{title:"Icons",filename:"icons",url:"icons.html#icons"},{title:"Icon with image or sprite",filename:"icons",url:"icons.html#icon-with-image-or-sprite"},{title:"Icon with image or sprite variables",filename:"icons",url:"icons.html#icon-with-image-or-sprite-variables"},{title:"Icon position for an icon with image or sprite",filename:"icons",url:"icons.html#icon-position-for-an-icon-with-image-or-sprite"},{title:"Position for icon with image or sprite mixin variables",filename:"icons",url:"icons.html#position-for-icon-with-image-or-sprite-mixin-variables"},{title:"Icon sprite position (with grid)",filename:"icons",url:"icons.html#icon-sprite-position-with-grid"},{title:"Icon sprite position variables",filename:"icons",url:"icons.html#icon-sprite-position-variables"},{title:"Image/sprite icon size",filename:"icons",url:"icons.html#imagesprite-icon-size"},{title:"Image/sprite icon size variables",filename:"icons",url:"icons.html#imagesprite-icon-size-variables"},{title:"Font icon",filename:"icons",url:"icons.html#font-icon"},{title:"Font icon variables",filename:"icons",url:"icons.html#font-icon-variables"},{title:"Change the size of font icon",filename:"icons",url:"icons.html#change-the-size-of-font-icon"},{title:"Change the size of font icon variables",filename:"icons",url:"icons.html#change-the-size-of-font-icon-variables"},{title:"Hide icon text",filename:"icons",url:"icons.html#hide-icon-text"},{title:"Sprite and font icons for Blank theme",filename:"icons",url:"icons.html#sprite-and-font-icons-for-blank-theme"},{title:"layout",filename:"layout",url:"layout.html"},{title:"Layout",filename:"layout",url:"layout.html#layout"},{title:"Layout global variables",filename:"layout",url:"layout.html#layout-global-variables"},{title:"Page layouts",filename:"layout",url:"layout.html#page-layouts"},{title:"Layout column",filename:"layout",url:"layout.html#layout-column"},{title:"Layout column variables",filename:"layout",url:"layout.html#layout-column-variables"},{title:"Layout width",filename:"layout",url:"layout.html#layout-width"},{title:"Layout width variables",filename:"layout",url:"layout.html#layout-width-variables"},{title:"lib",filename:"lib",url:"lib.html"},{title:"Including Magento UI library to your theme",filename:"lib",url:"lib.html#including-magento-ui-library-to-your-theme"},{title:"loaders",filename:"loaders",url:"loaders.html"},{title:"Loaders",filename:"loaders",url:"loaders.html#loaders"},{title:"Default loader variables",filename:"loaders",url:"loaders.html#default-loader-variables"},{title:"Loading",filename:"loaders",url:"loaders.html#loading"},{title:"Loading default variables",filename:"loaders",url:"loaders.html#loading-default-variables"},{title:"messages",filename:"messages",url:"messages.html"},{title:"Messages",filename:"messages",url:"messages.html#messages"},{title:"Information message",filename:"messages",url:"messages.html#information-message"},{title:"Warning message",filename:"messages",url:"messages.html#warning-message"},{title:"Error message",filename:"messages",url:"messages.html#error-message"},{title:"Success message",filename:"messages",url:"messages.html#success-message"},{title:"Notice message",filename:"messages",url:"messages.html#notice-message"},{title:"Message with inner icon",filename:"messages",url:"messages.html#message-with-inner-icon"},{title:"Message with lateral icon",filename:"messages",url:"messages.html#message-with-lateral-icon"},{title:"Custom message style",filename:"messages",url:"messages.html#custom-message-style"},{title:"Messages global variables",filename:"messages",url:"messages.html#messages-global-variables"},{title:"pages",filename:"pages",url:"pages.html"},{title:"Pagination HTML markup",filename:"pages",url:"pages.html#pagination-html-markup"},{title:"Pagination variables",filename:"pages",url:"pages.html#pagination-variables"},{title:"Pagination with label and gradient background on links",filename:"pages",url:"pages.html#pagination-with-label-and-gradient-background-on-links"},{title:'Pagination with "previous"..."next" text links and label',filename:"pages",url:"pages.html#pagination-with-previousnext-text-links-and-label"},{title:"Pagination without label, with solid background",filename:"pages",url:"pages.html#pagination-without-label-with-solid-background"},{title:"popups",filename:"popups",url:"popups.html"},{title:"Popups",filename:"popups",url:"popups.html#popups"},{title:"Popup variables",filename:"popups",url:"popups.html#popup-variables"},{title:"Window overlay mixin variables",filename:"popups",url:"popups.html#window-overlay-mixin-variables"},{title:"Fixed height popup",filename:"popups",url:"popups.html#fixed-height-popup"},{title:"Fixed content height popup",filename:"popups",url:"popups.html#fixed-content-height-popup"},{title:"Margins for header, content and footer block in popup",filename:"popups",url:"popups.html#margins-for-header-content-and-footer-block-in-popup"},{title:"Popup titles styled as theme headings",filename:"popups",url:"popups.html#popup-titles-styled-as-theme-headings"},{title:"Popup action toolbar",filename:"popups",url:"popups.html#popup-action-toolbar"},{title:"Popup Close button without an icon",filename:"popups",url:"popups.html#popup-close-button-without-an-icon"},{title:"Modify the icon of popup Close button",filename:"popups",url:"popups.html#modify-the-icon-of-popup-close-button"},{title:"Modify overlay styles",filename:"popups",url:"popups.html#modify-overlay-styles"},{title:"rating",filename:"rating",url:"rating.html"},{title:"Ratings",filename:"rating",url:"rating.html#ratings"},{title:"Global rating variables",filename:"rating",url:"rating.html#global-rating-variables"},{title:"Rating with vote",filename:"rating",url:"rating.html#rating-with-vote"},{title:"Rating with vote icons number customization",filename:"rating",url:"rating.html#rating-with-vote-icons-number-customization"},{title:"Rating with vote icons colors customization",filename:"rating",url:"rating.html#rating-with-vote-icons-colors-customization"},{title:"Rating with vote icons symbol customization",filename:"rating",url:"rating.html#rating-with-vote-icons-symbol-customization"},{title:"Accessible rating with vote",filename:"rating",url:"rating.html#accessible-rating-with-vote"},{title:"Rating summary",filename:"rating",url:"rating.html#rating-summary"},{title:"Rating summary icons number customization",filename:"rating",url:"rating.html#rating-summary-icons-number-customization"},{title:"Rating summary icons color customization",filename:"rating",url:"rating.html#rating-summary-icons-color-customization"},{title:"Rating summary icons symbol customization",filename:"rating",url:"rating.html#rating-summary-icons-symbol-customization"},{title:"Rating summary hide label",filename:"rating",url:"rating.html#rating-summary-hide-label"},{title:"Rating summary multiple ratings",filename:"rating",url:"rating.html#rating-summary-multiple-ratings"},{title:"Rating hide label mixin",filename:"rating",url:"rating.html#rating-hide-label-mixin"},{title:"resets",filename:"resets",url:"resets.html"},{title:"Resets",filename:"resets",url:"resets.html#resets"},{title:"responsive",filename:"responsive",url:"responsive.html"},{title:"Responsive",filename:"responsive",url:"responsive.html#responsive"},{title:"Responsive mixins usage",filename:"responsive",url:"responsive.html#responsive-mixins-usage"},{title:"Media query style groups separation variables",filename:"responsive",url:"responsive.html#media-query-style-groups-separation-variables"},{title:"Responsive breakpoints",filename:"responsive",url:"responsive.html#responsive-breakpoints"},{title:"sections",filename:"sections",url:"sections.html"},{title:"Tabs and accordions",filename:"sections",url:"sections.html#tabs-and-accordions"},{title:"Tabs",filename:"sections",url:"sections.html#tabs"},{title:"Tabs mixin variables",filename:"sections",url:"sections.html#tabs-mixin-variables"},{title:"Tabs with content top border",filename:"sections",url:"sections.html#tabs-with-content-top-border"},{title:"Accordion",filename:"sections",url:"sections.html#accordion"},{title:"Accordion mixin variables",filename:"sections",url:"sections.html#accordion-mixin-variables"},{title:"Responsive tabs",filename:"sections",url:"sections.html#responsive-tabs"},{title:"Tabs Base",filename:"sections",url:"sections.html#tabs-base"},{title:"Accordion Base",filename:"sections",url:"sections.html#accordion-base"},{title:"tables",filename:"tables",url:"tables.html"},{title:"Tables",filename:"tables",url:"tables.html#tables"},{title:"Table mixin variables",filename:"tables",url:"tables.html#table-mixin-variables"},{title:"Table typography",filename:"tables",url:"tables.html#table-typography"},{title:"Table typography mixin variables",filename:"tables",url:"tables.html#table-typography-mixin-variables"},{title:"Table caption",filename:"tables",url:"tables.html#table-caption"},{title:"Table caption mixin variables",filename:"tables",url:"tables.html#table-caption-mixin-variables"},{title:"Table cells resize",filename:"tables",url:"tables.html#table-cells-resize"},{title:"Table cells resize variables",filename:"tables",url:"tables.html#table-cells-resize-variables"},{title:"Table background customization",filename:"tables",url:"tables.html#table-background-customization"},{title:"Table background mixin variables",filename:"tables",url:"tables.html#table-background-mixin-variables"},{title:"Table borders customization",filename:"tables",url:"tables.html#table-borders-customization"},{title:"Table borders mixin variables",filename:"tables",url:"tables.html#table-borders-mixin-variables"},{title:"Table with horizontal borders",filename:"tables",url:"tables.html#table-with-horizontal-borders"},{title:"Table with vertical borders",filename:"tables",url:"tables.html#table-with-vertical-borders"},{title:"Table with light borders",filename:"tables",url:"tables.html#table-with-light-borders"},{title:"Table without borders",filename:"tables",url:"tables.html#table-without-borders"},{title:"Striped table",filename:"tables",url:"tables.html#striped-table"},{title:"Striped table mixin variables",filename:"tables",url:"tables.html#striped-table-mixin-variables"},{title:"Table with rows hover",filename:"tables",url:"tables.html#table-with-rows-hover"},{title:"Table with rows hover mixin variables",filename:"tables",url:"tables.html#table-with-rows-hover-mixin-variables"},{title:"Responsive table technics #1",filename:"tables",url:"tables.html#responsive-table-technics-1"},{title:"Responsive table technics #2",filename:"tables",url:"tables.html#responsive-table-technics-2"},{title:"Responsive table technics #2 mixin variables",filename:"tables",url:"tables.html#responsive-table-technics-2-mixin-variables"},{title:"tooltips",filename:"tooltips",url:"tooltips.html"},{title:"Tooltips",filename:"tooltips",url:"tooltips.html#tooltips"},{title:"Tooltips variables",filename:"tooltips",url:"tooltips.html#tooltips-variables"},{title:"typography",filename:"typography",url:"typography.html"},{title:"Typogrphy",filename:"typography",url:"typography.html#typogrphy"},{title:"Typography variables",filename:"typography",url:"typography.html#typography-variables"},{title:"Font-size mixin",filename:"typography",url:"typography.html#fontsize-mixin"},{title:"Line-height mixin",filename:"typography",url:"typography.html#lineheight-mixin"},{title:"Word breaking mixin",filename:"typography",url:"typography.html#word-breaking-mixin"},{title:"Font face mixin",filename:"typography",url:"typography.html#font-face-mixin"},{title:"Text overflow mixin",filename:"typography",url:"typography.html#text-overflow-mixin"},{title:"Text hide",filename:"typography",url:"typography.html#text-hide"},{title:"Hyphens",filename:"typography",url:"typography.html#hyphens"},{title:"Font style and color",filename:"typography",url:"typography.html#font-style-and-color"},{title:"Font style mixin variables",filename:"typography",url:"typography.html#font-style-mixin-variables"},{title:"Reset list styles",filename:"typography",url:"typography.html#reset-list-styles"},{title:"Reset list styles variables",filename:"typography",url:"typography.html#reset-list-styles-variables"},{title:"Inline-block list item styling",filename:"typography",url:"typography.html#inlineblock-list-item-styling"},{title:"Link styling mixin",filename:"typography",url:"typography.html#link-styling-mixin"},{title:"Link styling mixin variables",filename:"typography",url:"typography.html#link-styling-mixin-variables"},{title:"Heading styling mixin",filename:"typography",url:"typography.html#heading-styling-mixin"},{title:"Base typography mixins",filename:"typography",url:"typography.html#base-typography-mixins"},{title:"Base typography mixin variables",filename:"typography",url:"typography.html#base-typography-mixin-variables"},{title:"Headings typography mixin",filename:"typography",url:"typography.html#headings-typography-mixin"},{title:"Headings typography mixin variables",filename:"typography",url:"typography.html#headings-typography-mixin-variables"},{title:"Typography links mixin",filename:"typography",url:"typography.html#typography-links-mixin"},{title:"Typography lists mixin",filename:"typography",url:"typography.html#typography-lists-mixin"},{title:"Typography lists mixin variables",filename:"typography",url:"typography.html#typography-lists-mixin-variables"},{title:"Typography code elements mixin",filename:"typography",url:"typography.html#typography-code-elements-mixin"},{title:"Typography code mixin variables",filename:"typography",url:"typography.html#typography-code-mixin-variables"},{title:"Typography blockquote",filename:"typography",url:"typography.html#typography-blockquote"},{title:"Typography blockquote mixin variables",filename:"typography",url:"typography.html#typography-blockquote-mixin-variables"},{title:"utilities",filename:"utilities",url:"utilities.html"},{title:"Utilities",filename:"utilities",url:"utilities.html#utilities"},{title:".lib-clearfix()",filename:"utilities",url:"utilities.html#libclearfix"},{title:".lib-visibility-hidden()",filename:"utilities",url:"utilities.html#libvisibilityhidden"},{title:".lib-visually-hidden()",filename:"utilities",url:"utilities.html#libvisuallyhidden"},{title:".lib-visually-hidden-reset()",filename:"utilities",url:"utilities.html#libvisuallyhiddenreset"},{title:".lib-css()",filename:"utilities",url:"utilities.html#libcss"},{title:".lib-css() variables",filename:"utilities",url:"utilities.html#libcss-variables"},{title:".lib-rotate()",filename:"utilities",url:"utilities.html#librotate"},{title:".lib-rotate() variables",filename:"utilities",url:"utilities.html#librotate-variables"},{title:".lib-input-placeholder()",filename:"utilities",url:"utilities.html#libinputplaceholder"},{title:".lib-input-placeholder() variables",filename:"utilities",url:"utilities.html#libinputplaceholder-variables"},{title:".lib-background-gradient()",filename:"utilities",url:"utilities.html#libbackgroundgradient"},{title:".lib-background-gradient() variables",filename:"utilities",url:"utilities.html#libbackgroundgradient-variables"},{title:".lib-url-check()",filename:"utilities",url:"utilities.html#liburlcheck"},{title:".lib-url-check() variables",filename:"utilities",url:"utilities.html#liburlcheck-variables"},{title:"variables",filename:"variables",url:"variables.html"},{title:"List of Global Variables",filename:"variables",url:"variables.html#list-of-global-variables"},{title:"Table with rows hover mixin variables",filename:"variables",url:"variables.html#table-with-rows-hover-mixin-variables"},{title:"docs",filename:"docs",url:"docs.html"},{title:"Documentation",filename:"docs",url:"docs.html#documentation"}];(function(){"use strict";var b=function(a,b){return Array.prototype.indexOf.call(a,b)!==-1},c=function(a,b){return Array.prototype.filter.call(a,b)},d=function(a,b){return Array.prototype.forEach.call(a,b)},e=document.getElementsByTagName("body")[0];e.addEventListener("click",function(a){var b=a.target;b.tagName.toLowerCase()==="svg"&&(b=b.parentNode);var c=!1;b.dataset.toggle!=null&&(a.preventDefault(),b.classList.contains("is-active")||(c=!0)),d(e.querySelectorAll("[data-toggle]"),function(a){a.classList.remove("is-active"),document.getElementById(a.dataset.toggle).hidden=!0}),c&&(b.classList.add("is-active"),document.getElementById(b.dataset.toggle).hidden=!1)}),function(){var f=e.getElementsByClassName("nav")[0];if(!f)return;var g=document.createElement("ul");g.className="nav-results",g.id="nav-search",g.hidden=!0,d(a,function(a){var b,c,d;b=document.createElement("li"),b._title=a.title.toLowerCase(),b.hidden=!0,b.appendChild(c=document.createElement("a")),c.href=a.url,c.innerHTML=a.title,c.appendChild(d=document.createElement("span")),d.innerHTML=a.filename,d.className="nav-results-filename",g.appendChild(b)}),f.appendChild(g);var h=g.children,i=function(a){d(h,function(a){a.hidden=!0});var b=this.value.toLowerCase(),e=[];b!==""&&(e=c(h,function(a){return a._title.indexOf(b)!==-1})),e.length>0?(d(e,function(a){a.hidden=!1}),g.hidden=!1):g.hidden=!0},j=f.querySelector('input[type="search"]');j.addEventListener("keyup",i),j.addEventListener("focus",i),e.addEventListener("click",function(a){if(a.target.classList&&a.target.classList.contains("search"))return;g.hidden=!0}),g.addEventListener("click",function(a){j.value=""});var k=document.createElement("ul");k.id="nav-toc",k.hidden=!0,k.className="nav-results toc-list",c(e.getElementsByTagName("*"),function(a){return b(["h1","h2","h3"],a.tagName.toLowerCase())}).map(function(a){var b=document.createElement("li"),c=document.createElement("a"),d=a.tagName.toLowerCase()[1];c.classList.add("level-"+d),b.appendChild(c),c.href="#"+a.id,c.innerHTML=a.innerHTML,k.appendChild(b)}),f.appendChild(k)}()})(),function(){"use strict";if(location.hash==="#__preview__"||location.protocol==="data:")return;var a=function(a,b){return Array.prototype.forEach.call(a,b)},b=function(a,b){var e=Array.prototype.slice.call(arguments,2);return d(a,function(a){return(c(b)?b||a:a[b]).apply(a,e)})},c=function(a){return Object.prototype.toString.call(a)==="[object Function]"},d=function(a,b){return Array.prototype.map.call(a,b)},e=function(a,b){return d(a,function(a){return a[b]})},f=function(a){var b={},c=a.split(";");for(var d=0;c.length>d;d++){var e=c[d].trim().split("=");b[e[0]]=e[1]}return b},g=function(a,c){return b(e(a,"classList"),"remove",c)},h=function(a,b){a.contentDocument.defaultView.postMessage(b,"*")},i=document.getElementsByTagName("head")[0],j=document.getElementsByTagName("body")[0],k=e(i.querySelectorAll('style[type="text/preview"]'),"innerHTML").join(""),l=e(i.querySelectorAll('script[type="text/preview"]'),"innerHTML").join(""),m=location.href.split("#")[0]+"#__preview__",n=document.createElement("iframe");n.src="data:text/html,",j.appendChild(n),n.addEventListener("load",function(){var b={sameOriginDataUri:!0};try{this.contentDocument,this.contentDocument||(b.sameOriginDataUri=!1)}catch(c){b.sameOriginDataUri=!1}this.parentNode.removeChild(this),a(j.getElementsByTagName("textarea"),function(a,c){o(a,b,c),q(),p(a)})});var o=function(a,b,c){var d,e,f;d=document.createElement("div"),d.appendChild(e=document.createElement("div")),d.className="preview",e.appendChild(f=document.createElement("iframe")),e.className="resizeable",f.setAttribute("scrolling","no"),f.name="iframe"+c++,f.addEventListener("load",function(){var c,d,e,f,g,i,j;j=this.contentDocument;if(!b.sameOriginDataUri&&this.src!==m)return;this.src===m&&(c=j.createElement("html"),c.appendChild(j.createElement("head")),c.appendChild(d=j.createElement("body")),d.innerHTML=a.textContent,j.replaceChild(c,j.documentElement)),g=j.createElement("head"),g.appendChild(f=j.createElement("style")),g.appendChild(e=j.createElement("script")),e.textContent=l,f.textContent=k,i=j.getElementsByTagName("head")[0],i.parentNode.replaceChild(g,i),h(this,"getHeight")});var g;b.sameOriginDataUri?g="data:text/html;charset=utf-8,"+encodeURIComponent("<!doctype html><html><head></head></body>"+a.textContent):g=m,f.setAttribute("src",g);var i=function(){f.contentDocument.body.innerHTML=this.value,h(f,"getHeight")};a.addEventListener("keypress",i),a.addEventListener("keyup",i),a.parentNode.insertBefore(d,a)},p=function(a){var b=document.createElement("div");b.className="preview-code",b.style.position="absolute",b.style.left="-9999px",j.appendChild(b);var c=parseInt(window.getComputedStyle(a).getPropertyValue("max-height"),10),d=function(a){b.textContent=this.value+"\n";var d=b.offsetHeight+2;d>=c?this.style.overflow="auto":this.style.overflow="hidden",this.style.height=b.offsetHeight+2+"px"};a.addEventListener("keypress",d),a.addEventListener("keyup",d),d.call(a)},q=function(){var b=j.getElementsByClassName("settings")[0],c=j.getElementsByClassName("resizeable"),d=30,e=function(b){document.cookie="preview-width="+b,a(c,function(a){b==="auto"&&(b=a.parentNode.offsetWidth),a.style.width=b+"px",h(a.getElementsByTagName("iframe")[0],"getHeight")})},i=f(document.cookie)["preview-width"];if(i){e(i),g(b.getElementsByClassName("is-active"),"is-active");var k=b.querySelector('button[data-width="'+i+'"]');k&&k.classList.add("is-active")}window.addEventListener("message",function(a){if(a.data==null||!a.source)return;var b=a.data,c=document.getElementsByName(a.source.name)[0];b.height!=null&&c&&(c.parentNode.style.height=b.height+d+"px")},!1),b&&c.length>0&&(b.hidden=!1,b.addEventListener("click",function(a){var c=a.target.tagName.toLowerCase(),d;if(c==="button")d=a.target;else{if(c!=="svg")return;d=a.target.parentNode}a.preventDefault(),g(b.getElementsByClassName("is-active"),"is-active"),d.classList.add("is-active");var f=d.dataset.width;e(f)}))}}()})()</script></body></html><!-- Generated with StyleDocco (http://jacobrask.github.com/styledocco). --> +</div></article></section><div class="bar bottom"><div hidden class="settings container"><!-- Icons from http://iconmonstr.com--><button title="Desktop (1280)" data-width='1280'><svg viewBox="0 0 412 386" height="24" width="26" class="icon"><path d="m147.6,343.9c-4.5,15.9-26.2,37.6-42.1,42.1h201c-15.3,-4-38.1,-26.8-42.1,-42.1H147.6zM387,0.5H25c-13.8,0-25,11.2-25,25V294c0,13.8 11.2,25 25,25h362c13.8,0 25,-11.2 25,-25V25.5C412,11.7 400.8,0.5 387,0.5zM369.9,238.2H42.1L42.1,42.6 369.9,42.6V238.2z"></path></svg></button><button title="Laptop (1024)" data-width='1024'><svg viewBox="0 0 384 312" height="23" width="28" class="icon"><path d="m349.2,20.5c0,-11-9,-20-20,-20H53.6c-11,0-20,9-20,20v194H349.2v-194zm-27,167H60.6V27.5H322.2v160zm28,42H32.6L2.6,282.1c-3.5,6.2-3.5,13.8 0.1,19.9 3.6,6.2 10.2,9.9 17.3,9.9H363.1c7.1,0 13.7,-3.8 17.3,-10 3.6,-6.2 3.6,-13.8 0,-20l-30.2,-52.5zm-196.9,54 8,-23.5h60.5l8,23.5h-76.5z"></path></svg></button><button title="Tablet (768)" data-width='768'><svg viewBox="0 0 317 412" height="24" width="18" class="icon"><path d="M 316.5,380 V 32 c 0,-17.7 -14.3,-32 -32,-32 H 32 C 14.3,0 0,14.3 0,32 v 348 c 0,17.7 14.3,32 32,32 h 252.5 c 17.7,0 32,-14.3 32,-32 z M 40,367 V 45 H 276.5 V 367 H 40 z m 109.8,22.7 c 0,-4.7 3.8,-8.5 8.5,-8.5 4.7,0 8.5,3.8 8.5,8.5 0,4.7 -3.8,8.5 -8.5,8.5 -4.7,0 -8.5,-3.8 -8.5,-8.5 z"></path></svg></button><button title="Smart phone (320)" data-width='320'><svg viewBox="0 0 224 412" height="24" width="13" class="icon"><path d="M 190.7,0 H 33 C 14.8,0 0,14.8 0,33 v 346 c 0,18.2 14.8,33 33,33 h 157.7 c 18.2,0 33,-14.8 33,-33 V 33 c 0,-18.2 -14.8,-33 -33,-33 z M 94.3,30.2 h 37 c 2.2,0 4,1.8 4,4 0,2.2 -1.8,4 -4,4 h -37 c -2.2,0 -4,-1.8 -4,-4 0,-2.2 1.8,-4 4,-4 z m 18.5,362.8 c -8.8,0 -16,-7.2 -16,-16 0,-8.8 7.2,-16 16,-16 8.8,0 16,7.2 16,16 0,8.8 -7.2,16 -16,16 z M 198.6,343.8 H 25.1 V 68.2 h 173.5 v 275.5 z"></path></svg></button><button title="Feature phone (240)" data-width='240'><svg viewBox="0 0 201 412" height="24" width="12" class="icon"><path d="M 165.5,0.2 V 45 H 25 c -13.8,0 -25,11.2 -25,25 V 387 c 0,13.8 11.2,25 25,25 h 150.5 c 13.8,0 25,-11.2 25,-25 V 0.2 h -35 z M 65.2,366.5 H 34.2 v -24.5 h 31 v 24.5 z m 0,-44.3 H 34.2 v -24.5 h 31 v 24.5 z m 50.5,44.3 H 84.7 v -24.5 h 31 v 24.5 z m 0,-44.3 H 84.7 v -24.5 h 31 v 24.5 z m 50.5,44.3 h -31 v -24.5 h 31 v 24.5 z m 0,-44.3 h -31 v -24.5 h 31 v 24.5 z m 0,-59.3 h -132 V 95.4 h 132 V 262.9 z"></path></svg></button><button title="Auto (100%)" data-width="auto" class="auto is-active">Auto</button></div></div><script>(function(){var a=[{title:"actions-toolbar",filename:"actions-toolbar",url:"actions-toolbar.html"},{title:"Actions toolbar",filename:"actions-toolbar",url:"actions-toolbar.html#actions-toolbar"},{title:"Actions toolbar mixin variables",filename:"actions-toolbar",url:"actions-toolbar.html#actions-toolbar-mixin-variables"},{title:"Actions toolbar alignment",filename:"actions-toolbar",url:"actions-toolbar.html#actions-toolbar-alignment"},{title:"Reverse primary and secondary blocks",filename:"actions-toolbar",url:"actions-toolbar.html#reverse-primary-and-secondary-blocks"},{title:"Actions toolbar indents customizations",filename:"actions-toolbar",url:"actions-toolbar.html#actions-toolbar-indents-customizations"},{title:"Responsive actions toolbar",filename:"actions-toolbar",url:"actions-toolbar.html#responsive-actions-toolbar"},{title:"breadcrumbs",filename:"breadcrumbs",url:"breadcrumbs.html"},{title:"Breadcrumbs",filename:"breadcrumbs",url:"breadcrumbs.html#breadcrumbs"},{title:"Breadcrumbs variables",filename:"breadcrumbs",url:"breadcrumbs.html#breadcrumbs-variables"},{title:"Button-styled breadcrumbs with gradient background, border, and no separating symbol",filename:"breadcrumbs",url:"breadcrumbs.html#buttonstyled-breadcrumbs-with-gradient-background-border-and-no-separating-symbol"},{title:"Breadcrumbs with solid background",filename:"breadcrumbs",url:"breadcrumbs.html#breadcrumbs-with-solid-background"},{title:"buttons",filename:"buttons",url:"buttons.html"},{title:"Default button",filename:"buttons",url:"buttons.html#default-button"},{title:"Button variables",filename:"buttons",url:"buttons.html#button-variables"},{title:"Button as an icon",filename:"buttons",url:"buttons.html#button-as-an-icon"},{title:"Button with an icon on the left or right side of the text",filename:"buttons",url:"buttons.html#button-with-an-icon-on-the-left-or-right-side-of-the-text"},{title:"Button with fixed width",filename:"buttons",url:"buttons.html#button-with-fixed-width"},{title:"Primary button",filename:"buttons",url:"buttons.html#primary-button"},{title:"Primary button variables",filename:"buttons",url:"buttons.html#primary-button-variables"},{title:"Button with gradient background",filename:"buttons",url:"buttons.html#button-with-gradient-background"},{title:"Button as a link",filename:"buttons",url:"buttons.html#button-as-a-link"},{title:"Button as a link variables",filename:"buttons",url:"buttons.html#button-as-a-link-variables"},{title:"Link as a button",filename:"buttons",url:"buttons.html#link-as-a-button"},{title:"Button reset",filename:"buttons",url:"buttons.html#button-reset"},{title:"Button revert secondary color",filename:"buttons",url:"buttons.html#button-revert-secondary-color"},{title:"Button revert secondary color variables",filename:"buttons",url:"buttons.html#button-revert-secondary-color-variables"},{title:"Button revert secondary size",filename:"buttons",url:"buttons.html#button-revert-secondary-size"},{title:"Button revert secondary size variables",filename:"buttons",url:"buttons.html#button-revert-secondary-size-variables"},{title:"components",filename:"components",url:"components.html"},{title:"Components",filename:"components",url:"components.html#components"},{title:"Components Variables",filename:"components",url:"components.html#components-variables"},{title:"dropdowns",filename:"dropdowns",url:"dropdowns.html"},{title:"Drop-down and split buttons mixins",filename:"dropdowns",url:"dropdowns.html#dropdown-and-split-buttons-mixins"},{title:"Drop-down",filename:"dropdowns",url:"dropdowns.html#dropdown"},{title:"Drop-down variables",filename:"dropdowns",url:"dropdowns.html#dropdown-variables"},{title:"Drop-down with icon customization",filename:"dropdowns",url:"dropdowns.html#dropdown-with-icon-customization"},{title:"Modify dropdown list styles",filename:"dropdowns",url:"dropdowns.html#modify-dropdown-list-styles"},{title:"Split button",filename:"dropdowns",url:"dropdowns.html#split-button"},{title:"Split button variables",filename:"dropdowns",url:"dropdowns.html#split-button-variables"},{title:"Split button - button styling",filename:"dropdowns",url:"dropdowns.html#split-button-button-styling"},{title:"Split button icon customization",filename:"dropdowns",url:"dropdowns.html#split-button-icon-customization"},{title:"Split button drop-down list customization",filename:"dropdowns",url:"dropdowns.html#split-button-dropdown-list-customization"},{title:"forms",filename:"forms",url:"forms.html"},{title:"Forms mixins",filename:"forms",url:"forms.html#forms-mixins"},{title:"Global forms elements customization",filename:"forms",url:"forms.html#global-forms-elements-customization"},{title:"Fieldsets & fields customization",filename:"forms",url:"forms.html#fieldsets-fields-customization"},{title:"Fieldset and legend customization variables",filename:"forms",url:"forms.html#fieldset-and-legend-customization-variables"},{title:"Fields customization variables",filename:"forms",url:"forms.html#fields-customization-variables"},{title:"Required fields message customization variables",filename:"forms",url:"forms.html#required-fields-message-customization-variables"},{title:"Form element inputs customization",filename:"forms",url:"forms.html#form-element-inputs-customization"},{title:"Form element inputs customization variables",filename:"forms",url:"forms.html#form-element-inputs-customization-variables"},{title:"Form element choice",filename:"forms",url:"forms.html#form-element-choice"},{title:"Form element choice variables",filename:"forms",url:"forms.html#form-element-choice-variables"},{title:"Custom color",filename:"forms",url:"forms.html#custom-color"},{title:"Input number - input-text view",filename:"forms",url:"forms.html#input-number-inputtext-view"},{title:"Input search - input-text view",filename:"forms",url:"forms.html#input-search-inputtext-view"},{title:"Form validation",filename:"forms",url:"forms.html#form-validation"},{title:"Form validation variables",filename:"forms",url:"forms.html#form-validation-variables"},{title:"icons",filename:"icons",url:"icons.html"},{title:"Icons",filename:"icons",url:"icons.html#icons"},{title:"Icon with image or sprite",filename:"icons",url:"icons.html#icon-with-image-or-sprite"},{title:"Icon with image or sprite variables",filename:"icons",url:"icons.html#icon-with-image-or-sprite-variables"},{title:"Icon position for an icon with image or sprite",filename:"icons",url:"icons.html#icon-position-for-an-icon-with-image-or-sprite"},{title:"Position for icon with image or sprite mixin variables",filename:"icons",url:"icons.html#position-for-icon-with-image-or-sprite-mixin-variables"},{title:"Icon sprite position (with grid)",filename:"icons",url:"icons.html#icon-sprite-position-with-grid"},{title:"Icon sprite position variables",filename:"icons",url:"icons.html#icon-sprite-position-variables"},{title:"Image/sprite icon size",filename:"icons",url:"icons.html#imagesprite-icon-size"},{title:"Image/sprite icon size variables",filename:"icons",url:"icons.html#imagesprite-icon-size-variables"},{title:"Font icon",filename:"icons",url:"icons.html#font-icon"},{title:"Font icon variables",filename:"icons",url:"icons.html#font-icon-variables"},{title:"Change the size of font icon",filename:"icons",url:"icons.html#change-the-size-of-font-icon"},{title:"Change the size of font icon variables",filename:"icons",url:"icons.html#change-the-size-of-font-icon-variables"},{title:"Hide icon text",filename:"icons",url:"icons.html#hide-icon-text"},{title:"Sprite and font icons for Blank theme",filename:"icons",url:"icons.html#sprite-and-font-icons-for-blank-theme"},{title:"layout",filename:"layout",url:"layout.html"},{title:"Layout",filename:"layout",url:"layout.html#layout"},{title:"Layout global variables",filename:"layout",url:"layout.html#layout-global-variables"},{title:"Page layouts",filename:"layout",url:"layout.html#page-layouts"},{title:"Layout column",filename:"layout",url:"layout.html#layout-column"},{title:"Layout column variables",filename:"layout",url:"layout.html#layout-column-variables"},{title:"Layout width",filename:"layout",url:"layout.html#layout-width"},{title:"Layout width variables",filename:"layout",url:"layout.html#layout-width-variables"},{title:"lib",filename:"lib",url:"lib.html"},{title:"Including Magento UI library to your theme",filename:"lib",url:"lib.html#including-magento-ui-library-to-your-theme"},{title:"loaders",filename:"loaders",url:"loaders.html"},{title:"Loaders",filename:"loaders",url:"loaders.html#loaders"},{title:"Default loader variables",filename:"loaders",url:"loaders.html#default-loader-variables"},{title:"Loading",filename:"loaders",url:"loaders.html#loading"},{title:"Loading default variables",filename:"loaders",url:"loaders.html#loading-default-variables"},{title:"messages",filename:"messages",url:"messages.html"},{title:"Messages",filename:"messages",url:"messages.html#messages"},{title:"Information message",filename:"messages",url:"messages.html#information-message"},{title:"Warning message",filename:"messages",url:"messages.html#warning-message"},{title:"Error message",filename:"messages",url:"messages.html#error-message"},{title:"Success message",filename:"messages",url:"messages.html#success-message"},{title:"Notice message",filename:"messages",url:"messages.html#notice-message"},{title:"Message with inner icon",filename:"messages",url:"messages.html#message-with-inner-icon"},{title:"Message with lateral icon",filename:"messages",url:"messages.html#message-with-lateral-icon"},{title:"Custom message style",filename:"messages",url:"messages.html#custom-message-style"},{title:"Messages global variables",filename:"messages",url:"messages.html#messages-global-variables"},{title:"pages",filename:"pages",url:"pages.html"},{title:"Pagination HTML markup",filename:"pages",url:"pages.html#pagination-html-markup"},{title:"Pagination variables",filename:"pages",url:"pages.html#pagination-variables"},{title:"Pagination with label and gradient background on links",filename:"pages",url:"pages.html#pagination-with-label-and-gradient-background-on-links"},{title:'Pagination with "previous"..."next" text links and label',filename:"pages",url:"pages.html#pagination-with-previousnext-text-links-and-label"},{title:"Pagination without label, with solid background",filename:"pages",url:"pages.html#pagination-without-label-with-solid-background"},{title:"popups",filename:"popups",url:"popups.html"},{title:"Popups",filename:"popups",url:"popups.html#popups"},{title:"Popup variables",filename:"popups",url:"popups.html#popup-variables"},{title:"Window overlay mixin variables",filename:"popups",url:"popups.html#window-overlay-mixin-variables"},{title:"Fixed height popup",filename:"popups",url:"popups.html#fixed-height-popup"},{title:"Fixed content height popup",filename:"popups",url:"popups.html#fixed-content-height-popup"},{title:"Margins for header, content and footer block in popup",filename:"popups",url:"popups.html#margins-for-header-content-and-footer-block-in-popup"},{title:"Popup titles styled as theme headings",filename:"popups",url:"popups.html#popup-titles-styled-as-theme-headings"},{title:"Popup action toolbar",filename:"popups",url:"popups.html#popup-action-toolbar"},{title:"Popup Close button without an icon",filename:"popups",url:"popups.html#popup-close-button-without-an-icon"},{title:"Modify the icon of popup Close button",filename:"popups",url:"popups.html#modify-the-icon-of-popup-close-button"},{title:"Modify overlay styles",filename:"popups",url:"popups.html#modify-overlay-styles"},{title:"rating",filename:"rating",url:"rating.html"},{title:"Ratings",filename:"rating",url:"rating.html#ratings"},{title:"Global rating variables",filename:"rating",url:"rating.html#global-rating-variables"},{title:"Rating with vote",filename:"rating",url:"rating.html#rating-with-vote"},{title:"Rating with vote icons number customization",filename:"rating",url:"rating.html#rating-with-vote-icons-number-customization"},{title:"Rating with vote icons colors customization",filename:"rating",url:"rating.html#rating-with-vote-icons-colors-customization"},{title:"Rating with vote icons symbol customization",filename:"rating",url:"rating.html#rating-with-vote-icons-symbol-customization"},{title:"Accessible rating with vote",filename:"rating",url:"rating.html#accessible-rating-with-vote"},{title:"Rating summary",filename:"rating",url:"rating.html#rating-summary"},{title:"Rating summary icons number customization",filename:"rating",url:"rating.html#rating-summary-icons-number-customization"},{title:"Rating summary icons color customization",filename:"rating",url:"rating.html#rating-summary-icons-color-customization"},{title:"Rating summary icons symbol customization",filename:"rating",url:"rating.html#rating-summary-icons-symbol-customization"},{title:"Rating summary hide label",filename:"rating",url:"rating.html#rating-summary-hide-label"},{title:"Rating summary multiple ratings",filename:"rating",url:"rating.html#rating-summary-multiple-ratings"},{title:"Rating hide label mixin",filename:"rating",url:"rating.html#rating-hide-label-mixin"},{title:"resets",filename:"resets",url:"resets.html"},{title:"Resets",filename:"resets",url:"resets.html#resets"},{title:"responsive",filename:"responsive",url:"responsive.html"},{title:"Responsive",filename:"responsive",url:"responsive.html#responsive"},{title:"Responsive mixins usage",filename:"responsive",url:"responsive.html#responsive-mixins-usage"},{title:"Media query style groups separation variables",filename:"responsive",url:"responsive.html#media-query-style-groups-separation-variables"},{title:"Responsive breakpoints",filename:"responsive",url:"responsive.html#responsive-breakpoints"},{title:"sections",filename:"sections",url:"sections.html"},{title:"Tabs and accordions",filename:"sections",url:"sections.html#tabs-and-accordions"},{title:"Tabs",filename:"sections",url:"sections.html#tabs"},{title:"Tabs mixin variables",filename:"sections",url:"sections.html#tabs-mixin-variables"},{title:"Tabs with content top border",filename:"sections",url:"sections.html#tabs-with-content-top-border"},{title:"Accordion",filename:"sections",url:"sections.html#accordion"},{title:"Accordion mixin variables",filename:"sections",url:"sections.html#accordion-mixin-variables"},{title:"Responsive tabs",filename:"sections",url:"sections.html#responsive-tabs"},{title:"Tabs Base",filename:"sections",url:"sections.html#tabs-base"},{title:"Accordion Base",filename:"sections",url:"sections.html#accordion-base"},{title:"tables",filename:"tables",url:"tables.html"},{title:"Tables",filename:"tables",url:"tables.html#tables"},{title:"Table mixin variables",filename:"tables",url:"tables.html#table-mixin-variables"},{title:"Table typography",filename:"tables",url:"tables.html#table-typography"},{title:"Table typography mixin variables",filename:"tables",url:"tables.html#table-typography-mixin-variables"},{title:"Table caption",filename:"tables",url:"tables.html#table-caption"},{title:"Table caption mixin variables",filename:"tables",url:"tables.html#table-caption-mixin-variables"},{title:"Table cells resize",filename:"tables",url:"tables.html#table-cells-resize"},{title:"Table cells resize variables",filename:"tables",url:"tables.html#table-cells-resize-variables"},{title:"Table background customization",filename:"tables",url:"tables.html#table-background-customization"},{title:"Table background mixin variables",filename:"tables",url:"tables.html#table-background-mixin-variables"},{title:"Table borders customization",filename:"tables",url:"tables.html#table-borders-customization"},{title:"Table borders mixin variables",filename:"tables",url:"tables.html#table-borders-mixin-variables"},{title:"Table with horizontal borders",filename:"tables",url:"tables.html#table-with-horizontal-borders"},{title:"Table with vertical borders",filename:"tables",url:"tables.html#table-with-vertical-borders"},{title:"Table with light borders",filename:"tables",url:"tables.html#table-with-light-borders"},{title:"Table without borders",filename:"tables",url:"tables.html#table-without-borders"},{title:"Striped table",filename:"tables",url:"tables.html#striped-table"},{title:"Striped table mixin variables",filename:"tables",url:"tables.html#striped-table-mixin-variables"},{title:"Table with rows hover",filename:"tables",url:"tables.html#table-with-rows-hover"},{title:"Table with rows hover mixin variables",filename:"tables",url:"tables.html#table-with-rows-hover-mixin-variables"},{title:"Responsive table technics #1",filename:"tables",url:"tables.html#responsive-table-technics-1"},{title:"Responsive table technics #2",filename:"tables",url:"tables.html#responsive-table-technics-2"},{title:"Responsive table technics #2 mixin variables",filename:"tables",url:"tables.html#responsive-table-technics-2-mixin-variables"},{title:"tooltips",filename:"tooltips",url:"tooltips.html"},{title:"Tooltips",filename:"tooltips",url:"tooltips.html#tooltips"},{title:"Tooltips variables",filename:"tooltips",url:"tooltips.html#tooltips-variables"},{title:"typography",filename:"typography",url:"typography.html"},{title:"Typogrphy",filename:"typography",url:"typography.html#typogrphy"},{title:"Typography variables",filename:"typography",url:"typography.html#typography-variables"},{title:"Font-size mixin",filename:"typography",url:"typography.html#fontsize-mixin"},{title:"Line-height mixin",filename:"typography",url:"typography.html#lineheight-mixin"},{title:"Word breaking mixin",filename:"typography",url:"typography.html#word-breaking-mixin"},{title:"Font face mixin",filename:"typography",url:"typography.html#font-face-mixin"},{title:"Text overflow mixin",filename:"typography",url:"typography.html#text-overflow-mixin"},{title:"Text hide",filename:"typography",url:"typography.html#text-hide"},{title:"Hyphens",filename:"typography",url:"typography.html#hyphens"},{title:"Font style and color",filename:"typography",url:"typography.html#font-style-and-color"},{title:"Font style mixin variables",filename:"typography",url:"typography.html#font-style-mixin-variables"},{title:"Reset list styles",filename:"typography",url:"typography.html#reset-list-styles"},{title:"Reset list styles variables",filename:"typography",url:"typography.html#reset-list-styles-variables"},{title:"Inline-block list item styling",filename:"typography",url:"typography.html#inlineblock-list-item-styling"},{title:"Link styling mixin",filename:"typography",url:"typography.html#link-styling-mixin"},{title:"Link styling mixin variables",filename:"typography",url:"typography.html#link-styling-mixin-variables"},{title:"Heading styling mixin",filename:"typography",url:"typography.html#heading-styling-mixin"},{title:"Base typography mixins",filename:"typography",url:"typography.html#base-typography-mixins"},{title:"Base typography mixin variables",filename:"typography",url:"typography.html#base-typography-mixin-variables"},{title:"Headings typography mixin",filename:"typography",url:"typography.html#headings-typography-mixin"},{title:"Headings typography mixin variables",filename:"typography",url:"typography.html#headings-typography-mixin-variables"},{title:"Typography links mixin",filename:"typography",url:"typography.html#typography-links-mixin"},{title:"Typography lists mixin",filename:"typography",url:"typography.html#typography-lists-mixin"},{title:"Typography lists mixin variables",filename:"typography",url:"typography.html#typography-lists-mixin-variables"},{title:"Typography code elements mixin",filename:"typography",url:"typography.html#typography-code-elements-mixin"},{title:"Typography code mixin variables",filename:"typography",url:"typography.html#typography-code-mixin-variables"},{title:"Typography blockquote",filename:"typography",url:"typography.html#typography-blockquote"},{title:"Typography blockquote mixin variables",filename:"typography",url:"typography.html#typography-blockquote-mixin-variables"},{title:"utilities",filename:"utilities",url:"utilities.html"},{title:"Utilities",filename:"utilities",url:"utilities.html#utilities"},{title:".lib-clearfix()",filename:"utilities",url:"utilities.html#libclearfix"},{title:".lib-visibility-hidden()",filename:"utilities",url:"utilities.html#libvisibilityhidden"},{title:".lib-visually-hidden()",filename:"utilities",url:"utilities.html#libvisuallyhidden"},{title:".lib-visually-hidden-reset()",filename:"utilities",url:"utilities.html#libvisuallyhiddenreset"},{title:".lib-css()",filename:"utilities",url:"utilities.html#libcss"},{title:".lib-css() variables",filename:"utilities",url:"utilities.html#libcss-variables"},{title:".lib-rotate()",filename:"utilities",url:"utilities.html#librotate"},{title:".lib-rotate() variables",filename:"utilities",url:"utilities.html#librotate-variables"},{title:".lib-input-placeholder()",filename:"utilities",url:"utilities.html#libinputplaceholder"},{title:".lib-input-placeholder() variables",filename:"utilities",url:"utilities.html#libinputplaceholder-variables"},{title:".lib-background-gradient()",filename:"utilities",url:"utilities.html#libbackgroundgradient"},{title:".lib-background-gradient() variables",filename:"utilities",url:"utilities.html#libbackgroundgradient-variables"},{title:"variables",filename:"variables",url:"variables.html"},{title:"List of Global Variables",filename:"variables",url:"variables.html#list-of-global-variables"},{title:"Table with rows hover mixin variables",filename:"variables",url:"variables.html#table-with-rows-hover-mixin-variables"},{title:"docs",filename:"docs",url:"docs.html"},{title:"Documentation",filename:"docs",url:"docs.html#documentation"}];(function(){"use strict";var b=function(a,b){return Array.prototype.indexOf.call(a,b)!==-1},c=function(a,b){return Array.prototype.filter.call(a,b)},d=function(a,b){return Array.prototype.forEach.call(a,b)},e=document.getElementsByTagName("body")[0];e.addEventListener("click",function(a){var b=a.target;b.tagName.toLowerCase()==="svg"&&(b=b.parentNode);var c=!1;b.dataset.toggle!=null&&(a.preventDefault(),b.classList.contains("is-active")||(c=!0)),d(e.querySelectorAll("[data-toggle]"),function(a){a.classList.remove("is-active"),document.getElementById(a.dataset.toggle).hidden=!0}),c&&(b.classList.add("is-active"),document.getElementById(b.dataset.toggle).hidden=!1)}),function(){var f=e.getElementsByClassName("nav")[0];if(!f)return;var g=document.createElement("ul");g.className="nav-results",g.id="nav-search",g.hidden=!0,d(a,function(a){var b,c,d;b=document.createElement("li"),b._title=a.title.toLowerCase(),b.hidden=!0,b.appendChild(c=document.createElement("a")),c.href=a.url,c.innerHTML=a.title,c.appendChild(d=document.createElement("span")),d.innerHTML=a.filename,d.className="nav-results-filename",g.appendChild(b)}),f.appendChild(g);var h=g.children,i=function(a){d(h,function(a){a.hidden=!0});var b=this.value.toLowerCase(),e=[];b!==""&&(e=c(h,function(a){return a._title.indexOf(b)!==-1})),e.length>0?(d(e,function(a){a.hidden=!1}),g.hidden=!1):g.hidden=!0},j=f.querySelector('input[type="search"]');j.addEventListener("keyup",i),j.addEventListener("focus",i),e.addEventListener("click",function(a){if(a.target.classList&&a.target.classList.contains("search"))return;g.hidden=!0}),g.addEventListener("click",function(a){j.value=""});var k=document.createElement("ul");k.id="nav-toc",k.hidden=!0,k.className="nav-results toc-list",c(e.getElementsByTagName("*"),function(a){return b(["h1","h2","h3"],a.tagName.toLowerCase())}).map(function(a){var b=document.createElement("li"),c=document.createElement("a"),d=a.tagName.toLowerCase()[1];c.classList.add("level-"+d),b.appendChild(c),c.href="#"+a.id,c.innerHTML=a.innerHTML,k.appendChild(b)}),f.appendChild(k)}()})(),function(){"use strict";if(location.hash==="#__preview__"||location.protocol==="data:")return;var a=function(a,b){return Array.prototype.forEach.call(a,b)},b=function(a,b){var e=Array.prototype.slice.call(arguments,2);return d(a,function(a){return(c(b)?b||a:a[b]).apply(a,e)})},c=function(a){return Object.prototype.toString.call(a)==="[object Function]"},d=function(a,b){return Array.prototype.map.call(a,b)},e=function(a,b){return d(a,function(a){return a[b]})},f=function(a){var b={},c=a.split(";");for(var d=0;c.length>d;d++){var e=c[d].trim().split("=");b[e[0]]=e[1]}return b},g=function(a,c){return b(e(a,"classList"),"remove",c)},h=function(a,b){a.contentDocument.defaultView.postMessage(b,"*")},i=document.getElementsByTagName("head")[0],j=document.getElementsByTagName("body")[0],k=e(i.querySelectorAll('style[type="text/preview"]'),"innerHTML").join(""),l=e(i.querySelectorAll('script[type="text/preview"]'),"innerHTML").join(""),m=location.href.split("#")[0]+"#__preview__",n=document.createElement("iframe");n.src="data:text/html,",j.appendChild(n),n.addEventListener("load",function(){var b={sameOriginDataUri:!0};try{this.contentDocument,this.contentDocument||(b.sameOriginDataUri=!1)}catch(c){b.sameOriginDataUri=!1}this.parentNode.removeChild(this),a(j.getElementsByTagName("textarea"),function(a,c){o(a,b,c),q(),p(a)})});var o=function(a,b,c){var d,e,f;d=document.createElement("div"),d.appendChild(e=document.createElement("div")),d.className="preview",e.appendChild(f=document.createElement("iframe")),e.className="resizeable",f.setAttribute("scrolling","no"),f.name="iframe"+c++,f.addEventListener("load",function(){var c,d,e,f,g,i,j;j=this.contentDocument;if(!b.sameOriginDataUri&&this.src!==m)return;this.src===m&&(c=j.createElement("html"),c.appendChild(j.createElement("head")),c.appendChild(d=j.createElement("body")),d.innerHTML=a.textContent,j.replaceChild(c,j.documentElement)),g=j.createElement("head"),g.appendChild(f=j.createElement("style")),g.appendChild(e=j.createElement("script")),e.textContent=l,f.textContent=k,i=j.getElementsByTagName("head")[0],i.parentNode.replaceChild(g,i),h(this,"getHeight")});var g;b.sameOriginDataUri?g="data:text/html;charset=utf-8,"+encodeURIComponent("<!doctype html><html><head></head></body>"+a.textContent):g=m,f.setAttribute("src",g);var i=function(){f.contentDocument.body.innerHTML=this.value,h(f,"getHeight")};a.addEventListener("keypress",i),a.addEventListener("keyup",i),a.parentNode.insertBefore(d,a)},p=function(a){var b=document.createElement("div");b.className="preview-code",b.style.position="absolute",b.style.left="-9999px",j.appendChild(b);var c=parseInt(window.getComputedStyle(a).getPropertyValue("max-height"),10),d=function(a){b.textContent=this.value+"\n";var d=b.offsetHeight+2;d>=c?this.style.overflow="auto":this.style.overflow="hidden",this.style.height=b.offsetHeight+2+"px"};a.addEventListener("keypress",d),a.addEventListener("keyup",d),d.call(a)},q=function(){var b=j.getElementsByClassName("settings")[0],c=j.getElementsByClassName("resizeable"),d=30,e=function(b){document.cookie="preview-width="+b,a(c,function(a){b==="auto"&&(b=a.parentNode.offsetWidth),a.style.width=b+"px",h(a.getElementsByTagName("iframe")[0],"getHeight")})},i=f(document.cookie)["preview-width"];if(i){e(i),g(b.getElementsByClassName("is-active"),"is-active");var k=b.querySelector('button[data-width="'+i+'"]');k&&k.classList.add("is-active")}window.addEventListener("message",function(a){if(a.data==null||!a.source)return;var b=a.data,c=document.getElementsByName(a.source.name)[0];b.height!=null&&c&&(c.parentNode.style.height=b.height+d+"px")},!1),b&&c.length>0&&(b.hidden=!1,b.addEventListener("click",function(a){var c=a.target.tagName.toLowerCase(),d;if(c==="button")d=a.target;else{if(c!=="svg")return;d=a.target.parentNode}a.preventDefault(),g(b.getElementsByClassName("is-active"),"is-active"),d.classList.add("is-active");var f=d.dataset.width;e(f)}))}}()})()</script></body></html><!-- Generated with StyleDocco (http://jacobrask.github.com/styledocco). --> diff --git a/lib/web/css/docs/sections.html b/lib/web/css/docs/sections.html index c433216775ef4..8ed121578757a 100644 --- a/lib/web/css/docs/sections.html +++ b/lib/web/css/docs/sections.html @@ -643,4 +643,4 @@ </dl></textarea> </div><div class="code"><pre><code>.example-sections-6 { .lib-data-accordion__base(); -}</code></pre></div></article></section><div class="bar bottom"><div hidden class="settings container"><!-- Icons from http://iconmonstr.com--><button title="Desktop (1280)" data-width='1280'><svg viewBox="0 0 412 386" height="24" width="26" class="icon"><path d="m147.6,343.9c-4.5,15.9-26.2,37.6-42.1,42.1h201c-15.3,-4-38.1,-26.8-42.1,-42.1H147.6zM387,0.5H25c-13.8,0-25,11.2-25,25V294c0,13.8 11.2,25 25,25h362c13.8,0 25,-11.2 25,-25V25.5C412,11.7 400.8,0.5 387,0.5zM369.9,238.2H42.1L42.1,42.6 369.9,42.6V238.2z"></path></svg></button><button title="Laptop (1024)" data-width='1024'><svg viewBox="0 0 384 312" height="23" width="28" class="icon"><path d="m349.2,20.5c0,-11-9,-20-20,-20H53.6c-11,0-20,9-20,20v194H349.2v-194zm-27,167H60.6V27.5H322.2v160zm28,42H32.6L2.6,282.1c-3.5,6.2-3.5,13.8 0.1,19.9 3.6,6.2 10.2,9.9 17.3,9.9H363.1c7.1,0 13.7,-3.8 17.3,-10 3.6,-6.2 3.6,-13.8 0,-20l-30.2,-52.5zm-196.9,54 8,-23.5h60.5l8,23.5h-76.5z"></path></svg></button><button title="Tablet (768)" data-width='768'><svg viewBox="0 0 317 412" height="24" width="18" class="icon"><path d="M 316.5,380 V 32 c 0,-17.7 -14.3,-32 -32,-32 H 32 C 14.3,0 0,14.3 0,32 v 348 c 0,17.7 14.3,32 32,32 h 252.5 c 17.7,0 32,-14.3 32,-32 z M 40,367 V 45 H 276.5 V 367 H 40 z m 109.8,22.7 c 0,-4.7 3.8,-8.5 8.5,-8.5 4.7,0 8.5,3.8 8.5,8.5 0,4.7 -3.8,8.5 -8.5,8.5 -4.7,0 -8.5,-3.8 -8.5,-8.5 z"></path></svg></button><button title="Smart phone (320)" data-width='320'><svg viewBox="0 0 224 412" height="24" width="13" class="icon"><path d="M 190.7,0 H 33 C 14.8,0 0,14.8 0,33 v 346 c 0,18.2 14.8,33 33,33 h 157.7 c 18.2,0 33,-14.8 33,-33 V 33 c 0,-18.2 -14.8,-33 -33,-33 z M 94.3,30.2 h 37 c 2.2,0 4,1.8 4,4 0,2.2 -1.8,4 -4,4 h -37 c -2.2,0 -4,-1.8 -4,-4 0,-2.2 1.8,-4 4,-4 z m 18.5,362.8 c -8.8,0 -16,-7.2 -16,-16 0,-8.8 7.2,-16 16,-16 8.8,0 16,7.2 16,16 0,8.8 -7.2,16 -16,16 z M 198.6,343.8 H 25.1 V 68.2 h 173.5 v 275.5 z"></path></svg></button><button title="Feature phone (240)" data-width='240'><svg viewBox="0 0 201 412" height="24" width="12" class="icon"><path d="M 165.5,0.2 V 45 H 25 c -13.8,0 -25,11.2 -25,25 V 387 c 0,13.8 11.2,25 25,25 h 150.5 c 13.8,0 25,-11.2 25,-25 V 0.2 h -35 z M 65.2,366.5 H 34.2 v -24.5 h 31 v 24.5 z m 0,-44.3 H 34.2 v -24.5 h 31 v 24.5 z m 50.5,44.3 H 84.7 v -24.5 h 31 v 24.5 z m 0,-44.3 H 84.7 v -24.5 h 31 v 24.5 z m 50.5,44.3 h -31 v -24.5 h 31 v 24.5 z m 0,-44.3 h -31 v -24.5 h 31 v 24.5 z m 0,-59.3 h -132 V 95.4 h 132 V 262.9 z"></path></svg></button><button title="Auto (100%)" data-width="auto" class="auto is-active">Auto</button></div></div><script>(function(){var a=[{title:"actions-toolbar",filename:"actions-toolbar",url:"actions-toolbar.html"},{title:"Actions toolbar",filename:"actions-toolbar",url:"actions-toolbar.html#actions-toolbar"},{title:"Actions toolbar mixin variables",filename:"actions-toolbar",url:"actions-toolbar.html#actions-toolbar-mixin-variables"},{title:"Actions toolbar alignment",filename:"actions-toolbar",url:"actions-toolbar.html#actions-toolbar-alignment"},{title:"Reverse primary and secondary blocks",filename:"actions-toolbar",url:"actions-toolbar.html#reverse-primary-and-secondary-blocks"},{title:"Actions toolbar indents customizations",filename:"actions-toolbar",url:"actions-toolbar.html#actions-toolbar-indents-customizations"},{title:"Responsive actions toolbar",filename:"actions-toolbar",url:"actions-toolbar.html#responsive-actions-toolbar"},{title:"breadcrumbs",filename:"breadcrumbs",url:"breadcrumbs.html"},{title:"Breadcrumbs",filename:"breadcrumbs",url:"breadcrumbs.html#breadcrumbs"},{title:"Breadcrumbs variables",filename:"breadcrumbs",url:"breadcrumbs.html#breadcrumbs-variables"},{title:"Button-styled breadcrumbs with gradient background, border, and no separating symbol",filename:"breadcrumbs",url:"breadcrumbs.html#buttonstyled-breadcrumbs-with-gradient-background-border-and-no-separating-symbol"},{title:"Breadcrumbs with solid background",filename:"breadcrumbs",url:"breadcrumbs.html#breadcrumbs-with-solid-background"},{title:"buttons",filename:"buttons",url:"buttons.html"},{title:"Default button",filename:"buttons",url:"buttons.html#default-button"},{title:"Button variables",filename:"buttons",url:"buttons.html#button-variables"},{title:"Button as an icon",filename:"buttons",url:"buttons.html#button-as-an-icon"},{title:"Button with an icon on the left or right side of the text",filename:"buttons",url:"buttons.html#button-with-an-icon-on-the-left-or-right-side-of-the-text"},{title:"Button with fixed width",filename:"buttons",url:"buttons.html#button-with-fixed-width"},{title:"Primary button",filename:"buttons",url:"buttons.html#primary-button"},{title:"Primary button variables",filename:"buttons",url:"buttons.html#primary-button-variables"},{title:"Button with gradient background",filename:"buttons",url:"buttons.html#button-with-gradient-background"},{title:"Button as a link",filename:"buttons",url:"buttons.html#button-as-a-link"},{title:"Button as a link variables",filename:"buttons",url:"buttons.html#button-as-a-link-variables"},{title:"Link as a button",filename:"buttons",url:"buttons.html#link-as-a-button"},{title:"Button reset",filename:"buttons",url:"buttons.html#button-reset"},{title:"Button revert secondary color",filename:"buttons",url:"buttons.html#button-revert-secondary-color"},{title:"Button revert secondary color variables",filename:"buttons",url:"buttons.html#button-revert-secondary-color-variables"},{title:"Button revert secondary size",filename:"buttons",url:"buttons.html#button-revert-secondary-size"},{title:"Button revert secondary size variables",filename:"buttons",url:"buttons.html#button-revert-secondary-size-variables"},{title:"components",filename:"components",url:"components.html"},{title:"Components",filename:"components",url:"components.html#components"},{title:"Components Variables",filename:"components",url:"components.html#components-variables"},{title:"dropdowns",filename:"dropdowns",url:"dropdowns.html"},{title:"Drop-down and split buttons mixins",filename:"dropdowns",url:"dropdowns.html#dropdown-and-split-buttons-mixins"},{title:"Drop-down",filename:"dropdowns",url:"dropdowns.html#dropdown"},{title:"Drop-down variables",filename:"dropdowns",url:"dropdowns.html#dropdown-variables"},{title:"Drop-down with icon customization",filename:"dropdowns",url:"dropdowns.html#dropdown-with-icon-customization"},{title:"Modify dropdown list styles",filename:"dropdowns",url:"dropdowns.html#modify-dropdown-list-styles"},{title:"Split button",filename:"dropdowns",url:"dropdowns.html#split-button"},{title:"Split button variables",filename:"dropdowns",url:"dropdowns.html#split-button-variables"},{title:"Split button - button styling",filename:"dropdowns",url:"dropdowns.html#split-button-button-styling"},{title:"Split button icon customization",filename:"dropdowns",url:"dropdowns.html#split-button-icon-customization"},{title:"Split button drop-down list customization",filename:"dropdowns",url:"dropdowns.html#split-button-dropdown-list-customization"},{title:"forms",filename:"forms",url:"forms.html"},{title:"Forms mixins",filename:"forms",url:"forms.html#forms-mixins"},{title:"Global forms elements customization",filename:"forms",url:"forms.html#global-forms-elements-customization"},{title:"Fieldsets & fields customization",filename:"forms",url:"forms.html#fieldsets-fields-customization"},{title:"Fieldset and legend customization variables",filename:"forms",url:"forms.html#fieldset-and-legend-customization-variables"},{title:"Fields customization variables",filename:"forms",url:"forms.html#fields-customization-variables"},{title:"Required fields message customization variables",filename:"forms",url:"forms.html#required-fields-message-customization-variables"},{title:"Form element inputs customization",filename:"forms",url:"forms.html#form-element-inputs-customization"},{title:"Form element inputs customization variables",filename:"forms",url:"forms.html#form-element-inputs-customization-variables"},{title:"Form element choice",filename:"forms",url:"forms.html#form-element-choice"},{title:"Form element choice variables",filename:"forms",url:"forms.html#form-element-choice-variables"},{title:"Custom color",filename:"forms",url:"forms.html#custom-color"},{title:"Input number - input-text view",filename:"forms",url:"forms.html#input-number-inputtext-view"},{title:"Input search - input-text view",filename:"forms",url:"forms.html#input-search-inputtext-view"},{title:"Form validation",filename:"forms",url:"forms.html#form-validation"},{title:"Form validation variables",filename:"forms",url:"forms.html#form-validation-variables"},{title:"icons",filename:"icons",url:"icons.html"},{title:"Icons",filename:"icons",url:"icons.html#icons"},{title:"Icon with image or sprite",filename:"icons",url:"icons.html#icon-with-image-or-sprite"},{title:"Icon with image or sprite variables",filename:"icons",url:"icons.html#icon-with-image-or-sprite-variables"},{title:"Icon position for an icon with image or sprite",filename:"icons",url:"icons.html#icon-position-for-an-icon-with-image-or-sprite"},{title:"Position for icon with image or sprite mixin variables",filename:"icons",url:"icons.html#position-for-icon-with-image-or-sprite-mixin-variables"},{title:"Icon sprite position (with grid)",filename:"icons",url:"icons.html#icon-sprite-position-with-grid"},{title:"Icon sprite position variables",filename:"icons",url:"icons.html#icon-sprite-position-variables"},{title:"Image/sprite icon size",filename:"icons",url:"icons.html#imagesprite-icon-size"},{title:"Image/sprite icon size variables",filename:"icons",url:"icons.html#imagesprite-icon-size-variables"},{title:"Font icon",filename:"icons",url:"icons.html#font-icon"},{title:"Font icon variables",filename:"icons",url:"icons.html#font-icon-variables"},{title:"Change the size of font icon",filename:"icons",url:"icons.html#change-the-size-of-font-icon"},{title:"Change the size of font icon variables",filename:"icons",url:"icons.html#change-the-size-of-font-icon-variables"},{title:"Hide icon text",filename:"icons",url:"icons.html#hide-icon-text"},{title:"Sprite and font icons for Blank theme",filename:"icons",url:"icons.html#sprite-and-font-icons-for-blank-theme"},{title:"layout",filename:"layout",url:"layout.html"},{title:"Layout",filename:"layout",url:"layout.html#layout"},{title:"Layout global variables",filename:"layout",url:"layout.html#layout-global-variables"},{title:"Page layouts",filename:"layout",url:"layout.html#page-layouts"},{title:"Layout column",filename:"layout",url:"layout.html#layout-column"},{title:"Layout column variables",filename:"layout",url:"layout.html#layout-column-variables"},{title:"Layout width",filename:"layout",url:"layout.html#layout-width"},{title:"Layout width variables",filename:"layout",url:"layout.html#layout-width-variables"},{title:"lib",filename:"lib",url:"lib.html"},{title:"Including Magento UI library to your theme",filename:"lib",url:"lib.html#including-magento-ui-library-to-your-theme"},{title:"loaders",filename:"loaders",url:"loaders.html"},{title:"Loaders",filename:"loaders",url:"loaders.html#loaders"},{title:"Default loader variables",filename:"loaders",url:"loaders.html#default-loader-variables"},{title:"Loading",filename:"loaders",url:"loaders.html#loading"},{title:"Loading default variables",filename:"loaders",url:"loaders.html#loading-default-variables"},{title:"messages",filename:"messages",url:"messages.html"},{title:"Messages",filename:"messages",url:"messages.html#messages"},{title:"Information message",filename:"messages",url:"messages.html#information-message"},{title:"Warning message",filename:"messages",url:"messages.html#warning-message"},{title:"Error message",filename:"messages",url:"messages.html#error-message"},{title:"Success message",filename:"messages",url:"messages.html#success-message"},{title:"Notice message",filename:"messages",url:"messages.html#notice-message"},{title:"Message with inner icon",filename:"messages",url:"messages.html#message-with-inner-icon"},{title:"Message with lateral icon",filename:"messages",url:"messages.html#message-with-lateral-icon"},{title:"Custom message style",filename:"messages",url:"messages.html#custom-message-style"},{title:"Messages global variables",filename:"messages",url:"messages.html#messages-global-variables"},{title:"pages",filename:"pages",url:"pages.html"},{title:"Pagination HTML markup",filename:"pages",url:"pages.html#pagination-html-markup"},{title:"Pagination variables",filename:"pages",url:"pages.html#pagination-variables"},{title:"Pagination with label and gradient background on links",filename:"pages",url:"pages.html#pagination-with-label-and-gradient-background-on-links"},{title:'Pagination with "previous"..."next" text links and label',filename:"pages",url:"pages.html#pagination-with-previousnext-text-links-and-label"},{title:"Pagination without label, with solid background",filename:"pages",url:"pages.html#pagination-without-label-with-solid-background"},{title:"popups",filename:"popups",url:"popups.html"},{title:"Popups",filename:"popups",url:"popups.html#popups"},{title:"Popup variables",filename:"popups",url:"popups.html#popup-variables"},{title:"Window overlay mixin variables",filename:"popups",url:"popups.html#window-overlay-mixin-variables"},{title:"Fixed height popup",filename:"popups",url:"popups.html#fixed-height-popup"},{title:"Fixed content height popup",filename:"popups",url:"popups.html#fixed-content-height-popup"},{title:"Margins for header, content and footer block in popup",filename:"popups",url:"popups.html#margins-for-header-content-and-footer-block-in-popup"},{title:"Popup titles styled as theme headings",filename:"popups",url:"popups.html#popup-titles-styled-as-theme-headings"},{title:"Popup action toolbar",filename:"popups",url:"popups.html#popup-action-toolbar"},{title:"Popup Close button without an icon",filename:"popups",url:"popups.html#popup-close-button-without-an-icon"},{title:"Modify the icon of popup Close button",filename:"popups",url:"popups.html#modify-the-icon-of-popup-close-button"},{title:"Modify overlay styles",filename:"popups",url:"popups.html#modify-overlay-styles"},{title:"rating",filename:"rating",url:"rating.html"},{title:"Ratings",filename:"rating",url:"rating.html#ratings"},{title:"Global rating variables",filename:"rating",url:"rating.html#global-rating-variables"},{title:"Rating with vote",filename:"rating",url:"rating.html#rating-with-vote"},{title:"Rating with vote icons number customization",filename:"rating",url:"rating.html#rating-with-vote-icons-number-customization"},{title:"Rating with vote icons colors customization",filename:"rating",url:"rating.html#rating-with-vote-icons-colors-customization"},{title:"Rating with vote icons symbol customization",filename:"rating",url:"rating.html#rating-with-vote-icons-symbol-customization"},{title:"Accessible rating with vote",filename:"rating",url:"rating.html#accessible-rating-with-vote"},{title:"Rating summary",filename:"rating",url:"rating.html#rating-summary"},{title:"Rating summary icons number customization",filename:"rating",url:"rating.html#rating-summary-icons-number-customization"},{title:"Rating summary icons color customization",filename:"rating",url:"rating.html#rating-summary-icons-color-customization"},{title:"Rating summary icons symbol customization",filename:"rating",url:"rating.html#rating-summary-icons-symbol-customization"},{title:"Rating summary hide label",filename:"rating",url:"rating.html#rating-summary-hide-label"},{title:"Rating summary multiple ratings",filename:"rating",url:"rating.html#rating-summary-multiple-ratings"},{title:"Rating hide label mixin",filename:"rating",url:"rating.html#rating-hide-label-mixin"},{title:"resets",filename:"resets",url:"resets.html"},{title:"Resets",filename:"resets",url:"resets.html#resets"},{title:"responsive",filename:"responsive",url:"responsive.html"},{title:"Responsive",filename:"responsive",url:"responsive.html#responsive"},{title:"Responsive mixins usage",filename:"responsive",url:"responsive.html#responsive-mixins-usage"},{title:"Media query style groups separation variables",filename:"responsive",url:"responsive.html#media-query-style-groups-separation-variables"},{title:"Responsive breakpoints",filename:"responsive",url:"responsive.html#responsive-breakpoints"},{title:"sections",filename:"sections",url:"sections.html"},{title:"Tabs and accordions",filename:"sections",url:"sections.html#tabs-and-accordions"},{title:"Tabs",filename:"sections",url:"sections.html#tabs"},{title:"Tabs mixin variables",filename:"sections",url:"sections.html#tabs-mixin-variables"},{title:"Tabs with content top border",filename:"sections",url:"sections.html#tabs-with-content-top-border"},{title:"Accordion",filename:"sections",url:"sections.html#accordion"},{title:"Accordion mixin variables",filename:"sections",url:"sections.html#accordion-mixin-variables"},{title:"Responsive tabs",filename:"sections",url:"sections.html#responsive-tabs"},{title:"Tabs Base",filename:"sections",url:"sections.html#tabs-base"},{title:"Accordion Base",filename:"sections",url:"sections.html#accordion-base"},{title:"tables",filename:"tables",url:"tables.html"},{title:"Tables",filename:"tables",url:"tables.html#tables"},{title:"Table mixin variables",filename:"tables",url:"tables.html#table-mixin-variables"},{title:"Table typography",filename:"tables",url:"tables.html#table-typography"},{title:"Table typography mixin variables",filename:"tables",url:"tables.html#table-typography-mixin-variables"},{title:"Table caption",filename:"tables",url:"tables.html#table-caption"},{title:"Table caption mixin variables",filename:"tables",url:"tables.html#table-caption-mixin-variables"},{title:"Table cells resize",filename:"tables",url:"tables.html#table-cells-resize"},{title:"Table cells resize variables",filename:"tables",url:"tables.html#table-cells-resize-variables"},{title:"Table background customization",filename:"tables",url:"tables.html#table-background-customization"},{title:"Table background mixin variables",filename:"tables",url:"tables.html#table-background-mixin-variables"},{title:"Table borders customization",filename:"tables",url:"tables.html#table-borders-customization"},{title:"Table borders mixin variables",filename:"tables",url:"tables.html#table-borders-mixin-variables"},{title:"Table with horizontal borders",filename:"tables",url:"tables.html#table-with-horizontal-borders"},{title:"Table with vertical borders",filename:"tables",url:"tables.html#table-with-vertical-borders"},{title:"Table with light borders",filename:"tables",url:"tables.html#table-with-light-borders"},{title:"Table without borders",filename:"tables",url:"tables.html#table-without-borders"},{title:"Striped table",filename:"tables",url:"tables.html#striped-table"},{title:"Striped table mixin variables",filename:"tables",url:"tables.html#striped-table-mixin-variables"},{title:"Table with rows hover",filename:"tables",url:"tables.html#table-with-rows-hover"},{title:"Table with rows hover mixin variables",filename:"tables",url:"tables.html#table-with-rows-hover-mixin-variables"},{title:"Responsive table technics #1",filename:"tables",url:"tables.html#responsive-table-technics-1"},{title:"Responsive table technics #2",filename:"tables",url:"tables.html#responsive-table-technics-2"},{title:"Responsive table technics #2 mixin variables",filename:"tables",url:"tables.html#responsive-table-technics-2-mixin-variables"},{title:"tooltips",filename:"tooltips",url:"tooltips.html"},{title:"Tooltips",filename:"tooltips",url:"tooltips.html#tooltips"},{title:"Tooltips variables",filename:"tooltips",url:"tooltips.html#tooltips-variables"},{title:"typography",filename:"typography",url:"typography.html"},{title:"Typogrphy",filename:"typography",url:"typography.html#typogrphy"},{title:"Typography variables",filename:"typography",url:"typography.html#typography-variables"},{title:"Font-size mixin",filename:"typography",url:"typography.html#fontsize-mixin"},{title:"Line-height mixin",filename:"typography",url:"typography.html#lineheight-mixin"},{title:"Word breaking mixin",filename:"typography",url:"typography.html#word-breaking-mixin"},{title:"Font face mixin",filename:"typography",url:"typography.html#font-face-mixin"},{title:"Text overflow mixin",filename:"typography",url:"typography.html#text-overflow-mixin"},{title:"Text hide",filename:"typography",url:"typography.html#text-hide"},{title:"Hyphens",filename:"typography",url:"typography.html#hyphens"},{title:"Font style and color",filename:"typography",url:"typography.html#font-style-and-color"},{title:"Font style mixin variables",filename:"typography",url:"typography.html#font-style-mixin-variables"},{title:"Reset list styles",filename:"typography",url:"typography.html#reset-list-styles"},{title:"Reset list styles variables",filename:"typography",url:"typography.html#reset-list-styles-variables"},{title:"Inline-block list item styling",filename:"typography",url:"typography.html#inlineblock-list-item-styling"},{title:"Link styling mixin",filename:"typography",url:"typography.html#link-styling-mixin"},{title:"Link styling mixin variables",filename:"typography",url:"typography.html#link-styling-mixin-variables"},{title:"Heading styling mixin",filename:"typography",url:"typography.html#heading-styling-mixin"},{title:"Base typography mixins",filename:"typography",url:"typography.html#base-typography-mixins"},{title:"Base typography mixin variables",filename:"typography",url:"typography.html#base-typography-mixin-variables"},{title:"Headings typography mixin",filename:"typography",url:"typography.html#headings-typography-mixin"},{title:"Headings typography mixin variables",filename:"typography",url:"typography.html#headings-typography-mixin-variables"},{title:"Typography links mixin",filename:"typography",url:"typography.html#typography-links-mixin"},{title:"Typography lists mixin",filename:"typography",url:"typography.html#typography-lists-mixin"},{title:"Typography lists mixin variables",filename:"typography",url:"typography.html#typography-lists-mixin-variables"},{title:"Typography code elements mixin",filename:"typography",url:"typography.html#typography-code-elements-mixin"},{title:"Typography code mixin variables",filename:"typography",url:"typography.html#typography-code-mixin-variables"},{title:"Typography blockquote",filename:"typography",url:"typography.html#typography-blockquote"},{title:"Typography blockquote mixin variables",filename:"typography",url:"typography.html#typography-blockquote-mixin-variables"},{title:"utilities",filename:"utilities",url:"utilities.html"},{title:"Utilities",filename:"utilities",url:"utilities.html#utilities"},{title:".lib-clearfix()",filename:"utilities",url:"utilities.html#libclearfix"},{title:".lib-visibility-hidden()",filename:"utilities",url:"utilities.html#libvisibilityhidden"},{title:".lib-visually-hidden()",filename:"utilities",url:"utilities.html#libvisuallyhidden"},{title:".lib-visually-hidden-reset()",filename:"utilities",url:"utilities.html#libvisuallyhiddenreset"},{title:".lib-css()",filename:"utilities",url:"utilities.html#libcss"},{title:".lib-css() variables",filename:"utilities",url:"utilities.html#libcss-variables"},{title:".lib-rotate()",filename:"utilities",url:"utilities.html#librotate"},{title:".lib-rotate() variables",filename:"utilities",url:"utilities.html#librotate-variables"},{title:".lib-input-placeholder()",filename:"utilities",url:"utilities.html#libinputplaceholder"},{title:".lib-input-placeholder() variables",filename:"utilities",url:"utilities.html#libinputplaceholder-variables"},{title:".lib-background-gradient()",filename:"utilities",url:"utilities.html#libbackgroundgradient"},{title:".lib-background-gradient() variables",filename:"utilities",url:"utilities.html#libbackgroundgradient-variables"},{title:".lib-url-check()",filename:"utilities",url:"utilities.html#liburlcheck"},{title:".lib-url-check() variables",filename:"utilities",url:"utilities.html#liburlcheck-variables"},{title:"variables",filename:"variables",url:"variables.html"},{title:"List of Global Variables",filename:"variables",url:"variables.html#list-of-global-variables"},{title:"Table with rows hover mixin variables",filename:"variables",url:"variables.html#table-with-rows-hover-mixin-variables"},{title:"docs",filename:"docs",url:"docs.html"},{title:"Documentation",filename:"docs",url:"docs.html#documentation"}];(function(){"use strict";var b=function(a,b){return Array.prototype.indexOf.call(a,b)!==-1},c=function(a,b){return Array.prototype.filter.call(a,b)},d=function(a,b){return Array.prototype.forEach.call(a,b)},e=document.getElementsByTagName("body")[0];e.addEventListener("click",function(a){var b=a.target;b.tagName.toLowerCase()==="svg"&&(b=b.parentNode);var c=!1;b.dataset.toggle!=null&&(a.preventDefault(),b.classList.contains("is-active")||(c=!0)),d(e.querySelectorAll("[data-toggle]"),function(a){a.classList.remove("is-active"),document.getElementById(a.dataset.toggle).hidden=!0}),c&&(b.classList.add("is-active"),document.getElementById(b.dataset.toggle).hidden=!1)}),function(){var f=e.getElementsByClassName("nav")[0];if(!f)return;var g=document.createElement("ul");g.className="nav-results",g.id="nav-search",g.hidden=!0,d(a,function(a){var b,c,d;b=document.createElement("li"),b._title=a.title.toLowerCase(),b.hidden=!0,b.appendChild(c=document.createElement("a")),c.href=a.url,c.innerHTML=a.title,c.appendChild(d=document.createElement("span")),d.innerHTML=a.filename,d.className="nav-results-filename",g.appendChild(b)}),f.appendChild(g);var h=g.children,i=function(a){d(h,function(a){a.hidden=!0});var b=this.value.toLowerCase(),e=[];b!==""&&(e=c(h,function(a){return a._title.indexOf(b)!==-1})),e.length>0?(d(e,function(a){a.hidden=!1}),g.hidden=!1):g.hidden=!0},j=f.querySelector('input[type="search"]');j.addEventListener("keyup",i),j.addEventListener("focus",i),e.addEventListener("click",function(a){if(a.target.classList&&a.target.classList.contains("search"))return;g.hidden=!0}),g.addEventListener("click",function(a){j.value=""});var k=document.createElement("ul");k.id="nav-toc",k.hidden=!0,k.className="nav-results toc-list",c(e.getElementsByTagName("*"),function(a){return b(["h1","h2","h3"],a.tagName.toLowerCase())}).map(function(a){var b=document.createElement("li"),c=document.createElement("a"),d=a.tagName.toLowerCase()[1];c.classList.add("level-"+d),b.appendChild(c),c.href="#"+a.id,c.innerHTML=a.innerHTML,k.appendChild(b)}),f.appendChild(k)}()})(),function(){"use strict";if(location.hash==="#__preview__"||location.protocol==="data:")return;var a=function(a,b){return Array.prototype.forEach.call(a,b)},b=function(a,b){var e=Array.prototype.slice.call(arguments,2);return d(a,function(a){return(c(b)?b||a:a[b]).apply(a,e)})},c=function(a){return Object.prototype.toString.call(a)==="[object Function]"},d=function(a,b){return Array.prototype.map.call(a,b)},e=function(a,b){return d(a,function(a){return a[b]})},f=function(a){var b={},c=a.split(";");for(var d=0;c.length>d;d++){var e=c[d].trim().split("=");b[e[0]]=e[1]}return b},g=function(a,c){return b(e(a,"classList"),"remove",c)},h=function(a,b){a.contentDocument.defaultView.postMessage(b,"*")},i=document.getElementsByTagName("head")[0],j=document.getElementsByTagName("body")[0],k=e(i.querySelectorAll('style[type="text/preview"]'),"innerHTML").join(""),l=e(i.querySelectorAll('script[type="text/preview"]'),"innerHTML").join(""),m=location.href.split("#")[0]+"#__preview__",n=document.createElement("iframe");n.src="data:text/html,",j.appendChild(n),n.addEventListener("load",function(){var b={sameOriginDataUri:!0};try{this.contentDocument,this.contentDocument||(b.sameOriginDataUri=!1)}catch(c){b.sameOriginDataUri=!1}this.parentNode.removeChild(this),a(j.getElementsByTagName("textarea"),function(a,c){o(a,b,c),q(),p(a)})});var o=function(a,b,c){var d,e,f;d=document.createElement("div"),d.appendChild(e=document.createElement("div")),d.className="preview",e.appendChild(f=document.createElement("iframe")),e.className="resizeable",f.setAttribute("scrolling","no"),f.name="iframe"+c++,f.addEventListener("load",function(){var c,d,e,f,g,i,j;j=this.contentDocument;if(!b.sameOriginDataUri&&this.src!==m)return;this.src===m&&(c=j.createElement("html"),c.appendChild(j.createElement("head")),c.appendChild(d=j.createElement("body")),d.innerHTML=a.textContent,j.replaceChild(c,j.documentElement)),g=j.createElement("head"),g.appendChild(f=j.createElement("style")),g.appendChild(e=j.createElement("script")),e.textContent=l,f.textContent=k,i=j.getElementsByTagName("head")[0],i.parentNode.replaceChild(g,i),h(this,"getHeight")});var g;b.sameOriginDataUri?g="data:text/html;charset=utf-8,"+encodeURIComponent("<!doctype html><html><head></head></body>"+a.textContent):g=m,f.setAttribute("src",g);var i=function(){f.contentDocument.body.innerHTML=this.value,h(f,"getHeight")};a.addEventListener("keypress",i),a.addEventListener("keyup",i),a.parentNode.insertBefore(d,a)},p=function(a){var b=document.createElement("div");b.className="preview-code",b.style.position="absolute",b.style.left="-9999px",j.appendChild(b);var c=parseInt(window.getComputedStyle(a).getPropertyValue("max-height"),10),d=function(a){b.textContent=this.value+"\n";var d=b.offsetHeight+2;d>=c?this.style.overflow="auto":this.style.overflow="hidden",this.style.height=b.offsetHeight+2+"px"};a.addEventListener("keypress",d),a.addEventListener("keyup",d),d.call(a)},q=function(){var b=j.getElementsByClassName("settings")[0],c=j.getElementsByClassName("resizeable"),d=30,e=function(b){document.cookie="preview-width="+b,a(c,function(a){b==="auto"&&(b=a.parentNode.offsetWidth),a.style.width=b+"px",h(a.getElementsByTagName("iframe")[0],"getHeight")})},i=f(document.cookie)["preview-width"];if(i){e(i),g(b.getElementsByClassName("is-active"),"is-active");var k=b.querySelector('button[data-width="'+i+'"]');k&&k.classList.add("is-active")}window.addEventListener("message",function(a){if(a.data==null||!a.source)return;var b=a.data,c=document.getElementsByName(a.source.name)[0];b.height!=null&&c&&(c.parentNode.style.height=b.height+d+"px")},!1),b&&c.length>0&&(b.hidden=!1,b.addEventListener("click",function(a){var c=a.target.tagName.toLowerCase(),d;if(c==="button")d=a.target;else{if(c!=="svg")return;d=a.target.parentNode}a.preventDefault(),g(b.getElementsByClassName("is-active"),"is-active"),d.classList.add("is-active");var f=d.dataset.width;e(f)}))}}()})()</script></body></html><!-- Generated with StyleDocco (http://jacobrask.github.com/styledocco). --> +}</code></pre></div></article></section><div class="bar bottom"><div hidden class="settings container"><!-- Icons from http://iconmonstr.com--><button title="Desktop (1280)" data-width='1280'><svg viewBox="0 0 412 386" height="24" width="26" class="icon"><path d="m147.6,343.9c-4.5,15.9-26.2,37.6-42.1,42.1h201c-15.3,-4-38.1,-26.8-42.1,-42.1H147.6zM387,0.5H25c-13.8,0-25,11.2-25,25V294c0,13.8 11.2,25 25,25h362c13.8,0 25,-11.2 25,-25V25.5C412,11.7 400.8,0.5 387,0.5zM369.9,238.2H42.1L42.1,42.6 369.9,42.6V238.2z"></path></svg></button><button title="Laptop (1024)" data-width='1024'><svg viewBox="0 0 384 312" height="23" width="28" class="icon"><path d="m349.2,20.5c0,-11-9,-20-20,-20H53.6c-11,0-20,9-20,20v194H349.2v-194zm-27,167H60.6V27.5H322.2v160zm28,42H32.6L2.6,282.1c-3.5,6.2-3.5,13.8 0.1,19.9 3.6,6.2 10.2,9.9 17.3,9.9H363.1c7.1,0 13.7,-3.8 17.3,-10 3.6,-6.2 3.6,-13.8 0,-20l-30.2,-52.5zm-196.9,54 8,-23.5h60.5l8,23.5h-76.5z"></path></svg></button><button title="Tablet (768)" data-width='768'><svg viewBox="0 0 317 412" height="24" width="18" class="icon"><path d="M 316.5,380 V 32 c 0,-17.7 -14.3,-32 -32,-32 H 32 C 14.3,0 0,14.3 0,32 v 348 c 0,17.7 14.3,32 32,32 h 252.5 c 17.7,0 32,-14.3 32,-32 z M 40,367 V 45 H 276.5 V 367 H 40 z m 109.8,22.7 c 0,-4.7 3.8,-8.5 8.5,-8.5 4.7,0 8.5,3.8 8.5,8.5 0,4.7 -3.8,8.5 -8.5,8.5 -4.7,0 -8.5,-3.8 -8.5,-8.5 z"></path></svg></button><button title="Smart phone (320)" data-width='320'><svg viewBox="0 0 224 412" height="24" width="13" class="icon"><path d="M 190.7,0 H 33 C 14.8,0 0,14.8 0,33 v 346 c 0,18.2 14.8,33 33,33 h 157.7 c 18.2,0 33,-14.8 33,-33 V 33 c 0,-18.2 -14.8,-33 -33,-33 z M 94.3,30.2 h 37 c 2.2,0 4,1.8 4,4 0,2.2 -1.8,4 -4,4 h -37 c -2.2,0 -4,-1.8 -4,-4 0,-2.2 1.8,-4 4,-4 z m 18.5,362.8 c -8.8,0 -16,-7.2 -16,-16 0,-8.8 7.2,-16 16,-16 8.8,0 16,7.2 16,16 0,8.8 -7.2,16 -16,16 z M 198.6,343.8 H 25.1 V 68.2 h 173.5 v 275.5 z"></path></svg></button><button title="Feature phone (240)" data-width='240'><svg viewBox="0 0 201 412" height="24" width="12" class="icon"><path d="M 165.5,0.2 V 45 H 25 c -13.8,0 -25,11.2 -25,25 V 387 c 0,13.8 11.2,25 25,25 h 150.5 c 13.8,0 25,-11.2 25,-25 V 0.2 h -35 z M 65.2,366.5 H 34.2 v -24.5 h 31 v 24.5 z m 0,-44.3 H 34.2 v -24.5 h 31 v 24.5 z m 50.5,44.3 H 84.7 v -24.5 h 31 v 24.5 z m 0,-44.3 H 84.7 v -24.5 h 31 v 24.5 z m 50.5,44.3 h -31 v -24.5 h 31 v 24.5 z m 0,-44.3 h -31 v -24.5 h 31 v 24.5 z m 0,-59.3 h -132 V 95.4 h 132 V 262.9 z"></path></svg></button><button title="Auto (100%)" data-width="auto" class="auto is-active">Auto</button></div></div><script>(function(){var a=[{title:"actions-toolbar",filename:"actions-toolbar",url:"actions-toolbar.html"},{title:"Actions toolbar",filename:"actions-toolbar",url:"actions-toolbar.html#actions-toolbar"},{title:"Actions toolbar mixin variables",filename:"actions-toolbar",url:"actions-toolbar.html#actions-toolbar-mixin-variables"},{title:"Actions toolbar alignment",filename:"actions-toolbar",url:"actions-toolbar.html#actions-toolbar-alignment"},{title:"Reverse primary and secondary blocks",filename:"actions-toolbar",url:"actions-toolbar.html#reverse-primary-and-secondary-blocks"},{title:"Actions toolbar indents customizations",filename:"actions-toolbar",url:"actions-toolbar.html#actions-toolbar-indents-customizations"},{title:"Responsive actions toolbar",filename:"actions-toolbar",url:"actions-toolbar.html#responsive-actions-toolbar"},{title:"breadcrumbs",filename:"breadcrumbs",url:"breadcrumbs.html"},{title:"Breadcrumbs",filename:"breadcrumbs",url:"breadcrumbs.html#breadcrumbs"},{title:"Breadcrumbs variables",filename:"breadcrumbs",url:"breadcrumbs.html#breadcrumbs-variables"},{title:"Button-styled breadcrumbs with gradient background, border, and no separating symbol",filename:"breadcrumbs",url:"breadcrumbs.html#buttonstyled-breadcrumbs-with-gradient-background-border-and-no-separating-symbol"},{title:"Breadcrumbs with solid background",filename:"breadcrumbs",url:"breadcrumbs.html#breadcrumbs-with-solid-background"},{title:"buttons",filename:"buttons",url:"buttons.html"},{title:"Default button",filename:"buttons",url:"buttons.html#default-button"},{title:"Button variables",filename:"buttons",url:"buttons.html#button-variables"},{title:"Button as an icon",filename:"buttons",url:"buttons.html#button-as-an-icon"},{title:"Button with an icon on the left or right side of the text",filename:"buttons",url:"buttons.html#button-with-an-icon-on-the-left-or-right-side-of-the-text"},{title:"Button with fixed width",filename:"buttons",url:"buttons.html#button-with-fixed-width"},{title:"Primary button",filename:"buttons",url:"buttons.html#primary-button"},{title:"Primary button variables",filename:"buttons",url:"buttons.html#primary-button-variables"},{title:"Button with gradient background",filename:"buttons",url:"buttons.html#button-with-gradient-background"},{title:"Button as a link",filename:"buttons",url:"buttons.html#button-as-a-link"},{title:"Button as a link variables",filename:"buttons",url:"buttons.html#button-as-a-link-variables"},{title:"Link as a button",filename:"buttons",url:"buttons.html#link-as-a-button"},{title:"Button reset",filename:"buttons",url:"buttons.html#button-reset"},{title:"Button revert secondary color",filename:"buttons",url:"buttons.html#button-revert-secondary-color"},{title:"Button revert secondary color variables",filename:"buttons",url:"buttons.html#button-revert-secondary-color-variables"},{title:"Button revert secondary size",filename:"buttons",url:"buttons.html#button-revert-secondary-size"},{title:"Button revert secondary size variables",filename:"buttons",url:"buttons.html#button-revert-secondary-size-variables"},{title:"components",filename:"components",url:"components.html"},{title:"Components",filename:"components",url:"components.html#components"},{title:"Components Variables",filename:"components",url:"components.html#components-variables"},{title:"dropdowns",filename:"dropdowns",url:"dropdowns.html"},{title:"Drop-down and split buttons mixins",filename:"dropdowns",url:"dropdowns.html#dropdown-and-split-buttons-mixins"},{title:"Drop-down",filename:"dropdowns",url:"dropdowns.html#dropdown"},{title:"Drop-down variables",filename:"dropdowns",url:"dropdowns.html#dropdown-variables"},{title:"Drop-down with icon customization",filename:"dropdowns",url:"dropdowns.html#dropdown-with-icon-customization"},{title:"Modify dropdown list styles",filename:"dropdowns",url:"dropdowns.html#modify-dropdown-list-styles"},{title:"Split button",filename:"dropdowns",url:"dropdowns.html#split-button"},{title:"Split button variables",filename:"dropdowns",url:"dropdowns.html#split-button-variables"},{title:"Split button - button styling",filename:"dropdowns",url:"dropdowns.html#split-button-button-styling"},{title:"Split button icon customization",filename:"dropdowns",url:"dropdowns.html#split-button-icon-customization"},{title:"Split button drop-down list customization",filename:"dropdowns",url:"dropdowns.html#split-button-dropdown-list-customization"},{title:"forms",filename:"forms",url:"forms.html"},{title:"Forms mixins",filename:"forms",url:"forms.html#forms-mixins"},{title:"Global forms elements customization",filename:"forms",url:"forms.html#global-forms-elements-customization"},{title:"Fieldsets & fields customization",filename:"forms",url:"forms.html#fieldsets-fields-customization"},{title:"Fieldset and legend customization variables",filename:"forms",url:"forms.html#fieldset-and-legend-customization-variables"},{title:"Fields customization variables",filename:"forms",url:"forms.html#fields-customization-variables"},{title:"Required fields message customization variables",filename:"forms",url:"forms.html#required-fields-message-customization-variables"},{title:"Form element inputs customization",filename:"forms",url:"forms.html#form-element-inputs-customization"},{title:"Form element inputs customization variables",filename:"forms",url:"forms.html#form-element-inputs-customization-variables"},{title:"Form element choice",filename:"forms",url:"forms.html#form-element-choice"},{title:"Form element choice variables",filename:"forms",url:"forms.html#form-element-choice-variables"},{title:"Custom color",filename:"forms",url:"forms.html#custom-color"},{title:"Input number - input-text view",filename:"forms",url:"forms.html#input-number-inputtext-view"},{title:"Input search - input-text view",filename:"forms",url:"forms.html#input-search-inputtext-view"},{title:"Form validation",filename:"forms",url:"forms.html#form-validation"},{title:"Form validation variables",filename:"forms",url:"forms.html#form-validation-variables"},{title:"icons",filename:"icons",url:"icons.html"},{title:"Icons",filename:"icons",url:"icons.html#icons"},{title:"Icon with image or sprite",filename:"icons",url:"icons.html#icon-with-image-or-sprite"},{title:"Icon with image or sprite variables",filename:"icons",url:"icons.html#icon-with-image-or-sprite-variables"},{title:"Icon position for an icon with image or sprite",filename:"icons",url:"icons.html#icon-position-for-an-icon-with-image-or-sprite"},{title:"Position for icon with image or sprite mixin variables",filename:"icons",url:"icons.html#position-for-icon-with-image-or-sprite-mixin-variables"},{title:"Icon sprite position (with grid)",filename:"icons",url:"icons.html#icon-sprite-position-with-grid"},{title:"Icon sprite position variables",filename:"icons",url:"icons.html#icon-sprite-position-variables"},{title:"Image/sprite icon size",filename:"icons",url:"icons.html#imagesprite-icon-size"},{title:"Image/sprite icon size variables",filename:"icons",url:"icons.html#imagesprite-icon-size-variables"},{title:"Font icon",filename:"icons",url:"icons.html#font-icon"},{title:"Font icon variables",filename:"icons",url:"icons.html#font-icon-variables"},{title:"Change the size of font icon",filename:"icons",url:"icons.html#change-the-size-of-font-icon"},{title:"Change the size of font icon variables",filename:"icons",url:"icons.html#change-the-size-of-font-icon-variables"},{title:"Hide icon text",filename:"icons",url:"icons.html#hide-icon-text"},{title:"Sprite and font icons for Blank theme",filename:"icons",url:"icons.html#sprite-and-font-icons-for-blank-theme"},{title:"layout",filename:"layout",url:"layout.html"},{title:"Layout",filename:"layout",url:"layout.html#layout"},{title:"Layout global variables",filename:"layout",url:"layout.html#layout-global-variables"},{title:"Page layouts",filename:"layout",url:"layout.html#page-layouts"},{title:"Layout column",filename:"layout",url:"layout.html#layout-column"},{title:"Layout column variables",filename:"layout",url:"layout.html#layout-column-variables"},{title:"Layout width",filename:"layout",url:"layout.html#layout-width"},{title:"Layout width variables",filename:"layout",url:"layout.html#layout-width-variables"},{title:"lib",filename:"lib",url:"lib.html"},{title:"Including Magento UI library to your theme",filename:"lib",url:"lib.html#including-magento-ui-library-to-your-theme"},{title:"loaders",filename:"loaders",url:"loaders.html"},{title:"Loaders",filename:"loaders",url:"loaders.html#loaders"},{title:"Default loader variables",filename:"loaders",url:"loaders.html#default-loader-variables"},{title:"Loading",filename:"loaders",url:"loaders.html#loading"},{title:"Loading default variables",filename:"loaders",url:"loaders.html#loading-default-variables"},{title:"messages",filename:"messages",url:"messages.html"},{title:"Messages",filename:"messages",url:"messages.html#messages"},{title:"Information message",filename:"messages",url:"messages.html#information-message"},{title:"Warning message",filename:"messages",url:"messages.html#warning-message"},{title:"Error message",filename:"messages",url:"messages.html#error-message"},{title:"Success message",filename:"messages",url:"messages.html#success-message"},{title:"Notice message",filename:"messages",url:"messages.html#notice-message"},{title:"Message with inner icon",filename:"messages",url:"messages.html#message-with-inner-icon"},{title:"Message with lateral icon",filename:"messages",url:"messages.html#message-with-lateral-icon"},{title:"Custom message style",filename:"messages",url:"messages.html#custom-message-style"},{title:"Messages global variables",filename:"messages",url:"messages.html#messages-global-variables"},{title:"pages",filename:"pages",url:"pages.html"},{title:"Pagination HTML markup",filename:"pages",url:"pages.html#pagination-html-markup"},{title:"Pagination variables",filename:"pages",url:"pages.html#pagination-variables"},{title:"Pagination with label and gradient background on links",filename:"pages",url:"pages.html#pagination-with-label-and-gradient-background-on-links"},{title:'Pagination with "previous"..."next" text links and label',filename:"pages",url:"pages.html#pagination-with-previousnext-text-links-and-label"},{title:"Pagination without label, with solid background",filename:"pages",url:"pages.html#pagination-without-label-with-solid-background"},{title:"popups",filename:"popups",url:"popups.html"},{title:"Popups",filename:"popups",url:"popups.html#popups"},{title:"Popup variables",filename:"popups",url:"popups.html#popup-variables"},{title:"Window overlay mixin variables",filename:"popups",url:"popups.html#window-overlay-mixin-variables"},{title:"Fixed height popup",filename:"popups",url:"popups.html#fixed-height-popup"},{title:"Fixed content height popup",filename:"popups",url:"popups.html#fixed-content-height-popup"},{title:"Margins for header, content and footer block in popup",filename:"popups",url:"popups.html#margins-for-header-content-and-footer-block-in-popup"},{title:"Popup titles styled as theme headings",filename:"popups",url:"popups.html#popup-titles-styled-as-theme-headings"},{title:"Popup action toolbar",filename:"popups",url:"popups.html#popup-action-toolbar"},{title:"Popup Close button without an icon",filename:"popups",url:"popups.html#popup-close-button-without-an-icon"},{title:"Modify the icon of popup Close button",filename:"popups",url:"popups.html#modify-the-icon-of-popup-close-button"},{title:"Modify overlay styles",filename:"popups",url:"popups.html#modify-overlay-styles"},{title:"rating",filename:"rating",url:"rating.html"},{title:"Ratings",filename:"rating",url:"rating.html#ratings"},{title:"Global rating variables",filename:"rating",url:"rating.html#global-rating-variables"},{title:"Rating with vote",filename:"rating",url:"rating.html#rating-with-vote"},{title:"Rating with vote icons number customization",filename:"rating",url:"rating.html#rating-with-vote-icons-number-customization"},{title:"Rating with vote icons colors customization",filename:"rating",url:"rating.html#rating-with-vote-icons-colors-customization"},{title:"Rating with vote icons symbol customization",filename:"rating",url:"rating.html#rating-with-vote-icons-symbol-customization"},{title:"Accessible rating with vote",filename:"rating",url:"rating.html#accessible-rating-with-vote"},{title:"Rating summary",filename:"rating",url:"rating.html#rating-summary"},{title:"Rating summary icons number customization",filename:"rating",url:"rating.html#rating-summary-icons-number-customization"},{title:"Rating summary icons color customization",filename:"rating",url:"rating.html#rating-summary-icons-color-customization"},{title:"Rating summary icons symbol customization",filename:"rating",url:"rating.html#rating-summary-icons-symbol-customization"},{title:"Rating summary hide label",filename:"rating",url:"rating.html#rating-summary-hide-label"},{title:"Rating summary multiple ratings",filename:"rating",url:"rating.html#rating-summary-multiple-ratings"},{title:"Rating hide label mixin",filename:"rating",url:"rating.html#rating-hide-label-mixin"},{title:"resets",filename:"resets",url:"resets.html"},{title:"Resets",filename:"resets",url:"resets.html#resets"},{title:"responsive",filename:"responsive",url:"responsive.html"},{title:"Responsive",filename:"responsive",url:"responsive.html#responsive"},{title:"Responsive mixins usage",filename:"responsive",url:"responsive.html#responsive-mixins-usage"},{title:"Media query style groups separation variables",filename:"responsive",url:"responsive.html#media-query-style-groups-separation-variables"},{title:"Responsive breakpoints",filename:"responsive",url:"responsive.html#responsive-breakpoints"},{title:"sections",filename:"sections",url:"sections.html"},{title:"Tabs and accordions",filename:"sections",url:"sections.html#tabs-and-accordions"},{title:"Tabs",filename:"sections",url:"sections.html#tabs"},{title:"Tabs mixin variables",filename:"sections",url:"sections.html#tabs-mixin-variables"},{title:"Tabs with content top border",filename:"sections",url:"sections.html#tabs-with-content-top-border"},{title:"Accordion",filename:"sections",url:"sections.html#accordion"},{title:"Accordion mixin variables",filename:"sections",url:"sections.html#accordion-mixin-variables"},{title:"Responsive tabs",filename:"sections",url:"sections.html#responsive-tabs"},{title:"Tabs Base",filename:"sections",url:"sections.html#tabs-base"},{title:"Accordion Base",filename:"sections",url:"sections.html#accordion-base"},{title:"tables",filename:"tables",url:"tables.html"},{title:"Tables",filename:"tables",url:"tables.html#tables"},{title:"Table mixin variables",filename:"tables",url:"tables.html#table-mixin-variables"},{title:"Table typography",filename:"tables",url:"tables.html#table-typography"},{title:"Table typography mixin variables",filename:"tables",url:"tables.html#table-typography-mixin-variables"},{title:"Table caption",filename:"tables",url:"tables.html#table-caption"},{title:"Table caption mixin variables",filename:"tables",url:"tables.html#table-caption-mixin-variables"},{title:"Table cells resize",filename:"tables",url:"tables.html#table-cells-resize"},{title:"Table cells resize variables",filename:"tables",url:"tables.html#table-cells-resize-variables"},{title:"Table background customization",filename:"tables",url:"tables.html#table-background-customization"},{title:"Table background mixin variables",filename:"tables",url:"tables.html#table-background-mixin-variables"},{title:"Table borders customization",filename:"tables",url:"tables.html#table-borders-customization"},{title:"Table borders mixin variables",filename:"tables",url:"tables.html#table-borders-mixin-variables"},{title:"Table with horizontal borders",filename:"tables",url:"tables.html#table-with-horizontal-borders"},{title:"Table with vertical borders",filename:"tables",url:"tables.html#table-with-vertical-borders"},{title:"Table with light borders",filename:"tables",url:"tables.html#table-with-light-borders"},{title:"Table without borders",filename:"tables",url:"tables.html#table-without-borders"},{title:"Striped table",filename:"tables",url:"tables.html#striped-table"},{title:"Striped table mixin variables",filename:"tables",url:"tables.html#striped-table-mixin-variables"},{title:"Table with rows hover",filename:"tables",url:"tables.html#table-with-rows-hover"},{title:"Table with rows hover mixin variables",filename:"tables",url:"tables.html#table-with-rows-hover-mixin-variables"},{title:"Responsive table technics #1",filename:"tables",url:"tables.html#responsive-table-technics-1"},{title:"Responsive table technics #2",filename:"tables",url:"tables.html#responsive-table-technics-2"},{title:"Responsive table technics #2 mixin variables",filename:"tables",url:"tables.html#responsive-table-technics-2-mixin-variables"},{title:"tooltips",filename:"tooltips",url:"tooltips.html"},{title:"Tooltips",filename:"tooltips",url:"tooltips.html#tooltips"},{title:"Tooltips variables",filename:"tooltips",url:"tooltips.html#tooltips-variables"},{title:"typography",filename:"typography",url:"typography.html"},{title:"Typogrphy",filename:"typography",url:"typography.html#typogrphy"},{title:"Typography variables",filename:"typography",url:"typography.html#typography-variables"},{title:"Font-size mixin",filename:"typography",url:"typography.html#fontsize-mixin"},{title:"Line-height mixin",filename:"typography",url:"typography.html#lineheight-mixin"},{title:"Word breaking mixin",filename:"typography",url:"typography.html#word-breaking-mixin"},{title:"Font face mixin",filename:"typography",url:"typography.html#font-face-mixin"},{title:"Text overflow mixin",filename:"typography",url:"typography.html#text-overflow-mixin"},{title:"Text hide",filename:"typography",url:"typography.html#text-hide"},{title:"Hyphens",filename:"typography",url:"typography.html#hyphens"},{title:"Font style and color",filename:"typography",url:"typography.html#font-style-and-color"},{title:"Font style mixin variables",filename:"typography",url:"typography.html#font-style-mixin-variables"},{title:"Reset list styles",filename:"typography",url:"typography.html#reset-list-styles"},{title:"Reset list styles variables",filename:"typography",url:"typography.html#reset-list-styles-variables"},{title:"Inline-block list item styling",filename:"typography",url:"typography.html#inlineblock-list-item-styling"},{title:"Link styling mixin",filename:"typography",url:"typography.html#link-styling-mixin"},{title:"Link styling mixin variables",filename:"typography",url:"typography.html#link-styling-mixin-variables"},{title:"Heading styling mixin",filename:"typography",url:"typography.html#heading-styling-mixin"},{title:"Base typography mixins",filename:"typography",url:"typography.html#base-typography-mixins"},{title:"Base typography mixin variables",filename:"typography",url:"typography.html#base-typography-mixin-variables"},{title:"Headings typography mixin",filename:"typography",url:"typography.html#headings-typography-mixin"},{title:"Headings typography mixin variables",filename:"typography",url:"typography.html#headings-typography-mixin-variables"},{title:"Typography links mixin",filename:"typography",url:"typography.html#typography-links-mixin"},{title:"Typography lists mixin",filename:"typography",url:"typography.html#typography-lists-mixin"},{title:"Typography lists mixin variables",filename:"typography",url:"typography.html#typography-lists-mixin-variables"},{title:"Typography code elements mixin",filename:"typography",url:"typography.html#typography-code-elements-mixin"},{title:"Typography code mixin variables",filename:"typography",url:"typography.html#typography-code-mixin-variables"},{title:"Typography blockquote",filename:"typography",url:"typography.html#typography-blockquote"},{title:"Typography blockquote mixin variables",filename:"typography",url:"typography.html#typography-blockquote-mixin-variables"},{title:"utilities",filename:"utilities",url:"utilities.html"},{title:"Utilities",filename:"utilities",url:"utilities.html#utilities"},{title:".lib-clearfix()",filename:"utilities",url:"utilities.html#libclearfix"},{title:".lib-visibility-hidden()",filename:"utilities",url:"utilities.html#libvisibilityhidden"},{title:".lib-visually-hidden()",filename:"utilities",url:"utilities.html#libvisuallyhidden"},{title:".lib-visually-hidden-reset()",filename:"utilities",url:"utilities.html#libvisuallyhiddenreset"},{title:".lib-css()",filename:"utilities",url:"utilities.html#libcss"},{title:".lib-css() variables",filename:"utilities",url:"utilities.html#libcss-variables"},{title:".lib-rotate()",filename:"utilities",url:"utilities.html#librotate"},{title:".lib-rotate() variables",filename:"utilities",url:"utilities.html#librotate-variables"},{title:".lib-input-placeholder()",filename:"utilities",url:"utilities.html#libinputplaceholder"},{title:".lib-input-placeholder() variables",filename:"utilities",url:"utilities.html#libinputplaceholder-variables"},{title:".lib-background-gradient()",filename:"utilities",url:"utilities.html#libbackgroundgradient"},{title:".lib-background-gradient() variables",filename:"utilities",url:"utilities.html#libbackgroundgradient-variables"},{title:"variables",filename:"variables",url:"variables.html"},{title:"List of Global Variables",filename:"variables",url:"variables.html#list-of-global-variables"},{title:"Table with rows hover mixin variables",filename:"variables",url:"variables.html#table-with-rows-hover-mixin-variables"},{title:"docs",filename:"docs",url:"docs.html"},{title:"Documentation",filename:"docs",url:"docs.html#documentation"}];(function(){"use strict";var b=function(a,b){return Array.prototype.indexOf.call(a,b)!==-1},c=function(a,b){return Array.prototype.filter.call(a,b)},d=function(a,b){return Array.prototype.forEach.call(a,b)},e=document.getElementsByTagName("body")[0];e.addEventListener("click",function(a){var b=a.target;b.tagName.toLowerCase()==="svg"&&(b=b.parentNode);var c=!1;b.dataset.toggle!=null&&(a.preventDefault(),b.classList.contains("is-active")||(c=!0)),d(e.querySelectorAll("[data-toggle]"),function(a){a.classList.remove("is-active"),document.getElementById(a.dataset.toggle).hidden=!0}),c&&(b.classList.add("is-active"),document.getElementById(b.dataset.toggle).hidden=!1)}),function(){var f=e.getElementsByClassName("nav")[0];if(!f)return;var g=document.createElement("ul");g.className="nav-results",g.id="nav-search",g.hidden=!0,d(a,function(a){var b,c,d;b=document.createElement("li"),b._title=a.title.toLowerCase(),b.hidden=!0,b.appendChild(c=document.createElement("a")),c.href=a.url,c.innerHTML=a.title,c.appendChild(d=document.createElement("span")),d.innerHTML=a.filename,d.className="nav-results-filename",g.appendChild(b)}),f.appendChild(g);var h=g.children,i=function(a){d(h,function(a){a.hidden=!0});var b=this.value.toLowerCase(),e=[];b!==""&&(e=c(h,function(a){return a._title.indexOf(b)!==-1})),e.length>0?(d(e,function(a){a.hidden=!1}),g.hidden=!1):g.hidden=!0},j=f.querySelector('input[type="search"]');j.addEventListener("keyup",i),j.addEventListener("focus",i),e.addEventListener("click",function(a){if(a.target.classList&&a.target.classList.contains("search"))return;g.hidden=!0}),g.addEventListener("click",function(a){j.value=""});var k=document.createElement("ul");k.id="nav-toc",k.hidden=!0,k.className="nav-results toc-list",c(e.getElementsByTagName("*"),function(a){return b(["h1","h2","h3"],a.tagName.toLowerCase())}).map(function(a){var b=document.createElement("li"),c=document.createElement("a"),d=a.tagName.toLowerCase()[1];c.classList.add("level-"+d),b.appendChild(c),c.href="#"+a.id,c.innerHTML=a.innerHTML,k.appendChild(b)}),f.appendChild(k)}()})(),function(){"use strict";if(location.hash==="#__preview__"||location.protocol==="data:")return;var a=function(a,b){return Array.prototype.forEach.call(a,b)},b=function(a,b){var e=Array.prototype.slice.call(arguments,2);return d(a,function(a){return(c(b)?b||a:a[b]).apply(a,e)})},c=function(a){return Object.prototype.toString.call(a)==="[object Function]"},d=function(a,b){return Array.prototype.map.call(a,b)},e=function(a,b){return d(a,function(a){return a[b]})},f=function(a){var b={},c=a.split(";");for(var d=0;c.length>d;d++){var e=c[d].trim().split("=");b[e[0]]=e[1]}return b},g=function(a,c){return b(e(a,"classList"),"remove",c)},h=function(a,b){a.contentDocument.defaultView.postMessage(b,"*")},i=document.getElementsByTagName("head")[0],j=document.getElementsByTagName("body")[0],k=e(i.querySelectorAll('style[type="text/preview"]'),"innerHTML").join(""),l=e(i.querySelectorAll('script[type="text/preview"]'),"innerHTML").join(""),m=location.href.split("#")[0]+"#__preview__",n=document.createElement("iframe");n.src="data:text/html,",j.appendChild(n),n.addEventListener("load",function(){var b={sameOriginDataUri:!0};try{this.contentDocument,this.contentDocument||(b.sameOriginDataUri=!1)}catch(c){b.sameOriginDataUri=!1}this.parentNode.removeChild(this),a(j.getElementsByTagName("textarea"),function(a,c){o(a,b,c),q(),p(a)})});var o=function(a,b,c){var d,e,f;d=document.createElement("div"),d.appendChild(e=document.createElement("div")),d.className="preview",e.appendChild(f=document.createElement("iframe")),e.className="resizeable",f.setAttribute("scrolling","no"),f.name="iframe"+c++,f.addEventListener("load",function(){var c,d,e,f,g,i,j;j=this.contentDocument;if(!b.sameOriginDataUri&&this.src!==m)return;this.src===m&&(c=j.createElement("html"),c.appendChild(j.createElement("head")),c.appendChild(d=j.createElement("body")),d.innerHTML=a.textContent,j.replaceChild(c,j.documentElement)),g=j.createElement("head"),g.appendChild(f=j.createElement("style")),g.appendChild(e=j.createElement("script")),e.textContent=l,f.textContent=k,i=j.getElementsByTagName("head")[0],i.parentNode.replaceChild(g,i),h(this,"getHeight")});var g;b.sameOriginDataUri?g="data:text/html;charset=utf-8,"+encodeURIComponent("<!doctype html><html><head></head></body>"+a.textContent):g=m,f.setAttribute("src",g);var i=function(){f.contentDocument.body.innerHTML=this.value,h(f,"getHeight")};a.addEventListener("keypress",i),a.addEventListener("keyup",i),a.parentNode.insertBefore(d,a)},p=function(a){var b=document.createElement("div");b.className="preview-code",b.style.position="absolute",b.style.left="-9999px",j.appendChild(b);var c=parseInt(window.getComputedStyle(a).getPropertyValue("max-height"),10),d=function(a){b.textContent=this.value+"\n";var d=b.offsetHeight+2;d>=c?this.style.overflow="auto":this.style.overflow="hidden",this.style.height=b.offsetHeight+2+"px"};a.addEventListener("keypress",d),a.addEventListener("keyup",d),d.call(a)},q=function(){var b=j.getElementsByClassName("settings")[0],c=j.getElementsByClassName("resizeable"),d=30,e=function(b){document.cookie="preview-width="+b,a(c,function(a){b==="auto"&&(b=a.parentNode.offsetWidth),a.style.width=b+"px",h(a.getElementsByTagName("iframe")[0],"getHeight")})},i=f(document.cookie)["preview-width"];if(i){e(i),g(b.getElementsByClassName("is-active"),"is-active");var k=b.querySelector('button[data-width="'+i+'"]');k&&k.classList.add("is-active")}window.addEventListener("message",function(a){if(a.data==null||!a.source)return;var b=a.data,c=document.getElementsByName(a.source.name)[0];b.height!=null&&c&&(c.parentNode.style.height=b.height+d+"px")},!1),b&&c.length>0&&(b.hidden=!1,b.addEventListener("click",function(a){var c=a.target.tagName.toLowerCase(),d;if(c==="button")d=a.target;else{if(c!=="svg")return;d=a.target.parentNode}a.preventDefault(),g(b.getElementsByClassName("is-active"),"is-active"),d.classList.add("is-active");var f=d.dataset.width;e(f)}))}}()})()</script></body></html><!-- Generated with StyleDocco (http://jacobrask.github.com/styledocco). --> diff --git a/lib/web/css/docs/source/_variables.less b/lib/web/css/docs/source/_variables.less index 326580ead813f..e1845786067c8 100644 --- a/lib/web/css/docs/source/_variables.less +++ b/lib/web/css/docs/source/_variables.less @@ -7375,21 +7375,3 @@ // </tr> // </table> // </pre> -// -// #### <code>.lib-url-check()</code> mixin variables -// <pre> -// <table> -// <tr> -// <th class="vars_head">Mixin variable</th> -// <th class="vars_head">Allowed values</th> -// <th class="vars_head">Output variable</th> -// <th class="vars_head">Comment</th> -// </tr> -// <tr> -// <th>@_path</th> -// <td class="vars_value">'' | false | value</td> -// <td class="vars_value">@lib-url-check-output</td> -// <td>Passed url to wrap in 'url( ... )'. If the 'false' value passed mixin will return 'false'</td> -// </tr> -// </table> -// </pre> diff --git a/lib/web/css/docs/tables.html b/lib/web/css/docs/tables.html index 5a5067ebd0e4b..280f32135de62 100644 --- a/lib/web/css/docs/tables.html +++ b/lib/web/css/docs/tables.html @@ -1498,4 +1498,4 @@ </tr> </table> </pre> -</div></article></section><div class="bar bottom"><div hidden class="settings container"><!-- Icons from http://iconmonstr.com--><button title="Desktop (1280)" data-width='1280'><svg viewBox="0 0 412 386" height="24" width="26" class="icon"><path d="m147.6,343.9c-4.5,15.9-26.2,37.6-42.1,42.1h201c-15.3,-4-38.1,-26.8-42.1,-42.1H147.6zM387,0.5H25c-13.8,0-25,11.2-25,25V294c0,13.8 11.2,25 25,25h362c13.8,0 25,-11.2 25,-25V25.5C412,11.7 400.8,0.5 387,0.5zM369.9,238.2H42.1L42.1,42.6 369.9,42.6V238.2z"></path></svg></button><button title="Laptop (1024)" data-width='1024'><svg viewBox="0 0 384 312" height="23" width="28" class="icon"><path d="m349.2,20.5c0,-11-9,-20-20,-20H53.6c-11,0-20,9-20,20v194H349.2v-194zm-27,167H60.6V27.5H322.2v160zm28,42H32.6L2.6,282.1c-3.5,6.2-3.5,13.8 0.1,19.9 3.6,6.2 10.2,9.9 17.3,9.9H363.1c7.1,0 13.7,-3.8 17.3,-10 3.6,-6.2 3.6,-13.8 0,-20l-30.2,-52.5zm-196.9,54 8,-23.5h60.5l8,23.5h-76.5z"></path></svg></button><button title="Tablet (768)" data-width='768'><svg viewBox="0 0 317 412" height="24" width="18" class="icon"><path d="M 316.5,380 V 32 c 0,-17.7 -14.3,-32 -32,-32 H 32 C 14.3,0 0,14.3 0,32 v 348 c 0,17.7 14.3,32 32,32 h 252.5 c 17.7,0 32,-14.3 32,-32 z M 40,367 V 45 H 276.5 V 367 H 40 z m 109.8,22.7 c 0,-4.7 3.8,-8.5 8.5,-8.5 4.7,0 8.5,3.8 8.5,8.5 0,4.7 -3.8,8.5 -8.5,8.5 -4.7,0 -8.5,-3.8 -8.5,-8.5 z"></path></svg></button><button title="Smart phone (320)" data-width='320'><svg viewBox="0 0 224 412" height="24" width="13" class="icon"><path d="M 190.7,0 H 33 C 14.8,0 0,14.8 0,33 v 346 c 0,18.2 14.8,33 33,33 h 157.7 c 18.2,0 33,-14.8 33,-33 V 33 c 0,-18.2 -14.8,-33 -33,-33 z M 94.3,30.2 h 37 c 2.2,0 4,1.8 4,4 0,2.2 -1.8,4 -4,4 h -37 c -2.2,0 -4,-1.8 -4,-4 0,-2.2 1.8,-4 4,-4 z m 18.5,362.8 c -8.8,0 -16,-7.2 -16,-16 0,-8.8 7.2,-16 16,-16 8.8,0 16,7.2 16,16 0,8.8 -7.2,16 -16,16 z M 198.6,343.8 H 25.1 V 68.2 h 173.5 v 275.5 z"></path></svg></button><button title="Feature phone (240)" data-width='240'><svg viewBox="0 0 201 412" height="24" width="12" class="icon"><path d="M 165.5,0.2 V 45 H 25 c -13.8,0 -25,11.2 -25,25 V 387 c 0,13.8 11.2,25 25,25 h 150.5 c 13.8,0 25,-11.2 25,-25 V 0.2 h -35 z M 65.2,366.5 H 34.2 v -24.5 h 31 v 24.5 z m 0,-44.3 H 34.2 v -24.5 h 31 v 24.5 z m 50.5,44.3 H 84.7 v -24.5 h 31 v 24.5 z m 0,-44.3 H 84.7 v -24.5 h 31 v 24.5 z m 50.5,44.3 h -31 v -24.5 h 31 v 24.5 z m 0,-44.3 h -31 v -24.5 h 31 v 24.5 z m 0,-59.3 h -132 V 95.4 h 132 V 262.9 z"></path></svg></button><button title="Auto (100%)" data-width="auto" class="auto is-active">Auto</button></div></div><script>(function(){var a=[{title:"actions-toolbar",filename:"actions-toolbar",url:"actions-toolbar.html"},{title:"Actions toolbar",filename:"actions-toolbar",url:"actions-toolbar.html#actions-toolbar"},{title:"Actions toolbar mixin variables",filename:"actions-toolbar",url:"actions-toolbar.html#actions-toolbar-mixin-variables"},{title:"Actions toolbar alignment",filename:"actions-toolbar",url:"actions-toolbar.html#actions-toolbar-alignment"},{title:"Reverse primary and secondary blocks",filename:"actions-toolbar",url:"actions-toolbar.html#reverse-primary-and-secondary-blocks"},{title:"Actions toolbar indents customizations",filename:"actions-toolbar",url:"actions-toolbar.html#actions-toolbar-indents-customizations"},{title:"Responsive actions toolbar",filename:"actions-toolbar",url:"actions-toolbar.html#responsive-actions-toolbar"},{title:"breadcrumbs",filename:"breadcrumbs",url:"breadcrumbs.html"},{title:"Breadcrumbs",filename:"breadcrumbs",url:"breadcrumbs.html#breadcrumbs"},{title:"Breadcrumbs variables",filename:"breadcrumbs",url:"breadcrumbs.html#breadcrumbs-variables"},{title:"Button-styled breadcrumbs with gradient background, border, and no separating symbol",filename:"breadcrumbs",url:"breadcrumbs.html#buttonstyled-breadcrumbs-with-gradient-background-border-and-no-separating-symbol"},{title:"Breadcrumbs with solid background",filename:"breadcrumbs",url:"breadcrumbs.html#breadcrumbs-with-solid-background"},{title:"buttons",filename:"buttons",url:"buttons.html"},{title:"Default button",filename:"buttons",url:"buttons.html#default-button"},{title:"Button variables",filename:"buttons",url:"buttons.html#button-variables"},{title:"Button as an icon",filename:"buttons",url:"buttons.html#button-as-an-icon"},{title:"Button with an icon on the left or right side of the text",filename:"buttons",url:"buttons.html#button-with-an-icon-on-the-left-or-right-side-of-the-text"},{title:"Button with fixed width",filename:"buttons",url:"buttons.html#button-with-fixed-width"},{title:"Primary button",filename:"buttons",url:"buttons.html#primary-button"},{title:"Primary button variables",filename:"buttons",url:"buttons.html#primary-button-variables"},{title:"Button with gradient background",filename:"buttons",url:"buttons.html#button-with-gradient-background"},{title:"Button as a link",filename:"buttons",url:"buttons.html#button-as-a-link"},{title:"Button as a link variables",filename:"buttons",url:"buttons.html#button-as-a-link-variables"},{title:"Link as a button",filename:"buttons",url:"buttons.html#link-as-a-button"},{title:"Button reset",filename:"buttons",url:"buttons.html#button-reset"},{title:"Button revert secondary color",filename:"buttons",url:"buttons.html#button-revert-secondary-color"},{title:"Button revert secondary color variables",filename:"buttons",url:"buttons.html#button-revert-secondary-color-variables"},{title:"Button revert secondary size",filename:"buttons",url:"buttons.html#button-revert-secondary-size"},{title:"Button revert secondary size variables",filename:"buttons",url:"buttons.html#button-revert-secondary-size-variables"},{title:"components",filename:"components",url:"components.html"},{title:"Components",filename:"components",url:"components.html#components"},{title:"Components Variables",filename:"components",url:"components.html#components-variables"},{title:"dropdowns",filename:"dropdowns",url:"dropdowns.html"},{title:"Drop-down and split buttons mixins",filename:"dropdowns",url:"dropdowns.html#dropdown-and-split-buttons-mixins"},{title:"Drop-down",filename:"dropdowns",url:"dropdowns.html#dropdown"},{title:"Drop-down variables",filename:"dropdowns",url:"dropdowns.html#dropdown-variables"},{title:"Drop-down with icon customization",filename:"dropdowns",url:"dropdowns.html#dropdown-with-icon-customization"},{title:"Modify dropdown list styles",filename:"dropdowns",url:"dropdowns.html#modify-dropdown-list-styles"},{title:"Split button",filename:"dropdowns",url:"dropdowns.html#split-button"},{title:"Split button variables",filename:"dropdowns",url:"dropdowns.html#split-button-variables"},{title:"Split button - button styling",filename:"dropdowns",url:"dropdowns.html#split-button-button-styling"},{title:"Split button icon customization",filename:"dropdowns",url:"dropdowns.html#split-button-icon-customization"},{title:"Split button drop-down list customization",filename:"dropdowns",url:"dropdowns.html#split-button-dropdown-list-customization"},{title:"forms",filename:"forms",url:"forms.html"},{title:"Forms mixins",filename:"forms",url:"forms.html#forms-mixins"},{title:"Global forms elements customization",filename:"forms",url:"forms.html#global-forms-elements-customization"},{title:"Fieldsets & fields customization",filename:"forms",url:"forms.html#fieldsets-fields-customization"},{title:"Fieldset and legend customization variables",filename:"forms",url:"forms.html#fieldset-and-legend-customization-variables"},{title:"Fields customization variables",filename:"forms",url:"forms.html#fields-customization-variables"},{title:"Required fields message customization variables",filename:"forms",url:"forms.html#required-fields-message-customization-variables"},{title:"Form element inputs customization",filename:"forms",url:"forms.html#form-element-inputs-customization"},{title:"Form element inputs customization variables",filename:"forms",url:"forms.html#form-element-inputs-customization-variables"},{title:"Form element choice",filename:"forms",url:"forms.html#form-element-choice"},{title:"Form element choice variables",filename:"forms",url:"forms.html#form-element-choice-variables"},{title:"Custom color",filename:"forms",url:"forms.html#custom-color"},{title:"Input number - input-text view",filename:"forms",url:"forms.html#input-number-inputtext-view"},{title:"Input search - input-text view",filename:"forms",url:"forms.html#input-search-inputtext-view"},{title:"Form validation",filename:"forms",url:"forms.html#form-validation"},{title:"Form validation variables",filename:"forms",url:"forms.html#form-validation-variables"},{title:"icons",filename:"icons",url:"icons.html"},{title:"Icons",filename:"icons",url:"icons.html#icons"},{title:"Icon with image or sprite",filename:"icons",url:"icons.html#icon-with-image-or-sprite"},{title:"Icon with image or sprite variables",filename:"icons",url:"icons.html#icon-with-image-or-sprite-variables"},{title:"Icon position for an icon with image or sprite",filename:"icons",url:"icons.html#icon-position-for-an-icon-with-image-or-sprite"},{title:"Position for icon with image or sprite mixin variables",filename:"icons",url:"icons.html#position-for-icon-with-image-or-sprite-mixin-variables"},{title:"Icon sprite position (with grid)",filename:"icons",url:"icons.html#icon-sprite-position-with-grid"},{title:"Icon sprite position variables",filename:"icons",url:"icons.html#icon-sprite-position-variables"},{title:"Image/sprite icon size",filename:"icons",url:"icons.html#imagesprite-icon-size"},{title:"Image/sprite icon size variables",filename:"icons",url:"icons.html#imagesprite-icon-size-variables"},{title:"Font icon",filename:"icons",url:"icons.html#font-icon"},{title:"Font icon variables",filename:"icons",url:"icons.html#font-icon-variables"},{title:"Change the size of font icon",filename:"icons",url:"icons.html#change-the-size-of-font-icon"},{title:"Change the size of font icon variables",filename:"icons",url:"icons.html#change-the-size-of-font-icon-variables"},{title:"Hide icon text",filename:"icons",url:"icons.html#hide-icon-text"},{title:"Sprite and font icons for Blank theme",filename:"icons",url:"icons.html#sprite-and-font-icons-for-blank-theme"},{title:"layout",filename:"layout",url:"layout.html"},{title:"Layout",filename:"layout",url:"layout.html#layout"},{title:"Layout global variables",filename:"layout",url:"layout.html#layout-global-variables"},{title:"Page layouts",filename:"layout",url:"layout.html#page-layouts"},{title:"Layout column",filename:"layout",url:"layout.html#layout-column"},{title:"Layout column variables",filename:"layout",url:"layout.html#layout-column-variables"},{title:"Layout width",filename:"layout",url:"layout.html#layout-width"},{title:"Layout width variables",filename:"layout",url:"layout.html#layout-width-variables"},{title:"lib",filename:"lib",url:"lib.html"},{title:"Including Magento UI library to your theme",filename:"lib",url:"lib.html#including-magento-ui-library-to-your-theme"},{title:"loaders",filename:"loaders",url:"loaders.html"},{title:"Loaders",filename:"loaders",url:"loaders.html#loaders"},{title:"Default loader variables",filename:"loaders",url:"loaders.html#default-loader-variables"},{title:"Loading",filename:"loaders",url:"loaders.html#loading"},{title:"Loading default variables",filename:"loaders",url:"loaders.html#loading-default-variables"},{title:"messages",filename:"messages",url:"messages.html"},{title:"Messages",filename:"messages",url:"messages.html#messages"},{title:"Information message",filename:"messages",url:"messages.html#information-message"},{title:"Warning message",filename:"messages",url:"messages.html#warning-message"},{title:"Error message",filename:"messages",url:"messages.html#error-message"},{title:"Success message",filename:"messages",url:"messages.html#success-message"},{title:"Notice message",filename:"messages",url:"messages.html#notice-message"},{title:"Message with inner icon",filename:"messages",url:"messages.html#message-with-inner-icon"},{title:"Message with lateral icon",filename:"messages",url:"messages.html#message-with-lateral-icon"},{title:"Custom message style",filename:"messages",url:"messages.html#custom-message-style"},{title:"Messages global variables",filename:"messages",url:"messages.html#messages-global-variables"},{title:"pages",filename:"pages",url:"pages.html"},{title:"Pagination HTML markup",filename:"pages",url:"pages.html#pagination-html-markup"},{title:"Pagination variables",filename:"pages",url:"pages.html#pagination-variables"},{title:"Pagination with label and gradient background on links",filename:"pages",url:"pages.html#pagination-with-label-and-gradient-background-on-links"},{title:'Pagination with "previous"..."next" text links and label',filename:"pages",url:"pages.html#pagination-with-previousnext-text-links-and-label"},{title:"Pagination without label, with solid background",filename:"pages",url:"pages.html#pagination-without-label-with-solid-background"},{title:"popups",filename:"popups",url:"popups.html"},{title:"Popups",filename:"popups",url:"popups.html#popups"},{title:"Popup variables",filename:"popups",url:"popups.html#popup-variables"},{title:"Window overlay mixin variables",filename:"popups",url:"popups.html#window-overlay-mixin-variables"},{title:"Fixed height popup",filename:"popups",url:"popups.html#fixed-height-popup"},{title:"Fixed content height popup",filename:"popups",url:"popups.html#fixed-content-height-popup"},{title:"Margins for header, content and footer block in popup",filename:"popups",url:"popups.html#margins-for-header-content-and-footer-block-in-popup"},{title:"Popup titles styled as theme headings",filename:"popups",url:"popups.html#popup-titles-styled-as-theme-headings"},{title:"Popup action toolbar",filename:"popups",url:"popups.html#popup-action-toolbar"},{title:"Popup Close button without an icon",filename:"popups",url:"popups.html#popup-close-button-without-an-icon"},{title:"Modify the icon of popup Close button",filename:"popups",url:"popups.html#modify-the-icon-of-popup-close-button"},{title:"Modify overlay styles",filename:"popups",url:"popups.html#modify-overlay-styles"},{title:"rating",filename:"rating",url:"rating.html"},{title:"Ratings",filename:"rating",url:"rating.html#ratings"},{title:"Global rating variables",filename:"rating",url:"rating.html#global-rating-variables"},{title:"Rating with vote",filename:"rating",url:"rating.html#rating-with-vote"},{title:"Rating with vote icons number customization",filename:"rating",url:"rating.html#rating-with-vote-icons-number-customization"},{title:"Rating with vote icons colors customization",filename:"rating",url:"rating.html#rating-with-vote-icons-colors-customization"},{title:"Rating with vote icons symbol customization",filename:"rating",url:"rating.html#rating-with-vote-icons-symbol-customization"},{title:"Accessible rating with vote",filename:"rating",url:"rating.html#accessible-rating-with-vote"},{title:"Rating summary",filename:"rating",url:"rating.html#rating-summary"},{title:"Rating summary icons number customization",filename:"rating",url:"rating.html#rating-summary-icons-number-customization"},{title:"Rating summary icons color customization",filename:"rating",url:"rating.html#rating-summary-icons-color-customization"},{title:"Rating summary icons symbol customization",filename:"rating",url:"rating.html#rating-summary-icons-symbol-customization"},{title:"Rating summary hide label",filename:"rating",url:"rating.html#rating-summary-hide-label"},{title:"Rating summary multiple ratings",filename:"rating",url:"rating.html#rating-summary-multiple-ratings"},{title:"Rating hide label mixin",filename:"rating",url:"rating.html#rating-hide-label-mixin"},{title:"resets",filename:"resets",url:"resets.html"},{title:"Resets",filename:"resets",url:"resets.html#resets"},{title:"responsive",filename:"responsive",url:"responsive.html"},{title:"Responsive",filename:"responsive",url:"responsive.html#responsive"},{title:"Responsive mixins usage",filename:"responsive",url:"responsive.html#responsive-mixins-usage"},{title:"Media query style groups separation variables",filename:"responsive",url:"responsive.html#media-query-style-groups-separation-variables"},{title:"Responsive breakpoints",filename:"responsive",url:"responsive.html#responsive-breakpoints"},{title:"sections",filename:"sections",url:"sections.html"},{title:"Tabs and accordions",filename:"sections",url:"sections.html#tabs-and-accordions"},{title:"Tabs",filename:"sections",url:"sections.html#tabs"},{title:"Tabs mixin variables",filename:"sections",url:"sections.html#tabs-mixin-variables"},{title:"Tabs with content top border",filename:"sections",url:"sections.html#tabs-with-content-top-border"},{title:"Accordion",filename:"sections",url:"sections.html#accordion"},{title:"Accordion mixin variables",filename:"sections",url:"sections.html#accordion-mixin-variables"},{title:"Responsive tabs",filename:"sections",url:"sections.html#responsive-tabs"},{title:"Tabs Base",filename:"sections",url:"sections.html#tabs-base"},{title:"Accordion Base",filename:"sections",url:"sections.html#accordion-base"},{title:"tables",filename:"tables",url:"tables.html"},{title:"Tables",filename:"tables",url:"tables.html#tables"},{title:"Table mixin variables",filename:"tables",url:"tables.html#table-mixin-variables"},{title:"Table typography",filename:"tables",url:"tables.html#table-typography"},{title:"Table typography mixin variables",filename:"tables",url:"tables.html#table-typography-mixin-variables"},{title:"Table caption",filename:"tables",url:"tables.html#table-caption"},{title:"Table caption mixin variables",filename:"tables",url:"tables.html#table-caption-mixin-variables"},{title:"Table cells resize",filename:"tables",url:"tables.html#table-cells-resize"},{title:"Table cells resize variables",filename:"tables",url:"tables.html#table-cells-resize-variables"},{title:"Table background customization",filename:"tables",url:"tables.html#table-background-customization"},{title:"Table background mixin variables",filename:"tables",url:"tables.html#table-background-mixin-variables"},{title:"Table borders customization",filename:"tables",url:"tables.html#table-borders-customization"},{title:"Table borders mixin variables",filename:"tables",url:"tables.html#table-borders-mixin-variables"},{title:"Table with horizontal borders",filename:"tables",url:"tables.html#table-with-horizontal-borders"},{title:"Table with vertical borders",filename:"tables",url:"tables.html#table-with-vertical-borders"},{title:"Table with light borders",filename:"tables",url:"tables.html#table-with-light-borders"},{title:"Table without borders",filename:"tables",url:"tables.html#table-without-borders"},{title:"Striped table",filename:"tables",url:"tables.html#striped-table"},{title:"Striped table mixin variables",filename:"tables",url:"tables.html#striped-table-mixin-variables"},{title:"Table with rows hover",filename:"tables",url:"tables.html#table-with-rows-hover"},{title:"Table with rows hover mixin variables",filename:"tables",url:"tables.html#table-with-rows-hover-mixin-variables"},{title:"Responsive table technics #1",filename:"tables",url:"tables.html#responsive-table-technics-1"},{title:"Responsive table technics #2",filename:"tables",url:"tables.html#responsive-table-technics-2"},{title:"Responsive table technics #2 mixin variables",filename:"tables",url:"tables.html#responsive-table-technics-2-mixin-variables"},{title:"tooltips",filename:"tooltips",url:"tooltips.html"},{title:"Tooltips",filename:"tooltips",url:"tooltips.html#tooltips"},{title:"Tooltips variables",filename:"tooltips",url:"tooltips.html#tooltips-variables"},{title:"typography",filename:"typography",url:"typography.html"},{title:"Typogrphy",filename:"typography",url:"typography.html#typogrphy"},{title:"Typography variables",filename:"typography",url:"typography.html#typography-variables"},{title:"Font-size mixin",filename:"typography",url:"typography.html#fontsize-mixin"},{title:"Line-height mixin",filename:"typography",url:"typography.html#lineheight-mixin"},{title:"Word breaking mixin",filename:"typography",url:"typography.html#word-breaking-mixin"},{title:"Font face mixin",filename:"typography",url:"typography.html#font-face-mixin"},{title:"Text overflow mixin",filename:"typography",url:"typography.html#text-overflow-mixin"},{title:"Text hide",filename:"typography",url:"typography.html#text-hide"},{title:"Hyphens",filename:"typography",url:"typography.html#hyphens"},{title:"Font style and color",filename:"typography",url:"typography.html#font-style-and-color"},{title:"Font style mixin variables",filename:"typography",url:"typography.html#font-style-mixin-variables"},{title:"Reset list styles",filename:"typography",url:"typography.html#reset-list-styles"},{title:"Reset list styles variables",filename:"typography",url:"typography.html#reset-list-styles-variables"},{title:"Inline-block list item styling",filename:"typography",url:"typography.html#inlineblock-list-item-styling"},{title:"Link styling mixin",filename:"typography",url:"typography.html#link-styling-mixin"},{title:"Link styling mixin variables",filename:"typography",url:"typography.html#link-styling-mixin-variables"},{title:"Heading styling mixin",filename:"typography",url:"typography.html#heading-styling-mixin"},{title:"Base typography mixins",filename:"typography",url:"typography.html#base-typography-mixins"},{title:"Base typography mixin variables",filename:"typography",url:"typography.html#base-typography-mixin-variables"},{title:"Headings typography mixin",filename:"typography",url:"typography.html#headings-typography-mixin"},{title:"Headings typography mixin variables",filename:"typography",url:"typography.html#headings-typography-mixin-variables"},{title:"Typography links mixin",filename:"typography",url:"typography.html#typography-links-mixin"},{title:"Typography lists mixin",filename:"typography",url:"typography.html#typography-lists-mixin"},{title:"Typography lists mixin variables",filename:"typography",url:"typography.html#typography-lists-mixin-variables"},{title:"Typography code elements mixin",filename:"typography",url:"typography.html#typography-code-elements-mixin"},{title:"Typography code mixin variables",filename:"typography",url:"typography.html#typography-code-mixin-variables"},{title:"Typography blockquote",filename:"typography",url:"typography.html#typography-blockquote"},{title:"Typography blockquote mixin variables",filename:"typography",url:"typography.html#typography-blockquote-mixin-variables"},{title:"utilities",filename:"utilities",url:"utilities.html"},{title:"Utilities",filename:"utilities",url:"utilities.html#utilities"},{title:".lib-clearfix()",filename:"utilities",url:"utilities.html#libclearfix"},{title:".lib-visibility-hidden()",filename:"utilities",url:"utilities.html#libvisibilityhidden"},{title:".lib-visually-hidden()",filename:"utilities",url:"utilities.html#libvisuallyhidden"},{title:".lib-visually-hidden-reset()",filename:"utilities",url:"utilities.html#libvisuallyhiddenreset"},{title:".lib-css()",filename:"utilities",url:"utilities.html#libcss"},{title:".lib-css() variables",filename:"utilities",url:"utilities.html#libcss-variables"},{title:".lib-rotate()",filename:"utilities",url:"utilities.html#librotate"},{title:".lib-rotate() variables",filename:"utilities",url:"utilities.html#librotate-variables"},{title:".lib-input-placeholder()",filename:"utilities",url:"utilities.html#libinputplaceholder"},{title:".lib-input-placeholder() variables",filename:"utilities",url:"utilities.html#libinputplaceholder-variables"},{title:".lib-background-gradient()",filename:"utilities",url:"utilities.html#libbackgroundgradient"},{title:".lib-background-gradient() variables",filename:"utilities",url:"utilities.html#libbackgroundgradient-variables"},{title:".lib-url-check()",filename:"utilities",url:"utilities.html#liburlcheck"},{title:".lib-url-check() variables",filename:"utilities",url:"utilities.html#liburlcheck-variables"},{title:"variables",filename:"variables",url:"variables.html"},{title:"List of Global Variables",filename:"variables",url:"variables.html#list-of-global-variables"},{title:"Table with rows hover mixin variables",filename:"variables",url:"variables.html#table-with-rows-hover-mixin-variables"},{title:"docs",filename:"docs",url:"docs.html"},{title:"Documentation",filename:"docs",url:"docs.html#documentation"}];(function(){"use strict";var b=function(a,b){return Array.prototype.indexOf.call(a,b)!==-1},c=function(a,b){return Array.prototype.filter.call(a,b)},d=function(a,b){return Array.prototype.forEach.call(a,b)},e=document.getElementsByTagName("body")[0];e.addEventListener("click",function(a){var b=a.target;b.tagName.toLowerCase()==="svg"&&(b=b.parentNode);var c=!1;b.dataset.toggle!=null&&(a.preventDefault(),b.classList.contains("is-active")||(c=!0)),d(e.querySelectorAll("[data-toggle]"),function(a){a.classList.remove("is-active"),document.getElementById(a.dataset.toggle).hidden=!0}),c&&(b.classList.add("is-active"),document.getElementById(b.dataset.toggle).hidden=!1)}),function(){var f=e.getElementsByClassName("nav")[0];if(!f)return;var g=document.createElement("ul");g.className="nav-results",g.id="nav-search",g.hidden=!0,d(a,function(a){var b,c,d;b=document.createElement("li"),b._title=a.title.toLowerCase(),b.hidden=!0,b.appendChild(c=document.createElement("a")),c.href=a.url,c.innerHTML=a.title,c.appendChild(d=document.createElement("span")),d.innerHTML=a.filename,d.className="nav-results-filename",g.appendChild(b)}),f.appendChild(g);var h=g.children,i=function(a){d(h,function(a){a.hidden=!0});var b=this.value.toLowerCase(),e=[];b!==""&&(e=c(h,function(a){return a._title.indexOf(b)!==-1})),e.length>0?(d(e,function(a){a.hidden=!1}),g.hidden=!1):g.hidden=!0},j=f.querySelector('input[type="search"]');j.addEventListener("keyup",i),j.addEventListener("focus",i),e.addEventListener("click",function(a){if(a.target.classList&&a.target.classList.contains("search"))return;g.hidden=!0}),g.addEventListener("click",function(a){j.value=""});var k=document.createElement("ul");k.id="nav-toc",k.hidden=!0,k.className="nav-results toc-list",c(e.getElementsByTagName("*"),function(a){return b(["h1","h2","h3"],a.tagName.toLowerCase())}).map(function(a){var b=document.createElement("li"),c=document.createElement("a"),d=a.tagName.toLowerCase()[1];c.classList.add("level-"+d),b.appendChild(c),c.href="#"+a.id,c.innerHTML=a.innerHTML,k.appendChild(b)}),f.appendChild(k)}()})(),function(){"use strict";if(location.hash==="#__preview__"||location.protocol==="data:")return;var a=function(a,b){return Array.prototype.forEach.call(a,b)},b=function(a,b){var e=Array.prototype.slice.call(arguments,2);return d(a,function(a){return(c(b)?b||a:a[b]).apply(a,e)})},c=function(a){return Object.prototype.toString.call(a)==="[object Function]"},d=function(a,b){return Array.prototype.map.call(a,b)},e=function(a,b){return d(a,function(a){return a[b]})},f=function(a){var b={},c=a.split(";");for(var d=0;c.length>d;d++){var e=c[d].trim().split("=");b[e[0]]=e[1]}return b},g=function(a,c){return b(e(a,"classList"),"remove",c)},h=function(a,b){a.contentDocument.defaultView.postMessage(b,"*")},i=document.getElementsByTagName("head")[0],j=document.getElementsByTagName("body")[0],k=e(i.querySelectorAll('style[type="text/preview"]'),"innerHTML").join(""),l=e(i.querySelectorAll('script[type="text/preview"]'),"innerHTML").join(""),m=location.href.split("#")[0]+"#__preview__",n=document.createElement("iframe");n.src="data:text/html,",j.appendChild(n),n.addEventListener("load",function(){var b={sameOriginDataUri:!0};try{this.contentDocument,this.contentDocument||(b.sameOriginDataUri=!1)}catch(c){b.sameOriginDataUri=!1}this.parentNode.removeChild(this),a(j.getElementsByTagName("textarea"),function(a,c){o(a,b,c),q(),p(a)})});var o=function(a,b,c){var d,e,f;d=document.createElement("div"),d.appendChild(e=document.createElement("div")),d.className="preview",e.appendChild(f=document.createElement("iframe")),e.className="resizeable",f.setAttribute("scrolling","no"),f.name="iframe"+c++,f.addEventListener("load",function(){var c,d,e,f,g,i,j;j=this.contentDocument;if(!b.sameOriginDataUri&&this.src!==m)return;this.src===m&&(c=j.createElement("html"),c.appendChild(j.createElement("head")),c.appendChild(d=j.createElement("body")),d.innerHTML=a.textContent,j.replaceChild(c,j.documentElement)),g=j.createElement("head"),g.appendChild(f=j.createElement("style")),g.appendChild(e=j.createElement("script")),e.textContent=l,f.textContent=k,i=j.getElementsByTagName("head")[0],i.parentNode.replaceChild(g,i),h(this,"getHeight")});var g;b.sameOriginDataUri?g="data:text/html;charset=utf-8,"+encodeURIComponent("<!doctype html><html><head></head></body>"+a.textContent):g=m,f.setAttribute("src",g);var i=function(){f.contentDocument.body.innerHTML=this.value,h(f,"getHeight")};a.addEventListener("keypress",i),a.addEventListener("keyup",i),a.parentNode.insertBefore(d,a)},p=function(a){var b=document.createElement("div");b.className="preview-code",b.style.position="absolute",b.style.left="-9999px",j.appendChild(b);var c=parseInt(window.getComputedStyle(a).getPropertyValue("max-height"),10),d=function(a){b.textContent=this.value+"\n";var d=b.offsetHeight+2;d>=c?this.style.overflow="auto":this.style.overflow="hidden",this.style.height=b.offsetHeight+2+"px"};a.addEventListener("keypress",d),a.addEventListener("keyup",d),d.call(a)},q=function(){var b=j.getElementsByClassName("settings")[0],c=j.getElementsByClassName("resizeable"),d=30,e=function(b){document.cookie="preview-width="+b,a(c,function(a){b==="auto"&&(b=a.parentNode.offsetWidth),a.style.width=b+"px",h(a.getElementsByTagName("iframe")[0],"getHeight")})},i=f(document.cookie)["preview-width"];if(i){e(i),g(b.getElementsByClassName("is-active"),"is-active");var k=b.querySelector('button[data-width="'+i+'"]');k&&k.classList.add("is-active")}window.addEventListener("message",function(a){if(a.data==null||!a.source)return;var b=a.data,c=document.getElementsByName(a.source.name)[0];b.height!=null&&c&&(c.parentNode.style.height=b.height+d+"px")},!1),b&&c.length>0&&(b.hidden=!1,b.addEventListener("click",function(a){var c=a.target.tagName.toLowerCase(),d;if(c==="button")d=a.target;else{if(c!=="svg")return;d=a.target.parentNode}a.preventDefault(),g(b.getElementsByClassName("is-active"),"is-active"),d.classList.add("is-active");var f=d.dataset.width;e(f)}))}}()})()</script></body></html><!-- Generated with StyleDocco (http://jacobrask.github.com/styledocco). --> +</div></article></section><div class="bar bottom"><div hidden class="settings container"><!-- Icons from http://iconmonstr.com--><button title="Desktop (1280)" data-width='1280'><svg viewBox="0 0 412 386" height="24" width="26" class="icon"><path d="m147.6,343.9c-4.5,15.9-26.2,37.6-42.1,42.1h201c-15.3,-4-38.1,-26.8-42.1,-42.1H147.6zM387,0.5H25c-13.8,0-25,11.2-25,25V294c0,13.8 11.2,25 25,25h362c13.8,0 25,-11.2 25,-25V25.5C412,11.7 400.8,0.5 387,0.5zM369.9,238.2H42.1L42.1,42.6 369.9,42.6V238.2z"></path></svg></button><button title="Laptop (1024)" data-width='1024'><svg viewBox="0 0 384 312" height="23" width="28" class="icon"><path d="m349.2,20.5c0,-11-9,-20-20,-20H53.6c-11,0-20,9-20,20v194H349.2v-194zm-27,167H60.6V27.5H322.2v160zm28,42H32.6L2.6,282.1c-3.5,6.2-3.5,13.8 0.1,19.9 3.6,6.2 10.2,9.9 17.3,9.9H363.1c7.1,0 13.7,-3.8 17.3,-10 3.6,-6.2 3.6,-13.8 0,-20l-30.2,-52.5zm-196.9,54 8,-23.5h60.5l8,23.5h-76.5z"></path></svg></button><button title="Tablet (768)" data-width='768'><svg viewBox="0 0 317 412" height="24" width="18" class="icon"><path d="M 316.5,380 V 32 c 0,-17.7 -14.3,-32 -32,-32 H 32 C 14.3,0 0,14.3 0,32 v 348 c 0,17.7 14.3,32 32,32 h 252.5 c 17.7,0 32,-14.3 32,-32 z M 40,367 V 45 H 276.5 V 367 H 40 z m 109.8,22.7 c 0,-4.7 3.8,-8.5 8.5,-8.5 4.7,0 8.5,3.8 8.5,8.5 0,4.7 -3.8,8.5 -8.5,8.5 -4.7,0 -8.5,-3.8 -8.5,-8.5 z"></path></svg></button><button title="Smart phone (320)" data-width='320'><svg viewBox="0 0 224 412" height="24" width="13" class="icon"><path d="M 190.7,0 H 33 C 14.8,0 0,14.8 0,33 v 346 c 0,18.2 14.8,33 33,33 h 157.7 c 18.2,0 33,-14.8 33,-33 V 33 c 0,-18.2 -14.8,-33 -33,-33 z M 94.3,30.2 h 37 c 2.2,0 4,1.8 4,4 0,2.2 -1.8,4 -4,4 h -37 c -2.2,0 -4,-1.8 -4,-4 0,-2.2 1.8,-4 4,-4 z m 18.5,362.8 c -8.8,0 -16,-7.2 -16,-16 0,-8.8 7.2,-16 16,-16 8.8,0 16,7.2 16,16 0,8.8 -7.2,16 -16,16 z M 198.6,343.8 H 25.1 V 68.2 h 173.5 v 275.5 z"></path></svg></button><button title="Feature phone (240)" data-width='240'><svg viewBox="0 0 201 412" height="24" width="12" class="icon"><path d="M 165.5,0.2 V 45 H 25 c -13.8,0 -25,11.2 -25,25 V 387 c 0,13.8 11.2,25 25,25 h 150.5 c 13.8,0 25,-11.2 25,-25 V 0.2 h -35 z M 65.2,366.5 H 34.2 v -24.5 h 31 v 24.5 z m 0,-44.3 H 34.2 v -24.5 h 31 v 24.5 z m 50.5,44.3 H 84.7 v -24.5 h 31 v 24.5 z m 0,-44.3 H 84.7 v -24.5 h 31 v 24.5 z m 50.5,44.3 h -31 v -24.5 h 31 v 24.5 z m 0,-44.3 h -31 v -24.5 h 31 v 24.5 z m 0,-59.3 h -132 V 95.4 h 132 V 262.9 z"></path></svg></button><button title="Auto (100%)" data-width="auto" class="auto is-active">Auto</button></div></div><script>(function(){var a=[{title:"actions-toolbar",filename:"actions-toolbar",url:"actions-toolbar.html"},{title:"Actions toolbar",filename:"actions-toolbar",url:"actions-toolbar.html#actions-toolbar"},{title:"Actions toolbar mixin variables",filename:"actions-toolbar",url:"actions-toolbar.html#actions-toolbar-mixin-variables"},{title:"Actions toolbar alignment",filename:"actions-toolbar",url:"actions-toolbar.html#actions-toolbar-alignment"},{title:"Reverse primary and secondary blocks",filename:"actions-toolbar",url:"actions-toolbar.html#reverse-primary-and-secondary-blocks"},{title:"Actions toolbar indents customizations",filename:"actions-toolbar",url:"actions-toolbar.html#actions-toolbar-indents-customizations"},{title:"Responsive actions toolbar",filename:"actions-toolbar",url:"actions-toolbar.html#responsive-actions-toolbar"},{title:"breadcrumbs",filename:"breadcrumbs",url:"breadcrumbs.html"},{title:"Breadcrumbs",filename:"breadcrumbs",url:"breadcrumbs.html#breadcrumbs"},{title:"Breadcrumbs variables",filename:"breadcrumbs",url:"breadcrumbs.html#breadcrumbs-variables"},{title:"Button-styled breadcrumbs with gradient background, border, and no separating symbol",filename:"breadcrumbs",url:"breadcrumbs.html#buttonstyled-breadcrumbs-with-gradient-background-border-and-no-separating-symbol"},{title:"Breadcrumbs with solid background",filename:"breadcrumbs",url:"breadcrumbs.html#breadcrumbs-with-solid-background"},{title:"buttons",filename:"buttons",url:"buttons.html"},{title:"Default button",filename:"buttons",url:"buttons.html#default-button"},{title:"Button variables",filename:"buttons",url:"buttons.html#button-variables"},{title:"Button as an icon",filename:"buttons",url:"buttons.html#button-as-an-icon"},{title:"Button with an icon on the left or right side of the text",filename:"buttons",url:"buttons.html#button-with-an-icon-on-the-left-or-right-side-of-the-text"},{title:"Button with fixed width",filename:"buttons",url:"buttons.html#button-with-fixed-width"},{title:"Primary button",filename:"buttons",url:"buttons.html#primary-button"},{title:"Primary button variables",filename:"buttons",url:"buttons.html#primary-button-variables"},{title:"Button with gradient background",filename:"buttons",url:"buttons.html#button-with-gradient-background"},{title:"Button as a link",filename:"buttons",url:"buttons.html#button-as-a-link"},{title:"Button as a link variables",filename:"buttons",url:"buttons.html#button-as-a-link-variables"},{title:"Link as a button",filename:"buttons",url:"buttons.html#link-as-a-button"},{title:"Button reset",filename:"buttons",url:"buttons.html#button-reset"},{title:"Button revert secondary color",filename:"buttons",url:"buttons.html#button-revert-secondary-color"},{title:"Button revert secondary color variables",filename:"buttons",url:"buttons.html#button-revert-secondary-color-variables"},{title:"Button revert secondary size",filename:"buttons",url:"buttons.html#button-revert-secondary-size"},{title:"Button revert secondary size variables",filename:"buttons",url:"buttons.html#button-revert-secondary-size-variables"},{title:"components",filename:"components",url:"components.html"},{title:"Components",filename:"components",url:"components.html#components"},{title:"Components Variables",filename:"components",url:"components.html#components-variables"},{title:"dropdowns",filename:"dropdowns",url:"dropdowns.html"},{title:"Drop-down and split buttons mixins",filename:"dropdowns",url:"dropdowns.html#dropdown-and-split-buttons-mixins"},{title:"Drop-down",filename:"dropdowns",url:"dropdowns.html#dropdown"},{title:"Drop-down variables",filename:"dropdowns",url:"dropdowns.html#dropdown-variables"},{title:"Drop-down with icon customization",filename:"dropdowns",url:"dropdowns.html#dropdown-with-icon-customization"},{title:"Modify dropdown list styles",filename:"dropdowns",url:"dropdowns.html#modify-dropdown-list-styles"},{title:"Split button",filename:"dropdowns",url:"dropdowns.html#split-button"},{title:"Split button variables",filename:"dropdowns",url:"dropdowns.html#split-button-variables"},{title:"Split button - button styling",filename:"dropdowns",url:"dropdowns.html#split-button-button-styling"},{title:"Split button icon customization",filename:"dropdowns",url:"dropdowns.html#split-button-icon-customization"},{title:"Split button drop-down list customization",filename:"dropdowns",url:"dropdowns.html#split-button-dropdown-list-customization"},{title:"forms",filename:"forms",url:"forms.html"},{title:"Forms mixins",filename:"forms",url:"forms.html#forms-mixins"},{title:"Global forms elements customization",filename:"forms",url:"forms.html#global-forms-elements-customization"},{title:"Fieldsets & fields customization",filename:"forms",url:"forms.html#fieldsets-fields-customization"},{title:"Fieldset and legend customization variables",filename:"forms",url:"forms.html#fieldset-and-legend-customization-variables"},{title:"Fields customization variables",filename:"forms",url:"forms.html#fields-customization-variables"},{title:"Required fields message customization variables",filename:"forms",url:"forms.html#required-fields-message-customization-variables"},{title:"Form element inputs customization",filename:"forms",url:"forms.html#form-element-inputs-customization"},{title:"Form element inputs customization variables",filename:"forms",url:"forms.html#form-element-inputs-customization-variables"},{title:"Form element choice",filename:"forms",url:"forms.html#form-element-choice"},{title:"Form element choice variables",filename:"forms",url:"forms.html#form-element-choice-variables"},{title:"Custom color",filename:"forms",url:"forms.html#custom-color"},{title:"Input number - input-text view",filename:"forms",url:"forms.html#input-number-inputtext-view"},{title:"Input search - input-text view",filename:"forms",url:"forms.html#input-search-inputtext-view"},{title:"Form validation",filename:"forms",url:"forms.html#form-validation"},{title:"Form validation variables",filename:"forms",url:"forms.html#form-validation-variables"},{title:"icons",filename:"icons",url:"icons.html"},{title:"Icons",filename:"icons",url:"icons.html#icons"},{title:"Icon with image or sprite",filename:"icons",url:"icons.html#icon-with-image-or-sprite"},{title:"Icon with image or sprite variables",filename:"icons",url:"icons.html#icon-with-image-or-sprite-variables"},{title:"Icon position for an icon with image or sprite",filename:"icons",url:"icons.html#icon-position-for-an-icon-with-image-or-sprite"},{title:"Position for icon with image or sprite mixin variables",filename:"icons",url:"icons.html#position-for-icon-with-image-or-sprite-mixin-variables"},{title:"Icon sprite position (with grid)",filename:"icons",url:"icons.html#icon-sprite-position-with-grid"},{title:"Icon sprite position variables",filename:"icons",url:"icons.html#icon-sprite-position-variables"},{title:"Image/sprite icon size",filename:"icons",url:"icons.html#imagesprite-icon-size"},{title:"Image/sprite icon size variables",filename:"icons",url:"icons.html#imagesprite-icon-size-variables"},{title:"Font icon",filename:"icons",url:"icons.html#font-icon"},{title:"Font icon variables",filename:"icons",url:"icons.html#font-icon-variables"},{title:"Change the size of font icon",filename:"icons",url:"icons.html#change-the-size-of-font-icon"},{title:"Change the size of font icon variables",filename:"icons",url:"icons.html#change-the-size-of-font-icon-variables"},{title:"Hide icon text",filename:"icons",url:"icons.html#hide-icon-text"},{title:"Sprite and font icons for Blank theme",filename:"icons",url:"icons.html#sprite-and-font-icons-for-blank-theme"},{title:"layout",filename:"layout",url:"layout.html"},{title:"Layout",filename:"layout",url:"layout.html#layout"},{title:"Layout global variables",filename:"layout",url:"layout.html#layout-global-variables"},{title:"Page layouts",filename:"layout",url:"layout.html#page-layouts"},{title:"Layout column",filename:"layout",url:"layout.html#layout-column"},{title:"Layout column variables",filename:"layout",url:"layout.html#layout-column-variables"},{title:"Layout width",filename:"layout",url:"layout.html#layout-width"},{title:"Layout width variables",filename:"layout",url:"layout.html#layout-width-variables"},{title:"lib",filename:"lib",url:"lib.html"},{title:"Including Magento UI library to your theme",filename:"lib",url:"lib.html#including-magento-ui-library-to-your-theme"},{title:"loaders",filename:"loaders",url:"loaders.html"},{title:"Loaders",filename:"loaders",url:"loaders.html#loaders"},{title:"Default loader variables",filename:"loaders",url:"loaders.html#default-loader-variables"},{title:"Loading",filename:"loaders",url:"loaders.html#loading"},{title:"Loading default variables",filename:"loaders",url:"loaders.html#loading-default-variables"},{title:"messages",filename:"messages",url:"messages.html"},{title:"Messages",filename:"messages",url:"messages.html#messages"},{title:"Information message",filename:"messages",url:"messages.html#information-message"},{title:"Warning message",filename:"messages",url:"messages.html#warning-message"},{title:"Error message",filename:"messages",url:"messages.html#error-message"},{title:"Success message",filename:"messages",url:"messages.html#success-message"},{title:"Notice message",filename:"messages",url:"messages.html#notice-message"},{title:"Message with inner icon",filename:"messages",url:"messages.html#message-with-inner-icon"},{title:"Message with lateral icon",filename:"messages",url:"messages.html#message-with-lateral-icon"},{title:"Custom message style",filename:"messages",url:"messages.html#custom-message-style"},{title:"Messages global variables",filename:"messages",url:"messages.html#messages-global-variables"},{title:"pages",filename:"pages",url:"pages.html"},{title:"Pagination HTML markup",filename:"pages",url:"pages.html#pagination-html-markup"},{title:"Pagination variables",filename:"pages",url:"pages.html#pagination-variables"},{title:"Pagination with label and gradient background on links",filename:"pages",url:"pages.html#pagination-with-label-and-gradient-background-on-links"},{title:'Pagination with "previous"..."next" text links and label',filename:"pages",url:"pages.html#pagination-with-previousnext-text-links-and-label"},{title:"Pagination without label, with solid background",filename:"pages",url:"pages.html#pagination-without-label-with-solid-background"},{title:"popups",filename:"popups",url:"popups.html"},{title:"Popups",filename:"popups",url:"popups.html#popups"},{title:"Popup variables",filename:"popups",url:"popups.html#popup-variables"},{title:"Window overlay mixin variables",filename:"popups",url:"popups.html#window-overlay-mixin-variables"},{title:"Fixed height popup",filename:"popups",url:"popups.html#fixed-height-popup"},{title:"Fixed content height popup",filename:"popups",url:"popups.html#fixed-content-height-popup"},{title:"Margins for header, content and footer block in popup",filename:"popups",url:"popups.html#margins-for-header-content-and-footer-block-in-popup"},{title:"Popup titles styled as theme headings",filename:"popups",url:"popups.html#popup-titles-styled-as-theme-headings"},{title:"Popup action toolbar",filename:"popups",url:"popups.html#popup-action-toolbar"},{title:"Popup Close button without an icon",filename:"popups",url:"popups.html#popup-close-button-without-an-icon"},{title:"Modify the icon of popup Close button",filename:"popups",url:"popups.html#modify-the-icon-of-popup-close-button"},{title:"Modify overlay styles",filename:"popups",url:"popups.html#modify-overlay-styles"},{title:"rating",filename:"rating",url:"rating.html"},{title:"Ratings",filename:"rating",url:"rating.html#ratings"},{title:"Global rating variables",filename:"rating",url:"rating.html#global-rating-variables"},{title:"Rating with vote",filename:"rating",url:"rating.html#rating-with-vote"},{title:"Rating with vote icons number customization",filename:"rating",url:"rating.html#rating-with-vote-icons-number-customization"},{title:"Rating with vote icons colors customization",filename:"rating",url:"rating.html#rating-with-vote-icons-colors-customization"},{title:"Rating with vote icons symbol customization",filename:"rating",url:"rating.html#rating-with-vote-icons-symbol-customization"},{title:"Accessible rating with vote",filename:"rating",url:"rating.html#accessible-rating-with-vote"},{title:"Rating summary",filename:"rating",url:"rating.html#rating-summary"},{title:"Rating summary icons number customization",filename:"rating",url:"rating.html#rating-summary-icons-number-customization"},{title:"Rating summary icons color customization",filename:"rating",url:"rating.html#rating-summary-icons-color-customization"},{title:"Rating summary icons symbol customization",filename:"rating",url:"rating.html#rating-summary-icons-symbol-customization"},{title:"Rating summary hide label",filename:"rating",url:"rating.html#rating-summary-hide-label"},{title:"Rating summary multiple ratings",filename:"rating",url:"rating.html#rating-summary-multiple-ratings"},{title:"Rating hide label mixin",filename:"rating",url:"rating.html#rating-hide-label-mixin"},{title:"resets",filename:"resets",url:"resets.html"},{title:"Resets",filename:"resets",url:"resets.html#resets"},{title:"responsive",filename:"responsive",url:"responsive.html"},{title:"Responsive",filename:"responsive",url:"responsive.html#responsive"},{title:"Responsive mixins usage",filename:"responsive",url:"responsive.html#responsive-mixins-usage"},{title:"Media query style groups separation variables",filename:"responsive",url:"responsive.html#media-query-style-groups-separation-variables"},{title:"Responsive breakpoints",filename:"responsive",url:"responsive.html#responsive-breakpoints"},{title:"sections",filename:"sections",url:"sections.html"},{title:"Tabs and accordions",filename:"sections",url:"sections.html#tabs-and-accordions"},{title:"Tabs",filename:"sections",url:"sections.html#tabs"},{title:"Tabs mixin variables",filename:"sections",url:"sections.html#tabs-mixin-variables"},{title:"Tabs with content top border",filename:"sections",url:"sections.html#tabs-with-content-top-border"},{title:"Accordion",filename:"sections",url:"sections.html#accordion"},{title:"Accordion mixin variables",filename:"sections",url:"sections.html#accordion-mixin-variables"},{title:"Responsive tabs",filename:"sections",url:"sections.html#responsive-tabs"},{title:"Tabs Base",filename:"sections",url:"sections.html#tabs-base"},{title:"Accordion Base",filename:"sections",url:"sections.html#accordion-base"},{title:"tables",filename:"tables",url:"tables.html"},{title:"Tables",filename:"tables",url:"tables.html#tables"},{title:"Table mixin variables",filename:"tables",url:"tables.html#table-mixin-variables"},{title:"Table typography",filename:"tables",url:"tables.html#table-typography"},{title:"Table typography mixin variables",filename:"tables",url:"tables.html#table-typography-mixin-variables"},{title:"Table caption",filename:"tables",url:"tables.html#table-caption"},{title:"Table caption mixin variables",filename:"tables",url:"tables.html#table-caption-mixin-variables"},{title:"Table cells resize",filename:"tables",url:"tables.html#table-cells-resize"},{title:"Table cells resize variables",filename:"tables",url:"tables.html#table-cells-resize-variables"},{title:"Table background customization",filename:"tables",url:"tables.html#table-background-customization"},{title:"Table background mixin variables",filename:"tables",url:"tables.html#table-background-mixin-variables"},{title:"Table borders customization",filename:"tables",url:"tables.html#table-borders-customization"},{title:"Table borders mixin variables",filename:"tables",url:"tables.html#table-borders-mixin-variables"},{title:"Table with horizontal borders",filename:"tables",url:"tables.html#table-with-horizontal-borders"},{title:"Table with vertical borders",filename:"tables",url:"tables.html#table-with-vertical-borders"},{title:"Table with light borders",filename:"tables",url:"tables.html#table-with-light-borders"},{title:"Table without borders",filename:"tables",url:"tables.html#table-without-borders"},{title:"Striped table",filename:"tables",url:"tables.html#striped-table"},{title:"Striped table mixin variables",filename:"tables",url:"tables.html#striped-table-mixin-variables"},{title:"Table with rows hover",filename:"tables",url:"tables.html#table-with-rows-hover"},{title:"Table with rows hover mixin variables",filename:"tables",url:"tables.html#table-with-rows-hover-mixin-variables"},{title:"Responsive table technics #1",filename:"tables",url:"tables.html#responsive-table-technics-1"},{title:"Responsive table technics #2",filename:"tables",url:"tables.html#responsive-table-technics-2"},{title:"Responsive table technics #2 mixin variables",filename:"tables",url:"tables.html#responsive-table-technics-2-mixin-variables"},{title:"tooltips",filename:"tooltips",url:"tooltips.html"},{title:"Tooltips",filename:"tooltips",url:"tooltips.html#tooltips"},{title:"Tooltips variables",filename:"tooltips",url:"tooltips.html#tooltips-variables"},{title:"typography",filename:"typography",url:"typography.html"},{title:"Typogrphy",filename:"typography",url:"typography.html#typogrphy"},{title:"Typography variables",filename:"typography",url:"typography.html#typography-variables"},{title:"Font-size mixin",filename:"typography",url:"typography.html#fontsize-mixin"},{title:"Line-height mixin",filename:"typography",url:"typography.html#lineheight-mixin"},{title:"Word breaking mixin",filename:"typography",url:"typography.html#word-breaking-mixin"},{title:"Font face mixin",filename:"typography",url:"typography.html#font-face-mixin"},{title:"Text overflow mixin",filename:"typography",url:"typography.html#text-overflow-mixin"},{title:"Text hide",filename:"typography",url:"typography.html#text-hide"},{title:"Hyphens",filename:"typography",url:"typography.html#hyphens"},{title:"Font style and color",filename:"typography",url:"typography.html#font-style-and-color"},{title:"Font style mixin variables",filename:"typography",url:"typography.html#font-style-mixin-variables"},{title:"Reset list styles",filename:"typography",url:"typography.html#reset-list-styles"},{title:"Reset list styles variables",filename:"typography",url:"typography.html#reset-list-styles-variables"},{title:"Inline-block list item styling",filename:"typography",url:"typography.html#inlineblock-list-item-styling"},{title:"Link styling mixin",filename:"typography",url:"typography.html#link-styling-mixin"},{title:"Link styling mixin variables",filename:"typography",url:"typography.html#link-styling-mixin-variables"},{title:"Heading styling mixin",filename:"typography",url:"typography.html#heading-styling-mixin"},{title:"Base typography mixins",filename:"typography",url:"typography.html#base-typography-mixins"},{title:"Base typography mixin variables",filename:"typography",url:"typography.html#base-typography-mixin-variables"},{title:"Headings typography mixin",filename:"typography",url:"typography.html#headings-typography-mixin"},{title:"Headings typography mixin variables",filename:"typography",url:"typography.html#headings-typography-mixin-variables"},{title:"Typography links mixin",filename:"typography",url:"typography.html#typography-links-mixin"},{title:"Typography lists mixin",filename:"typography",url:"typography.html#typography-lists-mixin"},{title:"Typography lists mixin variables",filename:"typography",url:"typography.html#typography-lists-mixin-variables"},{title:"Typography code elements mixin",filename:"typography",url:"typography.html#typography-code-elements-mixin"},{title:"Typography code mixin variables",filename:"typography",url:"typography.html#typography-code-mixin-variables"},{title:"Typography blockquote",filename:"typography",url:"typography.html#typography-blockquote"},{title:"Typography blockquote mixin variables",filename:"typography",url:"typography.html#typography-blockquote-mixin-variables"},{title:"utilities",filename:"utilities",url:"utilities.html"},{title:"Utilities",filename:"utilities",url:"utilities.html#utilities"},{title:".lib-clearfix()",filename:"utilities",url:"utilities.html#libclearfix"},{title:".lib-visibility-hidden()",filename:"utilities",url:"utilities.html#libvisibilityhidden"},{title:".lib-visually-hidden()",filename:"utilities",url:"utilities.html#libvisuallyhidden"},{title:".lib-visually-hidden-reset()",filename:"utilities",url:"utilities.html#libvisuallyhiddenreset"},{title:".lib-css()",filename:"utilities",url:"utilities.html#libcss"},{title:".lib-css() variables",filename:"utilities",url:"utilities.html#libcss-variables"},{title:".lib-rotate()",filename:"utilities",url:"utilities.html#librotate"},{title:".lib-rotate() variables",filename:"utilities",url:"utilities.html#librotate-variables"},{title:".lib-input-placeholder()",filename:"utilities",url:"utilities.html#libinputplaceholder"},{title:".lib-input-placeholder() variables",filename:"utilities",url:"utilities.html#libinputplaceholder-variables"},{title:".lib-background-gradient()",filename:"utilities",url:"utilities.html#libbackgroundgradient"},{title:".lib-background-gradient() variables",filename:"utilities",url:"utilities.html#libbackgroundgradient-variables"},{title:"variables",filename:"variables",url:"variables.html"},{title:"List of Global Variables",filename:"variables",url:"variables.html#list-of-global-variables"},{title:"Table with rows hover mixin variables",filename:"variables",url:"variables.html#table-with-rows-hover-mixin-variables"},{title:"docs",filename:"docs",url:"docs.html"},{title:"Documentation",filename:"docs",url:"docs.html#documentation"}];(function(){"use strict";var b=function(a,b){return Array.prototype.indexOf.call(a,b)!==-1},c=function(a,b){return Array.prototype.filter.call(a,b)},d=function(a,b){return Array.prototype.forEach.call(a,b)},e=document.getElementsByTagName("body")[0];e.addEventListener("click",function(a){var b=a.target;b.tagName.toLowerCase()==="svg"&&(b=b.parentNode);var c=!1;b.dataset.toggle!=null&&(a.preventDefault(),b.classList.contains("is-active")||(c=!0)),d(e.querySelectorAll("[data-toggle]"),function(a){a.classList.remove("is-active"),document.getElementById(a.dataset.toggle).hidden=!0}),c&&(b.classList.add("is-active"),document.getElementById(b.dataset.toggle).hidden=!1)}),function(){var f=e.getElementsByClassName("nav")[0];if(!f)return;var g=document.createElement("ul");g.className="nav-results",g.id="nav-search",g.hidden=!0,d(a,function(a){var b,c,d;b=document.createElement("li"),b._title=a.title.toLowerCase(),b.hidden=!0,b.appendChild(c=document.createElement("a")),c.href=a.url,c.innerHTML=a.title,c.appendChild(d=document.createElement("span")),d.innerHTML=a.filename,d.className="nav-results-filename",g.appendChild(b)}),f.appendChild(g);var h=g.children,i=function(a){d(h,function(a){a.hidden=!0});var b=this.value.toLowerCase(),e=[];b!==""&&(e=c(h,function(a){return a._title.indexOf(b)!==-1})),e.length>0?(d(e,function(a){a.hidden=!1}),g.hidden=!1):g.hidden=!0},j=f.querySelector('input[type="search"]');j.addEventListener("keyup",i),j.addEventListener("focus",i),e.addEventListener("click",function(a){if(a.target.classList&&a.target.classList.contains("search"))return;g.hidden=!0}),g.addEventListener("click",function(a){j.value=""});var k=document.createElement("ul");k.id="nav-toc",k.hidden=!0,k.className="nav-results toc-list",c(e.getElementsByTagName("*"),function(a){return b(["h1","h2","h3"],a.tagName.toLowerCase())}).map(function(a){var b=document.createElement("li"),c=document.createElement("a"),d=a.tagName.toLowerCase()[1];c.classList.add("level-"+d),b.appendChild(c),c.href="#"+a.id,c.innerHTML=a.innerHTML,k.appendChild(b)}),f.appendChild(k)}()})(),function(){"use strict";if(location.hash==="#__preview__"||location.protocol==="data:")return;var a=function(a,b){return Array.prototype.forEach.call(a,b)},b=function(a,b){var e=Array.prototype.slice.call(arguments,2);return d(a,function(a){return(c(b)?b||a:a[b]).apply(a,e)})},c=function(a){return Object.prototype.toString.call(a)==="[object Function]"},d=function(a,b){return Array.prototype.map.call(a,b)},e=function(a,b){return d(a,function(a){return a[b]})},f=function(a){var b={},c=a.split(";");for(var d=0;c.length>d;d++){var e=c[d].trim().split("=");b[e[0]]=e[1]}return b},g=function(a,c){return b(e(a,"classList"),"remove",c)},h=function(a,b){a.contentDocument.defaultView.postMessage(b,"*")},i=document.getElementsByTagName("head")[0],j=document.getElementsByTagName("body")[0],k=e(i.querySelectorAll('style[type="text/preview"]'),"innerHTML").join(""),l=e(i.querySelectorAll('script[type="text/preview"]'),"innerHTML").join(""),m=location.href.split("#")[0]+"#__preview__",n=document.createElement("iframe");n.src="data:text/html,",j.appendChild(n),n.addEventListener("load",function(){var b={sameOriginDataUri:!0};try{this.contentDocument,this.contentDocument||(b.sameOriginDataUri=!1)}catch(c){b.sameOriginDataUri=!1}this.parentNode.removeChild(this),a(j.getElementsByTagName("textarea"),function(a,c){o(a,b,c),q(),p(a)})});var o=function(a,b,c){var d,e,f;d=document.createElement("div"),d.appendChild(e=document.createElement("div")),d.className="preview",e.appendChild(f=document.createElement("iframe")),e.className="resizeable",f.setAttribute("scrolling","no"),f.name="iframe"+c++,f.addEventListener("load",function(){var c,d,e,f,g,i,j;j=this.contentDocument;if(!b.sameOriginDataUri&&this.src!==m)return;this.src===m&&(c=j.createElement("html"),c.appendChild(j.createElement("head")),c.appendChild(d=j.createElement("body")),d.innerHTML=a.textContent,j.replaceChild(c,j.documentElement)),g=j.createElement("head"),g.appendChild(f=j.createElement("style")),g.appendChild(e=j.createElement("script")),e.textContent=l,f.textContent=k,i=j.getElementsByTagName("head")[0],i.parentNode.replaceChild(g,i),h(this,"getHeight")});var g;b.sameOriginDataUri?g="data:text/html;charset=utf-8,"+encodeURIComponent("<!doctype html><html><head></head></body>"+a.textContent):g=m,f.setAttribute("src",g);var i=function(){f.contentDocument.body.innerHTML=this.value,h(f,"getHeight")};a.addEventListener("keypress",i),a.addEventListener("keyup",i),a.parentNode.insertBefore(d,a)},p=function(a){var b=document.createElement("div");b.className="preview-code",b.style.position="absolute",b.style.left="-9999px",j.appendChild(b);var c=parseInt(window.getComputedStyle(a).getPropertyValue("max-height"),10),d=function(a){b.textContent=this.value+"\n";var d=b.offsetHeight+2;d>=c?this.style.overflow="auto":this.style.overflow="hidden",this.style.height=b.offsetHeight+2+"px"};a.addEventListener("keypress",d),a.addEventListener("keyup",d),d.call(a)},q=function(){var b=j.getElementsByClassName("settings")[0],c=j.getElementsByClassName("resizeable"),d=30,e=function(b){document.cookie="preview-width="+b,a(c,function(a){b==="auto"&&(b=a.parentNode.offsetWidth),a.style.width=b+"px",h(a.getElementsByTagName("iframe")[0],"getHeight")})},i=f(document.cookie)["preview-width"];if(i){e(i),g(b.getElementsByClassName("is-active"),"is-active");var k=b.querySelector('button[data-width="'+i+'"]');k&&k.classList.add("is-active")}window.addEventListener("message",function(a){if(a.data==null||!a.source)return;var b=a.data,c=document.getElementsByName(a.source.name)[0];b.height!=null&&c&&(c.parentNode.style.height=b.height+d+"px")},!1),b&&c.length>0&&(b.hidden=!1,b.addEventListener("click",function(a){var c=a.target.tagName.toLowerCase(),d;if(c==="button")d=a.target;else{if(c!=="svg")return;d=a.target.parentNode}a.preventDefault(),g(b.getElementsByClassName("is-active"),"is-active"),d.classList.add("is-active");var f=d.dataset.width;e(f)}))}}()})()</script></body></html><!-- Generated with StyleDocco (http://jacobrask.github.com/styledocco). --> diff --git a/lib/web/css/docs/tooltips.html b/lib/web/css/docs/tooltips.html index 20158046859f6..2b38aa0a55aef 100644 --- a/lib/web/css/docs/tooltips.html +++ b/lib/web/css/docs/tooltips.html @@ -186,4 +186,4 @@ </tr> </table> </pre> -</div></article></section><div class="bar bottom"><div hidden class="settings container"><!-- Icons from http://iconmonstr.com--><button title="Desktop (1280)" data-width='1280'><svg viewBox="0 0 412 386" height="24" width="26" class="icon"><path d="m147.6,343.9c-4.5,15.9-26.2,37.6-42.1,42.1h201c-15.3,-4-38.1,-26.8-42.1,-42.1H147.6zM387,0.5H25c-13.8,0-25,11.2-25,25V294c0,13.8 11.2,25 25,25h362c13.8,0 25,-11.2 25,-25V25.5C412,11.7 400.8,0.5 387,0.5zM369.9,238.2H42.1L42.1,42.6 369.9,42.6V238.2z"></path></svg></button><button title="Laptop (1024)" data-width='1024'><svg viewBox="0 0 384 312" height="23" width="28" class="icon"><path d="m349.2,20.5c0,-11-9,-20-20,-20H53.6c-11,0-20,9-20,20v194H349.2v-194zm-27,167H60.6V27.5H322.2v160zm28,42H32.6L2.6,282.1c-3.5,6.2-3.5,13.8 0.1,19.9 3.6,6.2 10.2,9.9 17.3,9.9H363.1c7.1,0 13.7,-3.8 17.3,-10 3.6,-6.2 3.6,-13.8 0,-20l-30.2,-52.5zm-196.9,54 8,-23.5h60.5l8,23.5h-76.5z"></path></svg></button><button title="Tablet (768)" data-width='768'><svg viewBox="0 0 317 412" height="24" width="18" class="icon"><path d="M 316.5,380 V 32 c 0,-17.7 -14.3,-32 -32,-32 H 32 C 14.3,0 0,14.3 0,32 v 348 c 0,17.7 14.3,32 32,32 h 252.5 c 17.7,0 32,-14.3 32,-32 z M 40,367 V 45 H 276.5 V 367 H 40 z m 109.8,22.7 c 0,-4.7 3.8,-8.5 8.5,-8.5 4.7,0 8.5,3.8 8.5,8.5 0,4.7 -3.8,8.5 -8.5,8.5 -4.7,0 -8.5,-3.8 -8.5,-8.5 z"></path></svg></button><button title="Smart phone (320)" data-width='320'><svg viewBox="0 0 224 412" height="24" width="13" class="icon"><path d="M 190.7,0 H 33 C 14.8,0 0,14.8 0,33 v 346 c 0,18.2 14.8,33 33,33 h 157.7 c 18.2,0 33,-14.8 33,-33 V 33 c 0,-18.2 -14.8,-33 -33,-33 z M 94.3,30.2 h 37 c 2.2,0 4,1.8 4,4 0,2.2 -1.8,4 -4,4 h -37 c -2.2,0 -4,-1.8 -4,-4 0,-2.2 1.8,-4 4,-4 z m 18.5,362.8 c -8.8,0 -16,-7.2 -16,-16 0,-8.8 7.2,-16 16,-16 8.8,0 16,7.2 16,16 0,8.8 -7.2,16 -16,16 z M 198.6,343.8 H 25.1 V 68.2 h 173.5 v 275.5 z"></path></svg></button><button title="Feature phone (240)" data-width='240'><svg viewBox="0 0 201 412" height="24" width="12" class="icon"><path d="M 165.5,0.2 V 45 H 25 c -13.8,0 -25,11.2 -25,25 V 387 c 0,13.8 11.2,25 25,25 h 150.5 c 13.8,0 25,-11.2 25,-25 V 0.2 h -35 z M 65.2,366.5 H 34.2 v -24.5 h 31 v 24.5 z m 0,-44.3 H 34.2 v -24.5 h 31 v 24.5 z m 50.5,44.3 H 84.7 v -24.5 h 31 v 24.5 z m 0,-44.3 H 84.7 v -24.5 h 31 v 24.5 z m 50.5,44.3 h -31 v -24.5 h 31 v 24.5 z m 0,-44.3 h -31 v -24.5 h 31 v 24.5 z m 0,-59.3 h -132 V 95.4 h 132 V 262.9 z"></path></svg></button><button title="Auto (100%)" data-width="auto" class="auto is-active">Auto</button></div></div><script>(function(){var a=[{title:"actions-toolbar",filename:"actions-toolbar",url:"actions-toolbar.html"},{title:"Actions toolbar",filename:"actions-toolbar",url:"actions-toolbar.html#actions-toolbar"},{title:"Actions toolbar mixin variables",filename:"actions-toolbar",url:"actions-toolbar.html#actions-toolbar-mixin-variables"},{title:"Actions toolbar alignment",filename:"actions-toolbar",url:"actions-toolbar.html#actions-toolbar-alignment"},{title:"Reverse primary and secondary blocks",filename:"actions-toolbar",url:"actions-toolbar.html#reverse-primary-and-secondary-blocks"},{title:"Actions toolbar indents customizations",filename:"actions-toolbar",url:"actions-toolbar.html#actions-toolbar-indents-customizations"},{title:"Responsive actions toolbar",filename:"actions-toolbar",url:"actions-toolbar.html#responsive-actions-toolbar"},{title:"breadcrumbs",filename:"breadcrumbs",url:"breadcrumbs.html"},{title:"Breadcrumbs",filename:"breadcrumbs",url:"breadcrumbs.html#breadcrumbs"},{title:"Breadcrumbs variables",filename:"breadcrumbs",url:"breadcrumbs.html#breadcrumbs-variables"},{title:"Button-styled breadcrumbs with gradient background, border, and no separating symbol",filename:"breadcrumbs",url:"breadcrumbs.html#buttonstyled-breadcrumbs-with-gradient-background-border-and-no-separating-symbol"},{title:"Breadcrumbs with solid background",filename:"breadcrumbs",url:"breadcrumbs.html#breadcrumbs-with-solid-background"},{title:"buttons",filename:"buttons",url:"buttons.html"},{title:"Default button",filename:"buttons",url:"buttons.html#default-button"},{title:"Button variables",filename:"buttons",url:"buttons.html#button-variables"},{title:"Button as an icon",filename:"buttons",url:"buttons.html#button-as-an-icon"},{title:"Button with an icon on the left or right side of the text",filename:"buttons",url:"buttons.html#button-with-an-icon-on-the-left-or-right-side-of-the-text"},{title:"Button with fixed width",filename:"buttons",url:"buttons.html#button-with-fixed-width"},{title:"Primary button",filename:"buttons",url:"buttons.html#primary-button"},{title:"Primary button variables",filename:"buttons",url:"buttons.html#primary-button-variables"},{title:"Button with gradient background",filename:"buttons",url:"buttons.html#button-with-gradient-background"},{title:"Button as a link",filename:"buttons",url:"buttons.html#button-as-a-link"},{title:"Button as a link variables",filename:"buttons",url:"buttons.html#button-as-a-link-variables"},{title:"Link as a button",filename:"buttons",url:"buttons.html#link-as-a-button"},{title:"Button reset",filename:"buttons",url:"buttons.html#button-reset"},{title:"Button revert secondary color",filename:"buttons",url:"buttons.html#button-revert-secondary-color"},{title:"Button revert secondary color variables",filename:"buttons",url:"buttons.html#button-revert-secondary-color-variables"},{title:"Button revert secondary size",filename:"buttons",url:"buttons.html#button-revert-secondary-size"},{title:"Button revert secondary size variables",filename:"buttons",url:"buttons.html#button-revert-secondary-size-variables"},{title:"components",filename:"components",url:"components.html"},{title:"Components",filename:"components",url:"components.html#components"},{title:"Components Variables",filename:"components",url:"components.html#components-variables"},{title:"dropdowns",filename:"dropdowns",url:"dropdowns.html"},{title:"Drop-down and split buttons mixins",filename:"dropdowns",url:"dropdowns.html#dropdown-and-split-buttons-mixins"},{title:"Drop-down",filename:"dropdowns",url:"dropdowns.html#dropdown"},{title:"Drop-down variables",filename:"dropdowns",url:"dropdowns.html#dropdown-variables"},{title:"Drop-down with icon customization",filename:"dropdowns",url:"dropdowns.html#dropdown-with-icon-customization"},{title:"Modify dropdown list styles",filename:"dropdowns",url:"dropdowns.html#modify-dropdown-list-styles"},{title:"Split button",filename:"dropdowns",url:"dropdowns.html#split-button"},{title:"Split button variables",filename:"dropdowns",url:"dropdowns.html#split-button-variables"},{title:"Split button - button styling",filename:"dropdowns",url:"dropdowns.html#split-button-button-styling"},{title:"Split button icon customization",filename:"dropdowns",url:"dropdowns.html#split-button-icon-customization"},{title:"Split button drop-down list customization",filename:"dropdowns",url:"dropdowns.html#split-button-dropdown-list-customization"},{title:"forms",filename:"forms",url:"forms.html"},{title:"Forms mixins",filename:"forms",url:"forms.html#forms-mixins"},{title:"Global forms elements customization",filename:"forms",url:"forms.html#global-forms-elements-customization"},{title:"Fieldsets & fields customization",filename:"forms",url:"forms.html#fieldsets-fields-customization"},{title:"Fieldset and legend customization variables",filename:"forms",url:"forms.html#fieldset-and-legend-customization-variables"},{title:"Fields customization variables",filename:"forms",url:"forms.html#fields-customization-variables"},{title:"Required fields message customization variables",filename:"forms",url:"forms.html#required-fields-message-customization-variables"},{title:"Form element inputs customization",filename:"forms",url:"forms.html#form-element-inputs-customization"},{title:"Form element inputs customization variables",filename:"forms",url:"forms.html#form-element-inputs-customization-variables"},{title:"Form element choice",filename:"forms",url:"forms.html#form-element-choice"},{title:"Form element choice variables",filename:"forms",url:"forms.html#form-element-choice-variables"},{title:"Custom color",filename:"forms",url:"forms.html#custom-color"},{title:"Input number - input-text view",filename:"forms",url:"forms.html#input-number-inputtext-view"},{title:"Input search - input-text view",filename:"forms",url:"forms.html#input-search-inputtext-view"},{title:"Form validation",filename:"forms",url:"forms.html#form-validation"},{title:"Form validation variables",filename:"forms",url:"forms.html#form-validation-variables"},{title:"icons",filename:"icons",url:"icons.html"},{title:"Icons",filename:"icons",url:"icons.html#icons"},{title:"Icon with image or sprite",filename:"icons",url:"icons.html#icon-with-image-or-sprite"},{title:"Icon with image or sprite variables",filename:"icons",url:"icons.html#icon-with-image-or-sprite-variables"},{title:"Icon position for an icon with image or sprite",filename:"icons",url:"icons.html#icon-position-for-an-icon-with-image-or-sprite"},{title:"Position for icon with image or sprite mixin variables",filename:"icons",url:"icons.html#position-for-icon-with-image-or-sprite-mixin-variables"},{title:"Icon sprite position (with grid)",filename:"icons",url:"icons.html#icon-sprite-position-with-grid"},{title:"Icon sprite position variables",filename:"icons",url:"icons.html#icon-sprite-position-variables"},{title:"Image/sprite icon size",filename:"icons",url:"icons.html#imagesprite-icon-size"},{title:"Image/sprite icon size variables",filename:"icons",url:"icons.html#imagesprite-icon-size-variables"},{title:"Font icon",filename:"icons",url:"icons.html#font-icon"},{title:"Font icon variables",filename:"icons",url:"icons.html#font-icon-variables"},{title:"Change the size of font icon",filename:"icons",url:"icons.html#change-the-size-of-font-icon"},{title:"Change the size of font icon variables",filename:"icons",url:"icons.html#change-the-size-of-font-icon-variables"},{title:"Hide icon text",filename:"icons",url:"icons.html#hide-icon-text"},{title:"Sprite and font icons for Blank theme",filename:"icons",url:"icons.html#sprite-and-font-icons-for-blank-theme"},{title:"layout",filename:"layout",url:"layout.html"},{title:"Layout",filename:"layout",url:"layout.html#layout"},{title:"Layout global variables",filename:"layout",url:"layout.html#layout-global-variables"},{title:"Page layouts",filename:"layout",url:"layout.html#page-layouts"},{title:"Layout column",filename:"layout",url:"layout.html#layout-column"},{title:"Layout column variables",filename:"layout",url:"layout.html#layout-column-variables"},{title:"Layout width",filename:"layout",url:"layout.html#layout-width"},{title:"Layout width variables",filename:"layout",url:"layout.html#layout-width-variables"},{title:"lib",filename:"lib",url:"lib.html"},{title:"Including Magento UI library to your theme",filename:"lib",url:"lib.html#including-magento-ui-library-to-your-theme"},{title:"loaders",filename:"loaders",url:"loaders.html"},{title:"Loaders",filename:"loaders",url:"loaders.html#loaders"},{title:"Default loader variables",filename:"loaders",url:"loaders.html#default-loader-variables"},{title:"Loading",filename:"loaders",url:"loaders.html#loading"},{title:"Loading default variables",filename:"loaders",url:"loaders.html#loading-default-variables"},{title:"messages",filename:"messages",url:"messages.html"},{title:"Messages",filename:"messages",url:"messages.html#messages"},{title:"Information message",filename:"messages",url:"messages.html#information-message"},{title:"Warning message",filename:"messages",url:"messages.html#warning-message"},{title:"Error message",filename:"messages",url:"messages.html#error-message"},{title:"Success message",filename:"messages",url:"messages.html#success-message"},{title:"Notice message",filename:"messages",url:"messages.html#notice-message"},{title:"Message with inner icon",filename:"messages",url:"messages.html#message-with-inner-icon"},{title:"Message with lateral icon",filename:"messages",url:"messages.html#message-with-lateral-icon"},{title:"Custom message style",filename:"messages",url:"messages.html#custom-message-style"},{title:"Messages global variables",filename:"messages",url:"messages.html#messages-global-variables"},{title:"pages",filename:"pages",url:"pages.html"},{title:"Pagination HTML markup",filename:"pages",url:"pages.html#pagination-html-markup"},{title:"Pagination variables",filename:"pages",url:"pages.html#pagination-variables"},{title:"Pagination with label and gradient background on links",filename:"pages",url:"pages.html#pagination-with-label-and-gradient-background-on-links"},{title:'Pagination with "previous"..."next" text links and label',filename:"pages",url:"pages.html#pagination-with-previousnext-text-links-and-label"},{title:"Pagination without label, with solid background",filename:"pages",url:"pages.html#pagination-without-label-with-solid-background"},{title:"popups",filename:"popups",url:"popups.html"},{title:"Popups",filename:"popups",url:"popups.html#popups"},{title:"Popup variables",filename:"popups",url:"popups.html#popup-variables"},{title:"Window overlay mixin variables",filename:"popups",url:"popups.html#window-overlay-mixin-variables"},{title:"Fixed height popup",filename:"popups",url:"popups.html#fixed-height-popup"},{title:"Fixed content height popup",filename:"popups",url:"popups.html#fixed-content-height-popup"},{title:"Margins for header, content and footer block in popup",filename:"popups",url:"popups.html#margins-for-header-content-and-footer-block-in-popup"},{title:"Popup titles styled as theme headings",filename:"popups",url:"popups.html#popup-titles-styled-as-theme-headings"},{title:"Popup action toolbar",filename:"popups",url:"popups.html#popup-action-toolbar"},{title:"Popup Close button without an icon",filename:"popups",url:"popups.html#popup-close-button-without-an-icon"},{title:"Modify the icon of popup Close button",filename:"popups",url:"popups.html#modify-the-icon-of-popup-close-button"},{title:"Modify overlay styles",filename:"popups",url:"popups.html#modify-overlay-styles"},{title:"rating",filename:"rating",url:"rating.html"},{title:"Ratings",filename:"rating",url:"rating.html#ratings"},{title:"Global rating variables",filename:"rating",url:"rating.html#global-rating-variables"},{title:"Rating with vote",filename:"rating",url:"rating.html#rating-with-vote"},{title:"Rating with vote icons number customization",filename:"rating",url:"rating.html#rating-with-vote-icons-number-customization"},{title:"Rating with vote icons colors customization",filename:"rating",url:"rating.html#rating-with-vote-icons-colors-customization"},{title:"Rating with vote icons symbol customization",filename:"rating",url:"rating.html#rating-with-vote-icons-symbol-customization"},{title:"Accessible rating with vote",filename:"rating",url:"rating.html#accessible-rating-with-vote"},{title:"Rating summary",filename:"rating",url:"rating.html#rating-summary"},{title:"Rating summary icons number customization",filename:"rating",url:"rating.html#rating-summary-icons-number-customization"},{title:"Rating summary icons color customization",filename:"rating",url:"rating.html#rating-summary-icons-color-customization"},{title:"Rating summary icons symbol customization",filename:"rating",url:"rating.html#rating-summary-icons-symbol-customization"},{title:"Rating summary hide label",filename:"rating",url:"rating.html#rating-summary-hide-label"},{title:"Rating summary multiple ratings",filename:"rating",url:"rating.html#rating-summary-multiple-ratings"},{title:"Rating hide label mixin",filename:"rating",url:"rating.html#rating-hide-label-mixin"},{title:"resets",filename:"resets",url:"resets.html"},{title:"Resets",filename:"resets",url:"resets.html#resets"},{title:"responsive",filename:"responsive",url:"responsive.html"},{title:"Responsive",filename:"responsive",url:"responsive.html#responsive"},{title:"Responsive mixins usage",filename:"responsive",url:"responsive.html#responsive-mixins-usage"},{title:"Media query style groups separation variables",filename:"responsive",url:"responsive.html#media-query-style-groups-separation-variables"},{title:"Responsive breakpoints",filename:"responsive",url:"responsive.html#responsive-breakpoints"},{title:"sections",filename:"sections",url:"sections.html"},{title:"Tabs and accordions",filename:"sections",url:"sections.html#tabs-and-accordions"},{title:"Tabs",filename:"sections",url:"sections.html#tabs"},{title:"Tabs mixin variables",filename:"sections",url:"sections.html#tabs-mixin-variables"},{title:"Tabs with content top border",filename:"sections",url:"sections.html#tabs-with-content-top-border"},{title:"Accordion",filename:"sections",url:"sections.html#accordion"},{title:"Accordion mixin variables",filename:"sections",url:"sections.html#accordion-mixin-variables"},{title:"Responsive tabs",filename:"sections",url:"sections.html#responsive-tabs"},{title:"Tabs Base",filename:"sections",url:"sections.html#tabs-base"},{title:"Accordion Base",filename:"sections",url:"sections.html#accordion-base"},{title:"tables",filename:"tables",url:"tables.html"},{title:"Tables",filename:"tables",url:"tables.html#tables"},{title:"Table mixin variables",filename:"tables",url:"tables.html#table-mixin-variables"},{title:"Table typography",filename:"tables",url:"tables.html#table-typography"},{title:"Table typography mixin variables",filename:"tables",url:"tables.html#table-typography-mixin-variables"},{title:"Table caption",filename:"tables",url:"tables.html#table-caption"},{title:"Table caption mixin variables",filename:"tables",url:"tables.html#table-caption-mixin-variables"},{title:"Table cells resize",filename:"tables",url:"tables.html#table-cells-resize"},{title:"Table cells resize variables",filename:"tables",url:"tables.html#table-cells-resize-variables"},{title:"Table background customization",filename:"tables",url:"tables.html#table-background-customization"},{title:"Table background mixin variables",filename:"tables",url:"tables.html#table-background-mixin-variables"},{title:"Table borders customization",filename:"tables",url:"tables.html#table-borders-customization"},{title:"Table borders mixin variables",filename:"tables",url:"tables.html#table-borders-mixin-variables"},{title:"Table with horizontal borders",filename:"tables",url:"tables.html#table-with-horizontal-borders"},{title:"Table with vertical borders",filename:"tables",url:"tables.html#table-with-vertical-borders"},{title:"Table with light borders",filename:"tables",url:"tables.html#table-with-light-borders"},{title:"Table without borders",filename:"tables",url:"tables.html#table-without-borders"},{title:"Striped table",filename:"tables",url:"tables.html#striped-table"},{title:"Striped table mixin variables",filename:"tables",url:"tables.html#striped-table-mixin-variables"},{title:"Table with rows hover",filename:"tables",url:"tables.html#table-with-rows-hover"},{title:"Table with rows hover mixin variables",filename:"tables",url:"tables.html#table-with-rows-hover-mixin-variables"},{title:"Responsive table technics #1",filename:"tables",url:"tables.html#responsive-table-technics-1"},{title:"Responsive table technics #2",filename:"tables",url:"tables.html#responsive-table-technics-2"},{title:"Responsive table technics #2 mixin variables",filename:"tables",url:"tables.html#responsive-table-technics-2-mixin-variables"},{title:"tooltips",filename:"tooltips",url:"tooltips.html"},{title:"Tooltips",filename:"tooltips",url:"tooltips.html#tooltips"},{title:"Tooltips variables",filename:"tooltips",url:"tooltips.html#tooltips-variables"},{title:"typography",filename:"typography",url:"typography.html"},{title:"Typogrphy",filename:"typography",url:"typography.html#typogrphy"},{title:"Typography variables",filename:"typography",url:"typography.html#typography-variables"},{title:"Font-size mixin",filename:"typography",url:"typography.html#fontsize-mixin"},{title:"Line-height mixin",filename:"typography",url:"typography.html#lineheight-mixin"},{title:"Word breaking mixin",filename:"typography",url:"typography.html#word-breaking-mixin"},{title:"Font face mixin",filename:"typography",url:"typography.html#font-face-mixin"},{title:"Text overflow mixin",filename:"typography",url:"typography.html#text-overflow-mixin"},{title:"Text hide",filename:"typography",url:"typography.html#text-hide"},{title:"Hyphens",filename:"typography",url:"typography.html#hyphens"},{title:"Font style and color",filename:"typography",url:"typography.html#font-style-and-color"},{title:"Font style mixin variables",filename:"typography",url:"typography.html#font-style-mixin-variables"},{title:"Reset list styles",filename:"typography",url:"typography.html#reset-list-styles"},{title:"Reset list styles variables",filename:"typography",url:"typography.html#reset-list-styles-variables"},{title:"Inline-block list item styling",filename:"typography",url:"typography.html#inlineblock-list-item-styling"},{title:"Link styling mixin",filename:"typography",url:"typography.html#link-styling-mixin"},{title:"Link styling mixin variables",filename:"typography",url:"typography.html#link-styling-mixin-variables"},{title:"Heading styling mixin",filename:"typography",url:"typography.html#heading-styling-mixin"},{title:"Base typography mixins",filename:"typography",url:"typography.html#base-typography-mixins"},{title:"Base typography mixin variables",filename:"typography",url:"typography.html#base-typography-mixin-variables"},{title:"Headings typography mixin",filename:"typography",url:"typography.html#headings-typography-mixin"},{title:"Headings typography mixin variables",filename:"typography",url:"typography.html#headings-typography-mixin-variables"},{title:"Typography links mixin",filename:"typography",url:"typography.html#typography-links-mixin"},{title:"Typography lists mixin",filename:"typography",url:"typography.html#typography-lists-mixin"},{title:"Typography lists mixin variables",filename:"typography",url:"typography.html#typography-lists-mixin-variables"},{title:"Typography code elements mixin",filename:"typography",url:"typography.html#typography-code-elements-mixin"},{title:"Typography code mixin variables",filename:"typography",url:"typography.html#typography-code-mixin-variables"},{title:"Typography blockquote",filename:"typography",url:"typography.html#typography-blockquote"},{title:"Typography blockquote mixin variables",filename:"typography",url:"typography.html#typography-blockquote-mixin-variables"},{title:"utilities",filename:"utilities",url:"utilities.html"},{title:"Utilities",filename:"utilities",url:"utilities.html#utilities"},{title:".lib-clearfix()",filename:"utilities",url:"utilities.html#libclearfix"},{title:".lib-visibility-hidden()",filename:"utilities",url:"utilities.html#libvisibilityhidden"},{title:".lib-visually-hidden()",filename:"utilities",url:"utilities.html#libvisuallyhidden"},{title:".lib-visually-hidden-reset()",filename:"utilities",url:"utilities.html#libvisuallyhiddenreset"},{title:".lib-css()",filename:"utilities",url:"utilities.html#libcss"},{title:".lib-css() variables",filename:"utilities",url:"utilities.html#libcss-variables"},{title:".lib-rotate()",filename:"utilities",url:"utilities.html#librotate"},{title:".lib-rotate() variables",filename:"utilities",url:"utilities.html#librotate-variables"},{title:".lib-input-placeholder()",filename:"utilities",url:"utilities.html#libinputplaceholder"},{title:".lib-input-placeholder() variables",filename:"utilities",url:"utilities.html#libinputplaceholder-variables"},{title:".lib-background-gradient()",filename:"utilities",url:"utilities.html#libbackgroundgradient"},{title:".lib-background-gradient() variables",filename:"utilities",url:"utilities.html#libbackgroundgradient-variables"},{title:".lib-url-check()",filename:"utilities",url:"utilities.html#liburlcheck"},{title:".lib-url-check() variables",filename:"utilities",url:"utilities.html#liburlcheck-variables"},{title:"variables",filename:"variables",url:"variables.html"},{title:"List of Global Variables",filename:"variables",url:"variables.html#list-of-global-variables"},{title:"Table with rows hover mixin variables",filename:"variables",url:"variables.html#table-with-rows-hover-mixin-variables"},{title:"docs",filename:"docs",url:"docs.html"},{title:"Documentation",filename:"docs",url:"docs.html#documentation"}];(function(){"use strict";var b=function(a,b){return Array.prototype.indexOf.call(a,b)!==-1},c=function(a,b){return Array.prototype.filter.call(a,b)},d=function(a,b){return Array.prototype.forEach.call(a,b)},e=document.getElementsByTagName("body")[0];e.addEventListener("click",function(a){var b=a.target;b.tagName.toLowerCase()==="svg"&&(b=b.parentNode);var c=!1;b.dataset.toggle!=null&&(a.preventDefault(),b.classList.contains("is-active")||(c=!0)),d(e.querySelectorAll("[data-toggle]"),function(a){a.classList.remove("is-active"),document.getElementById(a.dataset.toggle).hidden=!0}),c&&(b.classList.add("is-active"),document.getElementById(b.dataset.toggle).hidden=!1)}),function(){var f=e.getElementsByClassName("nav")[0];if(!f)return;var g=document.createElement("ul");g.className="nav-results",g.id="nav-search",g.hidden=!0,d(a,function(a){var b,c,d;b=document.createElement("li"),b._title=a.title.toLowerCase(),b.hidden=!0,b.appendChild(c=document.createElement("a")),c.href=a.url,c.innerHTML=a.title,c.appendChild(d=document.createElement("span")),d.innerHTML=a.filename,d.className="nav-results-filename",g.appendChild(b)}),f.appendChild(g);var h=g.children,i=function(a){d(h,function(a){a.hidden=!0});var b=this.value.toLowerCase(),e=[];b!==""&&(e=c(h,function(a){return a._title.indexOf(b)!==-1})),e.length>0?(d(e,function(a){a.hidden=!1}),g.hidden=!1):g.hidden=!0},j=f.querySelector('input[type="search"]');j.addEventListener("keyup",i),j.addEventListener("focus",i),e.addEventListener("click",function(a){if(a.target.classList&&a.target.classList.contains("search"))return;g.hidden=!0}),g.addEventListener("click",function(a){j.value=""});var k=document.createElement("ul");k.id="nav-toc",k.hidden=!0,k.className="nav-results toc-list",c(e.getElementsByTagName("*"),function(a){return b(["h1","h2","h3"],a.tagName.toLowerCase())}).map(function(a){var b=document.createElement("li"),c=document.createElement("a"),d=a.tagName.toLowerCase()[1];c.classList.add("level-"+d),b.appendChild(c),c.href="#"+a.id,c.innerHTML=a.innerHTML,k.appendChild(b)}),f.appendChild(k)}()})(),function(){"use strict";if(location.hash==="#__preview__"||location.protocol==="data:")return;var a=function(a,b){return Array.prototype.forEach.call(a,b)},b=function(a,b){var e=Array.prototype.slice.call(arguments,2);return d(a,function(a){return(c(b)?b||a:a[b]).apply(a,e)})},c=function(a){return Object.prototype.toString.call(a)==="[object Function]"},d=function(a,b){return Array.prototype.map.call(a,b)},e=function(a,b){return d(a,function(a){return a[b]})},f=function(a){var b={},c=a.split(";");for(var d=0;c.length>d;d++){var e=c[d].trim().split("=");b[e[0]]=e[1]}return b},g=function(a,c){return b(e(a,"classList"),"remove",c)},h=function(a,b){a.contentDocument.defaultView.postMessage(b,"*")},i=document.getElementsByTagName("head")[0],j=document.getElementsByTagName("body")[0],k=e(i.querySelectorAll('style[type="text/preview"]'),"innerHTML").join(""),l=e(i.querySelectorAll('script[type="text/preview"]'),"innerHTML").join(""),m=location.href.split("#")[0]+"#__preview__",n=document.createElement("iframe");n.src="data:text/html,",j.appendChild(n),n.addEventListener("load",function(){var b={sameOriginDataUri:!0};try{this.contentDocument,this.contentDocument||(b.sameOriginDataUri=!1)}catch(c){b.sameOriginDataUri=!1}this.parentNode.removeChild(this),a(j.getElementsByTagName("textarea"),function(a,c){o(a,b,c),q(),p(a)})});var o=function(a,b,c){var d,e,f;d=document.createElement("div"),d.appendChild(e=document.createElement("div")),d.className="preview",e.appendChild(f=document.createElement("iframe")),e.className="resizeable",f.setAttribute("scrolling","no"),f.name="iframe"+c++,f.addEventListener("load",function(){var c,d,e,f,g,i,j;j=this.contentDocument;if(!b.sameOriginDataUri&&this.src!==m)return;this.src===m&&(c=j.createElement("html"),c.appendChild(j.createElement("head")),c.appendChild(d=j.createElement("body")),d.innerHTML=a.textContent,j.replaceChild(c,j.documentElement)),g=j.createElement("head"),g.appendChild(f=j.createElement("style")),g.appendChild(e=j.createElement("script")),e.textContent=l,f.textContent=k,i=j.getElementsByTagName("head")[0],i.parentNode.replaceChild(g,i),h(this,"getHeight")});var g;b.sameOriginDataUri?g="data:text/html;charset=utf-8,"+encodeURIComponent("<!doctype html><html><head></head></body>"+a.textContent):g=m,f.setAttribute("src",g);var i=function(){f.contentDocument.body.innerHTML=this.value,h(f,"getHeight")};a.addEventListener("keypress",i),a.addEventListener("keyup",i),a.parentNode.insertBefore(d,a)},p=function(a){var b=document.createElement("div");b.className="preview-code",b.style.position="absolute",b.style.left="-9999px",j.appendChild(b);var c=parseInt(window.getComputedStyle(a).getPropertyValue("max-height"),10),d=function(a){b.textContent=this.value+"\n";var d=b.offsetHeight+2;d>=c?this.style.overflow="auto":this.style.overflow="hidden",this.style.height=b.offsetHeight+2+"px"};a.addEventListener("keypress",d),a.addEventListener("keyup",d),d.call(a)},q=function(){var b=j.getElementsByClassName("settings")[0],c=j.getElementsByClassName("resizeable"),d=30,e=function(b){document.cookie="preview-width="+b,a(c,function(a){b==="auto"&&(b=a.parentNode.offsetWidth),a.style.width=b+"px",h(a.getElementsByTagName("iframe")[0],"getHeight")})},i=f(document.cookie)["preview-width"];if(i){e(i),g(b.getElementsByClassName("is-active"),"is-active");var k=b.querySelector('button[data-width="'+i+'"]');k&&k.classList.add("is-active")}window.addEventListener("message",function(a){if(a.data==null||!a.source)return;var b=a.data,c=document.getElementsByName(a.source.name)[0];b.height!=null&&c&&(c.parentNode.style.height=b.height+d+"px")},!1),b&&c.length>0&&(b.hidden=!1,b.addEventListener("click",function(a){var c=a.target.tagName.toLowerCase(),d;if(c==="button")d=a.target;else{if(c!=="svg")return;d=a.target.parentNode}a.preventDefault(),g(b.getElementsByClassName("is-active"),"is-active"),d.classList.add("is-active");var f=d.dataset.width;e(f)}))}}()})()</script></body></html><!-- Generated with StyleDocco (http://jacobrask.github.com/styledocco). --> +</div></article></section><div class="bar bottom"><div hidden class="settings container"><!-- Icons from http://iconmonstr.com--><button title="Desktop (1280)" data-width='1280'><svg viewBox="0 0 412 386" height="24" width="26" class="icon"><path d="m147.6,343.9c-4.5,15.9-26.2,37.6-42.1,42.1h201c-15.3,-4-38.1,-26.8-42.1,-42.1H147.6zM387,0.5H25c-13.8,0-25,11.2-25,25V294c0,13.8 11.2,25 25,25h362c13.8,0 25,-11.2 25,-25V25.5C412,11.7 400.8,0.5 387,0.5zM369.9,238.2H42.1L42.1,42.6 369.9,42.6V238.2z"></path></svg></button><button title="Laptop (1024)" data-width='1024'><svg viewBox="0 0 384 312" height="23" width="28" class="icon"><path d="m349.2,20.5c0,-11-9,-20-20,-20H53.6c-11,0-20,9-20,20v194H349.2v-194zm-27,167H60.6V27.5H322.2v160zm28,42H32.6L2.6,282.1c-3.5,6.2-3.5,13.8 0.1,19.9 3.6,6.2 10.2,9.9 17.3,9.9H363.1c7.1,0 13.7,-3.8 17.3,-10 3.6,-6.2 3.6,-13.8 0,-20l-30.2,-52.5zm-196.9,54 8,-23.5h60.5l8,23.5h-76.5z"></path></svg></button><button title="Tablet (768)" data-width='768'><svg viewBox="0 0 317 412" height="24" width="18" class="icon"><path d="M 316.5,380 V 32 c 0,-17.7 -14.3,-32 -32,-32 H 32 C 14.3,0 0,14.3 0,32 v 348 c 0,17.7 14.3,32 32,32 h 252.5 c 17.7,0 32,-14.3 32,-32 z M 40,367 V 45 H 276.5 V 367 H 40 z m 109.8,22.7 c 0,-4.7 3.8,-8.5 8.5,-8.5 4.7,0 8.5,3.8 8.5,8.5 0,4.7 -3.8,8.5 -8.5,8.5 -4.7,0 -8.5,-3.8 -8.5,-8.5 z"></path></svg></button><button title="Smart phone (320)" data-width='320'><svg viewBox="0 0 224 412" height="24" width="13" class="icon"><path d="M 190.7,0 H 33 C 14.8,0 0,14.8 0,33 v 346 c 0,18.2 14.8,33 33,33 h 157.7 c 18.2,0 33,-14.8 33,-33 V 33 c 0,-18.2 -14.8,-33 -33,-33 z M 94.3,30.2 h 37 c 2.2,0 4,1.8 4,4 0,2.2 -1.8,4 -4,4 h -37 c -2.2,0 -4,-1.8 -4,-4 0,-2.2 1.8,-4 4,-4 z m 18.5,362.8 c -8.8,0 -16,-7.2 -16,-16 0,-8.8 7.2,-16 16,-16 8.8,0 16,7.2 16,16 0,8.8 -7.2,16 -16,16 z M 198.6,343.8 H 25.1 V 68.2 h 173.5 v 275.5 z"></path></svg></button><button title="Feature phone (240)" data-width='240'><svg viewBox="0 0 201 412" height="24" width="12" class="icon"><path d="M 165.5,0.2 V 45 H 25 c -13.8,0 -25,11.2 -25,25 V 387 c 0,13.8 11.2,25 25,25 h 150.5 c 13.8,0 25,-11.2 25,-25 V 0.2 h -35 z M 65.2,366.5 H 34.2 v -24.5 h 31 v 24.5 z m 0,-44.3 H 34.2 v -24.5 h 31 v 24.5 z m 50.5,44.3 H 84.7 v -24.5 h 31 v 24.5 z m 0,-44.3 H 84.7 v -24.5 h 31 v 24.5 z m 50.5,44.3 h -31 v -24.5 h 31 v 24.5 z m 0,-44.3 h -31 v -24.5 h 31 v 24.5 z m 0,-59.3 h -132 V 95.4 h 132 V 262.9 z"></path></svg></button><button title="Auto (100%)" data-width="auto" class="auto is-active">Auto</button></div></div><script>(function(){var a=[{title:"actions-toolbar",filename:"actions-toolbar",url:"actions-toolbar.html"},{title:"Actions toolbar",filename:"actions-toolbar",url:"actions-toolbar.html#actions-toolbar"},{title:"Actions toolbar mixin variables",filename:"actions-toolbar",url:"actions-toolbar.html#actions-toolbar-mixin-variables"},{title:"Actions toolbar alignment",filename:"actions-toolbar",url:"actions-toolbar.html#actions-toolbar-alignment"},{title:"Reverse primary and secondary blocks",filename:"actions-toolbar",url:"actions-toolbar.html#reverse-primary-and-secondary-blocks"},{title:"Actions toolbar indents customizations",filename:"actions-toolbar",url:"actions-toolbar.html#actions-toolbar-indents-customizations"},{title:"Responsive actions toolbar",filename:"actions-toolbar",url:"actions-toolbar.html#responsive-actions-toolbar"},{title:"breadcrumbs",filename:"breadcrumbs",url:"breadcrumbs.html"},{title:"Breadcrumbs",filename:"breadcrumbs",url:"breadcrumbs.html#breadcrumbs"},{title:"Breadcrumbs variables",filename:"breadcrumbs",url:"breadcrumbs.html#breadcrumbs-variables"},{title:"Button-styled breadcrumbs with gradient background, border, and no separating symbol",filename:"breadcrumbs",url:"breadcrumbs.html#buttonstyled-breadcrumbs-with-gradient-background-border-and-no-separating-symbol"},{title:"Breadcrumbs with solid background",filename:"breadcrumbs",url:"breadcrumbs.html#breadcrumbs-with-solid-background"},{title:"buttons",filename:"buttons",url:"buttons.html"},{title:"Default button",filename:"buttons",url:"buttons.html#default-button"},{title:"Button variables",filename:"buttons",url:"buttons.html#button-variables"},{title:"Button as an icon",filename:"buttons",url:"buttons.html#button-as-an-icon"},{title:"Button with an icon on the left or right side of the text",filename:"buttons",url:"buttons.html#button-with-an-icon-on-the-left-or-right-side-of-the-text"},{title:"Button with fixed width",filename:"buttons",url:"buttons.html#button-with-fixed-width"},{title:"Primary button",filename:"buttons",url:"buttons.html#primary-button"},{title:"Primary button variables",filename:"buttons",url:"buttons.html#primary-button-variables"},{title:"Button with gradient background",filename:"buttons",url:"buttons.html#button-with-gradient-background"},{title:"Button as a link",filename:"buttons",url:"buttons.html#button-as-a-link"},{title:"Button as a link variables",filename:"buttons",url:"buttons.html#button-as-a-link-variables"},{title:"Link as a button",filename:"buttons",url:"buttons.html#link-as-a-button"},{title:"Button reset",filename:"buttons",url:"buttons.html#button-reset"},{title:"Button revert secondary color",filename:"buttons",url:"buttons.html#button-revert-secondary-color"},{title:"Button revert secondary color variables",filename:"buttons",url:"buttons.html#button-revert-secondary-color-variables"},{title:"Button revert secondary size",filename:"buttons",url:"buttons.html#button-revert-secondary-size"},{title:"Button revert secondary size variables",filename:"buttons",url:"buttons.html#button-revert-secondary-size-variables"},{title:"components",filename:"components",url:"components.html"},{title:"Components",filename:"components",url:"components.html#components"},{title:"Components Variables",filename:"components",url:"components.html#components-variables"},{title:"dropdowns",filename:"dropdowns",url:"dropdowns.html"},{title:"Drop-down and split buttons mixins",filename:"dropdowns",url:"dropdowns.html#dropdown-and-split-buttons-mixins"},{title:"Drop-down",filename:"dropdowns",url:"dropdowns.html#dropdown"},{title:"Drop-down variables",filename:"dropdowns",url:"dropdowns.html#dropdown-variables"},{title:"Drop-down with icon customization",filename:"dropdowns",url:"dropdowns.html#dropdown-with-icon-customization"},{title:"Modify dropdown list styles",filename:"dropdowns",url:"dropdowns.html#modify-dropdown-list-styles"},{title:"Split button",filename:"dropdowns",url:"dropdowns.html#split-button"},{title:"Split button variables",filename:"dropdowns",url:"dropdowns.html#split-button-variables"},{title:"Split button - button styling",filename:"dropdowns",url:"dropdowns.html#split-button-button-styling"},{title:"Split button icon customization",filename:"dropdowns",url:"dropdowns.html#split-button-icon-customization"},{title:"Split button drop-down list customization",filename:"dropdowns",url:"dropdowns.html#split-button-dropdown-list-customization"},{title:"forms",filename:"forms",url:"forms.html"},{title:"Forms mixins",filename:"forms",url:"forms.html#forms-mixins"},{title:"Global forms elements customization",filename:"forms",url:"forms.html#global-forms-elements-customization"},{title:"Fieldsets & fields customization",filename:"forms",url:"forms.html#fieldsets-fields-customization"},{title:"Fieldset and legend customization variables",filename:"forms",url:"forms.html#fieldset-and-legend-customization-variables"},{title:"Fields customization variables",filename:"forms",url:"forms.html#fields-customization-variables"},{title:"Required fields message customization variables",filename:"forms",url:"forms.html#required-fields-message-customization-variables"},{title:"Form element inputs customization",filename:"forms",url:"forms.html#form-element-inputs-customization"},{title:"Form element inputs customization variables",filename:"forms",url:"forms.html#form-element-inputs-customization-variables"},{title:"Form element choice",filename:"forms",url:"forms.html#form-element-choice"},{title:"Form element choice variables",filename:"forms",url:"forms.html#form-element-choice-variables"},{title:"Custom color",filename:"forms",url:"forms.html#custom-color"},{title:"Input number - input-text view",filename:"forms",url:"forms.html#input-number-inputtext-view"},{title:"Input search - input-text view",filename:"forms",url:"forms.html#input-search-inputtext-view"},{title:"Form validation",filename:"forms",url:"forms.html#form-validation"},{title:"Form validation variables",filename:"forms",url:"forms.html#form-validation-variables"},{title:"icons",filename:"icons",url:"icons.html"},{title:"Icons",filename:"icons",url:"icons.html#icons"},{title:"Icon with image or sprite",filename:"icons",url:"icons.html#icon-with-image-or-sprite"},{title:"Icon with image or sprite variables",filename:"icons",url:"icons.html#icon-with-image-or-sprite-variables"},{title:"Icon position for an icon with image or sprite",filename:"icons",url:"icons.html#icon-position-for-an-icon-with-image-or-sprite"},{title:"Position for icon with image or sprite mixin variables",filename:"icons",url:"icons.html#position-for-icon-with-image-or-sprite-mixin-variables"},{title:"Icon sprite position (with grid)",filename:"icons",url:"icons.html#icon-sprite-position-with-grid"},{title:"Icon sprite position variables",filename:"icons",url:"icons.html#icon-sprite-position-variables"},{title:"Image/sprite icon size",filename:"icons",url:"icons.html#imagesprite-icon-size"},{title:"Image/sprite icon size variables",filename:"icons",url:"icons.html#imagesprite-icon-size-variables"},{title:"Font icon",filename:"icons",url:"icons.html#font-icon"},{title:"Font icon variables",filename:"icons",url:"icons.html#font-icon-variables"},{title:"Change the size of font icon",filename:"icons",url:"icons.html#change-the-size-of-font-icon"},{title:"Change the size of font icon variables",filename:"icons",url:"icons.html#change-the-size-of-font-icon-variables"},{title:"Hide icon text",filename:"icons",url:"icons.html#hide-icon-text"},{title:"Sprite and font icons for Blank theme",filename:"icons",url:"icons.html#sprite-and-font-icons-for-blank-theme"},{title:"layout",filename:"layout",url:"layout.html"},{title:"Layout",filename:"layout",url:"layout.html#layout"},{title:"Layout global variables",filename:"layout",url:"layout.html#layout-global-variables"},{title:"Page layouts",filename:"layout",url:"layout.html#page-layouts"},{title:"Layout column",filename:"layout",url:"layout.html#layout-column"},{title:"Layout column variables",filename:"layout",url:"layout.html#layout-column-variables"},{title:"Layout width",filename:"layout",url:"layout.html#layout-width"},{title:"Layout width variables",filename:"layout",url:"layout.html#layout-width-variables"},{title:"lib",filename:"lib",url:"lib.html"},{title:"Including Magento UI library to your theme",filename:"lib",url:"lib.html#including-magento-ui-library-to-your-theme"},{title:"loaders",filename:"loaders",url:"loaders.html"},{title:"Loaders",filename:"loaders",url:"loaders.html#loaders"},{title:"Default loader variables",filename:"loaders",url:"loaders.html#default-loader-variables"},{title:"Loading",filename:"loaders",url:"loaders.html#loading"},{title:"Loading default variables",filename:"loaders",url:"loaders.html#loading-default-variables"},{title:"messages",filename:"messages",url:"messages.html"},{title:"Messages",filename:"messages",url:"messages.html#messages"},{title:"Information message",filename:"messages",url:"messages.html#information-message"},{title:"Warning message",filename:"messages",url:"messages.html#warning-message"},{title:"Error message",filename:"messages",url:"messages.html#error-message"},{title:"Success message",filename:"messages",url:"messages.html#success-message"},{title:"Notice message",filename:"messages",url:"messages.html#notice-message"},{title:"Message with inner icon",filename:"messages",url:"messages.html#message-with-inner-icon"},{title:"Message with lateral icon",filename:"messages",url:"messages.html#message-with-lateral-icon"},{title:"Custom message style",filename:"messages",url:"messages.html#custom-message-style"},{title:"Messages global variables",filename:"messages",url:"messages.html#messages-global-variables"},{title:"pages",filename:"pages",url:"pages.html"},{title:"Pagination HTML markup",filename:"pages",url:"pages.html#pagination-html-markup"},{title:"Pagination variables",filename:"pages",url:"pages.html#pagination-variables"},{title:"Pagination with label and gradient background on links",filename:"pages",url:"pages.html#pagination-with-label-and-gradient-background-on-links"},{title:'Pagination with "previous"..."next" text links and label',filename:"pages",url:"pages.html#pagination-with-previousnext-text-links-and-label"},{title:"Pagination without label, with solid background",filename:"pages",url:"pages.html#pagination-without-label-with-solid-background"},{title:"popups",filename:"popups",url:"popups.html"},{title:"Popups",filename:"popups",url:"popups.html#popups"},{title:"Popup variables",filename:"popups",url:"popups.html#popup-variables"},{title:"Window overlay mixin variables",filename:"popups",url:"popups.html#window-overlay-mixin-variables"},{title:"Fixed height popup",filename:"popups",url:"popups.html#fixed-height-popup"},{title:"Fixed content height popup",filename:"popups",url:"popups.html#fixed-content-height-popup"},{title:"Margins for header, content and footer block in popup",filename:"popups",url:"popups.html#margins-for-header-content-and-footer-block-in-popup"},{title:"Popup titles styled as theme headings",filename:"popups",url:"popups.html#popup-titles-styled-as-theme-headings"},{title:"Popup action toolbar",filename:"popups",url:"popups.html#popup-action-toolbar"},{title:"Popup Close button without an icon",filename:"popups",url:"popups.html#popup-close-button-without-an-icon"},{title:"Modify the icon of popup Close button",filename:"popups",url:"popups.html#modify-the-icon-of-popup-close-button"},{title:"Modify overlay styles",filename:"popups",url:"popups.html#modify-overlay-styles"},{title:"rating",filename:"rating",url:"rating.html"},{title:"Ratings",filename:"rating",url:"rating.html#ratings"},{title:"Global rating variables",filename:"rating",url:"rating.html#global-rating-variables"},{title:"Rating with vote",filename:"rating",url:"rating.html#rating-with-vote"},{title:"Rating with vote icons number customization",filename:"rating",url:"rating.html#rating-with-vote-icons-number-customization"},{title:"Rating with vote icons colors customization",filename:"rating",url:"rating.html#rating-with-vote-icons-colors-customization"},{title:"Rating with vote icons symbol customization",filename:"rating",url:"rating.html#rating-with-vote-icons-symbol-customization"},{title:"Accessible rating with vote",filename:"rating",url:"rating.html#accessible-rating-with-vote"},{title:"Rating summary",filename:"rating",url:"rating.html#rating-summary"},{title:"Rating summary icons number customization",filename:"rating",url:"rating.html#rating-summary-icons-number-customization"},{title:"Rating summary icons color customization",filename:"rating",url:"rating.html#rating-summary-icons-color-customization"},{title:"Rating summary icons symbol customization",filename:"rating",url:"rating.html#rating-summary-icons-symbol-customization"},{title:"Rating summary hide label",filename:"rating",url:"rating.html#rating-summary-hide-label"},{title:"Rating summary multiple ratings",filename:"rating",url:"rating.html#rating-summary-multiple-ratings"},{title:"Rating hide label mixin",filename:"rating",url:"rating.html#rating-hide-label-mixin"},{title:"resets",filename:"resets",url:"resets.html"},{title:"Resets",filename:"resets",url:"resets.html#resets"},{title:"responsive",filename:"responsive",url:"responsive.html"},{title:"Responsive",filename:"responsive",url:"responsive.html#responsive"},{title:"Responsive mixins usage",filename:"responsive",url:"responsive.html#responsive-mixins-usage"},{title:"Media query style groups separation variables",filename:"responsive",url:"responsive.html#media-query-style-groups-separation-variables"},{title:"Responsive breakpoints",filename:"responsive",url:"responsive.html#responsive-breakpoints"},{title:"sections",filename:"sections",url:"sections.html"},{title:"Tabs and accordions",filename:"sections",url:"sections.html#tabs-and-accordions"},{title:"Tabs",filename:"sections",url:"sections.html#tabs"},{title:"Tabs mixin variables",filename:"sections",url:"sections.html#tabs-mixin-variables"},{title:"Tabs with content top border",filename:"sections",url:"sections.html#tabs-with-content-top-border"},{title:"Accordion",filename:"sections",url:"sections.html#accordion"},{title:"Accordion mixin variables",filename:"sections",url:"sections.html#accordion-mixin-variables"},{title:"Responsive tabs",filename:"sections",url:"sections.html#responsive-tabs"},{title:"Tabs Base",filename:"sections",url:"sections.html#tabs-base"},{title:"Accordion Base",filename:"sections",url:"sections.html#accordion-base"},{title:"tables",filename:"tables",url:"tables.html"},{title:"Tables",filename:"tables",url:"tables.html#tables"},{title:"Table mixin variables",filename:"tables",url:"tables.html#table-mixin-variables"},{title:"Table typography",filename:"tables",url:"tables.html#table-typography"},{title:"Table typography mixin variables",filename:"tables",url:"tables.html#table-typography-mixin-variables"},{title:"Table caption",filename:"tables",url:"tables.html#table-caption"},{title:"Table caption mixin variables",filename:"tables",url:"tables.html#table-caption-mixin-variables"},{title:"Table cells resize",filename:"tables",url:"tables.html#table-cells-resize"},{title:"Table cells resize variables",filename:"tables",url:"tables.html#table-cells-resize-variables"},{title:"Table background customization",filename:"tables",url:"tables.html#table-background-customization"},{title:"Table background mixin variables",filename:"tables",url:"tables.html#table-background-mixin-variables"},{title:"Table borders customization",filename:"tables",url:"tables.html#table-borders-customization"},{title:"Table borders mixin variables",filename:"tables",url:"tables.html#table-borders-mixin-variables"},{title:"Table with horizontal borders",filename:"tables",url:"tables.html#table-with-horizontal-borders"},{title:"Table with vertical borders",filename:"tables",url:"tables.html#table-with-vertical-borders"},{title:"Table with light borders",filename:"tables",url:"tables.html#table-with-light-borders"},{title:"Table without borders",filename:"tables",url:"tables.html#table-without-borders"},{title:"Striped table",filename:"tables",url:"tables.html#striped-table"},{title:"Striped table mixin variables",filename:"tables",url:"tables.html#striped-table-mixin-variables"},{title:"Table with rows hover",filename:"tables",url:"tables.html#table-with-rows-hover"},{title:"Table with rows hover mixin variables",filename:"tables",url:"tables.html#table-with-rows-hover-mixin-variables"},{title:"Responsive table technics #1",filename:"tables",url:"tables.html#responsive-table-technics-1"},{title:"Responsive table technics #2",filename:"tables",url:"tables.html#responsive-table-technics-2"},{title:"Responsive table technics #2 mixin variables",filename:"tables",url:"tables.html#responsive-table-technics-2-mixin-variables"},{title:"tooltips",filename:"tooltips",url:"tooltips.html"},{title:"Tooltips",filename:"tooltips",url:"tooltips.html#tooltips"},{title:"Tooltips variables",filename:"tooltips",url:"tooltips.html#tooltips-variables"},{title:"typography",filename:"typography",url:"typography.html"},{title:"Typogrphy",filename:"typography",url:"typography.html#typogrphy"},{title:"Typography variables",filename:"typography",url:"typography.html#typography-variables"},{title:"Font-size mixin",filename:"typography",url:"typography.html#fontsize-mixin"},{title:"Line-height mixin",filename:"typography",url:"typography.html#lineheight-mixin"},{title:"Word breaking mixin",filename:"typography",url:"typography.html#word-breaking-mixin"},{title:"Font face mixin",filename:"typography",url:"typography.html#font-face-mixin"},{title:"Text overflow mixin",filename:"typography",url:"typography.html#text-overflow-mixin"},{title:"Text hide",filename:"typography",url:"typography.html#text-hide"},{title:"Hyphens",filename:"typography",url:"typography.html#hyphens"},{title:"Font style and color",filename:"typography",url:"typography.html#font-style-and-color"},{title:"Font style mixin variables",filename:"typography",url:"typography.html#font-style-mixin-variables"},{title:"Reset list styles",filename:"typography",url:"typography.html#reset-list-styles"},{title:"Reset list styles variables",filename:"typography",url:"typography.html#reset-list-styles-variables"},{title:"Inline-block list item styling",filename:"typography",url:"typography.html#inlineblock-list-item-styling"},{title:"Link styling mixin",filename:"typography",url:"typography.html#link-styling-mixin"},{title:"Link styling mixin variables",filename:"typography",url:"typography.html#link-styling-mixin-variables"},{title:"Heading styling mixin",filename:"typography",url:"typography.html#heading-styling-mixin"},{title:"Base typography mixins",filename:"typography",url:"typography.html#base-typography-mixins"},{title:"Base typography mixin variables",filename:"typography",url:"typography.html#base-typography-mixin-variables"},{title:"Headings typography mixin",filename:"typography",url:"typography.html#headings-typography-mixin"},{title:"Headings typography mixin variables",filename:"typography",url:"typography.html#headings-typography-mixin-variables"},{title:"Typography links mixin",filename:"typography",url:"typography.html#typography-links-mixin"},{title:"Typography lists mixin",filename:"typography",url:"typography.html#typography-lists-mixin"},{title:"Typography lists mixin variables",filename:"typography",url:"typography.html#typography-lists-mixin-variables"},{title:"Typography code elements mixin",filename:"typography",url:"typography.html#typography-code-elements-mixin"},{title:"Typography code mixin variables",filename:"typography",url:"typography.html#typography-code-mixin-variables"},{title:"Typography blockquote",filename:"typography",url:"typography.html#typography-blockquote"},{title:"Typography blockquote mixin variables",filename:"typography",url:"typography.html#typography-blockquote-mixin-variables"},{title:"utilities",filename:"utilities",url:"utilities.html"},{title:"Utilities",filename:"utilities",url:"utilities.html#utilities"},{title:".lib-clearfix()",filename:"utilities",url:"utilities.html#libclearfix"},{title:".lib-visibility-hidden()",filename:"utilities",url:"utilities.html#libvisibilityhidden"},{title:".lib-visually-hidden()",filename:"utilities",url:"utilities.html#libvisuallyhidden"},{title:".lib-visually-hidden-reset()",filename:"utilities",url:"utilities.html#libvisuallyhiddenreset"},{title:".lib-css()",filename:"utilities",url:"utilities.html#libcss"},{title:".lib-css() variables",filename:"utilities",url:"utilities.html#libcss-variables"},{title:".lib-rotate()",filename:"utilities",url:"utilities.html#librotate"},{title:".lib-rotate() variables",filename:"utilities",url:"utilities.html#librotate-variables"},{title:".lib-input-placeholder()",filename:"utilities",url:"utilities.html#libinputplaceholder"},{title:".lib-input-placeholder() variables",filename:"utilities",url:"utilities.html#libinputplaceholder-variables"},{title:".lib-background-gradient()",filename:"utilities",url:"utilities.html#libbackgroundgradient"},{title:".lib-background-gradient() variables",filename:"utilities",url:"utilities.html#libbackgroundgradient-variables"},{title:"variables",filename:"variables",url:"variables.html"},{title:"List of Global Variables",filename:"variables",url:"variables.html#list-of-global-variables"},{title:"Table with rows hover mixin variables",filename:"variables",url:"variables.html#table-with-rows-hover-mixin-variables"},{title:"docs",filename:"docs",url:"docs.html"},{title:"Documentation",filename:"docs",url:"docs.html#documentation"}];(function(){"use strict";var b=function(a,b){return Array.prototype.indexOf.call(a,b)!==-1},c=function(a,b){return Array.prototype.filter.call(a,b)},d=function(a,b){return Array.prototype.forEach.call(a,b)},e=document.getElementsByTagName("body")[0];e.addEventListener("click",function(a){var b=a.target;b.tagName.toLowerCase()==="svg"&&(b=b.parentNode);var c=!1;b.dataset.toggle!=null&&(a.preventDefault(),b.classList.contains("is-active")||(c=!0)),d(e.querySelectorAll("[data-toggle]"),function(a){a.classList.remove("is-active"),document.getElementById(a.dataset.toggle).hidden=!0}),c&&(b.classList.add("is-active"),document.getElementById(b.dataset.toggle).hidden=!1)}),function(){var f=e.getElementsByClassName("nav")[0];if(!f)return;var g=document.createElement("ul");g.className="nav-results",g.id="nav-search",g.hidden=!0,d(a,function(a){var b,c,d;b=document.createElement("li"),b._title=a.title.toLowerCase(),b.hidden=!0,b.appendChild(c=document.createElement("a")),c.href=a.url,c.innerHTML=a.title,c.appendChild(d=document.createElement("span")),d.innerHTML=a.filename,d.className="nav-results-filename",g.appendChild(b)}),f.appendChild(g);var h=g.children,i=function(a){d(h,function(a){a.hidden=!0});var b=this.value.toLowerCase(),e=[];b!==""&&(e=c(h,function(a){return a._title.indexOf(b)!==-1})),e.length>0?(d(e,function(a){a.hidden=!1}),g.hidden=!1):g.hidden=!0},j=f.querySelector('input[type="search"]');j.addEventListener("keyup",i),j.addEventListener("focus",i),e.addEventListener("click",function(a){if(a.target.classList&&a.target.classList.contains("search"))return;g.hidden=!0}),g.addEventListener("click",function(a){j.value=""});var k=document.createElement("ul");k.id="nav-toc",k.hidden=!0,k.className="nav-results toc-list",c(e.getElementsByTagName("*"),function(a){return b(["h1","h2","h3"],a.tagName.toLowerCase())}).map(function(a){var b=document.createElement("li"),c=document.createElement("a"),d=a.tagName.toLowerCase()[1];c.classList.add("level-"+d),b.appendChild(c),c.href="#"+a.id,c.innerHTML=a.innerHTML,k.appendChild(b)}),f.appendChild(k)}()})(),function(){"use strict";if(location.hash==="#__preview__"||location.protocol==="data:")return;var a=function(a,b){return Array.prototype.forEach.call(a,b)},b=function(a,b){var e=Array.prototype.slice.call(arguments,2);return d(a,function(a){return(c(b)?b||a:a[b]).apply(a,e)})},c=function(a){return Object.prototype.toString.call(a)==="[object Function]"},d=function(a,b){return Array.prototype.map.call(a,b)},e=function(a,b){return d(a,function(a){return a[b]})},f=function(a){var b={},c=a.split(";");for(var d=0;c.length>d;d++){var e=c[d].trim().split("=");b[e[0]]=e[1]}return b},g=function(a,c){return b(e(a,"classList"),"remove",c)},h=function(a,b){a.contentDocument.defaultView.postMessage(b,"*")},i=document.getElementsByTagName("head")[0],j=document.getElementsByTagName("body")[0],k=e(i.querySelectorAll('style[type="text/preview"]'),"innerHTML").join(""),l=e(i.querySelectorAll('script[type="text/preview"]'),"innerHTML").join(""),m=location.href.split("#")[0]+"#__preview__",n=document.createElement("iframe");n.src="data:text/html,",j.appendChild(n),n.addEventListener("load",function(){var b={sameOriginDataUri:!0};try{this.contentDocument,this.contentDocument||(b.sameOriginDataUri=!1)}catch(c){b.sameOriginDataUri=!1}this.parentNode.removeChild(this),a(j.getElementsByTagName("textarea"),function(a,c){o(a,b,c),q(),p(a)})});var o=function(a,b,c){var d,e,f;d=document.createElement("div"),d.appendChild(e=document.createElement("div")),d.className="preview",e.appendChild(f=document.createElement("iframe")),e.className="resizeable",f.setAttribute("scrolling","no"),f.name="iframe"+c++,f.addEventListener("load",function(){var c,d,e,f,g,i,j;j=this.contentDocument;if(!b.sameOriginDataUri&&this.src!==m)return;this.src===m&&(c=j.createElement("html"),c.appendChild(j.createElement("head")),c.appendChild(d=j.createElement("body")),d.innerHTML=a.textContent,j.replaceChild(c,j.documentElement)),g=j.createElement("head"),g.appendChild(f=j.createElement("style")),g.appendChild(e=j.createElement("script")),e.textContent=l,f.textContent=k,i=j.getElementsByTagName("head")[0],i.parentNode.replaceChild(g,i),h(this,"getHeight")});var g;b.sameOriginDataUri?g="data:text/html;charset=utf-8,"+encodeURIComponent("<!doctype html><html><head></head></body>"+a.textContent):g=m,f.setAttribute("src",g);var i=function(){f.contentDocument.body.innerHTML=this.value,h(f,"getHeight")};a.addEventListener("keypress",i),a.addEventListener("keyup",i),a.parentNode.insertBefore(d,a)},p=function(a){var b=document.createElement("div");b.className="preview-code",b.style.position="absolute",b.style.left="-9999px",j.appendChild(b);var c=parseInt(window.getComputedStyle(a).getPropertyValue("max-height"),10),d=function(a){b.textContent=this.value+"\n";var d=b.offsetHeight+2;d>=c?this.style.overflow="auto":this.style.overflow="hidden",this.style.height=b.offsetHeight+2+"px"};a.addEventListener("keypress",d),a.addEventListener("keyup",d),d.call(a)},q=function(){var b=j.getElementsByClassName("settings")[0],c=j.getElementsByClassName("resizeable"),d=30,e=function(b){document.cookie="preview-width="+b,a(c,function(a){b==="auto"&&(b=a.parentNode.offsetWidth),a.style.width=b+"px",h(a.getElementsByTagName("iframe")[0],"getHeight")})},i=f(document.cookie)["preview-width"];if(i){e(i),g(b.getElementsByClassName("is-active"),"is-active");var k=b.querySelector('button[data-width="'+i+'"]');k&&k.classList.add("is-active")}window.addEventListener("message",function(a){if(a.data==null||!a.source)return;var b=a.data,c=document.getElementsByName(a.source.name)[0];b.height!=null&&c&&(c.parentNode.style.height=b.height+d+"px")},!1),b&&c.length>0&&(b.hidden=!1,b.addEventListener("click",function(a){var c=a.target.tagName.toLowerCase(),d;if(c==="button")d=a.target;else{if(c!=="svg")return;d=a.target.parentNode}a.preventDefault(),g(b.getElementsByClassName("is-active"),"is-active"),d.classList.add("is-active");var f=d.dataset.width;e(f)}))}}()})()</script></body></html><!-- Generated with StyleDocco (http://jacobrask.github.com/styledocco). --> diff --git a/lib/web/css/docs/typography.html b/lib/web/css/docs/typography.html index 76f704c17c1bd..a933bcb46bf64 100644 --- a/lib/web/css/docs/typography.html +++ b/lib/web/css/docs/typography.html @@ -1686,4 +1686,4 @@ </tr> </table> </pre> -</div></article></section><div class="bar bottom"><div hidden class="settings container"><!-- Icons from http://iconmonstr.com--><button title="Desktop (1280)" data-width='1280'><svg viewBox="0 0 412 386" height="24" width="26" class="icon"><path d="m147.6,343.9c-4.5,15.9-26.2,37.6-42.1,42.1h201c-15.3,-4-38.1,-26.8-42.1,-42.1H147.6zM387,0.5H25c-13.8,0-25,11.2-25,25V294c0,13.8 11.2,25 25,25h362c13.8,0 25,-11.2 25,-25V25.5C412,11.7 400.8,0.5 387,0.5zM369.9,238.2H42.1L42.1,42.6 369.9,42.6V238.2z"></path></svg></button><button title="Laptop (1024)" data-width='1024'><svg viewBox="0 0 384 312" height="23" width="28" class="icon"><path d="m349.2,20.5c0,-11-9,-20-20,-20H53.6c-11,0-20,9-20,20v194H349.2v-194zm-27,167H60.6V27.5H322.2v160zm28,42H32.6L2.6,282.1c-3.5,6.2-3.5,13.8 0.1,19.9 3.6,6.2 10.2,9.9 17.3,9.9H363.1c7.1,0 13.7,-3.8 17.3,-10 3.6,-6.2 3.6,-13.8 0,-20l-30.2,-52.5zm-196.9,54 8,-23.5h60.5l8,23.5h-76.5z"></path></svg></button><button title="Tablet (768)" data-width='768'><svg viewBox="0 0 317 412" height="24" width="18" class="icon"><path d="M 316.5,380 V 32 c 0,-17.7 -14.3,-32 -32,-32 H 32 C 14.3,0 0,14.3 0,32 v 348 c 0,17.7 14.3,32 32,32 h 252.5 c 17.7,0 32,-14.3 32,-32 z M 40,367 V 45 H 276.5 V 367 H 40 z m 109.8,22.7 c 0,-4.7 3.8,-8.5 8.5,-8.5 4.7,0 8.5,3.8 8.5,8.5 0,4.7 -3.8,8.5 -8.5,8.5 -4.7,0 -8.5,-3.8 -8.5,-8.5 z"></path></svg></button><button title="Smart phone (320)" data-width='320'><svg viewBox="0 0 224 412" height="24" width="13" class="icon"><path d="M 190.7,0 H 33 C 14.8,0 0,14.8 0,33 v 346 c 0,18.2 14.8,33 33,33 h 157.7 c 18.2,0 33,-14.8 33,-33 V 33 c 0,-18.2 -14.8,-33 -33,-33 z M 94.3,30.2 h 37 c 2.2,0 4,1.8 4,4 0,2.2 -1.8,4 -4,4 h -37 c -2.2,0 -4,-1.8 -4,-4 0,-2.2 1.8,-4 4,-4 z m 18.5,362.8 c -8.8,0 -16,-7.2 -16,-16 0,-8.8 7.2,-16 16,-16 8.8,0 16,7.2 16,16 0,8.8 -7.2,16 -16,16 z M 198.6,343.8 H 25.1 V 68.2 h 173.5 v 275.5 z"></path></svg></button><button title="Feature phone (240)" data-width='240'><svg viewBox="0 0 201 412" height="24" width="12" class="icon"><path d="M 165.5,0.2 V 45 H 25 c -13.8,0 -25,11.2 -25,25 V 387 c 0,13.8 11.2,25 25,25 h 150.5 c 13.8,0 25,-11.2 25,-25 V 0.2 h -35 z M 65.2,366.5 H 34.2 v -24.5 h 31 v 24.5 z m 0,-44.3 H 34.2 v -24.5 h 31 v 24.5 z m 50.5,44.3 H 84.7 v -24.5 h 31 v 24.5 z m 0,-44.3 H 84.7 v -24.5 h 31 v 24.5 z m 50.5,44.3 h -31 v -24.5 h 31 v 24.5 z m 0,-44.3 h -31 v -24.5 h 31 v 24.5 z m 0,-59.3 h -132 V 95.4 h 132 V 262.9 z"></path></svg></button><button title="Auto (100%)" data-width="auto" class="auto is-active">Auto</button></div></div><script>(function(){var a=[{title:"actions-toolbar",filename:"actions-toolbar",url:"actions-toolbar.html"},{title:"Actions toolbar",filename:"actions-toolbar",url:"actions-toolbar.html#actions-toolbar"},{title:"Actions toolbar mixin variables",filename:"actions-toolbar",url:"actions-toolbar.html#actions-toolbar-mixin-variables"},{title:"Actions toolbar alignment",filename:"actions-toolbar",url:"actions-toolbar.html#actions-toolbar-alignment"},{title:"Reverse primary and secondary blocks",filename:"actions-toolbar",url:"actions-toolbar.html#reverse-primary-and-secondary-blocks"},{title:"Actions toolbar indents customizations",filename:"actions-toolbar",url:"actions-toolbar.html#actions-toolbar-indents-customizations"},{title:"Responsive actions toolbar",filename:"actions-toolbar",url:"actions-toolbar.html#responsive-actions-toolbar"},{title:"breadcrumbs",filename:"breadcrumbs",url:"breadcrumbs.html"},{title:"Breadcrumbs",filename:"breadcrumbs",url:"breadcrumbs.html#breadcrumbs"},{title:"Breadcrumbs variables",filename:"breadcrumbs",url:"breadcrumbs.html#breadcrumbs-variables"},{title:"Button-styled breadcrumbs with gradient background, border, and no separating symbol",filename:"breadcrumbs",url:"breadcrumbs.html#buttonstyled-breadcrumbs-with-gradient-background-border-and-no-separating-symbol"},{title:"Breadcrumbs with solid background",filename:"breadcrumbs",url:"breadcrumbs.html#breadcrumbs-with-solid-background"},{title:"buttons",filename:"buttons",url:"buttons.html"},{title:"Default button",filename:"buttons",url:"buttons.html#default-button"},{title:"Button variables",filename:"buttons",url:"buttons.html#button-variables"},{title:"Button as an icon",filename:"buttons",url:"buttons.html#button-as-an-icon"},{title:"Button with an icon on the left or right side of the text",filename:"buttons",url:"buttons.html#button-with-an-icon-on-the-left-or-right-side-of-the-text"},{title:"Button with fixed width",filename:"buttons",url:"buttons.html#button-with-fixed-width"},{title:"Primary button",filename:"buttons",url:"buttons.html#primary-button"},{title:"Primary button variables",filename:"buttons",url:"buttons.html#primary-button-variables"},{title:"Button with gradient background",filename:"buttons",url:"buttons.html#button-with-gradient-background"},{title:"Button as a link",filename:"buttons",url:"buttons.html#button-as-a-link"},{title:"Button as a link variables",filename:"buttons",url:"buttons.html#button-as-a-link-variables"},{title:"Link as a button",filename:"buttons",url:"buttons.html#link-as-a-button"},{title:"Button reset",filename:"buttons",url:"buttons.html#button-reset"},{title:"Button revert secondary color",filename:"buttons",url:"buttons.html#button-revert-secondary-color"},{title:"Button revert secondary color variables",filename:"buttons",url:"buttons.html#button-revert-secondary-color-variables"},{title:"Button revert secondary size",filename:"buttons",url:"buttons.html#button-revert-secondary-size"},{title:"Button revert secondary size variables",filename:"buttons",url:"buttons.html#button-revert-secondary-size-variables"},{title:"components",filename:"components",url:"components.html"},{title:"Components",filename:"components",url:"components.html#components"},{title:"Components Variables",filename:"components",url:"components.html#components-variables"},{title:"dropdowns",filename:"dropdowns",url:"dropdowns.html"},{title:"Drop-down and split buttons mixins",filename:"dropdowns",url:"dropdowns.html#dropdown-and-split-buttons-mixins"},{title:"Drop-down",filename:"dropdowns",url:"dropdowns.html#dropdown"},{title:"Drop-down variables",filename:"dropdowns",url:"dropdowns.html#dropdown-variables"},{title:"Drop-down with icon customization",filename:"dropdowns",url:"dropdowns.html#dropdown-with-icon-customization"},{title:"Modify dropdown list styles",filename:"dropdowns",url:"dropdowns.html#modify-dropdown-list-styles"},{title:"Split button",filename:"dropdowns",url:"dropdowns.html#split-button"},{title:"Split button variables",filename:"dropdowns",url:"dropdowns.html#split-button-variables"},{title:"Split button - button styling",filename:"dropdowns",url:"dropdowns.html#split-button-button-styling"},{title:"Split button icon customization",filename:"dropdowns",url:"dropdowns.html#split-button-icon-customization"},{title:"Split button drop-down list customization",filename:"dropdowns",url:"dropdowns.html#split-button-dropdown-list-customization"},{title:"forms",filename:"forms",url:"forms.html"},{title:"Forms mixins",filename:"forms",url:"forms.html#forms-mixins"},{title:"Global forms elements customization",filename:"forms",url:"forms.html#global-forms-elements-customization"},{title:"Fieldsets & fields customization",filename:"forms",url:"forms.html#fieldsets-fields-customization"},{title:"Fieldset and legend customization variables",filename:"forms",url:"forms.html#fieldset-and-legend-customization-variables"},{title:"Fields customization variables",filename:"forms",url:"forms.html#fields-customization-variables"},{title:"Required fields message customization variables",filename:"forms",url:"forms.html#required-fields-message-customization-variables"},{title:"Form element inputs customization",filename:"forms",url:"forms.html#form-element-inputs-customization"},{title:"Form element inputs customization variables",filename:"forms",url:"forms.html#form-element-inputs-customization-variables"},{title:"Form element choice",filename:"forms",url:"forms.html#form-element-choice"},{title:"Form element choice variables",filename:"forms",url:"forms.html#form-element-choice-variables"},{title:"Custom color",filename:"forms",url:"forms.html#custom-color"},{title:"Input number - input-text view",filename:"forms",url:"forms.html#input-number-inputtext-view"},{title:"Input search - input-text view",filename:"forms",url:"forms.html#input-search-inputtext-view"},{title:"Form validation",filename:"forms",url:"forms.html#form-validation"},{title:"Form validation variables",filename:"forms",url:"forms.html#form-validation-variables"},{title:"icons",filename:"icons",url:"icons.html"},{title:"Icons",filename:"icons",url:"icons.html#icons"},{title:"Icon with image or sprite",filename:"icons",url:"icons.html#icon-with-image-or-sprite"},{title:"Icon with image or sprite variables",filename:"icons",url:"icons.html#icon-with-image-or-sprite-variables"},{title:"Icon position for an icon with image or sprite",filename:"icons",url:"icons.html#icon-position-for-an-icon-with-image-or-sprite"},{title:"Position for icon with image or sprite mixin variables",filename:"icons",url:"icons.html#position-for-icon-with-image-or-sprite-mixin-variables"},{title:"Icon sprite position (with grid)",filename:"icons",url:"icons.html#icon-sprite-position-with-grid"},{title:"Icon sprite position variables",filename:"icons",url:"icons.html#icon-sprite-position-variables"},{title:"Image/sprite icon size",filename:"icons",url:"icons.html#imagesprite-icon-size"},{title:"Image/sprite icon size variables",filename:"icons",url:"icons.html#imagesprite-icon-size-variables"},{title:"Font icon",filename:"icons",url:"icons.html#font-icon"},{title:"Font icon variables",filename:"icons",url:"icons.html#font-icon-variables"},{title:"Change the size of font icon",filename:"icons",url:"icons.html#change-the-size-of-font-icon"},{title:"Change the size of font icon variables",filename:"icons",url:"icons.html#change-the-size-of-font-icon-variables"},{title:"Hide icon text",filename:"icons",url:"icons.html#hide-icon-text"},{title:"Sprite and font icons for Blank theme",filename:"icons",url:"icons.html#sprite-and-font-icons-for-blank-theme"},{title:"layout",filename:"layout",url:"layout.html"},{title:"Layout",filename:"layout",url:"layout.html#layout"},{title:"Layout global variables",filename:"layout",url:"layout.html#layout-global-variables"},{title:"Page layouts",filename:"layout",url:"layout.html#page-layouts"},{title:"Layout column",filename:"layout",url:"layout.html#layout-column"},{title:"Layout column variables",filename:"layout",url:"layout.html#layout-column-variables"},{title:"Layout width",filename:"layout",url:"layout.html#layout-width"},{title:"Layout width variables",filename:"layout",url:"layout.html#layout-width-variables"},{title:"lib",filename:"lib",url:"lib.html"},{title:"Including Magento UI library to your theme",filename:"lib",url:"lib.html#including-magento-ui-library-to-your-theme"},{title:"loaders",filename:"loaders",url:"loaders.html"},{title:"Loaders",filename:"loaders",url:"loaders.html#loaders"},{title:"Default loader variables",filename:"loaders",url:"loaders.html#default-loader-variables"},{title:"Loading",filename:"loaders",url:"loaders.html#loading"},{title:"Loading default variables",filename:"loaders",url:"loaders.html#loading-default-variables"},{title:"messages",filename:"messages",url:"messages.html"},{title:"Messages",filename:"messages",url:"messages.html#messages"},{title:"Information message",filename:"messages",url:"messages.html#information-message"},{title:"Warning message",filename:"messages",url:"messages.html#warning-message"},{title:"Error message",filename:"messages",url:"messages.html#error-message"},{title:"Success message",filename:"messages",url:"messages.html#success-message"},{title:"Notice message",filename:"messages",url:"messages.html#notice-message"},{title:"Message with inner icon",filename:"messages",url:"messages.html#message-with-inner-icon"},{title:"Message with lateral icon",filename:"messages",url:"messages.html#message-with-lateral-icon"},{title:"Custom message style",filename:"messages",url:"messages.html#custom-message-style"},{title:"Messages global variables",filename:"messages",url:"messages.html#messages-global-variables"},{title:"pages",filename:"pages",url:"pages.html"},{title:"Pagination HTML markup",filename:"pages",url:"pages.html#pagination-html-markup"},{title:"Pagination variables",filename:"pages",url:"pages.html#pagination-variables"},{title:"Pagination with label and gradient background on links",filename:"pages",url:"pages.html#pagination-with-label-and-gradient-background-on-links"},{title:'Pagination with "previous"..."next" text links and label',filename:"pages",url:"pages.html#pagination-with-previousnext-text-links-and-label"},{title:"Pagination without label, with solid background",filename:"pages",url:"pages.html#pagination-without-label-with-solid-background"},{title:"popups",filename:"popups",url:"popups.html"},{title:"Popups",filename:"popups",url:"popups.html#popups"},{title:"Popup variables",filename:"popups",url:"popups.html#popup-variables"},{title:"Window overlay mixin variables",filename:"popups",url:"popups.html#window-overlay-mixin-variables"},{title:"Fixed height popup",filename:"popups",url:"popups.html#fixed-height-popup"},{title:"Fixed content height popup",filename:"popups",url:"popups.html#fixed-content-height-popup"},{title:"Margins for header, content and footer block in popup",filename:"popups",url:"popups.html#margins-for-header-content-and-footer-block-in-popup"},{title:"Popup titles styled as theme headings",filename:"popups",url:"popups.html#popup-titles-styled-as-theme-headings"},{title:"Popup action toolbar",filename:"popups",url:"popups.html#popup-action-toolbar"},{title:"Popup Close button without an icon",filename:"popups",url:"popups.html#popup-close-button-without-an-icon"},{title:"Modify the icon of popup Close button",filename:"popups",url:"popups.html#modify-the-icon-of-popup-close-button"},{title:"Modify overlay styles",filename:"popups",url:"popups.html#modify-overlay-styles"},{title:"rating",filename:"rating",url:"rating.html"},{title:"Ratings",filename:"rating",url:"rating.html#ratings"},{title:"Global rating variables",filename:"rating",url:"rating.html#global-rating-variables"},{title:"Rating with vote",filename:"rating",url:"rating.html#rating-with-vote"},{title:"Rating with vote icons number customization",filename:"rating",url:"rating.html#rating-with-vote-icons-number-customization"},{title:"Rating with vote icons colors customization",filename:"rating",url:"rating.html#rating-with-vote-icons-colors-customization"},{title:"Rating with vote icons symbol customization",filename:"rating",url:"rating.html#rating-with-vote-icons-symbol-customization"},{title:"Accessible rating with vote",filename:"rating",url:"rating.html#accessible-rating-with-vote"},{title:"Rating summary",filename:"rating",url:"rating.html#rating-summary"},{title:"Rating summary icons number customization",filename:"rating",url:"rating.html#rating-summary-icons-number-customization"},{title:"Rating summary icons color customization",filename:"rating",url:"rating.html#rating-summary-icons-color-customization"},{title:"Rating summary icons symbol customization",filename:"rating",url:"rating.html#rating-summary-icons-symbol-customization"},{title:"Rating summary hide label",filename:"rating",url:"rating.html#rating-summary-hide-label"},{title:"Rating summary multiple ratings",filename:"rating",url:"rating.html#rating-summary-multiple-ratings"},{title:"Rating hide label mixin",filename:"rating",url:"rating.html#rating-hide-label-mixin"},{title:"resets",filename:"resets",url:"resets.html"},{title:"Resets",filename:"resets",url:"resets.html#resets"},{title:"responsive",filename:"responsive",url:"responsive.html"},{title:"Responsive",filename:"responsive",url:"responsive.html#responsive"},{title:"Responsive mixins usage",filename:"responsive",url:"responsive.html#responsive-mixins-usage"},{title:"Media query style groups separation variables",filename:"responsive",url:"responsive.html#media-query-style-groups-separation-variables"},{title:"Responsive breakpoints",filename:"responsive",url:"responsive.html#responsive-breakpoints"},{title:"sections",filename:"sections",url:"sections.html"},{title:"Tabs and accordions",filename:"sections",url:"sections.html#tabs-and-accordions"},{title:"Tabs",filename:"sections",url:"sections.html#tabs"},{title:"Tabs mixin variables",filename:"sections",url:"sections.html#tabs-mixin-variables"},{title:"Tabs with content top border",filename:"sections",url:"sections.html#tabs-with-content-top-border"},{title:"Accordion",filename:"sections",url:"sections.html#accordion"},{title:"Accordion mixin variables",filename:"sections",url:"sections.html#accordion-mixin-variables"},{title:"Responsive tabs",filename:"sections",url:"sections.html#responsive-tabs"},{title:"Tabs Base",filename:"sections",url:"sections.html#tabs-base"},{title:"Accordion Base",filename:"sections",url:"sections.html#accordion-base"},{title:"tables",filename:"tables",url:"tables.html"},{title:"Tables",filename:"tables",url:"tables.html#tables"},{title:"Table mixin variables",filename:"tables",url:"tables.html#table-mixin-variables"},{title:"Table typography",filename:"tables",url:"tables.html#table-typography"},{title:"Table typography mixin variables",filename:"tables",url:"tables.html#table-typography-mixin-variables"},{title:"Table caption",filename:"tables",url:"tables.html#table-caption"},{title:"Table caption mixin variables",filename:"tables",url:"tables.html#table-caption-mixin-variables"},{title:"Table cells resize",filename:"tables",url:"tables.html#table-cells-resize"},{title:"Table cells resize variables",filename:"tables",url:"tables.html#table-cells-resize-variables"},{title:"Table background customization",filename:"tables",url:"tables.html#table-background-customization"},{title:"Table background mixin variables",filename:"tables",url:"tables.html#table-background-mixin-variables"},{title:"Table borders customization",filename:"tables",url:"tables.html#table-borders-customization"},{title:"Table borders mixin variables",filename:"tables",url:"tables.html#table-borders-mixin-variables"},{title:"Table with horizontal borders",filename:"tables",url:"tables.html#table-with-horizontal-borders"},{title:"Table with vertical borders",filename:"tables",url:"tables.html#table-with-vertical-borders"},{title:"Table with light borders",filename:"tables",url:"tables.html#table-with-light-borders"},{title:"Table without borders",filename:"tables",url:"tables.html#table-without-borders"},{title:"Striped table",filename:"tables",url:"tables.html#striped-table"},{title:"Striped table mixin variables",filename:"tables",url:"tables.html#striped-table-mixin-variables"},{title:"Table with rows hover",filename:"tables",url:"tables.html#table-with-rows-hover"},{title:"Table with rows hover mixin variables",filename:"tables",url:"tables.html#table-with-rows-hover-mixin-variables"},{title:"Responsive table technics #1",filename:"tables",url:"tables.html#responsive-table-technics-1"},{title:"Responsive table technics #2",filename:"tables",url:"tables.html#responsive-table-technics-2"},{title:"Responsive table technics #2 mixin variables",filename:"tables",url:"tables.html#responsive-table-technics-2-mixin-variables"},{title:"tooltips",filename:"tooltips",url:"tooltips.html"},{title:"Tooltips",filename:"tooltips",url:"tooltips.html#tooltips"},{title:"Tooltips variables",filename:"tooltips",url:"tooltips.html#tooltips-variables"},{title:"typography",filename:"typography",url:"typography.html"},{title:"Typogrphy",filename:"typography",url:"typography.html#typogrphy"},{title:"Typography variables",filename:"typography",url:"typography.html#typography-variables"},{title:"Font-size mixin",filename:"typography",url:"typography.html#fontsize-mixin"},{title:"Line-height mixin",filename:"typography",url:"typography.html#lineheight-mixin"},{title:"Word breaking mixin",filename:"typography",url:"typography.html#word-breaking-mixin"},{title:"Font face mixin",filename:"typography",url:"typography.html#font-face-mixin"},{title:"Text overflow mixin",filename:"typography",url:"typography.html#text-overflow-mixin"},{title:"Text hide",filename:"typography",url:"typography.html#text-hide"},{title:"Hyphens",filename:"typography",url:"typography.html#hyphens"},{title:"Font style and color",filename:"typography",url:"typography.html#font-style-and-color"},{title:"Font style mixin variables",filename:"typography",url:"typography.html#font-style-mixin-variables"},{title:"Reset list styles",filename:"typography",url:"typography.html#reset-list-styles"},{title:"Reset list styles variables",filename:"typography",url:"typography.html#reset-list-styles-variables"},{title:"Inline-block list item styling",filename:"typography",url:"typography.html#inlineblock-list-item-styling"},{title:"Link styling mixin",filename:"typography",url:"typography.html#link-styling-mixin"},{title:"Link styling mixin variables",filename:"typography",url:"typography.html#link-styling-mixin-variables"},{title:"Heading styling mixin",filename:"typography",url:"typography.html#heading-styling-mixin"},{title:"Base typography mixins",filename:"typography",url:"typography.html#base-typography-mixins"},{title:"Base typography mixin variables",filename:"typography",url:"typography.html#base-typography-mixin-variables"},{title:"Headings typography mixin",filename:"typography",url:"typography.html#headings-typography-mixin"},{title:"Headings typography mixin variables",filename:"typography",url:"typography.html#headings-typography-mixin-variables"},{title:"Typography links mixin",filename:"typography",url:"typography.html#typography-links-mixin"},{title:"Typography lists mixin",filename:"typography",url:"typography.html#typography-lists-mixin"},{title:"Typography lists mixin variables",filename:"typography",url:"typography.html#typography-lists-mixin-variables"},{title:"Typography code elements mixin",filename:"typography",url:"typography.html#typography-code-elements-mixin"},{title:"Typography code mixin variables",filename:"typography",url:"typography.html#typography-code-mixin-variables"},{title:"Typography blockquote",filename:"typography",url:"typography.html#typography-blockquote"},{title:"Typography blockquote mixin variables",filename:"typography",url:"typography.html#typography-blockquote-mixin-variables"},{title:"utilities",filename:"utilities",url:"utilities.html"},{title:"Utilities",filename:"utilities",url:"utilities.html#utilities"},{title:".lib-clearfix()",filename:"utilities",url:"utilities.html#libclearfix"},{title:".lib-visibility-hidden()",filename:"utilities",url:"utilities.html#libvisibilityhidden"},{title:".lib-visually-hidden()",filename:"utilities",url:"utilities.html#libvisuallyhidden"},{title:".lib-visually-hidden-reset()",filename:"utilities",url:"utilities.html#libvisuallyhiddenreset"},{title:".lib-css()",filename:"utilities",url:"utilities.html#libcss"},{title:".lib-css() variables",filename:"utilities",url:"utilities.html#libcss-variables"},{title:".lib-rotate()",filename:"utilities",url:"utilities.html#librotate"},{title:".lib-rotate() variables",filename:"utilities",url:"utilities.html#librotate-variables"},{title:".lib-input-placeholder()",filename:"utilities",url:"utilities.html#libinputplaceholder"},{title:".lib-input-placeholder() variables",filename:"utilities",url:"utilities.html#libinputplaceholder-variables"},{title:".lib-background-gradient()",filename:"utilities",url:"utilities.html#libbackgroundgradient"},{title:".lib-background-gradient() variables",filename:"utilities",url:"utilities.html#libbackgroundgradient-variables"},{title:".lib-url-check()",filename:"utilities",url:"utilities.html#liburlcheck"},{title:".lib-url-check() variables",filename:"utilities",url:"utilities.html#liburlcheck-variables"},{title:"variables",filename:"variables",url:"variables.html"},{title:"List of Global Variables",filename:"variables",url:"variables.html#list-of-global-variables"},{title:"Table with rows hover mixin variables",filename:"variables",url:"variables.html#table-with-rows-hover-mixin-variables"},{title:"docs",filename:"docs",url:"docs.html"},{title:"Documentation",filename:"docs",url:"docs.html#documentation"}];(function(){"use strict";var b=function(a,b){return Array.prototype.indexOf.call(a,b)!==-1},c=function(a,b){return Array.prototype.filter.call(a,b)},d=function(a,b){return Array.prototype.forEach.call(a,b)},e=document.getElementsByTagName("body")[0];e.addEventListener("click",function(a){var b=a.target;b.tagName.toLowerCase()==="svg"&&(b=b.parentNode);var c=!1;b.dataset.toggle!=null&&(a.preventDefault(),b.classList.contains("is-active")||(c=!0)),d(e.querySelectorAll("[data-toggle]"),function(a){a.classList.remove("is-active"),document.getElementById(a.dataset.toggle).hidden=!0}),c&&(b.classList.add("is-active"),document.getElementById(b.dataset.toggle).hidden=!1)}),function(){var f=e.getElementsByClassName("nav")[0];if(!f)return;var g=document.createElement("ul");g.className="nav-results",g.id="nav-search",g.hidden=!0,d(a,function(a){var b,c,d;b=document.createElement("li"),b._title=a.title.toLowerCase(),b.hidden=!0,b.appendChild(c=document.createElement("a")),c.href=a.url,c.innerHTML=a.title,c.appendChild(d=document.createElement("span")),d.innerHTML=a.filename,d.className="nav-results-filename",g.appendChild(b)}),f.appendChild(g);var h=g.children,i=function(a){d(h,function(a){a.hidden=!0});var b=this.value.toLowerCase(),e=[];b!==""&&(e=c(h,function(a){return a._title.indexOf(b)!==-1})),e.length>0?(d(e,function(a){a.hidden=!1}),g.hidden=!1):g.hidden=!0},j=f.querySelector('input[type="search"]');j.addEventListener("keyup",i),j.addEventListener("focus",i),e.addEventListener("click",function(a){if(a.target.classList&&a.target.classList.contains("search"))return;g.hidden=!0}),g.addEventListener("click",function(a){j.value=""});var k=document.createElement("ul");k.id="nav-toc",k.hidden=!0,k.className="nav-results toc-list",c(e.getElementsByTagName("*"),function(a){return b(["h1","h2","h3"],a.tagName.toLowerCase())}).map(function(a){var b=document.createElement("li"),c=document.createElement("a"),d=a.tagName.toLowerCase()[1];c.classList.add("level-"+d),b.appendChild(c),c.href="#"+a.id,c.innerHTML=a.innerHTML,k.appendChild(b)}),f.appendChild(k)}()})(),function(){"use strict";if(location.hash==="#__preview__"||location.protocol==="data:")return;var a=function(a,b){return Array.prototype.forEach.call(a,b)},b=function(a,b){var e=Array.prototype.slice.call(arguments,2);return d(a,function(a){return(c(b)?b||a:a[b]).apply(a,e)})},c=function(a){return Object.prototype.toString.call(a)==="[object Function]"},d=function(a,b){return Array.prototype.map.call(a,b)},e=function(a,b){return d(a,function(a){return a[b]})},f=function(a){var b={},c=a.split(";");for(var d=0;c.length>d;d++){var e=c[d].trim().split("=");b[e[0]]=e[1]}return b},g=function(a,c){return b(e(a,"classList"),"remove",c)},h=function(a,b){a.contentDocument.defaultView.postMessage(b,"*")},i=document.getElementsByTagName("head")[0],j=document.getElementsByTagName("body")[0],k=e(i.querySelectorAll('style[type="text/preview"]'),"innerHTML").join(""),l=e(i.querySelectorAll('script[type="text/preview"]'),"innerHTML").join(""),m=location.href.split("#")[0]+"#__preview__",n=document.createElement("iframe");n.src="data:text/html,",j.appendChild(n),n.addEventListener("load",function(){var b={sameOriginDataUri:!0};try{this.contentDocument,this.contentDocument||(b.sameOriginDataUri=!1)}catch(c){b.sameOriginDataUri=!1}this.parentNode.removeChild(this),a(j.getElementsByTagName("textarea"),function(a,c){o(a,b,c),q(),p(a)})});var o=function(a,b,c){var d,e,f;d=document.createElement("div"),d.appendChild(e=document.createElement("div")),d.className="preview",e.appendChild(f=document.createElement("iframe")),e.className="resizeable",f.setAttribute("scrolling","no"),f.name="iframe"+c++,f.addEventListener("load",function(){var c,d,e,f,g,i,j;j=this.contentDocument;if(!b.sameOriginDataUri&&this.src!==m)return;this.src===m&&(c=j.createElement("html"),c.appendChild(j.createElement("head")),c.appendChild(d=j.createElement("body")),d.innerHTML=a.textContent,j.replaceChild(c,j.documentElement)),g=j.createElement("head"),g.appendChild(f=j.createElement("style")),g.appendChild(e=j.createElement("script")),e.textContent=l,f.textContent=k,i=j.getElementsByTagName("head")[0],i.parentNode.replaceChild(g,i),h(this,"getHeight")});var g;b.sameOriginDataUri?g="data:text/html;charset=utf-8,"+encodeURIComponent("<!doctype html><html><head></head></body>"+a.textContent):g=m,f.setAttribute("src",g);var i=function(){f.contentDocument.body.innerHTML=this.value,h(f,"getHeight")};a.addEventListener("keypress",i),a.addEventListener("keyup",i),a.parentNode.insertBefore(d,a)},p=function(a){var b=document.createElement("div");b.className="preview-code",b.style.position="absolute",b.style.left="-9999px",j.appendChild(b);var c=parseInt(window.getComputedStyle(a).getPropertyValue("max-height"),10),d=function(a){b.textContent=this.value+"\n";var d=b.offsetHeight+2;d>=c?this.style.overflow="auto":this.style.overflow="hidden",this.style.height=b.offsetHeight+2+"px"};a.addEventListener("keypress",d),a.addEventListener("keyup",d),d.call(a)},q=function(){var b=j.getElementsByClassName("settings")[0],c=j.getElementsByClassName("resizeable"),d=30,e=function(b){document.cookie="preview-width="+b,a(c,function(a){b==="auto"&&(b=a.parentNode.offsetWidth),a.style.width=b+"px",h(a.getElementsByTagName("iframe")[0],"getHeight")})},i=f(document.cookie)["preview-width"];if(i){e(i),g(b.getElementsByClassName("is-active"),"is-active");var k=b.querySelector('button[data-width="'+i+'"]');k&&k.classList.add("is-active")}window.addEventListener("message",function(a){if(a.data==null||!a.source)return;var b=a.data,c=document.getElementsByName(a.source.name)[0];b.height!=null&&c&&(c.parentNode.style.height=b.height+d+"px")},!1),b&&c.length>0&&(b.hidden=!1,b.addEventListener("click",function(a){var c=a.target.tagName.toLowerCase(),d;if(c==="button")d=a.target;else{if(c!=="svg")return;d=a.target.parentNode}a.preventDefault(),g(b.getElementsByClassName("is-active"),"is-active"),d.classList.add("is-active");var f=d.dataset.width;e(f)}))}}()})()</script></body></html><!-- Generated with StyleDocco (http://jacobrask.github.com/styledocco). --> +</div></article></section><div class="bar bottom"><div hidden class="settings container"><!-- Icons from http://iconmonstr.com--><button title="Desktop (1280)" data-width='1280'><svg viewBox="0 0 412 386" height="24" width="26" class="icon"><path d="m147.6,343.9c-4.5,15.9-26.2,37.6-42.1,42.1h201c-15.3,-4-38.1,-26.8-42.1,-42.1H147.6zM387,0.5H25c-13.8,0-25,11.2-25,25V294c0,13.8 11.2,25 25,25h362c13.8,0 25,-11.2 25,-25V25.5C412,11.7 400.8,0.5 387,0.5zM369.9,238.2H42.1L42.1,42.6 369.9,42.6V238.2z"></path></svg></button><button title="Laptop (1024)" data-width='1024'><svg viewBox="0 0 384 312" height="23" width="28" class="icon"><path d="m349.2,20.5c0,-11-9,-20-20,-20H53.6c-11,0-20,9-20,20v194H349.2v-194zm-27,167H60.6V27.5H322.2v160zm28,42H32.6L2.6,282.1c-3.5,6.2-3.5,13.8 0.1,19.9 3.6,6.2 10.2,9.9 17.3,9.9H363.1c7.1,0 13.7,-3.8 17.3,-10 3.6,-6.2 3.6,-13.8 0,-20l-30.2,-52.5zm-196.9,54 8,-23.5h60.5l8,23.5h-76.5z"></path></svg></button><button title="Tablet (768)" data-width='768'><svg viewBox="0 0 317 412" height="24" width="18" class="icon"><path d="M 316.5,380 V 32 c 0,-17.7 -14.3,-32 -32,-32 H 32 C 14.3,0 0,14.3 0,32 v 348 c 0,17.7 14.3,32 32,32 h 252.5 c 17.7,0 32,-14.3 32,-32 z M 40,367 V 45 H 276.5 V 367 H 40 z m 109.8,22.7 c 0,-4.7 3.8,-8.5 8.5,-8.5 4.7,0 8.5,3.8 8.5,8.5 0,4.7 -3.8,8.5 -8.5,8.5 -4.7,0 -8.5,-3.8 -8.5,-8.5 z"></path></svg></button><button title="Smart phone (320)" data-width='320'><svg viewBox="0 0 224 412" height="24" width="13" class="icon"><path d="M 190.7,0 H 33 C 14.8,0 0,14.8 0,33 v 346 c 0,18.2 14.8,33 33,33 h 157.7 c 18.2,0 33,-14.8 33,-33 V 33 c 0,-18.2 -14.8,-33 -33,-33 z M 94.3,30.2 h 37 c 2.2,0 4,1.8 4,4 0,2.2 -1.8,4 -4,4 h -37 c -2.2,0 -4,-1.8 -4,-4 0,-2.2 1.8,-4 4,-4 z m 18.5,362.8 c -8.8,0 -16,-7.2 -16,-16 0,-8.8 7.2,-16 16,-16 8.8,0 16,7.2 16,16 0,8.8 -7.2,16 -16,16 z M 198.6,343.8 H 25.1 V 68.2 h 173.5 v 275.5 z"></path></svg></button><button title="Feature phone (240)" data-width='240'><svg viewBox="0 0 201 412" height="24" width="12" class="icon"><path d="M 165.5,0.2 V 45 H 25 c -13.8,0 -25,11.2 -25,25 V 387 c 0,13.8 11.2,25 25,25 h 150.5 c 13.8,0 25,-11.2 25,-25 V 0.2 h -35 z M 65.2,366.5 H 34.2 v -24.5 h 31 v 24.5 z m 0,-44.3 H 34.2 v -24.5 h 31 v 24.5 z m 50.5,44.3 H 84.7 v -24.5 h 31 v 24.5 z m 0,-44.3 H 84.7 v -24.5 h 31 v 24.5 z m 50.5,44.3 h -31 v -24.5 h 31 v 24.5 z m 0,-44.3 h -31 v -24.5 h 31 v 24.5 z m 0,-59.3 h -132 V 95.4 h 132 V 262.9 z"></path></svg></button><button title="Auto (100%)" data-width="auto" class="auto is-active">Auto</button></div></div><script>(function(){var a=[{title:"actions-toolbar",filename:"actions-toolbar",url:"actions-toolbar.html"},{title:"Actions toolbar",filename:"actions-toolbar",url:"actions-toolbar.html#actions-toolbar"},{title:"Actions toolbar mixin variables",filename:"actions-toolbar",url:"actions-toolbar.html#actions-toolbar-mixin-variables"},{title:"Actions toolbar alignment",filename:"actions-toolbar",url:"actions-toolbar.html#actions-toolbar-alignment"},{title:"Reverse primary and secondary blocks",filename:"actions-toolbar",url:"actions-toolbar.html#reverse-primary-and-secondary-blocks"},{title:"Actions toolbar indents customizations",filename:"actions-toolbar",url:"actions-toolbar.html#actions-toolbar-indents-customizations"},{title:"Responsive actions toolbar",filename:"actions-toolbar",url:"actions-toolbar.html#responsive-actions-toolbar"},{title:"breadcrumbs",filename:"breadcrumbs",url:"breadcrumbs.html"},{title:"Breadcrumbs",filename:"breadcrumbs",url:"breadcrumbs.html#breadcrumbs"},{title:"Breadcrumbs variables",filename:"breadcrumbs",url:"breadcrumbs.html#breadcrumbs-variables"},{title:"Button-styled breadcrumbs with gradient background, border, and no separating symbol",filename:"breadcrumbs",url:"breadcrumbs.html#buttonstyled-breadcrumbs-with-gradient-background-border-and-no-separating-symbol"},{title:"Breadcrumbs with solid background",filename:"breadcrumbs",url:"breadcrumbs.html#breadcrumbs-with-solid-background"},{title:"buttons",filename:"buttons",url:"buttons.html"},{title:"Default button",filename:"buttons",url:"buttons.html#default-button"},{title:"Button variables",filename:"buttons",url:"buttons.html#button-variables"},{title:"Button as an icon",filename:"buttons",url:"buttons.html#button-as-an-icon"},{title:"Button with an icon on the left or right side of the text",filename:"buttons",url:"buttons.html#button-with-an-icon-on-the-left-or-right-side-of-the-text"},{title:"Button with fixed width",filename:"buttons",url:"buttons.html#button-with-fixed-width"},{title:"Primary button",filename:"buttons",url:"buttons.html#primary-button"},{title:"Primary button variables",filename:"buttons",url:"buttons.html#primary-button-variables"},{title:"Button with gradient background",filename:"buttons",url:"buttons.html#button-with-gradient-background"},{title:"Button as a link",filename:"buttons",url:"buttons.html#button-as-a-link"},{title:"Button as a link variables",filename:"buttons",url:"buttons.html#button-as-a-link-variables"},{title:"Link as a button",filename:"buttons",url:"buttons.html#link-as-a-button"},{title:"Button reset",filename:"buttons",url:"buttons.html#button-reset"},{title:"Button revert secondary color",filename:"buttons",url:"buttons.html#button-revert-secondary-color"},{title:"Button revert secondary color variables",filename:"buttons",url:"buttons.html#button-revert-secondary-color-variables"},{title:"Button revert secondary size",filename:"buttons",url:"buttons.html#button-revert-secondary-size"},{title:"Button revert secondary size variables",filename:"buttons",url:"buttons.html#button-revert-secondary-size-variables"},{title:"components",filename:"components",url:"components.html"},{title:"Components",filename:"components",url:"components.html#components"},{title:"Components Variables",filename:"components",url:"components.html#components-variables"},{title:"dropdowns",filename:"dropdowns",url:"dropdowns.html"},{title:"Drop-down and split buttons mixins",filename:"dropdowns",url:"dropdowns.html#dropdown-and-split-buttons-mixins"},{title:"Drop-down",filename:"dropdowns",url:"dropdowns.html#dropdown"},{title:"Drop-down variables",filename:"dropdowns",url:"dropdowns.html#dropdown-variables"},{title:"Drop-down with icon customization",filename:"dropdowns",url:"dropdowns.html#dropdown-with-icon-customization"},{title:"Modify dropdown list styles",filename:"dropdowns",url:"dropdowns.html#modify-dropdown-list-styles"},{title:"Split button",filename:"dropdowns",url:"dropdowns.html#split-button"},{title:"Split button variables",filename:"dropdowns",url:"dropdowns.html#split-button-variables"},{title:"Split button - button styling",filename:"dropdowns",url:"dropdowns.html#split-button-button-styling"},{title:"Split button icon customization",filename:"dropdowns",url:"dropdowns.html#split-button-icon-customization"},{title:"Split button drop-down list customization",filename:"dropdowns",url:"dropdowns.html#split-button-dropdown-list-customization"},{title:"forms",filename:"forms",url:"forms.html"},{title:"Forms mixins",filename:"forms",url:"forms.html#forms-mixins"},{title:"Global forms elements customization",filename:"forms",url:"forms.html#global-forms-elements-customization"},{title:"Fieldsets & fields customization",filename:"forms",url:"forms.html#fieldsets-fields-customization"},{title:"Fieldset and legend customization variables",filename:"forms",url:"forms.html#fieldset-and-legend-customization-variables"},{title:"Fields customization variables",filename:"forms",url:"forms.html#fields-customization-variables"},{title:"Required fields message customization variables",filename:"forms",url:"forms.html#required-fields-message-customization-variables"},{title:"Form element inputs customization",filename:"forms",url:"forms.html#form-element-inputs-customization"},{title:"Form element inputs customization variables",filename:"forms",url:"forms.html#form-element-inputs-customization-variables"},{title:"Form element choice",filename:"forms",url:"forms.html#form-element-choice"},{title:"Form element choice variables",filename:"forms",url:"forms.html#form-element-choice-variables"},{title:"Custom color",filename:"forms",url:"forms.html#custom-color"},{title:"Input number - input-text view",filename:"forms",url:"forms.html#input-number-inputtext-view"},{title:"Input search - input-text view",filename:"forms",url:"forms.html#input-search-inputtext-view"},{title:"Form validation",filename:"forms",url:"forms.html#form-validation"},{title:"Form validation variables",filename:"forms",url:"forms.html#form-validation-variables"},{title:"icons",filename:"icons",url:"icons.html"},{title:"Icons",filename:"icons",url:"icons.html#icons"},{title:"Icon with image or sprite",filename:"icons",url:"icons.html#icon-with-image-or-sprite"},{title:"Icon with image or sprite variables",filename:"icons",url:"icons.html#icon-with-image-or-sprite-variables"},{title:"Icon position for an icon with image or sprite",filename:"icons",url:"icons.html#icon-position-for-an-icon-with-image-or-sprite"},{title:"Position for icon with image or sprite mixin variables",filename:"icons",url:"icons.html#position-for-icon-with-image-or-sprite-mixin-variables"},{title:"Icon sprite position (with grid)",filename:"icons",url:"icons.html#icon-sprite-position-with-grid"},{title:"Icon sprite position variables",filename:"icons",url:"icons.html#icon-sprite-position-variables"},{title:"Image/sprite icon size",filename:"icons",url:"icons.html#imagesprite-icon-size"},{title:"Image/sprite icon size variables",filename:"icons",url:"icons.html#imagesprite-icon-size-variables"},{title:"Font icon",filename:"icons",url:"icons.html#font-icon"},{title:"Font icon variables",filename:"icons",url:"icons.html#font-icon-variables"},{title:"Change the size of font icon",filename:"icons",url:"icons.html#change-the-size-of-font-icon"},{title:"Change the size of font icon variables",filename:"icons",url:"icons.html#change-the-size-of-font-icon-variables"},{title:"Hide icon text",filename:"icons",url:"icons.html#hide-icon-text"},{title:"Sprite and font icons for Blank theme",filename:"icons",url:"icons.html#sprite-and-font-icons-for-blank-theme"},{title:"layout",filename:"layout",url:"layout.html"},{title:"Layout",filename:"layout",url:"layout.html#layout"},{title:"Layout global variables",filename:"layout",url:"layout.html#layout-global-variables"},{title:"Page layouts",filename:"layout",url:"layout.html#page-layouts"},{title:"Layout column",filename:"layout",url:"layout.html#layout-column"},{title:"Layout column variables",filename:"layout",url:"layout.html#layout-column-variables"},{title:"Layout width",filename:"layout",url:"layout.html#layout-width"},{title:"Layout width variables",filename:"layout",url:"layout.html#layout-width-variables"},{title:"lib",filename:"lib",url:"lib.html"},{title:"Including Magento UI library to your theme",filename:"lib",url:"lib.html#including-magento-ui-library-to-your-theme"},{title:"loaders",filename:"loaders",url:"loaders.html"},{title:"Loaders",filename:"loaders",url:"loaders.html#loaders"},{title:"Default loader variables",filename:"loaders",url:"loaders.html#default-loader-variables"},{title:"Loading",filename:"loaders",url:"loaders.html#loading"},{title:"Loading default variables",filename:"loaders",url:"loaders.html#loading-default-variables"},{title:"messages",filename:"messages",url:"messages.html"},{title:"Messages",filename:"messages",url:"messages.html#messages"},{title:"Information message",filename:"messages",url:"messages.html#information-message"},{title:"Warning message",filename:"messages",url:"messages.html#warning-message"},{title:"Error message",filename:"messages",url:"messages.html#error-message"},{title:"Success message",filename:"messages",url:"messages.html#success-message"},{title:"Notice message",filename:"messages",url:"messages.html#notice-message"},{title:"Message with inner icon",filename:"messages",url:"messages.html#message-with-inner-icon"},{title:"Message with lateral icon",filename:"messages",url:"messages.html#message-with-lateral-icon"},{title:"Custom message style",filename:"messages",url:"messages.html#custom-message-style"},{title:"Messages global variables",filename:"messages",url:"messages.html#messages-global-variables"},{title:"pages",filename:"pages",url:"pages.html"},{title:"Pagination HTML markup",filename:"pages",url:"pages.html#pagination-html-markup"},{title:"Pagination variables",filename:"pages",url:"pages.html#pagination-variables"},{title:"Pagination with label and gradient background on links",filename:"pages",url:"pages.html#pagination-with-label-and-gradient-background-on-links"},{title:'Pagination with "previous"..."next" text links and label',filename:"pages",url:"pages.html#pagination-with-previousnext-text-links-and-label"},{title:"Pagination without label, with solid background",filename:"pages",url:"pages.html#pagination-without-label-with-solid-background"},{title:"popups",filename:"popups",url:"popups.html"},{title:"Popups",filename:"popups",url:"popups.html#popups"},{title:"Popup variables",filename:"popups",url:"popups.html#popup-variables"},{title:"Window overlay mixin variables",filename:"popups",url:"popups.html#window-overlay-mixin-variables"},{title:"Fixed height popup",filename:"popups",url:"popups.html#fixed-height-popup"},{title:"Fixed content height popup",filename:"popups",url:"popups.html#fixed-content-height-popup"},{title:"Margins for header, content and footer block in popup",filename:"popups",url:"popups.html#margins-for-header-content-and-footer-block-in-popup"},{title:"Popup titles styled as theme headings",filename:"popups",url:"popups.html#popup-titles-styled-as-theme-headings"},{title:"Popup action toolbar",filename:"popups",url:"popups.html#popup-action-toolbar"},{title:"Popup Close button without an icon",filename:"popups",url:"popups.html#popup-close-button-without-an-icon"},{title:"Modify the icon of popup Close button",filename:"popups",url:"popups.html#modify-the-icon-of-popup-close-button"},{title:"Modify overlay styles",filename:"popups",url:"popups.html#modify-overlay-styles"},{title:"rating",filename:"rating",url:"rating.html"},{title:"Ratings",filename:"rating",url:"rating.html#ratings"},{title:"Global rating variables",filename:"rating",url:"rating.html#global-rating-variables"},{title:"Rating with vote",filename:"rating",url:"rating.html#rating-with-vote"},{title:"Rating with vote icons number customization",filename:"rating",url:"rating.html#rating-with-vote-icons-number-customization"},{title:"Rating with vote icons colors customization",filename:"rating",url:"rating.html#rating-with-vote-icons-colors-customization"},{title:"Rating with vote icons symbol customization",filename:"rating",url:"rating.html#rating-with-vote-icons-symbol-customization"},{title:"Accessible rating with vote",filename:"rating",url:"rating.html#accessible-rating-with-vote"},{title:"Rating summary",filename:"rating",url:"rating.html#rating-summary"},{title:"Rating summary icons number customization",filename:"rating",url:"rating.html#rating-summary-icons-number-customization"},{title:"Rating summary icons color customization",filename:"rating",url:"rating.html#rating-summary-icons-color-customization"},{title:"Rating summary icons symbol customization",filename:"rating",url:"rating.html#rating-summary-icons-symbol-customization"},{title:"Rating summary hide label",filename:"rating",url:"rating.html#rating-summary-hide-label"},{title:"Rating summary multiple ratings",filename:"rating",url:"rating.html#rating-summary-multiple-ratings"},{title:"Rating hide label mixin",filename:"rating",url:"rating.html#rating-hide-label-mixin"},{title:"resets",filename:"resets",url:"resets.html"},{title:"Resets",filename:"resets",url:"resets.html#resets"},{title:"responsive",filename:"responsive",url:"responsive.html"},{title:"Responsive",filename:"responsive",url:"responsive.html#responsive"},{title:"Responsive mixins usage",filename:"responsive",url:"responsive.html#responsive-mixins-usage"},{title:"Media query style groups separation variables",filename:"responsive",url:"responsive.html#media-query-style-groups-separation-variables"},{title:"Responsive breakpoints",filename:"responsive",url:"responsive.html#responsive-breakpoints"},{title:"sections",filename:"sections",url:"sections.html"},{title:"Tabs and accordions",filename:"sections",url:"sections.html#tabs-and-accordions"},{title:"Tabs",filename:"sections",url:"sections.html#tabs"},{title:"Tabs mixin variables",filename:"sections",url:"sections.html#tabs-mixin-variables"},{title:"Tabs with content top border",filename:"sections",url:"sections.html#tabs-with-content-top-border"},{title:"Accordion",filename:"sections",url:"sections.html#accordion"},{title:"Accordion mixin variables",filename:"sections",url:"sections.html#accordion-mixin-variables"},{title:"Responsive tabs",filename:"sections",url:"sections.html#responsive-tabs"},{title:"Tabs Base",filename:"sections",url:"sections.html#tabs-base"},{title:"Accordion Base",filename:"sections",url:"sections.html#accordion-base"},{title:"tables",filename:"tables",url:"tables.html"},{title:"Tables",filename:"tables",url:"tables.html#tables"},{title:"Table mixin variables",filename:"tables",url:"tables.html#table-mixin-variables"},{title:"Table typography",filename:"tables",url:"tables.html#table-typography"},{title:"Table typography mixin variables",filename:"tables",url:"tables.html#table-typography-mixin-variables"},{title:"Table caption",filename:"tables",url:"tables.html#table-caption"},{title:"Table caption mixin variables",filename:"tables",url:"tables.html#table-caption-mixin-variables"},{title:"Table cells resize",filename:"tables",url:"tables.html#table-cells-resize"},{title:"Table cells resize variables",filename:"tables",url:"tables.html#table-cells-resize-variables"},{title:"Table background customization",filename:"tables",url:"tables.html#table-background-customization"},{title:"Table background mixin variables",filename:"tables",url:"tables.html#table-background-mixin-variables"},{title:"Table borders customization",filename:"tables",url:"tables.html#table-borders-customization"},{title:"Table borders mixin variables",filename:"tables",url:"tables.html#table-borders-mixin-variables"},{title:"Table with horizontal borders",filename:"tables",url:"tables.html#table-with-horizontal-borders"},{title:"Table with vertical borders",filename:"tables",url:"tables.html#table-with-vertical-borders"},{title:"Table with light borders",filename:"tables",url:"tables.html#table-with-light-borders"},{title:"Table without borders",filename:"tables",url:"tables.html#table-without-borders"},{title:"Striped table",filename:"tables",url:"tables.html#striped-table"},{title:"Striped table mixin variables",filename:"tables",url:"tables.html#striped-table-mixin-variables"},{title:"Table with rows hover",filename:"tables",url:"tables.html#table-with-rows-hover"},{title:"Table with rows hover mixin variables",filename:"tables",url:"tables.html#table-with-rows-hover-mixin-variables"},{title:"Responsive table technics #1",filename:"tables",url:"tables.html#responsive-table-technics-1"},{title:"Responsive table technics #2",filename:"tables",url:"tables.html#responsive-table-technics-2"},{title:"Responsive table technics #2 mixin variables",filename:"tables",url:"tables.html#responsive-table-technics-2-mixin-variables"},{title:"tooltips",filename:"tooltips",url:"tooltips.html"},{title:"Tooltips",filename:"tooltips",url:"tooltips.html#tooltips"},{title:"Tooltips variables",filename:"tooltips",url:"tooltips.html#tooltips-variables"},{title:"typography",filename:"typography",url:"typography.html"},{title:"Typogrphy",filename:"typography",url:"typography.html#typogrphy"},{title:"Typography variables",filename:"typography",url:"typography.html#typography-variables"},{title:"Font-size mixin",filename:"typography",url:"typography.html#fontsize-mixin"},{title:"Line-height mixin",filename:"typography",url:"typography.html#lineheight-mixin"},{title:"Word breaking mixin",filename:"typography",url:"typography.html#word-breaking-mixin"},{title:"Font face mixin",filename:"typography",url:"typography.html#font-face-mixin"},{title:"Text overflow mixin",filename:"typography",url:"typography.html#text-overflow-mixin"},{title:"Text hide",filename:"typography",url:"typography.html#text-hide"},{title:"Hyphens",filename:"typography",url:"typography.html#hyphens"},{title:"Font style and color",filename:"typography",url:"typography.html#font-style-and-color"},{title:"Font style mixin variables",filename:"typography",url:"typography.html#font-style-mixin-variables"},{title:"Reset list styles",filename:"typography",url:"typography.html#reset-list-styles"},{title:"Reset list styles variables",filename:"typography",url:"typography.html#reset-list-styles-variables"},{title:"Inline-block list item styling",filename:"typography",url:"typography.html#inlineblock-list-item-styling"},{title:"Link styling mixin",filename:"typography",url:"typography.html#link-styling-mixin"},{title:"Link styling mixin variables",filename:"typography",url:"typography.html#link-styling-mixin-variables"},{title:"Heading styling mixin",filename:"typography",url:"typography.html#heading-styling-mixin"},{title:"Base typography mixins",filename:"typography",url:"typography.html#base-typography-mixins"},{title:"Base typography mixin variables",filename:"typography",url:"typography.html#base-typography-mixin-variables"},{title:"Headings typography mixin",filename:"typography",url:"typography.html#headings-typography-mixin"},{title:"Headings typography mixin variables",filename:"typography",url:"typography.html#headings-typography-mixin-variables"},{title:"Typography links mixin",filename:"typography",url:"typography.html#typography-links-mixin"},{title:"Typography lists mixin",filename:"typography",url:"typography.html#typography-lists-mixin"},{title:"Typography lists mixin variables",filename:"typography",url:"typography.html#typography-lists-mixin-variables"},{title:"Typography code elements mixin",filename:"typography",url:"typography.html#typography-code-elements-mixin"},{title:"Typography code mixin variables",filename:"typography",url:"typography.html#typography-code-mixin-variables"},{title:"Typography blockquote",filename:"typography",url:"typography.html#typography-blockquote"},{title:"Typography blockquote mixin variables",filename:"typography",url:"typography.html#typography-blockquote-mixin-variables"},{title:"utilities",filename:"utilities",url:"utilities.html"},{title:"Utilities",filename:"utilities",url:"utilities.html#utilities"},{title:".lib-clearfix()",filename:"utilities",url:"utilities.html#libclearfix"},{title:".lib-visibility-hidden()",filename:"utilities",url:"utilities.html#libvisibilityhidden"},{title:".lib-visually-hidden()",filename:"utilities",url:"utilities.html#libvisuallyhidden"},{title:".lib-visually-hidden-reset()",filename:"utilities",url:"utilities.html#libvisuallyhiddenreset"},{title:".lib-css()",filename:"utilities",url:"utilities.html#libcss"},{title:".lib-css() variables",filename:"utilities",url:"utilities.html#libcss-variables"},{title:".lib-rotate()",filename:"utilities",url:"utilities.html#librotate"},{title:".lib-rotate() variables",filename:"utilities",url:"utilities.html#librotate-variables"},{title:".lib-input-placeholder()",filename:"utilities",url:"utilities.html#libinputplaceholder"},{title:".lib-input-placeholder() variables",filename:"utilities",url:"utilities.html#libinputplaceholder-variables"},{title:".lib-background-gradient()",filename:"utilities",url:"utilities.html#libbackgroundgradient"},{title:".lib-background-gradient() variables",filename:"utilities",url:"utilities.html#libbackgroundgradient-variables"},{title:"variables",filename:"variables",url:"variables.html"},{title:"List of Global Variables",filename:"variables",url:"variables.html#list-of-global-variables"},{title:"Table with rows hover mixin variables",filename:"variables",url:"variables.html#table-with-rows-hover-mixin-variables"},{title:"docs",filename:"docs",url:"docs.html"},{title:"Documentation",filename:"docs",url:"docs.html#documentation"}];(function(){"use strict";var b=function(a,b){return Array.prototype.indexOf.call(a,b)!==-1},c=function(a,b){return Array.prototype.filter.call(a,b)},d=function(a,b){return Array.prototype.forEach.call(a,b)},e=document.getElementsByTagName("body")[0];e.addEventListener("click",function(a){var b=a.target;b.tagName.toLowerCase()==="svg"&&(b=b.parentNode);var c=!1;b.dataset.toggle!=null&&(a.preventDefault(),b.classList.contains("is-active")||(c=!0)),d(e.querySelectorAll("[data-toggle]"),function(a){a.classList.remove("is-active"),document.getElementById(a.dataset.toggle).hidden=!0}),c&&(b.classList.add("is-active"),document.getElementById(b.dataset.toggle).hidden=!1)}),function(){var f=e.getElementsByClassName("nav")[0];if(!f)return;var g=document.createElement("ul");g.className="nav-results",g.id="nav-search",g.hidden=!0,d(a,function(a){var b,c,d;b=document.createElement("li"),b._title=a.title.toLowerCase(),b.hidden=!0,b.appendChild(c=document.createElement("a")),c.href=a.url,c.innerHTML=a.title,c.appendChild(d=document.createElement("span")),d.innerHTML=a.filename,d.className="nav-results-filename",g.appendChild(b)}),f.appendChild(g);var h=g.children,i=function(a){d(h,function(a){a.hidden=!0});var b=this.value.toLowerCase(),e=[];b!==""&&(e=c(h,function(a){return a._title.indexOf(b)!==-1})),e.length>0?(d(e,function(a){a.hidden=!1}),g.hidden=!1):g.hidden=!0},j=f.querySelector('input[type="search"]');j.addEventListener("keyup",i),j.addEventListener("focus",i),e.addEventListener("click",function(a){if(a.target.classList&&a.target.classList.contains("search"))return;g.hidden=!0}),g.addEventListener("click",function(a){j.value=""});var k=document.createElement("ul");k.id="nav-toc",k.hidden=!0,k.className="nav-results toc-list",c(e.getElementsByTagName("*"),function(a){return b(["h1","h2","h3"],a.tagName.toLowerCase())}).map(function(a){var b=document.createElement("li"),c=document.createElement("a"),d=a.tagName.toLowerCase()[1];c.classList.add("level-"+d),b.appendChild(c),c.href="#"+a.id,c.innerHTML=a.innerHTML,k.appendChild(b)}),f.appendChild(k)}()})(),function(){"use strict";if(location.hash==="#__preview__"||location.protocol==="data:")return;var a=function(a,b){return Array.prototype.forEach.call(a,b)},b=function(a,b){var e=Array.prototype.slice.call(arguments,2);return d(a,function(a){return(c(b)?b||a:a[b]).apply(a,e)})},c=function(a){return Object.prototype.toString.call(a)==="[object Function]"},d=function(a,b){return Array.prototype.map.call(a,b)},e=function(a,b){return d(a,function(a){return a[b]})},f=function(a){var b={},c=a.split(";");for(var d=0;c.length>d;d++){var e=c[d].trim().split("=");b[e[0]]=e[1]}return b},g=function(a,c){return b(e(a,"classList"),"remove",c)},h=function(a,b){a.contentDocument.defaultView.postMessage(b,"*")},i=document.getElementsByTagName("head")[0],j=document.getElementsByTagName("body")[0],k=e(i.querySelectorAll('style[type="text/preview"]'),"innerHTML").join(""),l=e(i.querySelectorAll('script[type="text/preview"]'),"innerHTML").join(""),m=location.href.split("#")[0]+"#__preview__",n=document.createElement("iframe");n.src="data:text/html,",j.appendChild(n),n.addEventListener("load",function(){var b={sameOriginDataUri:!0};try{this.contentDocument,this.contentDocument||(b.sameOriginDataUri=!1)}catch(c){b.sameOriginDataUri=!1}this.parentNode.removeChild(this),a(j.getElementsByTagName("textarea"),function(a,c){o(a,b,c),q(),p(a)})});var o=function(a,b,c){var d,e,f;d=document.createElement("div"),d.appendChild(e=document.createElement("div")),d.className="preview",e.appendChild(f=document.createElement("iframe")),e.className="resizeable",f.setAttribute("scrolling","no"),f.name="iframe"+c++,f.addEventListener("load",function(){var c,d,e,f,g,i,j;j=this.contentDocument;if(!b.sameOriginDataUri&&this.src!==m)return;this.src===m&&(c=j.createElement("html"),c.appendChild(j.createElement("head")),c.appendChild(d=j.createElement("body")),d.innerHTML=a.textContent,j.replaceChild(c,j.documentElement)),g=j.createElement("head"),g.appendChild(f=j.createElement("style")),g.appendChild(e=j.createElement("script")),e.textContent=l,f.textContent=k,i=j.getElementsByTagName("head")[0],i.parentNode.replaceChild(g,i),h(this,"getHeight")});var g;b.sameOriginDataUri?g="data:text/html;charset=utf-8,"+encodeURIComponent("<!doctype html><html><head></head></body>"+a.textContent):g=m,f.setAttribute("src",g);var i=function(){f.contentDocument.body.innerHTML=this.value,h(f,"getHeight")};a.addEventListener("keypress",i),a.addEventListener("keyup",i),a.parentNode.insertBefore(d,a)},p=function(a){var b=document.createElement("div");b.className="preview-code",b.style.position="absolute",b.style.left="-9999px",j.appendChild(b);var c=parseInt(window.getComputedStyle(a).getPropertyValue("max-height"),10),d=function(a){b.textContent=this.value+"\n";var d=b.offsetHeight+2;d>=c?this.style.overflow="auto":this.style.overflow="hidden",this.style.height=b.offsetHeight+2+"px"};a.addEventListener("keypress",d),a.addEventListener("keyup",d),d.call(a)},q=function(){var b=j.getElementsByClassName("settings")[0],c=j.getElementsByClassName("resizeable"),d=30,e=function(b){document.cookie="preview-width="+b,a(c,function(a){b==="auto"&&(b=a.parentNode.offsetWidth),a.style.width=b+"px",h(a.getElementsByTagName("iframe")[0],"getHeight")})},i=f(document.cookie)["preview-width"];if(i){e(i),g(b.getElementsByClassName("is-active"),"is-active");var k=b.querySelector('button[data-width="'+i+'"]');k&&k.classList.add("is-active")}window.addEventListener("message",function(a){if(a.data==null||!a.source)return;var b=a.data,c=document.getElementsByName(a.source.name)[0];b.height!=null&&c&&(c.parentNode.style.height=b.height+d+"px")},!1),b&&c.length>0&&(b.hidden=!1,b.addEventListener("click",function(a){var c=a.target.tagName.toLowerCase(),d;if(c==="button")d=a.target;else{if(c!=="svg")return;d=a.target.parentNode}a.preventDefault(),g(b.getElementsByClassName("is-active"),"is-active"),d.classList.add("is-active");var f=d.dataset.width;e(f)}))}}()})()</script></body></html><!-- Generated with StyleDocco (http://jacobrask.github.com/styledocco). --> diff --git a/lib/web/css/docs/utilities.html b/lib/web/css/docs/utilities.html index 29ecce2414e1e..8ab4a1136967e 100644 --- a/lib/web/css/docs/utilities.html +++ b/lib/web/css/docs/utilities.html @@ -261,50 +261,4 @@ </tr> </table> </pre> -</div></article><article id="liburlcheck" class="section"><div class="docs"><a href="#liburlcheck" class="permalink"><svg viewBox="0 0 512 512" height="32" width="32" class="icon"><path d="M156.2,199.7c7.5-7.5,15.9-13.8,24.8-18.7c49.6-27.3,113.1-12.8,145,35.5l-38.5,38.5c-11.1-25.2-38.5-39.6-65.8-33.5c-10.3,2.3-20.1,7.4-28,15.4l-73.9,73.9c-22.4,22.4-22.4,58.9,0,81.4c22.4,22.4,58.9,22.4,81.4,0l22.8-22.8c20.7,8.2,42.9,11.5,64.9,9.9l-50.3,50.3c-43.1,43.1-113,43.1-156.1,0c-43.1-43.1-43.1-113-0-156.1L156.2,199.7z M273.6,82.3l-50.3,50.3c21.9-1.6,44.2,1.6,64.9,9.9l22.8-22.8c22.4-22.4,58.9-22.4,81.4,0c22.4,22.4,22.4,58.9,0,81.4l-73.9,73.9c-22.5,22.5-59.1,22.3-81.4,0c-5.2-5.2-9.7-11.7-12.5-18l-38.5,38.5c4,6.1,8.3,11.5,13.7,16.9c13.9,13.9,31.7,24.3,52.1,29.3c26.5,6.4,54.8,2.8,79.2-10.6c8.9-4.9,17.3-11.1,24.8-18.7l73.9-73.9c43.1-43.1,43.1-113,0-156.1C386.6,39.2,316.7,39.2,273.6,82.3z"></path></svg></a><h1 id="liburlcheck">.lib-url-check()</h1> -<p> The <code>.lib-url-check()</code> mixin wraps passed value with 'url( ... )' and returns <code>@lib-url-check-output</code> variable. Can be used with <code>.lib-css()</code> mixin.</p> -<p> If the variable is set to <code>false</code>, the <code>.lib-url-check()</code> will return false.</p> -<textarea class="preview-code" spellcheck="false"> <div class="example-url-check"> - Block with background. - </div></textarea><textarea class="preview-code" spellcheck="false"> <div class="example-url-check-false"> - Block with no background. - </div></textarea> -</div><div class="code"><pre><code>.example-url-check { - // Set image path variable - @_icon-image: '/images/test.png'; - - // "Call" the mixin - .lib-url-check(@_icon-image); - - // Will return url('/images/test.png') - .lib-css(background, #eee @lib-url-check-output no-repeat 0 0); -} - - -.example-url-check-false { - // Set usage image path to false - @_icon-image: false; - - // "Call" the mixin - .lib-url-check(@_icon-image); - - // Will return 'false' and outputs nothing - .lib-css(background, #eee @lib-url-check-output no-repeat 0 0); -}</code></pre></div></article><article id="liburlcheck-variables" class="section"><div class="docs"><a href="#liburlcheck-variables" class="permalink"><svg viewBox="0 0 512 512" height="32" width="32" class="icon"><path d="M156.2,199.7c7.5-7.5,15.9-13.8,24.8-18.7c49.6-27.3,113.1-12.8,145,35.5l-38.5,38.5c-11.1-25.2-38.5-39.6-65.8-33.5c-10.3,2.3-20.1,7.4-28,15.4l-73.9,73.9c-22.4,22.4-22.4,58.9,0,81.4c22.4,22.4,58.9,22.4,81.4,0l22.8-22.8c20.7,8.2,42.9,11.5,64.9,9.9l-50.3,50.3c-43.1,43.1-113,43.1-156.1,0c-43.1-43.1-43.1-113-0-156.1L156.2,199.7z M273.6,82.3l-50.3,50.3c21.9-1.6,44.2,1.6,64.9,9.9l22.8-22.8c22.4-22.4,58.9-22.4,81.4,0c22.4,22.4,22.4,58.9,0,81.4l-73.9,73.9c-22.5,22.5-59.1,22.3-81.4,0c-5.2-5.2-9.7-11.7-12.5-18l-38.5,38.5c4,6.1,8.3,11.5,13.7,16.9c13.9,13.9,31.7,24.3,52.1,29.3c26.5,6.4,54.8,2.8,79.2-10.6c8.9-4.9,17.3-11.1,24.8-18.7l73.9-73.9c43.1-43.1,43.1-113,0-156.1C386.6,39.2,316.7,39.2,273.6,82.3z"></path></svg></a><h1 id="liburlcheck-variables">.lib-url-check() variables</h1> - <pre> - <table> - <tr> - <th class="vars_head">Mixin variable</th> - <th class="vars_head">Allowed values</th> - <th class="vars_head">Output variable</th> - <th class="vars_head">Comment</th> - </tr> - <tr> - <th>@_path</th> - <td class="vars_value">'' | false | value</td> - <td class="vars_value">@lib-url-check-output</td> - <td>Passed url to wrap in 'url( ... )'. If the 'false' value passed mixin will return 'false'</td> - </tr> - </table> - </pre> -</div></article></section><div class="bar bottom"><div hidden class="settings container"><!-- Icons from http://iconmonstr.com--><button title="Desktop (1280)" data-width='1280'><svg viewBox="0 0 412 386" height="24" width="26" class="icon"><path d="m147.6,343.9c-4.5,15.9-26.2,37.6-42.1,42.1h201c-15.3,-4-38.1,-26.8-42.1,-42.1H147.6zM387,0.5H25c-13.8,0-25,11.2-25,25V294c0,13.8 11.2,25 25,25h362c13.8,0 25,-11.2 25,-25V25.5C412,11.7 400.8,0.5 387,0.5zM369.9,238.2H42.1L42.1,42.6 369.9,42.6V238.2z"></path></svg></button><button title="Laptop (1024)" data-width='1024'><svg viewBox="0 0 384 312" height="23" width="28" class="icon"><path d="m349.2,20.5c0,-11-9,-20-20,-20H53.6c-11,0-20,9-20,20v194H349.2v-194zm-27,167H60.6V27.5H322.2v160zm28,42H32.6L2.6,282.1c-3.5,6.2-3.5,13.8 0.1,19.9 3.6,6.2 10.2,9.9 17.3,9.9H363.1c7.1,0 13.7,-3.8 17.3,-10 3.6,-6.2 3.6,-13.8 0,-20l-30.2,-52.5zm-196.9,54 8,-23.5h60.5l8,23.5h-76.5z"></path></svg></button><button title="Tablet (768)" data-width='768'><svg viewBox="0 0 317 412" height="24" width="18" class="icon"><path d="M 316.5,380 V 32 c 0,-17.7 -14.3,-32 -32,-32 H 32 C 14.3,0 0,14.3 0,32 v 348 c 0,17.7 14.3,32 32,32 h 252.5 c 17.7,0 32,-14.3 32,-32 z M 40,367 V 45 H 276.5 V 367 H 40 z m 109.8,22.7 c 0,-4.7 3.8,-8.5 8.5,-8.5 4.7,0 8.5,3.8 8.5,8.5 0,4.7 -3.8,8.5 -8.5,8.5 -4.7,0 -8.5,-3.8 -8.5,-8.5 z"></path></svg></button><button title="Smart phone (320)" data-width='320'><svg viewBox="0 0 224 412" height="24" width="13" class="icon"><path d="M 190.7,0 H 33 C 14.8,0 0,14.8 0,33 v 346 c 0,18.2 14.8,33 33,33 h 157.7 c 18.2,0 33,-14.8 33,-33 V 33 c 0,-18.2 -14.8,-33 -33,-33 z M 94.3,30.2 h 37 c 2.2,0 4,1.8 4,4 0,2.2 -1.8,4 -4,4 h -37 c -2.2,0 -4,-1.8 -4,-4 0,-2.2 1.8,-4 4,-4 z m 18.5,362.8 c -8.8,0 -16,-7.2 -16,-16 0,-8.8 7.2,-16 16,-16 8.8,0 16,7.2 16,16 0,8.8 -7.2,16 -16,16 z M 198.6,343.8 H 25.1 V 68.2 h 173.5 v 275.5 z"></path></svg></button><button title="Feature phone (240)" data-width='240'><svg viewBox="0 0 201 412" height="24" width="12" class="icon"><path d="M 165.5,0.2 V 45 H 25 c -13.8,0 -25,11.2 -25,25 V 387 c 0,13.8 11.2,25 25,25 h 150.5 c 13.8,0 25,-11.2 25,-25 V 0.2 h -35 z M 65.2,366.5 H 34.2 v -24.5 h 31 v 24.5 z m 0,-44.3 H 34.2 v -24.5 h 31 v 24.5 z m 50.5,44.3 H 84.7 v -24.5 h 31 v 24.5 z m 0,-44.3 H 84.7 v -24.5 h 31 v 24.5 z m 50.5,44.3 h -31 v -24.5 h 31 v 24.5 z m 0,-44.3 h -31 v -24.5 h 31 v 24.5 z m 0,-59.3 h -132 V 95.4 h 132 V 262.9 z"></path></svg></button><button title="Auto (100%)" data-width="auto" class="auto is-active">Auto</button></div></div><script>(function(){var a=[{title:"actions-toolbar",filename:"actions-toolbar",url:"actions-toolbar.html"},{title:"Actions toolbar",filename:"actions-toolbar",url:"actions-toolbar.html#actions-toolbar"},{title:"Actions toolbar mixin variables",filename:"actions-toolbar",url:"actions-toolbar.html#actions-toolbar-mixin-variables"},{title:"Actions toolbar alignment",filename:"actions-toolbar",url:"actions-toolbar.html#actions-toolbar-alignment"},{title:"Reverse primary and secondary blocks",filename:"actions-toolbar",url:"actions-toolbar.html#reverse-primary-and-secondary-blocks"},{title:"Actions toolbar indents customizations",filename:"actions-toolbar",url:"actions-toolbar.html#actions-toolbar-indents-customizations"},{title:"Responsive actions toolbar",filename:"actions-toolbar",url:"actions-toolbar.html#responsive-actions-toolbar"},{title:"breadcrumbs",filename:"breadcrumbs",url:"breadcrumbs.html"},{title:"Breadcrumbs",filename:"breadcrumbs",url:"breadcrumbs.html#breadcrumbs"},{title:"Breadcrumbs variables",filename:"breadcrumbs",url:"breadcrumbs.html#breadcrumbs-variables"},{title:"Button-styled breadcrumbs with gradient background, border, and no separating symbol",filename:"breadcrumbs",url:"breadcrumbs.html#buttonstyled-breadcrumbs-with-gradient-background-border-and-no-separating-symbol"},{title:"Breadcrumbs with solid background",filename:"breadcrumbs",url:"breadcrumbs.html#breadcrumbs-with-solid-background"},{title:"buttons",filename:"buttons",url:"buttons.html"},{title:"Default button",filename:"buttons",url:"buttons.html#default-button"},{title:"Button variables",filename:"buttons",url:"buttons.html#button-variables"},{title:"Button as an icon",filename:"buttons",url:"buttons.html#button-as-an-icon"},{title:"Button with an icon on the left or right side of the text",filename:"buttons",url:"buttons.html#button-with-an-icon-on-the-left-or-right-side-of-the-text"},{title:"Button with fixed width",filename:"buttons",url:"buttons.html#button-with-fixed-width"},{title:"Primary button",filename:"buttons",url:"buttons.html#primary-button"},{title:"Primary button variables",filename:"buttons",url:"buttons.html#primary-button-variables"},{title:"Button with gradient background",filename:"buttons",url:"buttons.html#button-with-gradient-background"},{title:"Button as a link",filename:"buttons",url:"buttons.html#button-as-a-link"},{title:"Button as a link variables",filename:"buttons",url:"buttons.html#button-as-a-link-variables"},{title:"Link as a button",filename:"buttons",url:"buttons.html#link-as-a-button"},{title:"Button reset",filename:"buttons",url:"buttons.html#button-reset"},{title:"Button revert secondary color",filename:"buttons",url:"buttons.html#button-revert-secondary-color"},{title:"Button revert secondary color variables",filename:"buttons",url:"buttons.html#button-revert-secondary-color-variables"},{title:"Button revert secondary size",filename:"buttons",url:"buttons.html#button-revert-secondary-size"},{title:"Button revert secondary size variables",filename:"buttons",url:"buttons.html#button-revert-secondary-size-variables"},{title:"components",filename:"components",url:"components.html"},{title:"Components",filename:"components",url:"components.html#components"},{title:"Components Variables",filename:"components",url:"components.html#components-variables"},{title:"dropdowns",filename:"dropdowns",url:"dropdowns.html"},{title:"Drop-down and split buttons mixins",filename:"dropdowns",url:"dropdowns.html#dropdown-and-split-buttons-mixins"},{title:"Drop-down",filename:"dropdowns",url:"dropdowns.html#dropdown"},{title:"Drop-down variables",filename:"dropdowns",url:"dropdowns.html#dropdown-variables"},{title:"Drop-down with icon customization",filename:"dropdowns",url:"dropdowns.html#dropdown-with-icon-customization"},{title:"Modify dropdown list styles",filename:"dropdowns",url:"dropdowns.html#modify-dropdown-list-styles"},{title:"Split button",filename:"dropdowns",url:"dropdowns.html#split-button"},{title:"Split button variables",filename:"dropdowns",url:"dropdowns.html#split-button-variables"},{title:"Split button - button styling",filename:"dropdowns",url:"dropdowns.html#split-button-button-styling"},{title:"Split button icon customization",filename:"dropdowns",url:"dropdowns.html#split-button-icon-customization"},{title:"Split button drop-down list customization",filename:"dropdowns",url:"dropdowns.html#split-button-dropdown-list-customization"},{title:"forms",filename:"forms",url:"forms.html"},{title:"Forms mixins",filename:"forms",url:"forms.html#forms-mixins"},{title:"Global forms elements customization",filename:"forms",url:"forms.html#global-forms-elements-customization"},{title:"Fieldsets & fields customization",filename:"forms",url:"forms.html#fieldsets-fields-customization"},{title:"Fieldset and legend customization variables",filename:"forms",url:"forms.html#fieldset-and-legend-customization-variables"},{title:"Fields customization variables",filename:"forms",url:"forms.html#fields-customization-variables"},{title:"Required fields message customization variables",filename:"forms",url:"forms.html#required-fields-message-customization-variables"},{title:"Form element inputs customization",filename:"forms",url:"forms.html#form-element-inputs-customization"},{title:"Form element inputs customization variables",filename:"forms",url:"forms.html#form-element-inputs-customization-variables"},{title:"Form element choice",filename:"forms",url:"forms.html#form-element-choice"},{title:"Form element choice variables",filename:"forms",url:"forms.html#form-element-choice-variables"},{title:"Custom color",filename:"forms",url:"forms.html#custom-color"},{title:"Input number - input-text view",filename:"forms",url:"forms.html#input-number-inputtext-view"},{title:"Input search - input-text view",filename:"forms",url:"forms.html#input-search-inputtext-view"},{title:"Form validation",filename:"forms",url:"forms.html#form-validation"},{title:"Form validation variables",filename:"forms",url:"forms.html#form-validation-variables"},{title:"icons",filename:"icons",url:"icons.html"},{title:"Icons",filename:"icons",url:"icons.html#icons"},{title:"Icon with image or sprite",filename:"icons",url:"icons.html#icon-with-image-or-sprite"},{title:"Icon with image or sprite variables",filename:"icons",url:"icons.html#icon-with-image-or-sprite-variables"},{title:"Icon position for an icon with image or sprite",filename:"icons",url:"icons.html#icon-position-for-an-icon-with-image-or-sprite"},{title:"Position for icon with image or sprite mixin variables",filename:"icons",url:"icons.html#position-for-icon-with-image-or-sprite-mixin-variables"},{title:"Icon sprite position (with grid)",filename:"icons",url:"icons.html#icon-sprite-position-with-grid"},{title:"Icon sprite position variables",filename:"icons",url:"icons.html#icon-sprite-position-variables"},{title:"Image/sprite icon size",filename:"icons",url:"icons.html#imagesprite-icon-size"},{title:"Image/sprite icon size variables",filename:"icons",url:"icons.html#imagesprite-icon-size-variables"},{title:"Font icon",filename:"icons",url:"icons.html#font-icon"},{title:"Font icon variables",filename:"icons",url:"icons.html#font-icon-variables"},{title:"Change the size of font icon",filename:"icons",url:"icons.html#change-the-size-of-font-icon"},{title:"Change the size of font icon variables",filename:"icons",url:"icons.html#change-the-size-of-font-icon-variables"},{title:"Hide icon text",filename:"icons",url:"icons.html#hide-icon-text"},{title:"Sprite and font icons for Blank theme",filename:"icons",url:"icons.html#sprite-and-font-icons-for-blank-theme"},{title:"layout",filename:"layout",url:"layout.html"},{title:"Layout",filename:"layout",url:"layout.html#layout"},{title:"Layout global variables",filename:"layout",url:"layout.html#layout-global-variables"},{title:"Page layouts",filename:"layout",url:"layout.html#page-layouts"},{title:"Layout column",filename:"layout",url:"layout.html#layout-column"},{title:"Layout column variables",filename:"layout",url:"layout.html#layout-column-variables"},{title:"Layout width",filename:"layout",url:"layout.html#layout-width"},{title:"Layout width variables",filename:"layout",url:"layout.html#layout-width-variables"},{title:"lib",filename:"lib",url:"lib.html"},{title:"Including Magento UI library to your theme",filename:"lib",url:"lib.html#including-magento-ui-library-to-your-theme"},{title:"loaders",filename:"loaders",url:"loaders.html"},{title:"Loaders",filename:"loaders",url:"loaders.html#loaders"},{title:"Default loader variables",filename:"loaders",url:"loaders.html#default-loader-variables"},{title:"Loading",filename:"loaders",url:"loaders.html#loading"},{title:"Loading default variables",filename:"loaders",url:"loaders.html#loading-default-variables"},{title:"messages",filename:"messages",url:"messages.html"},{title:"Messages",filename:"messages",url:"messages.html#messages"},{title:"Information message",filename:"messages",url:"messages.html#information-message"},{title:"Warning message",filename:"messages",url:"messages.html#warning-message"},{title:"Error message",filename:"messages",url:"messages.html#error-message"},{title:"Success message",filename:"messages",url:"messages.html#success-message"},{title:"Notice message",filename:"messages",url:"messages.html#notice-message"},{title:"Message with inner icon",filename:"messages",url:"messages.html#message-with-inner-icon"},{title:"Message with lateral icon",filename:"messages",url:"messages.html#message-with-lateral-icon"},{title:"Custom message style",filename:"messages",url:"messages.html#custom-message-style"},{title:"Messages global variables",filename:"messages",url:"messages.html#messages-global-variables"},{title:"pages",filename:"pages",url:"pages.html"},{title:"Pagination HTML markup",filename:"pages",url:"pages.html#pagination-html-markup"},{title:"Pagination variables",filename:"pages",url:"pages.html#pagination-variables"},{title:"Pagination with label and gradient background on links",filename:"pages",url:"pages.html#pagination-with-label-and-gradient-background-on-links"},{title:'Pagination with "previous"..."next" text links and label',filename:"pages",url:"pages.html#pagination-with-previousnext-text-links-and-label"},{title:"Pagination without label, with solid background",filename:"pages",url:"pages.html#pagination-without-label-with-solid-background"},{title:"popups",filename:"popups",url:"popups.html"},{title:"Popups",filename:"popups",url:"popups.html#popups"},{title:"Popup variables",filename:"popups",url:"popups.html#popup-variables"},{title:"Window overlay mixin variables",filename:"popups",url:"popups.html#window-overlay-mixin-variables"},{title:"Fixed height popup",filename:"popups",url:"popups.html#fixed-height-popup"},{title:"Fixed content height popup",filename:"popups",url:"popups.html#fixed-content-height-popup"},{title:"Margins for header, content and footer block in popup",filename:"popups",url:"popups.html#margins-for-header-content-and-footer-block-in-popup"},{title:"Popup titles styled as theme headings",filename:"popups",url:"popups.html#popup-titles-styled-as-theme-headings"},{title:"Popup action toolbar",filename:"popups",url:"popups.html#popup-action-toolbar"},{title:"Popup Close button without an icon",filename:"popups",url:"popups.html#popup-close-button-without-an-icon"},{title:"Modify the icon of popup Close button",filename:"popups",url:"popups.html#modify-the-icon-of-popup-close-button"},{title:"Modify overlay styles",filename:"popups",url:"popups.html#modify-overlay-styles"},{title:"rating",filename:"rating",url:"rating.html"},{title:"Ratings",filename:"rating",url:"rating.html#ratings"},{title:"Global rating variables",filename:"rating",url:"rating.html#global-rating-variables"},{title:"Rating with vote",filename:"rating",url:"rating.html#rating-with-vote"},{title:"Rating with vote icons number customization",filename:"rating",url:"rating.html#rating-with-vote-icons-number-customization"},{title:"Rating with vote icons colors customization",filename:"rating",url:"rating.html#rating-with-vote-icons-colors-customization"},{title:"Rating with vote icons symbol customization",filename:"rating",url:"rating.html#rating-with-vote-icons-symbol-customization"},{title:"Accessible rating with vote",filename:"rating",url:"rating.html#accessible-rating-with-vote"},{title:"Rating summary",filename:"rating",url:"rating.html#rating-summary"},{title:"Rating summary icons number customization",filename:"rating",url:"rating.html#rating-summary-icons-number-customization"},{title:"Rating summary icons color customization",filename:"rating",url:"rating.html#rating-summary-icons-color-customization"},{title:"Rating summary icons symbol customization",filename:"rating",url:"rating.html#rating-summary-icons-symbol-customization"},{title:"Rating summary hide label",filename:"rating",url:"rating.html#rating-summary-hide-label"},{title:"Rating summary multiple ratings",filename:"rating",url:"rating.html#rating-summary-multiple-ratings"},{title:"Rating hide label mixin",filename:"rating",url:"rating.html#rating-hide-label-mixin"},{title:"resets",filename:"resets",url:"resets.html"},{title:"Resets",filename:"resets",url:"resets.html#resets"},{title:"responsive",filename:"responsive",url:"responsive.html"},{title:"Responsive",filename:"responsive",url:"responsive.html#responsive"},{title:"Responsive mixins usage",filename:"responsive",url:"responsive.html#responsive-mixins-usage"},{title:"Media query style groups separation variables",filename:"responsive",url:"responsive.html#media-query-style-groups-separation-variables"},{title:"Responsive breakpoints",filename:"responsive",url:"responsive.html#responsive-breakpoints"},{title:"sections",filename:"sections",url:"sections.html"},{title:"Tabs and accordions",filename:"sections",url:"sections.html#tabs-and-accordions"},{title:"Tabs",filename:"sections",url:"sections.html#tabs"},{title:"Tabs mixin variables",filename:"sections",url:"sections.html#tabs-mixin-variables"},{title:"Tabs with content top border",filename:"sections",url:"sections.html#tabs-with-content-top-border"},{title:"Accordion",filename:"sections",url:"sections.html#accordion"},{title:"Accordion mixin variables",filename:"sections",url:"sections.html#accordion-mixin-variables"},{title:"Responsive tabs",filename:"sections",url:"sections.html#responsive-tabs"},{title:"Tabs Base",filename:"sections",url:"sections.html#tabs-base"},{title:"Accordion Base",filename:"sections",url:"sections.html#accordion-base"},{title:"tables",filename:"tables",url:"tables.html"},{title:"Tables",filename:"tables",url:"tables.html#tables"},{title:"Table mixin variables",filename:"tables",url:"tables.html#table-mixin-variables"},{title:"Table typography",filename:"tables",url:"tables.html#table-typography"},{title:"Table typography mixin variables",filename:"tables",url:"tables.html#table-typography-mixin-variables"},{title:"Table caption",filename:"tables",url:"tables.html#table-caption"},{title:"Table caption mixin variables",filename:"tables",url:"tables.html#table-caption-mixin-variables"},{title:"Table cells resize",filename:"tables",url:"tables.html#table-cells-resize"},{title:"Table cells resize variables",filename:"tables",url:"tables.html#table-cells-resize-variables"},{title:"Table background customization",filename:"tables",url:"tables.html#table-background-customization"},{title:"Table background mixin variables",filename:"tables",url:"tables.html#table-background-mixin-variables"},{title:"Table borders customization",filename:"tables",url:"tables.html#table-borders-customization"},{title:"Table borders mixin variables",filename:"tables",url:"tables.html#table-borders-mixin-variables"},{title:"Table with horizontal borders",filename:"tables",url:"tables.html#table-with-horizontal-borders"},{title:"Table with vertical borders",filename:"tables",url:"tables.html#table-with-vertical-borders"},{title:"Table with light borders",filename:"tables",url:"tables.html#table-with-light-borders"},{title:"Table without borders",filename:"tables",url:"tables.html#table-without-borders"},{title:"Striped table",filename:"tables",url:"tables.html#striped-table"},{title:"Striped table mixin variables",filename:"tables",url:"tables.html#striped-table-mixin-variables"},{title:"Table with rows hover",filename:"tables",url:"tables.html#table-with-rows-hover"},{title:"Table with rows hover mixin variables",filename:"tables",url:"tables.html#table-with-rows-hover-mixin-variables"},{title:"Responsive table technics #1",filename:"tables",url:"tables.html#responsive-table-technics-1"},{title:"Responsive table technics #2",filename:"tables",url:"tables.html#responsive-table-technics-2"},{title:"Responsive table technics #2 mixin variables",filename:"tables",url:"tables.html#responsive-table-technics-2-mixin-variables"},{title:"tooltips",filename:"tooltips",url:"tooltips.html"},{title:"Tooltips",filename:"tooltips",url:"tooltips.html#tooltips"},{title:"Tooltips variables",filename:"tooltips",url:"tooltips.html#tooltips-variables"},{title:"typography",filename:"typography",url:"typography.html"},{title:"Typogrphy",filename:"typography",url:"typography.html#typogrphy"},{title:"Typography variables",filename:"typography",url:"typography.html#typography-variables"},{title:"Font-size mixin",filename:"typography",url:"typography.html#fontsize-mixin"},{title:"Line-height mixin",filename:"typography",url:"typography.html#lineheight-mixin"},{title:"Word breaking mixin",filename:"typography",url:"typography.html#word-breaking-mixin"},{title:"Font face mixin",filename:"typography",url:"typography.html#font-face-mixin"},{title:"Text overflow mixin",filename:"typography",url:"typography.html#text-overflow-mixin"},{title:"Text hide",filename:"typography",url:"typography.html#text-hide"},{title:"Hyphens",filename:"typography",url:"typography.html#hyphens"},{title:"Font style and color",filename:"typography",url:"typography.html#font-style-and-color"},{title:"Font style mixin variables",filename:"typography",url:"typography.html#font-style-mixin-variables"},{title:"Reset list styles",filename:"typography",url:"typography.html#reset-list-styles"},{title:"Reset list styles variables",filename:"typography",url:"typography.html#reset-list-styles-variables"},{title:"Inline-block list item styling",filename:"typography",url:"typography.html#inlineblock-list-item-styling"},{title:"Link styling mixin",filename:"typography",url:"typography.html#link-styling-mixin"},{title:"Link styling mixin variables",filename:"typography",url:"typography.html#link-styling-mixin-variables"},{title:"Heading styling mixin",filename:"typography",url:"typography.html#heading-styling-mixin"},{title:"Base typography mixins",filename:"typography",url:"typography.html#base-typography-mixins"},{title:"Base typography mixin variables",filename:"typography",url:"typography.html#base-typography-mixin-variables"},{title:"Headings typography mixin",filename:"typography",url:"typography.html#headings-typography-mixin"},{title:"Headings typography mixin variables",filename:"typography",url:"typography.html#headings-typography-mixin-variables"},{title:"Typography links mixin",filename:"typography",url:"typography.html#typography-links-mixin"},{title:"Typography lists mixin",filename:"typography",url:"typography.html#typography-lists-mixin"},{title:"Typography lists mixin variables",filename:"typography",url:"typography.html#typography-lists-mixin-variables"},{title:"Typography code elements mixin",filename:"typography",url:"typography.html#typography-code-elements-mixin"},{title:"Typography code mixin variables",filename:"typography",url:"typography.html#typography-code-mixin-variables"},{title:"Typography blockquote",filename:"typography",url:"typography.html#typography-blockquote"},{title:"Typography blockquote mixin variables",filename:"typography",url:"typography.html#typography-blockquote-mixin-variables"},{title:"utilities",filename:"utilities",url:"utilities.html"},{title:"Utilities",filename:"utilities",url:"utilities.html#utilities"},{title:".lib-clearfix()",filename:"utilities",url:"utilities.html#libclearfix"},{title:".lib-visibility-hidden()",filename:"utilities",url:"utilities.html#libvisibilityhidden"},{title:".lib-visually-hidden()",filename:"utilities",url:"utilities.html#libvisuallyhidden"},{title:".lib-visually-hidden-reset()",filename:"utilities",url:"utilities.html#libvisuallyhiddenreset"},{title:".lib-css()",filename:"utilities",url:"utilities.html#libcss"},{title:".lib-css() variables",filename:"utilities",url:"utilities.html#libcss-variables"},{title:".lib-rotate()",filename:"utilities",url:"utilities.html#librotate"},{title:".lib-rotate() variables",filename:"utilities",url:"utilities.html#librotate-variables"},{title:".lib-input-placeholder()",filename:"utilities",url:"utilities.html#libinputplaceholder"},{title:".lib-input-placeholder() variables",filename:"utilities",url:"utilities.html#libinputplaceholder-variables"},{title:".lib-background-gradient()",filename:"utilities",url:"utilities.html#libbackgroundgradient"},{title:".lib-background-gradient() variables",filename:"utilities",url:"utilities.html#libbackgroundgradient-variables"},{title:".lib-url-check()",filename:"utilities",url:"utilities.html#liburlcheck"},{title:".lib-url-check() variables",filename:"utilities",url:"utilities.html#liburlcheck-variables"},{title:"variables",filename:"variables",url:"variables.html"},{title:"List of Global Variables",filename:"variables",url:"variables.html#list-of-global-variables"},{title:"Table with rows hover mixin variables",filename:"variables",url:"variables.html#table-with-rows-hover-mixin-variables"},{title:"docs",filename:"docs",url:"docs.html"},{title:"Documentation",filename:"docs",url:"docs.html#documentation"}];(function(){"use strict";var b=function(a,b){return Array.prototype.indexOf.call(a,b)!==-1},c=function(a,b){return Array.prototype.filter.call(a,b)},d=function(a,b){return Array.prototype.forEach.call(a,b)},e=document.getElementsByTagName("body")[0];e.addEventListener("click",function(a){var b=a.target;b.tagName.toLowerCase()==="svg"&&(b=b.parentNode);var c=!1;b.dataset.toggle!=null&&(a.preventDefault(),b.classList.contains("is-active")||(c=!0)),d(e.querySelectorAll("[data-toggle]"),function(a){a.classList.remove("is-active"),document.getElementById(a.dataset.toggle).hidden=!0}),c&&(b.classList.add("is-active"),document.getElementById(b.dataset.toggle).hidden=!1)}),function(){var f=e.getElementsByClassName("nav")[0];if(!f)return;var g=document.createElement("ul");g.className="nav-results",g.id="nav-search",g.hidden=!0,d(a,function(a){var b,c,d;b=document.createElement("li"),b._title=a.title.toLowerCase(),b.hidden=!0,b.appendChild(c=document.createElement("a")),c.href=a.url,c.innerHTML=a.title,c.appendChild(d=document.createElement("span")),d.innerHTML=a.filename,d.className="nav-results-filename",g.appendChild(b)}),f.appendChild(g);var h=g.children,i=function(a){d(h,function(a){a.hidden=!0});var b=this.value.toLowerCase(),e=[];b!==""&&(e=c(h,function(a){return a._title.indexOf(b)!==-1})),e.length>0?(d(e,function(a){a.hidden=!1}),g.hidden=!1):g.hidden=!0},j=f.querySelector('input[type="search"]');j.addEventListener("keyup",i),j.addEventListener("focus",i),e.addEventListener("click",function(a){if(a.target.classList&&a.target.classList.contains("search"))return;g.hidden=!0}),g.addEventListener("click",function(a){j.value=""});var k=document.createElement("ul");k.id="nav-toc",k.hidden=!0,k.className="nav-results toc-list",c(e.getElementsByTagName("*"),function(a){return b(["h1","h2","h3"],a.tagName.toLowerCase())}).map(function(a){var b=document.createElement("li"),c=document.createElement("a"),d=a.tagName.toLowerCase()[1];c.classList.add("level-"+d),b.appendChild(c),c.href="#"+a.id,c.innerHTML=a.innerHTML,k.appendChild(b)}),f.appendChild(k)}()})(),function(){"use strict";if(location.hash==="#__preview__"||location.protocol==="data:")return;var a=function(a,b){return Array.prototype.forEach.call(a,b)},b=function(a,b){var e=Array.prototype.slice.call(arguments,2);return d(a,function(a){return(c(b)?b||a:a[b]).apply(a,e)})},c=function(a){return Object.prototype.toString.call(a)==="[object Function]"},d=function(a,b){return Array.prototype.map.call(a,b)},e=function(a,b){return d(a,function(a){return a[b]})},f=function(a){var b={},c=a.split(";");for(var d=0;c.length>d;d++){var e=c[d].trim().split("=");b[e[0]]=e[1]}return b},g=function(a,c){return b(e(a,"classList"),"remove",c)},h=function(a,b){a.contentDocument.defaultView.postMessage(b,"*")},i=document.getElementsByTagName("head")[0],j=document.getElementsByTagName("body")[0],k=e(i.querySelectorAll('style[type="text/preview"]'),"innerHTML").join(""),l=e(i.querySelectorAll('script[type="text/preview"]'),"innerHTML").join(""),m=location.href.split("#")[0]+"#__preview__",n=document.createElement("iframe");n.src="data:text/html,",j.appendChild(n),n.addEventListener("load",function(){var b={sameOriginDataUri:!0};try{this.contentDocument,this.contentDocument||(b.sameOriginDataUri=!1)}catch(c){b.sameOriginDataUri=!1}this.parentNode.removeChild(this),a(j.getElementsByTagName("textarea"),function(a,c){o(a,b,c),q(),p(a)})});var o=function(a,b,c){var d,e,f;d=document.createElement("div"),d.appendChild(e=document.createElement("div")),d.className="preview",e.appendChild(f=document.createElement("iframe")),e.className="resizeable",f.setAttribute("scrolling","no"),f.name="iframe"+c++,f.addEventListener("load",function(){var c,d,e,f,g,i,j;j=this.contentDocument;if(!b.sameOriginDataUri&&this.src!==m)return;this.src===m&&(c=j.createElement("html"),c.appendChild(j.createElement("head")),c.appendChild(d=j.createElement("body")),d.innerHTML=a.textContent,j.replaceChild(c,j.documentElement)),g=j.createElement("head"),g.appendChild(f=j.createElement("style")),g.appendChild(e=j.createElement("script")),e.textContent=l,f.textContent=k,i=j.getElementsByTagName("head")[0],i.parentNode.replaceChild(g,i),h(this,"getHeight")});var g;b.sameOriginDataUri?g="data:text/html;charset=utf-8,"+encodeURIComponent("<!doctype html><html><head></head></body>"+a.textContent):g=m,f.setAttribute("src",g);var i=function(){f.contentDocument.body.innerHTML=this.value,h(f,"getHeight")};a.addEventListener("keypress",i),a.addEventListener("keyup",i),a.parentNode.insertBefore(d,a)},p=function(a){var b=document.createElement("div");b.className="preview-code",b.style.position="absolute",b.style.left="-9999px",j.appendChild(b);var c=parseInt(window.getComputedStyle(a).getPropertyValue("max-height"),10),d=function(a){b.textContent=this.value+"\n";var d=b.offsetHeight+2;d>=c?this.style.overflow="auto":this.style.overflow="hidden",this.style.height=b.offsetHeight+2+"px"};a.addEventListener("keypress",d),a.addEventListener("keyup",d),d.call(a)},q=function(){var b=j.getElementsByClassName("settings")[0],c=j.getElementsByClassName("resizeable"),d=30,e=function(b){document.cookie="preview-width="+b,a(c,function(a){b==="auto"&&(b=a.parentNode.offsetWidth),a.style.width=b+"px",h(a.getElementsByTagName("iframe")[0],"getHeight")})},i=f(document.cookie)["preview-width"];if(i){e(i),g(b.getElementsByClassName("is-active"),"is-active");var k=b.querySelector('button[data-width="'+i+'"]');k&&k.classList.add("is-active")}window.addEventListener("message",function(a){if(a.data==null||!a.source)return;var b=a.data,c=document.getElementsByName(a.source.name)[0];b.height!=null&&c&&(c.parentNode.style.height=b.height+d+"px")},!1),b&&c.length>0&&(b.hidden=!1,b.addEventListener("click",function(a){var c=a.target.tagName.toLowerCase(),d;if(c==="button")d=a.target;else{if(c!=="svg")return;d=a.target.parentNode}a.preventDefault(),g(b.getElementsByClassName("is-active"),"is-active"),d.classList.add("is-active");var f=d.dataset.width;e(f)}))}}()})()</script></body></html><!-- Generated with StyleDocco (http://jacobrask.github.com/styledocco). --> +</div></article></section><div class="bar bottom"><div hidden class="settings container"><!-- Icons from http://iconmonstr.com--><button title="Desktop (1280)" data-width='1280'><svg viewBox="0 0 412 386" height="24" width="26" class="icon"><path d="m147.6,343.9c-4.5,15.9-26.2,37.6-42.1,42.1h201c-15.3,-4-38.1,-26.8-42.1,-42.1H147.6zM387,0.5H25c-13.8,0-25,11.2-25,25V294c0,13.8 11.2,25 25,25h362c13.8,0 25,-11.2 25,-25V25.5C412,11.7 400.8,0.5 387,0.5zM369.9,238.2H42.1L42.1,42.6 369.9,42.6V238.2z"></path></svg></button><button title="Laptop (1024)" data-width='1024'><svg viewBox="0 0 384 312" height="23" width="28" class="icon"><path d="m349.2,20.5c0,-11-9,-20-20,-20H53.6c-11,0-20,9-20,20v194H349.2v-194zm-27,167H60.6V27.5H322.2v160zm28,42H32.6L2.6,282.1c-3.5,6.2-3.5,13.8 0.1,19.9 3.6,6.2 10.2,9.9 17.3,9.9H363.1c7.1,0 13.7,-3.8 17.3,-10 3.6,-6.2 3.6,-13.8 0,-20l-30.2,-52.5zm-196.9,54 8,-23.5h60.5l8,23.5h-76.5z"></path></svg></button><button title="Tablet (768)" data-width='768'><svg viewBox="0 0 317 412" height="24" width="18" class="icon"><path d="M 316.5,380 V 32 c 0,-17.7 -14.3,-32 -32,-32 H 32 C 14.3,0 0,14.3 0,32 v 348 c 0,17.7 14.3,32 32,32 h 252.5 c 17.7,0 32,-14.3 32,-32 z M 40,367 V 45 H 276.5 V 367 H 40 z m 109.8,22.7 c 0,-4.7 3.8,-8.5 8.5,-8.5 4.7,0 8.5,3.8 8.5,8.5 0,4.7 -3.8,8.5 -8.5,8.5 -4.7,0 -8.5,-3.8 -8.5,-8.5 z"></path></svg></button><button title="Smart phone (320)" data-width='320'><svg viewBox="0 0 224 412" height="24" width="13" class="icon"><path d="M 190.7,0 H 33 C 14.8,0 0,14.8 0,33 v 346 c 0,18.2 14.8,33 33,33 h 157.7 c 18.2,0 33,-14.8 33,-33 V 33 c 0,-18.2 -14.8,-33 -33,-33 z M 94.3,30.2 h 37 c 2.2,0 4,1.8 4,4 0,2.2 -1.8,4 -4,4 h -37 c -2.2,0 -4,-1.8 -4,-4 0,-2.2 1.8,-4 4,-4 z m 18.5,362.8 c -8.8,0 -16,-7.2 -16,-16 0,-8.8 7.2,-16 16,-16 8.8,0 16,7.2 16,16 0,8.8 -7.2,16 -16,16 z M 198.6,343.8 H 25.1 V 68.2 h 173.5 v 275.5 z"></path></svg></button><button title="Feature phone (240)" data-width='240'><svg viewBox="0 0 201 412" height="24" width="12" class="icon"><path d="M 165.5,0.2 V 45 H 25 c -13.8,0 -25,11.2 -25,25 V 387 c 0,13.8 11.2,25 25,25 h 150.5 c 13.8,0 25,-11.2 25,-25 V 0.2 h -35 z M 65.2,366.5 H 34.2 v -24.5 h 31 v 24.5 z m 0,-44.3 H 34.2 v -24.5 h 31 v 24.5 z m 50.5,44.3 H 84.7 v -24.5 h 31 v 24.5 z m 0,-44.3 H 84.7 v -24.5 h 31 v 24.5 z m 50.5,44.3 h -31 v -24.5 h 31 v 24.5 z m 0,-44.3 h -31 v -24.5 h 31 v 24.5 z m 0,-59.3 h -132 V 95.4 h 132 V 262.9 z"></path></svg></button><button title="Auto (100%)" data-width="auto" class="auto is-active">Auto</button></div></div><script>(function(){var a=[{title:"actions-toolbar",filename:"actions-toolbar",url:"actions-toolbar.html"},{title:"Actions toolbar",filename:"actions-toolbar",url:"actions-toolbar.html#actions-toolbar"},{title:"Actions toolbar mixin variables",filename:"actions-toolbar",url:"actions-toolbar.html#actions-toolbar-mixin-variables"},{title:"Actions toolbar alignment",filename:"actions-toolbar",url:"actions-toolbar.html#actions-toolbar-alignment"},{title:"Reverse primary and secondary blocks",filename:"actions-toolbar",url:"actions-toolbar.html#reverse-primary-and-secondary-blocks"},{title:"Actions toolbar indents customizations",filename:"actions-toolbar",url:"actions-toolbar.html#actions-toolbar-indents-customizations"},{title:"Responsive actions toolbar",filename:"actions-toolbar",url:"actions-toolbar.html#responsive-actions-toolbar"},{title:"breadcrumbs",filename:"breadcrumbs",url:"breadcrumbs.html"},{title:"Breadcrumbs",filename:"breadcrumbs",url:"breadcrumbs.html#breadcrumbs"},{title:"Breadcrumbs variables",filename:"breadcrumbs",url:"breadcrumbs.html#breadcrumbs-variables"},{title:"Button-styled breadcrumbs with gradient background, border, and no separating symbol",filename:"breadcrumbs",url:"breadcrumbs.html#buttonstyled-breadcrumbs-with-gradient-background-border-and-no-separating-symbol"},{title:"Breadcrumbs with solid background",filename:"breadcrumbs",url:"breadcrumbs.html#breadcrumbs-with-solid-background"},{title:"buttons",filename:"buttons",url:"buttons.html"},{title:"Default button",filename:"buttons",url:"buttons.html#default-button"},{title:"Button variables",filename:"buttons",url:"buttons.html#button-variables"},{title:"Button as an icon",filename:"buttons",url:"buttons.html#button-as-an-icon"},{title:"Button with an icon on the left or right side of the text",filename:"buttons",url:"buttons.html#button-with-an-icon-on-the-left-or-right-side-of-the-text"},{title:"Button with fixed width",filename:"buttons",url:"buttons.html#button-with-fixed-width"},{title:"Primary button",filename:"buttons",url:"buttons.html#primary-button"},{title:"Primary button variables",filename:"buttons",url:"buttons.html#primary-button-variables"},{title:"Button with gradient background",filename:"buttons",url:"buttons.html#button-with-gradient-background"},{title:"Button as a link",filename:"buttons",url:"buttons.html#button-as-a-link"},{title:"Button as a link variables",filename:"buttons",url:"buttons.html#button-as-a-link-variables"},{title:"Link as a button",filename:"buttons",url:"buttons.html#link-as-a-button"},{title:"Button reset",filename:"buttons",url:"buttons.html#button-reset"},{title:"Button revert secondary color",filename:"buttons",url:"buttons.html#button-revert-secondary-color"},{title:"Button revert secondary color variables",filename:"buttons",url:"buttons.html#button-revert-secondary-color-variables"},{title:"Button revert secondary size",filename:"buttons",url:"buttons.html#button-revert-secondary-size"},{title:"Button revert secondary size variables",filename:"buttons",url:"buttons.html#button-revert-secondary-size-variables"},{title:"components",filename:"components",url:"components.html"},{title:"Components",filename:"components",url:"components.html#components"},{title:"Components Variables",filename:"components",url:"components.html#components-variables"},{title:"dropdowns",filename:"dropdowns",url:"dropdowns.html"},{title:"Drop-down and split buttons mixins",filename:"dropdowns",url:"dropdowns.html#dropdown-and-split-buttons-mixins"},{title:"Drop-down",filename:"dropdowns",url:"dropdowns.html#dropdown"},{title:"Drop-down variables",filename:"dropdowns",url:"dropdowns.html#dropdown-variables"},{title:"Drop-down with icon customization",filename:"dropdowns",url:"dropdowns.html#dropdown-with-icon-customization"},{title:"Modify dropdown list styles",filename:"dropdowns",url:"dropdowns.html#modify-dropdown-list-styles"},{title:"Split button",filename:"dropdowns",url:"dropdowns.html#split-button"},{title:"Split button variables",filename:"dropdowns",url:"dropdowns.html#split-button-variables"},{title:"Split button - button styling",filename:"dropdowns",url:"dropdowns.html#split-button-button-styling"},{title:"Split button icon customization",filename:"dropdowns",url:"dropdowns.html#split-button-icon-customization"},{title:"Split button drop-down list customization",filename:"dropdowns",url:"dropdowns.html#split-button-dropdown-list-customization"},{title:"forms",filename:"forms",url:"forms.html"},{title:"Forms mixins",filename:"forms",url:"forms.html#forms-mixins"},{title:"Global forms elements customization",filename:"forms",url:"forms.html#global-forms-elements-customization"},{title:"Fieldsets & fields customization",filename:"forms",url:"forms.html#fieldsets-fields-customization"},{title:"Fieldset and legend customization variables",filename:"forms",url:"forms.html#fieldset-and-legend-customization-variables"},{title:"Fields customization variables",filename:"forms",url:"forms.html#fields-customization-variables"},{title:"Required fields message customization variables",filename:"forms",url:"forms.html#required-fields-message-customization-variables"},{title:"Form element inputs customization",filename:"forms",url:"forms.html#form-element-inputs-customization"},{title:"Form element inputs customization variables",filename:"forms",url:"forms.html#form-element-inputs-customization-variables"},{title:"Form element choice",filename:"forms",url:"forms.html#form-element-choice"},{title:"Form element choice variables",filename:"forms",url:"forms.html#form-element-choice-variables"},{title:"Custom color",filename:"forms",url:"forms.html#custom-color"},{title:"Input number - input-text view",filename:"forms",url:"forms.html#input-number-inputtext-view"},{title:"Input search - input-text view",filename:"forms",url:"forms.html#input-search-inputtext-view"},{title:"Form validation",filename:"forms",url:"forms.html#form-validation"},{title:"Form validation variables",filename:"forms",url:"forms.html#form-validation-variables"},{title:"icons",filename:"icons",url:"icons.html"},{title:"Icons",filename:"icons",url:"icons.html#icons"},{title:"Icon with image or sprite",filename:"icons",url:"icons.html#icon-with-image-or-sprite"},{title:"Icon with image or sprite variables",filename:"icons",url:"icons.html#icon-with-image-or-sprite-variables"},{title:"Icon position for an icon with image or sprite",filename:"icons",url:"icons.html#icon-position-for-an-icon-with-image-or-sprite"},{title:"Position for icon with image or sprite mixin variables",filename:"icons",url:"icons.html#position-for-icon-with-image-or-sprite-mixin-variables"},{title:"Icon sprite position (with grid)",filename:"icons",url:"icons.html#icon-sprite-position-with-grid"},{title:"Icon sprite position variables",filename:"icons",url:"icons.html#icon-sprite-position-variables"},{title:"Image/sprite icon size",filename:"icons",url:"icons.html#imagesprite-icon-size"},{title:"Image/sprite icon size variables",filename:"icons",url:"icons.html#imagesprite-icon-size-variables"},{title:"Font icon",filename:"icons",url:"icons.html#font-icon"},{title:"Font icon variables",filename:"icons",url:"icons.html#font-icon-variables"},{title:"Change the size of font icon",filename:"icons",url:"icons.html#change-the-size-of-font-icon"},{title:"Change the size of font icon variables",filename:"icons",url:"icons.html#change-the-size-of-font-icon-variables"},{title:"Hide icon text",filename:"icons",url:"icons.html#hide-icon-text"},{title:"Sprite and font icons for Blank theme",filename:"icons",url:"icons.html#sprite-and-font-icons-for-blank-theme"},{title:"layout",filename:"layout",url:"layout.html"},{title:"Layout",filename:"layout",url:"layout.html#layout"},{title:"Layout global variables",filename:"layout",url:"layout.html#layout-global-variables"},{title:"Page layouts",filename:"layout",url:"layout.html#page-layouts"},{title:"Layout column",filename:"layout",url:"layout.html#layout-column"},{title:"Layout column variables",filename:"layout",url:"layout.html#layout-column-variables"},{title:"Layout width",filename:"layout",url:"layout.html#layout-width"},{title:"Layout width variables",filename:"layout",url:"layout.html#layout-width-variables"},{title:"lib",filename:"lib",url:"lib.html"},{title:"Including Magento UI library to your theme",filename:"lib",url:"lib.html#including-magento-ui-library-to-your-theme"},{title:"loaders",filename:"loaders",url:"loaders.html"},{title:"Loaders",filename:"loaders",url:"loaders.html#loaders"},{title:"Default loader variables",filename:"loaders",url:"loaders.html#default-loader-variables"},{title:"Loading",filename:"loaders",url:"loaders.html#loading"},{title:"Loading default variables",filename:"loaders",url:"loaders.html#loading-default-variables"},{title:"messages",filename:"messages",url:"messages.html"},{title:"Messages",filename:"messages",url:"messages.html#messages"},{title:"Information message",filename:"messages",url:"messages.html#information-message"},{title:"Warning message",filename:"messages",url:"messages.html#warning-message"},{title:"Error message",filename:"messages",url:"messages.html#error-message"},{title:"Success message",filename:"messages",url:"messages.html#success-message"},{title:"Notice message",filename:"messages",url:"messages.html#notice-message"},{title:"Message with inner icon",filename:"messages",url:"messages.html#message-with-inner-icon"},{title:"Message with lateral icon",filename:"messages",url:"messages.html#message-with-lateral-icon"},{title:"Custom message style",filename:"messages",url:"messages.html#custom-message-style"},{title:"Messages global variables",filename:"messages",url:"messages.html#messages-global-variables"},{title:"pages",filename:"pages",url:"pages.html"},{title:"Pagination HTML markup",filename:"pages",url:"pages.html#pagination-html-markup"},{title:"Pagination variables",filename:"pages",url:"pages.html#pagination-variables"},{title:"Pagination with label and gradient background on links",filename:"pages",url:"pages.html#pagination-with-label-and-gradient-background-on-links"},{title:'Pagination with "previous"..."next" text links and label',filename:"pages",url:"pages.html#pagination-with-previousnext-text-links-and-label"},{title:"Pagination without label, with solid background",filename:"pages",url:"pages.html#pagination-without-label-with-solid-background"},{title:"popups",filename:"popups",url:"popups.html"},{title:"Popups",filename:"popups",url:"popups.html#popups"},{title:"Popup variables",filename:"popups",url:"popups.html#popup-variables"},{title:"Window overlay mixin variables",filename:"popups",url:"popups.html#window-overlay-mixin-variables"},{title:"Fixed height popup",filename:"popups",url:"popups.html#fixed-height-popup"},{title:"Fixed content height popup",filename:"popups",url:"popups.html#fixed-content-height-popup"},{title:"Margins for header, content and footer block in popup",filename:"popups",url:"popups.html#margins-for-header-content-and-footer-block-in-popup"},{title:"Popup titles styled as theme headings",filename:"popups",url:"popups.html#popup-titles-styled-as-theme-headings"},{title:"Popup action toolbar",filename:"popups",url:"popups.html#popup-action-toolbar"},{title:"Popup Close button without an icon",filename:"popups",url:"popups.html#popup-close-button-without-an-icon"},{title:"Modify the icon of popup Close button",filename:"popups",url:"popups.html#modify-the-icon-of-popup-close-button"},{title:"Modify overlay styles",filename:"popups",url:"popups.html#modify-overlay-styles"},{title:"rating",filename:"rating",url:"rating.html"},{title:"Ratings",filename:"rating",url:"rating.html#ratings"},{title:"Global rating variables",filename:"rating",url:"rating.html#global-rating-variables"},{title:"Rating with vote",filename:"rating",url:"rating.html#rating-with-vote"},{title:"Rating with vote icons number customization",filename:"rating",url:"rating.html#rating-with-vote-icons-number-customization"},{title:"Rating with vote icons colors customization",filename:"rating",url:"rating.html#rating-with-vote-icons-colors-customization"},{title:"Rating with vote icons symbol customization",filename:"rating",url:"rating.html#rating-with-vote-icons-symbol-customization"},{title:"Accessible rating with vote",filename:"rating",url:"rating.html#accessible-rating-with-vote"},{title:"Rating summary",filename:"rating",url:"rating.html#rating-summary"},{title:"Rating summary icons number customization",filename:"rating",url:"rating.html#rating-summary-icons-number-customization"},{title:"Rating summary icons color customization",filename:"rating",url:"rating.html#rating-summary-icons-color-customization"},{title:"Rating summary icons symbol customization",filename:"rating",url:"rating.html#rating-summary-icons-symbol-customization"},{title:"Rating summary hide label",filename:"rating",url:"rating.html#rating-summary-hide-label"},{title:"Rating summary multiple ratings",filename:"rating",url:"rating.html#rating-summary-multiple-ratings"},{title:"Rating hide label mixin",filename:"rating",url:"rating.html#rating-hide-label-mixin"},{title:"resets",filename:"resets",url:"resets.html"},{title:"Resets",filename:"resets",url:"resets.html#resets"},{title:"responsive",filename:"responsive",url:"responsive.html"},{title:"Responsive",filename:"responsive",url:"responsive.html#responsive"},{title:"Responsive mixins usage",filename:"responsive",url:"responsive.html#responsive-mixins-usage"},{title:"Media query style groups separation variables",filename:"responsive",url:"responsive.html#media-query-style-groups-separation-variables"},{title:"Responsive breakpoints",filename:"responsive",url:"responsive.html#responsive-breakpoints"},{title:"sections",filename:"sections",url:"sections.html"},{title:"Tabs and accordions",filename:"sections",url:"sections.html#tabs-and-accordions"},{title:"Tabs",filename:"sections",url:"sections.html#tabs"},{title:"Tabs mixin variables",filename:"sections",url:"sections.html#tabs-mixin-variables"},{title:"Tabs with content top border",filename:"sections",url:"sections.html#tabs-with-content-top-border"},{title:"Accordion",filename:"sections",url:"sections.html#accordion"},{title:"Accordion mixin variables",filename:"sections",url:"sections.html#accordion-mixin-variables"},{title:"Responsive tabs",filename:"sections",url:"sections.html#responsive-tabs"},{title:"Tabs Base",filename:"sections",url:"sections.html#tabs-base"},{title:"Accordion Base",filename:"sections",url:"sections.html#accordion-base"},{title:"tables",filename:"tables",url:"tables.html"},{title:"Tables",filename:"tables",url:"tables.html#tables"},{title:"Table mixin variables",filename:"tables",url:"tables.html#table-mixin-variables"},{title:"Table typography",filename:"tables",url:"tables.html#table-typography"},{title:"Table typography mixin variables",filename:"tables",url:"tables.html#table-typography-mixin-variables"},{title:"Table caption",filename:"tables",url:"tables.html#table-caption"},{title:"Table caption mixin variables",filename:"tables",url:"tables.html#table-caption-mixin-variables"},{title:"Table cells resize",filename:"tables",url:"tables.html#table-cells-resize"},{title:"Table cells resize variables",filename:"tables",url:"tables.html#table-cells-resize-variables"},{title:"Table background customization",filename:"tables",url:"tables.html#table-background-customization"},{title:"Table background mixin variables",filename:"tables",url:"tables.html#table-background-mixin-variables"},{title:"Table borders customization",filename:"tables",url:"tables.html#table-borders-customization"},{title:"Table borders mixin variables",filename:"tables",url:"tables.html#table-borders-mixin-variables"},{title:"Table with horizontal borders",filename:"tables",url:"tables.html#table-with-horizontal-borders"},{title:"Table with vertical borders",filename:"tables",url:"tables.html#table-with-vertical-borders"},{title:"Table with light borders",filename:"tables",url:"tables.html#table-with-light-borders"},{title:"Table without borders",filename:"tables",url:"tables.html#table-without-borders"},{title:"Striped table",filename:"tables",url:"tables.html#striped-table"},{title:"Striped table mixin variables",filename:"tables",url:"tables.html#striped-table-mixin-variables"},{title:"Table with rows hover",filename:"tables",url:"tables.html#table-with-rows-hover"},{title:"Table with rows hover mixin variables",filename:"tables",url:"tables.html#table-with-rows-hover-mixin-variables"},{title:"Responsive table technics #1",filename:"tables",url:"tables.html#responsive-table-technics-1"},{title:"Responsive table technics #2",filename:"tables",url:"tables.html#responsive-table-technics-2"},{title:"Responsive table technics #2 mixin variables",filename:"tables",url:"tables.html#responsive-table-technics-2-mixin-variables"},{title:"tooltips",filename:"tooltips",url:"tooltips.html"},{title:"Tooltips",filename:"tooltips",url:"tooltips.html#tooltips"},{title:"Tooltips variables",filename:"tooltips",url:"tooltips.html#tooltips-variables"},{title:"typography",filename:"typography",url:"typography.html"},{title:"Typogrphy",filename:"typography",url:"typography.html#typogrphy"},{title:"Typography variables",filename:"typography",url:"typography.html#typography-variables"},{title:"Font-size mixin",filename:"typography",url:"typography.html#fontsize-mixin"},{title:"Line-height mixin",filename:"typography",url:"typography.html#lineheight-mixin"},{title:"Word breaking mixin",filename:"typography",url:"typography.html#word-breaking-mixin"},{title:"Font face mixin",filename:"typography",url:"typography.html#font-face-mixin"},{title:"Text overflow mixin",filename:"typography",url:"typography.html#text-overflow-mixin"},{title:"Text hide",filename:"typography",url:"typography.html#text-hide"},{title:"Hyphens",filename:"typography",url:"typography.html#hyphens"},{title:"Font style and color",filename:"typography",url:"typography.html#font-style-and-color"},{title:"Font style mixin variables",filename:"typography",url:"typography.html#font-style-mixin-variables"},{title:"Reset list styles",filename:"typography",url:"typography.html#reset-list-styles"},{title:"Reset list styles variables",filename:"typography",url:"typography.html#reset-list-styles-variables"},{title:"Inline-block list item styling",filename:"typography",url:"typography.html#inlineblock-list-item-styling"},{title:"Link styling mixin",filename:"typography",url:"typography.html#link-styling-mixin"},{title:"Link styling mixin variables",filename:"typography",url:"typography.html#link-styling-mixin-variables"},{title:"Heading styling mixin",filename:"typography",url:"typography.html#heading-styling-mixin"},{title:"Base typography mixins",filename:"typography",url:"typography.html#base-typography-mixins"},{title:"Base typography mixin variables",filename:"typography",url:"typography.html#base-typography-mixin-variables"},{title:"Headings typography mixin",filename:"typography",url:"typography.html#headings-typography-mixin"},{title:"Headings typography mixin variables",filename:"typography",url:"typography.html#headings-typography-mixin-variables"},{title:"Typography links mixin",filename:"typography",url:"typography.html#typography-links-mixin"},{title:"Typography lists mixin",filename:"typography",url:"typography.html#typography-lists-mixin"},{title:"Typography lists mixin variables",filename:"typography",url:"typography.html#typography-lists-mixin-variables"},{title:"Typography code elements mixin",filename:"typography",url:"typography.html#typography-code-elements-mixin"},{title:"Typography code mixin variables",filename:"typography",url:"typography.html#typography-code-mixin-variables"},{title:"Typography blockquote",filename:"typography",url:"typography.html#typography-blockquote"},{title:"Typography blockquote mixin variables",filename:"typography",url:"typography.html#typography-blockquote-mixin-variables"},{title:"utilities",filename:"utilities",url:"utilities.html"},{title:"Utilities",filename:"utilities",url:"utilities.html#utilities"},{title:".lib-clearfix()",filename:"utilities",url:"utilities.html#libclearfix"},{title:".lib-visibility-hidden()",filename:"utilities",url:"utilities.html#libvisibilityhidden"},{title:".lib-visually-hidden()",filename:"utilities",url:"utilities.html#libvisuallyhidden"},{title:".lib-visually-hidden-reset()",filename:"utilities",url:"utilities.html#libvisuallyhiddenreset"},{title:".lib-css()",filename:"utilities",url:"utilities.html#libcss"},{title:".lib-css() variables",filename:"utilities",url:"utilities.html#libcss-variables"},{title:".lib-rotate()",filename:"utilities",url:"utilities.html#librotate"},{title:".lib-rotate() variables",filename:"utilities",url:"utilities.html#librotate-variables"},{title:".lib-input-placeholder()",filename:"utilities",url:"utilities.html#libinputplaceholder"},{title:".lib-input-placeholder() variables",filename:"utilities",url:"utilities.html#libinputplaceholder-variables"},{title:".lib-background-gradient()",filename:"utilities",url:"utilities.html#libbackgroundgradient"},{title:".lib-background-gradient() variables",filename:"utilities",url:"utilities.html#libbackgroundgradient-variables"},{title:"variables",filename:"variables",url:"variables.html"},{title:"List of Global Variables",filename:"variables",url:"variables.html#list-of-global-variables"},{title:"Table with rows hover mixin variables",filename:"variables",url:"variables.html#table-with-rows-hover-mixin-variables"},{title:"docs",filename:"docs",url:"docs.html"},{title:"Documentation",filename:"docs",url:"docs.html#documentation"}];(function(){"use strict";var b=function(a,b){return Array.prototype.indexOf.call(a,b)!==-1},c=function(a,b){return Array.prototype.filter.call(a,b)},d=function(a,b){return Array.prototype.forEach.call(a,b)},e=document.getElementsByTagName("body")[0];e.addEventListener("click",function(a){var b=a.target;b.tagName.toLowerCase()==="svg"&&(b=b.parentNode);var c=!1;b.dataset.toggle!=null&&(a.preventDefault(),b.classList.contains("is-active")||(c=!0)),d(e.querySelectorAll("[data-toggle]"),function(a){a.classList.remove("is-active"),document.getElementById(a.dataset.toggle).hidden=!0}),c&&(b.classList.add("is-active"),document.getElementById(b.dataset.toggle).hidden=!1)}),function(){var f=e.getElementsByClassName("nav")[0];if(!f)return;var g=document.createElement("ul");g.className="nav-results",g.id="nav-search",g.hidden=!0,d(a,function(a){var b,c,d;b=document.createElement("li"),b._title=a.title.toLowerCase(),b.hidden=!0,b.appendChild(c=document.createElement("a")),c.href=a.url,c.innerHTML=a.title,c.appendChild(d=document.createElement("span")),d.innerHTML=a.filename,d.className="nav-results-filename",g.appendChild(b)}),f.appendChild(g);var h=g.children,i=function(a){d(h,function(a){a.hidden=!0});var b=this.value.toLowerCase(),e=[];b!==""&&(e=c(h,function(a){return a._title.indexOf(b)!==-1})),e.length>0?(d(e,function(a){a.hidden=!1}),g.hidden=!1):g.hidden=!0},j=f.querySelector('input[type="search"]');j.addEventListener("keyup",i),j.addEventListener("focus",i),e.addEventListener("click",function(a){if(a.target.classList&&a.target.classList.contains("search"))return;g.hidden=!0}),g.addEventListener("click",function(a){j.value=""});var k=document.createElement("ul");k.id="nav-toc",k.hidden=!0,k.className="nav-results toc-list",c(e.getElementsByTagName("*"),function(a){return b(["h1","h2","h3"],a.tagName.toLowerCase())}).map(function(a){var b=document.createElement("li"),c=document.createElement("a"),d=a.tagName.toLowerCase()[1];c.classList.add("level-"+d),b.appendChild(c),c.href="#"+a.id,c.innerHTML=a.innerHTML,k.appendChild(b)}),f.appendChild(k)}()})(),function(){"use strict";if(location.hash==="#__preview__"||location.protocol==="data:")return;var a=function(a,b){return Array.prototype.forEach.call(a,b)},b=function(a,b){var e=Array.prototype.slice.call(arguments,2);return d(a,function(a){return(c(b)?b||a:a[b]).apply(a,e)})},c=function(a){return Object.prototype.toString.call(a)==="[object Function]"},d=function(a,b){return Array.prototype.map.call(a,b)},e=function(a,b){return d(a,function(a){return a[b]})},f=function(a){var b={},c=a.split(";");for(var d=0;c.length>d;d++){var e=c[d].trim().split("=");b[e[0]]=e[1]}return b},g=function(a,c){return b(e(a,"classList"),"remove",c)},h=function(a,b){a.contentDocument.defaultView.postMessage(b,"*")},i=document.getElementsByTagName("head")[0],j=document.getElementsByTagName("body")[0],k=e(i.querySelectorAll('style[type="text/preview"]'),"innerHTML").join(""),l=e(i.querySelectorAll('script[type="text/preview"]'),"innerHTML").join(""),m=location.href.split("#")[0]+"#__preview__",n=document.createElement("iframe");n.src="data:text/html,",j.appendChild(n),n.addEventListener("load",function(){var b={sameOriginDataUri:!0};try{this.contentDocument,this.contentDocument||(b.sameOriginDataUri=!1)}catch(c){b.sameOriginDataUri=!1}this.parentNode.removeChild(this),a(j.getElementsByTagName("textarea"),function(a,c){o(a,b,c),q(),p(a)})});var o=function(a,b,c){var d,e,f;d=document.createElement("div"),d.appendChild(e=document.createElement("div")),d.className="preview",e.appendChild(f=document.createElement("iframe")),e.className="resizeable",f.setAttribute("scrolling","no"),f.name="iframe"+c++,f.addEventListener("load",function(){var c,d,e,f,g,i,j;j=this.contentDocument;if(!b.sameOriginDataUri&&this.src!==m)return;this.src===m&&(c=j.createElement("html"),c.appendChild(j.createElement("head")),c.appendChild(d=j.createElement("body")),d.innerHTML=a.textContent,j.replaceChild(c,j.documentElement)),g=j.createElement("head"),g.appendChild(f=j.createElement("style")),g.appendChild(e=j.createElement("script")),e.textContent=l,f.textContent=k,i=j.getElementsByTagName("head")[0],i.parentNode.replaceChild(g,i),h(this,"getHeight")});var g;b.sameOriginDataUri?g="data:text/html;charset=utf-8,"+encodeURIComponent("<!doctype html><html><head></head></body>"+a.textContent):g=m,f.setAttribute("src",g);var i=function(){f.contentDocument.body.innerHTML=this.value,h(f,"getHeight")};a.addEventListener("keypress",i),a.addEventListener("keyup",i),a.parentNode.insertBefore(d,a)},p=function(a){var b=document.createElement("div");b.className="preview-code",b.style.position="absolute",b.style.left="-9999px",j.appendChild(b);var c=parseInt(window.getComputedStyle(a).getPropertyValue("max-height"),10),d=function(a){b.textContent=this.value+"\n";var d=b.offsetHeight+2;d>=c?this.style.overflow="auto":this.style.overflow="hidden",this.style.height=b.offsetHeight+2+"px"};a.addEventListener("keypress",d),a.addEventListener("keyup",d),d.call(a)},q=function(){var b=j.getElementsByClassName("settings")[0],c=j.getElementsByClassName("resizeable"),d=30,e=function(b){document.cookie="preview-width="+b,a(c,function(a){b==="auto"&&(b=a.parentNode.offsetWidth),a.style.width=b+"px",h(a.getElementsByTagName("iframe")[0],"getHeight")})},i=f(document.cookie)["preview-width"];if(i){e(i),g(b.getElementsByClassName("is-active"),"is-active");var k=b.querySelector('button[data-width="'+i+'"]');k&&k.classList.add("is-active")}window.addEventListener("message",function(a){if(a.data==null||!a.source)return;var b=a.data,c=document.getElementsByName(a.source.name)[0];b.height!=null&&c&&(c.parentNode.style.height=b.height+d+"px")},!1),b&&c.length>0&&(b.hidden=!1,b.addEventListener("click",function(a){var c=a.target.tagName.toLowerCase(),d;if(c==="button")d=a.target;else{if(c!=="svg")return;d=a.target.parentNode}a.preventDefault(),g(b.getElementsByClassName("is-active"),"is-active"),d.classList.add("is-active");var f=d.dataset.width;e(f)}))}}()})()</script></body></html><!-- Generated with StyleDocco (http://jacobrask.github.com/styledocco). --> diff --git a/lib/web/css/docs/variables.html b/lib/web/css/docs/variables.html index 4423d682d0f80..4f353dc1554a4 100644 --- a/lib/web/css/docs/variables.html +++ b/lib/web/css/docs/variables.html @@ -7391,4 +7391,4 @@ <h4 id="codeliburlcheckcode-mixin-variables"><code>.lib-url-check()</code> mixin </tr> </table> </pre> -</div></article></section><div class="bar bottom"><div hidden class="settings container"><!-- Icons from http://iconmonstr.com--><button title="Desktop (1280)" data-width='1280'><svg viewBox="0 0 412 386" height="24" width="26" class="icon"><path d="m147.6,343.9c-4.5,15.9-26.2,37.6-42.1,42.1h201c-15.3,-4-38.1,-26.8-42.1,-42.1H147.6zM387,0.5H25c-13.8,0-25,11.2-25,25V294c0,13.8 11.2,25 25,25h362c13.8,0 25,-11.2 25,-25V25.5C412,11.7 400.8,0.5 387,0.5zM369.9,238.2H42.1L42.1,42.6 369.9,42.6V238.2z"></path></svg></button><button title="Laptop (1024)" data-width='1024'><svg viewBox="0 0 384 312" height="23" width="28" class="icon"><path d="m349.2,20.5c0,-11-9,-20-20,-20H53.6c-11,0-20,9-20,20v194H349.2v-194zm-27,167H60.6V27.5H322.2v160zm28,42H32.6L2.6,282.1c-3.5,6.2-3.5,13.8 0.1,19.9 3.6,6.2 10.2,9.9 17.3,9.9H363.1c7.1,0 13.7,-3.8 17.3,-10 3.6,-6.2 3.6,-13.8 0,-20l-30.2,-52.5zm-196.9,54 8,-23.5h60.5l8,23.5h-76.5z"></path></svg></button><button title="Tablet (768)" data-width='768'><svg viewBox="0 0 317 412" height="24" width="18" class="icon"><path d="M 316.5,380 V 32 c 0,-17.7 -14.3,-32 -32,-32 H 32 C 14.3,0 0,14.3 0,32 v 348 c 0,17.7 14.3,32 32,32 h 252.5 c 17.7,0 32,-14.3 32,-32 z M 40,367 V 45 H 276.5 V 367 H 40 z m 109.8,22.7 c 0,-4.7 3.8,-8.5 8.5,-8.5 4.7,0 8.5,3.8 8.5,8.5 0,4.7 -3.8,8.5 -8.5,8.5 -4.7,0 -8.5,-3.8 -8.5,-8.5 z"></path></svg></button><button title="Smart phone (320)" data-width='320'><svg viewBox="0 0 224 412" height="24" width="13" class="icon"><path d="M 190.7,0 H 33 C 14.8,0 0,14.8 0,33 v 346 c 0,18.2 14.8,33 33,33 h 157.7 c 18.2,0 33,-14.8 33,-33 V 33 c 0,-18.2 -14.8,-33 -33,-33 z M 94.3,30.2 h 37 c 2.2,0 4,1.8 4,4 0,2.2 -1.8,4 -4,4 h -37 c -2.2,0 -4,-1.8 -4,-4 0,-2.2 1.8,-4 4,-4 z m 18.5,362.8 c -8.8,0 -16,-7.2 -16,-16 0,-8.8 7.2,-16 16,-16 8.8,0 16,7.2 16,16 0,8.8 -7.2,16 -16,16 z M 198.6,343.8 H 25.1 V 68.2 h 173.5 v 275.5 z"></path></svg></button><button title="Feature phone (240)" data-width='240'><svg viewBox="0 0 201 412" height="24" width="12" class="icon"><path d="M 165.5,0.2 V 45 H 25 c -13.8,0 -25,11.2 -25,25 V 387 c 0,13.8 11.2,25 25,25 h 150.5 c 13.8,0 25,-11.2 25,-25 V 0.2 h -35 z M 65.2,366.5 H 34.2 v -24.5 h 31 v 24.5 z m 0,-44.3 H 34.2 v -24.5 h 31 v 24.5 z m 50.5,44.3 H 84.7 v -24.5 h 31 v 24.5 z m 0,-44.3 H 84.7 v -24.5 h 31 v 24.5 z m 50.5,44.3 h -31 v -24.5 h 31 v 24.5 z m 0,-44.3 h -31 v -24.5 h 31 v 24.5 z m 0,-59.3 h -132 V 95.4 h 132 V 262.9 z"></path></svg></button><button title="Auto (100%)" data-width="auto" class="auto is-active">Auto</button></div></div><script>(function(){var a=[{title:"actions-toolbar",filename:"actions-toolbar",url:"actions-toolbar.html"},{title:"Actions toolbar",filename:"actions-toolbar",url:"actions-toolbar.html#actions-toolbar"},{title:"Actions toolbar mixin variables",filename:"actions-toolbar",url:"actions-toolbar.html#actions-toolbar-mixin-variables"},{title:"Actions toolbar alignment",filename:"actions-toolbar",url:"actions-toolbar.html#actions-toolbar-alignment"},{title:"Reverse primary and secondary blocks",filename:"actions-toolbar",url:"actions-toolbar.html#reverse-primary-and-secondary-blocks"},{title:"Actions toolbar indents customizations",filename:"actions-toolbar",url:"actions-toolbar.html#actions-toolbar-indents-customizations"},{title:"Responsive actions toolbar",filename:"actions-toolbar",url:"actions-toolbar.html#responsive-actions-toolbar"},{title:"breadcrumbs",filename:"breadcrumbs",url:"breadcrumbs.html"},{title:"Breadcrumbs",filename:"breadcrumbs",url:"breadcrumbs.html#breadcrumbs"},{title:"Breadcrumbs variables",filename:"breadcrumbs",url:"breadcrumbs.html#breadcrumbs-variables"},{title:"Button-styled breadcrumbs with gradient background, border, and no separating symbol",filename:"breadcrumbs",url:"breadcrumbs.html#buttonstyled-breadcrumbs-with-gradient-background-border-and-no-separating-symbol"},{title:"Breadcrumbs with solid background",filename:"breadcrumbs",url:"breadcrumbs.html#breadcrumbs-with-solid-background"},{title:"buttons",filename:"buttons",url:"buttons.html"},{title:"Default button",filename:"buttons",url:"buttons.html#default-button"},{title:"Button variables",filename:"buttons",url:"buttons.html#button-variables"},{title:"Button as an icon",filename:"buttons",url:"buttons.html#button-as-an-icon"},{title:"Button with an icon on the left or right side of the text",filename:"buttons",url:"buttons.html#button-with-an-icon-on-the-left-or-right-side-of-the-text"},{title:"Button with fixed width",filename:"buttons",url:"buttons.html#button-with-fixed-width"},{title:"Primary button",filename:"buttons",url:"buttons.html#primary-button"},{title:"Primary button variables",filename:"buttons",url:"buttons.html#primary-button-variables"},{title:"Button with gradient background",filename:"buttons",url:"buttons.html#button-with-gradient-background"},{title:"Button as a link",filename:"buttons",url:"buttons.html#button-as-a-link"},{title:"Button as a link variables",filename:"buttons",url:"buttons.html#button-as-a-link-variables"},{title:"Link as a button",filename:"buttons",url:"buttons.html#link-as-a-button"},{title:"Button reset",filename:"buttons",url:"buttons.html#button-reset"},{title:"Button revert secondary color",filename:"buttons",url:"buttons.html#button-revert-secondary-color"},{title:"Button revert secondary color variables",filename:"buttons",url:"buttons.html#button-revert-secondary-color-variables"},{title:"Button revert secondary size",filename:"buttons",url:"buttons.html#button-revert-secondary-size"},{title:"Button revert secondary size variables",filename:"buttons",url:"buttons.html#button-revert-secondary-size-variables"},{title:"components",filename:"components",url:"components.html"},{title:"Components",filename:"components",url:"components.html#components"},{title:"Components Variables",filename:"components",url:"components.html#components-variables"},{title:"dropdowns",filename:"dropdowns",url:"dropdowns.html"},{title:"Drop-down and split buttons mixins",filename:"dropdowns",url:"dropdowns.html#dropdown-and-split-buttons-mixins"},{title:"Drop-down",filename:"dropdowns",url:"dropdowns.html#dropdown"},{title:"Drop-down variables",filename:"dropdowns",url:"dropdowns.html#dropdown-variables"},{title:"Drop-down with icon customization",filename:"dropdowns",url:"dropdowns.html#dropdown-with-icon-customization"},{title:"Modify dropdown list styles",filename:"dropdowns",url:"dropdowns.html#modify-dropdown-list-styles"},{title:"Split button",filename:"dropdowns",url:"dropdowns.html#split-button"},{title:"Split button variables",filename:"dropdowns",url:"dropdowns.html#split-button-variables"},{title:"Split button - button styling",filename:"dropdowns",url:"dropdowns.html#split-button-button-styling"},{title:"Split button icon customization",filename:"dropdowns",url:"dropdowns.html#split-button-icon-customization"},{title:"Split button drop-down list customization",filename:"dropdowns",url:"dropdowns.html#split-button-dropdown-list-customization"},{title:"forms",filename:"forms",url:"forms.html"},{title:"Forms mixins",filename:"forms",url:"forms.html#forms-mixins"},{title:"Global forms elements customization",filename:"forms",url:"forms.html#global-forms-elements-customization"},{title:"Fieldsets & fields customization",filename:"forms",url:"forms.html#fieldsets-fields-customization"},{title:"Fieldset and legend customization variables",filename:"forms",url:"forms.html#fieldset-and-legend-customization-variables"},{title:"Fields customization variables",filename:"forms",url:"forms.html#fields-customization-variables"},{title:"Required fields message customization variables",filename:"forms",url:"forms.html#required-fields-message-customization-variables"},{title:"Form element inputs customization",filename:"forms",url:"forms.html#form-element-inputs-customization"},{title:"Form element inputs customization variables",filename:"forms",url:"forms.html#form-element-inputs-customization-variables"},{title:"Form element choice",filename:"forms",url:"forms.html#form-element-choice"},{title:"Form element choice variables",filename:"forms",url:"forms.html#form-element-choice-variables"},{title:"Custom color",filename:"forms",url:"forms.html#custom-color"},{title:"Input number - input-text view",filename:"forms",url:"forms.html#input-number-inputtext-view"},{title:"Input search - input-text view",filename:"forms",url:"forms.html#input-search-inputtext-view"},{title:"Form validation",filename:"forms",url:"forms.html#form-validation"},{title:"Form validation variables",filename:"forms",url:"forms.html#form-validation-variables"},{title:"icons",filename:"icons",url:"icons.html"},{title:"Icons",filename:"icons",url:"icons.html#icons"},{title:"Icon with image or sprite",filename:"icons",url:"icons.html#icon-with-image-or-sprite"},{title:"Icon with image or sprite variables",filename:"icons",url:"icons.html#icon-with-image-or-sprite-variables"},{title:"Icon position for an icon with image or sprite",filename:"icons",url:"icons.html#icon-position-for-an-icon-with-image-or-sprite"},{title:"Position for icon with image or sprite mixin variables",filename:"icons",url:"icons.html#position-for-icon-with-image-or-sprite-mixin-variables"},{title:"Icon sprite position (with grid)",filename:"icons",url:"icons.html#icon-sprite-position-with-grid"},{title:"Icon sprite position variables",filename:"icons",url:"icons.html#icon-sprite-position-variables"},{title:"Image/sprite icon size",filename:"icons",url:"icons.html#imagesprite-icon-size"},{title:"Image/sprite icon size variables",filename:"icons",url:"icons.html#imagesprite-icon-size-variables"},{title:"Font icon",filename:"icons",url:"icons.html#font-icon"},{title:"Font icon variables",filename:"icons",url:"icons.html#font-icon-variables"},{title:"Change the size of font icon",filename:"icons",url:"icons.html#change-the-size-of-font-icon"},{title:"Change the size of font icon variables",filename:"icons",url:"icons.html#change-the-size-of-font-icon-variables"},{title:"Hide icon text",filename:"icons",url:"icons.html#hide-icon-text"},{title:"Sprite and font icons for Blank theme",filename:"icons",url:"icons.html#sprite-and-font-icons-for-blank-theme"},{title:"layout",filename:"layout",url:"layout.html"},{title:"Layout",filename:"layout",url:"layout.html#layout"},{title:"Layout global variables",filename:"layout",url:"layout.html#layout-global-variables"},{title:"Page layouts",filename:"layout",url:"layout.html#page-layouts"},{title:"Layout column",filename:"layout",url:"layout.html#layout-column"},{title:"Layout column variables",filename:"layout",url:"layout.html#layout-column-variables"},{title:"Layout width",filename:"layout",url:"layout.html#layout-width"},{title:"Layout width variables",filename:"layout",url:"layout.html#layout-width-variables"},{title:"lib",filename:"lib",url:"lib.html"},{title:"Including Magento UI library to your theme",filename:"lib",url:"lib.html#including-magento-ui-library-to-your-theme"},{title:"loaders",filename:"loaders",url:"loaders.html"},{title:"Loaders",filename:"loaders",url:"loaders.html#loaders"},{title:"Default loader variables",filename:"loaders",url:"loaders.html#default-loader-variables"},{title:"Loading",filename:"loaders",url:"loaders.html#loading"},{title:"Loading default variables",filename:"loaders",url:"loaders.html#loading-default-variables"},{title:"messages",filename:"messages",url:"messages.html"},{title:"Messages",filename:"messages",url:"messages.html#messages"},{title:"Information message",filename:"messages",url:"messages.html#information-message"},{title:"Warning message",filename:"messages",url:"messages.html#warning-message"},{title:"Error message",filename:"messages",url:"messages.html#error-message"},{title:"Success message",filename:"messages",url:"messages.html#success-message"},{title:"Notice message",filename:"messages",url:"messages.html#notice-message"},{title:"Message with inner icon",filename:"messages",url:"messages.html#message-with-inner-icon"},{title:"Message with lateral icon",filename:"messages",url:"messages.html#message-with-lateral-icon"},{title:"Custom message style",filename:"messages",url:"messages.html#custom-message-style"},{title:"Messages global variables",filename:"messages",url:"messages.html#messages-global-variables"},{title:"pages",filename:"pages",url:"pages.html"},{title:"Pagination HTML markup",filename:"pages",url:"pages.html#pagination-html-markup"},{title:"Pagination variables",filename:"pages",url:"pages.html#pagination-variables"},{title:"Pagination with label and gradient background on links",filename:"pages",url:"pages.html#pagination-with-label-and-gradient-background-on-links"},{title:'Pagination with "previous"..."next" text links and label',filename:"pages",url:"pages.html#pagination-with-previousnext-text-links-and-label"},{title:"Pagination without label, with solid background",filename:"pages",url:"pages.html#pagination-without-label-with-solid-background"},{title:"popups",filename:"popups",url:"popups.html"},{title:"Popups",filename:"popups",url:"popups.html#popups"},{title:"Popup variables",filename:"popups",url:"popups.html#popup-variables"},{title:"Window overlay mixin variables",filename:"popups",url:"popups.html#window-overlay-mixin-variables"},{title:"Fixed height popup",filename:"popups",url:"popups.html#fixed-height-popup"},{title:"Fixed content height popup",filename:"popups",url:"popups.html#fixed-content-height-popup"},{title:"Margins for header, content and footer block in popup",filename:"popups",url:"popups.html#margins-for-header-content-and-footer-block-in-popup"},{title:"Popup titles styled as theme headings",filename:"popups",url:"popups.html#popup-titles-styled-as-theme-headings"},{title:"Popup action toolbar",filename:"popups",url:"popups.html#popup-action-toolbar"},{title:"Popup Close button without an icon",filename:"popups",url:"popups.html#popup-close-button-without-an-icon"},{title:"Modify the icon of popup Close button",filename:"popups",url:"popups.html#modify-the-icon-of-popup-close-button"},{title:"Modify overlay styles",filename:"popups",url:"popups.html#modify-overlay-styles"},{title:"rating",filename:"rating",url:"rating.html"},{title:"Ratings",filename:"rating",url:"rating.html#ratings"},{title:"Global rating variables",filename:"rating",url:"rating.html#global-rating-variables"},{title:"Rating with vote",filename:"rating",url:"rating.html#rating-with-vote"},{title:"Rating with vote icons number customization",filename:"rating",url:"rating.html#rating-with-vote-icons-number-customization"},{title:"Rating with vote icons colors customization",filename:"rating",url:"rating.html#rating-with-vote-icons-colors-customization"},{title:"Rating with vote icons symbol customization",filename:"rating",url:"rating.html#rating-with-vote-icons-symbol-customization"},{title:"Accessible rating with vote",filename:"rating",url:"rating.html#accessible-rating-with-vote"},{title:"Rating summary",filename:"rating",url:"rating.html#rating-summary"},{title:"Rating summary icons number customization",filename:"rating",url:"rating.html#rating-summary-icons-number-customization"},{title:"Rating summary icons color customization",filename:"rating",url:"rating.html#rating-summary-icons-color-customization"},{title:"Rating summary icons symbol customization",filename:"rating",url:"rating.html#rating-summary-icons-symbol-customization"},{title:"Rating summary hide label",filename:"rating",url:"rating.html#rating-summary-hide-label"},{title:"Rating summary multiple ratings",filename:"rating",url:"rating.html#rating-summary-multiple-ratings"},{title:"Rating hide label mixin",filename:"rating",url:"rating.html#rating-hide-label-mixin"},{title:"resets",filename:"resets",url:"resets.html"},{title:"Resets",filename:"resets",url:"resets.html#resets"},{title:"responsive",filename:"responsive",url:"responsive.html"},{title:"Responsive",filename:"responsive",url:"responsive.html#responsive"},{title:"Responsive mixins usage",filename:"responsive",url:"responsive.html#responsive-mixins-usage"},{title:"Media query style groups separation variables",filename:"responsive",url:"responsive.html#media-query-style-groups-separation-variables"},{title:"Responsive breakpoints",filename:"responsive",url:"responsive.html#responsive-breakpoints"},{title:"sections",filename:"sections",url:"sections.html"},{title:"Tabs and accordions",filename:"sections",url:"sections.html#tabs-and-accordions"},{title:"Tabs",filename:"sections",url:"sections.html#tabs"},{title:"Tabs mixin variables",filename:"sections",url:"sections.html#tabs-mixin-variables"},{title:"Tabs with content top border",filename:"sections",url:"sections.html#tabs-with-content-top-border"},{title:"Accordion",filename:"sections",url:"sections.html#accordion"},{title:"Accordion mixin variables",filename:"sections",url:"sections.html#accordion-mixin-variables"},{title:"Responsive tabs",filename:"sections",url:"sections.html#responsive-tabs"},{title:"Tabs Base",filename:"sections",url:"sections.html#tabs-base"},{title:"Accordion Base",filename:"sections",url:"sections.html#accordion-base"},{title:"tables",filename:"tables",url:"tables.html"},{title:"Tables",filename:"tables",url:"tables.html#tables"},{title:"Table mixin variables",filename:"tables",url:"tables.html#table-mixin-variables"},{title:"Table typography",filename:"tables",url:"tables.html#table-typography"},{title:"Table typography mixin variables",filename:"tables",url:"tables.html#table-typography-mixin-variables"},{title:"Table caption",filename:"tables",url:"tables.html#table-caption"},{title:"Table caption mixin variables",filename:"tables",url:"tables.html#table-caption-mixin-variables"},{title:"Table cells resize",filename:"tables",url:"tables.html#table-cells-resize"},{title:"Table cells resize variables",filename:"tables",url:"tables.html#table-cells-resize-variables"},{title:"Table background customization",filename:"tables",url:"tables.html#table-background-customization"},{title:"Table background mixin variables",filename:"tables",url:"tables.html#table-background-mixin-variables"},{title:"Table borders customization",filename:"tables",url:"tables.html#table-borders-customization"},{title:"Table borders mixin variables",filename:"tables",url:"tables.html#table-borders-mixin-variables"},{title:"Table with horizontal borders",filename:"tables",url:"tables.html#table-with-horizontal-borders"},{title:"Table with vertical borders",filename:"tables",url:"tables.html#table-with-vertical-borders"},{title:"Table with light borders",filename:"tables",url:"tables.html#table-with-light-borders"},{title:"Table without borders",filename:"tables",url:"tables.html#table-without-borders"},{title:"Striped table",filename:"tables",url:"tables.html#striped-table"},{title:"Striped table mixin variables",filename:"tables",url:"tables.html#striped-table-mixin-variables"},{title:"Table with rows hover",filename:"tables",url:"tables.html#table-with-rows-hover"},{title:"Table with rows hover mixin variables",filename:"tables",url:"tables.html#table-with-rows-hover-mixin-variables"},{title:"Responsive table technics #1",filename:"tables",url:"tables.html#responsive-table-technics-1"},{title:"Responsive table technics #2",filename:"tables",url:"tables.html#responsive-table-technics-2"},{title:"Responsive table technics #2 mixin variables",filename:"tables",url:"tables.html#responsive-table-technics-2-mixin-variables"},{title:"tooltips",filename:"tooltips",url:"tooltips.html"},{title:"Tooltips",filename:"tooltips",url:"tooltips.html#tooltips"},{title:"Tooltips variables",filename:"tooltips",url:"tooltips.html#tooltips-variables"},{title:"typography",filename:"typography",url:"typography.html"},{title:"Typogrphy",filename:"typography",url:"typography.html#typogrphy"},{title:"Typography variables",filename:"typography",url:"typography.html#typography-variables"},{title:"Font-size mixin",filename:"typography",url:"typography.html#fontsize-mixin"},{title:"Line-height mixin",filename:"typography",url:"typography.html#lineheight-mixin"},{title:"Word breaking mixin",filename:"typography",url:"typography.html#word-breaking-mixin"},{title:"Font face mixin",filename:"typography",url:"typography.html#font-face-mixin"},{title:"Text overflow mixin",filename:"typography",url:"typography.html#text-overflow-mixin"},{title:"Text hide",filename:"typography",url:"typography.html#text-hide"},{title:"Hyphens",filename:"typography",url:"typography.html#hyphens"},{title:"Font style and color",filename:"typography",url:"typography.html#font-style-and-color"},{title:"Font style mixin variables",filename:"typography",url:"typography.html#font-style-mixin-variables"},{title:"Reset list styles",filename:"typography",url:"typography.html#reset-list-styles"},{title:"Reset list styles variables",filename:"typography",url:"typography.html#reset-list-styles-variables"},{title:"Inline-block list item styling",filename:"typography",url:"typography.html#inlineblock-list-item-styling"},{title:"Link styling mixin",filename:"typography",url:"typography.html#link-styling-mixin"},{title:"Link styling mixin variables",filename:"typography",url:"typography.html#link-styling-mixin-variables"},{title:"Heading styling mixin",filename:"typography",url:"typography.html#heading-styling-mixin"},{title:"Base typography mixins",filename:"typography",url:"typography.html#base-typography-mixins"},{title:"Base typography mixin variables",filename:"typography",url:"typography.html#base-typography-mixin-variables"},{title:"Headings typography mixin",filename:"typography",url:"typography.html#headings-typography-mixin"},{title:"Headings typography mixin variables",filename:"typography",url:"typography.html#headings-typography-mixin-variables"},{title:"Typography links mixin",filename:"typography",url:"typography.html#typography-links-mixin"},{title:"Typography lists mixin",filename:"typography",url:"typography.html#typography-lists-mixin"},{title:"Typography lists mixin variables",filename:"typography",url:"typography.html#typography-lists-mixin-variables"},{title:"Typography code elements mixin",filename:"typography",url:"typography.html#typography-code-elements-mixin"},{title:"Typography code mixin variables",filename:"typography",url:"typography.html#typography-code-mixin-variables"},{title:"Typography blockquote",filename:"typography",url:"typography.html#typography-blockquote"},{title:"Typography blockquote mixin variables",filename:"typography",url:"typography.html#typography-blockquote-mixin-variables"},{title:"utilities",filename:"utilities",url:"utilities.html"},{title:"Utilities",filename:"utilities",url:"utilities.html#utilities"},{title:".lib-clearfix()",filename:"utilities",url:"utilities.html#libclearfix"},{title:".lib-visibility-hidden()",filename:"utilities",url:"utilities.html#libvisibilityhidden"},{title:".lib-visually-hidden()",filename:"utilities",url:"utilities.html#libvisuallyhidden"},{title:".lib-visually-hidden-reset()",filename:"utilities",url:"utilities.html#libvisuallyhiddenreset"},{title:".lib-css()",filename:"utilities",url:"utilities.html#libcss"},{title:".lib-css() variables",filename:"utilities",url:"utilities.html#libcss-variables"},{title:".lib-rotate()",filename:"utilities",url:"utilities.html#librotate"},{title:".lib-rotate() variables",filename:"utilities",url:"utilities.html#librotate-variables"},{title:".lib-input-placeholder()",filename:"utilities",url:"utilities.html#libinputplaceholder"},{title:".lib-input-placeholder() variables",filename:"utilities",url:"utilities.html#libinputplaceholder-variables"},{title:".lib-background-gradient()",filename:"utilities",url:"utilities.html#libbackgroundgradient"},{title:".lib-background-gradient() variables",filename:"utilities",url:"utilities.html#libbackgroundgradient-variables"},{title:".lib-url-check()",filename:"utilities",url:"utilities.html#liburlcheck"},{title:".lib-url-check() variables",filename:"utilities",url:"utilities.html#liburlcheck-variables"},{title:"variables",filename:"variables",url:"variables.html"},{title:"List of Global Variables",filename:"variables",url:"variables.html#list-of-global-variables"},{title:"Table with rows hover mixin variables",filename:"variables",url:"variables.html#table-with-rows-hover-mixin-variables"},{title:"docs",filename:"docs",url:"docs.html"},{title:"Documentation",filename:"docs",url:"docs.html#documentation"}];(function(){"use strict";var b=function(a,b){return Array.prototype.indexOf.call(a,b)!==-1},c=function(a,b){return Array.prototype.filter.call(a,b)},d=function(a,b){return Array.prototype.forEach.call(a,b)},e=document.getElementsByTagName("body")[0];e.addEventListener("click",function(a){var b=a.target;b.tagName.toLowerCase()==="svg"&&(b=b.parentNode);var c=!1;b.dataset.toggle!=null&&(a.preventDefault(),b.classList.contains("is-active")||(c=!0)),d(e.querySelectorAll("[data-toggle]"),function(a){a.classList.remove("is-active"),document.getElementById(a.dataset.toggle).hidden=!0}),c&&(b.classList.add("is-active"),document.getElementById(b.dataset.toggle).hidden=!1)}),function(){var f=e.getElementsByClassName("nav")[0];if(!f)return;var g=document.createElement("ul");g.className="nav-results",g.id="nav-search",g.hidden=!0,d(a,function(a){var b,c,d;b=document.createElement("li"),b._title=a.title.toLowerCase(),b.hidden=!0,b.appendChild(c=document.createElement("a")),c.href=a.url,c.innerHTML=a.title,c.appendChild(d=document.createElement("span")),d.innerHTML=a.filename,d.className="nav-results-filename",g.appendChild(b)}),f.appendChild(g);var h=g.children,i=function(a){d(h,function(a){a.hidden=!0});var b=this.value.toLowerCase(),e=[];b!==""&&(e=c(h,function(a){return a._title.indexOf(b)!==-1})),e.length>0?(d(e,function(a){a.hidden=!1}),g.hidden=!1):g.hidden=!0},j=f.querySelector('input[type="search"]');j.addEventListener("keyup",i),j.addEventListener("focus",i),e.addEventListener("click",function(a){if(a.target.classList&&a.target.classList.contains("search"))return;g.hidden=!0}),g.addEventListener("click",function(a){j.value=""});var k=document.createElement("ul");k.id="nav-toc",k.hidden=!0,k.className="nav-results toc-list",c(e.getElementsByTagName("*"),function(a){return b(["h1","h2","h3"],a.tagName.toLowerCase())}).map(function(a){var b=document.createElement("li"),c=document.createElement("a"),d=a.tagName.toLowerCase()[1];c.classList.add("level-"+d),b.appendChild(c),c.href="#"+a.id,c.innerHTML=a.innerHTML,k.appendChild(b)}),f.appendChild(k)}()})(),function(){"use strict";if(location.hash==="#__preview__"||location.protocol==="data:")return;var a=function(a,b){return Array.prototype.forEach.call(a,b)},b=function(a,b){var e=Array.prototype.slice.call(arguments,2);return d(a,function(a){return(c(b)?b||a:a[b]).apply(a,e)})},c=function(a){return Object.prototype.toString.call(a)==="[object Function]"},d=function(a,b){return Array.prototype.map.call(a,b)},e=function(a,b){return d(a,function(a){return a[b]})},f=function(a){var b={},c=a.split(";");for(var d=0;c.length>d;d++){var e=c[d].trim().split("=");b[e[0]]=e[1]}return b},g=function(a,c){return b(e(a,"classList"),"remove",c)},h=function(a,b){a.contentDocument.defaultView.postMessage(b,"*")},i=document.getElementsByTagName("head")[0],j=document.getElementsByTagName("body")[0],k=e(i.querySelectorAll('style[type="text/preview"]'),"innerHTML").join(""),l=e(i.querySelectorAll('script[type="text/preview"]'),"innerHTML").join(""),m=location.href.split("#")[0]+"#__preview__",n=document.createElement("iframe");n.src="data:text/html,",j.appendChild(n),n.addEventListener("load",function(){var b={sameOriginDataUri:!0};try{this.contentDocument,this.contentDocument||(b.sameOriginDataUri=!1)}catch(c){b.sameOriginDataUri=!1}this.parentNode.removeChild(this),a(j.getElementsByTagName("textarea"),function(a,c){o(a,b,c),q(),p(a)})});var o=function(a,b,c){var d,e,f;d=document.createElement("div"),d.appendChild(e=document.createElement("div")),d.className="preview",e.appendChild(f=document.createElement("iframe")),e.className="resizeable",f.setAttribute("scrolling","no"),f.name="iframe"+c++,f.addEventListener("load",function(){var c,d,e,f,g,i,j;j=this.contentDocument;if(!b.sameOriginDataUri&&this.src!==m)return;this.src===m&&(c=j.createElement("html"),c.appendChild(j.createElement("head")),c.appendChild(d=j.createElement("body")),d.innerHTML=a.textContent,j.replaceChild(c,j.documentElement)),g=j.createElement("head"),g.appendChild(f=j.createElement("style")),g.appendChild(e=j.createElement("script")),e.textContent=l,f.textContent=k,i=j.getElementsByTagName("head")[0],i.parentNode.replaceChild(g,i),h(this,"getHeight")});var g;b.sameOriginDataUri?g="data:text/html;charset=utf-8,"+encodeURIComponent("<!doctype html><html><head></head></body>"+a.textContent):g=m,f.setAttribute("src",g);var i=function(){f.contentDocument.body.innerHTML=this.value,h(f,"getHeight")};a.addEventListener("keypress",i),a.addEventListener("keyup",i),a.parentNode.insertBefore(d,a)},p=function(a){var b=document.createElement("div");b.className="preview-code",b.style.position="absolute",b.style.left="-9999px",j.appendChild(b);var c=parseInt(window.getComputedStyle(a).getPropertyValue("max-height"),10),d=function(a){b.textContent=this.value+"\n";var d=b.offsetHeight+2;d>=c?this.style.overflow="auto":this.style.overflow="hidden",this.style.height=b.offsetHeight+2+"px"};a.addEventListener("keypress",d),a.addEventListener("keyup",d),d.call(a)},q=function(){var b=j.getElementsByClassName("settings")[0],c=j.getElementsByClassName("resizeable"),d=30,e=function(b){document.cookie="preview-width="+b,a(c,function(a){b==="auto"&&(b=a.parentNode.offsetWidth),a.style.width=b+"px",h(a.getElementsByTagName("iframe")[0],"getHeight")})},i=f(document.cookie)["preview-width"];if(i){e(i),g(b.getElementsByClassName("is-active"),"is-active");var k=b.querySelector('button[data-width="'+i+'"]');k&&k.classList.add("is-active")}window.addEventListener("message",function(a){if(a.data==null||!a.source)return;var b=a.data,c=document.getElementsByName(a.source.name)[0];b.height!=null&&c&&(c.parentNode.style.height=b.height+d+"px")},!1),b&&c.length>0&&(b.hidden=!1,b.addEventListener("click",function(a){var c=a.target.tagName.toLowerCase(),d;if(c==="button")d=a.target;else{if(c!=="svg")return;d=a.target.parentNode}a.preventDefault(),g(b.getElementsByClassName("is-active"),"is-active"),d.classList.add("is-active");var f=d.dataset.width;e(f)}))}}()})()</script></body></html><!-- Generated with StyleDocco (http://jacobrask.github.com/styledocco). --> +</div></article></section><div class="bar bottom"><div hidden class="settings container"><!-- Icons from http://iconmonstr.com--><button title="Desktop (1280)" data-width='1280'><svg viewBox="0 0 412 386" height="24" width="26" class="icon"><path d="m147.6,343.9c-4.5,15.9-26.2,37.6-42.1,42.1h201c-15.3,-4-38.1,-26.8-42.1,-42.1H147.6zM387,0.5H25c-13.8,0-25,11.2-25,25V294c0,13.8 11.2,25 25,25h362c13.8,0 25,-11.2 25,-25V25.5C412,11.7 400.8,0.5 387,0.5zM369.9,238.2H42.1L42.1,42.6 369.9,42.6V238.2z"></path></svg></button><button title="Laptop (1024)" data-width='1024'><svg viewBox="0 0 384 312" height="23" width="28" class="icon"><path d="m349.2,20.5c0,-11-9,-20-20,-20H53.6c-11,0-20,9-20,20v194H349.2v-194zm-27,167H60.6V27.5H322.2v160zm28,42H32.6L2.6,282.1c-3.5,6.2-3.5,13.8 0.1,19.9 3.6,6.2 10.2,9.9 17.3,9.9H363.1c7.1,0 13.7,-3.8 17.3,-10 3.6,-6.2 3.6,-13.8 0,-20l-30.2,-52.5zm-196.9,54 8,-23.5h60.5l8,23.5h-76.5z"></path></svg></button><button title="Tablet (768)" data-width='768'><svg viewBox="0 0 317 412" height="24" width="18" class="icon"><path d="M 316.5,380 V 32 c 0,-17.7 -14.3,-32 -32,-32 H 32 C 14.3,0 0,14.3 0,32 v 348 c 0,17.7 14.3,32 32,32 h 252.5 c 17.7,0 32,-14.3 32,-32 z M 40,367 V 45 H 276.5 V 367 H 40 z m 109.8,22.7 c 0,-4.7 3.8,-8.5 8.5,-8.5 4.7,0 8.5,3.8 8.5,8.5 0,4.7 -3.8,8.5 -8.5,8.5 -4.7,0 -8.5,-3.8 -8.5,-8.5 z"></path></svg></button><button title="Smart phone (320)" data-width='320'><svg viewBox="0 0 224 412" height="24" width="13" class="icon"><path d="M 190.7,0 H 33 C 14.8,0 0,14.8 0,33 v 346 c 0,18.2 14.8,33 33,33 h 157.7 c 18.2,0 33,-14.8 33,-33 V 33 c 0,-18.2 -14.8,-33 -33,-33 z M 94.3,30.2 h 37 c 2.2,0 4,1.8 4,4 0,2.2 -1.8,4 -4,4 h -37 c -2.2,0 -4,-1.8 -4,-4 0,-2.2 1.8,-4 4,-4 z m 18.5,362.8 c -8.8,0 -16,-7.2 -16,-16 0,-8.8 7.2,-16 16,-16 8.8,0 16,7.2 16,16 0,8.8 -7.2,16 -16,16 z M 198.6,343.8 H 25.1 V 68.2 h 173.5 v 275.5 z"></path></svg></button><button title="Feature phone (240)" data-width='240'><svg viewBox="0 0 201 412" height="24" width="12" class="icon"><path d="M 165.5,0.2 V 45 H 25 c -13.8,0 -25,11.2 -25,25 V 387 c 0,13.8 11.2,25 25,25 h 150.5 c 13.8,0 25,-11.2 25,-25 V 0.2 h -35 z M 65.2,366.5 H 34.2 v -24.5 h 31 v 24.5 z m 0,-44.3 H 34.2 v -24.5 h 31 v 24.5 z m 50.5,44.3 H 84.7 v -24.5 h 31 v 24.5 z m 0,-44.3 H 84.7 v -24.5 h 31 v 24.5 z m 50.5,44.3 h -31 v -24.5 h 31 v 24.5 z m 0,-44.3 h -31 v -24.5 h 31 v 24.5 z m 0,-59.3 h -132 V 95.4 h 132 V 262.9 z"></path></svg></button><button title="Auto (100%)" data-width="auto" class="auto is-active">Auto</button></div></div><script>(function(){var a=[{title:"actions-toolbar",filename:"actions-toolbar",url:"actions-toolbar.html"},{title:"Actions toolbar",filename:"actions-toolbar",url:"actions-toolbar.html#actions-toolbar"},{title:"Actions toolbar mixin variables",filename:"actions-toolbar",url:"actions-toolbar.html#actions-toolbar-mixin-variables"},{title:"Actions toolbar alignment",filename:"actions-toolbar",url:"actions-toolbar.html#actions-toolbar-alignment"},{title:"Reverse primary and secondary blocks",filename:"actions-toolbar",url:"actions-toolbar.html#reverse-primary-and-secondary-blocks"},{title:"Actions toolbar indents customizations",filename:"actions-toolbar",url:"actions-toolbar.html#actions-toolbar-indents-customizations"},{title:"Responsive actions toolbar",filename:"actions-toolbar",url:"actions-toolbar.html#responsive-actions-toolbar"},{title:"breadcrumbs",filename:"breadcrumbs",url:"breadcrumbs.html"},{title:"Breadcrumbs",filename:"breadcrumbs",url:"breadcrumbs.html#breadcrumbs"},{title:"Breadcrumbs variables",filename:"breadcrumbs",url:"breadcrumbs.html#breadcrumbs-variables"},{title:"Button-styled breadcrumbs with gradient background, border, and no separating symbol",filename:"breadcrumbs",url:"breadcrumbs.html#buttonstyled-breadcrumbs-with-gradient-background-border-and-no-separating-symbol"},{title:"Breadcrumbs with solid background",filename:"breadcrumbs",url:"breadcrumbs.html#breadcrumbs-with-solid-background"},{title:"buttons",filename:"buttons",url:"buttons.html"},{title:"Default button",filename:"buttons",url:"buttons.html#default-button"},{title:"Button variables",filename:"buttons",url:"buttons.html#button-variables"},{title:"Button as an icon",filename:"buttons",url:"buttons.html#button-as-an-icon"},{title:"Button with an icon on the left or right side of the text",filename:"buttons",url:"buttons.html#button-with-an-icon-on-the-left-or-right-side-of-the-text"},{title:"Button with fixed width",filename:"buttons",url:"buttons.html#button-with-fixed-width"},{title:"Primary button",filename:"buttons",url:"buttons.html#primary-button"},{title:"Primary button variables",filename:"buttons",url:"buttons.html#primary-button-variables"},{title:"Button with gradient background",filename:"buttons",url:"buttons.html#button-with-gradient-background"},{title:"Button as a link",filename:"buttons",url:"buttons.html#button-as-a-link"},{title:"Button as a link variables",filename:"buttons",url:"buttons.html#button-as-a-link-variables"},{title:"Link as a button",filename:"buttons",url:"buttons.html#link-as-a-button"},{title:"Button reset",filename:"buttons",url:"buttons.html#button-reset"},{title:"Button revert secondary color",filename:"buttons",url:"buttons.html#button-revert-secondary-color"},{title:"Button revert secondary color variables",filename:"buttons",url:"buttons.html#button-revert-secondary-color-variables"},{title:"Button revert secondary size",filename:"buttons",url:"buttons.html#button-revert-secondary-size"},{title:"Button revert secondary size variables",filename:"buttons",url:"buttons.html#button-revert-secondary-size-variables"},{title:"components",filename:"components",url:"components.html"},{title:"Components",filename:"components",url:"components.html#components"},{title:"Components Variables",filename:"components",url:"components.html#components-variables"},{title:"dropdowns",filename:"dropdowns",url:"dropdowns.html"},{title:"Drop-down and split buttons mixins",filename:"dropdowns",url:"dropdowns.html#dropdown-and-split-buttons-mixins"},{title:"Drop-down",filename:"dropdowns",url:"dropdowns.html#dropdown"},{title:"Drop-down variables",filename:"dropdowns",url:"dropdowns.html#dropdown-variables"},{title:"Drop-down with icon customization",filename:"dropdowns",url:"dropdowns.html#dropdown-with-icon-customization"},{title:"Modify dropdown list styles",filename:"dropdowns",url:"dropdowns.html#modify-dropdown-list-styles"},{title:"Split button",filename:"dropdowns",url:"dropdowns.html#split-button"},{title:"Split button variables",filename:"dropdowns",url:"dropdowns.html#split-button-variables"},{title:"Split button - button styling",filename:"dropdowns",url:"dropdowns.html#split-button-button-styling"},{title:"Split button icon customization",filename:"dropdowns",url:"dropdowns.html#split-button-icon-customization"},{title:"Split button drop-down list customization",filename:"dropdowns",url:"dropdowns.html#split-button-dropdown-list-customization"},{title:"forms",filename:"forms",url:"forms.html"},{title:"Forms mixins",filename:"forms",url:"forms.html#forms-mixins"},{title:"Global forms elements customization",filename:"forms",url:"forms.html#global-forms-elements-customization"},{title:"Fieldsets & fields customization",filename:"forms",url:"forms.html#fieldsets-fields-customization"},{title:"Fieldset and legend customization variables",filename:"forms",url:"forms.html#fieldset-and-legend-customization-variables"},{title:"Fields customization variables",filename:"forms",url:"forms.html#fields-customization-variables"},{title:"Required fields message customization variables",filename:"forms",url:"forms.html#required-fields-message-customization-variables"},{title:"Form element inputs customization",filename:"forms",url:"forms.html#form-element-inputs-customization"},{title:"Form element inputs customization variables",filename:"forms",url:"forms.html#form-element-inputs-customization-variables"},{title:"Form element choice",filename:"forms",url:"forms.html#form-element-choice"},{title:"Form element choice variables",filename:"forms",url:"forms.html#form-element-choice-variables"},{title:"Custom color",filename:"forms",url:"forms.html#custom-color"},{title:"Input number - input-text view",filename:"forms",url:"forms.html#input-number-inputtext-view"},{title:"Input search - input-text view",filename:"forms",url:"forms.html#input-search-inputtext-view"},{title:"Form validation",filename:"forms",url:"forms.html#form-validation"},{title:"Form validation variables",filename:"forms",url:"forms.html#form-validation-variables"},{title:"icons",filename:"icons",url:"icons.html"},{title:"Icons",filename:"icons",url:"icons.html#icons"},{title:"Icon with image or sprite",filename:"icons",url:"icons.html#icon-with-image-or-sprite"},{title:"Icon with image or sprite variables",filename:"icons",url:"icons.html#icon-with-image-or-sprite-variables"},{title:"Icon position for an icon with image or sprite",filename:"icons",url:"icons.html#icon-position-for-an-icon-with-image-or-sprite"},{title:"Position for icon with image or sprite mixin variables",filename:"icons",url:"icons.html#position-for-icon-with-image-or-sprite-mixin-variables"},{title:"Icon sprite position (with grid)",filename:"icons",url:"icons.html#icon-sprite-position-with-grid"},{title:"Icon sprite position variables",filename:"icons",url:"icons.html#icon-sprite-position-variables"},{title:"Image/sprite icon size",filename:"icons",url:"icons.html#imagesprite-icon-size"},{title:"Image/sprite icon size variables",filename:"icons",url:"icons.html#imagesprite-icon-size-variables"},{title:"Font icon",filename:"icons",url:"icons.html#font-icon"},{title:"Font icon variables",filename:"icons",url:"icons.html#font-icon-variables"},{title:"Change the size of font icon",filename:"icons",url:"icons.html#change-the-size-of-font-icon"},{title:"Change the size of font icon variables",filename:"icons",url:"icons.html#change-the-size-of-font-icon-variables"},{title:"Hide icon text",filename:"icons",url:"icons.html#hide-icon-text"},{title:"Sprite and font icons for Blank theme",filename:"icons",url:"icons.html#sprite-and-font-icons-for-blank-theme"},{title:"layout",filename:"layout",url:"layout.html"},{title:"Layout",filename:"layout",url:"layout.html#layout"},{title:"Layout global variables",filename:"layout",url:"layout.html#layout-global-variables"},{title:"Page layouts",filename:"layout",url:"layout.html#page-layouts"},{title:"Layout column",filename:"layout",url:"layout.html#layout-column"},{title:"Layout column variables",filename:"layout",url:"layout.html#layout-column-variables"},{title:"Layout width",filename:"layout",url:"layout.html#layout-width"},{title:"Layout width variables",filename:"layout",url:"layout.html#layout-width-variables"},{title:"lib",filename:"lib",url:"lib.html"},{title:"Including Magento UI library to your theme",filename:"lib",url:"lib.html#including-magento-ui-library-to-your-theme"},{title:"loaders",filename:"loaders",url:"loaders.html"},{title:"Loaders",filename:"loaders",url:"loaders.html#loaders"},{title:"Default loader variables",filename:"loaders",url:"loaders.html#default-loader-variables"},{title:"Loading",filename:"loaders",url:"loaders.html#loading"},{title:"Loading default variables",filename:"loaders",url:"loaders.html#loading-default-variables"},{title:"messages",filename:"messages",url:"messages.html"},{title:"Messages",filename:"messages",url:"messages.html#messages"},{title:"Information message",filename:"messages",url:"messages.html#information-message"},{title:"Warning message",filename:"messages",url:"messages.html#warning-message"},{title:"Error message",filename:"messages",url:"messages.html#error-message"},{title:"Success message",filename:"messages",url:"messages.html#success-message"},{title:"Notice message",filename:"messages",url:"messages.html#notice-message"},{title:"Message with inner icon",filename:"messages",url:"messages.html#message-with-inner-icon"},{title:"Message with lateral icon",filename:"messages",url:"messages.html#message-with-lateral-icon"},{title:"Custom message style",filename:"messages",url:"messages.html#custom-message-style"},{title:"Messages global variables",filename:"messages",url:"messages.html#messages-global-variables"},{title:"pages",filename:"pages",url:"pages.html"},{title:"Pagination HTML markup",filename:"pages",url:"pages.html#pagination-html-markup"},{title:"Pagination variables",filename:"pages",url:"pages.html#pagination-variables"},{title:"Pagination with label and gradient background on links",filename:"pages",url:"pages.html#pagination-with-label-and-gradient-background-on-links"},{title:'Pagination with "previous"..."next" text links and label',filename:"pages",url:"pages.html#pagination-with-previousnext-text-links-and-label"},{title:"Pagination without label, with solid background",filename:"pages",url:"pages.html#pagination-without-label-with-solid-background"},{title:"popups",filename:"popups",url:"popups.html"},{title:"Popups",filename:"popups",url:"popups.html#popups"},{title:"Popup variables",filename:"popups",url:"popups.html#popup-variables"},{title:"Window overlay mixin variables",filename:"popups",url:"popups.html#window-overlay-mixin-variables"},{title:"Fixed height popup",filename:"popups",url:"popups.html#fixed-height-popup"},{title:"Fixed content height popup",filename:"popups",url:"popups.html#fixed-content-height-popup"},{title:"Margins for header, content and footer block in popup",filename:"popups",url:"popups.html#margins-for-header-content-and-footer-block-in-popup"},{title:"Popup titles styled as theme headings",filename:"popups",url:"popups.html#popup-titles-styled-as-theme-headings"},{title:"Popup action toolbar",filename:"popups",url:"popups.html#popup-action-toolbar"},{title:"Popup Close button without an icon",filename:"popups",url:"popups.html#popup-close-button-without-an-icon"},{title:"Modify the icon of popup Close button",filename:"popups",url:"popups.html#modify-the-icon-of-popup-close-button"},{title:"Modify overlay styles",filename:"popups",url:"popups.html#modify-overlay-styles"},{title:"rating",filename:"rating",url:"rating.html"},{title:"Ratings",filename:"rating",url:"rating.html#ratings"},{title:"Global rating variables",filename:"rating",url:"rating.html#global-rating-variables"},{title:"Rating with vote",filename:"rating",url:"rating.html#rating-with-vote"},{title:"Rating with vote icons number customization",filename:"rating",url:"rating.html#rating-with-vote-icons-number-customization"},{title:"Rating with vote icons colors customization",filename:"rating",url:"rating.html#rating-with-vote-icons-colors-customization"},{title:"Rating with vote icons symbol customization",filename:"rating",url:"rating.html#rating-with-vote-icons-symbol-customization"},{title:"Accessible rating with vote",filename:"rating",url:"rating.html#accessible-rating-with-vote"},{title:"Rating summary",filename:"rating",url:"rating.html#rating-summary"},{title:"Rating summary icons number customization",filename:"rating",url:"rating.html#rating-summary-icons-number-customization"},{title:"Rating summary icons color customization",filename:"rating",url:"rating.html#rating-summary-icons-color-customization"},{title:"Rating summary icons symbol customization",filename:"rating",url:"rating.html#rating-summary-icons-symbol-customization"},{title:"Rating summary hide label",filename:"rating",url:"rating.html#rating-summary-hide-label"},{title:"Rating summary multiple ratings",filename:"rating",url:"rating.html#rating-summary-multiple-ratings"},{title:"Rating hide label mixin",filename:"rating",url:"rating.html#rating-hide-label-mixin"},{title:"resets",filename:"resets",url:"resets.html"},{title:"Resets",filename:"resets",url:"resets.html#resets"},{title:"responsive",filename:"responsive",url:"responsive.html"},{title:"Responsive",filename:"responsive",url:"responsive.html#responsive"},{title:"Responsive mixins usage",filename:"responsive",url:"responsive.html#responsive-mixins-usage"},{title:"Media query style groups separation variables",filename:"responsive",url:"responsive.html#media-query-style-groups-separation-variables"},{title:"Responsive breakpoints",filename:"responsive",url:"responsive.html#responsive-breakpoints"},{title:"sections",filename:"sections",url:"sections.html"},{title:"Tabs and accordions",filename:"sections",url:"sections.html#tabs-and-accordions"},{title:"Tabs",filename:"sections",url:"sections.html#tabs"},{title:"Tabs mixin variables",filename:"sections",url:"sections.html#tabs-mixin-variables"},{title:"Tabs with content top border",filename:"sections",url:"sections.html#tabs-with-content-top-border"},{title:"Accordion",filename:"sections",url:"sections.html#accordion"},{title:"Accordion mixin variables",filename:"sections",url:"sections.html#accordion-mixin-variables"},{title:"Responsive tabs",filename:"sections",url:"sections.html#responsive-tabs"},{title:"Tabs Base",filename:"sections",url:"sections.html#tabs-base"},{title:"Accordion Base",filename:"sections",url:"sections.html#accordion-base"},{title:"tables",filename:"tables",url:"tables.html"},{title:"Tables",filename:"tables",url:"tables.html#tables"},{title:"Table mixin variables",filename:"tables",url:"tables.html#table-mixin-variables"},{title:"Table typography",filename:"tables",url:"tables.html#table-typography"},{title:"Table typography mixin variables",filename:"tables",url:"tables.html#table-typography-mixin-variables"},{title:"Table caption",filename:"tables",url:"tables.html#table-caption"},{title:"Table caption mixin variables",filename:"tables",url:"tables.html#table-caption-mixin-variables"},{title:"Table cells resize",filename:"tables",url:"tables.html#table-cells-resize"},{title:"Table cells resize variables",filename:"tables",url:"tables.html#table-cells-resize-variables"},{title:"Table background customization",filename:"tables",url:"tables.html#table-background-customization"},{title:"Table background mixin variables",filename:"tables",url:"tables.html#table-background-mixin-variables"},{title:"Table borders customization",filename:"tables",url:"tables.html#table-borders-customization"},{title:"Table borders mixin variables",filename:"tables",url:"tables.html#table-borders-mixin-variables"},{title:"Table with horizontal borders",filename:"tables",url:"tables.html#table-with-horizontal-borders"},{title:"Table with vertical borders",filename:"tables",url:"tables.html#table-with-vertical-borders"},{title:"Table with light borders",filename:"tables",url:"tables.html#table-with-light-borders"},{title:"Table without borders",filename:"tables",url:"tables.html#table-without-borders"},{title:"Striped table",filename:"tables",url:"tables.html#striped-table"},{title:"Striped table mixin variables",filename:"tables",url:"tables.html#striped-table-mixin-variables"},{title:"Table with rows hover",filename:"tables",url:"tables.html#table-with-rows-hover"},{title:"Table with rows hover mixin variables",filename:"tables",url:"tables.html#table-with-rows-hover-mixin-variables"},{title:"Responsive table technics #1",filename:"tables",url:"tables.html#responsive-table-technics-1"},{title:"Responsive table technics #2",filename:"tables",url:"tables.html#responsive-table-technics-2"},{title:"Responsive table technics #2 mixin variables",filename:"tables",url:"tables.html#responsive-table-technics-2-mixin-variables"},{title:"tooltips",filename:"tooltips",url:"tooltips.html"},{title:"Tooltips",filename:"tooltips",url:"tooltips.html#tooltips"},{title:"Tooltips variables",filename:"tooltips",url:"tooltips.html#tooltips-variables"},{title:"typography",filename:"typography",url:"typography.html"},{title:"Typogrphy",filename:"typography",url:"typography.html#typogrphy"},{title:"Typography variables",filename:"typography",url:"typography.html#typography-variables"},{title:"Font-size mixin",filename:"typography",url:"typography.html#fontsize-mixin"},{title:"Line-height mixin",filename:"typography",url:"typography.html#lineheight-mixin"},{title:"Word breaking mixin",filename:"typography",url:"typography.html#word-breaking-mixin"},{title:"Font face mixin",filename:"typography",url:"typography.html#font-face-mixin"},{title:"Text overflow mixin",filename:"typography",url:"typography.html#text-overflow-mixin"},{title:"Text hide",filename:"typography",url:"typography.html#text-hide"},{title:"Hyphens",filename:"typography",url:"typography.html#hyphens"},{title:"Font style and color",filename:"typography",url:"typography.html#font-style-and-color"},{title:"Font style mixin variables",filename:"typography",url:"typography.html#font-style-mixin-variables"},{title:"Reset list styles",filename:"typography",url:"typography.html#reset-list-styles"},{title:"Reset list styles variables",filename:"typography",url:"typography.html#reset-list-styles-variables"},{title:"Inline-block list item styling",filename:"typography",url:"typography.html#inlineblock-list-item-styling"},{title:"Link styling mixin",filename:"typography",url:"typography.html#link-styling-mixin"},{title:"Link styling mixin variables",filename:"typography",url:"typography.html#link-styling-mixin-variables"},{title:"Heading styling mixin",filename:"typography",url:"typography.html#heading-styling-mixin"},{title:"Base typography mixins",filename:"typography",url:"typography.html#base-typography-mixins"},{title:"Base typography mixin variables",filename:"typography",url:"typography.html#base-typography-mixin-variables"},{title:"Headings typography mixin",filename:"typography",url:"typography.html#headings-typography-mixin"},{title:"Headings typography mixin variables",filename:"typography",url:"typography.html#headings-typography-mixin-variables"},{title:"Typography links mixin",filename:"typography",url:"typography.html#typography-links-mixin"},{title:"Typography lists mixin",filename:"typography",url:"typography.html#typography-lists-mixin"},{title:"Typography lists mixin variables",filename:"typography",url:"typography.html#typography-lists-mixin-variables"},{title:"Typography code elements mixin",filename:"typography",url:"typography.html#typography-code-elements-mixin"},{title:"Typography code mixin variables",filename:"typography",url:"typography.html#typography-code-mixin-variables"},{title:"Typography blockquote",filename:"typography",url:"typography.html#typography-blockquote"},{title:"Typography blockquote mixin variables",filename:"typography",url:"typography.html#typography-blockquote-mixin-variables"},{title:"utilities",filename:"utilities",url:"utilities.html"},{title:"Utilities",filename:"utilities",url:"utilities.html#utilities"},{title:".lib-clearfix()",filename:"utilities",url:"utilities.html#libclearfix"},{title:".lib-visibility-hidden()",filename:"utilities",url:"utilities.html#libvisibilityhidden"},{title:".lib-visually-hidden()",filename:"utilities",url:"utilities.html#libvisuallyhidden"},{title:".lib-visually-hidden-reset()",filename:"utilities",url:"utilities.html#libvisuallyhiddenreset"},{title:".lib-css()",filename:"utilities",url:"utilities.html#libcss"},{title:".lib-css() variables",filename:"utilities",url:"utilities.html#libcss-variables"},{title:".lib-rotate()",filename:"utilities",url:"utilities.html#librotate"},{title:".lib-rotate() variables",filename:"utilities",url:"utilities.html#librotate-variables"},{title:".lib-input-placeholder()",filename:"utilities",url:"utilities.html#libinputplaceholder"},{title:".lib-input-placeholder() variables",filename:"utilities",url:"utilities.html#libinputplaceholder-variables"},{title:".lib-background-gradient()",filename:"utilities",url:"utilities.html#libbackgroundgradient"},{title:".lib-background-gradient() variables",filename:"utilities",url:"utilities.html#libbackgroundgradient-variables"},{title:"variables",filename:"variables",url:"variables.html"},{title:"List of Global Variables",filename:"variables",url:"variables.html#list-of-global-variables"},{title:"Table with rows hover mixin variables",filename:"variables",url:"variables.html#table-with-rows-hover-mixin-variables"},{title:"docs",filename:"docs",url:"docs.html"},{title:"Documentation",filename:"docs",url:"docs.html#documentation"}];(function(){"use strict";var b=function(a,b){return Array.prototype.indexOf.call(a,b)!==-1},c=function(a,b){return Array.prototype.filter.call(a,b)},d=function(a,b){return Array.prototype.forEach.call(a,b)},e=document.getElementsByTagName("body")[0];e.addEventListener("click",function(a){var b=a.target;b.tagName.toLowerCase()==="svg"&&(b=b.parentNode);var c=!1;b.dataset.toggle!=null&&(a.preventDefault(),b.classList.contains("is-active")||(c=!0)),d(e.querySelectorAll("[data-toggle]"),function(a){a.classList.remove("is-active"),document.getElementById(a.dataset.toggle).hidden=!0}),c&&(b.classList.add("is-active"),document.getElementById(b.dataset.toggle).hidden=!1)}),function(){var f=e.getElementsByClassName("nav")[0];if(!f)return;var g=document.createElement("ul");g.className="nav-results",g.id="nav-search",g.hidden=!0,d(a,function(a){var b,c,d;b=document.createElement("li"),b._title=a.title.toLowerCase(),b.hidden=!0,b.appendChild(c=document.createElement("a")),c.href=a.url,c.innerHTML=a.title,c.appendChild(d=document.createElement("span")),d.innerHTML=a.filename,d.className="nav-results-filename",g.appendChild(b)}),f.appendChild(g);var h=g.children,i=function(a){d(h,function(a){a.hidden=!0});var b=this.value.toLowerCase(),e=[];b!==""&&(e=c(h,function(a){return a._title.indexOf(b)!==-1})),e.length>0?(d(e,function(a){a.hidden=!1}),g.hidden=!1):g.hidden=!0},j=f.querySelector('input[type="search"]');j.addEventListener("keyup",i),j.addEventListener("focus",i),e.addEventListener("click",function(a){if(a.target.classList&&a.target.classList.contains("search"))return;g.hidden=!0}),g.addEventListener("click",function(a){j.value=""});var k=document.createElement("ul");k.id="nav-toc",k.hidden=!0,k.className="nav-results toc-list",c(e.getElementsByTagName("*"),function(a){return b(["h1","h2","h3"],a.tagName.toLowerCase())}).map(function(a){var b=document.createElement("li"),c=document.createElement("a"),d=a.tagName.toLowerCase()[1];c.classList.add("level-"+d),b.appendChild(c),c.href="#"+a.id,c.innerHTML=a.innerHTML,k.appendChild(b)}),f.appendChild(k)}()})(),function(){"use strict";if(location.hash==="#__preview__"||location.protocol==="data:")return;var a=function(a,b){return Array.prototype.forEach.call(a,b)},b=function(a,b){var e=Array.prototype.slice.call(arguments,2);return d(a,function(a){return(c(b)?b||a:a[b]).apply(a,e)})},c=function(a){return Object.prototype.toString.call(a)==="[object Function]"},d=function(a,b){return Array.prototype.map.call(a,b)},e=function(a,b){return d(a,function(a){return a[b]})},f=function(a){var b={},c=a.split(";");for(var d=0;c.length>d;d++){var e=c[d].trim().split("=");b[e[0]]=e[1]}return b},g=function(a,c){return b(e(a,"classList"),"remove",c)},h=function(a,b){a.contentDocument.defaultView.postMessage(b,"*")},i=document.getElementsByTagName("head")[0],j=document.getElementsByTagName("body")[0],k=e(i.querySelectorAll('style[type="text/preview"]'),"innerHTML").join(""),l=e(i.querySelectorAll('script[type="text/preview"]'),"innerHTML").join(""),m=location.href.split("#")[0]+"#__preview__",n=document.createElement("iframe");n.src="data:text/html,",j.appendChild(n),n.addEventListener("load",function(){var b={sameOriginDataUri:!0};try{this.contentDocument,this.contentDocument||(b.sameOriginDataUri=!1)}catch(c){b.sameOriginDataUri=!1}this.parentNode.removeChild(this),a(j.getElementsByTagName("textarea"),function(a,c){o(a,b,c),q(),p(a)})});var o=function(a,b,c){var d,e,f;d=document.createElement("div"),d.appendChild(e=document.createElement("div")),d.className="preview",e.appendChild(f=document.createElement("iframe")),e.className="resizeable",f.setAttribute("scrolling","no"),f.name="iframe"+c++,f.addEventListener("load",function(){var c,d,e,f,g,i,j;j=this.contentDocument;if(!b.sameOriginDataUri&&this.src!==m)return;this.src===m&&(c=j.createElement("html"),c.appendChild(j.createElement("head")),c.appendChild(d=j.createElement("body")),d.innerHTML=a.textContent,j.replaceChild(c,j.documentElement)),g=j.createElement("head"),g.appendChild(f=j.createElement("style")),g.appendChild(e=j.createElement("script")),e.textContent=l,f.textContent=k,i=j.getElementsByTagName("head")[0],i.parentNode.replaceChild(g,i),h(this,"getHeight")});var g;b.sameOriginDataUri?g="data:text/html;charset=utf-8,"+encodeURIComponent("<!doctype html><html><head></head></body>"+a.textContent):g=m,f.setAttribute("src",g);var i=function(){f.contentDocument.body.innerHTML=this.value,h(f,"getHeight")};a.addEventListener("keypress",i),a.addEventListener("keyup",i),a.parentNode.insertBefore(d,a)},p=function(a){var b=document.createElement("div");b.className="preview-code",b.style.position="absolute",b.style.left="-9999px",j.appendChild(b);var c=parseInt(window.getComputedStyle(a).getPropertyValue("max-height"),10),d=function(a){b.textContent=this.value+"\n";var d=b.offsetHeight+2;d>=c?this.style.overflow="auto":this.style.overflow="hidden",this.style.height=b.offsetHeight+2+"px"};a.addEventListener("keypress",d),a.addEventListener("keyup",d),d.call(a)},q=function(){var b=j.getElementsByClassName("settings")[0],c=j.getElementsByClassName("resizeable"),d=30,e=function(b){document.cookie="preview-width="+b,a(c,function(a){b==="auto"&&(b=a.parentNode.offsetWidth),a.style.width=b+"px",h(a.getElementsByTagName("iframe")[0],"getHeight")})},i=f(document.cookie)["preview-width"];if(i){e(i),g(b.getElementsByClassName("is-active"),"is-active");var k=b.querySelector('button[data-width="'+i+'"]');k&&k.classList.add("is-active")}window.addEventListener("message",function(a){if(a.data==null||!a.source)return;var b=a.data,c=document.getElementsByName(a.source.name)[0];b.height!=null&&c&&(c.parentNode.style.height=b.height+d+"px")},!1),b&&c.length>0&&(b.hidden=!1,b.addEventListener("click",function(a){var c=a.target.tagName.toLowerCase(),d;if(c==="button")d=a.target;else{if(c!=="svg")return;d=a.target.parentNode}a.preventDefault(),g(b.getElementsByClassName("is-active"),"is-active"),d.classList.add("is-active");var f=d.dataset.width;e(f)}))}}()})()</script></body></html><!-- Generated with StyleDocco (http://jacobrask.github.com/styledocco). --> diff --git a/lib/web/css/source/components/_modals.less b/lib/web/css/source/components/_modals.less index 51ba451681df5..fb29a74c60585 100644 --- a/lib/web/css/source/components/_modals.less +++ b/lib/web/css/source/components/_modals.less @@ -198,18 +198,14 @@ &._inner-scroll { overflow-y: visible; - .ie11 &, - .ie10 &, - .ie9 & { + .ie11 & { overflow-y: auto; } .modal-inner-wrap { max-height: 90%; - .ie11 &, - .ie10 &, - .ie9 & { + .ie11 & { max-height: none; } } diff --git a/lib/web/css/source/lib/_responsive.less b/lib/web/css/source/lib/_responsive.less index d1bbbae7f6875..efb706f85eac0 100644 --- a/lib/web/css/source/lib/_responsive.less +++ b/lib/web/css/source/lib/_responsive.less @@ -27,24 +27,24 @@ & when (@media-target = 'mobile'), (@media-target = 'all') { - @media only screen and (max-width: (@screen__xxs - 1)) { - .media-width('max', @screen__xxs); + @media only screen and (max-width: @screen__m) { + .media-width('max', (@screen__m + 1)); } - @media only screen and (max-width: (@screen__xs - 1)) { - .media-width('max', @screen__xs); + @media only screen and (max-width: (@screen__m - 1)) { + .media-width('max', @screen__m); } @media only screen and (max-width: (@screen__s - 1)) { .media-width('max', @screen__s); } - @media only screen and (max-width: (@screen__m - 1)) { - .media-width('max', @screen__m); + @media only screen and (max-width: (@screen__xs - 1)) { + .media-width('max', @screen__xs); } - @media only screen and (max-width: @screen__m) { - .media-width('max', (@screen__m + 1)); + @media only screen and (max-width: (@screen__xxs - 1)) { + .media-width('max', @screen__xxs); } @media all and (min-width: @screen__s) { diff --git a/lib/web/mage/adminhtml/browser.js b/lib/web/mage/adminhtml/browser.js index 26d6679bb3ce5..9528e023d3ee0 100644 --- a/lib/web/mage/adminhtml/browser.js +++ b/lib/web/mage/adminhtml/browser.js @@ -435,6 +435,10 @@ define([ }).done($.proxy(function () { self.reload(); self.element.find('#delete_files').toggleClass(self.options.hidden, true); + + $(window).trigger('fileDeleted.mediabrowser', { + ids: ids + }); }, this)); }, diff --git a/lib/web/mage/adminhtml/form.js b/lib/web/mage/adminhtml/form.js index 487c71484e4c5..b363109d80695 100644 --- a/lib/web/mage/adminhtml/form.js +++ b/lib/web/mage/adminhtml/form.js @@ -494,7 +494,8 @@ define([ inputs.each(function (item) { // don't touch hidden inputs (and Use Default inputs too), bc they may have custom logic if ((!item.type || item.type != 'hidden') && !($(item.id + '_inherit') && $(item.id + '_inherit').checked) && //eslint-disable-line - !(currentConfig['can_edit_price'] != undefined && !currentConfig['can_edit_price']) //eslint-disable-line + !(currentConfig['can_edit_price'] != undefined && !currentConfig['can_edit_price']) && //eslint-disable-line + !item.id.endsWith('_inherit') ) { item.disabled = false; jQuery(item).removeClass('ignore-validate'); diff --git a/lib/web/mage/adminhtml/wysiwyg/events.js b/lib/web/mage/adminhtml/wysiwyg/events.js new file mode 100644 index 0000000000000..36c680a7ffe46 --- /dev/null +++ b/lib/web/mage/adminhtml/wysiwyg/events.js @@ -0,0 +1,22 @@ +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ + +define([], function () { + 'use strict'; + + return { + afterInitialization: 'afterInitialization', + afterChangeContent: 'afterChangeContent', + afterUndo: 'afterUndo', + afterPaste: 'afterPaste', + beforeSetContent: 'beforeSetContent', + afterSetContent: 'afterSetContent', + afterSave: 'afterSave', + afterOpenFileBrowser: 'afterOpenFileBrowser', + afterFormSubmit: 'afterFormSubmit', + afterBlur: 'afterBlur', + afterFocus: 'afterFocus' + }; +}); diff --git a/lib/web/mage/adminhtml/wysiwyg/tiny_mce/plugins/magentowidget/editor_plugin.js b/lib/web/mage/adminhtml/wysiwyg/tiny_mce/plugins/magentowidget/editor_plugin.js index 73fd8658854f2..18d71aad2071a 100644 --- a/lib/web/mage/adminhtml/wysiwyg/tiny_mce/plugins/magentowidget/editor_plugin.js +++ b/lib/web/mage/adminhtml/wysiwyg/tiny_mce/plugins/magentowidget/editor_plugin.js @@ -7,7 +7,8 @@ /* eslint-disable strict */ define([ 'wysiwygAdapter', - 'mage/adminhtml/events' + 'mage/adminhtml/events', + 'mage/adminhtml/wysiwyg/widget' ], function (wysiwyg, varienGlobalEvents) { return function (config) { tinymce.create('tinymce.plugins.magentowidget', { diff --git a/lib/web/mage/adminhtml/wysiwyg/tiny_mce/setup.js b/lib/web/mage/adminhtml/wysiwyg/tiny_mce/setup.js index d992947dca6e3..223c6d6ab04ea 100644 --- a/lib/web/mage/adminhtml/wysiwyg/tiny_mce/setup.js +++ b/lib/web/mage/adminhtml/wysiwyg/tiny_mce/setup.js @@ -8,12 +8,14 @@ define([ 'jquery', 'underscore', 'wysiwygAdapter', + 'module', 'mage/translate', 'prototype', 'mage/adminhtml/events', 'mage/adminhtml/browser' -], function (jQuery, _, wysiwygAdapter) { - var wysiwygSetup = Class.create({ +], function (jQuery, _, wysiwygAdapter, module) { + var baseConfig = module.config().config || {}, + wysiwygSetup = Class.create({ wysiwygInstance: null }); @@ -27,7 +29,10 @@ define([ var WysiwygInstancePrototype = new wysiwygAdapter.getAdapterPrototype(); _.bindAll(this, 'openFileBrowser'); + + config = Object.assign({}, baseConfig, config || {}); this.wysiwygInstance = new WysiwygInstancePrototype(htmlId, config); + this.wysiwygInstance.eventBus = this.eventBus = new window.varienEvents(); }, /** @@ -67,6 +72,9 @@ define([ updateContent: function (content) { return this.wysiwygInstance.encodeContent(content); } + }; window.wysiwygSetup = wysiwygSetup; + + return wysiwygSetup; }); diff --git a/lib/web/mage/adminhtml/wysiwyg/tiny_mce/themes/ui.css b/lib/web/mage/adminhtml/wysiwyg/tiny_mce/themes/ui.css index 274dcc124a3a6..27373b2a5147b 100644 --- a/lib/web/mage/adminhtml/wysiwyg/tiny_mce/themes/ui.css +++ b/lib/web/mage/adminhtml/wysiwyg/tiny_mce/themes/ui.css @@ -15,6 +15,8 @@ font-style: normal; font-size: 14px; color: #000; + box-sizing: initial; + word-break: break-all; } .magento-placeholder-error { diff --git a/lib/web/mage/adminhtml/wysiwyg/tiny_mce/tinymce4Adapter.js b/lib/web/mage/adminhtml/wysiwyg/tiny_mce/tinymce4Adapter.js index 8f20243383db8..46a09b28c4a7e 100644 --- a/lib/web/mage/adminhtml/wysiwyg/tiny_mce/tinymce4Adapter.js +++ b/lib/web/mage/adminhtml/wysiwyg/tiny_mce/tinymce4Adapter.js @@ -10,10 +10,11 @@ define([ 'underscore', 'tinymce4', 'mage/adminhtml/events', + 'mage/adminhtml/wysiwyg/events', 'mage/translate', 'prototype', 'jquery/ui' -], function (jQuery, _, tinyMCE4, varienGlobalEvents) { +], function (jQuery, _, tinyMCE4, varienGlobalEvents, wysiwygEvents) { 'use strict'; var tinyMce4Wysiwyg = Class.create(); @@ -72,10 +73,6 @@ define([ this.turnOff(); - if (typeof mode === 'undefined') { - mode = this.mode; - } - if (this.config.plugins) { this.config.plugins.forEach(function (plugin) { var deferred; @@ -105,11 +102,21 @@ define([ } settings = this.getSettings(); - settings.mode = mode; + + if (mode === 'inline') { + settings.inline = true; + + if (!isNaN(settings.toolbarZIndex)) { + tinyMCE4.ui.FloatPanel.zIndex = settings.toolbarZIndex; + } + + varienGlobalEvents.removeEventHandler('tinymceChange', this.onChangeContent); + } jQuery.when.apply(jQuery, deferreds).done(function () { tinyMCE4.init(settings); this.getPluginButtons().hide(); + this.eventBus.attachEventHandler('open_browser_callback', this.openFileBrowser); }.bind(this)); }, @@ -165,10 +172,11 @@ define([ * @return {Object} */ getSettings: function () { - var settings; + var settings, + eventBus = this.eventBus; settings = { - selector: 'textarea#' + this.getId(), + selector: '#' + this.getId(), theme: 'modern', 'entity_encoding': 'raw', 'convert_urls': false, @@ -187,22 +195,35 @@ define([ editor.on('BeforeSetContent', function (evt) { varienGlobalEvents.fireEvent('tinymceBeforeSetContent', evt); + eventBus.fireEvent(wysiwygEvents.beforeSetContent); }); editor.on('SaveContent', function (evt) { varienGlobalEvents.fireEvent('tinymceSaveContent', evt); + eventBus.fireEvent(wysiwygEvents.afterSave); }); editor.on('paste', function (evt) { varienGlobalEvents.fireEvent('tinymcePaste', evt); + eventBus.fireEvent(wysiwygEvents.afterPaste); }); editor.on('PostProcess', function (evt) { varienGlobalEvents.fireEvent('tinymceSaveContent', evt); + eventBus.fireEvent(wysiwygEvents.afterSave); }); editor.on('undo', function (evt) { varienGlobalEvents.fireEvent('tinymceUndo', evt); + eventBus.fireEvent(wysiwygEvents.afterUndo); + }); + + editor.on('focus', function () { + eventBus.fireEvent(wysiwygEvents.afterFocus); + }); + + editor.on('blur', function () { + eventBus.fireEvent(wysiwygEvents.afterBlur); }); /** @@ -210,6 +231,7 @@ define([ */ onChange = function (evt) { varienGlobalEvents.fireEvent('tinymceChange', evt); + eventBus.fireEvent(wysiwygEvents.afterChangeContent); }; editor.on('Change', onChange); @@ -221,6 +243,7 @@ define([ editor.on('init', function (args) { varienGlobalEvents.fireEvent('wysiwygEditorInitialized', args.target); + eventBus.fireEvent(wysiwygEvents.afterInitialization); }); } }; @@ -241,12 +264,15 @@ define([ * @param {*} w */ settings['file_browser_callback'] = function (fieldName, url, objectType, w) { - varienGlobalEvents.fireEvent('open_browser_callback', { + var payload = { win: w, type: objectType, field: fieldName - }); - }; + }; + + varienGlobalEvents.fireEvent('open_browser_callback', payload); + this.eventBus.fireEvent('open_browser_callback', payload); + }.bind(this); } if (this.config.width) { @@ -303,6 +329,15 @@ define([ this.activeEditor().execCommand('mceInsertContent', typeof ui !== 'undefined' ? ui : false, content); }, + /** + * Replace entire contents of wysiwyg with string content parameter + * + * @param {String} content + */ + setContent: function (content) { + this.get(this.getId()).execCommand('mceSetContent', false, content); + }, + /** * Set caret location in WYSIWYG editor. * @@ -491,7 +526,7 @@ define([ * @return {String} */ getContent: function (id) { - return id ? this.get(id).getContent() : this.activeEditor().getContent(); + return id ? this.get(id).getContent() : this.get(this.getId()).getContent(); }, /** @@ -587,7 +622,7 @@ define([ */ encodeDirectives: function (content) { // collect all HTML tags with attributes that contain directives - return content.gsub(/<([a-z0-9\-\_]+[^>]+?)([a-z0-9\-\_]+=".*?\{\{.+?\}\}.*?".*?)>/i, function (match) { + return content.gsub(/<([a-z0-9\-\_]+[^>]+?)([a-z0-9\-\_]+="[^"]*?\{\{.+?\}\}.*?".*?)>/i, function (match) { var attributesString = match[2], decodedDirectiveString; diff --git a/lib/web/mage/adminhtml/wysiwyg/widget.js b/lib/web/mage/adminhtml/wysiwyg/widget.js index d609b3f244f1e..68206fdec6201 100644 --- a/lib/web/mage/adminhtml/wysiwyg/widget.js +++ b/lib/web/mage/adminhtml/wysiwyg/widget.js @@ -275,7 +275,12 @@ define([ } if (e != undefined && e.id) { //eslint-disable-line eqeqeq - widgetCode = Base64.idDecode(e.id); + // attempt to Base64-decode id on selected node; exception is thrown if it is in fact not a widget node + try { + widgetCode = Base64.idDecode(e.id); + } catch (ex) { + return false; + } if (widgetCode.indexOf('{{widget') !== -1) { this.optionValues = new Hash({}); diff --git a/lib/web/mage/collapsible.js b/lib/web/mage/collapsible.js index 97ee3af506f86..245c4a38a6aa9 100644 --- a/lib/web/mage/collapsible.js +++ b/lib/web/mage/collapsible.js @@ -448,6 +448,7 @@ define([ if (this.options.animate) { this._animate(showProps); } else { + this._scrollToTopIfVisible(this.content.get(0).parentElement); this.content.show(); } this._open(); @@ -553,6 +554,27 @@ define([ }, 1); }); } + }, + + /** + * @param {HTMLElement} elem + * @private + */ + _scrollToTopIfVisible: function (elem) { + if (this._isElementOutOfViewport(elem)) { + elem.scrollIntoView(); + } + }, + + /** + * @param {HTMLElement} elem + * @private + * @return {Boolean} + */ + _isElementOutOfViewport: function (elem) { + var rect = elem.getBoundingClientRect(); + + return rect.bottom < 0 || rect.right < 0 || rect.left > window.innerWidth || rect.top > window.innerHeight; } }); diff --git a/lib/web/mage/gallery/gallery.less b/lib/web/mage/gallery/gallery.less index 8f4dd78979018..3c35a772253bc 100644 --- a/lib/web/mage/gallery/gallery.less +++ b/lib/web/mage/gallery/gallery.less @@ -7,7 +7,6 @@ @import '../../css/source/lib/_lib.less'; // Global lib @import '../../css/source/_theme.less'; // Theme overrides @import '../../css/source/_variables.less'; // Local theme variables -@import '../../css/source/lib/_responsive.less'; @import 'module/_mixins.less'; //Mixins in gallery @import 'module/_extends.less'; @import 'module/_focus.less'; @@ -401,10 +400,6 @@ .fotorama-abs-center(); height: @size-fotorama-block; width: @size-fotorama-block; - - .ie9 & { - margin: (-@size-fotorama-block/2) 0 0 (-@size-fotorama-block/2); - } } } @@ -874,10 +869,6 @@ .fotorama__thumb--icon { .fotorama-abs-center(); width: 100%; - - .ie9 & { - margin: (-@fotorama-thumb-arrow/2) 0 0 (-@fotorama-thumb-arrow/2); - } } } .fotorama__thumb__arr--left { diff --git a/lib/web/mage/ie-class-fixer.js b/lib/web/mage/ie-class-fixer.js index 6e89c0779f1a0..683090b1d1386 100644 --- a/lib/web/mage/ie-class-fixer.js +++ b/lib/web/mage/ie-class-fixer.js @@ -7,19 +7,12 @@ (function () { var userAgent = navigator.userAgent, // user agent identifier html = document.documentElement, // html tag - version = 9, // minimal supported version of IE gap = ''; // gap between classes if (html.className) { // check if neighbour class exist in html tag gap = ' '; } // end if - for (version; version <= 10; version++) { // loop from minimal to 10 version of IE - if (userAgent.indexOf('MSIE ' + version) > -1) { // match IE individual name - html.className += gap + 'ie' + version; - } // end if - } - if (userAgent.match(/Trident.*rv[ :]*11\./)) { // Special case for IE11 html.className += gap + 'ie11'; } // end if diff --git a/lib/web/mage/requirejs/resolver.js b/lib/web/mage/requirejs/resolver.js index 5088206dd31d9..6927a3205d94d 100644 --- a/lib/web/mage/requirejs/resolver.js +++ b/lib/web/mage/requirejs/resolver.js @@ -8,11 +8,11 @@ define([ ], function (_) { 'use strict'; - var context = require.s.contexts._, - execCb = context.execCb, - registry = context.registry, - callbacks = [], - retries = 10, + var context = require.s.contexts._, + execCb = context.execCb, + registry = context.registry, + callbacks = [], + retries = 10, updateDelay = 1, ready, update; @@ -28,13 +28,13 @@ define([ } /** - * Checks if provided module is rejected during load. + * Checks if provided module is registered after load. * * @param {Object} module - Module to be checked. * @return {Boolean} */ - function isRejected(module) { - return registry[module.id] && registry[module.id].error; + function isRegistered(module) { + return registry[module.id]; } /** @@ -48,7 +48,7 @@ define([ return false; } - return module.depCount > _.filter(module.depMaps, isRejected).length; + return module.depCount > _.filter(module.depMaps, isRegistered).length; } /** diff --git a/lib/web/mage/utils/template.js b/lib/web/mage/utils/template.js index e29908b7c4e9c..7c50226d6aa3a 100644 --- a/lib/web/mage/utils/template.js +++ b/lib/web/mage/utils/template.js @@ -2,12 +2,15 @@ * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ + +/* eslint-disable no-shadow */ + define([ 'jquery', 'underscore', 'mage/utils/objects', 'mage/utils/strings' -], function (jQuery, _, utils, stringUtils) { +], function ($, _, utils, stringUtils) { 'use strict'; var tmplSettings = _.templateSettings, @@ -176,7 +179,7 @@ define([ if (isTemplate(value)) { list[key] = render(value, tmpl, castString); - } else if (jQuery.isPlainObject(value) || Array.isArray(value)) { + } else if ($.isPlainObject(value) || Array.isArray(value)) { _.each(value, iterate); } }); diff --git a/lib/web/magnifier/magnify.js b/lib/web/magnifier/magnify.js index 34ba6e8e24135..1fb73ea28bff1 100644 --- a/lib/web/magnifier/magnify.js +++ b/lib/web/magnifier/magnify.js @@ -53,21 +53,14 @@ define([ /** * Return width and height of original image - * @param src path for original image + * @param img original image node * @returns {{rw: number, rh: number}} */ - function getImageSize(src) { - var img = new Image(), - imgSize = { - rw: 0, - rh: 0 - }; - - img.src = src; - imgSize.rw = img.width; - imgSize.rh = img.height; - - return imgSize; + function getImageSize(img) { + return { + rw: img.naturalWidth, + rh: img.naturalHeight + }; } /** @@ -192,7 +185,7 @@ define([ if (!e.data.$image || !e.data.$image.length) return; - imageSize = getImageSize($(fullscreenImageSelector)[0].src); + imageSize = getImageSize($(fullscreenImageSelector)[0]); parentWidth = e.data.$image.parent().width(); parentHeight = e.data.$image.parent().height(); isImageSmall = parentWidth >= imageSize.rw && parentHeight >= imageSize.rh; @@ -277,7 +270,6 @@ define([ settings = $.extend(dimentions, { top: top, - bottom: bottom, left: left, right: right }); @@ -332,7 +324,7 @@ define([ if (allowZoomIn && (!transitionEnabled || !transitionActive) && (isTouchEnabled || !$(zoomInButtonSelector).hasClass(zoomInDisabled))) { $image = $(fullscreenImageSelector); - imgOriginalSize = getImageSize($image[0].src); + imgOriginalSize = getImageSize($image[0]); imageWidth = $image.width(); imageHeight = $image.height(); ratio = imageWidth / imageHeight; @@ -557,6 +549,16 @@ define([ trailing: false }); + /** + * Returns top position value for passed jQuery object. + * + * @param $el + * @return {number} + */ + function getTop($el) { + return parseInt($el.get(0).style.top); + } + function shiftImage(dx, dy, e) { var top = +imagePosY + dy, left = +imagePosX + dx, @@ -584,16 +586,13 @@ define([ } if ($image.height() > $imageContainer.height()) { - - if ($imageContainer.offset().top + $imageContainer.height() > top + $image.height()) { - top = $imageContainer.offset().top + $imageContainer.height() - $image.height(); + if ($imageContainer.height() > $image.height() + top) { + $image.css('top', $imageContainer.height() - $image.height()); } else { - top = $imageContainer.offset().top < top ? 0 : top; + top = $image.height() - getTop($image) - $imageContainer.height(); + dy = dy < top ? dy : top; + $image.css('top', getTop($image) + dy); } - $image.offset({ - 'top': top - }); - $image.css('bottom', ''); } if ($image.width() > $imageContainer.width()) { @@ -624,7 +623,7 @@ define([ * @param e - event object */ function dblClickHandler(e) { - var imgOriginalSize = getImageSize($image[0].src), + var imgOriginalSize = getImageSize($image[0]), proportions; if (imgOriginalSize.rh < $image.parent().height() && imgOriginalSize.rw < $image.parent().width()) { @@ -690,7 +689,7 @@ define([ } else if (gallery.fullScreen && (!transitionEnabled || !transitionActive)) { e.preventDefault(); - imagePosY = $image.offset().top; + imagePosY = getTop($image); imagePosX = $image.offset().left; if (isTouchEnabled) { @@ -746,6 +745,7 @@ define([ } if (allowZoomOut) { + imagePosY = getTop($(fullscreenImageSelector, $gallery)); shiftImage(clientX - startX, clientY - startY, e); } } @@ -771,13 +771,13 @@ define([ isFullScreen = $(gallerySelector).data('fotorama').fullScreen, initVars = function () { imagePosX = $(fullscreenImageSelector, $gallery).offset().left; - imagePosY = $(fullscreenImageSelector, $gallery).offset().top; + imagePosY = getTop($(fullscreenImageSelector, $gallery)); }; if (($focus.attr('data-gallery-role') || !$focus.length) && allowZoomOut) { if (isFullScreen) { imagePosX = $(fullscreenImageSelector, $(gallerySelector)).offset().left; - imagePosY = $(fullscreenImageSelector, $(gallerySelector)).offset().top; + imagePosY = getTop($(fullscreenImageSelector, $(gallerySelector))); } if (e.keyCode === 39) { diff --git a/nginx.conf.sample b/nginx.conf.sample index 881adb84c56e3..6f87a9a076666 100644 --- a/nginx.conf.sample +++ b/nginx.conf.sample @@ -102,7 +102,7 @@ location /static/ { rewrite ^/static/(version[^/]+/)?(.*)$ /static/$2 last; } - location ~* \.(ico|jpg|jpeg|png|gif|svg|js|css|swf|eot|ttf|otf|woff|woff2)$ { + location ~* \.(ico|jpg|jpeg|png|gif|svg|js|css|swf|eot|ttf|otf|woff|woff2|json)$ { add_header Cache-Control "public"; add_header X-Frame-Options "SAMEORIGIN"; expires +1y; diff --git a/pub/static/.htaccess b/pub/static/.htaccess index a10e234e07ff2..f49dce25d433e 100644 --- a/pub/static/.htaccess +++ b/pub/static/.htaccess @@ -67,7 +67,7 @@ AddType application/xml xml <IfModule mod_headers.c> - <FilesMatch .*\.(ico|jpg|jpeg|png|gif|svg|js|css|swf|eot|ttf|otf|woff|woff2)$> + <FilesMatch .*\.(ico|jpg|jpeg|png|gif|svg|js|css|swf|eot|ttf|otf|woff|woff2|json)$> Header append Cache-Control public </FilesMatch> @@ -97,12 +97,13 @@ AddType application/xml xml ExpiresByType application/x-bzip2 "access plus 0 seconds" # CSS, JavaScript, html - <FilesMatch \.(css|js|html)$> + <FilesMatch \.(css|js|html|json)$> ExpiresDefault "access plus 1 year" </FilesMatch> ExpiresByType text/css "access plus 1 year" ExpiresByType text/html "access plus 1 year" ExpiresByType application/javascript "access plus 1 year" + ExpiresByType application/json "access plus 1 year" # Favicon, images, flash <FilesMatch \.(ico|gif|png|jpg|jpeg|swf|svg)$> diff --git a/setup/performance-toolkit/benchmark.jmx b/setup/performance-toolkit/benchmark.jmx index 7ee0be37f6cfb..1cab68878bc20 100644 --- a/setup/performance-toolkit/benchmark.jmx +++ b/setup/performance-toolkit/benchmark.jmx @@ -214,6 +214,11 @@ <stringProp name="Argument.value">${__P(admin_browse_product_filter_text,Product)}</stringProp> <stringProp name="Argument.metadata">=</stringProp> </elementProp> + <elementProp name="admin_users_distribution_per_admin_pool" elementType="Argument"> + <stringProp name="Argument.name">admin_users_distribution_per_admin_pool</stringProp> + <stringProp name="Argument.value">${__P(admin_users_distribution_per_admin_pool,1)}</stringProp> + <stringProp name="Argument.metadata">=</stringProp> + </elementProp> <elementProp name="apiBasePercentage" elementType="Argument"> <stringProp name="Argument.name">apiBasePercentage</stringProp> <stringProp name="Argument.value">${__P(apiBasePercentage,0)}</stringProp> @@ -264,6 +269,11 @@ <stringProp name="Argument.value">${__P(browseProductGridPercentage,0)}</stringProp> <stringProp name="Argument.metadata">=</stringProp> </elementProp> + <elementProp name="cache_hits_percentage" elementType="Argument"> + <stringProp name="Argument.name">cache_hits_percentage</stringProp> + <stringProp name="Argument.value">${__P(cache_hits_percentage,100)}</stringProp> + <stringProp name="Argument.metadata">=</stringProp> + </elementProp> <elementProp name="catalogGraphQLPercentage" elementType="Argument"> <stringProp name="Argument.name">catalogGraphQLPercentage</stringProp> <stringProp name="Argument.value">${__P(catalogGraphQLPercentage,0)}</stringProp> @@ -291,7 +301,7 @@ </elementProp> <elementProp name="configurable_products_count" elementType="Argument"> <stringProp name="Argument.name">configurable_products_count</stringProp> - <stringProp name="Argument.value">${__P(configurable_products_count,30)}</stringProp> + <stringProp name="Argument.value">${__P(configurable_products_count,15)}</stringProp> <stringProp name="Argument.metadata">=</stringProp> </elementProp> <elementProp name="csrPoolUsers" elementType="Argument"> @@ -564,8 +574,8 @@ </elementProp> <stringProp name="HTTPSampler.domain">${host}</stringProp> <stringProp name="HTTPSampler.port"/> - <stringProp name="HTTPSampler.connect_timeout"/> - <stringProp name="HTTPSampler.response_timeout"/> + <stringProp name="HTTPSampler.connect_timeout">60000</stringProp> + <stringProp name="HTTPSampler.response_timeout">200000</stringProp> <stringProp name="HTTPSampler.protocol">${request_protocol}</stringProp> <stringProp name="HTTPSampler.contentEncoding">utf-8</stringProp> <stringProp name="HTTPSampler.path"/> @@ -643,7 +653,9 @@ props.remove("category_url_keys_list"); props.remove("category_name"); props.remove("category_names_list"); props.remove("simple_products_list"); +props.remove("simple_products_list_for_edit"); props.remove("configurable_products_list"); +props.remove("configurable_products_list_for_edit"); props.remove("users"); props.remove("customer_emails_list"); @@ -692,8 +704,8 @@ if (!slash.equals(path.substring(path.length() -1)) || !slash.equals(path.substr </elementProp> <stringProp name="HTTPSampler.domain"/> <stringProp name="HTTPSampler.port"/> - <stringProp name="HTTPSampler.connect_timeout"/> - <stringProp name="HTTPSampler.response_timeout"/> + <stringProp name="HTTPSampler.connect_timeout">60000</stringProp> + <stringProp name="HTTPSampler.response_timeout">200000</stringProp> <stringProp name="HTTPSampler.protocol">${request_protocol}</stringProp> <stringProp name="HTTPSampler.contentEncoding"/> <stringProp name="HTTPSampler.path">${base_path}${admin_path}</stringProp> @@ -772,8 +784,8 @@ if (!slash.equals(path.substring(path.length() -1)) || !slash.equals(path.substr </elementProp> <stringProp name="HTTPSampler.domain"/> <stringProp name="HTTPSampler.port"/> - <stringProp name="HTTPSampler.connect_timeout"/> - <stringProp name="HTTPSampler.response_timeout"/> + <stringProp name="HTTPSampler.connect_timeout">60000</stringProp> + <stringProp name="HTTPSampler.response_timeout">200000</stringProp> <stringProp name="HTTPSampler.protocol">${request_protocol}</stringProp> <stringProp name="HTTPSampler.contentEncoding"/> <stringProp name="HTTPSampler.path">${base_path}${admin_path}/admin/dashboard/</stringProp> @@ -841,8 +853,8 @@ if (!slash.equals(path.substring(path.length() -1)) || !slash.equals(path.substr </elementProp> <stringProp name="HTTPSampler.domain"/> <stringProp name="HTTPSampler.port"/> - <stringProp name="HTTPSampler.connect_timeout"/> - <stringProp name="HTTPSampler.response_timeout"/> + <stringProp name="HTTPSampler.connect_timeout">60000</stringProp> + <stringProp name="HTTPSampler.response_timeout">200000</stringProp> <stringProp name="HTTPSampler.protocol">${request_protocol}</stringProp> <stringProp name="HTTPSampler.contentEncoding"/> <stringProp name="HTTPSampler.path">${base_path}rest/V1/integration/admin/token</stringProp> @@ -933,8 +945,8 @@ if (!slash.equals(path.substring(path.length() -1)) || !slash.equals(path.substr </elementProp> <stringProp name="HTTPSampler.domain"/> <stringProp name="HTTPSampler.port"/> - <stringProp name="HTTPSampler.connect_timeout"/> - <stringProp name="HTTPSampler.response_timeout"/> + <stringProp name="HTTPSampler.connect_timeout">60000</stringProp> + <stringProp name="HTTPSampler.response_timeout">200000</stringProp> <stringProp name="HTTPSampler.protocol">${request_protocol}</stringProp> <stringProp name="HTTPSampler.contentEncoding"/> <stringProp name="HTTPSampler.path">${base_path}rest/V1/categories/list</stringProp> @@ -1044,6 +1056,186 @@ props.put("category_name", vars.get("category_name"));</stringProp> <hashTree/> </hashTree> + <TestFragmentController guiclass="TestFragmentControllerGui" testclass="TestFragmentController" testname="Extract categories id of last level" enabled="true"> + <stringProp name="TestPlan.comments">mpaf/tool/fragments/ce/setup/extract_categories_id_of_last_level.jmx</stringProp> +</TestFragmentController> + <hashTree> + <BeanShellSampler guiclass="BeanShellSamplerGui" testclass="BeanShellSampler" testname="SetUp - BeanShell Sampler: Clear Admin Category Management properties" enabled="true"> + <stringProp name="BeanShellSampler.query">props.remove("admin_category_ids_list");</stringProp> + <stringProp name="BeanShellSampler.filename"/> + <stringProp name="BeanShellSampler.parameters"/> + <boolProp name="BeanShellSampler.resetInterpreter">false</boolProp> + </BeanShellSampler> + <hashTree/> + <GenericController guiclass="LogicControllerGui" testclass="GenericController" testname="Get categories of last level" enabled="true"/> + <hashTree> + <HeaderManager guiclass="HeaderPanel" testclass="HeaderManager" testname="HTTP Header Manager" enabled="true"> + <collectionProp name="HeaderManager.headers"> + <elementProp name="" elementType="Header"> + <stringProp name="Header.name">Content-Type</stringProp> + <stringProp name="Header.value">application/json</stringProp> + </elementProp> + <elementProp name="" elementType="Header"> + <stringProp name="Header.name">Accept</stringProp> + <stringProp name="Header.value">*/*</stringProp> + </elementProp> + </collectionProp> + </HeaderManager> + <hashTree/> + <HTTPSamplerProxy guiclass="HttpTestSampleGui" testclass="HTTPSamplerProxy" testname="SetUp - Admin Token Retrieval" enabled="true"> + <boolProp name="HTTPSampler.postBodyRaw">true</boolProp> + <elementProp name="HTTPsampler.Arguments" elementType="Arguments"> + <collectionProp name="Arguments.arguments"> + <elementProp name="" elementType="HTTPArgument"> + <boolProp name="HTTPArgument.always_encode">false</boolProp> + <stringProp name="Argument.value">{"username":"${admin_user}","password":"${admin_password}"}</stringProp> + <stringProp name="Argument.metadata">=</stringProp> + </elementProp> + </collectionProp> + </elementProp> + <stringProp name="HTTPSampler.domain"/> + <stringProp name="HTTPSampler.port"/> + <stringProp name="HTTPSampler.connect_timeout">60000</stringProp> + <stringProp name="HTTPSampler.response_timeout">200000</stringProp> + <stringProp name="HTTPSampler.protocol">${request_protocol}</stringProp> + <stringProp name="HTTPSampler.contentEncoding"/> + <stringProp name="HTTPSampler.path">${base_path}rest/V1/integration/admin/token</stringProp> + <stringProp name="HTTPSampler.method">POST</stringProp> + <boolProp name="HTTPSampler.follow_redirects">true</boolProp> + <boolProp name="HTTPSampler.auto_redirects">false</boolProp> + <boolProp name="HTTPSampler.use_keepalive">true</boolProp> + <boolProp name="HTTPSampler.DO_MULTIPART_POST">false</boolProp> + <boolProp name="HTTPSampler.monitor">false</boolProp> + <stringProp name="HTTPSampler.embedded_url_re"/> + </HTTPSamplerProxy> + <hashTree> + <com.atlantbh.jmeter.plugins.jsonutils.jsonpathextractor.JSONPathExtractor guiclass="com.atlantbh.jmeter.plugins.jsonutils.jsonpathextractor.gui.JSONPathExtractorGui" testclass="com.atlantbh.jmeter.plugins.jsonutils.jsonpathextractor.JSONPathExtractor" testname="jp@gc - JSON Path Extractor" enabled="true"> + <stringProp name="VAR">admin_token</stringProp> + <stringProp name="JSONPATH">$</stringProp> + <stringProp name="DEFAULT"/> + <stringProp name="VARIABLE"/> + <stringProp name="SUBJECT">BODY</stringProp> + </com.atlantbh.jmeter.plugins.jsonutils.jsonpathextractor.JSONPathExtractor> + <hashTree/> + <ResponseAssertion guiclass="AssertionGui" testclass="ResponseAssertion" testname="Assert token not null" enabled="true"> + <collectionProp name="Asserion.test_strings"> + <stringProp name="484395188">^[a-z0-9-]+$</stringProp> + </collectionProp> + <stringProp name="Assertion.test_field">Assertion.response_data</stringProp> + <boolProp name="Assertion.assume_success">false</boolProp> + <intProp name="Assertion.test_type">1</intProp> + <stringProp name="Assertion.scope">variable</stringProp> + <stringProp name="Scope.variable">admin_token</stringProp> + </ResponseAssertion> + <hashTree/> + </hashTree> + <HeaderManager guiclass="HeaderPanel" testclass="HeaderManager" testname="HTTP Header Manager" enabled="true"> + <collectionProp name="HeaderManager.headers"> + <elementProp name="" elementType="Header"> + <stringProp name="Header.name">Authorization</stringProp> + <stringProp name="Header.value">Bearer ${admin_token}</stringProp> + </elementProp> + </collectionProp> + </HeaderManager> + <hashTree/> + <HTTPSamplerProxy guiclass="HttpTestSampleGui" testclass="HTTPSamplerProxy" testname="SetUp - API Get categories" enabled="true"> + <elementProp name="HTTPsampler.Arguments" elementType="Arguments" guiclass="HTTPArgumentsPanel" testclass="Arguments" enabled="true"> + <collectionProp name="Arguments.arguments"> + <elementProp name="searchCriteria[filterGroups][0][filters][0][field]" elementType="HTTPArgument"> + <boolProp name="HTTPArgument.always_encode">true</boolProp> + <stringProp name="Argument.value">children_count</stringProp> + <stringProp name="Argument.metadata">=</stringProp> + <boolProp name="HTTPArgument.use_equals">true</boolProp> + <stringProp name="Argument.name">searchCriteria[filterGroups][0][filters][0][field]</stringProp> + </elementProp> + <elementProp name="searchCriteria[filterGroups][0][filters][0][value]" elementType="HTTPArgument"> + <boolProp name="HTTPArgument.always_encode">true</boolProp> + <stringProp name="Argument.value">0</stringProp> + <stringProp name="Argument.metadata">=</stringProp> + <boolProp name="HTTPArgument.use_equals">true</boolProp> + <stringProp name="Argument.name">searchCriteria[filterGroups][0][filters][0][value]</stringProp> + </elementProp> + <elementProp name="searchCriteria[filterGroups][1][filters][0][field]" elementType="HTTPArgument"> + <boolProp name="HTTPArgument.always_encode">true</boolProp> + <stringProp name="Argument.value">level</stringProp> + <stringProp name="Argument.metadata">=</stringProp> + <boolProp name="HTTPArgument.use_equals">true</boolProp> + <stringProp name="Argument.name">searchCriteria[filterGroups][1][filters][0][field]</stringProp> + </elementProp> + <elementProp name="searchCriteria[filterGroups][1][filters][0][value]" elementType="HTTPArgument"> + <boolProp name="HTTPArgument.always_encode">true</boolProp> + <stringProp name="Argument.value">2</stringProp> + <stringProp name="Argument.metadata">=</stringProp> + <boolProp name="HTTPArgument.use_equals">true</boolProp> + <stringProp name="Argument.name">searchCriteria[filterGroups][1][filters][0][value]</stringProp> + </elementProp> + <elementProp name="searchCriteria[filterGroups][1][filters][0][conditionType]" elementType="HTTPArgument"> + <boolProp name="HTTPArgument.always_encode">true</boolProp> + <stringProp name="Argument.value">gt</stringProp> + <stringProp name="Argument.metadata">=</stringProp> + <boolProp name="HTTPArgument.use_equals">true</boolProp> + <stringProp name="Argument.name">searchCriteria[filterGroups][1][filters][0][conditionType]</stringProp> + </elementProp> + <elementProp name="searchCriteria[pageSize]" elementType="HTTPArgument"> + <boolProp name="HTTPArgument.always_encode">true</boolProp> + <stringProp name="Argument.value">${adminCategoryCount}</stringProp> + <stringProp name="Argument.metadata">=</stringProp> + <boolProp name="HTTPArgument.use_equals">true</boolProp> + <stringProp name="Argument.name">searchCriteria[pageSize]</stringProp> + </elementProp> + </collectionProp> + </elementProp> + <stringProp name="HTTPSampler.domain"/> + <stringProp name="HTTPSampler.port"/> + <stringProp name="HTTPSampler.connect_timeout">60000</stringProp> + <stringProp name="HTTPSampler.response_timeout">200000</stringProp> + <stringProp name="HTTPSampler.protocol">${request_protocol}</stringProp> + <stringProp name="HTTPSampler.contentEncoding"/> + <stringProp name="HTTPSampler.path">${base_path}rest/default/V1/categories/list</stringProp> + <stringProp name="HTTPSampler.method">GET</stringProp> + <boolProp name="HTTPSampler.follow_redirects">true</boolProp> + <boolProp name="HTTPSampler.auto_redirects">false</boolProp> + <boolProp name="HTTPSampler.use_keepalive">true</boolProp> + <boolProp name="HTTPSampler.DO_MULTIPART_POST">false</boolProp> + <boolProp name="HTTPSampler.monitor">false</boolProp> + <stringProp name="HTTPSampler.embedded_url_re"/> + </HTTPSamplerProxy> + <hashTree> + <RegexExtractor guiclass="RegexExtractorGui" testclass="RegexExtractor" testname="Regular Expression Extractor" enabled="true"> + <stringProp name="RegexExtractor.useHeaders">false</stringProp> + <stringProp name="RegexExtractor.refname">category_list_id</stringProp> + <stringProp name="RegexExtractor.regex">\{\"id\":(\d+),</stringProp> + <stringProp name="RegexExtractor.template">$1$</stringProp> + <stringProp name="RegexExtractor.default"/> + <stringProp name="RegexExtractor.match_number">-1</stringProp> + </RegexExtractor> + <hashTree/> + </hashTree> + <ForeachController guiclass="ForeachControlPanel" testclass="ForeachController" testname="ForEach Category Id" enabled="true"> + <stringProp name="ForeachController.inputVal">category_list_id</stringProp> + <stringProp name="ForeachController.returnVal">category_id</stringProp> + <boolProp name="ForeachController.useSeparator">true</boolProp> + </ForeachController> + <hashTree> + <BeanShellSampler guiclass="BeanShellSamplerGui" testclass="BeanShellSampler" testname="Process categories ids" enabled="true"> + <stringProp name="BeanShellSampler.query">import java.util.ArrayList; + +adminCategoryIdsList = props.get("admin_category_ids_list"); +// If it is first iteration of cycle then recreate categories ids list +if (adminCategoryIdsList == null) { + adminCategoryIdsList = new ArrayList(); + props.put("admin_category_ids_list", adminCategoryIdsList); +} +adminCategoryIdsList.add(vars.get("category_id"));</stringProp> + <stringProp name="BeanShellSampler.filename"/> + <stringProp name="BeanShellSampler.parameters"/> + <boolProp name="BeanShellSampler.resetInterpreter">false</boolProp> + </BeanShellSampler> + <hashTree/> + </hashTree> + </hashTree> + </hashTree> + <TestFragmentController guiclass="TestFragmentControllerGui" testclass="TestFragmentController" testname="Extract configurable products" enabled="true"> <stringProp name="TestPlan.comments">mpaf/tool/fragments/ce/setup/extract_configurable_products.jmx</stringProp> </TestFragmentController> @@ -1076,8 +1268,420 @@ props.put("category_name", vars.get("category_name"));</stringProp> </elementProp> <stringProp name="HTTPSampler.domain"/> <stringProp name="HTTPSampler.port"/> - <stringProp name="HTTPSampler.connect_timeout"/> - <stringProp name="HTTPSampler.response_timeout"/> + <stringProp name="HTTPSampler.connect_timeout">60000</stringProp> + <stringProp name="HTTPSampler.response_timeout">200000</stringProp> + <stringProp name="HTTPSampler.protocol">${request_protocol}</stringProp> + <stringProp name="HTTPSampler.contentEncoding"/> + <stringProp name="HTTPSampler.path">${base_path}rest/V1/integration/admin/token</stringProp> + <stringProp name="HTTPSampler.method">POST</stringProp> + <boolProp name="HTTPSampler.follow_redirects">true</boolProp> + <boolProp name="HTTPSampler.auto_redirects">false</boolProp> + <boolProp name="HTTPSampler.use_keepalive">true</boolProp> + <boolProp name="HTTPSampler.DO_MULTIPART_POST">false</boolProp> + <boolProp name="HTTPSampler.monitor">false</boolProp> + <stringProp name="HTTPSampler.embedded_url_re"/> + </HTTPSamplerProxy> + <hashTree> + <com.atlantbh.jmeter.plugins.jsonutils.jsonpathextractor.JSONPathExtractor guiclass="com.atlantbh.jmeter.plugins.jsonutils.jsonpathextractor.gui.JSONPathExtractorGui" testclass="com.atlantbh.jmeter.plugins.jsonutils.jsonpathextractor.JSONPathExtractor" testname="jp@gc - JSON Path Extractor" enabled="true"> + <stringProp name="VAR">admin_token</stringProp> + <stringProp name="JSONPATH">$</stringProp> + <stringProp name="DEFAULT"/> + <stringProp name="VARIABLE"/> + <stringProp name="SUBJECT">BODY</stringProp> + </com.atlantbh.jmeter.plugins.jsonutils.jsonpathextractor.JSONPathExtractor> + <hashTree/> + <ResponseAssertion guiclass="AssertionGui" testclass="ResponseAssertion" testname="Assert token not null" enabled="true"> + <collectionProp name="Asserion.test_strings"> + <stringProp name="484395188">^[a-z0-9-]+$</stringProp> + </collectionProp> + <stringProp name="Assertion.test_field">Assertion.response_data</stringProp> + <boolProp name="Assertion.assume_success">false</boolProp> + <intProp name="Assertion.test_type">1</intProp> + <stringProp name="Assertion.scope">variable</stringProp> + <stringProp name="Scope.variable">admin_token</stringProp> + </ResponseAssertion> + <hashTree/> + </hashTree> + <HeaderManager guiclass="HeaderPanel" testclass="HeaderManager" testname="HTTP Header Manager" enabled="true"> + <collectionProp name="HeaderManager.headers"> + <elementProp name="" elementType="Header"> + <stringProp name="Header.name">Authorization</stringProp> + <stringProp name="Header.value">Bearer ${admin_token}</stringProp> + </elementProp> + </collectionProp> + </HeaderManager> + <hashTree/> + <HTTPSamplerProxy guiclass="HttpTestSampleGui" testclass="HTTPSamplerProxy" testname="SetUp - Get configurable products" enabled="true"> + <elementProp name="HTTPsampler.Arguments" elementType="Arguments" guiclass="HTTPArgumentsPanel" testclass="Arguments" testname="User Defined Variables" enabled="true"> + <collectionProp name="Arguments.arguments"> + <elementProp name="searchCriteria[filterGroups][0][filters][0][field]" elementType="HTTPArgument"> + <boolProp name="HTTPArgument.always_encode">true</boolProp> + <stringProp name="Argument.value">type_id</stringProp> + <stringProp name="Argument.metadata">=</stringProp> + <boolProp name="HTTPArgument.use_equals">true</boolProp> + <stringProp name="Argument.name">searchCriteria[filterGroups][0][filters][0][field]</stringProp> + </elementProp> + <elementProp name="searchCriteria[filterGroups][0][filters][0][value]" elementType="HTTPArgument"> + <boolProp name="HTTPArgument.always_encode">true</boolProp> + <stringProp name="Argument.value">configurable</stringProp> + <stringProp name="Argument.metadata">=</stringProp> + <boolProp name="HTTPArgument.use_equals">true</boolProp> + <stringProp name="Argument.name">searchCriteria[filterGroups][0][filters][0][value]</stringProp> + </elementProp> + <elementProp name="searchCriteria[pageSize]" elementType="HTTPArgument"> + <boolProp name="HTTPArgument.always_encode">true</boolProp> + <stringProp name="Argument.value">${configurable_products_count}</stringProp> + <stringProp name="Argument.metadata">=</stringProp> + <boolProp name="HTTPArgument.use_equals">true</boolProp> + <stringProp name="Argument.name">searchCriteria[pageSize]</stringProp> + </elementProp> + </collectionProp> + </elementProp> + <stringProp name="HTTPSampler.domain"/> + <stringProp name="HTTPSampler.port"/> + <stringProp name="HTTPSampler.connect_timeout">60000</stringProp> + <stringProp name="HTTPSampler.response_timeout">200000</stringProp> + <stringProp name="HTTPSampler.protocol">${request_protocol}</stringProp> + <stringProp name="HTTPSampler.contentEncoding"/> + <stringProp name="HTTPSampler.path">${base_path}rest/V1/products</stringProp> + <stringProp name="HTTPSampler.method">GET</stringProp> + <boolProp name="HTTPSampler.follow_redirects">true</boolProp> + <boolProp name="HTTPSampler.auto_redirects">false</boolProp> + <boolProp name="HTTPSampler.use_keepalive">true</boolProp> + <boolProp name="HTTPSampler.DO_MULTIPART_POST">false</boolProp> + <boolProp name="HTTPSampler.monitor">false</boolProp> + <stringProp name="HTTPSampler.embedded_url_re"/> + </HTTPSamplerProxy> + <hashTree> + <RegexExtractor guiclass="RegexExtractorGui" testclass="RegexExtractor" testname="Regular Expression Extractor: Extract product url keys" enabled="true"> + <stringProp name="RegexExtractor.useHeaders">false</stringProp> + <stringProp name="RegexExtractor.refname">configurable_products_url_keys</stringProp> + <stringProp name="RegexExtractor.regex">url_key\",\"value\":\"(.*?)\"</stringProp> + <stringProp name="RegexExtractor.template">$1$</stringProp> + <stringProp name="RegexExtractor.default"/> + <stringProp name="RegexExtractor.match_number">-1</stringProp> + </RegexExtractor> + <hashTree/> + <RegexExtractor guiclass="RegexExtractorGui" testclass="RegexExtractor" testname="Regular Expression Extractor: Extract product ids" enabled="true"> + <stringProp name="RegexExtractor.useHeaders">false</stringProp> + <stringProp name="RegexExtractor.refname">configurable_product_ids</stringProp> + <stringProp name="RegexExtractor.regex">\"id\":(\d+),</stringProp> + <stringProp name="RegexExtractor.template">$1$</stringProp> + <stringProp name="RegexExtractor.default"/> + <stringProp name="RegexExtractor.match_number">-1</stringProp> + </RegexExtractor> + <hashTree/> + <RegexExtractor guiclass="RegexExtractorGui" testclass="RegexExtractor" testname="Regular Expression Extractor: Extract product titles" enabled="true"> + <stringProp name="RegexExtractor.useHeaders">false</stringProp> + <stringProp name="RegexExtractor.refname">configurable_product_names</stringProp> + <stringProp name="RegexExtractor.regex">name\":\"(.*?)\"</stringProp> + <stringProp name="RegexExtractor.template">$1$</stringProp> + <stringProp name="RegexExtractor.default"/> + <stringProp name="RegexExtractor.match_number">-1</stringProp> + </RegexExtractor> + <hashTree/> + <RegexExtractor guiclass="RegexExtractorGui" testclass="RegexExtractor" testname="Regular Expression Extractor: Extract product skus" enabled="true"> + <stringProp name="RegexExtractor.useHeaders">false</stringProp> + <stringProp name="RegexExtractor.refname">configurable_product_skus</stringProp> + <stringProp name="RegexExtractor.regex">sku\":\"(.*?)\"</stringProp> + <stringProp name="RegexExtractor.template">$1$</stringProp> + <stringProp name="RegexExtractor.default"/> + <stringProp name="RegexExtractor.match_number">-1</stringProp> + </RegexExtractor> + <hashTree/> + </hashTree> + </hashTree> + <ForeachController guiclass="ForeachControlPanel" testclass="ForeachController" testname="ForEach Controller: Prepare configurable products" enabled="true"> + <stringProp name="ForeachController.inputVal">configurable_product_ids</stringProp> + <stringProp name="ForeachController.returnVal">configurable_product_id</stringProp> + <boolProp name="ForeachController.useSeparator">true</boolProp> + </ForeachController> + <hashTree> + <CounterConfig guiclass="CounterConfigGui" testclass="CounterConfig" testname="Counter" enabled="true"> + <stringProp name="CounterConfig.start">1</stringProp> + <stringProp name="CounterConfig.end"/> + <stringProp name="CounterConfig.incr">1</stringProp> + <stringProp name="CounterConfig.name">configurable_products_counter</stringProp> + <stringProp name="CounterConfig.format"/> + <boolProp name="CounterConfig.per_user">false</boolProp> + </CounterConfig> + <hashTree/> + <BeanShellSampler guiclass="BeanShellSamplerGui" testclass="BeanShellSampler" testname="SetUp - BeanShell Sampler: Collect configurable product" enabled="true"> + <stringProp name="BeanShellSampler.query">import java.util.ArrayList; +import java.util.HashMap; +import org.apache.commons.codec.binary.Base64; + +// If it is first iteration of cycle then recreate productList +if (1 == Integer.parseInt(vars.get("configurable_products_counter"))) { + productList = new ArrayList(); + props.put("configurable_products_list", productList); +} else { + productList = props.get("configurable_products_list"); +} + +String productUrl = vars.get("request_protocol") + "://" + vars.get("host") + vars.get("base_path") + vars.get("configurable_products_url_keys_" + vars.get("configurable_products_counter"))+ vars.get("url_suffix"); +encodedUrl = Base64.encodeBase64(productUrl.getBytes()); +// Create product map +Map productMap = new HashMap(); +productMap.put("id", vars.get("configurable_product_id")); +productMap.put("title", vars.get("configurable_product_names_" + vars.get("configurable_products_counter"))); +productMap.put("sku", vars.get("configurable_product_skus_" + vars.get("configurable_products_counter"))); +productMap.put("url_key", vars.get("configurable_products_url_keys_" + vars.get("configurable_products_counter"))); +productMap.put("uenc", new String(encodedUrl)); + +// Collect products map in products list +productList.add(productMap);</stringProp> + <stringProp name="BeanShellSampler.filename"/> + <stringProp name="BeanShellSampler.parameters"/> + <boolProp name="BeanShellSampler.resetInterpreter">false</boolProp> + </BeanShellSampler> + <hashTree/> + </hashTree> + </hashTree> + + <TestFragmentController guiclass="TestFragmentControllerGui" testclass="TestFragmentController" testname="Extract configurable products for edit" enabled="true"> + <stringProp name="TestPlan.comments">mpaf/tool/fragments/ce/setup/extract_configurable_products_for_edit.jmx</stringProp> +</TestFragmentController> + <hashTree> + <GenericController guiclass="LogicControllerGui" testclass="GenericController" testname="SetUp - Retrieve configurable products for edit" enabled="true"/> + <hashTree> + <HeaderManager guiclass="HeaderPanel" testclass="HeaderManager" testname="HTTP Header Manager" enabled="true"> + <collectionProp name="HeaderManager.headers"> + <elementProp name="" elementType="Header"> + <stringProp name="Header.name">Content-Type</stringProp> + <stringProp name="Header.value">application/json</stringProp> + </elementProp> + <elementProp name="" elementType="Header"> + <stringProp name="Header.name">Accept</stringProp> + <stringProp name="Header.value">*/*</stringProp> + </elementProp> + </collectionProp> + </HeaderManager> + <hashTree/> + <HTTPSamplerProxy guiclass="HttpTestSampleGui" testclass="HTTPSamplerProxy" testname="SetUp - Admin Token Retrieval" enabled="true"> + <boolProp name="HTTPSampler.postBodyRaw">true</boolProp> + <elementProp name="HTTPsampler.Arguments" elementType="Arguments"> + <collectionProp name="Arguments.arguments"> + <elementProp name="" elementType="HTTPArgument"> + <boolProp name="HTTPArgument.always_encode">false</boolProp> + <stringProp name="Argument.value">{"username":"${admin_user}","password":"${admin_password}"}</stringProp> + <stringProp name="Argument.metadata">=</stringProp> + </elementProp> + </collectionProp> + </elementProp> + <stringProp name="HTTPSampler.domain"/> + <stringProp name="HTTPSampler.port"/> + <stringProp name="HTTPSampler.connect_timeout">60000</stringProp> + <stringProp name="HTTPSampler.response_timeout">200000</stringProp> + <stringProp name="HTTPSampler.protocol">${request_protocol}</stringProp> + <stringProp name="HTTPSampler.contentEncoding"/> + <stringProp name="HTTPSampler.path">${base_path}rest/V1/integration/admin/token</stringProp> + <stringProp name="HTTPSampler.method">POST</stringProp> + <boolProp name="HTTPSampler.follow_redirects">true</boolProp> + <boolProp name="HTTPSampler.auto_redirects">false</boolProp> + <boolProp name="HTTPSampler.use_keepalive">true</boolProp> + <boolProp name="HTTPSampler.DO_MULTIPART_POST">false</boolProp> + <boolProp name="HTTPSampler.monitor">false</boolProp> + <stringProp name="HTTPSampler.embedded_url_re"/> + </HTTPSamplerProxy> + <hashTree> + <com.atlantbh.jmeter.plugins.jsonutils.jsonpathextractor.JSONPathExtractor guiclass="com.atlantbh.jmeter.plugins.jsonutils.jsonpathextractor.gui.JSONPathExtractorGui" testclass="com.atlantbh.jmeter.plugins.jsonutils.jsonpathextractor.JSONPathExtractor" testname="jp@gc - JSON Path Extractor" enabled="true"> + <stringProp name="VAR">admin_token</stringProp> + <stringProp name="JSONPATH">$</stringProp> + <stringProp name="DEFAULT"/> + <stringProp name="VARIABLE"/> + <stringProp name="SUBJECT">BODY</stringProp> + </com.atlantbh.jmeter.plugins.jsonutils.jsonpathextractor.JSONPathExtractor> + <hashTree/> + <ResponseAssertion guiclass="AssertionGui" testclass="ResponseAssertion" testname="Assert token not null" enabled="true"> + <collectionProp name="Asserion.test_strings"> + <stringProp name="484395188">^[a-z0-9-]+$</stringProp> + </collectionProp> + <stringProp name="Assertion.test_field">Assertion.response_data</stringProp> + <boolProp name="Assertion.assume_success">false</boolProp> + <intProp name="Assertion.test_type">1</intProp> + <stringProp name="Assertion.scope">variable</stringProp> + <stringProp name="Scope.variable">admin_token</stringProp> + </ResponseAssertion> + <hashTree/> + </hashTree> + <HeaderManager guiclass="HeaderPanel" testclass="HeaderManager" testname="HTTP Header Manager" enabled="true"> + <collectionProp name="HeaderManager.headers"> + <elementProp name="" elementType="Header"> + <stringProp name="Header.name">Authorization</stringProp> + <stringProp name="Header.value">Bearer ${admin_token}</stringProp> + </elementProp> + </collectionProp> + </HeaderManager> + <hashTree/> + <HTTPSamplerProxy guiclass="HttpTestSampleGui" testclass="HTTPSamplerProxy" testname="SetUp - Get configurable products for edit" enabled="true"> + <elementProp name="HTTPsampler.Arguments" elementType="Arguments" guiclass="HTTPArgumentsPanel" testclass="Arguments" testname="User Defined Variables" enabled="true"> + <collectionProp name="Arguments.arguments"> + <elementProp name="searchCriteria[filterGroups][0][filters][0][field]" elementType="HTTPArgument"> + <boolProp name="HTTPArgument.always_encode">true</boolProp> + <stringProp name="Argument.value">type_id</stringProp> + <stringProp name="Argument.metadata">=</stringProp> + <boolProp name="HTTPArgument.use_equals">true</boolProp> + <stringProp name="Argument.name">searchCriteria[filterGroups][0][filters][0][field]</stringProp> + </elementProp> + <elementProp name="searchCriteria[filterGroups][0][filters][0][value]" elementType="HTTPArgument"> + <boolProp name="HTTPArgument.always_encode">true</boolProp> + <stringProp name="Argument.value">configurable</stringProp> + <stringProp name="Argument.metadata">=</stringProp> + <boolProp name="HTTPArgument.use_equals">true</boolProp> + <stringProp name="Argument.name">searchCriteria[filterGroups][0][filters][0][value]</stringProp> + </elementProp> + <elementProp name="searchCriteria[pageSize]" elementType="HTTPArgument"> + <boolProp name="HTTPArgument.always_encode">true</boolProp> + <stringProp name="Argument.value">${configurable_products_count}</stringProp> + <stringProp name="Argument.metadata">=</stringProp> + <boolProp name="HTTPArgument.use_equals">true</boolProp> + <stringProp name="Argument.name">searchCriteria[pageSize]</stringProp> + </elementProp> + <elementProp name="searchCriteria[currentPage]" elementType="HTTPArgument"> + <boolProp name="HTTPArgument.always_encode">true</boolProp> + <stringProp name="Argument.value">2</stringProp> + <stringProp name="Argument.metadata">=</stringProp> + <boolProp name="HTTPArgument.use_equals">true</boolProp> + <stringProp name="Argument.name">searchCriteria[currentPage]</stringProp> + </elementProp> + </collectionProp> + </elementProp> + <stringProp name="HTTPSampler.domain"/> + <stringProp name="HTTPSampler.port"/> + <stringProp name="HTTPSampler.connect_timeout">60000</stringProp> + <stringProp name="HTTPSampler.response_timeout">200000</stringProp> + <stringProp name="HTTPSampler.protocol">${request_protocol}</stringProp> + <stringProp name="HTTPSampler.contentEncoding"/> + <stringProp name="HTTPSampler.path">${base_path}rest/V1/products</stringProp> + <stringProp name="HTTPSampler.method">GET</stringProp> + <boolProp name="HTTPSampler.follow_redirects">true</boolProp> + <boolProp name="HTTPSampler.auto_redirects">false</boolProp> + <boolProp name="HTTPSampler.use_keepalive">true</boolProp> + <boolProp name="HTTPSampler.DO_MULTIPART_POST">false</boolProp> + <boolProp name="HTTPSampler.monitor">false</boolProp> + <stringProp name="HTTPSampler.embedded_url_re"/> + </HTTPSamplerProxy> + <hashTree> + <RegexExtractor guiclass="RegexExtractorGui" testclass="RegexExtractor" testname="Regular Expression Extractor: Extract product url keys" enabled="true"> + <stringProp name="RegexExtractor.useHeaders">false</stringProp> + <stringProp name="RegexExtractor.refname">configurable_products_for_edit_url_keys</stringProp> + <stringProp name="RegexExtractor.regex">url_key\",\"value\":\"(.*?)\"</stringProp> + <stringProp name="RegexExtractor.template">$1$</stringProp> + <stringProp name="RegexExtractor.default"/> + <stringProp name="RegexExtractor.match_number">-1</stringProp> + </RegexExtractor> + <hashTree/> + <RegexExtractor guiclass="RegexExtractorGui" testclass="RegexExtractor" testname="Regular Expression Extractor: Extract product ids" enabled="true"> + <stringProp name="RegexExtractor.useHeaders">false</stringProp> + <stringProp name="RegexExtractor.refname">configurable_product_for_edit_ids</stringProp> + <stringProp name="RegexExtractor.regex">\"id\":(\d+),</stringProp> + <stringProp name="RegexExtractor.template">$1$</stringProp> + <stringProp name="RegexExtractor.default"/> + <stringProp name="RegexExtractor.match_number">-1</stringProp> + </RegexExtractor> + <hashTree/> + <RegexExtractor guiclass="RegexExtractorGui" testclass="RegexExtractor" testname="Regular Expression Extractor: Extract product titles" enabled="true"> + <stringProp name="RegexExtractor.useHeaders">false</stringProp> + <stringProp name="RegexExtractor.refname">configurable_product_for_edit_names</stringProp> + <stringProp name="RegexExtractor.regex">name\":\"(.*?)\"</stringProp> + <stringProp name="RegexExtractor.template">$1$</stringProp> + <stringProp name="RegexExtractor.default"/> + <stringProp name="RegexExtractor.match_number">-1</stringProp> + </RegexExtractor> + <hashTree/> + <RegexExtractor guiclass="RegexExtractorGui" testclass="RegexExtractor" testname="Regular Expression Extractor: Extract product skus" enabled="true"> + <stringProp name="RegexExtractor.useHeaders">false</stringProp> + <stringProp name="RegexExtractor.refname">configurable_product_for_edit_skus</stringProp> + <stringProp name="RegexExtractor.regex">sku\":\"(.*?)\"</stringProp> + <stringProp name="RegexExtractor.template">$1$</stringProp> + <stringProp name="RegexExtractor.default"/> + <stringProp name="RegexExtractor.match_number">-1</stringProp> + </RegexExtractor> + <hashTree/> + </hashTree> + </hashTree> + <ForeachController guiclass="ForeachControlPanel" testclass="ForeachController" testname="ForEach Controller: Prepare configurable products for edit" enabled="true"> + <stringProp name="ForeachController.inputVal">configurable_product_for_edit_ids</stringProp> + <stringProp name="ForeachController.returnVal">configurable_product_for_edit_id</stringProp> + <boolProp name="ForeachController.useSeparator">true</boolProp> + </ForeachController> + <hashTree> + <CounterConfig guiclass="CounterConfigGui" testclass="CounterConfig" testname="Counter for edit" enabled="true"> + <stringProp name="CounterConfig.start">1</stringProp> + <stringProp name="CounterConfig.end"/> + <stringProp name="CounterConfig.incr">1</stringProp> + <stringProp name="CounterConfig.name">configurable_products_counter_for_edit</stringProp> + <stringProp name="CounterConfig.format"/> + <boolProp name="CounterConfig.per_user">false</boolProp> + </CounterConfig> + <hashTree/> + <BeanShellSampler guiclass="BeanShellSamplerGui" testclass="BeanShellSampler" testname="SetUp - BeanShell Sampler: Collect configurable product for edit" enabled="true"> + <stringProp name="BeanShellSampler.query">import java.util.ArrayList; +import java.util.HashMap; +import org.apache.commons.codec.binary.Base64; + +if (1 == Integer.parseInt(vars.get("configurable_products_counter_for_edit"))) { + editProductList = new ArrayList(); + props.put("configurable_products_list_for_edit", editProductList); +} else { + productList = props.get("configurable_products_list_for_edit"); +} + +String productUrl = vars.get("request_protocol") + "://" + vars.get("host") + vars.get("base_path") + vars.get("configurable_products_for_edit_url_keys_" + vars.get("configurable_products_counter_for_edit"))+ vars.get("url_suffix"); +encodedUrl = Base64.encodeBase64(productUrl.getBytes()); +// Create product map +Map editProductMap = new HashMap(); +editProductMap.put("id", vars.get("configurable_product_for_edit_id")); +editProductMap.put("title", vars.get("configurable_product_for_edit_names_" + vars.get("configurable_products_counter_for_edit"))); +editProductMap.put("sku", vars.get("configurable_product_for_edit_skus_" + vars.get("configurable_products_counter_for_edit"))); +editProductMap.put("url_key", vars.get("configurable_products_for_edit_url_keys_" + vars.get("configurable_products_counter_for_edit"))); +editProductMap.put("uenc", new String(encodedUrl)); + +// Collect products map in products list +editProductList.add(editProductMap);</stringProp> + <stringProp name="BeanShellSampler.filename"/> + <stringProp name="BeanShellSampler.parameters"/> + <boolProp name="BeanShellSampler.resetInterpreter">false</boolProp> + </BeanShellSampler> + <hashTree/> + </hashTree> + </hashTree> + + <TestFragmentController guiclass="TestFragmentControllerGui" testclass="TestFragmentController" testname="Extract simple products for edit" enabled="true"> + <stringProp name="TestPlan.comments">mpaf/tool/fragments/ce/setup/extract_simple_products_for_edit.jmx</stringProp> +</TestFragmentController> + <hashTree> + <GenericController guiclass="LogicControllerGui" testclass="GenericController" testname="SetUp - Retrieve simple products for edit" enabled="true"/> + <hashTree> + <HeaderManager guiclass="HeaderPanel" testclass="HeaderManager" testname="HTTP Header Manager" enabled="true"> + <collectionProp name="HeaderManager.headers"> + <elementProp name="" elementType="Header"> + <stringProp name="Header.name">Content-Type</stringProp> + <stringProp name="Header.value">application/json</stringProp> + </elementProp> + <elementProp name="" elementType="Header"> + <stringProp name="Header.name">Accept</stringProp> + <stringProp name="Header.value">*/*</stringProp> + </elementProp> + </collectionProp> + </HeaderManager> + <hashTree/> + <HTTPSamplerProxy guiclass="HttpTestSampleGui" testclass="HTTPSamplerProxy" testname="SetUp - Admin Token Retrieval" enabled="true"> + <boolProp name="HTTPSampler.postBodyRaw">true</boolProp> + <elementProp name="HTTPsampler.Arguments" elementType="Arguments"> + <collectionProp name="Arguments.arguments"> + <elementProp name="" elementType="HTTPArgument"> + <boolProp name="HTTPArgument.always_encode">false</boolProp> + <stringProp name="Argument.value">{"username":"${admin_user}","password":"${admin_password}"}</stringProp> + <stringProp name="Argument.metadata">=</stringProp> + </elementProp> + </collectionProp> + </elementProp> + <stringProp name="HTTPSampler.domain"/> + <stringProp name="HTTPSampler.port"/> + <stringProp name="HTTPSampler.connect_timeout">60000</stringProp> + <stringProp name="HTTPSampler.response_timeout">200000</stringProp> <stringProp name="HTTPSampler.protocol">${request_protocol}</stringProp> <stringProp name="HTTPSampler.contentEncoding"/> <stringProp name="HTTPSampler.path">${base_path}rest/V1/integration/admin/token</stringProp> @@ -1119,7 +1723,7 @@ props.put("category_name", vars.get("category_name"));</stringProp> </collectionProp> </HeaderManager> <hashTree/> - <HTTPSamplerProxy guiclass="HttpTestSampleGui" testclass="HTTPSamplerProxy" testname="SetUp - Get configurable products" enabled="true"> + <HTTPSamplerProxy guiclass="HttpTestSampleGui" testclass="HTTPSamplerProxy" testname="SetUp - Get simple products for edit" enabled="true"> <elementProp name="HTTPsampler.Arguments" elementType="Arguments" guiclass="HTTPArgumentsPanel" testclass="Arguments" testname="User Defined Variables" enabled="true"> <collectionProp name="Arguments.arguments"> <elementProp name="searchCriteria[filterGroups][0][filters][0][field]" elementType="HTTPArgument"> @@ -1131,24 +1735,45 @@ props.put("category_name", vars.get("category_name"));</stringProp> </elementProp> <elementProp name="searchCriteria[filterGroups][0][filters][0][value]" elementType="HTTPArgument"> <boolProp name="HTTPArgument.always_encode">true</boolProp> - <stringProp name="Argument.value">configurable</stringProp> + <stringProp name="Argument.value">simple</stringProp> <stringProp name="Argument.metadata">=</stringProp> <boolProp name="HTTPArgument.use_equals">true</boolProp> <stringProp name="Argument.name">searchCriteria[filterGroups][0][filters][0][value]</stringProp> </elementProp> <elementProp name="searchCriteria[pageSize]" elementType="HTTPArgument"> <boolProp name="HTTPArgument.always_encode">true</boolProp> - <stringProp name="Argument.value">${configurable_products_count}</stringProp> + <stringProp name="Argument.value">${simple_products_count}</stringProp> <stringProp name="Argument.metadata">=</stringProp> <boolProp name="HTTPArgument.use_equals">true</boolProp> <stringProp name="Argument.name">searchCriteria[pageSize]</stringProp> </elementProp> + <elementProp name="searchCriteria[currentPage]" elementType="HTTPArgument"> + <boolProp name="HTTPArgument.always_encode">true</boolProp> + <stringProp name="Argument.value">1</stringProp> + <stringProp name="Argument.metadata">=</stringProp> + <boolProp name="HTTPArgument.use_equals">true</boolProp> + <stringProp name="Argument.name">searchCriteria[currentPage]</stringProp> + </elementProp> + <elementProp name="searchCriteria[filterGroups][1][filters][1][field]" elementType="HTTPArgument"> + <boolProp name="HTTPArgument.always_encode">true</boolProp> + <stringProp name="Argument.value">attribute_set_id</stringProp> + <stringProp name="Argument.metadata">=</stringProp> + <boolProp name="HTTPArgument.use_equals">true</boolProp> + <stringProp name="Argument.name">searchCriteria[filterGroups][1][filters][1][field]</stringProp> + </elementProp> + <elementProp name="searchCriteria[filterGroups][1][filters][1][value]" elementType="HTTPArgument"> + <boolProp name="HTTPArgument.always_encode">true</boolProp> + <stringProp name="Argument.value">4</stringProp> + <stringProp name="Argument.metadata">=</stringProp> + <boolProp name="HTTPArgument.use_equals">true</boolProp> + <stringProp name="Argument.name">searchCriteria[filterGroups][1][filters][1][value]</stringProp> + </elementProp> </collectionProp> </elementProp> <stringProp name="HTTPSampler.domain"/> <stringProp name="HTTPSampler.port"/> - <stringProp name="HTTPSampler.connect_timeout"/> - <stringProp name="HTTPSampler.response_timeout"/> + <stringProp name="HTTPSampler.connect_timeout">60000</stringProp> + <stringProp name="HTTPSampler.response_timeout">200000</stringProp> <stringProp name="HTTPSampler.protocol">${request_protocol}</stringProp> <stringProp name="HTTPSampler.contentEncoding"/> <stringProp name="HTTPSampler.path">${base_path}rest/V1/products</stringProp> @@ -1163,7 +1788,7 @@ props.put("category_name", vars.get("category_name"));</stringProp> <hashTree> <RegexExtractor guiclass="RegexExtractorGui" testclass="RegexExtractor" testname="Regular Expression Extractor: Extract product url keys" enabled="true"> <stringProp name="RegexExtractor.useHeaders">false</stringProp> - <stringProp name="RegexExtractor.refname">configurable_products_url_keys</stringProp> + <stringProp name="RegexExtractor.refname">simple_products_for_edit_url_keys</stringProp> <stringProp name="RegexExtractor.regex">url_key\",\"value\":\"(.*?)\"</stringProp> <stringProp name="RegexExtractor.template">$1$</stringProp> <stringProp name="RegexExtractor.default"/> @@ -1172,7 +1797,7 @@ props.put("category_name", vars.get("category_name"));</stringProp> <hashTree/> <RegexExtractor guiclass="RegexExtractorGui" testclass="RegexExtractor" testname="Regular Expression Extractor: Extract product ids" enabled="true"> <stringProp name="RegexExtractor.useHeaders">false</stringProp> - <stringProp name="RegexExtractor.refname">configurable_product_ids</stringProp> + <stringProp name="RegexExtractor.refname">simple_product_for_edit_ids</stringProp> <stringProp name="RegexExtractor.regex">\"id\":(\d+),</stringProp> <stringProp name="RegexExtractor.template">$1$</stringProp> <stringProp name="RegexExtractor.default"/> @@ -1181,7 +1806,7 @@ props.put("category_name", vars.get("category_name"));</stringProp> <hashTree/> <RegexExtractor guiclass="RegexExtractorGui" testclass="RegexExtractor" testname="Regular Expression Extractor: Extract product titles" enabled="true"> <stringProp name="RegexExtractor.useHeaders">false</stringProp> - <stringProp name="RegexExtractor.refname">configurable_product_names</stringProp> + <stringProp name="RegexExtractor.refname">simple_product_for_edit_names</stringProp> <stringProp name="RegexExtractor.regex">name\":\"(.*?)\"</stringProp> <stringProp name="RegexExtractor.template">$1$</stringProp> <stringProp name="RegexExtractor.default"/> @@ -1190,7 +1815,7 @@ props.put("category_name", vars.get("category_name"));</stringProp> <hashTree/> <RegexExtractor guiclass="RegexExtractorGui" testclass="RegexExtractor" testname="Regular Expression Extractor: Extract product skus" enabled="true"> <stringProp name="RegexExtractor.useHeaders">false</stringProp> - <stringProp name="RegexExtractor.refname">configurable_product_skus</stringProp> + <stringProp name="RegexExtractor.refname">simple_product_for_edit_skus</stringProp> <stringProp name="RegexExtractor.regex">sku\":\"(.*?)\"</stringProp> <stringProp name="RegexExtractor.template">$1$</stringProp> <stringProp name="RegexExtractor.default"/> @@ -1199,46 +1824,45 @@ props.put("category_name", vars.get("category_name"));</stringProp> <hashTree/> </hashTree> </hashTree> - <ForeachController guiclass="ForeachControlPanel" testclass="ForeachController" testname="ForEach Controller: Prepare configurable products" enabled="true"> - <stringProp name="ForeachController.inputVal">configurable_product_ids</stringProp> - <stringProp name="ForeachController.returnVal">configurable_product_id</stringProp> + <ForeachController guiclass="ForeachControlPanel" testclass="ForeachController" testname="ForEach Controller: Prepare simple products for edit" enabled="true"> + <stringProp name="ForeachController.inputVal">simple_product_for_edit_ids</stringProp> + <stringProp name="ForeachController.returnVal">simple_product_for_edit_id</stringProp> <boolProp name="ForeachController.useSeparator">true</boolProp> </ForeachController> <hashTree> - <CounterConfig guiclass="CounterConfigGui" testclass="CounterConfig" testname="Counter" enabled="true"> + <CounterConfig guiclass="CounterConfigGui" testclass="CounterConfig" testname="Counter for edit" enabled="true"> <stringProp name="CounterConfig.start">1</stringProp> <stringProp name="CounterConfig.end"/> <stringProp name="CounterConfig.incr">1</stringProp> - <stringProp name="CounterConfig.name">configurable_products_counter</stringProp> + <stringProp name="CounterConfig.name">simple_products_counter_for_edit</stringProp> <stringProp name="CounterConfig.format"/> <boolProp name="CounterConfig.per_user">false</boolProp> </CounterConfig> <hashTree/> - <BeanShellSampler guiclass="BeanShellSamplerGui" testclass="BeanShellSampler" testname="SetUp - BeanShell Sampler: Collect configurable product" enabled="true"> + <BeanShellSampler guiclass="BeanShellSamplerGui" testclass="BeanShellSampler" testname="SetUp - BeanShell Sampler: Collect simple product for edit" enabled="true"> <stringProp name="BeanShellSampler.query">import java.util.ArrayList; import java.util.HashMap; import org.apache.commons.codec.binary.Base64; -// If it is first iteration of cycle then recreate productList -if (1 == Integer.parseInt(vars.get("configurable_products_counter"))) { - productList = new ArrayList(); - props.put("configurable_products_list", productList); +if (1 == Integer.parseInt(vars.get("simple_products_counter_for_edit"))) { + editProductList = new ArrayList(); + props.put("simple_products_list_for_edit", editProductList); } else { - productList = props.get("configurable_products_list"); + productList = props.get("simple_products_counter_for_edit"); } -String productUrl = vars.get("request_protocol") + "://" + vars.get("host") + vars.get("base_path") + vars.get("configurable_products_url_keys_" + vars.get("configurable_products_counter"))+ vars.get("url_suffix"); +String productUrl = vars.get("request_protocol") + "://" + vars.get("host") + vars.get("base_path") + vars.get("simple_products_for_edit_url_keys_" + vars.get("simple_products_counter_for_edit"))+ vars.get("url_suffix"); encodedUrl = Base64.encodeBase64(productUrl.getBytes()); // Create product map -Map productMap = new HashMap(); -productMap.put("id", vars.get("configurable_product_id")); -productMap.put("title", vars.get("configurable_product_names_" + vars.get("configurable_products_counter"))); -productMap.put("sku", vars.get("configurable_product_skus_" + vars.get("configurable_products_counter"))); -productMap.put("url_key", vars.get("configurable_products_url_keys_" + vars.get("configurable_products_counter"))); -productMap.put("uenc", new String(encodedUrl)); +Map editProductMap = new HashMap(); +editProductMap.put("id", vars.get("simple_product_for_edit_id")); +editProductMap.put("title", vars.get("simple_product_for_edit_names_" + vars.get("simple_products_counter_for_edit"))); +editProductMap.put("sku", vars.get("simple_product_for_edit_skus_" + vars.get("simple_products_counter_for_edit"))); +editProductMap.put("url_key", vars.get("simple_products_for_edit_url_keys_" + vars.get("simple_products_counter_for_edit"))); +editProductMap.put("uenc", new String(encodedUrl)); // Collect products map in products list -productList.add(productMap);</stringProp> +editProductList.add(editProductMap);</stringProp> <stringProp name="BeanShellSampler.filename"/> <stringProp name="BeanShellSampler.parameters"/> <boolProp name="BeanShellSampler.resetInterpreter">false</boolProp> @@ -1279,8 +1903,8 @@ productList.add(productMap);</stringProp> </elementProp> <stringProp name="HTTPSampler.domain"/> <stringProp name="HTTPSampler.port"/> - <stringProp name="HTTPSampler.connect_timeout"/> - <stringProp name="HTTPSampler.response_timeout"/> + <stringProp name="HTTPSampler.connect_timeout">60000</stringProp> + <stringProp name="HTTPSampler.response_timeout">200000</stringProp> <stringProp name="HTTPSampler.protocol">${request_protocol}</stringProp> <stringProp name="HTTPSampler.contentEncoding"/> <stringProp name="HTTPSampler.path">${base_path}rest/V1/integration/admin/token</stringProp> @@ -1346,12 +1970,26 @@ productList.add(productMap);</stringProp> <boolProp name="HTTPArgument.use_equals">true</boolProp> <stringProp name="Argument.name">searchCriteria[pageSize]</stringProp> </elementProp> + <elementProp name="searchCriteria[filterGroups][0][filters][1][field]" elementType="HTTPArgument"> + <boolProp name="HTTPArgument.always_encode">true</boolProp> + <stringProp name="Argument.value">attribute_set_id</stringProp> + <stringProp name="Argument.metadata">!=</stringProp> + <boolProp name="HTTPArgument.use_equals">true</boolProp> + <stringProp name="Argument.name">searchCriteria[filterGroups][0][filters][1][field]</stringProp> + </elementProp> + <elementProp name="searchCriteria[filterGroups][0][filters][1][value]" elementType="HTTPArgument"> + <boolProp name="HTTPArgument.always_encode">true</boolProp> + <stringProp name="Argument.value">4</stringProp> + <stringProp name="Argument.metadata">=</stringProp> + <boolProp name="HTTPArgument.use_equals">true</boolProp> + <stringProp name="Argument.name">searchCriteria[filterGroups][0][filters][1][value]</stringProp> + </elementProp> </collectionProp> </elementProp> <stringProp name="HTTPSampler.domain"/> <stringProp name="HTTPSampler.port"/> - <stringProp name="HTTPSampler.connect_timeout"/> - <stringProp name="HTTPSampler.response_timeout"/> + <stringProp name="HTTPSampler.connect_timeout">60000</stringProp> + <stringProp name="HTTPSampler.response_timeout">200000</stringProp> <stringProp name="HTTPSampler.protocol">${request_protocol}</stringProp> <stringProp name="HTTPSampler.contentEncoding"/> <stringProp name="HTTPSampler.path">${base_path}rest/V1/products</stringProp> @@ -1467,8 +2105,8 @@ productList.add(productMap);</stringProp> </elementProp> <stringProp name="HTTPSampler.domain"/> <stringProp name="HTTPSampler.port"/> - <stringProp name="HTTPSampler.connect_timeout"/> - <stringProp name="HTTPSampler.response_timeout"/> + <stringProp name="HTTPSampler.connect_timeout">60000</stringProp> + <stringProp name="HTTPSampler.response_timeout">200000</stringProp> <stringProp name="HTTPSampler.protocol">${request_protocol}</stringProp> <stringProp name="HTTPSampler.contentEncoding"/> <stringProp name="HTTPSampler.path">${base_path}${admin_path}/admin/user/roleGrid/limit/200/?ajax=true&isAjax=true</stringProp> @@ -1500,6 +2138,7 @@ productList.add(productMap);</stringProp> adminUserList.poll(); props.put("adminUserList", adminUserList); + props.put("adminUserListIterator", adminUserList.descendingIterator()); </stringProp> </BeanShellPostProcessor> <hashTree/> @@ -1516,8 +2155,8 @@ productList.add(productMap);</stringProp> </elementProp> <stringProp name="HTTPSampler.domain"/> <stringProp name="HTTPSampler.port"/> - <stringProp name="HTTPSampler.connect_timeout"/> - <stringProp name="HTTPSampler.response_timeout"/> + <stringProp name="HTTPSampler.connect_timeout">60000</stringProp> + <stringProp name="HTTPSampler.response_timeout">200000</stringProp> <stringProp name="HTTPSampler.protocol">${request_protocol}</stringProp> <stringProp name="HTTPSampler.contentEncoding"/> <stringProp name="HTTPSampler.path">${base_path}${admin_path}/customer/index/</stringProp> @@ -1590,6 +2229,13 @@ manager.add(cookie); </stringProp> <boolProp name="HTTPArgument.use_equals">true</boolProp> <stringProp name="Argument.name">filters[placeholder]</stringProp> </elementProp> + <elementProp name="filters[group_id]" elementType="HTTPArgument"> + <boolProp name="HTTPArgument.always_encode">true</boolProp> + <stringProp name="Argument.value">1</stringProp> + <stringProp name="Argument.metadata">=</stringProp> + <boolProp name="HTTPArgument.use_equals">true</boolProp> + <stringProp name="Argument.name">filters[group_id]</stringProp> + </elementProp> <elementProp name="filters[website_id]" elementType="HTTPArgument"> <boolProp name="HTTPArgument.always_encode">true</boolProp> <stringProp name="Argument.value">1</stringProp> @@ -1636,8 +2282,8 @@ manager.add(cookie); </stringProp> </elementProp> <stringProp name="HTTPSampler.domain"/> <stringProp name="HTTPSampler.port"/> - <stringProp name="HTTPSampler.connect_timeout"/> - <stringProp name="HTTPSampler.response_timeout"/> + <stringProp name="HTTPSampler.connect_timeout">60000</stringProp> + <stringProp name="HTTPSampler.response_timeout">200000</stringProp> <stringProp name="HTTPSampler.protocol">${request_protocol}</stringProp> <stringProp name="HTTPSampler.contentEncoding"/> <stringProp name="HTTPSampler.path">${base_path}${admin_path}/mui/index/render/</stringProp> @@ -1751,6 +2397,59 @@ idsList.add(vars.get("customer_id"));</stringProp> </hashTree> </hashTree> + <TestFragmentController guiclass="TestFragmentControllerGui" testclass="TestFragmentController" testname="Extract region ids" enabled="true"> + <stringProp name="TestPlan.comments">mpaf/tool/fragments/ce/setup/extract_region_ids.jmx</stringProp> + </TestFragmentController> + <hashTree> + <HTTPSamplerProxy guiclass="HttpTestSampleGui" testclass="HTTPSamplerProxy" testname="SetUp - Extract Region ids" enabled="true"> + <elementProp name="HTTPsampler.Arguments" elementType="Arguments" guiclass="HTTPArgumentsPanel" testclass="Arguments" enabled="true"> + <collectionProp name="Arguments.arguments"> + <elementProp name="parent" elementType="HTTPArgument"> + <boolProp name="HTTPArgument.always_encode">false</boolProp> + <stringProp name="Argument.value">US</stringProp> + <stringProp name="Argument.metadata">=</stringProp> + <boolProp name="HTTPArgument.use_equals">true</boolProp> + <stringProp name="Argument.name">parent</stringProp> + </elementProp> + </collectionProp> + </elementProp> + <stringProp name="HTTPSampler.domain"/> + <stringProp name="HTTPSampler.port"/> + <stringProp name="HTTPSampler.connect_timeout"/> + <stringProp name="HTTPSampler.response_timeout"/> + <stringProp name="HTTPSampler.protocol">${request_protocol}</stringProp> + <stringProp name="HTTPSampler.contentEncoding"/> + <stringProp name="HTTPSampler.path">${base_path}${admin_path}/directory/json/countryRegion/</stringProp> + <stringProp name="HTTPSampler.method">GET</stringProp> + <boolProp name="HTTPSampler.follow_redirects">true</boolProp> + <boolProp name="HTTPSampler.auto_redirects">false</boolProp> + <boolProp name="HTTPSampler.use_keepalive">true</boolProp> + <boolProp name="HTTPSampler.DO_MULTIPART_POST">false</boolProp> + <boolProp name="HTTPSampler.monitor">false</boolProp> + <stringProp name="HTTPSampler.embedded_url_re"/> + </HTTPSamplerProxy> + <hashTree> + <JSR223PostProcessor guiclass="TestBeanGUI" testclass="JSR223PostProcessor" testname="Parse and put region id into variables" enabled="true"> + <stringProp name="scriptLanguage">groovy</stringProp> + <stringProp name="parameters"/> + <stringProp name="filename"/> + <stringProp name="cacheKey"/> + <stringProp name="script">import groovy.json.JsonSlurper +def jsonSlurper = new JsonSlurper(); +def regionResponse = jsonSlurper.parseText(prev.getResponseDataAsString()); + +regionResponse.each { region -> + if (region.label.toString() == "Alabama") { + props.put("alabama_region_id", region.value.toString()); + } else if (region.label.toString() == 'California') { + props.put("california_region_id", region.value.toString()); + } +}</stringProp> + </JSR223PostProcessor> + <hashTree/> + </hashTree> + </hashTree> + <BeanShellSampler guiclass="BeanShellSamplerGui" testclass="BeanShellSampler" testname="SetUp - BeanShell Sampler: Validate properties and count users" enabled="true"> <stringProp name="BeanShellSampler.query">Boolean stopTestOnError (String error) { log.error(error); @@ -1762,9 +2461,15 @@ idsList.add(vars.get("customer_id"));</stringProp> if (props.get("simple_products_list") == null) { return stopTestOnError("Cannot find simple products. Test stopped."); } +if (props.get("simple_products_list_for_edit") == null) { + return stopTestOnError("Cannot find simple products for edit. Test stopped."); +} if (props.get("configurable_products_list") == null) { return stopTestOnError("Cannot find configurable products. Test stopped."); } +if (props.get("configurable_products_list_for_edit") == null) { + return stopTestOnError("Cannot find configurable products for edit. Test stopped."); +} if (props.get("customer_emails_list") == null) { return stopTestOnError("Cannot find customer emails. Test stopped."); } @@ -1816,8 +2521,8 @@ if (props.get("category_names_list") == null) { </elementProp> <stringProp name="HTTPSampler.domain"/> <stringProp name="HTTPSampler.port"/> - <stringProp name="HTTPSampler.connect_timeout"/> - <stringProp name="HTTPSampler.response_timeout"/> + <stringProp name="HTTPSampler.connect_timeout">60000</stringProp> + <stringProp name="HTTPSampler.response_timeout">200000</stringProp> <stringProp name="HTTPSampler.protocol">${request_protocol}</stringProp> <stringProp name="HTTPSampler.contentEncoding"/> <stringProp name="HTTPSampler.path">${base_path}checkout/cart/add</stringProp> @@ -1873,8 +2578,8 @@ if (props.get("category_names_list") == null) { </elementProp> <stringProp name="HTTPSampler.domain"/> <stringProp name="HTTPSampler.port"/> - <stringProp name="HTTPSampler.connect_timeout"/> - <stringProp name="HTTPSampler.response_timeout"/> + <stringProp name="HTTPSampler.connect_timeout">60000</stringProp> + <stringProp name="HTTPSampler.response_timeout">200000</stringProp> <stringProp name="HTTPSampler.protocol">${request_protocol}</stringProp> <stringProp name="HTTPSampler.contentEncoding"/> <stringProp name="HTTPSampler.path">${base_path}page_cache/block/render/</stringProp> @@ -1916,6 +2621,30 @@ if (props.get("category_names_list") == null) { <stringProp name="ThreadGroup.delay"/> <stringProp name="TestPlan.comments">mpaf/tool/fragments/_system/thread_group.jmx</stringProp></ThreadGroup> <hashTree> + <JSR223PreProcessor guiclass="TestBeanGUI" testclass="JSR223PreProcessor" testname="Cache hit miss" enabled="true"> + <stringProp name="scriptLanguage">javascript</stringProp> + <stringProp name="parameters"/> + <stringProp name="filename"/> + <stringProp name="cacheKey"/> + <stringProp name="script">var cacheHitPercent = vars.get("cache_hits_percentage"); + +if ( + cacheHitPercent < 100 && + sampler.getClass().getName() == 'org.apache.jmeter.protocol.http.sampler.HTTPSamplerProxy' +) { + doCache(); +} + +function doCache(){ + var random = Math.random() * 100; + if (cacheHitPercent < random) { + sampler.setPath(sampler.getPath() + "?cacheModifier=" + Math.random().toString(36).substring(2, 13)); + } +} +</stringProp> + <stringProp name="TestPlan.comments">mpaf/tool/fragments/ce/common/cache_hit_miss.jmx</stringProp></JSR223PreProcessor> + <hashTree/> + <ThroughputController guiclass="ThroughputControllerGui" testclass="ThroughputController" testname="Catalog Browsing By Customer" enabled="true"> <intProp name="ThroughputController.style">1</intProp> <boolProp name="ThroughputController.perThread">false</boolProp> @@ -2038,8 +2767,8 @@ vars.put("customer_email", customerUser); </elementProp> <stringProp name="HTTPSampler.domain"/> <stringProp name="HTTPSampler.port"/> - <stringProp name="HTTPSampler.connect_timeout"/> - <stringProp name="HTTPSampler.response_timeout"/> + <stringProp name="HTTPSampler.connect_timeout">60000</stringProp> + <stringProp name="HTTPSampler.response_timeout">200000</stringProp> <stringProp name="HTTPSampler.protocol">${request_protocol}</stringProp> <stringProp name="HTTPSampler.contentEncoding"/> <stringProp name="HTTPSampler.path">${base_path}customer/account/login/</stringProp> @@ -2098,8 +2827,8 @@ vars.put("customer_email", customerUser); </elementProp> <stringProp name="HTTPSampler.domain"/> <stringProp name="HTTPSampler.port"/> - <stringProp name="HTTPSampler.connect_timeout"/> - <stringProp name="HTTPSampler.response_timeout"/> + <stringProp name="HTTPSampler.connect_timeout">60000</stringProp> + <stringProp name="HTTPSampler.response_timeout">200000</stringProp> <stringProp name="HTTPSampler.protocol">${request_protocol}</stringProp> <stringProp name="HTTPSampler.contentEncoding"/> <stringProp name="HTTPSampler.path">${base_path}customer/account/loginPost/</stringProp> @@ -2170,8 +2899,8 @@ vars.put("customer_email", customerUser); </elementProp> <stringProp name="HTTPSampler.domain"/> <stringProp name="HTTPSampler.port"/> - <stringProp name="HTTPSampler.connect_timeout"/> - <stringProp name="HTTPSampler.response_timeout"/> + <stringProp name="HTTPSampler.connect_timeout">60000</stringProp> + <stringProp name="HTTPSampler.response_timeout">200000</stringProp> <stringProp name="HTTPSampler.protocol">${request_protocol}</stringProp> <stringProp name="HTTPSampler.contentEncoding"/> <stringProp name="HTTPSampler.path">${base_path}customer/section/load/</stringProp> @@ -2191,8 +2920,8 @@ vars.put("customer_email", customerUser); </elementProp> <stringProp name="HTTPSampler.domain"/> <stringProp name="HTTPSampler.port"/> - <stringProp name="HTTPSampler.connect_timeout"/> - <stringProp name="HTTPSampler.response_timeout"/> + <stringProp name="HTTPSampler.connect_timeout">60000</stringProp> + <stringProp name="HTTPSampler.response_timeout">200000</stringProp> <stringProp name="HTTPSampler.protocol">${request_protocol}</stringProp> <stringProp name="HTTPSampler.contentEncoding"/> <stringProp name="HTTPSampler.path">${base_path}</stringProp> @@ -2222,8 +2951,8 @@ vars.put("customer_email", customerUser); </elementProp> <stringProp name="HTTPSampler.domain"/> <stringProp name="HTTPSampler.port"/> - <stringProp name="HTTPSampler.connect_timeout"/> - <stringProp name="HTTPSampler.response_timeout"/> + <stringProp name="HTTPSampler.connect_timeout">60000</stringProp> + <stringProp name="HTTPSampler.response_timeout">200000</stringProp> <stringProp name="HTTPSampler.protocol">${request_protocol}</stringProp> <stringProp name="HTTPSampler.contentEncoding"/> <stringProp name="HTTPSampler.path">${base_path}${category_url_key}${url_suffix}</stringProp> @@ -2310,8 +3039,8 @@ vars.put("product_sku", product.get("sku")); </elementProp> <stringProp name="HTTPSampler.domain"/> <stringProp name="HTTPSampler.port"/> - <stringProp name="HTTPSampler.connect_timeout"/> - <stringProp name="HTTPSampler.response_timeout"/> + <stringProp name="HTTPSampler.connect_timeout">60000</stringProp> + <stringProp name="HTTPSampler.response_timeout">200000</stringProp> <stringProp name="HTTPSampler.protocol">${request_protocol}</stringProp> <stringProp name="HTTPSampler.contentEncoding"/> <stringProp name="HTTPSampler.path">${base_path}${product_url_key}${url_suffix}</stringProp> @@ -2378,8 +3107,8 @@ vars.put("product_sku", product.get("sku")); </elementProp> <stringProp name="HTTPSampler.domain"/> <stringProp name="HTTPSampler.port"/> - <stringProp name="HTTPSampler.connect_timeout"/> - <stringProp name="HTTPSampler.response_timeout"/> + <stringProp name="HTTPSampler.connect_timeout">60000</stringProp> + <stringProp name="HTTPSampler.response_timeout">200000</stringProp> <stringProp name="HTTPSampler.protocol">${request_protocol}</stringProp> <stringProp name="HTTPSampler.contentEncoding"/> <stringProp name="HTTPSampler.path">${base_path}${product_url_key}${url_suffix}</stringProp> @@ -2410,8 +3139,8 @@ vars.put("product_sku", product.get("sku")); </elementProp> <stringProp name="HTTPSampler.domain"/> <stringProp name="HTTPSampler.port"/> - <stringProp name="HTTPSampler.connect_timeout"/> - <stringProp name="HTTPSampler.response_timeout"/> + <stringProp name="HTTPSampler.connect_timeout">60000</stringProp> + <stringProp name="HTTPSampler.response_timeout">200000</stringProp> <stringProp name="HTTPSampler.protocol">${request_protocol}</stringProp> <stringProp name="HTTPSampler.contentEncoding"/> <stringProp name="HTTPSampler.path">${base_path}customer/account/logout/</stringProp> @@ -2544,8 +3273,8 @@ vars.put("category_name", props.get("category_names_list").get(number)); </elementProp> <stringProp name="HTTPSampler.domain"/> <stringProp name="HTTPSampler.port"/> - <stringProp name="HTTPSampler.connect_timeout"/> - <stringProp name="HTTPSampler.response_timeout"/> + <stringProp name="HTTPSampler.connect_timeout">60000</stringProp> + <stringProp name="HTTPSampler.response_timeout">200000</stringProp> <stringProp name="HTTPSampler.protocol">${request_protocol}</stringProp> <stringProp name="HTTPSampler.contentEncoding"/> <stringProp name="HTTPSampler.path">${base_path}</stringProp> @@ -2575,8 +3304,8 @@ vars.put("category_name", props.get("category_names_list").get(number)); </elementProp> <stringProp name="HTTPSampler.domain"/> <stringProp name="HTTPSampler.port"/> - <stringProp name="HTTPSampler.connect_timeout"/> - <stringProp name="HTTPSampler.response_timeout"/> + <stringProp name="HTTPSampler.connect_timeout">60000</stringProp> + <stringProp name="HTTPSampler.response_timeout">200000</stringProp> <stringProp name="HTTPSampler.protocol">${request_protocol}</stringProp> <stringProp name="HTTPSampler.contentEncoding"/> <stringProp name="HTTPSampler.path">${base_path}${category_url_key}${url_suffix}</stringProp> @@ -2663,8 +3392,8 @@ vars.put("product_sku", product.get("sku")); </elementProp> <stringProp name="HTTPSampler.domain"/> <stringProp name="HTTPSampler.port"/> - <stringProp name="HTTPSampler.connect_timeout"/> - <stringProp name="HTTPSampler.response_timeout"/> + <stringProp name="HTTPSampler.connect_timeout">60000</stringProp> + <stringProp name="HTTPSampler.response_timeout">200000</stringProp> <stringProp name="HTTPSampler.protocol">${request_protocol}</stringProp> <stringProp name="HTTPSampler.contentEncoding"/> <stringProp name="HTTPSampler.path">${base_path}${product_url_key}${url_suffix}</stringProp> @@ -2731,8 +3460,8 @@ vars.put("product_sku", product.get("sku")); </elementProp> <stringProp name="HTTPSampler.domain"/> <stringProp name="HTTPSampler.port"/> - <stringProp name="HTTPSampler.connect_timeout"/> - <stringProp name="HTTPSampler.response_timeout"/> + <stringProp name="HTTPSampler.connect_timeout">60000</stringProp> + <stringProp name="HTTPSampler.response_timeout">200000</stringProp> <stringProp name="HTTPSampler.protocol">${request_protocol}</stringProp> <stringProp name="HTTPSampler.contentEncoding"/> <stringProp name="HTTPSampler.path">${base_path}${product_url_key}${url_suffix}</stringProp> @@ -2802,6 +3531,30 @@ if (testLabel <stringProp name="TestPlan.comments">mpaf/tool/fragments/ce/search/search_terms.jmx</stringProp></CSVDataSet> <hashTree/> + <JSR223PreProcessor guiclass="TestBeanGUI" testclass="JSR223PreProcessor" testname="Cache hit miss" enabled="true"> + <stringProp name="scriptLanguage">javascript</stringProp> + <stringProp name="parameters"/> + <stringProp name="filename"/> + <stringProp name="cacheKey"/> + <stringProp name="script">var cacheHitPercent = vars.get("cache_hits_percentage"); + +if ( + cacheHitPercent < 100 && + sampler.getClass().getName() == 'org.apache.jmeter.protocol.http.sampler.HTTPSamplerProxy' +) { + doCache(); +} + +function doCache(){ + var random = Math.random() * 100; + if (cacheHitPercent < random) { + sampler.setPath(sampler.getPath() + "?cacheModifier=" + Math.random().toString(36).substring(2, 13)); + } +} +</stringProp> + <stringProp name="TestPlan.comments">mpaf/tool/fragments/ce/common/cache_hit_miss.jmx</stringProp></JSR223PreProcessor> + <hashTree/> + <ThroughputController guiclass="ThroughputControllerGui" testclass="ThroughputController" testname="Quick Search" enabled="true"> <intProp name="ThroughputController.style">1</intProp> <boolProp name="ThroughputController.perThread">false</boolProp> @@ -2864,8 +3617,8 @@ if (testLabel </elementProp> <stringProp name="HTTPSampler.domain"/> <stringProp name="HTTPSampler.port"/> - <stringProp name="HTTPSampler.connect_timeout"/> - <stringProp name="HTTPSampler.response_timeout"/> + <stringProp name="HTTPSampler.connect_timeout">60000</stringProp> + <stringProp name="HTTPSampler.response_timeout">200000</stringProp> <stringProp name="HTTPSampler.protocol">${request_protocol}</stringProp> <stringProp name="HTTPSampler.contentEncoding"/> <stringProp name="HTTPSampler.path">${base_path}</stringProp> @@ -2903,8 +3656,8 @@ if (testLabel </elementProp> <stringProp name="HTTPSampler.domain"/> <stringProp name="HTTPSampler.port"/> - <stringProp name="HTTPSampler.connect_timeout"/> - <stringProp name="HTTPSampler.response_timeout"/> + <stringProp name="HTTPSampler.connect_timeout">60000</stringProp> + <stringProp name="HTTPSampler.response_timeout">200000</stringProp> <stringProp name="HTTPSampler.protocol">${request_protocol}</stringProp> <stringProp name="HTTPSampler.contentEncoding"/> <stringProp name="HTTPSampler.path">${base_path}catalogsearch/result/</stringProp> @@ -2966,8 +3719,8 @@ if (testLabel </elementProp> <stringProp name="HTTPSampler.domain"/> <stringProp name="HTTPSampler.port"/> - <stringProp name="HTTPSampler.connect_timeout"/> - <stringProp name="HTTPSampler.response_timeout"/> + <stringProp name="HTTPSampler.connect_timeout">60000</stringProp> + <stringProp name="HTTPSampler.response_timeout">200000</stringProp> <stringProp name="HTTPSampler.protocol">${request_protocol}</stringProp> <stringProp name="HTTPSampler.contentEncoding"/> <stringProp name="HTTPSampler.path">${base_path}catalogsearch/searchTermsLog/save/</stringProp> @@ -3045,8 +3798,8 @@ vars.put("product_url_key", product); </elementProp> <stringProp name="HTTPSampler.domain"/> <stringProp name="HTTPSampler.port"/> - <stringProp name="HTTPSampler.connect_timeout"/> - <stringProp name="HTTPSampler.response_timeout"/> + <stringProp name="HTTPSampler.connect_timeout">60000</stringProp> + <stringProp name="HTTPSampler.response_timeout">200000</stringProp> <stringProp name="HTTPSampler.protocol">${request_protocol}</stringProp> <stringProp name="HTTPSampler.contentEncoding"/> <stringProp name="HTTPSampler.path">${base_path}${product_url_key}${url_suffix}</stringProp> @@ -3135,8 +3888,8 @@ if (testLabel </elementProp> <stringProp name="HTTPSampler.domain"/> <stringProp name="HTTPSampler.port"/> - <stringProp name="HTTPSampler.connect_timeout"/> - <stringProp name="HTTPSampler.response_timeout"/> + <stringProp name="HTTPSampler.connect_timeout">60000</stringProp> + <stringProp name="HTTPSampler.response_timeout">200000</stringProp> <stringProp name="HTTPSampler.protocol">${request_protocol}</stringProp> <stringProp name="HTTPSampler.contentEncoding"/> <stringProp name="HTTPSampler.path">${base_path}</stringProp> @@ -3174,8 +3927,8 @@ if (testLabel </elementProp> <stringProp name="HTTPSampler.domain"/> <stringProp name="HTTPSampler.port"/> - <stringProp name="HTTPSampler.connect_timeout"/> - <stringProp name="HTTPSampler.response_timeout"/> + <stringProp name="HTTPSampler.connect_timeout">60000</stringProp> + <stringProp name="HTTPSampler.response_timeout">200000</stringProp> <stringProp name="HTTPSampler.protocol"/> <stringProp name="HTTPSampler.contentEncoding"/> <stringProp name="HTTPSampler.path">${base_path}catalogsearch/result/</stringProp> @@ -3264,8 +4017,8 @@ if (testLabel </elementProp> <stringProp name="HTTPSampler.domain"/> <stringProp name="HTTPSampler.port"/> - <stringProp name="HTTPSampler.connect_timeout"/> - <stringProp name="HTTPSampler.response_timeout"/> + <stringProp name="HTTPSampler.connect_timeout">60000</stringProp> + <stringProp name="HTTPSampler.response_timeout">200000</stringProp> <stringProp name="HTTPSampler.protocol">${request_protocol}</stringProp> <stringProp name="HTTPSampler.contentEncoding"/> <stringProp name="HTTPSampler.path">${base_path}catalogsearch/searchTermsLog/save/</stringProp> @@ -3309,8 +4062,8 @@ if (testLabel </elementProp> <stringProp name="HTTPSampler.domain"/> <stringProp name="HTTPSampler.port"/> - <stringProp name="HTTPSampler.connect_timeout"/> - <stringProp name="HTTPSampler.response_timeout"/> + <stringProp name="HTTPSampler.connect_timeout">60000</stringProp> + <stringProp name="HTTPSampler.response_timeout">200000</stringProp> <stringProp name="HTTPSampler.protocol"/> <stringProp name="HTTPSampler.contentEncoding"/> <stringProp name="HTTPSampler.path">${attribute_1_filter_url}</stringProp> @@ -3381,8 +4134,8 @@ if (testLabel </elementProp> <stringProp name="HTTPSampler.domain"/> <stringProp name="HTTPSampler.port"/> - <stringProp name="HTTPSampler.connect_timeout"/> - <stringProp name="HTTPSampler.response_timeout"/> + <stringProp name="HTTPSampler.connect_timeout">60000</stringProp> + <stringProp name="HTTPSampler.response_timeout">200000</stringProp> <stringProp name="HTTPSampler.protocol"/> <stringProp name="HTTPSampler.contentEncoding"/> <stringProp name="HTTPSampler.path">${attribute_2_filter_url}</stringProp> @@ -3469,8 +4222,8 @@ vars.put("product_url_key", product); </elementProp> <stringProp name="HTTPSampler.domain"/> <stringProp name="HTTPSampler.port"/> - <stringProp name="HTTPSampler.connect_timeout"/> - <stringProp name="HTTPSampler.response_timeout"/> + <stringProp name="HTTPSampler.connect_timeout">60000</stringProp> + <stringProp name="HTTPSampler.response_timeout">200000</stringProp> <stringProp name="HTTPSampler.protocol">${request_protocol}</stringProp> <stringProp name="HTTPSampler.contentEncoding"/> <stringProp name="HTTPSampler.path">${base_path}${product_url_key}${url_suffix}</stringProp> @@ -3559,8 +4312,8 @@ if (testLabel </elementProp> <stringProp name="HTTPSampler.domain"/> <stringProp name="HTTPSampler.port"/> - <stringProp name="HTTPSampler.connect_timeout"/> - <stringProp name="HTTPSampler.response_timeout"/> + <stringProp name="HTTPSampler.connect_timeout">60000</stringProp> + <stringProp name="HTTPSampler.response_timeout">200000</stringProp> <stringProp name="HTTPSampler.protocol">${request_protocol}</stringProp> <stringProp name="HTTPSampler.contentEncoding"/> <stringProp name="HTTPSampler.path">${base_path}</stringProp> @@ -3591,8 +4344,8 @@ if (testLabel </elementProp> <stringProp name="HTTPSampler.domain"/> <stringProp name="HTTPSampler.port"/> - <stringProp name="HTTPSampler.connect_timeout"/> - <stringProp name="HTTPSampler.response_timeout"/> + <stringProp name="HTTPSampler.connect_timeout">60000</stringProp> + <stringProp name="HTTPSampler.response_timeout">200000</stringProp> <stringProp name="HTTPSampler.protocol"/> <stringProp name="HTTPSampler.contentEncoding"/> <stringProp name="HTTPSampler.path">${base_path}catalogsearch/advanced/</stringProp> @@ -3702,8 +4455,8 @@ if (testLabel </elementProp> <stringProp name="HTTPSampler.domain"/> <stringProp name="HTTPSampler.port"/> - <stringProp name="HTTPSampler.connect_timeout"/> - <stringProp name="HTTPSampler.response_timeout"/> + <stringProp name="HTTPSampler.connect_timeout">60000</stringProp> + <stringProp name="HTTPSampler.response_timeout">200000</stringProp> <stringProp name="HTTPSampler.protocol">${request_protocol}</stringProp> <stringProp name="HTTPSampler.contentEncoding"/> <stringProp name="HTTPSampler.path">${base_path}catalogsearch/advanced/result/</stringProp> @@ -3788,8 +4541,8 @@ vars.put("product_url_key", product); </elementProp> <stringProp name="HTTPSampler.domain"/> <stringProp name="HTTPSampler.port"/> - <stringProp name="HTTPSampler.connect_timeout"/> - <stringProp name="HTTPSampler.response_timeout"/> + <stringProp name="HTTPSampler.connect_timeout">60000</stringProp> + <stringProp name="HTTPSampler.response_timeout">200000</stringProp> <stringProp name="HTTPSampler.protocol">${request_protocol}</stringProp> <stringProp name="HTTPSampler.contentEncoding"/> <stringProp name="HTTPSampler.path">${base_path}${product_url_key}${url_suffix}</stringProp> @@ -3925,8 +4678,8 @@ vars.put("category_name", props.get("category_names_list").get(number)); </elementProp> <stringProp name="HTTPSampler.domain"/> <stringProp name="HTTPSampler.port"/> - <stringProp name="HTTPSampler.connect_timeout"/> - <stringProp name="HTTPSampler.response_timeout"/> + <stringProp name="HTTPSampler.connect_timeout">60000</stringProp> + <stringProp name="HTTPSampler.response_timeout">200000</stringProp> <stringProp name="HTTPSampler.protocol">${request_protocol}</stringProp> <stringProp name="HTTPSampler.contentEncoding"/> <stringProp name="HTTPSampler.path">${base_path}</stringProp> @@ -3956,8 +4709,8 @@ vars.put("category_name", props.get("category_names_list").get(number)); </elementProp> <stringProp name="HTTPSampler.domain"/> <stringProp name="HTTPSampler.port"/> - <stringProp name="HTTPSampler.connect_timeout"/> - <stringProp name="HTTPSampler.response_timeout"/> + <stringProp name="HTTPSampler.connect_timeout">60000</stringProp> + <stringProp name="HTTPSampler.response_timeout">200000</stringProp> <stringProp name="HTTPSampler.protocol">${request_protocol}</stringProp> <stringProp name="HTTPSampler.contentEncoding"/> <stringProp name="HTTPSampler.path">${base_path}${category_url_key}${url_suffix}</stringProp> @@ -4058,8 +4811,8 @@ vars.put("totalProductsAdded", String.valueOf(productsAdded)); </elementProp> <stringProp name="HTTPSampler.domain"/> <stringProp name="HTTPSampler.port"/> - <stringProp name="HTTPSampler.connect_timeout"/> - <stringProp name="HTTPSampler.response_timeout"/> + <stringProp name="HTTPSampler.connect_timeout">60000</stringProp> + <stringProp name="HTTPSampler.response_timeout">200000</stringProp> <stringProp name="HTTPSampler.protocol">${request_protocol}</stringProp> <stringProp name="HTTPSampler.contentEncoding"/> <stringProp name="HTTPSampler.path">${base_path}${product_url_key}${url_suffix}</stringProp> @@ -4118,8 +4871,8 @@ vars.put("totalProductsAdded", String.valueOf(productsAdded)); </elementProp> <stringProp name="HTTPSampler.domain"/> <stringProp name="HTTPSampler.port"/> - <stringProp name="HTTPSampler.connect_timeout"/> - <stringProp name="HTTPSampler.response_timeout"/> + <stringProp name="HTTPSampler.connect_timeout">60000</stringProp> + <stringProp name="HTTPSampler.response_timeout">200000</stringProp> <stringProp name="HTTPSampler.protocol">${request_protocol}</stringProp> <stringProp name="HTTPSampler.contentEncoding"/> <stringProp name="HTTPSampler.path">${base_path}checkout/cart/add/</stringProp> @@ -4171,8 +4924,8 @@ vars.put("totalProductsAdded", String.valueOf(productsAdded)); </elementProp> <stringProp name="HTTPSampler.domain"/> <stringProp name="HTTPSampler.port"/> - <stringProp name="HTTPSampler.connect_timeout"/> - <stringProp name="HTTPSampler.response_timeout"/> + <stringProp name="HTTPSampler.connect_timeout">60000</stringProp> + <stringProp name="HTTPSampler.response_timeout">200000</stringProp> <stringProp name="HTTPSampler.protocol">${request_protocol}</stringProp> <stringProp name="HTTPSampler.contentEncoding"/> <stringProp name="HTTPSampler.path">${base_path}customer/section/load/</stringProp> @@ -4281,8 +5034,8 @@ vars.put("totalProductsAdded", String.valueOf(productsAdded)); </elementProp> <stringProp name="HTTPSampler.domain"/> <stringProp name="HTTPSampler.port"/> - <stringProp name="HTTPSampler.connect_timeout"/> - <stringProp name="HTTPSampler.response_timeout"/> + <stringProp name="HTTPSampler.connect_timeout">60000</stringProp> + <stringProp name="HTTPSampler.response_timeout">200000</stringProp> <stringProp name="HTTPSampler.protocol">${request_protocol}</stringProp> <stringProp name="HTTPSampler.contentEncoding"/> <stringProp name="HTTPSampler.path">${base_path}${product_url_key}${url_suffix}</stringProp> @@ -4337,8 +5090,8 @@ vars.put("totalProductsAdded", String.valueOf(productsAdded)); </elementProp> <stringProp name="HTTPSampler.domain"/> <stringProp name="HTTPSampler.port"/> - <stringProp name="HTTPSampler.connect_timeout"/> - <stringProp name="HTTPSampler.response_timeout"/> + <stringProp name="HTTPSampler.connect_timeout">60000</stringProp> + <stringProp name="HTTPSampler.response_timeout">200000</stringProp> <stringProp name="HTTPSampler.protocol">${request_protocol}</stringProp> <stringProp name="HTTPSampler.contentEncoding"/> <stringProp name="HTTPSampler.path">${base_path}rest/V1/integration/admin/token</stringProp> @@ -4386,8 +5139,8 @@ vars.put("totalProductsAdded", String.valueOf(productsAdded)); </elementProp> <stringProp name="HTTPSampler.domain"/> <stringProp name="HTTPSampler.port"/> - <stringProp name="HTTPSampler.connect_timeout"/> - <stringProp name="HTTPSampler.response_timeout"/> + <stringProp name="HTTPSampler.connect_timeout">60000</stringProp> + <stringProp name="HTTPSampler.response_timeout">200000</stringProp> <stringProp name="HTTPSampler.protocol">${request_protocol}</stringProp> <stringProp name="HTTPSampler.contentEncoding"/> <stringProp name="HTTPSampler.path">${base_path}rest/V1/configurable-products/${product_sku}/options/all</stringProp> @@ -4454,8 +5207,8 @@ vars.put("totalProductsAdded", String.valueOf(productsAdded)); </elementProp> <stringProp name="HTTPSampler.domain"/> <stringProp name="HTTPSampler.port"/> - <stringProp name="HTTPSampler.connect_timeout"/> - <stringProp name="HTTPSampler.response_timeout"/> + <stringProp name="HTTPSampler.connect_timeout">60000</stringProp> + <stringProp name="HTTPSampler.response_timeout">200000</stringProp> <stringProp name="HTTPSampler.protocol">${request_protocol}</stringProp> <stringProp name="HTTPSampler.contentEncoding"/> <stringProp name="HTTPSampler.path">${base_path}checkout/cart/add/</stringProp> @@ -4537,8 +5290,8 @@ vars.put("totalProductsAdded", String.valueOf(productsAdded)); </elementProp> <stringProp name="HTTPSampler.domain"/> <stringProp name="HTTPSampler.port"/> - <stringProp name="HTTPSampler.connect_timeout"/> - <stringProp name="HTTPSampler.response_timeout"/> + <stringProp name="HTTPSampler.connect_timeout">60000</stringProp> + <stringProp name="HTTPSampler.response_timeout">200000</stringProp> <stringProp name="HTTPSampler.protocol">${request_protocol}</stringProp> <stringProp name="HTTPSampler.contentEncoding"/> <stringProp name="HTTPSampler.path">${base_path}customer/section/load/</stringProp> @@ -4699,8 +5452,8 @@ vars.put("customer_email", customerUser); </elementProp> <stringProp name="HTTPSampler.domain"/> <stringProp name="HTTPSampler.port"/> - <stringProp name="HTTPSampler.connect_timeout"/> - <stringProp name="HTTPSampler.response_timeout"/> + <stringProp name="HTTPSampler.connect_timeout">60000</stringProp> + <stringProp name="HTTPSampler.response_timeout">200000</stringProp> <stringProp name="HTTPSampler.protocol">${request_protocol}</stringProp> <stringProp name="HTTPSampler.contentEncoding"/> <stringProp name="HTTPSampler.path">${base_path}customer/account/login/</stringProp> @@ -4759,8 +5512,8 @@ vars.put("customer_email", customerUser); </elementProp> <stringProp name="HTTPSampler.domain"/> <stringProp name="HTTPSampler.port"/> - <stringProp name="HTTPSampler.connect_timeout"/> - <stringProp name="HTTPSampler.response_timeout"/> + <stringProp name="HTTPSampler.connect_timeout">60000</stringProp> + <stringProp name="HTTPSampler.response_timeout">200000</stringProp> <stringProp name="HTTPSampler.protocol">${request_protocol}</stringProp> <stringProp name="HTTPSampler.contentEncoding"/> <stringProp name="HTTPSampler.path">${base_path}customer/account/loginPost/</stringProp> @@ -4831,8 +5584,8 @@ vars.put("customer_email", customerUser); </elementProp> <stringProp name="HTTPSampler.domain"/> <stringProp name="HTTPSampler.port"/> - <stringProp name="HTTPSampler.connect_timeout"/> - <stringProp name="HTTPSampler.response_timeout"/> + <stringProp name="HTTPSampler.connect_timeout">60000</stringProp> + <stringProp name="HTTPSampler.response_timeout">200000</stringProp> <stringProp name="HTTPSampler.protocol">${request_protocol}</stringProp> <stringProp name="HTTPSampler.contentEncoding"/> <stringProp name="HTTPSampler.path">${base_path}customer/section/load/</stringProp> @@ -4888,8 +5641,8 @@ vars.put("product_sku", product.get("sku")); </elementProp> <stringProp name="HTTPSampler.domain"/> <stringProp name="HTTPSampler.port"/> - <stringProp name="HTTPSampler.connect_timeout"/> - <stringProp name="HTTPSampler.response_timeout"/> + <stringProp name="HTTPSampler.connect_timeout">60000</stringProp> + <stringProp name="HTTPSampler.response_timeout">200000</stringProp> <stringProp name="HTTPSampler.protocol">${request_protocol}</stringProp> <stringProp name="HTTPSampler.contentEncoding"/> <stringProp name="HTTPSampler.path">${base_path}${product_url_key}${url_suffix}</stringProp> @@ -4942,8 +5695,8 @@ vars.put("product_sku", product.get("sku")); </elementProp> <stringProp name="HTTPSampler.domain"/> <stringProp name="HTTPSampler.port"/> - <stringProp name="HTTPSampler.connect_timeout"/> - <stringProp name="HTTPSampler.response_timeout"/> + <stringProp name="HTTPSampler.connect_timeout">60000</stringProp> + <stringProp name="HTTPSampler.response_timeout">200000</stringProp> <stringProp name="HTTPSampler.protocol">${request_protocol}</stringProp> <stringProp name="HTTPSampler.contentEncoding"/> <stringProp name="HTTPSampler.path">${base_path}wishlist/index/add/</stringProp> @@ -5004,8 +5757,8 @@ vars.put("product_sku", product.get("sku")); </elementProp> <stringProp name="HTTPSampler.domain"/> <stringProp name="HTTPSampler.port"/> - <stringProp name="HTTPSampler.connect_timeout"/> - <stringProp name="HTTPSampler.response_timeout"/> + <stringProp name="HTTPSampler.connect_timeout">60000</stringProp> + <stringProp name="HTTPSampler.response_timeout">200000</stringProp> <stringProp name="HTTPSampler.protocol">${request_protocol}</stringProp> <stringProp name="HTTPSampler.contentEncoding"/> <stringProp name="HTTPSampler.path">${base_path}customer/section/load/</stringProp> @@ -5073,8 +5826,8 @@ vars.put("product_sku", product.get("sku")); </elementProp> <stringProp name="HTTPSampler.domain"/> <stringProp name="HTTPSampler.port"/> - <stringProp name="HTTPSampler.connect_timeout"/> - <stringProp name="HTTPSampler.response_timeout"/> + <stringProp name="HTTPSampler.connect_timeout">60000</stringProp> + <stringProp name="HTTPSampler.response_timeout">200000</stringProp> <stringProp name="HTTPSampler.protocol">${request_protocol}</stringProp> <stringProp name="HTTPSampler.contentEncoding"/> <stringProp name="HTTPSampler.path">${base_path}wishlist/index/remove/</stringProp> @@ -5094,8 +5847,8 @@ vars.put("product_sku", product.get("sku")); </elementProp> <stringProp name="HTTPSampler.domain"/> <stringProp name="HTTPSampler.port"/> - <stringProp name="HTTPSampler.connect_timeout"/> - <stringProp name="HTTPSampler.response_timeout"/> + <stringProp name="HTTPSampler.connect_timeout">60000</stringProp> + <stringProp name="HTTPSampler.response_timeout">200000</stringProp> <stringProp name="HTTPSampler.protocol">${request_protocol}</stringProp> <stringProp name="HTTPSampler.contentEncoding"/> <stringProp name="HTTPSampler.path">${base_path}customer/account/logout/</stringProp> @@ -5239,8 +5992,8 @@ vars.put("category_name", props.get("category_names_list").get(number)); </elementProp> <stringProp name="HTTPSampler.domain"/> <stringProp name="HTTPSampler.port"/> - <stringProp name="HTTPSampler.connect_timeout"/> - <stringProp name="HTTPSampler.response_timeout"/> + <stringProp name="HTTPSampler.connect_timeout">60000</stringProp> + <stringProp name="HTTPSampler.response_timeout">200000</stringProp> <stringProp name="HTTPSampler.protocol">${request_protocol}</stringProp> <stringProp name="HTTPSampler.contentEncoding"/> <stringProp name="HTTPSampler.path">${base_path}${category_url_key}${url_suffix}</stringProp> @@ -5340,8 +6093,8 @@ vars.put("totalProductsAdded", String.valueOf(productsAdded)); </elementProp> <stringProp name="HTTPSampler.domain"/> <stringProp name="HTTPSampler.port"/> - <stringProp name="HTTPSampler.connect_timeout"/> - <stringProp name="HTTPSampler.response_timeout"/> + <stringProp name="HTTPSampler.connect_timeout">60000</stringProp> + <stringProp name="HTTPSampler.response_timeout">200000</stringProp> <stringProp name="HTTPSampler.protocol">${request_protocol}</stringProp> <stringProp name="HTTPSampler.contentEncoding"/> <stringProp name="HTTPSampler.path">${base_path}${product_url_key}${url_suffix}</stringProp> @@ -5393,8 +6146,8 @@ vars.put("totalProductsAdded", String.valueOf(productsAdded)); </elementProp> <stringProp name="HTTPSampler.domain"/> <stringProp name="HTTPSampler.port"/> - <stringProp name="HTTPSampler.connect_timeout"/> - <stringProp name="HTTPSampler.response_timeout"/> + <stringProp name="HTTPSampler.connect_timeout">60000</stringProp> + <stringProp name="HTTPSampler.response_timeout">200000</stringProp> <stringProp name="HTTPSampler.protocol">${request_protocol}</stringProp> <stringProp name="HTTPSampler.contentEncoding"/> <stringProp name="HTTPSampler.path">${base_path}catalog/product_compare/add/</stringProp> @@ -5436,8 +6189,8 @@ vars.put("totalProductsAdded", String.valueOf(productsAdded)); </elementProp> <stringProp name="HTTPSampler.domain"/> <stringProp name="HTTPSampler.port"/> - <stringProp name="HTTPSampler.connect_timeout"/> - <stringProp name="HTTPSampler.response_timeout"/> + <stringProp name="HTTPSampler.connect_timeout">60000</stringProp> + <stringProp name="HTTPSampler.response_timeout">200000</stringProp> <stringProp name="HTTPSampler.protocol">${request_protocol}</stringProp> <stringProp name="HTTPSampler.contentEncoding"/> <stringProp name="HTTPSampler.path">${base_path}customer/section/load/</stringProp> @@ -5518,8 +6271,8 @@ vars.put("totalProductsAdded", String.valueOf(productsAdded)); </elementProp> <stringProp name="HTTPSampler.domain"/> <stringProp name="HTTPSampler.port"/> - <stringProp name="HTTPSampler.connect_timeout"/> - <stringProp name="HTTPSampler.response_timeout"/> + <stringProp name="HTTPSampler.connect_timeout">60000</stringProp> + <stringProp name="HTTPSampler.response_timeout">200000</stringProp> <stringProp name="HTTPSampler.protocol">${request_protocol}</stringProp> <stringProp name="HTTPSampler.contentEncoding"/> <stringProp name="HTTPSampler.path">${base_path}${product_url_key}${url_suffix}</stringProp> @@ -5571,8 +6324,8 @@ vars.put("totalProductsAdded", String.valueOf(productsAdded)); </elementProp> <stringProp name="HTTPSampler.domain"/> <stringProp name="HTTPSampler.port"/> - <stringProp name="HTTPSampler.connect_timeout"/> - <stringProp name="HTTPSampler.response_timeout"/> + <stringProp name="HTTPSampler.connect_timeout">60000</stringProp> + <stringProp name="HTTPSampler.response_timeout">200000</stringProp> <stringProp name="HTTPSampler.protocol">${request_protocol}</stringProp> <stringProp name="HTTPSampler.contentEncoding"/> <stringProp name="HTTPSampler.path">${base_path}catalog/product_compare/add/</stringProp> @@ -5614,8 +6367,8 @@ vars.put("totalProductsAdded", String.valueOf(productsAdded)); </elementProp> <stringProp name="HTTPSampler.domain"/> <stringProp name="HTTPSampler.port"/> - <stringProp name="HTTPSampler.connect_timeout"/> - <stringProp name="HTTPSampler.response_timeout"/> + <stringProp name="HTTPSampler.connect_timeout">60000</stringProp> + <stringProp name="HTTPSampler.response_timeout">200000</stringProp> <stringProp name="HTTPSampler.protocol">${request_protocol}</stringProp> <stringProp name="HTTPSampler.contentEncoding"/> <stringProp name="HTTPSampler.path">${base_path}customer/section/load/</stringProp> @@ -5646,8 +6399,8 @@ vars.put("totalProductsAdded", String.valueOf(productsAdded)); </elementProp> <stringProp name="HTTPSampler.domain"/> <stringProp name="HTTPSampler.port"/> - <stringProp name="HTTPSampler.connect_timeout"/> - <stringProp name="HTTPSampler.response_timeout"/> + <stringProp name="HTTPSampler.connect_timeout">60000</stringProp> + <stringProp name="HTTPSampler.response_timeout">200000</stringProp> <stringProp name="HTTPSampler.protocol">${request_protocol}</stringProp> <stringProp name="HTTPSampler.contentEncoding"/> <stringProp name="HTTPSampler.path">${base_path}catalog/product_compare/index/</stringProp> @@ -5682,8 +6435,8 @@ vars.put("totalProductsAdded", String.valueOf(productsAdded)); </elementProp> <stringProp name="HTTPSampler.domain"/> <stringProp name="HTTPSampler.port"/> - <stringProp name="HTTPSampler.connect_timeout"/> - <stringProp name="HTTPSampler.response_timeout"/> + <stringProp name="HTTPSampler.connect_timeout">60000</stringProp> + <stringProp name="HTTPSampler.response_timeout">200000</stringProp> <stringProp name="HTTPSampler.protocol">${request_protocol}</stringProp> <stringProp name="HTTPSampler.contentEncoding"/> <stringProp name="HTTPSampler.path">${base_path}catalog/product_compare/clear</stringProp> @@ -5806,8 +6559,8 @@ vars.put("category_name", props.get("category_names_list").get(number)); </elementProp> <stringProp name="HTTPSampler.domain"/> <stringProp name="HTTPSampler.port"/> - <stringProp name="HTTPSampler.connect_timeout"/> - <stringProp name="HTTPSampler.response_timeout"/> + <stringProp name="HTTPSampler.connect_timeout">60000</stringProp> + <stringProp name="HTTPSampler.response_timeout">200000</stringProp> <stringProp name="HTTPSampler.protocol">${request_protocol}</stringProp> <stringProp name="HTTPSampler.contentEncoding"/> <stringProp name="HTTPSampler.path">${base_path}</stringProp> @@ -5837,8 +6590,8 @@ vars.put("category_name", props.get("category_names_list").get(number)); </elementProp> <stringProp name="HTTPSampler.domain"/> <stringProp name="HTTPSampler.port"/> - <stringProp name="HTTPSampler.connect_timeout"/> - <stringProp name="HTTPSampler.response_timeout"/> + <stringProp name="HTTPSampler.connect_timeout">60000</stringProp> + <stringProp name="HTTPSampler.response_timeout">200000</stringProp> <stringProp name="HTTPSampler.protocol">${request_protocol}</stringProp> <stringProp name="HTTPSampler.contentEncoding"/> <stringProp name="HTTPSampler.path">${base_path}${category_url_key}${url_suffix}</stringProp> @@ -5939,8 +6692,8 @@ vars.put("totalProductsAdded", String.valueOf(productsAdded)); </elementProp> <stringProp name="HTTPSampler.domain"/> <stringProp name="HTTPSampler.port"/> - <stringProp name="HTTPSampler.connect_timeout"/> - <stringProp name="HTTPSampler.response_timeout"/> + <stringProp name="HTTPSampler.connect_timeout">60000</stringProp> + <stringProp name="HTTPSampler.response_timeout">200000</stringProp> <stringProp name="HTTPSampler.protocol">${request_protocol}</stringProp> <stringProp name="HTTPSampler.contentEncoding"/> <stringProp name="HTTPSampler.path">${base_path}${product_url_key}${url_suffix}</stringProp> @@ -5999,8 +6752,8 @@ vars.put("totalProductsAdded", String.valueOf(productsAdded)); </elementProp> <stringProp name="HTTPSampler.domain"/> <stringProp name="HTTPSampler.port"/> - <stringProp name="HTTPSampler.connect_timeout"/> - <stringProp name="HTTPSampler.response_timeout"/> + <stringProp name="HTTPSampler.connect_timeout">60000</stringProp> + <stringProp name="HTTPSampler.response_timeout">200000</stringProp> <stringProp name="HTTPSampler.protocol">${request_protocol}</stringProp> <stringProp name="HTTPSampler.contentEncoding"/> <stringProp name="HTTPSampler.path">${base_path}checkout/cart/add/</stringProp> @@ -6052,8 +6805,8 @@ vars.put("totalProductsAdded", String.valueOf(productsAdded)); </elementProp> <stringProp name="HTTPSampler.domain"/> <stringProp name="HTTPSampler.port"/> - <stringProp name="HTTPSampler.connect_timeout"/> - <stringProp name="HTTPSampler.response_timeout"/> + <stringProp name="HTTPSampler.connect_timeout">60000</stringProp> + <stringProp name="HTTPSampler.response_timeout">200000</stringProp> <stringProp name="HTTPSampler.protocol">${request_protocol}</stringProp> <stringProp name="HTTPSampler.contentEncoding"/> <stringProp name="HTTPSampler.path">${base_path}customer/section/load/</stringProp> @@ -6162,8 +6915,8 @@ vars.put("totalProductsAdded", String.valueOf(productsAdded)); </elementProp> <stringProp name="HTTPSampler.domain"/> <stringProp name="HTTPSampler.port"/> - <stringProp name="HTTPSampler.connect_timeout"/> - <stringProp name="HTTPSampler.response_timeout"/> + <stringProp name="HTTPSampler.connect_timeout">60000</stringProp> + <stringProp name="HTTPSampler.response_timeout">200000</stringProp> <stringProp name="HTTPSampler.protocol">${request_protocol}</stringProp> <stringProp name="HTTPSampler.contentEncoding"/> <stringProp name="HTTPSampler.path">${base_path}${product_url_key}${url_suffix}</stringProp> @@ -6218,8 +6971,8 @@ vars.put("totalProductsAdded", String.valueOf(productsAdded)); </elementProp> <stringProp name="HTTPSampler.domain"/> <stringProp name="HTTPSampler.port"/> - <stringProp name="HTTPSampler.connect_timeout"/> - <stringProp name="HTTPSampler.response_timeout"/> + <stringProp name="HTTPSampler.connect_timeout">60000</stringProp> + <stringProp name="HTTPSampler.response_timeout">200000</stringProp> <stringProp name="HTTPSampler.protocol">${request_protocol}</stringProp> <stringProp name="HTTPSampler.contentEncoding"/> <stringProp name="HTTPSampler.path">${base_path}rest/V1/integration/admin/token</stringProp> @@ -6267,8 +7020,8 @@ vars.put("totalProductsAdded", String.valueOf(productsAdded)); </elementProp> <stringProp name="HTTPSampler.domain"/> <stringProp name="HTTPSampler.port"/> - <stringProp name="HTTPSampler.connect_timeout"/> - <stringProp name="HTTPSampler.response_timeout"/> + <stringProp name="HTTPSampler.connect_timeout">60000</stringProp> + <stringProp name="HTTPSampler.response_timeout">200000</stringProp> <stringProp name="HTTPSampler.protocol">${request_protocol}</stringProp> <stringProp name="HTTPSampler.contentEncoding"/> <stringProp name="HTTPSampler.path">${base_path}rest/V1/configurable-products/${product_sku}/options/all</stringProp> @@ -6335,8 +7088,8 @@ vars.put("totalProductsAdded", String.valueOf(productsAdded)); </elementProp> <stringProp name="HTTPSampler.domain"/> <stringProp name="HTTPSampler.port"/> - <stringProp name="HTTPSampler.connect_timeout"/> - <stringProp name="HTTPSampler.response_timeout"/> + <stringProp name="HTTPSampler.connect_timeout">60000</stringProp> + <stringProp name="HTTPSampler.response_timeout">200000</stringProp> <stringProp name="HTTPSampler.protocol">${request_protocol}</stringProp> <stringProp name="HTTPSampler.contentEncoding"/> <stringProp name="HTTPSampler.path">${base_path}checkout/cart/add/</stringProp> @@ -6418,8 +7171,8 @@ vars.put("totalProductsAdded", String.valueOf(productsAdded)); </elementProp> <stringProp name="HTTPSampler.domain"/> <stringProp name="HTTPSampler.port"/> - <stringProp name="HTTPSampler.connect_timeout"/> - <stringProp name="HTTPSampler.response_timeout"/> + <stringProp name="HTTPSampler.connect_timeout">60000</stringProp> + <stringProp name="HTTPSampler.response_timeout">200000</stringProp> <stringProp name="HTTPSampler.protocol">${request_protocol}</stringProp> <stringProp name="HTTPSampler.contentEncoding"/> <stringProp name="HTTPSampler.path">${base_path}customer/section/load/</stringProp> @@ -6476,14 +7229,26 @@ vars.put("totalProductsAdded", String.valueOf(productsAdded)); <stringProp name="TestPlan.comments">mpaf/tool/fragments/ce/simple_controller.jmx</stringProp> </GenericController> <hashTree> + <JSR223PreProcessor guiclass="TestBeanGUI" testclass="JSR223PreProcessor" testname="Get region data" enabled="true"> + <stringProp name="scriptLanguage">javascript</stringProp> + <stringProp name="parameters"/> + <stringProp name="filename"/> + <stringProp name="cacheKey"/> + <stringProp name="script"> + vars.put("alabama_region_id", props.get("alabama_region_id")); + vars.put("california_region_id", props.get("california_region_id")); +</stringProp> + <stringProp name="TestPlan.comments">mpaf/tool/fragments/ce/common/get_region_data.jmx</stringProp></JSR223PreProcessor> + <hashTree/> + <HTTPSamplerProxy guiclass="HttpTestSampleGui" testclass="HTTPSamplerProxy" testname="Checkout start" enabled="true"> <elementProp name="HTTPsampler.Arguments" elementType="Arguments" guiclass="HTTPArgumentsPanel" testclass="Arguments" enabled="true"> <collectionProp name="Arguments.arguments"/> </elementProp> <stringProp name="HTTPSampler.domain"/> <stringProp name="HTTPSampler.port"/> - <stringProp name="HTTPSampler.connect_timeout"/> - <stringProp name="HTTPSampler.response_timeout"/> + <stringProp name="HTTPSampler.connect_timeout">60000</stringProp> + <stringProp name="HTTPSampler.response_timeout">200000</stringProp> <stringProp name="HTTPSampler.protocol">${request_protocol}</stringProp> <stringProp name="HTTPSampler.contentEncoding"/> <stringProp name="HTTPSampler.path">${base_path}checkout/</stringProp> @@ -6549,8 +7314,8 @@ vars.put("totalProductsAdded", String.valueOf(productsAdded)); </elementProp> <stringProp name="HTTPSampler.domain"/> <stringProp name="HTTPSampler.port"/> - <stringProp name="HTTPSampler.connect_timeout"/> - <stringProp name="HTTPSampler.response_timeout"/> + <stringProp name="HTTPSampler.connect_timeout">60000</stringProp> + <stringProp name="HTTPSampler.response_timeout">200000</stringProp> <stringProp name="HTTPSampler.protocol">${request_protocol}</stringProp> <stringProp name="HTTPSampler.contentEncoding"/> <stringProp name="HTTPSampler.path">${base_path}rest/default/V1/customers/isEmailAvailable</stringProp> @@ -6608,8 +7373,8 @@ vars.put("totalProductsAdded", String.valueOf(productsAdded)); </elementProp> <stringProp name="HTTPSampler.domain"/> <stringProp name="HTTPSampler.port"/> - <stringProp name="HTTPSampler.connect_timeout"/> - <stringProp name="HTTPSampler.response_timeout"/> + <stringProp name="HTTPSampler.connect_timeout">60000</stringProp> + <stringProp name="HTTPSampler.response_timeout">200000</stringProp> <stringProp name="HTTPSampler.protocol">${request_protocol}</stringProp> <stringProp name="HTTPSampler.contentEncoding"/> <stringProp name="HTTPSampler.path">${base_path}rest/default/V1/guest-carts/${cart_id}/estimate-shipping-methods</stringProp> @@ -6660,15 +7425,15 @@ vars.put("totalProductsAdded", String.valueOf(productsAdded)); <collectionProp name="Arguments.arguments"> <elementProp name="" elementType="HTTPArgument"> <boolProp name="HTTPArgument.always_encode">false</boolProp> - <stringProp name="Argument.value">{"addressInformation":{"shipping_address":{"countryId":"US","regionId":"12","regionCode":"CA","region":"California","street":["10441 Jefferson Blvd ste 200"],"company":"","telephone":"3109450345","fax":"","postcode":"90232","city":"Culver City","firstname":"Name","lastname":"Lastname"},"shipping_method_code":"flatrate","shipping_carrier_code":"flatrate"}}</stringProp> + <stringProp name="Argument.value">{"addressInformation":{"shipping_address":{"countryId":"US","regionId":"${california_region_id}","regionCode":"CA","region":"California","street":["10441 Jefferson Blvd ste 200"],"company":"","telephone":"3109450345","fax":"","postcode":"90232","city":"Culver City","firstname":"Name","lastname":"Lastname"},"shipping_method_code":"flatrate","shipping_carrier_code":"flatrate"}}</stringProp> <stringProp name="Argument.metadata">=</stringProp> </elementProp> </collectionProp> </elementProp> <stringProp name="HTTPSampler.domain"/> <stringProp name="HTTPSampler.port"/> - <stringProp name="HTTPSampler.connect_timeout"/> - <stringProp name="HTTPSampler.response_timeout"/> + <stringProp name="HTTPSampler.connect_timeout">60000</stringProp> + <stringProp name="HTTPSampler.response_timeout">200000</stringProp> <stringProp name="HTTPSampler.protocol">${request_protocol}</stringProp> <stringProp name="HTTPSampler.contentEncoding"/> <stringProp name="HTTPSampler.path">${base_path}rest/default/V1/guest-carts/${cart_id}/shipping-information</stringProp> @@ -6719,15 +7484,15 @@ vars.put("totalProductsAdded", String.valueOf(productsAdded)); <collectionProp name="Arguments.arguments"> <elementProp name="" elementType="HTTPArgument"> <boolProp name="HTTPArgument.always_encode">false</boolProp> - <stringProp name="Argument.value">{"cartId":"${cart_id}","email":"test@example.com","paymentMethod":{"method":"checkmo","po_number":null,"additional_data":null},"billingAddress":{"countryId":"US","regionId":"12","regionCode":"CA","region":"California","street":["10441 Jefferson Blvd ste 200"],"company":"","telephone":"3109450345","fax":"","postcode":"90232","city":"Culver City","firstname":"Name","lastname":"Lastname"}}</stringProp> + <stringProp name="Argument.value">{"cartId":"${cart_id}","email":"test@example.com","paymentMethod":{"method":"checkmo","po_number":null,"additional_data":null},"billingAddress":{"countryId":"US","regionId":"${california_region_id}","regionCode":"CA","region":"California","street":["10441 Jefferson Blvd ste 200"],"company":"","telephone":"3109450345","fax":"","postcode":"90232","city":"Culver City","firstname":"Name","lastname":"Lastname"}}</stringProp> <stringProp name="Argument.metadata">=</stringProp> </elementProp> </collectionProp> </elementProp> <stringProp name="HTTPSampler.domain"/> <stringProp name="HTTPSampler.port"/> - <stringProp name="HTTPSampler.connect_timeout"/> - <stringProp name="HTTPSampler.response_timeout"/> + <stringProp name="HTTPSampler.connect_timeout">60000</stringProp> + <stringProp name="HTTPSampler.response_timeout">200000</stringProp> <stringProp name="HTTPSampler.protocol">${request_protocol}</stringProp> <stringProp name="HTTPSampler.contentEncoding"/> <stringProp name="HTTPSampler.path">${base_path}rest/default/V1/guest-carts/${cart_id}/payment-information</stringProp> @@ -6797,8 +7562,8 @@ vars.put("totalProductsAdded", String.valueOf(productsAdded)); </elementProp> <stringProp name="HTTPSampler.domain"/> <stringProp name="HTTPSampler.port"/> - <stringProp name="HTTPSampler.connect_timeout"/> - <stringProp name="HTTPSampler.response_timeout"/> + <stringProp name="HTTPSampler.connect_timeout">60000</stringProp> + <stringProp name="HTTPSampler.response_timeout">200000</stringProp> <stringProp name="HTTPSampler.protocol">${request_protocol}</stringProp> <stringProp name="HTTPSampler.contentEncoding"/> <stringProp name="HTTPSampler.path">${base_path}checkout/onepage/success/</stringProp> @@ -6959,8 +7724,8 @@ vars.put("customer_email", customerUser); </elementProp> <stringProp name="HTTPSampler.domain"/> <stringProp name="HTTPSampler.port"/> - <stringProp name="HTTPSampler.connect_timeout"/> - <stringProp name="HTTPSampler.response_timeout"/> + <stringProp name="HTTPSampler.connect_timeout">60000</stringProp> + <stringProp name="HTTPSampler.response_timeout">200000</stringProp> <stringProp name="HTTPSampler.protocol">${request_protocol}</stringProp> <stringProp name="HTTPSampler.contentEncoding"/> <stringProp name="HTTPSampler.path">${base_path}</stringProp> @@ -6990,8 +7755,8 @@ vars.put("customer_email", customerUser); </elementProp> <stringProp name="HTTPSampler.domain"/> <stringProp name="HTTPSampler.port"/> - <stringProp name="HTTPSampler.connect_timeout"/> - <stringProp name="HTTPSampler.response_timeout"/> + <stringProp name="HTTPSampler.connect_timeout">60000</stringProp> + <stringProp name="HTTPSampler.response_timeout">200000</stringProp> <stringProp name="HTTPSampler.protocol">${request_protocol}</stringProp> <stringProp name="HTTPSampler.contentEncoding"/> <stringProp name="HTTPSampler.path">${base_path}customer/account/login/</stringProp> @@ -7050,8 +7815,8 @@ vars.put("customer_email", customerUser); </elementProp> <stringProp name="HTTPSampler.domain"/> <stringProp name="HTTPSampler.port"/> - <stringProp name="HTTPSampler.connect_timeout"/> - <stringProp name="HTTPSampler.response_timeout"/> + <stringProp name="HTTPSampler.connect_timeout">60000</stringProp> + <stringProp name="HTTPSampler.response_timeout">200000</stringProp> <stringProp name="HTTPSampler.protocol">${request_protocol}</stringProp> <stringProp name="HTTPSampler.contentEncoding"/> <stringProp name="HTTPSampler.path">${base_path}customer/account/loginPost/</stringProp> @@ -7122,8 +7887,8 @@ vars.put("customer_email", customerUser); </elementProp> <stringProp name="HTTPSampler.domain"/> <stringProp name="HTTPSampler.port"/> - <stringProp name="HTTPSampler.connect_timeout"/> - <stringProp name="HTTPSampler.response_timeout"/> + <stringProp name="HTTPSampler.connect_timeout">60000</stringProp> + <stringProp name="HTTPSampler.response_timeout">200000</stringProp> <stringProp name="HTTPSampler.protocol">${request_protocol}</stringProp> <stringProp name="HTTPSampler.contentEncoding"/> <stringProp name="HTTPSampler.path">${base_path}customer/section/load/</stringProp> @@ -7143,8 +7908,8 @@ vars.put("customer_email", customerUser); </elementProp> <stringProp name="HTTPSampler.domain"/> <stringProp name="HTTPSampler.port"/> - <stringProp name="HTTPSampler.connect_timeout"/> - <stringProp name="HTTPSampler.response_timeout"/> + <stringProp name="HTTPSampler.connect_timeout">60000</stringProp> + <stringProp name="HTTPSampler.response_timeout">200000</stringProp> <stringProp name="HTTPSampler.protocol">${request_protocol}</stringProp> <stringProp name="HTTPSampler.contentEncoding"/> <stringProp name="HTTPSampler.path">${base_path}${category_url_key}${url_suffix}</stringProp> @@ -7245,8 +8010,8 @@ vars.put("totalProductsAdded", String.valueOf(productsAdded)); </elementProp> <stringProp name="HTTPSampler.domain"/> <stringProp name="HTTPSampler.port"/> - <stringProp name="HTTPSampler.connect_timeout"/> - <stringProp name="HTTPSampler.response_timeout"/> + <stringProp name="HTTPSampler.connect_timeout">60000</stringProp> + <stringProp name="HTTPSampler.response_timeout">200000</stringProp> <stringProp name="HTTPSampler.protocol">${request_protocol}</stringProp> <stringProp name="HTTPSampler.contentEncoding"/> <stringProp name="HTTPSampler.path">${base_path}${product_url_key}${url_suffix}</stringProp> @@ -7305,8 +8070,8 @@ vars.put("totalProductsAdded", String.valueOf(productsAdded)); </elementProp> <stringProp name="HTTPSampler.domain"/> <stringProp name="HTTPSampler.port"/> - <stringProp name="HTTPSampler.connect_timeout"/> - <stringProp name="HTTPSampler.response_timeout"/> + <stringProp name="HTTPSampler.connect_timeout">60000</stringProp> + <stringProp name="HTTPSampler.response_timeout">200000</stringProp> <stringProp name="HTTPSampler.protocol">${request_protocol}</stringProp> <stringProp name="HTTPSampler.contentEncoding"/> <stringProp name="HTTPSampler.path">${base_path}checkout/cart/add/</stringProp> @@ -7358,8 +8123,8 @@ vars.put("totalProductsAdded", String.valueOf(productsAdded)); </elementProp> <stringProp name="HTTPSampler.domain"/> <stringProp name="HTTPSampler.port"/> - <stringProp name="HTTPSampler.connect_timeout"/> - <stringProp name="HTTPSampler.response_timeout"/> + <stringProp name="HTTPSampler.connect_timeout">60000</stringProp> + <stringProp name="HTTPSampler.response_timeout">200000</stringProp> <stringProp name="HTTPSampler.protocol">${request_protocol}</stringProp> <stringProp name="HTTPSampler.contentEncoding"/> <stringProp name="HTTPSampler.path">${base_path}customer/section/load/</stringProp> @@ -7468,8 +8233,8 @@ vars.put("totalProductsAdded", String.valueOf(productsAdded)); </elementProp> <stringProp name="HTTPSampler.domain"/> <stringProp name="HTTPSampler.port"/> - <stringProp name="HTTPSampler.connect_timeout"/> - <stringProp name="HTTPSampler.response_timeout"/> + <stringProp name="HTTPSampler.connect_timeout">60000</stringProp> + <stringProp name="HTTPSampler.response_timeout">200000</stringProp> <stringProp name="HTTPSampler.protocol">${request_protocol}</stringProp> <stringProp name="HTTPSampler.contentEncoding"/> <stringProp name="HTTPSampler.path">${base_path}${product_url_key}${url_suffix}</stringProp> @@ -7524,8 +8289,8 @@ vars.put("totalProductsAdded", String.valueOf(productsAdded)); </elementProp> <stringProp name="HTTPSampler.domain"/> <stringProp name="HTTPSampler.port"/> - <stringProp name="HTTPSampler.connect_timeout"/> - <stringProp name="HTTPSampler.response_timeout"/> + <stringProp name="HTTPSampler.connect_timeout">60000</stringProp> + <stringProp name="HTTPSampler.response_timeout">200000</stringProp> <stringProp name="HTTPSampler.protocol">${request_protocol}</stringProp> <stringProp name="HTTPSampler.contentEncoding"/> <stringProp name="HTTPSampler.path">${base_path}rest/V1/integration/admin/token</stringProp> @@ -7573,8 +8338,8 @@ vars.put("totalProductsAdded", String.valueOf(productsAdded)); </elementProp> <stringProp name="HTTPSampler.domain"/> <stringProp name="HTTPSampler.port"/> - <stringProp name="HTTPSampler.connect_timeout"/> - <stringProp name="HTTPSampler.response_timeout"/> + <stringProp name="HTTPSampler.connect_timeout">60000</stringProp> + <stringProp name="HTTPSampler.response_timeout">200000</stringProp> <stringProp name="HTTPSampler.protocol">${request_protocol}</stringProp> <stringProp name="HTTPSampler.contentEncoding"/> <stringProp name="HTTPSampler.path">${base_path}rest/V1/configurable-products/${product_sku}/options/all</stringProp> @@ -7641,8 +8406,8 @@ vars.put("totalProductsAdded", String.valueOf(productsAdded)); </elementProp> <stringProp name="HTTPSampler.domain"/> <stringProp name="HTTPSampler.port"/> - <stringProp name="HTTPSampler.connect_timeout"/> - <stringProp name="HTTPSampler.response_timeout"/> + <stringProp name="HTTPSampler.connect_timeout">60000</stringProp> + <stringProp name="HTTPSampler.response_timeout">200000</stringProp> <stringProp name="HTTPSampler.protocol">${request_protocol}</stringProp> <stringProp name="HTTPSampler.contentEncoding"/> <stringProp name="HTTPSampler.path">${base_path}checkout/cart/add/</stringProp> @@ -7724,8 +8489,8 @@ vars.put("totalProductsAdded", String.valueOf(productsAdded)); </elementProp> <stringProp name="HTTPSampler.domain"/> <stringProp name="HTTPSampler.port"/> - <stringProp name="HTTPSampler.connect_timeout"/> - <stringProp name="HTTPSampler.response_timeout"/> + <stringProp name="HTTPSampler.connect_timeout">60000</stringProp> + <stringProp name="HTTPSampler.response_timeout">200000</stringProp> <stringProp name="HTTPSampler.protocol">${request_protocol}</stringProp> <stringProp name="HTTPSampler.contentEncoding"/> <stringProp name="HTTPSampler.path">${base_path}customer/section/load/</stringProp> @@ -7782,14 +8547,26 @@ vars.put("totalProductsAdded", String.valueOf(productsAdded)); <stringProp name="TestPlan.comments">mpaf/tool/fragments/ce/simple_controller.jmx</stringProp> </GenericController> <hashTree> + <JSR223PreProcessor guiclass="TestBeanGUI" testclass="JSR223PreProcessor" testname="Get region data" enabled="true"> + <stringProp name="scriptLanguage">javascript</stringProp> + <stringProp name="parameters"/> + <stringProp name="filename"/> + <stringProp name="cacheKey"/> + <stringProp name="script"> + vars.put("alabama_region_id", props.get("alabama_region_id")); + vars.put("california_region_id", props.get("california_region_id")); +</stringProp> + <stringProp name="TestPlan.comments">mpaf/tool/fragments/ce/common/get_region_data.jmx</stringProp></JSR223PreProcessor> + <hashTree/> + <HTTPSamplerProxy guiclass="HttpTestSampleGui" testclass="HTTPSamplerProxy" testname="Checkout start" enabled="true"> <elementProp name="HTTPsampler.Arguments" elementType="Arguments" guiclass="HTTPArgumentsPanel" testclass="Arguments" enabled="true"> <collectionProp name="Arguments.arguments"/> </elementProp> <stringProp name="HTTPSampler.domain"/> <stringProp name="HTTPSampler.port"/> - <stringProp name="HTTPSampler.connect_timeout"/> - <stringProp name="HTTPSampler.response_timeout"/> + <stringProp name="HTTPSampler.connect_timeout">60000</stringProp> + <stringProp name="HTTPSampler.response_timeout">200000</stringProp> <stringProp name="HTTPSampler.protocol">${request_protocol}</stringProp> <stringProp name="HTTPSampler.contentEncoding"/> <stringProp name="HTTPSampler.path">${base_path}checkout/</stringProp> @@ -7895,8 +8672,8 @@ vars.put("totalProductsAdded", String.valueOf(productsAdded)); </elementProp> <stringProp name="HTTPSampler.domain"/> <stringProp name="HTTPSampler.port"/> - <stringProp name="HTTPSampler.connect_timeout"/> - <stringProp name="HTTPSampler.response_timeout"/> + <stringProp name="HTTPSampler.connect_timeout">60000</stringProp> + <stringProp name="HTTPSampler.response_timeout">200000</stringProp> <stringProp name="HTTPSampler.protocol">${request_protocol}</stringProp> <stringProp name="HTTPSampler.contentEncoding"/> <stringProp name="HTTPSampler.path">${base_path}rest/default/V1/carts/mine/estimate-shipping-methods-by-address-id</stringProp> @@ -7947,15 +8724,15 @@ vars.put("totalProductsAdded", String.valueOf(productsAdded)); <collectionProp name="Arguments.arguments"> <elementProp name="" elementType="HTTPArgument"> <boolProp name="HTTPArgument.always_encode">false</boolProp> - <stringProp name="Argument.value">{"addressInformation":{"shipping_address":{"customerAddressId":"${address_id}","countryId":"US","regionId":5,"regionCode":"AR","region":"Arkansas","customerId":"${customer_id}","street":["123 Freedom Blvd. #123"],"telephone":"022-333-4455","postcode":"123123","city":"Fayetteville","firstname":"Anthony","lastname":"Nealy"},"shipping_method_code":"flatrate","shipping_carrier_code":"flatrate"}}</stringProp> + <stringProp name="Argument.value">{"addressInformation":{"shipping_address":{"customerAddressId":"${address_id}","countryId":"US","regionId":"${alabama_region_id}","regionCode":"AL","region":"Alabama","customerId":"${customer_id}","street":["123 Freedom Blvd. #123"],"telephone":"022-333-4455","postcode":"123123","city":"Fayetteville","firstname":"Anthony","lastname":"Nealy"},"shipping_method_code":"flatrate","shipping_carrier_code":"flatrate"}}</stringProp> <stringProp name="Argument.metadata">=</stringProp> </elementProp> </collectionProp> </elementProp> <stringProp name="HTTPSampler.domain"/> <stringProp name="HTTPSampler.port"/> - <stringProp name="HTTPSampler.connect_timeout"/> - <stringProp name="HTTPSampler.response_timeout"/> + <stringProp name="HTTPSampler.connect_timeout">60000</stringProp> + <stringProp name="HTTPSampler.response_timeout">200000</stringProp> <stringProp name="HTTPSampler.protocol">${request_protocol}</stringProp> <stringProp name="HTTPSampler.contentEncoding"/> <stringProp name="HTTPSampler.path">${base_path}rest/default/V1/carts/mine/shipping-information</stringProp> @@ -8006,15 +8783,15 @@ vars.put("totalProductsAdded", String.valueOf(productsAdded)); <collectionProp name="Arguments.arguments"> <elementProp name="" elementType="HTTPArgument"> <boolProp name="HTTPArgument.always_encode">false</boolProp> - <stringProp name="Argument.value">{"cartId":"${cart_id}","paymentMethod":{"method":"checkmo","po_number":null,"additional_data":null},"billingAddress":{"customerAddressId":"${address_id}","countryId":"US","regionId":5,"regionCode":"AR","region":"Arkansas","customerId":"${customer_id}","street":["123 Freedom Blvd. #123"],"telephone":"022-333-4455","postcode":"123123","city":"Fayetteville","firstname":"Anthony","lastname":"Nealy"}}</stringProp> + <stringProp name="Argument.value">{"cartId":"${cart_id}","paymentMethod":{"method":"checkmo","po_number":null,"additional_data":null},"billingAddress":{"customerAddressId":"${address_id}","countryId":"US","regionId":"${alabama_region_id}","regionCode":"AL","region":"Alabama","customerId":"${customer_id}","street":["123 Freedom Blvd. #123"],"telephone":"022-333-4455","postcode":"123123","city":"Fayetteville","firstname":"Anthony","lastname":"Nealy"}}</stringProp> <stringProp name="Argument.metadata">=</stringProp> </elementProp> </collectionProp> </elementProp> <stringProp name="HTTPSampler.domain"/> <stringProp name="HTTPSampler.port"/> - <stringProp name="HTTPSampler.connect_timeout"/> - <stringProp name="HTTPSampler.response_timeout"/> + <stringProp name="HTTPSampler.connect_timeout">60000</stringProp> + <stringProp name="HTTPSampler.response_timeout">200000</stringProp> <stringProp name="HTTPSampler.protocol">${request_protocol}</stringProp> <stringProp name="HTTPSampler.contentEncoding"/> <stringProp name="HTTPSampler.path">${base_path}rest/default/V1/carts/mine/payment-information</stringProp> @@ -8065,8 +8842,8 @@ vars.put("totalProductsAdded", String.valueOf(productsAdded)); </elementProp> <stringProp name="HTTPSampler.domain"/> <stringProp name="HTTPSampler.port"/> - <stringProp name="HTTPSampler.connect_timeout"/> - <stringProp name="HTTPSampler.response_timeout"/> + <stringProp name="HTTPSampler.connect_timeout">60000</stringProp> + <stringProp name="HTTPSampler.response_timeout">200000</stringProp> <stringProp name="HTTPSampler.protocol">${request_protocol}</stringProp> <stringProp name="HTTPSampler.contentEncoding"/> <stringProp name="HTTPSampler.path">${base_path}checkout/onepage/success/</stringProp> @@ -8098,8 +8875,8 @@ vars.put("totalProductsAdded", String.valueOf(productsAdded)); </elementProp> <stringProp name="HTTPSampler.domain"/> <stringProp name="HTTPSampler.port"/> - <stringProp name="HTTPSampler.connect_timeout"/> - <stringProp name="HTTPSampler.response_timeout"/> + <stringProp name="HTTPSampler.connect_timeout">60000</stringProp> + <stringProp name="HTTPSampler.response_timeout">200000</stringProp> <stringProp name="HTTPSampler.protocol">${request_protocol}</stringProp> <stringProp name="HTTPSampler.contentEncoding"/> <stringProp name="HTTPSampler.path">${base_path}customer/account/logout/</stringProp> @@ -8255,8 +9032,8 @@ vars.put("customer_email", customerUser); </elementProp> <stringProp name="HTTPSampler.domain"/> <stringProp name="HTTPSampler.port"/> - <stringProp name="HTTPSampler.connect_timeout"/> - <stringProp name="HTTPSampler.response_timeout"/> + <stringProp name="HTTPSampler.connect_timeout">60000</stringProp> + <stringProp name="HTTPSampler.response_timeout">200000</stringProp> <stringProp name="HTTPSampler.protocol">${request_protocol}</stringProp> <stringProp name="HTTPSampler.contentEncoding"/> <stringProp name="HTTPSampler.path">${base_path}customer/account/login/</stringProp> @@ -8315,8 +9092,8 @@ vars.put("customer_email", customerUser); </elementProp> <stringProp name="HTTPSampler.domain"/> <stringProp name="HTTPSampler.port"/> - <stringProp name="HTTPSampler.connect_timeout"/> - <stringProp name="HTTPSampler.response_timeout"/> + <stringProp name="HTTPSampler.connect_timeout">60000</stringProp> + <stringProp name="HTTPSampler.response_timeout">200000</stringProp> <stringProp name="HTTPSampler.protocol">${request_protocol}</stringProp> <stringProp name="HTTPSampler.contentEncoding"/> <stringProp name="HTTPSampler.path">${base_path}customer/account/loginPost/</stringProp> @@ -8387,8 +9164,8 @@ vars.put("customer_email", customerUser); </elementProp> <stringProp name="HTTPSampler.domain"/> <stringProp name="HTTPSampler.port"/> - <stringProp name="HTTPSampler.connect_timeout"/> - <stringProp name="HTTPSampler.response_timeout"/> + <stringProp name="HTTPSampler.connect_timeout">60000</stringProp> + <stringProp name="HTTPSampler.response_timeout">200000</stringProp> <stringProp name="HTTPSampler.protocol">${request_protocol}</stringProp> <stringProp name="HTTPSampler.contentEncoding"/> <stringProp name="HTTPSampler.path">${base_path}customer/section/load/</stringProp> @@ -8444,8 +9221,8 @@ vars.put("product_sku", product.get("sku")); </elementProp> <stringProp name="HTTPSampler.domain"/> <stringProp name="HTTPSampler.port"/> - <stringProp name="HTTPSampler.connect_timeout"/> - <stringProp name="HTTPSampler.response_timeout"/> + <stringProp name="HTTPSampler.connect_timeout">60000</stringProp> + <stringProp name="HTTPSampler.response_timeout">200000</stringProp> <stringProp name="HTTPSampler.protocol">${request_protocol}</stringProp> <stringProp name="HTTPSampler.contentEncoding"/> <stringProp name="HTTPSampler.path">${base_path}${product_url_key}${url_suffix}</stringProp> @@ -8518,8 +9295,8 @@ vars.put("product_sku", product.get("sku")); </elementProp> <stringProp name="HTTPSampler.domain"/> <stringProp name="HTTPSampler.port"/> - <stringProp name="HTTPSampler.connect_timeout"/> - <stringProp name="HTTPSampler.response_timeout"/> + <stringProp name="HTTPSampler.connect_timeout">60000</stringProp> + <stringProp name="HTTPSampler.response_timeout">200000</stringProp> <stringProp name="HTTPSampler.protocol">${request_protocol}</stringProp> <stringProp name="HTTPSampler.contentEncoding"/> <stringProp name="HTTPSampler.path">${base_path}review/product/post/id/${product_id}</stringProp> @@ -8571,8 +9348,8 @@ vars.put("product_sku", product.get("sku")); </elementProp> <stringProp name="HTTPSampler.domain"/> <stringProp name="HTTPSampler.port"/> - <stringProp name="HTTPSampler.connect_timeout"/> - <stringProp name="HTTPSampler.response_timeout"/> + <stringProp name="HTTPSampler.connect_timeout">60000</stringProp> + <stringProp name="HTTPSampler.response_timeout">200000</stringProp> <stringProp name="HTTPSampler.protocol">${request_protocol}</stringProp> <stringProp name="HTTPSampler.contentEncoding"/> <stringProp name="HTTPSampler.path">${base_path}customer/section/load/</stringProp> @@ -8600,8 +9377,8 @@ vars.put("product_sku", product.get("sku")); </elementProp> <stringProp name="HTTPSampler.domain"/> <stringProp name="HTTPSampler.port"/> - <stringProp name="HTTPSampler.connect_timeout"/> - <stringProp name="HTTPSampler.response_timeout"/> + <stringProp name="HTTPSampler.connect_timeout">60000</stringProp> + <stringProp name="HTTPSampler.response_timeout">200000</stringProp> <stringProp name="HTTPSampler.protocol">${request_protocol}</stringProp> <stringProp name="HTTPSampler.contentEncoding"/> <stringProp name="HTTPSampler.path">${base_path}customer/account/logout/</stringProp> @@ -8771,8 +9548,8 @@ vars.put("customer_email", customerUser); </elementProp> <stringProp name="HTTPSampler.domain"/> <stringProp name="HTTPSampler.port"/> - <stringProp name="HTTPSampler.connect_timeout"/> - <stringProp name="HTTPSampler.response_timeout"/> + <stringProp name="HTTPSampler.connect_timeout">60000</stringProp> + <stringProp name="HTTPSampler.response_timeout">200000</stringProp> <stringProp name="HTTPSampler.protocol">${request_protocol}</stringProp> <stringProp name="HTTPSampler.contentEncoding"/> <stringProp name="HTTPSampler.path">${base_path}customer/account/login/</stringProp> @@ -8831,8 +9608,8 @@ vars.put("customer_email", customerUser); </elementProp> <stringProp name="HTTPSampler.domain"/> <stringProp name="HTTPSampler.port"/> - <stringProp name="HTTPSampler.connect_timeout"/> - <stringProp name="HTTPSampler.response_timeout"/> + <stringProp name="HTTPSampler.connect_timeout">60000</stringProp> + <stringProp name="HTTPSampler.response_timeout">200000</stringProp> <stringProp name="HTTPSampler.protocol">${request_protocol}</stringProp> <stringProp name="HTTPSampler.contentEncoding"/> <stringProp name="HTTPSampler.path">${base_path}customer/account/loginPost/</stringProp> @@ -8903,8 +9680,8 @@ vars.put("customer_email", customerUser); </elementProp> <stringProp name="HTTPSampler.domain"/> <stringProp name="HTTPSampler.port"/> - <stringProp name="HTTPSampler.connect_timeout"/> - <stringProp name="HTTPSampler.response_timeout"/> + <stringProp name="HTTPSampler.connect_timeout">60000</stringProp> + <stringProp name="HTTPSampler.response_timeout">200000</stringProp> <stringProp name="HTTPSampler.protocol">${request_protocol}</stringProp> <stringProp name="HTTPSampler.contentEncoding"/> <stringProp name="HTTPSampler.path">${base_path}customer/section/load/</stringProp> @@ -8924,8 +9701,8 @@ vars.put("customer_email", customerUser); </elementProp> <stringProp name="HTTPSampler.domain"/> <stringProp name="HTTPSampler.port"/> - <stringProp name="HTTPSampler.connect_timeout"/> - <stringProp name="HTTPSampler.response_timeout"/> + <stringProp name="HTTPSampler.connect_timeout">60000</stringProp> + <stringProp name="HTTPSampler.response_timeout">200000</stringProp> <stringProp name="HTTPSampler.protocol">${request_protocol}</stringProp> <stringProp name="HTTPSampler.contentEncoding"/> <stringProp name="HTTPSampler.path">${base_path}</stringProp> @@ -8955,8 +9732,8 @@ vars.put("customer_email", customerUser); </elementProp> <stringProp name="HTTPSampler.domain"/> <stringProp name="HTTPSampler.port"/> - <stringProp name="HTTPSampler.connect_timeout"/> - <stringProp name="HTTPSampler.response_timeout"/> + <stringProp name="HTTPSampler.connect_timeout">60000</stringProp> + <stringProp name="HTTPSampler.response_timeout">200000</stringProp> <stringProp name="HTTPSampler.protocol">${request_protocol}</stringProp> <stringProp name="HTTPSampler.contentEncoding"/> <stringProp name="HTTPSampler.path">${base_path}${category_url_key}${url_suffix}</stringProp> @@ -9057,8 +9834,8 @@ vars.put("totalProductsAdded", String.valueOf(productsAdded)); </elementProp> <stringProp name="HTTPSampler.domain"/> <stringProp name="HTTPSampler.port"/> - <stringProp name="HTTPSampler.connect_timeout"/> - <stringProp name="HTTPSampler.response_timeout"/> + <stringProp name="HTTPSampler.connect_timeout">60000</stringProp> + <stringProp name="HTTPSampler.response_timeout">200000</stringProp> <stringProp name="HTTPSampler.protocol">${request_protocol}</stringProp> <stringProp name="HTTPSampler.contentEncoding"/> <stringProp name="HTTPSampler.path">${base_path}${product_url_key}${url_suffix}</stringProp> @@ -9117,8 +9894,8 @@ vars.put("totalProductsAdded", String.valueOf(productsAdded)); </elementProp> <stringProp name="HTTPSampler.domain"/> <stringProp name="HTTPSampler.port"/> - <stringProp name="HTTPSampler.connect_timeout"/> - <stringProp name="HTTPSampler.response_timeout"/> + <stringProp name="HTTPSampler.connect_timeout">60000</stringProp> + <stringProp name="HTTPSampler.response_timeout">200000</stringProp> <stringProp name="HTTPSampler.protocol">${request_protocol}</stringProp> <stringProp name="HTTPSampler.contentEncoding"/> <stringProp name="HTTPSampler.path">${base_path}checkout/cart/add/</stringProp> @@ -9170,8 +9947,8 @@ vars.put("totalProductsAdded", String.valueOf(productsAdded)); </elementProp> <stringProp name="HTTPSampler.domain"/> <stringProp name="HTTPSampler.port"/> - <stringProp name="HTTPSampler.connect_timeout"/> - <stringProp name="HTTPSampler.response_timeout"/> + <stringProp name="HTTPSampler.connect_timeout">60000</stringProp> + <stringProp name="HTTPSampler.response_timeout">200000</stringProp> <stringProp name="HTTPSampler.protocol">${request_protocol}</stringProp> <stringProp name="HTTPSampler.contentEncoding"/> <stringProp name="HTTPSampler.path">${base_path}customer/section/load/</stringProp> @@ -9280,8 +10057,8 @@ vars.put("totalProductsAdded", String.valueOf(productsAdded)); </elementProp> <stringProp name="HTTPSampler.domain"/> <stringProp name="HTTPSampler.port"/> - <stringProp name="HTTPSampler.connect_timeout"/> - <stringProp name="HTTPSampler.response_timeout"/> + <stringProp name="HTTPSampler.connect_timeout">60000</stringProp> + <stringProp name="HTTPSampler.response_timeout">200000</stringProp> <stringProp name="HTTPSampler.protocol">${request_protocol}</stringProp> <stringProp name="HTTPSampler.contentEncoding"/> <stringProp name="HTTPSampler.path">${base_path}${product_url_key}${url_suffix}</stringProp> @@ -9336,8 +10113,8 @@ vars.put("totalProductsAdded", String.valueOf(productsAdded)); </elementProp> <stringProp name="HTTPSampler.domain"/> <stringProp name="HTTPSampler.port"/> - <stringProp name="HTTPSampler.connect_timeout"/> - <stringProp name="HTTPSampler.response_timeout"/> + <stringProp name="HTTPSampler.connect_timeout">60000</stringProp> + <stringProp name="HTTPSampler.response_timeout">200000</stringProp> <stringProp name="HTTPSampler.protocol">${request_protocol}</stringProp> <stringProp name="HTTPSampler.contentEncoding"/> <stringProp name="HTTPSampler.path">${base_path}rest/V1/integration/admin/token</stringProp> @@ -9385,8 +10162,8 @@ vars.put("totalProductsAdded", String.valueOf(productsAdded)); </elementProp> <stringProp name="HTTPSampler.domain"/> <stringProp name="HTTPSampler.port"/> - <stringProp name="HTTPSampler.connect_timeout"/> - <stringProp name="HTTPSampler.response_timeout"/> + <stringProp name="HTTPSampler.connect_timeout">60000</stringProp> + <stringProp name="HTTPSampler.response_timeout">200000</stringProp> <stringProp name="HTTPSampler.protocol">${request_protocol}</stringProp> <stringProp name="HTTPSampler.contentEncoding"/> <stringProp name="HTTPSampler.path">${base_path}rest/V1/configurable-products/${product_sku}/options/all</stringProp> @@ -9453,8 +10230,8 @@ vars.put("totalProductsAdded", String.valueOf(productsAdded)); </elementProp> <stringProp name="HTTPSampler.domain"/> <stringProp name="HTTPSampler.port"/> - <stringProp name="HTTPSampler.connect_timeout"/> - <stringProp name="HTTPSampler.response_timeout"/> + <stringProp name="HTTPSampler.connect_timeout">60000</stringProp> + <stringProp name="HTTPSampler.response_timeout">200000</stringProp> <stringProp name="HTTPSampler.protocol">${request_protocol}</stringProp> <stringProp name="HTTPSampler.contentEncoding"/> <stringProp name="HTTPSampler.path">${base_path}checkout/cart/add/</stringProp> @@ -9536,8 +10313,8 @@ vars.put("totalProductsAdded", String.valueOf(productsAdded)); </elementProp> <stringProp name="HTTPSampler.domain"/> <stringProp name="HTTPSampler.port"/> - <stringProp name="HTTPSampler.connect_timeout"/> - <stringProp name="HTTPSampler.response_timeout"/> + <stringProp name="HTTPSampler.connect_timeout">60000</stringProp> + <stringProp name="HTTPSampler.response_timeout">200000</stringProp> <stringProp name="HTTPSampler.protocol">${request_protocol}</stringProp> <stringProp name="HTTPSampler.contentEncoding"/> <stringProp name="HTTPSampler.path">${base_path}customer/section/load/</stringProp> @@ -9600,8 +10377,8 @@ vars.put("totalProductsAdded", String.valueOf(productsAdded)); </elementProp> <stringProp name="HTTPSampler.domain"/> <stringProp name="HTTPSampler.port"/> - <stringProp name="HTTPSampler.connect_timeout"/> - <stringProp name="HTTPSampler.response_timeout"/> + <stringProp name="HTTPSampler.connect_timeout">60000</stringProp> + <stringProp name="HTTPSampler.response_timeout">200000</stringProp> <stringProp name="HTTPSampler.protocol"/> <stringProp name="HTTPSampler.contentEncoding"/> <stringProp name="HTTPSampler.path">${base_path}checkout/cart/</stringProp> @@ -9690,8 +10467,8 @@ vars.put("item_id", vars.get("cart_items_qty_inputs_" + id)); </elementProp> <stringProp name="HTTPSampler.domain"/> <stringProp name="HTTPSampler.port"/> - <stringProp name="HTTPSampler.connect_timeout"/> - <stringProp name="HTTPSampler.response_timeout"/> + <stringProp name="HTTPSampler.connect_timeout">60000</stringProp> + <stringProp name="HTTPSampler.response_timeout">200000</stringProp> <stringProp name="HTTPSampler.protocol"/> <stringProp name="HTTPSampler.contentEncoding"/> <stringProp name="HTTPSampler.path">${base_path}checkout/cart/delete/</stringProp> @@ -9733,8 +10510,8 @@ vars.put("item_id", vars.get("cart_items_qty_inputs_" + id)); </elementProp> <stringProp name="HTTPSampler.domain"/> <stringProp name="HTTPSampler.port"/> - <stringProp name="HTTPSampler.connect_timeout"/> - <stringProp name="HTTPSampler.response_timeout"/> + <stringProp name="HTTPSampler.connect_timeout">60000</stringProp> + <stringProp name="HTTPSampler.response_timeout">200000</stringProp> <stringProp name="HTTPSampler.protocol">${request_protocol}</stringProp> <stringProp name="HTTPSampler.contentEncoding"/> <stringProp name="HTTPSampler.path">${base_path}customer/section/load/</stringProp> @@ -9765,8 +10542,8 @@ vars.put("item_id", vars.get("cart_items_qty_inputs_" + id)); </elementProp> <stringProp name="HTTPSampler.domain"/> <stringProp name="HTTPSampler.port"/> - <stringProp name="HTTPSampler.connect_timeout"/> - <stringProp name="HTTPSampler.response_timeout"/> + <stringProp name="HTTPSampler.connect_timeout">60000</stringProp> + <stringProp name="HTTPSampler.response_timeout">200000</stringProp> <stringProp name="HTTPSampler.protocol">${request_protocol}</stringProp> <stringProp name="HTTPSampler.contentEncoding"/> <stringProp name="HTTPSampler.path">${base_path}customer/account/logout/</stringProp> @@ -9891,8 +10668,8 @@ vars.put("customer_email", customerUser); </elementProp> <stringProp name="HTTPSampler.domain"/> <stringProp name="HTTPSampler.port"/> - <stringProp name="HTTPSampler.connect_timeout"/> - <stringProp name="HTTPSampler.response_timeout"/> + <stringProp name="HTTPSampler.connect_timeout">60000</stringProp> + <stringProp name="HTTPSampler.response_timeout">200000</stringProp> <stringProp name="HTTPSampler.protocol">${request_protocol}</stringProp> <stringProp name="HTTPSampler.contentEncoding"/> <stringProp name="HTTPSampler.path">${base_path}</stringProp> @@ -9922,8 +10699,8 @@ vars.put("customer_email", customerUser); </elementProp> <stringProp name="HTTPSampler.domain"/> <stringProp name="HTTPSampler.port"/> - <stringProp name="HTTPSampler.connect_timeout"/> - <stringProp name="HTTPSampler.response_timeout"/> + <stringProp name="HTTPSampler.connect_timeout">60000</stringProp> + <stringProp name="HTTPSampler.response_timeout">200000</stringProp> <stringProp name="HTTPSampler.protocol">${request_protocol}</stringProp> <stringProp name="HTTPSampler.contentEncoding"/> <stringProp name="HTTPSampler.path">${base_path}customer/account/login/</stringProp> @@ -9982,8 +10759,8 @@ vars.put("customer_email", customerUser); </elementProp> <stringProp name="HTTPSampler.domain"/> <stringProp name="HTTPSampler.port"/> - <stringProp name="HTTPSampler.connect_timeout"/> - <stringProp name="HTTPSampler.response_timeout"/> + <stringProp name="HTTPSampler.connect_timeout">60000</stringProp> + <stringProp name="HTTPSampler.response_timeout">200000</stringProp> <stringProp name="HTTPSampler.protocol">${request_protocol}</stringProp> <stringProp name="HTTPSampler.contentEncoding"/> <stringProp name="HTTPSampler.path">${base_path}customer/account/loginPost/</stringProp> @@ -10054,8 +10831,8 @@ vars.put("customer_email", customerUser); </elementProp> <stringProp name="HTTPSampler.domain"/> <stringProp name="HTTPSampler.port"/> - <stringProp name="HTTPSampler.connect_timeout"/> - <stringProp name="HTTPSampler.response_timeout"/> + <stringProp name="HTTPSampler.connect_timeout">60000</stringProp> + <stringProp name="HTTPSampler.response_timeout">200000</stringProp> <stringProp name="HTTPSampler.protocol">${request_protocol}</stringProp> <stringProp name="HTTPSampler.contentEncoding"/> <stringProp name="HTTPSampler.path">${base_path}customer/section/load/</stringProp> @@ -10075,8 +10852,8 @@ vars.put("customer_email", customerUser); </elementProp> <stringProp name="HTTPSampler.domain"/> <stringProp name="HTTPSampler.port"/> - <stringProp name="HTTPSampler.connect_timeout"/> - <stringProp name="HTTPSampler.response_timeout"/> + <stringProp name="HTTPSampler.connect_timeout">60000</stringProp> + <stringProp name="HTTPSampler.response_timeout">200000</stringProp> <stringProp name="HTTPSampler.protocol">${request_protocol}</stringProp> <stringProp name="HTTPSampler.contentEncoding"/> <stringProp name="HTTPSampler.path">${base_path}sales/order/history/</stringProp> @@ -10121,8 +10898,8 @@ vars.put("customer_email", customerUser); </elementProp> <stringProp name="HTTPSampler.domain"/> <stringProp name="HTTPSampler.port"/> - <stringProp name="HTTPSampler.connect_timeout"/> - <stringProp name="HTTPSampler.response_timeout"/> + <stringProp name="HTTPSampler.connect_timeout">60000</stringProp> + <stringProp name="HTTPSampler.response_timeout">200000</stringProp> <stringProp name="HTTPSampler.protocol">${request_protocol}</stringProp> <stringProp name="HTTPSampler.contentEncoding"/> <stringProp name="HTTPSampler.path">${base_path}sales/order/view/order_id/${orderId}</stringProp> @@ -10166,8 +10943,8 @@ vars.put("customer_email", customerUser); </elementProp> <stringProp name="HTTPSampler.domain"/> <stringProp name="HTTPSampler.port"/> - <stringProp name="HTTPSampler.connect_timeout"/> - <stringProp name="HTTPSampler.response_timeout"/> + <stringProp name="HTTPSampler.connect_timeout">60000</stringProp> + <stringProp name="HTTPSampler.response_timeout">200000</stringProp> <stringProp name="HTTPSampler.protocol">${request_protocol}</stringProp> <stringProp name="HTTPSampler.contentEncoding"/> <stringProp name="HTTPSampler.path">${base_path}sales/order/shipment/order_id/${orderId}</stringProp> @@ -10205,8 +10982,8 @@ vars.put("customer_email", customerUser); </elementProp> <stringProp name="HTTPSampler.domain"/> <stringProp name="HTTPSampler.port"/> - <stringProp name="HTTPSampler.connect_timeout"/> - <stringProp name="HTTPSampler.response_timeout"/> + <stringProp name="HTTPSampler.connect_timeout">60000</stringProp> + <stringProp name="HTTPSampler.response_timeout">200000</stringProp> <stringProp name="HTTPSampler.protocol">${request_protocol}</stringProp> <stringProp name="HTTPSampler.contentEncoding"/> <stringProp name="HTTPSampler.path">${popupLink}</stringProp> @@ -10238,8 +11015,8 @@ vars.put("customer_email", customerUser); </elementProp> <stringProp name="HTTPSampler.domain"/> <stringProp name="HTTPSampler.port"/> - <stringProp name="HTTPSampler.connect_timeout"/> - <stringProp name="HTTPSampler.response_timeout"/> + <stringProp name="HTTPSampler.connect_timeout">60000</stringProp> + <stringProp name="HTTPSampler.response_timeout">200000</stringProp> <stringProp name="HTTPSampler.protocol">${request_protocol}</stringProp> <stringProp name="HTTPSampler.contentEncoding"/> <stringProp name="HTTPSampler.path">${base_path}downloadable/customer/products</stringProp> @@ -10293,8 +11070,8 @@ vars.put("customer_email", customerUser); </elementProp> <stringProp name="HTTPSampler.domain"/> <stringProp name="HTTPSampler.port"/> - <stringProp name="HTTPSampler.connect_timeout"/> - <stringProp name="HTTPSampler.response_timeout"/> + <stringProp name="HTTPSampler.connect_timeout">60000</stringProp> + <stringProp name="HTTPSampler.response_timeout">200000</stringProp> <stringProp name="HTTPSampler.protocol">${request_protocol}</stringProp> <stringProp name="HTTPSampler.contentEncoding"/> <stringProp name="HTTPSampler.path">${base_path}sales/order/view/order_id/${orderId}</stringProp> @@ -10324,8 +11101,8 @@ vars.put("customer_email", customerUser); </elementProp> <stringProp name="HTTPSampler.domain"/> <stringProp name="HTTPSampler.port"/> - <stringProp name="HTTPSampler.connect_timeout"/> - <stringProp name="HTTPSampler.response_timeout"/> + <stringProp name="HTTPSampler.connect_timeout">60000</stringProp> + <stringProp name="HTTPSampler.response_timeout">200000</stringProp> <stringProp name="HTTPSampler.protocol">${request_protocol}</stringProp> <stringProp name="HTTPSampler.contentEncoding"/> <stringProp name="HTTPSampler.path">${base_path}downloadable/download/link/id/${linkId}</stringProp> @@ -10346,8 +11123,8 @@ vars.put("customer_email", customerUser); </elementProp> <stringProp name="HTTPSampler.domain"/> <stringProp name="HTTPSampler.port"/> - <stringProp name="HTTPSampler.connect_timeout"/> - <stringProp name="HTTPSampler.response_timeout"/> + <stringProp name="HTTPSampler.connect_timeout">60000</stringProp> + <stringProp name="HTTPSampler.response_timeout">200000</stringProp> <stringProp name="HTTPSampler.protocol">${request_protocol}</stringProp> <stringProp name="HTTPSampler.contentEncoding"/> <stringProp name="HTTPSampler.path">${base_path}wishlist</stringProp> @@ -10402,8 +11179,8 @@ vars.put("customer_email", customerUser); </elementProp> <stringProp name="HTTPSampler.domain"/> <stringProp name="HTTPSampler.port"/> - <stringProp name="HTTPSampler.connect_timeout"/> - <stringProp name="HTTPSampler.response_timeout"/> + <stringProp name="HTTPSampler.connect_timeout">60000</stringProp> + <stringProp name="HTTPSampler.response_timeout">200000</stringProp> <stringProp name="HTTPSampler.protocol">${request_protocol}</stringProp> <stringProp name="HTTPSampler.contentEncoding"/> <stringProp name="HTTPSampler.path">${base_path}wishlist/index/share/wishlist_id/${wishlistId}/</stringProp> @@ -10456,8 +11233,8 @@ vars.put("customer_email", customerUser); </elementProp> <stringProp name="HTTPSampler.domain"/> <stringProp name="HTTPSampler.port"/> - <stringProp name="HTTPSampler.connect_timeout"/> - <stringProp name="HTTPSampler.response_timeout"/> + <stringProp name="HTTPSampler.connect_timeout">60000</stringProp> + <stringProp name="HTTPSampler.response_timeout">200000</stringProp> <stringProp name="HTTPSampler.protocol">${request_protocol}</stringProp> <stringProp name="HTTPSampler.contentEncoding"/> <stringProp name="HTTPSampler.path">${base_path}wishlist/index/send/wishlist_id/${wishlistId}/</stringProp> @@ -10488,8 +11265,8 @@ vars.put("customer_email", customerUser); </elementProp> <stringProp name="HTTPSampler.domain"/> <stringProp name="HTTPSampler.port"/> - <stringProp name="HTTPSampler.connect_timeout"/> - <stringProp name="HTTPSampler.response_timeout"/> + <stringProp name="HTTPSampler.connect_timeout">60000</stringProp> + <stringProp name="HTTPSampler.response_timeout">200000</stringProp> <stringProp name="HTTPSampler.protocol">${request_protocol}</stringProp> <stringProp name="HTTPSampler.contentEncoding"/> <stringProp name="HTTPSampler.path">${base_path}customer/account/logout/</stringProp> @@ -10641,7 +11418,19 @@ if (testLabel <stringProp name="TestPlan.comments">mpaf/tool/fragments/ce/get_admin_email.jmx</stringProp> <stringProp name="BeanShellSampler.query"> adminUserList = props.get("adminUserList"); -adminUser = adminUserList.poll(); +adminUserListIterator = props.get("adminUserListIterator"); +adminUsersDistribution = Integer.parseInt(vars.get("admin_users_distribution_per_admin_pool")); + +if (adminUsersDistribution == 1) { + adminUser = adminUserList.poll(); +} else { + if (!adminUserListIterator.hasNext()) { + adminUserListIterator = adminUserList.descendingIterator(); + } + + adminUser = adminUserListIterator.next(); +} + if (adminUser == null) { SampleResult.setResponseMessage("adminUser list is empty"); SampleResult.setResponseData("adminUser list is empty","UTF-8"); @@ -10664,11 +11453,11 @@ vars.put("admin_user", adminUser); </elementProp> <stringProp name="HTTPSampler.domain"/> <stringProp name="HTTPSampler.port"/> - <stringProp name="HTTPSampler.connect_timeout"/> - <stringProp name="HTTPSampler.response_timeout"/> + <stringProp name="HTTPSampler.connect_timeout">60000</stringProp> + <stringProp name="HTTPSampler.response_timeout">200000</stringProp> <stringProp name="HTTPSampler.protocol">${request_protocol}</stringProp> <stringProp name="HTTPSampler.contentEncoding"/> - <stringProp name="HTTPSampler.path">${base_path}${admin_path}</stringProp> + <stringProp name="HTTPSampler.path">${base_path}${admin_path}/admin/</stringProp> <stringProp name="HTTPSampler.method">GET</stringProp> <boolProp name="HTTPSampler.follow_redirects">true</boolProp> <boolProp name="HTTPSampler.auto_redirects">false</boolProp> @@ -10745,8 +11534,8 @@ vars.put("admin_user", adminUser); </elementProp> <stringProp name="HTTPSampler.domain"/> <stringProp name="HTTPSampler.port"/> - <stringProp name="HTTPSampler.connect_timeout"/> - <stringProp name="HTTPSampler.response_timeout"/> + <stringProp name="HTTPSampler.connect_timeout">60000</stringProp> + <stringProp name="HTTPSampler.response_timeout">200000</stringProp> <stringProp name="HTTPSampler.protocol">${request_protocol}</stringProp> <stringProp name="HTTPSampler.contentEncoding"/> <stringProp name="HTTPSampler.path">${base_path}${admin_path}/admin/dashboard/</stringProp> @@ -10787,8 +11576,8 @@ vars.put("admin_user", adminUser); </elementProp> <stringProp name="HTTPSampler.domain"/> <stringProp name="HTTPSampler.port"/> - <stringProp name="HTTPSampler.connect_timeout"/> - <stringProp name="HTTPSampler.response_timeout"/> + <stringProp name="HTTPSampler.connect_timeout">60000</stringProp> + <stringProp name="HTTPSampler.response_timeout">200000</stringProp> <stringProp name="HTTPSampler.protocol">${request_protocol}</stringProp> <stringProp name="HTTPSampler.contentEncoding"/> <stringProp name="HTTPSampler.path">${base_path}${admin_path}/cms/page/</stringProp> @@ -10807,8 +11596,8 @@ vars.put("admin_user", adminUser); </elementProp> <stringProp name="HTTPSampler.domain"/> <stringProp name="HTTPSampler.port"/> - <stringProp name="HTTPSampler.connect_timeout"/> - <stringProp name="HTTPSampler.response_timeout"/> + <stringProp name="HTTPSampler.connect_timeout">60000</stringProp> + <stringProp name="HTTPSampler.response_timeout">200000</stringProp> <stringProp name="HTTPSampler.protocol">${request_protocol}</stringProp> <stringProp name="HTTPSampler.contentEncoding"/> <stringProp name="HTTPSampler.path">${base_path}${admin_path}/cms/page/new</stringProp> @@ -10940,8 +11729,8 @@ vars.put("admin_user", adminUser); </elementProp> <stringProp name="HTTPSampler.domain"/> <stringProp name="HTTPSampler.port"/> - <stringProp name="HTTPSampler.connect_timeout"/> - <stringProp name="HTTPSampler.response_timeout"/> + <stringProp name="HTTPSampler.connect_timeout">60000</stringProp> + <stringProp name="HTTPSampler.response_timeout">200000</stringProp> <stringProp name="HTTPSampler.protocol">${request_protocol}</stringProp> <stringProp name="HTTPSampler.contentEncoding"/> <stringProp name="HTTPSampler.path">${base_path}${admin_path}/cms/page/save/</stringProp> @@ -10979,8 +11768,8 @@ vars.put("admin_user", adminUser); </elementProp> <stringProp name="HTTPSampler.domain"/> <stringProp name="HTTPSampler.port"/> - <stringProp name="HTTPSampler.connect_timeout"/> - <stringProp name="HTTPSampler.response_timeout"/> + <stringProp name="HTTPSampler.connect_timeout">60000</stringProp> + <stringProp name="HTTPSampler.response_timeout">200000</stringProp> <stringProp name="HTTPSampler.protocol">${request_protocol}</stringProp> <stringProp name="HTTPSampler.contentEncoding"/> <stringProp name="HTTPSampler.path">${base_path}${admin_path}/admin/auth/logout/</stringProp> @@ -10999,8 +11788,11 @@ vars.put("admin_user", adminUser); <stringProp name="parameters"/> <stringProp name="filename"/> <stringProp name="script"> -adminUserList = props.get("adminUserList"); -adminUserList.add(vars.get("admin_user")); + adminUsersDistribution = Integer.parseInt(vars.get("admin_users_distribution_per_admin_pool")); + if (adminUsersDistribution == 1) { + adminUserList = props.get("adminUserList"); + adminUserList.add(vars.get("admin_user")); + } </stringProp> <stringProp name="TestPlan.comments">mpaf/tool/fragments/ce/common/return_admin_email_to_pool.jmx</stringProp></BeanShellPostProcessor> <hashTree/> @@ -11106,7 +11898,19 @@ if (testLabel <stringProp name="TestPlan.comments">mpaf/tool/fragments/ce/get_admin_email.jmx</stringProp> <stringProp name="BeanShellSampler.query"> adminUserList = props.get("adminUserList"); -adminUser = adminUserList.poll(); +adminUserListIterator = props.get("adminUserListIterator"); +adminUsersDistribution = Integer.parseInt(vars.get("admin_users_distribution_per_admin_pool")); + +if (adminUsersDistribution == 1) { + adminUser = adminUserList.poll(); +} else { + if (!adminUserListIterator.hasNext()) { + adminUserListIterator = adminUserList.descendingIterator(); + } + + adminUser = adminUserListIterator.next(); +} + if (adminUser == null) { SampleResult.setResponseMessage("adminUser list is empty"); SampleResult.setResponseData("adminUser list is empty","UTF-8"); @@ -11129,11 +11933,11 @@ vars.put("admin_user", adminUser); </elementProp> <stringProp name="HTTPSampler.domain"/> <stringProp name="HTTPSampler.port"/> - <stringProp name="HTTPSampler.connect_timeout"/> - <stringProp name="HTTPSampler.response_timeout"/> + <stringProp name="HTTPSampler.connect_timeout">60000</stringProp> + <stringProp name="HTTPSampler.response_timeout">200000</stringProp> <stringProp name="HTTPSampler.protocol">${request_protocol}</stringProp> <stringProp name="HTTPSampler.contentEncoding"/> - <stringProp name="HTTPSampler.path">${base_path}${admin_path}</stringProp> + <stringProp name="HTTPSampler.path">${base_path}${admin_path}/admin/</stringProp> <stringProp name="HTTPSampler.method">GET</stringProp> <boolProp name="HTTPSampler.follow_redirects">true</boolProp> <boolProp name="HTTPSampler.auto_redirects">false</boolProp> @@ -11210,8 +12014,8 @@ vars.put("admin_user", adminUser); </elementProp> <stringProp name="HTTPSampler.domain"/> <stringProp name="HTTPSampler.port"/> - <stringProp name="HTTPSampler.connect_timeout"/> - <stringProp name="HTTPSampler.response_timeout"/> + <stringProp name="HTTPSampler.connect_timeout">60000</stringProp> + <stringProp name="HTTPSampler.response_timeout">200000</stringProp> <stringProp name="HTTPSampler.protocol">${request_protocol}</stringProp> <stringProp name="HTTPSampler.contentEncoding"/> <stringProp name="HTTPSampler.path">${base_path}${admin_path}/admin/dashboard/</stringProp> @@ -11334,8 +12138,8 @@ vars.put("admin_user", adminUser); </elementProp> <stringProp name="HTTPSampler.domain"/> <stringProp name="HTTPSampler.port"/> - <stringProp name="HTTPSampler.connect_timeout"/> - <stringProp name="HTTPSampler.response_timeout"/> + <stringProp name="HTTPSampler.connect_timeout">60000</stringProp> + <stringProp name="HTTPSampler.response_timeout">200000</stringProp> <stringProp name="HTTPSampler.protocol">${request_protocol}</stringProp> <stringProp name="HTTPSampler.contentEncoding"/> <stringProp name="HTTPSampler.path">${base_path}${admin_path}/mui/index/render/</stringProp> @@ -11451,8 +12255,8 @@ vars.put("admin_user", adminUser); </elementProp> <stringProp name="HTTPSampler.domain"/> <stringProp name="HTTPSampler.port"/> - <stringProp name="HTTPSampler.connect_timeout"/> - <stringProp name="HTTPSampler.response_timeout"/> + <stringProp name="HTTPSampler.connect_timeout">60000</stringProp> + <stringProp name="HTTPSampler.response_timeout">200000</stringProp> <stringProp name="HTTPSampler.protocol">${request_protocol}</stringProp> <stringProp name="HTTPSampler.contentEncoding"/> <stringProp name="HTTPSampler.path">${base_path}${admin_path}/mui/index/render/</stringProp> @@ -11579,8 +12383,8 @@ vars.put("grid_pages_count_filtered", pageCount); </elementProp> <stringProp name="HTTPSampler.domain"/> <stringProp name="HTTPSampler.port"/> - <stringProp name="HTTPSampler.connect_timeout"/> - <stringProp name="HTTPSampler.response_timeout"/> + <stringProp name="HTTPSampler.connect_timeout">60000</stringProp> + <stringProp name="HTTPSampler.response_timeout">200000</stringProp> <stringProp name="HTTPSampler.protocol">${request_protocol}</stringProp> <stringProp name="HTTPSampler.contentEncoding"/> <stringProp name="HTTPSampler.path">${base_path}${admin_path}/mui/index/render/</stringProp> @@ -11706,8 +12510,8 @@ vars.put("grid_pages_count_filtered", pageCount); </elementProp> <stringProp name="HTTPSampler.domain"/> <stringProp name="HTTPSampler.port"/> - <stringProp name="HTTPSampler.connect_timeout"/> - <stringProp name="HTTPSampler.response_timeout"/> + <stringProp name="HTTPSampler.connect_timeout">60000</stringProp> + <stringProp name="HTTPSampler.response_timeout">200000</stringProp> <stringProp name="HTTPSampler.protocol">${request_protocol}</stringProp> <stringProp name="HTTPSampler.contentEncoding"/> <stringProp name="HTTPSampler.path">${base_path}${admin_path}/mui/index/render/</stringProp> @@ -11741,8 +12545,8 @@ vars.put("grid_pages_count_filtered", pageCount); </elementProp> <stringProp name="HTTPSampler.domain"/> <stringProp name="HTTPSampler.port"/> - <stringProp name="HTTPSampler.connect_timeout"/> - <stringProp name="HTTPSampler.response_timeout"/> + <stringProp name="HTTPSampler.connect_timeout">60000</stringProp> + <stringProp name="HTTPSampler.response_timeout">200000</stringProp> <stringProp name="HTTPSampler.protocol">${request_protocol}</stringProp> <stringProp name="HTTPSampler.contentEncoding"/> <stringProp name="HTTPSampler.path">${base_path}${admin_path}/admin/auth/logout/</stringProp> @@ -11761,8 +12565,11 @@ vars.put("grid_pages_count_filtered", pageCount); <stringProp name="parameters"/> <stringProp name="filename"/> <stringProp name="script"> -adminUserList = props.get("adminUserList"); -adminUserList.add(vars.get("admin_user")); + adminUsersDistribution = Integer.parseInt(vars.get("admin_users_distribution_per_admin_pool")); + if (adminUsersDistribution == 1) { + adminUserList = props.get("adminUserList"); + adminUserList.add(vars.get("admin_user")); + } </stringProp> <stringProp name="TestPlan.comments">mpaf/tool/fragments/ce/common/return_admin_email_to_pool.jmx</stringProp></BeanShellPostProcessor> <hashTree/> @@ -11868,7 +12675,19 @@ if (testLabel <stringProp name="TestPlan.comments">mpaf/tool/fragments/ce/get_admin_email.jmx</stringProp> <stringProp name="BeanShellSampler.query"> adminUserList = props.get("adminUserList"); -adminUser = adminUserList.poll(); +adminUserListIterator = props.get("adminUserListIterator"); +adminUsersDistribution = Integer.parseInt(vars.get("admin_users_distribution_per_admin_pool")); + +if (adminUsersDistribution == 1) { + adminUser = adminUserList.poll(); +} else { + if (!adminUserListIterator.hasNext()) { + adminUserListIterator = adminUserList.descendingIterator(); + } + + adminUser = adminUserListIterator.next(); +} + if (adminUser == null) { SampleResult.setResponseMessage("adminUser list is empty"); SampleResult.setResponseData("adminUser list is empty","UTF-8"); @@ -11891,11 +12710,11 @@ vars.put("admin_user", adminUser); </elementProp> <stringProp name="HTTPSampler.domain"/> <stringProp name="HTTPSampler.port"/> - <stringProp name="HTTPSampler.connect_timeout"/> - <stringProp name="HTTPSampler.response_timeout"/> + <stringProp name="HTTPSampler.connect_timeout">60000</stringProp> + <stringProp name="HTTPSampler.response_timeout">200000</stringProp> <stringProp name="HTTPSampler.protocol">${request_protocol}</stringProp> <stringProp name="HTTPSampler.contentEncoding"/> - <stringProp name="HTTPSampler.path">${base_path}${admin_path}</stringProp> + <stringProp name="HTTPSampler.path">${base_path}${admin_path}/admin/</stringProp> <stringProp name="HTTPSampler.method">GET</stringProp> <boolProp name="HTTPSampler.follow_redirects">true</boolProp> <boolProp name="HTTPSampler.auto_redirects">false</boolProp> @@ -11972,8 +12791,8 @@ vars.put("admin_user", adminUser); </elementProp> <stringProp name="HTTPSampler.domain"/> <stringProp name="HTTPSampler.port"/> - <stringProp name="HTTPSampler.connect_timeout"/> - <stringProp name="HTTPSampler.response_timeout"/> + <stringProp name="HTTPSampler.connect_timeout">60000</stringProp> + <stringProp name="HTTPSampler.response_timeout">200000</stringProp> <stringProp name="HTTPSampler.protocol">${request_protocol}</stringProp> <stringProp name="HTTPSampler.contentEncoding"/> <stringProp name="HTTPSampler.path">${base_path}${admin_path}/admin/dashboard/</stringProp> @@ -12096,8 +12915,8 @@ vars.put("admin_user", adminUser); </elementProp> <stringProp name="HTTPSampler.domain"/> <stringProp name="HTTPSampler.port"/> - <stringProp name="HTTPSampler.connect_timeout"/> - <stringProp name="HTTPSampler.response_timeout"/> + <stringProp name="HTTPSampler.connect_timeout">60000</stringProp> + <stringProp name="HTTPSampler.response_timeout">200000</stringProp> <stringProp name="HTTPSampler.protocol">${request_protocol}</stringProp> <stringProp name="HTTPSampler.contentEncoding"/> <stringProp name="HTTPSampler.path">${base_path}${admin_path}/mui/index/render/</stringProp> @@ -12213,8 +13032,8 @@ vars.put("admin_user", adminUser); </elementProp> <stringProp name="HTTPSampler.domain"/> <stringProp name="HTTPSampler.port"/> - <stringProp name="HTTPSampler.connect_timeout"/> - <stringProp name="HTTPSampler.response_timeout"/> + <stringProp name="HTTPSampler.connect_timeout">60000</stringProp> + <stringProp name="HTTPSampler.response_timeout">200000</stringProp> <stringProp name="HTTPSampler.protocol">${request_protocol}</stringProp> <stringProp name="HTTPSampler.contentEncoding"/> <stringProp name="HTTPSampler.path">${base_path}${admin_path}/mui/index/render/</stringProp> @@ -12341,8 +13160,8 @@ vars.put("grid_pages_count_filtered", pageCount); </elementProp> <stringProp name="HTTPSampler.domain"/> <stringProp name="HTTPSampler.port"/> - <stringProp name="HTTPSampler.connect_timeout"/> - <stringProp name="HTTPSampler.response_timeout"/> + <stringProp name="HTTPSampler.connect_timeout">60000</stringProp> + <stringProp name="HTTPSampler.response_timeout">200000</stringProp> <stringProp name="HTTPSampler.protocol">${request_protocol}</stringProp> <stringProp name="HTTPSampler.contentEncoding"/> <stringProp name="HTTPSampler.path">${base_path}${admin_path}/mui/index/render/</stringProp> @@ -12468,8 +13287,8 @@ vars.put("grid_pages_count_filtered", pageCount); </elementProp> <stringProp name="HTTPSampler.domain"/> <stringProp name="HTTPSampler.port"/> - <stringProp name="HTTPSampler.connect_timeout"/> - <stringProp name="HTTPSampler.response_timeout"/> + <stringProp name="HTTPSampler.connect_timeout">60000</stringProp> + <stringProp name="HTTPSampler.response_timeout">200000</stringProp> <stringProp name="HTTPSampler.protocol">${request_protocol}</stringProp> <stringProp name="HTTPSampler.contentEncoding"/> <stringProp name="HTTPSampler.path">${base_path}${admin_path}/mui/index/render/</stringProp> @@ -12503,8 +13322,8 @@ vars.put("grid_pages_count_filtered", pageCount); </elementProp> <stringProp name="HTTPSampler.domain"/> <stringProp name="HTTPSampler.port"/> - <stringProp name="HTTPSampler.connect_timeout"/> - <stringProp name="HTTPSampler.response_timeout"/> + <stringProp name="HTTPSampler.connect_timeout">60000</stringProp> + <stringProp name="HTTPSampler.response_timeout">200000</stringProp> <stringProp name="HTTPSampler.protocol">${request_protocol}</stringProp> <stringProp name="HTTPSampler.contentEncoding"/> <stringProp name="HTTPSampler.path">${base_path}${admin_path}/admin/auth/logout/</stringProp> @@ -12523,8 +13342,11 @@ vars.put("grid_pages_count_filtered", pageCount); <stringProp name="parameters"/> <stringProp name="filename"/> <stringProp name="script"> -adminUserList = props.get("adminUserList"); -adminUserList.add(vars.get("admin_user")); + adminUsersDistribution = Integer.parseInt(vars.get("admin_users_distribution_per_admin_pool")); + if (adminUsersDistribution == 1) { + adminUserList = props.get("adminUserList"); + adminUserList.add(vars.get("admin_user")); + } </stringProp> <stringProp name="TestPlan.comments">mpaf/tool/fragments/ce/common/return_admin_email_to_pool.jmx</stringProp></BeanShellPostProcessor> <hashTree/> @@ -12630,7 +13452,19 @@ if (testLabel <stringProp name="TestPlan.comments">mpaf/tool/fragments/ce/get_admin_email.jmx</stringProp> <stringProp name="BeanShellSampler.query"> adminUserList = props.get("adminUserList"); -adminUser = adminUserList.poll(); +adminUserListIterator = props.get("adminUserListIterator"); +adminUsersDistribution = Integer.parseInt(vars.get("admin_users_distribution_per_admin_pool")); + +if (adminUsersDistribution == 1) { + adminUser = adminUserList.poll(); +} else { + if (!adminUserListIterator.hasNext()) { + adminUserListIterator = adminUserList.descendingIterator(); + } + + adminUser = adminUserListIterator.next(); +} + if (adminUser == null) { SampleResult.setResponseMessage("adminUser list is empty"); SampleResult.setResponseData("adminUser list is empty","UTF-8"); @@ -12653,11 +13487,11 @@ vars.put("admin_user", adminUser); </elementProp> <stringProp name="HTTPSampler.domain"/> <stringProp name="HTTPSampler.port"/> - <stringProp name="HTTPSampler.connect_timeout"/> - <stringProp name="HTTPSampler.response_timeout"/> + <stringProp name="HTTPSampler.connect_timeout">60000</stringProp> + <stringProp name="HTTPSampler.response_timeout">200000</stringProp> <stringProp name="HTTPSampler.protocol">${request_protocol}</stringProp> <stringProp name="HTTPSampler.contentEncoding"/> - <stringProp name="HTTPSampler.path">${base_path}${admin_path}</stringProp> + <stringProp name="HTTPSampler.path">${base_path}${admin_path}/admin/</stringProp> <stringProp name="HTTPSampler.method">GET</stringProp> <boolProp name="HTTPSampler.follow_redirects">true</boolProp> <boolProp name="HTTPSampler.auto_redirects">false</boolProp> @@ -12734,8 +13568,8 @@ vars.put("admin_user", adminUser); </elementProp> <stringProp name="HTTPSampler.domain"/> <stringProp name="HTTPSampler.port"/> - <stringProp name="HTTPSampler.connect_timeout"/> - <stringProp name="HTTPSampler.response_timeout"/> + <stringProp name="HTTPSampler.connect_timeout">60000</stringProp> + <stringProp name="HTTPSampler.response_timeout">200000</stringProp> <stringProp name="HTTPSampler.protocol">${request_protocol}</stringProp> <stringProp name="HTTPSampler.contentEncoding"/> <stringProp name="HTTPSampler.path">${base_path}${admin_path}/admin/dashboard/</stringProp> @@ -12813,8 +13647,8 @@ vars.put("related_product_id", props.get("simple_products_list").get(relatedInde </elementProp> <stringProp name="HTTPSampler.domain"/> <stringProp name="HTTPSampler.port"/> - <stringProp name="HTTPSampler.connect_timeout"/> - <stringProp name="HTTPSampler.response_timeout"/> + <stringProp name="HTTPSampler.connect_timeout">60000</stringProp> + <stringProp name="HTTPSampler.response_timeout">200000</stringProp> <stringProp name="HTTPSampler.protocol">${request_protocol}</stringProp> <stringProp name="HTTPSampler.contentEncoding"/> <stringProp name="HTTPSampler.path">${base_path}rest/V1/integration/admin/token</stringProp> @@ -12893,8 +13727,8 @@ vars.put("related_product_id", props.get("simple_products_list").get(relatedInde </elementProp> <stringProp name="HTTPSampler.domain"/> <stringProp name="HTTPSampler.port"/> - <stringProp name="HTTPSampler.connect_timeout"/> - <stringProp name="HTTPSampler.response_timeout"/> + <stringProp name="HTTPSampler.connect_timeout">60000</stringProp> + <stringProp name="HTTPSampler.response_timeout">200000</stringProp> <stringProp name="HTTPSampler.protocol">${request_protocol}</stringProp> <stringProp name="HTTPSampler.contentEncoding"/> <stringProp name="HTTPSampler.path">${base_path}rest/default/V1/products/attributes</stringProp> @@ -12961,8 +13795,8 @@ vars.putObject("product_attributes", attributes); </elementProp> <stringProp name="HTTPSampler.domain"/> <stringProp name="HTTPSampler.port"/> - <stringProp name="HTTPSampler.connect_timeout"/> - <stringProp name="HTTPSampler.response_timeout"/> + <stringProp name="HTTPSampler.connect_timeout">60000</stringProp> + <stringProp name="HTTPSampler.response_timeout">200000</stringProp> <stringProp name="HTTPSampler.protocol">${request_protocol}</stringProp> <stringProp name="HTTPSampler.contentEncoding"/> <stringProp name="HTTPSampler.path">${base_path}${admin_path}/catalog/product_set/index/filter/${attribute_set_filter}</stringProp> @@ -13010,15 +13844,15 @@ Random random = new Random(); if (${seedForRandom} > 0) { random.setSeed(${seedForRandom}); } -number = random.nextInt(props.get("simple_products_list").size()); -simpleList = props.get("simple_products_list").get(number); +number = random.nextInt(props.get("simple_products_list_for_edit").size()); +simpleList = props.get("simple_products_list_for_edit").get(number); vars.put("simple_product_1_id", simpleList.get("id")); vars.put("simple_product_1_name", simpleList.get("title")); do { - number1 = random.nextInt(props.get("simple_products_list").size()); + number1 = random.nextInt(props.get("simple_products_list_for_edit").size()); } while(number == number1); -simpleList = props.get("simple_products_list").get(number1); +simpleList = props.get("simple_products_list_for_edit").get(number1); vars.put("simple_product_2_id", simpleList.get("id")); vars.put("simple_product_2_name", simpleList.get("title")); @@ -13056,8 +13890,8 @@ vars.put("configurable_sku", "Configurable Product - ${__time(YMD)}-${__threadNu </elementProp> <stringProp name="HTTPSampler.domain"/> <stringProp name="HTTPSampler.port"/> - <stringProp name="HTTPSampler.connect_timeout"/> - <stringProp name="HTTPSampler.response_timeout"/> + <stringProp name="HTTPSampler.connect_timeout">60000</stringProp> + <stringProp name="HTTPSampler.response_timeout">200000</stringProp> <stringProp name="HTTPSampler.protocol">${request_protocol}</stringProp> <stringProp name="HTTPSampler.contentEncoding"/> <stringProp name="HTTPSampler.path">${base_path}${admin_path}/catalog/product/</stringProp> @@ -13086,8 +13920,8 @@ vars.put("configurable_sku", "Configurable Product - ${__time(YMD)}-${__threadNu </elementProp> <stringProp name="HTTPSampler.domain"/> <stringProp name="HTTPSampler.port"/> - <stringProp name="HTTPSampler.connect_timeout"/> - <stringProp name="HTTPSampler.response_timeout"/> + <stringProp name="HTTPSampler.connect_timeout">60000</stringProp> + <stringProp name="HTTPSampler.response_timeout">200000</stringProp> <stringProp name="HTTPSampler.protocol">${request_protocol}</stringProp> <stringProp name="HTTPSampler.contentEncoding"/> <stringProp name="HTTPSampler.path">${base_path}${admin_path}/catalog/product/new/set/4/type/bundle/</stringProp> @@ -13989,8 +14823,8 @@ vars.put("configurable_sku", "Configurable Product - ${__time(YMD)}-${__threadNu </elementProp> <stringProp name="HTTPSampler.domain"/> <stringProp name="HTTPSampler.port"/> - <stringProp name="HTTPSampler.connect_timeout"/> - <stringProp name="HTTPSampler.response_timeout"/> + <stringProp name="HTTPSampler.connect_timeout">60000</stringProp> + <stringProp name="HTTPSampler.response_timeout">200000</stringProp> <stringProp name="HTTPSampler.protocol">${request_protocol}</stringProp> <stringProp name="HTTPSampler.contentEncoding"/> <stringProp name="HTTPSampler.path">${base_path}${admin_path}/catalog/product/validate/set/4/</stringProp> @@ -14923,8 +15757,8 @@ vars.put("configurable_sku", "Configurable Product - ${__time(YMD)}-${__threadNu </elementProp> <stringProp name="HTTPSampler.domain"/> <stringProp name="HTTPSampler.port"/> - <stringProp name="HTTPSampler.connect_timeout"/> - <stringProp name="HTTPSampler.response_timeout"/> + <stringProp name="HTTPSampler.connect_timeout">60000</stringProp> + <stringProp name="HTTPSampler.response_timeout">200000</stringProp> <stringProp name="HTTPSampler.protocol">${request_protocol}</stringProp> <stringProp name="HTTPSampler.contentEncoding"/> <stringProp name="HTTPSampler.path">${base_path}${admin_path}/catalog/product/save/set/4/type/bundle/back/edit/active_tab/product-details/</stringProp> @@ -14964,8 +15798,8 @@ vars.put("configurable_sku", "Configurable Product - ${__time(YMD)}-${__threadNu </elementProp> <stringProp name="HTTPSampler.domain"/> <stringProp name="HTTPSampler.port"/> - <stringProp name="HTTPSampler.connect_timeout"/> - <stringProp name="HTTPSampler.response_timeout"/> + <stringProp name="HTTPSampler.connect_timeout">60000</stringProp> + <stringProp name="HTTPSampler.response_timeout">200000</stringProp> <stringProp name="HTTPSampler.protocol">${request_protocol}</stringProp> <stringProp name="HTTPSampler.contentEncoding"/> <stringProp name="HTTPSampler.path">${base_path}${admin_path}/catalog/product/</stringProp> @@ -14995,8 +15829,8 @@ vars.put("configurable_sku", "Configurable Product - ${__time(YMD)}-${__threadNu </elementProp> <stringProp name="HTTPSampler.domain"/> <stringProp name="HTTPSampler.port"/> - <stringProp name="HTTPSampler.connect_timeout"/> - <stringProp name="HTTPSampler.response_timeout"/> + <stringProp name="HTTPSampler.connect_timeout">60000</stringProp> + <stringProp name="HTTPSampler.response_timeout">200000</stringProp> <stringProp name="HTTPSampler.protocol">${request_protocol}</stringProp> <stringProp name="HTTPSampler.contentEncoding"/> <stringProp name="HTTPSampler.path">${base_path}${admin_path}/catalog/product/new/set/${attribute_set_id}/type/configurable/</stringProp> @@ -15525,8 +16359,8 @@ vars.put("configurable_sku", "Configurable Product - ${__time(YMD)}-${__threadNu </elementProp> <stringProp name="HTTPSampler.domain"/> <stringProp name="HTTPSampler.port"/> - <stringProp name="HTTPSampler.connect_timeout"/> - <stringProp name="HTTPSampler.response_timeout"/> + <stringProp name="HTTPSampler.connect_timeout">60000</stringProp> + <stringProp name="HTTPSampler.response_timeout">200000</stringProp> <stringProp name="HTTPSampler.protocol">${request_protocol}</stringProp> <stringProp name="HTTPSampler.contentEncoding"/> <stringProp name="HTTPSampler.path">${base_path}${admin_path}/catalog/product/validate/set/${attribute_set_id}/</stringProp> @@ -15693,7 +16527,7 @@ function addConfigurableMatrix(attributes) { </elementProp> <elementProp name="product[category_ids][0]" elementType="HTTPArgument"> <boolProp name="HTTPArgument.always_encode">true</boolProp> - <stringProp name="Argument.value">4</stringProp> + <stringProp name="Argument.value">2</stringProp> <stringProp name="Argument.metadata">=</stringProp> <boolProp name="HTTPArgument.use_equals">true</boolProp> <stringProp name="Argument.name">product[category_ids][0]</stringProp> @@ -16137,8 +16971,8 @@ function addConfigurableMatrix(attributes) { </elementProp> <stringProp name="HTTPSampler.domain"/> <stringProp name="HTTPSampler.port"/> - <stringProp name="HTTPSampler.connect_timeout"/> - <stringProp name="HTTPSampler.response_timeout"/> + <stringProp name="HTTPSampler.connect_timeout">60000</stringProp> + <stringProp name="HTTPSampler.response_timeout">200000</stringProp> <stringProp name="HTTPSampler.protocol">${request_protocol}</stringProp> <stringProp name="HTTPSampler.contentEncoding"/> <stringProp name="HTTPSampler.path">${base_path}${admin_path}/catalog/product/save/set/${attribute_set_id}/type/configurable/back/edit/active_tab/product-details/</stringProp> @@ -16273,8 +17107,8 @@ function addConfigurableMatrix(attributes) { </elementProp> <stringProp name="HTTPSampler.domain"/> <stringProp name="HTTPSampler.port"/> - <stringProp name="HTTPSampler.connect_timeout"/> - <stringProp name="HTTPSampler.response_timeout"/> + <stringProp name="HTTPSampler.connect_timeout">60000</stringProp> + <stringProp name="HTTPSampler.response_timeout">200000</stringProp> <stringProp name="HTTPSampler.protocol">${request_protocol}</stringProp> <stringProp name="HTTPSampler.contentEncoding"/> <stringProp name="HTTPSampler.path">${base_path}${admin_path}/catalog/product/</stringProp> @@ -16303,8 +17137,8 @@ function addConfigurableMatrix(attributes) { </elementProp> <stringProp name="HTTPSampler.domain"/> <stringProp name="HTTPSampler.port"/> - <stringProp name="HTTPSampler.connect_timeout"/> - <stringProp name="HTTPSampler.response_timeout"/> + <stringProp name="HTTPSampler.connect_timeout">60000</stringProp> + <stringProp name="HTTPSampler.response_timeout">200000</stringProp> <stringProp name="HTTPSampler.protocol">${request_protocol}</stringProp> <stringProp name="HTTPSampler.contentEncoding"/> <stringProp name="HTTPSampler.path">${base_path}${admin_path}/catalog/product/new/set/4/type/downloadable/</stringProp> @@ -16351,8 +17185,8 @@ function addConfigurableMatrix(attributes) { </elementProp> <stringProp name="HTTPSampler.domain"/> <stringProp name="HTTPSampler.port"/> - <stringProp name="HTTPSampler.connect_timeout"/> - <stringProp name="HTTPSampler.response_timeout"/> + <stringProp name="HTTPSampler.connect_timeout">60000</stringProp> + <stringProp name="HTTPSampler.response_timeout">200000</stringProp> <stringProp name="HTTPSampler.protocol">${request_protocol}</stringProp> <stringProp name="HTTPSampler.contentEncoding"/> <stringProp name="HTTPSampler.path">${base_path}${admin_path}/admin/downloadable_file/upload/type/links/?isAjax=true</stringProp> @@ -16398,8 +17232,8 @@ function addConfigurableMatrix(attributes) { </elementProp> <stringProp name="HTTPSampler.domain"/> <stringProp name="HTTPSampler.port"/> - <stringProp name="HTTPSampler.connect_timeout"/> - <stringProp name="HTTPSampler.response_timeout"/> + <stringProp name="HTTPSampler.connect_timeout">60000</stringProp> + <stringProp name="HTTPSampler.response_timeout">200000</stringProp> <stringProp name="HTTPSampler.protocol">${request_protocol}</stringProp> <stringProp name="HTTPSampler.contentEncoding"/> <stringProp name="HTTPSampler.path">${base_path}${admin_path}/admin/downloadable_file/upload/type/samples/?isAjax=true</stringProp> @@ -17131,8 +17965,8 @@ function addConfigurableMatrix(attributes) { </elementProp> <stringProp name="HTTPSampler.domain"/> <stringProp name="HTTPSampler.port"/> - <stringProp name="HTTPSampler.connect_timeout"/> - <stringProp name="HTTPSampler.response_timeout"/> + <stringProp name="HTTPSampler.connect_timeout">60000</stringProp> + <stringProp name="HTTPSampler.response_timeout">200000</stringProp> <stringProp name="HTTPSampler.protocol">${request_protocol}</stringProp> <stringProp name="HTTPSampler.contentEncoding"/> <stringProp name="HTTPSampler.path">${base_path}${admin_path}/catalog/product/validate/set/4/type/downloadable/</stringProp> @@ -17853,8 +18687,8 @@ function addConfigurableMatrix(attributes) { </elementProp> <stringProp name="HTTPSampler.domain"/> <stringProp name="HTTPSampler.port"/> - <stringProp name="HTTPSampler.connect_timeout"/> - <stringProp name="HTTPSampler.response_timeout"/> + <stringProp name="HTTPSampler.connect_timeout">60000</stringProp> + <stringProp name="HTTPSampler.response_timeout">200000</stringProp> <stringProp name="HTTPSampler.protocol">${request_protocol}</stringProp> <stringProp name="HTTPSampler.contentEncoding"/> <stringProp name="HTTPSampler.path">${base_path}${admin_path}/catalog/product/save/set/4/type/downloadable/back/edit/active_tab/product-details/</stringProp> @@ -17898,8 +18732,8 @@ function addConfigurableMatrix(attributes) { </elementProp> <stringProp name="HTTPSampler.domain"/> <stringProp name="HTTPSampler.port"/> - <stringProp name="HTTPSampler.connect_timeout"/> - <stringProp name="HTTPSampler.response_timeout"/> + <stringProp name="HTTPSampler.connect_timeout">60000</stringProp> + <stringProp name="HTTPSampler.response_timeout">200000</stringProp> <stringProp name="HTTPSampler.protocol">${request_protocol}</stringProp> <stringProp name="HTTPSampler.contentEncoding"/> <stringProp name="HTTPSampler.path">${base_path}${admin_path}/catalog/product/</stringProp> @@ -17928,8 +18762,8 @@ function addConfigurableMatrix(attributes) { </elementProp> <stringProp name="HTTPSampler.domain"/> <stringProp name="HTTPSampler.port"/> - <stringProp name="HTTPSampler.connect_timeout"/> - <stringProp name="HTTPSampler.response_timeout"/> + <stringProp name="HTTPSampler.connect_timeout">60000</stringProp> + <stringProp name="HTTPSampler.response_timeout">200000</stringProp> <stringProp name="HTTPSampler.protocol">${request_protocol}</stringProp> <stringProp name="HTTPSampler.contentEncoding"/> <stringProp name="HTTPSampler.path">${base_path}${admin_path}/catalog/product/new/set/4/type/simple/</stringProp> @@ -18657,8 +19491,8 @@ function addConfigurableMatrix(attributes) { </elementProp> <stringProp name="HTTPSampler.domain"/> <stringProp name="HTTPSampler.port"/> - <stringProp name="HTTPSampler.connect_timeout"/> - <stringProp name="HTTPSampler.response_timeout"/> + <stringProp name="HTTPSampler.connect_timeout">60000</stringProp> + <stringProp name="HTTPSampler.response_timeout">200000</stringProp> <stringProp name="HTTPSampler.protocol">${request_protocol}</stringProp> <stringProp name="HTTPSampler.contentEncoding"/> <stringProp name="HTTPSampler.path">${base_path}${admin_path}/catalog/product/validate/set/4/</stringProp> @@ -19368,8 +20202,8 @@ function addConfigurableMatrix(attributes) { </elementProp> <stringProp name="HTTPSampler.domain"/> <stringProp name="HTTPSampler.port"/> - <stringProp name="HTTPSampler.connect_timeout"/> - <stringProp name="HTTPSampler.response_timeout"/> + <stringProp name="HTTPSampler.connect_timeout">60000</stringProp> + <stringProp name="HTTPSampler.response_timeout">200000</stringProp> <stringProp name="HTTPSampler.protocol">${request_protocol}</stringProp> <stringProp name="HTTPSampler.contentEncoding"/> <stringProp name="HTTPSampler.path">${base_path}${admin_path}/catalog/product/save/set/4/type/simple/back/edit/active_tab/product-details/</stringProp> @@ -19410,8 +20244,8 @@ function addConfigurableMatrix(attributes) { </elementProp> <stringProp name="HTTPSampler.domain"/> <stringProp name="HTTPSampler.port"/> - <stringProp name="HTTPSampler.connect_timeout"/> - <stringProp name="HTTPSampler.response_timeout"/> + <stringProp name="HTTPSampler.connect_timeout">60000</stringProp> + <stringProp name="HTTPSampler.response_timeout">200000</stringProp> <stringProp name="HTTPSampler.protocol">${request_protocol}</stringProp> <stringProp name="HTTPSampler.contentEncoding"/> <stringProp name="HTTPSampler.path">${base_path}${admin_path}/admin/auth/logout/</stringProp> @@ -19430,8 +20264,11 @@ function addConfigurableMatrix(attributes) { <stringProp name="parameters"/> <stringProp name="filename"/> <stringProp name="script"> -adminUserList = props.get("adminUserList"); -adminUserList.add(vars.get("admin_user")); + adminUsersDistribution = Integer.parseInt(vars.get("admin_users_distribution_per_admin_pool")); + if (adminUsersDistribution == 1) { + adminUserList = props.get("adminUserList"); + adminUserList.add(vars.get("admin_user")); + } </stringProp> <stringProp name="TestPlan.comments">mpaf/tool/fragments/ce/common/return_admin_email_to_pool.jmx</stringProp></BeanShellPostProcessor> <hashTree/> @@ -19537,7 +20374,19 @@ if (testLabel <stringProp name="TestPlan.comments">mpaf/tool/fragments/ce/get_admin_email.jmx</stringProp> <stringProp name="BeanShellSampler.query"> adminUserList = props.get("adminUserList"); -adminUser = adminUserList.poll(); +adminUserListIterator = props.get("adminUserListIterator"); +adminUsersDistribution = Integer.parseInt(vars.get("admin_users_distribution_per_admin_pool")); + +if (adminUsersDistribution == 1) { + adminUser = adminUserList.poll(); +} else { + if (!adminUserListIterator.hasNext()) { + adminUserListIterator = adminUserList.descendingIterator(); + } + + adminUser = adminUserListIterator.next(); +} + if (adminUser == null) { SampleResult.setResponseMessage("adminUser list is empty"); SampleResult.setResponseData("adminUser list is empty","UTF-8"); @@ -19560,11 +20409,11 @@ vars.put("admin_user", adminUser); </elementProp> <stringProp name="HTTPSampler.domain"/> <stringProp name="HTTPSampler.port"/> - <stringProp name="HTTPSampler.connect_timeout"/> - <stringProp name="HTTPSampler.response_timeout"/> + <stringProp name="HTTPSampler.connect_timeout">60000</stringProp> + <stringProp name="HTTPSampler.response_timeout">200000</stringProp> <stringProp name="HTTPSampler.protocol">${request_protocol}</stringProp> <stringProp name="HTTPSampler.contentEncoding"/> - <stringProp name="HTTPSampler.path">${base_path}${admin_path}</stringProp> + <stringProp name="HTTPSampler.path">${base_path}${admin_path}/admin/</stringProp> <stringProp name="HTTPSampler.method">GET</stringProp> <boolProp name="HTTPSampler.follow_redirects">true</boolProp> <boolProp name="HTTPSampler.auto_redirects">false</boolProp> @@ -19641,8 +20490,8 @@ vars.put("admin_user", adminUser); </elementProp> <stringProp name="HTTPSampler.domain"/> <stringProp name="HTTPSampler.port"/> - <stringProp name="HTTPSampler.connect_timeout"/> - <stringProp name="HTTPSampler.response_timeout"/> + <stringProp name="HTTPSampler.connect_timeout">60000</stringProp> + <stringProp name="HTTPSampler.response_timeout">200000</stringProp> <stringProp name="HTTPSampler.protocol">${request_protocol}</stringProp> <stringProp name="HTTPSampler.contentEncoding"/> <stringProp name="HTTPSampler.path">${base_path}${admin_path}/admin/dashboard/</stringProp> @@ -19686,8 +20535,8 @@ vars.put("admin_user", adminUser); if (${seedForRandom} > 0) { random.setSeed(${seedForRandom} + ${__threadNum}); } - simpleCount = props.get("simple_products_list").size(); - configCount = props.get("configurable_products_list").size(); + simpleCount = props.get("simple_products_list_for_edit").size(); + configCount = props.get("configurable_products_list_for_edit").size(); productCount = 0; if (simpleCount > configCount) { productCount = configCount; @@ -19723,14 +20572,14 @@ vars.put("admin_user", adminUser); i = productClusterLength * currentThreadNum + iterator; //ids of simple and configurable products to edit - vars.put("simple_product_id", props.get("simple_products_list").get(i).get("id")); - vars.put("configurable_product_id", props.get("configurable_products_list").get(i).get("id")); + vars.put("simple_product_id", props.get("simple_products_list_for_edit").get(i).get("id")); + vars.put("configurable_product_id", props.get("configurable_products_list_for_edit").get(i).get("id")); //id of related product do { - relatedIndex = random.nextInt(props.get("simple_products_list").size()); + relatedIndex = random.nextInt(props.get("simple_products_list_for_edit").size()); } while(i == relatedIndex); - vars.put("related_product_id", props.get("simple_products_list").get(relatedIndex).get("id")); + vars.put("related_product_id", props.get("simple_products_list_for_edit").get(relatedIndex).get("id")); } catch (Exception ex) { log.info("Script execution failed", ex); }</stringProp> @@ -19745,8 +20594,8 @@ vars.put("admin_user", adminUser); </elementProp> <stringProp name="HTTPSampler.domain"/> <stringProp name="HTTPSampler.port"/> - <stringProp name="HTTPSampler.connect_timeout"/> - <stringProp name="HTTPSampler.response_timeout"/> + <stringProp name="HTTPSampler.connect_timeout">60000</stringProp> + <stringProp name="HTTPSampler.response_timeout">200000</stringProp> <stringProp name="HTTPSampler.protocol">${request_protocol}</stringProp> <stringProp name="HTTPSampler.contentEncoding"/> <stringProp name="HTTPSampler.path">${base_path}${admin_path}/catalog/product/edit/id/${simple_product_id}/</stringProp> @@ -19799,20 +20648,32 @@ vars.put("admin_user", adminUser); <BeanShellSampler guiclass="BeanShellSamplerGui" testclass="BeanShellSampler" testname="SetUp - Set updated values" enabled="true"> <stringProp name="TestPlan.comments">Passing arguments between threads</stringProp> <stringProp name="BeanShellSampler.query">//Additional category to be added + import java.util.Random; - int categoryId = Integer.parseInt(vars.get("simple_product_category_id")); - if (categoryId > 4) { - categoryId = categoryId - 1; - } else { - categoryId = categoryId + 1; - } - vars.put("category_additional", categoryId.toString()); - //New price - vars.put("price_new", "9999"); - //New special price - vars.put("special_price_new", "8888"); - //New quantity - vars.put("quantity_new", "100600");</stringProp> + Random randomGenerator = new Random(); + if (${seedForRandom} > 0) { + randomGenerator.setSeed(${seedForRandom} + ${__threadNum}); + } + + int categoryId = Integer.parseInt(vars.get("simple_product_category_id")); + categoryList = props.get("admin_category_ids_list"); + + if (categoryList.size() > 1) { + do { + int index = randomGenerator.nextInt(categoryList.size()); + newCategoryId = categoryList.get(index); + } while (categoryId == newCategoryId); + + vars.put("category_additional", newCategoryId.toString()); + } + + //New price + vars.put("price_new", "9999"); + //New special price + vars.put("special_price_new", "8888"); + //New quantity + vars.put("quantity_new", "100600"); + </stringProp> <stringProp name="BeanShellSampler.filename"/> <stringProp name="BeanShellSampler.parameters"/> <boolProp name="BeanShellSampler.resetInterpreter">false</boolProp> @@ -20257,8 +21118,8 @@ vars.put("admin_user", adminUser); </elementProp> <stringProp name="HTTPSampler.domain"/> <stringProp name="HTTPSampler.port"/> - <stringProp name="HTTPSampler.connect_timeout"/> - <stringProp name="HTTPSampler.response_timeout"/> + <stringProp name="HTTPSampler.connect_timeout">60000</stringProp> + <stringProp name="HTTPSampler.response_timeout">200000</stringProp> <stringProp name="HTTPSampler.protocol">${request_protocol}</stringProp> <stringProp name="HTTPSampler.contentEncoding"/> <stringProp name="HTTPSampler.path">${base_path}${admin_path}/catalog/product/validate/id/${simple_product_id}/?isAjax=true</stringProp> @@ -20727,8 +21588,8 @@ vars.put("admin_user", adminUser); </elementProp> <stringProp name="HTTPSampler.domain"/> <stringProp name="HTTPSampler.port"/> - <stringProp name="HTTPSampler.connect_timeout"/> - <stringProp name="HTTPSampler.response_timeout"/> + <stringProp name="HTTPSampler.connect_timeout">60000</stringProp> + <stringProp name="HTTPSampler.response_timeout">200000</stringProp> <stringProp name="HTTPSampler.protocol">${request_protocol}</stringProp> <stringProp name="HTTPSampler.contentEncoding"/> <stringProp name="HTTPSampler.path">${base_path}${admin_path}/catalog/product/save/id/${simple_product_id}/back/edit/active_tab/product-details/</stringProp> @@ -20757,8 +21618,8 @@ vars.put("admin_user", adminUser); </elementProp> <stringProp name="HTTPSampler.domain"/> <stringProp name="HTTPSampler.port"/> - <stringProp name="HTTPSampler.connect_timeout"/> - <stringProp name="HTTPSampler.response_timeout"/> + <stringProp name="HTTPSampler.connect_timeout">60000</stringProp> + <stringProp name="HTTPSampler.response_timeout">200000</stringProp> <stringProp name="HTTPSampler.protocol">${request_protocol}</stringProp> <stringProp name="HTTPSampler.contentEncoding"/> <stringProp name="HTTPSampler.path">${base_path}${admin_path}/catalog/product/edit/id/${configurable_product_id}/</stringProp> @@ -21335,8 +22196,8 @@ vars.put("admin_user", adminUser); </elementProp> <stringProp name="HTTPSampler.domain"/> <stringProp name="HTTPSampler.port"/> - <stringProp name="HTTPSampler.connect_timeout"/> - <stringProp name="HTTPSampler.response_timeout"/> + <stringProp name="HTTPSampler.connect_timeout">60000</stringProp> + <stringProp name="HTTPSampler.response_timeout">200000</stringProp> <stringProp name="HTTPSampler.protocol">${request_protocol}</stringProp> <stringProp name="HTTPSampler.contentEncoding"/> <stringProp name="HTTPSampler.path">${base_path}${admin_path}/catalog/product/validate/id/${configurable_product_id}/</stringProp> @@ -21807,8 +22668,8 @@ vars.put("admin_user", adminUser); </elementProp> <stringProp name="HTTPSampler.domain"/> <stringProp name="HTTPSampler.port"/> - <stringProp name="HTTPSampler.connect_timeout"/> - <stringProp name="HTTPSampler.response_timeout"/> + <stringProp name="HTTPSampler.connect_timeout">60000</stringProp> + <stringProp name="HTTPSampler.response_timeout">200000</stringProp> <stringProp name="HTTPSampler.protocol">${request_protocol}</stringProp> <stringProp name="HTTPSampler.contentEncoding"/> <stringProp name="HTTPSampler.path">${base_path}${admin_path}/catalog/product/save/id/${configurable_product_id}/back/edit/active_tab/product-details/</stringProp> @@ -21878,8 +22739,8 @@ vars.put("admin_user", adminUser); </elementProp> <stringProp name="HTTPSampler.domain"/> <stringProp name="HTTPSampler.port"/> - <stringProp name="HTTPSampler.connect_timeout"/> - <stringProp name="HTTPSampler.response_timeout"/> + <stringProp name="HTTPSampler.connect_timeout">60000</stringProp> + <stringProp name="HTTPSampler.response_timeout">200000</stringProp> <stringProp name="HTTPSampler.protocol">${request_protocol}</stringProp> <stringProp name="HTTPSampler.contentEncoding"/> <stringProp name="HTTPSampler.path">${base_path}${admin_path}/admin/auth/logout/</stringProp> @@ -21898,8 +22759,11 @@ vars.put("admin_user", adminUser); <stringProp name="parameters"/> <stringProp name="filename"/> <stringProp name="script"> -adminUserList = props.get("adminUserList"); -adminUserList.add(vars.get("admin_user")); + adminUsersDistribution = Integer.parseInt(vars.get("admin_users_distribution_per_admin_pool")); + if (adminUsersDistribution == 1) { + adminUserList = props.get("adminUserList"); + adminUserList.add(vars.get("admin_user")); + } </stringProp> <stringProp name="TestPlan.comments">mpaf/tool/fragments/ce/common/return_admin_email_to_pool.jmx</stringProp></BeanShellPostProcessor> <hashTree/> @@ -22022,7 +22886,19 @@ if (testLabel <stringProp name="TestPlan.comments">mpaf/tool/fragments/ce/get_admin_email.jmx</stringProp> <stringProp name="BeanShellSampler.query"> adminUserList = props.get("adminUserList"); -adminUser = adminUserList.poll(); +adminUserListIterator = props.get("adminUserListIterator"); +adminUsersDistribution = Integer.parseInt(vars.get("admin_users_distribution_per_admin_pool")); + +if (adminUsersDistribution == 1) { + adminUser = adminUserList.poll(); +} else { + if (!adminUserListIterator.hasNext()) { + adminUserListIterator = adminUserList.descendingIterator(); + } + + adminUser = adminUserListIterator.next(); +} + if (adminUser == null) { SampleResult.setResponseMessage("adminUser list is empty"); SampleResult.setResponseData("adminUser list is empty","UTF-8"); @@ -22045,11 +22921,11 @@ vars.put("admin_user", adminUser); </elementProp> <stringProp name="HTTPSampler.domain"/> <stringProp name="HTTPSampler.port"/> - <stringProp name="HTTPSampler.connect_timeout"/> - <stringProp name="HTTPSampler.response_timeout"/> + <stringProp name="HTTPSampler.connect_timeout">60000</stringProp> + <stringProp name="HTTPSampler.response_timeout">200000</stringProp> <stringProp name="HTTPSampler.protocol">${request_protocol}</stringProp> <stringProp name="HTTPSampler.contentEncoding"/> - <stringProp name="HTTPSampler.path">${base_path}${admin_path}</stringProp> + <stringProp name="HTTPSampler.path">${base_path}${admin_path}/admin/</stringProp> <stringProp name="HTTPSampler.method">GET</stringProp> <boolProp name="HTTPSampler.follow_redirects">true</boolProp> <boolProp name="HTTPSampler.auto_redirects">false</boolProp> @@ -22126,8 +23002,8 @@ vars.put("admin_user", adminUser); </elementProp> <stringProp name="HTTPSampler.domain"/> <stringProp name="HTTPSampler.port"/> - <stringProp name="HTTPSampler.connect_timeout"/> - <stringProp name="HTTPSampler.response_timeout"/> + <stringProp name="HTTPSampler.connect_timeout">60000</stringProp> + <stringProp name="HTTPSampler.response_timeout">200000</stringProp> <stringProp name="HTTPSampler.protocol">${request_protocol}</stringProp> <stringProp name="HTTPSampler.contentEncoding"/> <stringProp name="HTTPSampler.path">${base_path}${admin_path}/admin/dashboard/</stringProp> @@ -22164,8 +23040,8 @@ vars.put("admin_user", adminUser); </elementProp> <stringProp name="HTTPSampler.domain"/> <stringProp name="HTTPSampler.port"/> - <stringProp name="HTTPSampler.connect_timeout"/> - <stringProp name="HTTPSampler.response_timeout"/> + <stringProp name="HTTPSampler.connect_timeout">60000</stringProp> + <stringProp name="HTTPSampler.response_timeout">200000</stringProp> <stringProp name="HTTPSampler.protocol">${request_protocol}</stringProp> <stringProp name="HTTPSampler.contentEncoding"/> <stringProp name="HTTPSampler.path">${base_path}${admin_path}/sales/order/</stringProp> @@ -22275,8 +23151,8 @@ vars.put("admin_user", adminUser); </elementProp> <stringProp name="HTTPSampler.domain"/> <stringProp name="HTTPSampler.port"/> - <stringProp name="HTTPSampler.connect_timeout"/> - <stringProp name="HTTPSampler.response_timeout"/> + <stringProp name="HTTPSampler.connect_timeout">60000</stringProp> + <stringProp name="HTTPSampler.response_timeout">200000</stringProp> <stringProp name="HTTPSampler.protocol">${request_protocol}</stringProp> <stringProp name="HTTPSampler.contentEncoding"/> <stringProp name="HTTPSampler.path">${base_path}${admin_path}/mui/index/render/</stringProp> @@ -22392,8 +23268,8 @@ vars.put("admin_user", adminUser); </elementProp> <stringProp name="HTTPSampler.domain"/> <stringProp name="HTTPSampler.port"/> - <stringProp name="HTTPSampler.connect_timeout"/> - <stringProp name="HTTPSampler.response_timeout"/> + <stringProp name="HTTPSampler.connect_timeout">60000</stringProp> + <stringProp name="HTTPSampler.response_timeout">200000</stringProp> <stringProp name="HTTPSampler.protocol">${request_protocol}</stringProp> <stringProp name="HTTPSampler.contentEncoding"/> <stringProp name="HTTPSampler.path">${base_path}${admin_path}/mui/index/render/</stringProp> @@ -22494,8 +23370,8 @@ vars.put("admin_user", adminUser); </elementProp> <stringProp name="HTTPSampler.domain"/> <stringProp name="HTTPSampler.port"/> - <stringProp name="HTTPSampler.connect_timeout"/> - <stringProp name="HTTPSampler.response_timeout"/> + <stringProp name="HTTPSampler.connect_timeout">60000</stringProp> + <stringProp name="HTTPSampler.response_timeout">200000</stringProp> <stringProp name="HTTPSampler.protocol">${request_protocol}</stringProp> <stringProp name="HTTPSampler.contentEncoding"/> <stringProp name="HTTPSampler.path">${base_path}${admin_path}/sales/order/view/order_id/${order_id}/</stringProp> @@ -22540,8 +23416,8 @@ vars.put("admin_user", adminUser); </elementProp> <stringProp name="HTTPSampler.domain"/> <stringProp name="HTTPSampler.port"/> - <stringProp name="HTTPSampler.connect_timeout"/> - <stringProp name="HTTPSampler.response_timeout"/> + <stringProp name="HTTPSampler.connect_timeout">60000</stringProp> + <stringProp name="HTTPSampler.response_timeout">200000</stringProp> <stringProp name="HTTPSampler.protocol">${request_protocol}</stringProp> <stringProp name="HTTPSampler.contentEncoding"/> <stringProp name="HTTPSampler.path">${base_path}${admin_path}/sales/order_invoice/start/order_id/${order_id}/</stringProp> @@ -22611,8 +23487,8 @@ vars.put("admin_user", adminUser); </elementProp> <stringProp name="HTTPSampler.domain"/> <stringProp name="HTTPSampler.port"/> - <stringProp name="HTTPSampler.connect_timeout"/> - <stringProp name="HTTPSampler.response_timeout"/> + <stringProp name="HTTPSampler.connect_timeout">60000</stringProp> + <stringProp name="HTTPSampler.response_timeout">200000</stringProp> <stringProp name="HTTPSampler.protocol">${request_protocol}</stringProp> <stringProp name="HTTPSampler.contentEncoding"/> <stringProp name="HTTPSampler.path">${base_path}${admin_path}/sales/order_invoice/save/order_id/${order_id}/</stringProp> @@ -22642,8 +23518,8 @@ vars.put("admin_user", adminUser); </elementProp> <stringProp name="HTTPSampler.domain"/> <stringProp name="HTTPSampler.port"/> - <stringProp name="HTTPSampler.connect_timeout"/> - <stringProp name="HTTPSampler.response_timeout"/> + <stringProp name="HTTPSampler.connect_timeout">60000</stringProp> + <stringProp name="HTTPSampler.response_timeout">200000</stringProp> <stringProp name="HTTPSampler.protocol">${request_protocol}</stringProp> <stringProp name="HTTPSampler.contentEncoding"/> <stringProp name="HTTPSampler.path">${base_path}${admin_path}/sales/order_creditmemo/start/order_id/${order_id}/</stringProp> @@ -22731,8 +23607,8 @@ vars.put("admin_user", adminUser); </elementProp> <stringProp name="HTTPSampler.domain"/> <stringProp name="HTTPSampler.port"/> - <stringProp name="HTTPSampler.connect_timeout"/> - <stringProp name="HTTPSampler.response_timeout"/> + <stringProp name="HTTPSampler.connect_timeout">60000</stringProp> + <stringProp name="HTTPSampler.response_timeout">200000</stringProp> <stringProp name="HTTPSampler.protocol">${request_protocol}</stringProp> <stringProp name="HTTPSampler.contentEncoding"/> <stringProp name="HTTPSampler.path">${base_path}${admin_path}/sales/order_creditmemo/save/order_id/${order_id}/</stringProp> @@ -22771,8 +23647,8 @@ vars.put("admin_user", adminUser); </elementProp> <stringProp name="HTTPSampler.domain"/> <stringProp name="HTTPSampler.port"/> - <stringProp name="HTTPSampler.connect_timeout"/> - <stringProp name="HTTPSampler.response_timeout"/> + <stringProp name="HTTPSampler.connect_timeout">60000</stringProp> + <stringProp name="HTTPSampler.response_timeout">200000</stringProp> <stringProp name="HTTPSampler.protocol">${request_protocol}</stringProp> <stringProp name="HTTPSampler.contentEncoding"/> <stringProp name="HTTPSampler.path">${base_path}${admin_path}/admin/auth/logout/</stringProp> @@ -22791,8 +23667,11 @@ vars.put("admin_user", adminUser); <stringProp name="parameters"/> <stringProp name="filename"/> <stringProp name="script"> -adminUserList = props.get("adminUserList"); -adminUserList.add(vars.get("admin_user")); + adminUsersDistribution = Integer.parseInt(vars.get("admin_users_distribution_per_admin_pool")); + if (adminUsersDistribution == 1) { + adminUserList = props.get("adminUserList"); + adminUserList.add(vars.get("admin_user")); + } </stringProp> <stringProp name="TestPlan.comments">mpaf/tool/fragments/ce/common/return_admin_email_to_pool.jmx</stringProp></BeanShellPostProcessor> <hashTree/> @@ -22898,7 +23777,19 @@ if (testLabel <stringProp name="TestPlan.comments">mpaf/tool/fragments/ce/get_admin_email.jmx</stringProp> <stringProp name="BeanShellSampler.query"> adminUserList = props.get("adminUserList"); -adminUser = adminUserList.poll(); +adminUserListIterator = props.get("adminUserListIterator"); +adminUsersDistribution = Integer.parseInt(vars.get("admin_users_distribution_per_admin_pool")); + +if (adminUsersDistribution == 1) { + adminUser = adminUserList.poll(); +} else { + if (!adminUserListIterator.hasNext()) { + adminUserListIterator = adminUserList.descendingIterator(); + } + + adminUser = adminUserListIterator.next(); +} + if (adminUser == null) { SampleResult.setResponseMessage("adminUser list is empty"); SampleResult.setResponseData("adminUser list is empty","UTF-8"); @@ -22921,11 +23812,11 @@ vars.put("admin_user", adminUser); </elementProp> <stringProp name="HTTPSampler.domain"/> <stringProp name="HTTPSampler.port"/> - <stringProp name="HTTPSampler.connect_timeout"/> - <stringProp name="HTTPSampler.response_timeout"/> + <stringProp name="HTTPSampler.connect_timeout">60000</stringProp> + <stringProp name="HTTPSampler.response_timeout">200000</stringProp> <stringProp name="HTTPSampler.protocol">${request_protocol}</stringProp> <stringProp name="HTTPSampler.contentEncoding"/> - <stringProp name="HTTPSampler.path">${base_path}${admin_path}</stringProp> + <stringProp name="HTTPSampler.path">${base_path}${admin_path}/admin/</stringProp> <stringProp name="HTTPSampler.method">GET</stringProp> <boolProp name="HTTPSampler.follow_redirects">true</boolProp> <boolProp name="HTTPSampler.auto_redirects">false</boolProp> @@ -23002,8 +23893,8 @@ vars.put("admin_user", adminUser); </elementProp> <stringProp name="HTTPSampler.domain"/> <stringProp name="HTTPSampler.port"/> - <stringProp name="HTTPSampler.connect_timeout"/> - <stringProp name="HTTPSampler.response_timeout"/> + <stringProp name="HTTPSampler.connect_timeout">60000</stringProp> + <stringProp name="HTTPSampler.response_timeout">200000</stringProp> <stringProp name="HTTPSampler.protocol">${request_protocol}</stringProp> <stringProp name="HTTPSampler.contentEncoding"/> <stringProp name="HTTPSampler.path">${base_path}${admin_path}/admin/dashboard/</stringProp> @@ -23126,8 +24017,8 @@ vars.put("admin_user", adminUser); </elementProp> <stringProp name="HTTPSampler.domain"/> <stringProp name="HTTPSampler.port"/> - <stringProp name="HTTPSampler.connect_timeout"/> - <stringProp name="HTTPSampler.response_timeout"/> + <stringProp name="HTTPSampler.connect_timeout">60000</stringProp> + <stringProp name="HTTPSampler.response_timeout">200000</stringProp> <stringProp name="HTTPSampler.protocol">${request_protocol}</stringProp> <stringProp name="HTTPSampler.contentEncoding"/> <stringProp name="HTTPSampler.path">${base_path}${admin_path}/mui/index/render/</stringProp> @@ -23243,8 +24134,8 @@ vars.put("admin_user", adminUser); </elementProp> <stringProp name="HTTPSampler.domain"/> <stringProp name="HTTPSampler.port"/> - <stringProp name="HTTPSampler.connect_timeout"/> - <stringProp name="HTTPSampler.response_timeout"/> + <stringProp name="HTTPSampler.connect_timeout">60000</stringProp> + <stringProp name="HTTPSampler.response_timeout">200000</stringProp> <stringProp name="HTTPSampler.protocol">${request_protocol}</stringProp> <stringProp name="HTTPSampler.contentEncoding"/> <stringProp name="HTTPSampler.path">${base_path}${admin_path}/mui/index/render/</stringProp> @@ -23371,8 +24262,8 @@ vars.put("grid_pages_count_filtered", pageCount); </elementProp> <stringProp name="HTTPSampler.domain"/> <stringProp name="HTTPSampler.port"/> - <stringProp name="HTTPSampler.connect_timeout"/> - <stringProp name="HTTPSampler.response_timeout"/> + <stringProp name="HTTPSampler.connect_timeout">60000</stringProp> + <stringProp name="HTTPSampler.response_timeout">200000</stringProp> <stringProp name="HTTPSampler.protocol">${request_protocol}</stringProp> <stringProp name="HTTPSampler.contentEncoding"/> <stringProp name="HTTPSampler.path">${base_path}${admin_path}/mui/index/render/</stringProp> @@ -23498,8 +24389,8 @@ vars.put("grid_pages_count_filtered", pageCount); </elementProp> <stringProp name="HTTPSampler.domain"/> <stringProp name="HTTPSampler.port"/> - <stringProp name="HTTPSampler.connect_timeout"/> - <stringProp name="HTTPSampler.response_timeout"/> + <stringProp name="HTTPSampler.connect_timeout">60000</stringProp> + <stringProp name="HTTPSampler.response_timeout">200000</stringProp> <stringProp name="HTTPSampler.protocol">${request_protocol}</stringProp> <stringProp name="HTTPSampler.contentEncoding"/> <stringProp name="HTTPSampler.path">${base_path}${admin_path}/mui/index/render/</stringProp> @@ -23533,8 +24424,8 @@ vars.put("grid_pages_count_filtered", pageCount); </elementProp> <stringProp name="HTTPSampler.domain"/> <stringProp name="HTTPSampler.port"/> - <stringProp name="HTTPSampler.connect_timeout"/> - <stringProp name="HTTPSampler.response_timeout"/> + <stringProp name="HTTPSampler.connect_timeout">60000</stringProp> + <stringProp name="HTTPSampler.response_timeout">200000</stringProp> <stringProp name="HTTPSampler.protocol">${request_protocol}</stringProp> <stringProp name="HTTPSampler.contentEncoding"/> <stringProp name="HTTPSampler.path">${base_path}${admin_path}/admin/auth/logout/</stringProp> @@ -23553,8 +24444,11 @@ vars.put("grid_pages_count_filtered", pageCount); <stringProp name="parameters"/> <stringProp name="filename"/> <stringProp name="script"> -adminUserList = props.get("adminUserList"); -adminUserList.add(vars.get("admin_user")); + adminUsersDistribution = Integer.parseInt(vars.get("admin_users_distribution_per_admin_pool")); + if (adminUsersDistribution == 1) { + adminUserList = props.get("adminUserList"); + adminUserList.add(vars.get("admin_user")); + } </stringProp> <stringProp name="TestPlan.comments">mpaf/tool/fragments/ce/common/return_admin_email_to_pool.jmx</stringProp></BeanShellPostProcessor> <hashTree/> @@ -23660,7 +24554,19 @@ if (testLabel <stringProp name="TestPlan.comments">mpaf/tool/fragments/ce/get_admin_email.jmx</stringProp> <stringProp name="BeanShellSampler.query"> adminUserList = props.get("adminUserList"); -adminUser = adminUserList.poll(); +adminUserListIterator = props.get("adminUserListIterator"); +adminUsersDistribution = Integer.parseInt(vars.get("admin_users_distribution_per_admin_pool")); + +if (adminUsersDistribution == 1) { + adminUser = adminUserList.poll(); +} else { + if (!adminUserListIterator.hasNext()) { + adminUserListIterator = adminUserList.descendingIterator(); + } + + adminUser = adminUserListIterator.next(); +} + if (adminUser == null) { SampleResult.setResponseMessage("adminUser list is empty"); SampleResult.setResponseData("adminUser list is empty","UTF-8"); @@ -23683,11 +24589,11 @@ vars.put("admin_user", adminUser); </elementProp> <stringProp name="HTTPSampler.domain"/> <stringProp name="HTTPSampler.port"/> - <stringProp name="HTTPSampler.connect_timeout"/> - <stringProp name="HTTPSampler.response_timeout"/> + <stringProp name="HTTPSampler.connect_timeout">60000</stringProp> + <stringProp name="HTTPSampler.response_timeout">200000</stringProp> <stringProp name="HTTPSampler.protocol">${request_protocol}</stringProp> <stringProp name="HTTPSampler.contentEncoding"/> - <stringProp name="HTTPSampler.path">${base_path}${admin_path}</stringProp> + <stringProp name="HTTPSampler.path">${base_path}${admin_path}/admin/</stringProp> <stringProp name="HTTPSampler.method">GET</stringProp> <boolProp name="HTTPSampler.follow_redirects">true</boolProp> <boolProp name="HTTPSampler.auto_redirects">false</boolProp> @@ -23764,8 +24670,8 @@ vars.put("admin_user", adminUser); </elementProp> <stringProp name="HTTPSampler.domain"/> <stringProp name="HTTPSampler.port"/> - <stringProp name="HTTPSampler.connect_timeout"/> - <stringProp name="HTTPSampler.response_timeout"/> + <stringProp name="HTTPSampler.connect_timeout">60000</stringProp> + <stringProp name="HTTPSampler.response_timeout">200000</stringProp> <stringProp name="HTTPSampler.protocol">${request_protocol}</stringProp> <stringProp name="HTTPSampler.contentEncoding"/> <stringProp name="HTTPSampler.path">${base_path}${admin_path}/admin/dashboard/</stringProp> @@ -23796,6 +24702,18 @@ vars.put("admin_user", adminUser); <stringProp name="TestPlan.comments">mpaf/tool/fragments/ce/simple_controller.jmx</stringProp> </GenericController> <hashTree> + <JSR223PreProcessor guiclass="TestBeanGUI" testclass="JSR223PreProcessor" testname="Get region data" enabled="true"> + <stringProp name="scriptLanguage">javascript</stringProp> + <stringProp name="parameters"/> + <stringProp name="filename"/> + <stringProp name="cacheKey"/> + <stringProp name="script"> + vars.put("alabama_region_id", props.get("alabama_region_id")); + vars.put("california_region_id", props.get("california_region_id")); +</stringProp> + <stringProp name="TestPlan.comments">mpaf/tool/fragments/ce/common/get_region_data.jmx</stringProp></JSR223PreProcessor> + <hashTree/> + <TestFragmentController guiclass="TestFragmentControllerGui" testclass="TestFragmentController" testname="Admin Create Order" enabled="true"/> <hashTree> <BeanShellSampler guiclass="BeanShellSamplerGui" testclass="BeanShellSampler" testname="SetUp - Set Arguments" enabled="true"> @@ -23860,8 +24778,8 @@ catch (java.lang.Exception e) { </elementProp> <stringProp name="HTTPSampler.domain"/> <stringProp name="HTTPSampler.port"/> - <stringProp name="HTTPSampler.connect_timeout"/> - <stringProp name="HTTPSampler.response_timeout"/> + <stringProp name="HTTPSampler.connect_timeout">60000</stringProp> + <stringProp name="HTTPSampler.response_timeout">200000</stringProp> <stringProp name="HTTPSampler.protocol">${request_protocol}</stringProp> <stringProp name="HTTPSampler.contentEncoding"/> <stringProp name="HTTPSampler.path">${base_path}${admin_path}/sales/order_create/start/</stringProp> @@ -23903,8 +24821,8 @@ catch (java.lang.Exception e) { </elementProp> <stringProp name="HTTPSampler.domain"/> <stringProp name="HTTPSampler.port"/> - <stringProp name="HTTPSampler.connect_timeout"/> - <stringProp name="HTTPSampler.response_timeout"/> + <stringProp name="HTTPSampler.connect_timeout">60000</stringProp> + <stringProp name="HTTPSampler.response_timeout">200000</stringProp> <stringProp name="HTTPSampler.protocol">${request_protocol}</stringProp> <stringProp name="HTTPSampler.contentEncoding"/> <stringProp name="HTTPSampler.path">${base_path}rest/V1/integration/admin/token</stringProp> @@ -23952,8 +24870,8 @@ catch (java.lang.Exception e) { </elementProp> <stringProp name="HTTPSampler.domain"/> <stringProp name="HTTPSampler.port"/> - <stringProp name="HTTPSampler.connect_timeout"/> - <stringProp name="HTTPSampler.response_timeout"/> + <stringProp name="HTTPSampler.connect_timeout">60000</stringProp> + <stringProp name="HTTPSampler.response_timeout">200000</stringProp> <stringProp name="HTTPSampler.protocol">${request_protocol}</stringProp> <stringProp name="HTTPSampler.contentEncoding"/> <stringProp name="HTTPSampler.path">${base_path}rest/V1/configurable-products/${configurable_product_1_sku}/options/all</stringProp> @@ -24075,8 +24993,8 @@ catch (java.lang.Exception e) { </elementProp> <stringProp name="HTTPSampler.domain"/> <stringProp name="HTTPSampler.port"/> - <stringProp name="HTTPSampler.connect_timeout"/> - <stringProp name="HTTPSampler.response_timeout"/> + <stringProp name="HTTPSampler.connect_timeout">60000</stringProp> + <stringProp name="HTTPSampler.response_timeout">200000</stringProp> <stringProp name="HTTPSampler.protocol">${request_protocol}</stringProp> <stringProp name="HTTPSampler.contentEncoding"/> <stringProp name="HTTPSampler.path">${base_path}${admin_path}/sales/order_create/loadBlock/block/search,items,shipping_method,totals,giftmessage,billing_method?isAjax=true</stringProp> @@ -24175,8 +25093,8 @@ catch (java.lang.Exception e) { </elementProp> <stringProp name="HTTPSampler.domain"/> <stringProp name="HTTPSampler.port"/> - <stringProp name="HTTPSampler.connect_timeout"/> - <stringProp name="HTTPSampler.response_timeout"/> + <stringProp name="HTTPSampler.connect_timeout">60000</stringProp> + <stringProp name="HTTPSampler.response_timeout">200000</stringProp> <stringProp name="HTTPSampler.protocol">${request_protocol}</stringProp> <stringProp name="HTTPSampler.contentEncoding"/> <stringProp name="HTTPSampler.path">${base_path}${admin_path}/sales/order_create/loadBlock/block/shipping_method,totals?isAjax=true</stringProp> @@ -24465,7 +25383,7 @@ catch (java.lang.Exception e) { <elementProp name="order[billing_address][region_id]" elementType="HTTPArgument"> <boolProp name="HTTPArgument.always_encode">true</boolProp> <stringProp name="Argument.name">order[billing_address][region_id]</stringProp> - <stringProp name="Argument.value">5</stringProp> + <stringProp name="Argument.value">${alabama_region_id}</stringProp> <stringProp name="Argument.metadata">=</stringProp> <boolProp name="HTTPArgument.use_equals">true</boolProp> </elementProp> @@ -24543,8 +25461,8 @@ catch (java.lang.Exception e) { </elementProp> <stringProp name="HTTPSampler.domain"/> <stringProp name="HTTPSampler.port"/> - <stringProp name="HTTPSampler.connect_timeout"/> - <stringProp name="HTTPSampler.response_timeout"/> + <stringProp name="HTTPSampler.connect_timeout">60000</stringProp> + <stringProp name="HTTPSampler.response_timeout">200000</stringProp> <stringProp name="HTTPSampler.protocol">${request_protocol}</stringProp> <stringProp name="HTTPSampler.contentEncoding"/> <stringProp name="HTTPSampler.path">${base_path}${admin_path}/sales/order_create/save/</stringProp> @@ -24690,8 +25608,8 @@ catch (java.lang.Exception e) { </elementProp> <stringProp name="HTTPSampler.domain"/> <stringProp name="HTTPSampler.port"/> - <stringProp name="HTTPSampler.connect_timeout"/> - <stringProp name="HTTPSampler.response_timeout"/> + <stringProp name="HTTPSampler.connect_timeout">60000</stringProp> + <stringProp name="HTTPSampler.response_timeout">200000</stringProp> <stringProp name="HTTPSampler.protocol">${request_protocol}</stringProp> <stringProp name="HTTPSampler.contentEncoding"/> <stringProp name="HTTPSampler.path">${base_path}${admin_path}/sales/order_invoice/save/order_id/${order_id}/</stringProp> @@ -24757,8 +25675,8 @@ catch (java.lang.Exception e) { </elementProp> <stringProp name="HTTPSampler.domain"/> <stringProp name="HTTPSampler.port"/> - <stringProp name="HTTPSampler.connect_timeout"/> - <stringProp name="HTTPSampler.response_timeout"/> + <stringProp name="HTTPSampler.connect_timeout">60000</stringProp> + <stringProp name="HTTPSampler.response_timeout">200000</stringProp> <stringProp name="HTTPSampler.protocol">${request_protocol}</stringProp> <stringProp name="HTTPSampler.contentEncoding"/> <stringProp name="HTTPSampler.path">${base_path}${admin_path}/admin/order_shipment/save/order_id/${order_id}/</stringProp> @@ -24791,8 +25709,8 @@ catch (java.lang.Exception e) { </elementProp> <stringProp name="HTTPSampler.domain"/> <stringProp name="HTTPSampler.port"/> - <stringProp name="HTTPSampler.connect_timeout"/> - <stringProp name="HTTPSampler.response_timeout"/> + <stringProp name="HTTPSampler.connect_timeout">60000</stringProp> + <stringProp name="HTTPSampler.response_timeout">200000</stringProp> <stringProp name="HTTPSampler.protocol">${request_protocol}</stringProp> <stringProp name="HTTPSampler.contentEncoding"/> <stringProp name="HTTPSampler.path">${base_path}${admin_path}/admin/auth/logout/</stringProp> @@ -24811,8 +25729,11 @@ catch (java.lang.Exception e) { <stringProp name="parameters"/> <stringProp name="filename"/> <stringProp name="script"> -adminUserList = props.get("adminUserList"); -adminUserList.add(vars.get("admin_user")); + adminUsersDistribution = Integer.parseInt(vars.get("admin_users_distribution_per_admin_pool")); + if (adminUsersDistribution == 1) { + adminUserList = props.get("adminUserList"); + adminUserList.add(vars.get("admin_user")); + } </stringProp> <stringProp name="TestPlan.comments">mpaf/tool/fragments/ce/common/return_admin_email_to_pool.jmx</stringProp></BeanShellPostProcessor> <hashTree/> @@ -24895,8 +25816,8 @@ if (testLabel </elementProp> <stringProp name="HTTPSampler.domain"/> <stringProp name="HTTPSampler.port"/> - <stringProp name="HTTPSampler.connect_timeout"/> - <stringProp name="HTTPSampler.response_timeout"/> + <stringProp name="HTTPSampler.connect_timeout">60000</stringProp> + <stringProp name="HTTPSampler.response_timeout">200000</stringProp> <stringProp name="HTTPSampler.protocol">${request_protocol}</stringProp> <stringProp name="HTTPSampler.contentEncoding"/> <stringProp name="HTTPSampler.path">${base_path}rest/V1/integration/admin/token</stringProp> @@ -24992,8 +25913,8 @@ if (testLabel </elementProp> <stringProp name="HTTPSampler.domain"/> <stringProp name="HTTPSampler.port"/> - <stringProp name="HTTPSampler.connect_timeout"/> - <stringProp name="HTTPSampler.response_timeout"/> + <stringProp name="HTTPSampler.connect_timeout">60000</stringProp> + <stringProp name="HTTPSampler.response_timeout">200000</stringProp> <stringProp name="HTTPSampler.protocol">${request_protocol}</stringProp> <stringProp name="HTTPSampler.contentEncoding"/> <stringProp name="HTTPSampler.path">${base_path}rest/default/V1/customers</stringProp> @@ -25033,8 +25954,8 @@ if (testLabel </elementProp> <stringProp name="HTTPSampler.domain"/> <stringProp name="HTTPSampler.port"/> - <stringProp name="HTTPSampler.connect_timeout"/> - <stringProp name="HTTPSampler.response_timeout"/> + <stringProp name="HTTPSampler.connect_timeout">60000</stringProp> + <stringProp name="HTTPSampler.response_timeout">200000</stringProp> <stringProp name="HTTPSampler.protocol">${request_protocol}</stringProp> <stringProp name="HTTPSampler.contentEncoding"/> <stringProp name="HTTPSampler.path">${base_path}rest/default/V1/customers/${customer_id}</stringProp> @@ -25096,8 +26017,8 @@ if (testLabel </elementProp> <stringProp name="HTTPSampler.domain"/> <stringProp name="HTTPSampler.port"/> - <stringProp name="HTTPSampler.connect_timeout"/> - <stringProp name="HTTPSampler.response_timeout"/> + <stringProp name="HTTPSampler.connect_timeout">60000</stringProp> + <stringProp name="HTTPSampler.response_timeout">200000</stringProp> <stringProp name="HTTPSampler.protocol">${request_protocol}</stringProp> <stringProp name="HTTPSampler.contentEncoding"/> <stringProp name="HTTPSampler.path">${base_path}rest/default/V1/categories</stringProp> @@ -25148,8 +26069,8 @@ if (testLabel </elementProp> <stringProp name="HTTPSampler.domain"/> <stringProp name="HTTPSampler.port"/> - <stringProp name="HTTPSampler.connect_timeout"/> - <stringProp name="HTTPSampler.response_timeout"/> + <stringProp name="HTTPSampler.connect_timeout">60000</stringProp> + <stringProp name="HTTPSampler.response_timeout">200000</stringProp> <stringProp name="HTTPSampler.protocol">${request_protocol}</stringProp> <stringProp name="HTTPSampler.contentEncoding"/> <stringProp name="HTTPSampler.path">${base_path}rest/default/V1/categories/${search_category_id}</stringProp> @@ -25198,8 +26119,8 @@ if (testLabel </elementProp> <stringProp name="HTTPSampler.domain"/> <stringProp name="HTTPSampler.port"/> - <stringProp name="HTTPSampler.connect_timeout"/> - <stringProp name="HTTPSampler.response_timeout"/> + <stringProp name="HTTPSampler.connect_timeout">60000</stringProp> + <stringProp name="HTTPSampler.response_timeout">200000</stringProp> <stringProp name="HTTPSampler.protocol">${request_protocol}</stringProp> <stringProp name="HTTPSampler.contentEncoding"/> <stringProp name="HTTPSampler.path">${base_path}rest/default/V1/products</stringProp> @@ -25300,8 +26221,8 @@ if (testLabel </elementProp> <stringProp name="HTTPSampler.domain"/> <stringProp name="HTTPSampler.port"/> - <stringProp name="HTTPSampler.connect_timeout"/> - <stringProp name="HTTPSampler.response_timeout"/> + <stringProp name="HTTPSampler.connect_timeout">60000</stringProp> + <stringProp name="HTTPSampler.response_timeout">200000</stringProp> <stringProp name="HTTPSampler.protocol">${request_protocol}</stringProp> <stringProp name="HTTPSampler.contentEncoding"/> <stringProp name="HTTPSampler.path">${base_path}rest/default/V1/search</stringProp> @@ -25376,6 +26297,18 @@ if (testLabel </BeanShellSampler> <hashTree/> + <JSR223PreProcessor guiclass="TestBeanGUI" testclass="JSR223PreProcessor" testname="Get region data" enabled="true"> + <stringProp name="scriptLanguage">javascript</stringProp> + <stringProp name="parameters"/> + <stringProp name="filename"/> + <stringProp name="cacheKey"/> + <stringProp name="script"> + vars.put("alabama_region_id", props.get("alabama_region_id")); + vars.put("california_region_id", props.get("california_region_id")); +</stringProp> + <stringProp name="TestPlan.comments">mpaf/tool/fragments/ce/common/get_region_data.jmx</stringProp></JSR223PreProcessor> + <hashTree/> + <BeanShellSampler guiclass="BeanShellSamplerGui" testclass="BeanShellSampler" testname="SetUp - Init Random Generator" enabled="true"> <stringProp name="TestPlan.comments">mpaf/tool/fragments/ce/common/init_random_generator_setup.jmx</stringProp> <stringProp name="BeanShellSampler.query"> @@ -25420,8 +26353,8 @@ vars.put("product_sku", product.get("sku")); </elementProp> <stringProp name="HTTPSampler.domain"/> <stringProp name="HTTPSampler.port"/> - <stringProp name="HTTPSampler.connect_timeout"/> - <stringProp name="HTTPSampler.response_timeout"/> + <stringProp name="HTTPSampler.connect_timeout">60000</stringProp> + <stringProp name="HTTPSampler.response_timeout">200000</stringProp> <stringProp name="HTTPSampler.protocol">${request_protocol}</stringProp> <stringProp name="HTTPSampler.contentEncoding"/> <stringProp name="HTTPSampler.path">${base_path}rest/default/V1/carts</stringProp> @@ -25475,8 +26408,8 @@ vars.put("product_sku", product.get("sku")); </elementProp> <stringProp name="HTTPSampler.domain"/> <stringProp name="HTTPSampler.port"/> - <stringProp name="HTTPSampler.connect_timeout"/> - <stringProp name="HTTPSampler.response_timeout"/> + <stringProp name="HTTPSampler.connect_timeout">60000</stringProp> + <stringProp name="HTTPSampler.response_timeout">200000</stringProp> <stringProp name="HTTPSampler.protocol">${request_protocol}</stringProp> <stringProp name="HTTPSampler.contentEncoding"/> <stringProp name="HTTPSampler.path">${base_path}rest/default/V1/carts/${quote_id}/items</stringProp> @@ -25506,8 +26439,8 @@ vars.put("product_sku", product.get("sku")); </elementProp> <stringProp name="HTTPSampler.domain"/> <stringProp name="HTTPSampler.port"/> - <stringProp name="HTTPSampler.connect_timeout"/> - <stringProp name="HTTPSampler.response_timeout"/> + <stringProp name="HTTPSampler.connect_timeout">60000</stringProp> + <stringProp name="HTTPSampler.response_timeout">200000</stringProp> <stringProp name="HTTPSampler.protocol">${request_protocol}</stringProp> <stringProp name="HTTPSampler.contentEncoding"/> <stringProp name="HTTPSampler.path">${base_path}rest/default/V1/carts/${quote_id}/items</stringProp> @@ -25545,8 +26478,8 @@ vars.put("product_sku", product.get("sku")); </elementProp> <stringProp name="HTTPSampler.domain"/> <stringProp name="HTTPSampler.port"/> - <stringProp name="HTTPSampler.connect_timeout"/> - <stringProp name="HTTPSampler.response_timeout"/> + <stringProp name="HTTPSampler.connect_timeout">60000</stringProp> + <stringProp name="HTTPSampler.response_timeout">200000</stringProp> <stringProp name="HTTPSampler.protocol">${request_protocol}</stringProp> <stringProp name="HTTPSampler.contentEncoding"/> <stringProp name="HTTPSampler.path">${base_path}rest/default/V1/guest-carts/</stringProp> @@ -25600,8 +26533,8 @@ vars.put("product_sku", product.get("sku")); </elementProp> <stringProp name="HTTPSampler.domain"/> <stringProp name="HTTPSampler.port"/> - <stringProp name="HTTPSampler.connect_timeout"/> - <stringProp name="HTTPSampler.response_timeout"/> + <stringProp name="HTTPSampler.connect_timeout">60000</stringProp> + <stringProp name="HTTPSampler.response_timeout">200000</stringProp> <stringProp name="HTTPSampler.protocol">${request_protocol}</stringProp> <stringProp name="HTTPSampler.contentEncoding"/> <stringProp name="HTTPSampler.path">${base_path}rest/default/V1/guest-carts/${cart_id}/items</stringProp> @@ -25642,8 +26575,8 @@ vars.put("product_sku", product.get("sku")); </elementProp> <stringProp name="HTTPSampler.domain"/> <stringProp name="HTTPSampler.port"/> - <stringProp name="HTTPSampler.connect_timeout"/> - <stringProp name="HTTPSampler.response_timeout"/> + <stringProp name="HTTPSampler.connect_timeout">60000</stringProp> + <stringProp name="HTTPSampler.response_timeout">200000</stringProp> <stringProp name="HTTPSampler.protocol">${request_protocol}</stringProp> <stringProp name="HTTPSampler.contentEncoding"/> <stringProp name="HTTPSampler.path">${base_path}rest/default/V1/guest-carts/${cart_id}/gift-message</stringProp> @@ -25679,8 +26612,8 @@ vars.put("product_sku", product.get("sku")); </elementProp> <stringProp name="HTTPSampler.domain"/> <stringProp name="HTTPSampler.port"/> - <stringProp name="HTTPSampler.connect_timeout"/> - <stringProp name="HTTPSampler.response_timeout"/> + <stringProp name="HTTPSampler.connect_timeout">60000</stringProp> + <stringProp name="HTTPSampler.response_timeout">200000</stringProp> <stringProp name="HTTPSampler.protocol">${request_protocol}</stringProp> <stringProp name="HTTPSampler.contentEncoding"/> <stringProp name="HTTPSampler.path">${base_path}rest/default/V1/guest-carts/${cart_id}/estimate-shipping-methods</stringProp> @@ -25731,15 +26664,15 @@ vars.put("product_sku", product.get("sku")); <collectionProp name="Arguments.arguments"> <elementProp name="" elementType="HTTPArgument"> <boolProp name="HTTPArgument.always_encode">false</boolProp> - <stringProp name="Argument.value">{"addressInformation":{"shipping_address":{"countryId":"US","regionId":"12","regionCode":"CA","region":"California","street":["10441 Jefferson Blvd ste 200"],"company":"","telephone":"3109450345","fax":"","postcode":"90232","city":"Culver City","firstname":"Name","lastname":"Lastname"},"shipping_method_code":"flatrate","shipping_carrier_code":"flatrate"}}</stringProp> + <stringProp name="Argument.value">{"addressInformation":{"shipping_address":{"countryId":"US","regionId":"${california_region_id}","regionCode":"CA","region":"California","street":["10441 Jefferson Blvd ste 200"],"company":"","telephone":"3109450345","fax":"","postcode":"90232","city":"Culver City","firstname":"Name","lastname":"Lastname"},"shipping_method_code":"flatrate","shipping_carrier_code":"flatrate"}}</stringProp> <stringProp name="Argument.metadata">=</stringProp> </elementProp> </collectionProp> </elementProp> <stringProp name="HTTPSampler.domain"/> <stringProp name="HTTPSampler.port"/> - <stringProp name="HTTPSampler.connect_timeout"/> - <stringProp name="HTTPSampler.response_timeout"/> + <stringProp name="HTTPSampler.connect_timeout">60000</stringProp> + <stringProp name="HTTPSampler.response_timeout">200000</stringProp> <stringProp name="HTTPSampler.protocol">${request_protocol}</stringProp> <stringProp name="HTTPSampler.contentEncoding"/> <stringProp name="HTTPSampler.path">${base_path}rest/default/V1/guest-carts/${cart_id}/shipping-information</stringProp> @@ -25790,15 +26723,15 @@ vars.put("product_sku", product.get("sku")); <collectionProp name="Arguments.arguments"> <elementProp name="" elementType="HTTPArgument"> <boolProp name="HTTPArgument.always_encode">false</boolProp> - <stringProp name="Argument.value">{"cartId":"${cart_id}","email":"test@example.com","paymentMethod":{"method":"checkmo","po_number":null,"additional_data":null},"billingAddress":{"countryId":"US","regionId":"12","regionCode":"CA","region":"California","street":["10441 Jefferson Blvd ste 200"],"company":"","telephone":"3109450345","fax":"","postcode":"90232","city":"Culver City","firstname":"Name","lastname":"Lastname","save_in_address_book":0}}</stringProp> + <stringProp name="Argument.value">{"cartId":"${cart_id}","email":"test@example.com","paymentMethod":{"method":"checkmo","po_number":null,"additional_data":null},"billingAddress":{"countryId":"US","regionId":"${california_region_id}","regionCode":"CA","region":"California","street":["10441 Jefferson Blvd ste 200"],"company":"","telephone":"3109450345","fax":"","postcode":"90232","city":"Culver City","firstname":"Name","lastname":"Lastname","save_in_address_book":0}}</stringProp> <stringProp name="Argument.metadata">=</stringProp> </elementProp> </collectionProp> </elementProp> <stringProp name="HTTPSampler.domain"/> <stringProp name="HTTPSampler.port"/> - <stringProp name="HTTPSampler.connect_timeout"/> - <stringProp name="HTTPSampler.response_timeout"/> + <stringProp name="HTTPSampler.connect_timeout">60000</stringProp> + <stringProp name="HTTPSampler.response_timeout">200000</stringProp> <stringProp name="HTTPSampler.protocol">${request_protocol}</stringProp> <stringProp name="HTTPSampler.contentEncoding"/> <stringProp name="HTTPSampler.path">${base_path}rest/default/V1/guest-carts/${cart_id}/payment-information</stringProp> @@ -25914,8 +26847,8 @@ if (testLabel </elementProp> <stringProp name="HTTPSampler.domain"/> <stringProp name="HTTPSampler.port"/> - <stringProp name="HTTPSampler.connect_timeout"/> - <stringProp name="HTTPSampler.response_timeout"/> + <stringProp name="HTTPSampler.connect_timeout">60000</stringProp> + <stringProp name="HTTPSampler.response_timeout">200000</stringProp> <stringProp name="HTTPSampler.protocol">${request_protocol}</stringProp> <stringProp name="HTTPSampler.contentEncoding"/> <stringProp name="HTTPSampler.path">${base_path}rest/default/V1/products</stringProp> @@ -26006,8 +26939,8 @@ if (testLabel </elementProp> <stringProp name="HTTPSampler.domain"/> <stringProp name="HTTPSampler.port"/> - <stringProp name="HTTPSampler.connect_timeout"/> - <stringProp name="HTTPSampler.response_timeout"/> + <stringProp name="HTTPSampler.connect_timeout">60000</stringProp> + <stringProp name="HTTPSampler.response_timeout">200000</stringProp> <stringProp name="HTTPSampler.protocol">${request_protocol}</stringProp> <stringProp name="HTTPSampler.contentEncoding"/> <stringProp name="HTTPSampler.path">${base_path}rest/default/V1/products/${simple_product_sku}/stockItems/${simple_stock_item_id}</stringProp> @@ -26043,8 +26976,8 @@ if (testLabel </elementProp> <stringProp name="HTTPSampler.domain"/> <stringProp name="HTTPSampler.port"/> - <stringProp name="HTTPSampler.connect_timeout"/> - <stringProp name="HTTPSampler.response_timeout"/> + <stringProp name="HTTPSampler.connect_timeout">60000</stringProp> + <stringProp name="HTTPSampler.response_timeout">200000</stringProp> <stringProp name="HTTPSampler.protocol">${request_protocol}</stringProp> <stringProp name="HTTPSampler.contentEncoding"/> <stringProp name="HTTPSampler.path">${base_path}rest/default/V1/products/${simple_product_sku}</stringProp> @@ -26146,8 +27079,8 @@ if (testLabel </elementProp> <stringProp name="HTTPSampler.domain"/> <stringProp name="HTTPSampler.port"/> - <stringProp name="HTTPSampler.connect_timeout"/> - <stringProp name="HTTPSampler.response_timeout"/> + <stringProp name="HTTPSampler.connect_timeout">60000</stringProp> + <stringProp name="HTTPSampler.response_timeout">200000</stringProp> <stringProp name="HTTPSampler.protocol">${request_protocol}</stringProp> <stringProp name="HTTPSampler.contentEncoding"/> <stringProp name="HTTPSampler.path">${base_path}rest/default/V1/products</stringProp> @@ -26232,8 +27165,8 @@ if (testLabel </elementProp> <stringProp name="HTTPSampler.domain"/> <stringProp name="HTTPSampler.port"/> - <stringProp name="HTTPSampler.connect_timeout"/> - <stringProp name="HTTPSampler.response_timeout"/> + <stringProp name="HTTPSampler.connect_timeout">60000</stringProp> + <stringProp name="HTTPSampler.response_timeout">200000</stringProp> <stringProp name="HTTPSampler.protocol">${request_protocol}</stringProp> <stringProp name="HTTPSampler.contentEncoding"/> <stringProp name="HTTPSampler.path">${base_path}rest/default/V1/products/${simple_product_sku}</stringProp> @@ -26399,7 +27332,19 @@ if (testLabel <stringProp name="TestPlan.comments">mpaf/tool/fragments/ce/get_admin_email.jmx</stringProp> <stringProp name="BeanShellSampler.query"> adminUserList = props.get("adminUserList"); -adminUser = adminUserList.poll(); +adminUserListIterator = props.get("adminUserListIterator"); +adminUsersDistribution = Integer.parseInt(vars.get("admin_users_distribution_per_admin_pool")); + +if (adminUsersDistribution == 1) { + adminUser = adminUserList.poll(); +} else { + if (!adminUserListIterator.hasNext()) { + adminUserListIterator = adminUserList.descendingIterator(); + } + + adminUser = adminUserListIterator.next(); +} + if (adminUser == null) { SampleResult.setResponseMessage("adminUser list is empty"); SampleResult.setResponseData("adminUser list is empty","UTF-8"); @@ -26422,11 +27367,11 @@ vars.put("admin_user", adminUser); </elementProp> <stringProp name="HTTPSampler.domain"/> <stringProp name="HTTPSampler.port"/> - <stringProp name="HTTPSampler.connect_timeout"/> - <stringProp name="HTTPSampler.response_timeout"/> + <stringProp name="HTTPSampler.connect_timeout">60000</stringProp> + <stringProp name="HTTPSampler.response_timeout">200000</stringProp> <stringProp name="HTTPSampler.protocol">${request_protocol}</stringProp> <stringProp name="HTTPSampler.contentEncoding"/> - <stringProp name="HTTPSampler.path">${base_path}${admin_path}</stringProp> + <stringProp name="HTTPSampler.path">${base_path}${admin_path}/admin/</stringProp> <stringProp name="HTTPSampler.method">GET</stringProp> <boolProp name="HTTPSampler.follow_redirects">true</boolProp> <boolProp name="HTTPSampler.auto_redirects">false</boolProp> @@ -26503,8 +27448,8 @@ vars.put("admin_user", adminUser); </elementProp> <stringProp name="HTTPSampler.domain"/> <stringProp name="HTTPSampler.port"/> - <stringProp name="HTTPSampler.connect_timeout"/> - <stringProp name="HTTPSampler.response_timeout"/> + <stringProp name="HTTPSampler.connect_timeout">60000</stringProp> + <stringProp name="HTTPSampler.response_timeout">200000</stringProp> <stringProp name="HTTPSampler.protocol">${request_protocol}</stringProp> <stringProp name="HTTPSampler.contentEncoding"/> <stringProp name="HTTPSampler.path">${base_path}${admin_path}/admin/dashboard/</stringProp> @@ -26613,8 +27558,8 @@ vars.put("admin_user", adminUser); </elementProp> <stringProp name="HTTPSampler.domain"/> <stringProp name="HTTPSampler.port"/> - <stringProp name="HTTPSampler.connect_timeout"/> - <stringProp name="HTTPSampler.response_timeout"/> + <stringProp name="HTTPSampler.connect_timeout">60000</stringProp> + <stringProp name="HTTPSampler.response_timeout">200000</stringProp> <stringProp name="HTTPSampler.protocol">${request_protocol}</stringProp> <stringProp name="HTTPSampler.contentEncoding"/> <stringProp name="HTTPSampler.path">${base_path}${admin_path}/mui/index/render/</stringProp> @@ -26775,8 +27720,8 @@ vars.put("visibility", String.valueOf(randomVisibility)); </elementProp> <stringProp name="HTTPSampler.domain"/> <stringProp name="HTTPSampler.port"/> - <stringProp name="HTTPSampler.connect_timeout"/> - <stringProp name="HTTPSampler.response_timeout"/> + <stringProp name="HTTPSampler.connect_timeout">60000</stringProp> + <stringProp name="HTTPSampler.response_timeout">200000</stringProp> <stringProp name="HTTPSampler.protocol">${request_protocol}</stringProp> <stringProp name="HTTPSampler.contentEncoding"/> <stringProp name="HTTPSampler.path">${base_path}${admin_path}/mui/index/render/</stringProp> @@ -26853,8 +27798,8 @@ vars.put("visibility", String.valueOf(randomVisibility)); </elementProp> <stringProp name="HTTPSampler.domain"/> <stringProp name="HTTPSampler.port"/> - <stringProp name="HTTPSampler.connect_timeout"/> - <stringProp name="HTTPSampler.response_timeout"/> + <stringProp name="HTTPSampler.connect_timeout">60000</stringProp> + <stringProp name="HTTPSampler.response_timeout">200000</stringProp> <stringProp name="HTTPSampler.protocol">${request_protocol}</stringProp> <stringProp name="HTTPSampler.contentEncoding"/> <stringProp name="HTTPSampler.path">${base_path}${admin_path}/catalog/product_action_attribute/edit</stringProp> @@ -26947,8 +27892,8 @@ vars.put("visibility", String.valueOf(randomVisibility)); </elementProp> <stringProp name="HTTPSampler.domain"/> <stringProp name="HTTPSampler.port"/> - <stringProp name="HTTPSampler.connect_timeout"/> - <stringProp name="HTTPSampler.response_timeout"/> + <stringProp name="HTTPSampler.connect_timeout">60000</stringProp> + <stringProp name="HTTPSampler.response_timeout">200000</stringProp> <stringProp name="HTTPSampler.protocol">${request_protocol}</stringProp> <stringProp name="HTTPSampler.contentEncoding"/> <stringProp name="HTTPSampler.path">${base_path}${admin_path}/catalog/product_action_attribute/validate</stringProp> @@ -27062,8 +28007,8 @@ vars.put("visibility", String.valueOf(randomVisibility)); </elementProp> <stringProp name="HTTPSampler.domain"/> <stringProp name="HTTPSampler.port"/> - <stringProp name="HTTPSampler.connect_timeout"/> - <stringProp name="HTTPSampler.response_timeout"/> + <stringProp name="HTTPSampler.connect_timeout">60000</stringProp> + <stringProp name="HTTPSampler.response_timeout">200000</stringProp> <stringProp name="HTTPSampler.protocol">${request_protocol}</stringProp> <stringProp name="HTTPSampler.contentEncoding"/> <stringProp name="HTTPSampler.path">${base_path}${admin_path}/catalog/product_action_attribute/save/store/0/active_tab/attributes</stringProp> @@ -27094,8 +28039,8 @@ vars.put("visibility", String.valueOf(randomVisibility)); </elementProp> <stringProp name="HTTPSampler.domain"/> <stringProp name="HTTPSampler.port"/> - <stringProp name="HTTPSampler.connect_timeout"/> - <stringProp name="HTTPSampler.response_timeout"/> + <stringProp name="HTTPSampler.connect_timeout">60000</stringProp> + <stringProp name="HTTPSampler.response_timeout">200000</stringProp> <stringProp name="HTTPSampler.protocol">${request_protocol}</stringProp> <stringProp name="HTTPSampler.contentEncoding"/> <stringProp name="HTTPSampler.path">${base_path}${admin_path}/admin/auth/logout/</stringProp> @@ -27114,8 +28059,11 @@ vars.put("visibility", String.valueOf(randomVisibility)); <stringProp name="parameters"/> <stringProp name="filename"/> <stringProp name="script"> -adminUserList = props.get("adminUserList"); -adminUserList.add(vars.get("admin_user")); + adminUsersDistribution = Integer.parseInt(vars.get("admin_users_distribution_per_admin_pool")); + if (adminUsersDistribution == 1) { + adminUserList = props.get("adminUserList"); + adminUserList.add(vars.get("admin_user")); + } </stringProp> <stringProp name="TestPlan.comments">mpaf/tool/fragments/ce/common/return_admin_email_to_pool.jmx</stringProp></BeanShellPostProcessor> <hashTree/> @@ -27221,7 +28169,19 @@ if (testLabel <stringProp name="TestPlan.comments">mpaf/tool/fragments/ce/get_admin_email.jmx</stringProp> <stringProp name="BeanShellSampler.query"> adminUserList = props.get("adminUserList"); -adminUser = adminUserList.poll(); +adminUserListIterator = props.get("adminUserListIterator"); +adminUsersDistribution = Integer.parseInt(vars.get("admin_users_distribution_per_admin_pool")); + +if (adminUsersDistribution == 1) { + adminUser = adminUserList.poll(); +} else { + if (!adminUserListIterator.hasNext()) { + adminUserListIterator = adminUserList.descendingIterator(); + } + + adminUser = adminUserListIterator.next(); +} + if (adminUser == null) { SampleResult.setResponseMessage("adminUser list is empty"); SampleResult.setResponseData("adminUser list is empty","UTF-8"); @@ -27244,11 +28204,11 @@ vars.put("admin_user", adminUser); </elementProp> <stringProp name="HTTPSampler.domain"/> <stringProp name="HTTPSampler.port"/> - <stringProp name="HTTPSampler.connect_timeout"/> - <stringProp name="HTTPSampler.response_timeout"/> + <stringProp name="HTTPSampler.connect_timeout">60000</stringProp> + <stringProp name="HTTPSampler.response_timeout">200000</stringProp> <stringProp name="HTTPSampler.protocol">${request_protocol}</stringProp> <stringProp name="HTTPSampler.contentEncoding"/> - <stringProp name="HTTPSampler.path">${base_path}${admin_path}</stringProp> + <stringProp name="HTTPSampler.path">${base_path}${admin_path}/admin/</stringProp> <stringProp name="HTTPSampler.method">GET</stringProp> <boolProp name="HTTPSampler.follow_redirects">true</boolProp> <boolProp name="HTTPSampler.auto_redirects">false</boolProp> @@ -27325,8 +28285,8 @@ vars.put("admin_user", adminUser); </elementProp> <stringProp name="HTTPSampler.domain"/> <stringProp name="HTTPSampler.port"/> - <stringProp name="HTTPSampler.connect_timeout"/> - <stringProp name="HTTPSampler.response_timeout"/> + <stringProp name="HTTPSampler.connect_timeout">60000</stringProp> + <stringProp name="HTTPSampler.response_timeout">200000</stringProp> <stringProp name="HTTPSampler.protocol">${request_protocol}</stringProp> <stringProp name="HTTPSampler.contentEncoding"/> <stringProp name="HTTPSampler.path">${base_path}${admin_path}/admin/dashboard/</stringProp> @@ -27375,8 +28335,8 @@ vars.put("adminImportFilePath", filepath); </stringProp> </elementProp> <stringProp name="HTTPSampler.domain"/> <stringProp name="HTTPSampler.port"/> - <stringProp name="HTTPSampler.connect_timeout"/> - <stringProp name="HTTPSampler.response_timeout"/> + <stringProp name="HTTPSampler.connect_timeout">60000</stringProp> + <stringProp name="HTTPSampler.response_timeout">200000</stringProp> <stringProp name="HTTPSampler.protocol">${request_protocol}</stringProp> <stringProp name="HTTPSampler.contentEncoding"/> <stringProp name="HTTPSampler.path">${base_path}${admin_path}/admin/import/</stringProp> @@ -27457,8 +28417,8 @@ vars.put("adminImportFilePath", filepath); </stringProp> </elementProp> <stringProp name="HTTPSampler.domain"/> <stringProp name="HTTPSampler.port"/> - <stringProp name="HTTPSampler.connect_timeout"/> - <stringProp name="HTTPSampler.response_timeout"/> + <stringProp name="HTTPSampler.connect_timeout">60000</stringProp> + <stringProp name="HTTPSampler.response_timeout">200000</stringProp> <stringProp name="HTTPSampler.protocol">${request_protocol}</stringProp> <stringProp name="HTTPSampler.contentEncoding"/> <stringProp name="HTTPSampler.path">${base_path}${admin_path}/admin/import/validate</stringProp> @@ -27553,8 +28513,8 @@ vars.put("adminImportFilePath", filepath); </stringProp> </elementProp> <stringProp name="HTTPSampler.domain"/> <stringProp name="HTTPSampler.port"/> - <stringProp name="HTTPSampler.connect_timeout"/> - <stringProp name="HTTPSampler.response_timeout"/> + <stringProp name="HTTPSampler.connect_timeout">60000</stringProp> + <stringProp name="HTTPSampler.response_timeout">200000</stringProp> <stringProp name="HTTPSampler.protocol">${request_protocol}</stringProp> <stringProp name="HTTPSampler.contentEncoding"/> <stringProp name="HTTPSampler.path">${base_path}${admin_path}/admin/import/start</stringProp> @@ -27595,8 +28555,8 @@ vars.put("adminImportFilePath", filepath); </stringProp> </elementProp> <stringProp name="HTTPSampler.domain"/> <stringProp name="HTTPSampler.port"/> - <stringProp name="HTTPSampler.connect_timeout"/> - <stringProp name="HTTPSampler.response_timeout"/> + <stringProp name="HTTPSampler.connect_timeout">60000</stringProp> + <stringProp name="HTTPSampler.response_timeout">200000</stringProp> <stringProp name="HTTPSampler.protocol">${request_protocol}</stringProp> <stringProp name="HTTPSampler.contentEncoding"/> <stringProp name="HTTPSampler.path">${base_path}${admin_path}/admin/auth/logout/</stringProp> @@ -27615,8 +28575,11 @@ vars.put("adminImportFilePath", filepath); </stringProp> <stringProp name="parameters"/> <stringProp name="filename"/> <stringProp name="script"> -adminUserList = props.get("adminUserList"); -adminUserList.add(vars.get("admin_user")); + adminUsersDistribution = Integer.parseInt(vars.get("admin_users_distribution_per_admin_pool")); + if (adminUsersDistribution == 1) { + adminUserList = props.get("adminUserList"); + adminUserList.add(vars.get("admin_user")); + } </stringProp> <stringProp name="TestPlan.comments">mpaf/tool/fragments/ce/common/return_admin_email_to_pool.jmx</stringProp></BeanShellPostProcessor> <hashTree/> @@ -27722,7 +28685,19 @@ if (testLabel <stringProp name="TestPlan.comments">mpaf/tool/fragments/ce/get_admin_email.jmx</stringProp> <stringProp name="BeanShellSampler.query"> adminUserList = props.get("adminUserList"); -adminUser = adminUserList.poll(); +adminUserListIterator = props.get("adminUserListIterator"); +adminUsersDistribution = Integer.parseInt(vars.get("admin_users_distribution_per_admin_pool")); + +if (adminUsersDistribution == 1) { + adminUser = adminUserList.poll(); +} else { + if (!adminUserListIterator.hasNext()) { + adminUserListIterator = adminUserList.descendingIterator(); + } + + adminUser = adminUserListIterator.next(); +} + if (adminUser == null) { SampleResult.setResponseMessage("adminUser list is empty"); SampleResult.setResponseData("adminUser list is empty","UTF-8"); @@ -27745,11 +28720,11 @@ vars.put("admin_user", adminUser); </elementProp> <stringProp name="HTTPSampler.domain"/> <stringProp name="HTTPSampler.port"/> - <stringProp name="HTTPSampler.connect_timeout"/> - <stringProp name="HTTPSampler.response_timeout"/> + <stringProp name="HTTPSampler.connect_timeout">60000</stringProp> + <stringProp name="HTTPSampler.response_timeout">200000</stringProp> <stringProp name="HTTPSampler.protocol">${request_protocol}</stringProp> <stringProp name="HTTPSampler.contentEncoding"/> - <stringProp name="HTTPSampler.path">${base_path}${admin_path}</stringProp> + <stringProp name="HTTPSampler.path">${base_path}${admin_path}/admin/</stringProp> <stringProp name="HTTPSampler.method">GET</stringProp> <boolProp name="HTTPSampler.follow_redirects">true</boolProp> <boolProp name="HTTPSampler.auto_redirects">false</boolProp> @@ -27826,8 +28801,8 @@ vars.put("admin_user", adminUser); </elementProp> <stringProp name="HTTPSampler.domain"/> <stringProp name="HTTPSampler.port"/> - <stringProp name="HTTPSampler.connect_timeout"/> - <stringProp name="HTTPSampler.response_timeout"/> + <stringProp name="HTTPSampler.connect_timeout">60000</stringProp> + <stringProp name="HTTPSampler.response_timeout">200000</stringProp> <stringProp name="HTTPSampler.protocol">${request_protocol}</stringProp> <stringProp name="HTTPSampler.contentEncoding"/> <stringProp name="HTTPSampler.path">${base_path}${admin_path}/admin/dashboard/</stringProp> @@ -27876,8 +28851,8 @@ vars.put("adminImportFilePath", filepath); </stringProp> </elementProp> <stringProp name="HTTPSampler.domain"/> <stringProp name="HTTPSampler.port"/> - <stringProp name="HTTPSampler.connect_timeout"/> - <stringProp name="HTTPSampler.response_timeout"/> + <stringProp name="HTTPSampler.connect_timeout">60000</stringProp> + <stringProp name="HTTPSampler.response_timeout">200000</stringProp> <stringProp name="HTTPSampler.protocol">${request_protocol}</stringProp> <stringProp name="HTTPSampler.contentEncoding"/> <stringProp name="HTTPSampler.path">${base_path}${admin_path}/admin/import/</stringProp> @@ -27958,8 +28933,8 @@ vars.put("adminImportFilePath", filepath); </stringProp> </elementProp> <stringProp name="HTTPSampler.domain"/> <stringProp name="HTTPSampler.port"/> - <stringProp name="HTTPSampler.connect_timeout"/> - <stringProp name="HTTPSampler.response_timeout"/> + <stringProp name="HTTPSampler.connect_timeout">60000</stringProp> + <stringProp name="HTTPSampler.response_timeout">200000</stringProp> <stringProp name="HTTPSampler.protocol">${request_protocol}</stringProp> <stringProp name="HTTPSampler.contentEncoding"/> <stringProp name="HTTPSampler.path">${base_path}${admin_path}/admin/import/validate</stringProp> @@ -28054,8 +29029,8 @@ vars.put("adminImportFilePath", filepath); </stringProp> </elementProp> <stringProp name="HTTPSampler.domain"/> <stringProp name="HTTPSampler.port"/> - <stringProp name="HTTPSampler.connect_timeout"/> - <stringProp name="HTTPSampler.response_timeout"/> + <stringProp name="HTTPSampler.connect_timeout">60000</stringProp> + <stringProp name="HTTPSampler.response_timeout">200000</stringProp> <stringProp name="HTTPSampler.protocol">${request_protocol}</stringProp> <stringProp name="HTTPSampler.contentEncoding"/> <stringProp name="HTTPSampler.path">${base_path}${admin_path}/admin/import/start</stringProp> @@ -28096,8 +29071,8 @@ vars.put("adminImportFilePath", filepath); </stringProp> </elementProp> <stringProp name="HTTPSampler.domain"/> <stringProp name="HTTPSampler.port"/> - <stringProp name="HTTPSampler.connect_timeout"/> - <stringProp name="HTTPSampler.response_timeout"/> + <stringProp name="HTTPSampler.connect_timeout">60000</stringProp> + <stringProp name="HTTPSampler.response_timeout">200000</stringProp> <stringProp name="HTTPSampler.protocol">${request_protocol}</stringProp> <stringProp name="HTTPSampler.contentEncoding"/> <stringProp name="HTTPSampler.path">${base_path}${admin_path}/admin/auth/logout/</stringProp> @@ -28116,8 +29091,11 @@ vars.put("adminImportFilePath", filepath); </stringProp> <stringProp name="parameters"/> <stringProp name="filename"/> <stringProp name="script"> -adminUserList = props.get("adminUserList"); -adminUserList.add(vars.get("admin_user")); + adminUsersDistribution = Integer.parseInt(vars.get("admin_users_distribution_per_admin_pool")); + if (adminUsersDistribution == 1) { + adminUserList = props.get("adminUserList"); + adminUserList.add(vars.get("admin_user")); + } </stringProp> <stringProp name="TestPlan.comments">mpaf/tool/fragments/ce/common/return_admin_email_to_pool.jmx</stringProp></BeanShellPostProcessor> <hashTree/> @@ -28223,7 +29201,19 @@ if (testLabel <stringProp name="TestPlan.comments">mpaf/tool/fragments/ce/get_admin_email.jmx</stringProp> <stringProp name="BeanShellSampler.query"> adminUserList = props.get("adminUserList"); -adminUser = adminUserList.poll(); +adminUserListIterator = props.get("adminUserListIterator"); +adminUsersDistribution = Integer.parseInt(vars.get("admin_users_distribution_per_admin_pool")); + +if (adminUsersDistribution == 1) { + adminUser = adminUserList.poll(); +} else { + if (!adminUserListIterator.hasNext()) { + adminUserListIterator = adminUserList.descendingIterator(); + } + + adminUser = adminUserListIterator.next(); +} + if (adminUser == null) { SampleResult.setResponseMessage("adminUser list is empty"); SampleResult.setResponseData("adminUser list is empty","UTF-8"); @@ -28246,11 +29236,11 @@ vars.put("admin_user", adminUser); </elementProp> <stringProp name="HTTPSampler.domain"/> <stringProp name="HTTPSampler.port"/> - <stringProp name="HTTPSampler.connect_timeout"/> - <stringProp name="HTTPSampler.response_timeout"/> + <stringProp name="HTTPSampler.connect_timeout">60000</stringProp> + <stringProp name="HTTPSampler.response_timeout">200000</stringProp> <stringProp name="HTTPSampler.protocol">${request_protocol}</stringProp> <stringProp name="HTTPSampler.contentEncoding"/> - <stringProp name="HTTPSampler.path">${base_path}${admin_path}</stringProp> + <stringProp name="HTTPSampler.path">${base_path}${admin_path}/admin/</stringProp> <stringProp name="HTTPSampler.method">GET</stringProp> <boolProp name="HTTPSampler.follow_redirects">true</boolProp> <boolProp name="HTTPSampler.auto_redirects">false</boolProp> @@ -28327,8 +29317,8 @@ vars.put("admin_user", adminUser); </elementProp> <stringProp name="HTTPSampler.domain"/> <stringProp name="HTTPSampler.port"/> - <stringProp name="HTTPSampler.connect_timeout"/> - <stringProp name="HTTPSampler.response_timeout"/> + <stringProp name="HTTPSampler.connect_timeout">60000</stringProp> + <stringProp name="HTTPSampler.response_timeout">200000</stringProp> <stringProp name="HTTPSampler.protocol">${request_protocol}</stringProp> <stringProp name="HTTPSampler.contentEncoding"/> <stringProp name="HTTPSampler.path">${base_path}${admin_path}/admin/dashboard/</stringProp> @@ -28365,8 +29355,8 @@ vars.put("admin_user", adminUser); </elementProp> <stringProp name="HTTPSampler.domain"/> <stringProp name="HTTPSampler.port"/> - <stringProp name="HTTPSampler.connect_timeout"/> - <stringProp name="HTTPSampler.response_timeout"/> + <stringProp name="HTTPSampler.connect_timeout">60000</stringProp> + <stringProp name="HTTPSampler.response_timeout">200000</stringProp> <stringProp name="HTTPSampler.protocol">${request_protocol}</stringProp> <stringProp name="HTTPSampler.contentEncoding"/> <stringProp name="HTTPSampler.path">${base_path}${admin_path}/admin/export/</stringProp> @@ -28950,8 +29940,8 @@ vars.put("admin_user", adminUser); </elementProp> <stringProp name="HTTPSampler.domain"/> <stringProp name="HTTPSampler.port"/> - <stringProp name="HTTPSampler.connect_timeout"/> - <stringProp name="HTTPSampler.response_timeout"/> + <stringProp name="HTTPSampler.connect_timeout">60000</stringProp> + <stringProp name="HTTPSampler.response_timeout">200000</stringProp> <stringProp name="HTTPSampler.protocol">${request_protocol}</stringProp> <stringProp name="HTTPSampler.contentEncoding"/> <stringProp name="HTTPSampler.path">${base_path}${admin_path}/admin/export/export/entity/catalog_product/file_format/csv</stringProp> @@ -28982,8 +29972,8 @@ vars.put("admin_user", adminUser); </elementProp> <stringProp name="HTTPSampler.domain"/> <stringProp name="HTTPSampler.port"/> - <stringProp name="HTTPSampler.connect_timeout"/> - <stringProp name="HTTPSampler.response_timeout"/> + <stringProp name="HTTPSampler.connect_timeout">60000</stringProp> + <stringProp name="HTTPSampler.response_timeout">200000</stringProp> <stringProp name="HTTPSampler.protocol">${request_protocol}</stringProp> <stringProp name="HTTPSampler.contentEncoding"/> <stringProp name="HTTPSampler.path">${base_path}${admin_path}/admin/auth/logout/</stringProp> @@ -29002,8 +29992,11 @@ vars.put("admin_user", adminUser); <stringProp name="parameters"/> <stringProp name="filename"/> <stringProp name="script"> -adminUserList = props.get("adminUserList"); -adminUserList.add(vars.get("admin_user")); + adminUsersDistribution = Integer.parseInt(vars.get("admin_users_distribution_per_admin_pool")); + if (adminUsersDistribution == 1) { + adminUserList = props.get("adminUserList"); + adminUserList.add(vars.get("admin_user")); + } </stringProp> <stringProp name="TestPlan.comments">mpaf/tool/fragments/ce/common/return_admin_email_to_pool.jmx</stringProp></BeanShellPostProcessor> <hashTree/> @@ -29109,7 +30102,19 @@ if (testLabel <stringProp name="TestPlan.comments">mpaf/tool/fragments/ce/get_admin_email.jmx</stringProp> <stringProp name="BeanShellSampler.query"> adminUserList = props.get("adminUserList"); -adminUser = adminUserList.poll(); +adminUserListIterator = props.get("adminUserListIterator"); +adminUsersDistribution = Integer.parseInt(vars.get("admin_users_distribution_per_admin_pool")); + +if (adminUsersDistribution == 1) { + adminUser = adminUserList.poll(); +} else { + if (!adminUserListIterator.hasNext()) { + adminUserListIterator = adminUserList.descendingIterator(); + } + + adminUser = adminUserListIterator.next(); +} + if (adminUser == null) { SampleResult.setResponseMessage("adminUser list is empty"); SampleResult.setResponseData("adminUser list is empty","UTF-8"); @@ -29132,11 +30137,11 @@ vars.put("admin_user", adminUser); </elementProp> <stringProp name="HTTPSampler.domain"/> <stringProp name="HTTPSampler.port"/> - <stringProp name="HTTPSampler.connect_timeout"/> - <stringProp name="HTTPSampler.response_timeout"/> + <stringProp name="HTTPSampler.connect_timeout">60000</stringProp> + <stringProp name="HTTPSampler.response_timeout">200000</stringProp> <stringProp name="HTTPSampler.protocol">${request_protocol}</stringProp> <stringProp name="HTTPSampler.contentEncoding"/> - <stringProp name="HTTPSampler.path">${base_path}${admin_path}</stringProp> + <stringProp name="HTTPSampler.path">${base_path}${admin_path}/admin/</stringProp> <stringProp name="HTTPSampler.method">GET</stringProp> <boolProp name="HTTPSampler.follow_redirects">true</boolProp> <boolProp name="HTTPSampler.auto_redirects">false</boolProp> @@ -29213,8 +30218,8 @@ vars.put("admin_user", adminUser); </elementProp> <stringProp name="HTTPSampler.domain"/> <stringProp name="HTTPSampler.port"/> - <stringProp name="HTTPSampler.connect_timeout"/> - <stringProp name="HTTPSampler.response_timeout"/> + <stringProp name="HTTPSampler.connect_timeout">60000</stringProp> + <stringProp name="HTTPSampler.response_timeout">200000</stringProp> <stringProp name="HTTPSampler.protocol">${request_protocol}</stringProp> <stringProp name="HTTPSampler.contentEncoding"/> <stringProp name="HTTPSampler.path">${base_path}${admin_path}/admin/dashboard/</stringProp> @@ -29251,8 +30256,8 @@ vars.put("admin_user", adminUser); </elementProp> <stringProp name="HTTPSampler.domain"/> <stringProp name="HTTPSampler.port"/> - <stringProp name="HTTPSampler.connect_timeout"/> - <stringProp name="HTTPSampler.response_timeout"/> + <stringProp name="HTTPSampler.connect_timeout">60000</stringProp> + <stringProp name="HTTPSampler.response_timeout">200000</stringProp> <stringProp name="HTTPSampler.protocol">${request_protocol}</stringProp> <stringProp name="HTTPSampler.contentEncoding"/> <stringProp name="HTTPSampler.path">${base_path}${admin_path}/admin/export/</stringProp> @@ -29491,8 +30496,8 @@ vars.put("admin_user", adminUser); </elementProp> <stringProp name="HTTPSampler.domain"/> <stringProp name="HTTPSampler.port"/> - <stringProp name="HTTPSampler.connect_timeout"/> - <stringProp name="HTTPSampler.response_timeout"/> + <stringProp name="HTTPSampler.connect_timeout">60000</stringProp> + <stringProp name="HTTPSampler.response_timeout">200000</stringProp> <stringProp name="HTTPSampler.protocol">${request_protocol}</stringProp> <stringProp name="HTTPSampler.contentEncoding"/> <stringProp name="HTTPSampler.path">${base_path}${admin_path}/admin/export/export/entity/customer/file_format/csv</stringProp> @@ -29523,8 +30528,8 @@ vars.put("admin_user", adminUser); </elementProp> <stringProp name="HTTPSampler.domain"/> <stringProp name="HTTPSampler.port"/> - <stringProp name="HTTPSampler.connect_timeout"/> - <stringProp name="HTTPSampler.response_timeout"/> + <stringProp name="HTTPSampler.connect_timeout">60000</stringProp> + <stringProp name="HTTPSampler.response_timeout">200000</stringProp> <stringProp name="HTTPSampler.protocol">${request_protocol}</stringProp> <stringProp name="HTTPSampler.contentEncoding"/> <stringProp name="HTTPSampler.path">${base_path}${admin_path}/admin/auth/logout/</stringProp> @@ -29543,8 +30548,11 @@ vars.put("admin_user", adminUser); <stringProp name="parameters"/> <stringProp name="filename"/> <stringProp name="script"> -adminUserList = props.get("adminUserList"); -adminUserList.add(vars.get("admin_user")); + adminUsersDistribution = Integer.parseInt(vars.get("admin_users_distribution_per_admin_pool")); + if (adminUsersDistribution == 1) { + adminUserList = props.get("adminUserList"); + adminUserList.add(vars.get("admin_user")); + } </stringProp> <stringProp name="TestPlan.comments">mpaf/tool/fragments/ce/common/return_admin_email_to_pool.jmx</stringProp></BeanShellPostProcessor> <hashTree/> @@ -29610,8 +30618,8 @@ if (testLabel </elementProp> <stringProp name="HTTPSampler.domain"/> <stringProp name="HTTPSampler.port"/> - <stringProp name="HTTPSampler.connect_timeout"/> - <stringProp name="HTTPSampler.response_timeout"/> + <stringProp name="HTTPSampler.connect_timeout">60000</stringProp> + <stringProp name="HTTPSampler.response_timeout">200000</stringProp> <stringProp name="HTTPSampler.protocol">${request_protocol}</stringProp> <stringProp name="HTTPSampler.contentEncoding"/> <stringProp name="HTTPSampler.path">${base_path}rest/V1/integration/admin/token</stringProp> @@ -29743,8 +30751,8 @@ if (testLabel </elementProp> <stringProp name="HTTPSampler.domain"/> <stringProp name="HTTPSampler.port"/> - <stringProp name="HTTPSampler.connect_timeout"/> - <stringProp name="HTTPSampler.response_timeout"/> + <stringProp name="HTTPSampler.connect_timeout">60000</stringProp> + <stringProp name="HTTPSampler.response_timeout">200000</stringProp> <stringProp name="HTTPSampler.protocol">${request_protocol}</stringProp> <stringProp name="HTTPSampler.contentEncoding"/> <stringProp name="HTTPSampler.path">${base_path}rest/default/V1/orders</stringProp> @@ -29779,8 +30787,8 @@ if (testLabel </elementProp> <stringProp name="HTTPSampler.domain"/> <stringProp name="HTTPSampler.port"/> - <stringProp name="HTTPSampler.connect_timeout"/> - <stringProp name="HTTPSampler.response_timeout"/> + <stringProp name="HTTPSampler.connect_timeout">60000</stringProp> + <stringProp name="HTTPSampler.response_timeout">200000</stringProp> <stringProp name="HTTPSampler.protocol">${request_protocol}</stringProp> <stringProp name="HTTPSampler.contentEncoding"/> <stringProp name="HTTPSampler.path">${base_path}rest/default/V1/order/${order_id}/invoice</stringProp> @@ -29810,8 +30818,8 @@ if (testLabel </elementProp> <stringProp name="HTTPSampler.domain"/> <stringProp name="HTTPSampler.port"/> - <stringProp name="HTTPSampler.connect_timeout"/> - <stringProp name="HTTPSampler.response_timeout"/> + <stringProp name="HTTPSampler.connect_timeout">60000</stringProp> + <stringProp name="HTTPSampler.response_timeout">200000</stringProp> <stringProp name="HTTPSampler.protocol">${request_protocol}</stringProp> <stringProp name="HTTPSampler.contentEncoding"/> <stringProp name="HTTPSampler.path">${base_path}rest/default/V1/order/${order_id}/ship</stringProp> @@ -29888,8 +30896,8 @@ if (testLabel </elementProp> <stringProp name="HTTPSampler.domain"/> <stringProp name="HTTPSampler.port"/> - <stringProp name="HTTPSampler.connect_timeout"/> - <stringProp name="HTTPSampler.response_timeout"/> + <stringProp name="HTTPSampler.connect_timeout">60000</stringProp> + <stringProp name="HTTPSampler.response_timeout">200000</stringProp> <stringProp name="HTTPSampler.protocol">${request_protocol}</stringProp> <stringProp name="HTTPSampler.contentEncoding"/> <stringProp name="HTTPSampler.path">${base_path}rest/default/V1/products/attribute-sets/</stringProp> @@ -29941,8 +30949,8 @@ if (testLabel </elementProp> <stringProp name="HTTPSampler.domain"/> <stringProp name="HTTPSampler.port"/> - <stringProp name="HTTPSampler.connect_timeout"/> - <stringProp name="HTTPSampler.response_timeout"/> + <stringProp name="HTTPSampler.connect_timeout">60000</stringProp> + <stringProp name="HTTPSampler.response_timeout">200000</stringProp> <stringProp name="HTTPSampler.protocol">${request_protocol}</stringProp> <stringProp name="HTTPSampler.contentEncoding"/> <stringProp name="HTTPSampler.path">${base_path}rest/default/V1/products/attribute-sets/groups</stringProp> @@ -30002,8 +31010,8 @@ if (testLabel </elementProp> <stringProp name="HTTPSampler.domain"/> <stringProp name="HTTPSampler.port"/> - <stringProp name="HTTPSampler.connect_timeout"/> - <stringProp name="HTTPSampler.response_timeout"/> + <stringProp name="HTTPSampler.connect_timeout">60000</stringProp> + <stringProp name="HTTPSampler.response_timeout">200000</stringProp> <stringProp name="HTTPSampler.protocol">${request_protocol}</stringProp> <stringProp name="HTTPSampler.contentEncoding"/> <stringProp name="HTTPSampler.path">${base_path}rest/default/V1/products/attributes/</stringProp> @@ -30074,8 +31082,8 @@ if (testLabel </elementProp> <stringProp name="HTTPSampler.domain"/> <stringProp name="HTTPSampler.port"/> - <stringProp name="HTTPSampler.connect_timeout"/> - <stringProp name="HTTPSampler.response_timeout"/> + <stringProp name="HTTPSampler.connect_timeout">60000</stringProp> + <stringProp name="HTTPSampler.response_timeout">200000</stringProp> <stringProp name="HTTPSampler.protocol">${request_protocol}</stringProp> <stringProp name="HTTPSampler.contentEncoding"/> <stringProp name="HTTPSampler.path">${base_path}rest/default/V1/products/attribute-sets/attributes</stringProp> @@ -30200,7 +31208,19 @@ if (testLabel <stringProp name="TestPlan.comments">mpaf/tool/fragments/ce/get_admin_email.jmx</stringProp> <stringProp name="BeanShellSampler.query"> adminUserList = props.get("adminUserList"); -adminUser = adminUserList.poll(); +adminUserListIterator = props.get("adminUserListIterator"); +adminUsersDistribution = Integer.parseInt(vars.get("admin_users_distribution_per_admin_pool")); + +if (adminUsersDistribution == 1) { + adminUser = adminUserList.poll(); +} else { + if (!adminUserListIterator.hasNext()) { + adminUserListIterator = adminUserList.descendingIterator(); + } + + adminUser = adminUserListIterator.next(); +} + if (adminUser == null) { SampleResult.setResponseMessage("adminUser list is empty"); SampleResult.setResponseData("adminUser list is empty","UTF-8"); @@ -30223,11 +31243,11 @@ vars.put("admin_user", adminUser); </elementProp> <stringProp name="HTTPSampler.domain"/> <stringProp name="HTTPSampler.port"/> - <stringProp name="HTTPSampler.connect_timeout"/> - <stringProp name="HTTPSampler.response_timeout"/> + <stringProp name="HTTPSampler.connect_timeout">60000</stringProp> + <stringProp name="HTTPSampler.response_timeout">200000</stringProp> <stringProp name="HTTPSampler.protocol">${request_protocol}</stringProp> <stringProp name="HTTPSampler.contentEncoding"/> - <stringProp name="HTTPSampler.path">${base_path}${admin_path}</stringProp> + <stringProp name="HTTPSampler.path">${base_path}${admin_path}/admin/</stringProp> <stringProp name="HTTPSampler.method">GET</stringProp> <boolProp name="HTTPSampler.follow_redirects">true</boolProp> <boolProp name="HTTPSampler.auto_redirects">false</boolProp> @@ -30304,8 +31324,8 @@ vars.put("admin_user", adminUser); </elementProp> <stringProp name="HTTPSampler.domain"/> <stringProp name="HTTPSampler.port"/> - <stringProp name="HTTPSampler.connect_timeout"/> - <stringProp name="HTTPSampler.response_timeout"/> + <stringProp name="HTTPSampler.connect_timeout">60000</stringProp> + <stringProp name="HTTPSampler.response_timeout">200000</stringProp> <stringProp name="HTTPSampler.protocol">${request_protocol}</stringProp> <stringProp name="HTTPSampler.contentEncoding"/> <stringProp name="HTTPSampler.path">${base_path}${admin_path}/admin/dashboard/</stringProp> @@ -30332,191 +31352,6 @@ vars.put("admin_user", adminUser); </hashTree> </hashTree> - <OnceOnlyController guiclass="OnceOnlyControllerGui" testclass="OnceOnlyController" testname="Once Only Controller" enabled="true"> - <stringProp name="TestPlan.comments">mpaf/tool/fragments/ce/once_only_controller.jmx</stringProp> -</OnceOnlyController> - <hashTree> - <GenericController guiclass="LogicControllerGui" testclass="GenericController" testname="SetUp - Admin Category Management" enabled="true"> - <stringProp name="TestPlan.comments">mpaf/tool/fragments/ce/setup/setup_admin_category_management.jmx</stringProp> -</GenericController> - <hashTree> - <BeanShellSampler guiclass="BeanShellSamplerGui" testclass="BeanShellSampler" testname="SetUp - BeanShell Sampler: Clear Admin Category Management properties" enabled="true"> - <stringProp name="BeanShellSampler.query">props.remove("admin_category_ids_list");</stringProp> - <stringProp name="BeanShellSampler.filename"/> - <stringProp name="BeanShellSampler.parameters"/> - <boolProp name="BeanShellSampler.resetInterpreter">false</boolProp> - </BeanShellSampler> - <hashTree/> - <GenericController guiclass="LogicControllerGui" testclass="GenericController" testname="Get categories of last level" enabled="true"/> - <hashTree> - <HeaderManager guiclass="HeaderPanel" testclass="HeaderManager" testname="HTTP Header Manager" enabled="true"> - <collectionProp name="HeaderManager.headers"> - <elementProp name="" elementType="Header"> - <stringProp name="Header.name">Content-Type</stringProp> - <stringProp name="Header.value">application/json</stringProp> - </elementProp> - <elementProp name="" elementType="Header"> - <stringProp name="Header.name">Accept</stringProp> - <stringProp name="Header.value">*/*</stringProp> - </elementProp> - </collectionProp> - </HeaderManager> - <hashTree/> - <HTTPSamplerProxy guiclass="HttpTestSampleGui" testclass="HTTPSamplerProxy" testname="SetUp - Admin Token Retrieval" enabled="true"> - <boolProp name="HTTPSampler.postBodyRaw">true</boolProp> - <elementProp name="HTTPsampler.Arguments" elementType="Arguments"> - <collectionProp name="Arguments.arguments"> - <elementProp name="" elementType="HTTPArgument"> - <boolProp name="HTTPArgument.always_encode">false</boolProp> - <stringProp name="Argument.value">{"username":"${admin_user}","password":"${admin_password}"}</stringProp> - <stringProp name="Argument.metadata">=</stringProp> - </elementProp> - </collectionProp> - </elementProp> - <stringProp name="HTTPSampler.domain"/> - <stringProp name="HTTPSampler.port"/> - <stringProp name="HTTPSampler.connect_timeout"/> - <stringProp name="HTTPSampler.response_timeout"/> - <stringProp name="HTTPSampler.protocol">${request_protocol}</stringProp> - <stringProp name="HTTPSampler.contentEncoding"/> - <stringProp name="HTTPSampler.path">${base_path}rest/V1/integration/admin/token</stringProp> - <stringProp name="HTTPSampler.method">POST</stringProp> - <boolProp name="HTTPSampler.follow_redirects">true</boolProp> - <boolProp name="HTTPSampler.auto_redirects">false</boolProp> - <boolProp name="HTTPSampler.use_keepalive">true</boolProp> - <boolProp name="HTTPSampler.DO_MULTIPART_POST">false</boolProp> - <boolProp name="HTTPSampler.monitor">false</boolProp> - <stringProp name="HTTPSampler.embedded_url_re"/> - </HTTPSamplerProxy> - <hashTree> - <com.atlantbh.jmeter.plugins.jsonutils.jsonpathextractor.JSONPathExtractor guiclass="com.atlantbh.jmeter.plugins.jsonutils.jsonpathextractor.gui.JSONPathExtractorGui" testclass="com.atlantbh.jmeter.plugins.jsonutils.jsonpathextractor.JSONPathExtractor" testname="jp@gc - JSON Path Extractor" enabled="true"> - <stringProp name="VAR">admin_token</stringProp> - <stringProp name="JSONPATH">$</stringProp> - <stringProp name="DEFAULT"/> - <stringProp name="VARIABLE"/> - <stringProp name="SUBJECT">BODY</stringProp> - </com.atlantbh.jmeter.plugins.jsonutils.jsonpathextractor.JSONPathExtractor> - <hashTree/> - <ResponseAssertion guiclass="AssertionGui" testclass="ResponseAssertion" testname="Assert token not null" enabled="true"> - <collectionProp name="Asserion.test_strings"> - <stringProp name="484395188">^[a-z0-9-]+$</stringProp> - </collectionProp> - <stringProp name="Assertion.test_field">Assertion.response_data</stringProp> - <boolProp name="Assertion.assume_success">false</boolProp> - <intProp name="Assertion.test_type">1</intProp> - <stringProp name="Assertion.scope">variable</stringProp> - <stringProp name="Scope.variable">admin_token</stringProp> - </ResponseAssertion> - <hashTree/> - </hashTree> - <HeaderManager guiclass="HeaderPanel" testclass="HeaderManager" testname="HTTP Header Manager" enabled="true"> - <collectionProp name="HeaderManager.headers"> - <elementProp name="" elementType="Header"> - <stringProp name="Header.name">Authorization</stringProp> - <stringProp name="Header.value">Bearer ${admin_token}</stringProp> - </elementProp> - </collectionProp> - </HeaderManager> - <hashTree/> - <HTTPSamplerProxy guiclass="HttpTestSampleGui" testclass="HTTPSamplerProxy" testname="SetUp - API Get categories" enabled="true"> - <elementProp name="HTTPsampler.Arguments" elementType="Arguments" guiclass="HTTPArgumentsPanel" testclass="Arguments" enabled="true"> - <collectionProp name="Arguments.arguments"> - <elementProp name="searchCriteria[filterGroups][0][filters][0][field]" elementType="HTTPArgument"> - <boolProp name="HTTPArgument.always_encode">true</boolProp> - <stringProp name="Argument.value">children_count</stringProp> - <stringProp name="Argument.metadata">=</stringProp> - <boolProp name="HTTPArgument.use_equals">true</boolProp> - <stringProp name="Argument.name">searchCriteria[filterGroups][0][filters][0][field]</stringProp> - </elementProp> - <elementProp name="searchCriteria[filterGroups][0][filters][0][value]" elementType="HTTPArgument"> - <boolProp name="HTTPArgument.always_encode">true</boolProp> - <stringProp name="Argument.value">0</stringProp> - <stringProp name="Argument.metadata">=</stringProp> - <boolProp name="HTTPArgument.use_equals">true</boolProp> - <stringProp name="Argument.name">searchCriteria[filterGroups][0][filters][0][value]</stringProp> - </elementProp> - <elementProp name="searchCriteria[filterGroups][1][filters][0][field]" elementType="HTTPArgument"> - <boolProp name="HTTPArgument.always_encode">true</boolProp> - <stringProp name="Argument.value">level</stringProp> - <stringProp name="Argument.metadata">=</stringProp> - <boolProp name="HTTPArgument.use_equals">true</boolProp> - <stringProp name="Argument.name">searchCriteria[filterGroups][1][filters][0][field]</stringProp> - </elementProp> - <elementProp name="searchCriteria[filterGroups][1][filters][0][value]" elementType="HTTPArgument"> - <boolProp name="HTTPArgument.always_encode">true</boolProp> - <stringProp name="Argument.value">2</stringProp> - <stringProp name="Argument.metadata">=</stringProp> - <boolProp name="HTTPArgument.use_equals">true</boolProp> - <stringProp name="Argument.name">searchCriteria[filterGroups][1][filters][0][value]</stringProp> - </elementProp> - <elementProp name="searchCriteria[filterGroups][1][filters][0][conditionType]" elementType="HTTPArgument"> - <boolProp name="HTTPArgument.always_encode">true</boolProp> - <stringProp name="Argument.value">gt</stringProp> - <stringProp name="Argument.metadata">=</stringProp> - <boolProp name="HTTPArgument.use_equals">true</boolProp> - <stringProp name="Argument.name">searchCriteria[filterGroups][1][filters][0][conditionType]</stringProp> - </elementProp> - <elementProp name="searchCriteria[pageSize]" elementType="HTTPArgument"> - <boolProp name="HTTPArgument.always_encode">true</boolProp> - <stringProp name="Argument.value">${adminCategoryCount}</stringProp> - <stringProp name="Argument.metadata">=</stringProp> - <boolProp name="HTTPArgument.use_equals">true</boolProp> - <stringProp name="Argument.name">searchCriteria[pageSize]</stringProp> - </elementProp> - </collectionProp> - </elementProp> - <stringProp name="HTTPSampler.domain"/> - <stringProp name="HTTPSampler.port"/> - <stringProp name="HTTPSampler.connect_timeout"/> - <stringProp name="HTTPSampler.response_timeout"/> - <stringProp name="HTTPSampler.protocol">${request_protocol}</stringProp> - <stringProp name="HTTPSampler.contentEncoding"/> - <stringProp name="HTTPSampler.path">${base_path}rest/default/V1/categories/list</stringProp> - <stringProp name="HTTPSampler.method">GET</stringProp> - <boolProp name="HTTPSampler.follow_redirects">true</boolProp> - <boolProp name="HTTPSampler.auto_redirects">false</boolProp> - <boolProp name="HTTPSampler.use_keepalive">true</boolProp> - <boolProp name="HTTPSampler.DO_MULTIPART_POST">false</boolProp> - <boolProp name="HTTPSampler.monitor">false</boolProp> - <stringProp name="HTTPSampler.embedded_url_re"/> - </HTTPSamplerProxy> - <hashTree> - <RegexExtractor guiclass="RegexExtractorGui" testclass="RegexExtractor" testname="Regular Expression Extractor" enabled="true"> - <stringProp name="RegexExtractor.useHeaders">false</stringProp> - <stringProp name="RegexExtractor.refname">category_list_id</stringProp> - <stringProp name="RegexExtractor.regex">\{\"id\":(\d+),</stringProp> - <stringProp name="RegexExtractor.template">$1$</stringProp> - <stringProp name="RegexExtractor.default"/> - <stringProp name="RegexExtractor.match_number">-1</stringProp> - </RegexExtractor> - <hashTree/> - </hashTree> - <ForeachController guiclass="ForeachControlPanel" testclass="ForeachController" testname="ForEach Category Id" enabled="true"> - <stringProp name="ForeachController.inputVal">category_list_id</stringProp> - <stringProp name="ForeachController.returnVal">category_id</stringProp> - <boolProp name="ForeachController.useSeparator">true</boolProp> - </ForeachController> - <hashTree> - <BeanShellSampler guiclass="BeanShellSamplerGui" testclass="BeanShellSampler" testname="Process categories ids" enabled="true"> - <stringProp name="BeanShellSampler.query">import java.util.ArrayList; - -adminCategoryIdsList = props.get("admin_category_ids_list"); -// If it is first iteration of cycle then recreate categories ids list -if (adminCategoryIdsList == null) { - adminCategoryIdsList = new ArrayList(); - props.put("admin_category_ids_list", adminCategoryIdsList); -} -adminCategoryIdsList.add(vars.get("category_id"));</stringProp> - <stringProp name="BeanShellSampler.filename"/> - <stringProp name="BeanShellSampler.parameters"/> - <boolProp name="BeanShellSampler.resetInterpreter">false</boolProp> - </BeanShellSampler> - <hashTree/> - </hashTree> - </hashTree> - </hashTree> - </hashTree> - <GenericController guiclass="LogicControllerGui" testclass="GenericController" testname="Simple Controller" enabled="true"> <stringProp name="TestPlan.comments">mpaf/tool/fragments/ce/simple_controller.jmx</stringProp> </GenericController> @@ -30548,13 +31383,13 @@ function getNextProductNumber(i) { } var productsVariationsSize = 5, - productsSize = props.get("simple_products_list").size(); + productsSize = props.get("simple_products_list_for_edit").size(); for (i = 1; i<= productsVariationsSize; i++) { var productVariablePrefix = "simple_product_" + i + "_"; number = getNextProductNumber(i); - simpleList = props.get("simple_products_list").get(number); + simpleList = props.get("simple_products_list_for_edit").get(number); vars.put(productVariablePrefix + "url_key", simpleList.get("url_key")); vars.put(productVariablePrefix + "id", simpleList.get("id")); @@ -30575,8 +31410,8 @@ vars.put("new_parent_category_id", props.get("admin_category_ids_list").get(cate </elementProp> <stringProp name="HTTPSampler.domain"/> <stringProp name="HTTPSampler.port"/> - <stringProp name="HTTPSampler.connect_timeout"/> - <stringProp name="HTTPSampler.response_timeout"/> + <stringProp name="HTTPSampler.connect_timeout">60000</stringProp> + <stringProp name="HTTPSampler.response_timeout">200000</stringProp> <stringProp name="HTTPSampler.protocol">${request_protocol}</stringProp> <stringProp name="HTTPSampler.contentEncoding"/> <stringProp name="HTTPSampler.path">${base_path}${admin_path}/catalog/category/</stringProp> @@ -30626,8 +31461,8 @@ vars.put("new_parent_category_id", props.get("admin_category_ids_list").get(cate </elementProp> <stringProp name="HTTPSampler.domain"/> <stringProp name="HTTPSampler.port"/> - <stringProp name="HTTPSampler.connect_timeout"/> - <stringProp name="HTTPSampler.response_timeout"/> + <stringProp name="HTTPSampler.connect_timeout">60000</stringProp> + <stringProp name="HTTPSampler.response_timeout">200000</stringProp> <stringProp name="HTTPSampler.protocol">${request_protocol}</stringProp> <stringProp name="HTTPSampler.contentEncoding"/> <stringProp name="HTTPSampler.path">${base_path}${admin_path}/catalog/category/edit/id/${parent_category_id}/</stringProp> @@ -30668,8 +31503,8 @@ vars.put("new_parent_category_id", props.get("admin_category_ids_list").get(cate </elementProp> <stringProp name="HTTPSampler.domain"/> <stringProp name="HTTPSampler.port"/> - <stringProp name="HTTPSampler.connect_timeout"/> - <stringProp name="HTTPSampler.response_timeout"/> + <stringProp name="HTTPSampler.connect_timeout">60000</stringProp> + <stringProp name="HTTPSampler.response_timeout">200000</stringProp> <stringProp name="HTTPSampler.protocol">${request_protocol}</stringProp> <stringProp name="HTTPSampler.contentEncoding"/> <stringProp name="HTTPSampler.path">${base_path}${admin_path}/catalog/category/add/store/0/parent/${parent_category_id}</stringProp> @@ -30874,8 +31709,8 @@ vars.put("new_parent_category_id", props.get("admin_category_ids_list").get(cate </elementProp> <stringProp name="HTTPSampler.domain"/> <stringProp name="HTTPSampler.port"/> - <stringProp name="HTTPSampler.connect_timeout"/> - <stringProp name="HTTPSampler.response_timeout"/> + <stringProp name="HTTPSampler.connect_timeout">60000</stringProp> + <stringProp name="HTTPSampler.response_timeout">200000</stringProp> <stringProp name="HTTPSampler.protocol">${request_protocol}</stringProp> <stringProp name="HTTPSampler.contentEncoding"/> <stringProp name="HTTPSampler.path">${base_path}${admin_path}/catalog/category/save/</stringProp> @@ -30915,8 +31750,8 @@ vars.put("new_parent_category_id", props.get("admin_category_ids_list").get(cate </elementProp> <stringProp name="HTTPSampler.domain"/> <stringProp name="HTTPSampler.port"/> - <stringProp name="HTTPSampler.connect_timeout"/> - <stringProp name="HTTPSampler.response_timeout"/> + <stringProp name="HTTPSampler.connect_timeout">60000</stringProp> + <stringProp name="HTTPSampler.response_timeout">200000</stringProp> <stringProp name="HTTPSampler.protocol">${request_protocol}</stringProp> <stringProp name="HTTPSampler.contentEncoding"/> <stringProp name="HTTPSampler.path">${base_path}${admin_path}/catalog/category/edit/id/${admin_category_id}/</stringProp> @@ -31220,8 +32055,8 @@ vars.put("new_parent_category_id", props.get("admin_category_ids_list").get(cate </elementProp> <stringProp name="HTTPSampler.domain"/> <stringProp name="HTTPSampler.port"/> - <stringProp name="HTTPSampler.connect_timeout"/> - <stringProp name="HTTPSampler.response_timeout"/> + <stringProp name="HTTPSampler.connect_timeout">60000</stringProp> + <stringProp name="HTTPSampler.response_timeout">200000</stringProp> <stringProp name="HTTPSampler.protocol">${request_protocol}</stringProp> <stringProp name="HTTPSampler.contentEncoding"/> <stringProp name="HTTPSampler.path">${base_path}${admin_path}/catalog/category/move/</stringProp> @@ -31240,8 +32075,8 @@ vars.put("new_parent_category_id", props.get("admin_category_ids_list").get(cate </elementProp> <stringProp name="HTTPSampler.domain"/> <stringProp name="HTTPSampler.port"/> - <stringProp name="HTTPSampler.connect_timeout"/> - <stringProp name="HTTPSampler.response_timeout"/> + <stringProp name="HTTPSampler.connect_timeout">60000</stringProp> + <stringProp name="HTTPSampler.response_timeout">200000</stringProp> <stringProp name="HTTPSampler.protocol">${request_protocol}</stringProp> <stringProp name="HTTPSampler.contentEncoding"/> <stringProp name="HTTPSampler.path">${base_path}${admin_path}/catalog/category/delete/id/${admin_category_id}/</stringProp> @@ -31279,8 +32114,8 @@ vars.put("new_parent_category_id", props.get("admin_category_ids_list").get(cate </elementProp> <stringProp name="HTTPSampler.domain"/> <stringProp name="HTTPSampler.port"/> - <stringProp name="HTTPSampler.connect_timeout"/> - <stringProp name="HTTPSampler.response_timeout"/> + <stringProp name="HTTPSampler.connect_timeout">60000</stringProp> + <stringProp name="HTTPSampler.response_timeout">200000</stringProp> <stringProp name="HTTPSampler.protocol">${request_protocol}</stringProp> <stringProp name="HTTPSampler.contentEncoding"/> <stringProp name="HTTPSampler.path">${base_path}${admin_path}/admin/auth/logout/</stringProp> @@ -31299,8 +32134,11 @@ vars.put("new_parent_category_id", props.get("admin_category_ids_list").get(cate <stringProp name="parameters"/> <stringProp name="filename"/> <stringProp name="script"> -adminUserList = props.get("adminUserList"); -adminUserList.add(vars.get("admin_user")); + adminUsersDistribution = Integer.parseInt(vars.get("admin_users_distribution_per_admin_pool")); + if (adminUsersDistribution == 1) { + adminUserList = props.get("adminUserList"); + adminUserList.add(vars.get("admin_user")); + } </stringProp> <stringProp name="TestPlan.comments">mpaf/tool/fragments/ce/common/return_admin_email_to_pool.jmx</stringProp></BeanShellPostProcessor> <hashTree/> @@ -31406,7 +32244,19 @@ if (testLabel <stringProp name="TestPlan.comments">mpaf/tool/fragments/ce/get_admin_email.jmx</stringProp> <stringProp name="BeanShellSampler.query"> adminUserList = props.get("adminUserList"); -adminUser = adminUserList.poll(); +adminUserListIterator = props.get("adminUserListIterator"); +adminUsersDistribution = Integer.parseInt(vars.get("admin_users_distribution_per_admin_pool")); + +if (adminUsersDistribution == 1) { + adminUser = adminUserList.poll(); +} else { + if (!adminUserListIterator.hasNext()) { + adminUserListIterator = adminUserList.descendingIterator(); + } + + adminUser = adminUserListIterator.next(); +} + if (adminUser == null) { SampleResult.setResponseMessage("adminUser list is empty"); SampleResult.setResponseData("adminUser list is empty","UTF-8"); @@ -31429,11 +32279,11 @@ vars.put("admin_user", adminUser); </elementProp> <stringProp name="HTTPSampler.domain"/> <stringProp name="HTTPSampler.port"/> - <stringProp name="HTTPSampler.connect_timeout"/> - <stringProp name="HTTPSampler.response_timeout"/> + <stringProp name="HTTPSampler.connect_timeout">60000</stringProp> + <stringProp name="HTTPSampler.response_timeout">200000</stringProp> <stringProp name="HTTPSampler.protocol">${request_protocol}</stringProp> <stringProp name="HTTPSampler.contentEncoding"/> - <stringProp name="HTTPSampler.path">${base_path}${admin_path}</stringProp> + <stringProp name="HTTPSampler.path">${base_path}${admin_path}/admin/</stringProp> <stringProp name="HTTPSampler.method">GET</stringProp> <boolProp name="HTTPSampler.follow_redirects">true</boolProp> <boolProp name="HTTPSampler.auto_redirects">false</boolProp> @@ -31510,8 +32360,8 @@ vars.put("admin_user", adminUser); </elementProp> <stringProp name="HTTPSampler.domain"/> <stringProp name="HTTPSampler.port"/> - <stringProp name="HTTPSampler.connect_timeout"/> - <stringProp name="HTTPSampler.response_timeout"/> + <stringProp name="HTTPSampler.connect_timeout">60000</stringProp> + <stringProp name="HTTPSampler.response_timeout">200000</stringProp> <stringProp name="HTTPSampler.protocol">${request_protocol}</stringProp> <stringProp name="HTTPSampler.contentEncoding"/> <stringProp name="HTTPSampler.path">${base_path}${admin_path}/admin/dashboard/</stringProp> @@ -31552,8 +32402,8 @@ vars.put("admin_user", adminUser); </elementProp> <stringProp name="HTTPSampler.domain"/> <stringProp name="HTTPSampler.port"/> - <stringProp name="HTTPSampler.connect_timeout"/> - <stringProp name="HTTPSampler.response_timeout"/> + <stringProp name="HTTPSampler.connect_timeout">60000</stringProp> + <stringProp name="HTTPSampler.response_timeout">200000</stringProp> <stringProp name="HTTPSampler.protocol">${request_protocol}</stringProp> <stringProp name="HTTPSampler.contentEncoding"/> <stringProp name="HTTPSampler.path">${base_path}${admin_path}/sales_rule/promo_quote/</stringProp> @@ -31572,8 +32422,8 @@ vars.put("admin_user", adminUser); </elementProp> <stringProp name="HTTPSampler.domain"/> <stringProp name="HTTPSampler.port"/> - <stringProp name="HTTPSampler.connect_timeout"/> - <stringProp name="HTTPSampler.response_timeout"/> + <stringProp name="HTTPSampler.connect_timeout">60000</stringProp> + <stringProp name="HTTPSampler.response_timeout">200000</stringProp> <stringProp name="HTTPSampler.protocol">${request_protocol}</stringProp> <stringProp name="HTTPSampler.contentEncoding"/> <stringProp name="HTTPSampler.path">${base_path}${admin_path}/sales_rule/promo_quote/new</stringProp> @@ -31622,8 +32472,8 @@ vars.put("admin_user", adminUser); </elementProp> <stringProp name="HTTPSampler.domain"/> <stringProp name="HTTPSampler.port"/> - <stringProp name="HTTPSampler.connect_timeout"/> - <stringProp name="HTTPSampler.response_timeout"/> + <stringProp name="HTTPSampler.connect_timeout">60000</stringProp> + <stringProp name="HTTPSampler.response_timeout">200000</stringProp> <stringProp name="HTTPSampler.protocol">${request_protocol}</stringProp> <stringProp name="HTTPSampler.contentEncoding"/> <stringProp name="HTTPSampler.path">${base_path}${admin_path}/sales_rule/promo_quote/newConditionHtml/form/sales_rule_formrule_conditions_fieldset_/form_namespace/sales_rule_form</stringProp> @@ -31909,8 +32759,8 @@ vars.put("admin_user", adminUser); </elementProp> <stringProp name="HTTPSampler.domain"/> <stringProp name="HTTPSampler.port"/> - <stringProp name="HTTPSampler.connect_timeout"/> - <stringProp name="HTTPSampler.response_timeout"/> + <stringProp name="HTTPSampler.connect_timeout">60000</stringProp> + <stringProp name="HTTPSampler.response_timeout">200000</stringProp> <stringProp name="HTTPSampler.protocol">${request_protocol}</stringProp> <stringProp name="HTTPSampler.contentEncoding"/> <stringProp name="HTTPSampler.path">${base_path}${admin_path}/sales_rule/promo_quote/save/</stringProp> @@ -31948,8 +32798,8 @@ vars.put("admin_user", adminUser); </elementProp> <stringProp name="HTTPSampler.domain"/> <stringProp name="HTTPSampler.port"/> - <stringProp name="HTTPSampler.connect_timeout"/> - <stringProp name="HTTPSampler.response_timeout"/> + <stringProp name="HTTPSampler.connect_timeout">60000</stringProp> + <stringProp name="HTTPSampler.response_timeout">200000</stringProp> <stringProp name="HTTPSampler.protocol">${request_protocol}</stringProp> <stringProp name="HTTPSampler.contentEncoding"/> <stringProp name="HTTPSampler.path">${base_path}${admin_path}/admin/auth/logout/</stringProp> @@ -31968,8 +32818,11 @@ vars.put("admin_user", adminUser); <stringProp name="parameters"/> <stringProp name="filename"/> <stringProp name="script"> -adminUserList = props.get("adminUserList"); -adminUserList.add(vars.get("admin_user")); + adminUsersDistribution = Integer.parseInt(vars.get("admin_users_distribution_per_admin_pool")); + if (adminUsersDistribution == 1) { + adminUserList = props.get("adminUserList"); + adminUserList.add(vars.get("admin_user")); + } </stringProp> <stringProp name="TestPlan.comments">mpaf/tool/fragments/ce/common/return_admin_email_to_pool.jmx</stringProp></BeanShellPostProcessor> <hashTree/> @@ -32075,7 +32928,19 @@ if (testLabel <stringProp name="TestPlan.comments">mpaf/tool/fragments/ce/get_admin_email.jmx</stringProp> <stringProp name="BeanShellSampler.query"> adminUserList = props.get("adminUserList"); -adminUser = adminUserList.poll(); +adminUserListIterator = props.get("adminUserListIterator"); +adminUsersDistribution = Integer.parseInt(vars.get("admin_users_distribution_per_admin_pool")); + +if (adminUsersDistribution == 1) { + adminUser = adminUserList.poll(); +} else { + if (!adminUserListIterator.hasNext()) { + adminUserListIterator = adminUserList.descendingIterator(); + } + + adminUser = adminUserListIterator.next(); +} + if (adminUser == null) { SampleResult.setResponseMessage("adminUser list is empty"); SampleResult.setResponseData("adminUser list is empty","UTF-8"); @@ -32098,11 +32963,11 @@ vars.put("admin_user", adminUser); </elementProp> <stringProp name="HTTPSampler.domain"/> <stringProp name="HTTPSampler.port"/> - <stringProp name="HTTPSampler.connect_timeout"/> - <stringProp name="HTTPSampler.response_timeout"/> + <stringProp name="HTTPSampler.connect_timeout">60000</stringProp> + <stringProp name="HTTPSampler.response_timeout">200000</stringProp> <stringProp name="HTTPSampler.protocol">${request_protocol}</stringProp> <stringProp name="HTTPSampler.contentEncoding"/> - <stringProp name="HTTPSampler.path">${base_path}${admin_path}</stringProp> + <stringProp name="HTTPSampler.path">${base_path}${admin_path}/admin/</stringProp> <stringProp name="HTTPSampler.method">GET</stringProp> <boolProp name="HTTPSampler.follow_redirects">true</boolProp> <boolProp name="HTTPSampler.auto_redirects">false</boolProp> @@ -32179,8 +33044,8 @@ vars.put("admin_user", adminUser); </elementProp> <stringProp name="HTTPSampler.domain"/> <stringProp name="HTTPSampler.port"/> - <stringProp name="HTTPSampler.connect_timeout"/> - <stringProp name="HTTPSampler.response_timeout"/> + <stringProp name="HTTPSampler.connect_timeout">60000</stringProp> + <stringProp name="HTTPSampler.response_timeout">200000</stringProp> <stringProp name="HTTPSampler.protocol">${request_protocol}</stringProp> <stringProp name="HTTPSampler.contentEncoding"/> <stringProp name="HTTPSampler.path">${base_path}${admin_path}/admin/dashboard/</stringProp> @@ -32221,8 +33086,8 @@ vars.put("admin_user", adminUser); </elementProp> <stringProp name="HTTPSampler.domain"/> <stringProp name="HTTPSampler.port"/> - <stringProp name="HTTPSampler.connect_timeout"/> - <stringProp name="HTTPSampler.response_timeout"/> + <stringProp name="HTTPSampler.connect_timeout">60000</stringProp> + <stringProp name="HTTPSampler.response_timeout">200000</stringProp> <stringProp name="HTTPSampler.protocol">${request_protocol}</stringProp> <stringProp name="HTTPSampler.contentEncoding"/> <stringProp name="HTTPSampler.path">${base_path}${admin_path}/customer/index</stringProp> @@ -32320,8 +33185,8 @@ vars.put("admin_user", adminUser); </elementProp> <stringProp name="HTTPSampler.domain"/> <stringProp name="HTTPSampler.port"/> - <stringProp name="HTTPSampler.connect_timeout"/> - <stringProp name="HTTPSampler.response_timeout"/> + <stringProp name="HTTPSampler.connect_timeout">60000</stringProp> + <stringProp name="HTTPSampler.response_timeout">200000</stringProp> <stringProp name="HTTPSampler.protocol">${request_protocol}</stringProp> <stringProp name="HTTPSampler.contentEncoding"/> <stringProp name="HTTPSampler.path">${base_path}${admin_path}/mui/index/render/</stringProp> @@ -32407,8 +33272,8 @@ vars.put("admin_user", adminUser); </elementProp> <stringProp name="HTTPSampler.domain"/> <stringProp name="HTTPSampler.port"/> - <stringProp name="HTTPSampler.connect_timeout"/> - <stringProp name="HTTPSampler.response_timeout"/> + <stringProp name="HTTPSampler.connect_timeout">60000</stringProp> + <stringProp name="HTTPSampler.response_timeout">200000</stringProp> <stringProp name="HTTPSampler.protocol">${request_protocol}</stringProp> <stringProp name="HTTPSampler.contentEncoding"/> <stringProp name="HTTPSampler.path">${base_path}${admin_path}/mui/index/render/</stringProp> @@ -32457,8 +33322,8 @@ vars.put("admin_user", adminUser); </elementProp> <stringProp name="HTTPSampler.domain"/> <stringProp name="HTTPSampler.port"/> - <stringProp name="HTTPSampler.connect_timeout"/> - <stringProp name="HTTPSampler.response_timeout"/> + <stringProp name="HTTPSampler.connect_timeout">60000</stringProp> + <stringProp name="HTTPSampler.response_timeout">200000</stringProp> <stringProp name="HTTPSampler.protocol">${request_protocol}</stringProp> <stringProp name="HTTPSampler.contentEncoding"/> <stringProp name="HTTPSampler.path">${base_path}${admin_path}${customer_edit_url_path}</stringProp> @@ -33554,7 +34419,7 @@ vars.put("admin_user", adminUser); </elementProp> <elementProp name="address[new_0][region_id]" elementType="HTTPArgument"> <boolProp name="HTTPArgument.always_encode">true</boolProp> - <stringProp name="Argument.value">12</stringProp> + <stringProp name="Argument.value">${admin_customer_address_region_id}</stringProp> <stringProp name="Argument.metadata">=</stringProp> <boolProp name="HTTPArgument.use_equals">true</boolProp> <stringProp name="Argument.name">address[new_0][region_id]</stringProp> @@ -33570,8 +34435,8 @@ vars.put("admin_user", adminUser); </elementProp> <stringProp name="HTTPSampler.domain"/> <stringProp name="HTTPSampler.port"/> - <stringProp name="HTTPSampler.connect_timeout"/> - <stringProp name="HTTPSampler.response_timeout"/> + <stringProp name="HTTPSampler.connect_timeout">60000</stringProp> + <stringProp name="HTTPSampler.response_timeout">200000</stringProp> <stringProp name="HTTPSampler.protocol">${request_protocol}</stringProp> <stringProp name="HTTPSampler.contentEncoding"/> <stringProp name="HTTPSampler.path">${base_path}${admin_path}/customer/index/validate/</stringProp> @@ -34043,8 +34908,8 @@ vars.put("admin_user", adminUser); </elementProp> <stringProp name="HTTPSampler.domain"/> <stringProp name="HTTPSampler.port"/> - <stringProp name="HTTPSampler.connect_timeout"/> - <stringProp name="HTTPSampler.response_timeout"/> + <stringProp name="HTTPSampler.connect_timeout">60000</stringProp> + <stringProp name="HTTPSampler.response_timeout">200000</stringProp> <stringProp name="HTTPSampler.protocol">${request_protocol}</stringProp> <stringProp name="HTTPSampler.contentEncoding"/> <stringProp name="HTTPSampler.path">${base_path}${admin_path}/customer/index/save/</stringProp> @@ -34082,8 +34947,8 @@ vars.put("admin_user", adminUser); </elementProp> <stringProp name="HTTPSampler.domain"/> <stringProp name="HTTPSampler.port"/> - <stringProp name="HTTPSampler.connect_timeout"/> - <stringProp name="HTTPSampler.response_timeout"/> + <stringProp name="HTTPSampler.connect_timeout">60000</stringProp> + <stringProp name="HTTPSampler.response_timeout">200000</stringProp> <stringProp name="HTTPSampler.protocol">${request_protocol}</stringProp> <stringProp name="HTTPSampler.contentEncoding"/> <stringProp name="HTTPSampler.path">${base_path}${admin_path}/admin/auth/logout/</stringProp> @@ -34102,8 +34967,11 @@ vars.put("admin_user", adminUser); <stringProp name="parameters"/> <stringProp name="filename"/> <stringProp name="script"> -adminUserList = props.get("adminUserList"); -adminUserList.add(vars.get("admin_user")); + adminUsersDistribution = Integer.parseInt(vars.get("admin_users_distribution_per_admin_pool")); + if (adminUsersDistribution == 1) { + adminUserList = props.get("adminUserList"); + adminUserList.add(vars.get("admin_user")); + } </stringProp> <stringProp name="TestPlan.comments">mpaf/tool/fragments/ce/common/return_admin_email_to_pool.jmx</stringProp></BeanShellPostProcessor> <hashTree/> @@ -34209,7 +35077,19 @@ if (testLabel <stringProp name="TestPlan.comments">mpaf/tool/fragments/ce/get_admin_email.jmx</stringProp> <stringProp name="BeanShellSampler.query"> adminUserList = props.get("adminUserList"); -adminUser = adminUserList.poll(); +adminUserListIterator = props.get("adminUserListIterator"); +adminUsersDistribution = Integer.parseInt(vars.get("admin_users_distribution_per_admin_pool")); + +if (adminUsersDistribution == 1) { + adminUser = adminUserList.poll(); +} else { + if (!adminUserListIterator.hasNext()) { + adminUserListIterator = adminUserList.descendingIterator(); + } + + adminUser = adminUserListIterator.next(); +} + if (adminUser == null) { SampleResult.setResponseMessage("adminUser list is empty"); SampleResult.setResponseData("adminUser list is empty","UTF-8"); @@ -34232,11 +35112,11 @@ vars.put("admin_user", adminUser); </elementProp> <stringProp name="HTTPSampler.domain"/> <stringProp name="HTTPSampler.port"/> - <stringProp name="HTTPSampler.connect_timeout"/> - <stringProp name="HTTPSampler.response_timeout"/> + <stringProp name="HTTPSampler.connect_timeout">60000</stringProp> + <stringProp name="HTTPSampler.response_timeout">200000</stringProp> <stringProp name="HTTPSampler.protocol">${request_protocol}</stringProp> <stringProp name="HTTPSampler.contentEncoding"/> - <stringProp name="HTTPSampler.path">${base_path}${admin_path}</stringProp> + <stringProp name="HTTPSampler.path">${base_path}${admin_path}/admin/</stringProp> <stringProp name="HTTPSampler.method">GET</stringProp> <boolProp name="HTTPSampler.follow_redirects">true</boolProp> <boolProp name="HTTPSampler.auto_redirects">false</boolProp> @@ -34313,8 +35193,8 @@ vars.put("admin_user", adminUser); </elementProp> <stringProp name="HTTPSampler.domain"/> <stringProp name="HTTPSampler.port"/> - <stringProp name="HTTPSampler.connect_timeout"/> - <stringProp name="HTTPSampler.response_timeout"/> + <stringProp name="HTTPSampler.connect_timeout">60000</stringProp> + <stringProp name="HTTPSampler.response_timeout">200000</stringProp> <stringProp name="HTTPSampler.protocol">${request_protocol}</stringProp> <stringProp name="HTTPSampler.contentEncoding"/> <stringProp name="HTTPSampler.path">${base_path}${admin_path}/admin/dashboard/</stringProp> @@ -34351,8 +35231,8 @@ vars.put("admin_user", adminUser); </elementProp> <stringProp name="HTTPSampler.domain"/> <stringProp name="HTTPSampler.port"/> - <stringProp name="HTTPSampler.connect_timeout"/> - <stringProp name="HTTPSampler.response_timeout"/> + <stringProp name="HTTPSampler.connect_timeout">60000</stringProp> + <stringProp name="HTTPSampler.response_timeout">200000</stringProp> <stringProp name="HTTPSampler.protocol">${request_protocol}</stringProp> <stringProp name="HTTPSampler.contentEncoding"/> <stringProp name="HTTPSampler.path">${base_path}${admin_path}/sales/order/</stringProp> @@ -34462,8 +35342,8 @@ vars.put("admin_user", adminUser); </elementProp> <stringProp name="HTTPSampler.domain"/> <stringProp name="HTTPSampler.port"/> - <stringProp name="HTTPSampler.connect_timeout"/> - <stringProp name="HTTPSampler.response_timeout"/> + <stringProp name="HTTPSampler.connect_timeout">60000</stringProp> + <stringProp name="HTTPSampler.response_timeout">200000</stringProp> <stringProp name="HTTPSampler.protocol">${request_protocol}</stringProp> <stringProp name="HTTPSampler.contentEncoding"/> <stringProp name="HTTPSampler.path">${base_path}${admin_path}/mui/index/render/</stringProp> @@ -34579,8 +35459,8 @@ vars.put("admin_user", adminUser); </elementProp> <stringProp name="HTTPSampler.domain"/> <stringProp name="HTTPSampler.port"/> - <stringProp name="HTTPSampler.connect_timeout"/> - <stringProp name="HTTPSampler.response_timeout"/> + <stringProp name="HTTPSampler.connect_timeout">60000</stringProp> + <stringProp name="HTTPSampler.response_timeout">200000</stringProp> <stringProp name="HTTPSampler.protocol">${request_protocol}</stringProp> <stringProp name="HTTPSampler.contentEncoding"/> <stringProp name="HTTPSampler.path">${base_path}${admin_path}/mui/index/render/</stringProp> @@ -34681,8 +35561,8 @@ vars.put("admin_user", adminUser); </elementProp> <stringProp name="HTTPSampler.domain"/> <stringProp name="HTTPSampler.port"/> - <stringProp name="HTTPSampler.connect_timeout"/> - <stringProp name="HTTPSampler.response_timeout"/> + <stringProp name="HTTPSampler.connect_timeout">60000</stringProp> + <stringProp name="HTTPSampler.response_timeout">200000</stringProp> <stringProp name="HTTPSampler.protocol">${request_protocol}</stringProp> <stringProp name="HTTPSampler.contentEncoding"/> <stringProp name="HTTPSampler.path">${base_path}${admin_path}/sales/order/view/order_id/${order_id}/</stringProp> @@ -34751,8 +35631,8 @@ vars.put("admin_user", adminUser); </elementProp> <stringProp name="HTTPSampler.domain"/> <stringProp name="HTTPSampler.port"/> - <stringProp name="HTTPSampler.connect_timeout"/> - <stringProp name="HTTPSampler.response_timeout"/> + <stringProp name="HTTPSampler.connect_timeout">60000</stringProp> + <stringProp name="HTTPSampler.response_timeout">200000</stringProp> <stringProp name="HTTPSampler.protocol">${request_protocol}</stringProp> <stringProp name="HTTPSampler.contentEncoding"/> <stringProp name="HTTPSampler.path">${base_path}${admin_path}/sales/order/addComment/order_id/${order_id}/?isAjax=true</stringProp> @@ -34782,8 +35662,8 @@ vars.put("admin_user", adminUser); </elementProp> <stringProp name="HTTPSampler.domain"/> <stringProp name="HTTPSampler.port"/> - <stringProp name="HTTPSampler.connect_timeout"/> - <stringProp name="HTTPSampler.response_timeout"/> + <stringProp name="HTTPSampler.connect_timeout">60000</stringProp> + <stringProp name="HTTPSampler.response_timeout">200000</stringProp> <stringProp name="HTTPSampler.protocol">${request_protocol}</stringProp> <stringProp name="HTTPSampler.contentEncoding"/> <stringProp name="HTTPSampler.path">${base_path}${admin_path}/sales/order_invoice/start/order_id/${order_id}/</stringProp> @@ -34853,8 +35733,8 @@ vars.put("admin_user", adminUser); </elementProp> <stringProp name="HTTPSampler.domain"/> <stringProp name="HTTPSampler.port"/> - <stringProp name="HTTPSampler.connect_timeout"/> - <stringProp name="HTTPSampler.response_timeout"/> + <stringProp name="HTTPSampler.connect_timeout">60000</stringProp> + <stringProp name="HTTPSampler.response_timeout">200000</stringProp> <stringProp name="HTTPSampler.protocol">${request_protocol}</stringProp> <stringProp name="HTTPSampler.contentEncoding"/> <stringProp name="HTTPSampler.path">${base_path}${admin_path}/sales/order_invoice/save/order_id/${order_id}/</stringProp> @@ -34884,8 +35764,8 @@ vars.put("admin_user", adminUser); </elementProp> <stringProp name="HTTPSampler.domain"/> <stringProp name="HTTPSampler.port"/> - <stringProp name="HTTPSampler.connect_timeout"/> - <stringProp name="HTTPSampler.response_timeout"/> + <stringProp name="HTTPSampler.connect_timeout">60000</stringProp> + <stringProp name="HTTPSampler.response_timeout">200000</stringProp> <stringProp name="HTTPSampler.protocol">${request_protocol}</stringProp> <stringProp name="HTTPSampler.contentEncoding"/> <stringProp name="HTTPSampler.path">${base_path}${admin_path}/admin/order_shipment/start/order_id/${order_id}/</stringProp> @@ -34945,8 +35825,8 @@ vars.put("admin_user", adminUser); </elementProp> <stringProp name="HTTPSampler.domain"/> <stringProp name="HTTPSampler.port"/> - <stringProp name="HTTPSampler.connect_timeout"/> - <stringProp name="HTTPSampler.response_timeout"/> + <stringProp name="HTTPSampler.connect_timeout">60000</stringProp> + <stringProp name="HTTPSampler.response_timeout">200000</stringProp> <stringProp name="HTTPSampler.protocol">${request_protocol}</stringProp> <stringProp name="HTTPSampler.contentEncoding"/> <stringProp name="HTTPSampler.path">${base_path}${admin_path}/admin/order_shipment/save/order_id/${order_id}/</stringProp> @@ -34978,8 +35858,8 @@ vars.put("admin_user", adminUser); </elementProp> <stringProp name="HTTPSampler.domain"/> <stringProp name="HTTPSampler.port"/> - <stringProp name="HTTPSampler.connect_timeout"/> - <stringProp name="HTTPSampler.response_timeout"/> + <stringProp name="HTTPSampler.connect_timeout">60000</stringProp> + <stringProp name="HTTPSampler.response_timeout">200000</stringProp> <stringProp name="HTTPSampler.protocol">${request_protocol}</stringProp> <stringProp name="HTTPSampler.contentEncoding"/> <stringProp name="HTTPSampler.path">${base_path}${admin_path}/admin/auth/logout/</stringProp> @@ -34998,8 +35878,11 @@ vars.put("admin_user", adminUser); <stringProp name="parameters"/> <stringProp name="filename"/> <stringProp name="script"> -adminUserList = props.get("adminUserList"); -adminUserList.add(vars.get("admin_user")); + adminUsersDistribution = Integer.parseInt(vars.get("admin_users_distribution_per_admin_pool")); + if (adminUsersDistribution == 1) { + adminUserList = props.get("adminUserList"); + adminUserList.add(vars.get("admin_user")); + } </stringProp> <stringProp name="TestPlan.comments">mpaf/tool/fragments/ce/common/return_admin_email_to_pool.jmx</stringProp></BeanShellPostProcessor> <hashTree/> @@ -35109,7 +35992,19 @@ if (testLabel <stringProp name="TestPlan.comments">mpaf/tool/fragments/ce/get_admin_email.jmx</stringProp> <stringProp name="BeanShellSampler.query"> adminUserList = props.get("adminUserList"); -adminUser = adminUserList.poll(); +adminUserListIterator = props.get("adminUserListIterator"); +adminUsersDistribution = Integer.parseInt(vars.get("admin_users_distribution_per_admin_pool")); + +if (adminUsersDistribution == 1) { + adminUser = adminUserList.poll(); +} else { + if (!adminUserListIterator.hasNext()) { + adminUserListIterator = adminUserList.descendingIterator(); + } + + adminUser = adminUserListIterator.next(); +} + if (adminUser == null) { SampleResult.setResponseMessage("adminUser list is empty"); SampleResult.setResponseData("adminUser list is empty","UTF-8"); @@ -35132,11 +36027,11 @@ vars.put("admin_user", adminUser); </elementProp> <stringProp name="HTTPSampler.domain"/> <stringProp name="HTTPSampler.port"/> - <stringProp name="HTTPSampler.connect_timeout"/> - <stringProp name="HTTPSampler.response_timeout"/> + <stringProp name="HTTPSampler.connect_timeout">60000</stringProp> + <stringProp name="HTTPSampler.response_timeout">200000</stringProp> <stringProp name="HTTPSampler.protocol">${request_protocol}</stringProp> <stringProp name="HTTPSampler.contentEncoding"/> - <stringProp name="HTTPSampler.path">${base_path}${admin_path}</stringProp> + <stringProp name="HTTPSampler.path">${base_path}${admin_path}/admin/</stringProp> <stringProp name="HTTPSampler.method">GET</stringProp> <boolProp name="HTTPSampler.follow_redirects">true</boolProp> <boolProp name="HTTPSampler.auto_redirects">false</boolProp> @@ -35213,8 +36108,8 @@ vars.put("admin_user", adminUser); </elementProp> <stringProp name="HTTPSampler.domain"/> <stringProp name="HTTPSampler.port"/> - <stringProp name="HTTPSampler.connect_timeout"/> - <stringProp name="HTTPSampler.response_timeout"/> + <stringProp name="HTTPSampler.connect_timeout">60000</stringProp> + <stringProp name="HTTPSampler.response_timeout">200000</stringProp> <stringProp name="HTTPSampler.protocol">${request_protocol}</stringProp> <stringProp name="HTTPSampler.contentEncoding"/> <stringProp name="HTTPSampler.path">${base_path}${admin_path}/admin/dashboard/</stringProp> @@ -35392,8 +36287,8 @@ vars.put("related_product_id", props.get("simple_products_list").get(relatedInde </elementProp> <stringProp name="HTTPSampler.domain"/> <stringProp name="HTTPSampler.port"/> - <stringProp name="HTTPSampler.connect_timeout"/> - <stringProp name="HTTPSampler.response_timeout"/> + <stringProp name="HTTPSampler.connect_timeout">60000</stringProp> + <stringProp name="HTTPSampler.response_timeout">200000</stringProp> <stringProp name="HTTPSampler.protocol">${request_protocol}</stringProp> <stringProp name="HTTPSampler.contentEncoding"/> <stringProp name="HTTPSampler.path">${base_path}rest/V1/integration/admin/token</stringProp> @@ -35472,8 +36367,8 @@ vars.put("related_product_id", props.get("simple_products_list").get(relatedInde </elementProp> <stringProp name="HTTPSampler.domain"/> <stringProp name="HTTPSampler.port"/> - <stringProp name="HTTPSampler.connect_timeout"/> - <stringProp name="HTTPSampler.response_timeout"/> + <stringProp name="HTTPSampler.connect_timeout">60000</stringProp> + <stringProp name="HTTPSampler.response_timeout">200000</stringProp> <stringProp name="HTTPSampler.protocol">${request_protocol}</stringProp> <stringProp name="HTTPSampler.contentEncoding"/> <stringProp name="HTTPSampler.path">${base_path}rest/default/V1/products/attributes</stringProp> @@ -35540,8 +36435,8 @@ vars.putObject("product_attributes", attributes); </elementProp> <stringProp name="HTTPSampler.domain"/> <stringProp name="HTTPSampler.port"/> - <stringProp name="HTTPSampler.connect_timeout"/> - <stringProp name="HTTPSampler.response_timeout"/> + <stringProp name="HTTPSampler.connect_timeout">60000</stringProp> + <stringProp name="HTTPSampler.response_timeout">200000</stringProp> <stringProp name="HTTPSampler.protocol">${request_protocol}</stringProp> <stringProp name="HTTPSampler.contentEncoding"/> <stringProp name="HTTPSampler.path">${base_path}${admin_path}/catalog/product_set/index/filter/${attribute_set_filter}</stringProp> @@ -35584,15 +36479,15 @@ Random random = new Random(); if (${seedForRandom} > 0) { random.setSeed(${seedForRandom}); } -number = random.nextInt(props.get("simple_products_list").size()); -simpleList = props.get("simple_products_list").get(number); +number = random.nextInt(props.get("simple_products_list_for_edit").size()); +simpleList = props.get("simple_products_list_for_edit").get(number); vars.put("simple_product_1_id", simpleList.get("id")); vars.put("simple_product_1_name", simpleList.get("title")); do { - number1 = random.nextInt(props.get("simple_products_list").size()); + number1 = random.nextInt(props.get("simple_products_list_for_edit").size()); } while(number == number1); -simpleList = props.get("simple_products_list").get(number1); +simpleList = props.get("simple_products_list_for_edit").get(number1); vars.put("simple_product_2_id", simpleList.get("id")); vars.put("simple_product_2_name", simpleList.get("title")); @@ -35630,8 +36525,8 @@ vars.put("configurable_sku", "Configurable Product - ${__time(YMD)}-${__threadNu </elementProp> <stringProp name="HTTPSampler.domain"/> <stringProp name="HTTPSampler.port"/> - <stringProp name="HTTPSampler.connect_timeout"/> - <stringProp name="HTTPSampler.response_timeout"/> + <stringProp name="HTTPSampler.connect_timeout">60000</stringProp> + <stringProp name="HTTPSampler.response_timeout">200000</stringProp> <stringProp name="HTTPSampler.protocol">${request_protocol}</stringProp> <stringProp name="HTTPSampler.contentEncoding"/> <stringProp name="HTTPSampler.path">${base_path}${admin_path}/catalog/product/</stringProp> @@ -35660,8 +36555,8 @@ vars.put("configurable_sku", "Configurable Product - ${__time(YMD)}-${__threadNu </elementProp> <stringProp name="HTTPSampler.domain"/> <stringProp name="HTTPSampler.port"/> - <stringProp name="HTTPSampler.connect_timeout"/> - <stringProp name="HTTPSampler.response_timeout"/> + <stringProp name="HTTPSampler.connect_timeout">60000</stringProp> + <stringProp name="HTTPSampler.response_timeout">200000</stringProp> <stringProp name="HTTPSampler.protocol">${request_protocol}</stringProp> <stringProp name="HTTPSampler.contentEncoding"/> <stringProp name="HTTPSampler.path">${base_path}${admin_path}/catalog/product/new/set/4/type/bundle/</stringProp> @@ -36563,8 +37458,8 @@ vars.put("configurable_sku", "Configurable Product - ${__time(YMD)}-${__threadNu </elementProp> <stringProp name="HTTPSampler.domain"/> <stringProp name="HTTPSampler.port"/> - <stringProp name="HTTPSampler.connect_timeout"/> - <stringProp name="HTTPSampler.response_timeout"/> + <stringProp name="HTTPSampler.connect_timeout">60000</stringProp> + <stringProp name="HTTPSampler.response_timeout">200000</stringProp> <stringProp name="HTTPSampler.protocol">${request_protocol}</stringProp> <stringProp name="HTTPSampler.contentEncoding"/> <stringProp name="HTTPSampler.path">${base_path}${admin_path}/catalog/product/validate/set/4/</stringProp> @@ -37497,8 +38392,8 @@ vars.put("configurable_sku", "Configurable Product - ${__time(YMD)}-${__threadNu </elementProp> <stringProp name="HTTPSampler.domain"/> <stringProp name="HTTPSampler.port"/> - <stringProp name="HTTPSampler.connect_timeout"/> - <stringProp name="HTTPSampler.response_timeout"/> + <stringProp name="HTTPSampler.connect_timeout">60000</stringProp> + <stringProp name="HTTPSampler.response_timeout">200000</stringProp> <stringProp name="HTTPSampler.protocol">${request_protocol}</stringProp> <stringProp name="HTTPSampler.contentEncoding"/> <stringProp name="HTTPSampler.path">${base_path}${admin_path}/catalog/product/save/set/4/type/bundle/back/edit/active_tab/product-details/</stringProp> @@ -37535,8 +38430,8 @@ vars.put("configurable_sku", "Configurable Product - ${__time(YMD)}-${__threadNu </elementProp> <stringProp name="HTTPSampler.domain"/> <stringProp name="HTTPSampler.port"/> - <stringProp name="HTTPSampler.connect_timeout"/> - <stringProp name="HTTPSampler.response_timeout"/> + <stringProp name="HTTPSampler.connect_timeout">60000</stringProp> + <stringProp name="HTTPSampler.response_timeout">200000</stringProp> <stringProp name="HTTPSampler.protocol">${request_protocol}</stringProp> <stringProp name="HTTPSampler.contentEncoding"/> <stringProp name="HTTPSampler.path">${base_path}${admin_path}/admin/auth/logout/</stringProp> @@ -37555,8 +38450,11 @@ vars.put("configurable_sku", "Configurable Product - ${__time(YMD)}-${__threadNu <stringProp name="parameters"/> <stringProp name="filename"/> <stringProp name="script"> -adminUserList = props.get("adminUserList"); -adminUserList.add(vars.get("admin_user")); + adminUsersDistribution = Integer.parseInt(vars.get("admin_users_distribution_per_admin_pool")); + if (adminUsersDistribution == 1) { + adminUserList = props.get("adminUserList"); + adminUserList.add(vars.get("admin_user")); + } </stringProp> <stringProp name="TestPlan.comments">mpaf/tool/fragments/ce/common/return_admin_email_to_pool.jmx</stringProp></BeanShellPostProcessor> <hashTree/> @@ -37593,8 +38491,8 @@ adminUserList.add(vars.get("admin_user")); </elementProp> <stringProp name="HTTPSampler.domain"/> <stringProp name="HTTPSampler.port"/> - <stringProp name="HTTPSampler.connect_timeout"/> - <stringProp name="HTTPSampler.response_timeout"/> + <stringProp name="HTTPSampler.connect_timeout">60000</stringProp> + <stringProp name="HTTPSampler.response_timeout">200000</stringProp> <stringProp name="HTTPSampler.protocol">${request_protocol}</stringProp> <stringProp name="HTTPSampler.contentEncoding"/> <stringProp name="HTTPSampler.path">${base_path}rest/V1/integration/admin/token</stringProp> @@ -37693,8 +38591,8 @@ adminUserList.add(vars.get("admin_user")); </elementProp> <stringProp name="HTTPSampler.domain"/> <stringProp name="HTTPSampler.port"/> - <stringProp name="HTTPSampler.connect_timeout"/> - <stringProp name="HTTPSampler.response_timeout"/> + <stringProp name="HTTPSampler.connect_timeout">60000</stringProp> + <stringProp name="HTTPSampler.response_timeout">200000</stringProp> <stringProp name="HTTPSampler.protocol">${request_protocol}</stringProp> <stringProp name="HTTPSampler.contentEncoding"/> <stringProp name="HTTPSampler.path">${base_path}rest/default/V1/products</stringProp> @@ -39806,8 +40704,8 @@ adminUserList.add(vars.get("admin_user")); </elementProp> <stringProp name="HTTPSampler.domain"/> <stringProp name="HTTPSampler.port"/> - <stringProp name="HTTPSampler.connect_timeout"/> - <stringProp name="HTTPSampler.response_timeout"/> + <stringProp name="HTTPSampler.connect_timeout">60000</stringProp> + <stringProp name="HTTPSampler.response_timeout">200000</stringProp> <stringProp name="HTTPSampler.protocol">${request_protocol}</stringProp> <stringProp name="HTTPSampler.contentEncoding"/> <stringProp name="HTTPSampler.path">${base_path}rest/V1/integration/admin/token</stringProp> @@ -40831,8 +41729,8 @@ if (name == null) { </elementProp> <stringProp name="HTTPSampler.domain"/> <stringProp name="HTTPSampler.port"/> - <stringProp name="HTTPSampler.connect_timeout"/> - <stringProp name="HTTPSampler.response_timeout"/> + <stringProp name="HTTPSampler.connect_timeout">60000</stringProp> + <stringProp name="HTTPSampler.response_timeout">200000</stringProp> <stringProp name="HTTPSampler.protocol">${request_protocol}</stringProp> <stringProp name="HTTPSampler.contentEncoding"/> <stringProp name="HTTPSampler.path">${base_path}DeploymentEvent.php</stringProp> diff --git a/setup/pub/styles/setup.css b/setup/pub/styles/setup.css index 13dc7b2a043d2..f290b155fb553 100644 --- a/setup/pub/styles/setup.css +++ b/setup/pub/styles/setup.css @@ -3,4 +3,4 @@ * See COPYING.txt for license details. */ -.abs-action-delete,.abs-icon,.action-close:before,.action-next:before,.action-previous:before,.admin-user .admin__action-dropdown:before,.admin__action-multiselect-dropdown:before,.admin__action-multiselect-search-label:before,.admin__control-checkbox+label:before,.admin__control-collapsible .admin__collapsible-block-wrapper .fieldset-wrapper-title .action-delete:before,.admin__control-table .action-delete:before,.admin__current-filters-list .action-remove:before,.admin__data-grid-action-bookmarks .action-delete:before,.admin__data-grid-action-bookmarks .action-edit:before,.admin__data-grid-action-bookmarks .action-submit:before,.admin__data-grid-action-bookmarks .admin__action-dropdown:before,.admin__data-grid-action-columns .admin__action-dropdown:before,.admin__data-grid-action-export .admin__action-dropdown:before,.admin__field-fallback-reset:before,.admin__menu .level-0>a:before,.admin__page-nav-item-message .admin__page-nav-item-message-icon,.admin__page-nav-title._collapsible:after,.data-grid-filters-action-wrap .action-default:before,.data-grid-row-changed:after,.data-grid-row-parent>td .data-grid-checkbox-cell-inner:before,.data-grid-search-control-wrap .action-submit:before,.extensions-information .list .extension-delete,.icon-failed:before,.icon-success:before,.notifications-action:before,.notifications-close:before,.page-actions .page-actions-buttons>button.action-back:before,.page-actions .page-actions-buttons>button.back:before,.page-actions>button.action-back:before,.page-actions>button.back:before,.page-title-jumbo-success:before,.search-global-label:before,.selectmenu .action-delete:before,.selectmenu .action-edit:before,.selectmenu .action-save:before,.setup-home-item:before,.sticky-header .data-grid-search-control-wrap .data-grid-search-label:before,.store-switcher .dropdown-menu .dropdown-toolbar a:before,.tooltip .help a:before,.tooltip .help span:before{-webkit-font-smoothing:antialiased;font-family:Icons;font-style:normal;font-weight:400;line-height:1;speak:none}.validation-symbol:after{color:#e22626;content:'*';font-weight:400;margin-left:3px}.abs-modal-overlay,.modals-overlay{background:rgba(0,0,0,.35);bottom:0;left:0;position:fixed;right:0;top:0}.abs-action-delete>span,.abs-visually-hidden,.action-multicheck-wrap .action-multicheck-toggle>span,.admin__actions-switch-checkbox,.admin__control-fields .admin__field:nth-child(n+2):not(.admin__field-option):not(.admin__field-group-show-label)>.admin__field-label,.admin__field-tooltip .admin__field-tooltip-action span,.customize-your-store .customize-your-store-default .legend,.extensions-information .list .extension-delete>span,.form-el-checkbox,.form-el-radio,.selectmenu .action-delete>span,.selectmenu .action-edit>span,.selectmenu .action-save>span,.selectmenu-toggle span,.tooltip .help a span,.tooltip .help span span,[class*=admin__control-grouped]>.admin__field:nth-child(n+2):not(.admin__field-option):not(.admin__field-group-show-label):not(.admin__field-date)>.admin__field-label{border:0;clip:rect(0,0,0,0);height:1px;margin:-1px;overflow:hidden;padding:0;position:absolute;width:1px}.abs-visually-hidden-reset,.admin__field-group-columns>.admin__field:nth-child(n+2):not(.admin__field-option):not(.admin__field-group-show-label):not(.admin__field-date)>.admin__field-label[class]{clip:auto;height:auto;margin:0;overflow:visible;position:static;width:auto}.abs-clearfix:after,.abs-clearfix:before,.action-multicheck-wrap:after,.action-multicheck-wrap:before,.actions-split:after,.actions-split:before,.admin__control-table-pagination:after,.admin__control-table-pagination:before,.admin__data-grid-action-columns-menu .admin__action-dropdown-menu-content:after,.admin__data-grid-action-columns-menu .admin__action-dropdown-menu-content:before,.admin__data-grid-filters-footer:after,.admin__data-grid-filters-footer:before,.admin__data-grid-filters:after,.admin__data-grid-filters:before,.admin__data-grid-header-row:after,.admin__data-grid-header-row:before,.admin__field-complex:after,.admin__field-complex:before,.modal-slide .magento-message .insert-title-inner:after,.modal-slide .magento-message .insert-title-inner:before,.modal-slide .main-col .insert-title-inner:after,.modal-slide .main-col .insert-title-inner:before,.page-actions._fixed:after,.page-actions._fixed:before,.page-content:after,.page-content:before,.page-header-actions:after,.page-header-actions:before,.page-main-actions:not(._hidden):after,.page-main-actions:not(._hidden):before{content:'';display:table}.abs-clearfix:after,.action-multicheck-wrap:after,.actions-split:after,.admin__control-table-pagination:after,.admin__data-grid-action-columns-menu .admin__action-dropdown-menu-content:after,.admin__data-grid-filters-footer:after,.admin__data-grid-filters:after,.admin__data-grid-header-row:after,.admin__field-complex:after,.modal-slide .magento-message .insert-title-inner:after,.modal-slide .main-col .insert-title-inner:after,.page-actions._fixed:after,.page-content:after,.page-header-actions:after,.page-main-actions:not(._hidden):after{clear:both}.abs-list-reset-styles{margin:0;padding:0;list-style:none}.abs-draggable-handle,.admin__control-collapsible .admin__collapsible-block-wrapper .fieldset-wrapper-title .draggable-handle,.admin__control-table .draggable-handle,.data-grid .data-grid-draggable-row-cell .draggable-handle{cursor:-webkit-grab;cursor:move;font-size:0;margin-top:-4px;padding:0 1rem 0 0;vertical-align:middle;display:inline-block;text-decoration:none}.abs-draggable-handle:before,.admin__control-collapsible .admin__collapsible-block-wrapper .fieldset-wrapper-title .draggable-handle:before,.admin__control-table .draggable-handle:before,.data-grid .data-grid-draggable-row-cell .draggable-handle:before{-webkit-font-smoothing:antialiased;font-size:1.8rem;line-height:inherit;color:#9e9e9e;content:'\e617';font-family:Icons;vertical-align:middle;display:inline-block;font-weight:400;overflow:hidden;speak:none;text-align:center}.abs-draggable-handle:hover:before,.admin__control-collapsible .admin__collapsible-block-wrapper .fieldset-wrapper-title .draggable-handle:hover:before,.admin__control-table .draggable-handle:hover:before,.data-grid .data-grid-draggable-row-cell .draggable-handle:hover:before{color:#858585}.abs-config-scope-label,.admin__field:not(.admin__field-option)>.admin__field-label span[data-config-scope]:before{bottom:-1.3rem;color:gray;content:attr(data-config-scope);font-size:1.1rem;font-weight:400;min-width:15rem;position:absolute;right:0;text-transform:lowercase}.abs-word-wrap,.admin__field:not(.admin__field-option)>.admin__field-label{overflow-wrap:break-word;word-wrap:break-word;-ms-word-break:break-all;word-break:break-word;-webkit-hyphens:auto;-ms-hyphens:auto;hyphens:auto}html{-ms-text-size-adjust:100%;-webkit-text-size-adjust:100%;box-sizing:border-box}*,:after,:before{box-sizing:inherit}:focus{box-shadow:none;outline:0}._keyfocus :focus{box-shadow:0 0 0 1px #008bdb}body{margin:0}article,aside,details,figcaption,figure,footer,header,main,menu,nav,section,summary{display:block}audio,canvas,progress,video{display:inline-block;vertical-align:baseline}audio:not([controls]){display:none;height:0}[hidden],template{display:none}a{background-color:transparent}a:active,a:hover{outline:0}abbr[title]{border-bottom:1px dotted}b,strong{font-weight:700}dfn{font-style:italic}mark{background:#ff0;color:#000}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sup{top:-.5em}sub{bottom:-.25em}img{border:0}embed,img,object,video{max-width:100%}svg:not(:root){overflow:hidden}figure{margin:1em 40px}hr{box-sizing:content-box;height:0}pre{overflow:auto}code,kbd,pre,samp{font-family:monospace,monospace;font-size:1em}button,input,optgroup,select,textarea{color:inherit;font:inherit;margin:0}button{overflow:visible}button,select{text-transform:none}button,html input[type=button],input[type=reset],input[type=submit]{-webkit-appearance:button;cursor:pointer}button[disabled],html input[disabled]{cursor:default}button::-moz-focus-inner,input::-moz-focus-inner{border:0;padding:0}input{line-height:normal}input[type=checkbox],input[type=radio]{box-sizing:border-box;padding:0}input[type=number]::-webkit-inner-spin-button,input[type=number]::-webkit-outer-spin-button{height:auto}input[type=search]{-webkit-appearance:textfield}input[type=search]::-webkit-search-cancel-button,input[type=search]::-webkit-search-decoration{-webkit-appearance:none}legend{border:0;padding:0}textarea{overflow:auto}optgroup{font-weight:700}table{border-collapse:collapse;border-spacing:0}td,th{padding:0}@font-face{font-family:'Open Sans';src:url(../fonts/opensans/light/opensans-300.eot);src:url(../fonts/opensans/light/opensans-300.eot?#iefix) format('embedded-opentype'),url(../fonts/opensans/light/opensans-300.woff2) format('woff2'),url(../fonts/opensans/light/opensans-300.woff) format('woff'),url(../fonts/opensans/light/opensans-300.ttf) format('truetype'),url('../fonts/opensans/light/opensans-300.svg#Open Sans') format('svg');font-weight:300;font-style:normal}@font-face{font-family:'Open Sans';src:url(../fonts/opensans/regular/opensans-400.eot);src:url(../fonts/opensans/regular/opensans-400.eot?#iefix) format('embedded-opentype'),url(../fonts/opensans/regular/opensans-400.woff2) format('woff2'),url(../fonts/opensans/regular/opensans-400.woff) format('woff'),url(../fonts/opensans/regular/opensans-400.ttf) format('truetype'),url('../fonts/opensans/regular/opensans-400.svg#Open Sans') format('svg');font-weight:400;font-style:normal}@font-face{font-family:'Open Sans';src:url(../fonts/opensans/semibold/opensans-600.eot);src:url(../fonts/opensans/semibold/opensans-600.eot?#iefix) format('embedded-opentype'),url(../fonts/opensans/semibold/opensans-600.woff2) format('woff2'),url(../fonts/opensans/semibold/opensans-600.woff) format('woff'),url(../fonts/opensans/semibold/opensans-600.ttf) format('truetype'),url('../fonts/opensans/semibold/opensans-600.svg#Open Sans') format('svg');font-weight:600;font-style:normal}@font-face{font-family:'Open Sans';src:url(../fonts/opensans/bold/opensans-700.eot);src:url(../fonts/opensans/bold/opensans-700.eot?#iefix) format('embedded-opentype'),url(../fonts/opensans/bold/opensans-700.woff2) format('woff2'),url(../fonts/opensans/bold/opensans-700.woff) format('woff'),url(../fonts/opensans/bold/opensans-700.ttf) format('truetype'),url('../fonts/opensans/bold/opensans-700.svg#Open Sans') format('svg');font-weight:700;font-style:normal}html{font-size:62.5%}body{color:#333;font-family:'Open Sans','Helvetica Neue',Helvetica,Arial,sans-serif;font-style:normal;font-weight:400;line-height:1.36;font-size:1.4rem}h1{margin:0 0 2rem;color:#41362f;font-weight:400;line-height:1.2;font-size:2.8rem}h2{margin:0 0 2rem;color:#41362f;font-weight:400;line-height:1.2;font-size:2rem}h3{margin:0 0 2rem;color:#41362f;font-weight:600;line-height:1.2;font-size:1.7rem}h4,h5,h6{font-weight:600;margin-top:0}p{margin:0 0 1em}small{font-size:1.2rem}a{color:#008bdb;text-decoration:none}a:hover{color:#0fa7ff;text-decoration:underline}dl,ol,ul{padding-left:0}nav ol,nav ul{list-style:none;margin:0;padding:0}html{height:100%}body{background-color:#fff;min-height:100%;min-width:102.4rem}.page-wrapper{background-color:#fff;display:inline-block;margin-left:-4px;vertical-align:top;width:calc(100% - 8.8rem)}.page-content{padding-bottom:3rem;padding-left:3rem;padding-right:3rem}.notices-wrapper{margin:0 3rem}.notices-wrapper .messages{margin-bottom:0}.row{margin-left:0;margin-right:0}.row:after{clear:both;content:'';display:table}.col-l-1,.col-l-10,.col-l-11,.col-l-12,.col-l-2,.col-l-3,.col-l-4,.col-l-5,.col-l-6,.col-l-7,.col-l-8,.col-l-9,.col-m-1,.col-m-10,.col-m-11,.col-m-12,.col-m-2,.col-m-3,.col-m-4,.col-m-5,.col-m-6,.col-m-7,.col-m-8,.col-m-9,.col-xl-1,.col-xl-10,.col-xl-11,.col-xl-12,.col-xl-2,.col-xl-3,.col-xl-4,.col-xl-5,.col-xl-6,.col-xl-7,.col-xl-8,.col-xl-9,.col-xs-1,.col-xs-10,.col-xs-11,.col-xs-12,.col-xs-2,.col-xs-3,.col-xs-4,.col-xs-5,.col-xs-6,.col-xs-7,.col-xs-8,.col-xs-9{min-height:1px;padding-left:0;padding-right:0;position:relative}.col-xs-1,.col-xs-10,.col-xs-11,.col-xs-12,.col-xs-2,.col-xs-3,.col-xs-4,.col-xs-5,.col-xs-6,.col-xs-7,.col-xs-8,.col-xs-9{float:left}.col-xs-12{width:100%}.col-xs-11{width:91.66666667%}.col-xs-10{width:83.33333333%}.col-xs-9{width:75%}.col-xs-8{width:66.66666667%}.col-xs-7{width:58.33333333%}.col-xs-6{width:50%}.col-xs-5{width:41.66666667%}.col-xs-4{width:33.33333333%}.col-xs-3{width:25%}.col-xs-2{width:16.66666667%}.col-xs-1{width:8.33333333%}.col-xs-pull-12{right:100%}.col-xs-pull-11{right:91.66666667%}.col-xs-pull-10{right:83.33333333%}.col-xs-pull-9{right:75%}.col-xs-pull-8{right:66.66666667%}.col-xs-pull-7{right:58.33333333%}.col-xs-pull-6{right:50%}.col-xs-pull-5{right:41.66666667%}.col-xs-pull-4{right:33.33333333%}.col-xs-pull-3{right:25%}.col-xs-pull-2{right:16.66666667%}.col-xs-pull-1{right:8.33333333%}.col-xs-pull-0{right:auto}.col-xs-push-12{left:100%}.col-xs-push-11{left:91.66666667%}.col-xs-push-10{left:83.33333333%}.col-xs-push-9{left:75%}.col-xs-push-8{left:66.66666667%}.col-xs-push-7{left:58.33333333%}.col-xs-push-6{left:50%}.col-xs-push-5{left:41.66666667%}.col-xs-push-4{left:33.33333333%}.col-xs-push-3{left:25%}.col-xs-push-2{left:16.66666667%}.col-xs-push-1{left:8.33333333%}.col-xs-push-0{left:auto}.col-xs-offset-12{margin-left:100%}.col-xs-offset-11{margin-left:91.66666667%}.col-xs-offset-10{margin-left:83.33333333%}.col-xs-offset-9{margin-left:75%}.col-xs-offset-8{margin-left:66.66666667%}.col-xs-offset-7{margin-left:58.33333333%}.col-xs-offset-6{margin-left:50%}.col-xs-offset-5{margin-left:41.66666667%}.col-xs-offset-4{margin-left:33.33333333%}.col-xs-offset-3{margin-left:25%}.col-xs-offset-2{margin-left:16.66666667%}.col-xs-offset-1{margin-left:8.33333333%}.col-xs-offset-0{margin-left:0}.row-gutter{margin-left:-1.5rem;margin-right:-1.5rem}.row-gutter>[class*=col-]{padding-left:1.5rem;padding-right:1.5rem}.abs-clearer:after,.extension-manager-content:after,.extension-manager-title:after,.form-row:after,.header:after,.nav:after,body:after{clear:both;content:'';display:table}.ng-cloak{display:none!important}.hide.hide{display:none}.show.show{display:block}.text-center{text-align:center}.text-right{text-align:right}@font-face{font-family:Icons;src:url(../fonts/icons/icons.eot);src:url(../fonts/icons/icons.eot?#iefix) format('embedded-opentype'),url(../fonts/icons/icons.woff2) format('woff2'),url(../fonts/icons/icons.woff) format('woff'),url(../fonts/icons/icons.ttf) format('truetype'),url(../fonts/icons/icons.svg#Icons) format('svg');font-weight:400;font-style:normal}[class*=icon-]{display:inline-block;line-height:1}.icon-failed:before,.icon-success:before,[class*=icon-]:after{font-family:Icons}.icon-success{color:#79a22e}.icon-success:before{content:'\e62d'}.icon-failed{color:#e22626}.icon-failed:before{content:'\e632'}.icon-success-thick:after{content:'\e62d'}.icon-collapse:after{content:'\e615'}.icon-failed-thick:after{content:'\e632'}.icon-expand:after{content:'\e616'}.icon-warning:after{content:'\e623'}.icon-failed-round,.icon-success-round{border-radius:100%;color:#fff;font-size:2.5rem;height:1em;position:relative;text-align:center;width:1em}.icon-failed-round:after,.icon-success-round:after{bottom:0;font-size:.5em;left:0;position:absolute;right:0;top:.45em}.icon-success-round{background-color:#79a22e}.icon-success-round:after{content:'\e62d'}.icon-failed-round{background-color:#e22626}.icon-failed-round:after{content:'\e632'}dl,ol,ul{margin-top:0}.list{padding-left:0}.list>li{display:block;margin-bottom:.75em;position:relative}.list>li>.icon-failed,.list>li>.icon-success{font-size:1.6em;left:-.1em;position:absolute;top:0}.list>li>.icon-success{color:#79a22e}.list>li>.icon-failed{color:#e22626}.list-item-failed,.list-item-icon,.list-item-success,.list-item-warning{padding-left:3.5rem}.list-item-failed:before,.list-item-success:before,.list-item-warning:before{left:-.1em;position:absolute}.list-item-success:before{color:#79a22e}.list-item-failed:before{color:#e22626}.list-item-warning:before{color:#ef672f}.list-definition{margin:0 0 3rem;padding:0}.list-definition>dt{clear:left;float:left}.list-definition>dd{margin-bottom:1em;margin-left:20rem}.btn-wrap{margin:0 auto}.btn-wrap .btn{width:100%}.btn{background:#e3e3e3;border:none;color:#514943;display:inline-block;font-size:1.6rem;font-weight:600;padding:.45em .9em;text-align:center}.btn:hover{background-color:#dbdbdb;color:#514943;text-decoration:none}.btn:active{background-color:#d6d6d6}.btn.disabled,.btn[disabled]{cursor:default;opacity:.5;pointer-events:none}.ie9 .btn.disabled,.ie9 .btn[disabled]{background-color:#f0f0f0;opacity:1;text-shadow:none}.btn-large{padding:.75em 1.25em}.btn-medium{font-size:1.4rem;padding:.5em 1.5em .6em}.btn-link{background-color:transparent;border:none;color:#008bdb;font-family:1.6rem;font-size:1.5rem}.btn-link:active,.btn-link:focus,.btn-link:hover{background-color:transparent;color:#0fa7ff}.btn-prime{background-color:#eb5202;color:#fff;text-shadow:1px 1px 0 rgba(0,0,0,.25)}.btn-prime:focus,.btn-prime:hover{background-color:#f65405;background-repeat:repeat-x;background-image:linear-gradient(to right,#e04f00 0,#f65405 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#e04f00', endColorstr='#f65405', GradientType=1);color:#fff}.btn-prime:active{background-color:#e04f00;background-repeat:repeat-x;background-image:linear-gradient(to right,#f65405 0,#e04f00 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#f65405', endColorstr='#e04f00', GradientType=1);color:#fff}.ie9 .btn-prime.disabled,.ie9 .btn-prime[disabled]{background-color:#fd6e23}.ie9 .btn-prime.disabled:active,.ie9 .btn-prime.disabled:hover,.ie9 .btn-prime[disabled]:active,.ie9 .btn-prime[disabled]:hover{background-color:#fd6e23;-webkit-filter:none;filter:none}.btn-secondary{background-color:#514943;color:#fff}.btn-secondary:hover{background-color:#5f564f;color:#fff}.btn-secondary:active,.btn-secondary:focus{background-color:#574e48;color:#fff}.ie9 .btn-secondary.disabled,.ie9 .btn-secondary[disabled]{background-color:#514943}.ie9 .btn-secondary.disabled:active,.ie9 .btn-secondary[disabled]:active{background-color:#514943;-webkit-filter:none;filter:none}[class*=btn-wrap-triangle]{overflow:hidden;position:relative}[class*=btn-wrap-triangle] .btn:after{border-style:solid;content:'';height:0;position:absolute;top:0;width:0}.btn-wrap-triangle-right{display:inline-block;padding-right:1.74rem;position:relative}.btn-wrap-triangle-right .btn{text-indent:.92rem}.btn-wrap-triangle-right .btn:after{border-color:transparent transparent transparent #e3e3e3;border-width:1.84rem 0 1.84rem 1.84rem;left:100%;margin-left:-1.74rem}.btn-wrap-triangle-right .btn:focus:after,.btn-wrap-triangle-right .btn:hover:after{border-left-color:#dbdbdb}.btn-wrap-triangle-right .btn:active:after{border-left-color:#d6d6d6}.btn-wrap-triangle-right .btn:not(.disabled):active,.btn-wrap-triangle-right .btn:not([disabled]):active{left:1px}.ie9 .btn-wrap-triangle-right .btn.disabled:after,.ie9 .btn-wrap-triangle-right .btn[disabled]:after{border-color:transparent transparent transparent #f0f0f0}.ie9 .btn-wrap-triangle-right .btn.disabled:active:after,.ie9 .btn-wrap-triangle-right .btn.disabled:focus:after,.ie9 .btn-wrap-triangle-right .btn.disabled:hover:after,.ie9 .btn-wrap-triangle-right .btn[disabled]:active:after,.ie9 .btn-wrap-triangle-right .btn[disabled]:focus:after,.ie9 .btn-wrap-triangle-right .btn[disabled]:hover:after{border-left-color:#f0f0f0}.btn-wrap-triangle-right .btn-prime:after{border-color:transparent transparent transparent #eb5202}.btn-wrap-triangle-right .btn-prime:focus:after,.btn-wrap-triangle-right .btn-prime:hover:after{border-left-color:#f65405}.btn-wrap-triangle-right .btn-prime:active:after{border-left-color:#e04f00}.btn-wrap-triangle-right .btn-prime:not(.disabled):active,.btn-wrap-triangle-right .btn-prime:not([disabled]):active{left:1px}.ie9 .btn-wrap-triangle-right .btn-prime.disabled:after,.ie9 .btn-wrap-triangle-right .btn-prime[disabled]:after{border-color:transparent transparent transparent #fd6e23}.ie9 .btn-wrap-triangle-right .btn-prime.disabled:active:after,.ie9 .btn-wrap-triangle-right .btn-prime.disabled:hover:after,.ie9 .btn-wrap-triangle-right .btn-prime[disabled]:active:after,.ie9 .btn-wrap-triangle-right .btn-prime[disabled]:hover:after{border-left-color:#fd6e23}.btn-wrap-triangle-left{display:inline-block;padding-left:1.74rem}.btn-wrap-triangle-left .btn{text-indent:-.92rem}.btn-wrap-triangle-left .btn:after{border-color:transparent #e3e3e3 transparent transparent;border-width:1.84rem 1.84rem 1.84rem 0;margin-right:-1.74rem;right:100%}.btn-wrap-triangle-left .btn:focus:after,.btn-wrap-triangle-left .btn:hover:after{border-right-color:#dbdbdb}.btn-wrap-triangle-left .btn:active:after{border-right-color:#d6d6d6}.btn-wrap-triangle-left .btn:not(.disabled):active,.btn-wrap-triangle-left .btn:not([disabled]):active{right:1px}.ie9 .btn-wrap-triangle-left .btn.disabled:after,.ie9 .btn-wrap-triangle-left .btn[disabled]:after{border-color:transparent #f0f0f0 transparent transparent}.ie9 .btn-wrap-triangle-left .btn.disabled:active:after,.ie9 .btn-wrap-triangle-left .btn.disabled:hover:after,.ie9 .btn-wrap-triangle-left .btn[disabled]:active:after,.ie9 .btn-wrap-triangle-left .btn[disabled]:hover:after{border-right-color:#f0f0f0}.btn-wrap-triangle-left .btn-prime:after{border-color:transparent #eb5202 transparent transparent}.btn-wrap-triangle-left .btn-prime:focus:after,.btn-wrap-triangle-left .btn-prime:hover:after{border-right-color:#e04f00}.btn-wrap-triangle-left .btn-prime:active:after{border-right-color:#f65405}.btn-wrap-triangle-left .btn-prime:not(.disabled):active,.btn-wrap-triangle-left .btn-prime:not([disabled]):active{right:1px}.ie9 .btn-wrap-triangle-left .btn-prime.disabled:after,.ie9 .btn-wrap-triangle-left .btn-prime[disabled]:after{border-color:transparent #fd6e23 transparent transparent}.ie9 .btn-wrap-triangle-left .btn-prime.disabled:active:after,.ie9 .btn-wrap-triangle-left .btn-prime.disabled:hover:after,.ie9 .btn-wrap-triangle-left .btn-prime[disabled]:active:after,.ie9 .btn-wrap-triangle-left .btn-prime[disabled]:hover:after{border-right-color:#fd6e23}.btn-expand{background-color:transparent;border:none;color:#303030;font-family:'Open Sans','Helvetica Neue',Helvetica,Arial,sans-serif;font-size:1.4rem;font-weight:700;padding:0;position:relative}.btn-expand.expanded:after{border-color:transparent transparent #303030;border-width:0 .285em .36em}.btn-expand.expanded:hover:after{border-color:transparent transparent #3d3d3d}.btn-expand:hover{background-color:transparent;border:none;color:#3d3d3d}.btn-expand:hover:after{border-color:#3d3d3d transparent transparent}.btn-expand:after{border-color:#303030 transparent transparent;border-style:solid;border-width:.36em .285em 0;content:'';height:0;left:100%;margin-left:.5em;margin-top:-.18em;position:absolute;top:50%;width:0}[class*=col-] .form-el-input,[class*=col-] .form-el-select{width:100%}.form-fieldset{border:none;margin:0 0 1em;padding:0}.form-row{margin-bottom:2.2rem}.form-row .form-row{margin-bottom:.4rem}.form-row .form-label{display:block;font-weight:600;padding:.6rem 2.1em 0 0;text-align:right}.form-row .form-label.required{position:relative}.form-row .form-label.required:after{color:#eb5202;content:'*';font-size:1.15em;position:absolute;right:.7em;top:.5em}.form-row .form-el-checkbox+.form-label:before,.form-row .form-el-radio+.form-label:before{top:.7rem}.form-row .form-el-checkbox+.form-label:after,.form-row .form-el-radio+.form-label:after{top:1.1rem}.form-row.form-row-text{padding-top:.6rem}.form-row.form-row-text .action-sign-out{font-size:1.2rem;margin-left:1rem}.form-note{font-size:1.2rem;font-weight:600;margin-top:1rem}.form-el-dummy{display:none}.fieldset{border:0;margin:0;min-width:0;padding:0}input:not([disabled]):focus,textarea:not([disabled]):focus{box-shadow:none}.form-el-input{border:1px solid #adadad;color:#303030;padding:.35em .55em .5em}.form-el-input:hover{border-color:#949494}.form-el-input:focus{border-color:#008bdb}.form-el-input:required{box-shadow:none}.form-label{margin-bottom:.5em}[class*=form-label][for]{cursor:pointer}.form-el-insider-wrap{display:table;width:100%}.form-el-insider-input{display:table-cell;width:100%}.form-el-insider{border-radius:2px;display:table-cell;padding:.43em .55em .5em 0;vertical-align:top}.form-legend,.form-legend-expand,.form-legend-light{display:block;margin:0}.form-legend,.form-legend-expand{font-size:1.25em;font-weight:600;margin-bottom:2.5em;padding-top:1.5em}.form-legend{border-top:1px solid #ccc;width:100%}.form-legend-light{font-size:1em;margin-bottom:1.5em}.form-legend-expand{cursor:pointer;transition:opacity .2s linear}.form-legend-expand:hover{opacity:.85}.form-legend-expand.expanded:after{content:'\e615'}.form-legend-expand:after{content:'\e616';font-family:Icons;font-size:1.15em;font-weight:400;margin-left:.5em;vertical-align:sub}.form-el-checkbox.disabled+.form-label,.form-el-checkbox.disabled+.form-label:before,.form-el-checkbox[disabled]+.form-label,.form-el-checkbox[disabled]+.form-label:before,.form-el-radio.disabled+.form-label,.form-el-radio.disabled+.form-label:before,.form-el-radio[disabled]+.form-label,.form-el-radio[disabled]+.form-label:before{cursor:default;opacity:.5;pointer-events:none}.form-el-checkbox:not(.disabled)+.form-label:hover:before,.form-el-checkbox:not([disabled])+.form-label:hover:before,.form-el-radio:not(.disabled)+.form-label:hover:before,.form-el-radio:not([disabled])+.form-label:hover:before{border-color:#514943}.form-el-checkbox+.form-label,.form-el-radio+.form-label{font-weight:400;padding-left:2em;padding-right:0;position:relative;text-align:left;transition:border-color .1s linear}.form-el-checkbox+.form-label:before,.form-el-radio+.form-label:before{border:1px solid;content:'';left:0;position:absolute;top:.1rem;transition:border-color .1s linear}.form-el-checkbox+.form-label:before{background-color:#fff;border-color:#adadad;border-radius:2px;font-size:1.2rem;height:1.6rem;line-height:1.2;width:1.6rem}.form-el-checkbox:checked+.form-label::before{content:'\e62d';font-family:Icons}.form-el-radio+.form-label:before{background-color:#fff;border:1px solid #adadad;border-radius:100%;height:1.8rem;width:1.8rem}.form-el-radio+.form-label:after{background:0 0;border:.5rem solid transparent;border-radius:100%;content:'';height:0;left:.4rem;position:absolute;top:.5rem;transition:background .3s linear;width:0}.form-el-radio:checked+.form-label{cursor:default}.form-el-radio:checked+.form-label:after{border-color:#514943}.form-select-label{border:1px solid #adadad;color:#303030;cursor:pointer;display:block;overflow:hidden;position:relative;z-index:0}.form-select-label:hover,.form-select-label:hover:after{border-color:#949494}.form-select-label:active,.form-select-label:active:after,.form-select-label:focus,.form-select-label:focus:after{border-color:#008bdb}.form-select-label:after{background:#e3e3e3;border-left:1px solid #adadad;bottom:0;content:'';position:absolute;right:0;top:0;width:2.36em;z-index:-2}.ie9 .form-select-label:after{display:none}.form-select-label:before{border-color:#303030 transparent transparent;border-style:solid;border-width:5px 4px 0;content:'';height:0;margin-right:-4px;margin-top:-2.5px;position:absolute;right:1.18em;top:50%;width:0;z-index:-1}.ie9 .form-select-label:before{display:none}.form-select-label .form-el-select{background:0 0;border:none;border-radius:0;content:'';display:block;margin:0;padding:.35em calc(2.36em + 10%) .5em .55em;width:110%}.ie9 .form-select-label .form-el-select{padding-right:.55em;width:100%}.form-select-label .form-el-select::-ms-expand{display:none}.form-el-select{background:#fff;border:1px solid #adadad;border-radius:2px;color:#303030;display:block;padding:.35em .55em}.multiselect-custom{border:1px solid #adadad;height:45.2rem;margin:0 0 1.5rem;overflow:auto;position:relative}.multiselect-custom ul{margin:0;padding:0;list-style:none;min-width:29rem}.multiselect-custom .item{padding:1rem 1.4rem}.multiselect-custom .selected{background-color:#e0f6fe}.multiselect-custom .form-label{margin-bottom:0}[class*=form-el-].invalid{border-color:#e22626}[class*=form-el-].invalid+.error-container{display:block}.error-container{background-color:#fffbbb;border:1px solid #ee7d7d;color:#514943;display:none;font-size:1.19rem;margin-top:.2rem;padding:.8rem 1rem .9rem}.check-result-message{margin-left:.5em;min-height:3.68rem;-ms-align-items:center;-ms-flex-align:center;align-items:center;display:-ms-flexbox;display:flex}.check-result-text{margin-left:.5em}body:not([class]){min-width:0}.container{display:block;margin:0 auto 4rem;max-width:100rem;padding:0}.abs-action-delete,.action-close:before,.action-next:before,.action-previous:before,.admin-user .admin__action-dropdown:before,.admin__action-multiselect-dropdown:before,.admin__action-multiselect-search-label:before,.admin__control-checkbox+label:before,.admin__control-collapsible .admin__collapsible-block-wrapper .fieldset-wrapper-title .action-delete:before,.admin__control-table .action-delete:before,.admin__current-filters-list .action-remove:before,.admin__data-grid-action-bookmarks .action-delete:before,.admin__data-grid-action-bookmarks .action-edit:before,.admin__data-grid-action-bookmarks .action-submit:before,.admin__data-grid-action-bookmarks .admin__action-dropdown:before,.admin__data-grid-action-columns .admin__action-dropdown:before,.admin__data-grid-action-export .admin__action-dropdown:before,.admin__field-fallback-reset:before,.admin__menu .level-0>a:before,.admin__page-nav-item-message .admin__page-nav-item-message-icon,.admin__page-nav-title._collapsible:after,.data-grid-filters-action-wrap .action-default:before,.data-grid-row-changed:after,.data-grid-row-parent>td .data-grid-checkbox-cell-inner:before,.data-grid-search-control-wrap .action-submit:before,.extensions-information .list .extension-delete,.icon-failed:before,.icon-success:before,.notifications-action:before,.notifications-close:before,.page-actions .page-actions-buttons>button.action-back:before,.page-actions .page-actions-buttons>button.back:before,.page-actions>button.action-back:before,.page-actions>button.back:before,.page-title-jumbo-success:before,.search-global-label:before,.selectmenu .action-delete:before,.selectmenu .action-edit:before,.selectmenu .action-save:before,.setup-home-item:before,.sticky-header .data-grid-search-control-wrap .data-grid-search-label:before,.store-switcher .dropdown-menu .dropdown-toolbar a:before,.tooltip .help a:before,.tooltip .help span:before{-webkit-font-smoothing:antialiased;font-family:Icons;font-style:normal;font-weight:400;line-height:1;speak:none}.text-stretch{margin-bottom:1.5em}.page-title-jumbo{font-size:4rem;font-weight:300;letter-spacing:-.05em;margin-bottom:2.9rem}.page-title-jumbo-success:before{color:#79a22e;content:'\e62d';font-size:3.9rem;margin-left:-.3rem;margin-right:2.4rem}.list{margin-bottom:3rem}.list-dot .list-item{display:list-item;list-style-position:inside;margin-bottom:1.2rem}.list-title{color:#333;font-size:1.4rem;font-weight:700;letter-spacing:.025em;margin-bottom:1.2rem}.list-item-failed:before,.list-item-success:before,.list-item-warning:before{font-family:Icons;font-size:1.6rem;top:0}.list-item-success:before{content:'\e62d';font-size:1.6rem}.list-item-failed:before{content:'\e632';font-size:1.4rem;left:.1rem;top:.2rem}.list-item-warning:before{content:'\e623';font-size:1.3rem;left:.2rem}.form-wrap{margin-bottom:3.6rem;padding-top:2.1rem}.form-el-label-horizontal{display:inline-block;font-size:1.3rem;font-weight:600;letter-spacing:.025em;margin-bottom:.4rem;margin-left:.4rem}.app-updater{min-width:768px}body._has-modal{height:100%;overflow:hidden;width:100%}.modals-overlay{z-index:899}.modal-popup,.modal-slide{bottom:0;min-width:0;position:fixed;right:0;top:0;visibility:hidden}.modal-popup._show,.modal-slide._show{visibility:visible}.modal-popup._show .modal-inner-wrap,.modal-slide._show .modal-inner-wrap{-ms-transform:translate(0,0);transform:translate(0,0)}.modal-popup .modal-inner-wrap,.modal-slide .modal-inner-wrap{background-color:#fff;box-shadow:0 0 12px 2px rgba(0,0,0,.35);opacity:1;pointer-events:auto}.modal-slide{left:14.8rem;z-index:900}.modal-slide._show .modal-inner-wrap{-ms-transform:translateX(0);transform:translateX(0)}.modal-slide .modal-inner-wrap{height:100%;overflow-y:auto;position:static;-ms-transform:translateX(100%);transform:translateX(100%);transition-duration:.3s;transition-property:transform,visibility;transition-timing-function:ease-in-out;width:auto}.modal-slide._inner-scroll .modal-inner-wrap{overflow-y:visible;display:-ms-flexbox;display:flex;-ms-flex-direction:column;flex-direction:column}.modal-slide._inner-scroll .modal-footer,.modal-slide._inner-scroll .modal-header{-webkit-flex-grow:0;-ms-flex-positive:0;flex-grow:0;-ms-flex-negative:0;flex-shrink:0}.modal-slide._inner-scroll .modal-content{overflow-y:auto}.modal-slide._inner-scroll .modal-footer{margin-top:auto}.modal-slide .modal-content,.modal-slide .modal-footer,.modal-slide .modal-header{padding:0 2.6rem 2.6rem}.modal-slide .modal-header{padding-bottom:2.1rem;padding-top:2.1rem}.modal-popup{z-index:900;left:0;overflow-y:auto}.modal-popup._show .modal-inner-wrap{-ms-transform:translateY(0);transform:translateY(0)}.modal-popup .modal-inner-wrap{margin:5rem auto;width:75%;display:-ms-flexbox;display:flex;-ms-flex-direction:column;flex-direction:column;box-sizing:border-box;height:auto;left:0;position:absolute;right:0;-ms-transform:translateY(-200%);transform:translateY(-200%);transition-duration:.2s;transition-property:transform,visibility;transition-timing-function:ease}.modal-popup._inner-scroll{overflow-y:visible}.ie10 .modal-popup._inner-scroll,.ie9 .modal-popup._inner-scroll{overflow-y:auto}.modal-popup._inner-scroll .modal-inner-wrap{max-height:90%}.ie10 .modal-popup._inner-scroll .modal-inner-wrap,.ie9 .modal-popup._inner-scroll .modal-inner-wrap{max-height:none}.modal-popup._inner-scroll .modal-content{overflow-y:auto}.modal-popup .modal-content,.modal-popup .modal-footer,.modal-popup .modal-header{padding-left:3rem;padding-right:3rem}.modal-popup .modal-footer,.modal-popup .modal-header{-webkit-flex-grow:0;-ms-flex-positive:0;flex-grow:0;-ms-flex-negative:0;flex-shrink:0}.modal-popup .modal-header{padding-bottom:1.2rem;padding-top:3rem}.modal-popup .modal-footer{margin-top:auto;padding-bottom:3rem}.modal-popup .modal-footer-actions{text-align:right}.admin__action-dropdown-wrap{display:inline-block;position:relative}.admin__action-dropdown-wrap .admin__action-dropdown-text:after{left:-6px;right:0}.admin__action-dropdown-wrap .admin__action-dropdown-menu{left:auto;right:0}.admin__action-dropdown-wrap._active .admin__action-dropdown,.admin__action-dropdown-wrap.active .admin__action-dropdown{border-color:#007bdb;box-shadow:1px 1px 5px rgba(0,0,0,.5)}.admin__action-dropdown-wrap._active .admin__action-dropdown-text:after,.admin__action-dropdown-wrap.active .admin__action-dropdown-text:after{background-color:#fff;content:'';height:6px;position:absolute;top:100%}.admin__action-dropdown-wrap._active .admin__action-dropdown-menu,.admin__action-dropdown-wrap.active .admin__action-dropdown-menu{display:block}.admin__action-dropdown-wrap._disabled .admin__action-dropdown{cursor:default}.admin__action-dropdown-wrap._disabled:hover .admin__action-dropdown{color:#333}.admin__action-dropdown{background-color:#fff;border:1px solid transparent;border-bottom:none;border-radius:0;box-shadow:none;color:#333;display:inline-block;font-size:1.3rem;font-weight:400;letter-spacing:-.025em;padding:.7rem 3.3rem .8rem 1.5rem;position:relative;vertical-align:baseline;z-index:2}.admin__action-dropdown._active:after,.admin__action-dropdown.active:after{-ms-transform:rotate(180deg);transform:rotate(180deg)}.admin__action-dropdown:after{border-color:#000 transparent transparent;border-style:solid;border-width:.5rem .4rem 0;content:'';height:0;margin-top:-.2rem;position:absolute;top:50%;transition:all .2s linear;width:0}._active .admin__action-dropdown:after,.active .admin__action-dropdown:after{-ms-transform:rotate(180deg);transform:rotate(180deg)}.admin__action-dropdown:hover:after{border-color:#000 transparent transparent}.admin__action-dropdown:focus,.admin__action-dropdown:hover{background-color:#fff;color:#000;text-decoration:none}.admin__action-dropdown:after{right:1.5rem}.admin__action-dropdown:before{margin-right:1rem}.admin__action-dropdown-menu{background-color:#fff;border:1px solid #007bdb;box-shadow:1px 1px 5px rgba(0,0,0,.5);display:none;line-height:1.36;margin-top:-1px;min-width:120%;padding:.5rem 1rem;position:absolute;top:100%;transition:all .15s ease;z-index:1}.admin__action-dropdown-menu>li{display:block}.admin__action-dropdown-menu>li>a{color:#333;display:block;text-decoration:none;padding:.6rem .5rem}.selectmenu{display:inline-block;position:relative;text-align:left;z-index:1}.selectmenu._active{border-color:#007bdb;z-index:500}.selectmenu .action-delete,.selectmenu .action-edit,.selectmenu .action-save{background-color:transparent;border-color:transparent;box-shadow:none;padding:0 1rem}.selectmenu .action-delete:hover,.selectmenu .action-edit:hover,.selectmenu .action-save:hover{background-color:transparent;border-color:transparent;box-shadow:none}.selectmenu .action-delete:before,.selectmenu .action-edit:before,.selectmenu .action-save:before{content:'\e630'}.selectmenu .action-delete,.selectmenu .action-edit{border:0 solid #fff;border-left-width:1px;bottom:0;position:absolute;right:0;top:0;z-index:1}.selectmenu .action-delete:hover,.selectmenu .action-edit:hover{border:0 solid #fff;border-left-width:1px}.selectmenu .action-save:before{content:'\e625'}.selectmenu .action-edit:before{content:'\e631'}.selectmenu-value{display:inline-block}.selectmenu-value input[type=text]{-webkit-appearance:none;-moz-appearance:none;-ms-appearance:none;appearance:none;border:0;display:inline;margin:0;width:6rem}body._keyfocus .selectmenu-value input[type=text]:focus{box-shadow:none}.selectmenu-toggle{padding-right:3rem;background:0 0;border-width:0;bottom:0;float:right;position:absolute;right:0;top:0;width:0}.selectmenu-toggle._active:after,.selectmenu-toggle.active:after{-ms-transform:rotate(180deg);transform:rotate(180deg)}.selectmenu-toggle:after{border-color:#000 transparent transparent;border-style:solid;border-width:.5rem .4rem 0;content:'';height:0;margin-top:-.2rem;position:absolute;right:1.1rem;top:50%;transition:all .2s linear;width:0}._active .selectmenu-toggle:after,.active .selectmenu-toggle:after{-ms-transform:rotate(180deg);transform:rotate(180deg)}.selectmenu-toggle:hover:after{border-color:#000 transparent transparent}.selectmenu-toggle:active,.selectmenu-toggle:focus,.selectmenu-toggle:hover{background:0 0}.selectmenu._active .selectmenu-toggle:before{border-color:#007bdb}body._keyfocus .selectmenu-toggle:focus{box-shadow:none}.selectmenu-toggle:before{background:#e3e3e3;border-left:1px solid #adadad;bottom:0;content:'';display:block;position:absolute;right:0;top:0;width:3.2rem}.selectmenu-items{background:#fff;border:1px solid #007bdb;box-shadow:1px 1px 5px rgba(0,0,0,.5);display:none;float:left;left:-1px;margin-top:3px;max-width:20rem;min-width:calc(100% + 2px);position:absolute;top:100%}.selectmenu-items._active{display:block}.selectmenu-items ul{float:left;list-style-type:none;margin:0;min-width:100%;padding:0}.selectmenu-items li{-webkit-flex-direction:row;display:flex;-ms-flex-direction:row;flex-direction:row;transition:background .2s linear}.selectmenu-items li:hover{background:#e3e3e3}.selectmenu-items li:last-child .selectmenu-item-action,.selectmenu-items li:last-child .selectmenu-item-action:visited{color:#008bdb;text-decoration:none}.selectmenu-items li:last-child .selectmenu-item-action:hover{color:#0fa7ff;text-decoration:underline}.selectmenu-items li:last-child .selectmenu-item-action:active{color:#ff5501;text-decoration:underline}.selectmenu-item{position:relative;width:100%;z-index:1}li._edit>.selectmenu-item{display:none}.selectmenu-item-edit{display:none;padding:.3rem 4rem .3rem .4rem;position:relative;white-space:nowrap;z-index:1}li:last-child .selectmenu-item-edit{padding-right:.4rem}.selectmenu-item-edit .admin__control-text{margin:0;width:5.4rem}li._edit .selectmenu-item-edit{display:block}.selectmenu-item-action{-webkit-appearance:none;-moz-appearance:none;-ms-appearance:none;appearance:none;background:0 0;border:0;color:#333;display:block;font-size:1.4rem;font-weight:400;min-width:100%;padding:1rem 6rem 1rem 1.5rem;text-align:left;transition:background .2s linear;width:5rem}.selectmenu-item-action:focus,.selectmenu-item-action:hover{background:#e3e3e3}.abs-actions-split-xl .action-default,.page-actions .actions-split .action-default{margin-right:4rem}.abs-actions-split-xl .action-toggle,.page-actions .actions-split .action-toggle{padding-right:4rem}.abs-actions-split-xl .action-toggle:after,.page-actions .actions-split .action-toggle:after{border-width:.9rem .6rem 0;margin-top:-.3rem;right:1.4rem}.actions-split{position:relative;z-index:400}.actions-split._active,.actions-split.active,.actions-split:hover{box-shadow:0 0 0 1px #007bdb}.actions-split._active .action-toggle.action-primary,.actions-split._active .action-toggle.primary,.actions-split.active .action-toggle.action-primary,.actions-split.active .action-toggle.primary{background-color:#ba4000;border-color:#ba4000}.actions-split._active .dropdown-menu,.actions-split.active .dropdown-menu{opacity:1;visibility:visible;display:block}.actions-split .action-default,.actions-split .action-toggle{float:left;margin:0}.actions-split .action-default._active,.actions-split .action-default.active,.actions-split .action-default:hover,.actions-split .action-toggle._active,.actions-split .action-toggle.active,.actions-split .action-toggle:hover{box-shadow:none}.actions-split .action-default{margin-right:3.2rem;min-width:9.3rem}.actions-split .action-toggle{padding-right:3.2rem;border-left-color:rgba(0,0,0,.2);bottom:0;padding-left:0;position:absolute;right:0;top:0}.actions-split .action-toggle._active:after,.actions-split .action-toggle.active:after{-ms-transform:rotate(180deg);transform:rotate(180deg)}.actions-split .action-toggle:after{border-color:#000 transparent transparent;border-style:solid;border-width:.5rem .4rem 0;content:'';height:0;margin-top:-.2rem;position:absolute;right:1.2rem;top:50%;transition:all .2s linear;width:0}._active .actions-split .action-toggle:after,.active .actions-split .action-toggle:after{-ms-transform:rotate(180deg);transform:rotate(180deg)}.actions-split .action-toggle:hover:after{border-color:#000 transparent transparent}.actions-split .action-toggle.action-primary:after,.actions-split .action-toggle.action-secondary:after,.actions-split .action-toggle.primary:after,.actions-split .action-toggle.secondary:after{border-color:#fff transparent transparent}.actions-split .action-toggle>span{clip:rect(0,0,0,0);overflow:hidden;position:absolute}.action-select-wrap{display:inline-block;position:relative}.action-select-wrap .action-select{padding-right:3.2rem;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;background-color:#fff;font-weight:400;text-align:left}.action-select-wrap .action-select._active:after,.action-select-wrap .action-select.active:after{-ms-transform:rotate(180deg);transform:rotate(180deg)}.action-select-wrap .action-select:after{border-color:#000 transparent transparent;border-style:solid;border-width:.5rem .4rem 0;content:'';height:0;margin-top:-.2rem;position:absolute;right:1.2rem;top:50%;transition:all .2s linear;width:0}._active .action-select-wrap .action-select:after,.active .action-select-wrap .action-select:after{-ms-transform:rotate(180deg);transform:rotate(180deg)}.action-select-wrap .action-select:hover:after{border-color:#000 transparent transparent}.action-select-wrap .action-select:hover,.action-select-wrap .action-select:hover:before{border-color:#878787}.action-select-wrap .action-select:before{background-color:#e3e3e3;border:1px solid #adadad;bottom:0;content:'';position:absolute;right:0;top:0;width:3.2rem}.action-select-wrap .action-select._active{border-color:#007bdb}.action-select-wrap .action-select._active:before{border-color:#007bdb #007bdb #007bdb #adadad}.action-select-wrap .action-select[disabled]{color:#333}.action-select-wrap .action-select[disabled]:after{border-color:#333 transparent transparent}.action-select-wrap._active{z-index:500}.action-select-wrap._active .action-select,.action-select-wrap._active .action-select:before{border-color:#007bdb}.action-select-wrap._active .action-select:after{-ms-transform:rotate(180deg);transform:rotate(180deg)}.action-select-wrap .abs-action-menu .action-submenu,.action-select-wrap .abs-action-menu .action-submenu .action-submenu,.action-select-wrap .action-menu,.action-select-wrap .action-menu .action-submenu,.action-select-wrap .actions-split .action-menu .action-submenu,.action-select-wrap .actions-split .action-menu .action-submenu .action-submenu,.action-select-wrap .actions-split .dropdown-menu .action-submenu,.action-select-wrap .actions-split .dropdown-menu .action-submenu .action-submenu{max-height:45rem;overflow-y:auto}.action-select-wrap .abs-action-menu .action-submenu ._disabled:hover,.action-select-wrap .abs-action-menu .action-submenu .action-submenu ._disabled:hover,.action-select-wrap .action-menu ._disabled:hover,.action-select-wrap .action-menu .action-submenu ._disabled:hover,.action-select-wrap .actions-split .action-menu .action-submenu ._disabled:hover,.action-select-wrap .actions-split .action-menu .action-submenu .action-submenu ._disabled:hover,.action-select-wrap .actions-split .dropdown-menu .action-submenu ._disabled:hover,.action-select-wrap .actions-split .dropdown-menu .action-submenu .action-submenu ._disabled:hover{background:#fff}.action-select-wrap .abs-action-menu .action-submenu ._disabled .action-menu-item,.action-select-wrap .abs-action-menu .action-submenu .action-submenu ._disabled .action-menu-item,.action-select-wrap .action-menu ._disabled .action-menu-item,.action-select-wrap .action-menu .action-submenu ._disabled .action-menu-item,.action-select-wrap .actions-split .action-menu .action-submenu ._disabled .action-menu-item,.action-select-wrap .actions-split .action-menu .action-submenu .action-submenu ._disabled .action-menu-item,.action-select-wrap .actions-split .dropdown-menu .action-submenu ._disabled .action-menu-item,.action-select-wrap .actions-split .dropdown-menu .action-submenu .action-submenu ._disabled .action-menu-item{cursor:default;opacity:.5}.action-select-wrap .action-menu-items{left:0;position:absolute;right:0;top:100%}.action-select-wrap .action-menu-items>.abs-action-menu .action-submenu,.action-select-wrap .action-menu-items>.abs-action-menu .action-submenu .action-submenu,.action-select-wrap .action-menu-items>.action-menu,.action-select-wrap .action-menu-items>.action-menu .action-submenu,.action-select-wrap .action-menu-items>.actions-split .action-menu .action-submenu,.action-select-wrap .action-menu-items>.actions-split .action-menu .action-submenu .action-submenu,.action-select-wrap .action-menu-items>.actions-split .dropdown-menu .action-submenu,.action-select-wrap .action-menu-items>.actions-split .dropdown-menu .action-submenu .action-submenu{min-width:100%;position:static}.action-select-wrap .action-menu-items>.abs-action-menu .action-submenu .action-submenu,.action-select-wrap .action-menu-items>.abs-action-menu .action-submenu .action-submenu .action-submenu,.action-select-wrap .action-menu-items>.action-menu .action-submenu,.action-select-wrap .action-menu-items>.action-menu .action-submenu .action-submenu,.action-select-wrap .action-menu-items>.actions-split .action-menu .action-submenu .action-submenu,.action-select-wrap .action-menu-items>.actions-split .action-menu .action-submenu .action-submenu .action-submenu,.action-select-wrap .action-menu-items>.actions-split .dropdown-menu .action-submenu .action-submenu,.action-select-wrap .action-menu-items>.actions-split .dropdown-menu .action-submenu .action-submenu .action-submenu{position:absolute}.action-multicheck-wrap{display:inline-block;height:1.6rem;padding-top:1px;position:relative;width:3.1rem;z-index:200}.action-multicheck-wrap:hover .action-multicheck-toggle,.action-multicheck-wrap:hover .admin__control-checkbox+label:before{border-color:#878787}.action-multicheck-wrap._active .action-multicheck-toggle,.action-multicheck-wrap._active .admin__control-checkbox+label:before{border-color:#007bdb}.action-multicheck-wrap._active .abs-action-menu .action-submenu,.action-multicheck-wrap._active .abs-action-menu .action-submenu .action-submenu,.action-multicheck-wrap._active .action-menu,.action-multicheck-wrap._active .action-menu .action-submenu,.action-multicheck-wrap._active .actions-split .action-menu .action-submenu,.action-multicheck-wrap._active .actions-split .action-menu .action-submenu .action-submenu,.action-multicheck-wrap._active .actions-split .dropdown-menu .action-submenu,.action-multicheck-wrap._active .actions-split .dropdown-menu .action-submenu .action-submenu{opacity:1;visibility:visible;display:block}.action-multicheck-wrap._disabled .admin__control-checkbox+label:before{background-color:#fff}.action-multicheck-wrap._disabled .action-multicheck-toggle,.action-multicheck-wrap._disabled .admin__control-checkbox+label:before{border-color:#adadad;opacity:1}.action-multicheck-wrap .action-multicheck-toggle,.action-multicheck-wrap .admin__control-checkbox,.action-multicheck-wrap .admin__control-checkbox+label{float:left}.action-multicheck-wrap .action-multicheck-toggle{border-radius:0 1px 1px 0;height:1.6rem;margin-left:-1px;padding:0;position:relative;transition:border-color .1s linear;width:1.6rem}.action-multicheck-wrap .action-multicheck-toggle._active:after,.action-multicheck-wrap .action-multicheck-toggle.active:after{-ms-transform:rotate(180deg);transform:rotate(180deg)}.action-multicheck-wrap .action-multicheck-toggle:after{border-color:#000 transparent transparent;border-style:solid;border-width:.5rem .4rem 0;content:'';height:0;margin-top:-.2rem;position:absolute;top:50%;transition:all .2s linear;width:0}._active .action-multicheck-wrap .action-multicheck-toggle:after,.active .action-multicheck-wrap .action-multicheck-toggle:after{-ms-transform:rotate(180deg);transform:rotate(180deg)}.action-multicheck-wrap .action-multicheck-toggle:hover:after{border-color:#000 transparent transparent}.action-multicheck-wrap .action-multicheck-toggle:focus{border-color:#007bdb}.action-multicheck-wrap .action-multicheck-toggle:after{right:.3rem}.action-multicheck-wrap .abs-action-menu .action-submenu,.action-multicheck-wrap .abs-action-menu .action-submenu .action-submenu,.action-multicheck-wrap .action-menu,.action-multicheck-wrap .action-menu .action-submenu,.action-multicheck-wrap .actions-split .action-menu .action-submenu,.action-multicheck-wrap .actions-split .action-menu .action-submenu .action-submenu,.action-multicheck-wrap .actions-split .dropdown-menu .action-submenu,.action-multicheck-wrap .actions-split .dropdown-menu .action-submenu .action-submenu{left:-1.1rem;margin-top:1px;right:auto;text-align:left}.action-multicheck-wrap .action-menu-item{white-space:nowrap}.admin__action-multiselect-wrap{display:block;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}.admin__action-multiselect-wrap.action-select-wrap:focus{box-shadow:none}.admin__action-multiselect-wrap.action-select-wrap .abs-action-menu .action-submenu,.admin__action-multiselect-wrap.action-select-wrap .abs-action-menu .action-submenu .action-submenu,.admin__action-multiselect-wrap.action-select-wrap .action-menu,.admin__action-multiselect-wrap.action-select-wrap .action-menu .action-submenu,.admin__action-multiselect-wrap.action-select-wrap .actions-split .action-menu .action-submenu,.admin__action-multiselect-wrap.action-select-wrap .actions-split .action-menu .action-submenu .action-submenu,.admin__action-multiselect-wrap.action-select-wrap .actions-split .dropdown-menu .action-submenu,.admin__action-multiselect-wrap.action-select-wrap .actions-split .dropdown-menu .action-submenu .action-submenu{max-height:none;overflow-y:inherit}.admin__action-multiselect-wrap .action-menu-item{transition:background-color .1s linear}.admin__action-multiselect-wrap .action-menu-item._selected{background-color:#e0f6fe}.admin__action-multiselect-wrap .action-menu-item._hover{background-color:#e3e3e3}.admin__action-multiselect-wrap .action-menu-item._unclickable{cursor:default}.admin__action-multiselect-wrap .admin__action-multiselect{border:1px solid #adadad;cursor:pointer;display:block;min-height:3.2rem;padding-right:3.6rem;white-space:normal}.admin__action-multiselect-wrap .admin__action-multiselect:after{bottom:1.25rem;top:auto}.admin__action-multiselect-wrap .admin__action-multiselect:before{height:3.3rem;top:auto}.admin__control-table-wrapper .admin__action-multiselect-wrap{position:static}.admin__control-table-wrapper .admin__action-multiselect-wrap .admin__action-multiselect{position:relative}.admin__control-table-wrapper .admin__action-multiselect-wrap .admin__action-multiselect:before{right:-1px;top:-1px}.admin__control-table-wrapper .admin__action-multiselect-wrap .abs-action-menu .action-submenu,.admin__control-table-wrapper .admin__action-multiselect-wrap .abs-action-menu .action-submenu .action-submenu,.admin__control-table-wrapper .admin__action-multiselect-wrap .action-menu,.admin__control-table-wrapper .admin__action-multiselect-wrap .action-menu .action-submenu,.admin__control-table-wrapper .admin__action-multiselect-wrap .actions-split .action-menu .action-submenu,.admin__control-table-wrapper .admin__action-multiselect-wrap .actions-split .action-menu .action-submenu .action-submenu,.admin__control-table-wrapper .admin__action-multiselect-wrap .actions-split .dropdown-menu .action-submenu,.admin__control-table-wrapper .admin__action-multiselect-wrap .actions-split .dropdown-menu .action-submenu .action-submenu{left:auto;min-width:34rem;right:auto;top:auto;z-index:1}.admin__action-multiselect-wrap .admin__action-multiselect-item-path{color:#a79d95;font-size:1.2rem;font-weight:400;padding-left:1rem}.admin__action-multiselect-actions-wrap{border-top:1px solid #e3e3e3;margin:0 1rem;padding:1rem 0;text-align:center}.admin__action-multiselect-actions-wrap .action-default{font-size:1.3rem;min-width:13rem}.admin__action-multiselect-text{padding:.6rem 1rem}.abs-action-menu .action-submenu,.abs-action-menu .action-submenu .action-submenu,.action-menu,.action-menu .action-submenu,.actions-split .action-menu .action-submenu,.actions-split .action-menu .action-submenu .action-submenu,.actions-split .dropdown-menu .action-submenu,.actions-split .dropdown-menu .action-submenu .action-submenu{text-align:left}.admin__action-multiselect-label{cursor:pointer;position:relative;z-index:1}.admin__action-multiselect-label:before{margin-right:.5rem}._unclickable .admin__action-multiselect-label{cursor:default;font-weight:700}.admin__action-multiselect-search-wrap{border-bottom:1px solid #e3e3e3;margin:0 1rem;padding:1rem 0;position:relative}.admin__action-multiselect-search{padding-right:3rem;width:100%}.admin__action-multiselect-search-label{display:block;font-size:1.5rem;height:1em;overflow:hidden;position:absolute;right:2.2rem;top:1.7rem;width:1em}.admin__action-multiselect-search-label:before{content:'\e60c'}.admin__action-multiselect-search-count{color:#a79d95;margin-top:1rem}.admin__action-multiselect-menu-inner{margin-bottom:0;max-height:46rem;overflow-y:auto}.admin__action-multiselect-menu-inner .admin__action-multiselect-menu-inner{list-style:none;max-height:none;overflow:hidden;padding-left:2.2rem}.admin__action-multiselect-menu-inner ._hidden{display:none}.admin__action-multiselect-crumb{background-color:#f5f5f5;border:1px solid #a79d95;border-radius:1px;display:inline-block;font-size:1.2rem;margin:.3rem -4px .3rem .3rem;padding:.3rem 2.4rem .4rem 1rem;position:relative;transition:border-color .1s linear}.admin__action-multiselect-crumb:hover{border-color:#908379}.admin__action-multiselect-crumb .action-close{bottom:0;font-size:.5em;position:absolute;right:0;top:0;width:2rem}.admin__action-multiselect-crumb .action-close:hover{color:#000}.admin__action-multiselect-crumb .action-close:active,.admin__action-multiselect-crumb .action-close:focus{background-color:transparent}.admin__action-multiselect-crumb .action-close:active{-ms-transform:scale(0.9);transform:scale(0.9)}.admin__action-multiselect-tree .abs-action-menu .action-submenu,.admin__action-multiselect-tree .abs-action-menu .action-submenu .action-submenu,.admin__action-multiselect-tree .action-menu,.admin__action-multiselect-tree .action-menu .action-submenu,.admin__action-multiselect-tree .actions-split .action-menu .action-submenu,.admin__action-multiselect-tree .actions-split .action-menu .action-submenu .action-submenu,.admin__action-multiselect-tree .actions-split .dropdown-menu .action-submenu,.admin__action-multiselect-tree .actions-split .dropdown-menu .action-submenu .action-submenu{min-width:34.7rem}.admin__action-multiselect-tree .abs-action-menu .action-submenu .action-menu-item,.admin__action-multiselect-tree .abs-action-menu .action-submenu .action-submenu .action-menu-item,.admin__action-multiselect-tree .action-menu .action-menu-item,.admin__action-multiselect-tree .action-menu .action-submenu .action-menu-item,.admin__action-multiselect-tree .actions-split .action-menu .action-submenu .action-menu-item,.admin__action-multiselect-tree .actions-split .action-menu .action-submenu .action-submenu .action-menu-item,.admin__action-multiselect-tree .actions-split .dropdown-menu .action-submenu .action-menu-item,.admin__action-multiselect-tree .actions-split .dropdown-menu .action-submenu .action-submenu .action-menu-item{margin-top:.1rem}.admin__action-multiselect-tree .action-menu-item{margin-left:4.2rem;position:relative}.admin__action-multiselect-tree .action-menu-item._expended:before{border-left:1px dashed #a79d95;bottom:0;content:'';left:-1rem;position:absolute;top:1rem;width:1px}.admin__action-multiselect-tree .action-menu-item._expended .admin__action-multiselect-dropdown:before{content:'\e615'}.admin__action-multiselect-tree .action-menu-item._with-checkbox .admin__action-multiselect-label{padding-left:2.6rem}.admin__action-multiselect-tree .admin__action-multiselect-menu-inner{position:relative}.admin__action-multiselect-tree .admin__action-multiselect-menu-inner .admin__action-multiselect-menu-inner{padding-left:3.2rem}.admin__action-multiselect-tree .admin__action-multiselect-menu-inner .admin__action-multiselect-menu-inner:before{left:4.3rem}.admin__action-multiselect-tree .admin__action-multiselect-menu-inner-item{position:relative}.admin__action-multiselect-tree .admin__action-multiselect-menu-inner-item:last-child:before{height:2.1rem}.admin__action-multiselect-tree .admin__action-multiselect-menu-inner-item:after,.admin__action-multiselect-tree .admin__action-multiselect-menu-inner-item:before{content:'';left:0;position:absolute}.admin__action-multiselect-tree .admin__action-multiselect-menu-inner-item:after{border-top:1px dashed #a79d95;height:1px;top:2.1rem;width:5.2rem}.admin__action-multiselect-tree .admin__action-multiselect-menu-inner-item:before{border-left:1px dashed #a79d95;height:100%;top:0;width:1px}.admin__action-multiselect-tree .admin__action-multiselect-menu-inner-item._parent:after{width:4.2rem}.admin__action-multiselect-tree .admin__action-multiselect-menu-inner-item._root{margin-left:-1rem}.admin__action-multiselect-tree .admin__action-multiselect-menu-inner-item._root:after{left:3.2rem;width:2.2rem}.admin__action-multiselect-tree .admin__action-multiselect-menu-inner-item._root:before{left:3.2rem;top:1rem}.admin__action-multiselect-tree .admin__action-multiselect-menu-inner-item._root._parent:after{display:none}.admin__action-multiselect-tree .admin__action-multiselect-menu-inner-item._root:first-child:before{top:2.1rem}.admin__action-multiselect-tree .admin__action-multiselect-menu-inner-item._root:last-child:before{height:1rem}.admin__action-multiselect-tree .admin__action-multiselect-label{line-height:2.2rem;vertical-align:middle;word-break:break-all}.admin__action-multiselect-tree .admin__action-multiselect-label:before{left:0;position:absolute;top:.4rem}.admin__action-multiselect-dropdown{border-radius:50%;height:2.2rem;left:-2.2rem;position:absolute;top:1rem;width:2.2rem;z-index:1}.admin__action-multiselect-dropdown:before{background:#fff;color:#a79d95;content:'\e616';font-size:2.2rem}.admin__actions-switch{display:inline-block;position:relative;vertical-align:middle}.admin__field-control .admin__actions-switch{line-height:3.2rem}.admin__actions-switch+.admin__field-service{min-width:34rem}._disabled .admin__actions-switch-checkbox+.admin__actions-switch-label,.admin__actions-switch-checkbox.disabled+.admin__actions-switch-label{cursor:not-allowed;opacity:.5;pointer-events:none}.admin__actions-switch-checkbox:checked+.admin__actions-switch-label:before{left:15px}.admin__actions-switch-checkbox:checked+.admin__actions-switch-label:after{background:#79a22e}.admin__actions-switch-checkbox:checked+.admin__actions-switch-label .admin__actions-switch-text:before{content:attr(data-text-on)}.admin__actions-switch-checkbox:focus+.admin__actions-switch-label:after,.admin__actions-switch-checkbox:focus+.admin__actions-switch-label:before{border-color:#007bdb}._error .admin__actions-switch-checkbox+.admin__actions-switch-label:after,._error .admin__actions-switch-checkbox+.admin__actions-switch-label:before{border-color:#e22626}.admin__actions-switch-label{cursor:pointer;display:inline-block;height:22px;line-height:22px;position:relative;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;vertical-align:middle}.admin__actions-switch-label:after,.admin__actions-switch-label:before{left:0;position:absolute;right:auto;top:0}.admin__actions-switch-label:before{background:#fff;border:1px solid #aaa6a0;border-radius:100%;content:'';display:block;height:22px;transition:left .2s ease-in 0s;width:22px;z-index:1}.admin__actions-switch-label:after{background:#e3e3e3;border:1px solid #aaa6a0;border-radius:12px;content:'';display:block;height:22px;transition:background .2s ease-in 0s;vertical-align:middle;width:37px;z-index:0}.admin__actions-switch-text:before{content:attr(data-text-off);padding-left:47px;white-space:nowrap}.abs-action-delete,.abs-action-reset,.action-close,.admin__field-fallback-reset,.extensions-information .list .extension-delete,.notifications-close,.search-global-field._active .search-global-action{background-color:transparent;border:none;border-radius:0;box-shadow:none;margin:0;padding:0}.abs-action-delete:hover,.abs-action-reset:hover,.action-close:hover,.admin__field-fallback-reset:hover,.extensions-information .list .extension-delete:hover,.notifications-close:hover,.search-global-field._active .search-global-action:hover{background-color:transparent;border:none;box-shadow:none}.abs-action-default,.abs-action-pattern,.abs-action-primary,.abs-action-quaternary,.abs-action-secondary,.abs-action-tertiary,.action-default,.action-primary,.action-quaternary,.action-secondary,.action-tertiary,.modal-popup .modal-footer .action-primary,.modal-popup .modal-footer .action-secondary,.page-actions .page-actions-buttons>button,.page-actions .page-actions-buttons>button.action-primary,.page-actions .page-actions-buttons>button.action-secondary,.page-actions .page-actions-buttons>button.primary,.page-actions>button,.page-actions>button.action-primary,.page-actions>button.action-secondary,.page-actions>button.primary,button,button.primary,button.secondary,button.tertiary{border:1px solid;border-radius:0;display:inline-block;font-family:'Open Sans','Helvetica Neue',Helvetica,Arial,sans-serif;font-size:1.4rem;font-weight:600;line-height:1.36;padding:.6rem 1em;text-align:center;vertical-align:baseline}.abs-action-default.disabled,.abs-action-default[disabled],.abs-action-pattern.disabled,.abs-action-pattern[disabled],.abs-action-primary.disabled,.abs-action-primary[disabled],.abs-action-quaternary.disabled,.abs-action-quaternary[disabled],.abs-action-secondary.disabled,.abs-action-secondary[disabled],.abs-action-tertiary.disabled,.abs-action-tertiary[disabled],.action-default.disabled,.action-default[disabled],.action-primary.disabled,.action-primary[disabled],.action-quaternary.disabled,.action-quaternary[disabled],.action-secondary.disabled,.action-secondary[disabled],.action-tertiary.disabled,.action-tertiary[disabled],.modal-popup .modal-footer .action-primary.disabled,.modal-popup .modal-footer .action-primary[disabled],.modal-popup .modal-footer .action-secondary.disabled,.modal-popup .modal-footer .action-secondary[disabled],.page-actions .page-actions-buttons>button.action-primary.disabled,.page-actions .page-actions-buttons>button.action-primary[disabled],.page-actions .page-actions-buttons>button.action-secondary.disabled,.page-actions .page-actions-buttons>button.action-secondary[disabled],.page-actions .page-actions-buttons>button.disabled,.page-actions .page-actions-buttons>button.primary.disabled,.page-actions .page-actions-buttons>button.primary[disabled],.page-actions .page-actions-buttons>button[disabled],.page-actions>button.action-primary.disabled,.page-actions>button.action-primary[disabled],.page-actions>button.action-secondary.disabled,.page-actions>button.action-secondary[disabled],.page-actions>button.disabled,.page-actions>button.primary.disabled,.page-actions>button.primary[disabled],.page-actions>button[disabled],button.disabled,button.primary.disabled,button.primary[disabled],button.secondary.disabled,button.secondary[disabled],button.tertiary.disabled,button.tertiary[disabled],button[disabled]{cursor:default;opacity:.5;pointer-events:none}.abs-action-l,.modal-popup .modal-footer .action-primary,.modal-popup .modal-footer .action-secondary,.page-actions .page-actions-buttons>button,.page-actions .page-actions-buttons>button.action-primary,.page-actions .page-actions-buttons>button.action-secondary,.page-actions .page-actions-buttons>button.primary,.page-actions button,.page-actions>button.action-primary,.page-actions>button.action-secondary,.page-actions>button.primary{font-size:1.6rem;letter-spacing:.025em;padding-bottom:.6875em;padding-top:.6875em}.abs-action-delete,.extensions-information .list .extension-delete{display:inline-block;font-size:1.6rem;margin-left:1.2rem;padding-top:.7rem;text-decoration:none;vertical-align:middle}.abs-action-delete:after,.extensions-information .list .extension-delete:after{color:#666;content:'\e630'}.abs-action-delete:hover:after,.extensions-information .list .extension-delete:hover:after{color:#35302c}.abs-action-button-as-link,.action-advanced,.data-grid .action-delete{line-height:1.36;padding:0;color:#008bdb;text-decoration:none;background:0 0;border:0;display:inline;font-weight:400;border-radius:0}.abs-action-button-as-link:visited,.action-advanced:visited,.data-grid .action-delete:visited{color:#008bdb;text-decoration:none}.abs-action-button-as-link:hover,.action-advanced:hover,.data-grid .action-delete:hover{text-decoration:underline}.abs-action-button-as-link:active,.action-advanced:active,.data-grid .action-delete:active{color:#ff5501;text-decoration:underline}.abs-action-button-as-link:hover,.action-advanced:hover,.data-grid .action-delete:hover{color:#0fa7ff}.abs-action-button-as-link:active,.abs-action-button-as-link:focus,.abs-action-button-as-link:hover,.action-advanced:active,.action-advanced:focus,.action-advanced:hover,.data-grid .action-delete:active,.data-grid .action-delete:focus,.data-grid .action-delete:hover{background:0 0;border:0}.abs-action-button-as-link.disabled,.abs-action-button-as-link[disabled],.action-advanced.disabled,.action-advanced[disabled],.data-grid .action-delete.disabled,.data-grid .action-delete[disabled],fieldset[disabled] .abs-action-button-as-link,fieldset[disabled] .action-advanced,fieldset[disabled] .data-grid .action-delete{color:#008bdb;opacity:.5;cursor:default;pointer-events:none;text-decoration:underline}.abs-action-button-as-link:active,.abs-action-button-as-link:not(:focus),.action-advanced:active,.action-advanced:not(:focus),.data-grid .action-delete:active,.data-grid .action-delete:not(:focus){box-shadow:none}.abs-action-button-as-link:focus,.action-advanced:focus,.data-grid .action-delete:focus{color:#0fa7ff}.abs-action-default,button{background:#e3e3e3;border-color:#adadad;color:#514943}.abs-action-default:active,.abs-action-default:focus,.abs-action-default:hover,button:active,button:focus,button:hover{background-color:#dbdbdb;color:#514943;text-decoration:none}.abs-action-primary,.page-actions .page-actions-buttons>button.action-primary,.page-actions .page-actions-buttons>button.primary,.page-actions>button.action-primary,.page-actions>button.primary,button.primary{background-color:#eb5202;border-color:#eb5202;color:#fff;text-shadow:1px 1px 0 rgba(0,0,0,.25)}.abs-action-primary:active,.abs-action-primary:focus,.abs-action-primary:hover,.page-actions .page-actions-buttons>button.action-primary:active,.page-actions .page-actions-buttons>button.action-primary:focus,.page-actions .page-actions-buttons>button.action-primary:hover,.page-actions .page-actions-buttons>button.primary:active,.page-actions .page-actions-buttons>button.primary:focus,.page-actions .page-actions-buttons>button.primary:hover,.page-actions>button.action-primary:active,.page-actions>button.action-primary:focus,.page-actions>button.action-primary:hover,.page-actions>button.primary:active,.page-actions>button.primary:focus,.page-actions>button.primary:hover,button.primary:active,button.primary:focus,button.primary:hover{background-color:#ba4000;border-color:#b84002;box-shadow:0 0 0 1px #007bdb;color:#fff;text-decoration:none}.abs-action-primary.disabled,.abs-action-primary[disabled],.page-actions .page-actions-buttons>button.action-primary.disabled,.page-actions .page-actions-buttons>button.action-primary[disabled],.page-actions .page-actions-buttons>button.primary.disabled,.page-actions .page-actions-buttons>button.primary[disabled],.page-actions>button.action-primary.disabled,.page-actions>button.action-primary[disabled],.page-actions>button.primary.disabled,.page-actions>button.primary[disabled],button.primary.disabled,button.primary[disabled]{cursor:default;opacity:.5;pointer-events:none}.abs-action-secondary,.modal-popup .modal-footer .action-primary,.page-actions .page-actions-buttons>button.action-secondary,.page-actions>button.action-secondary,button.secondary{background-color:#514943;border-color:#514943;color:#fff;text-shadow:1px 1px 1px rgba(0,0,0,.3)}.abs-action-secondary:active,.abs-action-secondary:focus,.abs-action-secondary:hover,.modal-popup .modal-footer .action-primary:active,.modal-popup .modal-footer .action-primary:focus,.modal-popup .modal-footer .action-primary:hover,.page-actions .page-actions-buttons>button.action-secondary:active,.page-actions .page-actions-buttons>button.action-secondary:focus,.page-actions .page-actions-buttons>button.action-secondary:hover,.page-actions>button.action-secondary:active,.page-actions>button.action-secondary:focus,.page-actions>button.action-secondary:hover,button.secondary:active,button.secondary:focus,button.secondary:hover{background-color:#35302c;border-color:#35302c;box-shadow:0 0 0 1px #007bdb;color:#fff;text-decoration:none}.abs-action-secondary:active,.modal-popup .modal-footer .action-primary:active,.page-actions .page-actions-buttons>button.action-secondary:active,.page-actions>button.action-secondary:active,button.secondary:active{background-color:#35302c}.abs-action-tertiary,.modal-popup .modal-footer .action-secondary,button.tertiary{background-color:transparent;border-color:transparent;text-shadow:none;color:#008bdb}.abs-action-tertiary:active,.abs-action-tertiary:focus,.abs-action-tertiary:hover,.modal-popup .modal-footer .action-secondary:active,.modal-popup .modal-footer .action-secondary:focus,.modal-popup .modal-footer .action-secondary:hover,button.tertiary:active,button.tertiary:focus,button.tertiary:hover{background-color:transparent;border-color:transparent;box-shadow:none;color:#0fa7ff;text-decoration:underline}.abs-action-quaternary,.page-actions .page-actions-buttons>button,.page-actions>button{background-color:transparent;border-color:transparent;text-shadow:none;color:#333}.abs-action-quaternary:active,.abs-action-quaternary:focus,.abs-action-quaternary:hover,.page-actions .page-actions-buttons>button:active,.page-actions .page-actions-buttons>button:focus,.page-actions .page-actions-buttons>button:hover,.page-actions>button:active,.page-actions>button:focus,.page-actions>button:hover{background-color:transparent;border-color:transparent;box-shadow:none;color:#1a1a1a}.abs-action-menu,.actions-split .abs-action-menu .action-submenu,.actions-split .abs-action-menu .action-submenu .action-submenu,.actions-split .action-menu,.actions-split .action-menu .action-submenu,.actions-split .actions-split .dropdown-menu .action-submenu,.actions-split .actions-split .dropdown-menu .action-submenu .action-submenu,.actions-split .dropdown-menu{text-align:left;background-color:#fff;border:1px solid #007bdb;border-radius:1px;box-shadow:1px 1px 5px rgba(0,0,0,.5);color:#333;display:none;font-weight:400;left:0;list-style:none;margin:2px 0 0;min-width:0;padding:0;position:absolute;right:0;top:100%}.abs-action-menu._active,.actions-split .abs-action-menu .action-submenu .action-submenu._active,.actions-split .abs-action-menu .action-submenu._active,.actions-split .action-menu .action-submenu._active,.actions-split .action-menu._active,.actions-split .actions-split .dropdown-menu .action-submenu .action-submenu._active,.actions-split .actions-split .dropdown-menu .action-submenu._active,.actions-split .dropdown-menu._active{display:block}.abs-action-menu>li,.actions-split .abs-action-menu .action-submenu .action-submenu>li,.actions-split .abs-action-menu .action-submenu>li,.actions-split .action-menu .action-submenu>li,.actions-split .action-menu>li,.actions-split .actions-split .dropdown-menu .action-submenu .action-submenu>li,.actions-split .actions-split .dropdown-menu .action-submenu>li,.actions-split .dropdown-menu>li{border:none;display:block;padding:0;transition:background-color .1s linear}.abs-action-menu>li>a:hover,.actions-split .abs-action-menu .action-submenu .action-submenu>li>a:hover,.actions-split .abs-action-menu .action-submenu>li>a:hover,.actions-split .action-menu .action-submenu>li>a:hover,.actions-split .action-menu>li>a:hover,.actions-split .actions-split .dropdown-menu .action-submenu .action-submenu>li>a:hover,.actions-split .actions-split .dropdown-menu .action-submenu>li>a:hover,.actions-split .dropdown-menu>li>a:hover{text-decoration:none}.abs-action-menu>li._visible,.abs-action-menu>li:hover,.actions-split .abs-action-menu .action-submenu .action-submenu>li._visible,.actions-split .abs-action-menu .action-submenu .action-submenu>li:hover,.actions-split .abs-action-menu .action-submenu>li._visible,.actions-split .abs-action-menu .action-submenu>li:hover,.actions-split .action-menu .action-submenu>li._visible,.actions-split .action-menu .action-submenu>li:hover,.actions-split .action-menu>li._visible,.actions-split .action-menu>li:hover,.actions-split .actions-split .dropdown-menu .action-submenu .action-submenu>li._visible,.actions-split .actions-split .dropdown-menu .action-submenu .action-submenu>li:hover,.actions-split .actions-split .dropdown-menu .action-submenu>li._visible,.actions-split .actions-split .dropdown-menu .action-submenu>li:hover,.actions-split .dropdown-menu>li._visible,.actions-split .dropdown-menu>li:hover{background-color:#e3e3e3}.abs-action-menu>li:active,.actions-split .abs-action-menu .action-submenu .action-submenu>li:active,.actions-split .abs-action-menu .action-submenu>li:active,.actions-split .action-menu .action-submenu>li:active,.actions-split .action-menu>li:active,.actions-split .actions-split .dropdown-menu .action-submenu .action-submenu>li:active,.actions-split .actions-split .dropdown-menu .action-submenu>li:active,.actions-split .dropdown-menu>li:active{background-color:#cacaca}.abs-action-menu>li._parent,.actions-split .abs-action-menu .action-submenu .action-submenu>li._parent,.actions-split .abs-action-menu .action-submenu>li._parent,.actions-split .action-menu .action-submenu>li._parent,.actions-split .action-menu>li._parent,.actions-split .actions-split .dropdown-menu .action-submenu .action-submenu>li._parent,.actions-split .actions-split .dropdown-menu .action-submenu>li._parent,.actions-split .dropdown-menu>li._parent{-webkit-flex-direction:row;display:flex;-ms-flex-direction:row;flex-direction:row}.abs-action-menu>li._parent>.action-menu-item,.actions-split .abs-action-menu .action-submenu .action-submenu>li._parent>.action-menu-item,.actions-split .abs-action-menu .action-submenu>li._parent>.action-menu-item,.actions-split .action-menu .action-submenu>li._parent>.action-menu-item,.actions-split .action-menu>li._parent>.action-menu-item,.actions-split .actions-split .dropdown-menu .action-submenu .action-submenu>li._parent>.action-menu-item,.actions-split .actions-split .dropdown-menu .action-submenu>li._parent>.action-menu-item,.actions-split .dropdown-menu>li._parent>.action-menu-item{min-width:100%}.abs-action-menu .action-menu-item,.abs-action-menu .item,.actions-split .abs-action-menu .action-submenu .action-menu-item,.actions-split .abs-action-menu .action-submenu .action-submenu .action-menu-item,.actions-split .abs-action-menu .action-submenu .action-submenu .item,.actions-split .abs-action-menu .action-submenu .item,.actions-split .action-menu .action-menu-item,.actions-split .action-menu .action-submenu .action-menu-item,.actions-split .action-menu .action-submenu .item,.actions-split .action-menu .item,.actions-split .actions-split .dropdown-menu .action-submenu .action-menu-item,.actions-split .actions-split .dropdown-menu .action-submenu .action-submenu .action-menu-item,.actions-split .actions-split .dropdown-menu .action-submenu .action-submenu .item,.actions-split .actions-split .dropdown-menu .action-submenu .item,.actions-split .dropdown-menu .action-menu-item,.actions-split .dropdown-menu .item{cursor:pointer;display:block;padding:.6875em 1em}.abs-action-menu .action-submenu,.actions-split .action-menu .action-submenu,.actions-split .action-menu .action-submenu .action-submenu,.actions-split .dropdown-menu .action-submenu{bottom:auto;left:auto;margin-left:0;margin-top:-1px;position:absolute;right:auto;top:auto}.ie9 .abs-action-menu .action-submenu,.ie9 .actions-split .abs-action-menu .action-submenu .action-submenu,.ie9 .actions-split .abs-action-menu .action-submenu .action-submenu .action-submenu,.ie9 .actions-split .action-menu .action-submenu,.ie9 .actions-split .action-menu .action-submenu .action-submenu,.ie9 .actions-split .actions-split .dropdown-menu .action-submenu .action-submenu,.ie9 .actions-split .actions-split .dropdown-menu .action-submenu .action-submenu .action-submenu,.ie9 .actions-split .dropdown-menu .action-submenu{margin-left:99%;margin-top:-3.5rem}.abs-action-menu a.action-menu-item,.actions-split .abs-action-menu .action-submenu .action-submenu a.action-menu-item,.actions-split .abs-action-menu .action-submenu a.action-menu-item,.actions-split .action-menu .action-submenu a.action-menu-item,.actions-split .action-menu a.action-menu-item,.actions-split .actions-split .dropdown-menu .action-submenu .action-submenu a.action-menu-item,.actions-split .actions-split .dropdown-menu .action-submenu a.action-menu-item,.actions-split .dropdown-menu a.action-menu-item{color:#333}.abs-action-menu a.action-menu-item:focus,.actions-split .abs-action-menu .action-submenu .action-submenu a.action-menu-item:focus,.actions-split .abs-action-menu .action-submenu a.action-menu-item:focus,.actions-split .action-menu .action-submenu a.action-menu-item:focus,.actions-split .action-menu a.action-menu-item:focus,.actions-split .actions-split .dropdown-menu .action-submenu .action-submenu a.action-menu-item:focus,.actions-split .actions-split .dropdown-menu .action-submenu a.action-menu-item:focus,.actions-split .dropdown-menu a.action-menu-item:focus{background-color:#e3e3e3;box-shadow:none}.abs-action-wrap-triangle{position:relative}.abs-action-wrap-triangle .action-default{width:100%}.abs-action-wrap-triangle .action-default:after,.abs-action-wrap-triangle .action-default:before{border-style:solid;content:'';height:0;position:absolute;top:0;width:0}.abs-action-wrap-triangle .action-default:active,.abs-action-wrap-triangle .action-default:focus,.abs-action-wrap-triangle .action-default:hover{box-shadow:none}._keyfocus .abs-action-wrap-triangle .action-default:focus{box-shadow:0 0 0 1px #007bdb}.ie10 .abs-action-wrap-triangle .action-default.disabled,.ie10 .abs-action-wrap-triangle .action-default[disabled],.ie9 .abs-action-wrap-triangle .action-default.disabled,.ie9 .abs-action-wrap-triangle .action-default[disabled]{background-color:#fcfcfc;opacity:1;text-shadow:none}.abs-action-wrap-triangle-right{display:inline-block;padding-right:1.6rem;position:relative}.abs-action-wrap-triangle-right .action-default:after,.abs-action-wrap-triangle-right .action-default:before{border-color:transparent transparent transparent #e3e3e3;border-width:1.7rem 0 1.6rem 1.7rem;left:100%;margin-left:-1.7rem}.abs-action-wrap-triangle-right .action-default:before{border-left-color:#949494;right:-1px}.abs-action-wrap-triangle-right .action-default:active:after,.abs-action-wrap-triangle-right .action-default:focus:after,.abs-action-wrap-triangle-right .action-default:hover:after{border-left-color:#dbdbdb}.ie10 .abs-action-wrap-triangle-right .action-default.disabled:after,.ie10 .abs-action-wrap-triangle-right .action-default[disabled]:after,.ie9 .abs-action-wrap-triangle-right .action-default.disabled:after,.ie9 .abs-action-wrap-triangle-right .action-default[disabled]:after{border-color:transparent transparent transparent #fcfcfc}.abs-action-wrap-triangle-right .action-primary:after{border-color:transparent transparent transparent #eb5202}.abs-action-wrap-triangle-right .action-primary:active:after,.abs-action-wrap-triangle-right .action-primary:focus:after,.abs-action-wrap-triangle-right .action-primary:hover:after{border-left-color:#ba4000}.abs-action-wrap-triangle-left{display:inline-block;padding-left:1.6rem}.abs-action-wrap-triangle-left .action-default{text-indent:-.85rem}.abs-action-wrap-triangle-left .action-default:after,.abs-action-wrap-triangle-left .action-default:before{border-color:transparent #e3e3e3 transparent transparent;border-width:1.7rem 1.7rem 1.6rem 0;margin-right:-1.7rem;right:100%}.abs-action-wrap-triangle-left .action-default:before{border-right-color:#949494;left:-1px}.abs-action-wrap-triangle-left .action-default:active:after,.abs-action-wrap-triangle-left .action-default:focus:after,.abs-action-wrap-triangle-left .action-default:hover:after{border-right-color:#dbdbdb}.ie10 .abs-action-wrap-triangle-left .action-default.disabled:after,.ie10 .abs-action-wrap-triangle-left .action-default[disabled]:after,.ie9 .abs-action-wrap-triangle-left .action-default.disabled:after,.ie9 .abs-action-wrap-triangle-left .action-default[disabled]:after{border-color:transparent #fcfcfc transparent transparent}.abs-action-wrap-triangle-left .action-primary:after{border-color:transparent #eb5202 transparent transparent}.abs-action-wrap-triangle-left .action-primary:active:after,.abs-action-wrap-triangle-left .action-primary:focus:after,.abs-action-wrap-triangle-left .action-primary:hover:after{border-right-color:#ba4000}.action-default,button{background:#e3e3e3;border-color:#adadad;color:#514943}.action-default:active,.action-default:focus,.action-default:hover,button:active,button:focus,button:hover{background-color:#dbdbdb;color:#514943;text-decoration:none}.action-primary{background-color:#eb5202;border-color:#eb5202;color:#fff;text-shadow:1px 1px 0 rgba(0,0,0,.25)}.action-primary:active,.action-primary:focus,.action-primary:hover{background-color:#ba4000;border-color:#b84002;box-shadow:0 0 0 1px #007bdb;color:#fff;text-decoration:none}.action-primary.disabled,.action-primary[disabled]{cursor:default;opacity:.5;pointer-events:none}.action-secondary{background-color:#514943;border-color:#514943;color:#fff;text-shadow:1px 1px 1px rgba(0,0,0,.3)}.action-secondary:active,.action-secondary:focus,.action-secondary:hover{background-color:#35302c;border-color:#35302c;box-shadow:0 0 0 1px #007bdb;color:#fff;text-decoration:none}.action-secondary:active{background-color:#35302c}.action-quaternary,.action-tertiary{background-color:transparent;border-color:transparent;text-shadow:none}.action-quaternary:active,.action-quaternary:focus,.action-quaternary:hover,.action-tertiary:active,.action-tertiary:focus,.action-tertiary:hover{background-color:transparent;border-color:transparent;box-shadow:none}.action-tertiary{color:#008bdb}.action-tertiary:active,.action-tertiary:focus,.action-tertiary:hover{color:#0fa7ff;text-decoration:underline}.action-quaternary{color:#333}.action-quaternary:active,.action-quaternary:focus,.action-quaternary:hover{color:#1a1a1a}.action-close>span{clip:rect(0,0,0,0);overflow:hidden;position:absolute}.action-close:active{-ms-transform:scale(0.9);transform:scale(0.9)}.action-close:before{content:'\e62f';transition:color .1s linear}.action-close:hover{cursor:pointer;text-decoration:none}.abs-action-menu .action-submenu,.abs-action-menu .action-submenu .action-submenu,.action-menu,.action-menu .action-submenu,.actions-split .action-menu .action-submenu,.actions-split .action-menu .action-submenu .action-submenu,.actions-split .dropdown-menu .action-submenu,.actions-split .dropdown-menu .action-submenu .action-submenu{background-color:#fff;border:1px solid #007bdb;border-radius:1px;box-shadow:1px 1px 5px rgba(0,0,0,.5);color:#333;display:none;font-weight:400;left:0;list-style:none;margin:2px 0 0;min-width:0;padding:0;position:absolute;right:0;top:100%}.abs-action-menu .action-submenu .action-submenu._active,.abs-action-menu .action-submenu._active,.action-menu .action-submenu._active,.action-menu._active,.actions-split .action-menu .action-submenu .action-submenu._active,.actions-split .action-menu .action-submenu._active,.actions-split .dropdown-menu .action-submenu .action-submenu._active,.actions-split .dropdown-menu .action-submenu._active{display:block}.abs-action-menu .action-submenu .action-submenu>li,.abs-action-menu .action-submenu>li,.action-menu .action-submenu>li,.action-menu>li,.actions-split .action-menu .action-submenu .action-submenu>li,.actions-split .action-menu .action-submenu>li,.actions-split .dropdown-menu .action-submenu .action-submenu>li,.actions-split .dropdown-menu .action-submenu>li{border:none;display:block;padding:0;transition:background-color .1s linear}.abs-action-menu .action-submenu .action-submenu>li>a:hover,.abs-action-menu .action-submenu>li>a:hover,.action-menu .action-submenu>li>a:hover,.action-menu>li>a:hover,.actions-split .action-menu .action-submenu .action-submenu>li>a:hover,.actions-split .action-menu .action-submenu>li>a:hover,.actions-split .dropdown-menu .action-submenu .action-submenu>li>a:hover,.actions-split .dropdown-menu .action-submenu>li>a:hover{text-decoration:none}.abs-action-menu .action-submenu .action-submenu>li._visible,.abs-action-menu .action-submenu .action-submenu>li:hover,.abs-action-menu .action-submenu>li._visible,.abs-action-menu .action-submenu>li:hover,.action-menu .action-submenu>li._visible,.action-menu .action-submenu>li:hover,.action-menu>li._visible,.action-menu>li:hover,.actions-split .action-menu .action-submenu .action-submenu>li._visible,.actions-split .action-menu .action-submenu .action-submenu>li:hover,.actions-split .action-menu .action-submenu>li._visible,.actions-split .action-menu .action-submenu>li:hover,.actions-split .dropdown-menu .action-submenu .action-submenu>li._visible,.actions-split .dropdown-menu .action-submenu .action-submenu>li:hover,.actions-split .dropdown-menu .action-submenu>li._visible,.actions-split .dropdown-menu .action-submenu>li:hover{background-color:#e3e3e3}.abs-action-menu .action-submenu .action-submenu>li:active,.abs-action-menu .action-submenu>li:active,.action-menu .action-submenu>li:active,.action-menu>li:active,.actions-split .action-menu .action-submenu .action-submenu>li:active,.actions-split .action-menu .action-submenu>li:active,.actions-split .dropdown-menu .action-submenu .action-submenu>li:active,.actions-split .dropdown-menu .action-submenu>li:active{background-color:#cacaca}.abs-action-menu .action-submenu .action-submenu>li._parent,.abs-action-menu .action-submenu>li._parent,.action-menu .action-submenu>li._parent,.action-menu>li._parent,.actions-split .action-menu .action-submenu .action-submenu>li._parent,.actions-split .action-menu .action-submenu>li._parent,.actions-split .dropdown-menu .action-submenu .action-submenu>li._parent,.actions-split .dropdown-menu .action-submenu>li._parent{-webkit-flex-direction:row;display:flex;-ms-flex-direction:row;flex-direction:row}.abs-action-menu .action-submenu .action-submenu>li._parent>.action-menu-item,.abs-action-menu .action-submenu>li._parent>.action-menu-item,.action-menu .action-submenu>li._parent>.action-menu-item,.action-menu>li._parent>.action-menu-item,.actions-split .action-menu .action-submenu .action-submenu>li._parent>.action-menu-item,.actions-split .action-menu .action-submenu>li._parent>.action-menu-item,.actions-split .dropdown-menu .action-submenu .action-submenu>li._parent>.action-menu-item,.actions-split .dropdown-menu .action-submenu>li._parent>.action-menu-item{min-width:100%}.abs-action-menu .action-submenu .action-menu-item,.abs-action-menu .action-submenu .action-submenu .action-menu-item,.abs-action-menu .action-submenu .action-submenu .item,.abs-action-menu .action-submenu .item,.action-menu .action-menu-item,.action-menu .action-submenu .action-menu-item,.action-menu .action-submenu .item,.action-menu .item,.actions-split .action-menu .action-submenu .action-menu-item,.actions-split .action-menu .action-submenu .action-submenu .action-menu-item,.actions-split .action-menu .action-submenu .action-submenu .item,.actions-split .action-menu .action-submenu .item,.actions-split .dropdown-menu .action-submenu .action-menu-item,.actions-split .dropdown-menu .action-submenu .action-submenu .action-menu-item,.actions-split .dropdown-menu .action-submenu .action-submenu .item,.actions-split .dropdown-menu .action-submenu .item{cursor:pointer;display:block;padding:.6875em 1em}.abs-action-menu .action-submenu .action-submenu,.action-menu .action-submenu,.actions-split .action-menu .action-submenu .action-submenu,.actions-split .dropdown-menu .action-submenu .action-submenu{bottom:auto;left:auto;margin-left:0;margin-top:-1px;position:absolute;right:auto;top:auto}.ie9 .abs-action-menu .action-submenu .action-submenu,.ie9 .abs-action-menu .action-submenu .action-submenu .action-submenu,.ie9 .action-menu .action-submenu,.ie9 .action-menu .action-submenu .action-submenu,.ie9 .actions-split .action-menu .action-submenu .action-submenu,.ie9 .actions-split .action-menu .action-submenu .action-submenu .action-submenu,.ie9 .actions-split .dropdown-menu .action-submenu .action-submenu,.ie9 .actions-split .dropdown-menu .action-submenu .action-submenu .action-submenu{margin-left:99%;margin-top:-3.5rem}.abs-action-menu .action-submenu .action-submenu a.action-menu-item,.abs-action-menu .action-submenu a.action-menu-item,.action-menu .action-submenu a.action-menu-item,.action-menu a.action-menu-item,.actions-split .action-menu .action-submenu .action-submenu a.action-menu-item,.actions-split .action-menu .action-submenu a.action-menu-item,.actions-split .dropdown-menu .action-submenu .action-submenu a.action-menu-item,.actions-split .dropdown-menu .action-submenu a.action-menu-item{color:#333}.abs-action-menu .action-submenu .action-submenu a.action-menu-item:focus,.abs-action-menu .action-submenu a.action-menu-item:focus,.action-menu .action-submenu a.action-menu-item:focus,.action-menu a.action-menu-item:focus,.actions-split .action-menu .action-submenu .action-submenu a.action-menu-item:focus,.actions-split .action-menu .action-submenu a.action-menu-item:focus,.actions-split .dropdown-menu .action-submenu .action-submenu a.action-menu-item:focus,.actions-split .dropdown-menu .action-submenu a.action-menu-item:focus{background-color:#e3e3e3;box-shadow:none}.messages .message:last-child{margin:0 0 2rem}.message{background:#fffbbb;border:none;border-radius:0;color:#333;font-size:1.4rem;margin:0 0 1px;padding:1.8rem 4rem 1.8rem 5.5rem;position:relative;text-shadow:none}.message:before{background:0 0;border:0;color:#007bdb;content:'\e61a';font-family:Icons;font-size:1.9rem;font-style:normal;font-weight:400;height:auto;left:1.9rem;line-height:inherit;margin-top:-1.3rem;position:absolute;speak:none;text-shadow:none;top:50%;width:auto}.message-notice:before{color:#007bdb;content:'\e61a'}.message-warning:before{color:#eb5202;content:'\e623'}.message-error{background:#fcc}.message-error:before{color:#e22626;content:'\e632';font-size:1.5rem;left:2.2rem;margin-top:-1rem}.message-success:before{color:#79a22e;content:'\e62d'}.message-spinner:before{display:none}.message-spinner .spinner{font-size:2.5rem;left:1.5rem;position:absolute;top:1.5rem}.message-in-rating-edit{margin-left:1.8rem;margin-right:1.8rem}.modal-popup .action-close,.modal-slide .action-close{color:#736963;position:absolute;right:0;top:0;z-index:1}.modal-popup .action-close:active,.modal-slide .action-close:active{-ms-transform:none;transform:none}.modal-popup .action-close:active:before,.modal-slide .action-close:active:before{font-size:1.8rem}.modal-popup .action-close:hover:before,.modal-slide .action-close:hover:before{color:#58504b}.modal-popup .action-close:before,.modal-slide .action-close:before{font-size:2rem}.modal-popup .action-close:focus,.modal-slide .action-close:focus{background-color:transparent}.modal-popup.prompt .prompt-message{padding:2rem 0}.modal-popup.prompt .prompt-message input{width:100%}.modal-popup.confirm .modal-inner-wrap .message,.modal-popup.prompt .modal-inner-wrap .message{background:#fff}.modal-popup.modal-system-messages .modal-inner-wrap{background:#fffbbb}.modal-popup._image-box .modal-inner-wrap{margin:5rem auto;max-width:78rem;position:static}.modal-popup._image-box .thumbnail-preview{padding-bottom:3rem;text-align:center}.modal-popup._image-box .thumbnail-preview .thumbnail-preview-image-block{border:1px solid #ccc;margin:0 auto 2rem;max-width:58rem;padding:2rem}.modal-popup._image-box .thumbnail-preview .thumbnail-preview-image{max-height:54rem}.modal-popup .modal-title{font-size:2.4rem;margin-right:6.4rem}.modal-popup .modal-footer{padding-top:2.6rem;text-align:right}.modal-popup .action-close{padding:3rem}.modal-popup .action-close:active,.modal-popup .action-close:focus{background:0 0;padding-right:3.1rem;padding-top:3.1rem}.modal-slide .modal-content-new-attribute{-webkit-overflow-scrolling:touch;overflow:auto;padding-bottom:0}.modal-slide .modal-content-new-attribute iframe{margin-bottom:-2.5rem}.modal-slide .modal-title{font-size:2.1rem;margin-right:5.7rem}.modal-slide .action-close{padding:2.1rem 2.6rem}.modal-slide .action-close:active{padding-right:2.7rem;padding-top:2.2rem}.modal-slide .page-main-actions{margin-bottom:.6rem;margin-top:2.1rem}.modal-slide .magento-message{padding:0 3rem 3rem;position:relative}.modal-slide .magento-message .insert-title-inner,.modal-slide .main-col .insert-title-inner{border-bottom:1px solid #adadad;margin:0 0 2rem;padding-bottom:.5rem}.modal-slide .magento-message .insert-actions,.modal-slide .main-col .insert-actions{float:right}.modal-slide .magento-message .title,.modal-slide .main-col .title{font-size:1.6rem;padding-top:.5rem}.modal-slide .main-col,.modal-slide .side-col{float:left;padding-bottom:0}.modal-slide .main-col:after,.modal-slide .side-col:after{display:none}.modal-slide .side-col{width:20%}.modal-slide .main-col{padding-right:0;width:80%}.modal-slide .content-footer .form-buttons{float:right}.modal-title{font-weight:400;margin-bottom:0;min-height:1em}.modal-title span{font-size:1.4rem;font-style:italic;margin-left:1rem}.spinner{display:inline-block;font-size:4rem;height:1em;margin-right:1.5rem;position:relative;width:1em}.spinner>span:nth-child(1){animation-delay:.27s;-ms-transform:rotate(-315deg);transform:rotate(-315deg)}.spinner>span:nth-child(2){animation-delay:.36s;-ms-transform:rotate(-270deg);transform:rotate(-270deg)}.spinner>span:nth-child(3){animation-delay:.45s;-ms-transform:rotate(-225deg);transform:rotate(-225deg)}.spinner>span:nth-child(4){animation-delay:.54s;-ms-transform:rotate(-180deg);transform:rotate(-180deg)}.spinner>span:nth-child(5){animation-delay:.63s;-ms-transform:rotate(-135deg);transform:rotate(-135deg)}.spinner>span:nth-child(6){animation-delay:.72s;-ms-transform:rotate(-90deg);transform:rotate(-90deg)}.spinner>span:nth-child(7){animation-delay:.81s;-ms-transform:rotate(-45deg);transform:rotate(-45deg)}.spinner>span:nth-child(8){animation-delay:.9;-ms-transform:rotate(0deg);transform:rotate(0deg)}@keyframes fade{0%{background-color:#514943}100%{background-color:#fff}}.spinner>span{-ms-transform:scale(0.4);transform:scale(0.4);animation-name:fade;animation-duration:.72s;animation-iteration-count:infinite;animation-direction:linear;background-color:#fff;border-radius:6px;clip:rect(0 .28571429em .1em 0);height:.1em;margin-top:.5em;position:absolute;width:1em}.ie9 .spinner{background:url(../images/ajax-loader.gif) center no-repeat}.ie9 .spinner>span{display:none}.popup-loading{background:rgba(255,255,255,.8);border-color:#ef672f;color:#ef672f;font-size:14px;font-weight:700;left:50%;margin-left:-100px;padding:100px 0 10px;position:fixed;text-align:center;top:40%;width:200px;z-index:1003}.popup-loading:after{background-image:url(../images/loader-1.gif);content:'';height:64px;left:50%;margin:-32px 0 0 -32px;position:absolute;top:40%;width:64px;z-index:2}.loading-mask,.loading-old{background:rgba(255,255,255,.4);bottom:0;left:0;position:fixed;right:0;top:0;z-index:2003}.loading-mask img,.loading-old img{display:none}.loading-mask p,.loading-old p{margin-top:118px}.loading-mask .loader,.loading-old .loader{background:url(../images/loader-1.gif) 50% 30% no-repeat #f7f3eb;border-radius:5px;bottom:0;color:#575757;font-size:14px;font-weight:700;height:160px;left:0;margin:auto;opacity:.95;position:absolute;right:0;text-align:center;top:0;width:160px}.admin-user{float:right;line-height:1.36;margin-left:.3rem;z-index:490}.admin-user._active .admin__action-dropdown,.admin-user.active .admin__action-dropdown{border-color:#007bdb;box-shadow:1px 1px 5px rgba(0,0,0,.5)}.admin-user .admin__action-dropdown{height:3.3rem;padding:.7rem 2.8rem .4rem 4rem}.admin-user .admin__action-dropdown._active:after,.admin-user .admin__action-dropdown.active:after{-ms-transform:rotate(180deg);transform:rotate(180deg)}.admin-user .admin__action-dropdown:after{border-color:#777 transparent transparent;border-style:solid;border-width:.5rem .4rem 0;content:'';height:0;margin-top:-.2rem;position:absolute;right:1.3rem;top:50%;transition:all .2s linear;width:0}._active .admin-user .admin__action-dropdown:after,.active .admin-user .admin__action-dropdown:after{-ms-transform:rotate(180deg);transform:rotate(180deg)}.admin-user .admin__action-dropdown:hover:after{border-color:#000 transparent transparent}.admin-user .admin__action-dropdown:before{color:#777;content:'\e600';font-size:2rem;left:1.1rem;margin-top:-1.1rem;position:absolute;top:50%}.admin-user .admin__action-dropdown:hover:before{color:#333}.admin-user .admin__action-dropdown-menu{min-width:20rem;padding-left:1rem;padding-right:1rem}.admin-user .admin__action-dropdown-menu>li>a{padding-left:.5em;padding-right:1.8rem;transition:background-color .1s linear;white-space:nowrap}.admin-user .admin__action-dropdown-menu>li>a:hover{background-color:#e0f6fe;color:#333}.admin-user .admin__action-dropdown-menu>li>a:active{background-color:#c7effd;bottom:-1px;position:relative}.admin-user .admin__action-dropdown-menu .admin-user-name{text-overflow:ellipsis;white-space:nowrap;display:inline-block;max-width:20rem;overflow:hidden;vertical-align:top}.admin-user-account-text{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;display:inline-block;max-width:11.2rem}.search-global{float:right;margin-right:-.3rem;position:relative;z-index:480}.search-global-field{min-width:5rem}.search-global-field._active .search-global-input{background-color:#fff;border-color:#007bdb;box-shadow:1px 1px 5px rgba(0,0,0,.5);padding-right:4rem;width:25rem}.search-global-field._active .search-global-action{display:block;height:3.3rem;position:absolute;right:0;text-indent:-100%;top:0;width:5rem;z-index:3}.search-global-field .autocomplete-results{height:3.3rem;position:absolute;right:0;top:0;width:25rem}.search-global-field .search-global-menu{border:1px solid #007bdb;border-top-color:transparent;box-shadow:1px 1px 5px rgba(0,0,0,.5);left:0;margin-top:-2px;padding:0;position:absolute;right:0;top:100%;z-index:2}.search-global-field .search-global-menu:after{background-color:#fff;content:'';height:5px;left:0;position:absolute;right:0;top:-5px}.search-global-field .search-global-menu>li{background-color:#fff;border-top:1px solid #ddd;display:block;font-size:1.2rem;padding:.75rem 1.4rem .55rem}.search-global-field .search-global-menu>li._active{background-color:#e0f6fe}.search-global-field .search-global-menu .title{display:block;font-size:1.4rem}.search-global-field .search-global-menu .type{color:#1a1a1a;display:block}.search-global-label{cursor:pointer;height:3.3rem;padding:.75rem 1.4rem .55rem;position:absolute;right:0;top:0;z-index:2}.search-global-label:active{-ms-transform:scale(0.9);transform:scale(0.9)}.search-global-label:hover:before{color:#000}.search-global-label:before{color:#777;content:'\e60c';font-size:2rem}.search-global-input{background-color:transparent;border:1px solid transparent;font-size:1.4rem;height:3.3rem;padding:.75rem 1.4rem .55rem;position:absolute;right:0;top:0;transition:all .1s linear,width .3s linear;width:5rem;z-index:1}.search-global-action{display:none}.notifications-wrapper{float:right;line-height:1;position:relative}.notifications-wrapper.active{z-index:500}.notifications-wrapper.active .notifications-action{border-color:#007bdb;box-shadow:1px 1px 5px rgba(0,0,0,.5)}.notifications-wrapper.active .notifications-action:after{background-color:#fff;border:none;content:'';display:block;height:6px;left:-6px;margin-top:0;position:absolute;right:0;top:100%;width:auto}.notifications-wrapper .admin__action-dropdown-menu{padding:1rem 0 0;width:32rem}.notifications-action{color:#777;height:3.3rem;padding:.75rem 2rem .65rem}.notifications-action:after{display:none}.notifications-action:before{content:'\e607';font-size:1.9rem;margin-right:0}.notifications-action:active:before{position:relative;top:1px}.notifications-action .notifications-counter{background-color:#e22626;border-radius:1em;color:#fff;display:inline-block;font-size:1.1rem;font-weight:700;left:50%;margin-left:.3em;margin-top:-1.1em;padding:.3em .5em;position:absolute;top:50%}.notifications-entry{line-height:1.36;padding:.6rem 2rem .8rem;position:relative;transition:background-color .1s linear}.notifications-entry:hover{background-color:#e0f6fe}.notifications-entry.notifications-entry-last{margin:0 2rem;padding:.3rem 0 1.3rem;text-align:center}.notifications-entry.notifications-entry-last:hover{background-color:transparent}.notifications-entry+.notifications-entry-last{border-top:1px solid #ddd;padding-bottom:.6rem}.notifications-entry ._cutted{cursor:pointer}.notifications-entry ._cutted .notifications-entry-description-start:after{content:'...'}.notifications-entry-title{color:#ef672f;display:block;font-size:1.1rem;font-weight:700;margin-bottom:.7rem;margin-right:1em}.notifications-entry-description{color:#333;font-size:1.1rem;margin-bottom:.8rem}.notifications-entry-description-end{display:none}.notifications-entry-description-end._show{display:inline}.notifications-entry-time{color:#777;font-size:1.1rem}.notifications-close{line-height:1;padding:1rem;position:absolute;right:0;top:.6rem}.notifications-close:before{color:#ccc;content:'\e620';transition:color .1s linear}.notifications-close:hover:before{color:#b3b3b3}.notifications-close:active{-ms-transform:scale(0.95);transform:scale(0.95)}.page-header-actions{padding-top:1.1rem}.page-header-hgroup{padding-right:1.5rem}.page-title{color:#333;font-size:2.8rem}.page-header{padding:1.5rem 3rem}.menu-wrapper{display:inline-block;position:relative;width:8.8rem;z-index:700}.menu-wrapper:before{background-color:#373330;bottom:0;content:'';left:0;position:fixed;top:0;width:8.8rem;z-index:699}.menu-wrapper._fixed{left:0;position:fixed;top:0}.menu-wrapper._fixed~.page-wrapper{margin-left:8.8rem}.menu-wrapper .logo{display:block;height:8.8rem;padding:2.4rem 0 2.2rem;position:relative;text-align:center;z-index:700}._keyfocus .menu-wrapper .logo:focus{background-color:#4a4542;box-shadow:none}._keyfocus .menu-wrapper .logo:focus+.admin__menu .level-0:first-child>a{background-color:#373330}._keyfocus .menu-wrapper .logo:focus+.admin__menu .level-0:first-child>a:after{display:none}.menu-wrapper .logo:hover .logo-img{-webkit-filter:brightness(1.1);filter:brightness(1.1)}.menu-wrapper .logo:active .logo-img{-ms-transform:scale(0.95);transform:scale(0.95)}.menu-wrapper .logo .logo-img{height:4.2rem;transition:-webkit-filter .2s linear,filter .2s linear,transform .1s linear;width:3.5rem}.abs-menu-separator,.admin__menu .item-partners>a:after,.admin__menu .level-0:first-child>a:after{background-color:#736963;content:'';display:block;height:1px;left:0;margin-left:16%;position:absolute;top:0;width:68%}.admin__menu li{display:block}.admin__menu .level-0:first-child>a{position:relative}.admin__menu .level-0._active>a,.admin__menu .level-0:hover>a{color:#f7f3eb}.admin__menu .level-0._active>a{background-color:#524d49}.admin__menu .level-0:hover>a{background-color:#4a4542}.admin__menu .level-0>a{color:#aaa6a0;display:block;font-size:1rem;letter-spacing:.025em;min-height:6.2rem;padding:1.2rem .5rem .5rem;position:relative;text-align:center;text-decoration:none;text-transform:uppercase;transition:background-color .1s linear;word-wrap:break-word;z-index:700}.admin__menu .level-0>a:focus{box-shadow:none}.admin__menu .level-0>a:before{content:'\e63a';display:block;font-size:2.2rem;height:2.2rem}.admin__menu .level-0>.submenu{background-color:#4a4542;box-shadow:0 0 3px #000;left:100%;min-height:calc(8.8rem + 2rem + 100%);padding:2rem 0 0;position:absolute;top:0;-ms-transform:translateX(-100%);transform:translateX(-100%);transition-duration:.3s;transition-property:transform,visibility;transition-timing-function:ease-in-out;visibility:hidden;z-index:697}.ie10 .admin__menu .level-0>.submenu,.ie11 .admin__menu .level-0>.submenu{height:100%}.admin__menu .level-0._show>.submenu{-ms-transform:translateX(0);transform:translateX(0);visibility:visible;z-index:698}.admin__menu .level-1{margin-left:1.5rem;margin-right:1.5rem}.admin__menu [class*=level-]:not(.level-0) a{display:block;padding:1.25rem 1.5rem}.admin__menu [class*=level-]:not(.level-0) a:hover{background-color:#403934}.admin__menu [class*=level-]:not(.level-0) a:active{background-color:#322c29;padding-bottom:1.15rem;padding-top:1.35rem}.admin__menu .submenu li{min-width:23.8rem}.admin__menu .submenu a{color:#fcfcfc;transition:background-color .1s linear}.admin__menu .submenu a:focus,.admin__menu .submenu a:hover{box-shadow:none;text-decoration:none}._keyfocus .admin__menu .submenu a:focus{background-color:#403934}._keyfocus .admin__menu .submenu a:active{background-color:#322c29}.admin__menu .submenu .parent{margin-bottom:4.5rem}.admin__menu .submenu .parent .submenu-group-title{color:#a79d95;display:block;font-size:1.6rem;font-weight:600;margin-bottom:.7rem;padding:1.25rem 1.5rem;pointer-events:none}.admin__menu .submenu .column{display:table-cell}.admin__menu .submenu-title{color:#fff;display:block;font-size:2.2rem;font-weight:600;margin-bottom:4.2rem;margin-left:3rem;margin-right:5.8rem}.admin__menu .submenu-sub-title{color:#fff;display:block;font-size:1.2rem;margin:-3.8rem 5.8rem 3.8rem 3rem}.admin__menu .action-close{padding:2.4rem 2.8rem;position:absolute;right:0;top:0}.admin__menu .action-close:before{color:#a79d95;font-size:1.7rem}.admin__menu .action-close:hover:before{color:#fff}.admin__menu .item-dashboard>a:before{content:'\e604';font-size:1.8rem;padding-top:.4rem}.admin__menu .item-sales>a:before{content:'\e60b'}.admin__menu .item-catalog>a:before{content:'\e608'}.admin__menu .item-customer>a:before{content:'\e603';font-size:2.6rem;position:relative;top:-.4rem}.admin__menu .item-marketing>a:before{content:'\e609';font-size:2rem;padding-top:.2rem}.admin__menu .item-content>a:before{content:'\e602';font-size:2.4rem;position:relative;top:-.2rem}.admin__menu .item-report>a:before{content:'\e60a'}.admin__menu .item-stores>a:before{content:'\e60d';font-size:1.9rem;padding-top:.3rem}.admin__menu .item-system>a:before{content:'\e610'}.admin__menu .item-partners._active>a:after,.admin__menu .item-system._current+.item-partners>a:after{display:none}.admin__menu .item-partners>a{padding-bottom:1rem}.admin__menu .item-partners>a:before{content:'\e612'}.admin__menu .level-0>.submenu>ul>.level-1:only-of-type>.submenu-group-title,.admin__menu .submenu .column:only-of-type .submenu-group-title{display:none}.admin__menu-overlay{bottom:0;left:0;position:fixed;right:0;top:0;z-index:697}.store-switcher{color:#333;float:left;font-size:1.3rem;margin-top:.7rem}.store-switcher .admin__action-dropdown{background-color:#f8f8f8;margin-left:.5em}.store-switcher .dropdown{display:inline-block;position:relative}.store-switcher .dropdown:after,.store-switcher .dropdown:before{content:'';display:table}.store-switcher .dropdown:after{clear:both}.store-switcher .dropdown .action.toggle{cursor:pointer;display:inline-block;text-decoration:none}.store-switcher .dropdown .action.toggle:after{-webkit-font-smoothing:antialiased;font-size:22px;line-height:2;color:#333;content:'\e607';font-family:icons-blank-theme;margin:0;vertical-align:top;display:inline-block;font-weight:400;overflow:hidden;speak:none;text-align:center}.store-switcher .dropdown .action.toggle:active:after,.store-switcher .dropdown .action.toggle:hover:after{color:#333}.store-switcher .dropdown .action.toggle.active{display:inline-block;text-decoration:none}.store-switcher .dropdown .action.toggle.active:after{-webkit-font-smoothing:antialiased;font-size:22px;line-height:2;color:#333;content:'\e618';font-family:icons-blank-theme;margin:0;vertical-align:top;display:inline-block;font-weight:400;overflow:hidden;speak:none;text-align:center}.store-switcher .dropdown .action.toggle.active:active:after,.store-switcher .dropdown .action.toggle.active:hover:after{color:#333}.store-switcher .dropdown .dropdown-menu{margin:4px 0 0;padding:0;list-style:none;background:#fff;border:1px solid #aaa6a0;min-width:19.5rem;z-index:100;box-sizing:border-box;display:none;position:absolute;top:100%;box-shadow:1px 1px 5px rgba(0,0,0,.5)}.store-switcher .dropdown .dropdown-menu li{margin:0;padding:0}.store-switcher .dropdown .dropdown-menu li:hover{background:0 0;cursor:pointer}.store-switcher .dropdown.active{overflow:visible}.store-switcher .dropdown.active .dropdown-menu{display:block}.store-switcher .dropdown-menu{left:0;margin-top:.5em;max-height:250px;overflow-y:auto;padding-top:.25em}.store-switcher .dropdown-menu li{border:0;cursor:default}.store-switcher .dropdown-menu li:hover{cursor:default}.store-switcher .dropdown-menu li a,.store-switcher .dropdown-menu li span{color:#333;display:block;padding:.5rem 1.3rem}.store-switcher .dropdown-menu li a{text-decoration:none}.store-switcher .dropdown-menu li a:hover{background:#e9e9e9}.store-switcher .dropdown-menu li span{color:#adadad;cursor:default}.store-switcher .dropdown-menu li.current span{background:#eee;color:#333}.store-switcher .dropdown-menu .store-switcher-store a,.store-switcher .dropdown-menu .store-switcher-store span{padding-left:2.6rem}.store-switcher .dropdown-menu .store-switcher-store-view a,.store-switcher .dropdown-menu .store-switcher-store-view span{padding-left:3.9rem}.store-switcher .dropdown-menu .dropdown-toolbar{border-top:1px solid #ebebeb;margin-top:1rem}.store-switcher .dropdown-menu .dropdown-toolbar a:before{content:'\e610';margin-right:.25em;position:relative;top:1px}.store-switcher-label{font-weight:700}.store-switcher-alt{display:inline-block;position:relative}.store-switcher-alt.active .dropdown-menu{display:block}.store-switcher-alt .dropdown-menu{margin-top:2px;white-space:nowrap}.store-switcher-alt .dropdown-menu ul{list-style:none;margin:0;padding:0}.store-switcher-alt strong{color:#a79d95;display:block;font-size:14px;font-weight:500;line-height:1.333;padding:5px 10px}.store-switcher-alt .store-selected{color:#676056;cursor:pointer;font-size:12px;font-weight:400;line-height:1.333}.store-switcher-alt .store-selected:after{-webkit-font-smoothing:antialiased;color:#afadac;content:'\e02c';font-style:normal;font-weight:400;margin:0 0 0 3px;speak:none;vertical-align:text-top}.store-switcher-alt .store-switcher-store,.store-switcher-alt .store-switcher-website{padding:0}.store-switcher-alt .store-switcher-store:hover,.store-switcher-alt .store-switcher-website:hover{background:0 0}.store-switcher-alt .manage-stores,.store-switcher-alt .store-switcher-all,.store-switcher-alt .store-switcher-store-view{padding:0}.store-switcher-alt .manage-stores>a,.store-switcher-alt .store-switcher-all>a{color:#676056;display:block;font-size:12px;padding:8px 15px;text-decoration:none}.store-switcher-website{margin:5px 0 0}.store-switcher-website>strong{padding-left:13px}.store-switcher-store{margin:1px 0 0}.store-switcher-store>strong{padding-left:20px}.store-switcher-store>ul{margin-top:1px}.store-switcher-store-view:first-child{border-top:1px solid #e5e5e5}.store-switcher-store-view>a{color:#333;display:block;font-size:13px;padding:5px 15px 5px 24px;text-decoration:none}.store-view:not(.store-switcher){float:left}.store-view .store-switcher-label{display:inline-block;margin-top:1rem}.tooltip{margin-left:.5em}.tooltip .help a,.tooltip .help span{cursor:pointer;display:inline-block;height:22px;position:relative;vertical-align:middle;width:22px;z-index:2}.tooltip .help a:before,.tooltip .help span:before{color:#333;content:'\e633';font-size:1.7rem}.tooltip .help a:hover{text-decoration:none}.tooltip .tooltip-content{background:#000;border-radius:3px;color:#fff;display:none;margin-left:-19px;margin-top:10px;max-width:200px;padding:4px 8px;position:absolute;text-shadow:none;z-index:20}.tooltip .tooltip-content:before{border-bottom:5px solid #000;border-left:5px solid transparent;border-right:5px solid transparent;content:'';height:0;left:20px;opacity:.8;position:absolute;top:-5px;width:0}.tooltip .tooltip-content.loading{position:absolute}.tooltip .tooltip-content.loading:before{border-bottom-color:rgba(0,0,0,.3)}.tooltip:hover>.tooltip-content{display:block}.page-actions._fixed,.page-main-actions:not(._hidden){background:#f8f8f8;border-bottom:1px solid #e3e3e3;border-top:1px solid #e3e3e3;padding:1.5rem}.page-main-actions{margin:0 0 3rem}.page-main-actions._hidden .store-switcher{display:none}.page-main-actions._hidden .page-actions-placeholder{min-height:50px}.page-actions{float:right}.page-main-actions .page-actions._fixed{left:8.8rem;position:fixed;right:0;top:0;z-index:501}.page-main-actions .page-actions._fixed .page-actions-inner:before{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;color:#333;content:attr(data-title);float:left;font-size:2.8rem;margin-top:.3rem;max-width:50%}.page-actions .page-actions-buttons>button,.page-actions>button{float:right;margin-left:1.3rem}.page-actions .page-actions-buttons>button.action-back,.page-actions .page-actions-buttons>button.back,.page-actions>button.action-back,.page-actions>button.back{float:left;-ms-flex-order:-1;order:-1}.page-actions .page-actions-buttons>button.action-back:before,.page-actions .page-actions-buttons>button.back:before,.page-actions>button.action-back:before,.page-actions>button.back:before{content:'\e626';margin-right:.5em;position:relative;top:1px}.page-actions .page-actions-buttons>button.action-primary,.page-actions .page-actions-buttons>button.primary,.page-actions>button.action-primary,.page-actions>button.primary{-ms-flex-order:2;order:2}.page-actions .page-actions-buttons>button.save:not(.primary),.page-actions>button.save:not(.primary){-ms-flex-order:1;order:1}.page-actions .page-actions-buttons>button.delete,.page-actions>button.delete{-ms-flex-order:-1;order:-1}.page-actions .actions-split{float:right;margin-left:1.3rem;-ms-flex-order:2;order:2}.page-actions .actions-split .dropdown-menu .item{display:block}.page-actions-buttons{float:right;-ms-flex-pack:end;justify-content:flex-end;display:-ms-flexbox;display:flex}.customer-index-edit .page-actions-buttons{background-color:transparent}.admin__page-nav{background:#f1f1f1;border:1px solid #e3e3e3}.admin__page-nav._collapsed:first-child{border-bottom:none}.admin__page-nav._collapsed._show{border-bottom:1px solid #e3e3e3}.admin__page-nav._collapsed._show ._collapsible{background:#f1f1f1}.admin__page-nav._collapsed._show ._collapsible:after{content:'\e62b'}.admin__page-nav._collapsed._show ._collapsible+.admin__page-nav-items{display:block}.admin__page-nav._collapsed._hide .admin__page-nav-title-messages,.admin__page-nav._collapsed._hide .admin__page-nav-title-messages ._active{display:inline-block}.admin__page-nav+._collapsed{border-bottom:none;border-top:none}.admin__page-nav-title{border-bottom:1px solid #e3e3e3;color:#303030;display:block;font-size:1.4rem;line-height:1.2;margin:0 0 -1px;padding:1.8rem 1.5rem;position:relative;text-transform:uppercase}.admin__page-nav-title._collapsible{background:#fff;cursor:pointer;margin:0;padding-right:3.5rem;transition:border-color .1s ease-out,background-color .1s ease-out}.admin__page-nav-title._collapsible+.admin__page-nav-items{display:none;margin-top:-1px}.admin__page-nav-title._collapsible:after{content:'\e628';font-size:1.3rem;font-weight:700;position:absolute;right:1.8rem;top:2rem}.admin__page-nav-title._collapsible:hover{background:#f1f1f1}.admin__page-nav-title._collapsible:last-child{margin:0 0 -1px}.admin__page-nav-title strong{font-weight:700}.admin__page-nav-title .admin__page-nav-title-messages{display:none}.admin__page-nav-items{list-style-type:none;margin:0;padding:1rem 0 1.3rem}.admin__page-nav-item{border-left:3px solid transparent;margin-left:.7rem;padding:0;position:relative;transition:border-color .1s ease-out,background-color .1s ease-out}.admin__page-nav-item:hover{border-color:#e4e4e4}.admin__page-nav-item:hover .admin__page-nav-link{background:#e4e4e4;color:#303030;text-decoration:none}.admin__page-nav-item._active,.admin__page-nav-item.ui-state-active{border-color:#eb5202}.admin__page-nav-item._active .admin__page-nav-link,.admin__page-nav-item.ui-state-active .admin__page-nav-link{background:#fff;border-color:#e3e3e3;border-right:1px solid #fff;color:#303030;margin-right:-1px;font-weight:600}.admin__page-nav-item._loading:before,.admin__page-nav-item.ui-tabs-loading:before{display:none}.admin__page-nav-item._loading .admin__page-nav-item-message-loader,.admin__page-nav-item.ui-tabs-loading .admin__page-nav-item-message-loader{display:inline-block}.admin__page-nav-link{border:1px solid transparent;border-width:1px 0;color:#303030;display:block;font-weight:500;line-height:1.2;margin:0 0 -1px;padding:2rem 4rem 2rem 1rem;transition:border-color .1s ease-out,background-color .1s ease-out;word-wrap:break-word}.admin__page-nav-item-messages{display:inline-block}.admin__page-nav-item-messages .admin__page-nav-item-message-tooltip{background:#f1f1f1;border:1px solid #f1f1f1;border-radius:1px;bottom:3.7rem;box-shadow:0 3px 9px 0 rgba(0,0,0,.3);display:none;font-size:1.4rem;font-weight:400;left:-1rem;line-height:1.36;padding:1.5rem;position:absolute;text-transform:none;width:27rem;word-break:normal;z-index:2}.admin__page-nav-item-messages .admin__page-nav-item-message-tooltip:after,.admin__page-nav-item-messages .admin__page-nav-item-message-tooltip:before{border:15px solid transparent;height:0;width:0;border-top-color:#f1f1f1;content:'';display:block;left:2rem;position:absolute;top:100%;z-index:3}.admin__page-nav-item-messages .admin__page-nav-item-message-tooltip:after{border-top-color:#f1f1f1;margin-top:-1px;z-index:4}.admin__page-nav-item-messages .admin__page-nav-item-message-tooltip:before{border-top-color:#bfbfbf;margin-top:1px}.admin__page-nav-item-message-loader{display:none;margin-top:-1rem;position:absolute;right:0;top:50%}.admin__page-nav-item-message-loader .spinner{font-size:2rem;margin-right:1.5rem}._loading>.admin__page-nav-item-messages .admin__page-nav-item-message-loader{display:inline-block}.admin__page-nav-item-message{position:relative}.admin__page-nav-item-message:hover{z-index:500}.admin__page-nav-item-message:hover .admin__page-nav-item-message-tooltip{display:block}.admin__page-nav-item-message._changed,.admin__page-nav-item-message._error{display:none}.admin__page-nav-item-message .admin__page-nav-item-message-icon{display:inline-block;font-size:1.4rem;padding-left:.8em;vertical-align:baseline}.admin__page-nav-item-message .admin__page-nav-item-message-icon:after{color:#666;content:'\e631'}._changed:not(._error)>.admin__page-nav-item-messages ._changed{display:inline-block}._error .admin__page-nav-item-message-icon:after{color:#eb5202;content:'\e623'}._error>.admin__page-nav-item-messages ._error{display:inline-block}._error>.admin__page-nav-item-messages ._error .spinner{font-size:2rem;margin-right:1.5rem}._error .admin__page-nav-item-message-tooltip{background:#f1f1f1;border:1px solid #f1f1f1;border-radius:1px;bottom:3.7rem;box-shadow:0 3px 9px 0 rgba(0,0,0,.3);display:none;font-weight:400;left:-1rem;line-height:1.36;padding:2rem;position:absolute;text-transform:none;width:27rem;word-break:normal;z-index:2}._error .admin__page-nav-item-message-tooltip:after,._error .admin__page-nav-item-message-tooltip:before{border:15px solid transparent;height:0;width:0;border-top-color:#f1f1f1;content:'';display:block;left:2rem;position:absolute;top:100%;z-index:3}._error .admin__page-nav-item-message-tooltip:after{border-top-color:#f1f1f1;margin-top:-1px;z-index:4}._error .admin__page-nav-item-message-tooltip:before{border-top-color:#bfbfbf}.admin__data-grid-wrap-static .data-grid{box-sizing:border-box}.admin__data-grid-wrap-static .data-grid thead{color:#333}.admin__data-grid-wrap-static .data-grid tr:nth-child(even) td{background-color:#f5f5f5}.admin__data-grid-wrap-static .data-grid tr:nth-child(even) td._dragging{background-color:rgba(245,245,245,.95)}.admin__data-grid-wrap-static .data-grid ul{margin-left:1rem;padding-left:1rem}.admin__data-grid-wrap-static .admin__data-grid-loading-mask{background:rgba(255,255,255,.5);bottom:0;left:0;position:absolute;right:0;top:0;z-index:399}.admin__data-grid-wrap-static .admin__data-grid-loading-mask .grid-loader{background:url(../images/loader-2.gif) 50% 50% no-repeat;bottom:0;height:149px;left:0;margin:auto;position:absolute;right:0;top:0;width:218px}.data-grid-filters-actions-wrap{float:right}.data-grid-search-control-wrap{float:left;max-width:45.5rem;position:relative;width:35%}.data-grid-search-control-wrap :-ms-input-placeholder{font-style:italic}.data-grid-search-control-wrap ::-webkit-input-placeholder{font-style:italic}.data-grid-search-control-wrap ::-moz-placeholder{font-style:italic}.data-grid-search-control-wrap .action-submit{background-color:transparent;border:none;border-radius:0;box-shadow:none;margin:0;padding:.6rem 2rem .2rem;position:absolute;right:0;top:1px}.data-grid-search-control-wrap .action-submit:hover{background-color:transparent;border:none;box-shadow:none}.data-grid-search-control-wrap .action-submit:active{-ms-transform:scale(0.9);transform:scale(0.9)}.data-grid-search-control-wrap .action-submit:hover:before{color:#1a1a1a}._keyfocus .data-grid-search-control-wrap .action-submit:focus{box-shadow:0 0 0 1px #008bdb}.data-grid-search-control-wrap .action-submit:before{content:'\e60c';font-size:2rem;transition:color .1s linear}.data-grid-search-control-wrap .action-submit>span{clip:rect(0,0,0,0);overflow:hidden;position:absolute}.data-grid-search-control-wrap .abs-action-menu .action-submenu,.data-grid-search-control-wrap .abs-action-menu .action-submenu .action-submenu,.data-grid-search-control-wrap .action-menu,.data-grid-search-control-wrap .action-menu .action-submenu,.data-grid-search-control-wrap .actions-split .action-menu .action-submenu,.data-grid-search-control-wrap .actions-split .action-menu .action-submenu .action-submenu,.data-grid-search-control-wrap .actions-split .dropdown-menu .action-submenu,.data-grid-search-control-wrap .actions-split .dropdown-menu .action-submenu .action-submenu{max-height:19.25rem;overflow-y:auto;z-index:398}.data-grid-search-control-wrap .action-menu-item._selected{background-color:#e0f6fe}.data-grid-search-control-wrap .data-grid-search-label{display:none}.data-grid-search-control{padding-right:6rem;width:100%}.data-grid-filters-action-wrap{float:left;padding-left:2rem}.data-grid-filters-action-wrap .action-default{font-size:1.3rem;margin-bottom:1rem;padding-left:1.7rem;padding-right:2.1rem;padding-top:.7rem}.data-grid-filters-action-wrap .action-default._active{background-color:#fff;border-bottom-color:#fff;border-right-color:#ccc;font-weight:600;margin:-.1rem 0 0;padding-bottom:1.6rem;padding-top:.8rem;position:relative;z-index:281}.data-grid-filters-action-wrap .action-default._active:after{background-color:#eb5202;bottom:100%;content:'';height:3px;left:-1px;position:absolute;right:-1px}.data-grid-filters-action-wrap .action-default:before{color:#333;content:'\e605';font-size:1.8rem;margin-right:.4rem;position:relative;top:-1px;vertical-align:top}.data-grid-filters-action-wrap .filters-active{display:none}.admin__action-grid-select .admin__control-select{margin:-.5rem .5rem 0 0;padding-bottom:.6rem;padding-top:.6rem}.admin__data-grid-filters-wrap{opacity:0;visibility:hidden;clear:both;font-size:1.3rem;transition:opacity .3s ease}.admin__data-grid-filters-wrap._show{opacity:1;visibility:visible;border-bottom:1px solid #ccc;border-top:1px solid #ccc;margin-bottom:.7rem;padding:3.6rem 0 3rem;position:relative;top:-1px;z-index:280}.admin__data-grid-filters-wrap._show .admin__data-grid-filters,.admin__data-grid-filters-wrap._show .admin__data-grid-filters-footer{display:block}.admin__data-grid-filters-wrap .admin__form-field-label,.admin__data-grid-filters-wrap .admin__form-field-legend{display:block;font-weight:700;margin:0 0 .3rem;text-align:left}.admin__data-grid-filters-wrap .admin__form-field{display:inline-block;margin-bottom:2em;margin-left:0;padding-left:2rem;padding-right:2rem;vertical-align:top;width:calc(100% / 4 - 4px)}.admin__data-grid-filters-wrap .admin__form-field .admin__form-field{display:block;float:none;margin-bottom:1.5rem;padding-left:0;padding-right:0;width:auto}.admin__data-grid-filters-wrap .admin__form-field .admin__form-field:last-child{margin-bottom:0}.admin__data-grid-filters-wrap .admin__form-field .admin__form-field .admin__form-field-label{border:1px solid transparent;float:left;font-weight:400;line-height:1.36;margin-bottom:0;padding-bottom:.6rem;padding-right:1em;padding-top:.6rem;width:25%}.admin__data-grid-filters-wrap .admin__form-field .admin__form-field .admin__form-field-control{margin-left:25%}.admin__data-grid-filters-wrap .admin__action-multiselect,.admin__data-grid-filters-wrap .admin__control-select,.admin__data-grid-filters-wrap .admin__control-text,.admin__data-grid-filters-wrap .admin__form-field-label{font-size:1.3rem}.admin__data-grid-filters-wrap .admin__control-select{height:3.2rem;padding-top:.5rem}.admin__data-grid-filters-wrap .admin__action-multiselect:before{height:3.2rem;width:3.2rem}.admin__data-grid-filters-wrap .admin__control-select,.admin__data-grid-filters-wrap .admin__control-text._has-datepicker{width:100%}.admin__data-grid-filters{display:none;margin-left:-2rem;margin-right:-2rem}.admin__filters-legend{clip:rect(0,0,0,0);overflow:hidden;position:absolute}.admin__data-grid-filters-footer{display:none;font-size:1.4rem}.admin__data-grid-filters-footer .admin__footer-main-actions{margin-left:25%;text-align:right}.admin__data-grid-filters-footer .admin__footer-secondary-actions{float:left;width:50%}.admin__data-grid-filters-current{border-bottom:.1rem solid #ccc;border-top:.1rem solid #ccc;display:none;font-size:1.3rem;margin-bottom:.9rem;padding-bottom:.8rem;padding-top:1.1rem;width:100%}.admin__data-grid-filters-current._show{display:table;position:relative;top:-1px;z-index:3}.admin__data-grid-filters-current._show+.admin__data-grid-filters-wrap._show{margin-top:-1rem}.admin__current-filters-actions-wrap,.admin__current-filters-list-wrap,.admin__current-filters-title-wrap{display:table-cell;vertical-align:top}.admin__current-filters-title{margin-right:1em;white-space:nowrap}.admin__current-filters-list-wrap{width:100%}.admin__current-filters-list{margin-bottom:0}.admin__current-filters-list>li{display:inline-block;font-weight:600;margin:0 1rem .5rem;padding-right:2.6rem;position:relative}.admin__current-filters-list .action-remove{background-color:transparent;border:none;border-radius:0;box-shadow:none;margin:0;padding:0;line-height:1;position:absolute;right:0;top:1px}.admin__current-filters-list .action-remove:hover{background-color:transparent;border:none;box-shadow:none}.admin__current-filters-list .action-remove:hover:before{color:#949494}.admin__current-filters-list .action-remove:active{-ms-transform:scale(0.9);transform:scale(0.9)}.admin__current-filters-list .action-remove:before{color:#adadad;content:'\e620';font-size:1.6rem;transition:color .1s linear}.admin__current-filters-list .action-remove>span{clip:rect(0,0,0,0);overflow:hidden;position:absolute}.admin__current-filters-actions-wrap .action-clear{border:none;padding-bottom:0;padding-top:0;white-space:nowrap}.admin__data-grid-pager-wrap{float:right;text-align:right}.admin__data-grid-pager{display:inline-block;margin-left:3rem}.admin__data-grid-pager .admin__control-text::-webkit-inner-spin-button,.admin__data-grid-pager .admin__control-text::-webkit-outer-spin-button{-webkit-appearance:none;margin:0}.admin__data-grid-pager .admin__control-text{-moz-appearance:textfield;text-align:center;width:4.4rem}.action-next,.action-previous{width:4.4rem}.action-next:before,.action-previous:before{font-weight:700}.action-next>span,.action-previous>span{clip:rect(0,0,0,0);overflow:hidden;position:absolute}.action-previous{margin-right:2.5rem;text-indent:-.25em}.action-previous:before{content:'\e629'}.action-next{margin-left:1.5rem;text-indent:.1em}.action-next:before{content:'\e62a'}.admin__data-grid-action-bookmarks{opacity:.98}.admin__data-grid-action-bookmarks .admin__action-dropdown-text:after{left:0;right:-6px}.admin__data-grid-action-bookmarks._active{z-index:290}.admin__data-grid-action-bookmarks .admin__action-dropdown .admin__action-dropdown-text{display:inline-block;max-width:15rem;min-width:4.9rem;vertical-align:top;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.admin__data-grid-action-bookmarks .admin__action-dropdown:before{content:'\e60f'}.admin__data-grid-action-bookmarks .admin__action-dropdown-menu{font-size:1.3rem;left:0;padding:1rem 0;right:auto}.admin__data-grid-action-bookmarks .admin__action-dropdown-menu>li{padding:0 5rem 0 0;position:relative;white-space:nowrap}.admin__data-grid-action-bookmarks .admin__action-dropdown-menu>li:not(.action-dropdown-menu-action){transition:background-color .1s linear}.admin__data-grid-action-bookmarks .admin__action-dropdown-menu>li:not(.action-dropdown-menu-action):hover{background-color:#e3e3e3}.admin__data-grid-action-bookmarks .admin__action-dropdown-menu .action-dropdown-menu-item{max-width:23rem;min-width:18rem;white-space:normal;word-break:break-all}.admin__data-grid-action-bookmarks .admin__action-dropdown-menu .action-dropdown-menu-item-edit{display:none;padding-bottom:1rem;padding-left:1rem;padding-top:1rem}.admin__data-grid-action-bookmarks .admin__action-dropdown-menu .action-dropdown-menu-item-edit .action-dropdown-menu-item-actions{padding-bottom:1rem;padding-top:1rem}.admin__data-grid-action-bookmarks .admin__action-dropdown-menu .action-dropdown-menu-action{padding-left:1rem;padding-top:1rem}.admin__data-grid-action-bookmarks .admin__action-dropdown-menu .action-dropdown-menu-action+.action-dropdown-menu-item-last{padding-top:.5rem}.admin__data-grid-action-bookmarks .admin__action-dropdown-menu .action-dropdown-menu-action>a{color:#008bdb;text-decoration:none;display:inline-block;padding-left:1.1rem}.admin__data-grid-action-bookmarks .admin__action-dropdown-menu .action-dropdown-menu-action>a:hover{color:#0fa7ff;text-decoration:underline}.admin__data-grid-action-bookmarks .admin__action-dropdown-menu .action-dropdown-menu-item-last{padding-bottom:0}.admin__data-grid-action-bookmarks .admin__action-dropdown-menu ._edit .action-dropdown-menu-item{display:none}.admin__data-grid-action-bookmarks .admin__action-dropdown-menu ._edit .action-dropdown-menu-item-edit{display:block}.admin__data-grid-action-bookmarks .admin__action-dropdown-menu ._active .action-dropdown-menu-link{font-weight:600}.admin__data-grid-action-bookmarks .admin__action-dropdown-menu .admin__control-text{font-size:1.3rem;min-width:15rem;width:calc(100% - 4rem)}.ie9 .admin__data-grid-action-bookmarks .admin__action-dropdown-menu .admin__control-text{width:15rem}.admin__data-grid-action-bookmarks .admin__action-dropdown-menu .action-dropdown-menu-item-actions{border-left:1px solid #fff;bottom:0;position:absolute;right:0;top:0;width:5rem}.admin__data-grid-action-bookmarks .admin__action-dropdown-menu .action-dropdown-menu-link{color:#333;display:block;text-decoration:none;padding:1rem 1rem 1rem 2.1rem}.admin__data-grid-action-bookmarks .action-delete,.admin__data-grid-action-bookmarks .action-edit,.admin__data-grid-action-bookmarks .action-submit{background-color:transparent;border:none;border-radius:0;box-shadow:none;margin:0;vertical-align:top}.admin__data-grid-action-bookmarks .action-delete:hover,.admin__data-grid-action-bookmarks .action-edit:hover,.admin__data-grid-action-bookmarks .action-submit:hover{background-color:transparent;border:none;box-shadow:none}.admin__data-grid-action-bookmarks .action-delete:before,.admin__data-grid-action-bookmarks .action-edit:before,.admin__data-grid-action-bookmarks .action-submit:before{font-size:1.7rem}.admin__data-grid-action-bookmarks .action-delete>span,.admin__data-grid-action-bookmarks .action-edit>span,.admin__data-grid-action-bookmarks .action-submit>span{clip:rect(0,0,0,0);overflow:hidden;position:absolute}.admin__data-grid-action-bookmarks .action-delete,.admin__data-grid-action-bookmarks .action-edit{padding:.6rem 1.4rem}.admin__data-grid-action-bookmarks .action-delete:active,.admin__data-grid-action-bookmarks .action-edit:active{-ms-transform:scale(0.9);transform:scale(0.9)}.admin__data-grid-action-bookmarks .action-submit{padding:.6rem 1rem .6rem .8rem}.admin__data-grid-action-bookmarks .action-submit:active{position:relative;right:-1px}.admin__data-grid-action-bookmarks .action-submit:before{content:'\e625'}.admin__data-grid-action-bookmarks .action-delete:before{content:'\e630'}.admin__data-grid-action-bookmarks .action-edit{padding-top:.8rem}.admin__data-grid-action-bookmarks .action-edit:before{content:'\e631'}.admin__data-grid-action-columns._active{opacity:.98;z-index:290}.admin__data-grid-action-columns .admin__action-dropdown:before{content:'\e610';font-size:1.8rem;margin-right:.7rem;vertical-align:top}.admin__data-grid-action-columns-menu{color:#303030;font-size:1.3rem;overflow:hidden;padding:2.2rem 3.5rem 1rem;z-index:1}.admin__data-grid-action-columns-menu._overflow .admin__action-dropdown-menu-header{border-bottom:1px solid #d1d1d1}.admin__data-grid-action-columns-menu._overflow .admin__action-dropdown-menu-content{width:49.2rem}.admin__data-grid-action-columns-menu._overflow .admin__action-dropdown-menu-footer{border-top:1px solid #d1d1d1;padding-top:2.5rem}.admin__data-grid-action-columns-menu .admin__action-dropdown-menu-content{max-height:22.85rem;overflow-y:auto;padding-top:1.5rem;position:relative;width:47.4rem}.admin__data-grid-action-columns-menu .admin__field-option{float:left;height:1.9rem;margin-bottom:1.5rem;padding:0 1rem 0 0;width:15.8rem}.admin__data-grid-action-columns-menu .admin__field-label{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;display:block}.admin__data-grid-action-columns-menu .admin__action-dropdown-menu-header{padding-bottom:1.5rem}.admin__data-grid-action-columns-menu .admin__action-dropdown-menu-footer{padding:1rem 0 2rem}.admin__data-grid-action-columns-menu .admin__action-dropdown-footer-main-actions{margin-left:25%;text-align:right}.admin__data-grid-action-columns-menu .admin__action-dropdown-footer-secondary-actions{float:left;margin-left:-1em}.admin__data-grid-action-export._active{opacity:.98;z-index:290}.admin__data-grid-action-export .admin__action-dropdown:before{content:'\e635';font-size:1.7rem;left:.3rem;margin-right:.7rem;vertical-align:top}.admin__data-grid-action-export-menu{padding-left:2rem;padding-right:2rem;padding-top:1rem}.admin__data-grid-action-export-menu .admin__action-dropdown-footer-main-actions{padding-bottom:2rem;padding-top:2.5rem;white-space:nowrap}.sticky-header{background-color:#f8f8f8;border-bottom:1px solid #e3e3e3;box-shadow:0 5px 5px 0 rgba(0,0,0,.25);left:8.8rem;margin-top:-1px;padding:.5rem 3rem 0;position:fixed;right:0;top:77px;z-index:398}.sticky-header .admin__data-grid-wrap{margin-bottom:0;overflow-x:visible;padding-bottom:0}.sticky-header .admin__data-grid-header-row{position:relative;text-align:right}.sticky-header .admin__data-grid-header-row:last-child{margin:0}.sticky-header .admin__data-grid-actions-wrap,.sticky-header .admin__data-grid-filters-wrap,.sticky-header .admin__data-grid-pager-wrap,.sticky-header .data-grid-filters-actions-wrap,.sticky-header .data-grid-search-control-wrap{display:inline-block;float:none;vertical-align:top}.sticky-header .action-select-wrap{float:left;margin-right:1.5rem;width:16.66666667%}.sticky-header .admin__control-support-text{float:left}.sticky-header .data-grid-search-control-wrap{margin:-.5rem 0 0 1.1rem;width:auto}.sticky-header .data-grid-search-control-wrap .data-grid-search-label{box-sizing:border-box;cursor:pointer;display:block;min-width:3.8rem;padding:1.2rem .6rem 1.7rem;position:relative;text-align:center}.sticky-header .data-grid-search-control-wrap .data-grid-search-label:before{color:#333;content:'\e60c';font-size:2rem;transition:color .1s linear}.sticky-header .data-grid-search-control-wrap .data-grid-search-label:hover:before{color:#000}.sticky-header .data-grid-search-control-wrap .data-grid-search-label span{display:none}.sticky-header .data-grid-filters-actions-wrap{margin:-.5rem 0 0 1.1rem;padding-left:0;position:relative}.sticky-header .data-grid-filters-actions-wrap .action-default{background-color:transparent;border:1px solid transparent;box-sizing:border-box;min-width:3.8rem;padding:1.2rem .6rem 1.7rem;text-align:center;transition:all .15s ease}.sticky-header .data-grid-filters-actions-wrap .action-default span{display:none}.sticky-header .data-grid-filters-actions-wrap .action-default:before{margin:0}.sticky-header .data-grid-filters-actions-wrap .action-default._active{background-color:#fff;border-color:#adadad #adadad #fff;box-shadow:1px 1px 5px rgba(0,0,0,.5);z-index:210}.sticky-header .data-grid-filters-actions-wrap .action-default._active:after{background-color:#fff;content:'';height:6px;left:-2px;position:absolute;right:-6px;top:100%}.sticky-header .data-grid-filters-action-wrap{padding:0}.sticky-header .admin__data-grid-filters-wrap{background-color:#fff;border:1px solid #adadad;box-shadow:0 5px 5px 0 rgba(0,0,0,.25);left:0;padding-left:3.5rem;padding-right:3.5rem;position:absolute;top:100%;width:100%;z-index:209}.sticky-header .admin__data-grid-filters-current+.admin__data-grid-filters-wrap._show{margin-top:-6px}.sticky-header .filters-active{background-color:#e04f00;border-radius:10px;color:#fff;display:block;font-size:1.4rem;font-weight:700;padding:.1rem .7rem;position:absolute;right:-7px;top:0;z-index:211}.sticky-header .filters-active:empty{padding-bottom:0;padding-top:0}.sticky-header .admin__data-grid-actions-wrap{margin:-.5rem 0 0 1.1rem;padding-right:.3rem}.sticky-header .admin__data-grid-actions-wrap .admin__action-dropdown{background-color:transparent;box-sizing:border-box;min-width:3.8rem;padding-left:.6rem;padding-right:.6rem;text-align:center}.sticky-header .admin__data-grid-actions-wrap .admin__action-dropdown .admin__action-dropdown-text{display:inline-block;max-width:0;min-width:0;overflow:hidden}.sticky-header .admin__data-grid-actions-wrap .admin__action-dropdown:before{margin:0}.sticky-header .admin__data-grid-actions-wrap .admin__action-dropdown-wrap{margin-right:1.1rem}.sticky-header .admin__data-grid-actions-wrap .admin__action-dropdown-wrap:after,.sticky-header .admin__data-grid-actions-wrap .admin__action-dropdown:after{display:none}.sticky-header .admin__data-grid-actions-wrap ._active .admin__action-dropdown{background-color:#fff}.sticky-header .admin__data-grid-action-bookmarks .admin__action-dropdown:before{position:relative;top:-3px}.sticky-header .admin__data-grid-filters-current{border-bottom:0;border-top:0;margin-bottom:0;padding-bottom:0;padding-top:0}.sticky-header .admin__data-grid-pager .admin__control-text,.sticky-header .admin__data-grid-pager-wrap .admin__control-support-text,.sticky-header .data-grid-search-control-wrap .action-submit,.sticky-header .data-grid-search-control-wrap .data-grid-search-control{display:none}.sticky-header .action-next{margin:0}.sticky-header .data-grid{margin-bottom:-1px}.data-grid-cap-left,.data-grid-cap-right{background-color:#f8f8f8;bottom:-2px;position:absolute;top:6rem;width:3rem;z-index:201}.data-grid-cap-left{left:0}.admin__data-grid-header{font-size:1.4rem}.admin__data-grid-header-row+.admin__data-grid-header-row{margin-top:1.1rem}.admin__data-grid-header-row:last-child{margin-bottom:0}.admin__data-grid-header-row .action-select-wrap{display:block}.admin__data-grid-header-row .action-select{width:100%}.admin__data-grid-actions-wrap{float:right;margin-left:1.1rem;margin-top:-.5rem;text-align:right}.admin__data-grid-actions-wrap .admin__action-dropdown-wrap{position:relative;text-align:left;vertical-align:middle}.admin__data-grid-actions-wrap .admin__action-dropdown-wrap._active+.admin__action-dropdown-wrap:after,.admin__data-grid-actions-wrap .admin__action-dropdown-wrap._active:after,.admin__data-grid-actions-wrap .admin__action-dropdown-wrap._hide+.admin__action-dropdown-wrap:after,.admin__data-grid-actions-wrap .admin__action-dropdown-wrap:first-child:after{display:none}.admin__data-grid-actions-wrap .admin__action-dropdown-wrap._active .admin__action-dropdown,.admin__data-grid-actions-wrap .admin__action-dropdown-wrap._active .admin__action-dropdown-menu{border-color:#adadad}.admin__data-grid-actions-wrap .admin__action-dropdown-wrap:after{border-left:1px solid #ccc;content:'';height:3.2rem;left:0;position:absolute;top:.5rem;z-index:3}.admin__data-grid-actions-wrap .admin__action-dropdown{padding-bottom:1.7rem;padding-top:1.2rem}.admin__data-grid-actions-wrap .admin__action-dropdown:after{margin-top:-.4rem}.admin__data-grid-outer-wrap{min-height:8rem;position:relative}.admin__data-grid-wrap{margin-bottom:2rem;max-width:100%;overflow-x:auto;padding-bottom:1rem;padding-top:2rem}.admin__data-grid-loading-mask{background:rgba(255,255,255,.5);bottom:0;left:0;position:absolute;right:0;top:0;z-index:399}.admin__data-grid-loading-mask .spinner{font-size:4rem;left:50%;margin-left:-2rem;margin-top:-2rem;position:absolute;top:50%}.ie9 .admin__data-grid-loading-mask .spinner{background:url(../images/loader-2.gif) 50% 50% no-repeat;bottom:0;height:149px;left:0;margin:auto;position:absolute;right:0;top:0;width:218px}.data-grid-cell-content{display:inline-block;overflow:hidden;width:100%}body._in-resize{cursor:col-resize;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}body._in-resize *,body._in-resize .data-grid-th,body._in-resize .data-grid-th._draggable,body._in-resize .data-grid-th._sortable{cursor:col-resize!important}._layout-fixed{table-layout:fixed}.data-grid{border:none;font-size:1.3rem;margin-bottom:0;width:100%}.data-grid:not(._dragging-copy) ._odd-row td._dragging{background-color:#d0d0d0}.data-grid:not(._dragging-copy) ._dragging{background-color:#d9d9d9;color:rgba(48,48,48,.95)}.data-grid:not(._dragging-copy) ._dragging a{color:rgba(0,139,219,.95)}.data-grid:not(._dragging-copy) ._dragging a:hover{color:rgba(15,167,255,.95)}.data-grid._dragged{outline:#007bdb solid 1px}.data-grid thead{background-color:transparent}.data-grid tfoot th{padding:1rem}.data-grid tr._odd-row td{background-color:#f5f5f5}.data-grid tr._odd-row td._update-status-active{background:#89e1ff}.data-grid tr._odd-row td._update-status-upcoming{background:#b7ee63}.data-grid tr:hover td._update-status-active,.data-grid tr:hover td._update-status-upcoming{background-color:#e5f7fe}.data-grid tr.data-grid-tr-no-data td{font-size:1.6rem;padding:3rem;text-align:center}.data-grid tr.data-grid-tr-no-data:hover td{background-color:#fff;cursor:default}.data-grid tr:active td{background-color:#e0f6fe}.data-grid tr:hover td{background-color:#e5f7fe}.data-grid tr._dragged td{background:#d0d0d0}.data-grid tr._dragover-top td{box-shadow:inset 0 3px 0 0 #008bdb}.data-grid tr._dragover-bottom td{box-shadow:inset 0 -3px 0 0 #008bdb}.data-grid tr:not(.data-grid-editable-row):last-child td{border-bottom:.1rem solid #d6d6d6}.data-grid tr ._clickable,.data-grid tr._clickable{cursor:pointer}.data-grid tr._disabled{pointer-events:none}.data-grid td,.data-grid th{font-size:1.3rem;line-height:1.36;transition:background-color .1s linear;vertical-align:top}.data-grid td._resizing,.data-grid th._resizing{border-left:1px solid #007bdb;border-right:1px solid #007bdb}.data-grid td._hidden,.data-grid th._hidden{display:none}.data-grid td._fit,.data-grid th._fit{width:1%}.data-grid td{background-color:#fff;border-left:.1rem dashed #d6d6d6;border-right:.1rem dashed #d6d6d6;color:#303030;padding:1rem}.data-grid td:first-child{border-left-style:solid}.data-grid td:last-child{border-right-style:solid}.data-grid td .action-select-wrap{position:static}.data-grid td .action-select{color:#008bdb;text-decoration:none;background-color:transparent;border:none;font-size:1.3rem;padding:0 3rem 0 0;position:relative}.data-grid td .action-select:hover{color:#0fa7ff;text-decoration:underline}.data-grid td .action-select:hover:after{border-color:#0fa7ff transparent transparent}.data-grid td .action-select:after{border-color:#008bdb transparent transparent;margin:.6rem 0 0 .7rem;right:auto;top:auto}.data-grid td .action-select:before{display:none}.data-grid td .abs-action-menu .action-submenu,.data-grid td .abs-action-menu .action-submenu .action-submenu,.data-grid td .action-menu,.data-grid td .action-menu .action-submenu,.data-grid td .actions-split .action-menu .action-submenu,.data-grid td .actions-split .action-menu .action-submenu .action-submenu,.data-grid td .actions-split .dropdown-menu .action-submenu,.data-grid td .actions-split .dropdown-menu .action-submenu .action-submenu{left:auto;min-width:10rem;right:0;text-align:left;top:auto;z-index:1}.data-grid td._update-status-active{background:#bceeff}.data-grid td._update-status-upcoming{background:#ccf391}.data-grid th{background-color:#514943;border:.1rem solid #8a837f;border-left-color:transparent;color:#fff;font-weight:600;padding:0;text-align:left}.data-grid th:first-child{border-left-color:#8a837f}.data-grid th._dragover-left{box-shadow:inset 3px 0 0 0 #fff;z-index:2}.data-grid th._dragover-right{box-shadow:inset -3px 0 0 0 #fff}.data-grid .shadow-div{cursor:col-resize;height:100%;margin-right:-5px;position:absolute;right:0;top:0;width:10px}.data-grid .data-grid-th{background-clip:padding-box;color:#fff;padding:1rem;position:relative;vertical-align:middle}.data-grid .data-grid-th._resize-visible .shadow-div{cursor:auto;display:none}.data-grid .data-grid-th._draggable{cursor:grab}.data-grid .data-grid-th._sortable{cursor:pointer;transition:background-color .1s linear;z-index:1}.data-grid .data-grid-th._sortable:focus,.data-grid .data-grid-th._sortable:hover{background-color:#5f564f}.data-grid .data-grid-th._sortable:active{padding-bottom:.9rem;padding-top:1.1rem}.data-grid .data-grid-th.required>span:after{color:#f38a5e;content:'*';margin-left:.3rem}.data-grid .data-grid-checkbox-cell{overflow:hidden;padding:0;vertical-align:top;width:5.2rem}.data-grid .data-grid-checkbox-cell:hover{cursor:default}.data-grid .data-grid-thumbnail-cell{text-align:center;width:7rem}.data-grid .data-grid-thumbnail-cell img{border:1px solid #d6d6d6;width:5rem}.data-grid .data-grid-multicheck-cell{padding:1rem 1rem .9rem;text-align:center;vertical-align:middle}.data-grid .data-grid-onoff-cell{text-align:center;width:12rem}.data-grid .data-grid-actions-cell{padding-left:2rem;padding-right:2rem;text-align:center;width:1%}.data-grid._hidden{display:none}.data-grid._dragging-copy{box-shadow:1px 1px 5px rgba(0,0,0,.5);left:0;opacity:.95;position:fixed;top:0;z-index:1000}.data-grid._dragging-copy .data-grid-th{border:1px solid #007bdb;border-bottom:none}.data-grid._dragging-copy .data-grid-th,.data-grid._dragging-copy .data-grid-th._sortable{cursor:grabbing}.data-grid._dragging-copy tr:last-child td{border-bottom:1px solid #007bdb}.data-grid._dragging-copy td{border-left:1px solid #007bdb;border-right:1px solid #007bdb}.data-grid._dragging-copy._in-edit .data-grid-editable-row.data-grid-bulk-edit-panel td,.data-grid._dragging-copy._in-edit .data-grid-editable-row.data-grid-bulk-edit-panel td:before,.data-grid._dragging-copy._in-edit .data-grid-editable-row.data-grid-bulk-edit-panel:hover td{background-color:rgba(255,251,230,.95)}.data-grid._dragging-copy._in-edit .data-grid-editable-row td,.data-grid._dragging-copy._in-edit .data-grid-editable-row:hover td{background-color:rgba(255,255,255,.95)}.data-grid._dragging-copy._in-edit .data-grid-editable-row td:after,.data-grid._dragging-copy._in-edit .data-grid-editable-row td:before{left:0;right:0}.data-grid._dragging-copy._in-edit .data-grid-editable-row td:before{background-color:rgba(255,255,255,.95)}.data-grid._dragging-copy._in-edit .data-grid-editable-row td:only-child{border-left:1px solid #007bdb;border-right:1px solid #007bdb;left:0}.data-grid._dragging-copy._in-edit .data-grid-editable-row .admin__control-select,.data-grid._dragging-copy._in-edit .data-grid-editable-row .admin__control-text{opacity:.5}.data-grid .data-grid-controls-row td{padding-top:1.6rem}.data-grid .data-grid-controls-row td.data-grid-checkbox-cell{padding-top:.6rem}.data-grid .data-grid-controls-row td [class*=admin__control-],.data-grid .data-grid-controls-row td button{margin-top:-1.7rem}.data-grid._in-edit tr:hover td{background-color:#e6e6e6}.data-grid._in-edit ._odd-row.data-grid-editable-row td,.data-grid._in-edit ._odd-row.data-grid-editable-row:hover td{background-color:#fff}.data-grid._in-edit ._odd-row td,.data-grid._in-edit ._odd-row:hover td{background-color:#dcdcdc}.data-grid._in-edit .data-grid-editable-row-actions td,.data-grid._in-edit .data-grid-editable-row-actions:hover td{background-color:#fff}.data-grid._in-edit td{background-color:#e6e6e6;pointer-events:none}.data-grid._in-edit .data-grid-checkbox-cell{pointer-events:auto}.data-grid._in-edit .data-grid-editable-row{border:.1rem solid #adadad;border-bottom-color:#c2c2c2}.data-grid._in-edit .data-grid-editable-row:hover td{background-color:#fff}.data-grid._in-edit .data-grid-editable-row td{background-color:#fff;border-bottom-color:#fff;border-left-style:hidden;border-right-style:hidden;border-top-color:#fff;pointer-events:auto;vertical-align:middle}.data-grid._in-edit .data-grid-editable-row td:first-child{border-left-color:#adadad;border-left-style:solid}.data-grid._in-edit .data-grid-editable-row td:first-child:after,.data-grid._in-edit .data-grid-editable-row td:first-child:before{left:0}.data-grid._in-edit .data-grid-editable-row td:last-child{border-right-color:#adadad;border-right-style:solid;left:-.1rem}.data-grid._in-edit .data-grid-editable-row td:last-child:after,.data-grid._in-edit .data-grid-editable-row td:last-child:before{right:0}.data-grid._in-edit .data-grid-editable-row .admin__control-select,.data-grid._in-edit .data-grid-editable-row .admin__control-text{width:100%}.data-grid._in-edit .data-grid-bulk-edit-panel td{vertical-align:bottom}.data-grid .data-grid-editable-row td{border-left-color:#fff;border-left-style:solid;position:relative;z-index:1}.data-grid .data-grid-editable-row td:after{bottom:0;box-shadow:0 5px 5px rgba(0,0,0,.25);content:'';height:.9rem;left:0;margin-top:-1rem;position:absolute;right:0}.data-grid .data-grid-editable-row td:before{background-color:#fff;bottom:0;content:'';height:1rem;left:-10px;position:absolute;right:-10px;z-index:1}.data-grid .data-grid-editable-row.data-grid-editable-row-actions td,.data-grid .data-grid-editable-row.data-grid-editable-row-actions:hover td{background-color:#fff}.data-grid .data-grid-editable-row.data-grid-editable-row-actions td:first-child{border-left-color:#fff;border-right-color:#fff}.data-grid .data-grid-editable-row.data-grid-editable-row-actions td:last-child{left:0}.data-grid .data-grid-editable-row.data-grid-bulk-edit-panel td,.data-grid .data-grid-editable-row.data-grid-bulk-edit-panel td:before,.data-grid .data-grid-editable-row.data-grid-bulk-edit-panel:hover td{background-color:#fffbe6}.data-grid .data-grid-editable-row-actions{left:50%;margin-left:-12.5rem;margin-top:-2px;position:absolute;text-align:center}.data-grid .data-grid-editable-row-actions td{width:25rem}.data-grid .data-grid-editable-row-actions [class*=action-]{min-width:9rem}.data-grid .data-grid-draggable-row-cell{width:1%}.data-grid .data-grid-draggable-row-cell .draggable-handle{padding:0}.data-grid-th._sortable._ascend,.data-grid-th._sortable._descend{padding-right:2.7rem}.data-grid-th._sortable._ascend:before,.data-grid-th._sortable._descend:before{margin-top:-1em;position:absolute;right:1rem;top:50%}.data-grid-th._sortable._ascend:before{content:'\2193'}.data-grid-th._sortable._descend:before{content:'\2191'}.data-grid-checkbox-cell-inner{display:block;padding:1.1rem 1.8rem .9rem;text-align:right}.data-grid-checkbox-cell-inner:hover{cursor:pointer}.data-grid-state-cell-inner{display:block;padding:1.1rem 1.8rem .9rem;text-align:center}.data-grid-state-cell-inner>span{display:inline-block;font-style:italic;padding:.6rem 0}.data-grid-row-parent._active>td .data-grid-checkbox-cell-inner:before{content:'\e62b'}.data-grid-row-parent>td .data-grid-checkbox-cell-inner{padding-left:3.7rem;position:relative}.data-grid-row-parent>td .data-grid-checkbox-cell-inner:before{content:'\e628';font-size:1rem;font-weight:700;left:1.35rem;position:absolute;top:1.6rem}.data-grid-th._col-xs{width:1%}.data-grid-info-panel{box-shadow:0 0 5px rgba(0,0,0,.5);margin:2rem .1rem -2rem}.data-grid-info-panel .messages{overflow:hidden}.data-grid-info-panel .messages .message{margin:1rem}.data-grid-info-panel .messages .message:last-child{margin-bottom:1rem}.data-grid-info-panel-actions{padding:1rem;text-align:right}.data-grid-editable-row .admin__field-control{position:relative}.data-grid-editable-row .admin__field-control._error:after{border-color:transparent #ee7d7d transparent transparent;border-style:solid;border-width:0 12px 12px 0;content:'';position:absolute;right:0;top:0}.data-grid-editable-row .admin__field-control._error .admin__control-text{border-color:#ee7d7d}.data-grid-editable-row .admin__field-control._focus:after{display:none}.data-grid-editable-row .admin__field-error{bottom:100%;box-shadow:1px 1px 5px rgba(0,0,0,.5);left:0;margin:0 auto 1.5rem;max-width:32rem;position:absolute;right:0}.data-grid-editable-row .admin__field-error:after,.data-grid-editable-row .admin__field-error:before{border-style:solid;content:'';left:50%;position:absolute;top:100%}.data-grid-editable-row .admin__field-error:after{border-color:#fffbbb transparent transparent;border-width:10px 10px 0;margin-left:-10px;z-index:1}.data-grid-editable-row .admin__field-error:before{border-color:#ee7d7d transparent transparent;border-width:11px 12px 0;margin-left:-12px}.data-grid-bulk-edit-panel .admin__field-label-vertical{display:block;font-size:1.2rem;margin-bottom:.5rem;text-align:left}.data-grid-row-changed{cursor:default;display:block;opacity:.5;position:relative;width:100%;z-index:1}.data-grid-row-changed:after{content:'\e631';display:inline-block}.data-grid-row-changed .data-grid-row-changed-tooltip{background:#f1f1f1;border:1px solid #f1f1f1;border-radius:1px;bottom:100%;box-shadow:0 3px 9px 0 rgba(0,0,0,.3);display:none;font-weight:400;line-height:1.36;margin-bottom:1.5rem;padding:1rem;position:absolute;right:-1rem;text-transform:none;width:27rem;word-break:normal;z-index:2}.data-grid-row-changed._changed{opacity:1;z-index:3}.data-grid-row-changed._changed:hover .data-grid-row-changed-tooltip{display:block}.data-grid-row-changed._changed:hover:before{background:#f1f1f1;border:1px solid #f1f1f1;bottom:100%;box-shadow:4px 4px 3px -1px rgba(0,0,0,.15);content:'';display:block;height:1.6rem;left:50%;margin:0 0 .7rem -.8rem;position:absolute;-ms-transform:rotate(45deg);transform:rotate(45deg);width:1.6rem;z-index:3}.ie9 .data-grid-row-changed._changed:hover:before{display:none}.admin__data-grid-outer-wrap .data-grid-checkbox-cell{overflow:hidden}.admin__data-grid-outer-wrap .data-grid-checkbox-cell-inner{position:relative}.admin__data-grid-outer-wrap .data-grid-checkbox-cell-inner:before{bottom:0;content:'';height:500%;left:0;position:absolute;right:0;top:0}.admin__data-grid-wrap-static .data-grid-checkbox-cell:hover{cursor:pointer}.admin__data-grid-wrap-static .data-grid-checkbox-cell-inner{margin:1.1rem 1.8rem .9rem;padding:0}.adminhtml-cms-hierarchy-index .admin__data-grid-wrap-static .data-grid-actions-cell:first-child{padding:0}.adminhtml-export-index .admin__data-grid-wrap-static .data-grid-checkbox-cell-inner{margin:0;padding:1.1rem 1.8rem 1.9rem}.admin__control-addon [class*=admin__control-][class]~[class*=admin__addon-]:last-child:before,.admin__control-file-label:before,.admin__control-multiselect,.admin__control-select,.admin__control-text,.admin__control-textarea,.selectmenu{-webkit-appearance:none;background-color:#fff;border:1px solid #adadad;border-radius:1px;box-shadow:none;color:#303030;font-size:1.4rem;font-weight:400;height:auto;line-height:1.36;padding:.6rem 1rem;transition:border-color .1s linear;vertical-align:baseline;width:auto}.admin__control-addon [class*=admin__control-][class]:hover~[class*=admin__addon-]:last-child:before,.admin__control-multiselect:hover,.admin__control-select:hover,.admin__control-text:hover,.admin__control-textarea:hover,.selectmenu:hover,.selectmenu:hover .selectmenu-toggle:before{border-color:#878787}.admin__control-addon [class*=admin__control-][class]:focus~[class*=admin__addon-]:last-child:before,.admin__control-file:active+.admin__control-file-label:before,.admin__control-file:focus+.admin__control-file-label:before,.admin__control-multiselect:focus,.admin__control-select:focus,.admin__control-text:focus,.admin__control-textarea:focus,.selectmenu._focus,.selectmenu._focus .selectmenu-toggle:before{border-color:#007bdb;box-shadow:none;outline:0}.admin__control-addon [class*=admin__control-][class][disabled]~[class*=admin__addon-]:last-child:before,.admin__control-file[disabled]+.admin__control-file-label:before,.admin__control-multiselect[disabled],.admin__control-select[disabled],.admin__control-text[disabled],.admin__control-textarea[disabled]{background-color:#e9e9e9;border-color:#adadad;color:#303030;cursor:not-allowed;opacity:.5}.admin__field-row[class]>.admin__field-control,.admin__fieldset>.admin__field.admin__field-wide[class]>.admin__field-control{clear:left;float:none;text-align:left;width:auto}.admin__field-row[class]:not(.admin__field-option)>.admin__field-label,.admin__fieldset>.admin__field.admin__field-wide[class]:not(.admin__field-option)>.admin__field-label{display:block;line-height:1.4rem;margin-bottom:.86rem;margin-top:-.14rem;text-align:left;width:auto}.admin__field-row[class]:not(.admin__field-option)>.admin__field-label:before,.admin__fieldset>.admin__field.admin__field-wide[class]:not(.admin__field-option)>.admin__field-label:before{display:none}.admin__field-row[class]:not(.admin__field-option)._required>.admin__field-label span,.admin__field-row[class]:not(.admin__field-option).required>.admin__field-label span,.admin__fieldset>.admin__field.admin__field-wide[class]:not(.admin__field-option)._required>.admin__field-label span,.admin__fieldset>.admin__field.admin__field-wide[class]:not(.admin__field-option).required>.admin__field-label span{padding-left:1.5rem}.admin__field-row[class]:not(.admin__field-option)._required>.admin__field-label span:after,.admin__field-row[class]:not(.admin__field-option).required>.admin__field-label span:after,.admin__fieldset>.admin__field.admin__field-wide[class]:not(.admin__field-option)._required>.admin__field-label span:after,.admin__fieldset>.admin__field.admin__field-wide[class]:not(.admin__field-option).required>.admin__field-label span:after{left:0;margin-left:30px}.admin__legend{font-size:1.8rem;font-weight:600;margin-bottom:3rem}.admin__control-checkbox,.admin__control-radio{cursor:pointer;opacity:.01;overflow:hidden;position:absolute;vertical-align:top}.admin__control-checkbox:after,.admin__control-radio:after{display:none}.admin__control-checkbox+label,.admin__control-radio+label{cursor:pointer;display:inline-block}.admin__control-checkbox+label:before,.admin__control-radio+label:before{background-color:#fff;border:1px solid #adadad;color:transparent;float:left;height:1.6rem;text-align:center;vertical-align:top;width:1.6rem}.admin__control-checkbox+.admin__field-label,.admin__control-radio+.admin__field-label{padding-left:2.6rem}.admin__control-checkbox+.admin__field-label:before,.admin__control-radio+.admin__field-label:before{margin:1px 1rem 0 -2.6rem}.admin__control-checkbox:checked+label:before,.admin__control-radio:checked+label:before{color:#514943}.admin__control-checkbox.disabled+label,.admin__control-checkbox[disabled]+label,.admin__control-radio.disabled+label,.admin__control-radio[disabled]+label{color:#303030;cursor:default;opacity:.5}.admin__control-checkbox.disabled+label:before,.admin__control-checkbox[disabled]+label:before,.admin__control-radio.disabled+label:before,.admin__control-radio[disabled]+label:before{background-color:#e9e9e9;border-color:#adadad;cursor:default}._keyfocus .admin__control-checkbox:not(.disabled):focus+label:before,._keyfocus .admin__control-checkbox:not([disabled]):focus+label:before,._keyfocus .admin__control-radio:not(.disabled):focus+label:before,._keyfocus .admin__control-radio:not([disabled]):focus+label:before{border-color:#007bdb}.admin__control-checkbox:not(.disabled):hover+label:before,.admin__control-checkbox:not([disabled]):hover+label:before,.admin__control-radio:not(.disabled):hover+label:before,.admin__control-radio:not([disabled]):hover+label:before{border-color:#878787}.admin__control-radio+label:before{border-radius:1.6rem;content:'';transition:border-color .1s linear,color .1s ease-in}.admin__control-radio.admin__control-radio+label:before{line-height:140%}.admin__control-radio:checked+label{position:relative}.admin__control-radio:checked+label:after{background-color:#514943;border-radius:50%;content:'';height:10px;left:3px;position:absolute;top:4px;width:10px}.admin__control-radio:checked:not(.disabled):hover,.admin__control-radio:checked:not(.disabled):hover+label,.admin__control-radio:checked:not([disabled]):hover,.admin__control-radio:checked:not([disabled]):hover+label{cursor:default}.admin__control-radio:checked:not(.disabled):hover+label:before,.admin__control-radio:checked:not([disabled]):hover+label:before{border-color:#adadad}.admin__control-checkbox+label:before{border-radius:1px;content:'';font-size:0;transition:font-size .1s ease-out,color .1s ease-out,border-color .1s linear}.admin__control-checkbox:checked+label:before{content:'\e62d';font-size:1.1rem;line-height:125%}.admin__control-checkbox:not(:checked)._indeterminate+label:before,.admin__control-checkbox:not(:checked):indeterminate+label:before{color:#514943;content:'-';font-family:'Open Sans','Helvetica Neue',Helvetica,Arial,sans-serif;font-size:1.4rem;font-weight:700}input[type=checkbox].admin__control-checkbox,input[type=radio].admin__control-checkbox{margin:0;position:absolute}.admin__control-text{min-width:4rem}.admin__control-select{-webkit-appearance:none;-moz-appearance:none;-ms-appearance:none;appearance:none;background-image:url(../images/arrows-bg.svg),linear-gradient(#e3e3e3,#e3e3e3),linear-gradient(#adadad,#adadad);background-position:calc(100% - 12px) -34px,100%,calc(100% - 3.2rem) 0;background-size:auto,3.2rem 100%,1px 100%;background-repeat:no-repeat;max-width:100%;min-width:8.5rem;padding-bottom:.5rem;padding-right:4.4rem;padding-top:.5rem;transition:border-color .1s linear}.admin__control-select:hover{border-color:#878787;cursor:pointer}.admin__control-select:focus{background-image:url(../images/arrows-bg.svg),linear-gradient(#e3e3e3,#e3e3e3),linear-gradient(#007bdb,#007bdb);background-position:calc(100% - 12px) 13px,100%,calc(100% - 3.2rem) 0;border-color:#007bdb}.admin__control-select::-ms-expand{display:none}.ie9 .admin__control-select{background-image:none;padding-right:1rem}option:empty{display:none}.admin__control-multiselect{height:auto;max-width:100%;min-width:15rem;overflow:auto;padding:0;resize:both}.admin__control-multiselect optgroup,.admin__control-multiselect option{padding:.5rem 1rem}.admin__control-file-wrapper{display:inline-block;padding:.5rem 1rem;position:relative;z-index:1}.admin__control-file-label:before{content:'';left:0;position:absolute;top:0;width:100%;z-index:0}.admin__control-file{background:0 0;border:0;padding-top:.7rem;position:relative;width:auto;z-index:1}.admin__control-support-text{border:1px solid transparent;display:inline-block;font-size:1.4rem;line-height:1.36;padding-bottom:.6rem;padding-top:.6rem}.admin__control-support-text+[class*=admin__control-],[class*=admin__control-]+.admin__control-support-text{margin-left:.7rem}.admin__control-service{float:left;margin:.8rem 0 0 3rem}.admin__control-textarea{height:8.48rem;line-height:1.18;padding-top:.8rem;resize:vertical}.admin__control-addon{-ms-flex-direction:row;flex-direction:row;display:inline-flex;-ms-flex-flow:row nowrap;flex-flow:row nowrap;position:relative;width:100%;z-index:1}.admin__control-addon>[class*=admin__addon-],.admin__control-addon>[class*=admin__control-]{-ms-flex-preferred-size:auto;flex-basis:auto;-webkit-flex-grow:0;-ms-flex-positive:0;flex-grow:0;-ms-flex-negative:0;flex-shrink:0;position:relative;z-index:1}.admin__control-addon .admin__control-select{width:auto}.admin__control-addon .admin__control-text{margin:.1rem;padding:.5rem .9rem;width:100%}.admin__control-addon [class*=admin__control-][class]{appearence:none;-webkit-flex-grow:1;-ms-flex-positive:1;flex-grow:1;-ms-flex-order:1;order:1;-ms-flex-negative:1;flex-shrink:1;background-color:transparent;border-color:transparent;box-shadow:none;vertical-align:top}.admin__control-addon [class*=admin__control-][class]+[class*=admin__control-]{border-left-color:#adadad}.admin__control-addon [class*=admin__control-][class] :focus{box-shadow:0}.admin__control-addon [class*=admin__control-][class]~[class*=admin__addon-]:last-child{padding-left:1rem;position:static!important;z-index:0}.admin__control-addon [class*=admin__control-][class]~[class*=admin__addon-]:last-child>*{position:relative;vertical-align:top;z-index:1}.admin__control-addon [class*=admin__control-][class]~[class*=admin__addon-]:last-child:empty{padding:0}.admin__control-addon [class*=admin__control-][class]~[class*=admin__addon-]:last-child:before{bottom:0;box-sizing:border-box;content:'';left:0;position:absolute;top:0;width:100%;z-index:-1}.admin__addon-prefix,.admin__addon-suffix{border:0;box-sizing:border-box;color:#858585;display:inline-block;font-size:1.4rem;font-weight:400;height:3.2rem;line-height:3.2rem;padding:0}.admin__addon-suffix{-ms-flex-order:3;order:3}.admin__addon-suffix:last-child{padding-right:1rem}.admin__addon-prefix{-ms-flex-order:0;order:0}.ie9 .admin__control-addon:after{clear:both;content:'';display:block;height:0;overflow:hidden}.ie9 .admin__addon{min-width:0;overflow:hidden;text-align:right;white-space:nowrap;width:auto}.ie9 .admin__addon [class*=admin__control-]{display:inline}.ie9 .admin__addon-prefix{float:left}.ie9 .admin__addon-suffix{float:right}.admin__control-collapsible{width:100%}.admin__control-collapsible ._dragged .admin__collapsible-block-wrapper .admin__collapsible-title{background:#d0d0d0}.admin__control-collapsible ._dragover-bottom .admin__collapsible-block-wrapper:before,.admin__control-collapsible ._dragover-top .admin__collapsible-block-wrapper:before{background:#008bdb;content:'';display:block;height:3px;left:0;position:absolute;right:0}.admin__control-collapsible ._dragover-top .admin__collapsible-block-wrapper:before{top:-3px}.admin__control-collapsible ._dragover-bottom .admin__collapsible-block-wrapper:before{bottom:-3px}.admin__control-collapsible .admin__collapsible-block-wrapper.fieldset-wrapper{border:0;margin:0;position:relative}.admin__control-collapsible .admin__collapsible-block-wrapper.fieldset-wrapper .fieldset-wrapper-title{background:#f8f8f8;border:2px solid #ccc}.admin__control-collapsible .admin__collapsible-block-wrapper .fieldset-wrapper-title .admin__collapsible-title{font-size:1.4rem;font-weight:400;line-height:1;padding:1.6rem 4rem 1.6rem 3.8rem}.admin__control-collapsible .admin__collapsible-block-wrapper .fieldset-wrapper-title .admin__collapsible-title:before{left:1rem;right:auto;top:1.4rem}.admin__control-collapsible .admin__collapsible-block-wrapper .fieldset-wrapper-title .action-delete{background-color:transparent;border-color:transparent;box-shadow:none;padding:0;position:absolute;right:1rem;top:1.4rem}.admin__control-collapsible .admin__collapsible-block-wrapper .fieldset-wrapper-title .action-delete:hover{background-color:transparent;border-color:transparent;box-shadow:none}.admin__control-collapsible .admin__collapsible-block-wrapper .fieldset-wrapper-title .action-delete:before{content:'\e630';font-size:2rem}.admin__control-collapsible .admin__collapsible-block-wrapper .fieldset-wrapper-title .action-delete>span{display:none}.admin__control-collapsible .admin__collapsible-content{background-color:#fff;margin-bottom:1rem}.admin__control-collapsible .admin__collapsible-content>.fieldset-wrapper{border:1px solid #ccc;margin-top:-1px;padding:1rem}.admin__control-collapsible .admin__collapsible-content .admin__fieldset{padding:0}.admin__control-collapsible .admin__collapsible-content .admin__field:last-child{margin-bottom:0}.admin__control-table-wrapper{max-width:100%;overflow-x:auto;overflow-y:hidden}.admin__control-table{width:100%}.admin__control-table thead{background-color:transparent}.admin__control-table tbody td{vertical-align:top}.admin__control-table tfoot th{padding-bottom:1.3rem}.admin__control-table tfoot th.validation{padding-bottom:0;padding-top:0}.admin__control-table tfoot td{border-top:1px solid #fff}.admin__control-table tfoot .admin__control-table-pagination{float:right;padding-bottom:0}.admin__control-table tfoot .action-previous{margin-right:.5rem}.admin__control-table tfoot .action-next{margin-left:.9rem}.admin__control-table tr:last-child td{border-bottom:none}.admin__control-table tr._dragover-top td{box-shadow:inset 0 3px 0 0 #008bdb}.admin__control-table tr._dragover-bottom td{box-shadow:inset 0 -3px 0 0 #008bdb}.admin__control-table tr._dragged td,.admin__control-table tr._dragged th{background:#d0d0d0}.admin__control-table td,.admin__control-table th{background-color:#efefef;border:0;border-bottom:1px solid #fff;padding:1.3rem 1rem 1.3rem 0;text-align:left;vertical-align:top}.admin__control-table td:first-child,.admin__control-table th:first-child{padding-left:1rem}.admin__control-table td>.admin__control-select,.admin__control-table td>.admin__control-text,.admin__control-table th>.admin__control-select,.admin__control-table th>.admin__control-text{width:100%}.admin__control-table td._hidden,.admin__control-table th._hidden{display:none}.admin__control-table td._fit,.admin__control-table th._fit{width:1px}.admin__control-table th{color:#303030;font-size:1.4rem;font-weight:600;vertical-align:bottom}.admin__control-table th._required span:after{color:#eb5202;content:'*'}.admin__control-table .control-table-actions-th{white-space:nowrap}.admin__control-table .control-table-actions-cell{padding-top:1.8rem;text-align:center;width:1%}.admin__control-table .control-table-options-th{text-align:center;width:10rem}.admin__control-table .control-table-options-cell{text-align:center}.admin__control-table .control-table-text{line-height:3.2rem}.admin__control-table .col-draggable{padding-top:2.2rem;width:1%}.admin__control-table .action-delete{background-color:transparent;border-color:transparent;box-shadow:none;padding-left:0;padding-right:0}.admin__control-table .action-delete:hover{background-color:transparent;border-color:transparent;box-shadow:none}.admin__control-table .action-delete:before{content:'\e630';font-size:2rem}.admin__control-table .action-delete>span{display:none}.admin__control-table .draggable-handle{padding:0}.admin__control-table._dragged{outline:#007bdb solid 1px}.admin__control-table-action{background-color:#efefef;border-top:1px solid #fff;padding:1.3rem 1rem}.admin__dynamic-rows._dragged{opacity:.95;position:absolute;z-index:999}.admin__dynamic-rows.admin__control-table .admin__control-fields>.admin__field{border:0;padding:0}.admin__dynamic-rows td>.admin__field{border:0;margin:0;padding:0}.admin__control-table-pagination{padding-bottom:1rem}.admin__control-table-pagination .admin__data-grid-pager{float:right}.admin__field-tooltip{display:inline-block;margin-top:.5rem;max-width:45px;overflow:visible;vertical-align:top;width:0}.admin__field-tooltip:hover{position:relative;z-index:500}.admin__field-option .admin__field-tooltip{margin-top:.5rem}.admin__field-tooltip .admin__field-tooltip-action{margin-left:2rem;position:relative;z-index:2;display:inline-block;text-decoration:none}.admin__field-tooltip .admin__field-tooltip-action:before{-webkit-font-smoothing:antialiased;font-size:2.2rem;line-height:1;color:#514943;content:'\e633';font-family:Icons;vertical-align:middle;display:inline-block;font-weight:400;overflow:hidden;speak:none;text-align:center}.admin__field-tooltip .admin__control-text:focus+.admin__field-tooltip-content,.admin__field-tooltip:hover .admin__field-tooltip-content{display:block}.admin__field-tooltip .admin__field-tooltip-content{bottom:3.8rem;display:none;right:-2.3rem}.admin__field-tooltip .admin__field-tooltip-content:after,.admin__field-tooltip .admin__field-tooltip-content:before{border:1.6rem solid transparent;height:0;width:0;border-top-color:#afadac;content:'';display:block;position:absolute;right:2rem;top:100%;z-index:3}.admin__field-tooltip .admin__field-tooltip-content:after{border-top-color:#fffbbb;margin-top:-1px;z-index:4}.abs-admin__field-tooltip-content,.admin__field-tooltip .admin__field-tooltip-content{box-shadow:0 2px 8px 0 rgba(0,0,0,.3);background:#fffbbb;border:1px solid #afadac;border-radius:1px;padding:1.5rem 2.5rem;position:absolute;width:32rem;z-index:1}.admin__field-fallback-reset{font-size:1.25rem;white-space:nowrap;width:30px}.admin__field-fallback-reset>span{margin-left:.5rem;position:relative}.admin__field-fallback-reset:active{-ms-transform:scale(0.98);transform:scale(0.98)}.admin__field-fallback-reset:before{transition:color .1s linear;content:'\e642';font-size:1.3rem;margin-left:.5rem}.admin__field-fallback-reset:hover{cursor:pointer;text-decoration:none}.admin__field-fallback-reset:focus{background:0 0}.abs-field-size-x-small,.abs-field-sizes.admin__field-x-small>.admin__field-control,.admin__field.admin__field-x-small>.admin__field-control,.admin__fieldset>.admin__field.admin__field-x-small>.admin__field-control,[class*=admin__control-grouped]>.admin__field.admin__field-x-small>.admin__field-control{width:8rem}.abs-field-size-small,.abs-field-sizes.admin__field-small>.admin__field-control,.admin__control-grouped-date>.admin__field-date.admin__field>.admin__field-control,.admin__field.admin__field-small>.admin__field-control,.admin__fieldset>.admin__field.admin__field-small>.admin__field-control,[class*=admin__control-grouped]>.admin__field.admin__field-small>.admin__field-control{width:15rem}.abs-field-size-medium,.abs-field-sizes.admin__field-medium>.admin__field-control,.admin__field.admin__field-medium>.admin__field-control,.admin__fieldset>.admin__field.admin__field-medium>.admin__field-control,[class*=admin__control-grouped]>.admin__field.admin__field-medium>.admin__field-control{width:34rem}.abs-field-size-large,.abs-field-sizes.admin__field-large>.admin__field-control,.admin__field.admin__field-large>.admin__field-control,.admin__fieldset>.admin__field.admin__field-large>.admin__field-control,[class*=admin__control-grouped]>.admin__field.admin__field-large>.admin__field-control{width:64rem}.abs-field-no-label,.admin__field-group-additional,.admin__field-no-label,.admin__fieldset>.admin__field.admin__field-no-label>.admin__field-control{margin-left:calc((100%) * .25 + 30px)}.admin__fieldset{border:0;margin:0;min-width:0;padding:0}.admin__fieldset .fieldset-wrapper.admin__fieldset-section>.fieldset-wrapper-title{padding-left:1rem}.admin__fieldset .fieldset-wrapper.admin__fieldset-section>.fieldset-wrapper-title strong{font-size:1.7rem;font-weight:600}.admin__fieldset .fieldset-wrapper.admin__fieldset-section .admin__fieldset-wrapper-content>.admin__fieldset{padding-top:1rem}.admin__fieldset .fieldset-wrapper.admin__fieldset-section:last-child .admin__fieldset-wrapper-content>.admin__fieldset{padding-bottom:0}.admin__fieldset>.admin__field{border:0;margin:0 0 0 -30px;padding:0}.admin__fieldset>.admin__field:after{clear:both;content:'';display:table}.admin__fieldset>.admin__field>.admin__field-control{width:calc((100%) * .5 - 30px);float:left;margin-left:30px}.admin__fieldset>.admin__field>.admin__field-label{width:calc((100%) * .25 - 30px);float:left;margin-left:30px}.admin__fieldset>.admin__field.admin__field-no-label>.admin__field-label{display:none}.admin__fieldset>.admin__field+.admin__field._empty._no-header{margin-top:-3rem}.admin__fieldset-product-websites{position:relative;z-index:300}.admin__fieldset-note{margin-bottom:2rem}.admin__form-field{border:0;margin:0;padding:0}.admin__field-control .admin__control-text,.admin__field-control .admin__control-textarea,.admin__form-field-control .admin__control-text,.admin__form-field-control .admin__control-textarea{width:100%}.admin__field-label{color:#303030;cursor:pointer;margin:0;text-align:right}.admin__field-label+br{display:none}.admin__field:not(.admin__field-option)>.admin__field-label{font-family:'Open Sans','Helvetica Neue',Helvetica,Arial,sans-serif;font-size:1.4rem;font-weight:600;line-height:3.2rem;padding:0;white-space:nowrap}.admin__field:not(.admin__field-option)>.admin__field-label:before{opacity:0;visibility:hidden;content:'.';margin-left:-7px;overflow:hidden}.admin__field:not(.admin__field-option)>.admin__field-label span{display:inline-block;line-height:1.2;vertical-align:middle;white-space:normal}.admin__field:not(.admin__field-option)>.admin__field-label span[data-config-scope]{position:relative}._required>.admin__field-label>span:after,.required>.admin__field-label>span:after{color:#eb5202;content:'*';display:inline-block;font-size:1.6rem;font-weight:500;line-height:1;margin-left:10px;margin-top:.2rem;position:absolute;z-index:1}._disabled>.admin__field-label{color:#999;cursor:default}.admin__field{margin-bottom:0}.admin__field+.admin__field{margin-top:1.5rem}.admin__field:not(.admin__field-option)~.admin__field-option{margin-top:.5rem}.admin__field.admin__field-option~.admin__field-option{margin-top:.9rem}.admin__field~.admin__field-option:last-child{margin-bottom:.8rem}.admin__fieldset>.admin__field{margin-bottom:3rem;position:relative}.admin__field legend.admin__field-label{opacity:0}.admin__field[data-config-scope]:before{color:gray;content:attr(data-config-scope);display:inline-block;font-size:1.2rem;left:calc((100%) * .75 - 30px);line-height:3.2rem;margin-left:60px;position:absolute;width:calc((100%) * .25 - 30px)}.admin__field-control .admin__field[data-config-scope]:nth-child(n+2):before{content:''}.admin__field._error .admin__field-control [class*=admin__addon-]:before,.admin__field._error .admin__field-control [class*=admin__control-] [class*=admin__addon-]:before,.admin__field._error .admin__field-control>[class*=admin__control-]{border-color:#e22626}.admin__field._disabled,.admin__field._disabled:hover{box-shadow:inherit;cursor:inherit;opacity:1;outline:inherit}.admin__field._hidden{display:none}.admin__field-control+.admin__field-control{margin-top:1.5rem}.admin__field-control._with-tooltip>.admin__control-addon,.admin__field-control._with-tooltip>.admin__control-select,.admin__field-control._with-tooltip>.admin__control-text,.admin__field-control._with-tooltip>.admin__control-textarea,.admin__field-control._with-tooltip>.admin__field-option{max-width:calc(100% - 45px - 4px)}.admin__field-control._with-tooltip .admin__field-tooltip{width:auto}.admin__field-control._with-tooltip .admin__field-option{display:inline-block}.admin__field-control._with-reset>.admin__control-addon,.admin__field-control._with-reset>.admin__control-text,.admin__field-control._with-reset>.admin__control-textarea{width:calc(100% - 30px - .5rem - 4px)}.admin__field-control._with-reset .admin__field-fallback-reset{margin-left:.5rem;margin-top:1rem;vertical-align:top}.admin__field-control._with-reset._with-tooltip>.admin__control-addon,.admin__field-control._with-reset._with-tooltip>.admin__control-text,.admin__field-control._with-reset._with-tooltip>.admin__control-textarea{width:calc(100% - 30px - .5rem - 45px - 8px)}.admin__fieldset>.admin__field-collapsible{margin-bottom:0}.admin__fieldset>.admin__field-collapsible .admin__field-control{border-top:1px solid #ccc;display:block;font-size:1.7rem;font-weight:700;padding:1.7rem 0;width:calc(97%)}.admin__fieldset>.admin__field-collapsible .admin__field-option{padding-top:0}.admin__field-collapsible+div{margin-top:2.5rem}.admin__field-collapsible .admin__control-radio+label:before{height:1.8rem;width:1.8rem}.admin__field-collapsible .admin__control-radio:checked+label:after{left:4px;top:5px}.admin__field-error{background:#fffbbb;border:1px solid #ee7d7d;box-sizing:border-box;color:#555;display:block;font-size:1.2rem;font-weight:400;line-height:1.2;margin:.2rem 0 0;padding:.8rem 1rem .9rem}.admin__field-note{color:#303030;font-size:1.2rem;margin:10px 0 0;padding:0}.admin__additional-info{padding-top:1rem}.admin__field-option{padding-top:.7rem}.admin__field-option .admin__field-label{text-align:left}.admin__field-control>.admin__field-option:nth-child(1):nth-last-child(2),.admin__field-control>.admin__field-option:nth-child(2):nth-last-child(1){display:inline-block}.admin__field-control>.admin__field-option:nth-child(1):nth-last-child(2)+.admin__field-option,.admin__field-control>.admin__field-option:nth-child(2):nth-last-child(1)+.admin__field-option{display:inline-block;margin-left:41px;margin-top:0}.admin__field-control>.admin__field-option:nth-child(1):nth-last-child(2)+.admin__field-option:before,.admin__field-control>.admin__field-option:nth-child(2):nth-last-child(1)+.admin__field-option:before{background:#cacaca;content:'';display:inline-block;height:20px;margin-left:-20px;position:absolute;width:1px}.admin__field-value{display:inline-block;padding-top:.7rem}.admin__field-service{padding-top:1rem}.admin__control-fields>.admin__field:first-child,[class*=admin__control-grouped]>.admin__field:first-child{position:static}.admin__control-fields>.admin__field:first-child>.admin__field-label,[class*=admin__control-grouped]>.admin__field:first-child>.admin__field-label{width:calc((100%) * .25 - 30px);float:left;margin-left:30px;background:#fff;cursor:pointer;left:0;position:absolute;top:0}.admin__control-fields>.admin__field:first-child>.admin__field-label span:before,[class*=admin__control-grouped]>.admin__field:first-child>.admin__field-label span:before{display:block}.admin__control-fields>.admin__field._disabled>.admin__field-label,[class*=admin__control-grouped]>.admin__field._disabled>.admin__field-label{cursor:default}.admin__control-fields>.admin__field>.admin__field-label span:before,[class*=admin__control-grouped]>.admin__field>.admin__field-label span:before{display:none}.admin__control-fields .admin__field-label~.admin__field-control{width:100%}.admin__control-fields .admin__field-option{padding-top:0}[class*=admin__control-grouped]{box-sizing:border-box;display:table;width:100%}[class*=admin__control-grouped]>.admin__field{display:table-cell;vertical-align:top}[class*=admin__control-grouped]>.admin__field>.admin__field-control{float:none;width:100%}[class*=admin__control-grouped]>.admin__field.admin__field-default,[class*=admin__control-grouped]>.admin__field.admin__field-large,[class*=admin__control-grouped]>.admin__field.admin__field-medium,[class*=admin__control-grouped]>.admin__field.admin__field-small,[class*=admin__control-grouped]>.admin__field.admin__field-x-small{width:1px}[class*=admin__control-grouped]>.admin__field.admin__field-default+.admin__field:last-child,[class*=admin__control-grouped]>.admin__field.admin__field-large+.admin__field:last-child,[class*=admin__control-grouped]>.admin__field.admin__field-medium+.admin__field:last-child,[class*=admin__control-grouped]>.admin__field.admin__field-small+.admin__field:last-child,[class*=admin__control-grouped]>.admin__field.admin__field-x-small+.admin__field:last-child{width:auto}[class*=admin__control-grouped]>.admin__field:nth-child(n+2){padding-left:20px}.admin__control-group-equal{table-layout:fixed}.admin__control-group-equal>.admin__field{width:50%}.admin__field-control-group{margin-top:.8rem}.admin__field-control-group>.admin__field{padding:0}.admin__control-grouped-date>.admin__field-date{white-space:nowrap;width:1px}.admin__control-grouped-date>.admin__field-date.admin__field>.admin__field-control{float:left;position:relative}.admin__control-grouped-date>.admin__field-date+.admin__field:last-child{width:auto}.admin__control-grouped-date>.admin__field-date+.admin__field-date>.admin__field-label{float:left;padding-right:20px}.admin__control-grouped-date .ui-datepicker-trigger{left:100%;top:0}.admin__field-group-columns.admin__field-control.admin__control-grouped{width:calc((100%) * 1 - 30px);float:left;margin-left:30px}.admin__field-group-columns>.admin__field:first-child>.admin__field-label{float:none;margin:0;opacity:1;position:static;text-align:left}.admin__field-group-columns .admin__control-select{width:100%}.admin__field-group-additional{clear:both}.admin__field-group-additional .action-advanced{margin-top:1rem}.admin__field-group-additional .action-secondary{width:100%}.admin__field-group-show-label{white-space:nowrap}.admin__field-group-show-label>.admin__field-control,.admin__field-group-show-label>.admin__field-label{display:inline-block;vertical-align:top}.admin__field-group-show-label>.admin__field-label{margin-right:20px}.admin__field-complex{margin:1rem 0 3rem;padding-left:1rem}.admin__field:not(._hidden)+.admin__field-complex{margin-top:3rem}.admin__field-complex .admin__field-complex-title{clear:both;color:#303030;font-size:1.7rem;font-weight:600;letter-spacing:.025em;margin-bottom:1rem}.admin__field-complex .admin__field-complex-elements{float:right;max-width:40%}.admin__field-complex .admin__field-complex-elements button{margin-left:1rem}.admin__field-complex .admin__field-complex-content{max-width:60%;overflow:hidden}.admin__field-complex .admin__field-complex-text{margin-left:-1rem}.admin__field-complex+.admin__field._empty._no-header{margin-top:-3rem}.admin__legend{float:left;position:static;width:100%}.admin__legend+br{clear:left;display:block;height:0;overflow:hidden}.message{margin-bottom:3rem}.message-icon-top:before{margin-top:0;top:1.8rem}.nav{background-color:#f8f8f8;border-bottom:1px solid #e3e3e3;border-top:1px solid #e3e3e3;display:none;margin-bottom:3rem;padding:2.2rem 1.5rem 0 0}.nav .btn-group,.nav-bar-outer-actions{float:right;margin-bottom:1.7rem}.nav .btn-group .btn-wrap,.nav-bar-outer-actions .btn-wrap{float:right;margin-left:.5rem;margin-right:.5rem}.nav .btn-group .btn-wrap .btn,.nav-bar-outer-actions .btn-wrap .btn{padding-left:.5rem;padding-right:.5rem}.nav-bar-outer-actions{margin-top:-10.6rem;padding-right:1.5rem}.btn-wrap-try-again{width:9.5rem}.btn-wrap-next,.btn-wrap-prev{width:8.5rem}.nav-bar{counter-reset:i;float:left;margin:0 1rem 1.7rem 0;padding:0;position:relative;white-space:nowrap}.nav-bar:before{background-color:#d4d4d4;background-repeat:repeat-x;background-image:linear-gradient(to bottom,#d1d1d1 0,#d4d4d4 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#d1d1d1', endColorstr='#d4d4d4', GradientType=0);border-bottom:1px solid #d9d9d9;border-top:1px solid #bfbfbf;content:'';height:1rem;left:5.15rem;position:absolute;right:5.15rem;top:.7rem}.nav-bar>li{display:inline-block;font-size:0;position:relative;vertical-align:top;width:10.3rem}.nav-bar>li:first-child:after{display:none}.nav-bar>li:after{background-color:#514943;content:'';height:.5rem;left:calc(-50% + .25rem);position:absolute;right:calc(50% + .7rem);top:.9rem}.nav-bar>li.disabled:before,.nav-bar>li.ui-state-disabled:before{bottom:0;content:'';left:0;position:absolute;right:0;top:0;z-index:1}.nav-bar>li.active~li:after,.nav-bar>li.ui-state-active~li:after{display:none}.nav-bar>li.active~li a:after,.nav-bar>li.ui-state-active~li a:after{background-color:transparent;border-color:transparent;color:#a6a6a6}.nav-bar>li.active a,.nav-bar>li.ui-state-active a{color:#000}.nav-bar>li.active a:hover,.nav-bar>li.ui-state-active a:hover{cursor:default}.nav-bar>li.active a:after,.nav-bar>li.ui-state-active a:after{background-color:#fff;content:''}.nav-bar a{color:#514943;display:block;font-size:1.2rem;font-weight:600;line-height:1.2;overflow:hidden;padding:3rem .5em 0;position:relative;text-align:center;text-overflow:ellipsis}.nav-bar a:hover{text-decoration:none}.nav-bar a:after{background-color:#514943;border:.4rem solid #514943;border-radius:100%;color:#fff;content:counter(i);counter-increment:i;height:1.5rem;left:50%;line-height:.6;margin-left:-.8rem;position:absolute;right:auto;text-align:center;top:.4rem;width:1.5rem}.nav-bar a:before{background-color:#d6d6d6;border:1px solid transparent;border-bottom-color:#d9d9d9;border-radius:100%;border-top-color:#bfbfbf;content:'';height:2.3rem;left:50%;line-height:1;margin-left:-1.2rem;position:absolute;top:0;width:2.3rem}.tooltip{display:block;font-family:'Open Sans','Helvetica Neue',Helvetica,Arial,sans-serif;font-size:1.19rem;font-weight:400;line-height:1.4;opacity:0;position:absolute;visibility:visible;z-index:10}.tooltip.in{opacity:.9}.tooltip.top{margin-top:-4px;padding:8px 0}.tooltip.right{margin-left:4px;padding:0 8px}.tooltip.bottom{margin-top:4px;padding:8px 0}.tooltip.left{margin-left:-4px;padding:0 8px}.tooltip p:last-child{margin-bottom:0}.tooltip-inner{background-color:#fff;border:1px solid #adadad;border-radius:0;box-shadow:1px 1px 1px #ccc;color:#41362f;max-width:31rem;padding:.5em 1em;text-decoration:none}.tooltip-arrow,.tooltip-arrow:after{border:solid transparent;height:0;position:absolute;width:0}.tooltip-arrow:after{content:'';position:absolute}.tooltip.top .tooltip-arrow,.tooltip.top .tooltip-arrow:after{border-top-color:#949494;border-width:8px 8px 0;bottom:0;left:50%;margin-left:-8px}.tooltip.top-left .tooltip-arrow,.tooltip.top-left .tooltip-arrow:after{border-top-color:#949494;border-width:8px 8px 0;bottom:0;margin-bottom:-8px;right:8px}.tooltip.top-right .tooltip-arrow,.tooltip.top-right .tooltip-arrow:after{border-top-color:#949494;border-width:8px 8px 0;bottom:0;left:8px;margin-bottom:-8px}.tooltip.right .tooltip-arrow,.tooltip.right .tooltip-arrow:after{border-right-color:#949494;border-width:8px 8px 8px 0;left:1px;margin-top:-8px;top:50%}.tooltip.right .tooltip-arrow:after{border-right-color:#fff;border-width:6px 7px 6px 0;margin-left:0;margin-top:-6px}.tooltip.left .tooltip-arrow,.tooltip.left .tooltip-arrow:after{border-left-color:#949494;border-width:8px 0 8px 8px;margin-top:-8px;right:0;top:50%}.tooltip.bottom .tooltip-arrow,.tooltip.bottom .tooltip-arrow:after{border-bottom-color:#949494;border-width:0 8px 8px;left:50%;margin-left:-8px;top:0}.tooltip.bottom-left .tooltip-arrow,.tooltip.bottom-left .tooltip-arrow:after{border-bottom-color:#949494;border-width:0 8px 8px;margin-top:-8px;right:8px;top:0}.tooltip.bottom-right .tooltip-arrow,.tooltip.bottom-right .tooltip-arrow:after{border-bottom-color:#949494;border-width:0 8px 8px;left:8px;margin-top:-8px;top:0}.password-strength{display:block;margin:0 -.3rem 1em;white-space:nowrap}.password-strength.password-strength-too-short .password-strength-item:first-child,.password-strength.password-strength-weak .password-strength-item:first-child,.password-strength.password-strength-weak .password-strength-item:first-child+.password-strength-item{background-color:#e22626}.password-strength.password-strength-fair .password-strength-item:first-child,.password-strength.password-strength-fair .password-strength-item:first-child+.password-strength-item,.password-strength.password-strength-fair .password-strength-item:first-child+.password-strength-item+.password-strength-item{background-color:#ef672f}.password-strength.password-strength-good .password-strength-item:first-child,.password-strength.password-strength-good .password-strength-item:first-child+.password-strength-item,.password-strength.password-strength-good .password-strength-item:first-child+.password-strength-item+.password-strength-item,.password-strength.password-strength-good .password-strength-item:first-child+.password-strength-item+.password-strength-item+.password-strength-item,.password-strength.password-strength-strong .password-strength-item{background-color:#79a22e}.password-strength .password-strength-item{background-color:#ccc;display:inline-block;font-size:0;height:1.4rem;margin-right:.3rem;width:calc(20% - .6rem)}@keyframes progress-bar-stripes{from{background-position:4rem 0}to{background-position:0 0}}.progress{background-color:#fafafa;border:1px solid #ccc;clear:left;height:3rem;margin-bottom:3rem;overflow:hidden}.progress-bar{background-color:#79a22e;color:#fff;float:left;font-size:1.19rem;height:100%;line-height:3rem;text-align:center;transition:width .6s ease;width:0}.progress-bar.active{animation:progress-bar-stripes 2s linear infinite}.progress-bar-text-description{margin-bottom:1.6rem}.progress-bar-text-progress{text-align:right}.page-columns .page-inner-sidebar{margin:0 0 3rem}.page-header{margin-bottom:2.7rem;padding-bottom:2rem;position:relative}.page-header:before{border-bottom:1px solid #e3e3e3;bottom:0;content:'';display:block;height:1px;left:3rem;position:absolute;right:3rem}.container .page-header:before{content:normal}.page-header .message{margin-bottom:1.8rem}.page-header .message+.message{margin-top:-1.5rem}.page-header .admin__action-dropdown,.page-header .search-global-input{transition:none}.container .page-header{margin-bottom:0}.page-title-wrapper{margin-top:1.1rem}.container .page-title-wrapper{background:url(../../pub/images/logo.svg) no-repeat;min-height:41px;padding:4px 0 0 45px}.admin__menu .level-0:first-child>a{margin-top:1.6rem}.admin__menu .level-0:first-child>a:after{top:-1.6rem}.admin__menu .level-0:first-child._active>a:after{display:block}.admin__menu .level-0>a{padding-bottom:1.3rem;padding-top:1.3rem}.admin__menu .level-0>a:before{margin-bottom:.7rem}.admin__menu .item-home>a:before{content:'\e611';font-size:2.3rem;padding-top:-.1rem}.admin__menu .item-component>a:before{content:'\e612'}.admin__menu .item-extension>a:before{content:'\e612'}.admin__menu .item-module>a:before{content:'\e647'}.admin__menu .item-upgrade>a:before{content:'\e614'}.admin__menu .item-system-config>a:before{content:'\e610'}.admin__menu .item-tools>a:before{content:'\e613'}.modal-sub-title{font-size:1.7rem;font-weight:600}.modal-connect-signin .modal-inner-wrap{max-width:80rem}@keyframes ngdialog-fadeout{0%{opacity:1}100%{opacity:0}}@keyframes ngdialog-fadein{0%{opacity:0}100%{opacity:1}}.ngdialog{-webkit-overflow-scrolling:touch;bottom:0;box-sizing:border-box;left:0;overflow:auto;position:fixed;right:0;top:0;z-index:999}.ngdialog *,.ngdialog:after,.ngdialog:before{box-sizing:inherit}.ngdialog.ngdialog-disabled-animation *{animation:none!important}.ngdialog.ngdialog-closing .ngdialog-content,.ngdialog.ngdialog-closing .ngdialog-overlay{-webkit-animation:ngdialog-fadeout .5s;-webkit-backface-visibility:hidden;animation:ngdialog-fadeout .5s}.ngdialog-overlay{-webkit-animation:ngdialog-fadein .5s;-webkit-backface-visibility:hidden;animation:ngdialog-fadein .5s;background:rgba(0,0,0,.4);bottom:0;left:0;position:fixed;right:0;top:0}.ngdialog-content{-webkit-animation:ngdialog-fadein .5s;-webkit-backface-visibility:hidden;animation:ngdialog-fadein .5s}body.ngdialog-open{overflow:hidden}.component-indicator{border-radius:50%;cursor:help;display:inline-block;height:16px;text-align:center;vertical-align:middle;width:16px}.component-indicator::after,.component-indicator::before{background:#fff;display:block;opacity:0;position:absolute;transition:opacity .2s linear .1s;visibility:hidden}.component-indicator::before{border:1px solid #adadad;border-radius:1px;box-shadow:0 0 2px rgba(0,0,0,.4);content:attr(data-label);font-size:1.2rem;margin:30px 0 0 -10px;min-width:50px;padding:4px 5px}.component-indicator::after{border-color:#999;border-style:solid;border-width:1px 0 0 1px;box-shadow:-1px -1px 1px rgba(0,0,0,.1);content:'';height:10px;margin:9px 0 0 5px;-ms-transform:rotate(45deg);transform:rotate(45deg);width:10px}.component-indicator:hover::after,.component-indicator:hover::before{opacity:1;transition:opacity .2s linear;visibility:visible}.component-indicator span{display:block;height:16px;overflow:hidden;width:16px}.component-indicator span:before{content:'';display:block;font-family:Icons;font-size:16px;height:100%;line-height:16px;width:100%}.component-indicator._on{background:#79a22e}.component-indicator._off{background:#e22626}.component-indicator._off span:before{background:#fff;height:4px;margin:8px auto 20px;width:12px}.component-indicator._info{background:0 0}.component-indicator._info span{width:21px}.component-indicator._info span:before{color:#008bdb;content:'\e648';font-family:Icons;font-size:16px}.component-indicator._tooltip{background:0 0;margin:0 0 8px 5px}.component-indicator._tooltip a{width:21px}.component-indicator._tooltip a:hover{text-decoration:none}.component-indicator._tooltip a:before{color:#514943;content:'\e633';font-family:Icons;font-size:16px}.col-manager-item-name .data-grid-data{padding-left:5px}.col-manager-item-name .ng-hide+.data-grid-data{padding-left:24px}.col-manager-item-name ._hide-dependencies,.col-manager-item-name ._show-dependencies{cursor:pointer;padding-left:24px;position:relative}.col-manager-item-name ._hide-dependencies:before,.col-manager-item-name ._show-dependencies:before{display:block;font-family:Icons;font-size:12px;left:0;position:absolute;top:1px}.col-manager-item-name ._show-dependencies:before{content:'\e62b'}.col-manager-item-name ._hide-dependencies:before{content:'\e628'}.col-manager-item-name ._no-dependencies{padding-left:24px}.product-modules-block{font-size:1.2rem;padding:15px 0 0}.col-manager-item-name .product-modules-block{padding-left:1rem}.product-modules-descriprion,.product-modules-title{font-weight:700;margin:0 0 7px}.product-modules-list{font-size:1.1rem;list-style:none;margin:0}.col-manager-item-name .product-modules-list{margin-left:15px}.col-manager-item-name .product-modules-list li{padding:0 0 0 15px;position:relative}.product-modules-list li{margin:0 0 .5rem}.product-modules-list .component-indicator{height:10px;left:0;position:absolute;top:3px;width:10px}.module-summary{white-space:nowrap}.module-summary-title{font-size:2.1rem;margin-right:1rem}.app-updater .nav{display:block;margin-bottom:3.1rem;margin-top:-2.8rem}.app-updater .nav-bar-outer-actions{margin-top:1rem;padding-right:0}.app-updater .nav-bar-outer-actions .btn-wrap-cancel{margin-right:2.6rem}.main{padding-bottom:2rem;padding-top:3rem}.menu-wrapper .logo-static{pointer-events:none}.header{display:none}.header .logo{float:left;height:4.1rem;width:3.5rem}.header-title{font-size:2.8rem;letter-spacing:.02em;line-height:1.4;margin:2.5rem 0 3.5rem 5rem}.page-title{margin-bottom:1rem}.page-sub-title{font-size:2rem}.accent-box{margin-bottom:2rem}.accent-box .btn-prime{margin-top:1.5rem}.spinner.side{float:left;font-size:2.4rem;margin-left:2rem;margin-top:-5px}.page-landing{margin:7.6% auto 0;max-width:44rem;text-align:center}.page-landing .logo{height:5.6rem;margin-bottom:2rem;width:19.2rem}.page-landing .text-version{margin-bottom:3rem}.page-landing .text-welcome{margin-bottom:6.5rem}.page-landing .text-terms{margin-bottom:2.5rem;text-align:center}.page-landing .btn-submit,.page-license .license-text{margin-bottom:2rem}.page-license .page-license-footer{text-align:right}.readiness-check-item{margin-bottom:4rem;min-height:2.5rem}.readiness-check-item .spinner{float:left;font-size:2.5rem;margin:-.4rem 0 0 1.7rem}.readiness-check-title{font-size:1.4rem;font-weight:700;margin-bottom:.1rem;margin-left:5.7rem}.readiness-check-content{margin-left:5.7rem;margin-right:22rem;position:relative}.readiness-check-content .readiness-check-title{margin-left:0}.readiness-check-content .list{margin-top:-.3rem}.readiness-check-side{left:100%;padding-left:2.4rem;position:absolute;top:0;width:22rem}.readiness-check-side .side-title{margin-bottom:0}.readiness-check-icon{float:left;margin-left:1.7rem;margin-top:.3rem}.extensions-information{margin-bottom:5rem}.extensions-information h3{font-size:1.4rem;margin-bottom:1.3rem}.extensions-information .message{margin-bottom:2.5rem}.extensions-information .message:before{margin-top:0;top:1.8rem}.extensions-information .extensions-container{padding:0 2rem}.extensions-information .list{margin-bottom:1rem}.extensions-information .list select{cursor:pointer}.extensions-information .list select:disabled{background:#ccc;cursor:default}.extensions-information .list .extension-delete{font-size:1.7rem;padding-top:0}.delete-modal-wrap{padding:0 4% 4rem}.delete-modal-wrap h3{font-size:3.4rem;display:inline-block;font-weight:300;margin:0 0 2rem;padding:.9rem 0 0;vertical-align:top}.delete-modal-wrap .actions{padding:3rem 0 0}.page-web-configuration .form-el-insider-wrap{width:auto}.page-web-configuration .form-el-insider{width:15.4rem}.page-web-configuration .form-el-insider-input .form-el-input{width:16.5rem}.customize-your-store .advanced-modules-count,.customize-your-store .advanced-modules-select{padding-left:1.5rem}.customize-your-store .customize-your-store-advanced{min-width:0}.customize-your-store .message-error:before{margin-top:0;top:1.8rem}.customize-your-store .message-error a{color:#333;text-decoration:underline}.customize-your-store .message-error .form-label:before{background:#fff}.customize-your-store .customize-database-clean p{margin-top:2.5rem}.content-install{margin-bottom:2rem}.console{border:1px solid #ccc;font-family:'Courier New',Courier,monospace;font-weight:300;height:20rem;margin:1rem 0 2rem;overflow-y:auto;padding:1.5rem 2rem 2rem;resize:vertical}.console .text-danger{color:#e22626}.console .text-success{color:#090}.console .hidden{display:none}.content-success .btn-prime{margin-top:1.5rem}.jumbo-title{font-size:3.6rem}.jumbo-title .jumbo-icon{font-size:3.8rem;margin-right:.25em;position:relative;top:.15em}.install-database-clean{margin-top:4rem}.install-database-clean .btn{margin-right:1rem}.page-sub-title{margin-bottom:2.1rem;margin-top:3rem}.multiselect-custom{max-width:71.1rem}.content-install{margin-top:3.7rem}.home-page-inner-wrap{margin:0 auto;max-width:91rem}.setup-home-title{margin-bottom:3.9rem;padding-top:1.8rem;text-align:center}.setup-home-item{background-color:#fafafa;border:1px solid #ccc;color:#333;display:block;margin-bottom:2rem;margin-left:1.3rem;margin-right:1.3rem;min-height:30rem;padding:2rem;text-align:center}.setup-home-item:hover{border-color:#8c8c8c;color:#333;text-decoration:none;transition:border-color .1s linear}.setup-home-item:active{-ms-transform:scale(0.99);transform:scale(0.99)}.setup-home-item:before{display:block;font-size:7rem;margin-bottom:3.3rem;margin-top:4rem}.setup-home-item-component:before,.setup-home-item-extension:before{content:'\e612'}.setup-home-item-module:before{content:'\e647'}.setup-home-item-upgrade:before{content:'\e614'}.setup-home-item-configuration:before{content:'\e610'}.setup-home-item-title{display:block;font-size:1.8rem;letter-spacing:.025em;margin-bottom:1rem}.setup-home-item-description{display:block}.extension-manager-wrap{border:1px solid #bbb;margin:0 0 4rem}.extension-manager-account{font-size:2.1rem;display:inline-block;font-weight:400}.extension-manager-title{font-size:3.2rem;background-color:#f8f8f8;border-bottom:1px solid #e3e3e3;color:#41362f;font-weight:600;line-height:1.2;padding:2rem}.extension-manager-content{padding:2.5rem 2rem 2rem}.extension-manager-items{list-style:none;margin:0;text-align:center}.extension-manager-items .btn{border:1px solid #adadad;display:block;margin:1rem auto 0}.extension-manager-items .item-title{font-size:2.1rem;display:inline-block;text-align:left}.extension-manager-items .item-number{font-size:4.1rem;display:inline-block;line-height:.8;margin:0 5px 1.5rem 0;vertical-align:top}.extension-manager-items .item-date{font-size:2.6rem;margin-top:1px}.extension-manager-items .item-date-title{font-size:1.5rem}.extension-manager-items .item-install{margin:0 0 2rem}.sync-login-wrap{padding:0 10% 4rem}.sync-login-wrap .legend{font-size:2.6rem;color:#eb5202;float:left;font-weight:300;line-height:1.2;margin:-1rem 0 2.5rem;position:static;width:100%}.sync-login-wrap .legend._hidden{display:none}.sync-login-wrap .login-header{font-size:3.4rem;font-weight:300;margin:0 0 2rem}.sync-login-wrap .login-header span{display:inline-block;padding:.9rem 0 0;vertical-align:top}.sync-login-wrap h4{font-size:1.4rem;margin:0 0 2rem}.sync-login-wrap .sync-login-steps{margin:0 0 2rem 1.5rem}.sync-login-wrap .sync-login-steps li{padding:0 0 0 1rem}.sync-login-wrap .form-row .form-label{display:inline-block}.sync-login-wrap .form-row .form-label.required{padding-left:1.5rem}.sync-login-wrap .form-row .form-label.required:after{left:0;position:absolute;right:auto}.sync-login-wrap .form-row{max-width:28rem}.sync-login-wrap .form-actions{display:table;margin-top:-1.3rem}.sync-login-wrap .form-actions .links{display:table-header-group}.sync-login-wrap .form-actions .actions{padding:3rem 0 0}@media all and (max-width:1047px){.admin__menu .submenu li{min-width:19.8rem}.nav{padding-bottom:5.38rem;padding-left:1.5rem;text-align:center}.nav-bar{display:inline-block;float:none;margin-right:0;vertical-align:top}.nav .btn-group,.nav-bar-outer-actions{display:inline-block;float:none;margin-top:-8.48rem;text-align:center;vertical-align:top;width:100%}.nav-bar-outer-actions{padding-right:0}.nav-bar-outer-actions .outer-actions-inner-wrap{display:inline-block}.app-updater .nav{padding-bottom:1.7rem}.app-updater .nav-bar-outer-actions{margin-top:2rem}}@media all and (min-width:768px){.page-layout-admin-2columns-left .page-columns{margin-left:-30px}.page-layout-admin-2columns-left .page-columns:after{clear:both;content:'';display:table}.page-layout-admin-2columns-left .page-columns .main-col{width:calc((100%) * .75 - 30px);float:right}.page-layout-admin-2columns-left .page-columns .side-col{width:calc((100%) * .25 - 30px);float:left;margin-left:30px}.col-m-1,.col-m-10,.col-m-11,.col-m-12,.col-m-2,.col-m-3,.col-m-4,.col-m-5,.col-m-6,.col-m-7,.col-m-8,.col-m-9{float:left}.col-m-12{width:100%}.col-m-11{width:91.66666667%}.col-m-10{width:83.33333333%}.col-m-9{width:75%}.col-m-8{width:66.66666667%}.col-m-7{width:58.33333333%}.col-m-6{width:50%}.col-m-5{width:41.66666667%}.col-m-4{width:33.33333333%}.col-m-3{width:25%}.col-m-2{width:16.66666667%}.col-m-1{width:8.33333333%}.col-m-pull-12{right:100%}.col-m-pull-11{right:91.66666667%}.col-m-pull-10{right:83.33333333%}.col-m-pull-9{right:75%}.col-m-pull-8{right:66.66666667%}.col-m-pull-7{right:58.33333333%}.col-m-pull-6{right:50%}.col-m-pull-5{right:41.66666667%}.col-m-pull-4{right:33.33333333%}.col-m-pull-3{right:25%}.col-m-pull-2{right:16.66666667%}.col-m-pull-1{right:8.33333333%}.col-m-pull-0{right:auto}.col-m-push-12{left:100%}.col-m-push-11{left:91.66666667%}.col-m-push-10{left:83.33333333%}.col-m-push-9{left:75%}.col-m-push-8{left:66.66666667%}.col-m-push-7{left:58.33333333%}.col-m-push-6{left:50%}.col-m-push-5{left:41.66666667%}.col-m-push-4{left:33.33333333%}.col-m-push-3{left:25%}.col-m-push-2{left:16.66666667%}.col-m-push-1{left:8.33333333%}.col-m-push-0{left:auto}.col-m-offset-12{margin-left:100%}.col-m-offset-11{margin-left:91.66666667%}.col-m-offset-10{margin-left:83.33333333%}.col-m-offset-9{margin-left:75%}.col-m-offset-8{margin-left:66.66666667%}.col-m-offset-7{margin-left:58.33333333%}.col-m-offset-6{margin-left:50%}.col-m-offset-5{margin-left:41.66666667%}.col-m-offset-4{margin-left:33.33333333%}.col-m-offset-3{margin-left:25%}.col-m-offset-2{margin-left:16.66666667%}.col-m-offset-1{margin-left:8.33333333%}.col-m-offset-0{margin-left:0}.page-columns{margin-left:-30px}.page-columns:after{clear:both;content:'';display:table}.page-columns .page-inner-content{width:calc((100%) * .75 - 30px);float:right}.page-columns .page-inner-sidebar{width:calc((100%) * .25 - 30px);float:left;margin-left:30px}}@media all and (min-width:1048px){.col-l-1,.col-l-10,.col-l-11,.col-l-12,.col-l-2,.col-l-3,.col-l-4,.col-l-5,.col-l-6,.col-l-7,.col-l-8,.col-l-9{float:left}.col-l-12{width:100%}.col-l-11{width:91.66666667%}.col-l-10{width:83.33333333%}.col-l-9{width:75%}.col-l-8{width:66.66666667%}.col-l-7{width:58.33333333%}.col-l-6{width:50%}.col-l-5{width:41.66666667%}.col-l-4{width:33.33333333%}.col-l-3{width:25%}.col-l-2{width:16.66666667%}.col-l-1{width:8.33333333%}.col-l-pull-12{right:100%}.col-l-pull-11{right:91.66666667%}.col-l-pull-10{right:83.33333333%}.col-l-pull-9{right:75%}.col-l-pull-8{right:66.66666667%}.col-l-pull-7{right:58.33333333%}.col-l-pull-6{right:50%}.col-l-pull-5{right:41.66666667%}.col-l-pull-4{right:33.33333333%}.col-l-pull-3{right:25%}.col-l-pull-2{right:16.66666667%}.col-l-pull-1{right:8.33333333%}.col-l-pull-0{right:auto}.col-l-push-12{left:100%}.col-l-push-11{left:91.66666667%}.col-l-push-10{left:83.33333333%}.col-l-push-9{left:75%}.col-l-push-8{left:66.66666667%}.col-l-push-7{left:58.33333333%}.col-l-push-6{left:50%}.col-l-push-5{left:41.66666667%}.col-l-push-4{left:33.33333333%}.col-l-push-3{left:25%}.col-l-push-2{left:16.66666667%}.col-l-push-1{left:8.33333333%}.col-l-push-0{left:auto}.col-l-offset-12{margin-left:100%}.col-l-offset-11{margin-left:91.66666667%}.col-l-offset-10{margin-left:83.33333333%}.col-l-offset-9{margin-left:75%}.col-l-offset-8{margin-left:66.66666667%}.col-l-offset-7{margin-left:58.33333333%}.col-l-offset-6{margin-left:50%}.col-l-offset-5{margin-left:41.66666667%}.col-l-offset-4{margin-left:33.33333333%}.col-l-offset-3{margin-left:25%}.col-l-offset-2{margin-left:16.66666667%}.col-l-offset-1{margin-left:8.33333333%}.col-l-offset-0{margin-left:0}}@media all and (min-width:1440px){.col-xl-1,.col-xl-10,.col-xl-11,.col-xl-12,.col-xl-2,.col-xl-3,.col-xl-4,.col-xl-5,.col-xl-6,.col-xl-7,.col-xl-8,.col-xl-9{float:left}.col-xl-12{width:100%}.col-xl-11{width:91.66666667%}.col-xl-10{width:83.33333333%}.col-xl-9{width:75%}.col-xl-8{width:66.66666667%}.col-xl-7{width:58.33333333%}.col-xl-6{width:50%}.col-xl-5{width:41.66666667%}.col-xl-4{width:33.33333333%}.col-xl-3{width:25%}.col-xl-2{width:16.66666667%}.col-xl-1{width:8.33333333%}.col-xl-pull-12{right:100%}.col-xl-pull-11{right:91.66666667%}.col-xl-pull-10{right:83.33333333%}.col-xl-pull-9{right:75%}.col-xl-pull-8{right:66.66666667%}.col-xl-pull-7{right:58.33333333%}.col-xl-pull-6{right:50%}.col-xl-pull-5{right:41.66666667%}.col-xl-pull-4{right:33.33333333%}.col-xl-pull-3{right:25%}.col-xl-pull-2{right:16.66666667%}.col-xl-pull-1{right:8.33333333%}.col-xl-pull-0{right:auto}.col-xl-push-12{left:100%}.col-xl-push-11{left:91.66666667%}.col-xl-push-10{left:83.33333333%}.col-xl-push-9{left:75%}.col-xl-push-8{left:66.66666667%}.col-xl-push-7{left:58.33333333%}.col-xl-push-6{left:50%}.col-xl-push-5{left:41.66666667%}.col-xl-push-4{left:33.33333333%}.col-xl-push-3{left:25%}.col-xl-push-2{left:16.66666667%}.col-xl-push-1{left:8.33333333%}.col-xl-push-0{left:auto}.col-xl-offset-12{margin-left:100%}.col-xl-offset-11{margin-left:91.66666667%}.col-xl-offset-10{margin-left:83.33333333%}.col-xl-offset-9{margin-left:75%}.col-xl-offset-8{margin-left:66.66666667%}.col-xl-offset-7{margin-left:58.33333333%}.col-xl-offset-6{margin-left:50%}.col-xl-offset-5{margin-left:41.66666667%}.col-xl-offset-4{margin-left:33.33333333%}.col-xl-offset-3{margin-left:25%}.col-xl-offset-2{margin-left:16.66666667%}.col-xl-offset-1{margin-left:8.33333333%}.col-xl-offset-0{margin-left:0}}@media all and (max-width:767px){.abs-clearer-mobile:after,.nav-bar:after{clear:both;content:'';display:table}.list-definition>dt{float:none}.list-definition>dd{margin-left:0}.form-row .form-label{text-align:left}.form-row .form-label.required:after{position:static}.nav{padding-bottom:0;padding-left:0;padding-right:0}.nav-bar-outer-actions{margin-top:0}.nav-bar{display:block;margin-bottom:0;margin-left:auto;margin-right:auto;width:30.9rem}.nav-bar:before{display:none}.nav-bar>li{float:left;min-height:9rem}.nav-bar>li:after{display:none}.nav-bar>li:nth-child(4n){clear:both}.nav-bar a{line-height:1.4}.tooltip{display:none!important}.readiness-check-content{margin-right:2rem}.readiness-check-side{padding:2rem 0;position:static}.form-el-insider,.form-el-insider-wrap,.page-web-configuration .form-el-insider-input,.page-web-configuration .form-el-insider-input .form-el-input{display:block;width:100%}}@media all and (max-width:479px){.nav-bar{width:23.175rem}.nav-bar>li{width:7.725rem}.nav .btn-group .btn-wrap-try-again,.nav-bar-outer-actions .btn-wrap-try-again{clear:both;display:block;float:none;margin-left:auto;margin-right:auto;margin-top:1rem;padding-top:1rem}} +.abs-action-delete,.abs-icon,.action-close:before,.action-next:before,.action-previous:before,.admin-user .admin__action-dropdown:before,.admin__action-multiselect-dropdown:before,.admin__action-multiselect-search-label:before,.admin__control-checkbox+label:before,.admin__control-collapsible .admin__collapsible-block-wrapper .fieldset-wrapper-title .action-delete:before,.admin__control-table .action-delete:before,.admin__current-filters-list .action-remove:before,.admin__data-grid-action-bookmarks .action-delete:before,.admin__data-grid-action-bookmarks .action-edit:before,.admin__data-grid-action-bookmarks .action-submit:before,.admin__data-grid-action-bookmarks .admin__action-dropdown:before,.admin__data-grid-action-columns .admin__action-dropdown:before,.admin__data-grid-action-export .admin__action-dropdown:before,.admin__field-fallback-reset:before,.admin__menu .level-0>a:before,.admin__page-nav-item-message .admin__page-nav-item-message-icon,.admin__page-nav-title._collapsible:after,.data-grid-filters-action-wrap .action-default:before,.data-grid-row-changed:after,.data-grid-row-parent>td .data-grid-checkbox-cell-inner:before,.data-grid-search-control-wrap .action-submit:before,.extensions-information .list .extension-delete,.icon-failed:before,.icon-success:before,.notifications-action:before,.notifications-close:before,.page-actions .page-actions-buttons>button.action-back:before,.page-actions .page-actions-buttons>button.back:before,.page-actions>button.action-back:before,.page-actions>button.back:before,.page-title-jumbo-success:before,.search-global-label:before,.selectmenu .action-delete:before,.selectmenu .action-edit:before,.selectmenu .action-save:before,.setup-home-item:before,.sticky-header .data-grid-search-control-wrap .data-grid-search-label:before,.store-switcher .dropdown-menu .dropdown-toolbar a:before,.tooltip .help a:before,.tooltip .help span:before{-webkit-font-smoothing:antialiased;font-family:Icons;font-style:normal;font-weight:400;line-height:1;speak:none}.validation-symbol:after{color:#e22626;content:'*';font-weight:400;margin-left:3px}.abs-modal-overlay,.modals-overlay{background:rgba(0,0,0,.35);bottom:0;left:0;position:fixed;right:0;top:0}.abs-action-delete>span,.abs-visually-hidden,.action-multicheck-wrap .action-multicheck-toggle>span,.admin__actions-switch-checkbox,.admin__control-fields .admin__field:nth-child(n+2):not(.admin__field-option):not(.admin__field-group-show-label)>.admin__field-label,.admin__field-tooltip .admin__field-tooltip-action span,.customize-your-store .customize-your-store-default .legend,.extensions-information .list .extension-delete>span,.form-el-checkbox,.form-el-radio,.selectmenu .action-delete>span,.selectmenu .action-edit>span,.selectmenu .action-save>span,.selectmenu-toggle span,.tooltip .help a span,.tooltip .help span span,[class*=admin__control-grouped]>.admin__field:nth-child(n+2):not(.admin__field-option):not(.admin__field-group-show-label):not(.admin__field-date)>.admin__field-label{border:0;clip:rect(0,0,0,0);height:1px;margin:-1px;overflow:hidden;padding:0;position:absolute;width:1px}.abs-visually-hidden-reset,.admin__field-group-columns>.admin__field:nth-child(n+2):not(.admin__field-option):not(.admin__field-group-show-label):not(.admin__field-date)>.admin__field-label[class]{clip:auto;height:auto;margin:0;overflow:visible;position:static;width:auto}.abs-clearfix:after,.abs-clearfix:before,.action-multicheck-wrap:after,.action-multicheck-wrap:before,.actions-split:after,.actions-split:before,.admin__control-table-pagination:after,.admin__control-table-pagination:before,.admin__data-grid-action-columns-menu .admin__action-dropdown-menu-content:after,.admin__data-grid-action-columns-menu .admin__action-dropdown-menu-content:before,.admin__data-grid-filters-footer:after,.admin__data-grid-filters-footer:before,.admin__data-grid-filters:after,.admin__data-grid-filters:before,.admin__data-grid-header-row:after,.admin__data-grid-header-row:before,.admin__field-complex:after,.admin__field-complex:before,.modal-slide .magento-message .insert-title-inner:after,.modal-slide .magento-message .insert-title-inner:before,.modal-slide .main-col .insert-title-inner:after,.modal-slide .main-col .insert-title-inner:before,.page-actions._fixed:after,.page-actions._fixed:before,.page-content:after,.page-content:before,.page-header-actions:after,.page-header-actions:before,.page-main-actions:not(._hidden):after,.page-main-actions:not(._hidden):before{content:'';display:table}.abs-clearfix:after,.action-multicheck-wrap:after,.actions-split:after,.admin__control-table-pagination:after,.admin__data-grid-action-columns-menu .admin__action-dropdown-menu-content:after,.admin__data-grid-filters-footer:after,.admin__data-grid-filters:after,.admin__data-grid-header-row:after,.admin__field-complex:after,.modal-slide .magento-message .insert-title-inner:after,.modal-slide .main-col .insert-title-inner:after,.page-actions._fixed:after,.page-content:after,.page-header-actions:after,.page-main-actions:not(._hidden):after{clear:both}.abs-list-reset-styles{margin:0;padding:0;list-style:none}.abs-draggable-handle,.admin__control-collapsible .admin__collapsible-block-wrapper .fieldset-wrapper-title .draggable-handle,.admin__control-table .draggable-handle,.data-grid .data-grid-draggable-row-cell .draggable-handle{cursor:-webkit-grab;cursor:move;font-size:0;margin-top:-4px;padding:0 1rem 0 0;vertical-align:middle;display:inline-block;text-decoration:none}.abs-draggable-handle:before,.admin__control-collapsible .admin__collapsible-block-wrapper .fieldset-wrapper-title .draggable-handle:before,.admin__control-table .draggable-handle:before,.data-grid .data-grid-draggable-row-cell .draggable-handle:before{-webkit-font-smoothing:antialiased;font-size:1.8rem;line-height:inherit;color:#9e9e9e;content:'\e617';font-family:Icons;vertical-align:middle;display:inline-block;font-weight:400;overflow:hidden;speak:none;text-align:center}.abs-draggable-handle:hover:before,.admin__control-collapsible .admin__collapsible-block-wrapper .fieldset-wrapper-title .draggable-handle:hover:before,.admin__control-table .draggable-handle:hover:before,.data-grid .data-grid-draggable-row-cell .draggable-handle:hover:before{color:#858585}.abs-config-scope-label,.admin__field:not(.admin__field-option)>.admin__field-label span[data-config-scope]:before{bottom:-1.3rem;color:gray;content:attr(data-config-scope);font-size:1.1rem;font-weight:400;min-width:15rem;position:absolute;right:0;text-transform:lowercase}.abs-word-wrap,.admin__field:not(.admin__field-option)>.admin__field-label{overflow-wrap:break-word;word-wrap:break-word;-ms-word-break:break-all;word-break:break-word;-webkit-hyphens:auto;-ms-hyphens:auto;hyphens:auto}html{-ms-text-size-adjust:100%;-webkit-text-size-adjust:100%;box-sizing:border-box}*,:after,:before{box-sizing:inherit}:focus{box-shadow:none;outline:0}._keyfocus :focus{box-shadow:0 0 0 1px #008bdb}body{margin:0}article,aside,details,figcaption,figure,footer,header,main,menu,nav,section,summary{display:block}audio,canvas,progress,video{display:inline-block;vertical-align:baseline}audio:not([controls]){display:none;height:0}[hidden],template{display:none}a{background-color:transparent}a:active,a:hover{outline:0}abbr[title]{border-bottom:1px dotted}b,strong{font-weight:700}dfn{font-style:italic}mark{background:#ff0;color:#000}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sup{top:-.5em}sub{bottom:-.25em}img{border:0}embed,img,object,video{max-width:100%}svg:not(:root){overflow:hidden}figure{margin:1em 40px}hr{box-sizing:content-box;height:0}pre{overflow:auto}code,kbd,pre,samp{font-family:monospace,monospace;font-size:1em}button,input,optgroup,select,textarea{color:inherit;font:inherit;margin:0}button{overflow:visible}button,select{text-transform:none}button,html input[type=button],input[type=reset],input[type=submit]{-webkit-appearance:button;cursor:pointer}button[disabled],html input[disabled]{cursor:default}button::-moz-focus-inner,input::-moz-focus-inner{border:0;padding:0}input{line-height:normal}input[type=checkbox],input[type=radio]{box-sizing:border-box;padding:0}input[type=number]::-webkit-inner-spin-button,input[type=number]::-webkit-outer-spin-button{height:auto}input[type=search]{-webkit-appearance:textfield}input[type=search]::-webkit-search-cancel-button,input[type=search]::-webkit-search-decoration{-webkit-appearance:none}legend{border:0;padding:0}textarea{overflow:auto}optgroup{font-weight:700}table{border-collapse:collapse;border-spacing:0}td,th{padding:0}@font-face{font-family:'Open Sans';src:url(../fonts/opensans/light/opensans-300.eot);src:url(../fonts/opensans/light/opensans-300.eot?#iefix) format('embedded-opentype'),url(../fonts/opensans/light/opensans-300.woff2) format('woff2'),url(../fonts/opensans/light/opensans-300.woff) format('woff'),url(../fonts/opensans/light/opensans-300.ttf) format('truetype'),url('../fonts/opensans/light/opensans-300.svg#Open Sans') format('svg');font-weight:300;font-style:normal}@font-face{font-family:'Open Sans';src:url(../fonts/opensans/regular/opensans-400.eot);src:url(../fonts/opensans/regular/opensans-400.eot?#iefix) format('embedded-opentype'),url(../fonts/opensans/regular/opensans-400.woff2) format('woff2'),url(../fonts/opensans/regular/opensans-400.woff) format('woff'),url(../fonts/opensans/regular/opensans-400.ttf) format('truetype'),url('../fonts/opensans/regular/opensans-400.svg#Open Sans') format('svg');font-weight:400;font-style:normal}@font-face{font-family:'Open Sans';src:url(../fonts/opensans/semibold/opensans-600.eot);src:url(../fonts/opensans/semibold/opensans-600.eot?#iefix) format('embedded-opentype'),url(../fonts/opensans/semibold/opensans-600.woff2) format('woff2'),url(../fonts/opensans/semibold/opensans-600.woff) format('woff'),url(../fonts/opensans/semibold/opensans-600.ttf) format('truetype'),url('../fonts/opensans/semibold/opensans-600.svg#Open Sans') format('svg');font-weight:600;font-style:normal}@font-face{font-family:'Open Sans';src:url(../fonts/opensans/bold/opensans-700.eot);src:url(../fonts/opensans/bold/opensans-700.eot?#iefix) format('embedded-opentype'),url(../fonts/opensans/bold/opensans-700.woff2) format('woff2'),url(../fonts/opensans/bold/opensans-700.woff) format('woff'),url(../fonts/opensans/bold/opensans-700.ttf) format('truetype'),url('../fonts/opensans/bold/opensans-700.svg#Open Sans') format('svg');font-weight:700;font-style:normal}html{font-size:62.5%}body{color:#333;font-family:'Open Sans','Helvetica Neue',Helvetica,Arial,sans-serif;font-style:normal;font-weight:400;line-height:1.36;font-size:1.4rem}h1{margin:0 0 2rem;color:#41362f;font-weight:400;line-height:1.2;font-size:2.8rem}h2{margin:0 0 2rem;color:#41362f;font-weight:400;line-height:1.2;font-size:2rem}h3{margin:0 0 2rem;color:#41362f;font-weight:600;line-height:1.2;font-size:1.7rem}h4,h5,h6{font-weight:600;margin-top:0}p{margin:0 0 1em}small{font-size:1.2rem}a{color:#008bdb;text-decoration:none}a:hover{color:#0fa7ff;text-decoration:underline}dl,ol,ul{padding-left:0}nav ol,nav ul{list-style:none;margin:0;padding:0}html{height:100%}body{background-color:#fff;min-height:100%;min-width:102.4rem}.page-wrapper{background-color:#fff;display:inline-block;margin-left:-4px;vertical-align:top;width:calc(100% - 8.8rem)}.page-content{padding-bottom:3rem;padding-left:3rem;padding-right:3rem}.notices-wrapper{margin:0 3rem}.notices-wrapper .messages{margin-bottom:0}.row{margin-left:0;margin-right:0}.row:after{clear:both;content:'';display:table}.col-l-1,.col-l-10,.col-l-11,.col-l-12,.col-l-2,.col-l-3,.col-l-4,.col-l-5,.col-l-6,.col-l-7,.col-l-8,.col-l-9,.col-m-1,.col-m-10,.col-m-11,.col-m-12,.col-m-2,.col-m-3,.col-m-4,.col-m-5,.col-m-6,.col-m-7,.col-m-8,.col-m-9,.col-xl-1,.col-xl-10,.col-xl-11,.col-xl-12,.col-xl-2,.col-xl-3,.col-xl-4,.col-xl-5,.col-xl-6,.col-xl-7,.col-xl-8,.col-xl-9,.col-xs-1,.col-xs-10,.col-xs-11,.col-xs-12,.col-xs-2,.col-xs-3,.col-xs-4,.col-xs-5,.col-xs-6,.col-xs-7,.col-xs-8,.col-xs-9{min-height:1px;padding-left:0;padding-right:0;position:relative}.col-xs-1,.col-xs-10,.col-xs-11,.col-xs-12,.col-xs-2,.col-xs-3,.col-xs-4,.col-xs-5,.col-xs-6,.col-xs-7,.col-xs-8,.col-xs-9{float:left}.col-xs-12{width:100%}.col-xs-11{width:91.66666667%}.col-xs-10{width:83.33333333%}.col-xs-9{width:75%}.col-xs-8{width:66.66666667%}.col-xs-7{width:58.33333333%}.col-xs-6{width:50%}.col-xs-5{width:41.66666667%}.col-xs-4{width:33.33333333%}.col-xs-3{width:25%}.col-xs-2{width:16.66666667%}.col-xs-1{width:8.33333333%}.col-xs-pull-12{right:100%}.col-xs-pull-11{right:91.66666667%}.col-xs-pull-10{right:83.33333333%}.col-xs-pull-9{right:75%}.col-xs-pull-8{right:66.66666667%}.col-xs-pull-7{right:58.33333333%}.col-xs-pull-6{right:50%}.col-xs-pull-5{right:41.66666667%}.col-xs-pull-4{right:33.33333333%}.col-xs-pull-3{right:25%}.col-xs-pull-2{right:16.66666667%}.col-xs-pull-1{right:8.33333333%}.col-xs-pull-0{right:auto}.col-xs-push-12{left:100%}.col-xs-push-11{left:91.66666667%}.col-xs-push-10{left:83.33333333%}.col-xs-push-9{left:75%}.col-xs-push-8{left:66.66666667%}.col-xs-push-7{left:58.33333333%}.col-xs-push-6{left:50%}.col-xs-push-5{left:41.66666667%}.col-xs-push-4{left:33.33333333%}.col-xs-push-3{left:25%}.col-xs-push-2{left:16.66666667%}.col-xs-push-1{left:8.33333333%}.col-xs-push-0{left:auto}.col-xs-offset-12{margin-left:100%}.col-xs-offset-11{margin-left:91.66666667%}.col-xs-offset-10{margin-left:83.33333333%}.col-xs-offset-9{margin-left:75%}.col-xs-offset-8{margin-left:66.66666667%}.col-xs-offset-7{margin-left:58.33333333%}.col-xs-offset-6{margin-left:50%}.col-xs-offset-5{margin-left:41.66666667%}.col-xs-offset-4{margin-left:33.33333333%}.col-xs-offset-3{margin-left:25%}.col-xs-offset-2{margin-left:16.66666667%}.col-xs-offset-1{margin-left:8.33333333%}.col-xs-offset-0{margin-left:0}.row-gutter{margin-left:-1.5rem;margin-right:-1.5rem}.row-gutter>[class*=col-]{padding-left:1.5rem;padding-right:1.5rem}.abs-clearer:after,.extension-manager-content:after,.extension-manager-title:after,.form-row:after,.header:after,.nav:after,body:after{clear:both;content:'';display:table}.ng-cloak{display:none!important}.hide.hide{display:none}.show.show{display:block}.text-center{text-align:center}.text-right{text-align:right}@font-face{font-family:Icons;src:url(../fonts/icons/icons.eot);src:url(../fonts/icons/icons.eot?#iefix) format('embedded-opentype'),url(../fonts/icons/icons.woff2) format('woff2'),url(../fonts/icons/icons.woff) format('woff'),url(../fonts/icons/icons.ttf) format('truetype'),url(../fonts/icons/icons.svg#Icons) format('svg');font-weight:400;font-style:normal}[class*=icon-]{display:inline-block;line-height:1}.icon-failed:before,.icon-success:before,[class*=icon-]:after{font-family:Icons}.icon-success{color:#79a22e}.icon-success:before{content:'\e62d'}.icon-failed{color:#e22626}.icon-failed:before{content:'\e632'}.icon-success-thick:after{content:'\e62d'}.icon-collapse:after{content:'\e615'}.icon-failed-thick:after{content:'\e632'}.icon-expand:after{content:'\e616'}.icon-warning:after{content:'\e623'}.icon-failed-round,.icon-success-round{border-radius:100%;color:#fff;font-size:2.5rem;height:1em;position:relative;text-align:center;width:1em}.icon-failed-round:after,.icon-success-round:after{bottom:0;font-size:.5em;left:0;position:absolute;right:0;top:.45em}.icon-success-round{background-color:#79a22e}.icon-success-round:after{content:'\e62d'}.icon-failed-round{background-color:#e22626}.icon-failed-round:after{content:'\e632'}dl,ol,ul{margin-top:0}.list{padding-left:0}.list>li{display:block;margin-bottom:.75em;position:relative}.list>li>.icon-failed,.list>li>.icon-success{font-size:1.6em;left:-.1em;position:absolute;top:0}.list>li>.icon-success{color:#79a22e}.list>li>.icon-failed{color:#e22626}.list-item-failed,.list-item-icon,.list-item-success,.list-item-warning{padding-left:3.5rem}.list-item-failed:before,.list-item-success:before,.list-item-warning:before{left:-.1em;position:absolute}.list-item-success:before{color:#79a22e}.list-item-failed:before{color:#e22626}.list-item-warning:before{color:#ef672f}.list-definition{margin:0 0 3rem;padding:0}.list-definition>dt{clear:left;float:left}.list-definition>dd{margin-bottom:1em;margin-left:20rem}.btn-wrap{margin:0 auto}.btn-wrap .btn{width:100%}.btn{background:#e3e3e3;border:none;color:#514943;display:inline-block;font-size:1.6rem;font-weight:600;padding:.45em .9em;text-align:center}.btn:hover{background-color:#dbdbdb;color:#514943;text-decoration:none}.btn:active{background-color:#d6d6d6}.btn.disabled,.btn[disabled]{cursor:default;opacity:.5;pointer-events:none}.ie9 .btn.disabled,.ie9 .btn[disabled]{background-color:#f0f0f0;opacity:1;text-shadow:none}.btn-large{padding:.75em 1.25em}.btn-medium{font-size:1.4rem;padding:.5em 1.5em .6em}.btn-link{background-color:transparent;border:none;color:#008bdb;font-family:1.6rem;font-size:1.5rem}.btn-link:active,.btn-link:focus,.btn-link:hover{background-color:transparent;color:#0fa7ff}.btn-prime{background-color:#eb5202;color:#fff;text-shadow:1px 1px 0 rgba(0,0,0,.25)}.btn-prime:focus,.btn-prime:hover{background-color:#f65405;background-repeat:repeat-x;background-image:linear-gradient(to right,#e04f00 0,#f65405 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#e04f00', endColorstr='#f65405', GradientType=1);color:#fff}.btn-prime:active{background-color:#e04f00;background-repeat:repeat-x;background-image:linear-gradient(to right,#f65405 0,#e04f00 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#f65405', endColorstr='#e04f00', GradientType=1);color:#fff}.ie9 .btn-prime.disabled,.ie9 .btn-prime[disabled]{background-color:#fd6e23}.ie9 .btn-prime.disabled:active,.ie9 .btn-prime.disabled:hover,.ie9 .btn-prime[disabled]:active,.ie9 .btn-prime[disabled]:hover{background-color:#fd6e23;-webkit-filter:none;filter:none}.btn-secondary{background-color:#514943;color:#fff}.btn-secondary:hover{background-color:#5f564f;color:#fff}.btn-secondary:active,.btn-secondary:focus{background-color:#574e48;color:#fff}.ie9 .btn-secondary.disabled,.ie9 .btn-secondary[disabled]{background-color:#514943}.ie9 .btn-secondary.disabled:active,.ie9 .btn-secondary[disabled]:active{background-color:#514943;-webkit-filter:none;filter:none}[class*=btn-wrap-triangle]{overflow:hidden;position:relative}[class*=btn-wrap-triangle] .btn:after{border-style:solid;content:'';height:0;position:absolute;top:0;width:0}.btn-wrap-triangle-right{display:inline-block;padding-right:1.74rem;position:relative}.btn-wrap-triangle-right .btn{text-indent:.92rem}.btn-wrap-triangle-right .btn:after{border-color:transparent transparent transparent #e3e3e3;border-width:1.84rem 0 1.84rem 1.84rem;left:100%;margin-left:-1.74rem}.btn-wrap-triangle-right .btn:focus:after,.btn-wrap-triangle-right .btn:hover:after{border-left-color:#dbdbdb}.btn-wrap-triangle-right .btn:active:after{border-left-color:#d6d6d6}.btn-wrap-triangle-right .btn:not(.disabled):active,.btn-wrap-triangle-right .btn:not([disabled]):active{left:1px}.ie9 .btn-wrap-triangle-right .btn.disabled:after,.ie9 .btn-wrap-triangle-right .btn[disabled]:after{border-color:transparent transparent transparent #f0f0f0}.ie9 .btn-wrap-triangle-right .btn.disabled:active:after,.ie9 .btn-wrap-triangle-right .btn.disabled:focus:after,.ie9 .btn-wrap-triangle-right .btn.disabled:hover:after,.ie9 .btn-wrap-triangle-right .btn[disabled]:active:after,.ie9 .btn-wrap-triangle-right .btn[disabled]:focus:after,.ie9 .btn-wrap-triangle-right .btn[disabled]:hover:after{border-left-color:#f0f0f0}.btn-wrap-triangle-right .btn-prime:after{border-color:transparent transparent transparent #eb5202}.btn-wrap-triangle-right .btn-prime:focus:after,.btn-wrap-triangle-right .btn-prime:hover:after{border-left-color:#f65405}.btn-wrap-triangle-right .btn-prime:active:after{border-left-color:#e04f00}.btn-wrap-triangle-right .btn-prime:not(.disabled):active,.btn-wrap-triangle-right .btn-prime:not([disabled]):active{left:1px}.ie9 .btn-wrap-triangle-right .btn-prime.disabled:after,.ie9 .btn-wrap-triangle-right .btn-prime[disabled]:after{border-color:transparent transparent transparent #fd6e23}.ie9 .btn-wrap-triangle-right .btn-prime.disabled:active:after,.ie9 .btn-wrap-triangle-right .btn-prime.disabled:hover:after,.ie9 .btn-wrap-triangle-right .btn-prime[disabled]:active:after,.ie9 .btn-wrap-triangle-right .btn-prime[disabled]:hover:after{border-left-color:#fd6e23}.btn-wrap-triangle-left{display:inline-block;padding-left:1.74rem}.btn-wrap-triangle-left .btn{text-indent:-.92rem}.btn-wrap-triangle-left .btn:after{border-color:transparent #e3e3e3 transparent transparent;border-width:1.84rem 1.84rem 1.84rem 0;margin-right:-1.74rem;right:100%}.btn-wrap-triangle-left .btn:focus:after,.btn-wrap-triangle-left .btn:hover:after{border-right-color:#dbdbdb}.btn-wrap-triangle-left .btn:active:after{border-right-color:#d6d6d6}.btn-wrap-triangle-left .btn:not(.disabled):active,.btn-wrap-triangle-left .btn:not([disabled]):active{right:1px}.ie9 .btn-wrap-triangle-left .btn.disabled:after,.ie9 .btn-wrap-triangle-left .btn[disabled]:after{border-color:transparent #f0f0f0 transparent transparent}.ie9 .btn-wrap-triangle-left .btn.disabled:active:after,.ie9 .btn-wrap-triangle-left .btn.disabled:hover:after,.ie9 .btn-wrap-triangle-left .btn[disabled]:active:after,.ie9 .btn-wrap-triangle-left .btn[disabled]:hover:after{border-right-color:#f0f0f0}.btn-wrap-triangle-left .btn-prime:after{border-color:transparent #eb5202 transparent transparent}.btn-wrap-triangle-left .btn-prime:focus:after,.btn-wrap-triangle-left .btn-prime:hover:after{border-right-color:#e04f00}.btn-wrap-triangle-left .btn-prime:active:after{border-right-color:#f65405}.btn-wrap-triangle-left .btn-prime:not(.disabled):active,.btn-wrap-triangle-left .btn-prime:not([disabled]):active{right:1px}.ie9 .btn-wrap-triangle-left .btn-prime.disabled:after,.ie9 .btn-wrap-triangle-left .btn-prime[disabled]:after{border-color:transparent #fd6e23 transparent transparent}.ie9 .btn-wrap-triangle-left .btn-prime.disabled:active:after,.ie9 .btn-wrap-triangle-left .btn-prime.disabled:hover:after,.ie9 .btn-wrap-triangle-left .btn-prime[disabled]:active:after,.ie9 .btn-wrap-triangle-left .btn-prime[disabled]:hover:after{border-right-color:#fd6e23}.btn-expand{background-color:transparent;border:none;color:#303030;font-family:'Open Sans','Helvetica Neue',Helvetica,Arial,sans-serif;font-size:1.4rem;font-weight:700;padding:0;position:relative}.btn-expand.expanded:after{border-color:transparent transparent #303030;border-width:0 .285em .36em}.btn-expand.expanded:hover:after{border-color:transparent transparent #3d3d3d}.btn-expand:hover{background-color:transparent;border:none;color:#3d3d3d}.btn-expand:hover:after{border-color:#3d3d3d transparent transparent}.btn-expand:after{border-color:#303030 transparent transparent;border-style:solid;border-width:.36em .285em 0;content:'';height:0;left:100%;margin-left:.5em;margin-top:-.18em;position:absolute;top:50%;width:0}[class*=col-] .form-el-input,[class*=col-] .form-el-select{width:100%}.form-fieldset{border:none;margin:0 0 1em;padding:0}.form-row{margin-bottom:2.2rem}.form-row .form-row{margin-bottom:.4rem}.form-row .form-label{display:block;font-weight:600;padding:.6rem 2.1em 0 0;text-align:right}.form-row .form-label.required{position:relative}.form-row .form-label.required:after{color:#eb5202;content:'*';font-size:1.15em;position:absolute;right:.7em;top:.5em}.form-row .form-el-checkbox+.form-label:before,.form-row .form-el-radio+.form-label:before{top:.7rem}.form-row .form-el-checkbox+.form-label:after,.form-row .form-el-radio+.form-label:after{top:1.1rem}.form-row.form-row-text{padding-top:.6rem}.form-row.form-row-text .action-sign-out{font-size:1.2rem;margin-left:1rem}.form-note{font-size:1.2rem;font-weight:600;margin-top:1rem}.form-el-dummy{display:none}.fieldset{border:0;margin:0;min-width:0;padding:0}input:not([disabled]):focus,textarea:not([disabled]):focus{box-shadow:none}.form-el-input{border:1px solid #adadad;color:#303030;padding:.35em .55em .5em}.form-el-input:hover{border-color:#949494}.form-el-input:focus{border-color:#008bdb}.form-el-input:required{box-shadow:none}.form-label{margin-bottom:.5em}[class*=form-label][for]{cursor:pointer}.form-el-insider-wrap{display:table;width:100%}.form-el-insider-input{display:table-cell;width:100%}.form-el-insider{border-radius:2px;display:table-cell;padding:.43em .55em .5em 0;vertical-align:top}.form-legend,.form-legend-expand,.form-legend-light{display:block;margin:0}.form-legend,.form-legend-expand{font-size:1.25em;font-weight:600;margin-bottom:2.5em;padding-top:1.5em}.form-legend{border-top:1px solid #ccc;width:100%}.form-legend-light{font-size:1em;margin-bottom:1.5em}.form-legend-expand{cursor:pointer;transition:opacity .2s linear}.form-legend-expand:hover{opacity:.85}.form-legend-expand.expanded:after{content:'\e615'}.form-legend-expand:after{content:'\e616';font-family:Icons;font-size:1.15em;font-weight:400;margin-left:.5em;vertical-align:sub}.form-el-checkbox.disabled+.form-label,.form-el-checkbox.disabled+.form-label:before,.form-el-checkbox[disabled]+.form-label,.form-el-checkbox[disabled]+.form-label:before,.form-el-radio.disabled+.form-label,.form-el-radio.disabled+.form-label:before,.form-el-radio[disabled]+.form-label,.form-el-radio[disabled]+.form-label:before{cursor:default;opacity:.5;pointer-events:none}.form-el-checkbox:not(.disabled)+.form-label:hover:before,.form-el-checkbox:not([disabled])+.form-label:hover:before,.form-el-radio:not(.disabled)+.form-label:hover:before,.form-el-radio:not([disabled])+.form-label:hover:before{border-color:#514943}.form-el-checkbox+.form-label,.form-el-radio+.form-label{font-weight:400;padding-left:2em;padding-right:0;position:relative;text-align:left;transition:border-color .1s linear}.form-el-checkbox+.form-label:before,.form-el-radio+.form-label:before{border:1px solid;content:'';left:0;position:absolute;top:.1rem;transition:border-color .1s linear}.form-el-checkbox+.form-label:before{background-color:#fff;border-color:#adadad;border-radius:2px;font-size:1.2rem;height:1.6rem;line-height:1.2;width:1.6rem}.form-el-checkbox:checked+.form-label::before{content:'\e62d';font-family:Icons}.form-el-radio+.form-label:before{background-color:#fff;border:1px solid #adadad;border-radius:100%;height:1.8rem;width:1.8rem}.form-el-radio+.form-label:after{background:0 0;border:.5rem solid transparent;border-radius:100%;content:'';height:0;left:.4rem;position:absolute;top:.5rem;transition:background .3s linear;width:0}.form-el-radio:checked+.form-label{cursor:default}.form-el-radio:checked+.form-label:after{border-color:#514943}.form-select-label{border:1px solid #adadad;color:#303030;cursor:pointer;display:block;overflow:hidden;position:relative;z-index:0}.form-select-label:hover,.form-select-label:hover:after{border-color:#949494}.form-select-label:active,.form-select-label:active:after,.form-select-label:focus,.form-select-label:focus:after{border-color:#008bdb}.form-select-label:after{background:#e3e3e3;border-left:1px solid #adadad;bottom:0;content:'';position:absolute;right:0;top:0;width:2.36em;z-index:-2}.ie9 .form-select-label:after{display:none}.form-select-label:before{border-color:#303030 transparent transparent;border-style:solid;border-width:5px 4px 0;content:'';height:0;margin-right:-4px;margin-top:-2.5px;position:absolute;right:1.18em;top:50%;width:0;z-index:-1}.ie9 .form-select-label:before{display:none}.form-select-label .form-el-select{background:0 0;border:none;border-radius:0;content:'';display:block;margin:0;padding:.35em calc(2.36em + 10%) .5em .55em;width:110%}.ie9 .form-select-label .form-el-select{padding-right:.55em;width:100%}.form-select-label .form-el-select::-ms-expand{display:none}.form-el-select{background:#fff;border:1px solid #adadad;border-radius:2px;color:#303030;display:block;padding:.35em .55em}.multiselect-custom{border:1px solid #adadad;height:45.2rem;margin:0 0 1.5rem;overflow:auto;position:relative}.multiselect-custom ul{margin:0;padding:0;list-style:none;min-width:29rem}.multiselect-custom .item{padding:1rem 1.4rem}.multiselect-custom .selected{background-color:#e0f6fe}.multiselect-custom .form-label{margin-bottom:0}[class*=form-el-].invalid{border-color:#e22626}[class*=form-el-].invalid+.error-container{display:block}.error-container{background-color:#fffbbb;border:1px solid #ee7d7d;color:#514943;display:none;font-size:1.19rem;margin-top:.2rem;padding:.8rem 1rem .9rem}.check-result-message{margin-left:.5em;min-height:3.68rem;-ms-align-items:center;-ms-flex-align:center;align-items:center;display:-ms-flexbox;display:flex}.check-result-text{margin-left:.5em}body:not([class]){min-width:0}.container{display:block;margin:0 auto 4rem;max-width:100rem;padding:0}.abs-action-delete,.action-close:before,.action-next:before,.action-previous:before,.admin-user .admin__action-dropdown:before,.admin__action-multiselect-dropdown:before,.admin__action-multiselect-search-label:before,.admin__control-checkbox+label:before,.admin__control-collapsible .admin__collapsible-block-wrapper .fieldset-wrapper-title .action-delete:before,.admin__control-table .action-delete:before,.admin__current-filters-list .action-remove:before,.admin__data-grid-action-bookmarks .action-delete:before,.admin__data-grid-action-bookmarks .action-edit:before,.admin__data-grid-action-bookmarks .action-submit:before,.admin__data-grid-action-bookmarks .admin__action-dropdown:before,.admin__data-grid-action-columns .admin__action-dropdown:before,.admin__data-grid-action-export .admin__action-dropdown:before,.admin__field-fallback-reset:before,.admin__menu .level-0>a:before,.admin__page-nav-item-message .admin__page-nav-item-message-icon,.admin__page-nav-title._collapsible:after,.data-grid-filters-action-wrap .action-default:before,.data-grid-row-changed:after,.data-grid-row-parent>td .data-grid-checkbox-cell-inner:before,.data-grid-search-control-wrap .action-submit:before,.extensions-information .list .extension-delete,.icon-failed:before,.icon-success:before,.notifications-action:before,.notifications-close:before,.page-actions .page-actions-buttons>button.action-back:before,.page-actions .page-actions-buttons>button.back:before,.page-actions>button.action-back:before,.page-actions>button.back:before,.page-title-jumbo-success:before,.search-global-label:before,.selectmenu .action-delete:before,.selectmenu .action-edit:before,.selectmenu .action-save:before,.setup-home-item:before,.sticky-header .data-grid-search-control-wrap .data-grid-search-label:before,.store-switcher .dropdown-menu .dropdown-toolbar a:before,.tooltip .help a:before,.tooltip .help span:before{-webkit-font-smoothing:antialiased;font-family:Icons;font-style:normal;font-weight:400;line-height:1;speak:none}.text-stretch{margin-bottom:1.5em}.page-title-jumbo{font-size:4rem;font-weight:300;letter-spacing:-.05em;margin-bottom:2.9rem}.page-title-jumbo-success:before{color:#79a22e;content:'\e62d';font-size:3.9rem;margin-left:-.3rem;margin-right:2.4rem}.list{margin-bottom:3rem}.list-dot .list-item{display:list-item;list-style-position:inside;margin-bottom:1.2rem}.list-title{color:#333;font-size:1.4rem;font-weight:700;letter-spacing:.025em;margin-bottom:1.2rem}.list-item-failed:before,.list-item-success:before,.list-item-warning:before{font-family:Icons;font-size:1.6rem;top:0}.list-item-success:before{content:'\e62d';font-size:1.6rem}.list-item-failed:before{content:'\e632';font-size:1.4rem;left:.1rem;top:.2rem}.list-item-warning:before{content:'\e623';font-size:1.3rem;left:.2rem}.form-wrap{margin-bottom:3.6rem;padding-top:2.1rem}.form-el-label-horizontal{display:inline-block;font-size:1.3rem;font-weight:600;letter-spacing:.025em;margin-bottom:.4rem;margin-left:.4rem}.app-updater{min-width:768px}body._has-modal{height:100%;overflow:hidden;width:100%}.modals-overlay{z-index:899}.modal-popup,.modal-slide{bottom:0;min-width:0;position:fixed;right:0;top:0;visibility:hidden}.modal-popup._show,.modal-slide._show{visibility:visible}.modal-popup._show .modal-inner-wrap,.modal-slide._show .modal-inner-wrap{-ms-transform:translate(0,0);transform:translate(0,0)}.modal-popup .modal-inner-wrap,.modal-slide .modal-inner-wrap{background-color:#fff;box-shadow:0 0 12px 2px rgba(0,0,0,.35);opacity:1;pointer-events:auto}.modal-slide{left:14.8rem;z-index:900}.modal-slide._show .modal-inner-wrap{-ms-transform:translateX(0);transform:translateX(0)}.modal-slide .modal-inner-wrap{height:100%;overflow-y:auto;position:static;-ms-transform:translateX(100%);transform:translateX(100%);transition-duration:.3s;transition-property:transform,visibility;transition-timing-function:ease-in-out;width:auto}.modal-slide._inner-scroll .modal-inner-wrap{overflow-y:visible;display:-ms-flexbox;display:flex;-ms-flex-direction:column;flex-direction:column}.modal-slide._inner-scroll .modal-footer,.modal-slide._inner-scroll .modal-header{-webkit-flex-grow:0;-ms-flex-positive:0;flex-grow:0;-ms-flex-negative:0;flex-shrink:0}.modal-slide._inner-scroll .modal-content{overflow-y:auto}.modal-slide._inner-scroll .modal-footer{margin-top:auto}.modal-slide .modal-content,.modal-slide .modal-footer,.modal-slide .modal-header{padding:0 2.6rem 2.6rem}.modal-slide .modal-header{padding-bottom:2.1rem;padding-top:2.1rem}.modal-popup{z-index:900;left:0;overflow-y:auto}.modal-popup._show .modal-inner-wrap{-ms-transform:translateY(0);transform:translateY(0)}.modal-popup .modal-inner-wrap{margin:5rem auto;width:75%;display:-ms-flexbox;display:flex;-ms-flex-direction:column;flex-direction:column;box-sizing:border-box;height:auto;left:0;position:absolute;right:0;-ms-transform:translateY(-200%);transform:translateY(-200%);transition-duration:.2s;transition-property:transform,visibility;transition-timing-function:ease}.modal-popup._inner-scroll{overflow-y:visible}.ie10 .modal-popup._inner-scroll,.ie9 .modal-popup._inner-scroll{overflow-y:auto}.modal-popup._inner-scroll .modal-inner-wrap{max-height:90%}.ie10 .modal-popup._inner-scroll .modal-inner-wrap,.ie9 .modal-popup._inner-scroll .modal-inner-wrap{max-height:none}.modal-popup._inner-scroll .modal-content{overflow-y:auto}.modal-popup .modal-content,.modal-popup .modal-footer,.modal-popup .modal-header{padding-left:3rem;padding-right:3rem}.modal-popup .modal-footer,.modal-popup .modal-header{-webkit-flex-grow:0;-ms-flex-positive:0;flex-grow:0;-ms-flex-negative:0;flex-shrink:0}.modal-popup .modal-header{padding-bottom:1.2rem;padding-top:3rem}.modal-popup .modal-footer{margin-top:auto;padding-bottom:3rem}.modal-popup .modal-footer-actions{text-align:right}.admin__action-dropdown-wrap{display:inline-block;position:relative}.admin__action-dropdown-wrap .admin__action-dropdown-text:after{left:-6px;right:0}.admin__action-dropdown-wrap .admin__action-dropdown-menu{left:auto;right:0}.admin__action-dropdown-wrap._active .admin__action-dropdown,.admin__action-dropdown-wrap.active .admin__action-dropdown{border-color:#007bdb;box-shadow:1px 1px 5px rgba(0,0,0,.5)}.admin__action-dropdown-wrap._active .admin__action-dropdown-text:after,.admin__action-dropdown-wrap.active .admin__action-dropdown-text:after{background-color:#fff;content:'';height:6px;position:absolute;top:100%}.admin__action-dropdown-wrap._active .admin__action-dropdown-menu,.admin__action-dropdown-wrap.active .admin__action-dropdown-menu{display:block}.admin__action-dropdown-wrap._disabled .admin__action-dropdown{cursor:default}.admin__action-dropdown-wrap._disabled:hover .admin__action-dropdown{color:#333}.admin__action-dropdown{background-color:#fff;border:1px solid transparent;border-bottom:none;border-radius:0;box-shadow:none;color:#333;display:inline-block;font-size:1.3rem;font-weight:400;letter-spacing:-.025em;padding:.7rem 3.3rem .8rem 1.5rem;position:relative;vertical-align:baseline;z-index:2}.admin__action-dropdown._active:after,.admin__action-dropdown.active:after{-ms-transform:rotate(180deg);transform:rotate(180deg)}.admin__action-dropdown:after{border-color:#000 transparent transparent;border-style:solid;border-width:.5rem .4rem 0;content:'';height:0;margin-top:-.2rem;position:absolute;top:50%;transition:all .2s linear;width:0}._active .admin__action-dropdown:after,.active .admin__action-dropdown:after{-ms-transform:rotate(180deg);transform:rotate(180deg)}.admin__action-dropdown:hover:after{border-color:#000 transparent transparent}.admin__action-dropdown:focus,.admin__action-dropdown:hover{background-color:#fff;color:#000;text-decoration:none}.admin__action-dropdown:after{right:1.5rem}.admin__action-dropdown:before{margin-right:1rem}.admin__action-dropdown-menu{background-color:#fff;border:1px solid #007bdb;box-shadow:1px 1px 5px rgba(0,0,0,.5);display:none;line-height:1.36;margin-top:-1px;min-width:120%;padding:.5rem 1rem;position:absolute;top:100%;transition:all .15s ease;z-index:1}.admin__action-dropdown-menu>li{display:block}.admin__action-dropdown-menu>li>a{color:#333;display:block;text-decoration:none;padding:.6rem .5rem}.selectmenu{display:inline-block;position:relative;text-align:left;z-index:1}.selectmenu._active{border-color:#007bdb;z-index:500}.selectmenu .action-delete,.selectmenu .action-edit,.selectmenu .action-save{background-color:transparent;border-color:transparent;box-shadow:none;padding:0 1rem}.selectmenu .action-delete:hover,.selectmenu .action-edit:hover,.selectmenu .action-save:hover{background-color:transparent;border-color:transparent;box-shadow:none}.selectmenu .action-delete:before,.selectmenu .action-edit:before,.selectmenu .action-save:before{content:'\e630'}.selectmenu .action-delete,.selectmenu .action-edit{border:0 solid #fff;border-left-width:1px;bottom:0;position:absolute;right:0;top:0;z-index:1}.selectmenu .action-delete:hover,.selectmenu .action-edit:hover{border:0 solid #fff;border-left-width:1px}.selectmenu .action-save:before{content:'\e625'}.selectmenu .action-edit:before{content:'\e631'}.selectmenu-value{display:inline-block}.selectmenu-value input[type=text]{-webkit-appearance:none;-moz-appearance:none;-ms-appearance:none;appearance:none;border:0;display:inline;margin:0;width:6rem}body._keyfocus .selectmenu-value input[type=text]:focus{box-shadow:none}.selectmenu-toggle{padding-right:3rem;background:0 0;border-width:0;bottom:0;float:right;position:absolute;right:0;top:0;width:0}.selectmenu-toggle._active:after,.selectmenu-toggle.active:after{-ms-transform:rotate(180deg);transform:rotate(180deg)}.selectmenu-toggle:after{border-color:#000 transparent transparent;border-style:solid;border-width:.5rem .4rem 0;content:'';height:0;margin-top:-.2rem;position:absolute;right:1.1rem;top:50%;transition:all .2s linear;width:0}._active .selectmenu-toggle:after,.active .selectmenu-toggle:after{-ms-transform:rotate(180deg);transform:rotate(180deg)}.selectmenu-toggle:hover:after{border-color:#000 transparent transparent}.selectmenu-toggle:active,.selectmenu-toggle:focus,.selectmenu-toggle:hover{background:0 0}.selectmenu._active .selectmenu-toggle:before{border-color:#007bdb}body._keyfocus .selectmenu-toggle:focus{box-shadow:none}.selectmenu-toggle:before{background:#e3e3e3;border-left:1px solid #adadad;bottom:0;content:'';display:block;position:absolute;right:0;top:0;width:3.2rem}.selectmenu-items{background:#fff;border:1px solid #007bdb;box-shadow:1px 1px 5px rgba(0,0,0,.5);display:none;float:left;left:-1px;margin-top:3px;max-width:20rem;min-width:calc(100% + 2px);position:absolute;top:100%}.selectmenu-items._active{display:block}.selectmenu-items ul{float:left;list-style-type:none;margin:0;min-width:100%;padding:0}.selectmenu-items li{-webkit-flex-direction:row;display:flex;-ms-flex-direction:row;flex-direction:row;transition:background .2s linear}.selectmenu-items li:hover{background:#e3e3e3}.selectmenu-items li:last-child .selectmenu-item-action,.selectmenu-items li:last-child .selectmenu-item-action:visited{color:#008bdb;text-decoration:none}.selectmenu-items li:last-child .selectmenu-item-action:hover{color:#0fa7ff;text-decoration:underline}.selectmenu-items li:last-child .selectmenu-item-action:active{color:#ff5501;text-decoration:underline}.selectmenu-item{position:relative;width:100%;z-index:1}li._edit>.selectmenu-item{display:none}.selectmenu-item-edit{display:none;padding:.3rem 4rem .3rem .4rem;position:relative;white-space:nowrap;z-index:1}li:last-child .selectmenu-item-edit{padding-right:.4rem}.selectmenu-item-edit .admin__control-text{margin:0;width:5.4rem}li._edit .selectmenu-item-edit{display:block}.selectmenu-item-action{-webkit-appearance:none;-moz-appearance:none;-ms-appearance:none;appearance:none;background:0 0;border:0;color:#333;display:block;font-size:1.4rem;font-weight:400;min-width:100%;padding:1rem 6rem 1rem 1.5rem;text-align:left;transition:background .2s linear;width:5rem}.selectmenu-item-action:focus,.selectmenu-item-action:hover{background:#e3e3e3}.abs-actions-split-xl .action-default,.page-actions .actions-split .action-default{margin-right:4rem}.abs-actions-split-xl .action-toggle,.page-actions .actions-split .action-toggle{padding-right:4rem}.abs-actions-split-xl .action-toggle:after,.page-actions .actions-split .action-toggle:after{border-width:.9rem .6rem 0;margin-top:-.3rem;right:1.4rem}.actions-split{position:relative;z-index:400}.actions-split._active,.actions-split.active,.actions-split:hover{box-shadow:0 0 0 1px #007bdb}.actions-split._active .action-toggle.action-primary,.actions-split._active .action-toggle.primary,.actions-split.active .action-toggle.action-primary,.actions-split.active .action-toggle.primary{background-color:#ba4000;border-color:#ba4000}.actions-split._active .dropdown-menu,.actions-split.active .dropdown-menu{opacity:1;visibility:visible;display:block}.actions-split .action-default,.actions-split .action-toggle{float:left;margin:0}.actions-split .action-default._active,.actions-split .action-default.active,.actions-split .action-default:hover,.actions-split .action-toggle._active,.actions-split .action-toggle.active,.actions-split .action-toggle:hover{box-shadow:none}.actions-split .action-default{margin-right:3.2rem;min-width:9.3rem}.actions-split .action-toggle{padding-right:3.2rem;border-left-color:rgba(0,0,0,.2);bottom:0;padding-left:0;position:absolute;right:0;top:0}.actions-split .action-toggle._active:after,.actions-split .action-toggle.active:after{-ms-transform:rotate(180deg);transform:rotate(180deg)}.actions-split .action-toggle:after{border-color:#000 transparent transparent;border-style:solid;border-width:.5rem .4rem 0;content:'';height:0;margin-top:-.2rem;position:absolute;right:1.2rem;top:50%;transition:all .2s linear;width:0}._active .actions-split .action-toggle:after,.active .actions-split .action-toggle:after{-ms-transform:rotate(180deg);transform:rotate(180deg)}.actions-split .action-toggle:hover:after{border-color:#000 transparent transparent}.actions-split .action-toggle.action-primary:after,.actions-split .action-toggle.action-secondary:after,.actions-split .action-toggle.primary:after,.actions-split .action-toggle.secondary:after{border-color:#fff transparent transparent}.actions-split .action-toggle>span{clip:rect(0,0,0,0);overflow:hidden;position:absolute}.action-select-wrap{display:inline-block;position:relative}.action-select-wrap .action-select{padding-right:3.2rem;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;background-color:#fff;font-weight:400;text-align:left}.action-select-wrap .action-select._active:after,.action-select-wrap .action-select.active:after{-ms-transform:rotate(180deg);transform:rotate(180deg)}.action-select-wrap .action-select:after{border-color:#000 transparent transparent;border-style:solid;border-width:.5rem .4rem 0;content:'';height:0;margin-top:-.2rem;position:absolute;right:1.2rem;top:50%;transition:all .2s linear;width:0}._active .action-select-wrap .action-select:after,.active .action-select-wrap .action-select:after{-ms-transform:rotate(180deg);transform:rotate(180deg)}.action-select-wrap .action-select:hover:after{border-color:#000 transparent transparent}.action-select-wrap .action-select:hover,.action-select-wrap .action-select:hover:before{border-color:#878787}.action-select-wrap .action-select:before{background-color:#e3e3e3;border:1px solid #adadad;bottom:0;content:'';position:absolute;right:0;top:0;width:3.2rem}.action-select-wrap .action-select._active{border-color:#007bdb}.action-select-wrap .action-select._active:before{border-color:#007bdb #007bdb #007bdb #adadad}.action-select-wrap .action-select[disabled]{color:#333}.action-select-wrap .action-select[disabled]:after{border-color:#333 transparent transparent}.action-select-wrap._active{z-index:500}.action-select-wrap._active .action-select,.action-select-wrap._active .action-select:before{border-color:#007bdb}.action-select-wrap._active .action-select:after{-ms-transform:rotate(180deg);transform:rotate(180deg)}.action-select-wrap .abs-action-menu .action-submenu,.action-select-wrap .abs-action-menu .action-submenu .action-submenu,.action-select-wrap .action-menu,.action-select-wrap .action-menu .action-submenu,.action-select-wrap .actions-split .action-menu .action-submenu,.action-select-wrap .actions-split .action-menu .action-submenu .action-submenu,.action-select-wrap .actions-split .dropdown-menu .action-submenu,.action-select-wrap .actions-split .dropdown-menu .action-submenu .action-submenu{max-height:45rem;overflow-y:auto}.action-select-wrap .abs-action-menu .action-submenu ._disabled:hover,.action-select-wrap .abs-action-menu .action-submenu .action-submenu ._disabled:hover,.action-select-wrap .action-menu ._disabled:hover,.action-select-wrap .action-menu .action-submenu ._disabled:hover,.action-select-wrap .actions-split .action-menu .action-submenu ._disabled:hover,.action-select-wrap .actions-split .action-menu .action-submenu .action-submenu ._disabled:hover,.action-select-wrap .actions-split .dropdown-menu .action-submenu ._disabled:hover,.action-select-wrap .actions-split .dropdown-menu .action-submenu .action-submenu ._disabled:hover{background:#fff}.action-select-wrap .abs-action-menu .action-submenu ._disabled .action-menu-item,.action-select-wrap .abs-action-menu .action-submenu .action-submenu ._disabled .action-menu-item,.action-select-wrap .action-menu ._disabled .action-menu-item,.action-select-wrap .action-menu .action-submenu ._disabled .action-menu-item,.action-select-wrap .actions-split .action-menu .action-submenu ._disabled .action-menu-item,.action-select-wrap .actions-split .action-menu .action-submenu .action-submenu ._disabled .action-menu-item,.action-select-wrap .actions-split .dropdown-menu .action-submenu ._disabled .action-menu-item,.action-select-wrap .actions-split .dropdown-menu .action-submenu .action-submenu ._disabled .action-menu-item{cursor:default;opacity:.5}.action-select-wrap .action-menu-items{left:0;position:absolute;right:0;top:100%}.action-select-wrap .action-menu-items>.abs-action-menu .action-submenu,.action-select-wrap .action-menu-items>.abs-action-menu .action-submenu .action-submenu,.action-select-wrap .action-menu-items>.action-menu,.action-select-wrap .action-menu-items>.action-menu .action-submenu,.action-select-wrap .action-menu-items>.actions-split .action-menu .action-submenu,.action-select-wrap .action-menu-items>.actions-split .action-menu .action-submenu .action-submenu,.action-select-wrap .action-menu-items>.actions-split .dropdown-menu .action-submenu,.action-select-wrap .action-menu-items>.actions-split .dropdown-menu .action-submenu .action-submenu{min-width:100%;position:static}.action-select-wrap .action-menu-items>.abs-action-menu .action-submenu .action-submenu,.action-select-wrap .action-menu-items>.abs-action-menu .action-submenu .action-submenu .action-submenu,.action-select-wrap .action-menu-items>.action-menu .action-submenu,.action-select-wrap .action-menu-items>.action-menu .action-submenu .action-submenu,.action-select-wrap .action-menu-items>.actions-split .action-menu .action-submenu .action-submenu,.action-select-wrap .action-menu-items>.actions-split .action-menu .action-submenu .action-submenu .action-submenu,.action-select-wrap .action-menu-items>.actions-split .dropdown-menu .action-submenu .action-submenu,.action-select-wrap .action-menu-items>.actions-split .dropdown-menu .action-submenu .action-submenu .action-submenu{position:absolute}.action-multicheck-wrap{display:inline-block;height:1.6rem;padding-top:1px;position:relative;width:3.1rem;z-index:200}.action-multicheck-wrap:hover .action-multicheck-toggle,.action-multicheck-wrap:hover .admin__control-checkbox+label:before{border-color:#878787}.action-multicheck-wrap._active .action-multicheck-toggle,.action-multicheck-wrap._active .admin__control-checkbox+label:before{border-color:#007bdb}.action-multicheck-wrap._active .abs-action-menu .action-submenu,.action-multicheck-wrap._active .abs-action-menu .action-submenu .action-submenu,.action-multicheck-wrap._active .action-menu,.action-multicheck-wrap._active .action-menu .action-submenu,.action-multicheck-wrap._active .actions-split .action-menu .action-submenu,.action-multicheck-wrap._active .actions-split .action-menu .action-submenu .action-submenu,.action-multicheck-wrap._active .actions-split .dropdown-menu .action-submenu,.action-multicheck-wrap._active .actions-split .dropdown-menu .action-submenu .action-submenu{opacity:1;visibility:visible;display:block}.action-multicheck-wrap._disabled .admin__control-checkbox+label:before{background-color:#fff}.action-multicheck-wrap._disabled .action-multicheck-toggle,.action-multicheck-wrap._disabled .admin__control-checkbox+label:before{border-color:#adadad;opacity:1}.action-multicheck-wrap .action-multicheck-toggle,.action-multicheck-wrap .admin__control-checkbox,.action-multicheck-wrap .admin__control-checkbox+label{float:left}.action-multicheck-wrap .action-multicheck-toggle{border-radius:0 1px 1px 0;height:1.6rem;margin-left:-1px;padding:0;position:relative;transition:border-color .1s linear;width:1.6rem}.action-multicheck-wrap .action-multicheck-toggle._active:after,.action-multicheck-wrap .action-multicheck-toggle.active:after{-ms-transform:rotate(180deg);transform:rotate(180deg)}.action-multicheck-wrap .action-multicheck-toggle:after{border-color:#000 transparent transparent;border-style:solid;border-width:.5rem .4rem 0;content:'';height:0;margin-top:-.2rem;position:absolute;top:50%;transition:all .2s linear;width:0}._active .action-multicheck-wrap .action-multicheck-toggle:after,.active .action-multicheck-wrap .action-multicheck-toggle:after{-ms-transform:rotate(180deg);transform:rotate(180deg)}.action-multicheck-wrap .action-multicheck-toggle:hover:after{border-color:#000 transparent transparent}.action-multicheck-wrap .action-multicheck-toggle:focus{border-color:#007bdb}.action-multicheck-wrap .action-multicheck-toggle:after{right:.3rem}.action-multicheck-wrap .abs-action-menu .action-submenu,.action-multicheck-wrap .abs-action-menu .action-submenu .action-submenu,.action-multicheck-wrap .action-menu,.action-multicheck-wrap .action-menu .action-submenu,.action-multicheck-wrap .actions-split .action-menu .action-submenu,.action-multicheck-wrap .actions-split .action-menu .action-submenu .action-submenu,.action-multicheck-wrap .actions-split .dropdown-menu .action-submenu,.action-multicheck-wrap .actions-split .dropdown-menu .action-submenu .action-submenu{left:-1.1rem;margin-top:1px;right:auto;text-align:left}.action-multicheck-wrap .action-menu-item{white-space:nowrap}.admin__action-multiselect-wrap{display:block;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}.admin__action-multiselect-wrap.action-select-wrap:focus{box-shadow:none}.admin__action-multiselect-wrap.action-select-wrap .abs-action-menu .action-submenu,.admin__action-multiselect-wrap.action-select-wrap .abs-action-menu .action-submenu .action-submenu,.admin__action-multiselect-wrap.action-select-wrap .action-menu,.admin__action-multiselect-wrap.action-select-wrap .action-menu .action-submenu,.admin__action-multiselect-wrap.action-select-wrap .actions-split .action-menu .action-submenu,.admin__action-multiselect-wrap.action-select-wrap .actions-split .action-menu .action-submenu .action-submenu,.admin__action-multiselect-wrap.action-select-wrap .actions-split .dropdown-menu .action-submenu,.admin__action-multiselect-wrap.action-select-wrap .actions-split .dropdown-menu .action-submenu .action-submenu{max-height:none;overflow-y:inherit}.admin__action-multiselect-wrap .action-menu-item{transition:background-color .1s linear}.admin__action-multiselect-wrap .action-menu-item._selected{background-color:#e0f6fe}.admin__action-multiselect-wrap .action-menu-item._hover{background-color:#e3e3e3}.admin__action-multiselect-wrap .action-menu-item._unclickable{cursor:default}.admin__action-multiselect-wrap .admin__action-multiselect{border:1px solid #adadad;cursor:pointer;display:block;min-height:3.2rem;padding-right:3.6rem;white-space:normal}.admin__action-multiselect-wrap .admin__action-multiselect:after{bottom:1.25rem;top:auto}.admin__action-multiselect-wrap .admin__action-multiselect:before{height:3.3rem;top:auto}.admin__control-table-wrapper .admin__action-multiselect-wrap{position:static}.admin__control-table-wrapper .admin__action-multiselect-wrap .admin__action-multiselect{position:relative}.admin__control-table-wrapper .admin__action-multiselect-wrap .admin__action-multiselect:before{right:-1px;top:-1px}.admin__control-table-wrapper .admin__action-multiselect-wrap .abs-action-menu .action-submenu,.admin__control-table-wrapper .admin__action-multiselect-wrap .abs-action-menu .action-submenu .action-submenu,.admin__control-table-wrapper .admin__action-multiselect-wrap .action-menu,.admin__control-table-wrapper .admin__action-multiselect-wrap .action-menu .action-submenu,.admin__control-table-wrapper .admin__action-multiselect-wrap .actions-split .action-menu .action-submenu,.admin__control-table-wrapper .admin__action-multiselect-wrap .actions-split .action-menu .action-submenu .action-submenu,.admin__control-table-wrapper .admin__action-multiselect-wrap .actions-split .dropdown-menu .action-submenu,.admin__control-table-wrapper .admin__action-multiselect-wrap .actions-split .dropdown-menu .action-submenu .action-submenu{left:auto;min-width:34rem;right:auto;top:auto;z-index:1}.admin__action-multiselect-wrap .admin__action-multiselect-item-path{color:#a79d95;font-size:1.2rem;font-weight:400;padding-left:1rem}.admin__action-multiselect-actions-wrap{border-top:1px solid #e3e3e3;margin:0 1rem;padding:1rem 0;text-align:center}.admin__action-multiselect-actions-wrap .action-default{font-size:1.3rem;min-width:13rem}.admin__action-multiselect-text{padding:.6rem 1rem}.abs-action-menu .action-submenu,.abs-action-menu .action-submenu .action-submenu,.action-menu,.action-menu .action-submenu,.actions-split .action-menu .action-submenu,.actions-split .action-menu .action-submenu .action-submenu,.actions-split .dropdown-menu .action-submenu,.actions-split .dropdown-menu .action-submenu .action-submenu{text-align:left}.admin__action-multiselect-label{cursor:pointer;position:relative;z-index:1}.admin__action-multiselect-label:before{margin-right:.5rem}._unclickable .admin__action-multiselect-label{cursor:default;font-weight:700}.admin__action-multiselect-search-wrap{border-bottom:1px solid #e3e3e3;margin:0 1rem;padding:1rem 0;position:relative}.admin__action-multiselect-search{padding-right:3rem;width:100%}.admin__action-multiselect-search-label{display:block;font-size:1.5rem;height:1em;overflow:hidden;position:absolute;right:2.2rem;top:1.7rem;width:1em}.admin__action-multiselect-search-label:before{content:'\e60c'}.admin__action-multiselect-search-count{color:#a79d95;margin-top:1rem}.admin__action-multiselect-menu-inner{margin-bottom:0;max-height:46rem;overflow-y:auto}.admin__action-multiselect-menu-inner .admin__action-multiselect-menu-inner{list-style:none;max-height:none;overflow:hidden;padding-left:2.2rem}.admin__action-multiselect-menu-inner ._hidden{display:none}.admin__action-multiselect-crumb{background-color:#f5f5f5;border:1px solid #a79d95;border-radius:1px;display:inline-block;font-size:1.2rem;margin:.3rem -4px .3rem .3rem;padding:.3rem 2.4rem .4rem 1rem;position:relative;transition:border-color .1s linear}.admin__action-multiselect-crumb:hover{border-color:#908379}.admin__action-multiselect-crumb .action-close{bottom:0;font-size:.5em;position:absolute;right:0;top:0;width:2rem}.admin__action-multiselect-crumb .action-close:hover{color:#000}.admin__action-multiselect-crumb .action-close:active,.admin__action-multiselect-crumb .action-close:focus{background-color:transparent}.admin__action-multiselect-crumb .action-close:active{-ms-transform:scale(0.9);transform:scale(0.9)}.admin__action-multiselect-tree .abs-action-menu .action-submenu,.admin__action-multiselect-tree .abs-action-menu .action-submenu .action-submenu,.admin__action-multiselect-tree .action-menu,.admin__action-multiselect-tree .action-menu .action-submenu,.admin__action-multiselect-tree .actions-split .action-menu .action-submenu,.admin__action-multiselect-tree .actions-split .action-menu .action-submenu .action-submenu,.admin__action-multiselect-tree .actions-split .dropdown-menu .action-submenu,.admin__action-multiselect-tree .actions-split .dropdown-menu .action-submenu .action-submenu{min-width:34.7rem}.admin__action-multiselect-tree .abs-action-menu .action-submenu .action-menu-item,.admin__action-multiselect-tree .abs-action-menu .action-submenu .action-submenu .action-menu-item,.admin__action-multiselect-tree .action-menu .action-menu-item,.admin__action-multiselect-tree .action-menu .action-submenu .action-menu-item,.admin__action-multiselect-tree .actions-split .action-menu .action-submenu .action-menu-item,.admin__action-multiselect-tree .actions-split .action-menu .action-submenu .action-submenu .action-menu-item,.admin__action-multiselect-tree .actions-split .dropdown-menu .action-submenu .action-menu-item,.admin__action-multiselect-tree .actions-split .dropdown-menu .action-submenu .action-submenu .action-menu-item{margin-top:.1rem}.admin__action-multiselect-tree .action-menu-item{margin-left:4.2rem;position:relative}.admin__action-multiselect-tree .action-menu-item._expended:before{border-left:1px dashed #a79d95;bottom:0;content:'';left:-1rem;position:absolute;top:1rem;width:1px}.admin__action-multiselect-tree .action-menu-item._expended .admin__action-multiselect-dropdown:before{content:'\e615'}.admin__action-multiselect-tree .action-menu-item._with-checkbox .admin__action-multiselect-label{padding-left:2.6rem}.admin__action-multiselect-tree .admin__action-multiselect-menu-inner{position:relative}.admin__action-multiselect-tree .admin__action-multiselect-menu-inner .admin__action-multiselect-menu-inner{padding-left:3.2rem}.admin__action-multiselect-tree .admin__action-multiselect-menu-inner .admin__action-multiselect-menu-inner:before{left:4.3rem}.admin__action-multiselect-tree .admin__action-multiselect-menu-inner-item{position:relative}.admin__action-multiselect-tree .admin__action-multiselect-menu-inner-item:last-child:before{height:2.1rem}.admin__action-multiselect-tree .admin__action-multiselect-menu-inner-item:after,.admin__action-multiselect-tree .admin__action-multiselect-menu-inner-item:before{content:'';left:0;position:absolute}.admin__action-multiselect-tree .admin__action-multiselect-menu-inner-item:after{border-top:1px dashed #a79d95;height:1px;top:2.1rem;width:5.2rem}.admin__action-multiselect-tree .admin__action-multiselect-menu-inner-item:before{border-left:1px dashed #a79d95;height:100%;top:0;width:1px}.admin__action-multiselect-tree .admin__action-multiselect-menu-inner-item._parent:after{width:4.2rem}.admin__action-multiselect-tree .admin__action-multiselect-menu-inner-item._root{margin-left:-1rem}.admin__action-multiselect-tree .admin__action-multiselect-menu-inner-item._root:after{left:3.2rem;width:2.2rem}.admin__action-multiselect-tree .admin__action-multiselect-menu-inner-item._root:before{left:3.2rem;top:1rem}.admin__action-multiselect-tree .admin__action-multiselect-menu-inner-item._root._parent:after{display:none}.admin__action-multiselect-tree .admin__action-multiselect-menu-inner-item._root:first-child:before{top:2.1rem}.admin__action-multiselect-tree .admin__action-multiselect-menu-inner-item._root:last-child:before{height:1rem}.admin__action-multiselect-tree .admin__action-multiselect-label{line-height:2.2rem;vertical-align:middle;word-break:break-all}.admin__action-multiselect-tree .admin__action-multiselect-label:before{left:0;position:absolute;top:.4rem}.admin__action-multiselect-dropdown{border-radius:50%;height:2.2rem;left:-2.2rem;position:absolute;top:1rem;width:2.2rem;z-index:1}.admin__action-multiselect-dropdown:before{background:#fff;color:#a79d95;content:'\e616';font-size:2.2rem}.admin__actions-switch{display:inline-block;position:relative;vertical-align:middle}.admin__field-control .admin__actions-switch{line-height:3.2rem}.admin__actions-switch+.admin__field-service{min-width:34rem}._disabled .admin__actions-switch-checkbox+.admin__actions-switch-label,.admin__actions-switch-checkbox.disabled+.admin__actions-switch-label{cursor:not-allowed;opacity:.5;pointer-events:none}.admin__actions-switch-checkbox:checked+.admin__actions-switch-label:before{left:15px}.admin__actions-switch-checkbox:checked+.admin__actions-switch-label:after{background:#79a22e}.admin__actions-switch-checkbox:checked+.admin__actions-switch-label .admin__actions-switch-text:before{content:attr(data-text-on)}.admin__actions-switch-checkbox:focus+.admin__actions-switch-label:after,.admin__actions-switch-checkbox:focus+.admin__actions-switch-label:before{border-color:#007bdb}._error .admin__actions-switch-checkbox+.admin__actions-switch-label:after,._error .admin__actions-switch-checkbox+.admin__actions-switch-label:before{border-color:#e22626}.admin__actions-switch-label{cursor:pointer;display:inline-block;height:22px;line-height:22px;position:relative;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;vertical-align:middle}.admin__actions-switch-label:after,.admin__actions-switch-label:before{left:0;position:absolute;right:auto;top:0}.admin__actions-switch-label:before{background:#fff;border:1px solid #aaa6a0;border-radius:100%;content:'';display:block;height:22px;transition:left .2s ease-in 0s;width:22px;z-index:1}.admin__actions-switch-label:after{background:#e3e3e3;border:1px solid #aaa6a0;border-radius:12px;content:'';display:block;height:22px;transition:background .2s ease-in 0s;vertical-align:middle;width:37px;z-index:0}.admin__actions-switch-text:before{content:attr(data-text-off);padding-left:47px;white-space:nowrap}.abs-action-delete,.abs-action-reset,.action-close,.admin__field-fallback-reset,.extensions-information .list .extension-delete,.notifications-close,.search-global-field._active .search-global-action{background-color:transparent;border:none;border-radius:0;box-shadow:none;margin:0;padding:0}.abs-action-delete:hover,.abs-action-reset:hover,.action-close:hover,.admin__field-fallback-reset:hover,.extensions-information .list .extension-delete:hover,.notifications-close:hover,.search-global-field._active .search-global-action:hover{background-color:transparent;border:none;box-shadow:none}.abs-action-default,.abs-action-pattern,.abs-action-primary,.abs-action-quaternary,.abs-action-secondary,.abs-action-tertiary,.action-default,.action-primary,.action-quaternary,.action-secondary,.action-tertiary,.modal-popup .modal-footer .action-primary,.modal-popup .modal-footer .action-secondary,.page-actions .page-actions-buttons>button,.page-actions .page-actions-buttons>button.action-primary,.page-actions .page-actions-buttons>button.action-secondary,.page-actions .page-actions-buttons>button.primary,.page-actions>button,.page-actions>button.action-primary,.page-actions>button.action-secondary,.page-actions>button.primary,button,button.primary,button.secondary,button.tertiary{border:1px solid;border-radius:0;display:inline-block;font-family:'Open Sans','Helvetica Neue',Helvetica,Arial,sans-serif;font-size:1.4rem;font-weight:600;line-height:1.36;padding:.6rem 1em;text-align:center;vertical-align:baseline}.abs-action-default.disabled,.abs-action-default[disabled],.abs-action-pattern.disabled,.abs-action-pattern[disabled],.abs-action-primary.disabled,.abs-action-primary[disabled],.abs-action-quaternary.disabled,.abs-action-quaternary[disabled],.abs-action-secondary.disabled,.abs-action-secondary[disabled],.abs-action-tertiary.disabled,.abs-action-tertiary[disabled],.action-default.disabled,.action-default[disabled],.action-primary.disabled,.action-primary[disabled],.action-quaternary.disabled,.action-quaternary[disabled],.action-secondary.disabled,.action-secondary[disabled],.action-tertiary.disabled,.action-tertiary[disabled],.modal-popup .modal-footer .action-primary.disabled,.modal-popup .modal-footer .action-primary[disabled],.modal-popup .modal-footer .action-secondary.disabled,.modal-popup .modal-footer .action-secondary[disabled],.page-actions .page-actions-buttons>button.action-primary.disabled,.page-actions .page-actions-buttons>button.action-primary[disabled],.page-actions .page-actions-buttons>button.action-secondary.disabled,.page-actions .page-actions-buttons>button.action-secondary[disabled],.page-actions .page-actions-buttons>button.disabled,.page-actions .page-actions-buttons>button.primary.disabled,.page-actions .page-actions-buttons>button.primary[disabled],.page-actions .page-actions-buttons>button[disabled],.page-actions>button.action-primary.disabled,.page-actions>button.action-primary[disabled],.page-actions>button.action-secondary.disabled,.page-actions>button.action-secondary[disabled],.page-actions>button.disabled,.page-actions>button.primary.disabled,.page-actions>button.primary[disabled],.page-actions>button[disabled],button.disabled,button.primary.disabled,button.primary[disabled],button.secondary.disabled,button.secondary[disabled],button.tertiary.disabled,button.tertiary[disabled],button[disabled]{cursor:default;opacity:.5;pointer-events:none}.abs-action-l,.modal-popup .modal-footer .action-primary,.modal-popup .modal-footer .action-secondary,.page-actions .page-actions-buttons>button,.page-actions .page-actions-buttons>button.action-primary,.page-actions .page-actions-buttons>button.action-secondary,.page-actions .page-actions-buttons>button.primary,.page-actions button,.page-actions>button.action-primary,.page-actions>button.action-secondary,.page-actions>button.primary{font-size:1.6rem;letter-spacing:.025em;padding-bottom:.6875em;padding-top:.6875em}.abs-action-delete,.extensions-information .list .extension-delete{display:inline-block;font-size:1.6rem;margin-left:1.2rem;padding-top:.7rem;text-decoration:none;vertical-align:middle}.abs-action-delete:after,.extensions-information .list .extension-delete:after{color:#666;content:'\e630'}.abs-action-delete:hover:after,.extensions-information .list .extension-delete:hover:after{color:#35302c}.abs-action-button-as-link,.action-advanced,.data-grid .action-delete{line-height:1.36;padding:0;color:#008bdb;text-decoration:none;background:0 0;border:0;display:inline;font-weight:400;border-radius:0}.abs-action-button-as-link:visited,.action-advanced:visited,.data-grid .action-delete:visited{color:#008bdb;text-decoration:none}.abs-action-button-as-link:hover,.action-advanced:hover,.data-grid .action-delete:hover{text-decoration:underline}.abs-action-button-as-link:active,.action-advanced:active,.data-grid .action-delete:active{color:#ff5501;text-decoration:underline}.abs-action-button-as-link:hover,.action-advanced:hover,.data-grid .action-delete:hover{color:#0fa7ff}.abs-action-button-as-link:active,.abs-action-button-as-link:focus,.abs-action-button-as-link:hover,.action-advanced:active,.action-advanced:focus,.action-advanced:hover,.data-grid .action-delete:active,.data-grid .action-delete:focus,.data-grid .action-delete:hover{background:0 0;border:0}.abs-action-button-as-link.disabled,.abs-action-button-as-link[disabled],.action-advanced.disabled,.action-advanced[disabled],.data-grid .action-delete.disabled,.data-grid .action-delete[disabled],fieldset[disabled] .abs-action-button-as-link,fieldset[disabled] .action-advanced,fieldset[disabled] .data-grid .action-delete{color:#008bdb;opacity:.5;cursor:default;pointer-events:none;text-decoration:underline}.abs-action-button-as-link:active,.abs-action-button-as-link:not(:focus),.action-advanced:active,.action-advanced:not(:focus),.data-grid .action-delete:active,.data-grid .action-delete:not(:focus){box-shadow:none}.abs-action-button-as-link:focus,.action-advanced:focus,.data-grid .action-delete:focus{color:#0fa7ff}.abs-action-default,button{background:#e3e3e3;border-color:#adadad;color:#514943}.abs-action-default:active,.abs-action-default:focus,.abs-action-default:hover,button:active,button:focus,button:hover{background-color:#dbdbdb;color:#514943;text-decoration:none}.abs-action-primary,.page-actions .page-actions-buttons>button.action-primary,.page-actions .page-actions-buttons>button.primary,.page-actions>button.action-primary,.page-actions>button.primary,button.primary{background-color:#eb5202;border-color:#eb5202;color:#fff;text-shadow:1px 1px 0 rgba(0,0,0,.25)}.abs-action-primary:active,.abs-action-primary:focus,.abs-action-primary:hover,.page-actions .page-actions-buttons>button.action-primary:active,.page-actions .page-actions-buttons>button.action-primary:focus,.page-actions .page-actions-buttons>button.action-primary:hover,.page-actions .page-actions-buttons>button.primary:active,.page-actions .page-actions-buttons>button.primary:focus,.page-actions .page-actions-buttons>button.primary:hover,.page-actions>button.action-primary:active,.page-actions>button.action-primary:focus,.page-actions>button.action-primary:hover,.page-actions>button.primary:active,.page-actions>button.primary:focus,.page-actions>button.primary:hover,button.primary:active,button.primary:focus,button.primary:hover{background-color:#ba4000;border-color:#b84002;box-shadow:0 0 0 1px #007bdb;color:#fff;text-decoration:none}.abs-action-primary.disabled,.abs-action-primary[disabled],.page-actions .page-actions-buttons>button.action-primary.disabled,.page-actions .page-actions-buttons>button.action-primary[disabled],.page-actions .page-actions-buttons>button.primary.disabled,.page-actions .page-actions-buttons>button.primary[disabled],.page-actions>button.action-primary.disabled,.page-actions>button.action-primary[disabled],.page-actions>button.primary.disabled,.page-actions>button.primary[disabled],button.primary.disabled,button.primary[disabled]{cursor:default;opacity:.5;pointer-events:none}.abs-action-secondary,.modal-popup .modal-footer .action-primary,.page-actions .page-actions-buttons>button.action-secondary,.page-actions>button.action-secondary,button.secondary{background-color:#514943;border-color:#514943;color:#fff;text-shadow:1px 1px 1px rgba(0,0,0,.3)}.abs-action-secondary:active,.abs-action-secondary:focus,.abs-action-secondary:hover,.modal-popup .modal-footer .action-primary:active,.modal-popup .modal-footer .action-primary:focus,.modal-popup .modal-footer .action-primary:hover,.page-actions .page-actions-buttons>button.action-secondary:active,.page-actions .page-actions-buttons>button.action-secondary:focus,.page-actions .page-actions-buttons>button.action-secondary:hover,.page-actions>button.action-secondary:active,.page-actions>button.action-secondary:focus,.page-actions>button.action-secondary:hover,button.secondary:active,button.secondary:focus,button.secondary:hover{background-color:#35302c;border-color:#35302c;box-shadow:0 0 0 1px #007bdb;color:#fff;text-decoration:none}.abs-action-secondary:active,.modal-popup .modal-footer .action-primary:active,.page-actions .page-actions-buttons>button.action-secondary:active,.page-actions>button.action-secondary:active,button.secondary:active{background-color:#35302c}.abs-action-tertiary,.modal-popup .modal-footer .action-secondary,button.tertiary{background-color:transparent;border-color:transparent;text-shadow:none;color:#008bdb}.abs-action-tertiary:active,.abs-action-tertiary:focus,.abs-action-tertiary:hover,.modal-popup .modal-footer .action-secondary:active,.modal-popup .modal-footer .action-secondary:focus,.modal-popup .modal-footer .action-secondary:hover,button.tertiary:active,button.tertiary:focus,button.tertiary:hover{background-color:transparent;border-color:transparent;box-shadow:none;color:#0fa7ff;text-decoration:underline}.abs-action-quaternary,.page-actions .page-actions-buttons>button,.page-actions>button{background-color:transparent;border-color:transparent;text-shadow:none;color:#333}.abs-action-quaternary:active,.abs-action-quaternary:focus,.abs-action-quaternary:hover,.page-actions .page-actions-buttons>button:active,.page-actions .page-actions-buttons>button:focus,.page-actions .page-actions-buttons>button:hover,.page-actions>button:active,.page-actions>button:focus,.page-actions>button:hover{background-color:transparent;border-color:transparent;box-shadow:none;color:#1a1a1a}.abs-action-menu,.actions-split .abs-action-menu .action-submenu,.actions-split .abs-action-menu .action-submenu .action-submenu,.actions-split .action-menu,.actions-split .action-menu .action-submenu,.actions-split .actions-split .dropdown-menu .action-submenu,.actions-split .actions-split .dropdown-menu .action-submenu .action-submenu,.actions-split .dropdown-menu{text-align:left;background-color:#fff;border:1px solid #007bdb;border-radius:1px;box-shadow:1px 1px 5px rgba(0,0,0,.5);color:#333;display:none;font-weight:400;left:0;list-style:none;margin:2px 0 0;min-width:0;padding:0;position:absolute;right:0;top:100%}.abs-action-menu._active,.actions-split .abs-action-menu .action-submenu .action-submenu._active,.actions-split .abs-action-menu .action-submenu._active,.actions-split .action-menu .action-submenu._active,.actions-split .action-menu._active,.actions-split .actions-split .dropdown-menu .action-submenu .action-submenu._active,.actions-split .actions-split .dropdown-menu .action-submenu._active,.actions-split .dropdown-menu._active{display:block}.abs-action-menu>li,.actions-split .abs-action-menu .action-submenu .action-submenu>li,.actions-split .abs-action-menu .action-submenu>li,.actions-split .action-menu .action-submenu>li,.actions-split .action-menu>li,.actions-split .actions-split .dropdown-menu .action-submenu .action-submenu>li,.actions-split .actions-split .dropdown-menu .action-submenu>li,.actions-split .dropdown-menu>li{border:none;display:block;padding:0;transition:background-color .1s linear}.abs-action-menu>li>a:hover,.actions-split .abs-action-menu .action-submenu .action-submenu>li>a:hover,.actions-split .abs-action-menu .action-submenu>li>a:hover,.actions-split .action-menu .action-submenu>li>a:hover,.actions-split .action-menu>li>a:hover,.actions-split .actions-split .dropdown-menu .action-submenu .action-submenu>li>a:hover,.actions-split .actions-split .dropdown-menu .action-submenu>li>a:hover,.actions-split .dropdown-menu>li>a:hover{text-decoration:none}.abs-action-menu>li._visible,.abs-action-menu>li:hover,.actions-split .abs-action-menu .action-submenu .action-submenu>li._visible,.actions-split .abs-action-menu .action-submenu .action-submenu>li:hover,.actions-split .abs-action-menu .action-submenu>li._visible,.actions-split .abs-action-menu .action-submenu>li:hover,.actions-split .action-menu .action-submenu>li._visible,.actions-split .action-menu .action-submenu>li:hover,.actions-split .action-menu>li._visible,.actions-split .action-menu>li:hover,.actions-split .actions-split .dropdown-menu .action-submenu .action-submenu>li._visible,.actions-split .actions-split .dropdown-menu .action-submenu .action-submenu>li:hover,.actions-split .actions-split .dropdown-menu .action-submenu>li._visible,.actions-split .actions-split .dropdown-menu .action-submenu>li:hover,.actions-split .dropdown-menu>li._visible,.actions-split .dropdown-menu>li:hover{background-color:#e3e3e3}.abs-action-menu>li:active,.actions-split .abs-action-menu .action-submenu .action-submenu>li:active,.actions-split .abs-action-menu .action-submenu>li:active,.actions-split .action-menu .action-submenu>li:active,.actions-split .action-menu>li:active,.actions-split .actions-split .dropdown-menu .action-submenu .action-submenu>li:active,.actions-split .actions-split .dropdown-menu .action-submenu>li:active,.actions-split .dropdown-menu>li:active{background-color:#cacaca}.abs-action-menu>li._parent,.actions-split .abs-action-menu .action-submenu .action-submenu>li._parent,.actions-split .abs-action-menu .action-submenu>li._parent,.actions-split .action-menu .action-submenu>li._parent,.actions-split .action-menu>li._parent,.actions-split .actions-split .dropdown-menu .action-submenu .action-submenu>li._parent,.actions-split .actions-split .dropdown-menu .action-submenu>li._parent,.actions-split .dropdown-menu>li._parent{-webkit-flex-direction:row;display:flex;-ms-flex-direction:row;flex-direction:row}.abs-action-menu>li._parent>.action-menu-item,.actions-split .abs-action-menu .action-submenu .action-submenu>li._parent>.action-menu-item,.actions-split .abs-action-menu .action-submenu>li._parent>.action-menu-item,.actions-split .action-menu .action-submenu>li._parent>.action-menu-item,.actions-split .action-menu>li._parent>.action-menu-item,.actions-split .actions-split .dropdown-menu .action-submenu .action-submenu>li._parent>.action-menu-item,.actions-split .actions-split .dropdown-menu .action-submenu>li._parent>.action-menu-item,.actions-split .dropdown-menu>li._parent>.action-menu-item{min-width:100%}.abs-action-menu .action-menu-item,.abs-action-menu .item,.actions-split .abs-action-menu .action-submenu .action-menu-item,.actions-split .abs-action-menu .action-submenu .action-submenu .action-menu-item,.actions-split .abs-action-menu .action-submenu .action-submenu .item,.actions-split .abs-action-menu .action-submenu .item,.actions-split .action-menu .action-menu-item,.actions-split .action-menu .action-submenu .action-menu-item,.actions-split .action-menu .action-submenu .item,.actions-split .action-menu .item,.actions-split .actions-split .dropdown-menu .action-submenu .action-menu-item,.actions-split .actions-split .dropdown-menu .action-submenu .action-submenu .action-menu-item,.actions-split .actions-split .dropdown-menu .action-submenu .action-submenu .item,.actions-split .actions-split .dropdown-menu .action-submenu .item,.actions-split .dropdown-menu .action-menu-item,.actions-split .dropdown-menu .item{cursor:pointer;display:block;padding:.6875em 1em}.abs-action-menu .action-submenu,.actions-split .action-menu .action-submenu,.actions-split .action-menu .action-submenu .action-submenu,.actions-split .dropdown-menu .action-submenu{bottom:auto;left:auto;margin-left:0;margin-top:-1px;position:absolute;right:auto;top:auto}.ie9 .abs-action-menu .action-submenu,.ie9 .actions-split .abs-action-menu .action-submenu .action-submenu,.ie9 .actions-split .abs-action-menu .action-submenu .action-submenu .action-submenu,.ie9 .actions-split .action-menu .action-submenu,.ie9 .actions-split .action-menu .action-submenu .action-submenu,.ie9 .actions-split .actions-split .dropdown-menu .action-submenu .action-submenu,.ie9 .actions-split .actions-split .dropdown-menu .action-submenu .action-submenu .action-submenu,.ie9 .actions-split .dropdown-menu .action-submenu{margin-left:99%;margin-top:-3.5rem}.abs-action-menu a.action-menu-item,.actions-split .abs-action-menu .action-submenu .action-submenu a.action-menu-item,.actions-split .abs-action-menu .action-submenu a.action-menu-item,.actions-split .action-menu .action-submenu a.action-menu-item,.actions-split .action-menu a.action-menu-item,.actions-split .actions-split .dropdown-menu .action-submenu .action-submenu a.action-menu-item,.actions-split .actions-split .dropdown-menu .action-submenu a.action-menu-item,.actions-split .dropdown-menu a.action-menu-item{color:#333}.abs-action-menu a.action-menu-item:focus,.actions-split .abs-action-menu .action-submenu .action-submenu a.action-menu-item:focus,.actions-split .abs-action-menu .action-submenu a.action-menu-item:focus,.actions-split .action-menu .action-submenu a.action-menu-item:focus,.actions-split .action-menu a.action-menu-item:focus,.actions-split .actions-split .dropdown-menu .action-submenu .action-submenu a.action-menu-item:focus,.actions-split .actions-split .dropdown-menu .action-submenu a.action-menu-item:focus,.actions-split .dropdown-menu a.action-menu-item:focus{background-color:#e3e3e3;box-shadow:none}.abs-action-wrap-triangle{position:relative}.abs-action-wrap-triangle .action-default{width:100%}.abs-action-wrap-triangle .action-default:after,.abs-action-wrap-triangle .action-default:before{border-style:solid;content:'';height:0;position:absolute;top:0;width:0}.abs-action-wrap-triangle .action-default:active,.abs-action-wrap-triangle .action-default:focus,.abs-action-wrap-triangle .action-default:hover{box-shadow:none}._keyfocus .abs-action-wrap-triangle .action-default:focus{box-shadow:0 0 0 1px #007bdb}.ie10 .abs-action-wrap-triangle .action-default.disabled,.ie10 .abs-action-wrap-triangle .action-default[disabled],.ie9 .abs-action-wrap-triangle .action-default.disabled,.ie9 .abs-action-wrap-triangle .action-default[disabled]{background-color:#fcfcfc;opacity:1;text-shadow:none}.abs-action-wrap-triangle-right{display:inline-block;padding-right:1.6rem;position:relative}.abs-action-wrap-triangle-right .action-default:after,.abs-action-wrap-triangle-right .action-default:before{border-color:transparent transparent transparent #e3e3e3;border-width:1.7rem 0 1.6rem 1.7rem;left:100%;margin-left:-1.7rem}.abs-action-wrap-triangle-right .action-default:before{border-left-color:#949494;right:-1px}.abs-action-wrap-triangle-right .action-default:active:after,.abs-action-wrap-triangle-right .action-default:focus:after,.abs-action-wrap-triangle-right .action-default:hover:after{border-left-color:#dbdbdb}.ie10 .abs-action-wrap-triangle-right .action-default.disabled:after,.ie10 .abs-action-wrap-triangle-right .action-default[disabled]:after,.ie9 .abs-action-wrap-triangle-right .action-default.disabled:after,.ie9 .abs-action-wrap-triangle-right .action-default[disabled]:after{border-color:transparent transparent transparent #fcfcfc}.abs-action-wrap-triangle-right .action-primary:after{border-color:transparent transparent transparent #eb5202}.abs-action-wrap-triangle-right .action-primary:active:after,.abs-action-wrap-triangle-right .action-primary:focus:after,.abs-action-wrap-triangle-right .action-primary:hover:after{border-left-color:#ba4000}.abs-action-wrap-triangle-left{display:inline-block;padding-left:1.6rem}.abs-action-wrap-triangle-left .action-default{text-indent:-.85rem}.abs-action-wrap-triangle-left .action-default:after,.abs-action-wrap-triangle-left .action-default:before{border-color:transparent #e3e3e3 transparent transparent;border-width:1.7rem 1.7rem 1.6rem 0;margin-right:-1.7rem;right:100%}.abs-action-wrap-triangle-left .action-default:before{border-right-color:#949494;left:-1px}.abs-action-wrap-triangle-left .action-default:active:after,.abs-action-wrap-triangle-left .action-default:focus:after,.abs-action-wrap-triangle-left .action-default:hover:after{border-right-color:#dbdbdb}.ie10 .abs-action-wrap-triangle-left .action-default.disabled:after,.ie10 .abs-action-wrap-triangle-left .action-default[disabled]:after,.ie9 .abs-action-wrap-triangle-left .action-default.disabled:after,.ie9 .abs-action-wrap-triangle-left .action-default[disabled]:after{border-color:transparent #fcfcfc transparent transparent}.abs-action-wrap-triangle-left .action-primary:after{border-color:transparent #eb5202 transparent transparent}.abs-action-wrap-triangle-left .action-primary:active:after,.abs-action-wrap-triangle-left .action-primary:focus:after,.abs-action-wrap-triangle-left .action-primary:hover:after{border-right-color:#ba4000}.action-default,button{background:#e3e3e3;border-color:#adadad;color:#514943}.action-default:active,.action-default:focus,.action-default:hover,button:active,button:focus,button:hover{background-color:#dbdbdb;color:#514943;text-decoration:none}.action-primary{background-color:#eb5202;border-color:#eb5202;color:#fff;text-shadow:1px 1px 0 rgba(0,0,0,.25)}.action-primary:active,.action-primary:focus,.action-primary:hover{background-color:#ba4000;border-color:#b84002;box-shadow:0 0 0 1px #007bdb;color:#fff;text-decoration:none}.action-primary.disabled,.action-primary[disabled]{cursor:default;opacity:.5;pointer-events:none}.action-secondary{background-color:#514943;border-color:#514943;color:#fff;text-shadow:1px 1px 1px rgba(0,0,0,.3)}.action-secondary:active,.action-secondary:focus,.action-secondary:hover{background-color:#35302c;border-color:#35302c;box-shadow:0 0 0 1px #007bdb;color:#fff;text-decoration:none}.action-secondary:active{background-color:#35302c}.action-quaternary,.action-tertiary{background-color:transparent;border-color:transparent;text-shadow:none}.action-quaternary:active,.action-quaternary:focus,.action-quaternary:hover,.action-tertiary:active,.action-tertiary:focus,.action-tertiary:hover{background-color:transparent;border-color:transparent;box-shadow:none}.action-tertiary{color:#008bdb}.action-tertiary:active,.action-tertiary:focus,.action-tertiary:hover{color:#0fa7ff;text-decoration:underline}.action-quaternary{color:#333}.action-quaternary:active,.action-quaternary:focus,.action-quaternary:hover{color:#1a1a1a}.action-close>span{clip:rect(0,0,0,0);overflow:hidden;position:absolute}.action-close:active{-ms-transform:scale(0.9);transform:scale(0.9)}.action-close:before{content:'\e62f';transition:color .1s linear}.action-close:hover{cursor:pointer;text-decoration:none}.abs-action-menu .action-submenu,.abs-action-menu .action-submenu .action-submenu,.action-menu,.action-menu .action-submenu,.actions-split .action-menu .action-submenu,.actions-split .action-menu .action-submenu .action-submenu,.actions-split .dropdown-menu .action-submenu,.actions-split .dropdown-menu .action-submenu .action-submenu{background-color:#fff;border:1px solid #007bdb;border-radius:1px;box-shadow:1px 1px 5px rgba(0,0,0,.5);color:#333;display:none;font-weight:400;left:0;list-style:none;margin:2px 0 0;min-width:0;padding:0;position:absolute;right:0;top:100%}.abs-action-menu .action-submenu .action-submenu._active,.abs-action-menu .action-submenu._active,.action-menu .action-submenu._active,.action-menu._active,.actions-split .action-menu .action-submenu .action-submenu._active,.actions-split .action-menu .action-submenu._active,.actions-split .dropdown-menu .action-submenu .action-submenu._active,.actions-split .dropdown-menu .action-submenu._active{display:block}.abs-action-menu .action-submenu .action-submenu>li,.abs-action-menu .action-submenu>li,.action-menu .action-submenu>li,.action-menu>li,.actions-split .action-menu .action-submenu .action-submenu>li,.actions-split .action-menu .action-submenu>li,.actions-split .dropdown-menu .action-submenu .action-submenu>li,.actions-split .dropdown-menu .action-submenu>li{border:none;display:block;padding:0;transition:background-color .1s linear}.abs-action-menu .action-submenu .action-submenu>li>a:hover,.abs-action-menu .action-submenu>li>a:hover,.action-menu .action-submenu>li>a:hover,.action-menu>li>a:hover,.actions-split .action-menu .action-submenu .action-submenu>li>a:hover,.actions-split .action-menu .action-submenu>li>a:hover,.actions-split .dropdown-menu .action-submenu .action-submenu>li>a:hover,.actions-split .dropdown-menu .action-submenu>li>a:hover{text-decoration:none}.abs-action-menu .action-submenu .action-submenu>li._visible,.abs-action-menu .action-submenu .action-submenu>li:hover,.abs-action-menu .action-submenu>li._visible,.abs-action-menu .action-submenu>li:hover,.action-menu .action-submenu>li._visible,.action-menu .action-submenu>li:hover,.action-menu>li._visible,.action-menu>li:hover,.actions-split .action-menu .action-submenu .action-submenu>li._visible,.actions-split .action-menu .action-submenu .action-submenu>li:hover,.actions-split .action-menu .action-submenu>li._visible,.actions-split .action-menu .action-submenu>li:hover,.actions-split .dropdown-menu .action-submenu .action-submenu>li._visible,.actions-split .dropdown-menu .action-submenu .action-submenu>li:hover,.actions-split .dropdown-menu .action-submenu>li._visible,.actions-split .dropdown-menu .action-submenu>li:hover{background-color:#e3e3e3}.abs-action-menu .action-submenu .action-submenu>li:active,.abs-action-menu .action-submenu>li:active,.action-menu .action-submenu>li:active,.action-menu>li:active,.actions-split .action-menu .action-submenu .action-submenu>li:active,.actions-split .action-menu .action-submenu>li:active,.actions-split .dropdown-menu .action-submenu .action-submenu>li:active,.actions-split .dropdown-menu .action-submenu>li:active{background-color:#cacaca}.abs-action-menu .action-submenu .action-submenu>li._parent,.abs-action-menu .action-submenu>li._parent,.action-menu .action-submenu>li._parent,.action-menu>li._parent,.actions-split .action-menu .action-submenu .action-submenu>li._parent,.actions-split .action-menu .action-submenu>li._parent,.actions-split .dropdown-menu .action-submenu .action-submenu>li._parent,.actions-split .dropdown-menu .action-submenu>li._parent{-webkit-flex-direction:row;display:flex;-ms-flex-direction:row;flex-direction:row}.abs-action-menu .action-submenu .action-submenu>li._parent>.action-menu-item,.abs-action-menu .action-submenu>li._parent>.action-menu-item,.action-menu .action-submenu>li._parent>.action-menu-item,.action-menu>li._parent>.action-menu-item,.actions-split .action-menu .action-submenu .action-submenu>li._parent>.action-menu-item,.actions-split .action-menu .action-submenu>li._parent>.action-menu-item,.actions-split .dropdown-menu .action-submenu .action-submenu>li._parent>.action-menu-item,.actions-split .dropdown-menu .action-submenu>li._parent>.action-menu-item{min-width:100%}.abs-action-menu .action-submenu .action-menu-item,.abs-action-menu .action-submenu .action-submenu .action-menu-item,.abs-action-menu .action-submenu .action-submenu .item,.abs-action-menu .action-submenu .item,.action-menu .action-menu-item,.action-menu .action-submenu .action-menu-item,.action-menu .action-submenu .item,.action-menu .item,.actions-split .action-menu .action-submenu .action-menu-item,.actions-split .action-menu .action-submenu .action-submenu .action-menu-item,.actions-split .action-menu .action-submenu .action-submenu .item,.actions-split .action-menu .action-submenu .item,.actions-split .dropdown-menu .action-submenu .action-menu-item,.actions-split .dropdown-menu .action-submenu .action-submenu .action-menu-item,.actions-split .dropdown-menu .action-submenu .action-submenu .item,.actions-split .dropdown-menu .action-submenu .item{cursor:pointer;display:block;padding:.6875em 1em}.abs-action-menu .action-submenu .action-submenu,.action-menu .action-submenu,.actions-split .action-menu .action-submenu .action-submenu,.actions-split .dropdown-menu .action-submenu .action-submenu{bottom:auto;left:auto;margin-left:0;margin-top:-1px;position:absolute;right:auto;top:auto}.ie9 .abs-action-menu .action-submenu .action-submenu,.ie9 .abs-action-menu .action-submenu .action-submenu .action-submenu,.ie9 .action-menu .action-submenu,.ie9 .action-menu .action-submenu .action-submenu,.ie9 .actions-split .action-menu .action-submenu .action-submenu,.ie9 .actions-split .action-menu .action-submenu .action-submenu .action-submenu,.ie9 .actions-split .dropdown-menu .action-submenu .action-submenu,.ie9 .actions-split .dropdown-menu .action-submenu .action-submenu .action-submenu{margin-left:99%;margin-top:-3.5rem}.abs-action-menu .action-submenu .action-submenu a.action-menu-item,.abs-action-menu .action-submenu a.action-menu-item,.action-menu .action-submenu a.action-menu-item,.action-menu a.action-menu-item,.actions-split .action-menu .action-submenu .action-submenu a.action-menu-item,.actions-split .action-menu .action-submenu a.action-menu-item,.actions-split .dropdown-menu .action-submenu .action-submenu a.action-menu-item,.actions-split .dropdown-menu .action-submenu a.action-menu-item{color:#333}.abs-action-menu .action-submenu .action-submenu a.action-menu-item:focus,.abs-action-menu .action-submenu a.action-menu-item:focus,.action-menu .action-submenu a.action-menu-item:focus,.action-menu a.action-menu-item:focus,.actions-split .action-menu .action-submenu .action-submenu a.action-menu-item:focus,.actions-split .action-menu .action-submenu a.action-menu-item:focus,.actions-split .dropdown-menu .action-submenu .action-submenu a.action-menu-item:focus,.actions-split .dropdown-menu .action-submenu a.action-menu-item:focus{background-color:#e3e3e3;box-shadow:none}.messages .message:last-child{margin:0 0 2rem}.message{background:#fffbbb;border:none;border-radius:0;color:#333;font-size:1.4rem;margin:0 0 1px;padding:1.8rem 4rem 1.8rem 5.5rem;position:relative;text-shadow:none}.message:before{background:0 0;border:0;color:#007bdb;content:'\e61a';font-family:Icons;font-size:1.9rem;font-style:normal;font-weight:400;height:auto;left:1.9rem;line-height:inherit;margin-top:-1.3rem;position:absolute;speak:none;text-shadow:none;top:50%;width:auto}.message-notice:before{color:#007bdb;content:'\e61a'}.message-warning:before{color:#eb5202;content:'\e623'}.message-error{background:#fcc}.message-error:before{color:#e22626;content:'\e632';font-size:1.5rem;left:2.2rem;margin-top:-1rem}.message-success:before{color:#79a22e;content:'\e62d'}.message-spinner:before{display:none}.message-spinner .spinner{font-size:2.5rem;left:1.5rem;position:absolute;top:1.5rem}.message-in-rating-edit{margin-left:1.8rem;margin-right:1.8rem}.modal-popup .action-close,.modal-slide .action-close{color:#736963;position:absolute;right:0;top:0;z-index:1}.modal-popup .action-close:active,.modal-slide .action-close:active{-ms-transform:none;transform:none}.modal-popup .action-close:active:before,.modal-slide .action-close:active:before{font-size:1.8rem}.modal-popup .action-close:hover:before,.modal-slide .action-close:hover:before{color:#58504b}.modal-popup .action-close:before,.modal-slide .action-close:before{font-size:2rem}.modal-popup .action-close:focus,.modal-slide .action-close:focus{background-color:transparent}.modal-popup.prompt .prompt-message{padding:2rem 0}.modal-popup.prompt .prompt-message input{width:100%}.modal-popup.confirm .modal-inner-wrap .message,.modal-popup.prompt .modal-inner-wrap .message{background:#fff}.modal-popup.modal-system-messages .modal-inner-wrap{background:#fffbbb}.modal-popup._image-box .modal-inner-wrap{margin:5rem auto;max-width:78rem;position:static}.modal-popup._image-box .thumbnail-preview{padding-bottom:3rem;text-align:center}.modal-popup._image-box .thumbnail-preview .thumbnail-preview-image-block{border:1px solid #ccc;margin:0 auto 2rem;max-width:58rem;padding:2rem}.modal-popup._image-box .thumbnail-preview .thumbnail-preview-image{max-height:54rem}.modal-popup .modal-title{font-size:2.4rem;margin-right:6.4rem}.modal-popup .modal-footer{padding-top:2.6rem;text-align:right}.modal-popup .action-close{padding:3rem}.modal-popup .action-close:active,.modal-popup .action-close:focus{background:0 0;padding-right:3.1rem;padding-top:3.1rem}.modal-slide .modal-content-new-attribute{-webkit-overflow-scrolling:touch;overflow:auto;padding-bottom:0}.modal-slide .modal-content-new-attribute iframe{margin-bottom:-2.5rem}.modal-slide .modal-title{font-size:2.1rem;margin-right:5.7rem}.modal-slide .action-close{padding:2.1rem 2.6rem}.modal-slide .action-close:active{padding-right:2.7rem;padding-top:2.2rem}.modal-slide .page-main-actions{margin-bottom:.6rem;margin-top:2.1rem}.modal-slide .magento-message{padding:0 3rem 3rem;position:relative}.modal-slide .magento-message .insert-title-inner,.modal-slide .main-col .insert-title-inner{border-bottom:1px solid #adadad;margin:0 0 2rem;padding-bottom:.5rem}.modal-slide .magento-message .insert-actions,.modal-slide .main-col .insert-actions{float:right}.modal-slide .magento-message .title,.modal-slide .main-col .title{font-size:1.6rem;padding-top:.5rem}.modal-slide .main-col,.modal-slide .side-col{float:left;padding-bottom:0}.modal-slide .main-col:after,.modal-slide .side-col:after{display:none}.modal-slide .side-col{width:20%}.modal-slide .main-col{padding-right:0;width:80%}.modal-slide .content-footer .form-buttons{float:right}.modal-title{font-weight:400;margin-bottom:0;min-height:1em}.modal-title span{font-size:1.4rem;font-style:italic;margin-left:1rem}.spinner{display:inline-block;font-size:4rem;height:1em;margin-right:1.5rem;position:relative;width:1em}.spinner>span:nth-child(1){animation-delay:.27s;-ms-transform:rotate(-315deg);transform:rotate(-315deg)}.spinner>span:nth-child(2){animation-delay:.36s;-ms-transform:rotate(-270deg);transform:rotate(-270deg)}.spinner>span:nth-child(3){animation-delay:.45s;-ms-transform:rotate(-225deg);transform:rotate(-225deg)}.spinner>span:nth-child(4){animation-delay:.54s;-ms-transform:rotate(-180deg);transform:rotate(-180deg)}.spinner>span:nth-child(5){animation-delay:.63s;-ms-transform:rotate(-135deg);transform:rotate(-135deg)}.spinner>span:nth-child(6){animation-delay:.72s;-ms-transform:rotate(-90deg);transform:rotate(-90deg)}.spinner>span:nth-child(7){animation-delay:.81s;-ms-transform:rotate(-45deg);transform:rotate(-45deg)}.spinner>span:nth-child(8){animation-delay:.9;-ms-transform:rotate(0deg);transform:rotate(0deg)}@keyframes fade{0%{background-color:#514943}100%{background-color:#fff}}.spinner>span{-ms-transform:scale(0.4);transform:scale(0.4);animation-name:fade;animation-duration:.72s;animation-iteration-count:infinite;animation-direction:linear;background-color:#fff;border-radius:6px;clip:rect(0 .28571429em .1em 0);height:.1em;margin-top:.5em;position:absolute;width:1em}.ie9 .spinner{background:url(../images/ajax-loader.gif) center no-repeat}.ie9 .spinner>span{display:none}.popup-loading{background:rgba(255,255,255,.8);border-color:#ef672f;color:#ef672f;font-size:14px;font-weight:700;left:50%;margin-left:-100px;padding:100px 0 10px;position:fixed;text-align:center;top:40%;width:200px;z-index:1003}.popup-loading:after{background-image:url(../images/loader-1.gif);content:'';height:64px;left:50%;margin:-32px 0 0 -32px;position:absolute;top:40%;width:64px;z-index:2}.loading-mask,.loading-old{background:rgba(255,255,255,.4);bottom:0;left:0;position:fixed;right:0;top:0;z-index:2003}.loading-mask img,.loading-old img{display:none}.loading-mask p,.loading-old p{margin-top:118px}.loading-mask .loader,.loading-old .loader{background:url(../images/loader-1.gif) 50% 30% no-repeat #f7f3eb;border-radius:5px;bottom:0;color:#575757;font-size:14px;font-weight:700;height:160px;left:0;margin:auto;opacity:.95;position:absolute;right:0;text-align:center;top:0;width:160px}.admin-user{float:right;line-height:1.36;margin-left:.3rem;z-index:490}.admin-user._active .admin__action-dropdown,.admin-user.active .admin__action-dropdown{border-color:#007bdb;box-shadow:1px 1px 5px rgba(0,0,0,.5)}.admin-user .admin__action-dropdown{height:3.3rem;padding:.7rem 2.8rem .4rem 4rem}.admin-user .admin__action-dropdown._active:after,.admin-user .admin__action-dropdown.active:after{-ms-transform:rotate(180deg);transform:rotate(180deg)}.admin-user .admin__action-dropdown:after{border-color:#777 transparent transparent;border-style:solid;border-width:.5rem .4rem 0;content:'';height:0;margin-top:-.2rem;position:absolute;right:1.3rem;top:50%;transition:all .2s linear;width:0}._active .admin-user .admin__action-dropdown:after,.active .admin-user .admin__action-dropdown:after{-ms-transform:rotate(180deg);transform:rotate(180deg)}.admin-user .admin__action-dropdown:hover:after{border-color:#000 transparent transparent}.admin-user .admin__action-dropdown:before{color:#777;content:'\e600';font-size:2rem;left:1.1rem;margin-top:-1.1rem;position:absolute;top:50%}.admin-user .admin__action-dropdown:hover:before{color:#333}.admin-user .admin__action-dropdown-menu{min-width:20rem;padding-left:1rem;padding-right:1rem}.admin-user .admin__action-dropdown-menu>li>a{padding-left:.5em;padding-right:1.8rem;transition:background-color .1s linear;white-space:nowrap}.admin-user .admin__action-dropdown-menu>li>a:hover{background-color:#e0f6fe;color:#333}.admin-user .admin__action-dropdown-menu>li>a:active{background-color:#c7effd;bottom:-1px;position:relative}.admin-user .admin__action-dropdown-menu .admin-user-name{text-overflow:ellipsis;white-space:nowrap;display:inline-block;max-width:20rem;overflow:hidden;vertical-align:top}.admin-user-account-text{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;display:inline-block;max-width:11.2rem}.search-global{float:right;margin-right:-.3rem;position:relative;z-index:480}.search-global-field{min-width:5rem}.search-global-field._active .search-global-input{background-color:#fff;border-color:#007bdb;box-shadow:1px 1px 5px rgba(0,0,0,.5);padding-right:4rem;width:25rem}.search-global-field._active .search-global-action{display:block;height:3.3rem;position:absolute;right:0;text-indent:-100%;top:0;width:5rem;z-index:3}.search-global-field .autocomplete-results{height:3.3rem;position:absolute;right:0;top:0;width:25rem}.search-global-field .search-global-menu{border:1px solid #007bdb;border-top-color:transparent;box-shadow:1px 1px 5px rgba(0,0,0,.5);left:0;margin-top:-2px;padding:0;position:absolute;right:0;top:100%;z-index:2}.search-global-field .search-global-menu:after{background-color:#fff;content:'';height:5px;left:0;position:absolute;right:0;top:-5px}.search-global-field .search-global-menu>li{background-color:#fff;border-top:1px solid #ddd;display:block;font-size:1.2rem;padding:.75rem 1.4rem .55rem}.search-global-field .search-global-menu>li._active{background-color:#e0f6fe}.search-global-field .search-global-menu .title{display:block;font-size:1.4rem}.search-global-field .search-global-menu .type{color:#1a1a1a;display:block}.search-global-label{cursor:pointer;height:3.3rem;padding:.75rem 1.4rem .55rem;position:absolute;right:0;top:0;z-index:2}.search-global-label:active{-ms-transform:scale(0.9);transform:scale(0.9)}.search-global-label:hover:before{color:#000}.search-global-label:before{color:#777;content:'\e60c';font-size:2rem}.search-global-input{background-color:transparent;border:1px solid transparent;font-size:1.4rem;height:3.3rem;padding:.75rem 1.4rem .55rem;position:absolute;right:0;top:0;transition:all .1s linear,width .3s linear;width:5rem;z-index:1}.search-global-action{display:none}.notifications-wrapper{float:right;line-height:1;position:relative}.notifications-wrapper.active{z-index:500}.notifications-wrapper.active .notifications-action{border-color:#007bdb;box-shadow:1px 1px 5px rgba(0,0,0,.5)}.notifications-wrapper.active .notifications-action:after{background-color:#fff;border:none;content:'';display:block;height:6px;left:-6px;margin-top:0;position:absolute;right:0;top:100%;width:auto}.notifications-wrapper .admin__action-dropdown-menu{padding:1rem 0 0;width:32rem}.notifications-action{color:#777;height:3.3rem;padding:.75rem 2rem .65rem}.notifications-action:after{display:none}.notifications-action:before{content:'\e607';font-size:1.9rem;margin-right:0}.notifications-action:active:before{position:relative;top:1px}.notifications-action .notifications-counter{background-color:#e22626;border-radius:1em;color:#fff;display:inline-block;font-size:1.1rem;font-weight:700;left:50%;margin-left:.3em;margin-top:-1.1em;padding:.3em .5em;position:absolute;top:50%}.notifications-entry{line-height:1.36;padding:.6rem 2rem .8rem;position:relative;transition:background-color .1s linear}.notifications-entry:hover{background-color:#e0f6fe}.notifications-entry.notifications-entry-last{margin:0 2rem;padding:.3rem 0 1.3rem;text-align:center}.notifications-entry.notifications-entry-last:hover{background-color:transparent}.notifications-entry+.notifications-entry-last{border-top:1px solid #ddd;padding-bottom:.6rem}.notifications-entry ._cutted{cursor:pointer}.notifications-entry ._cutted .notifications-entry-description-start:after{content:'...'}.notifications-entry-title{color:#ef672f;display:block;font-size:1.1rem;font-weight:700;margin-bottom:.7rem;margin-right:1em}.notifications-entry-description{color:#333;font-size:1.1rem;margin-bottom:.8rem}.notifications-entry-description-end{display:none}.notifications-entry-description-end._show{display:inline}.notifications-entry-time{color:#777;font-size:1.1rem}.notifications-close{line-height:1;padding:1rem;position:absolute;right:0;top:.6rem}.notifications-close:before{color:#ccc;content:'\e620';transition:color .1s linear}.notifications-close:hover:before{color:#b3b3b3}.notifications-close:active{-ms-transform:scale(0.95);transform:scale(0.95)}.page-header-actions{padding-top:1.1rem}.page-header-hgroup{padding-right:1.5rem}.page-title{color:#333;font-size:2.8rem}.page-header{padding:1.5rem 3rem}.menu-wrapper{display:inline-block;position:relative;width:8.8rem;z-index:700}.menu-wrapper:before{background-color:#373330;bottom:0;content:'';left:0;position:fixed;top:0;width:8.8rem;z-index:699}.menu-wrapper._fixed{left:0;position:fixed;top:0}.menu-wrapper._fixed~.page-wrapper{margin-left:8.8rem}.menu-wrapper .logo{display:block;height:8.8rem;padding:2.4rem 0 2.2rem;position:relative;text-align:center;z-index:700}._keyfocus .menu-wrapper .logo:focus{background-color:#4a4542;box-shadow:none}._keyfocus .menu-wrapper .logo:focus+.admin__menu .level-0:first-child>a{background-color:#373330}._keyfocus .menu-wrapper .logo:focus+.admin__menu .level-0:first-child>a:after{display:none}.menu-wrapper .logo:hover .logo-img{-webkit-filter:brightness(1.1);filter:brightness(1.1)}.menu-wrapper .logo:active .logo-img{-ms-transform:scale(0.95);transform:scale(0.95)}.menu-wrapper .logo .logo-img{height:4.2rem;transition:-webkit-filter .2s linear,filter .2s linear,transform .1s linear;width:3.5rem}.abs-menu-separator,.admin__menu .item-partners>a:after,.admin__menu .level-0:first-child>a:after{background-color:#736963;content:'';display:block;height:1px;left:0;margin-left:16%;position:absolute;top:0;width:68%}.admin__menu li{display:block}.admin__menu .level-0:first-child>a{position:relative}.admin__menu .level-0._active>a,.admin__menu .level-0:hover>a{color:#f7f3eb}.admin__menu .level-0._active>a{background-color:#524d49}.admin__menu .level-0:hover>a{background-color:#4a4542}.admin__menu .level-0>a{color:#aaa6a0;display:block;font-size:1rem;letter-spacing:.025em;min-height:6.2rem;padding:1.2rem .5rem .5rem;position:relative;text-align:center;text-decoration:none;text-transform:uppercase;transition:background-color .1s linear;word-wrap:break-word;z-index:700}.admin__menu .level-0>a:focus{box-shadow:none}.admin__menu .level-0>a:before{content:'\e63a';display:block;font-size:2.2rem;height:2.2rem}.admin__menu .level-0>.submenu{background-color:#4a4542;box-shadow:0 0 3px #000;left:100%;min-height:calc(8.8rem + 2rem + 100%);padding:2rem 0 0;position:absolute;top:0;-ms-transform:translateX(-100%);transform:translateX(-100%);transition-duration:.3s;transition-property:transform,visibility;transition-timing-function:ease-in-out;visibility:hidden;z-index:697}.ie10 .admin__menu .level-0>.submenu,.ie11 .admin__menu .level-0>.submenu{height:100%}.admin__menu .level-0._show>.submenu{-ms-transform:translateX(0);transform:translateX(0);visibility:visible;z-index:698}.admin__menu .level-1{margin-left:1.5rem;margin-right:1.5rem}.admin__menu [class*=level-]:not(.level-0) a{display:block;padding:1.25rem 1.5rem}.admin__menu [class*=level-]:not(.level-0) a:hover{background-color:#403934}.admin__menu [class*=level-]:not(.level-0) a:active{background-color:#322c29;padding-bottom:1.15rem;padding-top:1.35rem}.admin__menu .submenu li{min-width:23.8rem}.admin__menu .submenu a{color:#fcfcfc;transition:background-color .1s linear}.admin__menu .submenu a:focus,.admin__menu .submenu a:hover{box-shadow:none;text-decoration:none}._keyfocus .admin__menu .submenu a:focus{background-color:#403934}._keyfocus .admin__menu .submenu a:active{background-color:#322c29}.admin__menu .submenu .parent{margin-bottom:4.5rem}.admin__menu .submenu .parent .submenu-group-title{color:#a79d95;display:block;font-size:1.6rem;font-weight:600;margin-bottom:.7rem;padding:1.25rem 1.5rem;pointer-events:none}.admin__menu .submenu .column{display:table-cell}.admin__menu .submenu-title{color:#fff;display:block;font-size:2.2rem;font-weight:600;margin-bottom:4.2rem;margin-left:3rem;margin-right:5.8rem}.admin__menu .submenu-sub-title{color:#fff;display:block;font-size:1.2rem;margin:-3.8rem 5.8rem 3.8rem 3rem}.admin__menu .action-close{padding:2.4rem 2.8rem;position:absolute;right:0;top:0}.admin__menu .action-close:before{color:#a79d95;font-size:1.7rem}.admin__menu .action-close:hover:before{color:#fff}.admin__menu .item-dashboard>a:before{content:'\e604';font-size:1.8rem;padding-top:.4rem}.admin__menu .item-sales>a:before{content:'\e60b'}.admin__menu .item-catalog>a:before{content:'\e608'}.admin__menu .item-customer>a:before{content:'\e603';font-size:2.6rem;position:relative;top:-.4rem}.admin__menu .item-marketing>a:before{content:'\e609';font-size:2rem;padding-top:.2rem}.admin__menu .item-content>a:before{content:'\e602';font-size:2.4rem;position:relative;top:-.2rem}.admin__menu .item-report>a:before{content:'\e60a'}.admin__menu .item-stores>a:before{content:'\e60d';font-size:1.9rem;padding-top:.3rem}.admin__menu .item-system>a:before{content:'\e610'}.admin__menu .item-partners._active>a:after,.admin__menu .item-system._current+.item-partners>a:after{display:none}.admin__menu .item-partners>a{padding-bottom:1rem}.admin__menu .item-partners>a:before{content:'\e612'}.admin__menu .level-0>.submenu>ul>.level-1:only-of-type>.submenu-group-title,.admin__menu .submenu .column:only-of-type .submenu-group-title{display:none}.admin__menu-overlay{bottom:0;left:0;position:fixed;right:0;top:0;z-index:697}.store-switcher{color:#333;float:left;font-size:1.3rem;margin-top:.7rem}.store-switcher .admin__action-dropdown{background-color:#f8f8f8;margin-left:.5em}.store-switcher .dropdown{display:inline-block;position:relative}.store-switcher .dropdown:after,.store-switcher .dropdown:before{content:'';display:table}.store-switcher .dropdown:after{clear:both}.store-switcher .dropdown .action.toggle{cursor:pointer;display:inline-block;text-decoration:none}.store-switcher .dropdown .action.toggle:after{-webkit-font-smoothing:antialiased;font-size:22px;line-height:2;color:#333;content:'\e607';font-family:icons-blank-theme;margin:0;vertical-align:top;display:inline-block;font-weight:400;overflow:hidden;speak:none;text-align:center}.store-switcher .dropdown .action.toggle:active:after,.store-switcher .dropdown .action.toggle:hover:after{color:#333}.store-switcher .dropdown .action.toggle.active{display:inline-block;text-decoration:none}.store-switcher .dropdown .action.toggle.active:after{-webkit-font-smoothing:antialiased;font-size:22px;line-height:2;color:#333;content:'\e618';font-family:icons-blank-theme;margin:0;vertical-align:top;display:inline-block;font-weight:400;overflow:hidden;speak:none;text-align:center}.store-switcher .dropdown .action.toggle.active:active:after,.store-switcher .dropdown .action.toggle.active:hover:after{color:#333}.store-switcher .dropdown .dropdown-menu{margin:4px 0 0;padding:0;list-style:none;background:#fff;border:1px solid #aaa6a0;min-width:19.5rem;z-index:100;box-sizing:border-box;display:none;position:absolute;top:100%;box-shadow:1px 1px 5px rgba(0,0,0,.5)}.store-switcher .dropdown .dropdown-menu li{margin:0;padding:0}.store-switcher .dropdown .dropdown-menu li:hover{background:0 0;cursor:pointer}.store-switcher .dropdown.active{overflow:visible}.store-switcher .dropdown.active .dropdown-menu{display:block}.store-switcher .dropdown-menu{left:0;margin-top:.5em;max-height:250px;overflow-y:auto;padding-top:.25em}.store-switcher .dropdown-menu li{border:0;cursor:default}.store-switcher .dropdown-menu li:hover{cursor:default}.store-switcher .dropdown-menu li a,.store-switcher .dropdown-menu li span{color:#333;display:block;padding:.5rem 1.3rem}.store-switcher .dropdown-menu li a{text-decoration:none}.store-switcher .dropdown-menu li a:hover{background:#e9e9e9}.store-switcher .dropdown-menu li span{color:#adadad;cursor:default}.store-switcher .dropdown-menu li.current span{background:#eee;color:#333}.store-switcher .dropdown-menu .store-switcher-store a,.store-switcher .dropdown-menu .store-switcher-store span{padding-left:2.6rem}.store-switcher .dropdown-menu .store-switcher-store-view a,.store-switcher .dropdown-menu .store-switcher-store-view span{padding-left:3.9rem}.store-switcher .dropdown-menu .dropdown-toolbar{border-top:1px solid #ebebeb;margin-top:1rem}.store-switcher .dropdown-menu .dropdown-toolbar a:before{content:'\e610';margin-right:.25em;position:relative;top:1px}.store-switcher-label{font-weight:700}.store-switcher-alt{display:inline-block;position:relative}.store-switcher-alt.active .dropdown-menu{display:block}.store-switcher-alt .dropdown-menu{margin-top:2px;white-space:nowrap}.store-switcher-alt .dropdown-menu ul{list-style:none;margin:0;padding:0}.store-switcher-alt strong{color:#a79d95;display:block;font-size:14px;font-weight:500;line-height:1.333;padding:5px 10px}.store-switcher-alt .store-selected{color:#676056;cursor:pointer;font-size:12px;font-weight:400;line-height:1.333}.store-switcher-alt .store-selected:after{-webkit-font-smoothing:antialiased;color:#afadac;content:'\e02c';font-style:normal;font-weight:400;margin:0 0 0 3px;speak:none;vertical-align:text-top}.store-switcher-alt .store-switcher-store,.store-switcher-alt .store-switcher-website{padding:0}.store-switcher-alt .store-switcher-store:hover,.store-switcher-alt .store-switcher-website:hover{background:0 0}.store-switcher-alt .manage-stores,.store-switcher-alt .store-switcher-all,.store-switcher-alt .store-switcher-store-view{padding:0}.store-switcher-alt .manage-stores>a,.store-switcher-alt .store-switcher-all>a{color:#676056;display:block;font-size:12px;padding:8px 15px;text-decoration:none}.store-switcher-website{margin:5px 0 0}.store-switcher-website>strong{padding-left:13px}.store-switcher-store{margin:1px 0 0}.store-switcher-store>strong{padding-left:20px}.store-switcher-store>ul{margin-top:1px}.store-switcher-store-view:first-child{border-top:1px solid #e5e5e5}.store-switcher-store-view>a{color:#333;display:block;font-size:13px;padding:5px 15px 5px 24px;text-decoration:none}.store-view:not(.store-switcher){float:left}.store-view .store-switcher-label{display:inline-block;margin-top:1rem}.tooltip{margin-left:.5em}.tooltip .help a,.tooltip .help span{cursor:pointer;display:inline-block;height:22px;position:relative;vertical-align:middle;width:22px;z-index:2}.tooltip .help a:before,.tooltip .help span:before{color:#333;content:'\e633';font-size:1.7rem}.tooltip .help a:hover{text-decoration:none}.tooltip .tooltip-content{background:#000;border-radius:3px;color:#fff;display:none;margin-left:-19px;margin-top:10px;max-width:200px;padding:4px 8px;position:absolute;text-shadow:none;z-index:20}.tooltip .tooltip-content:before{border-bottom:5px solid #000;border-left:5px solid transparent;border-right:5px solid transparent;content:'';height:0;left:20px;opacity:.8;position:absolute;top:-5px;width:0}.tooltip .tooltip-content.loading{position:absolute}.tooltip .tooltip-content.loading:before{border-bottom-color:rgba(0,0,0,.3)}.tooltip:hover>.tooltip-content{display:block}.page-actions._fixed,.page-main-actions:not(._hidden){background:#f8f8f8;border-bottom:1px solid #e3e3e3;border-top:1px solid #e3e3e3;padding:1.5rem}.page-main-actions{margin:0 0 3rem}.page-main-actions._hidden .store-switcher{display:none}.page-main-actions._hidden .page-actions-placeholder{min-height:50px}.page-actions{float:right}.page-main-actions .page-actions._fixed{left:8.8rem;position:fixed;right:0;top:0;z-index:501}.page-main-actions .page-actions._fixed .page-actions-inner:before{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;color:#333;content:attr(data-title);float:left;font-size:2.8rem;margin-top:.3rem;max-width:50%}.page-actions .page-actions-buttons>button,.page-actions>button{float:right;margin-left:1.3rem}.page-actions .page-actions-buttons>button.action-back,.page-actions .page-actions-buttons>button.back,.page-actions>button.action-back,.page-actions>button.back{float:left;-ms-flex-order:-1;order:-1}.page-actions .page-actions-buttons>button.action-back:before,.page-actions .page-actions-buttons>button.back:before,.page-actions>button.action-back:before,.page-actions>button.back:before{content:'\e626';margin-right:.5em;position:relative;top:1px}.page-actions .page-actions-buttons>button.action-primary,.page-actions .page-actions-buttons>button.primary,.page-actions>button.action-primary,.page-actions>button.primary{-ms-flex-order:2;order:2}.page-actions .page-actions-buttons>button.save:not(.primary),.page-actions>button.save:not(.primary){-ms-flex-order:1;order:1}.page-actions .page-actions-buttons>button.delete,.page-actions>button.delete{-ms-flex-order:-1;order:-1}.page-actions .actions-split{float:right;margin-left:1.3rem;-ms-flex-order:2;order:2}.page-actions .actions-split .dropdown-menu .item{display:block}.page-actions-buttons{float:right;-ms-flex-pack:end;justify-content:flex-end;display:-ms-flexbox;display:flex}.customer-index-edit .page-actions-buttons{background-color:transparent}.admin__page-nav{background:#f1f1f1;border:1px solid #e3e3e3}.admin__page-nav._collapsed:first-child{border-bottom:none}.admin__page-nav._collapsed._show{border-bottom:1px solid #e3e3e3}.admin__page-nav._collapsed._show ._collapsible{background:#f1f1f1}.admin__page-nav._collapsed._show ._collapsible:after{content:'\e62b'}.admin__page-nav._collapsed._show ._collapsible+.admin__page-nav-items{display:block}.admin__page-nav._collapsed._hide .admin__page-nav-title-messages,.admin__page-nav._collapsed._hide .admin__page-nav-title-messages ._active{display:inline-block}.admin__page-nav+._collapsed{border-bottom:none;border-top:none}.admin__page-nav-title{border-bottom:1px solid #e3e3e3;color:#303030;display:block;font-size:1.4rem;line-height:1.2;margin:0 0 -1px;padding:1.8rem 1.5rem;position:relative;text-transform:uppercase}.admin__page-nav-title._collapsible{background:#fff;cursor:pointer;margin:0;padding-right:3.5rem;transition:border-color .1s ease-out,background-color .1s ease-out}.admin__page-nav-title._collapsible+.admin__page-nav-items{display:none;margin-top:-1px}.admin__page-nav-title._collapsible:after{content:'\e628';font-size:1.3rem;font-weight:700;position:absolute;right:1.8rem;top:2rem}.admin__page-nav-title._collapsible:hover{background:#f1f1f1}.admin__page-nav-title._collapsible:last-child{margin:0 0 -1px}.admin__page-nav-title strong{font-weight:700}.admin__page-nav-title .admin__page-nav-title-messages{display:none}.admin__page-nav-items{list-style-type:none;margin:0;padding:1rem 0 1.3rem}.admin__page-nav-item{border-left:3px solid transparent;margin-left:.7rem;padding:0;position:relative;transition:border-color .1s ease-out,background-color .1s ease-out}.admin__page-nav-item:hover{border-color:#e4e4e4}.admin__page-nav-item:hover .admin__page-nav-link{background:#e4e4e4;color:#303030;text-decoration:none}.admin__page-nav-item._active,.admin__page-nav-item.ui-state-active{border-color:#eb5202}.admin__page-nav-item._active .admin__page-nav-link,.admin__page-nav-item.ui-state-active .admin__page-nav-link{background:#fff;border-color:#e3e3e3;border-right:1px solid #fff;color:#303030;margin-right:-1px;font-weight:600}.admin__page-nav-item._loading:before,.admin__page-nav-item.ui-tabs-loading:before{display:none}.admin__page-nav-item._loading .admin__page-nav-item-message-loader,.admin__page-nav-item.ui-tabs-loading .admin__page-nav-item-message-loader{display:inline-block}.admin__page-nav-link{border:1px solid transparent;border-width:1px 0;color:#303030;display:block;font-weight:500;line-height:1.2;margin:0 0 -1px;padding:2rem 4rem 2rem 1rem;transition:border-color .1s ease-out,background-color .1s ease-out;word-wrap:break-word}.admin__page-nav-item-messages{display:inline-block}.admin__page-nav-item-messages .admin__page-nav-item-message-tooltip{background:#f1f1f1;border:1px solid #f1f1f1;border-radius:1px;bottom:3.7rem;box-shadow:0 3px 9px 0 rgba(0,0,0,.3);display:none;font-size:1.4rem;font-weight:400;left:-1rem;line-height:1.36;padding:1.5rem;position:absolute;text-transform:none;width:27rem;word-break:normal;z-index:2}.admin__page-nav-item-messages .admin__page-nav-item-message-tooltip:after,.admin__page-nav-item-messages .admin__page-nav-item-message-tooltip:before{border:15px solid transparent;height:0;width:0;border-top-color:#f1f1f1;content:'';display:block;left:2rem;position:absolute;top:100%;z-index:3}.admin__page-nav-item-messages .admin__page-nav-item-message-tooltip:after{border-top-color:#f1f1f1;margin-top:-1px;z-index:4}.admin__page-nav-item-messages .admin__page-nav-item-message-tooltip:before{border-top-color:#bfbfbf;margin-top:1px}.admin__page-nav-item-message-loader{display:none;margin-top:-1rem;position:absolute;right:0;top:50%}.admin__page-nav-item-message-loader .spinner{font-size:2rem;margin-right:1.5rem}._loading>.admin__page-nav-item-messages .admin__page-nav-item-message-loader{display:inline-block}.admin__page-nav-item-message{position:relative}.admin__page-nav-item-message:hover{z-index:500}.admin__page-nav-item-message:hover .admin__page-nav-item-message-tooltip{display:block}.admin__page-nav-item-message._changed,.admin__page-nav-item-message._error{display:none}.admin__page-nav-item-message .admin__page-nav-item-message-icon{display:inline-block;font-size:1.4rem;padding-left:.8em;vertical-align:baseline}.admin__page-nav-item-message .admin__page-nav-item-message-icon:after{color:#666;content:'\e631'}._changed:not(._error)>.admin__page-nav-item-messages ._changed{display:inline-block}._error .admin__page-nav-item-message-icon:after{color:#eb5202;content:'\e623'}._error>.admin__page-nav-item-messages ._error{display:inline-block}._error>.admin__page-nav-item-messages ._error .spinner{font-size:2rem;margin-right:1.5rem}._error .admin__page-nav-item-message-tooltip{background:#f1f1f1;border:1px solid #f1f1f1;border-radius:1px;bottom:3.7rem;box-shadow:0 3px 9px 0 rgba(0,0,0,.3);display:none;font-weight:400;left:-1rem;line-height:1.36;padding:2rem;position:absolute;text-transform:none;width:27rem;word-break:normal;z-index:2}._error .admin__page-nav-item-message-tooltip:after,._error .admin__page-nav-item-message-tooltip:before{border:15px solid transparent;height:0;width:0;border-top-color:#f1f1f1;content:'';display:block;left:2rem;position:absolute;top:100%;z-index:3}._error .admin__page-nav-item-message-tooltip:after{border-top-color:#f1f1f1;margin-top:-1px;z-index:4}._error .admin__page-nav-item-message-tooltip:before{border-top-color:#bfbfbf}.admin__data-grid-wrap-static .data-grid{box-sizing:border-box}.admin__data-grid-wrap-static .data-grid thead{color:#333}.admin__data-grid-wrap-static .data-grid tr:nth-child(even) td{background-color:#f5f5f5}.admin__data-grid-wrap-static .data-grid tr:nth-child(even) td._dragging{background-color:rgba(245,245,245,.95)}.admin__data-grid-wrap-static .data-grid ul{margin-left:1rem;padding-left:1rem}.admin__data-grid-wrap-static .admin__data-grid-loading-mask{background:rgba(255,255,255,.5);bottom:0;left:0;position:absolute;right:0;top:0;z-index:399}.admin__data-grid-wrap-static .admin__data-grid-loading-mask .grid-loader{background:url(../images/loader-2.gif) 50% 50% no-repeat;bottom:0;height:149px;left:0;margin:auto;position:absolute;right:0;top:0;width:218px}.data-grid-filters-actions-wrap{float:right}.data-grid-search-control-wrap{float:left;max-width:45.5rem;position:relative;width:35%}.data-grid-search-control-wrap :-ms-input-placeholder{font-style:italic}.data-grid-search-control-wrap ::-webkit-input-placeholder{font-style:italic}.data-grid-search-control-wrap ::-moz-placeholder{font-style:italic}.data-grid-search-control-wrap .action-submit{background-color:transparent;border:none;border-radius:0;box-shadow:none;margin:0;padding:.6rem 2rem .2rem;position:absolute;right:0;top:1px}.data-grid-search-control-wrap .action-submit:hover{background-color:transparent;border:none;box-shadow:none}.data-grid-search-control-wrap .action-submit:active{-ms-transform:scale(0.9);transform:scale(0.9)}.data-grid-search-control-wrap .action-submit:hover:before{color:#1a1a1a}._keyfocus .data-grid-search-control-wrap .action-submit:focus{box-shadow:0 0 0 1px #008bdb}.data-grid-search-control-wrap .action-submit:before{content:'\e60c';font-size:2rem;transition:color .1s linear}.data-grid-search-control-wrap .action-submit>span{clip:rect(0,0,0,0);overflow:hidden;position:absolute}.data-grid-search-control-wrap .abs-action-menu .action-submenu,.data-grid-search-control-wrap .abs-action-menu .action-submenu .action-submenu,.data-grid-search-control-wrap .action-menu,.data-grid-search-control-wrap .action-menu .action-submenu,.data-grid-search-control-wrap .actions-split .action-menu .action-submenu,.data-grid-search-control-wrap .actions-split .action-menu .action-submenu .action-submenu,.data-grid-search-control-wrap .actions-split .dropdown-menu .action-submenu,.data-grid-search-control-wrap .actions-split .dropdown-menu .action-submenu .action-submenu{max-height:19.25rem;overflow-y:auto;z-index:398}.data-grid-search-control-wrap .action-menu-item._selected{background-color:#e0f6fe}.data-grid-search-control-wrap .data-grid-search-label{display:none}.data-grid-search-control{padding-right:6rem;width:100%}.data-grid-filters-action-wrap{float:left;padding-left:2rem}.data-grid-filters-action-wrap .action-default{font-size:1.3rem;margin-bottom:1rem;padding-left:1.7rem;padding-right:2.1rem;padding-top:.7rem}.data-grid-filters-action-wrap .action-default._active{background-color:#fff;border-bottom-color:#fff;border-right-color:#ccc;font-weight:600;margin:-.1rem 0 0;padding-bottom:1.6rem;padding-top:.8rem;position:relative;z-index:281}.data-grid-filters-action-wrap .action-default._active:after{background-color:#eb5202;bottom:100%;content:'';height:3px;left:-1px;position:absolute;right:-1px}.data-grid-filters-action-wrap .action-default:before{color:#333;content:'\e605';font-size:1.8rem;margin-right:.4rem;position:relative;top:-1px;vertical-align:top}.data-grid-filters-action-wrap .filters-active{display:none}.admin__action-grid-select .admin__control-select{margin:-.5rem .5rem 0 0;padding-bottom:.6rem;padding-top:.6rem}.admin__data-grid-filters-wrap{opacity:0;visibility:hidden;clear:both;font-size:1.3rem;transition:opacity .3s ease}.admin__data-grid-filters-wrap._show{opacity:1;visibility:visible;border-bottom:1px solid #ccc;border-top:1px solid #ccc;margin-bottom:.7rem;padding:3.6rem 0 3rem;position:relative;top:-1px;z-index:280}.admin__data-grid-filters-wrap._show .admin__data-grid-filters,.admin__data-grid-filters-wrap._show .admin__data-grid-filters-footer{display:block}.admin__data-grid-filters-wrap .admin__form-field-label,.admin__data-grid-filters-wrap .admin__form-field-legend{display:block;font-weight:700;margin:0 0 .3rem;text-align:left}.admin__data-grid-filters-wrap .admin__form-field{display:inline-block;margin-bottom:2em;margin-left:0;padding-left:2rem;padding-right:2rem;vertical-align:top;width:calc(100% / 4 - 4px)}.admin__data-grid-filters-wrap .admin__form-field .admin__form-field{display:block;float:none;margin-bottom:1.5rem;padding-left:0;padding-right:0;width:auto}.admin__data-grid-filters-wrap .admin__form-field .admin__form-field:last-child{margin-bottom:0}.admin__data-grid-filters-wrap .admin__form-field .admin__form-field .admin__form-field-label{border:1px solid transparent;float:left;font-weight:400;line-height:1.36;margin-bottom:0;padding-bottom:.6rem;padding-right:1em;padding-top:.6rem;width:25%}.admin__data-grid-filters-wrap .admin__form-field .admin__form-field .admin__form-field-control{margin-left:25%}.admin__data-grid-filters-wrap .admin__action-multiselect,.admin__data-grid-filters-wrap .admin__control-select,.admin__data-grid-filters-wrap .admin__control-text,.admin__data-grid-filters-wrap .admin__form-field-label{font-size:1.3rem}.admin__data-grid-filters-wrap .admin__control-select{height:3.2rem;padding-top:.5rem}.admin__data-grid-filters-wrap .admin__action-multiselect:before{height:3.2rem;width:3.2rem}.admin__data-grid-filters-wrap .admin__control-select,.admin__data-grid-filters-wrap .admin__control-text._has-datepicker{width:100%}.admin__data-grid-filters{display:none;margin-left:-2rem;margin-right:-2rem}.admin__filters-legend{clip:rect(0,0,0,0);overflow:hidden;position:absolute}.admin__data-grid-filters-footer{display:none;font-size:1.4rem}.admin__data-grid-filters-footer .admin__footer-main-actions{margin-left:25%;text-align:right}.admin__data-grid-filters-footer .admin__footer-secondary-actions{float:left;width:50%}.admin__data-grid-filters-current{border-bottom:.1rem solid #ccc;border-top:.1rem solid #ccc;display:none;font-size:1.3rem;margin-bottom:.9rem;padding-bottom:.8rem;padding-top:1.1rem;width:100%}.admin__data-grid-filters-current._show{display:table;position:relative;top:-1px;z-index:3}.admin__data-grid-filters-current._show+.admin__data-grid-filters-wrap._show{margin-top:-1rem}.admin__current-filters-actions-wrap,.admin__current-filters-list-wrap,.admin__current-filters-title-wrap{display:table-cell;vertical-align:top}.admin__current-filters-title{margin-right:1em;white-space:nowrap}.admin__current-filters-list-wrap{width:100%}.admin__current-filters-list{margin-bottom:0}.admin__current-filters-list>li{display:inline-block;font-weight:600;margin:0 1rem .5rem;padding-right:2.6rem;position:relative}.admin__current-filters-list .action-remove{background-color:transparent;border:none;border-radius:0;box-shadow:none;margin:0;padding:0;line-height:1;position:absolute;right:0;top:1px}.admin__current-filters-list .action-remove:hover{background-color:transparent;border:none;box-shadow:none}.admin__current-filters-list .action-remove:hover:before{color:#949494}.admin__current-filters-list .action-remove:active{-ms-transform:scale(0.9);transform:scale(0.9)}.admin__current-filters-list .action-remove:before{color:#adadad;content:'\e620';font-size:1.6rem;transition:color .1s linear}.admin__current-filters-list .action-remove>span{clip:rect(0,0,0,0);overflow:hidden;position:absolute}.admin__current-filters-actions-wrap .action-clear{border:none;padding-bottom:0;padding-top:0;white-space:nowrap}.admin__data-grid-pager-wrap{float:right;text-align:right}.admin__data-grid-pager{display:inline-block;margin-left:3rem}.admin__data-grid-pager .admin__control-text::-webkit-inner-spin-button,.admin__data-grid-pager .admin__control-text::-webkit-outer-spin-button{-webkit-appearance:none;margin:0}.admin__data-grid-pager .admin__control-text{-moz-appearance:textfield;text-align:center;width:4.4rem}.action-next,.action-previous{width:4.4rem}.action-next:before,.action-previous:before{font-weight:700}.action-next>span,.action-previous>span{clip:rect(0,0,0,0);overflow:hidden;position:absolute}.action-previous{margin-right:2.5rem;text-indent:-.25em}.action-previous:before{content:'\e629'}.action-next{margin-left:1.5rem;text-indent:.1em}.action-next:before{content:'\e62a'}.admin__data-grid-action-bookmarks{opacity:.98}.admin__data-grid-action-bookmarks .admin__action-dropdown-text:after{left:0;right:-6px}.admin__data-grid-action-bookmarks._active{z-index:290}.admin__data-grid-action-bookmarks .admin__action-dropdown .admin__action-dropdown-text{display:inline-block;max-width:15rem;min-width:4.9rem;vertical-align:top;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.admin__data-grid-action-bookmarks .admin__action-dropdown:before{content:'\e60f'}.admin__data-grid-action-bookmarks .admin__action-dropdown-menu{font-size:1.3rem;left:0;padding:1rem 0;right:auto}.admin__data-grid-action-bookmarks .admin__action-dropdown-menu>li{padding:0 5rem 0 0;position:relative;white-space:nowrap}.admin__data-grid-action-bookmarks .admin__action-dropdown-menu>li:not(.action-dropdown-menu-action){transition:background-color .1s linear}.admin__data-grid-action-bookmarks .admin__action-dropdown-menu>li:not(.action-dropdown-menu-action):hover{background-color:#e3e3e3}.admin__data-grid-action-bookmarks .admin__action-dropdown-menu .action-dropdown-menu-item{max-width:23rem;min-width:18rem;white-space:normal;word-break:break-all}.admin__data-grid-action-bookmarks .admin__action-dropdown-menu .action-dropdown-menu-item-edit{display:none;padding-bottom:1rem;padding-left:1rem;padding-top:1rem}.admin__data-grid-action-bookmarks .admin__action-dropdown-menu .action-dropdown-menu-item-edit .action-dropdown-menu-item-actions{padding-bottom:1rem;padding-top:1rem}.admin__data-grid-action-bookmarks .admin__action-dropdown-menu .action-dropdown-menu-action{padding-left:1rem;padding-top:1rem}.admin__data-grid-action-bookmarks .admin__action-dropdown-menu .action-dropdown-menu-action+.action-dropdown-menu-item-last{padding-top:.5rem}.admin__data-grid-action-bookmarks .admin__action-dropdown-menu .action-dropdown-menu-action>a{color:#008bdb;text-decoration:none;display:inline-block;padding-left:1.1rem}.admin__data-grid-action-bookmarks .admin__action-dropdown-menu .action-dropdown-menu-action>a:hover{color:#0fa7ff;text-decoration:underline}.admin__data-grid-action-bookmarks .admin__action-dropdown-menu .action-dropdown-menu-item-last{padding-bottom:0}.admin__data-grid-action-bookmarks .admin__action-dropdown-menu ._edit .action-dropdown-menu-item{display:none}.admin__data-grid-action-bookmarks .admin__action-dropdown-menu ._edit .action-dropdown-menu-item-edit{display:block}.admin__data-grid-action-bookmarks .admin__action-dropdown-menu ._active .action-dropdown-menu-link{font-weight:600}.admin__data-grid-action-bookmarks .admin__action-dropdown-menu .admin__control-text{font-size:1.3rem;min-width:15rem;width:calc(100% - 4rem)}.ie9 .admin__data-grid-action-bookmarks .admin__action-dropdown-menu .admin__control-text{width:15rem}.admin__data-grid-action-bookmarks .admin__action-dropdown-menu .action-dropdown-menu-item-actions{border-left:1px solid #fff;bottom:0;position:absolute;right:0;top:0;width:5rem}.admin__data-grid-action-bookmarks .admin__action-dropdown-menu .action-dropdown-menu-link{color:#333;display:block;text-decoration:none;padding:1rem 1rem 1rem 2.1rem}.admin__data-grid-action-bookmarks .action-delete,.admin__data-grid-action-bookmarks .action-edit,.admin__data-grid-action-bookmarks .action-submit{background-color:transparent;border:none;border-radius:0;box-shadow:none;margin:0;vertical-align:top}.admin__data-grid-action-bookmarks .action-delete:hover,.admin__data-grid-action-bookmarks .action-edit:hover,.admin__data-grid-action-bookmarks .action-submit:hover{background-color:transparent;border:none;box-shadow:none}.admin__data-grid-action-bookmarks .action-delete:before,.admin__data-grid-action-bookmarks .action-edit:before,.admin__data-grid-action-bookmarks .action-submit:before{font-size:1.7rem}.admin__data-grid-action-bookmarks .action-delete>span,.admin__data-grid-action-bookmarks .action-edit>span,.admin__data-grid-action-bookmarks .action-submit>span{clip:rect(0,0,0,0);overflow:hidden;position:absolute}.admin__data-grid-action-bookmarks .action-delete,.admin__data-grid-action-bookmarks .action-edit{padding:.6rem 1.4rem}.admin__data-grid-action-bookmarks .action-delete:active,.admin__data-grid-action-bookmarks .action-edit:active{-ms-transform:scale(0.9);transform:scale(0.9)}.admin__data-grid-action-bookmarks .action-submit{padding:.6rem 1rem .6rem .8rem}.admin__data-grid-action-bookmarks .action-submit:active{position:relative;right:-1px}.admin__data-grid-action-bookmarks .action-submit:before{content:'\e625'}.admin__data-grid-action-bookmarks .action-delete:before{content:'\e630'}.admin__data-grid-action-bookmarks .action-edit{padding-top:.8rem}.admin__data-grid-action-bookmarks .action-edit:before{content:'\e631'}.admin__data-grid-action-columns._active{opacity:.98;z-index:290}.admin__data-grid-action-columns .admin__action-dropdown:before{content:'\e610';font-size:1.8rem;margin-right:.7rem;vertical-align:top}.admin__data-grid-action-columns-menu{color:#303030;font-size:1.3rem;overflow:hidden;padding:2.2rem 3.5rem 1rem;z-index:1}.admin__data-grid-action-columns-menu._overflow .admin__action-dropdown-menu-header{border-bottom:1px solid #d1d1d1}.admin__data-grid-action-columns-menu._overflow .admin__action-dropdown-menu-content{width:49.2rem}.admin__data-grid-action-columns-menu._overflow .admin__action-dropdown-menu-footer{border-top:1px solid #d1d1d1;padding-top:2.5rem}.admin__data-grid-action-columns-menu .admin__action-dropdown-menu-content{max-height:22.85rem;overflow-y:auto;padding-top:1.5rem;position:relative;width:47.4rem}.admin__data-grid-action-columns-menu .admin__field-option{float:left;height:1.9rem;margin-bottom:1.5rem;padding:0 1rem 0 0;width:15.8rem}.admin__data-grid-action-columns-menu .admin__field-label{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;display:block}.admin__data-grid-action-columns-menu .admin__action-dropdown-menu-header{padding-bottom:1.5rem}.admin__data-grid-action-columns-menu .admin__action-dropdown-menu-footer{padding:1rem 0 2rem}.admin__data-grid-action-columns-menu .admin__action-dropdown-footer-main-actions{margin-left:25%;text-align:right}.admin__data-grid-action-columns-menu .admin__action-dropdown-footer-secondary-actions{float:left;margin-left:-1em}.admin__data-grid-action-export._active{opacity:.98;z-index:290}.admin__data-grid-action-export .admin__action-dropdown:before{content:'\e635';font-size:1.7rem;left:.3rem;margin-right:.7rem;vertical-align:top}.admin__data-grid-action-export-menu{padding-left:2rem;padding-right:2rem;padding-top:1rem}.admin__data-grid-action-export-menu .admin__action-dropdown-footer-main-actions{padding-bottom:2rem;padding-top:2.5rem;white-space:nowrap}.sticky-header{background-color:#f8f8f8;border-bottom:1px solid #e3e3e3;box-shadow:0 5px 5px 0 rgba(0,0,0,.25);left:8.8rem;margin-top:-1px;padding:.5rem 3rem 0;position:fixed;right:0;top:77px;z-index:398}.sticky-header .admin__data-grid-wrap{margin-bottom:0;overflow-x:visible;padding-bottom:0}.sticky-header .admin__data-grid-header-row{position:relative;text-align:right}.sticky-header .admin__data-grid-header-row:last-child{margin:0}.sticky-header .admin__data-grid-actions-wrap,.sticky-header .admin__data-grid-filters-wrap,.sticky-header .admin__data-grid-pager-wrap,.sticky-header .data-grid-filters-actions-wrap,.sticky-header .data-grid-search-control-wrap{display:inline-block;float:none;vertical-align:top}.sticky-header .action-select-wrap{float:left;margin-right:1.5rem;width:16.66666667%}.sticky-header .admin__control-support-text{float:left}.sticky-header .data-grid-search-control-wrap{margin:-.5rem 0 0 1.1rem;width:auto}.sticky-header .data-grid-search-control-wrap .data-grid-search-label{box-sizing:border-box;cursor:pointer;display:block;min-width:3.8rem;padding:1.2rem .6rem 1.7rem;position:relative;text-align:center}.sticky-header .data-grid-search-control-wrap .data-grid-search-label:before{color:#333;content:'\e60c';font-size:2rem;transition:color .1s linear}.sticky-header .data-grid-search-control-wrap .data-grid-search-label:hover:before{color:#000}.sticky-header .data-grid-search-control-wrap .data-grid-search-label span{display:none}.sticky-header .data-grid-filters-actions-wrap{margin:-.5rem 0 0 1.1rem;padding-left:0;position:relative}.sticky-header .data-grid-filters-actions-wrap .action-default{background-color:transparent;border:1px solid transparent;box-sizing:border-box;min-width:3.8rem;padding:1.2rem .6rem 1.7rem;text-align:center;transition:all .15s ease}.sticky-header .data-grid-filters-actions-wrap .action-default span{display:none}.sticky-header .data-grid-filters-actions-wrap .action-default:before{margin:0}.sticky-header .data-grid-filters-actions-wrap .action-default._active{background-color:#fff;border-color:#adadad #adadad #fff;box-shadow:1px 1px 5px rgba(0,0,0,.5);z-index:210}.sticky-header .data-grid-filters-actions-wrap .action-default._active:after{background-color:#fff;content:'';height:6px;left:-2px;position:absolute;right:-6px;top:100%}.sticky-header .data-grid-filters-action-wrap{padding:0}.sticky-header .admin__data-grid-filters-wrap{background-color:#fff;border:1px solid #adadad;box-shadow:0 5px 5px 0 rgba(0,0,0,.25);left:0;padding-left:3.5rem;padding-right:3.5rem;position:absolute;top:100%;width:100%;z-index:209}.sticky-header .admin__data-grid-filters-current+.admin__data-grid-filters-wrap._show{margin-top:-6px}.sticky-header .filters-active{background-color:#e04f00;border-radius:10px;color:#fff;display:block;font-size:1.4rem;font-weight:700;padding:.1rem .7rem;position:absolute;right:-7px;top:0;z-index:211}.sticky-header .filters-active:empty{padding-bottom:0;padding-top:0}.sticky-header .admin__data-grid-actions-wrap{margin:-.5rem 0 0 1.1rem;padding-right:.3rem}.sticky-header .admin__data-grid-actions-wrap .admin__action-dropdown{background-color:transparent;box-sizing:border-box;min-width:3.8rem;padding-left:.6rem;padding-right:.6rem;text-align:center}.sticky-header .admin__data-grid-actions-wrap .admin__action-dropdown .admin__action-dropdown-text{display:inline-block;max-width:0;min-width:0;overflow:hidden}.sticky-header .admin__data-grid-actions-wrap .admin__action-dropdown:before{margin:0}.sticky-header .admin__data-grid-actions-wrap .admin__action-dropdown-wrap{margin-right:1.1rem}.sticky-header .admin__data-grid-actions-wrap .admin__action-dropdown-wrap:after,.sticky-header .admin__data-grid-actions-wrap .admin__action-dropdown:after{display:none}.sticky-header .admin__data-grid-actions-wrap ._active .admin__action-dropdown{background-color:#fff}.sticky-header .admin__data-grid-action-bookmarks .admin__action-dropdown:before{position:relative;top:-3px}.sticky-header .admin__data-grid-filters-current{border-bottom:0;border-top:0;margin-bottom:0;padding-bottom:0;padding-top:0}.sticky-header .admin__data-grid-pager .admin__control-text,.sticky-header .admin__data-grid-pager-wrap .admin__control-support-text,.sticky-header .data-grid-search-control-wrap .action-submit,.sticky-header .data-grid-search-control-wrap .data-grid-search-control{display:none}.sticky-header .action-next{margin:0}.sticky-header .data-grid{margin-bottom:-1px}.data-grid-cap-left,.data-grid-cap-right{background-color:#f8f8f8;bottom:-2px;position:absolute;top:6rem;width:3rem;z-index:201}.data-grid-cap-left{left:0}.admin__data-grid-header{font-size:1.4rem}.admin__data-grid-header-row+.admin__data-grid-header-row{margin-top:1.1rem}.admin__data-grid-header-row:last-child{margin-bottom:0}.admin__data-grid-header-row .action-select-wrap{display:block}.admin__data-grid-header-row .action-select{width:100%}.admin__data-grid-actions-wrap{float:right;margin-left:1.1rem;margin-top:-.5rem;text-align:right}.admin__data-grid-actions-wrap .admin__action-dropdown-wrap{position:relative;text-align:left;vertical-align:middle}.admin__data-grid-actions-wrap .admin__action-dropdown-wrap._active+.admin__action-dropdown-wrap:after,.admin__data-grid-actions-wrap .admin__action-dropdown-wrap._active:after,.admin__data-grid-actions-wrap .admin__action-dropdown-wrap._hide+.admin__action-dropdown-wrap:after,.admin__data-grid-actions-wrap .admin__action-dropdown-wrap:first-child:after{display:none}.admin__data-grid-actions-wrap .admin__action-dropdown-wrap._active .admin__action-dropdown,.admin__data-grid-actions-wrap .admin__action-dropdown-wrap._active .admin__action-dropdown-menu{border-color:#adadad}.admin__data-grid-actions-wrap .admin__action-dropdown-wrap:after{border-left:1px solid #ccc;content:'';height:3.2rem;left:0;position:absolute;top:.5rem;z-index:3}.admin__data-grid-actions-wrap .admin__action-dropdown{padding-bottom:1.7rem;padding-top:1.2rem}.admin__data-grid-actions-wrap .admin__action-dropdown:after{margin-top:-.4rem}.admin__data-grid-outer-wrap{min-height:8rem;position:relative}.admin__data-grid-wrap{margin-bottom:2rem;max-width:100%;overflow-x:auto;padding-bottom:1rem;padding-top:2rem}.admin__data-grid-loading-mask{background:rgba(255,255,255,.5);bottom:0;left:0;position:absolute;right:0;top:0;z-index:399}.admin__data-grid-loading-mask .spinner{font-size:4rem;left:50%;margin-left:-2rem;margin-top:-2rem;position:absolute;top:50%}.ie9 .admin__data-grid-loading-mask .spinner{background:url(../images/loader-2.gif) 50% 50% no-repeat;bottom:0;height:149px;left:0;margin:auto;position:absolute;right:0;top:0;width:218px}.data-grid-cell-content{display:inline-block;overflow:hidden;width:100%}body._in-resize{cursor:col-resize;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}body._in-resize *,body._in-resize .data-grid-th,body._in-resize .data-grid-th._draggable,body._in-resize .data-grid-th._sortable{cursor:col-resize!important}._layout-fixed{table-layout:fixed}.data-grid{border:none;font-size:1.3rem;margin-bottom:0;width:100%}.data-grid:not(._dragging-copy) ._odd-row td._dragging{background-color:#d0d0d0}.data-grid:not(._dragging-copy) ._dragging{background-color:#d9d9d9;color:rgba(48,48,48,.95)}.data-grid:not(._dragging-copy) ._dragging a{color:rgba(0,139,219,.95)}.data-grid:not(._dragging-copy) ._dragging a:hover{color:rgba(15,167,255,.95)}.data-grid._dragged{outline:#007bdb solid 1px}.data-grid thead{background-color:transparent}.data-grid tfoot th{padding:1rem}.data-grid tr._odd-row td{background-color:#f5f5f5}.data-grid tr._odd-row td._update-status-active{background:#89e1ff}.data-grid tr._odd-row td._update-status-upcoming{background:#b7ee63}.data-grid tr:hover td._update-status-active,.data-grid tr:hover td._update-status-upcoming{background-color:#e5f7fe}.data-grid tr.data-grid-tr-no-data td{font-size:1.6rem;padding:3rem;text-align:center}.data-grid tr.data-grid-tr-no-data:hover td{background-color:#fff;cursor:default}.data-grid tr:active td{background-color:#e0f6fe}.data-grid tr:hover td{background-color:#e5f7fe}.data-grid tr._dragged td{background:#d0d0d0}.data-grid tr._dragover-top td{box-shadow:inset 0 3px 0 0 #008bdb}.data-grid tr._dragover-bottom td{box-shadow:inset 0 -3px 0 0 #008bdb}.data-grid tr:not(.data-grid-editable-row):last-child td{border-bottom:.1rem solid #d6d6d6}.data-grid tr ._clickable,.data-grid tr._clickable{cursor:pointer}.data-grid tr._disabled{pointer-events:none}.data-grid td,.data-grid th{font-size:1.3rem;line-height:1.36;transition:background-color .1s linear;vertical-align:top}.data-grid td._resizing,.data-grid th._resizing{border-left:1px solid #007bdb;border-right:1px solid #007bdb}.data-grid td._hidden,.data-grid th._hidden{display:none}.data-grid td._fit,.data-grid th._fit{width:1%}.data-grid td{background-color:#fff;border-left:.1rem dashed #d6d6d6;border-right:.1rem dashed #d6d6d6;color:#303030;padding:1rem}.data-grid td:first-child{border-left-style:solid}.data-grid td:last-child{border-right-style:solid}.data-grid td .action-select-wrap{position:static}.data-grid td .action-select{color:#008bdb;text-decoration:none;background-color:transparent;border:none;font-size:1.3rem;padding:0 3rem 0 0;position:relative}.data-grid td .action-select:hover{color:#0fa7ff;text-decoration:underline}.data-grid td .action-select:hover:after{border-color:#0fa7ff transparent transparent}.data-grid td .action-select:after{border-color:#008bdb transparent transparent;margin:.6rem 0 0 .7rem;right:auto;top:auto}.data-grid td .action-select:before{display:none}.data-grid td .abs-action-menu .action-submenu,.data-grid td .abs-action-menu .action-submenu .action-submenu,.data-grid td .action-menu,.data-grid td .action-menu .action-submenu,.data-grid td .actions-split .action-menu .action-submenu,.data-grid td .actions-split .action-menu .action-submenu .action-submenu,.data-grid td .actions-split .dropdown-menu .action-submenu,.data-grid td .actions-split .dropdown-menu .action-submenu .action-submenu{left:auto;min-width:10rem;right:0;text-align:left;top:auto;z-index:1}.data-grid td._update-status-active{background:#bceeff}.data-grid td._update-status-upcoming{background:#ccf391}.data-grid th{background-color:#514943;border:.1rem solid #8a837f;border-left-color:transparent;color:#fff;font-weight:600;padding:0;text-align:left}.data-grid th:first-child{border-left-color:#8a837f}.data-grid th._dragover-left{box-shadow:inset 3px 0 0 0 #fff;z-index:2}.data-grid th._dragover-right{box-shadow:inset -3px 0 0 0 #fff}.data-grid .shadow-div{cursor:col-resize;height:100%;margin-right:-5px;position:absolute;right:0;top:0;width:10px}.data-grid .data-grid-th{background-clip:padding-box;color:#fff;padding:1rem;position:relative;vertical-align:middle}.data-grid .data-grid-th._resize-visible .shadow-div{cursor:auto;display:none}.data-grid .data-grid-th._draggable{cursor:grab}.data-grid .data-grid-th._sortable{cursor:pointer;transition:background-color .1s linear;z-index:1}.data-grid .data-grid-th._sortable:focus,.data-grid .data-grid-th._sortable:hover{background-color:#5f564f}.data-grid .data-grid-th._sortable:active{padding-bottom:.9rem;padding-top:1.1rem}.data-grid .data-grid-th.required>span:after{color:#f38a5e;content:'*';margin-left:.3rem}.data-grid .data-grid-checkbox-cell{overflow:hidden;padding:0;vertical-align:top;width:5.2rem}.data-grid .data-grid-checkbox-cell:hover{cursor:default}.data-grid .data-grid-thumbnail-cell{text-align:center;width:7rem}.data-grid .data-grid-thumbnail-cell img{border:1px solid #d6d6d6;width:5rem}.data-grid .data-grid-multicheck-cell{padding:1rem 1rem .9rem;text-align:center;vertical-align:middle}.data-grid .data-grid-onoff-cell{text-align:center;width:12rem}.data-grid .data-grid-actions-cell{padding-left:2rem;padding-right:2rem;text-align:center;width:1%}.data-grid._hidden{display:none}.data-grid._dragging-copy{box-shadow:1px 1px 5px rgba(0,0,0,.5);left:0;opacity:.95;position:fixed;top:0;z-index:1000}.data-grid._dragging-copy .data-grid-th{border:1px solid #007bdb;border-bottom:none}.data-grid._dragging-copy .data-grid-th,.data-grid._dragging-copy .data-grid-th._sortable{cursor:grabbing}.data-grid._dragging-copy tr:last-child td{border-bottom:1px solid #007bdb}.data-grid._dragging-copy td{border-left:1px solid #007bdb;border-right:1px solid #007bdb}.data-grid._dragging-copy._in-edit .data-grid-editable-row.data-grid-bulk-edit-panel td,.data-grid._dragging-copy._in-edit .data-grid-editable-row.data-grid-bulk-edit-panel td:before,.data-grid._dragging-copy._in-edit .data-grid-editable-row.data-grid-bulk-edit-panel:hover td{background-color:rgba(255,251,230,.95)}.data-grid._dragging-copy._in-edit .data-grid-editable-row td,.data-grid._dragging-copy._in-edit .data-grid-editable-row:hover td{background-color:rgba(255,255,255,.95)}.data-grid._dragging-copy._in-edit .data-grid-editable-row td:after,.data-grid._dragging-copy._in-edit .data-grid-editable-row td:before{left:0;right:0}.data-grid._dragging-copy._in-edit .data-grid-editable-row td:before{background-color:rgba(255,255,255,.95)}.data-grid._dragging-copy._in-edit .data-grid-editable-row td:only-child{border-left:1px solid #007bdb;border-right:1px solid #007bdb;left:0}.data-grid._dragging-copy._in-edit .data-grid-editable-row .admin__control-select,.data-grid._dragging-copy._in-edit .data-grid-editable-row .admin__control-text{opacity:.5}.data-grid .data-grid-controls-row td{padding-top:1.6rem}.data-grid .data-grid-controls-row td.data-grid-checkbox-cell{padding-top:.6rem}.data-grid .data-grid-controls-row td [class*=admin__control-],.data-grid .data-grid-controls-row td button{margin-top:-1.7rem}.data-grid._in-edit tr:hover td{background-color:#e6e6e6}.data-grid._in-edit ._odd-row.data-grid-editable-row td,.data-grid._in-edit ._odd-row.data-grid-editable-row:hover td{background-color:#fff}.data-grid._in-edit ._odd-row td,.data-grid._in-edit ._odd-row:hover td{background-color:#dcdcdc}.data-grid._in-edit .data-grid-editable-row-actions td,.data-grid._in-edit .data-grid-editable-row-actions:hover td{background-color:#fff}.data-grid._in-edit td{background-color:#e6e6e6;pointer-events:none}.data-grid._in-edit .data-grid-checkbox-cell{pointer-events:auto}.data-grid._in-edit .data-grid-editable-row{border:.1rem solid #adadad;border-bottom-color:#c2c2c2}.data-grid._in-edit .data-grid-editable-row:hover td{background-color:#fff}.data-grid._in-edit .data-grid-editable-row td{background-color:#fff;border-bottom-color:#fff;border-left-style:hidden;border-right-style:hidden;border-top-color:#fff;pointer-events:auto;vertical-align:middle}.data-grid._in-edit .data-grid-editable-row td:first-child{border-left-color:#adadad;border-left-style:solid}.data-grid._in-edit .data-grid-editable-row td:first-child:after,.data-grid._in-edit .data-grid-editable-row td:first-child:before{left:0}.data-grid._in-edit .data-grid-editable-row td:last-child{border-right-color:#adadad;border-right-style:solid;left:-.1rem}.data-grid._in-edit .data-grid-editable-row td:last-child:after,.data-grid._in-edit .data-grid-editable-row td:last-child:before{right:0}.data-grid._in-edit .data-grid-editable-row .admin__control-select,.data-grid._in-edit .data-grid-editable-row .admin__control-text{width:100%}.data-grid._in-edit .data-grid-bulk-edit-panel td{vertical-align:bottom}.data-grid .data-grid-editable-row td{border-left-color:#fff;border-left-style:solid;position:relative;z-index:1}.data-grid .data-grid-editable-row td:after{bottom:0;box-shadow:0 5px 5px rgba(0,0,0,.25);content:'';height:.9rem;left:0;margin-top:-1rem;position:absolute;right:0}.data-grid .data-grid-editable-row td:before{background-color:#fff;bottom:0;content:'';height:1rem;left:-10px;position:absolute;right:-10px;z-index:1}.data-grid .data-grid-editable-row.data-grid-editable-row-actions td,.data-grid .data-grid-editable-row.data-grid-editable-row-actions:hover td{background-color:#fff}.data-grid .data-grid-editable-row.data-grid-editable-row-actions td:first-child{border-left-color:#fff;border-right-color:#fff}.data-grid .data-grid-editable-row.data-grid-editable-row-actions td:last-child{left:0}.data-grid .data-grid-editable-row.data-grid-bulk-edit-panel td,.data-grid .data-grid-editable-row.data-grid-bulk-edit-panel td:before,.data-grid .data-grid-editable-row.data-grid-bulk-edit-panel:hover td{background-color:#fffbe6}.data-grid .data-grid-editable-row-actions{left:50%;margin-left:-12.5rem;margin-top:-2px;position:absolute;text-align:center}.data-grid .data-grid-editable-row-actions td{width:25rem}.data-grid .data-grid-editable-row-actions [class*=action-]{min-width:9rem}.data-grid .data-grid-draggable-row-cell{width:1%}.data-grid .data-grid-draggable-row-cell .draggable-handle{padding:0}.data-grid-th._sortable._ascend,.data-grid-th._sortable._descend{padding-right:2.7rem}.data-grid-th._sortable._ascend:before,.data-grid-th._sortable._descend:before{margin-top:-1em;position:absolute;right:1rem;top:50%}.data-grid-th._sortable._ascend:before{content:'\2193'}.data-grid-th._sortable._descend:before{content:'\2191'}.data-grid-checkbox-cell-inner{display:block;padding:1.1rem 1.8rem .9rem;text-align:right}.data-grid-checkbox-cell-inner:hover{cursor:pointer}.data-grid-state-cell-inner{display:block;padding:1.1rem 1.8rem .9rem;text-align:center}.data-grid-state-cell-inner>span{display:inline-block;font-style:italic;padding:.6rem 0}.data-grid-row-parent._active>td .data-grid-checkbox-cell-inner:before{content:'\e62b'}.data-grid-row-parent>td .data-grid-checkbox-cell-inner{padding-left:3.7rem;position:relative}.data-grid-row-parent>td .data-grid-checkbox-cell-inner:before{content:'\e628';font-size:1rem;font-weight:700;left:1.35rem;position:absolute;top:1.6rem}.data-grid-th._col-xs{width:1%}.data-grid-info-panel{box-shadow:0 0 5px rgba(0,0,0,.5);margin:2rem .1rem -2rem}.data-grid-info-panel .messages{overflow:hidden}.data-grid-info-panel .messages .message{margin:1rem}.data-grid-info-panel .messages .message:last-child{margin-bottom:1rem}.data-grid-info-panel-actions{padding:1rem;text-align:right}.data-grid-editable-row .admin__field-control{position:relative}.data-grid-editable-row .admin__field-control._error:after{border-color:transparent #ee7d7d transparent transparent;border-style:solid;border-width:0 12px 12px 0;content:'';position:absolute;right:0;top:0}.data-grid-editable-row .admin__field-control._error .admin__control-text{border-color:#ee7d7d}.data-grid-editable-row .admin__field-control._focus:after{display:none}.data-grid-editable-row .admin__field-error{bottom:100%;box-shadow:1px 1px 5px rgba(0,0,0,.5);left:0;margin:0 auto 1.5rem;max-width:32rem;position:absolute;right:0}.data-grid-editable-row .admin__field-error:after,.data-grid-editable-row .admin__field-error:before{border-style:solid;content:'';left:50%;position:absolute;top:100%}.data-grid-editable-row .admin__field-error:after{border-color:#fffbbb transparent transparent;border-width:10px 10px 0;margin-left:-10px;z-index:1}.data-grid-editable-row .admin__field-error:before{border-color:#ee7d7d transparent transparent;border-width:11px 12px 0;margin-left:-12px}.data-grid-bulk-edit-panel .admin__field-label-vertical{display:block;font-size:1.2rem;margin-bottom:.5rem;text-align:left}.data-grid-row-changed{cursor:default;display:block;opacity:.5;position:relative;width:100%;z-index:1}.data-grid-row-changed:after{content:'\e631';display:inline-block}.data-grid-row-changed .data-grid-row-changed-tooltip{background:#f1f1f1;border:1px solid #f1f1f1;border-radius:1px;bottom:100%;box-shadow:0 3px 9px 0 rgba(0,0,0,.3);display:none;font-weight:400;line-height:1.36;margin-bottom:1.5rem;padding:1rem;position:absolute;right:-1rem;text-transform:none;width:27rem;word-break:normal;z-index:2}.data-grid-row-changed._changed{opacity:1;z-index:3}.data-grid-row-changed._changed:hover .data-grid-row-changed-tooltip{display:block}.data-grid-row-changed._changed:hover:before{background:#f1f1f1;border:1px solid #f1f1f1;bottom:100%;box-shadow:4px 4px 3px -1px rgba(0,0,0,.15);content:'';display:block;height:1.6rem;left:50%;margin:0 0 .7rem -.8rem;position:absolute;-ms-transform:rotate(45deg);transform:rotate(45deg);width:1.6rem;z-index:3}.ie9 .data-grid-row-changed._changed:hover:before{display:none}.admin__data-grid-outer-wrap .data-grid-checkbox-cell{overflow:hidden}.admin__data-grid-outer-wrap .data-grid-checkbox-cell-inner{position:relative}.admin__data-grid-outer-wrap .data-grid-checkbox-cell-inner:before{bottom:0;content:'';height:500%;left:0;position:absolute;right:0;top:0}.admin__data-grid-wrap-static .data-grid-checkbox-cell:hover{cursor:pointer}.admin__data-grid-wrap-static .data-grid-checkbox-cell-inner{margin:1.1rem 1.8rem .9rem;padding:0}.adminhtml-cms-hierarchy-index .admin__data-grid-wrap-static .data-grid-actions-cell:first-child{padding:0}.adminhtml-export-index .admin__data-grid-wrap-static .data-grid-checkbox-cell-inner{margin:0;padding:1.1rem 1.8rem 1.9rem}.admin__control-addon [class*=admin__control-][class]~[class*=admin__addon-]:last-child:before,.admin__control-file-label:before,.admin__control-multiselect,.admin__control-select,.admin__control-text,.admin__control-textarea,.selectmenu{-webkit-appearance:none;background-color:#fff;border:1px solid #adadad;border-radius:1px;box-shadow:none;color:#303030;font-size:1.4rem;font-weight:400;height:auto;line-height:1.36;padding:.6rem 1rem;transition:border-color .1s linear;vertical-align:baseline;width:auto}.admin__control-addon [class*=admin__control-][class]:hover~[class*=admin__addon-]:last-child:before,.admin__control-multiselect:hover,.admin__control-select:hover,.admin__control-text:hover,.admin__control-textarea:hover,.selectmenu:hover,.selectmenu:hover .selectmenu-toggle:before{border-color:#878787}.admin__control-addon [class*=admin__control-][class]:focus~[class*=admin__addon-]:last-child:before,.admin__control-file:active+.admin__control-file-label:before,.admin__control-file:focus+.admin__control-file-label:before,.admin__control-multiselect:focus,.admin__control-select:focus,.admin__control-text:focus,.admin__control-textarea:focus,.selectmenu._focus,.selectmenu._focus .selectmenu-toggle:before{border-color:#007bdb;box-shadow:none;outline:0}.admin__control-addon [class*=admin__control-][class][disabled]~[class*=admin__addon-]:last-child:before,.admin__control-file[disabled]+.admin__control-file-label:before,.admin__control-multiselect[disabled],.admin__control-select[disabled],.admin__control-text[disabled],.admin__control-textarea[disabled]{background-color:#e9e9e9;border-color:#adadad;color:#303030;cursor:not-allowed;opacity:.5}.admin__field-row[class]>.admin__field-control,.admin__fieldset>.admin__field.admin__field-wide[class]>.admin__field-control{clear:left;float:none;text-align:left;width:auto}.admin__field-row[class]:not(.admin__field-option)>.admin__field-label,.admin__fieldset>.admin__field.admin__field-wide[class]:not(.admin__field-option)>.admin__field-label{display:block;line-height:1.4rem;margin-bottom:.86rem;margin-top:-.14rem;text-align:left;width:auto}.admin__field-row[class]:not(.admin__field-option)>.admin__field-label:before,.admin__fieldset>.admin__field.admin__field-wide[class]:not(.admin__field-option)>.admin__field-label:before{display:none}.admin__field-row[class]:not(.admin__field-option)._required>.admin__field-label span,.admin__field-row[class]:not(.admin__field-option).required>.admin__field-label span,.admin__fieldset>.admin__field.admin__field-wide[class]:not(.admin__field-option)._required>.admin__field-label span,.admin__fieldset>.admin__field.admin__field-wide[class]:not(.admin__field-option).required>.admin__field-label span{padding-left:1.5rem}.admin__field-row[class]:not(.admin__field-option)._required>.admin__field-label span:after,.admin__field-row[class]:not(.admin__field-option).required>.admin__field-label span:after,.admin__fieldset>.admin__field.admin__field-wide[class]:not(.admin__field-option)._required>.admin__field-label span:after,.admin__fieldset>.admin__field.admin__field-wide[class]:not(.admin__field-option).required>.admin__field-label span:after{left:0;margin-left:30px}.admin__legend{font-size:1.8rem;font-weight:600;margin-bottom:3rem}.admin__control-checkbox,.admin__control-radio{cursor:pointer;opacity:.01;overflow:hidden;position:absolute;vertical-align:top}.admin__control-checkbox:after,.admin__control-radio:after{display:none}.admin__control-checkbox+label,.admin__control-radio+label{cursor:pointer;display:inline-block}.admin__control-checkbox+label:before,.admin__control-radio+label:before{background-color:#fff;border:1px solid #adadad;color:transparent;float:left;height:1.6rem;text-align:center;vertical-align:top;width:1.6rem}.admin__control-checkbox+.admin__field-label,.admin__control-radio+.admin__field-label{padding-left:2.6rem}.admin__control-checkbox+.admin__field-label:before,.admin__control-radio+.admin__field-label:before{margin:1px 1rem 0 -2.6rem}.admin__control-checkbox:checked+label:before,.admin__control-radio:checked+label:before{color:#514943}.admin__control-checkbox.disabled+label,.admin__control-checkbox[disabled]+label,.admin__control-radio.disabled+label,.admin__control-radio[disabled]+label{color:#303030;cursor:default;opacity:.5}.admin__control-checkbox.disabled+label:before,.admin__control-checkbox[disabled]+label:before,.admin__control-radio.disabled+label:before,.admin__control-radio[disabled]+label:before{background-color:#e9e9e9;border-color:#adadad;cursor:default}._keyfocus .admin__control-checkbox:not(.disabled):focus+label:before,._keyfocus .admin__control-checkbox:not([disabled]):focus+label:before,._keyfocus .admin__control-radio:not(.disabled):focus+label:before,._keyfocus .admin__control-radio:not([disabled]):focus+label:before{border-color:#007bdb}.admin__control-checkbox:not(.disabled):hover+label:before,.admin__control-checkbox:not([disabled]):hover+label:before,.admin__control-radio:not(.disabled):hover+label:before,.admin__control-radio:not([disabled]):hover+label:before{border-color:#878787}.admin__control-radio+label:before{border-radius:1.6rem;content:'';transition:border-color .1s linear,color .1s ease-in}.admin__control-radio.admin__control-radio+label:before{line-height:140%}.admin__control-radio:checked+label{position:relative}.admin__control-radio:checked+label:after{background-color:#514943;border-radius:50%;content:'';height:10px;left:3px;position:absolute;top:4px;width:10px}.admin__control-radio:checked:not(.disabled):hover,.admin__control-radio:checked:not(.disabled):hover+label,.admin__control-radio:checked:not([disabled]):hover,.admin__control-radio:checked:not([disabled]):hover+label{cursor:default}.admin__control-radio:checked:not(.disabled):hover+label:before,.admin__control-radio:checked:not([disabled]):hover+label:before{border-color:#adadad}.admin__control-checkbox+label:before{border-radius:1px;content:'';font-size:0;transition:font-size .1s ease-out,color .1s ease-out,border-color .1s linear}.admin__control-checkbox:checked+label:before{content:'\e62d';font-size:1.1rem;line-height:125%}.admin__control-checkbox:not(:checked)._indeterminate+label:before,.admin__control-checkbox:not(:checked):indeterminate+label:before{color:#514943;content:'-';font-family:'Open Sans','Helvetica Neue',Helvetica,Arial,sans-serif;font-size:1.4rem;font-weight:700}input[type=checkbox].admin__control-checkbox,input[type=radio].admin__control-checkbox{margin:0;position:absolute}.admin__control-text{min-width:4rem}.admin__control-select{-webkit-appearance:none;-moz-appearance:none;-ms-appearance:none;appearance:none;background-image:url(../images/arrows-bg.svg),linear-gradient(#e3e3e3,#e3e3e3),linear-gradient(#adadad,#adadad);background-position:calc(100% - 12px) -34px,100%,calc(100% - 3.2rem) 0;background-size:auto,3.2rem 100%,1px 100%;background-repeat:no-repeat;max-width:100%;min-width:8.5rem;padding-bottom:.5rem;padding-right:4.4rem;padding-top:.5rem;transition:border-color .1s linear}.admin__control-select:hover{border-color:#878787;cursor:pointer}.admin__control-select:focus{background-image:url(../images/arrows-bg.svg),linear-gradient(#e3e3e3,#e3e3e3),linear-gradient(#007bdb,#007bdb);background-position:calc(100% - 12px) 13px,100%,calc(100% - 3.2rem) 0;border-color:#007bdb}.admin__control-select::-ms-expand{display:none}.ie9 .admin__control-select{background-image:none;padding-right:1rem}option:empty{display:none}.admin__control-multiselect{height:auto;max-width:100%;min-width:15rem;overflow:auto;padding:0;resize:both}.admin__control-multiselect optgroup,.admin__control-multiselect option{padding:.5rem 1rem}.admin__control-file-wrapper{display:inline-block;padding:.5rem 1rem;position:relative;z-index:1}.admin__control-file-label:before{content:'';left:0;position:absolute;top:0;width:100%;z-index:0}.admin__control-file{background:0 0;border:0;padding-top:.7rem;position:relative;width:auto;z-index:1}.admin__control-support-text{border:1px solid transparent;display:inline-block;font-size:1.4rem;line-height:1.36;padding-bottom:.6rem;padding-top:.6rem}.admin__control-support-text+[class*=admin__control-],[class*=admin__control-]+.admin__control-support-text{margin-left:.7rem}.admin__control-service{float:left;margin:.8rem 0 0 3rem}.admin__control-textarea{height:8.48rem;line-height:1.18;padding-top:.8rem;resize:vertical}.admin__control-addon{-ms-flex-direction:row;flex-direction:row;display:inline-flex;-ms-flex-flow:row nowrap;flex-flow:row nowrap;position:relative;width:100%;z-index:1}.admin__control-addon>[class*=admin__addon-],.admin__control-addon>[class*=admin__control-]{-ms-flex-preferred-size:auto;flex-basis:auto;-webkit-flex-grow:0;-ms-flex-positive:0;flex-grow:0;-ms-flex-negative:0;flex-shrink:0;position:relative;z-index:1}.admin__control-addon .admin__control-select{width:auto}.admin__control-addon .admin__control-text{margin:.1rem;padding:.5rem .9rem;width:100%}.admin__control-addon [class*=admin__control-][class]{appearence:none;-webkit-flex-grow:1;-ms-flex-positive:1;flex-grow:1;-ms-flex-order:1;order:1;-ms-flex-negative:1;flex-shrink:1;background-color:transparent;border-color:transparent;box-shadow:none;vertical-align:top}.admin__control-addon [class*=admin__control-][class]+[class*=admin__control-]{border-left-color:#adadad}.admin__control-addon [class*=admin__control-][class] :focus{box-shadow:0}.admin__control-addon [class*=admin__control-][class]~[class*=admin__addon-]:last-child{padding-left:1rem;position:static!important;z-index:0}.admin__control-addon [class*=admin__control-][class]~[class*=admin__addon-]:last-child>*{position:relative;vertical-align:top;z-index:1}.admin__control-addon [class*=admin__control-][class]~[class*=admin__addon-]:last-child:empty{padding:0}.admin__control-addon [class*=admin__control-][class]~[class*=admin__addon-]:last-child:before{bottom:0;box-sizing:border-box;content:'';left:0;position:absolute;top:0;width:100%;z-index:-1}.admin__addon-prefix,.admin__addon-suffix{border:0;box-sizing:border-box;color:#858585;display:inline-block;font-size:1.4rem;font-weight:400;height:3.2rem;line-height:3.2rem;padding:0}.admin__addon-suffix{-ms-flex-order:3;order:3}.admin__addon-suffix:last-child{padding-right:1rem}.admin__addon-prefix{-ms-flex-order:0;order:0}.ie9 .admin__control-addon:after{clear:both;content:'';display:block;height:0;overflow:hidden}.ie9 .admin__addon{min-width:0;overflow:hidden;text-align:right;white-space:nowrap;width:auto}.ie9 .admin__addon [class*=admin__control-]{display:inline}.ie9 .admin__addon-prefix{float:left}.ie9 .admin__addon-suffix{float:right}.admin__control-collapsible{width:100%}.admin__control-collapsible ._dragged .admin__collapsible-block-wrapper .admin__collapsible-title{background:#d0d0d0}.admin__control-collapsible ._dragover-bottom .admin__collapsible-block-wrapper:before,.admin__control-collapsible ._dragover-top .admin__collapsible-block-wrapper:before{background:#008bdb;content:'';display:block;height:3px;left:0;position:absolute;right:0}.admin__control-collapsible ._dragover-top .admin__collapsible-block-wrapper:before{top:-3px}.admin__control-collapsible ._dragover-bottom .admin__collapsible-block-wrapper:before{bottom:-3px}.admin__control-collapsible .admin__collapsible-block-wrapper.fieldset-wrapper{border:0;margin:0;position:relative}.admin__control-collapsible .admin__collapsible-block-wrapper.fieldset-wrapper .fieldset-wrapper-title{background:#f8f8f8;border:2px solid #ccc}.admin__control-collapsible .admin__collapsible-block-wrapper .fieldset-wrapper-title .admin__collapsible-title{font-size:1.4rem;font-weight:400;line-height:1;padding:1.6rem 4rem 1.6rem 3.8rem}.admin__control-collapsible .admin__collapsible-block-wrapper .fieldset-wrapper-title .admin__collapsible-title:before{left:1rem;right:auto;top:1.4rem}.admin__control-collapsible .admin__collapsible-block-wrapper .fieldset-wrapper-title .action-delete{background-color:transparent;border-color:transparent;box-shadow:none;padding:0;position:absolute;right:1rem;top:1.4rem}.admin__control-collapsible .admin__collapsible-block-wrapper .fieldset-wrapper-title .action-delete:hover{background-color:transparent;border-color:transparent;box-shadow:none}.admin__control-collapsible .admin__collapsible-block-wrapper .fieldset-wrapper-title .action-delete:before{content:'\e630';font-size:2rem}.admin__control-collapsible .admin__collapsible-block-wrapper .fieldset-wrapper-title .action-delete>span{display:none}.admin__control-collapsible .admin__collapsible-content{background-color:#fff;margin-bottom:1rem}.admin__control-collapsible .admin__collapsible-content>.fieldset-wrapper{border:1px solid #ccc;margin-top:-1px;padding:1rem}.admin__control-collapsible .admin__collapsible-content .admin__fieldset{padding:0}.admin__control-collapsible .admin__collapsible-content .admin__field:last-child{margin-bottom:0}.admin__control-table-wrapper{max-width:100%;overflow-x:auto;overflow-y:hidden}.admin__control-table{width:100%}.admin__control-table thead{background-color:transparent}.admin__control-table tbody td{vertical-align:top}.admin__control-table tfoot th{padding-bottom:1.3rem}.admin__control-table tfoot th.validation{padding-bottom:0;padding-top:0}.admin__control-table tfoot td{border-top:1px solid #fff}.admin__control-table tfoot .admin__control-table-pagination{float:right;padding-bottom:0}.admin__control-table tfoot .action-previous{margin-right:.5rem}.admin__control-table tfoot .action-next{margin-left:.9rem}.admin__control-table tr:last-child td{border-bottom:none}.admin__control-table tr._dragover-top td{box-shadow:inset 0 3px 0 0 #008bdb}.admin__control-table tr._dragover-bottom td{box-shadow:inset 0 -3px 0 0 #008bdb}.admin__control-table tr._dragged td,.admin__control-table tr._dragged th{background:#d0d0d0}.admin__control-table td,.admin__control-table th{background-color:#efefef;border:0;border-bottom:1px solid #fff;padding:1.3rem 1rem 1.3rem 0;text-align:left;vertical-align:top}.admin__control-table td:first-child,.admin__control-table th:first-child{padding-left:1rem}.admin__control-table td>.admin__control-select,.admin__control-table td>.admin__control-text,.admin__control-table th>.admin__control-select,.admin__control-table th>.admin__control-text{width:100%}.admin__control-table td._hidden,.admin__control-table th._hidden{display:none}.admin__control-table td._fit,.admin__control-table th._fit{width:1px}.admin__control-table th{color:#303030;font-size:1.4rem;font-weight:600;vertical-align:bottom}.admin__control-table th._required span:after{color:#eb5202;content:'*'}.admin__control-table .control-table-actions-th{white-space:nowrap}.admin__control-table .control-table-actions-cell{padding-top:1.8rem;text-align:center;width:1%}.admin__control-table .control-table-options-th{text-align:center;width:10rem}.admin__control-table .control-table-options-cell{text-align:center}.admin__control-table .control-table-text{line-height:3.2rem}.admin__control-table .col-draggable{padding-top:2.2rem;width:1%}.admin__control-table .action-delete{background-color:transparent;border-color:transparent;box-shadow:none;padding-left:0;padding-right:0}.admin__control-table .action-delete:hover{background-color:transparent;border-color:transparent;box-shadow:none}.admin__control-table .action-delete:before{content:'\e630';font-size:2rem}.admin__control-table .action-delete>span{display:none}.admin__control-table .draggable-handle{padding:0}.admin__control-table._dragged{outline:#007bdb solid 1px}.admin__control-table-action{background-color:#efefef;border-top:1px solid #fff;padding:1.3rem 1rem}.admin__dynamic-rows._dragged{opacity:.95;position:absolute;z-index:999}.admin__dynamic-rows.admin__control-table .admin__control-fields>.admin__field{border:0;padding:0}.admin__dynamic-rows td>.admin__field{border:0;margin:0;padding:0}.admin__control-table-pagination{padding-bottom:1rem}.admin__control-table-pagination .admin__data-grid-pager{float:right}.admin__field-tooltip{display:inline-block;margin-top:.5rem;max-width:45px;overflow:visible;vertical-align:top;width:0}.admin__field-tooltip:hover{position:relative;z-index:500}.admin__field-option .admin__field-tooltip{margin-top:.5rem}.admin__field-tooltip .admin__field-tooltip-action{margin-left:2rem;position:relative;z-index:2;display:inline-block;text-decoration:none}.admin__field-tooltip .admin__field-tooltip-action:before{-webkit-font-smoothing:antialiased;font-size:2.2rem;line-height:1;color:#514943;content:'\e633';font-family:Icons;vertical-align:middle;display:inline-block;font-weight:400;overflow:hidden;speak:none;text-align:center}.admin__field-tooltip .admin__control-text:focus+.admin__field-tooltip-content,.admin__field-tooltip:hover .admin__field-tooltip-content{display:block}.admin__field-tooltip .admin__field-tooltip-content{bottom:3.8rem;display:none;right:-2.3rem}.admin__field-tooltip .admin__field-tooltip-content:after,.admin__field-tooltip .admin__field-tooltip-content:before{border:1.6rem solid transparent;height:0;width:0;border-top-color:#afadac;content:'';display:block;position:absolute;right:2rem;top:100%;z-index:3}.admin__field-tooltip .admin__field-tooltip-content:after{border-top-color:#fffbbb;margin-top:-1px;z-index:4}.abs-admin__field-tooltip-content,.admin__field-tooltip .admin__field-tooltip-content{box-shadow:0 2px 8px 0 rgba(0,0,0,.3);background:#fffbbb;border:1px solid #afadac;border-radius:1px;padding:1.5rem 2.5rem;position:absolute;width:32rem;z-index:1}.admin__field-fallback-reset{font-size:1.25rem;white-space:nowrap;width:30px}.admin__field-fallback-reset>span{margin-left:.5rem;position:relative}.admin__field-fallback-reset:active{-ms-transform:scale(0.98);transform:scale(0.98)}.admin__field-fallback-reset:before{transition:color .1s linear;content:'\e642';font-size:1.3rem;margin-left:.5rem}.admin__field-fallback-reset:hover{cursor:pointer;text-decoration:none}.admin__field-fallback-reset:focus{background:0 0}.abs-field-size-x-small,.abs-field-sizes.admin__field-x-small>.admin__field-control,.admin__field.admin__field-x-small>.admin__field-control,.admin__fieldset>.admin__field.admin__field-x-small>.admin__field-control,[class*=admin__control-grouped]>.admin__field.admin__field-x-small>.admin__field-control{width:8rem}.abs-field-size-small,.abs-field-sizes.admin__field-small>.admin__field-control,.admin__control-grouped-date>.admin__field-date.admin__field>.admin__field-control,.admin__field.admin__field-small>.admin__field-control,.admin__fieldset>.admin__field.admin__field-small>.admin__field-control,[class*=admin__control-grouped]>.admin__field.admin__field-small>.admin__field-control{width:15rem}.abs-field-size-medium,.abs-field-sizes.admin__field-medium>.admin__field-control,.admin__field.admin__field-medium>.admin__field-control,.admin__fieldset>.admin__field.admin__field-medium>.admin__field-control,[class*=admin__control-grouped]>.admin__field.admin__field-medium>.admin__field-control{width:34rem}.abs-field-size-large,.abs-field-sizes.admin__field-large>.admin__field-control,.admin__field.admin__field-large>.admin__field-control,.admin__fieldset>.admin__field.admin__field-large>.admin__field-control,[class*=admin__control-grouped]>.admin__field.admin__field-large>.admin__field-control{width:64rem}.abs-field-no-label,.admin__field-group-additional,.admin__field-no-label,.admin__fieldset>.admin__field.admin__field-no-label>.admin__field-control{margin-left:calc((100%) * .25 + 30px)}.admin__fieldset{border:0;margin:0;min-width:0;padding:0}.admin__fieldset .fieldset-wrapper.admin__fieldset-section>.fieldset-wrapper-title{padding-left:1rem}.admin__fieldset .fieldset-wrapper.admin__fieldset-section>.fieldset-wrapper-title strong{font-size:1.7rem;font-weight:600}.admin__fieldset .fieldset-wrapper.admin__fieldset-section .admin__fieldset-wrapper-content>.admin__fieldset{padding-top:1rem}.admin__fieldset .fieldset-wrapper.admin__fieldset-section:last-child .admin__fieldset-wrapper-content>.admin__fieldset{padding-bottom:0}.admin__fieldset>.admin__field{border:0;margin:0 0 0 -30px;padding:0}.admin__fieldset>.admin__field:after{clear:both;content:'';display:table}.admin__fieldset>.admin__field>.admin__field-control{width:calc((100%) * .5 - 30px);float:left;margin-left:30px}.admin__fieldset>.admin__field>.admin__field-label{width:calc((100%) * .25 - 30px);float:left;margin-left:30px}.admin__fieldset>.admin__field.admin__field-no-label>.admin__field-label{display:none}.admin__fieldset>.admin__field+.admin__field._empty._no-header{margin-top:-3rem}.admin__fieldset-product-websites{position:relative;z-index:300}.admin__fieldset-note{margin-bottom:2rem}.admin__form-field{border:0;margin:0;padding:0}.admin__field-control .admin__control-text,.admin__field-control .admin__control-textarea,.admin__form-field-control .admin__control-text,.admin__form-field-control .admin__control-textarea{width:100%}.admin__field-label{color:#303030;cursor:pointer;margin:0;text-align:right}.admin__field-label+br{display:none}.admin__field:not(.admin__field-option)>.admin__field-label{font-family:'Open Sans','Helvetica Neue',Helvetica,Arial,sans-serif;font-size:1.4rem;font-weight:600;line-height:3.2rem;padding:0;white-space:nowrap}.admin__field:not(.admin__field-option)>.admin__field-label:before{opacity:0;visibility:hidden;content:'.';margin-left:-7px;overflow:hidden}.admin__field:not(.admin__field-option)>.admin__field-label span{display:inline-block;line-height:1.2;vertical-align:middle;white-space:normal}.admin__field:not(.admin__field-option)>.admin__field-label span[data-config-scope]{position:relative}._required>.admin__field-label>span:after,.required>.admin__field-label>span:after{color:#eb5202;content:'*';display:inline-block;font-size:1.6rem;font-weight:500;line-height:1;margin-left:10px;margin-top:.2rem;position:absolute;z-index:1}._disabled>.admin__field-label{color:#999;cursor:default}.admin__field{margin-bottom:0}.admin__field+.admin__field{margin-top:1.5rem}.admin__field:not(.admin__field-option)~.admin__field-option{margin-top:.5rem}.admin__field.admin__field-option~.admin__field-option{margin-top:.9rem}.admin__field~.admin__field-option:last-child{margin-bottom:.8rem}.admin__fieldset>.admin__field{margin-bottom:3rem;position:relative}.admin__field legend.admin__field-label{opacity:0}.admin__field[data-config-scope]:before{color:gray;content:attr(data-config-scope);display:inline-block;font-size:1.2rem;left:calc((100%) * .75 - 30px);line-height:3.2rem;margin-left:60px;position:absolute;width:calc((100%) * .25 - 30px)}.admin__field-control .admin__field[data-config-scope]:nth-child(n+2):before{content:''}.admin__field._error .admin__field-control [class*=admin__addon-]:before,.admin__field._error .admin__field-control [class*=admin__control-] [class*=admin__addon-]:before,.admin__field._error .admin__field-control>[class*=admin__control-]{border-color:#e22626}.admin__field._disabled,.admin__field._disabled:hover{box-shadow:inherit;cursor:inherit;opacity:1;outline:inherit}.admin__field._hidden{display:none}.admin__field-control+.admin__field-control{margin-top:1.5rem}.admin__field-control._with-tooltip>.admin__control-addon,.admin__field-control._with-tooltip>.admin__control-select,.admin__field-control._with-tooltip>.admin__control-text,.admin__field-control._with-tooltip>.admin__control-textarea,.admin__field-control._with-tooltip>.admin__field-option{max-width:calc(100% - 45px - 4px)}.admin__field-control._with-tooltip .admin__field-tooltip{width:auto}.admin__field-control._with-tooltip .admin__field-option{display:inline-block}.admin__field-control._with-reset>.admin__control-addon,.admin__field-control._with-reset>.admin__control-text,.admin__field-control._with-reset>.admin__control-textarea{width:calc(100% - 30px - .5rem - 4px)}.admin__field-control._with-reset .admin__field-fallback-reset{margin-left:.5rem;margin-top:1rem;vertical-align:top}.admin__field-control._with-reset._with-tooltip>.admin__control-addon,.admin__field-control._with-reset._with-tooltip>.admin__control-text,.admin__field-control._with-reset._with-tooltip>.admin__control-textarea{width:calc(100% - 30px - .5rem - 45px - 8px)}.admin__fieldset>.admin__field-collapsible{margin-bottom:0}.admin__fieldset>.admin__field-collapsible .admin__field-control{border-top:1px solid #ccc;display:block;font-size:1.7rem;font-weight:700;padding:1.7rem 0;width:calc(97%)}.admin__fieldset>.admin__field-collapsible .admin__field-option{padding-top:0}.admin__field-collapsible+div{margin-top:2.5rem}.admin__field-collapsible .admin__control-radio+label:before{height:1.8rem;width:1.8rem}.admin__field-collapsible .admin__control-radio:checked+label:after{left:4px;top:5px}.admin__field-error{background:#fffbbb;border:1px solid #ee7d7d;box-sizing:border-box;color:#555;display:block;font-size:1.2rem;font-weight:400;line-height:1.2;margin:.2rem 0 0;padding:.8rem 1rem .9rem}.admin__field-note{color:#303030;font-size:1.2rem;margin:10px 0 0;padding:0}.admin__additional-info{padding-top:1rem}.admin__field-option{padding-top:.7rem}.admin__field-option .admin__field-label{text-align:left}.admin__field-control>.admin__field-option:nth-child(1):nth-last-child(2),.admin__field-control>.admin__field-option:nth-child(2):nth-last-child(1){display:inline-block}.admin__field-control>.admin__field-option:nth-child(1):nth-last-child(2)+.admin__field-option,.admin__field-control>.admin__field-option:nth-child(2):nth-last-child(1)+.admin__field-option{display:inline-block;margin-left:41px;margin-top:0}.admin__field-control>.admin__field-option:nth-child(1):nth-last-child(2)+.admin__field-option:before,.admin__field-control>.admin__field-option:nth-child(2):nth-last-child(1)+.admin__field-option:before{background:#cacaca;content:'';display:inline-block;height:20px;margin-left:-20px;position:absolute;width:1px}.admin__field-value{display:inline-block;padding-top:.7rem}.admin__field-service{padding-top:1rem}.admin__control-fields>.admin__field:first-child,[class*=admin__control-grouped]>.admin__field:first-child{position:static}.admin__control-fields>.admin__field:first-child>.admin__field-label,[class*=admin__control-grouped]>.admin__field:first-child>.admin__field-label{width:calc((100%) * .25 - 30px);float:left;margin-left:30px;background:#fff;cursor:pointer;left:0;position:absolute;top:0}.admin__control-fields>.admin__field:first-child>.admin__field-label span:before,[class*=admin__control-grouped]>.admin__field:first-child>.admin__field-label span:before{display:block}.admin__control-fields>.admin__field._disabled>.admin__field-label,[class*=admin__control-grouped]>.admin__field._disabled>.admin__field-label{cursor:default}.admin__control-fields>.admin__field>.admin__field-label span:before,[class*=admin__control-grouped]>.admin__field>.admin__field-label span:before{display:none}.admin__control-fields .admin__field-label~.admin__field-control{width:100%}.admin__control-fields .admin__field-option{padding-top:0}[class*=admin__control-grouped]{box-sizing:border-box;display:table;width:100%}[class*=admin__control-grouped]>.admin__field{display:table-cell;vertical-align:top}[class*=admin__control-grouped]>.admin__field>.admin__field-control{float:none;width:100%}[class*=admin__control-grouped]>.admin__field.admin__field-default,[class*=admin__control-grouped]>.admin__field.admin__field-large,[class*=admin__control-grouped]>.admin__field.admin__field-medium,[class*=admin__control-grouped]>.admin__field.admin__field-small,[class*=admin__control-grouped]>.admin__field.admin__field-x-small{width:1px}[class*=admin__control-grouped]>.admin__field.admin__field-default+.admin__field:last-child,[class*=admin__control-grouped]>.admin__field.admin__field-large+.admin__field:last-child,[class*=admin__control-grouped]>.admin__field.admin__field-medium+.admin__field:last-child,[class*=admin__control-grouped]>.admin__field.admin__field-small+.admin__field:last-child,[class*=admin__control-grouped]>.admin__field.admin__field-x-small+.admin__field:last-child{width:auto}[class*=admin__control-grouped]>.admin__field:nth-child(n+2){padding-left:20px}.admin__control-group-equal{table-layout:fixed}.admin__control-group-equal>.admin__field{width:50%}.admin__field-control-group{margin-top:.8rem}.admin__field-control-group>.admin__field{padding:0}.admin__control-grouped-date>.admin__field-date{white-space:nowrap;width:1px}.admin__control-grouped-date>.admin__field-date.admin__field>.admin__field-control{float:left;position:relative}.admin__control-grouped-date>.admin__field-date+.admin__field:last-child{width:auto}.admin__control-grouped-date>.admin__field-date+.admin__field-date>.admin__field-label{float:left;padding-right:20px}.admin__control-grouped-date .ui-datepicker-trigger{left:100%;top:0}.admin__field-group-columns.admin__field-control.admin__control-grouped{width:calc((100%) * 1 - 30px);float:left;margin-left:30px}.admin__field-group-columns>.admin__field:first-child>.admin__field-label{float:none;margin:0;opacity:1;position:static;text-align:left}.admin__field-group-columns .admin__control-select{width:100%}.admin__field-group-additional{clear:both}.admin__field-group-additional .action-advanced{margin-top:1rem}.admin__field-group-additional .action-secondary{width:100%}.admin__field-group-show-label{white-space:nowrap}.admin__field-group-show-label>.admin__field-control,.admin__field-group-show-label>.admin__field-label{display:inline-block;vertical-align:top}.admin__field-group-show-label>.admin__field-label{margin-right:20px}.admin__field-complex{margin:1rem 0 3rem;padding-left:1rem}.admin__field:not(._hidden)+.admin__field-complex{margin-top:3rem}.admin__field-complex .admin__field-complex-title{clear:both;color:#303030;font-size:1.7rem;font-weight:600;letter-spacing:.025em;margin-bottom:1rem}.admin__field-complex .admin__field-complex-elements{float:right;max-width:40%}.admin__field-complex .admin__field-complex-elements button{margin-left:1rem}.admin__field-complex .admin__field-complex-content{max-width:60%;overflow:hidden}.admin__field-complex .admin__field-complex-text{margin-left:-1rem}.admin__field-complex+.admin__field._empty._no-header{margin-top:-3rem}.admin__legend{float:left;position:static;width:100%}.admin__legend+br{clear:left;display:block;height:0;overflow:hidden}.message{margin-bottom:3rem}.message-icon-top:before{margin-top:0;top:1.8rem}.nav{background-color:#f8f8f8;border-bottom:1px solid #e3e3e3;border-top:1px solid #e3e3e3;display:none;margin-bottom:3rem;padding:2.2rem 1.5rem 0 0}.nav .btn-group,.nav-bar-outer-actions{float:right;margin-bottom:1.7rem}.nav .btn-group .btn-wrap,.nav-bar-outer-actions .btn-wrap{float:right;margin-left:.5rem;margin-right:.5rem}.nav .btn-group .btn-wrap .btn,.nav-bar-outer-actions .btn-wrap .btn{padding-left:.5rem;padding-right:.5rem}.nav-bar-outer-actions{margin-top:-10.6rem;padding-right:1.5rem}.btn-wrap-try-again{width:9.5rem}.btn-wrap-next,.btn-wrap-prev{width:8.5rem}.nav-bar{counter-reset:i;float:left;margin:0 1rem 1.7rem 0;padding:0;position:relative;white-space:nowrap}.nav-bar:before{background-color:#d4d4d4;background-repeat:repeat-x;background-image:linear-gradient(to bottom,#d1d1d1 0,#d4d4d4 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#d1d1d1', endColorstr='#d4d4d4', GradientType=0);border-bottom:1px solid #d9d9d9;border-top:1px solid #bfbfbf;content:'';height:1rem;left:5.15rem;position:absolute;right:5.15rem;top:.7rem}.nav-bar>li{display:inline-block;font-size:0;position:relative;vertical-align:top;width:10.3rem}.nav-bar>li:first-child:after{display:none}.nav-bar>li:after{background-color:#514943;content:'';height:.5rem;left:calc(-50% + .25rem);position:absolute;right:calc(50% + .7rem);top:.9rem}.nav-bar>li.disabled:before,.nav-bar>li.ui-state-disabled:before{bottom:0;content:'';left:0;position:absolute;right:0;top:0;z-index:1}.nav-bar>li.active~li:after,.nav-bar>li.ui-state-active~li:after{display:none}.nav-bar>li.active~li a:after,.nav-bar>li.ui-state-active~li a:after{background-color:transparent;border-color:transparent;color:#a6a6a6}.nav-bar>li.active a,.nav-bar>li.ui-state-active a{color:#000}.nav-bar>li.active a:hover,.nav-bar>li.ui-state-active a:hover{cursor:default}.nav-bar>li.active a:after,.nav-bar>li.ui-state-active a:after{background-color:#fff;content:''}.nav-bar a{color:#514943;display:block;font-size:1.2rem;font-weight:600;line-height:1.2;overflow:hidden;padding:3rem .5em 0;position:relative;text-align:center;text-overflow:ellipsis}.nav-bar a:hover{text-decoration:none}.nav-bar a:after{background-color:#514943;border:.4rem solid #514943;border-radius:100%;color:#fff;content:counter(i);counter-increment:i;height:1.5rem;left:50%;line-height:.6;margin-left:-.8rem;position:absolute;right:auto;text-align:center;top:.4rem;width:1.5rem}.nav-bar a:before{background-color:#d6d6d6;border:1px solid transparent;border-bottom-color:#d9d9d9;border-radius:100%;border-top-color:#bfbfbf;content:'';height:2.3rem;left:50%;line-height:1;margin-left:-1.2rem;position:absolute;top:0;width:2.3rem}.tooltip{display:block;font-family:'Open Sans','Helvetica Neue',Helvetica,Arial,sans-serif;font-size:1.19rem;font-weight:400;line-height:1.4;opacity:0;position:absolute;visibility:visible;z-index:10}.tooltip.in{opacity:.9}.tooltip.top{margin-top:-4px;padding:8px 0}.tooltip.right{margin-left:4px;padding:0 8px}.tooltip.bottom{margin-top:4px;padding:8px 0}.tooltip.left{margin-left:-4px;padding:0 8px}.tooltip p:last-child{margin-bottom:0}.tooltip-inner{background-color:#fff;border:1px solid #adadad;border-radius:0;box-shadow:1px 1px 1px #ccc;color:#41362f;max-width:31rem;padding:.5em 1em;text-decoration:none}.tooltip-arrow,.tooltip-arrow:after{border:solid transparent;height:0;position:absolute;width:0}.tooltip-arrow:after{content:'';position:absolute}.tooltip.top .tooltip-arrow,.tooltip.top .tooltip-arrow:after{border-top-color:#949494;border-width:8px 8px 0;bottom:0;left:50%;margin-left:-8px}.tooltip.top-left .tooltip-arrow,.tooltip.top-left .tooltip-arrow:after{border-top-color:#949494;border-width:8px 8px 0;bottom:0;margin-bottom:-8px;right:8px}.tooltip.top-right .tooltip-arrow,.tooltip.top-right .tooltip-arrow:after{border-top-color:#949494;border-width:8px 8px 0;bottom:0;left:8px;margin-bottom:-8px}.tooltip.right .tooltip-arrow,.tooltip.right .tooltip-arrow:after{border-right-color:#949494;border-width:8px 8px 8px 0;left:1px;margin-top:-8px;top:50%}.tooltip.right .tooltip-arrow:after{border-right-color:#fff;border-width:6px 7px 6px 0;margin-left:0;margin-top:-6px}.tooltip.left .tooltip-arrow,.tooltip.left .tooltip-arrow:after{border-left-color:#949494;border-width:8px 0 8px 8px;margin-top:-8px;right:0;top:50%}.tooltip.bottom .tooltip-arrow,.tooltip.bottom .tooltip-arrow:after{border-bottom-color:#949494;border-width:0 8px 8px;left:50%;margin-left:-8px;top:0}.tooltip.bottom-left .tooltip-arrow,.tooltip.bottom-left .tooltip-arrow:after{border-bottom-color:#949494;border-width:0 8px 8px;margin-top:-8px;right:8px;top:0}.tooltip.bottom-right .tooltip-arrow,.tooltip.bottom-right .tooltip-arrow:after{border-bottom-color:#949494;border-width:0 8px 8px;left:8px;margin-top:-8px;top:0}.password-strength{display:block;margin:0 -.3rem 1em;white-space:nowrap}.password-strength.password-strength-too-short .password-strength-item:first-child,.password-strength.password-strength-weak .password-strength-item:first-child,.password-strength.password-strength-weak .password-strength-item:first-child+.password-strength-item{background-color:#e22626}.password-strength.password-strength-fair .password-strength-item:first-child,.password-strength.password-strength-fair .password-strength-item:first-child+.password-strength-item,.password-strength.password-strength-fair .password-strength-item:first-child+.password-strength-item+.password-strength-item{background-color:#ef672f}.password-strength.password-strength-good .password-strength-item:first-child,.password-strength.password-strength-good .password-strength-item:first-child+.password-strength-item,.password-strength.password-strength-good .password-strength-item:first-child+.password-strength-item+.password-strength-item,.password-strength.password-strength-good .password-strength-item:first-child+.password-strength-item+.password-strength-item+.password-strength-item,.password-strength.password-strength-strong .password-strength-item{background-color:#79a22e}.password-strength .password-strength-item{background-color:#ccc;display:inline-block;font-size:0;height:1.4rem;margin-right:.3rem;width:calc(20% - .6rem)}@keyframes progress-bar-stripes{from{background-position:4rem 0}to{background-position:0 0}}.progress{background-color:#fafafa;border:1px solid #ccc;clear:left;height:3rem;margin-bottom:3rem;overflow:hidden}.progress-bar{background-color:#79a22e;color:#fff;float:left;font-size:1.19rem;height:100%;line-height:3rem;text-align:center;transition:width .6s ease;width:0}.progress-bar.active{animation:progress-bar-stripes 2s linear infinite}.progress-bar-text-description{margin-bottom:1.6rem}.progress-bar-text-progress{text-align:right}.page-columns .page-inner-sidebar{margin:0 0 3rem}.page-header{margin-bottom:2.7rem;padding-bottom:2rem;position:relative}.page-header:before{border-bottom:1px solid #e3e3e3;bottom:0;content:'';display:block;height:1px;left:3rem;position:absolute;right:3rem}.container .page-header:before{content:normal}.page-header .message{margin-bottom:1.8rem}.page-header .message+.message{margin-top:-1.5rem}.page-header .admin__action-dropdown,.page-header .search-global-input{transition:none}.container .page-header{margin-bottom:0}.page-title-wrapper{margin-top:1.1rem}.container .page-title-wrapper{background:url(../../pub/images/logo.svg) no-repeat;min-height:41px;padding:4px 0 0 45px}.admin__menu .level-0:first-child>a{margin-top:1.6rem}.admin__menu .level-0:first-child>a:after{top:-1.6rem}.admin__menu .level-0:first-child._active>a:after{display:block}.admin__menu .level-0>a{padding-bottom:1.3rem;padding-top:1.3rem}.admin__menu .level-0>a:before{margin-bottom:.7rem}.admin__menu .item-home>a:before{content:'\e611';font-size:2.3rem;padding-top:-.1rem}.admin__menu .item-component>a:before{content:'\e612'}.admin__menu .item-extension>a:before{content:'\e612'}.admin__menu .item-module>a:before{content:'\e647'}.admin__menu .item-upgrade>a:before{content:'\e614'}.admin__menu .item-system-config>a:before{content:'\e610'}.admin__menu .item-tools>a:before{content:'\e613'}.modal-sub-title{font-size:1.7rem;font-weight:600}.modal-connect-signin .modal-inner-wrap{max-width:80rem}@keyframes ngdialog-fadeout{0%{opacity:1}100%{opacity:0}}@keyframes ngdialog-fadein{0%{opacity:0}100%{opacity:1}}.ngdialog{-webkit-overflow-scrolling:touch;bottom:0;box-sizing:border-box;left:0;overflow:auto;position:fixed;right:0;top:0;z-index:999}.ngdialog *,.ngdialog:after,.ngdialog:before{box-sizing:inherit}.ngdialog.ngdialog-disabled-animation *{animation:none!important}.ngdialog.ngdialog-closing .ngdialog-content,.ngdialog.ngdialog-closing .ngdialog-overlay{-webkit-animation:ngdialog-fadeout .5s;-webkit-backface-visibility:hidden;animation:ngdialog-fadeout .5s}.ngdialog-overlay{-webkit-animation:ngdialog-fadein .5s;-webkit-backface-visibility:hidden;animation:ngdialog-fadein .5s;background:rgba(0,0,0,.4);bottom:0;left:0;position:fixed;right:0;top:0}.ngdialog-content{-webkit-animation:ngdialog-fadein .5s;-webkit-backface-visibility:hidden;animation:ngdialog-fadein .5s}body.ngdialog-open{overflow:hidden}.component-indicator{border-radius:50%;cursor:help;display:inline-block;height:16px;text-align:center;vertical-align:middle;width:16px}.component-indicator::after,.component-indicator::before{background:#fff;display:block;opacity:0;position:absolute;transition:opacity .2s linear .1s;visibility:hidden}.component-indicator::before{border:1px solid #adadad;border-radius:1px;box-shadow:0 0 2px rgba(0,0,0,.4);content:attr(data-label);font-size:1.2rem;margin:30px 0 0 -10px;min-width:50px;padding:4px 5px}.component-indicator::after{border-color:#999;border-style:solid;border-width:1px 0 0 1px;box-shadow:-1px -1px 1px rgba(0,0,0,.1);content:'';height:10px;margin:9px 0 0 5px;-ms-transform:rotate(45deg);transform:rotate(45deg);width:10px}.component-indicator:hover::after,.component-indicator:hover::before{opacity:1;transition:opacity .2s linear;visibility:visible}.component-indicator span{display:block;height:16px;overflow:hidden;width:16px}.component-indicator span:before{content:'';display:block;font-family:Icons;font-size:16px;height:100%;line-height:16px;width:100%}.component-indicator._on{background:#79a22e}.component-indicator._off{background:#e22626}.component-indicator._off span:before{background:#fff;height:4px;margin:8px auto 20px;width:12px}.component-indicator._info{background:0 0}.component-indicator._info span{width:21px}.component-indicator._info span:before{color:#008bdb;content:'\e648';font-family:Icons;font-size:16px}.component-indicator._tooltip{background:0 0;margin:0 0 8px 5px}.component-indicator._tooltip a{width:21px}.component-indicator._tooltip a:hover{text-decoration:none}.component-indicator._tooltip a:before{color:#514943;content:'\e633';font-family:Icons;font-size:16px}.col-manager-item-name .data-grid-data{padding-left:5px}.col-manager-item-name .ng-hide+.data-grid-data{padding-left:24px}.col-manager-item-name ._hide-dependencies,.col-manager-item-name ._show-dependencies{cursor:pointer;padding-left:24px;position:relative}.col-manager-item-name ._hide-dependencies:before,.col-manager-item-name ._show-dependencies:before{display:block;font-family:Icons;font-size:12px;left:0;position:absolute;top:1px}.col-manager-item-name ._show-dependencies:before{content:'\e62b'}.col-manager-item-name ._hide-dependencies:before{content:'\e628'}.col-manager-item-name ._no-dependencies{padding-left:24px}.product-modules-block{font-size:1.2rem;padding:15px 0 0}.col-manager-item-name .product-modules-block{padding-left:1rem}.product-modules-descriprion,.product-modules-title{font-weight:700;margin:0 0 7px}.product-modules-list{font-size:1.1rem;list-style:none;margin:0}.col-manager-item-name .product-modules-list{margin-left:15px}.col-manager-item-name .product-modules-list li{padding:0 0 0 15px;position:relative}.product-modules-list li{margin:0 0 .5rem}.product-modules-list .component-indicator{height:10px;left:0;position:absolute;top:3px;width:10px}.module-summary{white-space:nowrap}.module-summary-title{font-size:2.1rem;margin-right:1rem}.app-updater .nav{display:block;margin-bottom:3.1rem;margin-top:-2.8rem}.app-updater .nav-bar-outer-actions{margin-top:1rem;padding-right:0}.app-updater .nav-bar-outer-actions .btn-wrap-cancel{margin-right:2.6rem}.main{padding-bottom:2rem;padding-top:3rem}.header{display:none}.header .logo{float:left;height:4.1rem;width:3.5rem}.header-title{font-size:2.8rem;letter-spacing:.02em;line-height:1.4;margin:2.5rem 0 3.5rem 5rem}.page-title{margin-bottom:1rem}.page-sub-title{font-size:2rem}.accent-box{margin-bottom:2rem}.accent-box .btn-prime{margin-top:1.5rem}.spinner.side{float:left;font-size:2.4rem;margin-left:2rem;margin-top:-5px}.page-landing{margin:7.6% auto 0;max-width:44rem;text-align:center}.page-landing .logo{height:5.6rem;margin-bottom:2rem;width:19.2rem}.page-landing .text-version{margin-bottom:3rem}.page-landing .text-welcome{margin-bottom:6.5rem}.page-landing .text-terms{margin-bottom:2.5rem;text-align:center}.page-landing .btn-submit,.page-license .license-text{margin-bottom:2rem}.page-license .page-license-footer{text-align:right}.readiness-check-item{margin-bottom:4rem;min-height:2.5rem}.readiness-check-item .spinner{float:left;font-size:2.5rem;margin:-.4rem 0 0 1.7rem}.readiness-check-title{font-size:1.4rem;font-weight:700;margin-bottom:.1rem;margin-left:5.7rem}.readiness-check-content{margin-left:5.7rem;margin-right:22rem;position:relative}.readiness-check-content .readiness-check-title{margin-left:0}.readiness-check-content .list{margin-top:-.3rem}.readiness-check-side{left:100%;padding-left:2.4rem;position:absolute;top:0;width:22rem}.readiness-check-side .side-title{margin-bottom:0}.readiness-check-icon{float:left;margin-left:1.7rem;margin-top:.3rem}.extensions-information{margin-bottom:5rem}.extensions-information h3{font-size:1.4rem;margin-bottom:1.3rem}.extensions-information .message{margin-bottom:2.5rem}.extensions-information .message:before{margin-top:0;top:1.8rem}.extensions-information .extensions-container{padding:0 2rem}.extensions-information .list{margin-bottom:1rem}.extensions-information .list select{cursor:pointer}.extensions-information .list select:disabled{background:#ccc;cursor:default}.extensions-information .list .extension-delete{font-size:1.7rem;padding-top:0}.delete-modal-wrap{padding:0 4% 4rem}.delete-modal-wrap h3{font-size:3.4rem;display:inline-block;font-weight:300;margin:0 0 2rem;padding:.9rem 0 0;vertical-align:top}.delete-modal-wrap .actions{padding:3rem 0 0}.page-web-configuration .form-el-insider-wrap{width:auto}.page-web-configuration .form-el-insider{width:15.4rem}.page-web-configuration .form-el-insider-input .form-el-input{width:16.5rem}.customize-your-store .advanced-modules-count,.customize-your-store .advanced-modules-select{padding-left:1.5rem}.customize-your-store .customize-your-store-advanced{min-width:0}.customize-your-store .message-error:before{margin-top:0;top:1.8rem}.customize-your-store .message-error a{color:#333;text-decoration:underline}.customize-your-store .message-error .form-label:before{background:#fff}.customize-your-store .customize-database-clean p{margin-top:2.5rem}.content-install{margin-bottom:2rem}.console{border:1px solid #ccc;font-family:'Courier New',Courier,monospace;font-weight:300;height:20rem;margin:1rem 0 2rem;overflow-y:auto;padding:1.5rem 2rem 2rem;resize:vertical}.console .text-danger{color:#e22626}.console .text-success{color:#090}.console .hidden{display:none}.content-success .btn-prime{margin-top:1.5rem}.jumbo-title{font-size:3.6rem}.jumbo-title .jumbo-icon{font-size:3.8rem;margin-right:.25em;position:relative;top:.15em}.install-database-clean{margin-top:4rem}.install-database-clean .btn{margin-right:1rem}.page-sub-title{margin-bottom:2.1rem;margin-top:3rem}.multiselect-custom{max-width:71.1rem}.content-install{margin-top:3.7rem}.home-page-inner-wrap{margin:0 auto;max-width:91rem}.setup-home-title{margin-bottom:3.9rem;padding-top:1.8rem;text-align:center}.setup-home-item{background-color:#fafafa;border:1px solid #ccc;color:#333;display:block;margin-bottom:2rem;margin-left:1.3rem;margin-right:1.3rem;min-height:30rem;padding:2rem;text-align:center}.setup-home-item:hover{border-color:#8c8c8c;color:#333;text-decoration:none;transition:border-color .1s linear}.setup-home-item:active{-ms-transform:scale(0.99);transform:scale(0.99)}.setup-home-item:before{display:block;font-size:7rem;margin-bottom:3.3rem;margin-top:4rem}.setup-home-item-component:before,.setup-home-item-extension:before{content:'\e612'}.setup-home-item-module:before{content:'\e647'}.setup-home-item-upgrade:before{content:'\e614'}.setup-home-item-configuration:before{content:'\e610'}.setup-home-item-title{display:block;font-size:1.8rem;letter-spacing:.025em;margin-bottom:1rem}.setup-home-item-description{display:block}.extension-manager-wrap{border:1px solid #bbb;margin:0 0 4rem}.extension-manager-account{font-size:2.1rem;display:inline-block;font-weight:400}.extension-manager-title{font-size:3.2rem;background-color:#f8f8f8;border-bottom:1px solid #e3e3e3;color:#41362f;font-weight:600;line-height:1.2;padding:2rem}.extension-manager-content{padding:2.5rem 2rem 2rem}.extension-manager-items{list-style:none;margin:0;text-align:center}.extension-manager-items .btn{border:1px solid #adadad;display:block;margin:1rem auto 0}.extension-manager-items .item-title{font-size:2.1rem;display:inline-block;text-align:left}.extension-manager-items .item-number{font-size:4.1rem;display:inline-block;line-height:.8;margin:0 5px 1.5rem 0;vertical-align:top}.extension-manager-items .item-date{font-size:2.6rem;margin-top:1px}.extension-manager-items .item-date-title{font-size:1.5rem}.extension-manager-items .item-install{margin:0 0 2rem}.sync-login-wrap{padding:0 10% 4rem}.sync-login-wrap .legend{font-size:2.6rem;color:#eb5202;float:left;font-weight:300;line-height:1.2;margin:-1rem 0 2.5rem;position:static;width:100%}.sync-login-wrap .legend._hidden{display:none}.sync-login-wrap .login-header{font-size:3.4rem;font-weight:300;margin:0 0 2rem}.sync-login-wrap .login-header span{display:inline-block;padding:.9rem 0 0;vertical-align:top}.sync-login-wrap h4{font-size:1.4rem;margin:0 0 2rem}.sync-login-wrap .sync-login-steps{margin:0 0 2rem 1.5rem}.sync-login-wrap .sync-login-steps li{padding:0 0 0 1rem}.sync-login-wrap .form-row .form-label{display:inline-block}.sync-login-wrap .form-row .form-label.required{padding-left:1.5rem}.sync-login-wrap .form-row .form-label.required:after{left:0;position:absolute;right:auto}.sync-login-wrap .form-row{max-width:28rem}.sync-login-wrap .form-actions{display:table;margin-top:-1.3rem}.sync-login-wrap .form-actions .links{display:table-header-group}.sync-login-wrap .form-actions .actions{padding:3rem 0 0}@media all and (max-width:1047px){.admin__menu .submenu li{min-width:19.8rem}.nav{padding-bottom:5.38rem;padding-left:1.5rem;text-align:center}.nav-bar{display:inline-block;float:none;margin-right:0;vertical-align:top}.nav .btn-group,.nav-bar-outer-actions{display:inline-block;float:none;margin-top:-8.48rem;text-align:center;vertical-align:top;width:100%}.nav-bar-outer-actions{padding-right:0}.nav-bar-outer-actions .outer-actions-inner-wrap{display:inline-block}.app-updater .nav{padding-bottom:1.7rem}.app-updater .nav-bar-outer-actions{margin-top:2rem}}@media all and (min-width:768px){.page-layout-admin-2columns-left .page-columns{margin-left:-30px}.page-layout-admin-2columns-left .page-columns:after{clear:both;content:'';display:table}.page-layout-admin-2columns-left .page-columns .main-col{width:calc((100%) * .75 - 30px);float:right}.page-layout-admin-2columns-left .page-columns .side-col{width:calc((100%) * .25 - 30px);float:left;margin-left:30px}.col-m-1,.col-m-10,.col-m-11,.col-m-12,.col-m-2,.col-m-3,.col-m-4,.col-m-5,.col-m-6,.col-m-7,.col-m-8,.col-m-9{float:left}.col-m-12{width:100%}.col-m-11{width:91.66666667%}.col-m-10{width:83.33333333%}.col-m-9{width:75%}.col-m-8{width:66.66666667%}.col-m-7{width:58.33333333%}.col-m-6{width:50%}.col-m-5{width:41.66666667%}.col-m-4{width:33.33333333%}.col-m-3{width:25%}.col-m-2{width:16.66666667%}.col-m-1{width:8.33333333%}.col-m-pull-12{right:100%}.col-m-pull-11{right:91.66666667%}.col-m-pull-10{right:83.33333333%}.col-m-pull-9{right:75%}.col-m-pull-8{right:66.66666667%}.col-m-pull-7{right:58.33333333%}.col-m-pull-6{right:50%}.col-m-pull-5{right:41.66666667%}.col-m-pull-4{right:33.33333333%}.col-m-pull-3{right:25%}.col-m-pull-2{right:16.66666667%}.col-m-pull-1{right:8.33333333%}.col-m-pull-0{right:auto}.col-m-push-12{left:100%}.col-m-push-11{left:91.66666667%}.col-m-push-10{left:83.33333333%}.col-m-push-9{left:75%}.col-m-push-8{left:66.66666667%}.col-m-push-7{left:58.33333333%}.col-m-push-6{left:50%}.col-m-push-5{left:41.66666667%}.col-m-push-4{left:33.33333333%}.col-m-push-3{left:25%}.col-m-push-2{left:16.66666667%}.col-m-push-1{left:8.33333333%}.col-m-push-0{left:auto}.col-m-offset-12{margin-left:100%}.col-m-offset-11{margin-left:91.66666667%}.col-m-offset-10{margin-left:83.33333333%}.col-m-offset-9{margin-left:75%}.col-m-offset-8{margin-left:66.66666667%}.col-m-offset-7{margin-left:58.33333333%}.col-m-offset-6{margin-left:50%}.col-m-offset-5{margin-left:41.66666667%}.col-m-offset-4{margin-left:33.33333333%}.col-m-offset-3{margin-left:25%}.col-m-offset-2{margin-left:16.66666667%}.col-m-offset-1{margin-left:8.33333333%}.col-m-offset-0{margin-left:0}.page-columns{margin-left:-30px}.page-columns:after{clear:both;content:'';display:table}.page-columns .page-inner-content{width:calc((100%) * .75 - 30px);float:right}.page-columns .page-inner-sidebar{width:calc((100%) * .25 - 30px);float:left;margin-left:30px}}@media all and (min-width:1048px){.col-l-1,.col-l-10,.col-l-11,.col-l-12,.col-l-2,.col-l-3,.col-l-4,.col-l-5,.col-l-6,.col-l-7,.col-l-8,.col-l-9{float:left}.col-l-12{width:100%}.col-l-11{width:91.66666667%}.col-l-10{width:83.33333333%}.col-l-9{width:75%}.col-l-8{width:66.66666667%}.col-l-7{width:58.33333333%}.col-l-6{width:50%}.col-l-5{width:41.66666667%}.col-l-4{width:33.33333333%}.col-l-3{width:25%}.col-l-2{width:16.66666667%}.col-l-1{width:8.33333333%}.col-l-pull-12{right:100%}.col-l-pull-11{right:91.66666667%}.col-l-pull-10{right:83.33333333%}.col-l-pull-9{right:75%}.col-l-pull-8{right:66.66666667%}.col-l-pull-7{right:58.33333333%}.col-l-pull-6{right:50%}.col-l-pull-5{right:41.66666667%}.col-l-pull-4{right:33.33333333%}.col-l-pull-3{right:25%}.col-l-pull-2{right:16.66666667%}.col-l-pull-1{right:8.33333333%}.col-l-pull-0{right:auto}.col-l-push-12{left:100%}.col-l-push-11{left:91.66666667%}.col-l-push-10{left:83.33333333%}.col-l-push-9{left:75%}.col-l-push-8{left:66.66666667%}.col-l-push-7{left:58.33333333%}.col-l-push-6{left:50%}.col-l-push-5{left:41.66666667%}.col-l-push-4{left:33.33333333%}.col-l-push-3{left:25%}.col-l-push-2{left:16.66666667%}.col-l-push-1{left:8.33333333%}.col-l-push-0{left:auto}.col-l-offset-12{margin-left:100%}.col-l-offset-11{margin-left:91.66666667%}.col-l-offset-10{margin-left:83.33333333%}.col-l-offset-9{margin-left:75%}.col-l-offset-8{margin-left:66.66666667%}.col-l-offset-7{margin-left:58.33333333%}.col-l-offset-6{margin-left:50%}.col-l-offset-5{margin-left:41.66666667%}.col-l-offset-4{margin-left:33.33333333%}.col-l-offset-3{margin-left:25%}.col-l-offset-2{margin-left:16.66666667%}.col-l-offset-1{margin-left:8.33333333%}.col-l-offset-0{margin-left:0}}@media all and (min-width:1440px){.col-xl-1,.col-xl-10,.col-xl-11,.col-xl-12,.col-xl-2,.col-xl-3,.col-xl-4,.col-xl-5,.col-xl-6,.col-xl-7,.col-xl-8,.col-xl-9{float:left}.col-xl-12{width:100%}.col-xl-11{width:91.66666667%}.col-xl-10{width:83.33333333%}.col-xl-9{width:75%}.col-xl-8{width:66.66666667%}.col-xl-7{width:58.33333333%}.col-xl-6{width:50%}.col-xl-5{width:41.66666667%}.col-xl-4{width:33.33333333%}.col-xl-3{width:25%}.col-xl-2{width:16.66666667%}.col-xl-1{width:8.33333333%}.col-xl-pull-12{right:100%}.col-xl-pull-11{right:91.66666667%}.col-xl-pull-10{right:83.33333333%}.col-xl-pull-9{right:75%}.col-xl-pull-8{right:66.66666667%}.col-xl-pull-7{right:58.33333333%}.col-xl-pull-6{right:50%}.col-xl-pull-5{right:41.66666667%}.col-xl-pull-4{right:33.33333333%}.col-xl-pull-3{right:25%}.col-xl-pull-2{right:16.66666667%}.col-xl-pull-1{right:8.33333333%}.col-xl-pull-0{right:auto}.col-xl-push-12{left:100%}.col-xl-push-11{left:91.66666667%}.col-xl-push-10{left:83.33333333%}.col-xl-push-9{left:75%}.col-xl-push-8{left:66.66666667%}.col-xl-push-7{left:58.33333333%}.col-xl-push-6{left:50%}.col-xl-push-5{left:41.66666667%}.col-xl-push-4{left:33.33333333%}.col-xl-push-3{left:25%}.col-xl-push-2{left:16.66666667%}.col-xl-push-1{left:8.33333333%}.col-xl-push-0{left:auto}.col-xl-offset-12{margin-left:100%}.col-xl-offset-11{margin-left:91.66666667%}.col-xl-offset-10{margin-left:83.33333333%}.col-xl-offset-9{margin-left:75%}.col-xl-offset-8{margin-left:66.66666667%}.col-xl-offset-7{margin-left:58.33333333%}.col-xl-offset-6{margin-left:50%}.col-xl-offset-5{margin-left:41.66666667%}.col-xl-offset-4{margin-left:33.33333333%}.col-xl-offset-3{margin-left:25%}.col-xl-offset-2{margin-left:16.66666667%}.col-xl-offset-1{margin-left:8.33333333%}.col-xl-offset-0{margin-left:0}}@media all and (max-width:767px){.abs-clearer-mobile:after,.nav-bar:after{clear:both;content:'';display:table}.list-definition>dt{float:none}.list-definition>dd{margin-left:0}.form-row .form-label{text-align:left}.form-row .form-label.required:after{position:static}.nav{padding-bottom:0;padding-left:0;padding-right:0}.nav-bar-outer-actions{margin-top:0}.nav-bar{display:block;margin-bottom:0;margin-left:auto;margin-right:auto;width:30.9rem}.nav-bar:before{display:none}.nav-bar>li{float:left;min-height:9rem}.nav-bar>li:after{display:none}.nav-bar>li:nth-child(4n){clear:both}.nav-bar a{line-height:1.4}.tooltip{display:none!important}.readiness-check-content{margin-right:2rem}.readiness-check-side{padding:2rem 0;position:static}.form-el-insider,.form-el-insider-wrap,.page-web-configuration .form-el-insider-input,.page-web-configuration .form-el-insider-input .form-el-input{display:block;width:100%}}@media all and (max-width:479px){.nav-bar{width:23.175rem}.nav-bar>li{width:7.725rem}.nav .btn-group .btn-wrap-try-again,.nav-bar-outer-actions .btn-wrap-try-again{clear:both;display:block;float:none;margin-left:auto;margin-right:auto;margin-top:1rem;padding-top:1rem}} diff --git a/setup/src/Magento/Setup/Model/ConfigOptionsList/Cache.php b/setup/src/Magento/Setup/Model/ConfigOptionsList/Cache.php index 1ec9d486a5a22..2f19f010c1704 100644 --- a/setup/src/Magento/Setup/Model/ConfigOptionsList/Cache.php +++ b/setup/src/Magento/Setup/Model/ConfigOptionsList/Cache.php @@ -26,11 +26,13 @@ class Cache implements ConfigOptionsListInterface const INPUT_KEY_CACHE_BACKEND_REDIS_SERVER = 'cache-backend-redis-server'; const INPUT_KEY_CACHE_BACKEND_REDIS_DATABASE = 'cache-backend-redis-db'; const INPUT_KEY_CACHE_BACKEND_REDIS_PORT = 'cache-backend-redis-port'; + const INPUT_KEY_CACHE_BACKEND_REDIS_PASSWORD = 'cache-backend-redis-password'; const CONFIG_PATH_CACHE_BACKEND = 'cache/frontend/default/backend'; const CONFIG_PATH_CACHE_BACKEND_SERVER = 'cache/frontend/default/backend_options/server'; const CONFIG_PATH_CACHE_BACKEND_DATABASE = 'cache/frontend/default/backend_options/database'; const CONFIG_PATH_CACHE_BACKEND_PORT = 'cache/frontend/default/backend_options/port'; + const CONFIG_PATH_CACHE_BACKEND_PASSWORD = 'cache/frontend/default/backend_options/password'; /** * @var array @@ -38,7 +40,8 @@ class Cache implements ConfigOptionsListInterface private $defaultConfigValues = [ self::INPUT_KEY_CACHE_BACKEND_REDIS_SERVER => '127.0.0.1', self::INPUT_KEY_CACHE_BACKEND_REDIS_DATABASE => '0', - self::INPUT_KEY_CACHE_BACKEND_REDIS_PORT => '6379' + self::INPUT_KEY_CACHE_BACKEND_REDIS_PORT => '6379', + self::INPUT_KEY_CACHE_BACKEND_REDIS_PASSWORD => '' ]; /** @@ -55,6 +58,7 @@ class Cache implements ConfigOptionsListInterface self::INPUT_KEY_CACHE_BACKEND_REDIS_SERVER => self::CONFIG_PATH_CACHE_BACKEND_SERVER, self::INPUT_KEY_CACHE_BACKEND_REDIS_DATABASE => self::CONFIG_PATH_CACHE_BACKEND_DATABASE, self::INPUT_KEY_CACHE_BACKEND_REDIS_PORT => self::CONFIG_PATH_CACHE_BACKEND_PORT, + self::INPUT_KEY_CACHE_BACKEND_REDIS_PASSWORD => self::CONFIG_PATH_CACHE_BACKEND_PASSWORD ]; /** @@ -102,12 +106,18 @@ public function getOptions() TextConfigOption::FRONTEND_WIZARD_TEXT, self::CONFIG_PATH_CACHE_BACKEND_PORT, 'Redis server listen port' + ), + new TextConfigOption( + self::INPUT_KEY_CACHE_BACKEND_REDIS_PASSWORD, + TextConfigOption::FRONTEND_WIZARD_TEXT, + self::CONFIG_PATH_CACHE_BACKEND_PASSWORD, + 'Redis server password' ) ]; } /** - * {@inheritdoc} + * @inheritdoc */ public function createConfig(array $options, DeploymentConfig $deploymentConfig) { @@ -131,7 +141,7 @@ public function createConfig(array $options, DeploymentConfig $deploymentConfig) } /** - * {@inheritdoc} + * @inheritdoc */ public function validate(array $options, DeploymentConfig $deploymentConfig) { @@ -190,6 +200,13 @@ private function validateRedisConfig(array $options, DeploymentConfig $deploymen self::CONFIG_PATH_CACHE_BACKEND_DATABASE, $this->getDefaultConfigValue(self::INPUT_KEY_CACHE_BACKEND_REDIS_DATABASE) ); + + $config['password'] = isset($options[self::INPUT_KEY_CACHE_BACKEND_REDIS_PASSWORD]) + ? $options[self::INPUT_KEY_CACHE_BACKEND_REDIS_PASSWORD] + : $deploymentConfig->get( + self::CONFIG_PATH_CACHE_BACKEND_PASSWORD, + $this->getDefaultConfigValue(self::INPUT_KEY_CACHE_BACKEND_REDIS_PASSWORD) + ); return $this->redisValidator->isValidConnection($config); } diff --git a/setup/src/Magento/Setup/Model/ConfigOptionsList/PageCache.php b/setup/src/Magento/Setup/Model/ConfigOptionsList/PageCache.php index be1cc5b010185..c288b4dd51d65 100644 --- a/setup/src/Magento/Setup/Model/ConfigOptionsList/PageCache.php +++ b/setup/src/Magento/Setup/Model/ConfigOptionsList/PageCache.php @@ -27,12 +27,14 @@ class PageCache implements ConfigOptionsListInterface const INPUT_KEY_PAGE_CACHE_BACKEND_REDIS_DATABASE = 'page-cache-redis-db'; const INPUT_KEY_PAGE_CACHE_BACKEND_REDIS_PORT = 'page-cache-redis-port'; const INPUT_KEY_PAGE_CACHE_BACKEND_REDIS_COMPRESS_DATA = 'page-cache-redis-compress-data'; + const INPUT_KEY_PAGE_CACHE_BACKEND_REDIS_PASSWORD = 'page-cache-redis-password'; const CONFIG_PATH_PAGE_CACHE_BACKEND = 'cache/frontend/page_cache/backend'; const CONFIG_PATH_PAGE_CACHE_BACKEND_SERVER = 'cache/frontend/page_cache/backend_options/server'; const CONFIG_PATH_PAGE_CACHE_BACKEND_DATABASE = 'cache/frontend/page_cache/backend_options/database'; const CONFIG_PATH_PAGE_CACHE_BACKEND_PORT = 'cache/frontend/page_cache/backend_options/port'; const CONFIG_PATH_PAGE_CACHE_BACKEND_COMPRESS_DATA = 'cache/frontend/page_cache/backend_options/compress_data'; + const CONFIG_PATH_PAGE_CACHE_BACKEND_PASSWORD = 'cache/frontend/page_cache/backend_options/password'; /** * @var array @@ -41,7 +43,8 @@ class PageCache implements ConfigOptionsListInterface self::INPUT_KEY_PAGE_CACHE_BACKEND_REDIS_SERVER => '127.0.0.1', self::INPUT_KEY_PAGE_CACHE_BACKEND_REDIS_DATABASE => '1', self::INPUT_KEY_PAGE_CACHE_BACKEND_REDIS_PORT => '6379', - self::INPUT_KEY_PAGE_CACHE_BACKEND_REDIS_COMPRESS_DATA => '0' + self::INPUT_KEY_PAGE_CACHE_BACKEND_REDIS_COMPRESS_DATA => '0', + self::INPUT_KEY_PAGE_CACHE_BACKEND_REDIS_PASSWORD => '' ]; /** @@ -58,7 +61,8 @@ class PageCache implements ConfigOptionsListInterface self::INPUT_KEY_PAGE_CACHE_BACKEND_REDIS_SERVER => self::CONFIG_PATH_PAGE_CACHE_BACKEND_SERVER, self::INPUT_KEY_PAGE_CACHE_BACKEND_REDIS_DATABASE => self::CONFIG_PATH_PAGE_CACHE_BACKEND_DATABASE, self::INPUT_KEY_PAGE_CACHE_BACKEND_REDIS_PORT => self::CONFIG_PATH_PAGE_CACHE_BACKEND_PORT, - self::INPUT_KEY_PAGE_CACHE_BACKEND_REDIS_COMPRESS_DATA => self::CONFIG_PATH_PAGE_CACHE_BACKEND_COMPRESS_DATA + self::INPUT_KEY_PAGE_CACHE_BACKEND_REDIS_COMPRESS_DATA => self::CONFIG_PATH_PAGE_CACHE_BACKEND_COMPRESS_DATA, + self::INPUT_KEY_PAGE_CACHE_BACKEND_REDIS_PASSWORD => self::CONFIG_PATH_PAGE_CACHE_BACKEND_PASSWORD ]; /** @@ -112,12 +116,18 @@ public function getOptions() TextConfigOption::FRONTEND_WIZARD_TEXT, self::CONFIG_PATH_PAGE_CACHE_BACKEND_COMPRESS_DATA, 'Set to 1 to compress the full page cache (use 0 to disable)' + ), + new TextConfigOption( + self::INPUT_KEY_PAGE_CACHE_BACKEND_REDIS_PASSWORD, + TextConfigOption::FRONTEND_WIZARD_TEXT, + self::CONFIG_PATH_PAGE_CACHE_BACKEND_PASSWORD, + 'Redis server password' ) ]; } /** - * {@inheritdoc} + * @inheritdoc */ public function createConfig(array $options, DeploymentConfig $deploymentConfig) { @@ -142,7 +152,7 @@ public function createConfig(array $options, DeploymentConfig $deploymentConfig) } /** - * {@inheritdoc} + * @inheritdoc */ public function validate(array $options, DeploymentConfig $deploymentConfig) { @@ -201,6 +211,13 @@ private function validateRedisConfig(array $options, DeploymentConfig $deploymen self::CONFIG_PATH_PAGE_CACHE_BACKEND_DATABASE, $this->getDefaultConfigValue(self::INPUT_KEY_PAGE_CACHE_BACKEND_REDIS_DATABASE) ); + + $config['password'] = isset($options[self::INPUT_KEY_PAGE_CACHE_BACKEND_REDIS_PASSWORD]) + ? $options[self::INPUT_KEY_PAGE_CACHE_BACKEND_REDIS_PASSWORD] + : $deploymentConfig->get( + self::CONFIG_PATH_PAGE_CACHE_BACKEND_PASSWORD, + $this->getDefaultConfigValue(self::INPUT_KEY_PAGE_CACHE_BACKEND_REDIS_PASSWORD) + ); return $this->redisValidator->isValidConnection($config); } diff --git a/setup/src/Magento/Setup/Test/Unit/Model/ConfigOptionsList/CacheTest.php b/setup/src/Magento/Setup/Test/Unit/Model/ConfigOptionsList/CacheTest.php index ef0ea3e988364..1bbd2e671e59a 100644 --- a/setup/src/Magento/Setup/Test/Unit/Model/ConfigOptionsList/CacheTest.php +++ b/setup/src/Magento/Setup/Test/Unit/Model/ConfigOptionsList/CacheTest.php @@ -28,6 +28,9 @@ class CacheTest extends \PHPUnit\Framework\TestCase */ private $deploymentConfigMock; + /** + * Tests setup + */ protected function setUp() { $this->validatorMock = $this->createMock(RedisConnectionValidator::class); @@ -36,10 +39,13 @@ protected function setUp() $this->configOptionsList = new CacheConfigOptionsList($this->validatorMock); } + /** + * testGetOptions + */ public function testGetOptions() { $options = $this->configOptionsList->getOptions(); - $this->assertCount(4, $options); + $this->assertCount(5, $options); $this->assertArrayHasKey(0, $options); $this->assertInstanceOf(SelectConfigOption::class, $options[0]); @@ -56,8 +62,15 @@ public function testGetOptions() $this->assertArrayHasKey(3, $options); $this->assertInstanceOf(TextConfigOption::class, $options[3]); $this->assertEquals('cache-backend-redis-port', $options[3]->getName()); + + $this->assertArrayHasKey(4, $options); + $this->assertInstanceOf(TextConfigOption::class, $options[4]); + $this->assertEquals('cache-backend-redis-password', $options[4]->getName()); } + /** + * testCreateConfigCacheRedis + */ public function testCreateConfigCacheRedis() { $this->deploymentConfigMock->method('get')->willReturn(''); @@ -70,7 +83,8 @@ public function testCreateConfigCacheRedis() 'backend_options' => [ 'server' => '', 'port' => '', - 'database' => '' + 'database' => '', + 'password' => '' ] ] ] @@ -82,6 +96,9 @@ public function testCreateConfigCacheRedis() $this->assertEquals($expectedConfigData, $configData->getData()); } + /** + * testCreateConfigWithRedisConfig + */ public function testCreateConfigWithRedisConfig() { $expectedConfigData = [ @@ -92,7 +109,8 @@ public function testCreateConfigWithRedisConfig() 'backend_options' => [ 'server' => 'localhost', 'port' => '1234', - 'database' => '5' + 'database' => '5', + 'password' => '' ] ] ] @@ -110,6 +128,9 @@ public function testCreateConfigWithRedisConfig() $this->assertEquals($expectedConfigData, $configData->getData()); } + /** + * testValidateWithValidInput + */ public function testValidateWithValidInput() { $options = [ @@ -118,7 +139,7 @@ public function testValidateWithValidInput() ]; $this->validatorMock->expects($this->once()) ->method('isValidConnection') - ->with(['host'=>'localhost', 'db'=>'', 'port'=>'']) + ->with(['host'=>'localhost', 'db'=>'', 'port'=>'', 'password'=>'']) ->willReturn(true); $errors = $this->configOptionsList->validate($options, $this->deploymentConfigMock); @@ -126,6 +147,9 @@ public function testValidateWithValidInput() $this->assertEmpty($errors); } + /** + * testValidateWithInvalidInput + */ public function testValidateWithInvalidInput() { $invalidCacheOption = 'clay-tablet'; diff --git a/setup/src/Magento/Setup/Test/Unit/Model/ConfigOptionsList/PageCacheTest.php b/setup/src/Magento/Setup/Test/Unit/Model/ConfigOptionsList/PageCacheTest.php index e654bea9ac1c5..6f8e97cd5dd8d 100644 --- a/setup/src/Magento/Setup/Test/Unit/Model/ConfigOptionsList/PageCacheTest.php +++ b/setup/src/Magento/Setup/Test/Unit/Model/ConfigOptionsList/PageCacheTest.php @@ -28,6 +28,9 @@ class PageCacheTest extends \PHPUnit\Framework\TestCase */ private $deploymentConfigMock; + /** + * Test setup + */ protected function setUp() { $this->validatorMock = $this->createMock(RedisConnectionValidator::class, [], [], '', false); @@ -36,10 +39,13 @@ protected function setUp() $this->configList = new PageCache($this->validatorMock); } + /** + * testGetOptions + */ public function testGetOptions() { $options = $this->configList->getOptions(); - $this->assertCount(5, $options); + $this->assertCount(6, $options); $this->assertArrayHasKey(0, $options); $this->assertInstanceOf(SelectConfigOption::class, $options[0]); @@ -60,8 +66,15 @@ public function testGetOptions() $this->assertArrayHasKey(4, $options); $this->assertInstanceOf(TextConfigOption::class, $options[4]); $this->assertEquals('page-cache-redis-compress-data', $options[4]->getName()); + + $this->assertArrayHasKey(5, $options); + $this->assertInstanceOf(TextConfigOption::class, $options[5]); + $this->assertEquals('page-cache-redis-password', $options[5]->getName()); } + /** + * testCreateConfigWithRedis + */ public function testCreateConfigWithRedis() { $this->deploymentConfigMock->method('get')->willReturn(''); @@ -75,7 +88,8 @@ public function testCreateConfigWithRedis() 'server'=> '', 'port' => '', 'database' => '', - 'compress_data' => '' + 'compress_data' => '', + 'password' => '' ] ] ] @@ -87,6 +101,9 @@ public function testCreateConfigWithRedis() $this->assertEquals($expectedConfigData, $configData->getData()); } + /** + * testCreateConfigWithRedisConfiguration + */ public function testCreateConfigWithRedisConfiguration() { $expectedConfigData = [ @@ -98,7 +115,8 @@ public function testCreateConfigWithRedisConfiguration() 'server' => 'foo.bar', 'port' => '9000', 'database' => '6', - 'compress_data' => '1' + 'compress_data' => '1', + 'password' => '' ] ] ] @@ -118,6 +136,9 @@ public function testCreateConfigWithRedisConfiguration() $this->assertEquals($expectedConfigData, $configData->getData()); } + /** + * testValidationWithValidData + */ public function testValidationWithValidData() { $this->validatorMock->expects($this->once()) @@ -134,6 +155,9 @@ public function testValidationWithValidData() $this->assertEmpty($errors); } + /** + * testValidationWithInvalidData + */ public function testValidationWithInvalidData() { $options = [ diff --git a/setup/src/Magento/Setup/Test/Unit/Model/InstallerTest.php b/setup/src/Magento/Setup/Test/Unit/Model/InstallerTest.php index 882483ce7674a..8a4263be18ecf 100644 --- a/setup/src/Magento/Setup/Test/Unit/Model/InstallerTest.php +++ b/setup/src/Magento/Setup/Test/Unit/Model/InstallerTest.php @@ -4,635 +4,642 @@ * See COPYING.txt for license details. */ -namespace Magento\Setup\Test\Unit\Model; - -use Magento\Backend\Setup\ConfigOptionsList; -use Magento\Framework\Config\ConfigOptionsListConstants; -use Magento\Framework\Setup\SchemaListener; -use Magento\Setup\Model\DeclarationInstaller; -use Magento\Setup\Model\Installer; -use Magento\Framework\App\Filesystem\DirectoryList; -use Magento\Framework\Filesystem\DriverPool; -use Magento\Framework\Config\File\ConfigFilePool; -use Magento\Framework\App\State\CleanupFiles; -use Magento\Framework\Setup\Patch\PatchApplier; -use Magento\Framework\Setup\Patch\PatchApplierFactory; -use Magento\Setup\Validator\DbValidator; - -/** - * @SuppressWarnings(PHPMD.TooManyFields) - * @SuppressWarnings(PHPMD.CouplingBetweenObjects) - */ -class InstallerTest extends \PHPUnit\Framework\TestCase -{ - /** - * @var \Magento\Setup\Model\Installer - */ - private $object; - - /** - * @var \Magento\Framework\Setup\FilePermissions|\PHPUnit_Framework_MockObject_MockObject - */ - private $filePermissions; - - /** - * @var \Magento\Framework\App\DeploymentConfig\Writer|\PHPUnit_Framework_MockObject_MockObject - */ - private $configWriter; - - /** - * @var \Magento\Framework\App\DeploymentConfig\Reader|\PHPUnit_Framework_MockObject_MockObject - */ - private $configReader; - - /** - * @var \Magento\Framework\App\DeploymentConfig|\PHPUnit_Framework_MockObject_MockObject - */ - private $config; - - /** - * @var \Magento\Framework\Module\ModuleListInterface|\PHPUnit_Framework_MockObject_MockObject - */ - private $moduleList; - - /** - * @var \Magento\Framework\Module\ModuleList\Loader|\PHPUnit_Framework_MockObject_MockObject - */ - private $moduleLoader; - - /** - * @var \Magento\Framework\App\Filesystem\DirectoryList|\PHPUnit_Framework_MockObject_MockObject - */ - private $directoryList; - - /** - * @var \Magento\Setup\Model\AdminAccountFactory|\PHPUnit_Framework_MockObject_MockObject - */ - private $adminFactory; - - /** - * @var \Magento\Framework\Setup\LoggerInterface|\PHPUnit_Framework_MockObject_MockObject - */ - private $logger; - - /** - * @var \Magento\Framework\Math\Random|\PHPUnit_Framework_MockObject_MockObject - */ - private $random; - - /** - * @var \PHPUnit_Framework_MockObject_MockObject - */ - private $connection; - - /** - * @var \Magento\Framework\App\MaintenanceMode|\PHPUnit_Framework_MockObject_MockObject - */ - private $maintenanceMode; - - /** - * @var \Magento\Framework\Filesystem|\PHPUnit_Framework_MockObject_MockObject - */ - private $filesystem; - - /** - * @var \PHPUnit_Framework_MockObject_MockObject - */ - private $objectManager; - - /** - * @var \Magento\Setup\Model\ConfigModel|\PHPUnit_Framework_MockObject_MockObject - */ - private $configModel; - - /** - * @var CleanupFiles|\PHPUnit_Framework_MockObject_MockObject - */ - private $cleanupFiles; - - /** - * @var DbValidator|\PHPUnit_Framework_MockObject_MockObject - */ - private $dbValidator; - - /** - * @var \Magento\Setup\Module\SetupFactory|\PHPUnit_Framework_MockObject_MockObject - */ - private $setupFactory; - - /** - * @var \Magento\Setup\Module\DataSetupFactory|\PHPUnit_Framework_MockObject_MockObject - */ - private $dataSetupFactory; - - /** - * @var \Magento\Framework\Setup\SampleData\State|\PHPUnit_Framework_MockObject_MockObject - */ - private $sampleDataState; - - /** - * @var \Magento\Framework\Component\ComponentRegistrar|\PHPUnit_Framework_MockObject_MockObject - */ - private $componentRegistrar; - - /** - * @var \PHPUnit_Framework_MockObject_MockObject|\Magento\Setup\Model\PhpReadinessCheck - */ - private $phpReadinessCheck; - - /** - * @var \Magento\Framework\Setup\DeclarationInstaller|\PHPUnit_Framework_MockObject_MockObject - */ - private $declarationInstallerMock; - - /** - * @var SchemaListener|\PHPUnit_Framework_MockObject_MockObject - */ - private $schemaListenerMock; - - /** - * Sample DB configuration segment - * - * @var array - */ - private static $dbConfig = [ - 'default' => [ - ConfigOptionsListConstants::KEY_HOST => '127.0.0.1', - ConfigOptionsListConstants::KEY_NAME => 'magento', - ConfigOptionsListConstants::KEY_USER => 'magento', - ConfigOptionsListConstants::KEY_PASSWORD => '', - ] - ]; - - /** - * @var \Magento\Framework\Model\ResourceModel\Db\Context|\PHPUnit_Framework_MockObject_MockObject - */ - private $contextMock; - - /** - * @var PatchApplier|\PHPUnit_Framework_MockObject_MockObject - */ - private $patchApplierMock; - - /** - * @var PatchApplierFactory|\PHPUnit_Framework_MockObject_MockObject - */ - private $patchApplierFactoryMock; - - protected function setUp() +namespace Magento\Setup\Test\Unit\Model { + + use Magento\Backend\Setup\ConfigOptionsList; + use Magento\Framework\Config\ConfigOptionsListConstants; + use Magento\Framework\Setup\SchemaListener; + use Magento\Setup\Model\DeclarationInstaller; + use Magento\Setup\Model\Installer; + use Magento\Framework\App\Filesystem\DirectoryList; + use Magento\Framework\Filesystem\DriverPool; + use Magento\Framework\Config\File\ConfigFilePool; + use Magento\Framework\App\State\CleanupFiles; + use Magento\Framework\Setup\Patch\PatchApplier; + use Magento\Framework\Setup\Patch\PatchApplierFactory; + use Magento\Setup\Validator\DbValidator; + + /** + * @SuppressWarnings(PHPMD.TooManyFields) + * @SuppressWarnings(PHPMD.CouplingBetweenObjects) + */ + class InstallerTest extends \PHPUnit\Framework\TestCase { - $this->filePermissions = $this->createMock(\Magento\Framework\Setup\FilePermissions::class); - $this->configWriter = $this->createMock(\Magento\Framework\App\DeploymentConfig\Writer::class); - $this->configReader = $this->createMock(\Magento\Framework\App\DeploymentConfig\Reader::class); - $this->config = $this->createMock(\Magento\Framework\App\DeploymentConfig::class); - - $this->moduleList = $this->getMockForAbstractClass(\Magento\Framework\Module\ModuleListInterface::class); - $this->moduleList->expects($this->any())->method('getOne')->willReturn( - ['setup_version' => '2.0.0'] - ); - $this->moduleList->expects($this->any())->method('getNames')->willReturn( - ['Foo_One', 'Bar_Two'] - ); - $this->moduleLoader = $this->createMock(\Magento\Framework\Module\ModuleList\Loader::class); - $this->directoryList = - $this->createMock(\Magento\Framework\App\Filesystem\DirectoryList::class); - $this->adminFactory = $this->createMock(\Magento\Setup\Model\AdminAccountFactory::class); - $this->logger = $this->getMockForAbstractClass(\Magento\Framework\Setup\LoggerInterface::class); - $this->random = $this->createMock(\Magento\Framework\Math\Random::class); - $this->connection = $this->getMockForAbstractClass(\Magento\Framework\DB\Adapter\AdapterInterface::class); - $this->maintenanceMode = $this->createMock(\Magento\Framework\App\MaintenanceMode::class); - $this->filesystem = $this->createMock(\Magento\Framework\Filesystem::class); - $this->objectManager = $this->getMockForAbstractClass(\Magento\Framework\ObjectManagerInterface::class); - $this->contextMock = - $this->createMock(\Magento\Framework\Model\ResourceModel\Db\Context::class); - $this->configModel = $this->createMock(\Magento\Setup\Model\ConfigModel::class); - $this->cleanupFiles = $this->createMock(\Magento\Framework\App\State\CleanupFiles::class); - $this->dbValidator = $this->createMock(\Magento\Setup\Validator\DbValidator::class); - $this->setupFactory = $this->createMock(\Magento\Setup\Module\SetupFactory::class); - $this->dataSetupFactory = $this->createMock(\Magento\Setup\Module\DataSetupFactory::class); - $this->sampleDataState = $this->createMock(\Magento\Framework\Setup\SampleData\State::class); - $this->componentRegistrar = - $this->createMock(\Magento\Framework\Component\ComponentRegistrar::class); - $this->phpReadinessCheck = $this->createMock(\Magento\Setup\Model\PhpReadinessCheck::class); - $this->declarationInstallerMock = $this->createMock(DeclarationInstaller::class); - $this->schemaListenerMock = $this->createMock(SchemaListener::class); - $this->patchApplierFactoryMock = $this->createMock(PatchApplierFactory::class); - $this->patchApplierMock = $this->createMock(PatchApplier::class); - $this->patchApplierFactoryMock->expects($this->any())->method('create')->willReturn($this->patchApplierMock); - $this->object = $this->createObject(); - } + /** + * @var \Magento\Setup\Model\Installer + */ + private $object; + + /** + * @var \Magento\Framework\Setup\FilePermissions|\PHPUnit_Framework_MockObject_MockObject + */ + private $filePermissions; + + /** + * @var \Magento\Framework\App\DeploymentConfig\Writer|\PHPUnit_Framework_MockObject_MockObject + */ + private $configWriter; + + /** + * @var \Magento\Framework\App\DeploymentConfig\Reader|\PHPUnit_Framework_MockObject_MockObject + */ + private $configReader; + + /** + * @var \Magento\Framework\App\DeploymentConfig|\PHPUnit_Framework_MockObject_MockObject + */ + private $config; + + /** + * @var \Magento\Framework\Module\ModuleListInterface|\PHPUnit_Framework_MockObject_MockObject + */ + private $moduleList; + + /** + * @var \Magento\Framework\Module\ModuleList\Loader|\PHPUnit_Framework_MockObject_MockObject + */ + private $moduleLoader; + + /** + * @var \Magento\Framework\App\Filesystem\DirectoryList|\PHPUnit_Framework_MockObject_MockObject + */ + private $directoryList; + + /** + * @var \Magento\Setup\Model\AdminAccountFactory|\PHPUnit_Framework_MockObject_MockObject + */ + private $adminFactory; + + /** + * @var \Magento\Framework\Setup\LoggerInterface|\PHPUnit_Framework_MockObject_MockObject + */ + private $logger; + + /** + * @var \Magento\Framework\Math\Random|\PHPUnit_Framework_MockObject_MockObject + */ + private $random; + + /** + * @var \PHPUnit_Framework_MockObject_MockObject + */ + private $connection; + + /** + * @var \Magento\Framework\App\MaintenanceMode|\PHPUnit_Framework_MockObject_MockObject + */ + private $maintenanceMode; + + /** + * @var \Magento\Framework\Filesystem|\PHPUnit_Framework_MockObject_MockObject + */ + private $filesystem; + + /** + * @var \PHPUnit_Framework_MockObject_MockObject + */ + private $objectManager; + + /** + * @var \Magento\Setup\Model\ConfigModel|\PHPUnit_Framework_MockObject_MockObject + */ + private $configModel; + + /** + * @var CleanupFiles|\PHPUnit_Framework_MockObject_MockObject + */ + private $cleanupFiles; + + /** + * @var DbValidator|\PHPUnit_Framework_MockObject_MockObject + */ + private $dbValidator; + + /** + * @var \Magento\Setup\Module\SetupFactory|\PHPUnit_Framework_MockObject_MockObject + */ + private $setupFactory; + + /** + * @var \Magento\Setup\Module\DataSetupFactory|\PHPUnit_Framework_MockObject_MockObject + */ + private $dataSetupFactory; + + /** + * @var \Magento\Framework\Setup\SampleData\State|\PHPUnit_Framework_MockObject_MockObject + */ + private $sampleDataState; + + /** + * @var \Magento\Framework\Component\ComponentRegistrar|\PHPUnit_Framework_MockObject_MockObject + */ + private $componentRegistrar; + + /** + * @var \PHPUnit_Framework_MockObject_MockObject|\Magento\Setup\Model\PhpReadinessCheck + */ + private $phpReadinessCheck; + + /** + * @var \Magento\Framework\Setup\DeclarationInstaller|\PHPUnit_Framework_MockObject_MockObject + */ + private $declarationInstallerMock; + + /** + * @var SchemaListener|\PHPUnit_Framework_MockObject_MockObject + */ + private $schemaListenerMock; + + /** + * Sample DB configuration segment + * @var array + */ + private static $dbConfig = [ + 'default' => [ + ConfigOptionsListConstants::KEY_HOST => '127.0.0.1', + ConfigOptionsListConstants::KEY_NAME => 'magento', + ConfigOptionsListConstants::KEY_USER => 'magento', + ConfigOptionsListConstants::KEY_PASSWORD => '', + ] + ]; - /** - * Instantiates the object with mocks - * - * @param \PHPUnit_Framework_MockObject_MockObject|bool $connectionFactory - * @param \PHPUnit_Framework_MockObject_MockObject|bool $objectManagerProvider - * @return Installer - */ - private function createObject($connectionFactory = false, $objectManagerProvider = false) - { - if (!$connectionFactory) { - $connectionFactory = $this->createMock(\Magento\Setup\Module\ConnectionFactory::class); - $connectionFactory->expects($this->any())->method('create')->willReturn($this->connection); - } - if (!$objectManagerProvider) { - $objectManagerProvider = - $this->createMock(\Magento\Setup\Model\ObjectManagerProvider::class); - $objectManagerProvider->expects($this->any())->method('get')->willReturn($this->objectManager); + /** + * @var \Magento\Framework\Model\ResourceModel\Db\Context|\PHPUnit_Framework_MockObject_MockObject + */ + private $contextMock; + + /** + * @var PatchApplier|\PHPUnit_Framework_MockObject_MockObject + */ + private $patchApplierMock; + + /** + * @var PatchApplierFactory|\PHPUnit_Framework_MockObject_MockObject + */ + private $patchApplierFactoryMock; + + protected function setUp() + { + $this->filePermissions = $this->createMock(\Magento\Framework\Setup\FilePermissions::class); + $this->configWriter = $this->createMock(\Magento\Framework\App\DeploymentConfig\Writer::class); + $this->configReader = $this->createMock(\Magento\Framework\App\DeploymentConfig\Reader::class); + $this->config = $this->createMock(\Magento\Framework\App\DeploymentConfig::class); + + $this->moduleList = $this->getMockForAbstractClass(\Magento\Framework\Module\ModuleListInterface::class); + $this->moduleList->expects($this->any())->method('getOne')->willReturn( + ['setup_version' => '2.0.0'] + ); + $this->moduleList->expects($this->any())->method('getNames')->willReturn( + ['Foo_One', 'Bar_Two'] + ); + $this->moduleLoader = $this->createMock(\Magento\Framework\Module\ModuleList\Loader::class); + $this->directoryList = + $this->createMock(\Magento\Framework\App\Filesystem\DirectoryList::class); + $this->adminFactory = $this->createMock(\Magento\Setup\Model\AdminAccountFactory::class); + $this->logger = $this->getMockForAbstractClass(\Magento\Framework\Setup\LoggerInterface::class); + $this->random = $this->createMock(\Magento\Framework\Math\Random::class); + $this->connection = $this->getMockForAbstractClass(\Magento\Framework\DB\Adapter\AdapterInterface::class); + $this->maintenanceMode = $this->createMock(\Magento\Framework\App\MaintenanceMode::class); + $this->filesystem = $this->createMock(\Magento\Framework\Filesystem::class); + $this->objectManager = $this->getMockForAbstractClass(\Magento\Framework\ObjectManagerInterface::class); + $this->contextMock = + $this->createMock(\Magento\Framework\Model\ResourceModel\Db\Context::class); + $this->configModel = $this->createMock(\Magento\Setup\Model\ConfigModel::class); + $this->cleanupFiles = $this->createMock(\Magento\Framework\App\State\CleanupFiles::class); + $this->dbValidator = $this->createMock(\Magento\Setup\Validator\DbValidator::class); + $this->setupFactory = $this->createMock(\Magento\Setup\Module\SetupFactory::class); + $this->dataSetupFactory = $this->createMock(\Magento\Setup\Module\DataSetupFactory::class); + $this->sampleDataState = $this->createMock(\Magento\Framework\Setup\SampleData\State::class); + $this->componentRegistrar = + $this->createMock(\Magento\Framework\Component\ComponentRegistrar::class); + $this->phpReadinessCheck = $this->createMock(\Magento\Setup\Model\PhpReadinessCheck::class); + $this->declarationInstallerMock = $this->createMock(DeclarationInstaller::class); + $this->schemaListenerMock = $this->createMock(SchemaListener::class); + $this->patchApplierFactoryMock = $this->createMock(PatchApplierFactory::class); + $this->patchApplierMock = $this->createMock(PatchApplier::class); + $this->patchApplierFactoryMock->expects($this->any())->method('create')->willReturn( + $this->patchApplierMock + ); + $this->object = $this->createObject(); } - return new Installer( - $this->filePermissions, - $this->configWriter, - $this->configReader, - $this->config, - $this->moduleList, - $this->moduleLoader, - $this->adminFactory, - $this->logger, - $connectionFactory, - $this->maintenanceMode, - $this->filesystem, - $objectManagerProvider, - $this->contextMock, - $this->configModel, - $this->cleanupFiles, - $this->dbValidator, - $this->setupFactory, - $this->dataSetupFactory, - $this->sampleDataState, - $this->componentRegistrar, - $this->phpReadinessCheck, - $this->declarationInstallerMock - ); - } + /** + * Instantiates the object with mocks + * @param \PHPUnit_Framework_MockObject_MockObject|bool $connectionFactory + * @param \PHPUnit_Framework_MockObject_MockObject|bool $objectManagerProvider + * @return Installer + */ + private function createObject($connectionFactory = false, $objectManagerProvider = false) + { + if (!$connectionFactory) { + $connectionFactory = $this->createMock(\Magento\Setup\Module\ConnectionFactory::class); + $connectionFactory->expects($this->any())->method('create')->willReturn($this->connection); + } + if (!$objectManagerProvider) { + $objectManagerProvider = + $this->createMock(\Magento\Setup\Model\ObjectManagerProvider::class); + $objectManagerProvider->expects($this->any())->method('get')->willReturn($this->objectManager); + } + + return new Installer( + $this->filePermissions, + $this->configWriter, + $this->configReader, + $this->config, + $this->moduleList, + $this->moduleLoader, + $this->adminFactory, + $this->logger, + $connectionFactory, + $this->maintenanceMode, + $this->filesystem, + $objectManagerProvider, + $this->contextMock, + $this->configModel, + $this->cleanupFiles, + $this->dbValidator, + $this->setupFactory, + $this->dataSetupFactory, + $this->sampleDataState, + $this->componentRegistrar, + $this->phpReadinessCheck, + $this->declarationInstallerMock + ); + } - /** - * @SuppressWarnings(PHPMD.ExcessiveMethodLength) - */ - public function testInstall() - { - $request = [ - ConfigOptionsListConstants::INPUT_KEY_DB_HOST => '127.0.0.1', - ConfigOptionsListConstants::INPUT_KEY_DB_NAME => 'magento', - ConfigOptionsListConstants::INPUT_KEY_DB_USER => 'magento', - ConfigOptionsListConstants::INPUT_KEY_ENCRYPTION_KEY => 'encryption_key', - ConfigOptionsList::INPUT_KEY_BACKEND_FRONTNAME => 'backend', - ]; - $this->config->expects($this->atLeastOnce()) - ->method('get') - ->willReturnMap( + /** + * @SuppressWarnings(PHPMD.ExcessiveMethodLength) + */ + public function testInstall() + { + $request = [ + ConfigOptionsListConstants::INPUT_KEY_DB_HOST => '127.0.0.1', + ConfigOptionsListConstants::INPUT_KEY_DB_NAME => 'magento', + ConfigOptionsListConstants::INPUT_KEY_DB_USER => 'magento', + ConfigOptionsListConstants::INPUT_KEY_ENCRYPTION_KEY => 'encryption_key', + ConfigOptionsList::INPUT_KEY_BACKEND_FRONTNAME => 'backend', + ]; + $this->config->expects($this->atLeastOnce()) + ->method('get') + ->willReturnMap( + [ + [ConfigOptionsListConstants::CONFIG_PATH_DB_CONNECTION_DEFAULT, null, true], + [ConfigOptionsListConstants::CONFIG_PATH_CRYPT_KEY, null, true], + ['modules/Magento_User', null, '1'] + ] + ); + $allModules = ['Foo_One' => [], 'Bar_Two' => []]; + + $this->declarationInstallerMock->expects($this->once())->method('installSchema'); + $this->moduleLoader->expects($this->any())->method('load')->willReturn($allModules); + $setup = $this->createMock(\Magento\Setup\Module\Setup::class); + $table = $this->createMock(\Magento\Framework\DB\Ddl\Table::class); + $connection = $this->getMockBuilder(\Magento\Framework\DB\Adapter\AdapterInterface::class) + ->setMethods(['getSchemaListener', 'newTable']) + ->getMockForAbstractClass(); + $connection->expects($this->any())->method('getSchemaListener')->willReturn($this->schemaListenerMock); + $setup->expects($this->any())->method('getConnection')->willReturn($connection); + $table->expects($this->any())->method('addColumn')->willReturn($table); + $table->expects($this->any())->method('setComment')->willReturn($table); + $table->expects($this->any())->method('addIndex')->willReturn($table); + $connection->expects($this->any())->method('newTable')->willReturn($table); + $resource = $this->createMock(\Magento\Framework\App\ResourceConnection::class); + $this->contextMock->expects($this->any())->method('getResources')->willReturn($resource); + $resource->expects($this->any())->method('getConnection')->will($this->returnValue($connection)); + $dataSetup = $this->createMock(\Magento\Setup\Module\DataSetup::class); + $dataSetup->expects($this->any())->method('getConnection')->willReturn($connection); + $cacheManager = $this->createMock(\Magento\Framework\App\Cache\Manager::class); + $cacheManager->expects($this->any())->method('getAvailableTypes')->willReturn(['foo', 'bar']); + $cacheManager->expects($this->once())->method('setEnabled')->willReturn(['foo', 'bar']); + $cacheManager->expects($this->any())->method('clean'); + $appState = $this->getMockBuilder(\Magento\Framework\App\State::class) + ->disableOriginalConstructor() + ->disableArgumentCloning() + ->getMock(); + $appState->expects($this->once()) + ->method('setAreaCode') + ->with(\Magento\Framework\App\Area::AREA_GLOBAL); + $registry = $this->createMock(\Magento\Framework\Registry::class); + $this->setupFactory->expects($this->atLeastOnce())->method('create')->with($resource)->willReturn($setup); + $this->dataSetupFactory->expects($this->atLeastOnce())->method('create')->willReturn($dataSetup); + $this->objectManager->expects($this->any()) + ->method('create') + ->will($this->returnValueMap([ + [\Magento\Framework\App\Cache\Manager::class, [], $cacheManager], + [\Magento\Framework\App\State::class, [], $appState], + [ + PatchApplierFactory::class, + ['objectManager' => $this->objectManager], + $this->patchApplierFactoryMock + ], + ])); + $this->patchApplierMock->expects($this->exactly(2))->method('applySchemaPatch')->willReturnMap( [ - [ConfigOptionsListConstants::CONFIG_PATH_DB_CONNECTION_DEFAULT, null, true], - [ConfigOptionsListConstants::CONFIG_PATH_CRYPT_KEY, null, true], - ['modules/Magento_User', null, '1'] + ['Bar_Two'], + ['Foo_One'], ] ); - $allModules = ['Foo_One' => [], 'Bar_Two' => []]; - - $this->declarationInstallerMock->expects($this->once())->method('installSchema'); - $this->moduleLoader->expects($this->any())->method('load')->willReturn($allModules); - $setup = $this->createMock(\Magento\Setup\Module\Setup::class); - $table = $this->createMock(\Magento\Framework\DB\Ddl\Table::class); - $connection = $this->getMockBuilder(\Magento\Framework\DB\Adapter\AdapterInterface::class) - ->setMethods(['getSchemaListener', 'newTable']) - ->getMockForAbstractClass(); - $connection->expects($this->any())->method('getSchemaListener')->willReturn($this->schemaListenerMock); - $setup->expects($this->any())->method('getConnection')->willReturn($connection); - $table->expects($this->any())->method('addColumn')->willReturn($table); - $table->expects($this->any())->method('setComment')->willReturn($table); - $table->expects($this->any())->method('addIndex')->willReturn($table); - $connection->expects($this->any())->method('newTable')->willReturn($table); - $resource = $this->createMock(\Magento\Framework\App\ResourceConnection::class); - $this->contextMock->expects($this->any())->method('getResources')->willReturn($resource); - $resource->expects($this->any())->method('getConnection')->will($this->returnValue($connection)); - $dataSetup = $this->createMock(\Magento\Setup\Module\DataSetup::class); - $dataSetup->expects($this->any())->method('getConnection')->willReturn($connection); - $cacheManager = $this->createMock(\Magento\Framework\App\Cache\Manager::class); - $cacheManager->expects($this->any())->method('getAvailableTypes')->willReturn(['foo', 'bar']); - $cacheManager->expects($this->once())->method('setEnabled')->willReturn(['foo', 'bar']); - $cacheManager->expects($this->any())->method('clean'); - $appState = $this->getMockBuilder(\Magento\Framework\App\State::class) - ->disableOriginalConstructor() - ->disableArgumentCloning() - ->getMock(); - $appState->expects($this->once()) - ->method('setAreaCode') - ->with(\Magento\Framework\App\Area::AREA_GLOBAL); - $registry = $this->createMock(\Magento\Framework\Registry::class); - $this->setupFactory->expects($this->atLeastOnce())->method('create')->with($resource)->willReturn($setup); - $this->dataSetupFactory->expects($this->atLeastOnce())->method('create')->willReturn($dataSetup); - $this->objectManager->expects($this->any()) - ->method('create') - ->will($this->returnValueMap([ - [\Magento\Framework\App\Cache\Manager::class, [], $cacheManager], - [\Magento\Framework\App\State::class, [], $appState], + $this->patchApplierMock->expects($this->exactly(2))->method('applyDataPatch')->willReturnMap( [ - PatchApplierFactory::class, - ['objectManager' => $this->objectManager], - $this->patchApplierFactoryMock - ], - ])); - $this->patchApplierMock->expects($this->exactly(2))->method('applySchemaPatch')->willReturnMap( - [ - ['Bar_Two'], - ['Foo_One'], - ] - ); - $this->patchApplierMock->expects($this->exactly(2))->method('applyDataPatch')->willReturnMap( - [ - ['Bar_Two'], - ['Foo_One'], - ] - ); - $this->objectManager->expects($this->any()) - ->method('get') - ->will($this->returnValueMap([ - [\Magento\Framework\App\State::class, $appState], - [\Magento\Framework\App\Cache\Manager::class, $cacheManager], - [\Magento\Setup\Model\DeclarationInstaller::class, $this->declarationInstallerMock], - [\Magento\Framework\Registry::class, $registry] - ])); - $this->adminFactory->expects($this->once())->method('create')->willReturn( - $this->createMock(\Magento\Setup\Model\AdminAccount::class) - ); - $this->sampleDataState->expects($this->once())->method('hasError')->willReturn(true); - $this->phpReadinessCheck->expects($this->once())->method('checkPhpExtensions')->willReturn( - ['responseType' => \Magento\Setup\Controller\ResponseTypeInterface::RESPONSE_TYPE_SUCCESS] - ); - $this->filePermissions->expects($this->any()) - ->method('getMissingWritablePathsForInstallation') - ->willReturn([]); - $this->filePermissions->expects($this->once()) - ->method('getMissingWritableDirectoriesForDbUpgrade') - ->willReturn([]); - $this->setupLoggerExpectsForInstall(); - - $this->object->install($request); - } - - public function testCheckInstallationFilePermissions() - { - $this->filePermissions - ->expects($this->once()) - ->method('getMissingWritablePathsForInstallation') - ->willReturn([]); - $this->object->checkInstallationFilePermissions(); - } - - /** - * @expectedException \Exception - * @expectedExceptionMessage Missing write permissions to the following paths: - */ - public function testCheckInstallationFilePermissionsError() - { - $this->filePermissions - ->expects($this->once()) - ->method('getMissingWritablePathsForInstallation') - ->willReturn(['foo', 'bar']); - $this->object->checkInstallationFilePermissions(); - } + ['Bar_Two'], + ['Foo_One'], + ] + ); + $this->objectManager->expects($this->any()) + ->method('get') + ->will($this->returnValueMap([ + [\Magento\Framework\App\State::class, $appState], + [\Magento\Framework\App\Cache\Manager::class, $cacheManager], + [\Magento\Setup\Model\DeclarationInstaller::class, $this->declarationInstallerMock], + [\Magento\Framework\Registry::class, $registry] + ])); + $this->adminFactory->expects($this->once())->method('create')->willReturn( + $this->createMock(\Magento\Setup\Model\AdminAccount::class) + ); + $this->sampleDataState->expects($this->once())->method('hasError')->willReturn(true); + $this->phpReadinessCheck->expects($this->once())->method('checkPhpExtensions')->willReturn( + ['responseType' => \Magento\Setup\Controller\ResponseTypeInterface::RESPONSE_TYPE_SUCCESS] + ); + $this->filePermissions->expects($this->any()) + ->method('getMissingWritablePathsForInstallation') + ->willReturn([]); + $this->filePermissions->expects($this->once()) + ->method('getMissingWritableDirectoriesForDbUpgrade') + ->willReturn([]); + $this->setupLoggerExpectsForInstall(); + + $this->object->install($request); + } - public function testCheckExtensions() - { - $this->phpReadinessCheck->expects($this->once())->method('checkPhpExtensions')->willReturn( - ['responseType' => \Magento\Setup\Controller\ResponseTypeInterface::RESPONSE_TYPE_SUCCESS] - ); - $this->object->checkExtensions(); - } + public function testCheckInstallationFilePermissions() + { + $this->filePermissions + ->expects($this->once()) + ->method('getMissingWritablePathsForInstallation') + ->willReturn([]); + $this->object->checkInstallationFilePermissions(); + } - /** - * @expectedException \Exception - * @expectedExceptionMessage Missing following extensions: 'foo' - */ - public function testCheckExtensionsError() - { - $this->phpReadinessCheck->expects($this->once())->method('checkPhpExtensions')->willReturn( - ['responseType' => \Magento\Setup\Controller\ResponseTypeInterface::RESPONSE_TYPE_ERROR, - 'data'=>['required'=>['foo', 'bar'], 'missing'=>['foo']]] - ); - $this->object->checkExtensions(); - } + /** + * @expectedException \Exception + * @expectedExceptionMessage Missing write permissions to the following paths: + */ + public function testCheckInstallationFilePermissionsError() + { + $this->filePermissions + ->expects($this->once()) + ->method('getMissingWritablePathsForInstallation') + ->willReturn(['foo', 'bar']); + $this->object->checkInstallationFilePermissions(); + } - public function testCheckApplicationFilePermissions() - { - $this->filePermissions - ->expects($this->once()) - ->method('getUnnecessaryWritableDirectoriesForApplication') - ->willReturn(['foo', 'bar']); - $expectedMessage = "For security, remove write permissions from these directories: 'foo' 'bar'"; - $this->logger->expects($this->once())->method('log')->with($expectedMessage); - $this->object->checkApplicationFilePermissions(); - $this->assertSame(['message' => [$expectedMessage]], $this->object->getInstallInfo()); - } + public function testCheckExtensions() + { + $this->phpReadinessCheck->expects($this->once())->method('checkPhpExtensions')->willReturn( + ['responseType' => \Magento\Setup\Controller\ResponseTypeInterface::RESPONSE_TYPE_SUCCESS] + ); + $this->object->checkExtensions(); + } - public function testUpdateModulesSequence() - { - $this->cleanupFiles->expects($this->once())->method('clearCodeGeneratedFiles')->will( - $this->returnValue( + /** + * @expectedException \Exception + * @expectedExceptionMessage Missing following extensions: 'foo' + */ + public function testCheckExtensionsError() + { + $this->phpReadinessCheck->expects($this->once())->method('checkPhpExtensions')->willReturn( [ - "The directory '/generation' doesn't exist - skipping cleanup", + 'responseType' => \Magento\Setup\Controller\ResponseTypeInterface::RESPONSE_TYPE_ERROR, + 'data' => ['required' => ['foo', 'bar'], 'missing' => ['foo']] ] - ) - ); - $installer = $this->prepareForUpdateModulesTests(); - - $this->logger->expects($this->at(0))->method('log')->with('Cache cleared successfully'); - $this->logger->expects($this->at(1))->method('log')->with('File system cleanup:'); - $this->logger->expects($this->at(2))->method('log') - ->with('The directory \'/generation\' doesn\'t exist - skipping cleanup'); - $this->logger->expects($this->at(3))->method('log')->with('Updating modules:'); - $installer->updateModulesSequence(false); - } + ); + $this->object->checkExtensions(); + } - public function testUpdateModulesSequenceKeepGenerated() - { - $this->cleanupFiles->expects($this->never())->method('clearCodeGeneratedClasses'); + public function testCheckApplicationFilePermissions() + { + $this->filePermissions + ->expects($this->once()) + ->method('getUnnecessaryWritableDirectoriesForApplication') + ->willReturn(['foo', 'bar']); + $expectedMessage = "For security, remove write permissions from these directories: 'foo' 'bar'"; + $this->logger->expects($this->once())->method('log')->with($expectedMessage); + $this->object->checkApplicationFilePermissions(); + $this->assertSame(['message' => [$expectedMessage]], $this->object->getInstallInfo()); + } - $installer = $this->prepareForUpdateModulesTests(); + public function testUpdateModulesSequence() + { + $this->cleanupFiles->expects($this->once())->method('clearCodeGeneratedFiles')->will( + $this->returnValue( + [ + "The directory '/generation' doesn't exist - skipping cleanup", + ] + ) + ); + $installer = $this->prepareForUpdateModulesTests(); + + $this->logger->expects($this->at(0))->method('log')->with('Cache cleared successfully'); + $this->logger->expects($this->at(1))->method('log')->with('File system cleanup:'); + $this->logger->expects($this->at(2))->method('log') + ->with('The directory \'/generation\' doesn\'t exist - skipping cleanup'); + $this->logger->expects($this->at(3))->method('log')->with('Updating modules:'); + $installer->updateModulesSequence(false); + } - $this->logger->expects($this->at(0))->method('log')->with('Cache cleared successfully'); - $this->logger->expects($this->at(1))->method('log')->with('Updating modules:'); - $installer->updateModulesSequence(true); - } + public function testUpdateModulesSequenceKeepGenerated() + { + $this->cleanupFiles->expects($this->never())->method('clearCodeGeneratedClasses'); - public function testUninstall() - { - $this->config->expects($this->once()) - ->method('get') - ->with(ConfigOptionsListConstants::CONFIG_PATH_DB_CONNECTIONS) - ->willReturn([]); - $this->configReader->expects($this->once())->method('getFiles')->willReturn(['ConfigOne.php', 'ConfigTwo.php']); - $configDir = $this->getMockForAbstractClass( - \Magento\Framework\Filesystem\Directory\WriteInterface::class - ); - $configDir - ->expects($this->exactly(2)) - ->method('getAbsolutePath') - ->will( - $this->returnValueMap( + $installer = $this->prepareForUpdateModulesTests(); + + $this->logger->expects($this->at(0))->method('log')->with('Cache cleared successfully'); + $this->logger->expects($this->at(1))->method('log')->with('Updating modules:'); + $installer->updateModulesSequence(true); + } + + public function testUninstall() + { + $this->config->expects($this->once()) + ->method('get') + ->with(ConfigOptionsListConstants::CONFIG_PATH_DB_CONNECTIONS) + ->willReturn([]); + $this->configReader->expects($this->once())->method('getFiles')->willReturn([ + 'ConfigOne.php', + 'ConfigTwo.php' + ]); + $configDir = $this->getMockForAbstractClass( + \Magento\Framework\Filesystem\Directory\WriteInterface::class + ); + $configDir + ->expects($this->exactly(2)) + ->method('getAbsolutePath') + ->will( + $this->returnValueMap( + [ + ['ConfigOne.php', '/config/ConfigOne.php'], + ['ConfigTwo.php', '/config/ConfigTwo.php'] + ] + ) + ); + $this->filesystem + ->expects($this->any()) + ->method('getDirectoryWrite') + ->will($this->returnValueMap([ + [DirectoryList::CONFIG, DriverPool::FILE, $configDir], + ])); + $this->logger->expects($this->at(0))->method('log')->with('Starting Magento uninstallation:'); + $this->logger + ->expects($this->at(2)) + ->method('log') + ->with('No database connection defined - skipping database cleanup'); + $cacheManager = $this->createMock(\Magento\Framework\App\Cache\Manager::class); + $cacheManager->expects($this->once())->method('getAvailableTypes')->willReturn(['foo', 'bar']); + $cacheManager->expects($this->once())->method('clean'); + $this->objectManager->expects($this->any()) + ->method('get') + ->with(\Magento\Framework\App\Cache\Manager::class) + ->willReturn($cacheManager); + $this->logger->expects($this->at(1))->method('log')->with('Cache cleared successfully'); + $this->logger->expects($this->at(3))->method('log')->with('File system cleanup:'); + $this->logger + ->expects($this->at(4)) + ->method('log') + ->with("The directory '/var' doesn't exist - skipping cleanup"); + $this->logger + ->expects($this->at(5)) + ->method('log') + ->with("The directory '/static' doesn't exist - skipping cleanup"); + $this->logger + ->expects($this->at(6)) + ->method('log') + ->with("The file '/config/ConfigOne.php' doesn't exist - skipping cleanup"); + $this->logger + ->expects($this->at(7)) + ->method('log') + ->with("The file '/config/ConfigTwo.php' doesn't exist - skipping cleanup"); + $this->logger->expects($this->once())->method('logSuccess')->with('Magento uninstallation complete.'); + $this->cleanupFiles->expects($this->once())->method('clearAllFiles')->will( + $this->returnValue( [ - ['ConfigOne.php', '/config/ConfigOne.php'], - ['ConfigTwo.php', '/config/ConfigTwo.php'] + "The directory '/var' doesn't exist - skipping cleanup", + "The directory '/static' doesn't exist - skipping cleanup" ] ) ); - $this->filesystem - ->expects($this->any()) - ->method('getDirectoryWrite') - ->will($this->returnValueMap([ - [DirectoryList::CONFIG, DriverPool::FILE, $configDir], - ])); - $this->logger->expects($this->at(0))->method('log')->with('Starting Magento uninstallation:'); - $this->logger - ->expects($this->at(2)) - ->method('log') - ->with('No database connection defined - skipping database cleanup'); - $cacheManager = $this->createMock(\Magento\Framework\App\Cache\Manager::class); - $cacheManager->expects($this->once())->method('getAvailableTypes')->willReturn(['foo', 'bar']); - $cacheManager->expects($this->once())->method('clean'); - $this->objectManager->expects($this->any()) - ->method('get') - ->with(\Magento\Framework\App\Cache\Manager::class) - ->willReturn($cacheManager); - $this->logger->expects($this->at(1))->method('log')->with('Cache cleared successfully'); - $this->logger->expects($this->at(3))->method('log')->with('File system cleanup:'); - $this->logger - ->expects($this->at(4)) - ->method('log') - ->with("The directory '/var' doesn't exist - skipping cleanup"); - $this->logger - ->expects($this->at(5)) - ->method('log') - ->with("The directory '/static' doesn't exist - skipping cleanup"); - $this->logger - ->expects($this->at(6)) - ->method('log') - ->with("The file '/config/ConfigOne.php' doesn't exist - skipping cleanup"); - $this->logger - ->expects($this->at(7)) - ->method('log') - ->with("The file '/config/ConfigTwo.php' doesn't exist - skipping cleanup"); - $this->logger->expects($this->once())->method('logSuccess')->with('Magento uninstallation complete.'); - $this->cleanupFiles->expects($this->once())->method('clearAllFiles')->will( - $this->returnValue( - [ - "The directory '/var' doesn't exist - skipping cleanup", - "The directory '/static' doesn't exist - skipping cleanup" - ] - ) - ); - - $this->object->uninstall(); - } - public function testCleanupDb() - { - $this->config->expects($this->once()) - ->method('get') - ->with(ConfigOptionsListConstants::CONFIG_PATH_DB_CONNECTIONS) - ->willReturn(self::$dbConfig); - $this->connection->expects($this->at(0))->method('quoteIdentifier')->with('magento')->willReturn('`magento`'); - $this->connection->expects($this->at(1))->method('query')->with('DROP DATABASE IF EXISTS `magento`'); - $this->connection->expects($this->at(2))->method('query')->with('CREATE DATABASE IF NOT EXISTS `magento`'); - $this->logger->expects($this->once())->method('log')->with('Cleaning up database `magento`'); - $this->object->cleanupDb(); - } + $this->object->uninstall(); + } - /** - * Prepare mocks for update modules tests and returns the installer to use - * - * @return Installer - */ - private function prepareForUpdateModulesTests() - { - $allModules = [ - 'Foo_One' => [], - 'Bar_Two' => [], - 'New_Module' => [], - ]; + public function testCleanupDb() + { + $this->config->expects($this->once()) + ->method('get') + ->with(ConfigOptionsListConstants::CONFIG_PATH_DB_CONNECTIONS) + ->willReturn(self::$dbConfig); + $this->connection->expects($this->at(0))->method('quoteIdentifier')->with('magento')->willReturn( + '`magento`' + ); + $this->connection->expects($this->at(1))->method('query')->with('DROP DATABASE IF EXISTS `magento`'); + $this->connection->expects($this->at(2))->method('query')->with('CREATE DATABASE IF NOT EXISTS `magento`'); + $this->logger->expects($this->once())->method('log')->with('Cleaning up database `magento`'); + $this->object->cleanupDb(); + } - $cacheManager = $this->createMock(\Magento\Framework\App\Cache\Manager::class); - $cacheManager->expects($this->once())->method('getAvailableTypes')->willReturn(['foo', 'bar']); - $cacheManager->expects($this->once())->method('clean'); - $this->objectManager->expects($this->any()) - ->method('get') - ->will($this->returnValueMap([ - [\Magento\Framework\App\Cache\Manager::class, $cacheManager] - ])); - $this->moduleLoader->expects($this->once())->method('load')->willReturn($allModules); - - $expectedModules = [ - ConfigFilePool::APP_CONFIG => [ - 'modules' => [ - 'Bar_Two' => 0, - 'Foo_One' => 1, - 'New_Module' => 1 + /** + * Prepare mocks for update modules tests and returns the installer to use + * @return Installer + */ + private function prepareForUpdateModulesTests() + { + $allModules = [ + 'Foo_One' => [], + 'Bar_Two' => [], + 'New_Module' => [], + ]; + + $cacheManager = $this->createMock(\Magento\Framework\App\Cache\Manager::class); + $cacheManager->expects($this->once())->method('getAvailableTypes')->willReturn(['foo', 'bar']); + $cacheManager->expects($this->once())->method('clean'); + $this->objectManager->expects($this->any()) + ->method('get') + ->will($this->returnValueMap([ + [\Magento\Framework\App\Cache\Manager::class, $cacheManager] + ])); + $this->moduleLoader->expects($this->once())->method('load')->willReturn($allModules); + + $expectedModules = [ + ConfigFilePool::APP_CONFIG => [ + 'modules' => [ + 'Bar_Two' => 0, + 'Foo_One' => 1, + 'New_Module' => 1 + ] ] - ] - ]; + ]; + + $this->config->expects($this->atLeastOnce()) + ->method('get') + ->with(ConfigOptionsListConstants::KEY_MODULES) + ->willReturn(true); - $this->config->expects($this->atLeastOnce()) - ->method('get') - ->with(ConfigOptionsListConstants::KEY_MODULES) - ->willReturn(true); + $newObject = $this->createObject(false, false); + $this->configReader->expects($this->once())->method('load') + ->willReturn(['modules' => ['Bar_Two' => 0, 'Foo_One' => 1, 'Old_Module' => 0]]); + $this->configWriter->expects($this->once())->method('saveConfig')->with($expectedModules); - $newObject = $this->createObject(false, false); - $this->configReader->expects($this->once())->method('load') - ->willReturn(['modules' => ['Bar_Two' => 0, 'Foo_One' => 1, 'Old_Module' => 0] ]); - $this->configWriter->expects($this->once())->method('saveConfig')->with($expectedModules); + return $newObject; + } - return $newObject; + /** + * Set up logger expectations for install method + * @return void + */ + private function setupLoggerExpectsForInstall() + { + $this->logger->expects($this->at(0))->method('log')->with('Starting Magento installation:'); + $this->logger->expects($this->at(1))->method('log')->with('File permissions check...'); + $this->logger->expects($this->at(3))->method('log')->with('Required extensions check...'); + // at(2) invokes logMeta() + $this->logger->expects($this->at(5))->method('log')->with('Enabling Maintenance Mode...'); + // at(4) - logMeta and so on... + $this->logger->expects($this->at(7))->method('log')->with('Installing deployment configuration...'); + $this->logger->expects($this->at(9))->method('log')->with('Installing database schema:'); + $this->logger->expects($this->at(11))->method('log')->with("Module 'Foo_One':"); + $this->logger->expects($this->at(13))->method('log')->with("Module 'Bar_Two':"); + $this->logger->expects($this->at(15))->method('log')->with('Schema post-updates:'); + $this->logger->expects($this->at(16))->method('log')->with("Module 'Foo_One':"); + $this->logger->expects($this->at(18))->method('log')->with("Module 'Bar_Two':"); + $this->logger->expects($this->at(21))->method('log')->with('Installing user configuration...'); + $this->logger->expects($this->at(23))->method('log')->with('Enabling caches:'); + $this->logger->expects($this->at(27))->method('log')->with('Installing data...'); + $this->logger->expects($this->at(28))->method('log')->with('Data install/update:'); + $this->logger->expects($this->at(29))->method('log')->with("Module 'Foo_One':"); + $this->logger->expects($this->at(31))->method('log')->with("Module 'Bar_Two':"); + $this->logger->expects($this->at(33))->method('log')->with('Data post-updates:'); + $this->logger->expects($this->at(34))->method('log')->with("Module 'Foo_One':"); + $this->logger->expects($this->at(36))->method('log')->with("Module 'Bar_Two':"); + $this->logger->expects($this->at(39))->method('log')->with('Installing admin user...'); + $this->logger->expects($this->at(41))->method('log')->with('Caches clearing:'); + $this->logger->expects($this->at(44))->method('log')->with('Disabling Maintenance Mode:'); + $this->logger->expects($this->at(46))->method('log')->with('Post installation file permissions check...'); + $this->logger->expects($this->at(48))->method('log')->with('Write installation date...'); + $this->logger->expects($this->at(50))->method('logSuccess')->with('Magento installation complete.'); + $this->logger->expects($this->at(52))->method('log') + ->with('Sample Data is installed with errors. See log file for details'); + } } +} + +namespace Magento\Setup\Model { /** - * Set up logger expectations for install method + * Mocking autoload function * - * @return void + * @returns array */ - private function setupLoggerExpectsForInstall() + function spl_autoload_functions() { - $this->logger->expects($this->at(0))->method('log')->with('Starting Magento installation:'); - $this->logger->expects($this->at(1))->method('log')->with('File permissions check...'); - $this->logger->expects($this->at(3))->method('log')->with('Required extensions check...'); - // at(2) invokes logMeta() - $this->logger->expects($this->at(5))->method('log')->with('Enabling Maintenance Mode...'); - // at(4) - logMeta and so on... - $this->logger->expects($this->at(7))->method('log')->with('Installing deployment configuration...'); - $this->logger->expects($this->at(9))->method('log')->with('Installing database schema:'); - $this->logger->expects($this->at(11))->method('log')->with("Module 'Foo_One':"); - $this->logger->expects($this->at(13))->method('log')->with("Module 'Bar_Two':"); - $this->logger->expects($this->at(15))->method('log')->with('Schema post-updates:'); - $this->logger->expects($this->at(16))->method('log')->with("Module 'Foo_One':"); - $this->logger->expects($this->at(18))->method('log')->with("Module 'Bar_Two':"); - $this->logger->expects($this->at(21))->method('log')->with('Installing user configuration...'); - $this->logger->expects($this->at(23))->method('log')->with('Enabling caches:'); - $this->logger->expects($this->at(27))->method('log')->with('Installing data...'); - $this->logger->expects($this->at(28))->method('log')->with('Data install/update:'); - $this->logger->expects($this->at(29))->method('log')->with("Module 'Foo_One':"); - $this->logger->expects($this->at(31))->method('log')->with("Module 'Bar_Two':"); - $this->logger->expects($this->at(33))->method('log')->with('Data post-updates:'); - $this->logger->expects($this->at(34))->method('log')->with("Module 'Foo_One':"); - $this->logger->expects($this->at(36))->method('log')->with("Module 'Bar_Two':"); - $this->logger->expects($this->at(39))->method('log')->with('Installing admin user...'); - $this->logger->expects($this->at(41))->method('log')->with('Caches clearing:'); - $this->logger->expects($this->at(44))->method('log')->with('Disabling Maintenance Mode:'); - $this->logger->expects($this->at(46))->method('log')->with('Post installation file permissions check...'); - $this->logger->expects($this->at(48))->method('log')->with('Write installation date...'); - $this->logger->expects($this->at(50))->method('logSuccess')->with('Magento installation complete.'); - $this->logger->expects($this->at(52))->method('log') - ->with('Sample Data is installed with errors. See log file for details'); + return ['mock_function_one', 'mock_function_two']; } } - -namespace Magento\Setup\Model; - -/** - * Mocking autoload function - * - * @returns array - */ -function spl_autoload_functions() -{ - return ['mock_function_one', 'mock_function_two']; -} diff --git a/setup/view/layout/layout.phtml b/setup/view/layout/layout.phtml index 613ff391a8fff..0415aff91fc7b 100644 --- a/setup/view/layout/layout.phtml +++ b/setup/view/layout/layout.phtml @@ -5,8 +5,6 @@ */ ?> <?= $this->doctype() ?> -<!--[if IE 9]> -<html class="ie9" lang="en" ng-app="magentoSetup"><![endif]--> <!--[if !IE]><!--> <html lang="en" ng-app="magentoSetup"> <!--<![endif]--> diff --git a/setup/view/magento/setup/navigation/side-menu.phtml b/setup/view/magento/setup/navigation/side-menu.phtml index 58d12a4de448a..6354af875ae8c 100644 --- a/setup/view/magento/setup/navigation/side-menu.phtml +++ b/setup/view/magento/setup/navigation/side-menu.phtml @@ -6,6 +6,13 @@ // @codingStandardsIgnoreFile +use Magento\Backend\Model\UrlInterface; +use Magento\Framework\App\ObjectManager; + +$objectManager = ObjectManager::getInstance(); +/** @var Magento\Backend\Model\UrlInterface $backendUrl */ +$backendUrl = $objectManager->get(UrlInterface::class); + ?> <?php $expressions = []; foreach ( $this->main as $item ): ?> <?php $expressions[] = '!$state.is(\'' . $item['id'] . '\')'; @@ -20,13 +27,13 @@ ng-show="<?= implode( '&&', $expressions) ?>" > <nav class="admin__menu" ng-controller="mainController"> - <span - class="logo logo-static" + <a href="<?= $backendUrl->getBaseUrl() . $backendUrl->getAreaFrontName(); ?>" + class="logo" data-edition="Community Edition"> <img class="logo-img" src="./pub/images/logo.svg" alt="Magento Admin Panel"> - </span> + </a> <ul id="nav" role="menubar"> <li class="item-home level-0" ng-class="{_active: $state.current.name === 'root.home'}"> <a href="" ui-sref="root.home">