diff --git a/app/code/Magento/Backend/view/adminhtml/templates/admin/login.phtml b/app/code/Magento/Backend/view/adminhtml/templates/admin/login.phtml index 353605881db41afc7ea63e2dd2169c2bbf7ab2ab..0968047053bc5b2088f2a449ec243a08da5a99b7 100644 --- a/app/code/Magento/Backend/view/adminhtml/templates/admin/login.phtml +++ b/app/code/Magento/Backend/view/adminhtml/templates/admin/login.phtml @@ -27,7 +27,7 @@ value="" data-validate="{required:true}" placeholder="<?php /* @escapeNotVerified */ echo __('user name') ?>" - autocomplete="username" + autocomplete="off" /> </div> </div> @@ -43,7 +43,7 @@ data-validate="{required:true}" value="" placeholder="<?php /* @escapeNotVerified */ echo __('password') ?>" - autocomplete="current-password" + autocomplete="off" /> </div> </div> diff --git a/app/code/Magento/Catalog/Controller/Adminhtml/Product/Save.php b/app/code/Magento/Catalog/Controller/Adminhtml/Product/Save.php index d7cd6ba3984241576669bac898c412a9351d0858..89081edb46ca1c6f1f3849f6a7f8246dd0625fba 100644 --- a/app/code/Magento/Catalog/Controller/Adminhtml/Product/Save.php +++ b/app/code/Magento/Catalog/Controller/Adminhtml/Product/Save.php @@ -9,7 +9,12 @@ namespace Magento\Catalog\Controller\Adminhtml\Product; use Magento\Backend\App\Action; use Magento\Catalog\Controller\Adminhtml\Product; use Magento\Store\Model\StoreManagerInterface; +use Magento\Framework\App\Request\DataPersistorInterface; +/** + * Class Save + * @SuppressWarnings(PHPMD.CouplingBetweenObjects) + */ class Save extends \Magento\Catalog\Controller\Adminhtml\Product { /** @@ -37,6 +42,11 @@ class Save extends \Magento\Catalog\Controller\Adminhtml\Product */ protected $productRepository; + /** + * @var DataPersistorInterface + */ + protected $dataPersistor; + /** * @var StoreManagerInterface */ @@ -110,6 +120,7 @@ class Save extends \Magento\Catalog\Controller\Adminhtml\Product $this->copyToStores($data, $productId); $this->messageManager->addSuccess(__('You saved the product.')); + $this->getDataPersistor()->clear('catalog_product'); if ($product->getSku() != $originalSku) { $this->messageManager->addNotice( __( @@ -131,11 +142,13 @@ class Save extends \Magento\Catalog\Controller\Adminhtml\Product } catch (\Magento\Framework\Exception\LocalizedException $e) { $this->messageManager->addError($e->getMessage()); $this->_session->setProductData($data); + $this->getDataPersistor()->set('catalog_product', $data); $redirectBack = $productId ? true : 'new'; } catch (\Exception $e) { $this->_objectManager->get('Psr\Log\LoggerInterface')->critical($e); $this->messageManager->addError($e->getMessage()); $this->_session->setProductData($data); + $this->getDataPersistor()->set('catalog_product', $data); $redirectBack = $productId ? true : 'new'; } } else { @@ -246,4 +259,18 @@ class Save extends \Magento\Catalog\Controller\Adminhtml\Product } return $this->storeManager; } + + /** + * Retrieve data persistor + * + * @return DataPersistorInterface|mixed + */ + protected function getDataPersistor() + { + if (null === $this->dataPersistor) { + $this->dataPersistor = $this->_objectManager->get(DataPersistorInterface::class); + } + + return $this->dataPersistor; + } } diff --git a/app/code/Magento/Catalog/Model/ImageExtractor.php b/app/code/Magento/Catalog/Model/ImageExtractor.php index bf45816f45a1c063ef616f16b074326fdc885e3e..c83c7106ce20a5621951ee950c2812251341730f 100644 --- a/app/code/Magento/Catalog/Model/ImageExtractor.php +++ b/app/code/Magento/Catalog/Model/ImageExtractor.php @@ -30,7 +30,11 @@ class ImageExtractor implements \Magento\Framework\View\Xsd\Media\TypeDataExtrac if ($attribute->nodeType != XML_ELEMENT_NODE) { continue; } - $nodeValue = $attribute->nodeValue; + if ($attribute->tagName == 'background') { + $nodeValue = $this->processImageBackground($attribute->nodeValue); + } else { + $nodeValue = $attribute->nodeValue; + } $result[$mediaParentTag][$moduleNameImage][Image::MEDIA_TYPE_CONFIG_NODE][$imageId][$attribute->tagName] = $nodeValue; } @@ -38,4 +42,20 @@ class ImageExtractor implements \Magento\Framework\View\Xsd\Media\TypeDataExtrac return $result; } + + /** + * Convert rgb background string into array + * + * @param string $backgroundString + * @return int[] + */ + private function processImageBackground($backgroundString) + { + $pattern = '#\[(\d{1,3}),\s*(\d{1,3}),\s*(\d{1,3})\]#'; + $backgroundArray = []; + if (preg_match($pattern, $backgroundString, $backgroundArray)) { + array_shift($backgroundArray); + } + return $backgroundArray; + } } diff --git a/app/code/Magento/Catalog/Model/Locator/RegistryLocator.php b/app/code/Magento/Catalog/Model/Locator/RegistryLocator.php index 433fe2b324bdd5129aa1a35c6e8e5e30e68bb9ad..3b288b00b6e467d49715013c73ffc879a9943380 100644 --- a/app/code/Magento/Catalog/Model/Locator/RegistryLocator.php +++ b/app/code/Magento/Catalog/Model/Locator/RegistryLocator.php @@ -5,7 +5,10 @@ */ namespace Magento\Catalog\Model\Locator; +use Magento\Catalog\Api\Data\ProductInterface; +use Magento\Framework\Exception\NotFoundException; use Magento\Framework\Registry; +use Magento\Store\Api\Data\StoreInterface; /** * Class RegistryLocator @@ -15,7 +18,17 @@ class RegistryLocator implements LocatorInterface /** * @var Registry */ - protected $registry; + private $registry; + + /** + * @var ProductInterface + */ + private $product; + + /** + * @var StoreInterface + */ + private $store; /** * @param Registry $registry @@ -27,30 +40,46 @@ class RegistryLocator implements LocatorInterface /** * {@inheritdoc} + * @throws NotFoundException */ public function getProduct() { - return $this->registry->registry('current_product'); + if (null !== $this->product) { + return $this->product; + } + + if ($product = $this->registry->registry('current_product')) { + return $this->product = $product; + } + + throw new NotFoundException(__('Product was not registered')); } /** * {@inheritdoc} + * @throws NotFoundException */ public function getStore() { - return $this->registry->registry('current_store'); - } + if (null !== $this->store) { + return $this->store; + } + if ($store = $this->registry->registry('current_store')) { + return $this->store = $store; + } + + throw new NotFoundException(__('Store was not registered')); + } /** * {@inheritdoc} */ public function getWebsiteIds() { - return $this->registry->registry('current_product')->getWebsiteIds(); + return $this->getProduct()->getWebsiteIds(); } - /** * {@inheritdoc} */ diff --git a/app/code/Magento/Catalog/Model/Product/Link/Converter.php b/app/code/Magento/Catalog/Model/Product/Link/Converter.php index 7fa80daeb92db0116ebbf631a7744c7e6b5cb883..351afe7ddec65f9cb3b3c9ba8e94c78aeba915d5 100644 --- a/app/code/Magento/Catalog/Model/Product/Link/Converter.php +++ b/app/code/Magento/Catalog/Model/Product/Link/Converter.php @@ -19,7 +19,7 @@ class Converter protected function indexBySku(array $products) { $converted = []; - foreach($products as $product) { + foreach ($products as $product) { $converted[$product->getSku()] = $product; } return $converted; @@ -34,7 +34,7 @@ class Converter $basicData = $entity->getProductLinks(); $associatedProducts = $entity->getTypeInstance()->getAssociatedProducts($entity); $associatedProducts = $this->indexBySku($associatedProducts); - + $linksAsArray = []; /** @var \Magento\Catalog\Api\Data\ProductLinkInterface $link */ foreach ($basicData as $link) { $info = $link->getData(); @@ -46,4 +46,4 @@ class Converter } return $linksAsArray; } -} \ No newline at end of file +} diff --git a/app/code/Magento/Catalog/Model/Product/Link/Resolver.php b/app/code/Magento/Catalog/Model/Product/Link/Resolver.php index daedf3d335ca3020e1b4f9cb869504b59485b710..3de971b6b2a9e2ec3d2ceb4bdefa3b9e8c5351c9 100644 --- a/app/code/Magento/Catalog/Model/Product/Link/Resolver.php +++ b/app/code/Magento/Catalog/Model/Product/Link/Resolver.php @@ -17,13 +17,16 @@ class Resolver */ protected $links = null; + /** + * Resolver constructor. + * @param \Magento\Framework\App\RequestInterface $request + */ public function __construct( \Magento\Framework\App\RequestInterface $request ) { $this->request = $request; } - /** * Get stored value. * Fallback to request if none. @@ -42,6 +45,7 @@ class Resolver * Override link data from request * * @param array|null $links + * @return void */ public function override($links) { diff --git a/app/code/Magento/Catalog/Model/ProductRepository.php b/app/code/Magento/Catalog/Model/ProductRepository.php index e8b5dea903b9e4c9c0cf77673ae69db5ada199e2..14ee790b382344285422dfa8583312b835a9d5fe 100644 --- a/app/code/Magento/Catalog/Model/ProductRepository.php +++ b/app/code/Magento/Catalog/Model/ProductRepository.php @@ -15,6 +15,7 @@ use Magento\Framework\Api\ImageContentValidatorInterface; use Magento\Framework\Api\ImageProcessorInterface; use Magento\Framework\Api\SortOrder; use Magento\Framework\Exception\InputException; +use Magento\Framework\Exception\LocalizedException; use Magento\Framework\Exception\NoSuchEntityException; use Magento\Framework\Exception\StateException; use Magento\Framework\Exception\ValidatorException; @@ -546,6 +547,8 @@ class ProductRepository implements \Magento\Catalog\Api\ProductRepositoryInterfa ); } catch (ValidatorException $e) { throw new CouldNotSaveException(__($e->getMessage())); + } catch (LocalizedException $e) { + throw $e; } catch (\Exception $e) { throw new \Magento\Framework\Exception\CouldNotSaveException(__('Unable to save product')); } diff --git a/app/code/Magento/Catalog/Test/Unit/Model/ImageExtractorTest.php b/app/code/Magento/Catalog/Test/Unit/Model/ImageExtractorTest.php new file mode 100644 index 0000000000000000000000000000000000000000..fe255ea63ca667bc2959b0256b93df6038a528ab --- /dev/null +++ b/app/code/Magento/Catalog/Test/Unit/Model/ImageExtractorTest.php @@ -0,0 +1,40 @@ +<?php +/** + * Copyright © 2016 Magento. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\Catalog\Test\Unit\Model; + +use Magento\Framework\TestFramework\Unit\Helper\ObjectManager; + +class ImageExtractorTest extends \PHPUnit_Framework_TestCase +{ + /** + * @var \Magento\Catalog\Model\ImageExtractor + */ + private $model; + + protected function setUp() + { + $objectManager = new ObjectManager($this); + $this->model = $objectManager->getObject(\Magento\Catalog\Model\ImageExtractor::class); + } + + public function testProcess() + { + $expectedArray = include(__DIR__ . '/_files/converted_view.php'); + $this->assertEquals($expectedArray, $this->model->process($this->getDomElement(), 'media')); + } + + /** + * Get mocked dom element + * + * @return \DOMElement + */ + private function getDomElement() + { + $doc = new \DOMDocument(); + $doc->load(__DIR__ . '/_files/valid_view.xml'); + return $doc->getElementsByTagName('images')->item(0); + } +} diff --git a/app/code/Magento/Catalog/Test/Unit/Model/Locator/RegistryLocatorTest.php b/app/code/Magento/Catalog/Test/Unit/Model/Locator/RegistryLocatorTest.php index 86df3eaf30ebb1c02dd51cd3514d6ee458cafbf4..d66bb4192a693887abb1f81ed61745af9b6b880d 100644 --- a/app/code/Magento/Catalog/Test/Unit/Model/Locator/RegistryLocatorTest.php +++ b/app/code/Magento/Catalog/Test/Unit/Model/Locator/RegistryLocatorTest.php @@ -9,6 +9,7 @@ use Magento\Catalog\Api\Data\ProductInterface; use Magento\Catalog\Model\Locator\RegistryLocator; use Magento\Framework\Registry; use Magento\Framework\TestFramework\Unit\Helper\ObjectManager; +use Magento\Store\Api\Data\StoreInterface; /** * Class RegistryLocatorTest @@ -26,36 +27,75 @@ class RegistryLocatorTest extends \PHPUnit_Framework_TestCase protected $model; /** - * @var Registry + * @var Registry|\PHPUnit_Framework_MockObject_MockObject */ protected $registryMock; /** - * @var ProductInterface + * @var ProductInterface|\PHPUnit_Framework_MockObject_MockObject */ protected $productMock; + /** + * @var StoreInterface|\PHPUnit_Framework_MockObject_MockObject + */ + protected $storeMock; + protected function setUp() { $this->objectManager = new ObjectManager($this); - $this->registryMock = $this->getMockBuilder('Magento\Framework\Registry') + $this->registryMock = $this->getMockBuilder(Registry::class) ->setMethods(['registry']) ->getMock(); - $this->productMock = $this->getMockBuilder('Magento\Catalog\Api\Data\ProductInterface') + $this->productMock = $this->getMockBuilder(ProductInterface::class) + ->getMockForAbstractClass(); + $this->storeMock = $this->getMockBuilder(StoreInterface::class) ->getMockForAbstractClass(); + $this->model = $this->objectManager->getObject(RegistryLocator::class, [ + 'registry' => $this->registryMock, + ]); + } + + public function testGetProduct() + { $this->registryMock->expects($this->once()) ->method('registry') ->with('current_product') ->willReturn($this->productMock); - $this->model = $this->objectManager->getObject('Magento\Catalog\Model\Locator\RegistryLocator', [ - 'registry' => $this->registryMock, - ]); + $this->assertInstanceOf(ProductInterface::class, $this->model->getProduct()); + // Lazy loading + $this->assertInstanceOf(ProductInterface::class, $this->model->getProduct()); } - public function testGetProduct() + public function testGetStore() + { + $this->registryMock->expects($this->once()) + ->method('registry') + ->with('current_store') + ->willReturn($this->storeMock); + + $this->assertInstanceOf(StoreInterface::class, $this->model->getStore()); + // Lazy loading + $this->assertInstanceOf(StoreInterface::class, $this->model->getStore()); + } + + /** + * @expectedException \Magento\Framework\Exception\NotFoundException + * @expectedExceptionMessage Product was not registered + */ + public function testGetProductWithException() + { + $this->assertInstanceOf(ProductInterface::class, $this->model->getProduct()); + } + + /** + * @expectedException \Magento\Framework\Exception\NotFoundException + * @expectedExceptionMessage Store was not registered + */ + public function testGetStoreWithException() { - $this->assertInstanceOf('Magento\Catalog\Api\Data\ProductInterface', $this->model->getProduct()); + $this->assertInstanceOf(StoreInterface::class, $this->model->getStore()); } } diff --git a/app/code/Magento/Catalog/Test/Unit/Model/Product/Link/ConverterTest.php b/app/code/Magento/Catalog/Test/Unit/Model/Product/Link/ConverterTest.php new file mode 100644 index 0000000000000000000000000000000000000000..07e0e6467ced7874cfa568f39527aeafb9742931 --- /dev/null +++ b/app/code/Magento/Catalog/Test/Unit/Model/Product/Link/ConverterTest.php @@ -0,0 +1,85 @@ +<?php +/** + * Copyright © 2016 Magento. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\Catalog\Test\Unit\Model\Product\Link; + +use Magento\Catalog\Model\Product\Link\Converter; + +class ConverterTest extends \PHPUnit_Framework_TestCase +{ + /** + * @var Converter + */ + protected $converter; + + protected function setUp() + { + $this->converter = new Converter(); + } + + public function testConvertLinksToGroupedArray() + { + $linkedProductSku = 'linkedProductSample'; + $linkedProductId = '2016'; + $linkType = 'associated'; + $linkMock = $this->getMockBuilder(\Magento\Catalog\Api\Data\ProductLinkInterface::class) + ->disableOriginalConstructor() + ->setMethods(['getData', 'getLinkType', 'getLinkedProductSku', 'getExtensionAttributes']) + ->getMockForAbstractClass(); + $basicData = [$linkMock]; + $linkedProductMock = $this->getMockBuilder(\Magento\Catalog\Model\Product::class) + ->disableOriginalConstructor() + ->getMock(); + $associatedProducts = [$linkedProductSku => $linkedProductMock]; + $info = [100, 300, 500]; + $infoFinal = [100, 300, 500, 'id' => $linkedProductId, 'qty' => 33]; + $linksAsArray = [$linkType => [$infoFinal]]; + + $typeMock = $this->getMockBuilder(\Magento\Catalog\Model\Product\Type\AbstractType::class) + ->setMethods(['getAssociatedProducts']) + ->disableOriginalConstructor() + ->getMockForAbstractClass(); + + $productMock = $this->getMockBuilder(\Magento\Catalog\Model\Product::class) + ->disableOriginalConstructor() + ->getMock(); + $productMock->expects($this->once()) + ->method('getProductLinks') + ->willReturn($basicData); + $productMock->expects($this->once()) + ->method('getTypeInstance') + ->willReturn($typeMock); + $typeMock->expects($this->once()) + ->method('getAssociatedProducts') + ->with($productMock) + ->willReturn($associatedProducts); + $linkedProductMock->expects($this->once()) + ->method('getSku') + ->willReturn($linkedProductSku); + $linkMock->expects($this->once()) + ->method('getData') + ->willReturn($info); + $linkMock->expects($this->exactly(2)) + ->method('getLinkType') + ->willReturn($linkType); + $linkMock->expects($this->once()) + ->method('getLinkedProductSku') + ->willReturn($linkedProductSku); + $linkedProductMock->expects($this->once()) + ->method('getId') + ->willReturn($linkedProductId); + $attributeMock = $this->getMockBuilder(\Magento\Framework\Api\ExtensionAttributesInterface::class) + ->setMethods(['__toArray']) + ->getMockForAbstractClass(); + $linkMock->expects($this->once()) + ->method('getExtensionAttributes') + ->willReturn($attributeMock); + $attributeMock->expects($this->once()) + ->method('__toArray') + ->willReturn(['qty' => 33]); + + $this->assertEquals($linksAsArray, $this->converter->convertLinksToGroupedArray($productMock)); + } +} diff --git a/app/code/Magento/Catalog/Test/Unit/Model/Product/Link/ResolverTest.php b/app/code/Magento/Catalog/Test/Unit/Model/Product/Link/ResolverTest.php new file mode 100644 index 0000000000000000000000000000000000000000..58b5a5968bece650b7bfdfdd8e1e1565396ac016 --- /dev/null +++ b/app/code/Magento/Catalog/Test/Unit/Model/Product/Link/ResolverTest.php @@ -0,0 +1,51 @@ +<?php +/** + * Copyright © 2016 Magento. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\Catalog\Test\Unit\Model\Product\Link; + +use Magento\Catalog\Model\Product\Link\Resolver; + +class ResolverTest extends \PHPUnit_Framework_TestCase +{ + /** + * @var \PHPUnit_Framework_MockObject_MockObject + */ + protected $requestMock; + + /** + * @var Resolver + */ + protected $resolver; + + protected function setUp() + { + $this->requestMock = $this->getMockBuilder(\Magento\Framework\App\RequestInterface::class) + ->getMockForAbstractClass(); + + $this->resolver = new Resolver($this->requestMock); + } + + public function testGetLinksEmpty() + { + $someLinks = [1, 2, 3]; + $this->requestMock->expects($this->once()) + ->method('getParam') + ->with('links', []) + ->willReturn($someLinks); + $this->assertEquals($someLinks, $this->resolver->getLinks()); + + } + + public function testGetLinksOverridden() + { + $overriddenLinks = [3, 5, 7]; + $this->requestMock->expects($this->never()) + ->method('getParam'); + + $this->resolver->override($overriddenLinks); + $this->assertEquals($overriddenLinks, $this->resolver->getLinks()); + + } +} diff --git a/app/code/Magento/Catalog/Test/Unit/Model/_files/converted_view.php b/app/code/Magento/Catalog/Test/Unit/Model/_files/converted_view.php new file mode 100644 index 0000000000000000000000000000000000000000..49d865253ced4917fabaa7c245ef238421a05e46 --- /dev/null +++ b/app/code/Magento/Catalog/Test/Unit/Model/_files/converted_view.php @@ -0,0 +1,19 @@ +<?php +/** + * Copyright © 2016 Magento. All rights reserved. + * See COPYING.txt for license details. + */ +return [ + "media" => [ + "Magento_Catalog" => [ + "images" => [ + "swatch_thumb_base" => [ + "type" => "swatch_thumb", + "width" => 75, + "height" => 75, + "background" => [255, 25, 2] + ] + ] + ] + ] +]; diff --git a/app/code/Magento/Catalog/Test/Unit/Model/_files/valid_view.xml b/app/code/Magento/Catalog/Test/Unit/Model/_files/valid_view.xml new file mode 100644 index 0000000000000000000000000000000000000000..c6a1aec333fab172f6094a3c8903dea8e0b17ff4 --- /dev/null +++ b/app/code/Magento/Catalog/Test/Unit/Model/_files/valid_view.xml @@ -0,0 +1,18 @@ +<?xml version="1.0"?> +<!-- +/** + * Copyright © 2016 Magento. All rights reserved. + * See COPYING.txt for license details. + */ +--> +<view xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:Config/etc/view.xsd"> + <media> + <images module="Magento_Catalog"> + <image id="swatch_thumb_base" type="swatch_thumb"> + <width>75</width> + <height>75</height> + <background>[255, 25, 2]</background> + </image> + </images> + </media> +</view> diff --git a/app/code/Magento/Catalog/Test/Unit/Ui/DataProvider/Product/Form/Modifier/AbstractModifierTest.php b/app/code/Magento/Catalog/Test/Unit/Ui/DataProvider/Product/Form/Modifier/AbstractModifierTest.php index 72ebbf5529a581c5030fa7c79bae622769369519..648775613d37fa2d73ede066cb6a1ea622c4eb48 100644 --- a/app/code/Magento/Catalog/Test/Unit/Ui/DataProvider/Product/Form/Modifier/AbstractModifierTest.php +++ b/app/code/Magento/Catalog/Test/Unit/Ui/DataProvider/Product/Form/Modifier/AbstractModifierTest.php @@ -66,7 +66,7 @@ abstract class AbstractModifierTest extends \PHPUnit_Framework_TestCase 'getExistsStoreValueFlag' ])->getMockForAbstractClass(); $this->storeMock = $this->getMockBuilder(StoreInterface::class) - ->setMethods(['load', 'getId']) + ->setMethods(['load', 'getId', 'getConfig']) ->getMockForAbstractClass(); $this->arrayManagerMock = $this->getMockBuilder(ArrayManager::class) ->disableOriginalConstructor() diff --git a/app/code/Magento/Catalog/Ui/Component/Listing/Columns/Websites.php b/app/code/Magento/Catalog/Ui/Component/Listing/Columns/Websites.php index 92b551a820194879de22d9ce789ed62c6d4f04f4..f3c441f1aec06c6bfa1fb9141ef6936a6d404b29 100644 --- a/app/code/Magento/Catalog/Ui/Component/Listing/Columns/Websites.php +++ b/app/code/Magento/Catalog/Ui/Component/Listing/Columns/Websites.php @@ -56,6 +56,9 @@ class Websites extends \Magento\Ui\Component\Listing\Columns\Column foreach ($dataSource['data']['items'] as & $item) { $websites = []; foreach ($item[$fieldName] as $websiteId) { + if (!isset($websiteNames[$websiteId])) { + continue; + } $websites[] = $websiteNames[$websiteId]; } $item[$fieldName] = implode(', ', $websites); diff --git a/app/code/Magento/Catalog/Ui/DataProvider/Product/Form/Modifier/Eav.php b/app/code/Magento/Catalog/Ui/DataProvider/Product/Form/Modifier/Eav.php index ca9f88a81e1f925f866df8ddd30c1f27375059b1..454cf335632e6935a4d1ca693a03b14fb5dff891 100644 --- a/app/code/Magento/Catalog/Ui/DataProvider/Product/Form/Modifier/Eav.php +++ b/app/code/Magento/Catalog/Ui/DataProvider/Product/Form/Modifier/Eav.php @@ -18,6 +18,7 @@ use Magento\Eav\Model\Config; use Magento\Eav\Model\ResourceModel\Entity\Attribute\Group\CollectionFactory as GroupCollectionFactory; use Magento\Framework\Api\SearchCriteriaBuilder; use Magento\Framework\Api\SortOrderBuilder; +use Magento\Framework\App\Request\DataPersistorInterface; use Magento\Framework\App\RequestInterface; use Magento\Framework\Filter\Translit; use Magento\Framework\Stdlib\ArrayManager; @@ -155,6 +156,11 @@ class Eav extends AbstractModifier */ private $attributesToEliminate; + /** + * @var DataPersistorInterface + */ + private $dataPersistor; + /** * @param LocatorInterface $locator * @param EavValidationRules $eavValidationRules @@ -172,6 +178,7 @@ class Eav extends AbstractModifier * @param Translit $translitFilter * @param ArrayManager $arrayManager * @param ScopeOverriddenValue $scopeOverriddenValue + * @param DataPersistorInterface $dataPersistor * @param array $attributesToDisable * @param array $attributesToEliminate * @SuppressWarnings(PHPMD.ExcessiveParameterList) @@ -193,6 +200,7 @@ class Eav extends AbstractModifier Translit $translitFilter, ArrayManager $arrayManager, ScopeOverriddenValue $scopeOverriddenValue, + DataPersistorInterface $dataPersistor, $attributesToDisable = [], $attributesToEliminate = [] ) { @@ -212,6 +220,7 @@ class Eav extends AbstractModifier $this->translitFilter = $translitFilter; $this->arrayManager = $arrayManager; $this->scopeOverriddenValue = $scopeOverriddenValue; + $this->dataPersistor = $dataPersistor; $this->attributesToDisable = $attributesToDisable; $this->attributesToEliminate = $attributesToEliminate; } @@ -322,6 +331,10 @@ class Eav extends AbstractModifier */ public function modifyData(array $data) { + if (!$this->locator->getProduct()->getId() && $this->dataPersistor->get('catalog_product')) { + return $this->resolvePersistentData($data); + } + $productId = $this->locator->getProduct()->getId(); /** @var string $groupCode */ @@ -340,6 +353,29 @@ class Eav extends AbstractModifier return $data; } + /** + * Resolve data persistence + * + * @param array $data + * @return array + */ + private function resolvePersistentData(array $data) + { + $persistentData = (array)$this->dataPersistor->get('catalog_product'); + $productId = $this->locator->getProduct()->getId(); + + if (empty($data[$productId][self::DATA_SOURCE_DEFAULT])) { + $data[$productId][self::DATA_SOURCE_DEFAULT] = []; + } + + $data[$productId] = array_replace_recursive( + $data[$productId][self::DATA_SOURCE_DEFAULT], + $persistentData + ); + + return $data; + } + /** * Get product type * @@ -548,7 +584,7 @@ class Eav extends AbstractModifier $meta = $this->customizePriceAttribute($attribute, $meta); break; case 'gallery': - // Gallery attribute is being handled by "Images And Videos Tab" + // Gallery attribute is being handled by "Images And Videos" section $meta = []; break; } diff --git a/app/code/Magento/Catalog/Ui/DataProvider/Product/Form/Modifier/General.php b/app/code/Magento/Catalog/Ui/DataProvider/Product/Form/Modifier/General.php index 7b85bbbb8aaec682b3f9d8ee9efd36cfc4d70a90..b4147229b81d6be08e7757d3546175a94bece238 100644 --- a/app/code/Magento/Catalog/Ui/DataProvider/Product/Form/Modifier/General.php +++ b/app/code/Magento/Catalog/Ui/DataProvider/Product/Form/Modifier/General.php @@ -163,24 +163,18 @@ class General extends AbstractModifier protected function customizeStatusField(array $meta) { $switcherConfig = [ - 'arguments' => [ - 'data' => [ - 'config' => [ - 'dataType' => Form\Element\DataType\Number::NAME, - 'formElement' => Form\Element\Checkbox::NAME, - 'componentType' => Form\Field::NAME, - 'prefer' => 'toggle', - 'valueMap' => [ - 'true' => '1', - 'false' => '2' - ], - ], - ], + 'dataType' => Form\Element\DataType\Number::NAME, + 'formElement' => Form\Element\Checkbox::NAME, + 'componentType' => Form\Field::NAME, + 'prefer' => 'toggle', + 'valueMap' => [ + 'true' => '1', + 'false' => '2' ], ]; $path = $this->arrayManager->findPath(ProductAttributeInterface::CODE_STATUS, $meta, null, 'children'); - $meta = $this->arrayManager->merge($path, $meta, $switcherConfig); + $meta = $this->arrayManager->merge($path . static::META_CONFIG_PATH, $meta, $switcherConfig); return $meta; } @@ -203,7 +197,7 @@ class General extends AbstractModifier [ 'dataScope' => ProductAttributeInterface::CODE_WEIGHT, 'validation' => [ - 'validate-number' => true, + 'validate-zero-or-greater' => true ], 'additionalClasses' => 'admin__field-small', 'addafter' => $this->locator->getStore()->getConfig('general/locale/weight_unit'), @@ -220,44 +214,33 @@ class General extends AbstractModifier null, 'children' ); - $meta = $this->arrayManager->merge($containerPath, $meta, [ - 'arguments' => [ - 'data' => [ - 'config' => [ - 'component' => 'Magento_Ui/js/form/components/group', - ], - ], - ], + $meta = $this->arrayManager->merge($containerPath . static::META_CONFIG_PATH, $meta, [ + 'component' => 'Magento_Ui/js/form/components/group', ]); $hasWeightPath = $this->arrayManager->slicePath($weightPath, 0, -1) . '/' . ProductAttributeInterface::CODE_HAS_WEIGHT; $meta = $this->arrayManager->set( - $hasWeightPath, + $hasWeightPath . static::META_CONFIG_PATH, $meta, [ - 'arguments' => [ - 'data' => [ - 'config' => [ - 'dataType' => 'boolean', - 'formElement' => Form\Element\Select::NAME, - 'componentType' => Form\Field::NAME, - 'dataScope' => 'product_has_weight', - 'label' => '', - 'options' => [ - [ - 'label' => __('This item has weight'), - 'value' => 1 - ], - [ - 'label' => __('This item has no weight'), - 'value' => 0 - ], - ], - 'value' => (int)$this->locator->getProduct()->getTypeInstance()->hasWeight(), - ], + + 'dataType' => 'boolean', + 'formElement' => Form\Element\Select::NAME, + 'componentType' => Form\Field::NAME, + 'dataScope' => 'product_has_weight', + 'label' => '', + 'options' => [ + [ + 'label' => __('This item has weight'), + 'value' => 1 ], - ] + [ + 'label' => __('This item has no weight'), + 'value' => 0 + ], + ], + 'value' => (int)$this->locator->getProduct()->getTypeInstance()->hasWeight(), ] ); } @@ -340,39 +323,53 @@ class General extends AbstractModifier ProductAttributeInterface::CODE_SEO_FIELD_META_KEYWORD, ProductAttributeInterface::CODE_SEO_FIELD_META_DESCRIPTION, ]; + $textListeners = [ + ProductAttributeInterface::CODE_SEO_FIELD_META_KEYWORD, + ProductAttributeInterface::CODE_SEO_FIELD_META_DESCRIPTION + ]; + foreach ($listeners as $listener) { $listenerPath = $this->arrayManager->findPath($listener, $meta, null, 'children'); $importsConfig = [ - 'arguments' => [ - 'data' => [ - 'config' => [ - 'component' => 'Magento_Catalog/js/components/import-handler', - 'imports' => [ - 'handleChanges' => '${$.provider}:data.product.name', - ], - 'autoImportIfEmpty' => true, - 'allowImport' => $this->locator->getProduct()->getId() ? false : true, - ], - ], + 'mask' => $this->locator->getStore()->getConfig('catalog/fields_masks/' . $listener), + 'component' => 'Magento_Catalog/js/components/import-handler', + 'imports' => [ + 'handleNameChanges' => '${$.provider}:data.product.name', + 'handleDescriptionChanges' => '${$.provider}:data.product.description', + 'handleSkuChanges' => '${$.provider}:data.product.sku', + 'handleColorChanges' => '${$.provider}:data.product.color', + 'handleCountryChanges' => '${$.provider}:data.product.country_of_manufacture', + 'handleGenderChanges' => '${$.provider}:data.product.gender', + 'handleMaterialChanges' => '${$.provider}:data.product.material', + 'handleShortDescriptionChanges' => '${$.provider}:data.product.short_description', + 'handleSizeChanges' => '${$.provider}:data.product.size' ], ]; - $meta = $this->arrayManager->merge($listenerPath, $meta, $importsConfig); + if (!in_array($listener, $textListeners)) { + $importsConfig['elementTmpl'] = 'ui/form/element/input'; + } + + $meta = $this->arrayManager->merge($listenerPath . static::META_CONFIG_PATH, $meta, $importsConfig); } + $skuPath = $this->arrayManager->findPath(ProductAttributeInterface::CODE_SKU, $meta, null, 'children'); + $meta = $this->arrayManager->merge( + $skuPath . static::META_CONFIG_PATH, + $meta, + [ + 'autoImportIfEmpty' => true, + 'allowImport' => $this->locator->getProduct()->getId() ? false : true, + ] + ); + $namePath = $this->arrayManager->findPath(ProductAttributeInterface::CODE_NAME, $meta, null, 'children'); return $this->arrayManager->merge( - $namePath, + $namePath . static::META_CONFIG_PATH, $meta, [ - 'arguments' => [ - 'data' => [ - 'config' => [ - 'valueUpdate' => 'keyup' - ], - ], - ], + 'valueUpdate' => 'keyup' ] ); } diff --git a/app/code/Magento/Catalog/Ui/DataProvider/Product/Form/ProductDataProvider.php b/app/code/Magento/Catalog/Ui/DataProvider/Product/Form/ProductDataProvider.php index 294b8188ea0106522e6a64f36b3c2dfd19f36221..a390bb6e9a9d99a97fb4ec2933ab515e3ce9665c 100644 --- a/app/code/Magento/Catalog/Ui/DataProvider/Product/Form/ProductDataProvider.php +++ b/app/code/Magento/Catalog/Ui/DataProvider/Product/Form/ProductDataProvider.php @@ -18,7 +18,7 @@ class ProductDataProvider extends AbstractDataProvider /** * @var PoolInterface */ - protected $pool; + private $pool; /** * @param string $name diff --git a/app/code/Magento/Catalog/view/adminhtml/templates/catalog/product/attribute/options.phtml b/app/code/Magento/Catalog/view/adminhtml/templates/catalog/product/attribute/options.phtml index 6cb4325dd8ada0df072bd59158b465e06455876e..82b70fb8c71a885e0bd91f426c17ba17478d1899 100644 --- a/app/code/Magento/Catalog/view/adminhtml/templates/catalog/product/attribute/options.phtml +++ b/app/code/Magento/Catalog/view/adminhtml/templates/catalog/product/attribute/options.phtml @@ -10,8 +10,8 @@ ?> <fieldset class="fieldset"> <legend class="legend"><span><?php /* @escapeNotVerified */ echo __('Manage Options (Values of Your Attribute)') ?></span></legend> - <div id="manage-options-panel"> - <table class="admin__control-table"> + <div id="manage-options-panel" data-index="attribute_options_select_container"> + <table class="admin__control-table" data-index="attribute_options_select"> <thead> <tr id="attribute-options-table"> <th class="col-draggable"></th> @@ -37,7 +37,7 @@ <tr> <th colspan="<?php /* @escapeNotVerified */ echo $storetotal; ?>" class="col-actions-add"> <?php if (!$block->getReadOnly() && !$block->canManageOptionDefaultOnly()):?> - <button id="add_new_option_button" title="<?php /* @escapeNotVerified */ echo __('Add Option'); ?>" + <button id="add_new_option_button" data-action="add_new_row" title="<?php /* @escapeNotVerified */ echo __('Add Option'); ?>" type="button" class="action- scalable add"> <span><?php /* @escapeNotVerified */ echo __('Add Option'); ?></span> </button> diff --git a/app/code/Magento/Catalog/view/adminhtml/web/js/components/import-handler.js b/app/code/Magento/Catalog/view/adminhtml/web/js/components/import-handler.js index 38608556a92064e5d80b639b59f4f122afb60edd..fd69874c318e21606361d503cc55ea900ad604cf 100644 --- a/app/code/Magento/Catalog/view/adminhtml/web/js/components/import-handler.js +++ b/app/code/Magento/Catalog/view/adminhtml/web/js/components/import-handler.js @@ -4,26 +4,150 @@ */ define([ - 'Magento_Ui/js/form/element/abstract' -], function (Abstract) { + 'Magento_Ui/js/form/element/textarea' +], function (Textarea) { 'use strict'; - return Abstract.extend({ + return Textarea.extend({ defaults: { allowImport: true, autoImportIfEmpty: false, - nameValue: '', - valueUpdate: 'input' + values: { + 'name': '', + 'description': '', + 'sku': '', + 'color': '', + 'country_of_manufacture': '', + 'gender': '', + 'material': '', + 'short_description': '', + 'size': '' + }, + valueUpdate: 'input', + mask: '' }, /** - * Import value, if it's allowed + * Handle name value changes, if it's allowed + * + * @param {String} newValue + */ + handleNameChanges: function (newValue) { + this.values.name = newValue; + this.updateValue(); + }, + + /** + * Handle description value changes, if it's allowed + * + * @param {String} newValue + */ + handleDescriptionChanges: function (newValue) { + this.values.description = newValue; + this.updateValue(); + }, + + /** + * Handle sku value changes, if it's allowed + * + * @param {String} newValue + */ + handleSkuChanges: function (newValue) { + if (this.code !== 'sku') { + this.values.sku = newValue; + this.updateValue(); + } + }, + + /** + * Handle color value changes, if it's allowed + * + * @param {String} newValue */ - handleChanges: function (newValue) { - this.nameValue = newValue; + handleColorChanges: function (newValue) { + this.values.color = newValue; + this.updateValue(); + }, + + /** + * Handle country value changes, if it's allowed + * + * @param {String} newValue + */ + handleCountryChanges: function (newValue) { + this.values.country = newValue; + this.updateValue(); + }, + + /** + * Handle gender value changes, if it's allowed + * + * @param {String} newValue + */ + handleGenderChanges: function (newValue) { + this.values.gender = newValue; + this.updateValue(); + }, + + /** + * Handle material value changes, if it's allowed + * + * @param {String} newValue + */ + handleMaterialChanges: function (newValue) { + this.values.material = newValue; + this.updateValue(); + }, + + /** + * Handle short description value changes, if it's allowed + * + * @param {String} newValue + */ + handleShortDescriptionChanges: function (newValue) { + this.values['short_description'] = newValue; + this.updateValue(); + }, + + /** + * Handle size value changes, if it's allowed + * + * @param {String} newValue + */ + handleSizeChanges: function (newValue) { + this.values.size = newValue; + this.updateValue(); + }, + + /** + * Update field value, if it's allowed + */ + updateValue: function () { + var str = this.mask, + nonEmptyValueFlag = false, + placeholder, + property, + tmpElement; + + if (!this.allowImport) { + return; + } + + for (property in this.values) { + if (this.values.hasOwnProperty(property)) { + placeholder = ''; + placeholder = placeholder.concat('{{', property, '}}'); + str = str.replace(placeholder, this.values[property]); + nonEmptyValueFlag = nonEmptyValueFlag || !!this.values[property]; + } + } + // strip tags + tmpElement = document.createElement('div'); + tmpElement.innerHTML = str; + str = tmpElement.textContent || tmpElement.innerText || ''; - if (this.allowImport) { - this.value(newValue); + if (nonEmptyValueFlag) { + this.value(str); } }, @@ -53,7 +177,7 @@ define([ this.allowImport = true; if (this.autoImportIfEmpty) { - this.value(this.nameValue); + this.updateValue(); } } else { this.allowImport = false; diff --git a/app/code/Magento/CatalogSearch/Model/Adapter/Mysql/Aggregation/DataProvider.php b/app/code/Magento/CatalogSearch/Model/Adapter/Mysql/Aggregation/DataProvider.php index 0dc343c88192b43e9f133ee589bfea81e247c018..9b75e6e6e0c325819d09f543cc445ae61eb7fb84 100644 --- a/app/code/Magento/CatalogSearch/Model/Adapter/Mysql/Aggregation/DataProvider.php +++ b/app/code/Magento/CatalogSearch/Model/Adapter/Mysql/Aggregation/DataProvider.php @@ -73,7 +73,7 @@ class DataProvider implements DataProviderInterface array $dimensions, Table $entityIdsTable ) { - $currentScope = $dimensions['scope']->getValue(); + $currentScope = $this->scopeResolver->getScope($dimensions['scope']->getValue())->getId(); $attribute = $this->eavConfig->getAttribute(Product::ENTITY, $bucket->getField()); 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 5161cc3e31a4d516108d8b46bb62c4f33abe1e5a..e6a6128cdc05866e912d6d0134fb439fbccd2b1a 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 @@ -67,8 +67,7 @@ class DataProvider Table $entityIdsTable ) { if ($bucket->getField() == 'category_ids') { - $currentScope = $dimensions['scope']->getValue(); - $currentScopeId = $this->scopeResolver->getScope($currentScope)->getId(); + $currentScopeId = $this->scopeResolver->getScope($dimensions['scope']->getValue())->getId(); $currentCategory = $this->layer->getCurrentCategory(); $derivedTable = $this->resource->getConnection()->select(); diff --git a/app/code/Magento/CatalogSearch/Model/Indexer/Fulltext/Plugin/Product.php b/app/code/Magento/CatalogSearch/Model/Indexer/Fulltext/Plugin/Product.php index 72b5b776750ec09afa2da08bf296bcd9a84f524b..26e4336f53d03f005003f1ae87d50d2728fae91a 100644 --- a/app/code/Magento/CatalogSearch/Model/Indexer/Fulltext/Plugin/Product.php +++ b/app/code/Magento/CatalogSearch/Model/Indexer/Fulltext/Plugin/Product.php @@ -6,45 +6,58 @@ namespace Magento\CatalogSearch\Model\Indexer\Fulltext\Plugin; +use Magento\Catalog\Model\ResourceModel\Product as ResourceProduct; +use Magento\Framework\Model\AbstractModel; + class Product extends AbstractPlugin { /** * Reindex on product save * - * @param \Magento\Catalog\Model\ResourceModel\Product $productResource + * @param ResourceProduct $productResource * @param \Closure $proceed - * @param \Magento\Framework\Model\AbstractModel $product - * @return \Magento\Catalog\Model\ResourceModel\Product - * @SuppressWarnings(PHPMD.UnusedFormalParameter) + * @param AbstractModel $product + * @return ResourceProduct */ - public function aroundSave( - \Magento\Catalog\Model\ResourceModel\Product $productResource, - \Closure $proceed, - \Magento\Framework\Model\AbstractModel $product - ) { - $productResource->addCommitCallback(function () use ($product) { - $this->reindexRow($product->getEntityId()); - }); - return $proceed($product); + public function aroundSave(ResourceProduct $productResource, \Closure $proceed, AbstractModel $product) + { + return $this->addCommitCallback($productResource, $proceed, $product); } /** * Reindex on product delete * - * @param \Magento\Catalog\Model\ResourceModel\Product $productResource + * @param ResourceProduct $productResource * @param \Closure $proceed - * @param \Magento\Framework\Model\AbstractModel $product - * @return \Magento\Catalog\Model\ResourceModel\Product - * @SuppressWarnings(PHPMD.UnusedFormalParameter) + * @param AbstractModel $product + * @return ResourceProduct */ - public function aroundDelete( - \Magento\Catalog\Model\ResourceModel\Product $productResource, - \Closure $proceed, - \Magento\Framework\Model\AbstractModel $product - ) { - $productResource->addCommitCallback(function () use ($product) { - $this->reindexRow($product->getEntityId()); - }); - return $proceed($product); + public function aroundDelete(ResourceProduct $productResource, \Closure $proceed, AbstractModel $product) + { + return $this->addCommitCallback($productResource, $proceed, $product); + } + + /** + * @param ResourceProduct $productResource + * @param \Closure $proceed + * @param AbstractModel $product + * @return ResourceProduct + * @throws \Exception + */ + private function addCommitCallback(ResourceProduct $productResource, \Closure $proceed, AbstractModel $product) + { + try { + $productResource->beginTransaction(); + $result = $proceed($product); + $productResource->addCommitCallback(function () use ($product) { + $this->reindexRow($product->getEntityId()); + }); + $productResource->commit(); + } catch (\Exception $e) { + $productResource->rollBack(); + throw $e; + } + + return $result; } } diff --git a/app/code/Magento/CatalogSearch/Model/Search/IndexBuilder.php b/app/code/Magento/CatalogSearch/Model/Search/IndexBuilder.php index 5bec5552e091376ce22351302c615d6acaa7c2fc..72134fb16912939f5a80e42e8803fd7120e6f3a5 100644 --- a/app/code/Magento/CatalogSearch/Model/Search/IndexBuilder.php +++ b/app/code/Magento/CatalogSearch/Model/Search/IndexBuilder.php @@ -20,6 +20,7 @@ use Magento\Framework\Search\RequestInterface; use Magento\Framework\Indexer\ScopeResolver\IndexScopeResolver; use Magento\Store\Model\ScopeInterface; use Magento\Store\Model\StoreManagerInterface; +use Magento\Framework\App\ScopeResolverInterface; /** * Build base Query for Index @@ -57,6 +58,11 @@ class IndexBuilder implements IndexBuilderInterface */ private $tableMapper; + /** + * @var ScopeResolverInterface + */ + private $dimensionScopeResolver; + /** * @param \Magento\Framework\App\ResourceConnection $resource * @param ScopeConfigInterface $config @@ -64,6 +70,7 @@ class IndexBuilder implements IndexBuilderInterface * @param ConditionManager $conditionManager * @param IndexScopeResolver $scopeResolver * @param TableMapper $tableMapper + * @param ScopeResolverInterface $dimensionScopeResolver */ public function __construct( ResourceConnection $resource, @@ -71,7 +78,8 @@ class IndexBuilder implements IndexBuilderInterface StoreManagerInterface $storeManager, ConditionManager $conditionManager, IndexScopeResolver $scopeResolver, - TableMapper $tableMapper + TableMapper $tableMapper, + ScopeResolverInterface $dimensionScopeResolver ) { $this->resource = $resource; $this->config = $config; @@ -79,6 +87,7 @@ class IndexBuilder implements IndexBuilderInterface $this->conditionManager = $conditionManager; $this->scopeResolver = $scopeResolver; $this->tableMapper = $tableMapper; + $this->dimensionScopeResolver = $dimensionScopeResolver; } /** @@ -158,7 +167,7 @@ class IndexBuilder implements IndexBuilderInterface $preparedDimensions[] = $this->conditionManager->generateCondition( $dimension->getName(), '=', - $dimension->getValue() + $this->dimensionScopeResolver->getScope($dimension->getValue())->getId() ); } diff --git a/app/code/Magento/CatalogSearch/Test/Unit/Model/Indexer/Fulltext/Plugin/ProductTest.php b/app/code/Magento/CatalogSearch/Test/Unit/Model/Indexer/Fulltext/Plugin/ProductTest.php index c6666a5a2e22e0a039bf33168550643fc81dc933..649b332fbf80309631444b4be5ba741082053289 100644 --- a/app/code/Magento/CatalogSearch/Test/Unit/Model/Indexer/Fulltext/Plugin/ProductTest.php +++ b/app/code/Magento/CatalogSearch/Test/Unit/Model/Indexer/Fulltext/Plugin/ProductTest.php @@ -6,22 +6,28 @@ namespace Magento\CatalogSearch\Test\Unit\Model\Indexer\Fulltext\Plugin; +use Magento\Catalog\Model\Product as ProductModel; +use Magento\Catalog\Model\ResourceModel\Product as ProductResourceModel; use \Magento\CatalogSearch\Model\Indexer\Fulltext\Plugin\Product; +use Magento\Framework\DB\Adapter\AdapterInterface; +use Magento\Framework\Indexer\IndexerInterface; +use Magento\Framework\Indexer\IndexerRegistry; +use Magento\Framework\TestFramework\Unit\Helper\ObjectManager; class ProductTest extends \PHPUnit_Framework_TestCase { /** - * @var \PHPUnit_Framework_MockObject_MockObject|\Magento\Framework\Indexer\IndexerInterface + * @var \PHPUnit_Framework_MockObject_MockObject|IndexerInterface */ protected $indexerMock; /** - * @var \PHPUnit_Framework_MockObject_MockObject|\Magento\Catalog\Model\ResourceModel\Product + * @var \PHPUnit_Framework_MockObject_MockObject|ProductResourceModel */ protected $subjectMock; /** - * @var \PHPUnit_Framework_MockObject_MockObject|\Magento\Catalog\Model\Product + * @var \PHPUnit_Framework_MockObject_MockObject|ProductModel */ protected $productMock; @@ -31,7 +37,7 @@ class ProductTest extends \PHPUnit_Framework_TestCase protected $proceed; /** - * @var \Magento\Framework\Indexer\IndexerRegistry|\PHPUnit_Framework_MockObject_MockObject + * @var IndexerRegistry|\PHPUnit_Framework_MockObject_MockObject */ protected $indexerRegistryMock; @@ -42,30 +48,34 @@ class ProductTest extends \PHPUnit_Framework_TestCase protected function setUp() { - $this->productMock = $this->getMock('Magento\Catalog\Model\Product', [], [], '', false); - $this->subjectMock = $this->getMock('Magento\Catalog\Model\ResourceModel\Product', [], [], '', false); - $this->indexerMock = $this->getMockForAbstractClass( - 'Magento\Framework\Indexer\IndexerInterface', - [], - '', - false, - false, - true, - ['getId', 'getState', '__wakeup'] - ); - $this->indexerRegistryMock = $this->getMock( - 'Magento\Framework\Indexer\IndexerRegistry', - ['get'], - [], - '', - false - ); + $this->productMock = $this->getMockBuilder(ProductModel::class) + ->disableOriginalConstructor() + ->getMock(); + $this->subjectMock = $this->getMockBuilder(ProductResourceModel::class) + ->disableOriginalConstructor() + ->getMock(); + $connection = $this->getMockBuilder(AdapterInterface::class) + ->disableOriginalConstructor() + ->getMockForAbstractClass(); + $this->subjectMock->method('getConnection')->willReturn($connection); + + $this->indexerMock = $this->getMockBuilder(IndexerInterface::class) + ->disableOriginalConstructor() + ->setMethods(['getId', 'getState', '__wakeup']) + ->getMockForAbstractClass(); + $this->indexerRegistryMock = $this->getMockBuilder(IndexerRegistry::class) + ->disableOriginalConstructor() + ->setMethods(['get']) + ->getMock(); $this->proceed = function () { return $this->subjectMock; }; - $this->model = new Product($this->indexerRegistryMock); + $this->model = (new ObjectManager($this))->getObject( + Product::class, + ['indexerRegistry' => $this->indexerRegistryMock] + ); } public function testAfterSaveNonScheduled() diff --git a/app/code/Magento/CatalogSearch/Test/Unit/Model/Search/IndexBuilderTest.php b/app/code/Magento/CatalogSearch/Test/Unit/Model/Search/IndexBuilderTest.php index 21e466383f9f1030b03da311019c4a6a153ff2e1..73dfd3867b0dcaf870794e6195d508309f440600 100644 --- a/app/code/Magento/CatalogSearch/Test/Unit/Model/Search/IndexBuilderTest.php +++ b/app/code/Magento/CatalogSearch/Test/Unit/Model/Search/IndexBuilderTest.php @@ -6,39 +6,38 @@ namespace Magento\CatalogSearch\Test\Unit\Model\Search; -use Magento\Framework\TestFramework\Unit\Helper\ObjectManager as ObjectManagerHelper; -use PHPUnit_Framework_MockObject_MockObject as MockObject; - /** * Test for \Magento\CatalogSearch\Model\Search\IndexBuilder + * + * @SuppressWarnings(PHPMD.CouplingBetweenObjects) */ class IndexBuilderTest extends \PHPUnit_Framework_TestCase { - /** @var \Magento\CatalogSearch\Model\Search\TableMapper|MockObject */ + /** @var \Magento\CatalogSearch\Model\Search\TableMapper|\PHPUnit_Framework_MockObject_MockObject */ private $tableMapper; - /** @var \Magento\Framework\Search\Adapter\Mysql\ConditionManager|MockObject */ + /** @var \Magento\Framework\Search\Adapter\Mysql\ConditionManager|\PHPUnit_Framework_MockObject_MockObject */ private $conditionManager; - /** @var \Magento\Search\Model\IndexScopeResolver|MockObject */ + /** @var \Magento\Search\Model\IndexScopeResolver|\PHPUnit_Framework_MockObject_MockObject */ private $scopeResolver; - /** @var \Magento\Framework\DB\Adapter\AdapterInterface|MockObject */ + /** @var \Magento\Framework\DB\Adapter\AdapterInterface|\PHPUnit_Framework_MockObject_MockObject */ private $connection; - /** @var \Magento\Framework\DB\Select|MockObject */ + /** @var \Magento\Framework\DB\Select|\PHPUnit_Framework_MockObject_MockObject */ private $select; - /** @var \Magento\Framework\App\Config\ScopeConfigInterface|MockObject */ + /** @var \Magento\Framework\App\Config\ScopeConfigInterface|\PHPUnit_Framework_MockObject_MockObject */ private $config; - /** @var \Magento\Store\Model\StoreManagerInterface|MockObject */ + /** @var \Magento\Store\Model\StoreManagerInterface|\PHPUnit_Framework_MockObject_MockObject */ private $storeManager; - /** @var \Magento\Framework\Search\RequestInterface|MockObject */ + /** @var \Magento\Framework\Search\RequestInterface|\PHPUnit_Framework_MockObject_MockObject */ private $request; - /** @var \Magento\Search\Model\IndexScopeResolver|MockObject */ + /** @var \Magento\Search\Model\IndexScopeResolver|\PHPUnit_Framework_MockObject_MockObject */ private $resource; /** @@ -46,6 +45,16 @@ class IndexBuilderTest extends \PHPUnit_Framework_TestCase */ private $target; + /** + * @var \Magento\Framework\App\ScopeResolverInterface|\PHPUnit_Framework_MockObject_MockObject + */ + private $dimensionScopeResolver; + + /** + * @var \Magento\Framework\App\ScopeInterface|\PHPUnit_Framework_MockObject_MockObject + */ + private $scopeInterface; + protected function setUp() { $this->select = $this->getMockBuilder('\Magento\Framework\DB\Select') @@ -118,8 +127,20 @@ class IndexBuilderTest extends \PHPUnit_Framework_TestCase ->method('addTables') ->with($this->select, $this->request) ->willReturnArgument(0); + $this->dimensionScopeResolver = $this->getMockForAbstractClass( + '\Magento\Framework\App\ScopeResolverInterface', + [], + '', + false + ); + $this->scopeInterface = $this->getMockForAbstractClass( + '\Magento\Framework\App\ScopeInterface', + [], + '', + false + ); - $objectManagerHelper = new ObjectManagerHelper($this); + $objectManagerHelper = new \Magento\Framework\TestFramework\Unit\Helper\ObjectManager($this); $this->target = $objectManagerHelper->getObject( 'Magento\CatalogSearch\Model\Search\IndexBuilder', [ @@ -129,6 +150,7 @@ class IndexBuilderTest extends \PHPUnit_Framework_TestCase 'conditionManager' => $this->conditionManager, 'scopeResolver' => $this->scopeResolver, 'tableMapper' => $this->tableMapper, + 'dimensionScopeResolver' => $this->dimensionScopeResolver ] ); } @@ -167,6 +189,12 @@ class IndexBuilderTest extends \PHPUnit_Framework_TestCase $this->request->expects($this->exactly(2)) ->method('getDimensions') ->willReturn($dimensions); + $this->dimensionScopeResolver->expects($this->once()) + ->method('getScope') + ->willReturn($this->scopeInterface); + $this->scopeInterface->expects($this->once()) + ->method('getId') + ->willReturn('someValue'); $this->mockBuild($index, $tableSuffix, false); @@ -270,7 +298,7 @@ class IndexBuilderTest extends \PHPUnit_Framework_TestCase /** * @param $name * @param $value - * @return MockObject + * @return \PHPUnit_Framework_MockObject_MockObject */ private function createDimension($name, $value) { diff --git a/app/code/Magento/CatalogUrlRewrite/etc/setup/events.xml b/app/code/Magento/CatalogUrlRewrite/etc/setup/events.xml deleted file mode 100644 index e880a73ed296d5edc907b483235aa254f4ac628e..0000000000000000000000000000000000000000 --- a/app/code/Magento/CatalogUrlRewrite/etc/setup/events.xml +++ /dev/null @@ -1,12 +0,0 @@ -<?xml version="1.0"?> -<!-- -/** - * Copyright © 2016 Magento. All rights reserved. - * See COPYING.txt for license details. - */ ---> -<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:Event/etc/events.xsd"> - <event name="catalog_product_save_after"> - <observer name="process_url_rewrite_saving" instance="\Magento\CatalogUrlRewrite\Observer\ProductProcessUrlRewriteSavingObserver"/> - </event> -</config> diff --git a/app/code/Magento/Checkout/Block/Shipping/Price.php b/app/code/Magento/Checkout/Block/Shipping/Price.php index 07cbe74ab9482507f13f427c56c6bd5e1d466950..8bba359ec316b3f68444d8e3d71e57c34b179e54 100644 --- a/app/code/Magento/Checkout/Block/Shipping/Price.php +++ b/app/code/Magento/Checkout/Block/Shipping/Price.php @@ -9,6 +9,10 @@ use Magento\Checkout\Block\Cart\AbstractCart; use Magento\Framework\Pricing\PriceCurrencyInterface; use Magento\Quote\Model\Quote\Address\Rate; +/** + * Class Price + * @deprecated + */ class Price extends AbstractCart { /** diff --git a/app/code/Magento/Checkout/view/frontend/layout/checkout_cart_index.xml b/app/code/Magento/Checkout/view/frontend/layout/checkout_cart_index.xml index f4b924dee078e95642346000baf2a364b4e79e93..8e5392d5c6a2475f68ddcb2d5723cdfc72a7f347 100644 --- a/app/code/Magento/Checkout/view/frontend/layout/checkout_cart_index.xml +++ b/app/code/Magento/Checkout/view/frontend/layout/checkout_cart_index.xml @@ -7,7 +7,6 @@ --> <page xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" layout="1column" xsi:noNamespaceSchemaLocation="urn:magento:framework:View/Layout/etc/page_configuration.xsd"> <update handle="checkout_cart_item_renderers"/> - <update handle="checkout_shipping_price_renderer"/> <body> <referenceContainer name="page.messages"> <block class="Magento\Checkout\Block\Cart\ValidationMessages" name="checkout.cart.validationmessages"/> diff --git a/app/code/Magento/Checkout/view/frontend/layout/checkout_cart_sidebar_total_renderers.xml b/app/code/Magento/Checkout/view/frontend/layout/checkout_cart_sidebar_total_renderers.xml index 0da9a686ee7d8fbdb2983b74df66b0128a1eeb15..60e88c5a4ac1b34a0aeb7eebf9cb131feb5bfba1 100644 --- a/app/code/Magento/Checkout/view/frontend/layout/checkout_cart_sidebar_total_renderers.xml +++ b/app/code/Magento/Checkout/view/frontend/layout/checkout_cart_sidebar_total_renderers.xml @@ -18,7 +18,7 @@ <item name="subtotal" xsi:type="array"> <item name="children" xsi:type="array"> <item name="subtotal.totals" xsi:type="array"> - <item name="component" xsi:type="string">uiComponent</item> + <item name="component" xsi:type="string">Magento_Checkout/js/view/checkout/minicart/subtotal/totals</item> <item name="config" xsi:type="array"> <item name="template" xsi:type="string">Magento_Checkout/minicart/subtotal/totals</item> </item> diff --git a/app/code/Magento/Checkout/view/frontend/layout/checkout_shipping_price_renderer.xml b/app/code/Magento/Checkout/view/frontend/layout/checkout_shipping_price_renderer.xml deleted file mode 100644 index 41a9ab6be8b0af068bba69ca3edae16056eca35a..0000000000000000000000000000000000000000 --- a/app/code/Magento/Checkout/view/frontend/layout/checkout_shipping_price_renderer.xml +++ /dev/null @@ -1,12 +0,0 @@ -<?xml version="1.0"?> -<!-- -/** - * Copyright © 2016 Magento. All rights reserved. - * See COPYING.txt for license details. - */ ---> -<layout xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:View/Layout/etc/layout_generic.xsd"> - <referenceContainer name="root"> - <block class="Magento\Checkout\Block\Shipping\Price" name="checkout.shipping.price" as="shipping.price" template="shipping/price.phtml"/> - </referenceContainer> -</layout> diff --git a/app/code/Magento/Checkout/view/frontend/web/js/model/address-converter.js b/app/code/Magento/Checkout/view/frontend/web/js/model/address-converter.js index d1bf7e1d0830db69f00d21aa521c6a9855443074..3ee5bd0679827ce5562bc07c4c684c58ffcb1573 100644 --- a/app/code/Magento/Checkout/view/frontend/web/js/model/address-converter.js +++ b/app/code/Magento/Checkout/view/frontend/web/js/model/address-converter.js @@ -107,8 +107,9 @@ define( */ objectToArray: function (object) { var convertedArray = []; + $.each(object, function (key) { - return object[key].length ? convertedArray.push(object[key]) : false; + return typeof object[key] === 'string' ? convertedArray.push(object[key]) : false; }); return convertedArray.slice(0); diff --git a/app/code/Magento/Checkout/view/frontend/web/js/view/checkout/minicart/subtotal/totals.js b/app/code/Magento/Checkout/view/frontend/web/js/view/checkout/minicart/subtotal/totals.js new file mode 100644 index 0000000000000000000000000000000000000000..6ca3f6f9f2c14e87059485d156f78a4da6d19ec3 --- /dev/null +++ b/app/code/Magento/Checkout/view/frontend/web/js/view/checkout/minicart/subtotal/totals.js @@ -0,0 +1,23 @@ +/** + * Copyright © 2016 Magento. All rights reserved. + * See COPYING.txt for license details. + */ +define([ + 'ko', + 'uiComponent', + 'Magento_Customer/js/customer-data' +], function (ko, Component, customerData) { + 'use strict'; + + return Component.extend({ + displaySubtotal: ko.observable(true), + + /** + * @override + */ + initialize: function () { + this._super(); + this.cart = customerData.get('cart'); + } + }); +}); diff --git a/app/code/Magento/Checkout/view/frontend/web/template/minicart/subtotal/totals.html b/app/code/Magento/Checkout/view/frontend/web/template/minicart/subtotal/totals.html index ff04b6d1375f826a8c0ae895f574bb43a258f163..baca55151c18a01a808d5fe02d9904c289002fe1 100644 --- a/app/code/Magento/Checkout/view/frontend/web/template/minicart/subtotal/totals.html +++ b/app/code/Magento/Checkout/view/frontend/web/template/minicart/subtotal/totals.html @@ -5,5 +5,5 @@ */ --> <div class="amount"> - <span data-bind="html: getCartParam('subtotal')"></span> + <span data-bind="html: cart().subtotal"></span> </div> diff --git a/app/code/Magento/Cms/Model/ResourceModel/Page/Grid/Collection.php b/app/code/Magento/Cms/Model/ResourceModel/Page/Grid/Collection.php index 4337c5457e1c1e570b338f3be37c5e74fb15232d..b1bcb33b69d7ecc42375e4f07f0af2933e4e41a0 100644 --- a/app/code/Magento/Cms/Model/ResourceModel/Page/Grid/Collection.php +++ b/app/code/Magento/Cms/Model/ResourceModel/Page/Grid/Collection.php @@ -5,9 +5,11 @@ */ namespace Magento\Cms\Model\ResourceModel\Page\Grid; +use Magento\Cms\Model\Page; use Magento\Framework\Api\Search\SearchResultInterface; use Magento\Framework\Api\Search\AggregationInterface; use Magento\Cms\Model\ResourceModel\Page\Collection as PageCollection; +use Magento\Framework\View\Element\UiComponent\DataProvider\Document; /** * Class Collection @@ -23,7 +25,7 @@ class Collection extends PageCollection implements SearchResultInterface /** * @var \Magento\Framework\View\Element\UiComponent\DataProvider\Document[] */ - private $loadedData; + private $loadedData = []; /** * @param \Magento\Framework\Data\Collection\EntityFactoryInterface $entityFactory @@ -151,16 +153,14 @@ class Collection extends PageCollection implements SearchResultInterface */ public function getItems() { - if (isset($this->loadedData)) { + if ($this->loadedData) { return $this->loadedData; } - /** @var \Magento\Cms\Model\Page $page */ - $page = $this->_entityFactory->create(\Magento\Cms\Model\Page::class); - /** Load every record separately to make sure the list of associated stores is available */ - /** @var \Magento\Framework\View\Element\UiComponent\DataProvider\Document $pageDocument */ + + /** @var Document $pageDocument */ foreach (parent::getItems() as $pageDocument) { $this->loadedData[$pageDocument->getId()] = $pageDocument->setData( - $page->load($pageDocument->getId())->getData() + $this->_entityFactory->create(Page::class)->load($pageDocument->getId())->getData() ); } diff --git a/app/code/Magento/Cms/Test/Unit/Model/ResourceModel/Page/Grid/CollectionTest.php b/app/code/Magento/Cms/Test/Unit/Model/ResourceModel/Page/Grid/CollectionTest.php new file mode 100644 index 0000000000000000000000000000000000000000..408c9c662b863e6440bd64d9ece1d8581239c601 --- /dev/null +++ b/app/code/Magento/Cms/Test/Unit/Model/ResourceModel/Page/Grid/CollectionTest.php @@ -0,0 +1,140 @@ +<?php +/** + * Copyright © 2016 Magento. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\Cms\Test\Unit\Model\ResourceModel\Page\Grid; + +use Magento\Cms\Model\ResourceModel\Page\Grid\Collection; +use Magento\Framework\Api\Search\AggregationInterface; +use Magento\Framework\Data\Collection\Db\FetchStrategyInterface; +use Magento\Framework\Data\Collection\EntityFactoryInterface; +use Magento\Framework\DB\Adapter\AdapterInterface; +use Magento\Framework\Event\ManagerInterface; +use Magento\Framework\Model\Entity\MetadataPool; +use Magento\Framework\Model\ResourceModel\Db\AbstractDb; +use Magento\Framework\TestFramework\Unit\Helper\ObjectManager; +use Magento\Store\Model\StoreManagerInterface; +use Psr\Log\LoggerInterface; +use Magento\Framework\DB\Select; + +/** + * Class CollectionTest + * @SuppressWarnings(PHPMD.CouplingBetweenObjects) + */ +class CollectionTest extends \PHPUnit_Framework_TestCase +{ + /** + * @var EntityFactoryInterface|\PHPUnit_Framework_MockObject_MockObject + */ + protected $entityFactoryMock; + + /** + * @var LoggerInterface|\PHPUnit_Framework_MockObject_MockObject + */ + protected $loggerMock; + + /** + * @var FetchStrategyInterface|\PHPUnit_Framework_MockObject_MockObject + */ + protected $fetchStrategyMock; + + /** + * @var ManagerInterface|\PHPUnit_Framework_MockObject_MockObject + */ + protected $eventManagerMock; + + /** + * @var StoreManagerInterface|\PHPUnit_Framework_MockObject_MockObject + */ + protected $storeManagerMock; + + /** + * @var MetadataPool|\PHPUnit_Framework_MockObject_MockObject + */ + protected $metadataPoolMock; + + /** + * @var AdapterInterface|\PHPUnit_Framework_MockObject_MockObject + */ + protected $connectionMock; + + /** + * @var AbstractDb|\PHPUnit_Framework_MockObject_MockObject + */ + protected $resourceMock; + + /** + * @var AggregationInterface|\PHPUnit_Framework_MockObject_MockObject + */ + protected $aggregationsMock; + + /** + * @var Select + */ + protected $selectMock; + + /** + * @var Collection + */ + protected $model; + + protected function setUp() + { + $this->entityFactoryMock = $this->getMockBuilder(EntityFactoryInterface::class) + ->getMockForAbstractClass(); + $this->loggerMock = $this->getMockBuilder(LoggerInterface::class) + ->getMockForAbstractClass(); + $this->fetchStrategyMock = $this->getMockBuilder(FetchStrategyInterface::class) + ->getMockForAbstractClass(); + $this->eventManagerMock = $this->getMockBuilder(ManagerInterface::class) + ->getMockForAbstractClass(); + $this->storeManagerMock = $this->getMockBuilder(StoreManagerInterface::class) + ->getMockForAbstractClass(); + $this->metadataPoolMock = $this->getMockBuilder(MetadataPool::class) + ->disableOriginalConstructor() + ->getMock(); + $this->resourceMock = $this->getMockBuilder(AbstractDb::class) + ->disableOriginalConstructor() + ->getMock(); + $this->aggregationsMock = $this->getMockBuilder(AggregationInterface::class) + ->getMockForAbstractClass(); + $this->connectionMock = $this->getMockBuilder(AdapterInterface::class) + ->getMockForAbstractClass(); + $this->selectMock = $this->getMockBuilder(Select::class) + ->disableOriginalConstructor() + ->getMock(); + + $this->resourceMock->expects($this->any()) + ->method('getConnection') + ->willReturn($this->connectionMock); + $this->connectionMock->expects($this->once()) + ->method('select') + ->willReturn($this->selectMock); + + $this->model = (new ObjectManager($this))->getObject(Collection::class, [ + 'entityFactory' => $this->entityFactoryMock, + 'logger' => $this->loggerMock, + 'fetchStrategy' => $this->fetchStrategyMock, + 'eventManager' => $this->eventManagerMock, + 'storeManager' => $this->storeManagerMock, + 'metadataPool' => $this->metadataPoolMock, + 'mainTable' => null, + 'eventPrefix' => 'test_event_prefix', + 'eventObject' => 'test_event_object', + 'resourceModel' => null, + 'resource' => $this->resourceMock, + ]); + } + + public function testSetterGetter() + { + $this->model->setAggregations($this->aggregationsMock); + $this->assertInstanceOf(AggregationInterface::class, $this->model->getAggregations()); + } + + public function testSetSearchCriteria() + { + $this->assertEquals($this->model, $this->model->setSearchCriteria()); + } +} diff --git a/app/code/Magento/CmsUrlRewrite/etc/adminhtml/events.xml b/app/code/Magento/CmsUrlRewrite/etc/events.xml similarity index 100% rename from app/code/Magento/CmsUrlRewrite/etc/adminhtml/events.xml rename to app/code/Magento/CmsUrlRewrite/etc/events.xml diff --git a/app/code/Magento/CmsUrlRewrite/etc/setup/events.xml b/app/code/Magento/CmsUrlRewrite/etc/setup/events.xml deleted file mode 100644 index 79798b599e2942ed6994b1c0e00b51d39de7e6bd..0000000000000000000000000000000000000000 --- a/app/code/Magento/CmsUrlRewrite/etc/setup/events.xml +++ /dev/null @@ -1,12 +0,0 @@ -<?xml version="1.0"?> -<!-- -/** - * Copyright © 2016 Magento. All rights reserved. - * See COPYING.txt for license details. - */ ---> -<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:Event/etc/events.xsd"> - <event name="cms_page_save_after"> - <observer name="process_url_rewrite_saving" instance="Magento\CmsUrlRewrite\Observer\ProcessUrlRewriteSavingObserver" /> - </event> -</config> diff --git a/app/code/Magento/Config/Model/Config/Backend/Cache.php b/app/code/Magento/Config/Model/Config/Backend/Cache.php index 361cbcd25510c23a46c9e107a09c865b18d05be3..ba437c0f971b2ada295c37ce0e9871b218aa4c1a 100644 --- a/app/code/Magento/Config/Model/Config/Backend/Cache.php +++ b/app/code/Magento/Config/Model/Config/Backend/Cache.php @@ -22,12 +22,13 @@ class Cache extends \Magento\Framework\App\Config\Value /** * Clean cache, value was changed * - * @return void + * @return $this */ public function afterSave() { if ($this->isValueChanged()) { $this->_cacheManager->clean($this->_cacheTags); } + return $this; } } diff --git a/app/code/Magento/Config/Model/Config/Backend/Datashare.php b/app/code/Magento/Config/Model/Config/Backend/Datashare.php index dff894cb559605e6f04937fc939f127e3a2ca1cf..bd0bfaa478abc5713d73a830126b64e6028bba1d 100644 --- a/app/code/Magento/Config/Model/Config/Backend/Datashare.php +++ b/app/code/Magento/Config/Model/Config/Backend/Datashare.php @@ -14,9 +14,10 @@ namespace Magento\Config\Model\Config\Backend; class Datashare extends \Magento\Framework\App\Config\Value { /** - * @return void + * @return $this */ public function afterSave() { + return $this; } } diff --git a/app/code/Magento/ConfigurableProduct/Controller/Adminhtml/Product/Initialization/Helper/Plugin/Configurable.php b/app/code/Magento/ConfigurableProduct/Controller/Adminhtml/Product/Initialization/Helper/Plugin/Configurable.php index bd8bea9f25a57386f3fbba84cb2ea1ddf0c49983..df7ceda95692d9f92df1c983619931f202845868 100644 --- a/app/code/Magento/ConfigurableProduct/Controller/Adminhtml/Product/Initialization/Helper/Plugin/Configurable.php +++ b/app/code/Magento/ConfigurableProduct/Controller/Adminhtml/Product/Initialization/Helper/Plugin/Configurable.php @@ -129,6 +129,11 @@ class Configurable { $associatedProductIds = $this->request->getPost('associated_product_ids', []); $variationsMatrix = $this->getVariationMatrix(); + + if ($associatedProductIds || $variationsMatrix) { + $this->variationHandler->prepareAttributeSet($product); + } + if (!empty($variationsMatrix)) { $generatedProductIds = $this->variationHandler->generateSimpleProducts($product, $variationsMatrix); $associatedProductIds = array_merge($associatedProductIds, $generatedProductIds); diff --git a/app/code/Magento/ConfigurableProduct/Model/Product/Type/Configurable.php b/app/code/Magento/ConfigurableProduct/Model/Product/Type/Configurable.php index e2a2cdf527fd5a337c85fa5b72822f55d2e68829..2fc849be10f10988356b977298168173a18a4f7b 100644 --- a/app/code/Magento/ConfigurableProduct/Model/Product/Type/Configurable.php +++ b/app/code/Magento/ConfigurableProduct/Model/Product/Type/Configurable.php @@ -508,6 +508,7 @@ class Configurable extends \Magento\Catalog\Model\Product\Type\AbstractType $collection = $this->getUsedProductCollection($product) ->addAttributeToSelect('name') ->addAttributeToSelect('price') + ->addAttributeToSelect('weight') // ->addAttributeToSelect('msrp') // ->addAttributeToSelect('media_gallery') ->addFilterByRequiredOptions() diff --git a/app/code/Magento/ConfigurableProduct/Model/Product/VariationHandler.php b/app/code/Magento/ConfigurableProduct/Model/Product/VariationHandler.php index 86d5aa130637b59f9d4ad431eda589679aebda31..9a40931c05d024f4f25cf793b30f1b4d30bb6019 100644 --- a/app/code/Magento/ConfigurableProduct/Model/Product/VariationHandler.php +++ b/app/code/Magento/ConfigurableProduct/Model/Product/VariationHandler.php @@ -66,7 +66,6 @@ class VariationHandler */ public function generateSimpleProducts($parentProduct, $productsData) { - $this->prepareAttributeSetToBeBaseForNewVariations($parentProduct); $generatedProductIds = []; $productsData = $this->duplicateImagesForVariations($productsData); foreach ($productsData as $simpleProductData) { @@ -93,11 +92,22 @@ class VariationHandler /** * Prepare attribute set comprising all selected configurable attributes * + * @deprecated since 2.1.0 * @param \Magento\Catalog\Model\Product $product - * * @return void */ protected function prepareAttributeSetToBeBaseForNewVariations(\Magento\Catalog\Model\Product $product) + { + $this->prepareAttributeSet($product); + } + + /** + * Prepare attribute set comprising all selected configurable attributes + * + * @param \Magento\Catalog\Model\Product $product + * @return void + */ + public function prepareAttributeSet(\Magento\Catalog\Model\Product $product) { $attributes = $this->configurableProduct->getUsedProductAttributes($product); $attributeSetId = $product->getNewVariationsAttributeSetId(); @@ -156,7 +166,8 @@ class VariationHandler $product->setData($attribute->getAttributeCode(), $parentProduct->getData($attribute->getAttributeCode())); } - $postData['stock_data'] = $parentProduct->getStockData(); + $keysFilter = ['item_id', 'product_id', 'stock_id', 'type_id', 'website_id']; + $postData['stock_data'] = array_diff_key((array)$parentProduct->getStockData(), array_flip($keysFilter)); $postData['stock_data']['manage_stock'] = $postData['quantity_and_stock_status']['qty'] === '' ? 0 : 1; if (!isset($postData['stock_data']['is_in_stock'])) { $stockStatus = $parentProduct->getQuantityAndStockStatus(); diff --git a/app/code/Magento/ConfigurableProduct/Test/Unit/Controller/Adminhtml/Product/Initialization/Helper/Plugin/ConfigurableTest.php b/app/code/Magento/ConfigurableProduct/Test/Unit/Controller/Adminhtml/Product/Initialization/Helper/Plugin/ConfigurableTest.php index 055cc18ffbd02409698e97c200c6c6f4d1a3b863..f8b42171dd674cd09c17c3949fa20805fb35c871 100644 --- a/app/code/Magento/ConfigurableProduct/Test/Unit/Controller/Adminhtml/Product/Initialization/Helper/Plugin/ConfigurableTest.php +++ b/app/code/Magento/ConfigurableProduct/Test/Unit/Controller/Adminhtml/Product/Initialization/Helper/Plugin/ConfigurableTest.php @@ -57,7 +57,7 @@ class ConfigurableTest extends \PHPUnit_Framework_TestCase { $this->variationHandler = $this->getMockBuilder(VariationHandler::class) ->disableOriginalConstructor() - ->setMethods(['generateSimpleProducts']) + ->setMethods(['generateSimpleProducts', 'prepareAttributeSet']) ->getMock(); $this->request = $this->getMockBuilder(Http::class) @@ -183,6 +183,10 @@ class ConfigurableTest extends \PHPUnit_Framework_TestCase ->method('setConfigurableProductOptions') ->with($attributes); + $this->variationHandler->expects(static::once()) + ->method('prepareAttributeSet') + ->with($this->product); + $this->variationHandler->expects(static::once()) ->method('generateSimpleProducts') ->with($this->product, $variationMatrix) @@ -248,6 +252,9 @@ class ConfigurableTest extends \PHPUnit_Framework_TestCase ->method('setConfigurableProductOptions') ->with($attributes); + $this->variationHandler->expects(static::never()) + ->method('prepareAttributeSet'); + $this->variationHandler->expects(static::never()) ->method('generateSimpleProducts'); @@ -277,6 +284,8 @@ class ConfigurableTest extends \PHPUnit_Framework_TestCase ->method('getExtensionAttributes'); $this->request->expects(static::once()) ->method('getPost'); + $this->variationHandler->expects(static::never()) + ->method('prepareAttributeSet'); $this->variationHandler->expects(static::never()) ->method('generateSimpleProducts'); $this->plugin->afterInitialize($this->subject, $this->product); @@ -294,6 +303,8 @@ class ConfigurableTest extends \PHPUnit_Framework_TestCase ->method('getExtensionAttributes'); $this->request->expects(static::once()) ->method('getPost'); + $this->variationHandler->expects(static::never()) + ->method('prepareAttributeSet'); $this->variationHandler->expects(static::never()) ->method('generateSimpleProducts'); $this->plugin->afterInitialize($this->subject, $this->product); diff --git a/app/code/Magento/ConfigurableProduct/Test/Unit/Model/Product/VariationHandlerTest.php b/app/code/Magento/ConfigurableProduct/Test/Unit/Model/Product/VariationHandlerTest.php index 85f4154a1b81341797734603ac4efae95ae59013..7efc0794f11b80edb6893871b727298672142f6a 100644 --- a/app/code/Magento/ConfigurableProduct/Test/Unit/Model/Product/VariationHandlerTest.php +++ b/app/code/Magento/ConfigurableProduct/Test/Unit/Model/Product/VariationHandlerTest.php @@ -18,27 +18,27 @@ class VariationHandlerTest extends \PHPUnit_Framework_TestCase /** * @var VariationHandler */ - protected $_model; + protected $model; /** * @var \PHPUnit_Framework_MockObject_MockObject|\Magento\Eav\Model\Entity\Attribute\SetFactory */ - protected $_attributeSetFactory; + protected $attributeSetFactory; /** * @var \PHPUnit_Framework_MockObject_MockObject|\Magento\Eav\Model\EntityFactory */ - protected $_entityFactoryMock; + protected $entityFactoryMock; /** * @var \PHPUnit_Framework_MockObject_MockObject|\Magento\Catalog\Model\ProductFactory */ - protected $_productFactoryMock; + protected $productFactoryMock; /** * @var \PHPUnit_Framework_MockObject_MockObject|\Magento\CatalogInventory\Api\StockConfigurationInterface */ - protected $_stockConfiguration; + protected $stockConfiguration; /** * @var \PHPUnit_Framework_MockObject_MockObject|\Magento\ConfigurableProduct\Model\Product\Type\Configurable @@ -48,41 +48,41 @@ class VariationHandlerTest extends \PHPUnit_Framework_TestCase /** * @var \Magento\Framework\TestFramework\Unit\Helper\ObjectManager */ - protected $_objectHelper; + protected $objectHelper; /** * @var \Magento\Catalog\Model\Product|\PHPUnit_Framework_MockObject_MockObject */ - private $_product; + private $product; /** * @SuppressWarnings(PHPMD.ExcessiveMethodLength) */ protected function setUp() { - $this->_objectHelper = new \Magento\Framework\TestFramework\Unit\Helper\ObjectManager($this); - $this->_productFactoryMock = $this->getMock( + $this->objectHelper = new \Magento\Framework\TestFramework\Unit\Helper\ObjectManager($this); + $this->productFactoryMock = $this->getMock( 'Magento\Catalog\Model\ProductFactory', ['create'], [], '', false ); - $this->_entityFactoryMock = $this->getMock( + $this->entityFactoryMock = $this->getMock( 'Magento\Eav\Model\EntityFactory', ['create'], [], '', false ); - $this->_attributeSetFactory = $this->getMock( + $this->attributeSetFactory = $this->getMock( 'Magento\Eav\Model\Entity\Attribute\SetFactory', ['create'], [], '', false ); - $this->_stockConfiguration = $this->getMock( + $this->stockConfiguration = $this->getMock( 'Magento\CatalogInventory\Api\StockConfigurationInterface', [], [], @@ -97,20 +97,68 @@ class VariationHandlerTest extends \PHPUnit_Framework_TestCase false ); - $this->_product = $this->getMock('Magento\Catalog\Model\Product', ['getMediaGallery'], [], '', false); + $this->product = $this->getMock('Magento\Catalog\Model\Product', ['getMediaGallery'], [], '', false); - $this->_model = $this->_objectHelper->getObject( + $this->model = $this->objectHelper->getObject( 'Magento\ConfigurableProduct\Model\Product\VariationHandler', [ - 'productFactory' => $this->_productFactoryMock, - 'entityFactory' => $this->_entityFactoryMock, - 'attributeSetFactory' => $this->_attributeSetFactory, - 'stockConfiguration' => $this->_stockConfiguration, + 'productFactory' => $this->productFactoryMock, + 'entityFactory' => $this->entityFactoryMock, + 'attributeSetFactory' => $this->attributeSetFactory, + 'stockConfiguration' => $this->stockConfiguration, 'configurableProduct' => $this->configurableProduct ] ); } + public function testPrepareAttributeSet() + { + + $productMock = $this->getMockBuilder('\Magento\Catalog\Model\Product') + ->setMethods(['getNewVariationsAttributeSetId']) + ->disableOriginalConstructor() + ->getMock(); + $attributeMock = $this->getMockBuilder('\Magento\Eav\Model\Entity\Attribute') + ->setMethods(['isInSet', 'setAttributeSetId', 'setAttributeGroupId', 'save']) + ->disableOriginalConstructor() + ->getMock(); + $attributeSetMock = $this->getMockBuilder('Magento\Eav\Model\Entity\Attribute\Set') + ->setMethods(['load', 'addSetInfo', 'getDefaultGroupId']) + ->disableOriginalConstructor() + ->getMock(); + $eavEntityMock = $this->getMockBuilder('\Magento\Eav\Model\Entity') + ->setMethods(['setType', 'getTypeId']) + ->disableOriginalConstructor() + ->getMock(); + + $productMock->expects($this->once()) + ->method('getNewVariationsAttributeSetId') + ->willReturn('new_attr_set_id'); + $this->configurableProduct->expects($this->once()) + ->method('getUsedProductAttributes') + ->with($productMock) + ->willReturn([$attributeMock]); + $this->attributeSetFactory->expects($this->once())->method('create')->willReturn($attributeSetMock); + $attributeSetMock->expects($this->once())->method('load')->with('new_attr_set_id')->willReturnSelf(); + $this->entityFactoryMock->expects($this->once())->method('create')->willReturn($eavEntityMock); + $eavEntityMock->expects($this->once())->method('setType')->with('catalog_product')->willReturnSelf(); + $eavEntityMock->expects($this->once())->method('getTypeId')->willReturn('type_id'); + $attributeSetMock->expects($this->once())->method('addSetInfo')->with('type_id', [$attributeMock]); + $attributeMock->expects($this->once())->method('isInSet')->with('new_attr_set_id')->willReturn(false); + $attributeMock->expects($this->once())->method('setAttributeSetId')->with('new_attr_set_id')->willReturnSelf(); + $attributeSetMock->expects($this->once()) + ->method('getDefaultGroupId') + ->with('new_attr_set_id') + ->willReturn('default_group_id'); + $attributeMock->expects($this->once()) + ->method('setAttributeGroupId') + ->with('default_group_id') + ->willReturnSelf(); + $attributeMock->expects($this->once())->method('save')->willReturnSelf(); + + $this->model->prepareAttributeSet($productMock); + } + /** * @SuppressWarnings(PHPMD.ExcessiveMethodLength) */ @@ -169,18 +217,6 @@ class VariationHandlerTest extends \PHPUnit_Framework_TestCase ) ->disableOriginalConstructor() ->getMock(); - $attributeMock = $this->getMockBuilder('\Magento\Eav\Model\Entity\Attribute') - ->setMethods(['isInSet', 'setAttributeSetId', 'setAttributeGroupId', 'save']) - ->disableOriginalConstructor() - ->getMock(); - $attributeSetMock = $this->getMockBuilder('Magento\Eav\Model\Entity\Attribute\Set') - ->setMethods(['load', 'addSetInfo', 'getDefaultGroupId']) - ->disableOriginalConstructor() - ->getMock(); - $eavEntityMock = $this->getMockBuilder('\Magento\Eav\Model\Entity') - ->setMethods(['setType', 'getTypeId']) - ->disableOriginalConstructor() - ->getMock(); $productTypeMock = $this->getMockBuilder('Magento\Catalog\Model\Product\Type') ->setMethods(['getSetAttributes']) ->disableOriginalConstructor() @@ -194,29 +230,10 @@ class VariationHandlerTest extends \PHPUnit_Framework_TestCase ->disableOriginalConstructor() ->getMock(); - $this->configurableProduct->expects($this->once())->method('getUsedProductAttributes') - ->willReturn([$attributeMock]); - $parentProductMock->expects($this->any()) + $parentProductMock->expects($this->once()) ->method('getNewVariationsAttributeSetId') ->willReturn('new_attr_set_id'); - $this->_attributeSetFactory->expects($this->once())->method('create')->willReturn($attributeSetMock); - $attributeSetMock->expects($this->once())->method('load')->with('new_attr_set_id')->willReturnSelf(); - $this->_entityFactoryMock->expects($this->once())->method('create')->willReturn($eavEntityMock); - $eavEntityMock->expects($this->once())->method('setType')->with('catalog_product')->willReturnSelf(); - $eavEntityMock->expects($this->once())->method('getTypeId')->willReturn('type_id'); - $attributeSetMock->expects($this->once())->method('addSetInfo')->with('type_id', [$attributeMock]); - $attributeMock->expects($this->once())->method('isInSet')->with('new_attr_set_id')->willReturn(false); - $attributeMock->expects($this->once())->method('setAttributeSetId')->with('new_attr_set_id')->willReturnSelf(); - $attributeSetMock->expects($this->once()) - ->method('getDefaultGroupId') - ->with('new_attr_set_id') - ->willReturn('default_group_id'); - $attributeMock->expects($this->once()) - ->method('setAttributeGroupId') - ->with('default_group_id') - ->willReturnSelf(); - $attributeMock->expects($this->once())->method('save')->willReturnSelf(); - $this->_productFactoryMock->expects($this->once())->method('create')->willReturn($newSimpleProductMock); + $this->productFactoryMock->expects($this->once())->method('create')->willReturn($newSimpleProductMock); $newSimpleProductMock->expects($this->once())->method('setStoreId')->with(0)->willReturnSelf(); $newSimpleProductMock->expects($this->once())->method('setTypeId')->with('simple')->willReturnSelf(); $newSimpleProductMock->expects($this->once()) @@ -238,7 +255,7 @@ class VariationHandlerTest extends \PHPUnit_Framework_TestCase ->method('getQuantityAndStockStatus') ->willReturn(['is_in_stock' => 1]); $newSimpleProductMock->expects($this->once())->method('getStoreId')->willReturn('store_id'); - $this->_stockConfiguration->expects($this->once()) + $this->stockConfiguration->expects($this->once()) ->method('getManageStock') ->with('store_id') ->willReturn(1); @@ -249,41 +266,41 @@ class VariationHandlerTest extends \PHPUnit_Framework_TestCase $newSimpleProductMock->expects($this->once())->method('save')->willReturnSelf(); $newSimpleProductMock->expects($this->once())->method('getId')->willReturn('product_id'); - $this->assertEquals(['product_id'], $this->_model->generateSimpleProducts($parentProductMock, $productsData)); + $this->assertEquals(['product_id'], $this->model->generateSimpleProducts($parentProductMock, $productsData)); } public function testProcessMediaGalleryWithImagesAndGallery() { - $this->_product->expects($this->atLeastOnce())->method('getMediaGallery')->with('images')->willReturn([]); + $this->product->expects($this->atLeastOnce())->method('getMediaGallery')->with('images')->willReturn([]); $productData['image'] = 'test'; $productData['media_gallery']['images'] = [ [ 'file' => 'test', ], ]; - $result = $this->_model->processMediaGallery($this->_product, $productData); + $result = $this->model->processMediaGallery($this->product, $productData); $this->assertEquals($productData, $result); } public function testProcessMediaGalleryIfImageIsEmptyButProductMediaGalleryIsNotEmpty() { - $this->_product->expects($this->atLeastOnce())->method('getMediaGallery')->with('images')->willReturn([]); + $this->product->expects($this->atLeastOnce())->method('getMediaGallery')->with('images')->willReturn([]); $productData['image'] = false; $productData['media_gallery']['images'] = [ [ 'name' => 'test', ], ]; - $result = $this->_model->processMediaGallery($this->_product, $productData); + $result = $this->model->processMediaGallery($this->product, $productData); $this->assertEquals($productData, $result); } public function testProcessMediaGalleryIfProductDataHasNoImagesAndGallery() { - $this->_product->expects($this->once())->method('getMediaGallery')->with('images')->willReturn([]); + $this->product->expects($this->once())->method('getMediaGallery')->with('images')->willReturn([]); $productData['image'] = false; $productData['media_gallery']['images'] = false; - $result = $this->_model->processMediaGallery($this->_product, $productData); + $result = $this->model->processMediaGallery($this->product, $productData); $this->assertEquals($productData, $result); } @@ -294,7 +311,7 @@ class VariationHandlerTest extends \PHPUnit_Framework_TestCase */ public function testProcessMediaGalleryForFillingGallery($productData, $expected) { - $this->assertEquals($expected, $this->_model->processMediaGallery($this->_product, $productData)); + $this->assertEquals($expected, $this->model->processMediaGallery($this->product, $productData)); } /** diff --git a/app/code/Magento/ConfigurableProduct/Ui/DataProvider/Product/Form/Modifier/ConfigurableAttributeSetHandler.php b/app/code/Magento/ConfigurableProduct/Ui/DataProvider/Product/Form/Modifier/ConfigurableAttributeSetHandler.php index ce7524a783e9649fda851b7ec0b18e3ae2f13f6f..5832c18744b661712a040b2f9f7e98490bdb21e8 100644 --- a/app/code/Magento/ConfigurableProduct/Ui/DataProvider/Product/Form/Modifier/ConfigurableAttributeSetHandler.php +++ b/app/code/Magento/ConfigurableProduct/Ui/DataProvider/Product/Form/Modifier/ConfigurableAttributeSetHandler.php @@ -199,6 +199,7 @@ class ConfigurableAttributeSetHandler extends AbstractModifier 'formElement' => Form\Element\Input::NAME, 'componentType' => Form\Field::NAME, 'dataScope' => 'configurableNewAttributeSetName', + 'additionalClasses' => 'new-attribute-set-name', 'label' => __('New Attribute Set Name'), 'sortOrder' => 40, 'validation' => ['required-entry' => true], diff --git a/app/code/Magento/ConfigurableProduct/Ui/DataProvider/Product/Form/Modifier/ConfigurablePanel.php b/app/code/Magento/ConfigurableProduct/Ui/DataProvider/Product/Form/Modifier/ConfigurablePanel.php index 5810eefe9007cd14f4e83ec34fba84df2e5b9c95..fb2161d3c64cb1093d82487f6219a9cfd81a5d0a 100644 --- a/app/code/Magento/ConfigurableProduct/Ui/DataProvider/Product/Form/Modifier/ConfigurablePanel.php +++ b/app/code/Magento/ConfigurableProduct/Ui/DataProvider/Product/Form/Modifier/ConfigurablePanel.php @@ -129,7 +129,7 @@ class ConfigurablePanel extends AbstractModifier 'config' => [ 'componentType' => Modal::NAME, 'dataScope' => '', - 'provider' => $this->dataSourceName, + 'provider' => static::FORM_NAME . '.product_form_data_source', 'options' => [ 'title' => __('Select Associated Product'), 'buttons' => [ @@ -138,9 +138,7 @@ class ConfigurablePanel extends AbstractModifier 'class' => 'action-primary', 'actions' => [ [ - 'targetName' => 'ns= ' . $this->associatedListingPrefix - . static::ASSOCIATED_PRODUCT_LISTING - . ', index=' . static::ASSOCIATED_PRODUCT_LISTING, + 'targetName' => 'index=' . static::ASSOCIATED_PRODUCT_LISTING, 'actionName' => 'save' ], 'closeModal' @@ -227,6 +225,10 @@ class ConfigurablePanel extends AbstractModifier . 'configurable_associated_product_listing.product_columns.ids', 'modalWithGrid' => 'ns=' . $this->formName . ', index=' . static::ASSOCIATED_PRODUCT_MODAL, + 'productsFilters' => $this->associatedListingPrefix + . 'configurable_associated_product_listing' + . '.' . $this->associatedListingPrefix + . 'configurable_associated_product_listing.listing_top.listing_filters', ], ], ], @@ -292,13 +294,12 @@ class ConfigurablePanel extends AbstractModifier 'displayAsLink' => true, 'actions' => [ [ - 'targetName' => 'ns=' . $this->formName . ', index=' + 'targetName' => 'ns=' . static::FORM_NAME . ', index=' . static::ASSOCIATED_PRODUCT_MODAL, 'actionName' => 'openModal', ], [ - 'targetName' => 'ns=' . $this->associatedListingPrefix - . static::ASSOCIATED_PRODUCT_LISTING + 'targetName' => 'ns=' . static::ASSOCIATED_PRODUCT_LISTING . ', index=' . static::ASSOCIATED_PRODUCT_LISTING, 'actionName' => 'showGridAssignProduct', ], @@ -325,13 +326,13 @@ class ConfigurablePanel extends AbstractModifier 'actions' => [ [ 'targetName' => - $this->dataScopeName . '.configurableModal', + 'product_form.product_form.configurableModal', 'actionName' => 'trigger', 'params' => ['active', true], ], [ 'targetName' => - $this->dataScopeName . '.configurableModal', + 'product_form.product_form.configurableModal', 'actionName' => 'openModal', ], ], @@ -369,7 +370,7 @@ class ConfigurablePanel extends AbstractModifier 'isEmpty' => true, 'itemTemplate' => 'record', 'dataScope' => 'data', - 'dataProviderFromGrid' => $this->associatedListingPrefix . static::ASSOCIATED_PRODUCT_LISTING, + 'dataProviderFromGrid' => static::ASSOCIATED_PRODUCT_LISTING, 'dataProviderChangeFromGrid' => 'change_product', 'dataProviderFromWizard' => 'variations', 'map' => [ @@ -394,10 +395,9 @@ class ConfigurablePanel extends AbstractModifier 'sortOrder' => 20, 'columnsHeader' => false, 'columnsHeaderAfterRender' => true, - 'modalWithGrid' => 'ns=' . $this->formName . ', index=' + 'modalWithGrid' => 'ns=' . static::FORM_NAME . ', index=' . static::ASSOCIATED_PRODUCT_MODAL, - 'gridWithProducts' => 'ns=' . $this->associatedListingPrefix - . static::ASSOCIATED_PRODUCT_LISTING + 'gridWithProducts' => 'ns=' . static::ASSOCIATED_PRODUCT_LISTING . ', index=' . static::ASSOCIATED_PRODUCT_LISTING, ], ], @@ -439,10 +439,6 @@ class ConfigurablePanel extends AbstractModifier 'elementTmpl' => 'Magento_ConfigurableProduct/components/file-uploader', 'fileInputName' => 'image', 'isMultipleFiles' => false, - 'imports' => [ - 'thumbnailUrl' => '${$.provider}:${$.parentScope}.thumbnail_image', - 'thumbnail' => '${$.provider}:${$.parentScope}.thumbnail' - ], 'uploaderConfig' => [ 'url' => $this->urlBuilder->addSessionParam()->getUrl( 'catalog/product_gallery/upload' diff --git a/app/code/Magento/ConfigurableProduct/view/adminhtml/templates/catalog/product/edit/attribute/steps/attributes_values.phtml b/app/code/Magento/ConfigurableProduct/view/adminhtml/templates/catalog/product/edit/attribute/steps/attributes_values.phtml index 0dfcf167bda4d1061b690d9469f1b754fa7b550a..a684ccef60f15e1ffb38b8c5a5556ea653fe6edf 100644 --- a/app/code/Magento/ConfigurableProduct/view/adminhtml/templates/catalog/product/edit/attribute/steps/attributes_values.phtml +++ b/app/code/Magento/ConfigurableProduct/view/adminhtml/templates/catalog/product/edit/attribute/steps/attributes_values.phtml @@ -9,9 +9,13 @@ /* @var $block \Magento\ConfigurableProduct\Block\Adminhtml\Product\Steps\AttributeValues */ ?> <div data-bind="scope: '<?= /* @noEscape */ $block->getComponentName()?>'"> - <h2 class="steps-wizard-title"><?= /* @noEscape */ __('Step 2: Attribute Values') ?></h2> + <h2 class="steps-wizard-title"><?php echo $block->escapeHtml( + __('Step 2: Attribute Values') + ); ?></h2> <div class="steps-wizard-info"> - <span><?= $block->escapeHtml(__('Select from the following attribute values for this product. Each unique combination of values creates a unique product SKU.')) ?></span> + <span><?php echo $block->escapeHtml( + __('Select values from each attribute to include in this product. Each unique combination of values creates a unigue product SKU.') + );?></span> </div> <div data-bind="foreach: attributes, sortableList: attributes"> @@ -25,7 +29,9 @@ <div class="attribute-entity-title" data-bind="text: label"></div> <div class="attribute-options-block"> (<span class="attribute-length" data-bind="text: $data.options().length"></span> - <?= /* @noEscape */ __('Options') ?>) + <?php echo $block->escapeHtml( + __('Options') + ); ?>) </div> </div> @@ -34,19 +40,25 @@ class="action-select-all action-tertiary" data-bind="click: $parent.selectAllAttributes" title="<?= $block->escapeHtml(__('Select All')) ?>"> - <span><?= /* @noEscape */ __('Select All') ?></span> + <span><?php echo $block->escapeHtml( + __('Select All') + ); ?></span> </button> <button type="button" class="action-deselect-all action-tertiary" data-bind="click: $parent.deSelectAllAttributes" title="<?= $block->escapeHtml(__('Deselect All')) ?>"> - <span><?= /* @noEscape */ __('Deselect All') ?></span> + <span><?php echo $block->escapeHtml( + __('Deselect All') + ); ?></span> </button> <button type="button" class="action-remove-all action-tertiary" data-bind="click: $parent.removeAttribute.bind($parent)" title="<?= $block->escapeHtml(__('Remove Attribute')) ?>"> - <span><?= /* @noEscape */ __('Remove Attribute') ?></span> + <span><?php echo $block->escapeHtml( + __('Remove Attribute') + ); ?></span> </button> </div> </div> @@ -74,14 +86,18 @@ title="<?= $block->escapeHtml(__('Save Option')) ?>" data-action="save" data-bind="click: $parents[1].saveOption.bind($parent)"> - <span><?= /* @noEscape */ __('Save Option') ?></span> + <span><?php echo $block->escapeHtml( + __('Save Option') + ); ?></span> </button> <button type="button" class="action-remove" title="<?= $block->escapeHtml(__('Remove Option')) ?>" data-action="remove" data-bind="click: $parents[1].removeOption.bind($parent)"> - <span><?= /* @noEscape */ __('Remove Option') ?></span> + <span><?php echo $block->escapeHtml( + _('Remove Option') + ); ?></span> </button> </div> </li> @@ -90,8 +106,10 @@ <button class="action-create-new action-tertiary" type="button" data-action="addOption" - data-bind="click: $parent.createOption"> - <span><?= /* @escapeNotVerified */ __('Create New Value') ?></span> + data-bind="click: $parent.createOption, visible: canCreateOption"> + <span><?php echo $block->escapeHtml( + __('Create New Value') + ); ?></span> </button> </div> </div> diff --git a/app/code/Magento/ConfigurableProduct/view/adminhtml/templates/catalog/product/edit/attribute/steps/bulk.phtml b/app/code/Magento/ConfigurableProduct/view/adminhtml/templates/catalog/product/edit/attribute/steps/bulk.phtml index c3e410ac833ddff6cd933100526a9c6caeeb367d..24bfcabcacea23446cc716f8f2c72e6344f84fd5 100644 --- a/app/code/Magento/ConfigurableProduct/view/adminhtml/templates/catalog/product/edit/attribute/steps/bulk.phtml +++ b/app/code/Magento/ConfigurableProduct/view/adminhtml/templates/catalog/product/edit/attribute/steps/bulk.phtml @@ -10,547 +10,592 @@ ?> <div data-bind="scope: '<?= /* @noEscape */ $block->getComponentName()?>'" data-role="bulk-step"> - <h2 class="steps-wizard-title"><?= /* @noEscape */ __('Step 3: Bulk Images, Price and Quantity') ?></h2> + <h2 class="steps-wizard-title"><?php echo $block->escapeHtml(__('Step 3: Bulk Images, Price and Quantity')); ?></h2> <div class="steps-wizard-info"> - <?= /* @noEscape */ __('Based on your selections <span class="new-products-count" data-bind="text:countVariations"></span> - new products will be created. Use this step to customize images and price for your new products.') ?> + <?php /* @escapeNotVerified */ echo __('Based on your selections %1 new products will be created. Use this step to customize images and price for your new products.', '<span class="new-products-count" data-bind="text:countVariations"></span>') ?> </div> <div data-bind="with: sections().images" class="steps-wizard-section"> <div data-role="section"> - <div class="steps-wizard-section-title"> - <span><?= /* @noEscape */ __('Images') ?></span> - </div> + <div class="steps-wizard-section-title"> + <span><?php echo $block->escapeHtml( + __('Images') + ); ?></span> + </div> - <ul class="steps-wizard-section-list"> - <li> - <div class="admin__field admin__field-option"> - <input type="radio" - id="apply-single-set-radio" - class="admin__control-radio" - value="single" - data-bind="checked:type"> - <label for="apply-single-set-radio" class="admin__field-label"> - <span><?= /* @noEscape */ __('Apply single set of images to all SKUs') ?></span> - </label> - </div> - </li> - <li> - <div class="admin__field admin__field-option"> - <input type="radio" - id="apply-unique-images-radio" - class="admin__control-radio" - value="each" - data-bind="checked:type"> - <label for="apply-unique-images-radio" class="admin__field-label"> - <span><?= /* @noEscape */ __('Apply unique images by attribute to each SKU') ?></span> - </label> - </div> - </li> - <li> - <div class="admin__field admin__field-option"> - <input type="radio" - id="skip-images-uploading-radio" - class="admin__control-radio" - value="none" - checked - data-bind="checked:type"> - <label for="skip-images-uploading-radio" class="admin__field-label"> - <span><?= /* @noEscape */ __('Skip image uploading at this time') ?></span> - </label> - </div> - </li> - </ul> - - <div data-role="step-gallery-single" - class="attribute-image-selector" - data-bind="visible: type() == 'single'"> - <div data-role="gallery" - class="gallery" - data-images="[]" - data-types="<?php echo $block->escapeHtml( - $this->helper('Magento\Framework\Json\Helper\Data')->jsonEncode($block->getImageTypes()) - ) ?>" - > - <div class="image image-placeholder"> - <div data-role="uploader" class="uploader"> - <div class="image-browse"> - <span><?= /* @noEscape */ __('Browse Files...') ?></span> - <input type="file" - id="" - name="image" - class="admin__control-file" - multiple="multiple" - data-url="<?= /* @noEscape */ $block->getUrl('catalog/product_gallery/upload') ?>" /> - </div> + <ul class="steps-wizard-section-list"> + <li> + <div class="admin__field admin__field-option"> + <input type="radio" + id="apply-single-set-radio" + class="admin__control-radio" + value="single" + data-bind="checked:type"> + <label for="apply-single-set-radio" class="admin__field-label"> + <span><?php echo $block->escapeHtml( + __('Apply single set of images to all SKUs') + ); ?></span> + </label> </div> - <div class="product-image-wrapper"> - <p class="image-placeholder-text"><?= /* @noEscape */ __('Browse to find or drag image here') ?></p> + </li> + <li> + <div class="admin__field admin__field-option"> + <input type="radio" + id="apply-unique-images-radio" + class="admin__control-radio" + value="each" + data-bind="checked:type"> + <label for="apply-unique-images-radio" class="admin__field-label"> + <span><?php echo $block->escapeHtml(__('Apply unique images by attribute to each SKU')) ?></span> + </label> </div> - </div> - - <?php foreach ($block->getImageTypes() as $typeData): - ?> - <input name="<?php echo $block->escapeHtml($typeData['name']) ?>" - class="image-<?php echo $block->escapeHtml($typeData['code']) ?>" - type="hidden" - value="<?php echo $block->escapeHtml($typeData['value']) ?>"/> - <?php - endforeach; - ?> + </li> + <li> + <div class="admin__field admin__field-option"> + <input type="radio" + id="skip-images-uploading-radio" + class="admin__control-radio" + value="none" + checked + data-bind="checked:type"> + <label for="skip-images-uploading-radio" class="admin__field-label"> + <span><?php echo $block->escapeHtml(__('Skip image uploading at this time')) ?></span> + </label> + </div> + </li> + </ul> - <script data-template="uploader" type="text/x-magento-template"> - <div id="<%- data.id %>" class="file-row"> - <span class="file-info"><%- data.name %> (<%- data.size %>)</span> - <div class="progressbar-container"> - <div class="progressbar upload-progress" style="width: 0%;"></div> + <div data-role="step-gallery-single" + class="attribute-image-selector" + data-bind="visible: type() == 'single'"> + <div data-role="gallery" + class="gallery" + data-images="[]" + data-types="<?php echo $block->escapeHtml( + $this->helper('Magento\Framework\Json\Helper\Data')->jsonEncode($block->getImageTypes()) + ) ?>" + > + <div class="image image-placeholder"> + <div data-role="uploader" class="uploader"> + <div class="image-browse"> + <span><?php echo $block->escapeHtml(__('Browse Files...')) ?></span> + <input type="file" + id="" + name="image" + class="admin__control-file" + multiple="multiple" + data-url="<?= /* @noEscape */ $block->getUrl('catalog/product_gallery/upload') ?>" /> + </div> </div> - <div class="spinner"> - <span></span><span></span><span></span><span></span> - <span></span><span></span><span></span><span></span> + <div class="product-image-wrapper"> + <p class="image-placeholder-text"><?php echo $block->escapeHtml(__('Browse to find or drag image here')) ?></p> </div> </div> - </script> - - <script data-template="gallery-content" type="text/x-magento-template"> - <div class="image item <% if (data.disabled == 1) { %>hidden-for-front<% } %>" - data-role="image"> - <input type="hidden" - name="product[media_gallery][images][<%- data.file_id %>][position]" - value="<%- data.position %>"/> - <input type="hidden" - name="product[media_gallery][images][<%- data.file_id %>][file]" - value="<%- data.file %>"/> - <input type="hidden" - name="product[media_gallery][images][<%- data.file_id %>][value_id]" - value="<%- data.value_id %>"/> - <input type="hidden" - name="product[media_gallery][images][<%- data.file_id %>][label]" - value="<%- data.label %>"/> - <input type="hidden" - name="product[media_gallery][images][<%- data.file_id %>][disabled]" - value="<%- data.disabled %>"/> - <input type="hidden" - name="product[media_gallery][images][<%- data.file_id %>][removed]"/> - <div class="product-image-wrapper"> - <img class="product-image" data-role="image-element" src="<%- data.url %>" alt="<%- data.label %>"/> - <div class="actions"> - <button type="button" - class="action-remove" - data-role="delete-button" - title="<?= $block->escapeHtml(__('Remove image')) ?>"> - <span><?= /* @noEscape */ __('Remove image') ?></span> - </button> - <div class="draggable-handle"></div> + + <?php foreach ($block->getImageTypes() as $typeData): + ?> + <input name="<?php echo $block->escapeHtml($typeData['name']) ?>" + class="image-<?php echo $block->escapeHtml($typeData['code']) ?>" + type="hidden" + value="<?php echo $block->escapeHtml($typeData['value']) ?>"/> + <?php + endforeach; + ?> + + <script data-template="uploader" type="text/x-magento-template"> + <div id="<%- data.id %>" class="file-row"> + <span class="file-info"><%- data.name %> (<%- data.size %>)</span> + <div class="progressbar-container"> + <div class="progressbar upload-progress" style="width: 0%;"></div> </div> - <div class="image-fade"><span><?= /* @noEscape */ __('Hidden') ?></span></div> - </div> - <div class="item-description"> - <div class="item-title" data-role="img-title"><%- data.label %></div> - <div class="item-size"> - <span data-role="image-dimens"></span>, <span data-role="image-size"><%- data.sizeLabel %></span> + <div class="spinner"> + <span></span><span></span><span></span><span></span> + <span></span><span></span><span></span><span></span> </div> </div> - <ul class="item-roles" data-role="roles-labels"> - <?php - foreach ($block->getMediaAttributes() as $attribute): - ?> - <li data-role-code="<?php echo $block->escapeHtml( - $attribute->getAttributeCode() - ) ?>" class="item-role item-role-<?php echo $block->escapeHtml( - $attribute->getAttributeCode() - ) ?>"> - <?php /* @noEscape */ echo $attribute->getFrontendLabel() ?> - </li> + </script> + + <script data-template="gallery-content" type="text/x-magento-template"> + <div class="image item <% if (data.disabled == 1) { %>hidden-for-front<% } %>" + data-role="image"> + <input type="hidden" + name="product[media_gallery][images][<%- data.file_id %>][position]" + value="<%- data.position %>"/> + <input type="hidden" + name="product[media_gallery][images][<%- data.file_id %>][file]" + value="<%- data.file %>"/> + <input type="hidden" + name="product[media_gallery][images][<%- data.file_id %>][value_id]" + value="<%- data.value_id %>"/> + <input type="hidden" + name="product[media_gallery][images][<%- data.file_id %>][label]" + value="<%- data.label %>"/> + <input type="hidden" + name="product[media_gallery][images][<%- data.file_id %>][disabled]" + value="<%- data.disabled %>"/> + <input type="hidden" + name="product[media_gallery][images][<%- data.file_id %>][removed]"/> + <div class="product-image-wrapper"> + <img class="product-image" data-role="image-element" src="<%- data.url %>" alt="<%- data.label %>"/> + <div class="actions"> + <button type="button" + class="action-remove" + data-role="delete-button" + title="<?= $block->escapeHtml(__('Remove image')) ?>"> + <span><?php echo $block->escapeHtml(__('Remove image')) ?></span> + </button> + <div class="draggable-handle"></div> + </div> + <div class="image-fade"><span><?php echo $block->escapeHtml(__('Hidden')) ?></span></div> + </div> + <div class="item-description"> + <div class="item-title" data-role="img-title"><%- data.label %></div> + <div class="item-size"> + <span data-role="image-dimens"></span>, <span data-role="image-size"><%- data.sizeLabel %></span> + </div> + </div> + <ul class="item-roles" data-role="roles-labels"> <?php - endforeach; - ?> - </ul> - </div> - </script> + foreach ($block->getMediaAttributes() as $attribute): + ?> + <li data-role-code="<?php echo $block->escapeHtml( + $attribute->getAttributeCode() + ) ?>" class="item-role item-role-<?php echo $block->escapeHtml( + $attribute->getAttributeCode() + ) ?>"> + <?php /* @noEscape */ echo $attribute->getFrontendLabel() ?> + </li> + <?php + endforeach; + ?> + </ul> + </div> + </script> - <script data-template="image" type="text/x-magento-template"> - <div class="image"> - <div class="product-image-wrapper"> - <img class="product-image" - data-role="image-element" - src="<%- data.url %>" - data-position="<%- data.position %>" - alt="<%- data.label %>" /> - - <div class="actions"> - <button type="button" - class="action-remove" - data-role="delete-button" - title="<?= $block->escapeHtml(__('Remove image')) ?>"> - <span><?= /* @noEscape */ __('Remove image') ?></span> - </button> - - <div class="draggable-handle"></div> - </div> + <script data-template="image" type="text/x-magento-template"> + <div class="image"> + <div class="product-image-wrapper"> + <img class="product-image" + data-role="image-element" + src="<%- data.url %>" + data-position="<%- data.position %>" + alt="<%- data.label %>" /> + + <div class="actions"> + <button type="button" + class="action-remove" + data-role="delete-button" + title="<?= $block->escapeHtml(__('Remove image')) ?>"> + <span><?php echo $block->escapeHtml(__('Remove image')) ?></span> + </button> + + <div class="draggable-handle"></div> + </div> - <div class="image-fade"><span><?= /* @noEscape */ __('Hidden') ?></span></div> + <div class="image-fade"><span><?php echo $block->escapeHtml(__('Hidden')) ?></span></div> + </div> + <!--<ul class="item-roles"> + <li class="item-role item-role-base">Base</li> + </ul>--> </div> - <!--<ul class="item-roles"> - <li class="item-role item-role-base">Base</li> - </ul>--> - </div> - </script> + </script> - <script data-role="img-dialog-container-tmpl" type="text/x-magento-template"> - <div class="image-panel ui-tabs-panel ui-widget-content ui-corner-bottom" data-role="dialog"> - </div> - </script> + <script data-role="img-dialog-container-tmpl" type="text/x-magento-template"> + <div class="image-panel ui-tabs-panel ui-widget-content ui-corner-bottom" data-role="dialog"> + </div> + </script> - <script class="dialog-template" type="text/x-magento-template" data-title="Image Options"> - <div class="image-panel-preview"> - <img src="<%- data.url %>" alt="<%- data.label %>" /> - </div> - <div class="image-panel-controls"> - <strong class="image-name"><%- data.label %></strong> + <script class="dialog-template" type="text/x-magento-template" data-title="Image Options"> + <div class="image-panel-preview"> + <img src="<%- data.url %>" alt="<%- data.label %>" /> + </div> + <div class="image-panel-controls"> + <strong class="image-name"><%- data.label %></strong> - <fieldset class="admin__fieldset fieldset-image-panel"> - <div class="admin__field field-image-description"> - <label class="admin__field-label" for="image-description"> - <span><?php /* @escapeNotVerified */ echo __('Alt Text')?></span> - </label> + <fieldset class="admin__fieldset fieldset-image-panel"> + <div class="admin__field field-image-description"> + <label class="admin__field-label" for="image-description"> + <span><?php echo $block->escapeHtml(__('Alt Text')) ?></span> + </label> - <div class="admin__field-control"> + <div class="admin__field-control"> <textarea data-role="image-description" rows="3" class="admin__control-textarea" name="product[media_gallery][images][<%- data.file_id %>][label]" - ><%- data.label %></textarea> + ><%- data.label %></textarea> + </div> </div> - </div> - <div class="admin__field field-image-role"> - <label class="admin__field-label"> - <span><?php /* @noEscape */ echo __('Role')?></span> - </label> - <div class="admin__field-control"> - <ul class="multiselect-alt"> - <?php - foreach ($block->getMediaAttributes() as $attribute) : - ?> - <li class="item"> - <label> - <input class="image-type" - data-role="type-selector" - type="checkbox" - value="<?php echo $block->escapeHtml( - $attribute->getAttributeCode() - ) ?>" - /> - <?php /* @noEscape */ echo $attribute->getFrontendLabel()?> - </label> - </li> + <div class="admin__field field-image-role"> + <label class="admin__field-label"> + <span><?php echo $block->escapeHtml( + __('Role') + ); ?></span> + </label> + <div class="admin__field-control"> + <ul class="multiselect-alt"> <?php - endforeach; - ?> - </ul> + foreach ($block->getMediaAttributes() as $attribute) : + ?> + <li class="item"> + <label> + <input class="image-type" + data-role="type-selector" + type="checkbox" + value="<?php echo $block->escapeHtml( + $attribute->getAttributeCode() + ) ?>" + /> + <?php echo $block->escapeHtml( + $attribute->getFrontendLabel() + ); ?> + </label> + </li> + <?php + endforeach; + ?> + </ul> + </div> </div> - </div> - <div class="admin__field admin__field-inline field-image-size" data-role="size"> - <label class="admin__field-label"> - <span><?php /* @noEscape */ echo __('Image Size') ?></span> - </label> - <div class="admin__field-value" data-message="<?php /* @noEscape */ echo __('{size}') ?>"></div> - </div> + <div class="admin__field admin__field-inline field-image-size" data-role="size"> + <label class="admin__field-label"> + <span><?php echo $block->escapeHtml( + __('Image Size') + ); ?></span> + </label> + <div class="admin__field-value" data-message="<?php echo $block->escapeHtml( + __('{size}') + );?>"></div> + </div> - <div class="admin__field admin__field-inline field-image-resolution" data-role="resolution"> - <label class="admin__field-label"> - <span><?php /* @noEscape */ echo __('Image Resolution') ?></span> - </label> - <div class="admin__field-value" data-message="<?php /* @noEscape */ echo __('{width}^{height} px') ?>"></div> - </div> + <div class="admin__field admin__field-inline field-image-resolution" data-role="resolution"> + <label class="admin__field-label"> + <span><?php echo $block->escapeHtml( + __('Image Resolution') + ); ?></span> + </label> + <div class="admin__field-value" data-message="<?php echo $block->escapeHtml( + __('{width}^{height} px') + );?>"></div> + </div> - <div class="admin__field field-image-hide"> - <div class="admin__field-control"> - <div class="admin__field admin__field-option"> - <input type="checkbox" - id="hide-from-product-page" - data-role="visibility-trigger" - value="1" - class="admin__control-checkbox" - name="product[media_gallery][images][<%- data.file_id %>][disabled]" - <% if (data.disabled == 1) { %>checked="checked"<% } %> /> - - <label for="hide-from-product-page" class="admin__field-label"> - <?php /* @noEscape */ echo __('Hide from Product Page')?> - </label> + <div class="admin__field field-image-hide"> + <div class="admin__field-control"> + <div class="admin__field admin__field-option"> + <input type="checkbox" + id="hide-from-product-page" + data-role="visibility-trigger" + value="1" + class="admin__control-checkbox" + name="product[media_gallery][images][<%- data.file_id %>][disabled]" + <% if (data.disabled == 1) { %>checked="checked"<% } %> /> + + <label for="hide-from-product-page" class="admin__field-label"> + <?php echo $block->escapeHtml( + __('Hide from Product Page') + ); ?> + </label> + </div> </div> </div> - </div> - </fieldset> - </div> - </script> + </fieldset> + </div> + </script> + </div> </div> - </div> - <div data-role="step-gallery-each" class="attribute-image-selector" data-bind="visible: type() == 'each'"> - <fieldset class="admin__fieldset bulk-attribute-values"> - <div class="admin__field _required"> - <label class="admin__field-label" for="apply-images-attributes"> - <span><?= /* @noEscape */ __('Select attribute')?></span> - </label> - <div class="admin__field-control"> - <select - id="apply-images-attributes" - class="admin__control-select" - data-bind=" + <div data-role="step-gallery-each" class="attribute-image-selector" data-bind="visible: type() == 'each'"> + <fieldset class="admin__fieldset bulk-attribute-values"> + <div class="admin__field _required"> + <label class="admin__field-label" for="apply-images-attributes"> + <span><?php echo $block->escapeHtml( + __('Select attribute') + ); ?></span> + </label> + <div class="admin__field-control"> + <select + id="apply-images-attributes" + class="admin__control-select" + data-bind=" options: $parent.attributes, optionsText: 'label', value: attribute, - optionsCaption: '<?= /* @noEscape */ __("Select")?>' + optionsCaption: '<?php echo $block->escapeHtml( + __("Select") + ); ?>' "> - </select> - </div> - </div> - </fieldset> - - <ul class="items attributes-selector-list" data-bind="if:attribute, visible: attribute"> - <!-- ko foreach: {data: attribute().chosen, afterRender: $parent.bindGalleries} --> - <li class="item" data-bind="attr:{'data-role':'step-gallery-option-' + id}"> - <label class="attribute-label"> - <span data-bind="text:label"></span> - </label> - - <div data-role="gallery" - class="gallery" - data-images="[]" - data-types="<?php /* @noEscape */ echo $block->escapeHtml( - $this->helper('Magento\Framework\Json\Helper\Data')->jsonEncode($block->getImageTypes()) - ) ?>" - > - <div class="image image-placeholder"> - <div data-role="uploader" class="uploader"> - <div class="image-browse"> - <span><?= /* @noEscape */ __('Browse Files...') ?></span> - <input type="file" name="image" multiple="multiple" - data-url="<?= /* @noEscape */ $block->getUrl('catalog/product_gallery/upload') ?>" /> - </div> - </div> - <div class="product-image-wrapper"> - <p class="image-placeholder-text"><?= /* @noEscape */ __('Browse to find or drag image here') ?></p> - </div> - <div class="spinner"> - <span></span><span></span><span></span><span></span> - <span></span><span></span><span></span><span></span> - </div> + </select> </div> + </div> + </fieldset> - <?php foreach ($block->getImageTypes() as $typeData): - ?> - <input name="<?php echo $block->escapeHtml($typeData['name']) ?>" - class="image-<?php echo $block->escapeHtml($typeData['code']) ?>" - type="hidden" - value="<?php echo $block->escapeHtml($typeData['value']) ?>"/> - <?php - endforeach; - ?> + <ul class="items attributes-selector-list" data-bind="if:attribute, visible: attribute"> + <!-- ko foreach: {data: attribute().chosen, afterRender: $parent.bindGalleries} --> + <li class="item" data-bind="attr:{'data-role':'step-gallery-option-' + id}"> + <label class="attribute-label"> + <span data-bind="text:label"></span> + </label> - <script data-template="uploader" type="text/x-magento-template"> - <div id="<%- data.id %>" class="file-row"> - <span class="file-info"><%- data.name %> (<%- data.size %>)</span> - <div class="progressbar-container"> - <div class="progressbar upload-progress" style="width: 0%;"></div> + <div data-role="gallery" + class="gallery" + data-images="[]" + data-types="<?php echo $block->escapeHtml( + $this->helper('Magento\Framework\Json\Helper\Data')->jsonEncode($block->getImageTypes()) + ) ?>" + > + <div class="image image-placeholder"> + <div data-role="uploader" class="uploader"> + <div class="image-browse"> + <span><?php echo $block->escapeHtml( + __('Browse Files...') + ); ?></span> + <input type="file" name="image" multiple="multiple" + data-url="<?= /* @noEscape */ $block->getUrl('catalog/product_gallery/upload') ?>" /> + </div> + </div> + <div class="product-image-wrapper"> + <p class="image-placeholder-text"><?php echo $block->escapeHtml( + __('Browse to find or drag image here') + ); ?></p> </div> <div class="spinner"> <span></span><span></span><span></span><span></span> <span></span><span></span><span></span><span></span> </div> </div> - </script> - - <script data-template="gallery-content" type="text/x-magento-template"> - <div class="image item <% if (data.disabled == 1) { %>hidden-for-front<% } %>" - data-role="image"> - <input type="hidden" - name="product[media_gallery][images][<%- data.file_id %>][position]" - value="<%- data.position %>" class="position"/> - <input type="hidden" - name="product[media_gallery][images][<%- data.file_id %>][file]" - value="<%- data.file %>"/> - <input type="hidden" - name="product[media_gallery][images][<%- data.file_id %>][value_id]" - value="<%- data.value_id %>"/> - <input type="hidden" - name="product[media_gallery][images][<%- data.file_id %>][label]" - value="<%- data.label %>"/> - <input type="hidden" - name="product[media_gallery][images][<%- data.file_id %>][disabled]" - value="<%- data.disabled %>"/> - <input type="hidden" - name="product[media_gallery][images][<%- data.file_id %>][removed]" - value="" - class="is-removed"/> - <div class="product-image-wrapper"> - <img class="product-image" data-role="image-element" src="<%- data.url %>" alt="<%- data.label %>"/> - <div class="actions"> - <button type="button" - class="action-remove" - data-role="delete-button" - title="<?= $block->escapeHtml(__('Remove image')) ?>"> - <span><?php /* @noEscape */ echo __('Remove image') ?></span> - </button> - <div class="draggable-handle"></div> + + <?php foreach ($block->getImageTypes() as $typeData): + ?> + <input name="<?php echo $block->escapeHtml($typeData['name']) ?>" + class="image-<?php echo $block->escapeHtml($typeData['code']) ?>" + type="hidden" + value="<?php echo $block->escapeHtml($typeData['value']) ?>"/> + <?php + endforeach; + ?> + + <script data-template="uploader" type="text/x-magento-template"> + <div id="<%- data.id %>" class="file-row"> + <span class="file-info"><%- data.name %> (<%- data.size %>)</span> + <div class="progressbar-container"> + <div class="progressbar upload-progress" style="width: 0%;"></div> </div> - <div class="image-fade"><span><?= /* @noEscape */ __('Hidden') ?></span></div> - </div> - <div class="item-description"> - <div class="item-title" data-role="img-title"><%- data.label %></div> - <div class="item-size"> - <span data-role="image-dimens"></span>, <span data-role="image-size"><%- data.sizeLabel %></span> + <div class="spinner"> + <span></span><span></span><span></span><span></span> + <span></span><span></span><span></span><span></span> </div> </div> - <ul class="item-roles" data-role="roles-labels"> - <?php - foreach ($block->getMediaAttributes() as $attribute): - ?> - <li data-role-code="<?php echo $block->escapeHtml( - $attribute->getAttributeCode() - ) ?>" class="item-role item-role-<?php echo $block->escapeHtml( - $attribute->getAttributeCode() - ) ?>"> - <?php echo $block->escapeHtml($attribute->getFrontendLabel()) ?> - </li> + </script> + + <script data-template="gallery-content" type="text/x-magento-template"> + <div class="image item <% if (data.disabled == 1) { %>hidden-for-front<% } %>" + data-role="image"> + <input type="hidden" + name="product[media_gallery][images][<%- data.file_id %>][position]" + value="<%- data.position %>" class="position"/> + <input type="hidden" + name="product[media_gallery][images][<%- data.file_id %>][file]" + value="<%- data.file %>"/> + <input type="hidden" + name="product[media_gallery][images][<%- data.file_id %>][value_id]" + value="<%- data.value_id %>"/> + <input type="hidden" + name="product[media_gallery][images][<%- data.file_id %>][label]" + value="<%- data.label %>"/> + <input type="hidden" + name="product[media_gallery][images][<%- data.file_id %>][disabled]" + value="<%- data.disabled %>"/> + <input type="hidden" + name="product[media_gallery][images][<%- data.file_id %>][removed]" + value="" + class="is-removed"/> + <div class="product-image-wrapper"> + <img class="product-image" data-role="image-element" src="<%- data.url %>" alt="<%- data.label %>"/> + <div class="actions"> + <button type="button" + class="action-remove" + data-role="delete-button" + title="<?= $block->escapeHtml(__('Remove image')) ?>"> + <span><?php echo $block->escapeHtml( + __('Remove image') + ); ?></span> + </button> + <div class="draggable-handle"></div> + </div> + <div class="image-fade"><span><?php echo $block->escapeHtml( + __('Hidden') + ); ?></span></div> + </div> + <div class="item-description"> + <div class="item-title" data-role="img-title"><%- data.label %></div> + <div class="item-size"> + <span data-role="image-dimens"></span>, <span data-role="image-size"><%- data.sizeLabel %></span> + </div> + </div> + <ul class="item-roles" data-role="roles-labels"> <?php - endforeach; - ?> - </ul> - </div> - </script> - - <script data-template="image" type="text/x-magento-template"> - <div class="image"> - <div class="product-image-wrapper"> - <img class="product-image" - src="<%- data.url %>" - data-role="image-element" - data-position="<%- data.position %>" - alt="<%- data.label %>" /> - <div class="actions"> - <button type="button" - class="action-remove" - data-role="delete-button" - title="<?= $block->escapeHtml(__('Remove image')) ?>"> - <span><?= /* @noEscape */ __('Remove image') ?></span> - </button> - <div class="draggable-handle"></div> + foreach ($block->getMediaAttributes() as $attribute): + ?> + <li data-role-code="<?php echo $block->escapeHtml( + $attribute->getAttributeCode() + ) ?>" class="item-role item-role-<?php echo $block->escapeHtml( + $attribute->getAttributeCode() + ) ?>"> + <?php echo $block->escapeHtml($attribute->getFrontendLabel()) ?> + </li> + <?php + endforeach; + ?> + </ul> + </div> + </script> + + <script data-template="image" type="text/x-magento-template"> + <div class="image"> + <div class="product-image-wrapper"> + <img class="product-image" + src="<%- data.url %>" + data-role="image-element" + data-position="<%- data.position %>" + alt="<%- data.label %>" /> + <div class="actions"> + <button type="button" + class="action-remove" + data-role="delete-button" + title="<?= $block->escapeHtml(__('Remove image')) ?>"> + <span><?php echo $block->escapeHtml(__('Remove image')) ?></span> + </button> + <div class="draggable-handle"></div> + </div> + <div class="image-fade"><span><?php echo $block->escapeHtml(__('Hidden')) ?></span></div> </div> - <div class="image-fade"><span><?= /* @noEscape */ __('Hidden') ?></span></div> + <!--<ul class="item-roles"> + <li class="item-role item-role-base">Base</li> + </ul>--> </div> - <!--<ul class="item-roles"> - <li class="item-role item-role-base">Base</li> - </ul>--> - </div> - </script> - - <script data-role="img-dialog-container-tmpl" type="text/x-magento-template"> - <div class="image-panel ui-tabs-panel ui-widget-content ui-corner-bottom" data-role="dialog"> - </div> - </script> + </script> - <script class="dialog-template" type="text/x-magento-template" data-title="Image Options"> - <div class="image-panel-preview"> - <img src="<%- data.url %>" alt="<%- data.label %>" /> - </div> - <div class="image-panel-controls"> - <strong class="image-name"><%- data.label %></strong> - - <fieldset class="admin__fieldset fieldset-image-panel"> - <div class="admin__field field-image-description"> - <label class="admin__field-label" for="image-description"> - <span><?php /* @noEscape */ echo __('Alt Text')?></span> - </label> + <script data-role="img-dialog-container-tmpl" type="text/x-magento-template"> + <div class="image-panel ui-tabs-panel ui-widget-content ui-corner-bottom" data-role="dialog"> + </div> + </script> - <div class="admin__field-control"> + <script class="dialog-template" type="text/x-magento-template" data-title="Image Options"> + <div class="image-panel-preview"> + <img src="<%- data.url %>" alt="<%- data.label %>" /> + </div> + <div class="image-panel-controls"> + <strong class="image-name"><%- data.label %></strong> + + <fieldset class="admin__fieldset fieldset-image-panel"> + <div class="admin__field field-image-description"> + <label class="admin__field-label" for="image-description"> + <span><?php echo $block->escapeHtml( + __('Alt Text') + );?></span> + </label> + + <div class="admin__field-control"> <textarea data-role="image-description" rows="3" class="admin__control-textarea" name="product[media_gallery][images][<%- data.file_id %>][label]" - ><%- data.label %></textarea> + ><%- data.label %></textarea> + </div> </div> - </div> - <div class="admin__field field-image-role"> - <label class="admin__field-label"> - <span><?php /* @noEscape */ echo __('Role')?></span> - </label> - <div class="admin__field-control"> - <ul class="multiselect-alt"> - <?php - foreach ($block->getMediaAttributes() as $attribute) : - ?> - <li class="item"> - <label> - <input class="image-type" - data-role="type-selector" - type="checkbox" - value="<?php echo $block->escapeHtml( - $attribute->getAttributeCode() - ) ?>" - /> - <?php echo $block->escapeHtml( - $attribute->getFrontendLabel() - ) ?> - </label> - </li> + <div class="admin__field field-image-role"> + <label class="admin__field-label"> + <span><?php echo $block->escapeHtml( + __('Role') + );?></span> + </label> + <div class="admin__field-control"> + <ul class="multiselect-alt"> <?php - endforeach; - ?> - </ul> + foreach ($block->getMediaAttributes() as $attribute) : + ?> + <li class="item"> + <label> + <input class="image-type" + data-role="type-selector" + type="checkbox" + value="<?php echo $block->escapeHtml( + $attribute->getAttributeCode() + ) ?>" + /> + <?php echo $block->escapeHtml( + $attribute->getFrontendLabel() + ) ?> + </label> + </li> + <?php + endforeach; + ?> + </ul> + </div> </div> - </div> - <div class="admin__field admin__field-inline field-image-size" data-role="size"> - <label class="admin__field-label"> - <span><?php /* @noEscape */ echo __('Image Size') ?></span> - </label> - <div class="admin__field-value" data-message="<?php /* @noEscape */ echo __('{size}') ?>"></div> - </div> + <div class="admin__field admin__field-inline field-image-size" data-role="size"> + <label class="admin__field-label"> + <span><?php echo $block->escapeHtml( + __('Image Size') + ); ?></span> + </label> + <div class="admin__field-value" data-message="<?php echo $block->escapeHtml( + __('{size}') + ); ?>"></div> + </div> - <div class="admin__field admin__field-inline field-image-resolution" data-role="resolution"> - <label class="admin__field-label"> - <span><?php /* @noEscape */ echo __('Image Resolution') ?></span> - </label> - <div class="admin__field-value" data-message="<?php /* @noEscape */ echo __('{width}^{height} px') ?>"></div> - </div> + <div class="admin__field admin__field-inline field-image-resolution" data-role="resolution"> + <label class="admin__field-label"> + <span><?php echo $block->escapeHtml( + __('Image Resolution') + ); ?></span> + </label> + <div class="admin__field-value" data-message="<?php echo $block->escapeHtml( + __('{width}^{height} px') + ); ?>"></div> + </div> - <div class="admin__field field-image-hide"> - <div class="admin__field-control"> - <div class="admin__field admin__field-option"> - <input type="checkbox" - id="hide-from-product-page" - data-role="visibility-trigger" - value="1" - class="admin__control-checkbox" - name="product[media_gallery][images][<%- data.file_id %>][disabled]" - <% if (data.disabled == 1) { %>checked="checked"<% } %> /> - - <label for="hide-from-product-page" class="admin__field-label"> - <?php /* @noEscape */ echo __('Hide from Product Page')?> - </label> + <div class="admin__field field-image-hide"> + <div class="admin__field-control"> + <div class="admin__field admin__field-option"> + <input type="checkbox" + id="hide-from-product-page" + data-role="visibility-trigger" + value="1" + class="admin__control-checkbox" + name="product[media_gallery][images][<%- data.file_id %>][disabled]" + <% if (data.disabled == 1) { %>checked="checked"<% } %> /> + + <label for="hide-from-product-page" class="admin__field-label"> + <?php echo $block->escapeHtml( + __('Hide from Product Page') + ); ?> + </label> + </div> </div> </div> - </div> - </fieldset> - </div> - </script> - </div> - </li> - <!-- /ko --> - </ul> + </fieldset> + </div> + </script> + </div> + </li> + <!-- /ko --> + </ul> + </div> </div> </div> -</div> <div data-bind="with: sections().price" class="steps-wizard-section"> <div data-role="section"> <div class="steps-wizard-section-title"> - <span><?php /* @noEscape */ echo __('Price') ?></span> + <span><?php echo $block->escapeHtml( + __('Price') + ); ?></span> </div> <ul class="steps-wizard-section-list"> <li> @@ -562,7 +607,9 @@ data-bind="checked:type" /> <label for="apply-single-price-radio" class="admin__field-label"> - <span><?php /* @noEscape */ echo __('Apply single price to all SKUs') ?></span> + <span><?php echo $block->escapeHtml( + __('Apply single price to all SKUs') + ); ?></span> </label> </div> </li> @@ -575,7 +622,9 @@ data-bind="checked:type" /> <label for="apply-unique-prices-radio" class="admin__field-label"> - <span><?php /* @noEscape */ echo __('Apply unique prices by attribute to each SKU') ?></span> + <span><?php echo $block->escapeHtml( + __('Apply unique prices by attribute to each SKU') + ); ?></span> </label> </div> </li> @@ -588,33 +637,39 @@ checked data-bind="checked:type" /> <label for="skip-pricing-radio" class="admin__field-label"> - <span><?php /* @noEscape */ echo __('Skip price at this time') ?></span> + <span><?php echo $block->escapeHtml( + __('Skip price at this time') + ); ?></span> </label> </div> </li> </ul> <form data-role="attributes-values-form"> - <fieldset class="admin__fieldset bulk-attribute-values" data-bind="visible: type() == 'single'"> - <div class="admin__field _required"> - <label for="apply-single-price-input" class="admin__field-label"> - <span><?php /* @noEscape */ echo __('Price') ?></span> - </label> - <div class="admin__field-control"> - <div class="currency-addon"> - <input class="admin__control-text required-entry validate-zero-or-greater" type="text" - data-bind="value:value, uniqueName: true" id="apply-single-price-input"/> - <span class="currency-symbol" data-bind="text:currencySymbol"></span> + <fieldset class="admin__fieldset bulk-attribute-values" data-bind="visible: type() == 'single'"> + <div class="admin__field _required"> + <label for="apply-single-price-input" class="admin__field-label"> + <span><?php echo $block->escapeHtml( + __('Price') + ); ?></span> + </label> + <div class="admin__field-control"> + <div class="currency-addon"> + <input class="admin__control-text required-entry validate-zero-or-greater" type="text" + data-bind="value:value, uniqueName: true" id="apply-single-price-input"/> + <span class="currency-symbol" data-bind="text:currencySymbol"></span> + </div> </div> </div> - </div> - </fieldset> + </fieldset> </form> <div data-bind="visible: type() == 'each'"> <fieldset class="admin__fieldset bulk-attribute-values"> <div class="admin__field _required"> <label for="select-each-price" class="admin__field-label"> - <span><?php /* @noEscape */ echo __('Select attribute') ?></span> + <span><?php echo $block->escapeHtml( + __('Select attribute') + ); ?></span> </label> <div class="admin__field-control"> <select id="select-each-price" class="admin__control-select" data-bind=" @@ -653,7 +708,7 @@ <div data-bind="with: sections().quantity" class="steps-wizard-section"> <div data-role="section"> <div class="steps-wizard-section-title"> - <span><?php /* @noEscape */ echo __('Quantity') ?></span> + <span><?php echo $block->escapeHtml(__('Quantity')) ?></span> </div> <ul class="steps-wizard-section-list"> <li> @@ -664,7 +719,7 @@ value="single" data-bind="checked: type" /> <label for="apply-single-inventory-radio" class="admin__field-label"> - <span><?php /* @noEscape */ echo __('Apply single quantity to each SKUs') ?></span> + <span><?php echo $block->escapeHtml(__('Apply single quantity to each SKUs')) ?></span> </label> </div> </li> @@ -676,7 +731,7 @@ value="each" data-bind="checked: type" /> <label for="apply-unique-inventory-radio" class="admin__field-label"> - <span><?php /* @noEscape */ echo __('Apply unique quantity by attribute to each SKU') ?></span> + <span><?php echo $block->escapeHtml(__('Apply unique quantity by attribute to each SKU')) ?></span> </label> </div> </li> @@ -689,33 +744,33 @@ checked data-bind="checked: type" /> <label for="skip-inventory-radio" class="admin__field-label"> - <span><?php /* @noEscape */ echo __('Skip quantity at this time') ?></span> + <span><?php echo $block->escapeHtml(__('Skip quantity at this time')) ?></span> </label> </div> </li> </ul> <form data-role="attributes-values-form"> - <fieldset class="admin__fieldset bulk-attribute-values" data-bind="visible: type() == 'single'"> - <div class="admin__field _required"> - <label for="apply-single-inventory-input" class="admin__field-label"> - <span><?php /* @noEscape */ echo __('Quantity') ?></span> - </label> - <div class="admin__field-control"> - <input type="text" - id="apply-single-inventory-input" - class="admin__control-text required-entry validate-zero-or-greater" - data-bind="value: value, uniqueName: true" /> + <fieldset class="admin__fieldset bulk-attribute-values" data-bind="visible: type() == 'single'"> + <div class="admin__field _required"> + <label for="apply-single-inventory-input" class="admin__field-label"> + <span><?php echo $block->escapeHtml(__('Quantity')) ?></span> + </label> + <div class="admin__field-control"> + <input type="text" + id="apply-single-inventory-input" + class="admin__control-text required-entry validate-zero-or-greater" + data-bind="value: value, uniqueName: true" /> + </div> </div> - </div> - </fieldset> + </fieldset> </form> <div data-bind="visible: type() == 'each'"> <fieldset class="admin__fieldset bulk-attribute-values"> <div class="admin__field _required"> <label for="apply-single-price-input-qty" class="admin__field-label"> - <span><?php /* @noEscape */ echo __('Select attribute') ?></span> + <span><?php echo $block->escapeHtml(__('Select attribute')) ?></span> </label> <div class="admin__field-control"> <select id="apply-single-price-input-qty" class="admin__control-select" data-bind=" @@ -727,26 +782,26 @@ </div> </fieldset> <form data-role="attributes-values-form"> - <fieldset class="admin__fieldset bulk-attribute-values" data-bind="if:attribute"> - <!-- ko foreach: attribute().chosen --> - <div class="admin__field _required"> - <label data-bind="attr: {for: 'apply-qty-input-' + $index()}" class="admin__field-label"> - <span data-bind="text:label"></span> - </label> - <div class="admin__field-control"> - <input id="apply-single-price-input-value" - class="admin__control-text required-entry validate-zero-or-greater" type="text" - data-bind="value:sections()[$parent.label], uniqueName: true, + <fieldset class="admin__fieldset bulk-attribute-values" data-bind="if:attribute"> + <!-- ko foreach: attribute().chosen --> + <div class="admin__field _required"> + <label data-bind="attr: {for: 'apply-qty-input-' + $index()}" class="admin__field-label"> + <span data-bind="text:label"></span> + </label> + <div class="admin__field-control"> + <input id="apply-single-price-input-value" + class="admin__control-text required-entry validate-zero-or-greater" type="text" + data-bind="value:sections()[$parent.label], uniqueName: true, attr: {id: 'apply-qty-input-' + $index()}"/> + </div> </div> - </div> - <!-- /ko --> - </fieldset> + <!-- /ko --> + </fieldset> </form> </div> </div> </div> -</form> + </form> </div> <script type="text/x-magento-init"> diff --git a/app/code/Magento/ConfigurableProduct/view/adminhtml/templates/catalog/product/edit/attribute/steps/select_attributes.phtml b/app/code/Magento/ConfigurableProduct/view/adminhtml/templates/catalog/product/edit/attribute/steps/select_attributes.phtml index 7028eadb72c848ae6c21ac6c797afe6705d52e9a..ffb27ccd3c85561dfd377f7dd4cb6301339e70ab 100644 --- a/app/code/Magento/ConfigurableProduct/view/adminhtml/templates/catalog/product/edit/attribute/steps/select_attributes.phtml +++ b/app/code/Magento/ConfigurableProduct/view/adminhtml/templates/catalog/product/edit/attribute/steps/select_attributes.phtml @@ -12,9 +12,13 @@ <div class="select-attributes-actions" data-type="skipKO"> <?= /* @noEscape */ $block->getAddNewAttributeButton(); ?> </div> - <h2 class="steps-wizard-title"><?= /* @noEscape */ __('Step 1: Select Attributes') ?></h2> + <h2 class="steps-wizard-title"><?php echo $block->escapeHtml( + __('Step 1: Select Attributes') + ); ?></h2> <div class="selected-attributes" data-bind="scope: '<?= /* @noEscape */ $block->getComponentName()?>'"> - <?= /* @noEscape */ __('Selected Attributes:') ?> + <?php echo $block->escapeHtml( + __('Selected Attributes:') + ); ?> <span data-bind="text: selectedAttributes() || '--'"></span> </div> </div> diff --git a/app/code/Magento/ConfigurableProduct/view/adminhtml/templates/catalog/product/edit/attribute/steps/summary.phtml b/app/code/Magento/ConfigurableProduct/view/adminhtml/templates/catalog/product/edit/attribute/steps/summary.phtml index e5ab81c99cc19fd9434babddc0c6a2df847c4f54..37bde42041b6dc10b0cff20137890730fd68c092 100644 --- a/app/code/Magento/ConfigurableProduct/view/adminhtml/templates/catalog/product/edit/attribute/steps/summary.phtml +++ b/app/code/Magento/ConfigurableProduct/view/adminhtml/templates/catalog/product/edit/attribute/steps/summary.phtml @@ -9,34 +9,36 @@ /* @var $block \Magento\ConfigurableProduct\Block\Adminhtml\Product\Steps\Summary */ ?> <div data-bind="scope: '<?= /* @noEscape */ $block->getComponentName()?>'"> - <h2 class="steps-wizard-title"><?= /* @noEscape */ __('Step 4: Summary') ?></h2> + <h2 class="steps-wizard-title"><?php echo $block->escapeHtml( + __('Step 4: Summary') + ); ?></h2> <div class="admin__data-grid-wrap admin__data-grid-wrap-static"> <!-- ko if: gridNew().length --> - <!-- ko template: {name: getGridTemplate(), data: { - grid: gridNew, - id: getGridId(), - title: $t('New Product Review'), - note: $t('Here are the products you\'re about to create.') - }} --><!-- /ko --> + <!-- ko template: {name: getGridTemplate(), data: { + grid: gridNew, + id: getGridId(), + title: $t('New Product Review'), + note: $t('Here are the products you\'re about to create.') + }} --><!-- /ko --> <!-- /ko --> <!-- ko if: gridExisting().length --> - <!-- ko template: {name: getGridTemplate(), data: { - grid: gridExisting, - id: getGridId(), - title: $t('Associated Products'), - note: $t('You created these products for this configuration.') - }} --><!-- /ko --> + <!-- ko template: {name: getGridTemplate(), data: { + grid: gridExisting, + id: getGridId(), + title: $t('Associated Products'), + note: $t('You created these products for this configuration.') + }} --><!-- /ko --> <!-- /ko --> <!-- ko if: gridDeleted().length --> - <!-- ko template: {name: getGridTemplate(), data: { - grid: gridDeleted, - id: getGridId(), - title: $t('Disassociated Products'), - note: $t('These products are not associated.') - }} --><!-- /ko --> + <!-- ko template: {name: getGridTemplate(), data: { + grid: gridDeleted, + id: getGridId(), + title: $t('Disassociated Products'), + note: $t('These products are not associated.') + }} --><!-- /ko --> <!-- /ko --> </div> </div> diff --git a/app/code/Magento/ConfigurableProduct/view/adminhtml/templates/catalog/product/edit/super/wizard.phtml b/app/code/Magento/ConfigurableProduct/view/adminhtml/templates/catalog/product/edit/super/wizard.phtml index 0736fa20fd21e6cf07512e665ce79c3d40c8ceb0..930a264ea8952623bb6f1e5e45a42516e12a9c1c 100644 --- a/app/code/Magento/ConfigurableProduct/view/adminhtml/templates/catalog/product/edit/super/wizard.phtml +++ b/app/code/Magento/ConfigurableProduct/view/adminhtml/templates/catalog/product/edit/super/wizard.phtml @@ -26,7 +26,7 @@ $currencySymbol = $block->getCurrencySymbol(); "components": { "<?= /* @noEscape */ $block->getData('config/form') ?>.<?= /* @noEscape */ $block->getModal() ?>": { "component": "Magento_ConfigurableProduct/js/components/modal-configurable", - "options": {"type": "slide", "title": "<?= /* @escapeNotVerified */ __('Create Product Configurations') ?>"}, + "options": {"type": "slide", "title": "<?php echo $block->escapeHtml(__('Create Product Configurations')); ?>"}, "formName": "<?= /* @noEscape */ $block->getForm() ?>", "isTemplate": false, "stepWizard": "<?= /* @noEscape */ $block->getData('config/nameStepWizard') ?>", @@ -47,7 +47,7 @@ $currencySymbol = $block->getCurrencySymbol(); "formName": "<?= /* @noEscape */ $block->getForm() ?>", "attributeSetHandler": "<?= /* @noEscape */ $block->getForm() ?>.configurable_attribute_set_handler_modal", "wizardModalButtonName": "<?= /* @noEscape */ $block->getForm() ?>.configurable.configurable_products_button_set.create_configurable_products_button", - "wizardModalButtonTitle": "<?= /* @noEscape */ __('Edit Configurations') ?>", + "wizardModalButtonTitle": "<?php echo $block->escapeHtml(__('Edit Configurations')); ?>", "productAttributes": <?= /* @noEscape */ $this->helper('Magento\Framework\Json\Helper\Data')->jsonEncode($attributes) ?>, "productUrl": "<?= /* @noEscape */ $block->getUrl('catalog/product/edit', ['id' => '%id%']) ?>", "variations": <?= /* @noEscape */ $this->helper('Magento\Framework\Json\Helper\Data')->jsonEncode($productMatrix) ?>, diff --git a/app/code/Magento/ConfigurableProduct/view/adminhtml/web/js/components/associated-product-insert-listing.js b/app/code/Magento/ConfigurableProduct/view/adminhtml/web/js/components/associated-product-insert-listing.js index 0c2847683474f813a72d884e5fbb6d002f94400f..ecc960bdb9ea59f09903dea3a118f65642993e8e 100644 --- a/app/code/Magento/ConfigurableProduct/view/adminhtml/web/js/components/associated-product-insert-listing.js +++ b/app/code/Magento/ConfigurableProduct/view/adminhtml/web/js/components/associated-product-insert-listing.js @@ -24,7 +24,8 @@ define([ productsProvider: '${ $.productsProvider }', productsColumns: '${ $.productsColumns }', productsMassAction: '${ $.productsMassAction }', - modalWithGrid: '${ $.modalWithGrid }' + modalWithGrid: '${ $.modalWithGrid }', + productsFilters: '${ $.productsFilters }' }, exports: { externalProviderParams: '${ $.externalProvider }:params' @@ -58,7 +59,9 @@ define([ * @returns {Array} */ getUsedProductIds: function () { - return this.source.get(this.dataScopeAssociatedProduct); + var usedProductsIds = this.source.get(this.dataScopeAssociatedProduct); + + return usedProductsIds.slice(); }, /** @@ -72,6 +75,7 @@ define([ if (this.gridInitialized) { this.paramsUpdated = false; + this.productsFilters().clear(); this._setFilters(this.externalProviderParams); this._setVisibilityMassActionColumn(); } @@ -142,11 +146,13 @@ define([ usedProductIds, attributes; + params = _.omit(params); + if (!this.paramsUpdated) { this.gridInitialized = true; this.paramsUpdated = true; - attrCodes = this._getAttributesCodes(), + attrCodes = this._getAttributesCodes(); usedProductIds = this.getUsedProductIds(); if (this.currentProductId) { @@ -173,6 +179,8 @@ define([ })); params.filters = attributes; + } else { + params.filters = {}; } params['attributes_codes'] = attrCodes; diff --git a/app/code/Magento/ConfigurableProduct/view/adminhtml/web/js/components/dynamic-rows-configurable.js b/app/code/Magento/ConfigurableProduct/view/adminhtml/web/js/components/dynamic-rows-configurable.js index 46c0443b16a069e5d68d1519d0782ac349e9d4d1..7614f41250af2c128c58d28d7528b333d61e0623 100644 --- a/app/code/Magento/ConfigurableProduct/view/adminhtml/web/js/components/dynamic-rows-configurable.js +++ b/app/code/Magento/ConfigurableProduct/view/adminhtml/web/js/components/dynamic-rows-configurable.js @@ -113,7 +113,7 @@ define([ var tmpArray; this.reRender = false; - tmpArray = this.unionInsertData(); + tmpArray = this.getUnionInsertData(); tmpArray.splice(index, 1); if (!tmpArray.length) { @@ -130,7 +130,7 @@ define([ generateAssociatedProducts: function () { var productsIds = []; - this.unionInsertData().each(function (data) { + this.getUnionInsertData().each(function (data) { if (data.id !== null) { productsIds.push(data.id); } @@ -153,6 +153,22 @@ define([ return this; }, + /** + * Get union insert data from source + * + * @returns {Array} + */ + getUnionInsertData: function () { + var source = this.source.get(this.dataScope + '.' + this.index), + result = []; + + _.each(source, function (data) { + result.push(data); + }); + + return result; + }, + /** * Process union insert data. * @@ -217,7 +233,7 @@ define([ return; } - tmpArray = this.unionInsertData(); + tmpArray = this.getUnionInsertData(); changes = this._checkGridData(data); this.cacheGridData = data; @@ -241,7 +257,7 @@ define([ * @param {Object} data */ processingChangeDataFromGrid: function (data) { - var tmpArray = this.unionInsertData(), + var tmpArray = this.getUnionInsertData(), mappedData = this.mappingValue(data.product); mappedData[this.canEditField] = 0; @@ -295,7 +311,7 @@ define([ * @param {Object} data */ processingInsertDataFromWizard: function (data) { - var tmpArray = this.unionInsertData(), + var tmpArray = this.getUnionInsertData(), productIdsToDelete = this.source.get(this.dataScopeAssociatedProduct), index, product = {}; @@ -466,7 +482,7 @@ define([ * @param {Number} rowIndex */ toggleStatusProduct: function (rowIndex) { - var tmpArray = this.unionInsertData(), + var tmpArray = this.getUnionInsertData(), status = parseInt(tmpArray[rowIndex].status, 10); if (status === 1) { diff --git a/app/code/Magento/Customer/Model/ResourceModel/Grid/Collection.php b/app/code/Magento/Customer/Model/ResourceModel/Grid/Collection.php new file mode 100644 index 0000000000000000000000000000000000000000..d31e3c2930522ed610c9e23f4fbcaf4e2e81d0a9 --- /dev/null +++ b/app/code/Magento/Customer/Model/ResourceModel/Grid/Collection.php @@ -0,0 +1,36 @@ +<?php +/** + * Copyright © 2016 Magento. All rights reserved. + * See COPYING.txt for license details. + */ + +namespace Magento\Customer\Model\ResourceModel\Grid; + +use Magento\Framework\Data\Collection\Db\FetchStrategyInterface as FetchStrategy; +use Magento\Framework\Data\Collection\EntityFactoryInterface as EntityFactory; +use Magento\Framework\Event\ManagerInterface as EventManager; +use Psr\Log\LoggerInterface as Logger; + +class Collection extends \Magento\Framework\View\Element\UiComponent\DataProvider\SearchResult +{ + /** + * Initialize dependencies. + * + * @param EntityFactory $entityFactory + * @param Logger $logger + * @param FetchStrategy $fetchStrategy + * @param EventManager $eventManager + * @param string $mainTable + * @param string $resourceModel + */ + public function __construct( + EntityFactory $entityFactory, + Logger $logger, + FetchStrategy $fetchStrategy, + EventManager $eventManager, + $mainTable = 'customer_grid_flat', + $resourceModel = '\Magento\Customer\Model\ResourceModel\Customer' + ) { + parent::__construct($entityFactory, $logger, $fetchStrategy, $eventManager, $mainTable, $resourceModel); + } +} diff --git a/app/code/Magento/Customer/etc/di.xml b/app/code/Magento/Customer/etc/di.xml index f5c66d78c5b8114ba535c41730d940edf9828424..647ec87efca25a1e583df18d3d469f586996b2c2 100644 --- a/app/code/Magento/Customer/etc/di.xml +++ b/app/code/Magento/Customer/etc/di.xml @@ -180,12 +180,6 @@ <argument name="entitySnapshot" xsi:type="object">EavVersionControlSnapshot</argument> </arguments> </type> - <virtualType name="Magento\Customer\Model\ResourceModel\Grid\Collection" type="Magento\Framework\View\Element\UiComponent\DataProvider\SearchResult"> - <arguments> - <argument name="mainTable" xsi:type="string">customer_grid_flat</argument> - <argument name="resourceModel" xsi:type="string">Magento\Customer\Model\ResourceModel\Customer</argument> - </arguments> - </virtualType> <type name="Magento\Framework\View\Element\UiComponent\DataProvider\CollectionFactory"> <arguments> <argument name="collections" xsi:type="array"> diff --git a/app/code/Magento/Directory/etc/adminhtml/system.xml b/app/code/Magento/Directory/etc/adminhtml/system.xml index a22bef73a275a75400edcd35c4ee3f84f8ec7ef9..5e61820f49c60429b965533f664ef36f307552c8 100644 --- a/app/code/Magento/Directory/etc/adminhtml/system.xml +++ b/app/code/Magento/Directory/etc/adminhtml/system.xml @@ -13,7 +13,7 @@ <resource>Magento_Backend::currency</resource> <group id="options" translate="label" sortOrder="30" showInDefault="1" showInWebsite="1" showInStore="1"> <label>Currency Options</label> - <field id="base" translate="label comment" type="select" sortOrder="1" showInDefault="1" showInWebsite="1" showInStore="0"> + <field id="base" translate="label comment" type="select" sortOrder="1" showInDefault="1" showInWebsite="1" showInStore="1"> <label>Base Currency</label> <frontend_model>Magento\Directory\Block\Adminhtml\Frontend\Currency\Base</frontend_model> <source_model>Magento\Config\Model\Config\Source\Locale\Currency</source_model> diff --git a/app/code/Magento/Eav/Model/Entity/Type.php b/app/code/Magento/Eav/Model/Entity/Type.php index 7318e443fe3ada57c0b331ef48324ed4b6013521..6b3547a4f4b9828d126305820b8f4d8644a59849 100644 --- a/app/code/Magento/Eav/Model/Entity/Type.php +++ b/app/code/Magento/Eav/Model/Entity/Type.php @@ -278,7 +278,11 @@ class Type extends \Magento\Framework\Model\AbstractModel */ public function getEntityTable() { - return isset($this->_data['entity_table']) ? $this->_data['entity_table'] : null; + if (isset($this->_data['entity_table'])) { + return $this->getResource()->getTable($this->_data['entity_table']); + } + + return null; } /** diff --git a/app/code/Magento/GoogleOptimizer/Observer/AbstractSave.php b/app/code/Magento/GoogleOptimizer/Observer/AbstractSave.php index dc1a5ef3166f0711f6918b660bcbc0513681d952..3c3afd7a784b65ea1d2d23ee694104b43fc861ea 100644 --- a/app/code/Magento/GoogleOptimizer/Observer/AbstractSave.php +++ b/app/code/Magento/GoogleOptimizer/Observer/AbstractSave.php @@ -58,7 +58,7 @@ abstract class AbstractSave implements ObserverInterface { $this->_initEntity($observer); - if ($this->_isGoogleExperimentActive()) { + if ($this->_isGoogleExperimentActive() && $this->isDataAvailable()) { $this->_processCode(); } @@ -112,11 +112,10 @@ abstract class AbstractSave implements ObserverInterface */ protected function _initRequestParams() { - $params = $this->_request->getParam('google_experiment'); - if (!is_array($params) || !isset($params['experiment_script']) || !isset($params['code_id'])) { + if (!$this->isDataAvailable()) { throw new \InvalidArgumentException('Wrong request parameters'); } - $this->_params = $params; + $this->_params = $this->getRequestData(); } /** @@ -181,4 +180,21 @@ abstract class AbstractSave implements ObserverInterface { $this->_modelCode->delete(); } + + /** + * @return array + */ + private function isDataAvailable() + { + $params = $this->getRequestData(); + return is_array($params) && isset($params['experiment_script']) && isset($params['code_id']); + } + + /** + * @return mixed + */ + private function getRequestData() + { + return $this->_request->getParam('google_experiment'); + } } diff --git a/app/code/Magento/GoogleOptimizer/Test/Unit/Observer/Category/SaveGoogleExperimentScriptObserverTest.php b/app/code/Magento/GoogleOptimizer/Test/Unit/Observer/Category/SaveGoogleExperimentScriptObserverTest.php index 14f0cd8f43727b985f8283ff5e703a9c71fc38e7..f6f6b4670bffcf9f1e5e6b7a43531cbcd4ce21b9 100644 --- a/app/code/Magento/GoogleOptimizer/Test/Unit/Observer/Category/SaveGoogleExperimentScriptObserverTest.php +++ b/app/code/Magento/GoogleOptimizer/Test/Unit/Observer/Category/SaveGoogleExperimentScriptObserverTest.php @@ -85,7 +85,7 @@ class SaveGoogleExperimentScriptObserverTest extends \PHPUnit_Framework_TestCase ); $this->_requestMock->expects( - $this->once() + $this->exactly(3) )->method( 'getParam' )->with( @@ -113,8 +113,6 @@ class SaveGoogleExperimentScriptObserverTest extends \PHPUnit_Framework_TestCase /** * @param array $params - * @expectedException \InvalidArgumentException - * @expectedExceptionMessage Wrong request parameters * @dataProvider dataProviderWrongRequestForCreating */ public function testCreatingCodeIfRequestIsNotValid($params) @@ -174,7 +172,7 @@ class SaveGoogleExperimentScriptObserverTest extends \PHPUnit_Framework_TestCase ); $this->_requestMock->expects( - $this->once() + $this->exactly(3) )->method( 'getParam' )->with( @@ -223,7 +221,7 @@ class SaveGoogleExperimentScriptObserverTest extends \PHPUnit_Framework_TestCase ); $this->_requestMock->expects( - $this->once() + $this->exactly(3) )->method( 'getParam' )->with( @@ -254,7 +252,7 @@ class SaveGoogleExperimentScriptObserverTest extends \PHPUnit_Framework_TestCase ); $this->_requestMock->expects( - $this->once() + $this->exactly(3) )->method( 'getParam' )->with( diff --git a/app/code/Magento/GoogleOptimizer/Test/Unit/Observer/CmsPage/SaveGoogleExperimentScriptObserverTest.php b/app/code/Magento/GoogleOptimizer/Test/Unit/Observer/CmsPage/SaveGoogleExperimentScriptObserverTest.php index 485fc36343df1d8a6e440af7ed3bc0daafac9cb3..4e1f0245176b951ddfc1642de6206e7baaf0bd0e 100644 --- a/app/code/Magento/GoogleOptimizer/Test/Unit/Observer/CmsPage/SaveGoogleExperimentScriptObserverTest.php +++ b/app/code/Magento/GoogleOptimizer/Test/Unit/Observer/CmsPage/SaveGoogleExperimentScriptObserverTest.php @@ -70,7 +70,7 @@ class SaveGoogleExperimentScriptObserverTest extends \PHPUnit_Framework_TestCase $this->_helperMock->expects($this->once())->method('isGoogleExperimentActive')->will($this->returnValue(true)); $this->_requestMock->expects( - $this->once() + $this->exactly(3) )->method( 'getParam' )->with( @@ -98,8 +98,6 @@ class SaveGoogleExperimentScriptObserverTest extends \PHPUnit_Framework_TestCase /** * @param array $params - * @expectedException \InvalidArgumentException - * @expectedExceptionMessage Wrong request parameters * @dataProvider dataProviderWrongRequestForCreating */ public function testCreatingCodeIfRequestIsNotValid($params) @@ -143,7 +141,7 @@ class SaveGoogleExperimentScriptObserverTest extends \PHPUnit_Framework_TestCase $this->_helperMock->expects($this->once())->method('isGoogleExperimentActive')->will($this->returnValue(true)); $this->_requestMock->expects( - $this->once() + $this->exactly(3) )->method( 'getParam' )->with( @@ -184,7 +182,7 @@ class SaveGoogleExperimentScriptObserverTest extends \PHPUnit_Framework_TestCase $this->_helperMock->expects($this->once())->method('isGoogleExperimentActive')->will($this->returnValue(true)); $this->_requestMock->expects( - $this->once() + $this->exactly(3) )->method( 'getParam' )->with( @@ -215,7 +213,7 @@ class SaveGoogleExperimentScriptObserverTest extends \PHPUnit_Framework_TestCase ); $this->_requestMock->expects( - $this->once() + $this->exactly(3) )->method( 'getParam' )->with( diff --git a/app/code/Magento/GoogleOptimizer/Test/Unit/Observer/Product/SaveGoogleExperimentScriptObserverTest.php b/app/code/Magento/GoogleOptimizer/Test/Unit/Observer/Product/SaveGoogleExperimentScriptObserverTest.php index fe25ce77646eb82e55ee201dd3021ff2342691e2..34821ca212159b4dde351da10099040da9f17395 100644 --- a/app/code/Magento/GoogleOptimizer/Test/Unit/Observer/Product/SaveGoogleExperimentScriptObserverTest.php +++ b/app/code/Magento/GoogleOptimizer/Test/Unit/Observer/Product/SaveGoogleExperimentScriptObserverTest.php @@ -85,7 +85,7 @@ class SaveGoogleExperimentScriptObserverTest extends \PHPUnit_Framework_TestCase ); $this->_requestMock->expects( - $this->once() + $this->exactly(3) )->method( 'getParam' )->with( @@ -113,8 +113,6 @@ class SaveGoogleExperimentScriptObserverTest extends \PHPUnit_Framework_TestCase /** * @param array $params - * @expectedException \InvalidArgumentException - * @expectedExceptionMessage Wrong request parameters * @dataProvider dataProviderWrongRequestForCreating */ public function testCreatingCodeIfRequestIsNotValid($params) @@ -174,7 +172,7 @@ class SaveGoogleExperimentScriptObserverTest extends \PHPUnit_Framework_TestCase ); $this->_requestMock->expects( - $this->once() + $this->exactly(3) )->method( 'getParam' )->with( @@ -223,7 +221,7 @@ class SaveGoogleExperimentScriptObserverTest extends \PHPUnit_Framework_TestCase ); $this->_requestMock->expects( - $this->once() + $this->exactly(3) )->method( 'getParam' )->with( @@ -254,7 +252,7 @@ class SaveGoogleExperimentScriptObserverTest extends \PHPUnit_Framework_TestCase ); $this->_requestMock->expects( - $this->once() + $this->exactly(3) )->method( 'getParam' )->with( diff --git a/app/code/Magento/Integration/Controller/Adminhtml/Integration/TokensExchange.php b/app/code/Magento/Integration/Controller/Adminhtml/Integration/TokensExchange.php index 799420efcc0d59c265c7298dcc1630e144bfbce7..2251ed525db604133ae17ece56080d3ebc62dba7 100644 --- a/app/code/Magento/Integration/Controller/Adminhtml/Integration/TokensExchange.php +++ b/app/code/Magento/Integration/Controller/Adminhtml/Integration/TokensExchange.php @@ -53,10 +53,16 @@ class TokensExchange extends \Magento\Integration\Controller\Adminhtml\Integrati $this->_setActivationInProcessMsg($isReauthorize, $integration->getName()); $this->_view->renderLayout(); $popupContent = $this->_response->getBody(); + $consumer = $this->_oauthService->loadConsumer($integration->getConsumerId()); + if (!$consumer->getId()) { + throw new \Magento\Framework\Oauth\Exception( + __('A consumer with ID %1 does not exist', $integration->getConsumerId()) + ); + } /** Initialize response body */ $result = [ IntegrationModel::IDENTITY_LINK_URL => $integration->getIdentityLinkUrl(), - IntegrationModel::CONSUMER_ID => $integration->getConsumerId(), + 'oauth_consumer_key' => $consumer->getKey(), 'popup_content' => $popupContent, ]; $this->getResponse()->representJson($this->jsonHelper->jsonEncode($result)); diff --git a/app/code/Magento/Integration/Model/OauthService.php b/app/code/Magento/Integration/Model/OauthService.php index 9ce2df70a547b5029307d9b89e4cdb90fb03d164..16dbf5aa04b1013b62d3572f7092696b8eec0800 100644 --- a/app/code/Magento/Integration/Model/OauthService.php +++ b/app/code/Magento/Integration/Model/OauthService.php @@ -192,7 +192,7 @@ class OauthService implements \Magento\Integration\Api\OauthServiceInterface public function postToConsumer($consumerId, $endpointUrl) { try { - $consumer = $this->_consumerFactory->create()->load($consumerId); + $consumer = $this->loadConsumer($consumerId); if (!$consumer->getId()) { throw new \Magento\Framework\Oauth\Exception( __('A consumer with ID %1 does not exist', $consumerId) diff --git a/app/code/Magento/Integration/Model/ResourceModel/Oauth/Consumer.php b/app/code/Magento/Integration/Model/ResourceModel/Oauth/Consumer.php index 2fcd1910b1bccad50b36fb878e44c70076f7f1f8..9b677099e49e72b23df6925abeae88c9017fd0fc 100644 --- a/app/code/Magento/Integration/Model/ResourceModel/Oauth/Consumer.php +++ b/app/code/Magento/Integration/Model/ResourceModel/Oauth/Consumer.php @@ -37,8 +37,8 @@ class Consumer extends \Magento\Framework\Model\ResourceModel\Db\AbstractDb public function _afterDelete(\Magento\Framework\Model\AbstractModel $object) { $connection = $this->getConnection(); - $connection->delete($this->getTable('oauth_nonce'), ['consumer_id' => $object->getId()]); - $connection->delete($this->getTable('oauth_token'), ['consumer_id' => $object->getId()]); + $connection->delete($this->getTable('oauth_nonce'), ['consumer_id = ?' => (int)$object->getId()]); + $connection->delete($this->getTable('oauth_token'), ['consumer_id = ?' => (int)$object->getId()]); return parent::_afterDelete($object); } diff --git a/app/code/Magento/Integration/Test/Unit/Controller/Adminhtml/Integration/TokensDialogTest.php b/app/code/Magento/Integration/Test/Unit/Controller/Adminhtml/Integration/TokensDialogTest.php index fc28ff0f63dd52d34ded0e5ac415add915902d5d..7f6912c5d3270ecf5da2f702f66d1bb3956e09b9 100644 --- a/app/code/Magento/Integration/Test/Unit/Controller/Adminhtml/Integration/TokensDialogTest.php +++ b/app/code/Magento/Integration/Test/Unit/Controller/Adminhtml/Integration/TokensDialogTest.php @@ -84,6 +84,9 @@ class TokensDialogTest extends \Magento\Integration\Test\Unit\Controller\Adminht $this->_oauthSvcMock->expects($this->once())->method('deleteIntegrationToken'); $this->_oauthSvcMock->expects($this->once())->method('postToConsumer'); + $consumerMock = $this->getMock(\Magento\Integration\Model\Oauth\Consumer::class, [], [], '' , false); + $consumerMock->expects($this->once())->method('getId')->willReturn(1); + $this->_oauthSvcMock->expects($this->once())->method('loadConsumer')->willReturn($consumerMock); $this->_messageManager->expects($this->once())->method('addNotice'); $this->_messageManager->expects($this->never())->method('addError'); diff --git a/app/code/Magento/Integration/view/adminhtml/web/js/integration.js b/app/code/Magento/Integration/view/adminhtml/web/js/integration.js index 40aa90c281f1166a23547f4fb7d91e644f1c329f..776339f15c2d72425f53fa802629f4c2e15a4e2f 100644 --- a/app/code/Magento/Integration/view/adminhtml/web/js/integration.js +++ b/app/code/Magento/Integration/view/adminhtml/web/js/integration.js @@ -133,11 +133,11 @@ define([ TOP: screen.height - 510 - 300 }, - invokePopup: function (identityCallbackUrl, consumerId, jqInfoDialog) { + invokePopup: function (identityCallbackUrl, consumerKey, jqInfoDialog) { // Callback should be invoked only once. Reset callback flag on subsequent invocations. IdentityLogin.isCalledBack = false; IdentityLogin.jqInfoDialog = jqInfoDialog; - var param = $.param({"consumer_id": consumerId, "success_call_back": IdentityLogin.successCallbackUrl}); + var param = $.param({"oauth_consumer_key": consumerKey, "success_call_back": IdentityLogin.successCallbackUrl}); IdentityLogin.win = window.open(identityCallbackUrl + '?' + param, '', 'top=' + IdentityLogin.Constants.TOP + ', left=' + IdentityLogin.Constants.LEFT + @@ -205,7 +205,7 @@ define([ } var identityLinkUrl = null, - consumerId = null, + consumerKey = null, popupHtml = null, popup = $('#integration-popup-container'); @@ -215,15 +215,15 @@ define([ result; identityLinkUrl = resultObj['identity_link_url']; - consumerId = resultObj['consumer_id']; + consumerKey = resultObj['oauth_consumer_key']; popupHtml = resultObj['popup_content']; } catch (e) { //This is expected if result is not json. Do nothing. } - if (identityLinkUrl && consumerId && popupHtml) { - IdentityLogin.invokePopup(identityLinkUrl, consumerId, popup); + if (identityLinkUrl && consumerKey && popupHtml) { + IdentityLogin.invokePopup(identityLinkUrl, consumerKey, popup); } else { popupHtml = result; } diff --git a/app/code/Magento/Multishipping/Model/Cart/Controller/CartPlugin.php b/app/code/Magento/Multishipping/Model/Cart/Controller/CartPlugin.php new file mode 100644 index 0000000000000000000000000000000000000000..9df2cff55f271884ce2af57553739dad1ded277c --- /dev/null +++ b/app/code/Magento/Multishipping/Model/Cart/Controller/CartPlugin.php @@ -0,0 +1,57 @@ +<?php +/** + * Copyright © 2016 Magento. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\Multishipping\Model\Cart\Controller; + +class CartPlugin +{ + /** + * @var \Magento\Quote\Api\CartRepositoryInterface + */ + private $cartRepository; + + /** + * @var \Magento\Checkout\Model\Session + */ + private $checkoutSession; + + /** + * @param \Magento\Quote\Api\CartRepositoryInterface $cartRepository + * @param \Magento\Checkout\Model\Session $checkoutSession + */ + public function __construct( + \Magento\Quote\Api\CartRepositoryInterface $cartRepository, + \Magento\Checkout\Model\Session $checkoutSession + ) { + $this->cartRepository = $cartRepository; + $this->checkoutSession = $checkoutSession; + } + + /** + * @param \Magento\Checkout\Controller\Cart $subject + * @param \Magento\Framework\App\RequestInterface $request + * @return void + * @SuppressWarnings(PHPMD.UnusedFormalParameter) + */ + public function beforeDispatch( + \Magento\Checkout\Controller\Cart $subject, + \Magento\Framework\App\RequestInterface $request + ) { + /** @var \Magento\Quote\Model\Quote $quote */ + $quote = $this->checkoutSession->getQuote(); + + // Clear shipping addresses and item assignments after Multishipping flow + if ($quote->isMultipleShippingAddresses()) { + foreach ($quote->getAllShippingAddresses() as $address) { + $quote->removeAddress($address->getId()); + } + $quote->getShippingAddress(); + $quote->setIsMultiShipping(false); + $quote->collectTotals(); + + $this->cartRepository->save($quote); + } + } +} diff --git a/app/code/Magento/Multishipping/Test/Unit/Model/Cart/Controller/CartPluginTest.php b/app/code/Magento/Multishipping/Test/Unit/Model/Cart/Controller/CartPluginTest.php new file mode 100644 index 0000000000000000000000000000000000000000..5b6ba1b447a394d1efa0dd10ccd597b44e4fbec0 --- /dev/null +++ b/app/code/Magento/Multishipping/Test/Unit/Model/Cart/Controller/CartPluginTest.php @@ -0,0 +1,71 @@ +<?php +/** + * Copyright © 2016 Magento. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\Multishipping\Test\Unit\Model\Cart\Controller; + +class CartPluginTest extends \PHPUnit_Framework_TestCase +{ + /** + * @var \Magento\Multishipping\Model\Cart\Controller\CartPlugin + */ + private $model; + + /** + * @var \PHPUnit_Framework_MockObject_MockObject + */ + private $cartRepositoryMock; + + /** + * @var \PHPUnit_Framework_MockObject_MockObject + */ + private $checkoutSessionMock; + + protected function setUp() + { + $this->cartRepositoryMock = $this->getMock('\Magento\Quote\Api\CartRepositoryInterface'); + $this->checkoutSessionMock = $this->getMock('\Magento\Checkout\Model\Session', [], [], '', false); + $this->model = new \Magento\Multishipping\Model\Cart\Controller\CartPlugin( + $this->cartRepositoryMock, + $this->checkoutSessionMock + ); + } + + public function testBeforeDispatch() + { + $addressId = 100; + $quoteMock = $this->getMock( + '\Magento\Quote\Model\Quote', + [ + 'isMultipleShippingAddresses', + 'getAllShippingAddresses', + 'removeAddress', + 'getShippingAddress', + 'setIsMultiShipping', + 'collectTotals' + ], + [], + '', + false + ); + $this->checkoutSessionMock->expects($this->once())->method('getQuote')->willReturn($quoteMock); + + $addressMock = $this->getMock('\Magento\Quote\Model\Quote\Address', [], [], '', false); + $addressMock->expects($this->once())->method('getId')->willReturn($addressId); + + $quoteMock->expects($this->once())->method('isMultipleShippingAddresses')->willReturn(true); + $quoteMock->expects($this->once())->method('getAllShippingAddresses')->willReturn([$addressMock]); + $quoteMock->expects($this->once())->method('removeAddress')->with($addressId)->willReturnSelf(); + $quoteMock->expects($this->once())->method('getShippingAddress'); + $quoteMock->expects($this->once())->method('setIsMultiShipping')->with(false)->willReturnSelf(); + $quoteMock->expects($this->once())->method('collectTotals')->willReturnSelf(); + + $this->cartRepositoryMock->expects($this->once())->method('save')->with($quoteMock); + + $this->model->beforeDispatch( + $this->getMock('\Magento\Checkout\Controller\Cart', [], [], '', false), + $this->getMock('\Magento\Framework\App\RequestInterface') + ); + } +} diff --git a/app/code/Magento/Multishipping/etc/frontend/di.xml b/app/code/Magento/Multishipping/etc/frontend/di.xml index 6d7ac0ea8aabc2e691a52c5efc5b1a33db774d79..3f1ee5dcaa34fbb1c31a2fd7bf7476438c695313 100644 --- a/app/code/Magento/Multishipping/etc/frontend/di.xml +++ b/app/code/Magento/Multishipping/etc/frontend/di.xml @@ -42,4 +42,7 @@ <type name="Magento\Checkout\Model\Cart"> <plugin name="multishipping_session_mapper" type="Magento\Multishipping\Model\Checkout\Type\Multishipping\Plugin" sortOrder="50" /> </type> + <type name="Magento\Checkout\Controller\Cart"> + <plugin name="multishipping_clear_addresses" type="Magento\Multishipping\Model\Cart\Controller\CartPlugin" /> + </type> </config> diff --git a/app/code/Magento/Persistent/Observer/EmulateCustomerObserver.php b/app/code/Magento/Persistent/Observer/EmulateCustomerObserver.php index 7f9d88cb36e4883669f5797e71ad98317c2a3820..b68803a50d191a1df97e3795712c322324c3c903 100644 --- a/app/code/Magento/Persistent/Observer/EmulateCustomerObserver.php +++ b/app/code/Magento/Persistent/Observer/EmulateCustomerObserver.php @@ -113,7 +113,8 @@ class EmulateCustomerObserver implements ObserverInterface } $this->_customerSession ->setCustomerId($customer->getId()) - ->setCustomerGroupId($customer->getGroupId()); + ->setCustomerGroupId($customer->getGroupId()) + ->setIsCustomerEmulated(true); } return $this; } diff --git a/app/code/Magento/Persistent/Test/Unit/Observer/EmulateCustomerObserverTest.php b/app/code/Magento/Persistent/Test/Unit/Observer/EmulateCustomerObserverTest.php index 2f0a59d448e2427cb8c501a2e35fd262f1ae45b9..854113a33edc7b8d89b10be5457d0fdebdf2a66f 100644 --- a/app/code/Magento/Persistent/Test/Unit/Observer/EmulateCustomerObserverTest.php +++ b/app/code/Magento/Persistent/Test/Unit/Observer/EmulateCustomerObserverTest.php @@ -57,7 +57,9 @@ class EmulateCustomerObserverTest extends \PHPUnit_Framework_TestCase 'setDefaultTaxBillingAddress', 'setCustomerId', 'setCustomerGroupId', - 'isLoggedIn' + 'isLoggedIn', + 'setIsCustomerEmulated', + '__wakeUp' ]; $this->customerSessionMock = $this->getMock('Magento\Customer\Model\Session', $methods, [], '', false); $this->sessionHelperMock = $this->getMock('Magento\Persistent\Helper\Session', [], [], '', false); @@ -168,7 +170,15 @@ class EmulateCustomerObserverTest extends \PHPUnit_Framework_TestCase ->method('setCustomerId') ->with($customerId) ->will($this->returnSelf()); - $this->customerSessionMock->expects($this->once())->method('setCustomerGroupId')->with($customerGroupId); + $this->customerSessionMock + ->expects($this->once()) + ->method('setCustomerGroupId') + ->with($customerGroupId)->will($this->returnSelf()); + $this->customerSessionMock + ->expects($this->once()) + ->method('setIsCustomerEmulated') + ->with(true) + ->will($this->returnSelf()); $this->model->execute($this->observerMock); } diff --git a/app/code/Magento/ProductVideo/view/adminhtml/templates/helper/gallery.phtml b/app/code/Magento/ProductVideo/view/adminhtml/templates/helper/gallery.phtml index f57ba1ce79e1ed0680ae4bfd83a02f770494679c..806b4a75d377efa73cc41ceb7ae5faf698f8a639 100755 --- a/app/code/Magento/ProductVideo/view/adminhtml/templates/helper/gallery.phtml +++ b/app/code/Magento/ProductVideo/view/adminhtml/templates/helper/gallery.phtml @@ -37,7 +37,7 @@ $elementToggleCode = $element->getToggleCode() ? $element->getToggleCode() : 'to data-types="<?php echo $block->escapeHtml( $this->helper('Magento\Framework\Json\Helper\Data')->jsonEncode($block->getImageTypes()) ) ?>" - > +> <?php if (!$block->getElement()->getReadonly()): @@ -47,7 +47,9 @@ $elementToggleCode = $element->getToggleCode() ? $element->getToggleCode() : 'to ?> <div class="product-image-wrapper"> <p class="image-placeholder-text"> - <?php /* @noEscape */ echo __('Browse to find or drag image here'); ?> + <?php echo $block->escapeHtml( + __('Browse to find or drag image here') + ); ?> </p> </div> </div> @@ -141,32 +143,42 @@ $elementToggleCode = $element->getToggleCode() ? $element->getToggleCode() : 'to class="action-remove" data-role="delete-button" title="<% if (data.media_type == 'external-video') {%> - <?php /* @noEscape */echo __('Delete video') ?> + <?php echo $block->escapeHtml( + __('Delete video') + ); ?> <%} else {%> - <?php /* @noEscape */ echo __('Delete image') ?> + <?php echo $block->escapeHtml( + __('Delete image') + ); ?> <%}%>"> <span> <% if (data.media_type == 'external-video') { %> - <?php /* @noEscape */ echo __('Delete video') ?> + <?php echo $block->escapeHtml( + __('Delete video') + ); ?> <% } else {%> - <?php /* @noEscape */ echo __('Delete image') ?> + <?php echo $block->escapeHtml( + __('Delete image') + ); ?> <%} %> </span> </button> <div class="draggable-handle"></div> </div> - <div class="image-fade"><span><?php /* @noEscape */ echo __('Hidden') ?></span></div> + <div class="image-fade"><span><?php echo $block->escapeHtml( + __('Hidden') + ); ?></span></div> </div> <div class="item-description"> - <% if (data.media_type !== 'external-video') {%> + <% if (data.media_type !== 'external-video') {%> <div class="item-title" data-role="img-title"><%- data.label %></div> <div class="item-size"> - <span data-role="image-dimens"></span>, <span data-role="image-size"><%- data.sizeLabel %></span> - </div> - <% } else { %> + <span data-role="image-dimens"></span>, <span data-role="image-size"><%- data.sizeLabel %></span> + </div> + <% } else { %> <div class="item-title" data-role="img-title"><%- data.video_title %></div> - <% } %> + <% } %> </div> <ul class="item-roles" data-role="roles-labels"> @@ -188,114 +200,126 @@ $elementToggleCode = $element->getToggleCode() ? $element->getToggleCode() : 'to </script> <script data-role="img-dialog-container-tmpl" type="text/x-magento-template"> - <div class="image-panel" data-role="dialog"> - </div> + <div class="image-panel" data-role="dialog"> + </div> </script> <script data-role="img-dialog-tmpl" type="text/x-magento-template"> - <div class="image-panel-preview"> - <img src="<%- data.url %>" alt="<%- data.label %>" /> - </div> - <div class="image-panel-controls"> - <strong class="image-name"><%- data.label %></strong> + <div class="image-panel-preview"> + <img src="<%- data.url %>" alt="<%- data.label %>" /> + </div> + <div class="image-panel-controls"> + <strong class="image-name"><%- data.label %></strong> - <fieldset class="admin__fieldset fieldset-image-panel"> - <div class="admin__field field-image-description"> - <label class="admin__field-label" for="image-description"> - <span><?php /* @escapeNotVerified */ echo __('Alt Text')?></span> - </label> + <fieldset class="admin__fieldset fieldset-image-panel"> + <div class="admin__field field-image-description"> + <label class="admin__field-label" for="image-description"> + <span><?php /* @escapeNotVerified */ echo __('Alt Text')?></span> + </label> - <div class="admin__field-control"> + <div class="admin__field-control"> <textarea data-role="image-description" rows="3" class="admin__control-textarea" name="<?php /* @escapeNotVerified */ echo $elementName ?>[<%- data.file_id %>][label]"><%- data.label %></textarea> - </div> </div> + </div> - <div class="admin__field field-image-role"> - <label class="admin__field-label"> - <span><?php /* @noEscape */ echo __('Role')?></span> - </label> - <div class="admin__field-control"> - <ul class="multiselect-alt"> - <?php - foreach ($block->getMediaAttributes() as $attribute) : - ?> - <li class="item"> - <label> - <input class="image-type" - data-role="type-selector" - data-form-part="<?php /* @escapeNotVerified */ echo $formName ?>" - type="checkbox" - value="<?php echo $block->escapeHtml( - $attribute->getAttributeCode() - ) ?>" - /> - <?php /* @escapeNotVerified */ echo $block->escapeHtml( - $attribute->getFrontendLabel() - ) ?> - </label> - </li> - <?php - endforeach; + <div class="admin__field field-image-role"> + <label class="admin__field-label"> + <span><?php echo $block->escapeHtml( + __('Role') + ); ?></span> + </label> + <div class="admin__field-control"> + <ul class="multiselect-alt"> + <?php + foreach ($block->getMediaAttributes() as $attribute) : ?> - </ul> - </div> + <li class="item"> + <label> + <input class="image-type" + data-role="type-selector" + data-form-part="<?php /* @escapeNotVerified */ echo $formName ?>" + type="checkbox" + value="<?php echo $block->escapeHtml( + $attribute->getAttributeCode() + ) ?>" + /> + <?php /* @escapeNotVerified */ echo $block->escapeHtml( + $attribute->getFrontendLabel() + ) ?> + </label> + </li> + <?php + endforeach; + ?> + </ul> </div> + </div> - <div class="admin__field admin__field-inline field-image-size" data-role="size"> - <label class="admin__field-label"> - <span><?php /* @escapeNotVerified */ echo __('Image Size') ?></span> - </label> - <div class="admin__field-value" data-message="<?php /* @escapeNotVerified */ echo __('{size}') ?>"></div> - </div> + <div class="admin__field admin__field-inline field-image-size" data-role="size"> + <label class="admin__field-label"> + <span><?php /* @escapeNotVerified */ echo __('Image Size') ?></span> + </label> + <div class="admin__field-value" data-message="<?php /* @escapeNotVerified */ echo __('{size}') ?>"></div> + </div> - <div class="admin__field admin__field-inline field-image-resolution" data-role="resolution"> - <label class="admin__field-label"> - <span><?php /* @escapeNotVerified */ echo __('Image Resolution') ?></span> - </label> - <div class="admin__field-value" data-message="<?php /* @escapeNotVerified */ echo __('{width}^{height} px') ?>"></div> - </div> + <div class="admin__field admin__field-inline field-image-resolution" data-role="resolution"> + <label class="admin__field-label"> + <span><?php /* @escapeNotVerified */ echo __('Image Resolution') ?></span> + </label> + <div class="admin__field-value" data-message="<?php /* @escapeNotVerified */ echo __('{width}^{height} px') ?>"></div> + </div> - <div class="admin__field field-image-hide"> - <div class="admin__field-control"> - <div class="admin__field admin__field-option"> - <input type="checkbox" - id="hide-from-product-page" - data-role="visibility-trigger" - data-form-part="<?php /* @escapeNotVerified */ echo $formName ?>" - value="1" - class="admin__control-checkbox" - name="<?php /* @escapeNotVerified */ echo $elementName ?>[<%- data.file_id %>][disabled]" - <% if (data.disabled == 1) { %>checked="checked"<% } %> /> + <div class="admin__field field-image-hide"> + <div class="admin__field-control"> + <div class="admin__field admin__field-option"> + <input type="checkbox" + id="hide-from-product-page" + data-role="visibility-trigger" + data-form-part="<?php /* @escapeNotVerified */ echo $formName ?>" + value="1" + class="admin__control-checkbox" + name="<?php /* @escapeNotVerified */ echo $elementName ?>[<%- data.file_id %>][disabled]" + <% if (data.disabled == 1) { %>checked="checked"<% } %> /> - <label for="hide-from-product-page" class="admin__field-label"> - <?php /* @noEscape */ echo __('Hide from Product Page')?> - </label> - </div> + <label for="hide-from-product-page" class="admin__field-label"> + <?php echo $block->escapeHtml( + __('Hide from Product Page') + ); ?> + </label> </div> </div> - </fieldset> - </div> + </div> + </fieldset> + </div> </script> <div id="<?php /* @noEscape */ echo $block->getNewVideoBlockName();?>" style="display:none"> <?php /* @escapeNotVerified */ echo $block->getFormHtml();?> <div id="video-player-preview-location" class="video-player-sidebar"> <div class="video-player-container"></div> <div class="video-information title"> - <label><?php /* @noEscape */ echo __('Title:') ?> </label><span></span> + <label><?php echo $block->escapeHtml( + __('Title:') + ); ?> </label><span></span> </div> <div class="video-information uploaded"> - <label><?php /* @noEscape */ echo __('Uploaded:') ?> </label><span></span> + <label><?php echo $block->escapeHtml( + __('Uploaded:') + ); ?> </label><span></span> </div> <div class="video-information uploader"> - <label><?php /* @noEscape */ echo __('Uploader:') ?> </label><span></span> + <label><?php echo $block->escapeHtml( + __('Uploader:') + ); ?> </label><span></span> </div> <div class="video-information duration"> - <label><?php /* @noEscape */ echo __('Duration:') ?> </label><span></span> + <label><?php echo $block->escapeHtml( + __('Duration:') + ); ?> </label><span></span> </div> </div> </div> @@ -305,4 +329,3 @@ $elementToggleCode = $element->getToggleCode() ? $element->getToggleCode() : 'to <script> jQuery('body').trigger('contentUpdated'); </script> - diff --git a/app/code/Magento/Quote/Model/Cart/TotalsConverter.php b/app/code/Magento/Quote/Model/Cart/TotalsConverter.php index f0f61ea2439ac97105eff0b1b0525cedd631e3df..f196493e27bc405aed53ee50106154443de9eb60 100644 --- a/app/code/Magento/Quote/Model/Cart/TotalsConverter.php +++ b/app/code/Magento/Quote/Model/Cart/TotalsConverter.php @@ -27,7 +27,6 @@ class TotalsConverter $this->factory = $factory; } - /** * @param \Magento\Quote\Model\Quote\Address\Total[] $addressTotals * @return \Magento\Quote\Api\Data\TotalSegmentInterface[] @@ -44,7 +43,7 @@ class TotalsConverter TotalSegmentInterface::AREA => $addressTotal->getArea(), ]; if (is_object($addressTotal->getTitle())) { - $pureData[TotalSegmentInterface::TITLE] = $addressTotal->getTitle()->getText(); + $pureData[TotalSegmentInterface::TITLE] = $addressTotal->getTitle()->render(); } /** @var \Magento\Quote\Model\Cart\TotalSegment $total */ $total = $this->factory->create(); diff --git a/app/code/Magento/Quote/Model/Quote/Address/Total/Shipping.php b/app/code/Magento/Quote/Model/Quote/Address/Total/Shipping.php index f1660c9f9d6427fb617c2de9d87ae2a8026be3aa..88edeb5b99dd6c32e43994796eb48a6646ba5bc9 100644 --- a/app/code/Magento/Quote/Model/Quote/Address/Total/Shipping.php +++ b/app/code/Magento/Quote/Model/Quote/Address/Total/Shipping.php @@ -60,9 +60,10 @@ class Shipping extends \Magento\Quote\Model\Quote\Address\Total\AbstractTotal $addressWeight = $address->getWeight(); $freeMethodWeight = $address->getFreeMethodWeight(); - $address->setFreeShipping( - $this->freeShipping->isFreeShipping($quote, $shippingAssignment->getItems()) - ); + $isAllFree = $this->freeShipping->isFreeShipping($quote, $shippingAssignment->getItems()); + if ($isAllFree && !$address->getFreeShipping()) { + $address->setFreeShipping(true); + } $total->setTotalAmount($this->getCode(), 0); $total->setBaseTotalAmount($this->getCode(), 0); diff --git a/app/code/Magento/Quote/Model/Quote/Address/Total/Subtotal.php b/app/code/Magento/Quote/Model/Quote/Address/Total/Subtotal.php index e164146318bc86c88e0627967b140a91d968b4ae..7d4afa813165188890536f7287fa28c311b20e94 100644 --- a/app/code/Magento/Quote/Model/Quote/Address/Total/Subtotal.php +++ b/app/code/Magento/Quote/Model/Quote/Address/Total/Subtotal.php @@ -71,6 +71,8 @@ class Subtotal extends \Magento\Quote\Model\Quote\Address\Total\AbstractTotal */ $this->quoteValidator->validateQuoteAmount($quote, $total->getSubtotal()); $this->quoteValidator->validateQuoteAmount($quote, $total->getBaseSubtotal()); + $address->setSubtotal($total->getSubtotal()); + $address->setBaseSubtotal($total->getBaseSubtotal()); return $this; } diff --git a/app/code/Magento/Quote/Model/QuoteRepository/SaveHandler.php b/app/code/Magento/Quote/Model/QuoteRepository/SaveHandler.php index eff7bdc30b7c327357f946d31e08d83548022ab5..a3d0507c394850f171d312467e4b5757a905bb02 100644 --- a/app/code/Magento/Quote/Model/QuoteRepository/SaveHandler.php +++ b/app/code/Magento/Quote/Model/QuoteRepository/SaveHandler.php @@ -5,22 +5,18 @@ */ namespace Magento\Quote\Model\QuoteRepository; -use Magento\Quote\Model\Quote\Address\BillingAddressPersister; -use Magento\Quote\Model\Quote\ShippingAssignment\ShippingAssignmentPersister; -use Magento\Quote\Model\Quote\Item\CartItemPersister; use Magento\Quote\Api\Data\CartInterface; use Magento\Framework\Exception\InputException; -use Magento\Quote\Model\ResourceModel\Quote; class SaveHandler { /** - * @var CartItemPersister + * @var \Magento\Quote\Model\Quote\Item\CartItemPersister */ private $cartItemPersister; /** - * @var BillingAddressPersister + * @var \Magento\Quote\Model\Quote\Address\BillingAddressPersister */ private $billingAddressPersister; @@ -30,21 +26,21 @@ class SaveHandler private $quoteResourceModel; /** - * @var ShippingAssignmentPersister + * @var \Magento\Quote\Model\Quote\ShippingAssignment\ShippingAssignmentPersister */ private $shippingAssignmentPersister; /** - * @param Quote $quoteResource - * @param CartItemPersister $cartItemPersister - * @param BillingAddressPersister $billingAddressPersister - * @param ShippingAssignmentPersister $shippingAssignmentPersister + * @param \Magento\Quote\Model\ResourceModel\Quote $quoteResource + * @param \Magento\Quote\Model\Quote\Item\CartItemPersister $cartItemPersister + * @param \Magento\Quote\Model\Quote\Address\BillingAddressPersister $billingAddressPersister + * @param \Magento\Quote\Model\Quote\ShippingAssignment\ShippingAssignmentPersister $shippingAssignmentPersister */ public function __construct( - Quote $quoteResource, - CartItemPersister $cartItemPersister, - BillingAddressPersister $billingAddressPersister, - ShippingAssignmentPersister $shippingAssignmentPersister + \Magento\Quote\Model\ResourceModel\Quote $quoteResource, + \Magento\Quote\Model\Quote\Item\CartItemPersister $cartItemPersister, + \Magento\Quote\Model\Quote\Address\BillingAddressPersister $billingAddressPersister, + \Magento\Quote\Model\Quote\ShippingAssignment\ShippingAssignmentPersister $shippingAssignmentPersister ) { $this->quoteResourceModel = $quoteResource; $this->cartItemPersister = $cartItemPersister; @@ -65,8 +61,9 @@ class SaveHandler { /** @var \Magento\Quote\Model\Quote $quote */ // Quote Item processing - if ($quote->getItems()) { - foreach ($quote->getItems() as $item) { + $items = $quote->getItems(); + if ($items) { + foreach ($items as $item) { /** @var \Magento\Quote\Model\Quote\Item $item */ if (!$item->isDeleted()) { $quote->setLastAddedItem($this->cartItemPersister->save($quote, $item)); @@ -75,20 +72,32 @@ class SaveHandler } // Billing Address processing - if ($quote->getBillingAddress() && $quote->getIsActive()) { - $this->billingAddressPersister->save($quote, $quote->getBillingAddress()); + $billingAddress = $quote->getBillingAddress(); + if ($billingAddress && $quote->getIsActive()) { + $this->billingAddressPersister->save($quote, $billingAddress); } + $this->processShippingAssignment($quote); + + $this->quoteResourceModel->save($quote->collectTotals()); + return $quote; + } + + /** + * @param \Magento\Quote\Model\Quote $quote + * @return void + * @throws InputException + */ + private function processShippingAssignment($quote) + { // Shipping Assignments processing - if ($quote->getExtensionAttributes() && $quote->getExtensionAttributes()->getShippingAssignments()) { - $shippingAssignments = $quote->getExtensionAttributes()->getShippingAssignments(); + $extensionAttributes = $quote->getExtensionAttributes(); + if (!$quote->isVirtual() && $extensionAttributes && $extensionAttributes->getShippingAssignments()) { + $shippingAssignments = $extensionAttributes->getShippingAssignments(); if (count($shippingAssignments) > 1) { throw new InputException(__("Only 1 shipping assignment can be set")); } $this->shippingAssignmentPersister->save($quote, $shippingAssignments[0]); } - - $this->quoteResourceModel->save($quote->collectTotals()); - return $quote; } } diff --git a/app/code/Magento/Quote/Test/Unit/Model/Quote/Address/Total/ShippingTest.php b/app/code/Magento/Quote/Test/Unit/Model/Quote/Address/Total/ShippingTest.php index 47d844093e6219a466e1a7fa83b043f35cf690ab..ae905becfa6d5f0e73dbf5554eaa3b9cc673cb26 100644 --- a/app/code/Magento/Quote/Test/Unit/Model/Quote/Address/Total/ShippingTest.php +++ b/app/code/Magento/Quote/Test/Unit/Model/Quote/Address/Total/ShippingTest.php @@ -200,9 +200,7 @@ class ShippingTest extends \PHPUnit_Framework_TestCase $this->cartItem->expects($this->atLeastOnce()) ->method('getQty') ->willReturn(2); - $this->address->expects($this->once()) - ->method('getFreeShipping') - ->willReturn(true); + $this->freeShippingAssertions(); $this->cartItem->expects($this->once()) ->method('setRowWeight') ->with(0); @@ -255,4 +253,18 @@ class ShippingTest extends \PHPUnit_Framework_TestCase $this->shippingModel->collect($this->quote, $this->shippingAssignment, $this->total); } + + protected function freeShippingAssertions() + { + $this->address->expects($this->at(0)) + ->method('getFreeShipping') + ->willReturn(false); + $this->address->expects($this->at(1)) + ->method('getFreeShipping') + ->willReturn(true); + $this->cartItem->expects($this->atLeastOnce()) + ->method('getFreeShipping') + ->willReturn(true); + + } } diff --git a/app/code/Magento/Quote/Test/Unit/Model/Quote/Item/RepositoryTest.php b/app/code/Magento/Quote/Test/Unit/Model/Quote/Item/RepositoryTest.php index 6c495fb5b29d263ba1e9c5bf7dacd871c78c2ac4..f341bacef4713c939b970e4e7285e97eabe537a0 100644 --- a/app/code/Magento/Quote/Test/Unit/Model/Quote/Item/RepositoryTest.php +++ b/app/code/Magento/Quote/Test/Unit/Model/Quote/Item/RepositoryTest.php @@ -52,6 +52,9 @@ class RepositoryTest extends \PHPUnit_Framework_TestCase /** @var \Magento\Catalog\Model\CustomOptions\CustomOptionProcessor|\PHPUnit_Framework_MockObject_MockObject */ protected $customOptionProcessor; + /** @var \PHPUnit_Framework_MockObject_MockObject */ + protected $shippingAddressMock; + /** * @return void */ @@ -74,6 +77,13 @@ class RepositoryTest extends \PHPUnit_Framework_TestCase '', false ); + $this->shippingAddressMock = $this->getMock( + \Magento\Quote\Model\Quote\Address::class, + ['setCollectShippingRates'], + [], + '', + false + ); $this->repository = new \Magento\Quote\Model\Quote\Item\Repository( $this->quoteRepositoryMock, @@ -176,6 +186,12 @@ class RepositoryTest extends \PHPUnit_Framework_TestCase ->willReturn($this->productMock); $this->quoteMock->expects($this->never())->method('getItemById'); $this->quoteMock->expects($this->once())->method('collectTotals')->will($this->returnValue($this->quoteMock)); + $this->quoteMock->expects($this->once()) + ->method('getShippingAddress') + ->willReturn($this->shippingAddressMock); + $this->shippingAddressMock->expects($this->once()) + ->method('setCollectShippingRates') + ->with(true); $this->quoteRepositoryMock->expects($this->once())->method('save')->with($this->quoteMock); $this->dataMock->expects($this->once())->method('getItemId')->will($this->returnValue(null)); $exceptionMessage = 'Could not save quote'; @@ -223,6 +239,12 @@ class RepositoryTest extends \PHPUnit_Framework_TestCase ->willReturn($this->productMock); $this->quoteMock->expects($this->never())->method('getItemById'); $this->quoteMock->expects($this->once())->method('collectTotals')->will($this->returnValue($this->quoteMock)); + $this->quoteMock->expects($this->once()) + ->method('getShippingAddress') + ->willReturn($this->shippingAddressMock); + $this->shippingAddressMock->expects($this->once()) + ->method('setCollectShippingRates') + ->with(true); $this->quoteRepositoryMock->expects($this->once())->method('save')->with($this->quoteMock); $this->dataMock->expects($this->once())->method('getItemId')->will($this->returnValue(null)); $this->quoteMock @@ -256,6 +278,12 @@ class RepositoryTest extends \PHPUnit_Framework_TestCase ->willReturn($this->productMock); $this->quoteMock->expects($this->never())->method('getItemById'); $this->quoteMock->expects($this->once())->method('collectTotals')->will($this->returnValue($this->quoteMock)); + $this->quoteMock->expects($this->once()) + ->method('getShippingAddress') + ->willReturn($this->shippingAddressMock); + $this->shippingAddressMock->expects($this->once()) + ->method('setCollectShippingRates') + ->with(true); $this->quoteRepositoryMock->expects($this->once())->method('save')->with($this->quoteMock); $this->dataMock->expects($this->once())->method('getItemId')->will($this->returnValue(null)); $this->quoteMock->expects($this->once()) @@ -323,6 +351,12 @@ class RepositoryTest extends \PHPUnit_Framework_TestCase $this->quoteItemMock->expects($this->never())->method('getId'); $exceptionMessage = 'Could not save quote'; $exception = new \Magento\Framework\Exception\CouldNotSaveException(__($exceptionMessage)); + $this->quoteMock->expects($this->once()) + ->method('getShippingAddress') + ->willReturn($this->shippingAddressMock); + $this->shippingAddressMock->expects($this->once()) + ->method('setCollectShippingRates') + ->with(true); $this->quoteRepositoryMock->expects($this->once()) ->method('save') ->with($this->quoteMock) @@ -361,6 +395,12 @@ class RepositoryTest extends \PHPUnit_Framework_TestCase ->expects($this->never())->method('get'); $this->quoteItemMock->expects($this->never())->method('addProduct'); $this->quoteMock->expects($this->once())->method('collectTotals')->will($this->returnValue($this->quoteMock)); + $this->quoteMock->expects($this->once()) + ->method('getShippingAddress') + ->willReturn($this->shippingAddressMock); + $this->shippingAddressMock->expects($this->once()) + ->method('setCollectShippingRates') + ->with(true); $this->quoteRepositoryMock->expects($this->once())->method('save')->with($this->quoteMock); $this->quoteMock ->expects($this->once()) @@ -424,6 +464,12 @@ class RepositoryTest extends \PHPUnit_Framework_TestCase $this->productRepositoryMock ->expects($this->never())->method('get'); $this->quoteMock->expects($this->once())->method('collectTotals')->will($this->returnValue($this->quoteMock)); + $this->quoteMock->expects($this->once()) + ->method('getShippingAddress') + ->willReturn($this->shippingAddressMock); + $this->shippingAddressMock->expects($this->once()) + ->method('setCollectShippingRates') + ->with(true); $this->quoteRepositoryMock->expects($this->once())->method('save')->with($this->quoteMock); $this->quoteMock ->expects($this->once()) diff --git a/app/code/Magento/Quote/Test/Unit/Model/QuoteRepository/SaveHandlerTest.php b/app/code/Magento/Quote/Test/Unit/Model/QuoteRepository/SaveHandlerTest.php new file mode 100644 index 0000000000000000000000000000000000000000..76504b5064a2b987219c7df8dcf0ca61a18e9246 --- /dev/null +++ b/app/code/Magento/Quote/Test/Unit/Model/QuoteRepository/SaveHandlerTest.php @@ -0,0 +1,140 @@ +<?php +/** + * Copyright © 2016 Magento. All rights reserved. + * See COPYING.txt for license details. + */ + +namespace Magento\Quote\Test\Unit\Model\QuoteRepository; + +use Magento\Quote\Model\QuoteRepository\SaveHandler; + +class SaveHandlerTest extends \PHPUnit_Framework_TestCase +{ + /** + * @var SaveHandler + */ + private $saveHandler; + + /** + * @var \PHPUnit_Framework_MockObject_MockObject + */ + private $cartItemPersister; + + /** + * @var \PHPUnit_Framework_MockObject_MockObject + */ + private $billingAddressPersister; + + /** + * @var \PHPUnit_Framework_MockObject_MockObject + */ + private $quoteResourceModel; + + /** + * @var \PHPUnit_Framework_MockObject_MockObject + */ + private $shippingAssignmentPersister; + + /** + * @var \PHPUnit_Framework_MockObject_MockObject + */ + private $quoteMock; + + /** + * @var \PHPUnit_Framework_MockObject_MockObject + */ + private $itemMock; + + /** + * @var \PHPUnit_Framework_MockObject_MockObject + */ + private $billingAddressMock; + + /** + * @var \PHPUnit_Framework_MockObject_MockObject + */ + private $extensionAttributeMock; + + /** + * @var \PHPUnit_Framework_MockObject_MockObject + */ + private $shippingAssignmentMock; + + protected function setUp() + { + $this->quoteResourceModel = $this->getMock(\Magento\Quote\Model\ResourceModel\Quote::class, [], [], '', false); + $this->cartItemPersister = $this->getMock( + \Magento\Quote\Model\Quote\Item\CartItemPersister::class, + [], + [], + '', + false + ); + $this->billingAddressPersister = $this->getMock( + \Magento\Quote\Model\Quote\Address\BillingAddressPersister::class, + [], + [], + '', + false + ); + $this->shippingAssignmentPersister = $this->getMock( + \Magento\Quote\Model\Quote\ShippingAssignment\ShippingAssignmentPersister::class, + [], + [], + '', + false + ); + $methods = [ + 'getItems', 'setLastAddedItem', 'getBillingAddress', 'getIsActive', + 'getExtensionAttributes', 'isVirtual', 'collectTotals' + ]; + $this->quoteMock = $this->getMock(\Magento\Quote\Model\Quote::class, $methods, [], '', false); + $this->itemMock = $this->getMock(\Magento\Quote\Model\Quote\Item::class, [], [], '', false); + $this->billingAddressMock = $this->getMock(\Magento\Quote\Model\Quote\Address::class, [], [], '', false); + $this->extensionAttributeMock = $this->getMock(\Magento\Quote\Api\Data\CartExtensionInterface::class); + $this->shippingAssignmentMock = + $this->getMock( + \Magento\Quote\Api\Data\CartExtension::class, + ['getShippingAssignments', 'setShippingAssignments'], + [], + '', + false + ); + $this->saveHandler = new SaveHandler( + $this->quoteResourceModel, + $this->cartItemPersister, + $this->billingAddressPersister, + $this->shippingAssignmentPersister + ); + + } + + public function testSaveForVirtualQuote() + { + $this->quoteMock->expects($this->once())->method('getItems')->willReturn([$this->itemMock]); + $this->itemMock->expects($this->once())->method('isDeleted')->willReturn(false); + $this->cartItemPersister + ->expects($this->once()) + ->method('save') + ->with($this->quoteMock, $this->itemMock) + ->willReturn($this->itemMock); + $this->quoteMock->expects($this->once())->method('setLastAddedItem')->with($this->itemMock); + $this->quoteMock->expects($this->once())->method('getBillingAddress')->willReturn($this->billingAddressMock); + $this->quoteMock->expects($this->once())->method('getIsActive')->willReturn(true); + $this->billingAddressPersister + ->expects($this->once()) + ->method('save') + ->with($this->quoteMock, $this->billingAddressMock); + $this->quoteMock + ->expects($this->once()) + ->method('getExtensionAttributes') + ->willReturn($this->extensionAttributeMock); + $this->extensionAttributeMock + ->expects($this->never()) + ->method('getShippingAssignments'); + $this->quoteMock->expects($this->once())->method('isVirtual')->willReturn(true); + $this->quoteMock->expects($this->once())->method('collectTotals')->willReturn($this->quoteMock); + $this->quoteResourceModel->expects($this->once())->method('save')->with($this->quoteMock); + $this->assertEquals($this->quoteMock, $this->saveHandler->save($this->quoteMock)); + } +} diff --git a/app/code/Magento/Sales/Model/ResourceModel/Order/Creditmemo/Grid/Collection.php b/app/code/Magento/Sales/Model/ResourceModel/Order/Creditmemo/Grid/Collection.php new file mode 100644 index 0000000000000000000000000000000000000000..d5c0689c140225ebcf3e743602e48a432b0bf3f4 --- /dev/null +++ b/app/code/Magento/Sales/Model/ResourceModel/Order/Creditmemo/Grid/Collection.php @@ -0,0 +1,36 @@ +<?php +/** + * Copyright © 2016 Magento. All rights reserved. + * See COPYING.txt for license details. + */ + +namespace Magento\Sales\Model\ResourceModel\Order\Creditmemo\Grid; + +use Magento\Framework\Data\Collection\Db\FetchStrategyInterface as FetchStrategy; +use Magento\Framework\Data\Collection\EntityFactoryInterface as EntityFactory; +use Magento\Framework\Event\ManagerInterface as EventManager; +use Psr\Log\LoggerInterface as Logger; + +class Collection extends \Magento\Framework\View\Element\UiComponent\DataProvider\SearchResult +{ + /** + * Initialize dependencies. + * + * @param EntityFactory $entityFactory + * @param Logger $logger + * @param FetchStrategy $fetchStrategy + * @param EventManager $eventManager + * @param string $mainTable + * @param string $resourceModel + */ + public function __construct( + EntityFactory $entityFactory, + Logger $logger, + FetchStrategy $fetchStrategy, + EventManager $eventManager, + $mainTable = 'sales_creditmemo_grid', + $resourceModel = '\Magento\Sales\Model\ResourceModel\Order\Creditmemo' + ) { + parent::__construct($entityFactory, $logger, $fetchStrategy, $eventManager, $mainTable, $resourceModel); + } +} diff --git a/app/code/Magento/Sales/Model/ResourceModel/Order/Creditmemo/Order/Grid/Collection.php b/app/code/Magento/Sales/Model/ResourceModel/Order/Creditmemo/Order/Grid/Collection.php new file mode 100644 index 0000000000000000000000000000000000000000..4455879910ac83ddade0510937a61584773606ee --- /dev/null +++ b/app/code/Magento/Sales/Model/ResourceModel/Order/Creditmemo/Order/Grid/Collection.php @@ -0,0 +1,36 @@ +<?php +/** + * Copyright © 2016 Magento. All rights reserved. + * See COPYING.txt for license details. + */ + +namespace Magento\Sales\Model\ResourceModel\Order\Creditmemo\Order\Grid; + +use Magento\Framework\Data\Collection\Db\FetchStrategyInterface as FetchStrategy; +use Magento\Framework\Data\Collection\EntityFactoryInterface as EntityFactory; +use Magento\Framework\Event\ManagerInterface as EventManager; +use Psr\Log\LoggerInterface as Logger; + +class Collection extends \Magento\Framework\View\Element\UiComponent\DataProvider\SearchResult +{ + /** + * Initialize dependencies. + * + * @param EntityFactory $entityFactory + * @param Logger $logger + * @param FetchStrategy $fetchStrategy + * @param EventManager $eventManager + * @param string $mainTable + * @param string $resourceModel + */ + public function __construct( + EntityFactory $entityFactory, + Logger $logger, + FetchStrategy $fetchStrategy, + EventManager $eventManager, + $mainTable = 'sales_creditmemo_grid', + $resourceModel = '\Magento\Sales\Model\ResourceModel\Order\Creditmemo' + ) { + parent::__construct($entityFactory, $logger, $fetchStrategy, $eventManager, $mainTable, $resourceModel); + } +} diff --git a/app/code/Magento/Sales/Model/ResourceModel/Order/Invoice/Grid/Collection.php b/app/code/Magento/Sales/Model/ResourceModel/Order/Invoice/Grid/Collection.php new file mode 100644 index 0000000000000000000000000000000000000000..97a8cda9ab1eb2b3e64a73682dd4971189a2ccb6 --- /dev/null +++ b/app/code/Magento/Sales/Model/ResourceModel/Order/Invoice/Grid/Collection.php @@ -0,0 +1,36 @@ +<?php +/** + * Copyright © 2016 Magento. All rights reserved. + * See COPYING.txt for license details. + */ + +namespace Magento\Sales\Model\ResourceModel\Order\Invoice\Grid; + +use Magento\Framework\Data\Collection\Db\FetchStrategyInterface as FetchStrategy; +use Magento\Framework\Data\Collection\EntityFactoryInterface as EntityFactory; +use Magento\Framework\Event\ManagerInterface as EventManager; +use Psr\Log\LoggerInterface as Logger; + +class Collection extends \Magento\Framework\View\Element\UiComponent\DataProvider\SearchResult +{ + /** + * Initialize dependencies. + * + * @param EntityFactory $entityFactory + * @param Logger $logger + * @param FetchStrategy $fetchStrategy + * @param EventManager $eventManager + * @param string $mainTable + * @param string $resourceModel + */ + public function __construct( + EntityFactory $entityFactory, + Logger $logger, + FetchStrategy $fetchStrategy, + EventManager $eventManager, + $mainTable = 'sales_invoice_grid', + $resourceModel = '\Magento\Sales\Model\ResourceModel\Order\Invoice' + ) { + parent::__construct($entityFactory, $logger, $fetchStrategy, $eventManager, $mainTable, $resourceModel); + } +} diff --git a/app/code/Magento/Sales/Model/ResourceModel/Order/Invoice/Orders/Grid/Collection.php b/app/code/Magento/Sales/Model/ResourceModel/Order/Invoice/Orders/Grid/Collection.php new file mode 100644 index 0000000000000000000000000000000000000000..ae4788c4daea365854e698c25a3041d089d528eb --- /dev/null +++ b/app/code/Magento/Sales/Model/ResourceModel/Order/Invoice/Orders/Grid/Collection.php @@ -0,0 +1,36 @@ +<?php +/** + * Copyright © 2016 Magento. All rights reserved. + * See COPYING.txt for license details. + */ + +namespace Magento\Sales\Model\ResourceModel\Order\Invoice\Orders\Grid; + +use Magento\Framework\Data\Collection\Db\FetchStrategyInterface as FetchStrategy; +use Magento\Framework\Data\Collection\EntityFactoryInterface as EntityFactory; +use Magento\Framework\Event\ManagerInterface as EventManager; +use Psr\Log\LoggerInterface as Logger; + +class Collection extends \Magento\Framework\View\Element\UiComponent\DataProvider\SearchResult +{ + /** + * Initialize dependencies. + * + * @param EntityFactory $entityFactory + * @param Logger $logger + * @param FetchStrategy $fetchStrategy + * @param EventManager $eventManager + * @param string $mainTable + * @param string $resourceModel + */ + public function __construct( + EntityFactory $entityFactory, + Logger $logger, + FetchStrategy $fetchStrategy, + EventManager $eventManager, + $mainTable = 'sales_invoice_grid', + $resourceModel = '\Magento\Sales\Model\ResourceModel\Order\Invoice' + ) { + parent::__construct($entityFactory, $logger, $fetchStrategy, $eventManager, $mainTable, $resourceModel); + } +} diff --git a/app/code/Magento/Sales/Model/ResourceModel/Order/Shipment/Grid/Collection.php b/app/code/Magento/Sales/Model/ResourceModel/Order/Shipment/Grid/Collection.php new file mode 100644 index 0000000000000000000000000000000000000000..f3141f521623fdb35e0f5e921636bdb68ae9e2cb --- /dev/null +++ b/app/code/Magento/Sales/Model/ResourceModel/Order/Shipment/Grid/Collection.php @@ -0,0 +1,36 @@ +<?php +/** + * Copyright © 2016 Magento. All rights reserved. + * See COPYING.txt for license details. + */ + +namespace Magento\Sales\Model\ResourceModel\Order\Shipment\Grid; + +use Magento\Framework\Data\Collection\Db\FetchStrategyInterface as FetchStrategy; +use Magento\Framework\Data\Collection\EntityFactoryInterface as EntityFactory; +use Magento\Framework\Event\ManagerInterface as EventManager; +use Psr\Log\LoggerInterface as Logger; + +class Collection extends \Magento\Framework\View\Element\UiComponent\DataProvider\SearchResult +{ + /** + * Initialize dependencies. + * + * @param EntityFactory $entityFactory + * @param Logger $logger + * @param FetchStrategy $fetchStrategy + * @param EventManager $eventManager + * @param string $mainTable + * @param string $resourceModel + */ + public function __construct( + EntityFactory $entityFactory, + Logger $logger, + FetchStrategy $fetchStrategy, + EventManager $eventManager, + $mainTable = 'sales_shipment_grid', + $resourceModel = '\Magento\Sales\Model\ResourceModel\Order\Shipment' + ) { + parent::__construct($entityFactory, $logger, $fetchStrategy, $eventManager, $mainTable, $resourceModel); + } +} diff --git a/app/code/Magento/Sales/Model/ResourceModel/Order/Shipment/Order/Grid/Collection.php b/app/code/Magento/Sales/Model/ResourceModel/Order/Shipment/Order/Grid/Collection.php new file mode 100644 index 0000000000000000000000000000000000000000..941b510a7f6320fe978a50904ef0cc74b99e85c5 --- /dev/null +++ b/app/code/Magento/Sales/Model/ResourceModel/Order/Shipment/Order/Grid/Collection.php @@ -0,0 +1,36 @@ +<?php +/** + * Copyright © 2016 Magento. All rights reserved. + * See COPYING.txt for license details. + */ + +namespace Magento\Sales\Model\ResourceModel\Order\Shipment\Order\Grid; + +use Magento\Framework\Data\Collection\Db\FetchStrategyInterface as FetchStrategy; +use Magento\Framework\Data\Collection\EntityFactoryInterface as EntityFactory; +use Magento\Framework\Event\ManagerInterface as EventManager; +use Psr\Log\LoggerInterface as Logger; + +class Collection extends \Magento\Framework\View\Element\UiComponent\DataProvider\SearchResult +{ + /** + * Initialize dependencies. + * + * @param EntityFactory $entityFactory + * @param Logger $logger + * @param FetchStrategy $fetchStrategy + * @param EventManager $eventManager + * @param string $mainTable + * @param string $resourceModel + */ + public function __construct( + EntityFactory $entityFactory, + Logger $logger, + FetchStrategy $fetchStrategy, + EventManager $eventManager, + $mainTable = 'sales_shipment_grid', + $resourceModel = '\Magento\Sales\Model\ResourceModel\Order\Shipment' + ) { + parent::__construct($entityFactory, $logger, $fetchStrategy, $eventManager, $mainTable, $resourceModel); + } +} diff --git a/app/code/Magento/Sales/etc/di.xml b/app/code/Magento/Sales/etc/di.xml index 32c1a17c90dfefc4a75e7c21abda71fb0ac3d2eb..209e46c3240b675f32622f3547331856bf87a1eb 100644 --- a/app/code/Magento/Sales/etc/di.xml +++ b/app/code/Magento/Sales/etc/di.xml @@ -780,42 +780,6 @@ <argument name="state" xsi:type="object">Magento\Framework\App\State\Proxy</argument> </arguments> </type> - <virtualType name="Magento\Sales\Model\ResourceModel\Order\Invoice\Grid\Collection" type="Magento\Framework\View\Element\UiComponent\DataProvider\SearchResult"> - <arguments> - <argument name="mainTable" xsi:type="string">sales_invoice_grid</argument> - <argument name="resourceModel" xsi:type="string">Magento\Sales\Model\ResourceModel\Order\Invoice</argument> - </arguments> - </virtualType> - <virtualType name="Magento\Sales\Model\ResourceModel\Order\Shipment\Grid\Collection" type="Magento\Framework\View\Element\UiComponent\DataProvider\SearchResult"> - <arguments> - <argument name="mainTable" xsi:type="string">sales_shipment_grid</argument> - <argument name="resourceModel" xsi:type="string">Magento\Sales\Model\ResourceModel\Order\Shipment</argument> - </arguments> - </virtualType> - <virtualType name="Magento\Sales\Model\ResourceModel\Order\Creditmemo\Grid\Collection" type="Magento\Framework\View\Element\UiComponent\DataProvider\SearchResult"> - <arguments> - <argument name="mainTable" xsi:type="string">sales_creditmemo_grid</argument> - <argument name="resourceModel" xsi:type="string">Magento\Sales\Model\ResourceModel\Order\Creditmemo</argument> - </arguments> - </virtualType> - <virtualType name="Magento\Sales\Model\ResourceModel\Order\Invoice\Orders\Grid\Collection" type="Magento\Framework\View\Element\UiComponent\DataProvider\SearchResult"> - <arguments> - <argument name="mainTable" xsi:type="string">sales_invoice_grid</argument> - <argument name="resourceModel" xsi:type="string">Magento\Sales\Model\ResourceModel\Order\Invoice</argument> - </arguments> - </virtualType> - <virtualType name="Magento\Sales\Model\ResourceModel\Order\Shipment\Order\Grid\Collection" type="Magento\Framework\View\Element\UiComponent\DataProvider\SearchResult"> - <arguments> - <argument name="mainTable" xsi:type="string">sales_shipment_grid</argument> - <argument name="resourceModel" xsi:type="string">Magento\Sales\Model\ResourceModel\Order\Shipment</argument> - </arguments> - </virtualType> - <virtualType name="Magento\Sales\Model\ResourceModel\Order\Creditmemo\Order\Grid\Collection" type="Magento\Framework\View\Element\UiComponent\DataProvider\SearchResult"> - <arguments> - <argument name="mainTable" xsi:type="string">sales_creditmemo_grid</argument> - <argument name="resourceModel" xsi:type="string">Magento\Sales\Model\ResourceModel\Order\Creditmemo</argument> - </arguments> - </virtualType> <virtualType name="orderMetadata" type="Magento\Sales\Model\ResourceModel\Metadata"> <arguments> <argument name="resourceClassName" xsi:type="string">Magento\Sales\Model\ResourceModel\Order</argument> diff --git a/app/code/Magento/Tax/Block/Checkout/Shipping/Price.php b/app/code/Magento/Tax/Block/Checkout/Shipping/Price.php index de762ec60c0e5305959dbc57f43611ed645d44fb..47712fe4894d944dca587f2b9bd811d299d5c47a 100644 --- a/app/code/Magento/Tax/Block/Checkout/Shipping/Price.php +++ b/app/code/Magento/Tax/Block/Checkout/Shipping/Price.php @@ -7,6 +7,10 @@ namespace Magento\Tax\Block\Checkout\Shipping; use Magento\Framework\Pricing\PriceCurrencyInterface; +/** + * Class Price + * @deprecated + */ class Price extends \Magento\Checkout\Block\Shipping\Price { /** diff --git a/app/code/Magento/Tax/Model/Config/Price/IncludePrice.php b/app/code/Magento/Tax/Model/Config/Price/IncludePrice.php index 3a3c9b2b3bc680d628237abe167cdc74719749ac..40030a70e62b8ed7c833b945d6e91382b3949bb4 100644 --- a/app/code/Magento/Tax/Model/Config/Price/IncludePrice.php +++ b/app/code/Magento/Tax/Model/Config/Price/IncludePrice.php @@ -8,11 +8,13 @@ namespace Magento\Tax\Model\Config\Price; class IncludePrice extends \Magento\Framework\App\Config\Value { /** - * @return void + * @return $this */ public function afterSave() { - parent::afterSave(); + $result = parent::afterSave(); $this->_cacheManager->clean(['checkout_quote']); + + return $result; } } diff --git a/app/code/Magento/Tax/view/frontend/layout/checkout_shipping_price_renderer.xml b/app/code/Magento/Tax/view/frontend/layout/checkout_shipping_price_renderer.xml deleted file mode 100644 index c2a5428cc5beabe2cc41f76372bbc1957b64e477..0000000000000000000000000000000000000000 --- a/app/code/Magento/Tax/view/frontend/layout/checkout_shipping_price_renderer.xml +++ /dev/null @@ -1,12 +0,0 @@ -<?xml version="1.0"?> -<!-- -/** - * Copyright © 2016 Magento. All rights reserved. - * See COPYING.txt for license details. - */ ---> -<page xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:View/Layout/etc/page_configuration.xsd"> - <body> - <block class="Magento\Tax\Block\Checkout\Shipping\Price" name="checkout.shipping.price" as="shipping.price" template="Magento_Tax::checkout/shipping/price.phtml"/> - </body> -</page> diff --git a/app/code/Magento/Theme/view/base/requirejs-config.js b/app/code/Magento/Theme/view/base/requirejs-config.js index 6d71b3b36d13f792b4e557b0a7a3a89e5b9755e9..abe587777dd9c0f0b786faffcb09686d3f6378a4 100644 --- a/app/code/Magento/Theme/view/base/requirejs-config.js +++ b/app/code/Magento/Theme/view/base/requirejs-config.js @@ -51,7 +51,14 @@ var config = { }, "deps": [ "jquery/jquery-migrate" - ] + ], + "config": { + "mixins": { + "jquery/jstree/jquery.jstree": { + "mage/backend/jstree-mixin": true + } + } + } }; require(['jquery'], function ($) { diff --git a/app/code/Magento/Ui/view/base/web/js/form/element/wysiwyg.js b/app/code/Magento/Ui/view/base/web/js/form/element/wysiwyg.js index 6d7c937f62ee051f7994ab7a54b4464bfa2f4d02..b3db5d11b98a51bc166082a10ae351949f317d9c 100644 --- a/app/code/Magento/Ui/view/base/web/js/form/element/wysiwyg.js +++ b/app/code/Magento/Ui/view/base/web/js/form/element/wysiwyg.js @@ -2,6 +2,7 @@ * Copyright © 2016 Magento. All rights reserved. * See COPYING.txt for license details. */ + define([ 'Magento_Ui/js/lib/view/utils/async', 'underscore', diff --git a/app/code/Magento/Ui/view/base/web/templates/form/components/single/radio.html b/app/code/Magento/Ui/view/base/web/templates/form/components/single/radio.html index 0cd5828e6ce5c9d2ad20357326e4cfd92ea10d99..0328957c8f6efa6df49c990f9f23571b02e7efba 100644 --- a/app/code/Magento/Ui/view/base/web/templates/form/components/single/radio.html +++ b/app/code/Magento/Ui/view/base/web/templates/form/components/single/radio.html @@ -12,7 +12,7 @@ ko-focused="focused" ko-value="value" keyboard="keyboard" - attr="id: uid, name: inputName"/> + attr="id: uid, name: inputName, 'data-index': index"/> <label class="admin__field-label" text="description" attr="for: uid"/> </div> 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 ac5a6aea6b7c4fe1294bfb2c07345150515b5296..6c4156291d3219fdb96552feb9218181db4c32e7 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> + <css src="jquery/jstree/themes/default/style.css"/> <css src="css/styles-old.css"/> <css src="css/styles.css"/> </head> 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 9a23471f828bd61393ba0aee53abeb4c44b2ef85..187712e090aa1c58d508d2b0853f15b3b65ebf17 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 @@ -320,6 +320,32 @@ cursor: not-allowed; } +// ToDo: remove after "Product Attributes Mass update" implementation +.attributes-edit-form { + .field { + .control { + input[type='text'][disabled] ~ .addafter, + select[disabled] ~ .addafter, + .attribute-change-checkbox { + background: none; + color: #676056; + cursor: inherit; + opacity: 1; + + strong { + background: none; + } + } + } + } + + .weight-switcher { + .addafter { + margin-top: 30px; + } + } +} + .field .control input[type='text'][disabled] ~ .addafter strong, .field .control select[disabled] ~ .addafter strong { background-color: #e9e9e9; 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 7c758b5ddca71e5d511d01b5b38a47bd57d4daa6..abc9067338072dead69a9b1e2f2f13bb9cba691f 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 @@ -241,6 +241,8 @@ option:empty { } .admin__control-text { + margin: .1rem; + padding: @field-control__padding-top - .1rem @field-control__padding-horizontal - .1rem @field-control__padding-bottom - .1rem; width: 100%; } 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 613c55cebc297b1b363c67f92aa3e7253781e003..28cae989ae50a4641be6eb568536fcdcfcd5abca 100644 --- a/app/design/adminhtml/Magento/backend/web/css/styles-old.less +++ b/app/design/adminhtml/Magento/backend/web/css/styles-old.less @@ -887,6 +887,7 @@ background-color: #e9e9e9; border-color: #adadad; opacity: .5; + &.admin__control-checkbox, &.admin__control-radio { opacity: 0.01; @@ -1387,6 +1388,7 @@ line-height: 1.33; vertical-align: middle; white-space: normal; + word-break: break-all; &[data-config-scope] { position: relative; diff --git a/dev/tests/functional/tests/app/Magento/Bundle/Test/Fixture/Cart/Item.php b/dev/tests/functional/tests/app/Magento/Bundle/Test/Fixture/Cart/Item.php index ee78eb61c5572f132017810cf6ed54d81f1eee78..cb46e728191bffb5a770a2809019fb2833f9f0d3 100644 --- a/dev/tests/functional/tests/app/Magento/Bundle/Test/Fixture/Cart/Item.php +++ b/dev/tests/functional/tests/app/Magento/Bundle/Test/Fixture/Cart/Item.php @@ -53,7 +53,7 @@ class Item extends \Magento\Catalog\Test\Fixture\Cart\Item $bundleOptions = $bundleSelection['bundle_options'][$attributeKey]; $value = $bundleSelectionAttribute[$optionKey]->getName(); $qty = $bundleOptions['assigned_products'][$optionKey]['data']['selection_qty']; - $price = $product->getPriceType() == 'Dynamic' + $price = $product->getPriceType() == 'Yes' ? number_format($bundleSelectionAttribute[$optionKey]->getPrice(), 2) : number_format($bundleOptions['assigned_products'][$optionKey]['data']['selection_price_value'], 2); $optionData = [ diff --git a/dev/tests/functional/tests/app/Magento/Bundle/Test/Handler/BundleProduct/Curl.php b/dev/tests/functional/tests/app/Magento/Bundle/Test/Handler/BundleProduct/Curl.php index 28fb86de9ffeb2e193177b9eda6282710bb43135..4a4aea603cf8619d0d12335f496b1e6a9e50fd33 100644 --- a/dev/tests/functional/tests/app/Magento/Bundle/Test/Handler/BundleProduct/Curl.php +++ b/dev/tests/functional/tests/app/Magento/Bundle/Test/Handler/BundleProduct/Curl.php @@ -98,7 +98,7 @@ class Curl extends ProductCurl implements BundleProductInterface parent::prepareProductDetails(); if (!isset($this->fields['product']['price_type'])) { - $this->fields['product']['price_type'] = 'Dynamic'; + $this->fields['product']['price_type'] = 'Yes'; } } diff --git a/dev/tests/functional/tests/app/Magento/Catalog/Test/Block/Adminhtml/Product/Attribute/AttributeForm.php b/dev/tests/functional/tests/app/Magento/Catalog/Test/Block/Adminhtml/Product/Attribute/AttributeForm.php index 5568040980de8c3a3b3660ceb77f10a04d54ce17..ad4d946f850347d987870594aa4201df27970381 100644 --- a/dev/tests/functional/tests/app/Magento/Catalog/Test/Block/Adminhtml/Product/Attribute/AttributeForm.php +++ b/dev/tests/functional/tests/app/Magento/Catalog/Test/Block/Adminhtml/Product/Attribute/AttributeForm.php @@ -6,25 +6,15 @@ namespace Magento\Catalog\Test\Block\Adminhtml\Product\Attribute; -use Magento\Backend\Test\Block\Widget\FormTabs; -use Magento\Backend\Test\Block\Widget\Tab; -use Magento\Mtf\Client\Element; +use Magento\Ui\Test\Block\Adminhtml\FormSections; use Magento\Mtf\Client\Element\SimpleElement; -use Magento\Mtf\Client\Locator; use Magento\Mtf\Fixture\FixtureInterface; /** * Edit attribute form on catalog product edit page. */ -class AttributeForm extends FormTabs +class AttributeForm extends FormSections { - /** - * Iframe locator. - * - * @var string - */ - protected $iFrame = '#create_new_attribute_container'; - /** * Save button selector. * @@ -32,24 +22,6 @@ class AttributeForm extends FormTabs */ protected $saveButton = '#save'; - /** - * Attribute to determine whether tab is opened. - * - * @var string - */ - protected $isTabOpened = '.opened '; - - /** - * Initialize block. Switch to frame. - * - * @return void - */ - protected function init() - { - parent::init(); - $this->browser->switchToFrame(new Locator($this->iFrame)); - } - /** * Fill the attribute form. * @@ -67,28 +39,6 @@ class AttributeForm extends FormTabs } ); parent::fill($fixture, $element); - $this->browser->switchToFrame(); - } - - /** - * Open tab. - * - * @param string $tabName - * @return Tab - */ - public function openTab($tabName) - { - $selector = $this->getTabs()[$tabName]['selector']; - $strategy = isset($this->getTabs()[$tabName]['strategy']) - ? $this->getTabs()[$tabName]['strategy'] - : Locator::SELECTOR_CSS; - - $isTabOpened = $this->_rootElement->find($this->isTabOpened . $selector, $strategy); - if (!$isTabOpened->isVisible()) { - $this->_rootElement->find($selector, $strategy)->click(); - } - - return $this; } /** diff --git a/dev/tests/functional/tests/app/Magento/Catalog/Test/Block/Adminhtml/Product/Attribute/AttributeForm.xml b/dev/tests/functional/tests/app/Magento/Catalog/Test/Block/Adminhtml/Product/Attribute/AttributeForm.xml index 5c5cf01bd9b907c70381ff9ecd2b729f046e73b4..bd1354d51a28cd1277714aab54849dae53de9c05 100644 --- a/dev/tests/functional/tests/app/Magento/Catalog/Test/Block/Adminhtml/Product/Attribute/AttributeForm.xml +++ b/dev/tests/functional/tests/app/Magento/Catalog/Test/Block/Adminhtml/Product/Attribute/AttributeForm.xml @@ -5,10 +5,10 @@ * See COPYING.txt for license details. */ --> -<tabs> +<sections> <properties> - <class>\Magento\Backend\Test\Block\Widget\Tab</class> - <selector>#edit_form</selector> + <class>\Magento\Ui\Test\Block\Adminhtml\Section</class> + <selector>.product_form_product_form_add_attribute_modal_create_new_attribute_modal_product_attribute_add_form</selector> <strategy>css selector</strategy> <fields> <frontend_label> @@ -18,36 +18,32 @@ <input>select</input> </frontend_input> <is_required> - <input>select</input> + <input>switcher</input> </is_required> <options> <class>\Magento\Catalog\Test\Block\Adminhtml\Product\Attribute\Edit\Options</class> - <selector>#manage-options-panel</selector> + <selector>[data-index="attribute_options_select_container"]</selector> <strategy>css selector</strategy> </options> </fields> </properties> <advanced-properties> - <class>\Magento\Backend\Test\Block\Widget\Tab</class> - <selector>[data-target="#advanced_fieldset-content"]</selector> + <class>\Magento\Ui\Test\Block\Adminhtml\Section</class> + <selector>[data-index="advanced_fieldset"]</selector> <strategy>css selector</strategy> <fields> - <attribute_code> - </attribute_code> + <attribute_code/> <is_global> <input>select</input> </is_global> - <default_value> - <selector>[name^='default_value_']</selector> - </default_value> <is_unique> - <input>select</input> + <input>switcher</input> </is_unique> </fields> </advanced-properties> <manage-labels> - <class>\Magento\Backend\Test\Block\Widget\Tab</class> - <selector>[data-target="#manage-titles-content"]</selector> + <class>\Magento\Ui\Test\Block\Adminhtml\Section</class> + <selector>[data-index="manage-titles"]</selector> <strategy>css selector</strategy> <fields> <manage_frontend_label> @@ -56,40 +52,40 @@ </fields> </manage-labels> <frontend-properties> - <class>\Magento\Backend\Test\Block\Widget\Tab</class> - <selector>[data-target="#front_fieldset-content"]</selector> + <class>\Magento\Ui\Test\Block\Adminhtml\Section</class> + <selector>[data-index="front_fieldset"]</selector> <strategy>css selector</strategy> <fields> <is_searchable> - <input>select</input> + <input>switcher</input> </is_searchable> <is_visible_in_advanced_search> - <input>select</input> + <input>switcher</input> </is_visible_in_advanced_search> <is_comparable> - <input>select</input> + <input>switcher</input> </is_comparable> <is_filterable> <input>select</input> </is_filterable> <is_filterable_in_search> - <input>select</input> + <input>switcher</input> </is_filterable_in_search> <is_used_for_promo_rules> - <input>select</input> + <input>switcher</input> </is_used_for_promo_rules> <is_html_allowed_on_front> - <input>select</input> + <input>switcher</input> </is_html_allowed_on_front> <is_visible_on_front> - <input>select</input> + <input>switcher</input> </is_visible_on_front> <used_in_product_listing> - <input>select</input> + <input>switcher</input> </used_in_product_listing> <used_for_sort_by> - <input>select</input> + <input>switcher</input> </used_for_sort_by> </fields> </frontend-properties> -</tabs> +</sections> diff --git a/dev/tests/functional/tests/app/Magento/Catalog/Test/Block/Adminhtml/Product/Attribute/CustomAttribute.php b/dev/tests/functional/tests/app/Magento/Catalog/Test/Block/Adminhtml/Product/Attribute/CustomAttribute.php index 926d04335665cf35ffb7e6c23786bcfd13a56319..91d722f8ef4eb3e3404214a5827c74b76bb48eb3 100644 --- a/dev/tests/functional/tests/app/Magento/Catalog/Test/Block/Adminhtml/Product/Attribute/CustomAttribute.php +++ b/dev/tests/functional/tests/app/Magento/Catalog/Test/Block/Adminhtml/Product/Attribute/CustomAttribute.php @@ -19,7 +19,7 @@ class CustomAttribute extends SimpleElement * * @var string */ - protected $inputSelector = '.control [name]:not([type="hidden"]), table'; + protected $inputSelector = '[name="product[%s]"]'; /** * Attribute class to element type reference. @@ -27,11 +27,12 @@ class CustomAttribute extends SimpleElement * @var array */ protected $classReference = [ - 'input-text' => null, + 'admin__control-text' => null, 'textarea' => null, 'hasDatepicker' => 'datepicker', - 'select' => 'select', - 'multiselect' => 'multiselect', + 'admin__control-select' => 'select', + 'admin__control-multiselect' => 'multiselect', + 'admin__actions-switch-checkbox' => 'switcher' ]; /** @@ -43,10 +44,11 @@ class CustomAttribute extends SimpleElement public function setValue($data) { $this->eventManager->dispatchEvent(['set_value'], [__METHOD__, $this->getAbsoluteSelector()]); - $element = $this->getElementByClass($this->getElementClass()); + $code = isset($data['code']) ? $data['code'] : $this->getAttributeCode($this->getAbsoluteSelector()); + $element = $this->getElementByClass($this->getElementClass($code)); $value = is_array($data) ? $data['value'] : $data; if ($value !== null) { - $this->find($this->inputSelector, Locator::SELECTOR_CSS, $element)->setValue($value); + $this->find(sprintf($this->inputSelector, $code), Locator::SELECTOR_CSS, $element)->setValue($value); } } @@ -58,8 +60,9 @@ class CustomAttribute extends SimpleElement public function getValue() { $this->eventManager->dispatchEvent(['get_value'], [__METHOD__, $this->getAbsoluteSelector()]); - $inputType = $this->getElementByClass($this->getElementClass()); - return $this->find($this->inputSelector, Locator::SELECTOR_CSS, $inputType)->getValue(); + $code = $this->getAttributeCode($this->getAbsoluteSelector()); + $inputType = $this->getElementByClass($this->getElementClass($code)); + return $this->find(sprintf($this->inputSelector, $code), Locator::SELECTOR_CSS, $inputType)->getValue(); } /** @@ -68,7 +71,7 @@ class CustomAttribute extends SimpleElement * @param string $class * @return string */ - protected function getElementByClass($class) + private function getElementByClass($class) { $element = null; foreach ($this->classReference as $key => $reference) { @@ -82,10 +85,25 @@ class CustomAttribute extends SimpleElement /** * Get element class. * + * @param string $code * @return string */ - protected function getElementClass() + private function getElementClass($code) { - return $this->find($this->inputSelector, Locator::SELECTOR_CSS)->getAttribute('class'); + return $this->find(sprintf($this->inputSelector, $code), Locator::SELECTOR_CSS)->getAttribute('class'); + } + + /** + * Get attribute code. + * + * @param string $attributeSelector + * @return string + */ + private function getAttributeCode($attributeSelector) + { + preg_match('/data-index="(.*)"/', $attributeSelector, $matches); + $code = !empty($matches[1]) ? $matches[1] : ''; + + return $code; } } diff --git a/dev/tests/functional/tests/app/Magento/Catalog/Test/Block/Adminhtml/Product/Attribute/Edit/Options.php b/dev/tests/functional/tests/app/Magento/Catalog/Test/Block/Adminhtml/Product/Attribute/Edit/Options.php index 657166f1e184928c0cde9ac35c2bf35be7827f76..8c1f41f907e4889a7f9769ddcfe2d0f3da2502e6 100644 --- a/dev/tests/functional/tests/app/Magento/Catalog/Test/Block/Adminhtml/Product/Attribute/Edit/Options.php +++ b/dev/tests/functional/tests/app/Magento/Catalog/Test/Block/Adminhtml/Product/Attribute/Edit/Options.php @@ -20,14 +20,14 @@ class Options extends SimpleElement * * @var string */ - protected $addOption = '#add_new_option_button'; + protected $addOption = 'button[data-action="add_new_row"]'; /** * Option form selector. * * @var string */ - protected $option = '.ui-sortable tr'; + protected $option = '[data-index="attribute_options_select"] tbody tr'; /** * Set value. diff --git a/dev/tests/functional/tests/app/Magento/Catalog/Test/Block/Adminhtml/Product/Edit/Section/Attributes.php b/dev/tests/functional/tests/app/Magento/Catalog/Test/Block/Adminhtml/Product/Edit/Section/Attributes.php index 4070630c913262ef332937834b506c5d50fc87b9..68bf3fe0d5069fd3eee1a3f6c480e70c7f4f3d68 100644 --- a/dev/tests/functional/tests/app/Magento/Catalog/Test/Block/Adminhtml/Product/Edit/Section/Attributes.php +++ b/dev/tests/functional/tests/app/Magento/Catalog/Test/Block/Adminhtml/Product/Edit/Section/Attributes.php @@ -6,8 +6,6 @@ namespace Magento\Catalog\Test\Block\Adminhtml\Product\Edit\Section; -use Magento\Mtf\Client\Locator; -use Magento\Catalog\Test\Block\Adminhtml\Product\Attribute\Edit; use Magento\Ui\Test\Block\Adminhtml\Section; /** @@ -15,27 +13,6 @@ use Magento\Ui\Test\Block\Adminhtml\Section; */ class Attributes extends Section { - /** - * Attribute Search locator the Product page. - * - * @var string - */ - protected $attributeSearch = "//div[contains(@data-role, 'product-details')]//*[@data-toggle='dropdown']/span"; - - /** - * Selector for 'New Attribute' button. - * - * @var string - */ - protected $newAttributeButton = '[id^="create_attribute"]'; - - /** - * Selector for search input field. - * - * @var string - */ - protected $searchAttribute = "//input[@data-role='product-attribute-search']"; - /** * Fixture mapping. * @@ -51,33 +28,4 @@ class Attributes extends Section } return parent::dataMapping($fields, $parent); } - - /** - * Click on 'New Attribute' button. - * - * @param string $tabName - * @return void - */ - public function addNewAttribute($tabName) - { - $element = $this->_rootElement; - $selector = sprintf($this->attributeSearch, $tabName); - $element->waitUntil( - function () use ($element, $selector) { - return $element->find($selector, Locator::SELECTOR_XPATH)->isVisible() ? true : null; - } - ); - $addAttributeToggle = $element->find($selector, Locator::SELECTOR_XPATH); - $addAttributeToggle->click(); - if (!$addAttributeToggle->find($this->newAttributeButton)->isVisible()) { - $element->find($this->searchAttribute, Locator::SELECTOR_XPATH)->click(); - $this->browser->waitUntil( - function () { - $element = $this->browser->find($this->searchAttribute, Locator::SELECTOR_XPATH); - return $element->isVisible() == true ? true : null; - } - ); - } - $element->find($this->newAttributeButton)->click(); - } } diff --git a/dev/tests/functional/tests/app/Magento/Catalog/Test/Block/Adminhtml/Product/Edit/Section/Attributes/Grid.php b/dev/tests/functional/tests/app/Magento/Catalog/Test/Block/Adminhtml/Product/Edit/Section/Attributes/Grid.php new file mode 100644 index 0000000000000000000000000000000000000000..c10d6c2a18fa7f591496a6f98dd2a70f1662bb5b --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Catalog/Test/Block/Adminhtml/Product/Edit/Section/Attributes/Grid.php @@ -0,0 +1,26 @@ +<?php +/** + * Copyright © 2016 Magento. All rights reserved. + * See COPYING.txt for license details. + */ + +namespace Magento\Catalog\Test\Block\Adminhtml\Product\Edit\Section\Attributes; + +use Magento\Ui\Test\Block\Adminhtml\DataGrid; + +/** + * Product attributes grid. + */ +class Grid extends DataGrid +{ + /** + * Grid fields map + * + * @var array + */ + protected $filters = [ + 'label' => [ + 'selector' => '[name="frontend_label"]', + ] + ]; +} diff --git a/dev/tests/functional/tests/app/Magento/Catalog/Test/Block/Adminhtml/Product/Edit/Section/Options/Type/DropDown.php b/dev/tests/functional/tests/app/Magento/Catalog/Test/Block/Adminhtml/Product/Edit/Section/Options/Type/DropDown.php index 1e433a329ec42cc136c1eefc2b984294792c7670..0dfb865d05aae09ee9e18e8278d58ee01b10bb01 100644 --- a/dev/tests/functional/tests/app/Magento/Catalog/Test/Block/Adminhtml/Product/Edit/Section/Options/Type/DropDown.php +++ b/dev/tests/functional/tests/app/Magento/Catalog/Test/Block/Adminhtml/Product/Edit/Section/Options/Type/DropDown.php @@ -21,13 +21,6 @@ class DropDown extends AbstractOptions */ protected $addValueButton = '[data-action="add_new_row"]'; - /** - * Title column locator. - * - * @var string - */ - protected $optionTitle = '[data-name="title"]'; - /** * Fill the form. * @@ -37,7 +30,6 @@ class DropDown extends AbstractOptions */ public function fillOptions(array $fields, SimpleElement $element = null) { - $this->_rootElement->find($this->optionTitle)->click(); $this->_rootElement->find($this->addValueButton)->click(); return parent::fillOptions($fields, $element); diff --git a/dev/tests/functional/tests/app/Magento/Catalog/Test/Block/Adminhtml/Product/Edit/Section/ProductDetails.php b/dev/tests/functional/tests/app/Magento/Catalog/Test/Block/Adminhtml/Product/Edit/Section/ProductDetails.php index 49c2c786d9afe9663f5cfc7ea08fbe449fd86c52..e0c1df99391052cd9681611eec895db60f790168 100644 --- a/dev/tests/functional/tests/app/Magento/Catalog/Test/Block/Adminhtml/Product/Edit/Section/ProductDetails.php +++ b/dev/tests/functional/tests/app/Magento/Catalog/Test/Block/Adminhtml/Product/Edit/Section/ProductDetails.php @@ -6,7 +6,6 @@ namespace Magento\Catalog\Test\Block\Adminhtml\Product\Edit\Section; -use Magento\Catalog\Test\Fixture\Category; use Magento\Ui\Test\Block\Adminhtml\Section; use Magento\Mtf\Client\Element\SimpleElement; @@ -21,6 +20,7 @@ class ProductDetails extends Section * @var string */ protected $categoryIds = '.admin__field[data-index="category_ids"]'; + /** * Locator for following sibling of category element. * @@ -28,6 +28,22 @@ class ProductDetails extends Section */ protected $newCategoryRootElement = '.product_form_product_form_create_category_modal'; + /** + * Fixture mapping. + * + * @param array|null $fields + * @param string|null $parent + * @return array + */ + protected function dataMapping(array $fields = null, $parent = null) + { + if (isset($fields['custom_attribute'])) { + $this->placeholders = ['attribute_code' => $fields['custom_attribute']['value']['code']]; + $this->applyPlaceholders(); + } + return parent::dataMapping($fields, $parent); + } + /** * Fill data to fields on section. * diff --git a/dev/tests/functional/tests/app/Magento/Catalog/Test/Block/Adminhtml/Product/FormPageActions.php b/dev/tests/functional/tests/app/Magento/Catalog/Test/Block/Adminhtml/Product/FormPageActions.php index 3306bd4f870c6eaf1b8e811db9bf760ae1d47c21..decc7996a7e1e7e97c46fb5d711deb7005dd4bcc 100644 --- a/dev/tests/functional/tests/app/Magento/Catalog/Test/Block/Adminhtml/Product/FormPageActions.php +++ b/dev/tests/functional/tests/app/Magento/Catalog/Test/Block/Adminhtml/Product/FormPageActions.php @@ -51,6 +51,13 @@ class FormPageActions extends ParentFormPageActions */ protected $saveButton = '[data-ui-id="save-button"]'; + /** + * "Add Attribute" button. + * + * @var string + */ + private $addAttribute = '[data-ui-id="addattribute-button"]'; + /** * Click on "Save" button. * @@ -105,4 +112,14 @@ class FormPageActions extends ParentFormPageActions $this->_rootElement->find($this->toggleButton, Locator::SELECTOR_CSS)->click(); $this->_rootElement->find(sprintf($this->saveTypeItem, static::SAVE_CLOSE), Locator::SELECTOR_CSS)->click(); } + + /** + * Click "Add Attribute" button. + * + * @return void + */ + public function addNewAttribute() + { + $this->_rootElement->find($this->addAttribute)->click(); + } } diff --git a/dev/tests/functional/tests/app/Magento/Catalog/Test/Block/Adminhtml/Product/Modal/AddAttribute.php b/dev/tests/functional/tests/app/Magento/Catalog/Test/Block/Adminhtml/Product/Modal/AddAttribute.php new file mode 100644 index 0000000000000000000000000000000000000000..c30ee5ee9442809a38229bd3a9148fd1123b3b82 --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Catalog/Test/Block/Adminhtml/Product/Modal/AddAttribute.php @@ -0,0 +1,32 @@ +<?php +/** + * Copyright © 2016 Magento. All rights reserved. + * See COPYING.txt for license details. + */ + +namespace Magento\Catalog\Test\Block\Adminhtml\Product\Modal; + +use Magento\Ui\Test\Block\Adminhtml\FormSections; + +/** + * Add new attribute modal. + */ +class AddAttribute extends FormSections +{ + /** + * Selector for "Create New Attribute" button. + * + * @var string + */ + private $createNewAttribute = 'button[data-index="add_new_attribute_button"]'; + + /** + * Click on "Create new attribute" button. + * + * @return void + */ + public function createNewAttribute() + { + $this->_rootElement->find($this->createNewAttribute)->click(); + } +} diff --git a/dev/tests/functional/tests/app/Magento/Catalog/Test/Block/Adminhtml/Product/Modal/NewAttribute.php b/dev/tests/functional/tests/app/Magento/Catalog/Test/Block/Adminhtml/Product/Modal/NewAttribute.php new file mode 100644 index 0000000000000000000000000000000000000000..59e999bf791ad9d453ee6fa2b6e7afa3faa58c76 --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Catalog/Test/Block/Adminhtml/Product/Modal/NewAttribute.php @@ -0,0 +1,32 @@ +<?php +/** + * Copyright © 2016 Magento. All rights reserved. + * See COPYING.txt for license details. + */ + +namespace Magento\Catalog\Test\Block\Adminhtml\Product\Modal; + +use Magento\Ui\Test\Block\Adminhtml\FormSections; + +/** + * Product new attribute modal. + */ +class NewAttribute extends FormSections +{ + /** + * Selector for "Save" button. + * + * @var string + */ + private $save = 'button#save'; + + /** + * Click "Save Attribute" button on attribute form. + * + * @return void + */ + public function saveAttribute() + { + $this->_rootElement->find($this->save)->click(); + } +} 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 b0f2b27042b03c54285163f3a03be28ec9dc19eb..24a2a2f7b8c8c1562bbf02180d65ca09a7b602aa 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 @@ -11,13 +11,9 @@ use Magento\Catalog\Test\Block\Adminhtml\Product\Attribute\AttributeForm; use Magento\Catalog\Test\Block\Adminhtml\Product\Attribute\CustomAttribute; use Magento\Catalog\Test\Fixture\CatalogProductAttribute; use Magento\Mtf\Client\Element\SimpleElement; -use Magento\Catalog\Test\Block\Adminhtml\Product\Edit\Section\Attributes; -use Magento\Mtf\Client\Element; use Magento\Mtf\Client\Locator; use Magento\Mtf\Fixture\FixtureInterface; -use Magento\Mtf\Fixture\InjectableFixture; -use Magento\Catalog\Test\Fixture\Category; -use Magento\Catalog\Test\Block\Adminhtml\Product\Edit\Section\Attributes\Search; +use Magento\Ui\Test\Block\Adminhtml\DataGrid; /** * Product form on backend product page. @@ -32,11 +28,11 @@ class ProductForm extends FormSections protected $attribute = './/*[contains(@class,"label")]/span[text()="%s"]'; /** - * Attribute Search locator the Product page. + * Attributes Search modal locator. * * @var string */ - protected $attributeSearch = '#product-attribute-search-container'; + protected $attributeSearch = '.product_form_product_form_add_attribute_modal'; /** * Custom Section locator. @@ -50,28 +46,21 @@ class ProductForm extends FormSections * * @var string */ - protected $attributeBlock = '#attribute-%s-container'; + protected $attributeBlock = '[data-index="%s"]'; /** - * Magento loader. - * - * @var string - */ - protected $loader = '[data-role="loader"]'; - - /** - * New attribute form selector. + * Magento form loader. * * @var string */ - protected $newAttributeForm = '#create_new_attribute'; + protected $spinner = '[data-role="spinner"]'; /** - * Magento form loader. + * New Attribute modal locator. * * @var string */ - protected $spinner = '[data-role="spinner"]'; + protected $newAttributeModal = '.product_form_product_form_add_attribute_modal_create_new_attribute_modal'; /** * Fill the product form. @@ -104,34 +93,11 @@ class ProductForm extends FormSections $sections['product-details']['category_ids']['value'] = $category->getName(); } $this->fillContainers($sections, $element); - - if ($product->hasData('custom_attribute')) { - $this->createCustomAttribute($product); - } } return $this; } - /** - * Create custom attribute. - * - * @param InjectableFixture $product - * @param string $tabName - * @return void - */ - protected function createCustomAttribute(InjectableFixture $product, $tabName = 'product-details') - { - $attribute = $product->getDataFieldConfig('custom_attribute')['source']->getAttribute(); - $this->openSection('product-details'); - if (!$this->checkAttributeLabel($attribute)) { - /** @var \Magento\Catalog\Test\Block\Adminhtml\Product\Edit\Section\ProductDetails $section */ - $section = $this->openSection($tabName); - $section->addNewAttribute($tabName); - $this->getAttributeForm()->fill($attribute); - } - } - /** * Open section or click on button to open modal window. * @@ -176,28 +142,15 @@ class ProductForm extends FormSections } /** - * Call method that checking present attribute in search result. - * - * @param CatalogProductAttribute $productAttribute - * @return bool - */ - public function checkAttributeInSearchAttributeForm(CatalogProductAttribute $productAttribute) - { - $this->waitPageToLoad(); - return $this->getAttributesSearchForm()->isExistAttributeInSearchResult($productAttribute); - } - - /** - * Get attributes search form. + * Get attributes search grid. * - * @return Search + * @return DataGrid */ - protected function getAttributesSearchForm() + public function getAttributesSearchGrid() { - return $this->_rootElement->find( - $this->attributeSearch, - Locator::SELECTOR_CSS, - 'Magento\Catalog\Test\Block\Adminhtml\Product\Edit\Section\Attributes\Search' + return $this->blockFactory->create( + '\Magento\Catalog\Test\Block\Adminhtml\Product\Edit\Section\Attributes\Grid', + ['element' => $this->browser->find($this->attributeSearch)] ); } @@ -210,8 +163,7 @@ class ProductForm extends FormSections public function isCustomSectionVisible($sectionName) { $sectionName = strtolower($sectionName); - $selector = sprintf($this->customSection, $sectionName); - $this->waitForElementVisible($selector); + $selector = sprintf($this->attributeBlock, $sectionName); return $this->_rootElement->find($selector)->isVisible(); } @@ -228,31 +180,6 @@ class ProductForm extends FormSections $this->_rootElement->find(sprintf($this->customSection, $sectionName))->click(); } - /** - * Click "Save" button on attribute form. - * - * @return void - */ - public function saveAttributeForm() - { - $this->getAttributeForm()->saveAttributeForm(); - - $browser = $this->browser; - $element = $this->newAttributeForm; - $loader = $this->loader; - $this->_rootElement->waitUntil( - function () use ($browser, $element) { - return $browser->find($element)->isVisible() == false ? true : null; - } - ); - - $this->_rootElement->waitUntil( - function () use ($browser, $loader) { - return $browser->find($loader)->isVisible() == false ? true : null; - } - ); - } - /** * Get Attribute Form. * @@ -262,7 +189,7 @@ class ProductForm extends FormSections { return $this->blockFactory->create( 'Magento\Catalog\Test\Block\Adminhtml\Product\Attribute\AttributeForm', - ['element' => $this->browser->find('body')] + ['element' => $this->browser->find($this->newAttributeModal)] ); } @@ -280,23 +207,4 @@ class ProductForm extends FormSections 'Magento\Catalog\Test\Block\Adminhtml\Product\Attribute\CustomAttribute' ); } - - /** - * Click "Add Attribute" button from specific section. - * - * @param string $sectionName - * @throws \Exception - */ - public function addNewAttribute($sectionName = 'product-details') - { - $section = $this->getSection($sectionName); - if ($section instanceof Attributes) { - $this->openSection($sectionName); - $section->addNewAttribute($sectionName); - } else { - throw new \Exception( - "$sectionName hasn't 'Add attribute' button or is not instance of ProductSection class." - ); - } - } } diff --git a/dev/tests/functional/tests/app/Magento/Catalog/Test/Block/Adminhtml/Product/ProductForm.xml b/dev/tests/functional/tests/app/Magento/Catalog/Test/Block/Adminhtml/Product/ProductForm.xml index eb7766dcc327b9590e89361a28fd4e9c6bc5861a..b98cdb8c848f3d6a55cda58f45ae066814a4657e 100644 --- a/dev/tests/functional/tests/app/Magento/Catalog/Test/Block/Adminhtml/Product/ProductForm.xml +++ b/dev/tests/functional/tests/app/Magento/Catalog/Test/Block/Adminhtml/Product/ProductForm.xml @@ -19,10 +19,6 @@ <selector>[data-index="attribute_set_id"]</selector> <class>Magento\Catalog\Test\Block\Adminhtml\Product\Edit\Section\ProductDetails\AttributeSet</class> </attribute_set_id> - <attribute_id> - <selector>#product-attribute-search-container</selector> - <class>Magento\Catalog\Test\Block\Adminhtml\Product\Edit\Section\Attributes\Search</class> - </attribute_id> <tax_class_id> <input>select</input> </tax_class_id> @@ -44,7 +40,7 @@ </quantity_and_stock_status> <custom_attribute> <class>Magento\Catalog\Test\Block\Adminhtml\Product\Attribute\CustomAttribute</class> - <selector>#attribute-%attribute_code%-container</selector> + <selector>[data-index="%attribute_code%"]</selector> </custom_attribute> <visibility> <input>select</input> @@ -132,6 +128,17 @@ <short_description /> </fields> </content> + <attributes> + <class>\Magento\Catalog\Test\Block\Adminhtml\Product\Edit\Section\Attributes</class> + <selector>[data-index="attributes"]</selector> + <strategy>css selector</strategy> + <fields> + <custom_attribute> + <class>Magento\Catalog\Test\Block\Adminhtml\Product\Attribute\CustomAttribute</class> + <selector>[data-index="%attribute_code%"]</selector> + </custom_attribute> + </fields> + </attributes> <gallery> <class>\Magento\Ui\Test\Block\Adminhtml\Section</class> <selector>[data-index='block_gallery']</selector> diff --git a/dev/tests/functional/tests/app/Magento/Catalog/Test/Block/Product/Compare/Sidebar.php b/dev/tests/functional/tests/app/Magento/Catalog/Test/Block/Product/Compare/Sidebar.php index 773a18bac7e2ccce07d8c0e43e0277d072d25ddd..596dbd38664b3b097302e6f6f0e62d13fbe96017 100644 --- a/dev/tests/functional/tests/app/Magento/Catalog/Test/Block/Product/Compare/Sidebar.php +++ b/dev/tests/functional/tests/app/Magento/Catalog/Test/Block/Product/Compare/Sidebar.php @@ -79,6 +79,5 @@ class Sidebar extends ListCompare } ); $this->_rootElement->find($this->clearAll)->click(); - $this->browser->acceptAlert(); } } diff --git a/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertAddedProductAttributeOnProductForm.php b/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertAddedProductAttributeOnProductForm.php index d3d8f790b225738d1714481f0712c0f7833f00fc..6116c66f06478cfca0831360d1546f25adcf6e0b 100644 --- a/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertAddedProductAttributeOnProductForm.php +++ b/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertAddedProductAttributeOnProductForm.php @@ -7,20 +7,23 @@ namespace Magento\Catalog\Test\Constraint; use Magento\Catalog\Test\Fixture\CatalogAttributeSet; -use Magento\Catalog\Test\Fixture\CatalogProductSimple; use Magento\Mtf\Fixture\InjectableFixture; use Magento\Mtf\Fixture\FixtureFactory; use Magento\Mtf\Constraint\AbstractConstraint; use Magento\Catalog\Test\Fixture\CatalogProductAttribute; use Magento\Catalog\Test\Page\Adminhtml\CatalogProductEdit; use Magento\Catalog\Test\Page\Adminhtml\CatalogProductIndex; -use Magento\Mtf\ObjectManager; /** * Check attribute on product form. */ class AssertAddedProductAttributeOnProductForm extends AbstractConstraint { + /** + * Attributes section. + */ + const ATTRIBUTES = 'attributes'; + /** * Fixture factory. * @@ -89,7 +92,9 @@ class AssertAddedProductAttributeOnProductForm extends AbstractConstraint $catalogProductAttribute = ($productAttributeOriginal !== null) ? array_merge($productAttributeOriginal->getData(), $attribute->getData()) : $attribute->getData(); - + if ($catalogProductEdit->getProductForm()->isSectionVisible(self::ATTRIBUTES)) { + $catalogProductEdit->getProductForm()->openSection(self::ATTRIBUTES); + } \PHPUnit_Framework_Assert::assertTrue( $catalogProductEdit->getProductForm()->checkAttributeLabel($catalogProductAttribute), "Product Attribute is absent on Product form." diff --git a/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertProductAttributeAbsenceInSearchOnProductForm.php b/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertProductAttributeAbsenceInSearchOnProductForm.php index 6ff16c2a96ad8255f2ef6dce1ee3bd071c03511d..63fa283baa4ea0a2929e09a34444b614c00f7c59 100644 --- a/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertProductAttributeAbsenceInSearchOnProductForm.php +++ b/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertProductAttributeAbsenceInSearchOnProductForm.php @@ -31,9 +31,13 @@ class AssertProductAttributeAbsenceInSearchOnProductForm extends AbstractConstra ) { $productGrid->open(); $productGrid->getGridPageActionBlock()->addProduct('simple'); + $newProductPage->getFormPageActions()->addNewAttribute(); + $filter = [ + 'label' => $productAttribute->getFrontendLabel(), + ]; \PHPUnit_Framework_Assert::assertFalse( - $newProductPage->getProductForm()->checkAttributeInSearchAttributeForm($productAttribute), - "Product attribute found in Attribute Search form." + $newProductPage->getProductForm()->getAttributesSearchGrid()->isRowVisible($filter), + 'Attribute \'' . $productAttribute->getFrontendLabel() . '\' is found in Attributes grid.' ); } diff --git a/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertProductAttributeInGrid.php b/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertProductAttributeInGrid.php index d23e92007df57e375cfef4dd130b63ca623a0a39..a1da3f696cca633b38a79b9220db4c84ef785b90 100644 --- a/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertProductAttributeInGrid.php +++ b/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertProductAttributeInGrid.php @@ -11,8 +11,7 @@ use Magento\Catalog\Test\Page\Adminhtml\CatalogProductAttributeIndex; use Magento\Mtf\Constraint\AbstractConstraint; /** - * Class AssertProductAttributeInGrid - * Assert that created product attribute is found in grid + * Assert that created product attribute is found in grid. */ class AssertProductAttributeInGrid extends AbstractConstraint { diff --git a/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertProductAttributeIsRequired.php b/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertProductAttributeIsRequired.php index 403664ac3b82c693b38b14a6887bcf21ed809091..4f80e101e73ae6f9959796589dacfccb72fc24aa 100644 --- a/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertProductAttributeIsRequired.php +++ b/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertProductAttributeIsRequired.php @@ -39,10 +39,13 @@ class AssertProductAttributeIsRequired extends AbstractConstraint ) { $catalogProductIndex->open()->getProductGrid()->searchAndOpen(['sku' => $product->getSku()]); $productForm = $catalogProductEdit->getProductForm(); + if (!$productForm->checkAttributeLabel($attribute)) { + $productForm->openSection('attributes'); + } $productForm->getAttributeElement($attribute)->setValue(''); $catalogProductEdit->getFormPageActions()->save(); - $failedAttributes = $productForm->getRequireNoticeAttributes($product); - $actualMessage = $failedAttributes['product-details'][$attribute->getFrontendLabel()]; + $failedFields = $productForm->getRequireNoticeFields($product); + $actualMessage = $failedFields['attributes'][$attribute->getFrontendLabel()]; \PHPUnit_Framework_Assert::assertEquals( self::REQUIRE_MESSAGE, diff --git a/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertProductAttributeIsUnique.php b/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertProductAttributeIsUnique.php index 46cdf8fe2cab0d06cfe978f34001a3507b75571a..3c11b613ea3f0dcda3173815850a59f5ad95d75b 100644 --- a/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertProductAttributeIsUnique.php +++ b/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertProductAttributeIsUnique.php @@ -58,31 +58,16 @@ class AssertProductAttributeIsUnique extends AbstractConstraint $productForm = $catalogProductEdit->getProductForm(); $productForm->fill($simpleProduct); $catalogProductEdit->getFormPageActions()->save(); - $failedAttributes = $productForm->getRequireNoticeAttributes($simpleProduct); + $actualErrorMessage = $catalogProductEdit->getMessagesBlock()->getErrorMessage(); $attributeLabel = $attribute->getFrontendLabel(); - $actualMessage = $this->getActualMessage($failedAttributes, $attributeLabel); \PHPUnit_Framework_Assert::assertEquals( sprintf(self::UNIQUE_MESSAGE, $attributeLabel), - $actualMessage, + $actualErrorMessage, 'JS error notice on product edit page is not equal to expected.' ); } - /** - * Get actual message. - * - * @param array $errors - * @param string $attributeLabel - * @return mixed - */ - protected function getActualMessage(array $errors, $attributeLabel) - { - return isset($errors['product-details'][$attributeLabel]) - ? $errors['product-details'][$attributeLabel] - : null; - } - /** * Create simple product fixture. * diff --git a/dev/tests/functional/tests/app/Magento/Catalog/Test/Fixture/CatalogProductSimple.xml b/dev/tests/functional/tests/app/Magento/Catalog/Test/Fixture/CatalogProductSimple.xml index ef25f951e1f7b644d86a936d1a8fa0534d5098ad..d2a53d1eb757a64323dbb64db2a49531ca655348 100644 --- a/dev/tests/functional/tests/app/Magento/Catalog/Test/Fixture/CatalogProductSimple.xml +++ b/dev/tests/functional/tests/app/Magento/Catalog/Test/Fixture/CatalogProductSimple.xml @@ -73,7 +73,7 @@ <field name="id" group="null" /> <field name="type_id" /> <field name="attribute_set_id" group="product-details" source="Magento\Catalog\Test\Fixture\Product\AttributeSetId" /> - <field name="custom_attribute" group="product-details" source="Magento\Catalog\Test\Fixture\CatalogProductSimple\CustomAttribute" /> + <field name="custom_attribute" source="Magento\Catalog\Test\Fixture\CatalogProductSimple\CustomAttribute" /> <field name="custom_options" is_required="0" group="customer-options" source="Magento\Catalog\Test\Fixture\Product\CustomOptions" repository="Magento\Catalog\Test\Repository\Product\CustomOptions" /> <field name="website_ids" group="websites" /> <field name="is_returnable" is_required="0" group="product-details" /> diff --git a/dev/tests/functional/tests/app/Magento/Catalog/Test/Page/Adminhtml/CatalogProductEdit.xml b/dev/tests/functional/tests/app/Magento/Catalog/Test/Page/Adminhtml/CatalogProductEdit.xml index 1736cebd10e8e7ef5674fec29edfce7860986bf0..dc6b1e8213628f54597d2db52c9eb8b5a2b1fe66 100644 --- a/dev/tests/functional/tests/app/Magento/Catalog/Test/Page/Adminhtml/CatalogProductEdit.xml +++ b/dev/tests/functional/tests/app/Magento/Catalog/Test/Page/Adminhtml/CatalogProductEdit.xml @@ -9,6 +9,8 @@ <page name="CatalogProductEdit" area="Adminhtml" mca="catalog/product/edit" module="Magento_Catalog"> <block name="messagesBlock" class="Magento\Backend\Test\Block\Messages" locator="#messages .messages" strategy="css selector"/> <block name="formPageActions" class="Magento\Catalog\Test\Block\Adminhtml\Product\FormPageActions" locator=".page-main-actions" strategy="css selector"/> + <block name="addAttributeModal" class="Magento\Catalog\Test\Block\Adminhtml\Product\Modal\AddAttribute" locator=".product_form_product_form_add_attribute_modal" strategy="css selector"/> + <block name="newAttributeModal" class="Magento\Catalog\Test\Block\Adminhtml\Product\Modal\NewAttribute" locator=".product_form_product_form_add_attribute_modal_create_new_attribute_modal" strategy="css selector"/> <block name="productForm" class="Magento\Catalog\Test\Block\Adminhtml\Product\ProductForm" locator="[id='page:main-container']" strategy="css selector"/> </page> </config> diff --git a/dev/tests/functional/tests/app/Magento/Catalog/Test/Repository/CatalogProductAttribute.xml b/dev/tests/functional/tests/app/Magento/Catalog/Test/Repository/CatalogProductAttribute.xml index 2134b0c13ef23838c1fc1193a41676a954d3e2d0..8ebc57837ec8f4f0e1d12e15db0ab17afb50cb5c 100644 --- a/dev/tests/functional/tests/app/Magento/Catalog/Test/Repository/CatalogProductAttribute.xml +++ b/dev/tests/functional/tests/app/Magento/Catalog/Test/Repository/CatalogProductAttribute.xml @@ -35,8 +35,8 @@ <dataset name="tax_class_id"> <field name="attribute_id" xsi:type="number">172</field> - <field name="frontend_label" xsi:type="string">Tax Class</field> - <field name="attribute_code" xsi:type="string">tax_class_id</field> + <field name="frontend_label" xsi:type="string">Tax Class%isolation%</field> + <field name="attribute_code" xsi:type="string">tax_class_id%isolation%</field> <field name="frontend_input" xsi:type="string">Dropdown</field> <field name="is_required" xsi:type="string">No</field> <field name="options" xsi:type="array"> diff --git a/dev/tests/functional/tests/app/Magento/Catalog/Test/Repository/CatalogProductVirtual.xml b/dev/tests/functional/tests/app/Magento/Catalog/Test/Repository/CatalogProductVirtual.xml index 910d475e83a2051de6bc0eac0793400067c3b146..164053ada95253eeddf8b9e67f804634b967f18f 100644 --- a/dev/tests/functional/tests/app/Magento/Catalog/Test/Repository/CatalogProductVirtual.xml +++ b/dev/tests/functional/tests/app/Magento/Catalog/Test/Repository/CatalogProductVirtual.xml @@ -26,6 +26,7 @@ <item name="qty" xsi:type="string">666</item> <item name="is_in_stock" xsi:type="string">In Stock</item> </field> + <field name="product_has_weight" xsi:type="string">This item has no weight</field> <field name="price" xsi:type="array"> <item name="value" xsi:type="string">10</item> </field> @@ -44,6 +45,7 @@ <field name="tax_class_id" xsi:type="array"> <item name="dataset" xsi:type="string">taxable_goods</item> </field> + <field name="product_has_weight" xsi:type="string">This item has no weight</field> <field name="website_ids" xsi:type="array"> <item name="0" xsi:type="string">Main Website</item> </field> diff --git a/dev/tests/functional/tests/app/Magento/Catalog/Test/TestCase/Product/AddToCartCrossSellTest.xml b/dev/tests/functional/tests/app/Magento/Catalog/Test/TestCase/Product/AddToCartCrossSellTest.xml index f5086b3d40287af985578f62febb070f27dea64e..1e816de3b17fb74e7352777acc12c15faeb5583b 100644 --- a/dev/tests/functional/tests/app/Magento/Catalog/Test/TestCase/Product/AddToCartCrossSellTest.xml +++ b/dev/tests/functional/tests/app/Magento/Catalog/Test/TestCase/Product/AddToCartCrossSellTest.xml @@ -10,9 +10,9 @@ <variation name="AddToCartCrossSellTestVariation1" method="test"> <data name="tag" xsi:type="string">test_type:acceptance_test, test_type:extended_acceptance_test</data> <data name="products" xsi:type="string">simple1::catalogProductSimple::product_with_category,simple2::catalogProductSimple::product_with_category,config1::configurableProduct::two_options_with_fixed_price</data> - <data name="promotedProducts" xsi:type="string">simple1:simple2,config1;simple2:config1</data> - <data name="navigateProductsOrder" xsi:type="string">simple1,simple2,config1</data> - <data name="productsToVerify" xsi:type="string">simple1:simple2,config1;simple2:config1;config1:</data> + <data name="promotedProducts" xsi:type="string">simple1:simple2,config1;config1:simple2</data> + <data name="navigateProductsOrder" xsi:type="string">simple1,config1,simple2</data> + <data name="productsToVerify" xsi:type="string">simple1:simple2,config1;config1:simple2;simple2:</data> </variation> </testCase> </config> diff --git a/dev/tests/functional/tests/app/Magento/Catalog/Test/TestCase/Product/NavigateUpSellProductsTest.xml b/dev/tests/functional/tests/app/Magento/Catalog/Test/TestCase/Product/NavigateUpSellProductsTest.xml index 85bc8146d8649b84a573fa6c7625e9d74a0ab8d5..32c0f51f4f10663219ef4d8e2f5ada6a66ec6691 100644 --- a/dev/tests/functional/tests/app/Magento/Catalog/Test/TestCase/Product/NavigateUpSellProductsTest.xml +++ b/dev/tests/functional/tests/app/Magento/Catalog/Test/TestCase/Product/NavigateUpSellProductsTest.xml @@ -10,9 +10,9 @@ <variation name="NavigateUpSellProductsTestVariation1" method="test"> <data name="tag" xsi:type="string">test_type:acceptance_test, test_type:extended_acceptance_test</data> <data name="products" xsi:type="string">simple1::catalogProductSimple::product_with_category,simple2::catalogProductSimple::product_with_category,config1::configurableProduct::two_options_with_fixed_price</data> - <data name="promotedProducts" xsi:type="string">simple1:simple2,config1;simple2:config1</data> - <data name="navigateProductsOrder" xsi:type="string">simple1,simple2,config1</data> - <data name="productsToVerify" xsi:type="string">simple1:simple2,config1;simple2:config1;config1:</data> + <data name="promotedProducts" xsi:type="string">simple1:simple2,config1;config1:simple2</data> + <data name="navigateProductsOrder" xsi:type="string">simple1,config1,simple2</data> + <data name="productsToVerify" xsi:type="string">simple1:simple2,config1;config1:simple2;simple2:</data> </variation> </testCase> </config> diff --git a/dev/tests/functional/tests/app/Magento/Catalog/Test/TestCase/Product/ProductTypeSwitchingOnUpdateTest.php b/dev/tests/functional/tests/app/Magento/Catalog/Test/TestCase/Product/ProductTypeSwitchingOnUpdateTest.php index 4b99c2bb8940e2a4908f41e00590c4470e7111da..55814088db48197c6b247518b042ca59ba38310a 100644 --- a/dev/tests/functional/tests/app/Magento/Catalog/Test/TestCase/Product/ProductTypeSwitchingOnUpdateTest.php +++ b/dev/tests/functional/tests/app/Magento/Catalog/Test/TestCase/Product/ProductTypeSwitchingOnUpdateTest.php @@ -8,7 +8,7 @@ namespace Magento\Catalog\Test\TestCase\Product; use Magento\Catalog\Test\Page\Adminhtml\CatalogProductEdit; use Magento\Catalog\Test\Page\Adminhtml\CatalogProductIndex; -use Magento\ConfigurableProduct\Test\Block\Adminhtml\Product\Edit\Tab\Variations\Config; +use Magento\ConfigurableProduct\Test\Block\Adminhtml\Product\Edit\Section\Variations\Config; use Magento\Downloadable\Test\Block\Adminhtml\Catalog\Product\Edit\Section\Downloadable; use Magento\Mtf\Fixture\FixtureFactory; use Magento\Mtf\TestCase\Injectable; diff --git a/dev/tests/functional/tests/app/Magento/Catalog/Test/TestStep/AddNewAttributeFromProductPageStep.php b/dev/tests/functional/tests/app/Magento/Catalog/Test/TestStep/AddNewAttributeFromProductPageStep.php index fbf36b230f2bd929592f3b91109dacd5ac5c5b97..10ec591099f9b474e9b64a1abb1e47b9ca452fb3 100644 --- a/dev/tests/functional/tests/app/Magento/Catalog/Test/TestStep/AddNewAttributeFromProductPageStep.php +++ b/dev/tests/functional/tests/app/Magento/Catalog/Test/TestStep/AddNewAttributeFromProductPageStep.php @@ -21,22 +21,13 @@ class AddNewAttributeFromProductPageStep implements TestStepInterface */ protected $catalogProductEdit; - /** - * Tab name for adding attribute. - * - * @var string - */ - protected $tabName; - /** * @constructor * @param CatalogProductEdit $catalogProductEdit - * @param string $tabName */ - public function __construct(CatalogProductEdit $catalogProductEdit, $tabName) + public function __construct(CatalogProductEdit $catalogProductEdit) { $this->catalogProductEdit = $catalogProductEdit; - $this->tabName = $tabName; } /** @@ -46,7 +37,8 @@ class AddNewAttributeFromProductPageStep implements TestStepInterface */ public function run() { - $productForm = $this->catalogProductEdit->getProductForm(); - $productForm->addNewAttribute($this->tabName); + $productForm = $this->catalogProductEdit->getFormPageActions(); + $productForm->addNewAttribute(); + $this->catalogProductEdit->getAddAttributeModal()->createNewAttribute(); } } diff --git a/dev/tests/functional/tests/app/Magento/Catalog/Test/TestStep/SaveAttributeOnProductPageStep.php b/dev/tests/functional/tests/app/Magento/Catalog/Test/TestStep/SaveAttributeOnProductPageStep.php index 48c94b86e7a8edf88f79ef3df9fffac9557437af..c01b09a684ce683325d651e12c2e08a1133f52f1 100644 --- a/dev/tests/functional/tests/app/Magento/Catalog/Test/TestStep/SaveAttributeOnProductPageStep.php +++ b/dev/tests/functional/tests/app/Magento/Catalog/Test/TestStep/SaveAttributeOnProductPageStep.php @@ -16,13 +16,6 @@ use Magento\Catalog\Test\Page\Adminhtml\CatalogProductEdit; */ class SaveAttributeOnProductPageStep implements TestStepInterface { - /** - * Catalog product edit page. - * - * @var CatalogProductEdit - */ - protected $catalogProductEdit; - /** * Product attribute fixture. * @@ -37,30 +30,37 @@ class SaveAttributeOnProductPageStep implements TestStepInterface */ protected $objectManager; + /** + * Catalog product edit page. + * + * @var CatalogProductEdit + */ + protected $catalogProductEdit; + /** * @constructor - * @param CatalogProductEdit $catalogProductEdit * @param CatalogProductAttribute $attribute * @param ObjectManager $objectManager + * @param CatalogProductEdit $catalogProductEdit */ public function __construct( - CatalogProductEdit $catalogProductEdit, CatalogProductAttribute $attribute, - ObjectManager $objectManager + ObjectManager $objectManager, + CatalogProductEdit $catalogProductEdit ) { - $this->catalogProductEdit = $catalogProductEdit; $this->attribute = $attribute; $this->objectManager = $objectManager; + $this->catalogProductEdit = $catalogProductEdit; } /** - * Click "Save" button on attribute form on product page. + * Click "Save" button on attribute form. * - * @return array + * @return void */ public function run() { - $this->catalogProductEdit->getProductForm()->saveAttributeForm(); + $this->catalogProductEdit->getNewAttributeModal()->saveAttribute(); } /** diff --git a/dev/tests/functional/tests/app/Magento/Catalog/Test/etc/testcase.xml b/dev/tests/functional/tests/app/Magento/Catalog/Test/etc/testcase.xml index f9cf350993613862ff92b789b8c94397cf9d17f1..40e9a20adf3b33069c3e7fa7804921afea16ebc8 100644 --- a/dev/tests/functional/tests/app/Magento/Catalog/Test/etc/testcase.xml +++ b/dev/tests/functional/tests/app/Magento/Catalog/Test/etc/testcase.xml @@ -8,9 +8,7 @@ <config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../../../../vendor/magento/mtf/Magento/Mtf/TestCase/etc/testcase.xsd"> <scenario name="CreateProductAttributeEntityFromProductPageTest" firstStep="openProductOnBackend"> <step name="openProductOnBackend" module="Magento_Catalog" next="addNewAttributeFromProductPage"/> - <step name="addNewAttributeFromProductPage" module="Magento_Catalog" next="fillAttributeFormOnProductPage"> - <item name="tabName" value="product-details"/> - </step> + <step name="addNewAttributeFromProductPage" module="Magento_Catalog" next="fillAttributeFormOnProductPage"/> <step name="fillAttributeFormOnProductPage" module="Magento_Catalog" next="saveAttributeOnProductPage"/> <step name="saveAttributeOnProductPage" module="Magento_Catalog" next="setDefaultAttributeValue"/> <step name="setDefaultAttributeValue" module="Magento_Catalog" next="saveProduct"/> diff --git a/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/Block/Adminhtml/Product/AffectedAttributeSet.php b/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/Block/Adminhtml/Product/AffectedAttributeSet.php index 7d731915be33026f11ff96b2fb41d3fa8b398d46..d7fcc85e65f7fbfda4f51e2e08c35e5e876c842b 100644 --- a/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/Block/Adminhtml/Product/AffectedAttributeSet.php +++ b/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/Block/Adminhtml/Product/AffectedAttributeSet.php @@ -13,27 +13,26 @@ use Magento\Mtf\Client\Element\SimpleElement; use Magento\Mtf\Block\Form as ParentForm; /** - * Class AffectedAttributeSet - * Choose affected attribute set dialog popup window + * Choose affected attribute set dialog popup window. */ class AffectedAttributeSet extends ParentForm { /** - * 'Confirm' button locator + * 'Confirm' button locator. * * @var string */ - protected $confirmButton = '[data-role=action]'; + protected $confirmButton = '[data-index="confirm_button"]'; /** - * Locator buttons new name attribute set + * Add configurable attributes to the New Attribute Set. * * @var string */ - protected $affectedAttributeSetNew = '#new-affected-attribute-set'; + protected $affectedAttributeSetNew = 'input[data-index="affectedAttributeSetNew"]'; /** - * Fill popup form + * Fill popup form. * * @param FixtureInterface $product * @param SimpleElement|null $element [optional] @@ -55,7 +54,7 @@ class AffectedAttributeSet extends ParentForm } /** - * Click confirm button + * Click confirm button. * * @return void */ diff --git a/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/Block/Adminhtml/Product/AffectedAttributeSet.xml b/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/Block/Adminhtml/Product/AffectedAttributeSet.xml index f5eeb1b659895e53b116864c1cdf753a3a78f4ab..69884c2660f9b3a5f0cd54d3d546be8651d140d0 100644 --- a/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/Block/Adminhtml/Product/AffectedAttributeSet.xml +++ b/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/Block/Adminhtml/Product/AffectedAttributeSet.xml @@ -8,7 +8,7 @@ <mapping strict="0"> <fields> <new_attribute_set_name> - <selector>[name='new-attribute-set-name']</selector> + <selector>.new-attribute-set-name input</selector> </new_attribute_set_name> </fields> </mapping> diff --git a/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/Block/Adminhtml/Product/Edit/NewConfigurableAttributeForm.php b/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/Block/Adminhtml/Product/Edit/NewConfigurableAttributeForm.php new file mode 100644 index 0000000000000000000000000000000000000000..a09c9b4dd6e00a73132295a89f17b71d5ccac68c --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/Block/Adminhtml/Product/Edit/NewConfigurableAttributeForm.php @@ -0,0 +1,92 @@ +<?php +/** + * Copyright © 2016 Magento. All rights reserved. + * See COPYING.txt for license details. + */ + +namespace Magento\ConfigurableProduct\Test\Block\Adminhtml\Product\Edit; + +use Magento\Ui\Test\Block\Adminhtml\FormSections; +use Magento\Mtf\Client\Element\SimpleElement; +use Magento\Mtf\Client\Locator; +use Magento\Mtf\Fixture\FixtureInterface; + +/** + * New attribute form on configurable product page. + */ +class NewConfigurableAttributeForm extends FormSections +{ + /** + * Iframe locator. + * + * @var string + */ + protected $iFrame = '#create_new_attribute_container'; + + /** + * Save button selector. + * + * @var string + */ + protected $saveButton = '#save'; + + /** + * Attribute to check whether section is opened. + * + * @var string + */ + private $isSectionOpened = 'active'; + + /** + * Fill the attribute form. + * + * @param FixtureInterface $fixture + * @param SimpleElement|null $element + * @return $this + */ + public function fill(FixtureInterface $fixture, SimpleElement $element = null) + { + $this->browser->switchToFrame(new Locator($this->iFrame)); + $browser = $this->browser; + $selector = $this->saveButton; + $this->browser->waitUntil( + function () use ($browser, $selector) { + return $browser->find($selector)->isVisible() ? true : null; + } + ); + parent::fill($fixture, $element); + $this->browser->switchToFrame(); + } + + /** + * Open section. + * + * @param string $sectionName + * @return FormSections + */ + public function openSection($sectionName) + { + $selector = $this->getContainerElement($sectionName)->getLocator()['value']; + $strategy = null !== $this->getContainerElement($sectionName)->getLocator()['using'] + ? $this->getContainerElement($sectionName)->getLocator()['using'] + : Locator::SELECTOR_CSS; + $sectionClass = $this->_rootElement->find($selector, $strategy)->getAttribute('class'); + if (strpos($sectionClass, $this->isSectionOpened) === false) { + $this->_rootElement->find($selector, $strategy)->click(); + } + + return $this; + } + + /** + * Click on "Save" button. + * + * @return void + */ + public function saveAttributeForm() + { + $this->browser->switchToFrame(new Locator($this->iFrame)); + $this->browser->find($this->saveButton)->click(); + $this->browser->switchToFrame(); + } +} diff --git a/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/Block/Adminhtml/Product/Edit/NewConfigurableAttributeForm.xml b/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/Block/Adminhtml/Product/Edit/NewConfigurableAttributeForm.xml new file mode 100644 index 0000000000000000000000000000000000000000..e211a7882463d1039ec444500ccfa8cf6ccda7fe --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/Block/Adminhtml/Product/Edit/NewConfigurableAttributeForm.xml @@ -0,0 +1,95 @@ +<?xml version="1.0" ?> +<!-- +/** + * Copyright © 2016 Magento. All rights reserved. + * See COPYING.txt for license details. + */ +--> +<sections> + <properties> + <class>\Magento\Ui\Test\Block\Adminhtml\Section</class> + <selector>#edit_form</selector> + <strategy>css selector</strategy> + <fields> + <frontend_label> + <selector>[name^='frontend_label']</selector> + </frontend_label> + <frontend_input> + <input>select</input> + </frontend_input> + <is_required> + <input>select</input> + </is_required> + <options> + <class>\Magento\Catalog\Test\Block\Adminhtml\Product\Attribute\Edit\Options</class> + <selector>#manage-options-panel</selector> + <strategy>css selector</strategy> + </options> + </fields> + </properties> + <advanced-properties> + <class>\Magento\Ui\Test\Block\Adminhtml\Section</class> + <selector>[data-target="#advanced_fieldset-content"]</selector> + <strategy>css selector</strategy> + <fields> + <attribute_code> + </attribute_code> + <is_global> + <input>select</input> + </is_global> + <default_value> + <selector>[name^='default_value_']</selector> + </default_value> + <is_unique> + <input>select</input> + </is_unique> + </fields> + </advanced-properties> + <manage-labels> + <class>\Magento\Ui\Test\Block\Adminhtml\Section</class> + <selector>[data-target="#manage-titles-content"]</selector> + <strategy>css selector</strategy> + <fields> + <manage_frontend_label> + <selector>[name^='frontend_label']</selector> + </manage_frontend_label> + </fields> + </manage-labels> + <frontend-properties> + <class>\Magento\Backend\Test\Block\Widget\Tab</class> + <selector>[data-target="#front_fieldset-content"]</selector> + <strategy>css selector</strategy> + <fields> + <is_searchable> + <input>select</input> + </is_searchable> + <is_visible_in_advanced_search> + <input>select</input> + </is_visible_in_advanced_search> + <is_comparable> + <input>select</input> + </is_comparable> + <is_filterable> + <input>select</input> + </is_filterable> + <is_filterable_in_search> + <input>select</input> + </is_filterable_in_search> + <is_used_for_promo_rules> + <input>select</input> + </is_used_for_promo_rules> + <is_html_allowed_on_front> + <input>select</input> + </is_html_allowed_on_front> + <is_visible_on_front> + <input>select</input> + </is_visible_on_front> + <used_in_product_listing> + <input>select</input> + </used_in_product_listing> + <used_for_sort_by> + <input>select</input> + </used_for_sort_by> + </fields> + </frontend-properties> +</sections> diff --git a/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/Block/Adminhtml/Product/Edit/Tab/Variations/Config.php b/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/Block/Adminhtml/Product/Edit/Section/Variations/Config.php similarity index 83% rename from dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/Block/Adminhtml/Product/Edit/Tab/Variations/Config.php rename to dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/Block/Adminhtml/Product/Edit/Section/Variations/Config.php index 805fe65d1ebec7e1406713d013a6722a2cc1420b..6fa06e0736c34caafbf3f960e07d0a46dd32f4c5 100644 --- a/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/Block/Adminhtml/Product/Edit/Tab/Variations/Config.php +++ b/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/Block/Adminhtml/Product/Edit/Section/Variations/Config.php @@ -4,21 +4,21 @@ * See COPYING.txt for license details. */ -namespace Magento\ConfigurableProduct\Test\Block\Adminhtml\Product\Edit\Tab\Variations; +namespace Magento\ConfigurableProduct\Test\Block\Adminhtml\Product\Edit\Section\Variations; use Magento\Backend\Test\Block\Template; -use Magento\Backend\Test\Block\Widget\Tab; +use Magento\Ui\Test\Block\Adminhtml\Section; use Magento\Mtf\Client\Element; use Magento\Mtf\Client\Element\SimpleElement; use Magento\Mtf\Client\Locator; /** - * Adminhtml catalog super product configurable tab. + * Adminhtml catalog super product configurable section. */ -class Config extends Tab +class Config extends Section { /** @var string */ - protected $createConfigurationsButton = '[data-action=open-steps-wizard]'; + protected $createConfigurationsButton = '[data-index="create_configurable_products_button"] > span'; /** * Selector for trigger show/hide "Variations" tab. @@ -46,7 +46,7 @@ class Config extends Tab * * @var string */ - protected $variationsMatrix = '[data-role="product-variations-matrix"]'; + protected $variationsMatrix = 'div[data-index="configurable-matrix"]'; /** * Selector for template block. @@ -62,6 +62,13 @@ class Config extends Tab */ protected $variationsContent = '#product_info_tabs_super_config_content'; + /** + * Locator for Configurations section. + * + * @var string + */ + private $configurationsSection = '[data-index="configurable"]'; + /** * Fill variations fieldset. * @@ -77,7 +84,6 @@ class Config extends Tab ? $fields['configurable_attributes_data']['value'] : []; - $this->showContent(); $attributesValue = isset($fields['configurable_attributes_data']['source']) ? $fields['configurable_attributes_data']['source']->getAttributesData() : []; @@ -94,20 +100,6 @@ class Config extends Tab return $this; } - /** - * Show "Variations" tab content. - * - * @return void - */ - public function showContent() - { - $content = $this->_rootElement->find($this->variationsTabContent); - if (!$content->isVisible()) { - $this->_rootElement->find($this->variationsTabTrigger)->click(); - $this->waitForElementVisible($this->variationsTabContent); - } - } - /** * Click 'Create Configurations' button. * @@ -115,6 +107,7 @@ class Config extends Tab */ public function createConfigurations() { + $this->_rootElement->find($this->configurationsSection)->hover(); $this->_rootElement->find($this->createConfigurationsButton)->click(); } @@ -132,12 +125,12 @@ class Config extends Tab /** * Get block of attributes. * - * @return \Magento\ConfigurableProduct\Test\Block\Adminhtml\Product\Edit\Tab\Variations\Config\Attribute + * @return \Magento\ConfigurableProduct\Test\Block\Adminhtml\Product\Edit\Section\Variations\Config\Attribute */ public function getAttributeBlock() { return $this->blockFactory->create( - 'Magento\ConfigurableProduct\Test\Block\Adminhtml\Product\Edit\Tab\Variations\Config\Attribute', + 'Magento\ConfigurableProduct\Test\Block\Adminhtml\Product\Edit\Section\Variations\Config\Attribute', ['element' => $this->_rootElement] ); } @@ -145,12 +138,12 @@ class Config extends Tab /** * Get block of variations. * - * @return \Magento\ConfigurableProduct\Test\Block\Adminhtml\Product\Edit\Tab\Variations\Config\Matrix + * @return \Magento\ConfigurableProduct\Test\Block\Adminhtml\Product\Edit\Section\Variations\Config\Matrix */ public function getVariationsBlock() { return $this->blockFactory->create( - 'Magento\ConfigurableProduct\Test\Block\Adminhtml\Product\Edit\Tab\Variations\Config\Matrix', + 'Magento\ConfigurableProduct\Test\Block\Adminhtml\Product\Edit\Section\Variations\Config\Matrix', ['element' => $this->_rootElement->find($this->variationsMatrix)] ); } @@ -180,8 +173,6 @@ class Config extends Tab public function getFieldsData($fields = null, SimpleElement $element = null) { $data = []; - - $this->showContent(); $data['matrix'] = $this->getVariationsBlock()->getVariationsData(); return ['configurable_attributes_data' => $data]; diff --git a/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/Block/Adminhtml/Product/Edit/Tab/Variations/Config/Attribute.php b/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/Block/Adminhtml/Product/Edit/Section/Variations/Config/Attribute.php similarity index 93% rename from dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/Block/Adminhtml/Product/Edit/Tab/Variations/Config/Attribute.php rename to dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/Block/Adminhtml/Product/Edit/Section/Variations/Config/Attribute.php index 0459c4d67ecb8643b9498fa37decd3e9e0981bb3..9b91ecbbc15e9f747e52e20878cfd24b40d4d47c 100644 --- a/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/Block/Adminhtml/Product/Edit/Tab/Variations/Config/Attribute.php +++ b/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/Block/Adminhtml/Product/Edit/Section/Variations/Config/Attribute.php @@ -4,9 +4,9 @@ * See COPYING.txt for license details. */ -namespace Magento\ConfigurableProduct\Test\Block\Adminhtml\Product\Edit\Tab\Variations\Config; +namespace Magento\ConfigurableProduct\Test\Block\Adminhtml\Product\Edit\Section\Variations\Config; -use Magento\ConfigurableProduct\Test\Block\Adminhtml\Product\Edit\Tab\Variations\Config\Attribute\AttributeSelector; +use Magento\ConfigurableProduct\Test\Block\Adminhtml\Product\Edit\Section\Variations\Config\Attribute\AttributeSelector; use Magento\Mtf\Block\Form; use Magento\Mtf\Client\Element\SimpleElement; use Magento\Mtf\Client\Locator; @@ -152,6 +152,13 @@ class Attribute extends Form */ protected $templateBlock = './ancestor::body'; + /** + * List of selected attributes + * + * @var string + */ + private $selectedAttributes = 'span[data-bind*="selectedAttributes"]'; + /** * Fill attributes * @@ -170,7 +177,11 @@ class Attribute extends Form //select attributes $this->getAttributesGrid()->resetFilter(); - $this->getAttributesGrid()->deselectAttributes(); + $attributesList = $this->browser->find($this->selectedAttributes)->getText(); + if ($attributesList != '--') { + $this->getAttributesGrid()->deselectAttributes(); + } + if ($this->_rootElement->find('[class$=no-data]')->isVisible()) { return; } @@ -214,8 +225,9 @@ class Attribute extends Form ); $this->browser->find($this->createNewVariationSet)->click(); - $this->getEditAttributeForm()->fill($attributeFixture); - $this->getEditAttributeForm()->saveAttributeForm(); + $newAttributeForm = $this->getNewAttributeForm(); + $newAttributeForm->fill($attributeFixture); + $newAttributeForm->saveAttributeForm(); $this->waitBlock($this->newAttributeFrame); } @@ -322,14 +334,14 @@ class Attribute extends Form } /** - * Get attribute form block + * Get new attribute form block. * - * @return \Magento\Catalog\Test\Block\Adminhtml\Product\Attribute\AttributeForm + * @return \Magento\ConfigurableProduct\Test\Block\Adminhtml\Product\Edit\NewConfigurableAttributeForm */ - protected function getEditAttributeForm() + protected function getNewAttributeForm() { return $this->blockFactory->create( - 'Magento\Catalog\Test\Block\Adminhtml\Product\Attribute\AttributeForm', + 'Magento\ConfigurableProduct\Test\Block\Adminhtml\Product\Edit\NewConfigurableAttributeForm', ['element' => $this->browser->find($this->newAttribute)] ); } @@ -344,7 +356,7 @@ class Attribute extends Form return $this->_rootElement->find( $this->variationSearchBlock, Locator::SELECTOR_CSS, - 'Magento\ConfigurableProduct\Test\Block\Adminhtml\Product\Edit\Tab\Variations\Config\Attribute' + 'Magento\ConfigurableProduct\Test\Block\Adminhtml\Product\Edit\Section\Variations\Config\Attribute' . '\AttributeSelector' ); } diff --git a/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/Block/Adminhtml/Product/Edit/Tab/Variations/Config/Attribute.xml b/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/Block/Adminhtml/Product/Edit/Section/Variations/Config/Attribute.xml similarity index 100% rename from dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/Block/Adminhtml/Product/Edit/Tab/Variations/Config/Attribute.xml rename to dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/Block/Adminhtml/Product/Edit/Section/Variations/Config/Attribute.xml diff --git a/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/Block/Adminhtml/Product/Edit/Tab/Variations/Config/Attribute/AttributeSelector.php b/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/Block/Adminhtml/Product/Edit/Section/Variations/Config/Attribute/AttributeSelector.php similarity index 94% rename from dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/Block/Adminhtml/Product/Edit/Tab/Variations/Config/Attribute/AttributeSelector.php rename to dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/Block/Adminhtml/Product/Edit/Section/Variations/Config/Attribute/AttributeSelector.php index d62e39beb7396285fdc0c8460f8ada8705c3cac6..5a6ebf949ec08cfc30a6597779ef9f49c35302d0 100644 --- a/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/Block/Adminhtml/Product/Edit/Tab/Variations/Config/Attribute/AttributeSelector.php +++ b/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/Block/Adminhtml/Product/Edit/Section/Variations/Config/Attribute/AttributeSelector.php @@ -4,7 +4,7 @@ * See COPYING.txt for license details. */ -namespace Magento\ConfigurableProduct\Test\Block\Adminhtml\Product\Edit\Tab\Variations\Config\Attribute; +namespace Magento\ConfigurableProduct\Test\Block\Adminhtml\Product\Edit\Section\Variations\Config\Attribute; use Magento\Mtf\Client\Element\SuggestElement; diff --git a/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/Block/Adminhtml/Product/Edit/Tab/Variations/Config/Attribute/ToggleDropdown.php b/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/Block/Adminhtml/Product/Edit/Section/Variations/Config/Attribute/ToggleDropdown.php similarity index 97% rename from dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/Block/Adminhtml/Product/Edit/Tab/Variations/Config/Attribute/ToggleDropdown.php rename to dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/Block/Adminhtml/Product/Edit/Section/Variations/Config/Attribute/ToggleDropdown.php index e1c6d9ca30164257dbd0bc0eace33ef3bf3f54de..ea0f83671d20bd13ce9cb0744a9adb9070bff0c8 100644 --- a/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/Block/Adminhtml/Product/Edit/Tab/Variations/Config/Attribute/ToggleDropdown.php +++ b/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/Block/Adminhtml/Product/Edit/Section/Variations/Config/Attribute/ToggleDropdown.php @@ -4,7 +4,7 @@ * See COPYING.txt for license details. */ -namespace Magento\ConfigurableProduct\Test\Block\Adminhtml\Product\Edit\Tab\Variations\Config\Attribute; +namespace Magento\ConfigurableProduct\Test\Block\Adminhtml\Product\Edit\Section\Variations\Config\Attribute; use Magento\Mtf\Client\Element\SimpleElement; use Magento\Mtf\Client\Locator; diff --git a/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/Block/Adminhtml/Product/Edit/Tab/Variations/Config/Matrix.php b/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/Block/Adminhtml/Product/Edit/Section/Variations/Config/Matrix.php similarity index 79% rename from dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/Block/Adminhtml/Product/Edit/Tab/Variations/Config/Matrix.php rename to dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/Block/Adminhtml/Product/Edit/Section/Variations/Config/Matrix.php index 231ce9ae6b500c3f1e2490b6d7f571a982153fae..ed8cbc800b2e672008347881a5bd18e1e674135f 100644 --- a/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/Block/Adminhtml/Product/Edit/Tab/Variations/Config/Matrix.php +++ b/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/Block/Adminhtml/Product/Edit/Section/Variations/Config/Matrix.php @@ -4,7 +4,7 @@ * See COPYING.txt for license details. */ -namespace Magento\ConfigurableProduct\Test\Block\Adminhtml\Product\Edit\Tab\Variations\Config; +namespace Magento\ConfigurableProduct\Test\Block\Adminhtml\Product\Edit\Section\Variations\Config; use Magento\Mtf\Client\ElementInterface; use Magento\Mtf\Client\Locator; @@ -13,66 +13,59 @@ use Magento\Mtf\Block\Form; use Magento\Mtf\Client\Element\SimpleElement; /** - * Class Matrix - * Matrix row form + * Matrix row form. */ class Matrix extends Form { /** - * Mapping for get optional fields + * Mapping for get optional fields. * * @var array */ protected $mappingGetFields = [ 'name' => [ - 'selector' => 'td[data-column="name"] > a', + 'selector' => 'td[data-index="name_container"] a', 'strategy' => Locator::SELECTOR_CSS, ], 'sku' => [ - 'selector' => 'td[data-column="sku"]', + 'selector' => 'td[data-index="sku_container"] span[data-index="sku_text"]', 'strategy' => Locator::SELECTOR_CSS, ], 'price' => [ - 'selector' => 'td[data-column="price"]', + 'selector' => 'td[data-index="price_container"] span[data-index="price_text"]', 'strategy' => Locator::SELECTOR_CSS, ], - 'quantity_and_stock_status' => [ - 'composite' => 1, - 'fields' => [ - 'qty' => [ - 'selector' => 'td[data-column="qty"]', - 'strategy' => Locator::SELECTOR_CSS, - ], - ], + 'qty' => [ + 'selector' => 'td[data-index="quantity_container"] span[data-index="quantity_text"]', + 'strategy' => Locator::SELECTOR_CSS, ], 'weight' => [ - 'selector' => 'td[data-column="weight"]', + 'selector' => 'td[data-index="price_weight"] span[data-index="weight_text"]', 'strategy' => Locator::SELECTOR_CSS, ], ]; /** - * Selector for variation row by number + * Selector for variation row by number. * * @var string */ - protected $variationRowByNumber = './/tr[@data-role="row"][%d]'; + protected $variationRowByNumber = './/tr[@class="data-row" or @class="data-row _odd-row"][%d]'; /** - * Selector for variation row + * Selector for variation row. * * @var string */ - protected $variationRow = 'tr[data-role="row"]'; + protected $variationRow = './/tr[contains(@class, "data-row")]'; - // @codingStandardsIgnoreStart /** - * Selector for row on product grid by product id + * Selector for row on product grid by product id. * * @var string */ - protected $associatedProductGrid = 'div[data-grid-id="associated-products-container"]'; - // @codingStandardsIgnoreEnd + protected $associatedProductGrid = + '[data-bind*="configurable_associated_product_listing.configurable_associated_product_listing"]'; /** * Selector for template block. @@ -86,14 +79,14 @@ class Matrix extends Form * * @var string */ - protected $deleteVariation = '[data-bind*="removeProduct"]'; + protected $deleteVariation = '[data-bind*="deleteRecord"]'; /** * Choose a different Product button selector. * * @var string */ - protected $chooseProduct = '[data-bind*="showGrid"]'; + protected $chooseProduct = '[data-bind*="openModalWithGrid"]'; /** * Action menu @@ -152,7 +145,7 @@ class Matrix extends Form public function getVariationsData() { $data = []; - $variationRows = $this->_rootElement->getElements($this->variationRow); + $variationRows = $this->_rootElement->getElements($this->variationRow, Locator::SELECTOR_XPATH); foreach ($variationRows as $key => $variationRow) { /** @var SimpleElement $variationRow */ @@ -200,7 +193,7 @@ class Matrix extends Form public function deleteVariations() { - $variations = $this->_rootElement->getElements($this->variationRow); + $variations = $this->_rootElement->getElements($this->variationRow, Locator::SELECTOR_XPATH); foreach (array_reverse($variations) as $variation) { $variation->find($this->actionMenu)->hover(); $variation->find($this->actionMenu)->click(); diff --git a/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/Block/Adminhtml/Product/Edit/Tab/Variations/Config/Matrix.xml b/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/Block/Adminhtml/Product/Edit/Section/Variations/Config/Matrix.xml similarity index 71% rename from dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/Block/Adminhtml/Product/Edit/Tab/Variations/Config/Matrix.xml rename to dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/Block/Adminhtml/Product/Edit/Section/Variations/Config/Matrix.xml index ea25b923bafc55125e207da2908134169cbba12c..f2525ca789ddf64513391d186275229c0f5f27fb 100644 --- a/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/Block/Adminhtml/Product/Edit/Tab/Variations/Config/Matrix.xml +++ b/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/Block/Adminhtml/Product/Edit/Section/Variations/Config/Matrix.xml @@ -16,11 +16,9 @@ <price> <selector>[name$="[price]"]</selector> </price> - <quantity_and_stock_status composite="1"> - <qty> - <selector>[name$="[quantity_and_stock_status][qty]"]</selector> - </qty> - </quantity_and_stock_status> + <qty> + <selector>[name$="[qty]"]</selector> + </qty> <weight> <selector>[name$="[weight]"]</selector> </weight> diff --git a/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/Block/Adminhtml/Product/FormPageActions.php b/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/Block/Adminhtml/Product/FormPageActions.php index 01bcd91da8c03dd90f69aa29ea7b04f1179e9f7c..11c66f128b5b28504042b99e56f4948a77f2fac5 100644 --- a/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/Block/Adminhtml/Product/FormPageActions.php +++ b/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/Block/Adminhtml/Product/FormPageActions.php @@ -21,7 +21,7 @@ class FormPageActions extends \Magento\Catalog\Test\Block\Adminhtml\Product\Form * * @var string */ - protected $affectedAttributeSetForm = '//div[@data-role="affected-attribute-set-selector"]/ancestor::*[@data-role="modal"]'; + protected $affectedAttributeSetForm = '.product_form_product_form_configurable_attribute_set_handler_modal [data-role="focusable-scope"]'; // @codingStandardsIgnoreEnd /** @@ -48,7 +48,7 @@ class FormPageActions extends \Magento\Catalog\Test\Block\Adminhtml\Product\Form { return $this->blockFactory->create( '\Magento\ConfigurableProduct\Test\Block\Adminhtml\Product\AffectedAttributeSet', - ['element' => $this->browser->find($this->affectedAttributeSetForm, Locator::SELECTOR_XPATH)] + ['element' => $this->browser->find($this->affectedAttributeSetForm)] ); } } diff --git a/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/Block/Adminhtml/Product/ProductForm.php b/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/Block/Adminhtml/Product/ProductForm.php index b8a51d8231d81bc2b3f68ac4745934d2ab29556c..80ea10808de0add0bce44d07402c9f98a137a0d1 100644 --- a/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/Block/Adminhtml/Product/ProductForm.php +++ b/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/Block/Adminhtml/Product/ProductForm.php @@ -35,7 +35,6 @@ class ProductForm extends \Magento\Catalog\Test\Block\Adminhtml\Product\ProductF return $this->fillContainers($sections, $element); } - /** * Create data array for filling tabs. * Skip Advanced Price tab @@ -45,10 +44,10 @@ class ProductForm extends \Magento\Catalog\Test\Block\Adminhtml\Product\ProductF */ protected function getFixtureFieldsByContainers(InjectableFixture $fixture) { - $tabs = parent::getFixtureFieldsByContainers($fixture); - if (isset($tabs['advanced-pricing'])) { - unset($tabs['advanced-pricing']); + $sections = parent::getFixtureFieldsByContainers($fixture); + if (isset($sections['advanced-pricing'])) { + unset($sections['advanced-pricing']); } - return $tabs; + return $sections; } } diff --git a/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/Block/Adminhtml/Product/ProductForm.xml b/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/Block/Adminhtml/Product/ProductForm.xml index 7d13ef869364bbbc77168a6beefb77898a88a238..788105979cb2223906bfa98c3a6220cd21efab02 100644 --- a/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/Block/Adminhtml/Product/ProductForm.xml +++ b/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/Block/Adminhtml/Product/ProductForm.xml @@ -7,15 +7,15 @@ --> <sections> <variations> - <class>\Magento\ConfigurableProduct\Test\Block\Adminhtml\Product\Edit\Tab\Variations\Config</class> - <selector>[data-index='product-details']</selector> + <class>\Magento\ConfigurableProduct\Test\Block\Adminhtml\Product\Edit\Section\Variations\Config</class> + <selector>[data-index="configurable"]</selector> <strategy>css selector</strategy> <fields> <attributes_data> - <selector>#super_config-wrapper</selector> + <selector>[data-index="configurable"] fieldset</selector> </attributes_data> <matrix> - <selector>#product-variations-matrix</selector> + <selector>[data-index="configurable-matrix"]</selector> </matrix> </fields> </variations> diff --git a/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/Constraint/AssertProductAttributeAbsenceInVariationsSearch.php b/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/Constraint/AssertProductAttributeAbsenceInVariationsSearch.php index 5a27cc69211bb0d91b61fd8597cca86003b72295..2763563c86df599d69dd70d176393d27ed03a248 100644 --- a/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/Constraint/AssertProductAttributeAbsenceInVariationsSearch.php +++ b/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/Constraint/AssertProductAttributeAbsenceInVariationsSearch.php @@ -6,8 +6,8 @@ namespace Magento\ConfigurableProduct\Test\Constraint; -use Magento\ConfigurableProduct\Test\Block\Adminhtml\Product\Edit\Tab\Variations\Config as VariationsTab; -use Magento\ConfigurableProduct\Test\Block\Adminhtml\Product\Edit\Tab\Variations\Config\Attribute as AttributeBlock; +use Magento\ConfigurableProduct\Test\Block\Adminhtml\Product\Edit\Section\Variations\Config as VariationsTab; +use Magento\ConfigurableProduct\Test\Block\Adminhtml\Product\Edit\Section\Variations\Config\Attribute as AttributeBlock; use Magento\Catalog\Test\Fixture\CatalogProductAttribute; use Magento\Catalog\Test\Page\Adminhtml\CatalogProductIndex; use Magento\Catalog\Test\Page\Adminhtml\CatalogProductNew; @@ -44,8 +44,7 @@ class AssertProductAttributeAbsenceInVariationsSearch extends AbstractConstraint /** @var VariationsTab $variationsTab */ $newProductPage->getProductForm()->fill($assertProduct); - $variationsTab = $newProductPage->getProductForm()->getTab(self::TAB_VARIATIONS); - $variationsTab->showContent(); + $variationsTab = $newProductPage->getProductForm()->getSection(self::TAB_VARIATIONS); $variationsTab->createConfigurations(); $attributesGrid = $variationsTab->getAttributeBlock()->getAttributesGrid(); \PHPUnit_Framework_Assert::assertFalse( diff --git a/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/Constraint/AssertProductAttributeIsConfigurable.php b/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/Constraint/AssertProductAttributeIsConfigurable.php index 383d76a2367e47c3b63108305b8dca5e84350c1e..251af2e1893a67b8de3dd99d7cfc4e310035afc6 100644 --- a/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/Constraint/AssertProductAttributeIsConfigurable.php +++ b/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/Constraint/AssertProductAttributeIsConfigurable.php @@ -9,7 +9,7 @@ namespace Magento\ConfigurableProduct\Test\Constraint; use Magento\Catalog\Test\Fixture\CatalogProductAttribute; use Magento\Catalog\Test\Page\Adminhtml\CatalogProductIndex; use Magento\Catalog\Test\Page\Adminhtml\CatalogProductNew; -use Magento\ConfigurableProduct\Test\Block\Adminhtml\Product\Edit\Tab\Variations\Config as TabVariation; +use Magento\ConfigurableProduct\Test\Block\Adminhtml\Product\Edit\Section\Variations\Config as SectionVariation; use Magento\ConfigurableProduct\Test\Fixture\ConfigurableProduct; use Magento\Mtf\Constraint\AbstractConstraint; @@ -36,11 +36,11 @@ class AssertProductAttributeIsConfigurable extends AbstractConstraint $productGrid->getGridPageActionBlock()->addProduct('configurable'); $productBlockForm = $newProductPage->getProductForm(); $productBlockForm->fill($assertProduct); - $productBlockForm->openTab('variations'); - /** @var \Magento\ConfigurableProduct\Test\Block\Adminhtml\Product\Edit\Tab\Variations\Config $variationsTab */ - $variationsTab = $productBlockForm->getTab('variations'); - $variationsTab->createConfigurations(); - $attributesGrid = $variationsTab->getAttributeBlock()->getAttributesGrid(); + $productBlockForm->openSection('variations'); + /** @var SectionVariation $variationsSection */ + $variationsSection = $productBlockForm->getSection('variations'); + $variationsSection->createConfigurations(); + $attributesGrid = $variationsSection->getAttributeBlock()->getAttributesGrid(); \PHPUnit_Framework_Assert::assertTrue( $attributesGrid->isRowVisible(['frontend_label' => $attribute->getFrontendLabel()]), "Product attribute is absent on the product page." diff --git a/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/TestCase/CreateConfigurableProductEntityTest.php b/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/TestCase/CreateConfigurableProductEntityTest.php index dd7ca68f9b6fcea8e9b82b0d86d283757f3c183f..c800c8b1bfef5ca7a73f53ef6c76709dd886abfd 100644 --- a/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/TestCase/CreateConfigurableProductEntityTest.php +++ b/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/TestCase/CreateConfigurableProductEntityTest.php @@ -45,21 +45,21 @@ class CreateConfigurableProductEntityTest extends Injectable /* end tags */ /** - * Product page with a grid + * Product page with a grid. * * @var CatalogProductIndex */ protected $productIndex; /** - * Page to create a product + * Page to create a product. * * @var CatalogProductNew */ protected $productNew; /** - * Injection data + * Injection data. * * @param CatalogProductIndex $productIndex * @param CatalogProductNew $productNew @@ -72,14 +72,13 @@ class CreateConfigurableProductEntityTest extends Injectable } /** - * Test create catalog Configurable product run + * Test create catalog Configurable product run. * * @param ConfigurableProduct $product * @return void */ public function test(ConfigurableProduct $product) { - $this->markTestIncomplete('MAGETWO-50179'); // Steps $this->productIndex->open(); $this->productIndex->getGridPageActionBlock()->addProduct('configurable'); diff --git a/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/TestStep/UpdateConfigurableProductStep.php b/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/TestStep/UpdateConfigurableProductStep.php index e59e0d6b0d487431ec48696cd78f8eeba7ac8bc8..40dbe1f857f238d0ca7dd21fb1d062e7ba65cad3 100644 --- a/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/TestStep/UpdateConfigurableProductStep.php +++ b/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/TestStep/UpdateConfigurableProductStep.php @@ -9,6 +9,8 @@ namespace Magento\ConfigurableProduct\Test\TestStep; use Magento\Catalog\Test\Fixture\CatalogProductAttribute; use Magento\Catalog\Test\Page\Adminhtml\CatalogProductEdit; use Magento\ConfigurableProduct\Test\Fixture\ConfigurableProduct; +use Magento\ConfigurableProduct\Test\Block\Adminhtml\Product\Edit\Section\Variations\Config; +use Magento\Catalog\Test\Page\Adminhtml\CatalogProductIndex; use Magento\Mtf\Fixture\FixtureFactory; use Magento\Mtf\TestStep\TestStepInterface; @@ -59,9 +61,15 @@ class UpdateConfigurableProductStep implements TestStepInterface */ protected $attributeTypeAction = ''; + /** + * @var CatalogProductIndex + */ + private $productGrid; + /** * @constructor * @param FixtureFactory $fixtureFactory + * @param CatalogProductIndex $productGrid * @param CatalogProductEdit $catalogProductEdit * @param ConfigurableProduct $product * @param ConfigurableProduct $updatedProduct @@ -69,6 +77,7 @@ class UpdateConfigurableProductStep implements TestStepInterface */ public function __construct( FixtureFactory $fixtureFactory, + CatalogProductIndex $productGrid, CatalogProductEdit $catalogProductEdit, ConfigurableProduct $product, ConfigurableProduct $updatedProduct, @@ -79,6 +88,7 @@ class UpdateConfigurableProductStep implements TestStepInterface $this->initialProduct = $product; $this->product = $updatedProduct; $this->attributeTypeAction = $attributeTypeAction; + $this->productGrid = $productGrid; } /** @@ -186,9 +196,17 @@ class UpdateConfigurableProductStep implements TestStepInterface */ protected function updateProduct(ConfigurableProduct $product) { + //open product + $filter = ['sku' => $this->initialProduct->getSku()]; + $this->productGrid->open(); + $this->productGrid->getProductGrid()->searchAndOpen($filter); + + //update $productForm = $this->catalogProductEdit->getProductForm(); - $productForm->openTab('variations'); - $productForm->getTab('variations')->deleteVariations(); + $productForm->openSection('variations'); + /** @var Config $variationsSection */ + $variationsSection = $productForm->getSection('variations'); + $variationsSection->deleteVariations(); $this->catalogProductEdit->getProductForm()->fill($product); } } diff --git a/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/etc/testcase.xml b/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/etc/testcase.xml index 31c1155f66c1c195ab21abef8b6724ee88f13b9a..c902f9430bcf1ee341e6de84f4ddf7e34c406a8f 100644 --- a/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/etc/testcase.xml +++ b/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/etc/testcase.xml @@ -7,10 +7,9 @@ --> <config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../../../../vendor/magento/mtf/Magento/Mtf/TestCase/etc/testcase.xsd"> <scenario name="UpdateConfigurableProductEntityTest" firstStep="createProduct"> - <step name="createProduct" module="Magento_Catalog" next="openProductOnBackend"> + <step name="createProduct" module="Magento_Catalog" next="updateConfigurableProduct"> <item name="product" value="configurableProduct::default"/> </step> - <step name="openProductOnBackend" module="Magento_Catalog" next="updateConfigurableProduct"/> <step name="updateConfigurableProduct" module="Magento_ConfigurableProduct" next="saveProduct"/> <step name="saveProduct" module="Magento_Catalog"/> </scenario> diff --git a/dev/tests/functional/tests/app/Magento/Downloadable/Test/Repository/DownloadableProduct.xml b/dev/tests/functional/tests/app/Magento/Downloadable/Test/Repository/DownloadableProduct.xml index 05ae4f0a614e8f9f9104ebd8d3e63f3a32940f7d..261bb040f55b1284e9729a839061e66d5ba35735 100644 --- a/dev/tests/functional/tests/app/Magento/Downloadable/Test/Repository/DownloadableProduct.xml +++ b/dev/tests/functional/tests/app/Magento/Downloadable/Test/Repository/DownloadableProduct.xml @@ -28,6 +28,7 @@ <field name="downloadable_links" xsi:type="array"> <item name="dataset" xsi:type="string">with_two_separately_links</item> </field> + <field name="product_has_weight" xsi:type="string">This item has no weight</field> <field name="website_ids" xsi:type="array"> <item name="0" xsi:type="string">Main Website</item> </field> diff --git a/dev/tests/functional/tests/app/Magento/Ui/Test/Block/Adminhtml/AbstractFormContainers.php b/dev/tests/functional/tests/app/Magento/Ui/Test/Block/Adminhtml/AbstractFormContainers.php index 6756d4eaf737a058e2cbb803c474e1535917289e..b6ed37af715be90fc600aa5728744ccd3a160d68 100644 --- a/dev/tests/functional/tests/app/Magento/Ui/Test/Block/Adminhtml/AbstractFormContainers.php +++ b/dev/tests/functional/tests/app/Magento/Ui/Test/Block/Adminhtml/AbstractFormContainers.php @@ -39,6 +39,13 @@ abstract class AbstractFormContainers extends Form */ protected $header = 'header.page-header'; + /** + * Close button locator. + * + * @var string + */ + protected $closeButton = 'aside[style]:not([style=""]) [data-role="closeBtn"]'; + /** * Initialize. * @@ -188,12 +195,15 @@ abstract class AbstractFormContainers extends Form if ($this->openContainer($containerName)) { $mapping = $container->dataMapping($this->unassignedFields); foreach ($mapping as $fieldName => $data) { - $element = $container->_rootElement->find($data['selector'], $data['strategy'], $data['input']); + $element = $this->getElement($this->_rootElement, $data); if ($element->isVisible()) { $element->setValue($data['value']); unset($this->unassignedFields[$fieldName]); } } + if ($this->browser->find($this->closeButton)->isVisible()) { + $this->browser->find($this->closeButton)->click(); + } if (empty($this->unassignedFields)) { break; } 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 2bf428feff8ef6290accb174f7f4fd55c3c29d63..6a5919b8cb1cfcfc2c8a666009e977ab0baafe0b 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 @@ -44,6 +44,13 @@ class FormSections extends AbstractFormContainers */ protected $opened = '._show'; + /** + * Locator for error messages. + * + * @var string + */ + protected $errorMessages = '[data-ui-id="messages-message-error"]'; + /** * Get Section class. * @@ -120,24 +127,35 @@ class FormSections extends AbstractFormContainers } /** - * Get Require Notice Attributes. + * Get require notice fields. * * @param InjectableFixture $product * @return array */ - public function getRequireNoticeAttributes(InjectableFixture $product) + public function getRequireNoticeFields(InjectableFixture $product) { $data = []; - $tabs = $this->getFixtureFieldsByContainers($product); - foreach (array_keys($tabs) as $tabName) { - $tab = $this->getSection($tabName); - $this->openSection($tabName); - $errors = $tab->getJsErrors(); + $sections = $this->getFixtureFieldsByContainers($product); + foreach (array_keys($sections) as $sectionName) { + $section = $this->getSection($sectionName); + $this->openSection($sectionName); + $errors = $section->getValidationErrors(); if (!empty($errors)) { - $data[$tabName] = $errors; + $data[$sectionName] = $errors; } } return $data; } + + /** + * Check if section is visible. + * + * @param string $sectionName + * @return bool + */ + public function isSectionVisible($sectionName) + { + return ($this->isCollapsible($sectionName) && !$this->isCollapsed($sectionName)); + } } diff --git a/dev/tests/functional/tests/app/Magento/Ui/Test/Block/Adminhtml/Section.php b/dev/tests/functional/tests/app/Magento/Ui/Test/Block/Adminhtml/Section.php index ce746e53e4d92c9ded1337e72c9a4b771a478189..f0aafd5250fd4209bc524102ee2f50724fbeeec7 100644 --- a/dev/tests/functional/tests/app/Magento/Ui/Test/Block/Adminhtml/Section.php +++ b/dev/tests/functional/tests/app/Magento/Ui/Test/Block/Adminhtml/Section.php @@ -6,10 +6,68 @@ namespace Magento\Ui\Test\Block\Adminhtml; +use Magento\Mtf\Client\Locator; + /** * Is used to represent any (collapsible) section on the page. */ class Section extends AbstractContainer { - // + /** + * Field with error. + * + * @var string + */ + protected $errorField = '//fieldset/*[contains(@class,"field ")][.//*[contains(@class,"error")]]'; + + /** + * Error label. + * + * @var string + */ + protected $errorLabel = './/*[contains(@class,"label")]'; + + /** + * Error text. + * + * @var string + */ + protected $errorText = './/label[contains(@class,"error")]'; + + /** + * Locator for section. + * + * @var string + */ + protected $section = '[data-index="%s"]'; + + /** + * Get array of label => validation error text. + * + * @return array + */ + public function getValidationErrors() + { + $data = []; + $elements = $this->_rootElement->getElements($this->errorField, Locator::SELECTOR_XPATH); + foreach ($elements as $element) { + $error = $element->find($this->errorText, Locator::SELECTOR_XPATH); + if ($error->isVisible()) { + $label = $element->find($this->errorLabel, Locator::SELECTOR_XPATH)->getText(); + $data[$label] = $error->getText(); + } + } + return $data; + } + + /** + * Check whether section is visible. + * + * @param string $sectionName + * @return bool + */ + public function isSectionVisible($sectionName) + { + return $this->_rootElement->find(sprintf($this->section, $sectionName))->isVisible(); + } } diff --git a/dev/tests/static/testsuite/Magento/Test/Legacy/_files/obsolete_classes.php b/dev/tests/static/testsuite/Magento/Test/Legacy/_files/obsolete_classes.php index be9b65ed051d3e757c197feb845b14541ee8f4e3..bdcadc125b2ca3c0b47eb52ecc3dcc56eff30a24 100755 --- a/dev/tests/static/testsuite/Magento/Test/Legacy/_files/obsolete_classes.php +++ b/dev/tests/static/testsuite/Magento/Test/Legacy/_files/obsolete_classes.php @@ -4220,5 +4220,5 @@ return [ ['Magento\Braintree\Test\Unit\Model\VaultTest'], ['Magento\Braintree\Test\Unit\Observer\DeleteBraintreeCustomerTest'], ['Magento\Braintree\Test\Unit\Observer\ProcessBraintreeAddressTest'], - ['Magento\Braintree\Test\Unit\Observer\ProcessBraintreePaymentTest'] + ['Magento\Braintree\Test\Unit\Observer\ProcessBraintreePaymentTest'], ]; diff --git a/lib/internal/Magento/Framework/Filesystem/Filter/ExcludeFilter.php b/lib/internal/Magento/Framework/Filesystem/Filter/ExcludeFilter.php new file mode 100644 index 0000000000000000000000000000000000000000..a00bf449718ab3f148d039e810c1a863cf89a7b2 --- /dev/null +++ b/lib/internal/Magento/Framework/Filesystem/Filter/ExcludeFilter.php @@ -0,0 +1,56 @@ +<?php +/** + * Copyright © 2016 Magento. All rights reserved. + * See COPYING.txt for license details. + */ + +namespace Magento\Framework\Filesystem\Filter; + +/** + * Filters Iterator to exclude specified files + */ +class ExcludeFilter extends \FilterIterator +{ + /** + * Array that is used for filtering + * + * @var array + */ + protected $_filters; + + /** + * Constructor + * + * @param \Iterator $iterator + * @param array $filters list of files to skip + */ + public function __construct(\Iterator $iterator, array $filters) + { + parent::__construct($iterator); + $this->_filters = $filters; + } + + /** + * Check whether the current element of the iterator is acceptable + * + * @return bool + */ + public function accept() + { + $current = str_replace('\\', '/', $this->current()->__toString()); + $currentFilename = str_replace('\\', '/', $this->current()->getFilename()); + + if ($currentFilename == '.' || $currentFilename == '..') { + return false; + } + + foreach ($this->_filters as $filter) { + $filter = str_replace('\\', '/', $filter); + if (false !== strpos($current, $filter)) { + return false; + } + } + + return true; + } +} diff --git a/lib/internal/Magento/Framework/Filesystem/Test/Unit/File/ExcludeFilterTest.php b/lib/internal/Magento/Framework/Filesystem/Test/Unit/File/ExcludeFilterTest.php new file mode 100644 index 0000000000000000000000000000000000000000..bca9b5b66768591238324b4262fe8471374d47e3 --- /dev/null +++ b/lib/internal/Magento/Framework/Filesystem/Test/Unit/File/ExcludeFilterTest.php @@ -0,0 +1,57 @@ +<?php +/** + * Copyright © 2016 Magento. All rights reserved. + * See COPYING.txt for license details. + */ + +namespace Magento\Framework\Filesystem\Test\Unit\File; + +use \Magento\Framework\Filesystem\Filter\ExcludeFilter; + +/** + * Class ExcludeFilterTest + */ +class ExcludeFilterTest extends \PHPUnit_Framework_TestCase +{ + /** + * @var \Iterator + */ + protected $iterator; + + protected function setUp() + { + $this->iterator = $this->getFilesIterator(); + } + + public function testExclusion() + { + $iterator = new ExcludeFilter( + $this->iterator, + [ + BP . '/var/session/' + ] + ); + + foreach ($iterator as $i) { + $result[] = $i; + } + + $this->assertTrue(!in_array(BP . '/var/session/', $result), 'Filtered path should not be in array'); + } + + private function getFilesIterator () + { + $files = [ + BP . '/var/', + BP . '/var/session/', + BP . '/var/cache/' + ]; + + foreach ($files as $file) { + $item = $this->getMockBuilder('SplFileInfoClass')->setMethods(['__toString', 'getFilename'])->getMock(); + $item->expects($this->any())->method('__toString')->willReturn($file); + $item->expects($this->any())->method('getFilename')->willReturn('notDots'); + yield $item; + } + } +} diff --git a/lib/internal/Magento/Framework/Model/ResourceModel/AbstractResource.php b/lib/internal/Magento/Framework/Model/ResourceModel/AbstractResource.php index d2b901d950555508b7f7edbb1b58cb3338af1a0d..451ec868bef316b3393b31912c4811530b0a8b25 100644 --- a/lib/internal/Magento/Framework/Model/ResourceModel/AbstractResource.php +++ b/lib/internal/Magento/Framework/Model/ResourceModel/AbstractResource.php @@ -56,7 +56,7 @@ abstract class AbstractResource /** * Subscribe some callback to transaction commit * - * @param array $callback + * @param callable|array $callback * @return $this * @api */ diff --git a/lib/internal/Magento/Framework/Module/DependencyChecker.php b/lib/internal/Magento/Framework/Module/DependencyChecker.php index 1149d2f35bcdbbf723ca939bd93635ba81c31edc..92adbd6fbb7bfdff02ce8ace917c063e8010236d 100644 --- a/lib/internal/Magento/Framework/Module/DependencyChecker.php +++ b/lib/internal/Magento/Framework/Module/DependencyChecker.php @@ -50,7 +50,6 @@ class DependencyChecker $this->enabledModuleList = $list->getNames(); $this->fullModuleList = $loader->load(); $this->packageInfo = $packageInfoFactory->create(); - $this->graph = $this->createGraph(); } /** @@ -93,6 +92,7 @@ class DependencyChecker */ private function checkDependencyGraph($isEnable, $moduleNames, $enabledModules) { + $this->graph = $this->createGraph(); $dependenciesMissingAll = []; $graphMode = $isEnable ? Graph::DIRECTIONAL : Graph::INVERSE; foreach ($moduleNames as $moduleName) { diff --git a/lib/internal/Magento/Framework/Search/Search.php b/lib/internal/Magento/Framework/Search/Search.php index 718357d4c29ca237ebaa0772f0dadc1dbbbe197a..d7d00b08f484df6cfe2a4bdbbf4f31f83c0a405e 100644 --- a/lib/internal/Magento/Framework/Search/Search.php +++ b/lib/internal/Magento/Framework/Search/Search.php @@ -57,7 +57,7 @@ class Search implements SearchInterface { $this->requestBuilder->setRequestName($searchCriteria->getRequestName()); - $scope = $this->scopeResolver->getScope(); + $scope = $this->scopeResolver->getScope()->getId(); $this->requestBuilder->bindDimension('scope', $scope); foreach ($searchCriteria->getFilterGroups() as $filterGroup) { @@ -84,7 +84,7 @@ class Search implements SearchInterface */ private function addFieldToFilter($field, $condition = null) { - if (!is_array($condition) || !in_array(key($condition), ['from', 'to'])) { + if (!is_array($condition) || !in_array(key($condition), ['from', 'to'], true)) { $this->requestBuilder->bind($field, $condition); } else { if (!empty($condition['from'])) { diff --git a/lib/internal/Magento/Framework/Search/Test/Unit/SearchTest.php b/lib/internal/Magento/Framework/Search/Test/Unit/SearchTest.php index bb4f56445c862182dcc703e5e3258dc2b8abf6c9..89e83e7cc8bf1609419c76f79f387064a4b51ac5 100644 --- a/lib/internal/Magento/Framework/Search/Test/Unit/SearchTest.php +++ b/lib/internal/Magento/Framework/Search/Test/Unit/SearchTest.php @@ -65,26 +65,25 @@ class SearchTest extends \PHPUnit_Framework_TestCase public function testSearch() { $requestName = 'requestName'; - $scope = 333; - $filterField = 'filterField'; - $filterValue = 'filterValue'; - - $filter = $this->getMockBuilder('Magento\Framework\Api\Filter') + $scopeId = 333; + $filters = [ + $this->createFilterMock('array_filter', ['arrayValue1', 'arrayValue2']), + $this->createFilterMock('simple_filter', 'filterValue'), + $this->createFilterMock('from_filter', ['from' => 30]), + $this->createFilterMock('to_filter', ['to' => 100]), + $this->createFilterMock('range_filter', ['from' => 60, 'to' => 82]), + ]; + + $scope = $this->getMockBuilder('Magento\Framework\App\ScopeInterface') ->disableOriginalConstructor() - ->getMock(); - $filter->expects($this->once()) - ->method('getField') - ->willReturn($filterField); - $filter->expects($this->once()) - ->method('getValue') - ->willReturn($filterValue); - + ->getMockForAbstractClass(); + $filterGroup = $this->getMockBuilder('Magento\Framework\Api\Search\FilterGroup') ->disableOriginalConstructor() ->getMock(); $filterGroup->expects($this->once()) ->method('getFilters') - ->willReturn([$filter]); + ->willReturn($filters); $searchCriteria = $this->getMockBuilder('Magento\Framework\Api\Search\SearchCriteriaInterface') ->disableOriginalConstructor() @@ -113,8 +112,8 @@ class SearchTest extends \PHPUnit_Framework_TestCase ->with($requestName); $this->requestBuilder->expects($this->once()) ->method('bindDimension') - ->with('scope', $scope); - $this->requestBuilder->expects($this->any()) + ->with('scope', $scopeId); + $this->requestBuilder->expects($this->exactly(6)) ->method('bind'); $this->requestBuilder->expects($this->once()) ->method('create') @@ -134,8 +133,31 @@ class SearchTest extends \PHPUnit_Framework_TestCase ->method('getScope') ->willReturn($scope); + $scope->expects($this->once()) + ->method('getId') + ->willReturn($scopeId); + $searchResult = $this->model->search($searchCriteria); $this->assertInstanceOf('Magento\Framework\Api\Search\SearchResultInterface', $searchResult); } + + /** + * @param $field + * @param $value + * @return \Magento\Framework\Api\Filter|\PHPUnit_Framework_MockObject_MockObject + */ + private function createFilterMock($field, $value) + { + $filter = $this->getMockBuilder('Magento\Framework\Api\Filter') + ->disableOriginalConstructor() + ->getMock(); + $filter->expects($this->once()) + ->method('getField') + ->willReturn($field); + $filter->expects($this->once()) + ->method('getValue') + ->willReturn($value); + return $filter; + } } diff --git a/lib/internal/Magento/Framework/Setup/FilePermissions.php b/lib/internal/Magento/Framework/Setup/FilePermissions.php index e70e583c27114c0071fe16d85b7cccb1f05324aa..df65ae89296fc685d3fa240720a6ea3463307670 100644 --- a/lib/internal/Magento/Framework/Setup/FilePermissions.php +++ b/lib/internal/Magento/Framework/Setup/FilePermissions.php @@ -8,8 +8,10 @@ namespace Magento\Framework\Setup; use Magento\Framework\App\Filesystem\DirectoryList; use Magento\Framework\Backup\Filesystem\Iterator\Filter; +use Magento\Framework\Filesystem\Filter\ExcludeFilter; use Magento\Framework\Filesystem; use Magento\Framework\Filesystem\Driver\File; +use Magento\Framework\OsInfo; class FilePermissions { @@ -63,19 +65,27 @@ class FilePermissions */ protected $nonWritablePathsInDirectories = []; + /** + * @var \Magento\Framework\OsInfo + */ + protected $osInfo; + /** * @param Filesystem $filesystem * @param DirectoryList $directoryList * @param File $driverFile + * @param OsInfo $osInfo */ public function __construct( Filesystem $filesystem, DirectoryList $directoryList, - File $driverFile + File $driverFile, + OsInfo $osInfo ) { $this->filesystem = $filesystem; $this->directoryList = $directoryList; $this->driverFile = $driverFile; + $this->osInfo = $osInfo; } /** @@ -152,10 +162,18 @@ class FilePermissions ); $noWritableFilesFolders = [ $this->directoryList->getPath(DirectoryList::GENERATION) . '/', - $this->directoryList->getPath(DirectoryList::DI) .'/' + $this->directoryList->getPath(DirectoryList::DI) . '/', ]; $directoryIterator = new Filter($directoryIterator, $noWritableFilesFolders); + + $directoryIterator = new ExcludeFilter( + $directoryIterator, + [ + $this->directoryList->getPath(DirectoryList::SESSION) . '/', + ] + ); + $foundNonWritable = false; try { @@ -224,10 +242,7 @@ class FilePermissions array_unshift($dirs, $varGenerationDir); foreach ($dirs as $dir) { - if (!is_dir($dir) - || !is_readable($dir) - || !is_executable($dir) - ) { + if (!$this->directoryPermissionForCLIUserValid($dir)) { return false; } } @@ -293,4 +308,16 @@ class FilePermissions $current = $this->getApplicationCurrentNonWritableDirectories(); return array_diff($required, $current); } + + /** + * Checks if directory has permissions needed for CLI user (valid directory, readable, and executable.) + * Ignores executable permission for Windows. + * + * @param string $dir + * @return bool + */ + private function directoryPermissionForCLIUserValid($dir) + { + return (is_dir($dir) && is_readable($dir) && (is_executable($dir) || $this->osInfo->isWindows())); + } } diff --git a/lib/internal/Magento/Framework/Setup/Test/Unit/FilePermissionsTest.php b/lib/internal/Magento/Framework/Setup/Test/Unit/FilePermissionsTest.php index 29869b89be72a9f4b194fff100f18b8272b80e13..3788a1ede33cfef1b935159fa8c74eeac7d8fadb 100644 --- a/lib/internal/Magento/Framework/Setup/Test/Unit/FilePermissionsTest.php +++ b/lib/internal/Magento/Framework/Setup/Test/Unit/FilePermissionsTest.php @@ -8,7 +8,6 @@ namespace Magento\Framework\Setup\Test\Unit; use \Magento\Framework\Setup\FilePermissions; use Magento\Framework\App\Filesystem\DirectoryList; -use Magento\Framework\Filesystem\Driver\File; class FilePermissionsTest extends \PHPUnit_Framework_TestCase { @@ -32,6 +31,11 @@ class FilePermissionsTest extends \PHPUnit_Framework_TestCase */ private $driverFileMock; + /** + * @var \PHPUnit_Framework_MockObject_MockObject|\Magento\Framework\OsInfo + */ + private $osInfoMock; + /** * @var FilePermissions */ @@ -42,6 +46,7 @@ class FilePermissionsTest extends \PHPUnit_Framework_TestCase $this->directoryWriteMock = $this->getMock('Magento\Framework\Filesystem\Directory\Write', [], [], '', false); $this->filesystemMock = $this->getMock('Magento\Framework\Filesystem', [], [], '', false); $this->driverFileMock = $this->getMock('Magento\Framework\Filesystem\Driver\File', [], [], '', false); + $this->osInfoMock = $this->getMock('Magento\Framework\OsInfo', [], [], '', false); $this->filesystemMock ->expects($this->any()) @@ -52,7 +57,8 @@ class FilePermissionsTest extends \PHPUnit_Framework_TestCase $this->filePermissions = new FilePermissions( $this->filesystemMock, $this->directoryListMock, - $this->driverFileMock + $this->driverFileMock, + $this->osInfoMock ); } @@ -206,6 +212,55 @@ class FilePermissionsTest extends \PHPUnit_Framework_TestCase ]; } + /** + * Directories have executable permission, not Windows + */ + public function testCheckDirectoryPermissionForCLIUser() + { + $this->directoryListMock->expects($this->once())->method('getPath')->willReturn('/var/generation'); + $this->driverFileMock->expects($this->once()) + ->method('readDirectory') + ->willReturn(['/var/generation/Composer', '/var/gen/Magento']); + // Should never check for OS if executable + $this->osInfoMock->expects($this->never())->method('isWindows'); + $this->assertTrue($this->filePermissions->checkDirectoryPermissionForCLIUser()); + } + + /** + * Directories do not have executable permissions, is Windows + */ + public function testCheckDirectoryPermissionForCLIUserWin() + { + $this->directoryListMock->expects($this->once())->method('getPath')->willReturn('/var/generationNotExec'); + $this->driverFileMock->expects($this->once()) + ->method('readDirectory') + ->willReturn(['/var/generation/ComposerNotExec', '/var/generation/MagentoNotExec']); + // Contains a 'NotExec', so is_executable will return false, isWindows should be called once for each + // directory (including parent) and return true + $this->osInfoMock->expects($this->exactly(3))->method('isWindows')->willReturn(true); + $this->assertTrue($this->filePermissions->checkDirectoryPermissionForCLIUser()); + } + + /** + * One directory does not have executable permission, is not Windows + */ + public function testCheckDirectoryPermissionForCLIUserNotExecutable() + { + $this->directoryListMock->expects($this->once())->method('getPath')->willReturn('/var/generation'); + $this->driverFileMock->expects($this->once()) + ->method('readDirectory') + ->willReturn(['/var/generation/ComposerNotExec', '/var/gen/Magento']); + // Contains a 'NotExec', so is_executable will return false, isWindows should be called and return false + $this->osInfoMock->expects($this->once())->method('isWindows')->willReturn(false); + $this->assertFalse($this->filePermissions->checkDirectoryPermissionForCLIUser()); + } + + /* + * exec directory, unix + * non-exec directory, windows + * non-exec directory, unix + */ + public function setUpDirectoryListInstallation() { $this->directoryListMock @@ -285,3 +340,46 @@ class FilePermissionsTest extends \PHPUnit_Framework_TestCase ->will($this->returnValue(false)); } } + +namespace Magento\Framework\Setup; + +/** + * Overriding the built-in PHP function is_dir, always returns true, + * allows unit test of this code without having to setup special directories. + * + * @param string $filename + * @return true + * @SuppressWarnings(PHPMD.UnusedFormalParameter) + */ +function is_dir($filename) +{ + return true; +} + +/** + * Overriding the built-in PHP function is_readable, always returns true, + * allows unit test of this code without having to setup special directories. + * + * @param string $filename + * @return true + * @SuppressWarnings(PHPMD.UnusedFormalParameter) + */ +function is_readable($filename) +{ + return true; +} + +/** + * Overriding the built-in PHP function is_executable, will return false if directory name contains 'NotExec' + * Allows unit test of this code without having to setup a special directory with non-executable permission. + * + * @param string $filename + * @return bool + */ +function is_executable($filename) +{ + if (strpos($filename, 'NotExec') !== false) { + return false; + } + return true; +} diff --git a/lib/internal/Magento/Framework/Stdlib/DateTime/Filter/Date.php b/lib/internal/Magento/Framework/Stdlib/DateTime/Filter/Date.php index 3f0749c5b9573ed64557f0959682cc71ea1a70c4..43c05e99084b505d2b88a25f97fb80ff8d6bb0c8 100644 --- a/lib/internal/Magento/Framework/Stdlib/DateTime/Filter/Date.php +++ b/lib/internal/Magento/Framework/Stdlib/DateTime/Filter/Date.php @@ -52,6 +52,11 @@ class Date implements \Zend_Filter_Interface */ public function filter($value) { - return $this->_normalToLocalFilter->filter($this->_localToNormalFilter->filter($value)); + $value = $this->_normalToLocalFilter->filter($this->_localToNormalFilter->filter($value)); + + /** + * @todo MAGETWO-51391 + */ + return str_replace("\xc2\xa0", '', $value); } } diff --git a/lib/web/jquery/jstree/jquery.jstree.js b/lib/web/jquery/jstree/jquery.jstree.js index c6ea72abecf32e2360e2b7afe30f46e6c80e7d1b..e2f6330ba45eb0ea6d74ed49a065d6745dac3c6c 100644 --- a/lib/web/jquery/jstree/jquery.jstree.js +++ b/lib/web/jquery/jstree/jquery.jstree.js @@ -31,11 +31,11 @@ (function () { if(jQuery && jQuery.jstree) { return; } var is_ie6 = false, is_ie7 = false, is_ff2 = false; -/* +/* * jsTree core */ (function ($) { - // Common functions not related to jsTree + // Common functions not related to jsTree // decided to move them to a `vakata` "namespace" $.vakata = {}; // CSS related functions @@ -63,8 +63,8 @@ if(sheet.insertRule) { sheet.insertRule(rule_name + ' { }', 0); } else { sheet.addRule(rule_name, null, 0); } return $.vakata.css.get_css(rule_name); }, - remove_css : function(rule_name, sheet) { - return $.vakata.css.get_css(rule_name, true, sheet); + remove_css : function(rule_name, sheet) { + return $.vakata.css.get_css(rule_name, true, sheet); }, add_sheet : function(opts) { var tmp = false, is_new = true; @@ -77,12 +77,12 @@ if(opts.title) { tmp.setAttribute("id", opts.title + "-stylesheet"); } } if(tmp.styleSheet) { - if(is_new) { - document.getElementsByTagName("head")[0].appendChild(tmp); - tmp.styleSheet.cssText = opts.str; + if(is_new) { + document.getElementsByTagName("head")[0].appendChild(tmp); + tmp.styleSheet.cssText = opts.str; } else { - tmp.styleSheet.cssText = tmp.styleSheet.cssText + " " + opts.str; + tmp.styleSheet.cssText = tmp.styleSheet.cssText + " " + opts.str; } } else { @@ -108,7 +108,7 @@ } }; - // private variables + // private variables var instances = [], // instance array (used by $.jstree.reference/create/focused) focused_instance = -1, // the index in the instance array of the currently focused instance plugins = {}, // list of included plugins @@ -117,7 +117,7 @@ // jQuery plugin wrapper (thanks to jquery UI widget function) $.fn.jstree = function (settings) { var isMethodCall = (typeof settings == 'string'), // is this a method call like $().jstree("open_node") - args = Array.prototype.slice.call(arguments, 1), + args = Array.prototype.slice.call(arguments, 1), returnValue = this; // if a method call execute the method on all selected instances @@ -135,8 +135,8 @@ var instance_id = $.data(this, "jstree_instance_id"), a = [], b = settings ? $.extend({}, true, settings) : {}, - c = $(this), - s = false, + c = $(this), + s = false, t = []; a = a.concat(args); if(c.data("jstree")) { a.push(c.data("jstree")); } @@ -157,14 +157,14 @@ // extend defaults with passed data s = $.extend(true, {}, $.jstree.defaults, b); s.plugins = b.plugins; - $.each(plugins, function (i, val) { - if($.inArray(i, s.plugins) === -1) { s[i] = null; delete s[i]; } + $.each(plugins, function (i, val) { + if($.inArray(i, s.plugins) === -1) { s[i] = null; delete s[i]; } else { t.push(i); } }); s.plugins = t; // push the new object to the instances array (at the same time set the default classes to the container) and init - instances[instance_id] = new $.jstree._instance(instance_id, $(this).addClass("jstree jstree-" + instance_id), s); + instances[instance_id] = new $.jstree._instance(instance_id, $(this).addClass("jstree jstree-" + instance_id), s); // init all activated plugins for this instance $.each(instances[instance_id]._get_settings().plugins, function (i, val) { instances[instance_id].data[val] = {}; }); $.each(instances[instance_id]._get_settings().plugins, function (i, val) { if(plugins[val]) { plugins[val].__init.apply(instances[instance_id]); } }); @@ -181,16 +181,16 @@ plugins : [] }, _focused : function () { return instances[focused_instance] || null; }, - _reference : function (needle) { + _reference : function (needle) { // get by instance id if(instances[needle]) { return instances[needle]; } // get by DOM (if still no luck - return null - var o = $(needle); + var o = $(needle); if(!o.length && typeof needle === "string") { o = $("#" + needle); } if(!o.length) { return null; } - return instances[o.closest(".jstree").data("jstree_instance_id")] || null; + return instances[o.closest(".jstree").data("jstree_instance_id")] || null; }, - _instance : function (index, container, settings) { + _instance : function (index, container, settings) { // for plugins to store data in this.data = { core : {} }; this.get_settings = function () { return $.extend(true, {}, settings); }; @@ -198,14 +198,14 @@ this.get_index = function () { return index; }; this.get_container = function () { return container; }; this.get_container_ul = function () { return container.children("ul:eq(0)"); }; - this._set_settings = function (s) { + this._set_settings = function (s) { settings = $.extend(true, {}, settings, s); }; }, _fn : { }, plugin : function (pname, pdata) { pdata = $.extend({}, { - __init : $.noop, + __init : $.noop, __destroy : $.noop, _fn : {}, defaults : false @@ -242,11 +242,11 @@ if(typeof rslt !== "undefined") { args = rslt; } rslt = func.apply( - $.extend({}, this, { - __callback : function (data) { + $.extend({}, this, { + __callback : function (data) { this.get_container().triggerHandler( i + '.jstree', { "inst" : this, "args" : args, "rslt" : data, "rlbk" : rlbk }); }, - __rollback : function () { + __rollback : function () { rlbk = this.get_rollback(); return rlbk; }, @@ -280,22 +280,22 @@ // code is copied from jQuery ($.browser is deprecated + there is a bug in IE) var u = navigator.userAgent.toLowerCase(), v = (u.match( /.+?(?:rv|it|ra|ie)[\/: ]([\d.]+)/ ) || [0,'0'])[1], - css_string = '' + - '.jstree ul, .jstree li { display:block; margin:0 0 0 0; padding:0 0 0 0; list-style-type:none; } ' + - '.jstree li { display:block; min-height:18px; line-height:18px; white-space:nowrap; margin-left:18px; min-width:18px; } ' + - '.jstree-rtl li { margin-left:0; margin-right:18px; } ' + - '.jstree > ul > li { margin-left:0px; } ' + - '.jstree-rtl > ul > li { margin-right:0px; } ' + - '.jstree ins { display:inline-block; text-decoration:none; width:18px; height:18px; margin:0 0 0 0; padding:0; } ' + - '.jstree a { display:inline-block; line-height:16px; height:16px; color:black; white-space:nowrap; text-decoration:none; padding:1px 2px; margin:0; } ' + - '.jstree a:focus { outline: none; } ' + - '.jstree a > ins { height:16px; width:16px; } ' + - '.jstree a > .jstree-icon { margin-right:3px; } ' + - '.jstree-rtl a > .jstree-icon { margin-left:3px; margin-right:0; } ' + - 'li.jstree-open > ul { display:block; } ' + + css_string = '' + + '.jstree ul, .jstree li { display:block; margin:0 0 0 0; padding:0 0 0 0; list-style-type:none; } ' + + '.jstree li { display:block; min-height:18px; line-height:18px; white-space:nowrap; margin-left:18px; min-width:18px; } ' + + '.jstree-rtl li { margin-left:0; margin-right:18px; } ' + + '.jstree > ul > li { margin-left:0px; } ' + + '.jstree-rtl > ul > li { margin-right:0px; } ' + + '.jstree ins { display:inline-block; text-decoration:none; width:18px; height:18px; margin:0 0 0 0; padding:0; } ' + + '.jstree a { display:inline-block; line-height:16px; height:16px; color:black; white-space:nowrap; text-decoration:none; padding:1px 2px; margin:0; } ' + + '.jstree a:focus { outline: none; } ' + + '.jstree a > ins { height:16px; width:16px; } ' + + '.jstree a > .jstree-icon { margin-right:3px; } ' + + '.jstree-rtl a > .jstree-icon { margin-left:3px; margin-right:0; } ' + + 'li.jstree-open > ul { display:block; } ' + 'li.jstree-closed > ul { display:none; } '; // Correct IE 6 (does not support the > CSS selector) - if(/msie/.test(u) && parseInt(v, 10) == 6) { + if(/msie/.test(u) && parseInt(v, 10) == 6) { is_ie6 = true; // fix image flicker and lack of caching @@ -303,28 +303,28 @@ document.execCommand("BackgroundImageCache", false, true); } catch (err) { } - css_string += '' + - '.jstree li { height:18px; margin-left:0; margin-right:0; } ' + - '.jstree li li { margin-left:18px; } ' + - '.jstree-rtl li li { margin-left:0px; margin-right:18px; } ' + - 'li.jstree-open ul { display:block; } ' + - 'li.jstree-closed ul { display:none !important; } ' + - '.jstree li a { display:inline; border-width:0 !important; padding:0px 2px !important; } ' + - '.jstree li a ins { height:16px; width:16px; margin-right:3px; } ' + + css_string += '' + + '.jstree li { height:18px; margin-left:0; margin-right:0; } ' + + '.jstree li li { margin-left:18px; } ' + + '.jstree-rtl li li { margin-left:0px; margin-right:18px; } ' + + 'li.jstree-open ul { display:block; } ' + + 'li.jstree-closed ul { display:none !important; } ' + + '.jstree li a { display:inline; border-width:0 !important; padding:0px 2px !important; } ' + + '.jstree li a ins { height:16px; width:16px; margin-right:3px; } ' + '.jstree-rtl li a ins { margin-right:0px; margin-left:3px; } '; } // Correct IE 7 (shifts anchor nodes onhover) - if(/msie/.test(u) && parseInt(v, 10) == 7) { + if(/msie/.test(u) && parseInt(v, 10) == 7) { is_ie7 = true; css_string += '.jstree li a { border-width:0 !important; padding:0px 2px !important; } '; } // correct ff2 lack of display:inline-block if(!/compatible/.test(u) && /mozilla/.test(u) && parseFloat(v, 10) < 1.9) { is_ff2 = true; - css_string += '' + - '.jstree ins { display:-moz-inline-box; } ' + + css_string += '' + + '.jstree ins { display:-moz-inline-box; } ' + '.jstree li { line-height:12px; } ' + // WHY?? - '.jstree a { display:-moz-inline-box; } ' + + '.jstree a { display:-moz-inline-box; } ' + '.jstree .jstree-no-icons .jstree-checkbox { display:-moz-inline-stack !important; } '; /* this shouldn't be here as it is theme specific */ } @@ -339,7 +339,7 @@ this.data.core.to_open = this.get_settings().core.initially_open; this.data.core.to_load = this.get_settings().core.initially_load; }, - defaults : { + defaults : { html_titles : false, animation : 500, initially_open : [], @@ -354,9 +354,9 @@ multiple_selection : "Multiple selection" } }, - _fn : { - init : function () { - this.set_focus(); + _fn : { + init : function () { + this.set_focus(); if(this._get_settings().core.rtl) { this.get_container().addClass("jstree-rtl").css("direction", "rtl"); } @@ -369,16 +369,16 @@ // if(trgt.is("ins") && event.pageY - trgt.offset().top < this.data.core.li_height) { this.toggle_node(trgt); } this.toggle_node(trgt); }, this)) - .bind("mousedown.jstree", $.proxy(function () { + .bind("mousedown.jstree", $.proxy(function () { this.set_focus(); // This used to be setTimeout(set_focus,0) - why? }, this)) - .bind("dblclick.jstree", function (event) { + .bind("dblclick.jstree", function (event) { var sel; if(document.selection && document.selection.empty) { document.selection.empty(); } else { if(window.getSelection) { sel = window.getSelection(); - try { + try { sel.removeAllRanges(); sel.collapse(); } catch (err) { } @@ -387,7 +387,7 @@ }); if(this._get_settings().core.notify_plugins) { this.get_container() - .bind("load_node.jstree", $.proxy(function (e, data) { + .bind("load_node.jstree", $.proxy(function (e, data) { var o = this._get_node(data.rslt.obj), t = this; if(o === -1) { o = this.get_container_ul(); } @@ -406,7 +406,7 @@ } if(this._get_settings().core.load_open) { this.get_container() - .bind("load_node.jstree", $.proxy(function (e, data) { + .bind("load_node.jstree", $.proxy(function (e, data) { var o = this._get_node(data.rslt.obj), t = this; if(o === -1) { o = this.get_container_ul(); } @@ -419,7 +419,7 @@ this.__callback(); this.load_node(-1, function () { this.loaded(); this.reload_nodes(); }); }, - destroy : function () { + destroy : function () { var i, n = this.get_index(), s = this._get_settings(), @@ -430,12 +430,12 @@ }); this.__callback(); // set focus to another instance if this one is focused - if(this.is_focused()) { - for(i in instances) { - if(instances.hasOwnProperty(i) && i != n) { - instances[i].set_focus(); - break; - } + if(this.is_focused()) { + for(i in instances) { + if(instances.hasOwnProperty(i) && i != n) { + instances[i].set_focus(); + break; + } } } // if no other instance found @@ -476,7 +476,7 @@ save_opened : function () { var _this = this; this.data.core.to_open = []; - this.get_container_ul().find("li.jstree-open").each(function () { + this.get_container_ul().find("li.jstree-open").each(function () { if(this.id) { _this.data.core.to_open.push("#" + this.id.toString().replace(/^#/,"").replace(/\\\//g,"/").replace(/\//g,"\\\/").replace(/\\\./g,".").replace(/\./g,"\\.").replace(/\:/g,"\\:")); } }); this.__callback(_this.data.core.to_open); @@ -487,9 +487,9 @@ done = true, current = [], remaining = []; - if(!is_callback) { - this.data.core.reopen = false; - this.data.core.refreshing = true; + if(!is_callback) { + this.data.core.reopen = false; + this.data.core.refreshing = true; this.data.core.to_open = $.map($.makeArray(this.data.core.to_open), function (n) { return "#" + n.toString().replace(/^#/,"").replace(/\\\//g,"/").replace(/\//g,"\\\/").replace(/\\\./g,".").replace(/\./g,"\\.").replace(/\:/g,"\\:"); }); this.data.core.to_load = $.map($.makeArray(this.data.core.to_load), function (n) { return "#" + n.toString().replace(/^#/,"").replace(/\\\//g,"/").replace(/\//g,"\\\/").replace(/\\\./g,".").replace(/\./g,"\\.").replace(/\:/g,"\\:"); }); if(this.data.core.to_open.length) { @@ -504,7 +504,7 @@ }); if(current.length) { this.data.core.to_load = remaining; - $.each(current, function (i, val) { + $.each(current, function (i, val) { if(!_this._is_loaded(val)) { _this.load_node(val, function () { _this.reload_nodes(true); }, function () { _this.reload_nodes(true); }); done = false; @@ -514,10 +514,10 @@ } if(this.data.core.to_open.length) { $.each(this.data.core.to_open, function (i, val) { - _this.open_node(val, false, true); + _this.open_node(val, false, true); }); } - if(done) { + if(done) { // TODO: find a more elegant approach to syncronizing returning requests if(this.data.core.reopen) { clearTimeout(this.data.core.reopen); } this.data.core.reopen = setTimeout(function () { _this.__callback({}, _this); }, 50); @@ -529,7 +529,7 @@ var _this = this; if(this.data.core.to_open.length) { $.each(this.data.core.to_open, function (i, val) { - _this.open_node(val, false, true); + _this.open_node(val, false, true); }); } this.__callback({}); @@ -545,36 +545,36 @@ this.load_node(obj, function () { _this.__callback({ "obj" : obj}); _this.reload_nodes(); }); }, // Dummy function to fire after the first load (so that there is a jstree.loaded event) - loaded : function () { - this.__callback(); + loaded : function () { + this.__callback(); }, // deal with focus - set_focus : function () { + set_focus : function () { if(this.is_focused()) { return; } var f = $.jstree._focused(); if(f) { f.unset_focus(); } - this.get_container().addClass("jstree-focused"); - focused_instance = this.get_index(); + this.get_container().addClass("jstree-focused"); + focused_instance = this.get_index(); this.__callback(); }, - is_focused : function () { - return focused_instance == this.get_index(); + is_focused : function () { + return focused_instance == this.get_index(); }, unset_focus : function () { if(this.is_focused()) { - this.get_container().removeClass("jstree-focused"); - focused_instance = -1; + this.get_container().removeClass("jstree-focused"); + focused_instance = -1; } this.__callback(); }, // traverse - _get_node : function (obj) { - var $obj = $(obj, this.get_container()); - if($obj.is(".jstree") || obj == -1) { return -1; } - $obj = $obj.closest("li", this.get_container()); - return $obj.length ? $obj : false; + _get_node : function (obj) { + var $obj = $(obj, this.get_container()); + if($obj.is(".jstree") || obj == -1) { return -1; } + $obj = $obj.closest("li", this.get_container()); + return $obj.length ? $obj : false; }, _get_next : function (obj, strict) { obj = this._get_node(obj); @@ -684,7 +684,7 @@ open_all : function (obj, do_animation, original_obj) { obj = obj ? this._get_node(obj) : -1; if(!obj || obj === -1) { obj = this.get_container_ul(); } - if(original_obj) { + if(original_obj) { obj = obj.find("li.jstree-closed"); } else { @@ -693,8 +693,8 @@ else { obj = obj.find("li.jstree-closed"); } } var _this = this; - obj.each(function () { - var __this = this; + obj.each(function () { + var __this = this; if(!_this._is_loaded(this)) { _this.open_node(this, function() { _this.open_all(__this, do_animation, original_obj); }, !do_animation); } else { _this.open_node(this, false, !do_animation); } }); @@ -719,9 +719,9 @@ this.__callback({ "obj" : obj }); }, // rollback - get_rollback : function () { + get_rollback : function () { this.__callback(); - return { i : this.get_index(), h : this.get_container().children("ul").clone(true), d : this.data }; + return { i : this.get_index(), h : this.get_container().children("ul").clone(true), d : this.data }; }, set_rollback : function (html, data) { this.get_container().empty().append(html); @@ -764,7 +764,7 @@ } tmp.prepend("<ins class='jstree-icon'> </ins>"); if(!m.icon && js.icon) { m.icon = js.icon; } - if(m.icon) { + if(m.icon) { if(m.icon.indexOf("/") === -1) { tmp.children("ins").addClass(m.icon); } else { tmp.children("ins").css("background","url('" + m.icon + "') center center no-repeat"); } } @@ -879,11 +879,11 @@ case "first": case "before": case "inside": - p.cp = 0; + p.cp = 0; break; case "after": case "last": - p.cp = p.rt.get_container().find(" > ul > li").length; + p.cp = p.rt.get_container().find(" > ul > li").length; break; default: p.cp = p.p; @@ -909,10 +909,10 @@ p.cr = p.r; break; case "last": - p.cp = p.r.find(" > ul > li").length; + p.cp = p.r.find(" > ul > li").length; p.cr = p.r; break; - default: + default: p.cp = p.p; p.cr = p.r; break; @@ -933,18 +933,18 @@ var obj = prepared_move, ret = true, r = obj.r === -1 ? this.get_container() : obj.r; if(!obj || !obj.o || obj.or[0] === obj.o[0]) { return false; } if(obj.op && obj.np && obj.op[0] === obj.np[0] && obj.cp - 1 === obj.o.index()) { return false; } - obj.o.each(function () { + obj.o.each(function () { if(r.parentsUntil(".jstree", "li").addBack().index(this) !== -1) { ret = false; return false; } }); return ret; }, move_node : function (obj, ref, position, is_copy, is_prepared, skip_check) { - if(!is_prepared) { + if(!is_prepared) { return this.prepare_move(obj, ref, position, function (p) { this.move_node(p, false, false, is_copy, true, skip_check); }); } - if(is_copy) { + if(is_copy) { prepared_move.cy = true; } if(!skip_check && !this.check_move()) { return false; } @@ -960,12 +960,12 @@ else { o = obj.o; } if(obj.or.length) { obj.or.before(o); } - else { + else { if(!obj.np.children("ul").length) { $("<ul />").appendTo(obj.np); } - obj.np.children("ul:eq(0)").append(o); + obj.np.children("ul:eq(0)").append(o); } - try { + try { obj.ot.clean_node(obj.op); obj.rt.clean_node(obj.np); if(!obj.op.find("> ul > li").length) { @@ -973,9 +973,9 @@ } } catch (e) { } - if(is_copy) { + if(is_copy) { prepared_move.cy = true; - prepared_move.oc = o; + prepared_move.oc = o; } this.__callback(prepared_move); return prepared_move; @@ -986,7 +986,7 @@ })(jQuery); //*/ -/* +/* * jsTree ui plugin * This plugins handles selecting/deselecting/hovering/dehovering nodes */ @@ -998,7 +998,7 @@ e2 = $('<textarea cols="10" rows="2" style="overflow: hidden;"></textarea>').css({ position: 'absolute', top: -1000, left: 0 }).appendTo('body'); scrollbar_width = e1.width() - e2.width(); e1.add(e2).remove(); - } + } else { e1 = $('<div />').css({ width: 100, height: 100, overflow: 'auto', position: 'absolute', top: -1000, left: 0 }) .prependTo('body').append('<div />').find('div').css({ width: '100%', height: 200 }); @@ -1007,9 +1007,9 @@ } }); $.jstree.plugin("ui", { - __init : function () { - this.data.ui.selected = $(); - this.data.ui.last_selected = false; + __init : function () { + this.data.ui.selected = $(); + this.data.ui.last_selected = false; this.data.ui.hovered = null; this.data.ui.to_select = this.get_settings().ui.initially_select; @@ -1031,41 +1031,41 @@ this.dehover_node(event.target); } }, this)) - .bind("reopen.jstree", $.proxy(function () { + .bind("reopen.jstree", $.proxy(function () { this.reselect(); }, this)) - .bind("get_rollback.jstree", $.proxy(function () { + .bind("get_rollback.jstree", $.proxy(function () { this.dehover_node(); this.save_selected(); }, this)) - .bind("set_rollback.jstree", $.proxy(function () { + .bind("set_rollback.jstree", $.proxy(function () { this.reselect(); }, this)) - .bind("close_node.jstree", $.proxy(function (event, data) { + .bind("close_node.jstree", $.proxy(function (event, data) { var s = this._get_settings().ui, obj = this._get_node(data.rslt.obj), clk = (obj && obj.length) ? obj.children("ul").find("a.jstree-clicked") : $(), _this = this; if(s.selected_parent_close === false || !clk.length) { return; } - clk.each(function () { + clk.each(function () { _this.deselect_node(this); if(s.selected_parent_close === "select_parent") { _this.select_node(obj); } }); }, this)) - .bind("delete_node.jstree", $.proxy(function (event, data) { + .bind("delete_node.jstree", $.proxy(function (event, data) { var s = this._get_settings().ui.select_prev_on_delete, obj = this._get_node(data.rslt.obj), clk = (obj && obj.length) ? obj.find("a.jstree-clicked") : [], _this = this; clk.each(function () { _this.deselect_node(this); }); - if(s && clk.length) { - data.rslt.prev.each(function () { + if(s && clk.length) { + data.rslt.prev.each(function () { if(this.parentNode) { _this.select_node(this); return false; /* if return false is removed all prev nodes will be selected */} }); } }, this)) - .bind("move_node.jstree", $.proxy(function (event, data) { - if(data.rslt.cy) { + .bind("move_node.jstree", $.proxy(function (event, data) { + if(data.rslt.cy) { data.rslt.oc.find("a.jstree-clicked").removeClass("jstree-clicked"); } }, this)); @@ -1080,13 +1080,13 @@ disable_selecting_children : false, initially_select : [] }, - _fn : { + _fn : { _get_node : function (obj, allow_multiple) { if(typeof obj === "undefined" || obj === null) { return allow_multiple ? this.data.ui.selected : this.data.ui.last_selected; } - var $obj = $(obj, this.get_container()); - if($obj.is(".jstree") || obj == -1) { return -1; } - $obj = $obj.closest("li", this.get_container()); - return $obj.length ? $obj : false; + var $obj = $(obj, this.get_container()); + if($obj.is(".jstree") || obj == -1) { return -1; } + $obj = $obj.closest("li", this.get_container()); + return $obj.length ? $obj : false; }, _ui_notify : function (n, data) { if(data.selected) { @@ -1138,7 +1138,7 @@ proceed = true, t = this; if(check) { - if(s.disable_selecting_children && is_multiple && + if(s.disable_selecting_children && is_multiple && ( (obj.parentsUntil(".jstree","li").children("a.jstree-clicked").length) || (obj.children("ul").find("a.jstree-clicked:eq(0)").length) @@ -1163,22 +1163,22 @@ proceed = false; } break; - case (is_selected && !is_multiple): + case (is_selected && !is_multiple): this.deselect_all(); is_selected = false; proceed = true; break; - case (!is_selected && !is_multiple): + case (!is_selected && !is_multiple): if(s.select_limit == -1 || s.select_limit > 0) { this.deselect_all(); proceed = true; } break; - case (is_selected && is_multiple): + case (is_selected && is_multiple): this.deselect_node(obj); break; - case (!is_selected && is_multiple): - if(s.select_limit == -1 || this.data.ui.selected.length + 1 <= s.select_limit) { + case (!is_selected && is_multiple): + if(s.select_limit == -1 || this.data.ui.selected.length + 1 <= s.select_limit) { proceed = true; } break; @@ -1201,11 +1201,11 @@ obj = this._get_node(obj); if(!obj || obj === -1 || !obj.length || !obj.is(":visible")) { return; } t = obj.offset().top - this.get_container().offset().top; - if(t < 0) { - c.scrollTop = c.scrollTop + t - 1; + if(t < 0) { + c.scrollTop = c.scrollTop + t - 1; } - if(t + this.data.core.li_height + (c.scrollWidth > c.offsetWidth ? scrollbar_width : 0) > c.offsetHeight) { - c.scrollTop = c.scrollTop + (t - c.offsetHeight + this.data.core.li_height + 1 + (c.scrollWidth > c.offsetWidth ? scrollbar_width : 0)); + if(t + this.data.core.li_height + (c.scrollWidth > c.offsetWidth ? scrollbar_width : 0) > c.offsetHeight) { + c.scrollTop = c.scrollTop + (t - c.offsetHeight + this.data.core.li_height + 1 + (c.scrollWidth > c.offsetWidth ? scrollbar_width : 0)); } } }, @@ -1226,8 +1226,8 @@ else { this.select_node(obj); } }, is_selected : function (obj) { return this.data.ui.selected.index(this._get_node(obj)) >= 0; }, - get_selected : function (context) { - return context ? $(context).find("a.jstree-clicked").parent() : this.data.ui.selected; + get_selected : function (context) { + return context ? $(context).find("a.jstree-clicked").parent() : this.data.ui.selected; }, deselect_all : function (context) { var ret = context ? $(context).find("a.jstree-clicked").parent() : this.get_container().find("a.jstree-clicked").parent(); @@ -1243,12 +1243,12 @@ })(jQuery); //*/ -/* +/* * jsTree CRRM plugin * Handles creating/renaming/removing/moving nodes by user interaction. */ (function ($) { - $.jstree.plugin("crrm", { + $.jstree.plugin("crrm", { __init : function () { this.get_container() .bind("move_node.jstree", $.proxy(function (e, data) { @@ -1279,7 +1279,7 @@ t = this.get_text(obj), h1 = $("<div />", { css : { "position" : "absolute", "top" : "-200px", "left" : (rtl ? "0px" : "-1000px"), "visibility" : "hidden" } }).appendTo("body"), h2 = obj.css("position","relative").append( - $("<input />", { + $("<input />", { "value" : t, "class" : "jstree-rename-input", // "size" : t.length, @@ -1318,7 +1318,7 @@ if(key == 13) { return false; } } }) - ).children(".jstree-rename-input"); + ).children(".jstree-rename-input"); this.set_text(obj, ""); h1.css({ fontFamily : h2.css('fontFamily') || '', @@ -1336,7 +1336,7 @@ obj = this._get_node(obj); this.__rollback(); var f = this.__callback; - this._show_input(obj, function (obj, new_name, old_name) { + this._show_input(obj, function (obj, new_name, old_name) { f.call(this, { "obj" : obj, "new_name" : new_name, "old_name" : old_name }); }); }, @@ -1350,8 +1350,8 @@ pos = $(t).index(); if(callback) { callback.call(this, t); } if(p.length && p.hasClass("jstree-closed")) { this.open_node(p, false, true); } - if(!skip_rename) { - this._show_input(t, function (obj, new_name, old_name) { + if(!skip_rename) { + this._show_input(t, function (obj, new_name, old_name) { _this.__callback({ "obj" : obj, "name" : new_name, "parent" : p, "position" : pos }); }); } @@ -1374,7 +1374,7 @@ }, move_node : function (obj, ref, position, is_copy, is_prepared, skip_check) { var s = this._get_settings().crrm.move; - if(!is_prepared) { + if(!is_prepared) { if(typeof position === "undefined") { position = s.default_position; } if(position === "inside" && !s.default_position.match(/^(before|after)$/)) { position = s.default_position; } return this.__call_old(true, obj, ref, position, is_copy, false, skip_check); @@ -1400,7 +1400,7 @@ this.data.crrm.cp_nodes = obj; this.__callback({ "obj" : obj }); }, - paste : function (obj) { + paste : function (obj) { obj = this._get_node(obj); if(!obj || !obj.length) { return false; } var nodes = this.data.crrm.ct_nodes ? this.data.crrm.ct_nodes : this.data.crrm.cp_nodes; @@ -1416,7 +1416,7 @@ })(jQuery); //*/ -/* +/* * jsTree themes plugin * Handles loading and setting themes, as well as detecting path to themes, etc. */ @@ -1425,12 +1425,12 @@ // this variable stores the path to the themes folder - if left as false - it will be autodetected $.jstree._themes = false; $.jstree.plugin("themes", { - __init : function () { + __init : function () { this.get_container() .bind("init.jstree", $.proxy(function () { var s = this._get_settings().themes; - this.data.themes.dots = s.dots; - this.data.themes.icons = s.icons; + this.data.themes.dots = s.dots; + this.data.themes.icons = s.icons; this.set_theme(s.theme, s.url); }, this)) .bind("loaded.jstree", $.proxy(function () { @@ -1441,10 +1441,10 @@ else { this.show_icons(); } }, this)); }, - defaults : { - theme : "default", + defaults : { + theme : "default", url : false, - dots : true, + dots : false, icons : true }, _fn : { @@ -1452,7 +1452,7 @@ if(!theme_name) { return false; } if(!theme_url) { theme_url = $.jstree._themes + theme_name + '/style.css'; } if($.inArray(theme_url, themes_loaded) == -1) { - $.vakata.css.add_sheet({ "url" : theme_url }); + // $.vakata.css.add_sheet({ "url" : theme_url }); themes_loaded.push(theme_url); } if(this.data.themes.theme != theme_name) { @@ -1480,10 +1480,10 @@ // autodetect themes path $(function () { if($.jstree._themes === false) { - $("script").each(function () { - if(this.src.toString().match(/jquery\.jstree[^\/]*?\.js(\?.*)?$/)) { - $.jstree._themes = this.src.toString().replace(/jquery\.jstree[^\/]*?\.js(\?.*)?$/, "") + 'themes/'; - return false; + $("script").each(function () { + if(this.src.toString().match(/jquery\.jstree[^\/]*?\.js(\?.*)?$/)) { + $.jstree._themes = this.src.toString().replace(/jquery\.jstree[^\/]*?\.js(\?.*)?$/, "") + 'themes/'; + return false; } }); } @@ -1503,7 +1503,7 @@ var bound = []; function exec(i, event) { var f = $.jstree._focused(), tmp; - if(f && f.data && f.data.hotkeys && f.data.hotkeys.enabled) { + if(f && f.data && f.data.hotkeys && f.data.hotkeys.enabled) { tmp = f._get_settings().hotkeys[i]; if(tmp) { return tmp.call(f, event); } } @@ -1528,37 +1528,37 @@ this.enable_hotkeys(); }, defaults : { - "up" : function () { + "up" : function () { var o = this.data.ui.hovered || this.data.ui.last_selected || -1; this.hover_node(this._get_prev(o)); - return false; + return false; }, - "ctrl+up" : function () { + "ctrl+up" : function () { var o = this.data.ui.hovered || this.data.ui.last_selected || -1; this.hover_node(this._get_prev(o)); - return false; + return false; }, - "shift+up" : function () { + "shift+up" : function () { var o = this.data.ui.hovered || this.data.ui.last_selected || -1; this.hover_node(this._get_prev(o)); - return false; + return false; }, - "down" : function () { + "down" : function () { var o = this.data.ui.hovered || this.data.ui.last_selected || -1; this.hover_node(this._get_next(o)); return false; }, - "ctrl+down" : function () { + "ctrl+down" : function () { var o = this.data.ui.hovered || this.data.ui.last_selected || -1; this.hover_node(this._get_next(o)); return false; }, - "shift+down" : function () { + "shift+down" : function () { var o = this.data.ui.hovered || this.data.ui.last_selected || -1; this.hover_node(this._get_next(o)); return false; }, - "left" : function () { + "left" : function () { var o = this.data.ui.hovered || this.data.ui.last_selected; if(o) { if(o.hasClass("jstree-open")) { this.close_node(o); } @@ -1566,7 +1566,7 @@ } return false; }, - "ctrl+left" : function () { + "ctrl+left" : function () { var o = this.data.ui.hovered || this.data.ui.last_selected; if(o) { if(o.hasClass("jstree-open")) { this.close_node(o); } @@ -1574,7 +1574,7 @@ } return false; }, - "shift+left" : function () { + "shift+left" : function () { var o = this.data.ui.hovered || this.data.ui.last_selected; if(o) { if(o.hasClass("jstree-open")) { this.close_node(o); } @@ -1582,7 +1582,7 @@ } return false; }, - "right" : function () { + "right" : function () { var o = this.data.ui.hovered || this.data.ui.last_selected; if(o && o.length) { if(o.hasClass("jstree-closed")) { this.open_node(o); } @@ -1590,7 +1590,7 @@ } return false; }, - "ctrl+right" : function () { + "ctrl+right" : function () { var o = this.data.ui.hovered || this.data.ui.last_selected; if(o && o.length) { if(o.hasClass("jstree-closed")) { this.open_node(o); } @@ -1598,7 +1598,7 @@ } return false; }, - "shift+right" : function () { + "shift+right" : function () { var o = this.data.ui.hovered || this.data.ui.last_selected; if(o && o.length) { if(o.hasClass("jstree-closed")) { this.open_node(o); } @@ -1606,19 +1606,19 @@ } return false; }, - "space" : function () { - if(this.data.ui.hovered) { this.data.ui.hovered.children("a:eq(0)").click(); } - return false; + "space" : function () { + if(this.data.ui.hovered) { this.data.ui.hovered.children("a:eq(0)").click(); } + return false; }, - "ctrl+space" : function (event) { + "ctrl+space" : function (event) { event.type = "click"; - if(this.data.ui.hovered) { this.data.ui.hovered.children("a:eq(0)").trigger(event); } - return false; + if(this.data.ui.hovered) { this.data.ui.hovered.children("a:eq(0)").trigger(event); } + return false; }, - "shift+space" : function (event) { + "shift+space" : function (event) { event.type = "click"; - if(this.data.ui.hovered) { this.data.ui.hovered.children("a:eq(0)").trigger(event); } - return false; + if(this.data.ui.hovered) { this.data.ui.hovered.children("a:eq(0)").trigger(event); } + return false; }, "f2" : function () { this.rename(this.data.ui.hovered || this.data.ui.last_selected); }, "del" : function () { this.remove(this.data.ui.hovered || this._get_node(null)); } @@ -1635,7 +1635,7 @@ })(jQuery); //*/ -/* +/* * jsTree JSON plugin * The JSON data store. Datastores are build by overriding the `load_node` and `_is_loaded` functions. */ @@ -1649,11 +1649,11 @@ }); } }, - defaults : { + defaults : { // `data` can be a function: // * accepts two arguments - node being loaded and a callback to pass the result to // * will be executed in the current tree's scope & ajax won't be supported - data : false, + data : false, ajax : false, correct_state : true, progressive_render : false, @@ -1661,9 +1661,9 @@ }, _fn : { load_node : function (obj, s_call, e_call) { var _this = this; this.load_node_json(obj, function () { _this.__callback({ "obj" : _this._get_node(obj) }); s_call.call(this); }, e_call); }, - _is_loaded : function (obj) { + _is_loaded : function (obj) { var s = this._get_settings().json_data; - obj = this._get_node(obj); + obj = this._get_node(obj); return obj == -1 || !obj || (!s.ajax && !s.progressive_render && !$.isFunction(s.data)) || obj.is(".jstree-open, .jstree-leaf") || obj.children("ul").children("li").length > 0; }, refresh : function (obj) { @@ -1701,7 +1701,7 @@ case ($.isFunction(s.data)): s.data.call(this, obj, $.proxy(function (d) { d = this._parse_json(d, obj); - if(!d) { + if(!d) { if(obj === -1 || !obj) { if(s.correct_state) { this.get_container().children("ul").empty(); } } @@ -1727,7 +1727,7 @@ this.get_container().children("ul").empty().append(d.children()); this.clean_node(); } - else { + else { if(s.correct_state) { this.get_container().children("ul").empty(); } } } @@ -1735,7 +1735,7 @@ break; case (!s.data && !!s.ajax) || (!!s.data && !!s.ajax && obj && obj !== -1): error_func = function (x, t, e) { - var ef = this.get_settings().json_data.ajax.error; + var ef = this.get_settings().json_data.ajax.error; if(ef) { ef.call(this, x, t, e); } if(obj != -1 && obj.length) { obj.children("a.jstree-loading").removeClass("jstree-loading"); @@ -1748,7 +1748,7 @@ if(e_call) { e_call.call(this); } }; success_func = function (d, t, x) { - var sf = this.get_settings().json_data.ajax.success; + var sf = this.get_settings().json_data.ajax.success; if(sf) { d = sf.call(this,d,t,x) || d; } if(d === "" || (d && d.toString && d.toString().replace(/^[\s\n]+$/,"") === "") || (!$.isArray(d) && !$.isPlainObject(d))) { return error_func.call(this, x, t, ""); @@ -1762,17 +1762,17 @@ } else { if(obj === -1 || !obj) { - if(s.correct_state) { - this.get_container().children("ul").empty(); + if(s.correct_state) { + this.get_container().children("ul").empty(); if(s_call) { s_call.call(this); } } } else { obj.children("a.jstree-loading").removeClass("jstree-loading"); obj.removeData("jstree_is_loading"); - if(s.correct_state) { + if(s.correct_state) { this.correct_state(obj); - if(s_call) { s_call.call(this); } + if(s_call) { s_call.call(this); } } } } @@ -1788,14 +1788,14 @@ } }, _parse_json : function (js, obj, is_callback) { - var d = false, + var d = false, p = this._get_settings(), s = p.json_data, t = p.core.html_titles, tmp, i, j, ul1, ul2; if(!js) { return d; } - if(s.progressive_unload && obj && obj !== -1) { + if(s.progressive_unload && obj && obj !== -1) { obj.data("jstree_children", d); } if($.isArray(js)) { @@ -1826,14 +1826,14 @@ } tmp.prepend("<ins class='jstree-icon'> </ins>"); if(!m.icon && js.icon) { m.icon = js.icon; } - if(m.icon) { + if(m.icon) { if(m.icon.indexOf("/") === -1) { tmp.children("ins").addClass(m.icon); } else { tmp.children("ins").css("background","url('" + m.icon + "') center center no-repeat"); } } d.append(tmp); }); d.prepend("<ins class='jstree-icon'> </ins>"); - if(js.children) { + if(js.children) { if(s.progressive_render && js.state !== "open") { d.addClass("jstree-closed").data("jstree_children", js.children); } @@ -1858,8 +1858,8 @@ return d; }, get_json : function (obj, li_attr, a_attr, is_callback) { - var result = [], - s = this._get_settings(), + var result = [], + s = this._get_settings(), _this = this, tmp1, tmp2, li, a, t, lang; obj = this._get_node(obj); @@ -1872,10 +1872,10 @@ li = $(this); tmp1 = { data : [] }; if(li_attr.length) { tmp1.attr = { }; } - $.each(li_attr, function (i, v) { - tmp2 = li.attr(v); + $.each(li_attr, function (i, v) { + tmp2 = li.attr(v); if(tmp2 && tmp2.length && tmp2.replace(/jstree[^ ]*/ig,'').length) { - tmp1.attr[v] = (" " + tmp2).replace(/ jstree[^ ]*/ig,'').replace(/\s+$/ig," ").replace(/^ /,"").replace(/ $/,""); + tmp1.attr[v] = (" " + tmp2).replace(/ jstree[^ ]*/ig,'').replace(/\s+$/ig," ").replace(/^ /,"").replace(/ $/,""); } }); if(li.hasClass("jstree-open")) { tmp1.state = "open"; } @@ -1885,11 +1885,11 @@ a.each(function () { t = $(this); if( - a_attr.length || - $.inArray("languages", s.plugins) !== -1 || - t.children("ins").get(0).style.backgroundImage.length || + a_attr.length || + $.inArray("languages", s.plugins) !== -1 || + t.children("ins").get(0).style.backgroundImage.length || (t.children("ins").get(0).className && t.children("ins").get(0).className.replace(/jstree[^ ]*|$/ig,'').length) - ) { + ) { lang = false; if($.inArray("languages", s.plugins) !== -1 && $.isArray(s.languages) && s.languages.length) { $.each(s.languages, function (l, lv) { @@ -1899,7 +1899,7 @@ } }); } - tmp2 = { attr : { }, title : _this.get_text(t, lang) }; + tmp2 = { attr : { }, title : _this.get_text(t, lang) }; $.each(a_attr, function (k, z) { tmp2.attr[z] = (" " + (t.attr(z) || "")).replace(/ jstree[^ ]*/ig,'').replace(/\s+$/ig," ").replace(/^ /,"").replace(/ $/,""); }); @@ -1932,7 +1932,7 @@ })(jQuery); //*/ -/* +/* * jsTree languages plugin * Adds support for multiple language versions in one tree * This basically allows for many titles coexisting in one node, but only one of them being visible at any given time @@ -1943,7 +1943,7 @@ __init : function () { this._load_css(); }, defaults : [], _fn : { - set_lang : function (i) { + set_lang : function (i) { var langs = this._get_settings().languages, st = false, selector = ".jstree-" + this.get_index() + ' a'; @@ -2081,7 +2081,7 @@ this.get_container() .one( ( this.data.ui ? "reselect" : "reopen" ) + ".jstree", $.proxy(function () { this.get_container() - .bind("open_node.jstree close_node.jstree select_node.jstree deselect_node.jstree", $.proxy(function (e) { + .bind("open_node.jstree close_node.jstree select_node.jstree deselect_node.jstree", $.proxy(function (e) { if(this._get_settings().cookies.auto_save) { this.save_cookie((e.handleObj.namespace + e.handleObj.type).replace("jstree","")); } }, this)); }, this)); @@ -2115,20 +2115,20 @@ switch(c) { case "open_node": case "close_node": - if(!!s.save_opened) { - this.save_opened(); - $.cookie(s.save_opened, this.data.core.to_open.join(","), s.cookie_options); + if(!!s.save_opened) { + this.save_opened(); + $.cookie(s.save_opened, this.data.core.to_open.join(","), s.cookie_options); } - if(!!s.save_loaded) { - this.save_loaded(); - $.cookie(s.save_loaded, this.data.core.to_load.join(","), s.cookie_options); + if(!!s.save_loaded) { + this.save_loaded(); + $.cookie(s.save_loaded, this.data.core.to_load.join(","), s.cookie_options); } break; case "select_node": case "deselect_node": - if(!!s.save_selected && this.data.ui) { - this.save_selected(); - $.cookie(s.save_selected, this.data.ui.to_select.join(","), s.cookie_options); + if(!!s.save_selected && this.data.ui) { + this.save_selected(); + $.cookie(s.save_selected, this.data.ui.to_select.join(","), s.cookie_options); } break; } @@ -2201,7 +2201,7 @@ helper_top : 10, user_data : {}, - drag_start : function (e, data, html) { + drag_start : function (e, data, html) { if($.vakata.dnd.is_drag) { $.vakata.drag_stop({}); } try { e.currentTarget.unselectable = "on"; @@ -2217,10 +2217,10 @@ $(document).bind("mouseup", $.vakata.dnd.drag_stop); return false; }, - drag : function (e) { + drag : function (e) { if(!$.vakata.dnd.is_down) { return; } if(!$.vakata.dnd.is_drag) { - if(Math.abs(e.pageX - $.vakata.dnd.init_x) > 5 || Math.abs(e.pageY - $.vakata.dnd.init_y) > 5) { + if(Math.abs(e.pageX - $.vakata.dnd.init_x) > 5 || Math.abs(e.pageY - $.vakata.dnd.init_y) > 5) { $.vakata.dnd.helper.appendTo("body"); $.vakata.dnd.is_drag = true; $(document).triggerHandler("drag_start.vakata", { "event" : e, "data" : $.vakata.dnd.user_data }); @@ -2231,18 +2231,18 @@ // maybe use a scrolling parent element instead of document? if(e.type === "mousemove") { // thought of adding scroll in order to move the helper, but mouse poisition is n/a var d = $(document), t = d.scrollTop(), l = d.scrollLeft(); - if(e.pageY - t < 20) { + if(e.pageY - t < 20) { if(sti && dir1 === "down") { clearInterval(sti); sti = false; } if(!sti) { dir1 = "up"; sti = setInterval(function () { $(document).scrollTop($(document).scrollTop() - $.vakata.dnd.scroll_spd); }, 150); } } - else { + else { if(sti && dir1 === "up") { clearInterval(sti); sti = false; } } if($(window).height() - (e.pageY - t) < 20) { if(sti && dir1 === "up") { clearInterval(sti); sti = false; } if(!sti) { dir1 = "down"; sti = setInterval(function () { $(document).scrollTop($(document).scrollTop() + $.vakata.dnd.scroll_spd); }, 150); } } - else { + else { if(sti && dir1 === "down") { clearInterval(sti); sti = false; } } @@ -2250,14 +2250,14 @@ if(sli && dir2 === "right") { clearInterval(sli); sli = false; } if(!sli) { dir2 = "left"; sli = setInterval(function () { $(document).scrollLeft($(document).scrollLeft() - $.vakata.dnd.scroll_spd); }, 150); } } - else { + else { if(sli && dir2 === "left") { clearInterval(sli); sli = false; } } if($(window).width() - (e.pageX - l) < 20) { if(sli && dir2 === "left") { clearInterval(sli); sli = false; } if(!sli) { dir2 = "right"; sli = setInterval(function () { $(document).scrollLeft($(document).scrollLeft() + $.vakata.dnd.scroll_spd); }, 150); } } - else { + else { if(sli && dir2 === "right") { clearInterval(sli); sli = false; } } } @@ -2307,7 +2307,7 @@ .bind("mouseenter.jstree", $.proxy(function (e) { if($.vakata.dnd.is_drag && $.vakata.dnd.user_data.jstree) { if(this.data.themes) { - m.attr("class", "jstree-" + this.data.themes.theme); + m.attr("class", "jstree-" + this.data.themes.theme); if(ml) { ml.attr("class", "jstree-" + this.data.themes.theme); } $.vakata.dnd.helper.attr("class", "jstree-dnd-helper jstree-" + this.data.themes.theme); } @@ -2346,7 +2346,7 @@ }, this)) .bind("mouseleave.jstree", $.proxy(function (e) { if(e.relatedTarget && e.relatedTarget.id && e.relatedTarget.id === "jstree-marker-line") { - return false; + return false; } if($.vakata.dnd.is_drag && $.vakata.dnd.user_data.jstree) { if(this.data.dnd.i1) { clearInterval(this.data.dnd.i1); } @@ -2390,24 +2390,24 @@ } }, this)) - .bind("scroll.jstree", $.proxy(function (e) { + .bind("scroll.jstree", $.proxy(function (e) { if($.vakata.dnd.is_drag && $.vakata.dnd.user_data.jstree && m && ml) { m.hide(); ml.hide(); } }, this)) - .delegate("a", "mousedown.jstree", $.proxy(function (e) { + .delegate("a", "mousedown.jstree", $.proxy(function (e) { if(e.which === 1) { this.start_drag(e.currentTarget, e); return false; } }, this)) - .delegate("a", "mouseenter.jstree", $.proxy(function (e) { + .delegate("a", "mouseenter.jstree", $.proxy(function (e) { if($.vakata.dnd.is_drag && $.vakata.dnd.user_data.jstree) { this.dnd_enter(e.currentTarget); } }, this)) - .delegate("a", "mousemove.jstree", $.proxy(function (e) { + .delegate("a", "mousemove.jstree", $.proxy(function (e) { if($.vakata.dnd.is_drag && $.vakata.dnd.user_data.jstree) { if(!r || !r.length || r.children("a")[0] !== e.currentTarget) { this.dnd_enter(e.currentTarget); @@ -2418,27 +2418,27 @@ this.dnd_show(); } }, this)) - .delegate("a", "mouseleave.jstree", $.proxy(function (e) { + .delegate("a", "mouseleave.jstree", $.proxy(function (e) { if($.vakata.dnd.is_drag && $.vakata.dnd.user_data.jstree) { if(e.relatedTarget && e.relatedTarget.id && e.relatedTarget.id === "jstree-marker-line") { - return false; + return false; } if(m) { m.hide(); } if(ml) { ml.hide(); } /* - var ec = $(e.currentTarget).closest("li"), + var ec = $(e.currentTarget).closest("li"), er = $(e.relatedTarget).closest("li"); if(er[0] !== ec.prev()[0] && er[0] !== ec.next()[0]) { if(m) { m.hide(); } if(ml) { ml.hide(); } } */ - this.data.dnd.mto = setTimeout( + this.data.dnd.mto = setTimeout( (function (t) { return function () { t.dnd_leave(e); }; })(this), 0); } }, this)) - .delegate("a", "mouseup.jstree", $.proxy(function (e) { + .delegate("a", "mouseup.jstree", $.proxy(function (e) { if($.vakata.dnd.is_drag && $.vakata.dnd.user_data.jstree) { this.dnd_finish(e); } @@ -2466,7 +2466,7 @@ if(ml) { ml.css({ "top" : "-2000px" }); } }, this)) .bind("drag_start.vakata", $.proxy(function (e, data) { - if(data.data.jstree) { + if(data.data.jstree) { var et = $(data.event.target); if(et.closest(".jstree").hasClass("jstree-" + this.get_index())) { this.dnd_enter(et); @@ -2479,7 +2479,7 @@ var h = $.vakata.dnd.helper.children("ins"); if(e[this._get_settings().dnd.copy_modifier + "Key"] && h.hasClass("jstree-ok")) { h.parent().html(h.parent().html().replace(/ \(Copy\)$/, "") + " (Copy)"); - } + } else { h.parent().html(h.parent().html().replace(/ \(Copy\)$/, "")); } @@ -2494,10 +2494,10 @@ .delegate(s.drag_target, "mousedown.jstree-" + this.get_index(), $.proxy(function (e) { o = e.target; $.vakata.dnd.drag_start(e, { jstree : true, obj : e.target }, "<ins class='jstree-icon'></ins>" + $(e.target).text() ); - if(this.data.themes) { + if(this.data.themes) { if(m) { m.attr("class", "jstree-" + this.data.themes.theme); } if(ml) { ml.attr("class", "jstree-" + this.data.themes.theme); } - $.vakata.dnd.helper.attr("class", "jstree-dnd-helper jstree-" + this.data.themes.theme); + $.vakata.dnd.helper.attr("class", "jstree-dnd-helper jstree-" + this.data.themes.theme); } $.vakata.dnd.helper.children("ins").attr("class","jstree-invalid"); var cnt = this.get_container(); @@ -2578,7 +2578,7 @@ o = this.data.dnd.w < this.data.core.li_height/2 ? ["inside","before","after"] : ["inside","after","before"]; } else { o = ["after","inside","before"]; } - $.each(o, $.proxy(function (i, val) { + $.each(o, $.proxy(function (i, val) { if(this.data.dnd[val]) { $.vakata.dnd.helper.children("ins").attr("class","jstree-ok"); r = val; @@ -2586,7 +2586,7 @@ } }, this)); if(r === false) { $.vakata.dnd.helper.children("ins").attr("class","jstree-invalid"); } - + pos = rtl ? (this.data.dnd.off.right - 18) : (this.data.dnd.off.left + 10); switch(r) { case "before": @@ -2629,30 +2629,30 @@ if(ml) { ml.hide(); } }, dnd_enter : function (obj) { - if(this.data.dnd.mto) { + if(this.data.dnd.mto) { clearTimeout(this.data.dnd.mto); this.data.dnd.mto = false; } var s = this._get_settings().dnd; this.data.dnd.prepared = false; r = this._get_node(obj); - if(s.check_timeout) { + if(s.check_timeout) { // do the calculations after a minimal timeout (users tend to drag quickly to the desired location) if(this.data.dnd.to1) { clearTimeout(this.data.dnd.to1); } - this.data.dnd.to1 = setTimeout($.proxy(this.dnd_prepare, this), s.check_timeout); + this.data.dnd.to1 = setTimeout($.proxy(this.dnd_prepare, this), s.check_timeout); } - else { - this.dnd_prepare(); + else { + this.dnd_prepare(); } - if(s.open_timeout) { + if(s.open_timeout) { if(this.data.dnd.to2) { clearTimeout(this.data.dnd.to2); } - if(r && r.length && r.hasClass("jstree-closed")) { + if(r && r.length && r.hasClass("jstree-closed")) { // if the node is closed - open it, then recalculate this.data.dnd.to2 = setTimeout($.proxy(this.dnd_open, this), s.open_timeout); } } else { - if(r && r.length && r.hasClass("jstree-closed")) { + if(r && r.length && r.hasClass("jstree-closed")) { this.dnd_open(); } } @@ -2682,10 +2682,10 @@ cnt = this.get_container(); if(!this._get_settings().core.html_titles) { dt = dt.replace(/</ig,"<").replace(/>/ig,">"); } $.vakata.dnd.drag_start(e, { jstree : true, obj : o }, "<ins class='jstree-icon'></ins>" + dt ); - if(this.data.themes) { + if(this.data.themes) { if(m) { m.attr("class", "jstree-" + this.data.themes.theme); } if(ml) { ml.attr("class", "jstree-" + this.data.themes.theme); } - $.vakata.dnd.helper.attr("class", "jstree-dnd-helper jstree-" + this.data.themes.theme); + $.vakata.dnd.helper.attr("class", "jstree-dnd-helper jstree-" + this.data.themes.theme); } this.data.dnd.cof = cnt.offset(); this.data.dnd.cw = parseInt(cnt.width(),10); @@ -2695,47 +2695,47 @@ } }); $(function() { - var css_string = '' + - '#vakata-dragged ins { display:block; text-decoration:none; width:16px; height:16px; margin:0 0 0 0; padding:0; position:absolute; top:4px; left:4px; ' + + var css_string = '' + + '#vakata-dragged ins { display:block; text-decoration:none; width:16px; height:16px; margin:0 0 0 0; padding:0; position:absolute; top:4px; left:4px; ' + ' -moz-border-radius:4px; border-radius:4px; -webkit-border-radius:4px; ' + - '} ' + - '#vakata-dragged .jstree-ok { background:green; } ' + - '#vakata-dragged .jstree-invalid { background:red; } ' + - '#jstree-marker { padding:0; margin:0; font-size:12px; overflow:hidden; height:12px; width:8px; position:absolute; top:-30px; z-index:10001; background-repeat:no-repeat; display:none; background-color:transparent; text-shadow:1px 1px 1px white; color:black; line-height:10px; } ' + - '#jstree-marker-line { padding:0; margin:0; line-height:0%; font-size:1px; overflow:hidden; height:1px; width:100px; position:absolute; top:-30px; z-index:10000; background-repeat:no-repeat; display:none; background-color:#456c43; ' + - ' cursor:pointer; border:1px solid #eeeeee; border-left:0; -moz-box-shadow: 0px 0px 2px #666; -webkit-box-shadow: 0px 0px 2px #666; box-shadow: 0px 0px 2px #666; ' + + '} ' + + '#vakata-dragged .jstree-ok { background:green; } ' + + '#vakata-dragged .jstree-invalid { background:red; } ' + + '#jstree-marker { padding:0; margin:0; font-size:12px; overflow:hidden; height:12px; width:8px; position:absolute; top:-30px; z-index:10001; background-repeat:no-repeat; display:none; background-color:transparent; text-shadow:1px 1px 1px white; color:black; line-height:10px; } ' + + '#jstree-marker-line { padding:0; margin:0; line-height:0%; font-size:1px; overflow:hidden; height:1px; width:100px; position:absolute; top:-30px; z-index:10000; background-repeat:no-repeat; display:none; background-color:#456c43; ' + + ' cursor:pointer; border:1px solid #eeeeee; border-left:0; -moz-box-shadow: 0px 0px 2px #666; -webkit-box-shadow: 0px 0px 2px #666; box-shadow: 0px 0px 2px #666; ' + ' -moz-border-radius:1px; border-radius:1px; -webkit-border-radius:1px; ' + - '}' + + '}' + ''; $.vakata.css.add_sheet({ str : css_string, title : "jstree" }); m = $("<div />").attr({ id : "jstree-marker" }).hide().html("»") - .bind("mouseleave mouseenter", function (e) { + .bind("mouseleave mouseenter", function (e) { m.hide(); ml.hide(); - e.preventDefault(); - e.stopImmediatePropagation(); - return false; + e.preventDefault(); + e.stopImmediatePropagation(); + return false; }) .appendTo("body"); ml = $("<div />").attr({ id : "jstree-marker-line" }).hide() - .bind("mouseup", function (e) { - if(r && r.length) { - r.children("a").trigger(e); - e.preventDefault(); - e.stopImmediatePropagation(); - return false; - } + .bind("mouseup", function (e) { + if(r && r.length) { + r.children("a").trigger(e); + e.preventDefault(); + e.stopImmediatePropagation(); + return false; + } }) - .bind("mouseleave", function (e) { + .bind("mouseleave", function (e) { var rt = $(e.relatedTarget); if(rt.is(".jstree") || rt.closest(".jstree").length === 0) { - if(r && r.length) { - r.children("a").trigger(e); + if(r && r.length) { + r.children("a").trigger(e); m.hide(); ml.hide(); - e.preventDefault(); - e.stopImmediatePropagation(); - return false; + e.preventDefault(); + e.stopImmediatePropagation(); + return false; } } }) @@ -2766,7 +2766,7 @@ } this.get_container() - .bind("open_node.jstree create_node.jstree clean_node.jstree refresh.jstree", $.proxy(function (e, data) { + .bind("open_node.jstree create_node.jstree clean_node.jstree refresh.jstree", $.proxy(function (e, data) { this._prepare_checkboxes(data.rslt.obj); }, this)) .bind("loaded.jstree", $.proxy(function (e) { @@ -2836,7 +2836,7 @@ }); }); if(!ts) { - obj.find(".jstree-checked").parent().parent().each(function () { _this._repair_state(this); }); + obj.find(".jstree-checked").parent().parent().each(function () { _this._repair_state(this); }); } }, change_state : function (obj, state) { @@ -2845,26 +2845,26 @@ if(!obj || obj === -1) { return false; } state = (state === false || state === true) ? state : obj.hasClass("jstree-checked"); if(this._get_settings().checkbox.two_state) { - if(state) { - obj.removeClass("jstree-checked").addClass("jstree-unchecked"); + if(state) { + obj.removeClass("jstree-checked").addClass("jstree-unchecked"); if(rc) { obj.children(":checkbox").prop("checked", false); } } - else { - obj.removeClass("jstree-unchecked").addClass("jstree-checked"); + else { + obj.removeClass("jstree-unchecked").addClass("jstree-checked"); if(rc) { obj.children(":checkbox").prop("checked", true); } } } else { - if(state) { + if(state) { coll = obj.find("li").addBack(); if(!coll.filter(".jstree-checked, .jstree-undetermined").length) { return false; } - coll.removeClass("jstree-checked jstree-undetermined").addClass("jstree-unchecked"); + coll.removeClass("jstree-checked jstree-undetermined").addClass("jstree-unchecked"); if(rc) { coll.children(":checkbox").prop("checked", false); } } - else { + else { coll = obj.find("li").addBack(); if(!coll.filter(".jstree-unchecked, .jstree-undetermined").length) { return false; } - coll.removeClass("jstree-unchecked jstree-undetermined").addClass("jstree-checked"); + coll.removeClass("jstree-unchecked jstree-undetermined").addClass("jstree-checked"); if(rc) { coll.children(":checkbox").prop("checked", true); } if(this.data.ui) { this.data.ui.last_selected = obj; } this.data.checkbox.last_selected = obj; @@ -2900,20 +2900,20 @@ return true; }, check_node : function (obj) { - if(this.change_state(obj, false)) { + if(this.change_state(obj, false)) { obj = this._get_node(obj); if(this._get_settings().checkbox.checked_parent_open) { var t = this; obj.parents(".jstree-closed").each(function () { t.open_node(this, false, true); }); } - this.__callback({ "obj" : obj }); + this.__callback({ "obj" : obj }); } }, uncheck_node : function (obj) { if(this.change_state(obj, true)) { this.__callback({ "obj" : this._get_node(obj) }); } }, check_all : function () { - var _this = this, + var _this = this, coll = this._get_settings().checkbox.two_state ? this.get_container_ul().find("li") : this.get_container_ul().children("li"); coll.each(function () { _this.change_state(this, false); @@ -2937,7 +2937,7 @@ obj = !obj || obj === -1 ? this.get_container() : this._get_node(obj); return get_all || this._get_settings().checkbox.two_state ? obj.find(".jstree-checked") : obj.find("> ul > .jstree-checked, .jstree-undetermined > ul > .jstree-checked"); }, - get_unchecked : function (obj, get_all) { + get_unchecked : function (obj, get_all) { obj = !obj || obj === -1 ? this.get_container() : this._get_node(obj); return get_all || this._get_settings().checkbox.two_state ? obj.find(".jstree-unchecked") : obj.find("> ul > .jstree-unchecked, .jstree-undetermined > ul > .jstree-unchecked"); }, @@ -2959,13 +2959,13 @@ if(c === 0) { if(obj.hasClass("jstree-undetermined")) { this.change_state(obj, false); } } else if(a === 0 && b === 0) { this.change_state(obj, true); } else if(a === c) { this.change_state(obj, false); } - else { + else { obj.parentsUntil(".jstree","li").addBack().removeClass("jstree-checked jstree-unchecked").addClass("jstree-undetermined"); if(rc) { obj.parentsUntil(".jstree", "li").addBack().children(":checkbox").prop("checked", false); } } }, reselect : function () { - if(this.data.ui && this.data.checkbox.noui) { + if(this.data.ui && this.data.checkbox.noui) { var _this = this, s = this.data.ui.to_select; s = $.map($.makeArray(s), function (n) { return "#" + n.toString().replace(/^#/,"").replace(/\\\//g,"/").replace(/\//g,"\\\/").replace(/\\\./g,".").replace(/\./g,"\\.").replace(/\:/g,"\\:"); }); @@ -2973,8 +2973,8 @@ $.each(s, function (i, val) { _this.check_node(val); }); this.__callback(); } - else { - this.__call_old(); + else { + this.__call_old(); } }, save_loaded : function () { @@ -2993,7 +2993,7 @@ })(jQuery); //*/ -/* +/* * jsTree XML plugin * The XML data store. Datastores are build by overriding the `load_node` and `_is_loaded` functions. */ @@ -3020,7 +3020,7 @@ xsl = new DOMParser().parseFromString(xsl, "text/xml"); // alert(xml.transformNode()); // callback.call(null, new XMLSerializer().serializeToString(rs)); - + } if(typeof window.DOMParser !== "undefined" && typeof window.XMLHttpRequest !== "undefined" && typeof window.XSLTProcessor !== "undefined") { processor = new XSLTProcessor(); @@ -3044,137 +3044,137 @@ return false; }; var xsl = { - 'nest' : '<' + '?xml version="1.0" encoding="utf-8" ?>' + - '<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" >' + - '<xsl:output method="html" encoding="utf-8" omit-xml-declaration="yes" standalone="no" indent="no" media-type="text/html" />' + - '<xsl:template match="/">' + - ' <xsl:call-template name="nodes">' + - ' <xsl:with-param name="node" select="/root" />' + - ' </xsl:call-template>' + - '</xsl:template>' + - '<xsl:template name="nodes">' + - ' <xsl:param name="node" />' + - ' <ul>' + - ' <xsl:for-each select="$node/item">' + - ' <xsl:variable name="children" select="count(./item) > 0" />' + - ' <li>' + - ' <xsl:attribute name="class">' + - ' <xsl:if test="position() = last()">jstree-last </xsl:if>' + - ' <xsl:choose>' + - ' <xsl:when test="@state = \'open\'">jstree-open </xsl:when>' + - ' <xsl:when test="$children or @hasChildren or @state = \'closed\'">jstree-closed </xsl:when>' + - ' <xsl:otherwise>jstree-leaf </xsl:otherwise>' + - ' </xsl:choose>' + - ' <xsl:value-of select="@class" />' + - ' </xsl:attribute>' + - ' <xsl:for-each select="@*">' + - ' <xsl:if test="name() != \'class\' and name() != \'state\' and name() != \'hasChildren\'">' + - ' <xsl:attribute name="{name()}"><xsl:value-of select="." /></xsl:attribute>' + - ' </xsl:if>' + - ' </xsl:for-each>' + - ' <ins class="jstree-icon"><xsl:text> </xsl:text></ins>' + - ' <xsl:for-each select="content/name">' + - ' <a>' + - ' <xsl:attribute name="href">' + - ' <xsl:choose>' + - ' <xsl:when test="@href"><xsl:value-of select="@href" /></xsl:when>' + - ' <xsl:otherwise>#</xsl:otherwise>' + - ' </xsl:choose>' + - ' </xsl:attribute>' + - ' <xsl:attribute name="class"><xsl:value-of select="@lang" /> <xsl:value-of select="@class" /></xsl:attribute>' + - ' <xsl:attribute name="style"><xsl:value-of select="@style" /></xsl:attribute>' + - ' <xsl:for-each select="@*">' + - ' <xsl:if test="name() != \'style\' and name() != \'class\' and name() != \'href\'">' + - ' <xsl:attribute name="{name()}"><xsl:value-of select="." /></xsl:attribute>' + - ' </xsl:if>' + - ' </xsl:for-each>' + - ' <ins>' + - ' <xsl:attribute name="class">jstree-icon ' + - ' <xsl:if test="string-length(attribute::icon) > 0 and not(contains(@icon,\'/\'))"><xsl:value-of select="@icon" /></xsl:if>' + - ' </xsl:attribute>' + - ' <xsl:if test="string-length(attribute::icon) > 0 and contains(@icon,\'/\')"><xsl:attribute name="style">background:url(<xsl:value-of select="@icon" />) center center no-repeat;</xsl:attribute></xsl:if>' + - ' <xsl:text> </xsl:text>' + - ' </ins>' + - ' <xsl:copy-of select="./child::node()" />' + - ' </a>' + - ' </xsl:for-each>' + - ' <xsl:if test="$children or @hasChildren"><xsl:call-template name="nodes"><xsl:with-param name="node" select="current()" /></xsl:call-template></xsl:if>' + - ' </li>' + - ' </xsl:for-each>' + - ' </ul>' + - '</xsl:template>' + + 'nest' : '<' + '?xml version="1.0" encoding="utf-8" ?>' + + '<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" >' + + '<xsl:output method="html" encoding="utf-8" omit-xml-declaration="yes" standalone="no" indent="no" media-type="text/html" />' + + '<xsl:template match="/">' + + ' <xsl:call-template name="nodes">' + + ' <xsl:with-param name="node" select="/root" />' + + ' </xsl:call-template>' + + '</xsl:template>' + + '<xsl:template name="nodes">' + + ' <xsl:param name="node" />' + + ' <ul>' + + ' <xsl:for-each select="$node/item">' + + ' <xsl:variable name="children" select="count(./item) > 0" />' + + ' <li>' + + ' <xsl:attribute name="class">' + + ' <xsl:if test="position() = last()">jstree-last </xsl:if>' + + ' <xsl:choose>' + + ' <xsl:when test="@state = \'open\'">jstree-open </xsl:when>' + + ' <xsl:when test="$children or @hasChildren or @state = \'closed\'">jstree-closed </xsl:when>' + + ' <xsl:otherwise>jstree-leaf </xsl:otherwise>' + + ' </xsl:choose>' + + ' <xsl:value-of select="@class" />' + + ' </xsl:attribute>' + + ' <xsl:for-each select="@*">' + + ' <xsl:if test="name() != \'class\' and name() != \'state\' and name() != \'hasChildren\'">' + + ' <xsl:attribute name="{name()}"><xsl:value-of select="." /></xsl:attribute>' + + ' </xsl:if>' + + ' </xsl:for-each>' + + ' <ins class="jstree-icon"><xsl:text> </xsl:text></ins>' + + ' <xsl:for-each select="content/name">' + + ' <a>' + + ' <xsl:attribute name="href">' + + ' <xsl:choose>' + + ' <xsl:when test="@href"><xsl:value-of select="@href" /></xsl:when>' + + ' <xsl:otherwise>#</xsl:otherwise>' + + ' </xsl:choose>' + + ' </xsl:attribute>' + + ' <xsl:attribute name="class"><xsl:value-of select="@lang" /> <xsl:value-of select="@class" /></xsl:attribute>' + + ' <xsl:attribute name="style"><xsl:value-of select="@style" /></xsl:attribute>' + + ' <xsl:for-each select="@*">' + + ' <xsl:if test="name() != \'style\' and name() != \'class\' and name() != \'href\'">' + + ' <xsl:attribute name="{name()}"><xsl:value-of select="." /></xsl:attribute>' + + ' </xsl:if>' + + ' </xsl:for-each>' + + ' <ins>' + + ' <xsl:attribute name="class">jstree-icon ' + + ' <xsl:if test="string-length(attribute::icon) > 0 and not(contains(@icon,\'/\'))"><xsl:value-of select="@icon" /></xsl:if>' + + ' </xsl:attribute>' + + ' <xsl:if test="string-length(attribute::icon) > 0 and contains(@icon,\'/\')"><xsl:attribute name="style">background:url(<xsl:value-of select="@icon" />) center center no-repeat;</xsl:attribute></xsl:if>' + + ' <xsl:text> </xsl:text>' + + ' </ins>' + + ' <xsl:copy-of select="./child::node()" />' + + ' </a>' + + ' </xsl:for-each>' + + ' <xsl:if test="$children or @hasChildren"><xsl:call-template name="nodes"><xsl:with-param name="node" select="current()" /></xsl:call-template></xsl:if>' + + ' </li>' + + ' </xsl:for-each>' + + ' </ul>' + + '</xsl:template>' + '</xsl:stylesheet>', - 'flat' : '<' + '?xml version="1.0" encoding="utf-8" ?>' + - '<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" >' + - '<xsl:output method="html" encoding="utf-8" omit-xml-declaration="yes" standalone="no" indent="no" media-type="text/xml" />' + - '<xsl:template match="/">' + - ' <ul>' + + 'flat' : '<' + '?xml version="1.0" encoding="utf-8" ?>' + + '<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" >' + + '<xsl:output method="html" encoding="utf-8" omit-xml-declaration="yes" standalone="no" indent="no" media-type="text/xml" />' + + '<xsl:template match="/">' + + ' <ul>' + ' <xsl:for-each select="//item[not(@parent_id) or @parent_id=0 or not(@parent_id = //item/@id)]">' + /* the last `or` may be removed */ - ' <xsl:call-template name="nodes">' + - ' <xsl:with-param name="node" select="." />' + - ' <xsl:with-param name="is_last" select="number(position() = last())" />' + - ' </xsl:call-template>' + - ' </xsl:for-each>' + - ' </ul>' + - '</xsl:template>' + - '<xsl:template name="nodes">' + - ' <xsl:param name="node" />' + - ' <xsl:param name="is_last" />' + - ' <xsl:variable name="children" select="count(//item[@parent_id=$node/attribute::id]) > 0" />' + - ' <li>' + - ' <xsl:attribute name="class">' + - ' <xsl:if test="$is_last = true()">jstree-last </xsl:if>' + - ' <xsl:choose>' + - ' <xsl:when test="@state = \'open\'">jstree-open </xsl:when>' + - ' <xsl:when test="$children or @hasChildren or @state = \'closed\'">jstree-closed </xsl:when>' + - ' <xsl:otherwise>jstree-leaf </xsl:otherwise>' + - ' </xsl:choose>' + - ' <xsl:value-of select="@class" />' + - ' </xsl:attribute>' + - ' <xsl:for-each select="@*">' + - ' <xsl:if test="name() != \'parent_id\' and name() != \'hasChildren\' and name() != \'class\' and name() != \'state\'">' + - ' <xsl:attribute name="{name()}"><xsl:value-of select="." /></xsl:attribute>' + - ' </xsl:if>' + - ' </xsl:for-each>' + - ' <ins class="jstree-icon"><xsl:text> </xsl:text></ins>' + - ' <xsl:for-each select="content/name">' + - ' <a>' + - ' <xsl:attribute name="href">' + - ' <xsl:choose>' + - ' <xsl:when test="@href"><xsl:value-of select="@href" /></xsl:when>' + - ' <xsl:otherwise>#</xsl:otherwise>' + - ' </xsl:choose>' + - ' </xsl:attribute>' + - ' <xsl:attribute name="class"><xsl:value-of select="@lang" /> <xsl:value-of select="@class" /></xsl:attribute>' + - ' <xsl:attribute name="style"><xsl:value-of select="@style" /></xsl:attribute>' + - ' <xsl:for-each select="@*">' + - ' <xsl:if test="name() != \'style\' and name() != \'class\' and name() != \'href\'">' + - ' <xsl:attribute name="{name()}"><xsl:value-of select="." /></xsl:attribute>' + - ' </xsl:if>' + - ' </xsl:for-each>' + - ' <ins>' + - ' <xsl:attribute name="class">jstree-icon ' + - ' <xsl:if test="string-length(attribute::icon) > 0 and not(contains(@icon,\'/\'))"><xsl:value-of select="@icon" /></xsl:if>' + - ' </xsl:attribute>' + - ' <xsl:if test="string-length(attribute::icon) > 0 and contains(@icon,\'/\')"><xsl:attribute name="style">background:url(<xsl:value-of select="@icon" />) center center no-repeat;</xsl:attribute></xsl:if>' + - ' <xsl:text> </xsl:text>' + - ' </ins>' + - ' <xsl:copy-of select="./child::node()" />' + - ' </a>' + - ' </xsl:for-each>' + - ' <xsl:if test="$children">' + - ' <ul>' + - ' <xsl:for-each select="//item[@parent_id=$node/attribute::id]">' + - ' <xsl:call-template name="nodes">' + - ' <xsl:with-param name="node" select="." />' + - ' <xsl:with-param name="is_last" select="number(position() = last())" />' + - ' </xsl:call-template>' + - ' </xsl:for-each>' + - ' </ul>' + - ' </xsl:if>' + - ' </li>' + - '</xsl:template>' + + ' <xsl:call-template name="nodes">' + + ' <xsl:with-param name="node" select="." />' + + ' <xsl:with-param name="is_last" select="number(position() = last())" />' + + ' </xsl:call-template>' + + ' </xsl:for-each>' + + ' </ul>' + + '</xsl:template>' + + '<xsl:template name="nodes">' + + ' <xsl:param name="node" />' + + ' <xsl:param name="is_last" />' + + ' <xsl:variable name="children" select="count(//item[@parent_id=$node/attribute::id]) > 0" />' + + ' <li>' + + ' <xsl:attribute name="class">' + + ' <xsl:if test="$is_last = true()">jstree-last </xsl:if>' + + ' <xsl:choose>' + + ' <xsl:when test="@state = \'open\'">jstree-open </xsl:when>' + + ' <xsl:when test="$children or @hasChildren or @state = \'closed\'">jstree-closed </xsl:when>' + + ' <xsl:otherwise>jstree-leaf </xsl:otherwise>' + + ' </xsl:choose>' + + ' <xsl:value-of select="@class" />' + + ' </xsl:attribute>' + + ' <xsl:for-each select="@*">' + + ' <xsl:if test="name() != \'parent_id\' and name() != \'hasChildren\' and name() != \'class\' and name() != \'state\'">' + + ' <xsl:attribute name="{name()}"><xsl:value-of select="." /></xsl:attribute>' + + ' </xsl:if>' + + ' </xsl:for-each>' + + ' <ins class="jstree-icon"><xsl:text> </xsl:text></ins>' + + ' <xsl:for-each select="content/name">' + + ' <a>' + + ' <xsl:attribute name="href">' + + ' <xsl:choose>' + + ' <xsl:when test="@href"><xsl:value-of select="@href" /></xsl:when>' + + ' <xsl:otherwise>#</xsl:otherwise>' + + ' </xsl:choose>' + + ' </xsl:attribute>' + + ' <xsl:attribute name="class"><xsl:value-of select="@lang" /> <xsl:value-of select="@class" /></xsl:attribute>' + + ' <xsl:attribute name="style"><xsl:value-of select="@style" /></xsl:attribute>' + + ' <xsl:for-each select="@*">' + + ' <xsl:if test="name() != \'style\' and name() != \'class\' and name() != \'href\'">' + + ' <xsl:attribute name="{name()}"><xsl:value-of select="." /></xsl:attribute>' + + ' </xsl:if>' + + ' </xsl:for-each>' + + ' <ins>' + + ' <xsl:attribute name="class">jstree-icon ' + + ' <xsl:if test="string-length(attribute::icon) > 0 and not(contains(@icon,\'/\'))"><xsl:value-of select="@icon" /></xsl:if>' + + ' </xsl:attribute>' + + ' <xsl:if test="string-length(attribute::icon) > 0 and contains(@icon,\'/\')"><xsl:attribute name="style">background:url(<xsl:value-of select="@icon" />) center center no-repeat;</xsl:attribute></xsl:if>' + + ' <xsl:text> </xsl:text>' + + ' </ins>' + + ' <xsl:copy-of select="./child::node()" />' + + ' </a>' + + ' </xsl:for-each>' + + ' <xsl:if test="$children">' + + ' <ul>' + + ' <xsl:for-each select="//item[@parent_id=$node/attribute::id]">' + + ' <xsl:call-template name="nodes">' + + ' <xsl:with-param name="node" select="." />' + + ' <xsl:with-param name="is_last" select="number(position() = last())" />' + + ' </xsl:call-template>' + + ' </xsl:for-each>' + + ' </ul>' + + ' </xsl:if>' + + ' </li>' + + '</xsl:template>' + '</xsl:stylesheet>' }, escape_xml = function(string) { @@ -3187,7 +3187,7 @@ .replace(/'/g, '''); }; $.jstree.plugin("xml_data", { - defaults : { + defaults : { data : false, ajax : false, xsl : "flat", @@ -3198,7 +3198,7 @@ }, _fn : { load_node : function (obj, s_call, e_call) { var _this = this; this.load_node_xml(obj, function () { _this.__callback({ "obj" : _this._get_node(obj) }); s_call.call(this); }, e_call); }, - _is_loaded : function (obj) { + _is_loaded : function (obj) { var s = this._get_settings().xml_data; obj = this._get_node(obj); return obj == -1 || !obj || (!s.ajax && !$.isFunction(s.data)) || obj.is(".jstree-open, .jstree-leaf") || obj.children("ul").children("li").size() > 0; @@ -3228,18 +3228,18 @@ if(s_call) { s_call.call(this); } } else { - if(obj && obj !== -1) { + if(obj && obj !== -1) { obj.children("a.jstree-loading").removeClass("jstree-loading"); obj.removeData("jstree_is_loading"); - if(s.correct_state) { + if(s.correct_state) { this.correct_state(obj); - if(s_call) { s_call.call(this); } + if(s_call) { s_call.call(this); } } } else { - if(s.correct_state) { + if(s.correct_state) { this.get_container().children("ul").empty(); - if(s_call) { s_call.call(this); } + if(s_call) { s_call.call(this); } } } } @@ -3259,9 +3259,9 @@ if(s_call) { s_call.call(this); } } } - else { - if(s.correct_state) { - this.get_container().children("ul").empty(); + else { + if(s.correct_state) { + this.get_container().children("ul").empty(); if(s_call) { s_call.call(this); } } } @@ -3270,7 +3270,7 @@ break; case (!s.data && !!s.ajax) || (!!s.data && !!s.ajax && obj && obj !== -1): error_func = function (x, t, e) { - var ef = this.get_settings().xml_data.ajax.error; + var ef = this.get_settings().xml_data.ajax.error; if(ef) { ef.call(this, x, t, e); } if(obj !== -1 && obj.length) { obj.children("a.jstree-loading").removeClass("jstree-loading"); @@ -3284,7 +3284,7 @@ }; success_func = function (d, t, x) { d = x.responseText; - var sf = this.get_settings().xml_data.ajax.success; + var sf = this.get_settings().xml_data.ajax.success; if(sf) { d = sf.call(this,d,t,x) || d; } if(d === "" || (d && d.toString && d.toString().replace(/^[\s\n]+$/,"") === "")) { return error_func.call(this, x, t, ""); @@ -3300,18 +3300,18 @@ if(s_call) { s_call.call(this); } } else { - if(obj && obj !== -1) { + if(obj && obj !== -1) { obj.children("a.jstree-loading").removeClass("jstree-loading"); obj.removeData("jstree_is_loading"); - if(s.correct_state) { + if(s.correct_state) { this.correct_state(obj); - if(s_call) { s_call.call(this); } + if(s_call) { s_call.call(this); } } } else { - if(s.correct_state) { + if(s.correct_state) { this.get_container().children("ul").empty(); - if(s_call) { s_call.call(this); } + if(s_call) { s_call.call(this); } } } } @@ -3333,8 +3333,8 @@ $.vakata.xslt(xml, xsl[s.xsl], callback); }, get_xml : function (tp, obj, li_attr, a_attr, is_callback) { - var result = "", - s = this._get_settings(), + var result = "", + s = this._get_settings(), _this = this, tmp1, tmp2, li, a, lang; if(!tp) { tp = "flat"; } @@ -3346,19 +3346,19 @@ a_attr = $.isArray(a_attr) ? a_attr : [ ]; - if(!is_callback) { - if(s.xml_data.get_include_preamble) { - result += '<' + '?xml version="1.0" encoding="UTF-8"?' + '>'; + if(!is_callback) { + if(s.xml_data.get_include_preamble) { + result += '<' + '?xml version="1.0" encoding="UTF-8"?' + '>'; } - result += "<root>"; + result += "<root>"; } obj.each(function () { result += "<item"; li = $(this); - $.each(li_attr, function (i, v) { + $.each(li_attr, function (i, v) { var t = li.attr(v); if(!s.xml_data.get_skip_empty || typeof t !== "undefined") { - result += " " + v + "=\"" + escape_xml((" " + (t || "")).replace(/ jstree[^ ]*/ig,'').replace(/\s+$/ig," ").replace(/^ /,"").replace(/ $/,"")) + "\""; + result += " " + v + "=\"" + escape_xml((" " + (t || "")).replace(/ jstree[^ ]*/ig,'').replace(/\s+$/ig," ").replace(/^ /,"").replace(/ $/,"")) + "\""; } }); if(li.hasClass("jstree-open")) { result += " state=\"open\""; } @@ -3376,7 +3376,7 @@ if(tmp1.hasClass(z)) { result += " lang=\"" + escape_xml(z) + "\""; lang = z; return false; } }); } - if(a_attr.length) { + if(a_attr.length) { $.each(a_attr, function (k, z) { var t = tmp1.attr(z); if(!s.xml_data.get_skip_empty || typeof t !== "undefined") { @@ -3447,7 +3447,7 @@ _fn : { search : function (str, skip_async) { if($.trim(str) === "") { this.clear_search(); return; } - var s = this.get_settings().search, + var s = this.get_settings().search, t = this, error_func = function () { }, success_func = function () { }; @@ -3457,7 +3457,7 @@ this.search.supress_callback = true; error_func = function () { }; success_func = function (d, t, x) { - var sf = this.get_settings().search.ajax.success; + var sf = this.get_settings().search.ajax.success; if(sf) { d = sf.call(this,d,t,x) || d; } this.data.search.to_open = d; this._search_open(); @@ -3497,8 +3497,8 @@ }); if(current.length) { this.data.search.to_open = remaining; - $.each(current, function (i, val) { - _this.open_node(val, function () { _this._search_open(true); }); + $.each(current, function (i, val) { + _this.open_node(val, function () { _this._search_open(true); }); }); done = false; } @@ -3510,7 +3510,7 @@ })(jQuery); //*/ -/* +/* * jsTree contextmenu plugin */ (function ($) { @@ -3543,27 +3543,27 @@ h = $.vakata.context.cnt.height(); w = $.vakata.context.cnt.width(); - if(x + w > $(document).width()) { - x = $(document).width() - (w + 5); - $.vakata.context.cnt.find("li > ul").addClass("right"); + if(x + w > $(document).width()) { + x = $(document).width() - (w + 5); + $.vakata.context.cnt.find("li > ul").addClass("right"); } - if(y + h > $(document).height()) { - y = y - (h + t[0].offsetHeight); - $.vakata.context.cnt.find("li > ul").addClass("bottom"); + if(y + h > $(document).height()) { + y = y - (h + t[0].offsetHeight); + $.vakata.context.cnt.find("li > ul").addClass("bottom"); } $.vakata.context.cnt .css({ "left" : x, "top" : y }) .find("li:has(ul)") - .bind("mouseenter", function (e) { + .bind("mouseenter", function (e) { var w = $(document).width(), h = $(document).height(), - ul = $(this).children("ul").show(); + ul = $(this).children("ul").show(); if(w !== $(document).width()) { ul.toggleClass("right"); } if(h !== $(document).height()) { ul.toggleClass("bottom"); } }) - .bind("mouseleave", function (e) { - $(this).children("ul").hide(); + .bind("mouseleave", function (e) { + $(this).children("ul").hide(); }) .end() .css({ "visibility" : "visible" }) @@ -3622,17 +3622,17 @@ } }; $(function () { - var css_string = '' + - '#vakata-contextmenu { display:block; visibility:hidden; left:0; top:-200px; position:absolute; margin:0; padding:0; min-width:180px; background:#ebebeb; border:1px solid silver; z-index:10000; *width:180px; } ' + - '#vakata-contextmenu ul { min-width:180px; *width:180px; } ' + - '#vakata-contextmenu ul, #vakata-contextmenu li { margin:0; padding:0; list-style-type:none; display:block; } ' + - '#vakata-contextmenu li { line-height:20px; min-height:20px; position:relative; padding:0px; } ' + - '#vakata-contextmenu li a { padding:1px 6px; line-height:17px; display:block; text-decoration:none; margin:1px 1px 0 1px; } ' + - '#vakata-contextmenu li ins { float:left; width:16px; height:16px; text-decoration:none; margin-right:2px; } ' + - '#vakata-contextmenu li a:hover, #vakata-contextmenu li.vakata-hover > a { background:gray; color:white; } ' + - '#vakata-contextmenu li ul { display:none; position:absolute; top:-2px; left:100%; background:#ebebeb; border:1px solid gray; } ' + - '#vakata-contextmenu .right { right:100%; left:auto; } ' + - '#vakata-contextmenu .bottom { bottom:-1px; top:auto; } ' + + var css_string = '' + + '#vakata-contextmenu { display:block; visibility:hidden; left:0; top:-200px; position:absolute; margin:0; padding:0; min-width:180px; background:#ebebeb; border:1px solid silver; z-index:10000; *width:180px; } ' + + '#vakata-contextmenu ul { min-width:180px; *width:180px; } ' + + '#vakata-contextmenu ul, #vakata-contextmenu li { margin:0; padding:0; list-style-type:none; display:block; } ' + + '#vakata-contextmenu li { line-height:20px; min-height:20px; position:relative; padding:0px; } ' + + '#vakata-contextmenu li a { padding:1px 6px; line-height:17px; display:block; text-decoration:none; margin:1px 1px 0 1px; } ' + + '#vakata-contextmenu li ins { float:left; width:16px; height:16px; text-decoration:none; margin-right:2px; } ' + + '#vakata-contextmenu li a:hover, #vakata-contextmenu li.vakata-hover > a { background:gray; color:white; } ' + + '#vakata-contextmenu li ul { display:none; position:absolute; top:-2px; left:100%; background:#ebebeb; border:1px solid gray; } ' + + '#vakata-contextmenu .right { right:100%; left:auto; } ' + + '#vakata-contextmenu .bottom { bottom:-1px; top:auto; } ' + '#vakata-contextmenu li.vakata-separator { min-height:0; height:1px; line-height:1px; font-size:1px; overflow:hidden; margin:0 2px; background:silver; /* border-top:1px solid #fefefe; */ padding:0; } '; $.vakata.css.add_sheet({ str : css_string, title : "vakata" }); $.vakata.context.cnt @@ -3650,43 +3650,43 @@ $(document).bind("mousedown", function (e) { if($.vakata.context.vis && !$.contains($.vakata.context.cnt[0], e.target)) { $.vakata.context.hide(); } }); if(typeof $.hotkeys !== "undefined") { $(document) - .bind("keydown", "up", function (e) { - if($.vakata.context.vis) { + .bind("keydown", "up", function (e) { + if($.vakata.context.vis) { var o = $.vakata.context.cnt.find("ul:visible").last().children(".vakata-hover").removeClass("vakata-hover").prevAll("li:not(.vakata-separator)").first(); if(!o.length) { o = $.vakata.context.cnt.find("ul:visible").last().children("li:not(.vakata-separator)").last(); } o.addClass("vakata-hover"); - e.stopImmediatePropagation(); + e.stopImmediatePropagation(); e.preventDefault(); - } + } }) - .bind("keydown", "down", function (e) { - if($.vakata.context.vis) { + .bind("keydown", "down", function (e) { + if($.vakata.context.vis) { var o = $.vakata.context.cnt.find("ul:visible").last().children(".vakata-hover").removeClass("vakata-hover").nextAll("li:not(.vakata-separator)").first(); if(!o.length) { o = $.vakata.context.cnt.find("ul:visible").last().children("li:not(.vakata-separator)").first(); } o.addClass("vakata-hover"); - e.stopImmediatePropagation(); + e.stopImmediatePropagation(); e.preventDefault(); - } + } }) - .bind("keydown", "right", function (e) { - if($.vakata.context.vis) { + .bind("keydown", "right", function (e) { + if($.vakata.context.vis) { $.vakata.context.cnt.find(".vakata-hover").children("ul").show().children("li:not(.vakata-separator)").removeClass("vakata-hover").first().addClass("vakata-hover"); - e.stopImmediatePropagation(); + e.stopImmediatePropagation(); e.preventDefault(); - } + } }) - .bind("keydown", "left", function (e) { - if($.vakata.context.vis) { + .bind("keydown", "left", function (e) { + if($.vakata.context.vis) { $.vakata.context.cnt.find(".vakata-hover").children("ul").hide().children(".vakata-separator").removeClass("vakata-hover"); - e.stopImmediatePropagation(); + e.stopImmediatePropagation(); e.preventDefault(); - } + } }) - .bind("keydown", "esc", function (e) { - $.vakata.context.hide(); + .bind("keydown", "esc", function (e) { + $.vakata.context.hide(); e.preventDefault(); }) - .bind("keydown", "space", function (e) { + .bind("keydown", "space", function (e) { $.vakata.context.cnt.find(".vakata-hover").last().children("a").click(); e.preventDefault(); }); @@ -3715,7 +3715,7 @@ }, this)); $(document).bind("context_hide.vakata", $.proxy(function () { this.data.contextmenu = false; }, this)); }, - defaults : { + defaults : { select_node : false, // requires UI plugin show_at_node : true, items : { // Could be a function that should return an object like this one @@ -3744,7 +3744,7 @@ "separator_after" : false, "label" : "Edit", "action" : false, - "submenu" : { + "submenu" : { "cut" : { "separator_before" : false, "separator_after" : false, @@ -3796,7 +3796,7 @@ })(jQuery); //*/ -/* +/* * jsTree types plugin * Adds support types of nodes * You can set an attribute on each li node, that represents its type. @@ -3808,14 +3808,14 @@ var s = this._get_settings().types; this.data.types.attach_to = []; this.get_container() - .bind("init.jstree", $.proxy(function () { - var types = s.types, - attr = s.type_attr, - icons_css = "", + .bind("init.jstree", $.proxy(function () { + var types = s.types, + attr = s.type_attr, + icons_css = "", _this = this; $.each(types, function (i, tp) { - $.each(tp, function (k, v) { + $.each(tp, function (k, v) { if(!/^(max_depth|max_children|icon|valid_children)$/.test(k)) { _this.data.types.attach_to.push(k); } }); if(!tp.icon) { return true; } @@ -3830,9 +3830,9 @@ }); if(icons_css !== "") { $.vakata.css.add_sheet({ 'str' : icons_css, title : "jstree-types" }); } }, this)) - .bind("before.jstree", $.proxy(function (e, data) { - var s, t, - o = this._get_settings().types.use_data ? this._get_node(data.args[0]) : false, + .bind("before.jstree", $.proxy(function (e, data) { + var s, t, + o = this._get_settings().types.use_data ? this._get_node(data.args[0]) : false, d = o && o !== -1 && o.length ? o.data("jstree") : false; if(d && d.types && d.types[data.func] === false) { e.stopImmediatePropagation(); return false; } if($.inArray(data.func, this.data.types.attach_to) !== -1) { @@ -3840,9 +3840,9 @@ s = this._get_settings().types.types; t = this._get_type(data.args[0]); if( - ( - (s[t] && typeof s[t][data.func] !== "undefined") || - (s["default"] && typeof s["default"][data.func] !== "undefined") + ( + (s[t] && typeof s[t][data.func] !== "undefined") || + (s["default"] && typeof s["default"][data.func] !== "undefined") ) && this._check(data.func, data.args[0]) === false ) { e.stopImmediatePropagation(); @@ -3875,7 +3875,7 @@ valid_children : "all", // whether to use $.data - use_data : false, + use_data : false, // where is the type stores (the rel attribute of the LI element) type_attr : "rel", // a list of types @@ -3910,7 +3910,7 @@ _check : function (rule, obj, opts) { obj = this._get_node(obj); var v = false, t = this._get_type(obj), d = 0, _this = this, s = this._get_settings().types, data = false; - if(obj === -1) { + if(obj === -1) { if(!!s[rule]) { v = s[rule]; } else { return; } } @@ -3947,7 +3947,7 @@ vc = m.rt._check("valid_children", m.cr), ch = 0, d = 1, t; - if(vc === "none") { return false; } + if(vc === "none") { return false; } if($.isArray(vc) && m.ot && m.ot._get_type) { m.o.each(function () { if($.inArray(m.ot._get_type(this), vc) === -1) { d = false; return false; } @@ -3984,11 +3984,11 @@ ch; if(typeof js === "string") { js = { data : js }; } if(!js) { js = {}; } - if(vc === "none") { return false; } + if(vc === "none") { return false; } if($.isArray(vc)) { - if(!js.attr || !js.attr[s.type_attr]) { + if(!js.attr || !js.attr[s.type_attr]) { if(!js.attr) { js.attr = {}; } - js.attr[s.type_attr] = vc[0]; + js.attr[s.type_attr] = vc[0]; } else { if($.inArray(js.attr[s.type_attr], vc) === -1) { return false; } @@ -4007,27 +4007,27 @@ })(jQuery); //*/ -/* +/* * jsTree HTML plugin * The HTML data store. Datastores are build by replacing the `load_node` and `_is_loaded` functions. */ (function ($) { $.jstree.plugin("html_data", { - __init : function () { + __init : function () { // this used to use html() and clean the whitespace, but this way any attached data was lost this.data.html_data.original_container_html = this.get_container().find(" > ul > li").clone(true); // remove white space from LI node - otherwise nodes appear a bit to the right this.data.html_data.original_container_html.find("li").addBack().contents().filter(function() { return this.nodeType == 3; }).remove(); }, - defaults : { + defaults : { data : false, ajax : false, correct_state : true }, _fn : { load_node : function (obj, s_call, e_call) { var _this = this; this.load_node_html(obj, function () { _this.__callback({ "obj" : _this._get_node(obj) }); s_call.call(this); }, e_call); }, - _is_loaded : function (obj) { - obj = this._get_node(obj); + _is_loaded : function (obj) { + obj = this._get_node(obj); return obj == -1 || !obj || (!this._get_settings().html_data.ajax && !$.isFunction(this._get_settings().html_data.data)) || obj.is(".jstree-open, .jstree-leaf") || obj.children("ul").children("li").size() > 0; }, load_node_html : function (obj, s_call, e_call) { @@ -4055,15 +4055,15 @@ if(obj && obj !== -1) { obj.children("a.jstree-loading").removeClass("jstree-loading"); obj.removeData("jstree_is_loading"); - if(s.correct_state) { + if(s.correct_state) { this.correct_state(obj); - if(s_call) { s_call.call(this); } + if(s_call) { s_call.call(this); } } } else { - if(s.correct_state) { + if(s.correct_state) { this.get_container().children("ul").empty(); - if(s_call) { s_call.call(this); } + if(s_call) { s_call.call(this); } } } } @@ -4095,7 +4095,7 @@ case (!s.data && !!s.ajax) || (!!s.data && !!s.ajax && obj && obj !== -1): obj = this._get_node(obj); error_func = function (x, t, e) { - var ef = this.get_settings().html_data.ajax.error; + var ef = this.get_settings().html_data.ajax.error; if(ef) { ef.call(this, x, t, e); } if(obj != -1 && obj.length) { obj.children("a.jstree-loading").removeClass("jstree-loading"); @@ -4108,7 +4108,7 @@ if(e_call) { e_call.call(this); } }; success_func = function (d, t, x) { - var sf = this.get_settings().html_data.ajax.success; + var sf = this.get_settings().html_data.ajax.success; if(sf) { d = sf.call(this,d,t,x) || d; } if(d === "" || (d && d.toString && d.toString().replace(/^[\s\n]+$/,"") === "")) { return error_func.call(this, x, t, ""); @@ -4125,15 +4125,15 @@ if(obj && obj !== -1) { obj.children("a.jstree-loading").removeClass("jstree-loading"); obj.removeData("jstree_is_loading"); - if(s.correct_state) { + if(s.correct_state) { this.correct_state(obj); - if(s_call) { s_call.call(this); } + if(s_call) { s_call.call(this); } } } else { - if(s.correct_state) { + if(s.correct_state) { this.get_container().children("ul").empty(); - if(s_call) { s_call.call(this); } + if(s_call) { s_call.call(this); } } } } @@ -4155,7 +4155,7 @@ })(jQuery); //*/ -/* +/* * jsTree themeroller plugin * Adds support for jQuery UI themes. Include this at the end of your plugins list, also make sure "themes" is not included. */ @@ -4174,11 +4174,11 @@ .delegate("a","mouseleave.jstree", function () { $(this).removeClass(s.item_h); }) - .bind("init.jstree", $.proxy(function (e, data) { + .bind("init.jstree", $.proxy(function (e, data) { data.inst.get_container().find("> ul > li > .jstree-loading > ins").addClass("ui-icon-refresh"); this._themeroller(data.inst.get_container().find("> ul > li")); }, this)) - .bind("open_node.jstree create_node.jstree", $.proxy(function (e, data) { + .bind("open_node.jstree create_node.jstree", $.proxy(function (e, data) { this._themeroller(data.rslt.obj); }, this)) .bind("loaded.jstree refresh.jstree", $.proxy(function (e) { @@ -4194,10 +4194,10 @@ data.rslt.obj .children("ins.jstree-icon").removeClass(s.opened + " " + s.closed + " ui-icon").end() .find("> a > ins.ui-icon") - .filter(function() { + .filter(function() { return this.className.toString() .replace(s.item_clsd,"").replace(s.item_open,"").replace(s.item_leaf,"") - .indexOf("ui-icon-") === -1; + .indexOf("ui-icon-") === -1; }).removeClass(s.item_open + " " + s.item_clsd).addClass(s.item_leaf || "jstree-no-icon"); }, this)) .bind("select_node.jstree", $.proxy(function (e, data) { @@ -4241,10 +4241,10 @@ .children("ins.jstree-icon").removeClass(s.opened).addClass("ui-icon " + s.closed).end() .children("a").addClass(s.item) .children("ins.jstree-icon").addClass("ui-icon") - .filter(function() { + .filter(function() { return this.className.toString() .replace(s.item_clsd,"").replace(s.item_open,"").replace(s.item_leaf,"") - .indexOf("ui-icon-") === -1; + .indexOf("ui-icon-") === -1; }).removeClass(s.item_leaf + " " + s.item_open).addClass(s.item_clsd || "jstree-no-icon") .end() .end() @@ -4254,10 +4254,10 @@ .children("ins.jstree-icon").removeClass(s.closed).addClass("ui-icon " + s.opened).end() .children("a").addClass(s.item) .children("ins.jstree-icon").addClass("ui-icon") - .filter(function() { + .filter(function() { return this.className.toString() .replace(s.item_clsd,"").replace(s.item_open,"").replace(s.item_leaf,"") - .indexOf("ui-icon-") === -1; + .indexOf("ui-icon-") === -1; }).removeClass(s.item_leaf + " " + s.item_clsd).addClass(s.item_open || "jstree-no-icon") .end() .end() @@ -4267,10 +4267,10 @@ .children("ins.jstree-icon").removeClass(s.closed + " ui-icon " + s.opened).end() .children("a").addClass(s.item) .children("ins.jstree-icon").addClass("ui-icon") - .filter(function() { + .filter(function() { return this.className.toString() .replace(s.item_clsd,"").replace(s.item_open,"").replace(s.item_leaf,"") - .indexOf("ui-icon-") === -1; + .indexOf("ui-icon-") === -1; }).removeClass(s.item_clsd + " " + s.item_open).addClass(s.item_leaf || "jstree-no-icon"); } }, @@ -4286,16 +4286,16 @@ } }); $(function() { - var css_string = '' + - '.jstree-themeroller .ui-icon { overflow:visible; } ' + - '.jstree-themeroller a { padding:0 2px; } ' + + var css_string = '' + + '.jstree-themeroller .ui-icon { overflow:visible; } ' + + '.jstree-themeroller a { padding:0 2px; } ' + '.jstree-themeroller .jstree-no-icon { display:none; }'; $.vakata.css.add_sheet({ str : css_string, title : "jstree" }); }); })(jQuery); //*/ -/* +/* * jsTree unique plugin * Forces different names amongst siblings (still a bit experimental) * NOTE: does not check language versions (it will not be possible to have nodes with the same title, even in different languages) @@ -4304,7 +4304,7 @@ $.jstree.plugin("unique", { __init : function () { this.get_container() - .bind("before.jstree", $.proxy(function (e, data) { + .bind("before.jstree", $.proxy(function (e, data) { var nms = [], res = true, p, t; if(data.func == "move_node") { // obj, ref, position, is_copy, is_prepared, skip_check @@ -4343,10 +4343,10 @@ } }, this)); }, - defaults : { + defaults : { error_callback : $.noop }, - _fn : { + _fn : { _check_unique : function (nms, p, func) { var cnms = []; p.children("a").each(function () { cnms.push($(this).text().replace(/^\s+/g,"")); }); @@ -4384,27 +4384,27 @@ this.data.wholerow.html = false; this.data.wholerow.to = false; this.get_container() - .bind("init.jstree", $.proxy(function (e, data) { + .bind("init.jstree", $.proxy(function (e, data) { this._get_settings().core.animation = 0; }, this)) - .bind("open_node.jstree create_node.jstree clean_node.jstree loaded.jstree", $.proxy(function (e, data) { + .bind("open_node.jstree create_node.jstree clean_node.jstree loaded.jstree", $.proxy(function (e, data) { this._prepare_wholerow_span( data && data.rslt && data.rslt.obj ? data.rslt.obj : -1 ); }, this)) - .bind("search.jstree clear_search.jstree reopen.jstree after_open.jstree after_close.jstree create_node.jstree delete_node.jstree clean_node.jstree", $.proxy(function (e, data) { + .bind("search.jstree clear_search.jstree reopen.jstree after_open.jstree after_close.jstree create_node.jstree delete_node.jstree clean_node.jstree", $.proxy(function (e, data) { if(this.data.to) { clearTimeout(this.data.to); } this.data.to = setTimeout( (function (t, o) { return function() { t._prepare_wholerow_ul(o); }; })(this, data && data.rslt && data.rslt.obj ? data.rslt.obj : -1), 0); }, this)) - .bind("deselect_all.jstree", $.proxy(function (e, data) { + .bind("deselect_all.jstree", $.proxy(function (e, data) { this.get_container().find(" > .jstree-wholerow .jstree-clicked").removeClass("jstree-clicked " + (this.data.themeroller ? this._get_settings().themeroller.item_a : "" )); }, this)) - .bind("select_node.jstree deselect_node.jstree ", $.proxy(function (e, data) { - data.rslt.obj.each(function () { + .bind("select_node.jstree deselect_node.jstree ", $.proxy(function (e, data) { + data.rslt.obj.each(function () { var ref = data.inst.get_container().find(" > .jstree-wholerow li:visible:eq(" + ( parseInt((($(this).offset().top - data.inst.get_container().offset().top + data.inst.get_container()[0].scrollTop) / data.inst.data.core.li_height),10)) + ")"); // ref.children("a")[e.type === "select_node" ? "addClass" : "removeClass"]("jstree-clicked"); ref.children("a").attr("class",data.rslt.obj.children("a").attr("class")); }); }, this)) - .bind("hover_node.jstree dehover_node.jstree", $.proxy(function (e, data) { + .bind("hover_node.jstree dehover_node.jstree", $.proxy(function (e, data) { this.get_container().find(" > .jstree-wholerow .jstree-hovered").removeClass("jstree-hovered " + (this.data.themeroller ? this._get_settings().themeroller.item_h : "" )); if(e.type === "hover_node") { var ref = this.get_container().find(" > .jstree-wholerow li:visible:eq(" + ( parseInt(((data.rslt.obj.offset().top - this.get_container().offset().top + this.get_container()[0].scrollTop) / this.data.core.li_height),10)) + ")"); @@ -4468,25 +4468,25 @@ } }); $(function() { - var css_string = '' + - '.jstree .jstree-wholerow-real { position:relative; z-index:1; } ' + - '.jstree .jstree-wholerow-real li { cursor:pointer; } ' + - '.jstree .jstree-wholerow-real a { border-left-color:transparent !important; border-right-color:transparent !important; } ' + - '.jstree .jstree-wholerow { position:relative; z-index:0; height:0; } ' + - '.jstree .jstree-wholerow ul, .jstree .jstree-wholerow li { width:100%; } ' + - '.jstree .jstree-wholerow, .jstree .jstree-wholerow ul, .jstree .jstree-wholerow li, .jstree .jstree-wholerow a { margin:0 !important; padding:0 !important; } ' + - '.jstree .jstree-wholerow, .jstree .jstree-wholerow ul, .jstree .jstree-wholerow li { background:transparent !important; }' + - '.jstree .jstree-wholerow ins, .jstree .jstree-wholerow span, .jstree .jstree-wholerow input { display:none !important; }' + - '.jstree .jstree-wholerow a, .jstree .jstree-wholerow a:hover { text-indent:-9999px; !important; width:100%; padding:0 !important; border-right-width:0px !important; border-left-width:0px !important; } ' + + var css_string = '' + + '.jstree .jstree-wholerow-real { position:relative; z-index:1; } ' + + '.jstree .jstree-wholerow-real li { cursor:pointer; } ' + + '.jstree .jstree-wholerow-real a { border-left-color:transparent !important; border-right-color:transparent !important; } ' + + '.jstree .jstree-wholerow { position:relative; z-index:0; height:0; } ' + + '.jstree .jstree-wholerow ul, .jstree .jstree-wholerow li { width:100%; } ' + + '.jstree .jstree-wholerow, .jstree .jstree-wholerow ul, .jstree .jstree-wholerow li, .jstree .jstree-wholerow a { margin:0 !important; padding:0 !important; } ' + + '.jstree .jstree-wholerow, .jstree .jstree-wholerow ul, .jstree .jstree-wholerow li { background:transparent !important; }' + + '.jstree .jstree-wholerow ins, .jstree .jstree-wholerow span, .jstree .jstree-wholerow input { display:none !important; }' + + '.jstree .jstree-wholerow a, .jstree .jstree-wholerow a:hover { text-indent:-9999px; !important; width:100%; padding:0 !important; border-right-width:0px !important; border-left-width:0px !important; } ' + '.jstree .jstree-wholerow-span { position:absolute; left:0; margin:0px; padding:0; height:18px; border-width:0; padding:0; z-index:0; }'; if(is_ff2) { - css_string += '' + - '.jstree .jstree-wholerow a { display:block; height:18px; margin:0; padding:0; border:0; } ' + + css_string += '' + + '.jstree .jstree-wholerow a { display:block; height:18px; margin:0; padding:0; border:0; } ' + '.jstree .jstree-wholerow-real a { border-color:transparent !important; } '; } if(is_ie7 || is_ie6) { - css_string += '' + - '.jstree .jstree-wholerow, .jstree .jstree-wholerow li, .jstree .jstree-wholerow ul, .jstree .jstree-wholerow a { margin:0; padding:0; line-height:18px; } ' + + css_string += '' + + '.jstree .jstree-wholerow, .jstree .jstree-wholerow li, .jstree .jstree-wholerow ul, .jstree .jstree-wholerow a { margin:0; padding:0; line-height:18px; } ' + '.jstree .jstree-wholerow a { display:block; height:18px; line-height:18px; overflow:hidden; } '; } $.vakata.css.add_sheet({ str : css_string, title : "jstree" }); @@ -4532,7 +4532,7 @@ }, _fn : { model_done : function (data, callback) { - var ret = [], + var ret = [], s = this._get_settings(), _this = this; diff --git a/lib/web/mage/backend/jstree-mixin.js b/lib/web/mage/backend/jstree-mixin.js new file mode 100644 index 0000000000000000000000000000000000000000..78e02034fdf0f57ab9a2b698e0e43723cd09f9a7 --- /dev/null +++ b/lib/web/mage/backend/jstree-mixin.js @@ -0,0 +1,13 @@ +/** + * Copyright © 2016 Magento. All rights reserved. + * See COPYING.txt for license details. + */ +define([ + 'jquery' +], function ($) { + 'use strict'; + + return function () { + $.jstree._themes = require.s.contexts._.config.baseUrl + 'jquery/jstree/themes/'; + }; +}); diff --git a/setup/src/Magento/Setup/Fixtures/FixtureModel.php b/setup/src/Magento/Setup/Fixtures/FixtureModel.php index edd7297db4b0c1126e8fc1ddf2b8ffd0581e3d04..0bbb4167854d124a3393414276b63623319c7faa 100644 --- a/setup/src/Magento/Setup/Fixtures/FixtureModel.php +++ b/setup/src/Magento/Setup/Fixtures/FixtureModel.php @@ -110,12 +110,8 @@ class FixtureModel foreach ($files as $file) { $file = basename($file, '.php'); /** @var \Magento\Setup\Fixtures\Fixture $fixture */ - $fixture = $this->objectManager->create( - 'Magento\Setup\Fixtures' . '\\' . $file, - [ - 'fixtureModel' => $this - ] - ); + $type = 'Magento\Setup\Fixtures' . '\\' . $file; + $fixture = new $type($this); $this->fixtures[$fixture->getPriority()] = $fixture; } diff --git a/setup/src/Magento/Setup/Model/Installer.php b/setup/src/Magento/Setup/Model/Installer.php index d2c37704e42055d304f03f20c2462e0cc54a3da3..595f34a03d05396bd300be86d66b0b6a75aecf8f 100644 --- a/setup/src/Magento/Setup/Model/Installer.php +++ b/setup/src/Magento/Setup/Model/Installer.php @@ -825,7 +825,7 @@ class Installer $this->log->log("Module '{$moduleName}':"); $modulePostUpdater = $this->getSchemaDataHandler($moduleName, $handlerType); if ($modulePostUpdater) { - $this->log->logInline('Running ' + str_replace('-', ' ', $handlerType) + '...'); + $this->log->logInline('Running ' . str_replace('-', ' ', $handlerType) . '...'); $modulePostUpdater->install($setup, $moduleContextList[$moduleName]); } $this->logProgress(); diff --git a/setup/src/Magento/Setup/Mvc/Bootstrap/InitParamListener.php b/setup/src/Magento/Setup/Mvc/Bootstrap/InitParamListener.php index 769b3b634d0215b53bfbe8f3df7a5c7171aafaae..135e03ae69b800d593bf6c0592f7454c7b9f1da2 100644 --- a/setup/src/Magento/Setup/Mvc/Bootstrap/InitParamListener.php +++ b/setup/src/Magento/Setup/Mvc/Bootstrap/InitParamListener.php @@ -123,15 +123,16 @@ class InitParamListener implements ListenerAggregateInterface, FactoryInterface /** @var \Magento\Framework\App\State $adminAppState */ $adminAppState = $objectManager->get('Magento\Framework\App\State'); $adminAppState->setAreaCode(\Magento\Framework\App\Area::AREA_ADMIN); - $objectManager->create( - 'Magento\Backend\Model\Auth\Session', + /** @var \Magento\Backend\Model\Auth\Session $adminSession */ + $adminSession = $objectManager->create( + \Magento\Backend\Model\Auth\Session::class, [ - 'sessionConfig' => $objectManager->get('Magento\Backend\Model\Session\AdminConfig'), + 'sessionConfig' => $objectManager->get(\Magento\Backend\Model\Session\AdminConfig::class), 'appState' => $adminAppState ] ); - - if (!$objectManager->get('Magento\Backend\Model\Auth')->isLoggedIn()) { + if (!$objectManager->get(\Magento\Backend\Model\Auth::class)->isLoggedIn()) { + $adminSession->expireSessionCookie(); $response = $event->getResponse(); $response->getHeaders()->addHeaderLine('Location', 'index.php/session/unlogin'); $response->setStatusCode(302);