= $block->getChildHtml('child_grid') ?>
diff --git a/app/code/Magento/SalesRule/Model/Quote/Discount.php b/app/code/Magento/SalesRule/Model/Quote/Discount.php
index bee007b41181f..693a61b272f66 100644
--- a/app/code/Magento/SalesRule/Model/Quote/Discount.php
+++ b/app/code/Magento/SalesRule/Model/Quote/Discount.php
@@ -179,7 +179,7 @@ protected function distributeDiscount(\Magento\Quote\Model\Quote\Item\AbstractIt
$roundingDelta[$key] = 0.0000001;
}
foreach ($item->getChildren() as $child) {
- $ratio = $child->getBaseRowTotal() / $parentBaseRowTotal;
+ $ratio = $parentBaseRowTotal != 0 ? $child->getBaseRowTotal() / $parentBaseRowTotal : 0;
foreach ($keys as $key) {
if (!$item->hasData($key)) {
continue;
diff --git a/app/code/Magento/SalesRule/Test/Unit/Model/Quote/DiscountTest.php b/app/code/Magento/SalesRule/Test/Unit/Model/Quote/DiscountTest.php
index a1c325f39a947..671f20a27a460 100644
--- a/app/code/Magento/SalesRule/Test/Unit/Model/Quote/DiscountTest.php
+++ b/app/code/Magento/SalesRule/Test/Unit/Model/Quote/DiscountTest.php
@@ -229,7 +229,30 @@ public function collectItemHasChildrenDataProvider()
{
$data = [
// 3 items, each $100, testing that discount are distributed to item correctly
- 'three_items' => [
+ [
+ 'child_item_data' => [
+ 'item1' => [
+ 'base_row_total' => 0,
+ ]
+ ],
+ 'parent_item_data' => [
+ 'discount_amount' => 20,
+ 'base_discount_amount' => 10,
+ 'original_discount_amount' => 40,
+ 'base_original_discount_amount' => 20,
+ 'base_row_total' => 0,
+ ],
+ 'expected_child_item_data' => [
+ 'item1' => [
+ 'discount_amount' => 0,
+ 'base_discount_amount' => 0,
+ 'original_discount_amount' => 0,
+ 'base_original_discount_amount' => 0,
+ ]
+ ],
+ ],
+ [
+ // 3 items, each $100, testing that discount are distributed to item correctly
'child_item_data' => [
'item1' => [
'base_row_total' => 100,
diff --git a/app/code/Magento/Search/view/frontend/web/form-mini.js b/app/code/Magento/Search/view/frontend/web/form-mini.js
index 1811274af0167..de16305bbbe8d 100644
--- a/app/code/Magento/Search/view/frontend/web/form-mini.js
+++ b/app/code/Magento/Search/view/frontend/web/form-mini.js
@@ -206,13 +206,17 @@ define([
switch (keyCode) {
case $.ui.keyCode.HOME:
- this._getFirstVisibleElement().addClass(this.options.selectClass);
- this.responseList.selected = this._getFirstVisibleElement();
+ if (this._getFirstVisibleElement()) {
+ this._getFirstVisibleElement().addClass(this.options.selectClass);
+ this.responseList.selected = this._getFirstVisibleElement();
+ }
break;
case $.ui.keyCode.END:
- this._getLastElement().addClass(this.options.selectClass);
- this.responseList.selected = this._getLastElement();
+ if (this._getLastElement()) {
+ this._getLastElement().addClass(this.options.selectClass);
+ this.responseList.selected = this._getLastElement();
+ }
break;
case $.ui.keyCode.ESCAPE:
diff --git a/app/code/Magento/Store/Block/Switcher.php b/app/code/Magento/Store/Block/Switcher.php
index 074dcb0262040..b0659b7caf7e8 100644
--- a/app/code/Magento/Store/Block/Switcher.php
+++ b/app/code/Magento/Store/Block/Switcher.php
@@ -10,7 +10,9 @@
namespace Magento\Store\Block;
use Magento\Directory\Helper\Data;
+use Magento\Store\Api\StoreResolverInterface;
use Magento\Store\Model\Group;
+use Magento\Store\Model\Store;
/**
* @api
@@ -217,15 +219,18 @@ public function getStoreName()
/**
* Returns target store post data
*
- * @param \Magento\Store\Model\Store $store
+ * @param Store $store
* @param array $data
* @return string
*/
- public function getTargetStorePostData(\Magento\Store\Model\Store $store, $data = [])
+ public function getTargetStorePostData(Store $store, $data = [])
{
- $data[\Magento\Store\Api\StoreResolverInterface::PARAM_NAME] = $store->getCode();
+ $data[StoreResolverInterface::PARAM_NAME] = $store->getCode();
+
+ //We need to set fromStore argument as true because
+ //it will enable proper URL rewriting during store switching.
return $this->_postDataHelper->getPostData(
- $store->getCurrentUrl(false),
+ $store->getCurrentUrl(true),
$data
);
}
diff --git a/app/code/Magento/Store/Model/ResourceModel/Website/Collection.php b/app/code/Magento/Store/Model/ResourceModel/Website/Collection.php
index 5b3a74d5d8d39..fb23e842a38e3 100644
--- a/app/code/Magento/Store/Model/ResourceModel/Website/Collection.php
+++ b/app/code/Magento/Store/Model/ResourceModel/Website/Collection.php
@@ -138,11 +138,11 @@ public function joinGroupAndStore()
$this->getSelect()->joinLeft(
['group_table' => $this->getTable('store_group')],
'main_table.website_id = group_table.website_id',
- ['group_id' => 'group_id', 'group_title' => 'name']
+ ['group_id' => 'group_id', 'group_title' => 'name', 'group_code' => 'code']
)->joinLeft(
['store_table' => $this->getTable('store')],
'group_table.group_id = store_table.group_id',
- ['store_id' => 'store_id', 'store_title' => 'name']
+ ['store_id' => 'store_id', 'store_title' => 'name', 'store_code' => 'code']
);
$this->addOrder('group_table.name', \Magento\Framework\DB\Select::SQL_ASC) // store name
->addOrder(
diff --git a/app/code/Magento/Store/Setup/Patch/Schema/InitializeStoresAndWebsites.php b/app/code/Magento/Store/Setup/Patch/Schema/InitializeStoresAndWebsites.php
index a282f2c21ef0e..05e46e04b5c96 100644
--- a/app/code/Magento/Store/Setup/Patch/Schema/InitializeStoresAndWebsites.php
+++ b/app/code/Magento/Store/Setup/Patch/Schema/InitializeStoresAndWebsites.php
@@ -10,6 +10,7 @@
use Magento\Framework\Setup\SchemaSetupInterface;
use Magento\Framework\Setup\Patch\PatchVersionInterface;
use Magento\Framework\Setup\Patch\SchemaPatchInterface;
+use Magento\Store\Api\Data\WebsiteInterface;
/**
* Create stores and websites. Actually stores and websites are part of schema as
@@ -64,7 +65,7 @@ public function apply()
$this->schemaSetup->getTable('store_website'),
[
'website_id' => 0,
- 'code' => 'admin',
+ 'code' => WebsiteInterface::ADMIN_CODE,
'name' => 'Admin',
'sort_order' => 0,
'default_group_id' => 0,
diff --git a/app/code/Magento/Store/Test/Unit/Block/SwitcherTest.php b/app/code/Magento/Store/Test/Unit/Block/SwitcherTest.php
index 5f0ba6c0b42d3..8b4799d2b3437 100644
--- a/app/code/Magento/Store/Test/Unit/Block/SwitcherTest.php
+++ b/app/code/Magento/Store/Test/Unit/Block/SwitcherTest.php
@@ -53,7 +53,7 @@ public function testGetTargetStorePostData()
$storeSwitchUrl = 'http://domain.com/stores/store/switch';
$store->expects($this->atLeastOnce())
->method('getCurrentUrl')
- ->with(false)
+ ->with(true)
->willReturn($storeSwitchUrl);
$this->corePostDataHelper->expects($this->any())
->method('getPostData')
diff --git a/app/code/Magento/Tax/Block/Adminhtml/Rate/Toolbar/Add.php b/app/code/Magento/Tax/Block/Adminhtml/Rate/Toolbar/Add.php
index 80cc9673a0d38..9cf96bc21e962 100644
--- a/app/code/Magento/Tax/Block/Adminhtml/Rate/Toolbar/Add.php
+++ b/app/code/Magento/Tax/Block/Adminhtml/Rate/Toolbar/Add.php
@@ -11,8 +11,6 @@
*/
namespace Magento\Tax\Block\Adminhtml\Rate\Toolbar;
-use Magento\Framework\View\Element\Template;
-
/**
* @api
* @since 100.0.2
diff --git a/app/code/Magento/Tax/Helper/Data.php b/app/code/Magento/Tax/Helper/Data.php
index 6d79540464ea1..1a531858797ac 100644
--- a/app/code/Magento/Tax/Helper/Data.php
+++ b/app/code/Magento/Tax/Helper/Data.php
@@ -9,7 +9,6 @@
use Magento\Store\Model\Store;
use Magento\Customer\Model\Address;
use Magento\Tax\Model\Config;
-use Magento\Customer\Model\Session as CustomerSession;
use Magento\Tax\Api\OrderTaxManagementInterface;
use Magento\Sales\Model\Order\Invoice;
use Magento\Sales\Model\Order\Creditmemo;
diff --git a/app/code/Magento/Tax/Model/Calculation/Rule/Validator.php b/app/code/Magento/Tax/Model/Calculation/Rule/Validator.php
index 2149a0c3c3ca2..29601b53c7765 100644
--- a/app/code/Magento/Tax/Model/Calculation/Rule/Validator.php
+++ b/app/code/Magento/Tax/Model/Calculation/Rule/Validator.php
@@ -6,7 +6,6 @@
namespace Magento\Tax\Model\Calculation\Rule;
-use Magento\Framework\Exception\InputException;
use Magento\Framework\Exception\NoSuchEntityException;
use Magento\Tax\Model\ClassModel as TaxClassModel;
use Magento\Tax\Model\ClassModelRegistry;
diff --git a/app/code/Magento/Tax/Model/Sales/Order/TaxManagement.php b/app/code/Magento/Tax/Model/Sales/Order/TaxManagement.php
index c563ee1b3084e..2e6e74a573f99 100644
--- a/app/code/Magento/Tax/Model/Sales/Order/TaxManagement.php
+++ b/app/code/Magento/Tax/Model/Sales/Order/TaxManagement.php
@@ -10,7 +10,6 @@
use Magento\Framework\Exception\NoSuchEntityException;
use Magento\Tax\Api\Data\OrderTaxDetailsAppliedTaxInterfaceFactory as TaxDetailsDataObjectFactory;
use Magento\Tax\Api\Data\OrderTaxDetailsAppliedTaxInterface as AppliedTax;
-use Magento\Tax\Model\Sales\Order\Tax;
use Magento\Sales\Model\Order\Tax\Item;
class TaxManagement implements \Magento\Tax\Api\OrderTaxManagementInterface
diff --git a/app/code/Magento/Tax/Model/TaxRuleCollection.php b/app/code/Magento/Tax/Model/TaxRuleCollection.php
index 33aaf3b22b6d6..5c6f3b1f14455 100644
--- a/app/code/Magento/Tax/Model/TaxRuleCollection.php
+++ b/app/code/Magento/Tax/Model/TaxRuleCollection.php
@@ -27,14 +27,14 @@ class TaxRuleCollection extends AbstractServiceCollection
/**
* Initialize dependencies.
*
- * @param \Magento\Framework\Data\Collection\EntityFactory $entityFactory
+ * @param EntityFactory $entityFactory
* @param FilterBuilder $filterBuilder
* @param SearchCriteriaBuilder $searchCriteriaBuilder
* @param SortOrderBuilder $sortOrderBuilder
* @param TaxRuleRepositoryInterface $ruleService
*/
public function __construct(
- \Magento\Framework\Data\Collection\EntityFactory $entityFactory,
+ EntityFactory $entityFactory,
FilterBuilder $filterBuilder,
SearchCriteriaBuilder $searchCriteriaBuilder,
SortOrderBuilder $sortOrderBuilder,
diff --git a/app/code/Magento/Theme/view/base/requirejs-config.js b/app/code/Magento/Theme/view/base/requirejs-config.js
index bd72a3d74fad1..c5ebd40e896e1 100644
--- a/app/code/Magento/Theme/view/base/requirejs-config.js
+++ b/app/code/Magento/Theme/view/base/requirejs-config.js
@@ -15,7 +15,6 @@ var config = {
},
'shim': {
'jquery/jquery-migrate': ['jquery'],
- 'jquery/jquery.hashchange': ['jquery', 'jquery/jquery-migrate'],
'jquery/jstree/jquery.hotkeys': ['jquery'],
'jquery/hover-intent': ['jquery'],
'mage/adminhtml/backup': ['prototype'],
@@ -39,7 +38,6 @@ var config = {
'jquery/validate': 'jquery/jquery.validate',
'jquery/hover-intent': 'jquery/jquery.hoverIntent',
'jquery/file-uploader': 'jquery/fileUploader/jquery.fileupload-fp',
- 'jquery/jquery.hashchange': 'jquery/jquery.ba-hashchange.min',
'prototype': 'legacy-build.min',
'jquery/jquery-storageapi': 'jquery/jquery.storageapi.min',
'text': 'mage/requirejs/text',
diff --git a/app/code/Magento/Ui/Component/Form/Element/UrlInput.php b/app/code/Magento/Ui/Component/Form/Element/UrlInput.php
new file mode 100644
index 0000000000000..1427e7b3fad9f
--- /dev/null
+++ b/app/code/Magento/Ui/Component/Form/Element/UrlInput.php
@@ -0,0 +1,42 @@
+getData('config');
+ //process urlTypes
+ if (isset($config['urlTypes'])) {
+ $links = $config['urlTypes']->getConfig();
+ $config['urlTypes'] = $links;
+ }
+ $this->setData('config', (array)$config);
+ parent::prepare();
+ }
+}
diff --git a/app/code/Magento/Ui/Component/Form/Field/DefaultValue.php b/app/code/Magento/Ui/Component/Form/Field/DefaultValue.php
new file mode 100644
index 0000000000000..99c124e88787f
--- /dev/null
+++ b/app/code/Magento/Ui/Component/Form/Field/DefaultValue.php
@@ -0,0 +1,70 @@
+scopeConfig = $scopeConfig;
+ $this->storeManager = $storeManager;
+ $this->path = $path;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function prepare()
+ {
+ parent::prepare();
+ $store = $this->storeManager->getStore();
+ $this->_data['config']['default'] = $this->scopeConfig->getValue(
+ $this->path,
+ \Magento\Store\Model\ScopeInterface::SCOPE_STORE,
+ $store
+ );
+ }
+}
diff --git a/app/code/Magento/Ui/Model/UrlInput/ConfigInterface.php b/app/code/Magento/Ui/Model/UrlInput/ConfigInterface.php
new file mode 100644
index 0000000000000..b7254b5ff342c
--- /dev/null
+++ b/app/code/Magento/Ui/Model/UrlInput/ConfigInterface.php
@@ -0,0 +1,21 @@
+linksConfiguration = $linksConfiguration;
+ $this->objectManager = $objectManager;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getConfig()
+ {
+ $config = [];
+ foreach ($this->linksConfiguration as $linkName => $className) {
+ $config[$linkName] = $this->createConfigProvider($className)->getConfig();
+ }
+ return $config;
+ }
+
+ /**
+ * Create config provider
+ *
+ * @param string $instance
+ * @return ConfigInterface
+ */
+ private function createConfigProvider($instance)
+ {
+ if (!is_subclass_of(
+ $instance,
+ ConfigInterface::class
+ )
+ ) {
+ throw new \InvalidArgumentException(
+ $instance .
+ ' does not implement ' .
+ ConfigInterface::class
+ );
+ }
+ return $this->objectManager->create($instance);
+ }
+}
diff --git a/app/code/Magento/Ui/Model/UrlInput/Url.php b/app/code/Magento/Ui/Model/UrlInput/Url.php
new file mode 100644
index 0000000000000..35361728c5a63
--- /dev/null
+++ b/app/code/Magento/Ui/Model/UrlInput/Url.php
@@ -0,0 +1,27 @@
+ __('URL'),
+ 'component' => 'Magento_Ui/js/form/element/abstract',
+ 'template' => 'ui/form/element/input',
+ 'sortOrder' => 20,
+ ];
+ }
+}
diff --git a/app/code/Magento/Ui/etc/adminhtml/di.xml b/app/code/Magento/Ui/etc/adminhtml/di.xml
index 416d7a6916f88..1198f4b1e9e3c 100644
--- a/app/code/Magento/Ui/etc/adminhtml/di.xml
+++ b/app/code/Magento/Ui/etc/adminhtml/di.xml
@@ -44,4 +44,11 @@
+
+
+
+ - Magento\Ui\Model\UrlInput\Url
+
+
+
diff --git a/app/code/Magento/Ui/etc/di.xml b/app/code/Magento/Ui/etc/di.xml
index 09a17f8b2af3f..8cf0e1e12e781 100644
--- a/app/code/Magento/Ui/etc/di.xml
+++ b/app/code/Magento/Ui/etc/di.xml
@@ -416,6 +416,7 @@
- Magento\Ui\Config\Converter\AdditionalClasses
- Magento\Ui\Config\Converter\Options
- Magento\Ui\Config\Converter\Actions\Proxy
+
- Magento\Ui\Config\Converter\Actions\Proxy
type
diff --git a/app/code/Magento/Ui/etc/ui_components.xsd b/app/code/Magento/Ui/etc/ui_components.xsd
index 3d3c0d11bb454..af0d8bb6f187c 100644
--- a/app/code/Magento/Ui/etc/ui_components.xsd
+++ b/app/code/Magento/Ui/etc/ui_components.xsd
@@ -28,6 +28,7 @@
+
diff --git a/app/code/Magento/Ui/etc/ui_configuration.xsd b/app/code/Magento/Ui/etc/ui_configuration.xsd
index 5783323b53188..17b19d2d6d691 100644
--- a/app/code/Magento/Ui/etc/ui_configuration.xsd
+++ b/app/code/Magento/Ui/etc/ui_configuration.xsd
@@ -54,6 +54,7 @@
+
@@ -780,4 +781,12 @@
+
+
+
+ The Url Input component allows to insert External URL and relative URL into the content. Add abilities
+ to define custom url link types.
+
+
+
diff --git a/app/code/Magento/Ui/etc/ui_definition.xsd b/app/code/Magento/Ui/etc/ui_definition.xsd
index d1787309d051e..7473e943115b6 100644
--- a/app/code/Magento/Ui/etc/ui_definition.xsd
+++ b/app/code/Magento/Ui/etc/ui_definition.xsd
@@ -75,6 +75,7 @@
+
diff --git a/app/code/Magento/Ui/view/base/ui_component/etc/definition.map.xml b/app/code/Magento/Ui/view/base/ui_component/etc/definition.map.xml
index cc3162e2b9acb..277eef2f2d25c 100644
--- a/app/code/Magento/Ui/view/base/ui_component/etc/definition.map.xml
+++ b/app/code/Magento/Ui/view/base/ui_component/etc/definition.map.xml
@@ -410,6 +410,22 @@
+
+
+
+
+ -
+
+
- settings/urlTypes
+ - settings/isDisplayAdditionalSettings
+ - settings/settingLabel
+ - settings/typeSelectorTemplate
+ - settings/settingTemplate
+ - settings/settingValue
+
+
+
+
diff --git a/app/code/Magento/Ui/view/base/ui_component/etc/definition.xml b/app/code/Magento/Ui/view/base/ui_component/etc/definition.xml
index 4b4eac517a299..73bf7ffbfa44a 100755
--- a/app/code/Magento/Ui/view/base/ui_component/etc/definition.xml
+++ b/app/code/Magento/Ui/view/base/ui_component/etc/definition.xml
@@ -149,6 +149,13 @@
wysiwyg
+
+
+ ui/form/element/urlInput/setting
+ ui/form/element/urlInput/typeSelector
+ true
+
+
diff --git a/app/code/Magento/Ui/view/base/ui_component/etc/definition/ui_settings.xsd b/app/code/Magento/Ui/view/base/ui_component/etc/definition/ui_settings.xsd
index 9f9d1f519f45e..cbf69e6046943 100644
--- a/app/code/Magento/Ui/view/base/ui_component/etc/definition/ui_settings.xsd
+++ b/app/code/Magento/Ui/view/base/ui_component/etc/definition/ui_settings.xsd
@@ -219,6 +219,15 @@
+
+
+
+ The array of the configuration for urls types to be displayed in the list for selection.
+
+
+
+
+
@@ -601,18 +610,33 @@
-
+
-
+
+
+
+
+ The array of the configuration for urls types to be displayed in the list for selection.
+
+
+
+
+
+ Path to the PHP class that provides configuration.
+
+
+
+
+
diff --git a/app/code/Magento/Ui/view/base/ui_component/etc/definition/urlInput.xsd b/app/code/Magento/Ui/view/base/ui_component/etc/definition/urlInput.xsd
new file mode 100644
index 0000000000000..98918d92944e9
--- /dev/null
+++ b/app/code/Magento/Ui/view/base/ui_component/etc/definition/urlInput.xsd
@@ -0,0 +1,74 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Options for "urlInput" element
+
+
+
+
+
+
+ The path to the custom url setting ".html" template.
+
+
+
+
+
+
+ The path to the custom url types selector ".html" template.
+
+
+
+
+
+
+ The label for custom url setting.
+
+
+
+
+
+
+ Allows to specify if display additional settings
+
+
+
+
+
+
+ Allows to specify default value for setting
+
+
+
+
+
+
diff --git a/app/code/Magento/Ui/view/base/web/js/form/element/url-input.js b/app/code/Magento/Ui/view/base/web/js/form/element/url-input.js
new file mode 100644
index 0000000000000..1365e19a8e5b6
--- /dev/null
+++ b/app/code/Magento/Ui/view/base/web/js/form/element/url-input.js
@@ -0,0 +1,162 @@
+/**
+ * Copyright © Magento, Inc. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+
+/**
+ * @api
+ */
+define([
+ 'underscore',
+ 'uiLayout',
+ 'mage/translate',
+ 'Magento_Ui/js/form/element/abstract'
+], function (_, layout, $t, Abstract) {
+ 'use strict';
+
+ return Abstract.extend({
+ defaults: {
+ linkedElement: {},
+ settingTemplate: 'ui/form/element/urlInput/setting',
+ typeSelectorTemplate: 'ui/form/element/urlInput/typeSelector',
+ options: [],
+ linkedElementInstances: {},
+ //checkbox
+ isDisplayAdditionalSettings: true,
+ settingValue: false,
+ settingLabel: $t('Open in new tab'),
+ tracks: {
+ linkedElement: true
+ },
+ baseLinkSetting: {
+ namePrefix: '${$.name}.',
+ dataScopePrefix: '${$.dataScope}.',
+ provider: '${$.provider}'
+ },
+ urlTypes: {},
+ listens: {
+ settingValue: 'checked',
+ disabled: 'hideLinkedElement',
+ linkType: 'createChildUrlInputComponent'
+ },
+ links: {
+ linkType: '${$.provider}:${$.dataScope}.type',
+ settingValue: '${$.provider}:${$.dataScope}.setting'
+ }
+ },
+
+ /** @inheritdoc */
+ initConfig: function (config) {
+ var processedLinkTypes = {},
+ baseLinkType = this.constructor.defaults.baseLinkSetting;
+
+ _.each(config.urlTypes, function (linkSettingsArray, linkName) {
+ //add link name by link type
+ linkSettingsArray.name = baseLinkType.namePrefix + linkName;
+ linkSettingsArray.dataScope = baseLinkType.dataScopePrefix + linkName;
+ linkSettingsArray.type = linkName;
+ processedLinkTypes[linkName] = {};
+ _.extend(processedLinkTypes[linkName], baseLinkType, linkSettingsArray);
+ });
+ _.extend(this.constructor.defaults.urlTypes, processedLinkTypes);
+
+ this._super();
+ },
+
+ /**
+ * Initializes observable properties of instance
+ *
+ * @returns {Abstract} Chainable.
+ */
+ initObservable: function () {
+ this._super()
+ .observe('componentTemplate options value linkType settingValue checked isDisplayAdditionalSettings')
+ .setOptions();
+
+ return this;
+ },
+
+ /**
+ * Set options to select based on link types configuration
+ *
+ * @return {Object}
+ */
+ setOptions: function () {
+ var result = [];
+
+ _.each(this.urlTypes, function (option, key) {
+ result.push({
+ value: key,
+ label: option.label,
+ sortOrder: option.sortOrder || 0
+ });
+ });
+
+ //sort options by sortOrder
+ result.sort(function (a, b) {
+ return a.sortOrder > b.sortOrder ? 1 : -1;
+ });
+
+ this.options(result);
+
+ return this;
+ },
+
+ /** @inheritdoc */
+ setPreview: function (visible) {
+ this.linkedElement().visible(visible);
+ },
+
+ /**
+ * Initializes observable properties of instance
+ *
+ * @param {Boolean} disabled
+ */
+ hideLinkedElement: function (disabled) {
+ this.linkedElement().disabled(disabled);
+ },
+
+ /** @inheritdoc */
+ destroy: function () {
+ _.each(this.linkedElementInstances, function (value) {
+ value().destroy();
+ });
+ this._super();
+ },
+
+ /**
+ * Create child component by value
+ *
+ * @param {String} value
+ * @return void
+ */
+ createChildUrlInputComponent: function (value) {
+ var elementConfig;
+
+ if (_.isUndefined(this.linkedElementInstances[value])) {
+ elementConfig = this.urlTypes[value];
+ layout([elementConfig]);
+ this.linkedElementInstances[value] = this.requestModule(elementConfig.name);
+ }
+ this.linkedElement = this.linkedElementInstances[value];
+
+ },
+
+ /**
+ * Returns linked element to display related field in template
+ * @return String
+ */
+ getLinkedElementName: function () {
+ return this.linkedElement;
+ },
+
+ /**
+ * Add ability to choose check box by clicking on label
+ */
+ checkboxClick: function () {
+ if (!this.disabled()) {
+ this.settingValue(!this.settingValue());
+ }
+ }
+ });
+});
diff --git a/app/code/Magento/Ui/view/base/web/js/lib/validation/rules.js b/app/code/Magento/Ui/view/base/web/js/lib/validation/rules.js
index 0ffd65c47d4cf..8f276223b6ec3 100644
--- a/app/code/Magento/Ui/view/base/web/js/lib/validation/rules.js
+++ b/app/code/Magento/Ui/view/base/web/js/lib/validation/rules.js
@@ -963,6 +963,12 @@ define([
return moment.utc(value, params.dateFormat).unix() <= maxValue;
},
$.mage.__('The date is not within the specified range.')
+ ],
+ 'blacklist-url': [
+ function (value, param) {
+ return new RegExp(param).test(value);
+ },
+ $.mage.__('This link is not allowed.')
]
}, function (data) {
return {
diff --git a/app/code/Magento/Ui/view/base/web/js/lib/view/utils/raf.js b/app/code/Magento/Ui/view/base/web/js/lib/view/utils/raf.js
index 1cbbfb3ecee48..3ec0996543c7d 100644
--- a/app/code/Magento/Ui/view/base/web/js/lib/view/utils/raf.js
+++ b/app/code/Magento/Ui/view/base/web/js/lib/view/utils/raf.js
@@ -19,6 +19,9 @@ define([
window.onRequestAnimationFrame ||
window.msRequestAnimationFrame ||
function (callback) {
+ if (typeof callback != 'function') {
+ throw new Error('raf argument "callback" must be of type function');
+ }
window.setTimeout(callback, 1000 / 60);
};
diff --git a/app/code/Magento/Ui/view/base/web/templates/form/element/url-input.html b/app/code/Magento/Ui/view/base/web/templates/form/element/url-input.html
new file mode 100644
index 0000000000000..412184b751ad5
--- /dev/null
+++ b/app/code/Magento/Ui/view/base/web/templates/form/element/url-input.html
@@ -0,0 +1,30 @@
+
+
+
diff --git a/app/code/Magento/Ui/view/base/web/templates/form/element/urlInput/setting.html b/app/code/Magento/Ui/view/base/web/templates/form/element/urlInput/setting.html
new file mode 100644
index 0000000000000..5d4818fa56965
--- /dev/null
+++ b/app/code/Magento/Ui/view/base/web/templates/form/element/urlInput/setting.html
@@ -0,0 +1,18 @@
+
+
+
+
+
+
+
diff --git a/app/code/Magento/Ui/view/base/web/templates/form/element/urlInput/typeSelector.html b/app/code/Magento/Ui/view/base/web/templates/form/element/urlInput/typeSelector.html
new file mode 100644
index 0000000000000..95a87a2789d50
--- /dev/null
+++ b/app/code/Magento/Ui/view/base/web/templates/form/element/urlInput/typeSelector.html
@@ -0,0 +1,19 @@
+
+
\ No newline at end of file
diff --git a/app/code/Magento/Ups/Model/Carrier.php b/app/code/Magento/Ups/Model/Carrier.php
index dad8a8b157fee..ca5fb36c5eba4 100644
--- a/app/code/Magento/Ups/Model/Carrier.php
+++ b/app/code/Magento/Ups/Model/Carrier.php
@@ -716,6 +716,9 @@ protected function _getXmlQuotes()
if ($this->getConfigFlag('negotiated_active')) {
$xmlParams .= "";
}
+ if ($this->getConfigFlag('include_taxes')) {
+ $xmlParams .= "";
+ }
$xmlParams .= <<
@@ -791,6 +794,8 @@ private function mapCurrencyCode($code)
* @param mixed $xmlResponse
* @return Result
* @SuppressWarnings(PHPMD.CyclomaticComplexity)
+ * @SuppressWarnings(PHPMD.ExcessiveMethodLength)
+ * @SuppressWarnings(PHPMD.ElseExpression)
*/
protected function _parseXmlResponse($xmlResponse)
{
@@ -815,17 +820,52 @@ protected function _parseXmlResponse($xmlResponse)
foreach ($arr as $shipElement) {
$code = (string)$shipElement->Service->Code;
if (in_array($code, $allowedMethods)) {
+ //The location of tax information is in a different place
+ // depending on whether we are using negotiated rates or not
if ($negotiatedActive) {
- $cost = $shipElement->NegotiatedRates->NetSummaryCharges->GrandTotal->MonetaryValue;
+ $includeTaxesArr = $xml->getXpath(
+ "//RatingServiceSelectionResponse/RatedShipment/NegotiatedRates"
+ . "/NetSummaryCharges/TotalChargesWithTaxes"
+ );
+ $includeTaxesActive = $this->getConfigFlag('include_taxes') && !empty($includeTaxesArr);
+ if ($includeTaxesActive) {
+ $cost = $shipElement->NegotiatedRates
+ ->NetSummaryCharges
+ ->TotalChargesWithTaxes
+ ->MonetaryValue;
+
+ $responseCurrencyCode = $this->mapCurrencyCode(
+ (string)$shipElement->NegotiatedRates
+ ->NetSummaryCharges
+ ->TotalChargesWithTaxes
+ ->CurrencyCode
+ );
+ } else {
+ $cost = $shipElement->NegotiatedRates->NetSummaryCharges->GrandTotal->MonetaryValue;
+ $responseCurrencyCode = $this->mapCurrencyCode(
+ (string)$shipElement->NegotiatedRates->NetSummaryCharges->GrandTotal->CurrencyCode
+ );
+ }
} else {
- $cost = $shipElement->TotalCharges->MonetaryValue;
+ $includeTaxesArr = $xml->getXpath(
+ "//RatingServiceSelectionResponse/RatedShipment/TotalChargesWithTaxes"
+ );
+ $includeTaxesActive = $this->getConfigFlag('include_taxes') && !empty($includeTaxesArr);
+ if ($includeTaxesActive) {
+ $cost = $shipElement->TotalChargesWithTaxes->MonetaryValue;
+ $responseCurrencyCode = $this->mapCurrencyCode(
+ (string)$shipElement->TotalChargesWithTaxes->CurrencyCode
+ );
+ } else {
+ $cost = $shipElement->TotalCharges->MonetaryValue;
+ $responseCurrencyCode = $this->mapCurrencyCode(
+ (string)$shipElement->TotalCharges->CurrencyCode
+ );
+ }
}
//convert price with Origin country currency code to base currency code
$successConversion = true;
- $responseCurrencyCode = $this->mapCurrencyCode(
- (string)$shipElement->TotalCharges->CurrencyCode
- );
if ($responseCurrencyCode) {
if (in_array($responseCurrencyCode, $allowedCurrencies)) {
$cost = (double)$cost * $this->_getBaseCurrencyRate($responseCurrencyCode);
diff --git a/app/code/Magento/Ups/Test/Unit/Model/CarrierCollectRatesOptionsTest.php b/app/code/Magento/Ups/Test/Unit/Model/CarrierCollectRatesOptionsTest.php
new file mode 100644
index 0000000000000..854f14f1b48bc
--- /dev/null
+++ b/app/code/Magento/Ups/Test/Unit/Model/CarrierCollectRatesOptionsTest.php
@@ -0,0 +1,325 @@
+objectManager = new \Magento\Framework\TestFramework\Unit\Helper\ObjectManager($this);
+
+ $scopeMock = $this->getMockBuilder(ScopeConfigInterface::class)
+ ->disableOriginalConstructor()
+ ->getMock();
+
+ $scopeMock->expects($this->any())
+ ->method('getValue')
+ ->willReturnCallback([$this, 'scopeConfigGetValue']);
+ $scopeMock->expects($this->any())
+ ->method('isSetFlag')
+ ->willReturnCallback([$this, 'scopeConfigisSetFlag']);
+
+ $errorFactoryMock = $this->getMockBuilder(RateResultErrorFactory::class)
+ ->disableOriginalConstructor()
+ ->getMock();
+
+ $loggerInterfaceMock = $this->getMockBuilder(LoggerInterface::class)
+ ->disableOriginalConstructor()
+ ->getMock();
+
+ $securityMock = $this->getMockBuilder(Security::class)
+ ->disableOriginalConstructor()
+ ->getMock();
+
+ $elementFactoryMock = $this->getMockBuilder(ElementFactory::class)
+ ->disableOriginalConstructor()
+ ->getMock();
+
+ $rateResultMock = $this->getMockBuilder(RateResult::class)
+ ->disableOriginalConstructor()
+ ->setMethods(['getError'])
+ ->getMock();
+
+ $rateFactoryMock = $this->getMockBuilder(RateResultFactory::class)
+ ->disableOriginalConstructor()
+ ->setMethods(['create'])
+ ->getMock();
+
+ $rateFactoryMock->expects($this->any())
+ ->method('create')
+ ->willReturn($rateResultMock);
+
+ $priceInterfaceMock = $this->getMockBuilder(PriceCurrencyInterface::class)
+ ->disableOriginalConstructor()
+ ->getMock();
+
+ $rateMethodMock = $this->getMockBuilder(Method::class)
+ ->setConstructorArgs(['priceCurrency' => $priceInterfaceMock])
+ ->setMethods(null)
+ ->getMock();
+
+ $methodFactoryMock = $this->getMockBuilder(MethodFactory::class)
+ ->disableOriginalConstructor()
+ ->setMethods(['create'])
+ ->getMock();
+
+ $methodFactoryMock->expects($this->any())
+ ->method('create')
+ ->willReturn($rateMethodMock);
+
+ $resultFactoryMock = $this->getMockBuilder(TrackResultFactory::class)
+ ->disableOriginalConstructor()
+ ->getMock();
+
+ $trErrorFactoryMock = $this->getMockBuilder(TrackingResultErrorFactory::class)
+ ->disableOriginalConstructor()
+ ->getMock();
+
+ $statusFactoryMock = $this->getMockBuilder(StatusFactory::class)
+ ->disableOriginalConstructor()
+ ->getMock();
+
+ $regionFactoryMock = $this->getMockBuilder(RegionFactory::class)
+ ->disableOriginalConstructor()
+ ->getMock();
+
+ $countryMock = $this->getMockBuilder(Country::class)
+ ->disableOriginalConstructor()
+ ->setMethods(['load', 'getData'])
+ ->getMock();
+
+ $countryMock->expects($this->any())
+ ->method('load')
+ ->willReturnSelf();
+
+ $countryFactoryMock = $this->getMockBuilder(CountryFactory::class)
+ ->disableOriginalConstructor()
+ ->setMethods(['create'])
+ ->getMock();
+
+ $countryFactoryMock->expects($this->any())
+ ->method('create')
+ ->willReturn($countryMock);
+
+ $allowCurrencies = ['GBP'];
+ $baseCurrencies = ['GBP'];
+ $currencyRates = ['GBP' => ['GBP' => 1]];
+ $currencyFactoryMock = $this->getMockBuilder(CurrencyFactory::class)
+ ->disableOriginalConstructor()
+ ->setMethods(['create'])
+ ->getMock();
+ $currencyMock = $this->getMockBuilder(Currency::class)
+ ->disableOriginalConstructor()
+ ->setMethods(['getConfigAllowCurrencies', 'getConfigBaseCurrencies', 'getCurrencyRates'])
+ ->getMock();
+ $currencyFactoryMock->expects($this->once())
+ ->method('create')
+ ->willReturn($currencyMock);
+ $currencyMock->expects($this->any())
+ ->method('getConfigAllowCurrencies')
+ ->willReturn($allowCurrencies);
+ $currencyMock->expects($this->any())
+ ->method('getConfigBaseCurrencies')
+ ->willReturn($baseCurrencies);
+ $currencyMock->expects($this->any())
+ ->method('getCurrencyRates')
+ ->with($baseCurrencies, $allowCurrencies)
+ ->willReturn($currencyRates);
+
+ $dataMock = $this->getMockBuilder(Data::class)
+ ->disableOriginalConstructor()
+ ->getMock();
+
+ $stockRegistryMock = $this->getMockBuilder(StockRegistry::class)
+ ->disableOriginalConstructor()
+ ->getMock();
+
+ $formatInterfaceMock = $this->getMockBuilder(FormatInterface::class)
+ ->disableOriginalConstructor()
+ ->getMock();
+
+ $configHelperMock = $this->getMockBuilder(Config::class)
+ ->disableOriginalConstructor()
+ ->getMock();
+
+ $this->model = $this->getMockBuilder(Carrier::class)
+ ->setMethods(['_getCachedQuotes', 'canCollectRates', '_updateFreeMethodQuote', '_getBaseCurrencyRate'])
+ ->setConstructorArgs(
+ [
+ 'scopeConfig' => $scopeMock,
+ 'rateErrorFactory' => $errorFactoryMock,
+ 'logger' => $loggerInterfaceMock,
+ 'xmlSecurity' => $securityMock,
+ 'xmlElFactory' => $elementFactoryMock,
+ 'rateFactory' => $rateFactoryMock,
+ 'rateMethodFactory' => $methodFactoryMock,
+ 'trackFactory' => $resultFactoryMock,
+ 'trackErrorFactory' => $trErrorFactoryMock,
+ 'trackStatusFactory' => $statusFactoryMock,
+ 'regionFactory' => $regionFactoryMock,
+ 'countryFactory' => $countryFactoryMock,
+ 'currencyFactory' => $currencyFactoryMock,
+ 'directoryData' => $dataMock,
+ 'stockRegistry' => $stockRegistryMock,
+ 'localeFormat' => $formatInterfaceMock,
+ 'configHelper' => $configHelperMock,
+ 'data' => [],
+ ]
+ )
+ ->getMock();
+
+ $this->model->expects($this->any())
+ ->method('canCollectRates')
+ ->willReturn(true);
+
+ $this->model->expects($this->any())
+ ->method('_getBaseCurrencyRate')
+ ->willReturn(1.00);
+
+ $this->rateRequest = $this->objectManager->getObject(RateRequest::class);
+ }
+
+ /**
+ * Callback function, emulates getValue function
+ * @param $path
+ * @return null|string
+ */
+ public function scopeConfigGetValue($path)
+ {
+ $pathMap = [
+ 'carriers/ups/type' => 'UPS_XML',
+ 'carriers/ups/shipper_number' => '12345',
+ 'carriers/ups/allowed_methods' => $this->allowed_methods,
+ ];
+
+ return isset($pathMap[$path]) ? $pathMap[$path] : null;
+ }
+
+ /**
+ * Callback function, emulates isSetFlag function
+ * @param $path
+ * @return bool
+ */
+ public function scopeConfigisSetFlag($path)
+ {
+ $pathMap = [
+ 'carriers/ups/negotiated_active' => $this->negotiatedactive,
+ 'carriers/ups/include_taxes' => $this->include_taxes,
+ ];
+
+ if (isset($pathMap[$path])) {
+ if ($pathMap[$path]) {
+ return(true);
+ }
+ }
+ return(false);
+ }
+
+ /**
+ * @param int $neg
+ * @param int $tax
+ * @param string $file
+ * @param string $method
+ * @param float $expectedprice
+ * @dataProvider collectRatesDataProvider
+ */
+ public function testCollectRates($neg, $tax, $file, $method, $expectedprice)
+ {
+ $this->negotiatedactive = $neg;
+ $this->include_taxes = $tax;
+ $this->allowed_methods = $method;
+
+ $response = file_get_contents(__DIR__ . $file);
+ $this->model->expects($this->any())
+ ->method('_getCachedQuotes')
+ ->willReturn($response);
+
+ $rates = $this->model->collectRates($this->rateRequest)->getAllRates();
+ $this->assertEquals($expectedprice, $rates[0]->getData('cost'));
+ $this->assertEquals($method, $rates[0]->getData('method'));
+ }
+
+ /**
+ * Get list of rates variations
+ * @return array
+ */
+ public function collectRatesDataProvider()
+ {
+ return [
+ [0, 0, '/_files/ups_rates_response_option1.xml', '11', 6.45 ],
+ [0, 0, '/_files/ups_rates_response_option2.xml', '65', 29.59 ],
+ [0, 1, '/_files/ups_rates_response_option3.xml', '11', 7.74 ],
+ [0, 1, '/_files/ups_rates_response_option4.xml', '65', 29.59 ],
+ [1, 0, '/_files/ups_rates_response_option5.xml', '11', 9.35 ],
+ [1, 0, '/_files/ups_rates_response_option6.xml', '65', 41.61 ],
+ [1, 1, '/_files/ups_rates_response_option7.xml', '11', 11.22 ],
+ [1, 1, '/_files/ups_rates_response_option8.xml', '65', 41.61 ],
+ ];
+ }
+}
diff --git a/app/code/Magento/Ups/Test/Unit/Model/_files/ups_rates_response_option1.xml b/app/code/Magento/Ups/Test/Unit/Model/_files/ups_rates_response_option1.xml
new file mode 100644
index 0000000000000..658bf756aacfb
--- /dev/null
+++ b/app/code/Magento/Ups/Test/Unit/Model/_files/ups_rates_response_option1.xml
@@ -0,0 +1,164 @@
+
+
+
+
+
+ Rating and Service
+ 1.0
+
+ 1
+ Success
+
+
+
+ 11
+
+ Your invoice may vary from the displayed reference
+ rates
+
+
+
+ KGS
+
+ 2.0
+
+
+ GBP
+ 6.45
+
+
+ GBP
+ 0.00
+
+
+ GBP
+ 6.45
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 2.0
+
+
+
+
+
+
+
+
+
+
+ 65
+
+ Your invoice may vary from the displayed reference
+ rates
+
+
+
+ KGS
+
+ 2.0
+
+
+ GBP
+ 10.25
+
+
+ GBP
+ 0.00
+
+
+ GBP
+ 10.25
+
+ 1
+ 12:00 Noon
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 2.0
+
+
+
+
+
+
+
+
+
+
+ 54
+
+ Your invoice may vary from the displayed reference
+ rates
+
+
+
+ KGS
+
+ 2.0
+
+
+ GBP
+ 15.02
+
+
+ GBP
+ 0.00
+
+
+ GBP
+ 15.02
+
+ 1
+ 9:00 A.M.
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 2.0
+
+
+
+
+
+
+
+
+
diff --git a/app/code/Magento/Ups/Test/Unit/Model/_files/ups_rates_response_option2.xml b/app/code/Magento/Ups/Test/Unit/Model/_files/ups_rates_response_option2.xml
new file mode 100644
index 0000000000000..88fe2de81a3de
--- /dev/null
+++ b/app/code/Magento/Ups/Test/Unit/Model/_files/ups_rates_response_option2.xml
@@ -0,0 +1,213 @@
+
+
+
+
+
+ Rating and Service
+ 1.0
+
+ 1
+ Success
+
+
+
+ 07
+
+ Your invoice may vary from the displayed reference
+ rates
+
+
+
+ KGS
+
+ 2.0
+
+
+ GBP
+ 35.16
+
+
+ GBP
+ 0.00
+
+
+ GBP
+ 35.16
+
+ 1
+ 10:30 A.M.
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 2.0
+
+
+
+
+
+
+
+
+
+
+ 08
+
+ Your invoice may vary from the displayed reference
+ rates
+
+
+
+ KGS
+
+ 2.0
+
+
+ GBP
+ 34.15
+
+
+ GBP
+ 0.00
+
+
+ GBP
+ 34.15
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 2.0
+
+
+
+
+
+
+
+
+
+
+ 65
+
+ Your invoice may vary from the displayed reference
+ rates
+
+
+
+ KGS
+
+ 2.0
+
+
+ GBP
+ 29.59
+
+
+ GBP
+ 0.00
+
+
+ GBP
+ 29.59
+
+ 1
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 2.0
+
+
+
+
+
+
+
+
+
+
+ 54
+
+ Your invoice may vary from the displayed reference
+ rates
+
+
+
+ KGS
+
+ 2.0
+
+
+ GBP
+ 45.18
+
+
+ GBP
+ 0.00
+
+
+ GBP
+ 45.18
+
+ 1
+ 8:30 A.M.
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 2.0
+
+
+
+
+
+
+
+
+
diff --git a/app/code/Magento/Ups/Test/Unit/Model/_files/ups_rates_response_option3.xml b/app/code/Magento/Ups/Test/Unit/Model/_files/ups_rates_response_option3.xml
new file mode 100644
index 0000000000000..1732594c57ea6
--- /dev/null
+++ b/app/code/Magento/Ups/Test/Unit/Model/_files/ups_rates_response_option3.xml
@@ -0,0 +1,209 @@
+
+
+
+
+
+ Rating and Service
+ 1.0
+
+ 1
+ Success
+
+
+
+ 01
+ Taxes are included in the shipping cost and apply to the transportation charges
+ but additional duties/taxes may apply and are not reflected in the total amount
+ due.
+
+
+
+ 11
+
+ Your invoice may vary from the displayed reference
+ rates
+
+
+
+ KGS
+
+ 2.0
+
+
+ GBP
+ 6.45
+
+
+ GBP
+ 0.00
+
+
+ VAT
+ 1.29
+
+
+ GBP
+ 6.45
+
+
+ GBP
+ 7.74
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 2.0
+
+
+
+
+
+
+
+
+
+
+ 01
+ Taxes are included in the shipping cost and apply to the transportation charges
+ but additional duties/taxes may apply and are not reflected in the total amount
+ due.
+
+
+
+ 65
+
+ Your invoice may vary from the displayed reference
+ rates
+
+
+
+ KGS
+
+ 2.0
+
+
+ GBP
+ 10.25
+
+
+ GBP
+ 0.00
+
+
+ VAT
+ 2.05
+
+
+ GBP
+ 10.25
+
+
+ GBP
+ 12.30
+
+ 1
+ 12:00 Noon
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 2.0
+
+
+
+
+
+
+
+
+
+
+ 01
+ Taxes are included in the shipping cost and apply to the transportation charges
+ but additional duties/taxes may apply and are not reflected in the total amount
+ due.
+
+
+
+ 54
+
+ Your invoice may vary from the displayed reference
+ rates
+
+
+
+ KGS
+
+ 2.0
+
+
+ GBP
+ 15.02
+
+
+ GBP
+ 0.00
+
+
+ VAT
+ 3.00
+
+
+ GBP
+ 15.02
+
+
+ GBP
+ 18.02
+
+ 1
+ 9:00 A.M.
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 2.0
+
+
+
+
+
+
+
+
+
diff --git a/app/code/Magento/Ups/Test/Unit/Model/_files/ups_rates_response_option4.xml b/app/code/Magento/Ups/Test/Unit/Model/_files/ups_rates_response_option4.xml
new file mode 100644
index 0000000000000..8de6b45982767
--- /dev/null
+++ b/app/code/Magento/Ups/Test/Unit/Model/_files/ups_rates_response_option4.xml
@@ -0,0 +1,237 @@
+
+
+
+
+
+ Rating and Service
+ 1.0
+
+ 1
+ Success
+
+
+
+ 03
+ Additional duties/taxes may apply and are not reflected in the total amount
+ due.
+
+
+
+ 07
+
+ Your invoice may vary from the displayed reference
+ rates
+
+
+
+ KGS
+
+ 2.0
+
+
+ GBP
+ 35.16
+
+
+ GBP
+ 0.00
+
+
+ GBP
+ 35.16
+
+ 1
+ 10:30 A.M.
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 2.0
+
+
+
+
+
+
+
+
+
+
+ 03
+ Additional duties/taxes may apply and are not reflected in the total amount
+ due.
+
+
+
+ 08
+
+ Your invoice may vary from the displayed reference
+ rates
+
+
+
+ KGS
+
+ 2.0
+
+
+ GBP
+ 34.15
+
+
+ GBP
+ 0.00
+
+
+ GBP
+ 34.15
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 2.0
+
+
+
+
+
+
+
+
+
+
+ 03
+ Additional duties/taxes may apply and are not reflected in the total amount
+ due.
+
+
+
+ 65
+
+ Your invoice may vary from the displayed reference
+ rates
+
+
+
+ KGS
+
+ 2.0
+
+
+ GBP
+ 29.59
+
+
+ GBP
+ 0.00
+
+
+ GBP
+ 29.59
+
+ 1
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 2.0
+
+
+
+
+
+
+
+
+
+
+ 03
+ Additional duties/taxes may apply and are not reflected in the total amount
+ due.
+
+
+
+ 54
+
+ Your invoice may vary from the displayed reference
+ rates
+
+
+
+ KGS
+
+ 2.0
+
+
+ GBP
+ 45.18
+
+
+ GBP
+ 0.00
+
+
+ GBP
+ 45.18
+
+ 1
+ 8:30 A.M.
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 2.0
+
+
+
+
+
+
+
+
+
diff --git a/app/code/Magento/Ups/Test/Unit/Model/_files/ups_rates_response_option5.xml b/app/code/Magento/Ups/Test/Unit/Model/_files/ups_rates_response_option5.xml
new file mode 100644
index 0000000000000..7b8b3a906781f
--- /dev/null
+++ b/app/code/Magento/Ups/Test/Unit/Model/_files/ups_rates_response_option5.xml
@@ -0,0 +1,188 @@
+
+
+
+
+
+ Rating and Service
+ 1.0
+
+ 1
+ Success
+
+
+
+ 11
+
+ Your invoice may vary from the displayed reference
+ rates
+
+
+
+ KGS
+
+ 2.0
+
+
+ GBP
+ 6.45
+
+
+ GBP
+ 0.00
+
+
+ GBP
+ 6.45
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 2.0
+
+
+
+
+
+
+
+
+
+
+ GBP
+ 9.35
+
+
+
+
+
+
+ 65
+
+ Your invoice may vary from the displayed reference
+ rates
+
+
+
+ KGS
+
+ 2.0
+
+
+ GBP
+ 10.25
+
+
+ GBP
+ 0.00
+
+
+ GBP
+ 10.25
+
+ 1
+ 12:00 Noon
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 2.0
+
+
+
+
+
+
+
+
+
+
+ GBP
+ 13.33
+
+
+
+
+
+
+ 54
+
+ Your invoice may vary from the displayed reference
+ rates
+
+
+
+ KGS
+
+ 2.0
+
+
+ GBP
+ 15.02
+
+
+ GBP
+ 0.00
+
+
+ GBP
+ 15.02
+
+ 1
+ 9:00 A.M.
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 2.0
+
+
+
+
+
+
+
+
+
+
+ GBP
+ 74.83
+
+
+
+
+
diff --git a/app/code/Magento/Ups/Test/Unit/Model/_files/ups_rates_response_option6.xml b/app/code/Magento/Ups/Test/Unit/Model/_files/ups_rates_response_option6.xml
new file mode 100644
index 0000000000000..97a19e5086d7a
--- /dev/null
+++ b/app/code/Magento/Ups/Test/Unit/Model/_files/ups_rates_response_option6.xml
@@ -0,0 +1,245 @@
+
+
+
+
+
+ Rating and Service
+ 1.0
+
+ 1
+ Success
+
+
+
+ 07
+
+ Your invoice may vary from the displayed reference
+ rates
+
+
+
+ KGS
+
+ 2.0
+
+
+ GBP
+ 35.16
+
+
+ GBP
+ 0.00
+
+
+ GBP
+ 35.16
+
+ 1
+ 10:30 A.M.
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 2.0
+
+
+
+
+
+
+
+
+
+
+ GBP
+ 44.37
+
+
+
+
+
+
+ 08
+
+ Your invoice may vary from the displayed reference
+ rates
+
+
+
+ KGS
+
+ 2.0
+
+
+ GBP
+ 34.15
+
+
+ GBP
+ 0.00
+
+
+ GBP
+ 34.15
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 2.0
+
+
+
+
+
+
+
+
+
+
+ GBP
+ 60.57
+
+
+
+
+
+
+ 65
+
+ Your invoice may vary from the displayed reference
+ rates
+
+
+
+ KGS
+
+ 2.0
+
+
+ GBP
+ 29.59
+
+
+ GBP
+ 0.00
+
+
+ GBP
+ 29.59
+
+ 1
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 2.0
+
+
+
+
+
+
+
+
+
+
+ GBP
+ 41.61
+
+
+
+
+
+
+ 54
+
+ Your invoice may vary from the displayed reference
+ rates
+
+
+
+ KGS
+
+ 2.0
+
+
+ GBP
+ 45.18
+
+
+ GBP
+ 0.00
+
+
+ GBP
+ 45.18
+
+ 1
+ 8:30 A.M.
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 2.0
+
+
+
+
+
+
+
+
+
+
+ GBP
+ 157.47
+
+
+
+
+
diff --git a/app/code/Magento/Ups/Test/Unit/Model/_files/ups_rates_response_option7.xml b/app/code/Magento/Ups/Test/Unit/Model/_files/ups_rates_response_option7.xml
new file mode 100644
index 0000000000000..e84e3aa7aefb0
--- /dev/null
+++ b/app/code/Magento/Ups/Test/Unit/Model/_files/ups_rates_response_option7.xml
@@ -0,0 +1,233 @@
+
+
+
+
+
+ Rating and Service
+ 1.0
+
+ 1
+ Success
+
+
+
+ 01
+ Taxes are included in the shipping cost and apply to the transportation charges
+ but additional duties/taxes may apply and are not reflected in the total amount
+ due.
+
+
+
+ 11
+
+ Your invoice may vary from the displayed reference
+ rates
+
+
+
+ KGS
+
+ 2.0
+
+
+ GBP
+ 6.45
+
+
+ GBP
+ 0.00
+
+
+ GBP
+ 6.45
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 2.0
+
+
+
+
+
+
+
+
+
+ VAT
+ 1.87
+
+
+
+ GBP
+ 9.35
+
+
+ GBP
+ 11.22
+
+
+
+
+
+
+ 01
+ Taxes are included in the shipping cost and apply to the transportation charges
+ but additional duties/taxes may apply and are not reflected in the total amount
+ due.
+
+
+
+ 65
+
+ Your invoice may vary from the displayed reference
+ rates
+
+
+
+ KGS
+
+ 2.0
+
+
+ GBP
+ 10.25
+
+
+ GBP
+ 0.00
+
+
+ GBP
+ 10.25
+
+ 1
+ 12:00 Noon
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 2.0
+
+
+
+
+
+
+
+
+
+ VAT
+ 2.66
+
+
+
+ GBP
+ 13.33
+
+
+ GBP
+ 15.99
+
+
+
+
+
+
+ 01
+ Taxes are included in the shipping cost and apply to the transportation charges
+ but additional duties/taxes may apply and are not reflected in the total amount
+ due.
+
+
+
+ 54
+
+ Your invoice may vary from the displayed reference
+ rates
+
+
+
+ KGS
+
+ 2.0
+
+
+ GBP
+ 15.02
+
+
+ GBP
+ 0.00
+
+
+ GBP
+ 15.02
+
+ 1
+ 9:00 A.M.
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 2.0
+
+
+
+
+
+
+
+
+
+ VAT
+ 14.97
+
+
+
+ GBP
+ 74.83
+
+
+ GBP
+ 89.80
+
+
+
+
+
diff --git a/app/code/Magento/Ups/Test/Unit/Model/_files/ups_rates_response_option8.xml b/app/code/Magento/Ups/Test/Unit/Model/_files/ups_rates_response_option8.xml
new file mode 100644
index 0000000000000..b5711f9f12bfa
--- /dev/null
+++ b/app/code/Magento/Ups/Test/Unit/Model/_files/ups_rates_response_option8.xml
@@ -0,0 +1,269 @@
+
+
+
+
+
+ Rating and Service
+ 1.0
+
+ 1
+ Success
+
+
+
+ 03
+ Additional duties/taxes may apply and are not reflected in the total amount
+ due.
+
+
+
+ 07
+
+ Your invoice may vary from the displayed reference
+ rates
+
+
+
+ KGS
+
+ 2.0
+
+
+ GBP
+ 35.16
+
+
+ GBP
+ 0.00
+
+
+ GBP
+ 35.16
+
+ 1
+ 10:30 A.M.
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 2.0
+
+
+
+
+
+
+
+
+
+
+ GBP
+ 44.37
+
+
+
+
+
+
+ 03
+ Additional duties/taxes may apply and are not reflected in the total amount
+ due.
+
+
+
+ 08
+
+ Your invoice may vary from the displayed reference
+ rates
+
+
+
+ KGS
+
+ 2.0
+
+
+ GBP
+ 34.15
+
+
+ GBP
+ 0.00
+
+
+ GBP
+ 34.15
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 2.0
+
+
+
+
+
+
+
+
+
+
+ GBP
+ 60.57
+
+
+
+
+
+
+ 03
+ Additional duties/taxes may apply and are not reflected in the total amount
+ due.
+
+
+
+ 65
+
+ Your invoice may vary from the displayed reference
+ rates
+
+
+
+ KGS
+
+ 2.0
+
+
+ GBP
+ 29.59
+
+
+ GBP
+ 0.00
+
+
+ GBP
+ 29.59
+
+ 1
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 2.0
+
+
+
+
+
+
+
+
+
+
+ GBP
+ 41.61
+
+
+
+
+
+
+ 03
+ Additional duties/taxes may apply and are not reflected in the total amount
+ due.
+
+
+
+ 54
+
+ Your invoice may vary from the displayed reference
+ rates
+
+
+
+ KGS
+
+ 2.0
+
+
+ GBP
+ 45.18
+
+
+ GBP
+ 0.00
+
+
+ GBP
+ 45.18
+
+ 1
+ 8:30 A.M.
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 2.0
+
+
+
+
+
+
+
+
+
+
+ GBP
+ 157.47
+
+
+
+
+
diff --git a/app/code/Magento/Ups/etc/adminhtml/system.xml b/app/code/Magento/Ups/etc/adminhtml/system.xml
index 255039e6499cc..07bfaeea6337a 100644
--- a/app/code/Magento/Ups/etc/adminhtml/system.xml
+++ b/app/code/Magento/Ups/etc/adminhtml/system.xml
@@ -118,6 +118,11 @@
Magento\Config\Model\Config\Source\Yesno
+
+
+ Magento\Config\Model\Config\Source\Yesno
+ When applicable, taxes (sales tax, VAT etc.) are included in the rate
+
Required for negotiated rates; 6-character UPS
diff --git a/app/code/Magento/Ups/etc/config.xml b/app/code/Magento/Ups/etc/config.xml
index 7dd47b6bf673b..0f92ae4dad195 100644
--- a/app/code/Magento/Ups/etc/config.xml
+++ b/app/code/Magento/Ups/etc/config.xml
@@ -35,6 +35,7 @@
F
O
0
+ 0
1
UPS
0
diff --git a/app/code/Magento/Ups/i18n/en_US.csv b/app/code/Magento/Ups/i18n/en_US.csv
index 0412a993b00ef..baf8ecc855440 100644
--- a/app/code/Magento/Ups/i18n/en_US.csv
+++ b/app/code/Magento/Ups/i18n/en_US.csv
@@ -103,6 +103,8 @@ Title,Title
"Weight Unit","Weight Unit"
"User ID","User ID"
"Enable Negotiated Rates","Enable Negotiated Rates"
+"Request Tax-Inclusive Rate","Request Tax-Inclusive Rate"
+"When applicable, taxes (sales tax, VAT etc.) are included in the rate","When applicable, taxes (sales tax, VAT etc.) are included in the rate"
"Shipper Number","Shipper Number"
"Required for negotiated rates; 6-character UPS","Required for negotiated rates; 6-character UPS"
"Ship to Applicable Countries","Ship to Applicable Countries"
diff --git a/app/code/Magento/Ups/view/adminhtml/templates/system/shipping/carrier_config.phtml b/app/code/Magento/Ups/view/adminhtml/templates/system/shipping/carrier_config.phtml
index 388727f1e0d65..411bec20cde57 100644
--- a/app/code/Magento/Ups/view/adminhtml/templates/system/shipping/carrier_config.phtml
+++ b/app/code/Magento/Ups/view/adminhtml/templates/system/shipping/carrier_config.phtml
@@ -81,7 +81,7 @@ require(["prototype"], function(){
this.onlyUpsXmlElements = ['carriers_ups_gateway_xml_url','carriers_ups_tracking_xml_url',
'carriers_ups_username','carriers_ups_password','carriers_ups_access_license_number',
'carriers_ups_origin_shipment','carriers_ups_negotiated_active','carriers_ups_shipper_number',
- 'carriers_ups_mode_xml'];
+ 'carriers_ups_mode_xml','carriers_ups_include_taxes'];
this.onlyUpsElements = ['carriers_ups_gateway_url'];
this.storedOriginShipment = '= /* @noEscape */ $storedOriginShipment ?>';
diff --git a/app/code/Magento/UrlRewrite/Controller/Router.php b/app/code/Magento/UrlRewrite/Controller/Router.php
index 66ba3d9bbabe1..73002c10cf1b6 100644
--- a/app/code/Magento/UrlRewrite/Controller/Router.php
+++ b/app/code/Magento/UrlRewrite/Controller/Router.php
@@ -5,10 +5,16 @@
*/
namespace Magento\UrlRewrite\Controller;
+use Magento\Framework\App\RequestInterface;
use Magento\UrlRewrite\Controller\Adminhtml\Url\Rewrite;
use Magento\UrlRewrite\Model\OptionProvider;
use Magento\UrlRewrite\Model\UrlFinderInterface;
use Magento\UrlRewrite\Service\V1\Data\UrlRewrite;
+use Magento\Framework\App\Request\Http as HttpRequest;
+use Magento\Framework\App\Response\Http as HttpResponse;
+use Magento\Framework\UrlInterface;
+use Magento\Framework\App\Action\Redirect;
+use Magento\Framework\App\ActionInterface;
/**
* UrlRewrite Controller Router
@@ -23,7 +29,7 @@ class Router implements \Magento\Framework\App\RouterInterface
protected $actionFactory;
/**
- * @var \Magento\Framework\UrlInterface
+ * @var UrlInterface
*/
protected $url;
@@ -33,7 +39,7 @@ class Router implements \Magento\Framework\App\RouterInterface
protected $storeManager;
/**
- * @var \Magento\Framework\App\ResponseInterface
+ * @var HttpResponse
*/
protected $response;
@@ -44,14 +50,14 @@ class Router implements \Magento\Framework\App\RouterInterface
/**
* @param \Magento\Framework\App\ActionFactory $actionFactory
- * @param \Magento\Framework\UrlInterface $url
+ * @param UrlInterface $url
* @param \Magento\Store\Model\StoreManagerInterface $storeManager
* @param \Magento\Framework\App\ResponseInterface $response
* @param UrlFinderInterface $urlFinder
*/
public function __construct(
\Magento\Framework\App\ActionFactory $actionFactory,
- \Magento\Framework\UrlInterface $url,
+ UrlInterface $url,
\Magento\Store\Model\StoreManagerInterface $storeManager,
\Magento\Framework\App\ResponseInterface $response,
UrlFinderInterface $urlFinder
@@ -64,48 +70,83 @@ public function __construct(
}
/**
- * Match corresponding URL Rewrite and modify request
+ * Match corresponding URL Rewrite and modify request.
*
- * @param \Magento\Framework\App\RequestInterface $request
- * @return \Magento\Framework\App\ActionInterface|null
+ * @param RequestInterface|HttpRequest $request
+ *
+ * @return ActionInterface|null
*/
- public function match(\Magento\Framework\App\RequestInterface $request)
+ public function match(RequestInterface $request)
{
if ($fromStore = $request->getParam('___from_store')) {
+ //If we're in the process of switching stores then matching rewrite
+ //rule from previous store because the URL was not changed yet from
+ //old store's format.
$oldStoreId = $this->storeManager->getStore($fromStore)->getId();
- $oldRewrite = $this->getRewrite($request->getPathInfo(), $oldStoreId);
- if ($oldRewrite) {
- $rewrite = $this->urlFinder->findOneByData(
+ $oldRewrite = $this->getRewrite(
+ $request->getPathInfo(),
+ $oldStoreId
+ );
+ if ($oldRewrite && $oldRewrite->getRedirectType() === 0) {
+ //If there is a match and it's a correct URL then just
+ //redirecting to current store's URL equivalent,
+ //otherwise just continuing finding a rule within current store.
+ $currentRewrite = $this->urlFinder->findOneByData(
[
UrlRewrite::ENTITY_TYPE => $oldRewrite->getEntityType(),
UrlRewrite::ENTITY_ID => $oldRewrite->getEntityId(),
- UrlRewrite::STORE_ID => $this->storeManager->getStore()->getId(),
- UrlRewrite::IS_AUTOGENERATED => 1,
+ UrlRewrite::STORE_ID =>
+ $this->storeManager->getStore()->getId(),
+ UrlRewrite::REDIRECT_TYPE => 0,
]
);
- if ($rewrite && $rewrite->getRequestPath() !== $oldRewrite->getRequestPath()) {
- return $this->redirect($request, $rewrite->getRequestPath(), OptionProvider::TEMPORARY);
+ if ($currentRewrite
+ && $currentRewrite->getRequestPath()
+ !== $oldRewrite->getRequestPath()
+ ) {
+ return $this->redirect(
+ $request,
+ $this->url->getUrl(
+ '',
+ ['_direct' => $currentRewrite->getRequestPath()]
+ ),
+ OptionProvider::TEMPORARY
+ );
}
}
}
- $rewrite = $this->getRewrite($request->getPathInfo(), $this->storeManager->getStore()->getId());
+
+ $rewrite = $this->getRewrite(
+ $request->getPathInfo(),
+ $this->storeManager->getStore()->getId()
+ );
+
if ($rewrite === null) {
+ //No rewrite rule matching current URl found, continuing with
+ //processing of this URL.
return null;
}
-
if ($rewrite->getRedirectType()) {
+ //Rule requires the request to be redirected to another URL
+ //and cannot be processed further.
return $this->processRedirect($request, $rewrite);
}
-
- $request->setAlias(\Magento\Framework\UrlInterface::REWRITE_REQUEST_PATH_ALIAS, $rewrite->getRequestPath());
+ //Rule provides actual URL that can be processed by a controller.
+ $request->setAlias(
+ UrlInterface::REWRITE_REQUEST_PATH_ALIAS,
+ $rewrite->getRequestPath()
+ );
$request->setPathInfo('/' . $rewrite->getTargetPath());
- return $this->actionFactory->create(\Magento\Framework\App\Action\Forward::class);
+ return $this->actionFactory->create(
+ \Magento\Framework\App\Action\Forward::class
+ );
}
/**
- * @param \Magento\Framework\App\RequestInterface $request
+ * @param RequestInterface $request
* @param UrlRewrite $rewrite
- * @return \Magento\Framework\App\ActionInterface|null
+ *
+ * @return ActionInterface|null
*/
protected function processRedirect($request, $rewrite)
{
@@ -119,16 +160,17 @@ protected function processRedirect($request, $rewrite)
}
/**
- * @param \Magento\Framework\App\RequestInterface $request
+ * @param RequestInterface|HttpRequest $request
* @param string $url
* @param int $code
- * @return \Magento\Framework\App\ActionInterface
+ * @return ActionInterface
*/
protected function redirect($request, $url, $code)
{
$this->response->setRedirect($url, $code);
$request->setDispatched(true);
- return $this->actionFactory->create(\Magento\Framework\App\Action\Redirect::class);
+
+ return $this->actionFactory->create(Redirect::class);
}
/**
diff --git a/app/code/Magento/UrlRewrite/Test/Unit/Controller/RouterTest.php b/app/code/Magento/UrlRewrite/Test/Unit/Controller/RouterTest.php
index acf05242d6aa2..49300448146f2 100644
--- a/app/code/Magento/UrlRewrite/Test/Unit/Controller/RouterTest.php
+++ b/app/code/Magento/UrlRewrite/Test/Unit/Controller/RouterTest.php
@@ -76,51 +76,6 @@ public function testNoRewriteExist()
$this->assertNull($this->router->match($this->request));
}
- public function testRewriteAfterStoreSwitcher()
- {
- $this->request->expects($this->any())->method('getPathInfo')->will($this->returnValue('request-path'));
- $this->request->expects($this->any())->method('getParam')->with('___from_store')
- ->will($this->returnValue('old-store'));
- $oldStore = $this->getMockBuilder(\Magento\Store\Model\Store::class)->disableOriginalConstructor()->getMock();
- $this->storeManager->expects($this->any())->method('getStore')
- ->will($this->returnValueMap([['old-store', $oldStore], [null, $this->store]]));
- $oldStore->expects($this->any())->method('getId')->will($this->returnValue('old-store-id'));
- $this->store->expects($this->any())->method('getId')->will($this->returnValue('current-store-id'));
- $oldUrlRewrite = $this->getMockBuilder(\Magento\UrlRewrite\Service\V1\Data\UrlRewrite::class)
- ->disableOriginalConstructor()->getMock();
- $oldUrlRewrite->expects($this->any())->method('getEntityType')->will($this->returnValue('entity-type'));
- $oldUrlRewrite->expects($this->any())->method('getEntityId')->will($this->returnValue('entity-id'));
- $oldUrlRewrite->expects($this->any())->method('getRequestPath')->will($this->returnValue('old-request-path'));
- $urlRewrite = $this->getMockBuilder(\Magento\UrlRewrite\Service\V1\Data\UrlRewrite::class)
- ->disableOriginalConstructor()->getMock();
- $urlRewrite->expects($this->any())->method('getRequestPath')->will($this->returnValue('new-request-path'));
-
- $this->urlFinder->expects($this->any())->method('findOneByData')->will(
- $this->returnValueMap([
- [
- [UrlRewrite::REQUEST_PATH => 'request-path', UrlRewrite::STORE_ID => 'old-store-id'],
- $oldUrlRewrite,
- ],
- [
- [
- UrlRewrite::ENTITY_TYPE => 'entity-type',
- UrlRewrite::ENTITY_ID => 'entity-id',
- UrlRewrite::STORE_ID => 'current-store-id',
- UrlRewrite::IS_AUTOGENERATED => 1,
- ],
- $urlRewrite
- ],
- ])
- );
- $this->response->expects($this->once())->method('setRedirect')
- ->with('new-request-path', OptionProvider::TEMPORARY);
- $this->request->expects($this->once())->method('setDispatched')->with(true);
- $this->actionFactory->expects($this->once())->method('create')
- ->with(\Magento\Framework\App\Action\Redirect::class);
-
- $this->router->match($this->request);
- }
-
public function testNoRewriteAfterStoreSwitcherWhenNoOldRewrite()
{
$this->request->expects($this->any())->method('getPathInfo')->will($this->returnValue('request-path'));
diff --git a/app/code/Magento/User/view/adminhtml/web/app-config.js b/app/code/Magento/User/view/adminhtml/web/app-config.js
index 0a58d181276ae..6387bec03ea90 100644
--- a/app/code/Magento/User/view/adminhtml/web/app-config.js
+++ b/app/code/Magento/User/view/adminhtml/web/app-config.js
@@ -9,7 +9,6 @@
require.config({
'waitSeconds': 0,
'shim': {
- 'jquery/jquery.hashchange': ['jquery'],
'jquery/jstree/jquery.hotkeys': ['jquery'],
'jquery/hover-intent': ['jquery'],
'mage/adminhtml/backup': ['prototype'],
@@ -28,7 +27,6 @@ require.config({
'jquery/validate': 'jquery/jquery.validate',
'jquery/hover-intent': 'jquery/jquery.hoverIntent',
'jquery/file-uploader': 'jquery/fileUploader/jquery.fileupload-fp',
- 'jquery/jquery.hashchange': 'jquery/jquery.ba-hashchange.min',
'prototype': 'prototype/prototype-amd',
'text': 'requirejs/text',
'domReady': 'requirejs/domReady',
diff --git a/app/code/Magento/Webapi/Controller/Rest.php b/app/code/Magento/Webapi/Controller/Rest.php
index 3c0bf85eb5247..0ef88f9ebf31f 100644
--- a/app/code/Magento/Webapi/Controller/Rest.php
+++ b/app/code/Magento/Webapi/Controller/Rest.php
@@ -14,15 +14,13 @@
use Magento\Framework\Webapi\Request;
use Magento\Framework\Webapi\Rest\Request as RestRequest;
use Magento\Framework\Webapi\Rest\Response as RestResponse;
-use Magento\Framework\Webapi\Rest\Response\FieldsFilter;
use Magento\Framework\Webapi\ServiceInputProcessor;
-use Magento\Framework\Webapi\ServiceOutputProcessor;
use Magento\Store\Model\Store;
use Magento\Store\Model\StoreManagerInterface;
use Magento\Webapi\Controller\Rest\ParamsOverrider;
use Magento\Webapi\Controller\Rest\Router;
use Magento\Webapi\Controller\Rest\Router\Route;
-use Magento\Webapi\Model\Rest\Swagger\Generator;
+use Magento\Webapi\Controller\Rest\RequestProcessorPool;
/**
* Front controller for WebAPI REST area.
@@ -32,7 +30,11 @@
*/
class Rest implements \Magento\Framework\App\FrontControllerInterface
{
- /** Path for accessing REST API schema */
+ /**
+ * Path for accessing REST API schema
+ *
+ * @deprecated 100.3.0
+ */
const SCHEMA_PATH = '/schema';
/**
@@ -94,11 +96,6 @@ class Rest implements \Magento\Framework\App\FrontControllerInterface
*/
protected $areaList;
- /**
- * @var \Magento\Framework\Webapi\Rest\Response\FieldsFilter
- */
- protected $fieldsFilter;
-
/**
* @var \Magento\Framework\Session\Generic
*/
@@ -111,14 +108,9 @@ class Rest implements \Magento\Framework\App\FrontControllerInterface
protected $paramsOverrider;
/**
- * @var \Magento\Framework\Webapi\ServiceOutputProcessor
- */
- protected $serviceOutputProcessor;
-
- /**
- * @var \Magento\Webapi\Model\Rest\Swagger\Generator
+ * @var RequestProcessorPool
*/
- protected $swaggerGenerator;
+ protected $requestProcessorPool;
/**
* @var StoreManagerInterface
@@ -126,16 +118,6 @@ class Rest implements \Magento\Framework\App\FrontControllerInterface
*/
private $storeManager;
- /**
- * @var DeploymentConfig
- */
- private $deploymentConfig;
-
- /**
- * @var Rest\InputParamsResolver
- */
- private $inputParamsResolver;
-
/**
* Initialize dependencies
*
@@ -149,11 +131,9 @@ class Rest implements \Magento\Framework\App\FrontControllerInterface
* @param ErrorProcessor $errorProcessor
* @param PathProcessor $pathProcessor
* @param \Magento\Framework\App\AreaList $areaList
- * @param FieldsFilter $fieldsFilter
* @param ParamsOverrider $paramsOverrider
- * @param ServiceOutputProcessor $serviceOutputProcessor
- * @param Generator $swaggerGenerator ,
* @param StoreManagerInterface $storeManager
+ * @param RequestProcessorPool $requestProcessorPool
*
* TODO: Consider removal of warning suppression
* @SuppressWarnings(PHPMD.ExcessiveParameterList)
@@ -169,11 +149,9 @@ public function __construct(
ErrorProcessor $errorProcessor,
PathProcessor $pathProcessor,
\Magento\Framework\App\AreaList $areaList,
- FieldsFilter $fieldsFilter,
ParamsOverrider $paramsOverrider,
- ServiceOutputProcessor $serviceOutputProcessor,
- Generator $swaggerGenerator,
- StoreManagerInterface $storeManager
+ StoreManagerInterface $storeManager,
+ RequestProcessorPool $requestProcessorPool
) {
$this->_router = $router;
$this->_request = $request;
@@ -185,37 +163,9 @@ public function __construct(
$this->_errorProcessor = $errorProcessor;
$this->_pathProcessor = $pathProcessor;
$this->areaList = $areaList;
- $this->fieldsFilter = $fieldsFilter;
$this->paramsOverrider = $paramsOverrider;
- $this->serviceOutputProcessor = $serviceOutputProcessor;
- $this->swaggerGenerator = $swaggerGenerator;
$this->storeManager = $storeManager;
- }
-
- /**
- * Get deployment config
- *
- * @return DeploymentConfig
- */
- private function getDeploymentConfig()
- {
- if (!$this->deploymentConfig instanceof \Magento\Framework\App\DeploymentConfig) {
- $this->deploymentConfig = \Magento\Framework\App\ObjectManager::getInstance()
- ->get(\Magento\Framework\App\DeploymentConfig::class);
- }
- return $this->deploymentConfig;
- }
-
- /**
- * Set deployment config
- *
- * @param \Magento\Framework\App\DeploymentConfig $deploymentConfig
- * @return void
- * @deprecated 100.1.0
- */
- public function setDeploymentConfig(\Magento\Framework\App\DeploymentConfig $deploymentConfig)
- {
- $this->deploymentConfig = $deploymentConfig;
+ $this->requestProcessorPool = $requestProcessorPool;
}
/**
@@ -234,15 +184,13 @@ public function dispatch(\Magento\Framework\App\RequestInterface $request)
$this->areaList->getArea($this->_appState->getAreaCode())
->load(\Magento\Framework\App\Area::PART_TRANSLATE);
try {
- if ($this->isSchemaRequest()) {
- $this->processSchemaRequest();
- } else {
- $this->processApiRequest();
- }
+ $processor = $this->requestProcessorPool->getProcessor($this->_request);
+ $processor->process($this->_request);
} catch (\Exception $e) {
$maskedException = $this->_errorProcessor->maskException($e);
$this->_response->setException($maskedException);
}
+
return $this->_response;
}
@@ -268,6 +216,7 @@ protected function getCurrentRoute()
if (!$this->_route) {
$this->_route = $this->_router->match($this->_request);
}
+
return $this->_route;
}
@@ -290,60 +239,6 @@ protected function checkPermissions()
}
}
- /**
- * Execute schema request
- *
- * @return void
- */
- protected function processSchemaRequest()
- {
- $requestedServices = $this->_request->getRequestedServices('all');
- $requestedServices = $requestedServices == Request::ALL_SERVICES
- ? $this->swaggerGenerator->getListOfServices()
- : $requestedServices;
- $responseBody = $this->swaggerGenerator->generate(
- $requestedServices,
- $this->_request->getScheme(),
- $this->_request->getHttpHost(false),
- $this->_request->getRequestUri()
- );
- $this->_response->setBody($responseBody)->setHeader('Content-Type', 'application/json');
- }
-
- /**
- * Execute API request
- *
- * @return void
- * @throws AuthorizationException
- * @throws \Magento\Framework\Exception\InputException
- * @throws \Magento\Framework\Webapi\Exception
- */
- protected function processApiRequest()
- {
- $inputParams = $this->getInputParamsResolver()->resolve();
-
- $route = $this->getInputParamsResolver()->getRoute();
- $serviceMethodName = $route->getServiceMethod();
- $serviceClassName = $route->getServiceClass();
-
- $service = $this->_objectManager->get($serviceClassName);
- /** @var \Magento\Framework\Api\AbstractExtensibleObject $outputData */
- $outputData = call_user_func_array([$service, $serviceMethodName], $inputParams);
- $outputData = $this->serviceOutputProcessor->process(
- $outputData,
- $serviceClassName,
- $serviceMethodName
- );
- if ($this->_request->getParam(FieldsFilter::FILTER_PARAMETER) && is_array($outputData)) {
- $outputData = $this->fieldsFilter->filter($outputData);
- }
- $header = $this->getDeploymentConfig()->get(ConfigOptionsListConstants::CONFIG_PATH_X_FRAME_OPT);
- if ($header) {
- $this->_response->setHeader('X-Frame-Options', $header);
- }
- $this->_response->prepareResponse($outputData);
- }
-
/**
* Validate request
*
@@ -365,20 +260,4 @@ protected function validateRequest()
throw new \Magento\Framework\Webapi\Exception(__('Cannot perform GET operation with store code \'all\''));
}
}
-
- /**
- * The getter function to get InputParamsResolver object
- *
- * @return \Magento\Webapi\Controller\Rest\InputParamsResolver
- *
- * @deprecated 100.1.0
- */
- private function getInputParamsResolver()
- {
- if ($this->inputParamsResolver === null) {
- $this->inputParamsResolver = \Magento\Framework\App\ObjectManager::getInstance()
- ->get(\Magento\Webapi\Controller\Rest\InputParamsResolver::class);
- }
- return $this->inputParamsResolver;
- }
}
diff --git a/app/code/Magento/Webapi/Controller/Rest/RequestProcessorInterface.php b/app/code/Magento/Webapi/Controller/Rest/RequestProcessorInterface.php
new file mode 100644
index 0000000000000..f4340c18e2134
--- /dev/null
+++ b/app/code/Magento/Webapi/Controller/Rest/RequestProcessorInterface.php
@@ -0,0 +1,35 @@
+requestProcessors = $requestProcessors;
+ }
+
+ /**
+ * {@inheritdoc}
+ *
+ * @throws \Magento\Framework\Webapi\Exception
+ * return RequestProcessorInterface
+ */
+ public function getProcessor(\Magento\Framework\Webapi\Rest\Request $request)
+ {
+ foreach ($this->requestProcessors as $processor) {
+ if ($processor->canProcess($request)) {
+ return $processor;
+ }
+ }
+
+ throw new \Magento\Framework\Webapi\Exception(
+ __('Specified request cannot be processed.'),
+ 0,
+ \Magento\Framework\Webapi\Exception::HTTP_BAD_REQUEST
+ );
+ }
+}
diff --git a/app/code/Magento/Webapi/Controller/Rest/Router/Route.php b/app/code/Magento/Webapi/Controller/Rest/Router/Route.php
index 6e2fda94237d7..ca5dfe2e2b822 100644
--- a/app/code/Magento/Webapi/Controller/Rest/Router/Route.php
+++ b/app/code/Magento/Webapi/Controller/Rest/Router/Route.php
@@ -241,4 +241,14 @@ public function getParameters()
{
return $this->parameters;
}
+
+ /**
+ * Get route path.
+ *
+ * @return string
+ */
+ public function getRoutePath()
+ {
+ return $this->route;
+ }
}
diff --git a/app/code/Magento/Webapi/Controller/Rest/SchemaRequestProcessor.php b/app/code/Magento/Webapi/Controller/Rest/SchemaRequestProcessor.php
new file mode 100644
index 0000000000000..0f1587c342fa7
--- /dev/null
+++ b/app/code/Magento/Webapi/Controller/Rest/SchemaRequestProcessor.php
@@ -0,0 +1,74 @@
+swaggerGenerator = $swaggerGenerator;
+ $this->response = $response;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function process(\Magento\Framework\Webapi\Rest\Request $request)
+ {
+ $requestedServices = $request->getRequestedServices('all');
+ $requestedServices = $requestedServices == Request::ALL_SERVICES
+ ? $this->swaggerGenerator->getListOfServices()
+ : $requestedServices;
+ $responseBody = $this->swaggerGenerator->generate(
+ $requestedServices,
+ $request->getScheme(),
+ $request->getHttpHost(false),
+ $request->getRequestUri()
+ );
+ $this->response->setBody($responseBody)->setHeader('Content-Type', 'application/json');
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function canProcess(\Magento\Framework\Webapi\Rest\Request $request)
+ {
+ if (strpos(ltrim($request->getPathInfo(), '/'), self::PROCESSOR_PATH) === 0) {
+ return true;
+ }
+ return false;
+ }
+}
diff --git a/app/code/Magento/Webapi/Controller/Rest/SynchronousRequestProcessor.php b/app/code/Magento/Webapi/Controller/Rest/SynchronousRequestProcessor.php
new file mode 100644
index 0000000000000..e2dcbb5a40237
--- /dev/null
+++ b/app/code/Magento/Webapi/Controller/Rest/SynchronousRequestProcessor.php
@@ -0,0 +1,121 @@
+response = $response;
+ $this->inputParamsResolver = $inputParamsResolver;
+ $this->serviceOutputProcessor = $serviceOutputProcessor;
+ $this->fieldsFilter = $fieldsFilter;
+ $this->deploymentConfig = $deploymentConfig;
+ $this->objectManager = $objectManager;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function process(\Magento\Framework\Webapi\Rest\Request $request)
+ {
+ $inputParams = $this->inputParamsResolver->resolve();
+
+ $route = $this->inputParamsResolver->getRoute();
+ $serviceMethodName = $route->getServiceMethod();
+ $serviceClassName = $route->getServiceClass();
+ $service = $this->objectManager->get($serviceClassName);
+
+ /**
+ * @var \Magento\Framework\Api\AbstractExtensibleObject $outputData
+ */
+ $outputData = call_user_func_array([$service, $serviceMethodName], $inputParams);
+ $outputData = $this->serviceOutputProcessor->process(
+ $outputData,
+ $serviceClassName,
+ $serviceMethodName
+ );
+ if ($request->getParam(FieldsFilter::FILTER_PARAMETER) && is_array($outputData)) {
+ $outputData = $this->fieldsFilter->filter($outputData);
+ }
+ $header = $this->deploymentConfig->get(ConfigOptionsListConstants::CONFIG_PATH_X_FRAME_OPT);
+ if ($header) {
+ $this->response->setHeader('X-Frame-Options', $header);
+ }
+ $this->response->prepareResponse($outputData);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function canProcess(\Magento\Framework\Webapi\Rest\Request $request)
+ {
+ if (preg_match(self::PROCESSOR_PATH, ltrim($request->getPathInfo(), '/')) === 0) {
+ return true;
+ }
+ return false;
+ }
+}
diff --git a/app/code/Magento/Webapi/Test/Unit/Controller/RestTest.php b/app/code/Magento/Webapi/Test/Unit/Controller/RestTest.php
index 99274724cc565..cea006bcbf3df 100644
--- a/app/code/Magento/Webapi/Test/Unit/Controller/RestTest.php
+++ b/app/code/Magento/Webapi/Test/Unit/Controller/RestTest.php
@@ -62,16 +62,30 @@ class RestTest extends \PHPUnit\Framework\TestCase
*/
protected $swaggerGeneratorMock;
- /** @var \Magento\Store\Model\StoreManagerInterface | \PHPUnit_Framework_MockObject_MockObject */
+ /**
+ * @var \Magento\Store\Model\StoreManagerInterface | \PHPUnit_Framework_MockObject_MockObject
+ */
private $storeManagerMock;
- /** @var \Magento\Store\Api\Data\StoreInterface | \PHPUnit_Framework_MockObject_MockObject */
+ /**
+ * @var \Magento\Store\Api\Data\StoreInterface | \PHPUnit_Framework_MockObject_MockObject
+ */
private $storeMock;
/**
- * @var \PHPUnit_Framework_MockObject_MockObject
+ * @var \Magento\Webapi\Controller\Rest\SchemaRequestProcessor | \PHPUnit_Framework_MockObject_MockObject
*/
- private $deploymentConfigMock;
+ protected $schemaRequestProcessor;
+
+ /**
+ * @var \Magento\Webapi\Controller\Rest\SynchronousRequestProcessor | \PHPUnit_Framework_MockObject_MockObject
+ */
+ protected $synchronousRequestProcessor;
+
+ /**
+ * @var \Magento\Webapi\Controller\Rest\RequestProcessorPool | \PHPUnit_Framework_MockObject_MockObject
+ */
+ protected $requestProcessorPool;
const SERVICE_METHOD = 'testMethod';
@@ -79,94 +93,87 @@ class RestTest extends \PHPUnit\Framework\TestCase
protected function setUp()
{
- $this->deploymentConfigMock = $this->createMock(\Magento\Framework\App\DeploymentConfig::class);
- $this->_requestMock = $this->getMockBuilder(\Magento\Framework\Webapi\Rest\Request::class)
- ->setMethods(
- [
- 'isSecure',
- 'getRequestData',
- 'getParams',
- 'getParam',
- 'getRequestedServices',
- 'getPathInfo',
- 'getHttpHost',
- 'getMethod',
- ]
- )->disableOriginalConstructor()->getMock();
+ $objectManagerMock = $this->createMock(\Magento\Framework\ObjectManagerInterface::class);
+ $this->_requestMock = $this->getRequestMock();
$this->_requestMock->expects($this->any())->method('getHttpHost')->willReturn('testHostName.com');
- $this->_responseMock = $this->getMockBuilder(\Magento\Framework\Webapi\Rest\Response::class)
- ->setMethods(['sendResponse', 'prepareResponse', 'setHeader'])->disableOriginalConstructor()->getMock();
+ $this->_responseMock = $this->getResponseMock();
$routerMock = $this->getMockBuilder(\Magento\Webapi\Controller\Rest\Router::class)->setMethods(['match'])
- ->disableOriginalConstructor()->getMock();
- $this->_routeMock = $this->getMockBuilder(\Magento\Webapi\Controller\Rest\Router\Route::class)
- ->setMethods(['isSecure', 'getServiceMethod', 'getServiceClass', 'getAclResources', 'getParameters'])
- ->disableOriginalConstructor()->getMock();
- $objectManagerMock = $this->createMock(\Magento\Framework\ObjectManagerInterface::class);
+ ->disableOriginalConstructor()->getMock();
+
+ $this->_routeMock = $this->getRouteMock();
$this->_serviceMock = $this->getMockBuilder(self::SERVICE_ID)->setMethods([self::SERVICE_METHOD])
- ->disableOriginalConstructor()->getMock();
+ ->disableOriginalConstructor()->getMock();
+
$this->_oauthServiceMock = $this->getMockBuilder(\Magento\Framework\Oauth\OauthInterface::class)
- ->setMethods(['validateAccessTokenRequest'])->getMockForAbstractClass();
+ ->setMethods(['validateAccessTokenRequest'])->getMockForAbstractClass();
$this->_authorizationMock = $this->getMockBuilder(\Magento\Framework\Webapi\Authorization::class)
- ->disableOriginalConstructor()->getMock();
+ ->disableOriginalConstructor()->getMock();
+
$paramsOverriderMock = $this->getMockBuilder(\Magento\Webapi\Controller\Rest\ParamsOverrider::class)
- ->setMethods(['overrideParams'])
- ->disableOriginalConstructor()->getMock();
+ ->setMethods(['overrideParams'])
+ ->disableOriginalConstructor()->getMock();
+
$dataObjectProcessorMock = $this->getMockBuilder(\Magento\Framework\Reflection\DataObjectProcessor::class)
- ->disableOriginalConstructor()->setMethods(['getMethodReturnType'])->getMockForAbstractClass();
- $this->swaggerGeneratorMock = $this->getMockBuilder(\Magento\Webapi\Model\Rest\Swagger\Generator::class)
- ->disableOriginalConstructor()
- ->setMethods(['generate', 'getListOfServices'])
- ->getMockForAbstractClass();
+ ->disableOriginalConstructor()
+ ->setMethods(['getMethodReturnType'])
+ ->getMockForAbstractClass();
$layoutMock = $this->getMockBuilder(\Magento\Framework\View\LayoutInterface::class)
- ->disableOriginalConstructor()->getMock();
+ ->disableOriginalConstructor()->getMock();
+
$errorProcessorMock = $this->createMock(\Magento\Framework\Webapi\ErrorProcessor::class);
$errorProcessorMock->expects($this->any())->method('maskException')->will($this->returnArgument(0));
+
$objectManager = new \Magento\Framework\TestFramework\Unit\Helper\ObjectManager($this);
+
$this->serviceInputProcessorMock = $this->getMockBuilder(\Magento\Framework\Webapi\ServiceInputProcessor::class)
- ->disableOriginalConstructor()->setMethods(['process'])->getMock();
+ ->disableOriginalConstructor()->setMethods(['process'])->getMock();
+
$areaListMock = $this->createMock(\Magento\Framework\App\AreaList::class);
$areaMock = $this->createMock(\Magento\Framework\App\AreaInterface::class);
$areaListMock->expects($this->any())->method('getArea')->will($this->returnValue($areaMock));
$this->storeMock = $this->createMock(\Magento\Store\Api\Data\StoreInterface::class);
$this->storeManagerMock = $this->createMock(\Magento\Store\Model\StoreManagerInterface::class);
$this->storeManagerMock->expects($this->any())->method('getStore')->willReturn($this->storeMock);
+ $this->requestProcessorPool = $this->getRequestProccessotPoolMock();
- /** Init SUT. */
$this->_restController =
$objectManager->getObject(
\Magento\Webapi\Controller\Rest::class,
[
- 'request' => $this->_requestMock,
- 'response' => $this->_responseMock,
- 'router' => $routerMock,
- 'objectManager' => $objectManagerMock,
- 'layout' => $layoutMock,
- 'oauthService' => $this->_oauthServiceMock,
- 'authorization' => $this->_authorizationMock,
+ 'request' => $this->_requestMock,
+ 'response' => $this->_responseMock,
+ 'router' => $routerMock,
+ 'objectManager' => $objectManagerMock,
+ 'layout' => $layoutMock,
+ 'oauthService' => $this->_oauthServiceMock,
+ 'authorization' => $this->_authorizationMock,
'serviceInputProcessor' => $this->serviceInputProcessorMock,
- 'errorProcessor' => $errorProcessorMock,
- 'areaList' => $areaListMock,
- 'paramsOverrider' => $paramsOverriderMock,
- 'dataObjectProcessor' => $dataObjectProcessorMock,
- 'swaggerGenerator' => $this->swaggerGeneratorMock,
- 'storeManager' => $this->storeManagerMock
+ 'errorProcessor' => $errorProcessorMock,
+ 'areaList' => $areaListMock,
+ 'paramsOverrider' => $paramsOverriderMock,
+ 'dataObjectProcessor' => $dataObjectProcessorMock,
+ 'storeManager' => $this->storeManagerMock,
+ 'requestProcessorPool' => $this->requestProcessorPool,
]
);
- $this->_restController->setDeploymentConfig($this->deploymentConfigMock);
- // Set default expectations used by all tests
$this->_routeMock->expects($this->any())->method('getServiceClass')->will($this->returnValue(self::SERVICE_ID));
$this->_routeMock->expects($this->any())->method('getServiceMethod')
- ->will($this->returnValue(self::SERVICE_METHOD));
+ ->will($this->returnValue(self::SERVICE_METHOD));
+
$routerMock->expects($this->any())->method('match')->will($this->returnValue($this->_routeMock));
+
$objectManagerMock->expects($this->any())->method('get')->will($this->returnValue($this->_serviceMock));
$this->_responseMock->expects($this->any())->method('prepareResponse')->will($this->returnValue([]));
$this->_serviceMock->expects($this->any())->method(self::SERVICE_METHOD)->will($this->returnValue(null));
+
$dataObjectProcessorMock->expects($this->any())->method('getMethodReturnType')
- ->with(self::SERVICE_ID, self::SERVICE_METHOD)
- ->will($this->returnValue('null'));
+ ->with(self::SERVICE_ID, self::SERVICE_METHOD)
+ ->will($this->returnValue('null'));
+
$paramsOverriderMock->expects($this->any())->method('overrideParams')->will($this->returnValue([]));
+
parent::setUp();
}
@@ -176,17 +183,18 @@ public function testDispatchSchemaRequest()
\Magento\Framework\Webapi\Request::REQUEST_PARAM_SERVICES => 'foo',
];
$this->_requestMock->expects($this->any())
- ->method('getPathInfo')
- ->willReturn(\Magento\Webapi\Controller\Rest::SCHEMA_PATH);
+ ->method('getPathInfo')
+ ->willReturn(\Magento\Webapi\Controller\Rest\SchemaRequestProcessor::PROCESSOR_PATH);
+
$this->_requestMock->expects($this->any())
- ->method('getParams')
- ->will($this->returnValue($params));
+ ->method('getParams')
+ ->will($this->returnValue($params));
+
$schema = 'Some REST schema content';
$this->swaggerGeneratorMock->expects($this->any())->method('generate')->willReturn($schema);
+ $this->requestProcessorPool->getProcessor($this->_requestMock)->process($this->_requestMock);
- /** @var \Magento\Framework\App\ResponseInterface $response */
- $response = $this->_restController->dispatch($this->_requestMock);
- $this->assertEquals($schema, $response->getBody());
+ $this->assertEquals($schema, $this->_responseMock->getBody());
}
public function testDispatchAllSchemaRequest()
@@ -195,28 +203,114 @@ public function testDispatchAllSchemaRequest()
\Magento\Framework\Webapi\Request::REQUEST_PARAM_SERVICES => 'all',
];
$this->_requestMock->expects($this->any())
- ->method('getPathInfo')
- ->willReturn(\Magento\Webapi\Controller\Rest::SCHEMA_PATH);
+ ->method('getPathInfo')
+ ->willReturn(\Magento\Webapi\Controller\Rest\SchemaRequestProcessor::PROCESSOR_PATH);
$this->_requestMock->expects($this->any())
- ->method('getParam')
- ->will(
- $this->returnValueMap(
- [
- [\Magento\Framework\Webapi\Request::REQUEST_PARAM_SERVICES, null, 'all']
- ]
- )
- );
+ ->method('getParam')
+ ->will(
+ $this->returnValueMap([
+ [
+ \Magento\Framework\Webapi\Request::REQUEST_PARAM_SERVICES,
+ null,
+ 'all',
+ ],
+ ])
+ );
$this->_requestMock->expects($this->any())
- ->method('getParams')
- ->will($this->returnValue($params));
+ ->method('getParams')
+ ->will($this->returnValue($params));
$this->_requestMock->expects($this->any())
- ->method('getRequestedServices')
- ->will($this->returnValue('all'));
+ ->method('getRequestedServices')
+ ->will($this->returnValue('all'));
+
$schema = 'Some REST schema content';
$this->swaggerGeneratorMock->expects($this->any())->method('generate')->willReturn($schema);
- $this->swaggerGeneratorMock->expects($this->once())->method('getListOfServices')
- ->willReturn(['listOfServices']);
- $this->_restController->dispatch($this->_requestMock);
+ $this->requestProcessorPool->getProcessor($this->_requestMock)->process($this->_requestMock);
+
$this->assertEquals($schema, $this->_responseMock->getBody());
}
+
+ /**
+ * @return object|\Magento\Webapi\Controller\Rest\RequestProcessorPool
+ */
+ private function getRequestProccessotPoolMock()
+ {
+ $objectManager = new \Magento\Framework\TestFramework\Unit\Helper\ObjectManager($this);
+
+ $this->swaggerGeneratorMock = $this->getMockBuilder(\Magento\Webapi\Model\Rest\Swagger\Generator::class)
+ ->disableOriginalConstructor()
+ ->setMethods(['generate', 'getListOfServices'])
+ ->getMockForAbstractClass();
+
+ $this->schemaRequestProcessor = $objectManager->getObject(
+ \Magento\Webapi\Controller\Rest\SchemaRequestProcessor::class,
+ [
+ 'swaggerGenerator' => $this->swaggerGeneratorMock,
+ 'response' => $this->_responseMock,
+ ]
+ );
+
+ $this->synchronousRequestProcessor =
+ $this->getMockBuilder(\Magento\Webapi\Controller\Rest\SynchronousRequestProcessor::class)
+ ->setMethods(['process'])
+ ->disableOriginalConstructor()
+ ->getMock();
+
+ return $objectManager->getObject(
+ \Magento\Webapi\Controller\Rest\RequestProcessorPool::class,
+ [
+ 'requestProcessors' => [
+ 'syncSchema' => $this->schemaRequestProcessor,
+ 'sync' => $this->synchronousRequestProcessor,
+ ],
+ ]
+ );
+ }
+
+ /**
+ * @return \Magento\Webapi\Controller\Rest\Router\Route | \PHPUnit_Framework_MockObject_MockObject
+ */
+ private function getRouteMock()
+ {
+ return $this->getMockBuilder(\Magento\Webapi\Controller\Rest\Router\Route::class)
+ ->setMethods([
+ 'isSecure',
+ 'getServiceMethod',
+ 'getServiceClass',
+ 'getAclResources',
+ 'getParameters',
+ ])
+ ->disableOriginalConstructor()->getMock();
+ }
+
+ /**
+ * @return \Magento\Framework\Webapi\Rest\Request|\PHPUnit_Framework_MockObject_MockObject
+ */
+ private function getRequestMock()
+ {
+ return $this->getMockBuilder(\Magento\Framework\Webapi\Rest\Request::class)
+ ->setMethods(
+ [
+ 'isSecure',
+ 'getRequestData',
+ 'getParams',
+ 'getParam',
+ 'getRequestedServices',
+ 'getPathInfo',
+ 'getHttpHost',
+ 'getMethod',
+ ]
+ )->disableOriginalConstructor()->getMock();
+ }
+
+ /**
+ * @return \Magento\Framework\Webapi\Rest\Response|\PHPUnit_Framework_MockObject_MockObject
+ */
+ private function getResponseMock()
+ {
+ return $this->getMockBuilder(\Magento\Framework\Webapi\Rest\Response::class)
+ ->setMethods(['sendResponse', 'prepareResponse', 'setHeader'])
+ ->disableOriginalConstructor()
+ ->getMock();
+ }
}
diff --git a/app/code/Magento/Webapi/etc/webapi_rest/di.xml b/app/code/Magento/Webapi/etc/webapi_rest/di.xml
index fa8252aca9095..f958d0d821a4b 100644
--- a/app/code/Magento/Webapi/etc/webapi_rest/di.xml
+++ b/app/code/Magento/Webapi/etc/webapi_rest/di.xml
@@ -69,4 +69,15 @@
+
+
+
+
+
+
+ - Magento\Webapi\Controller\Rest\SchemaRequestProcessor
+ - Magento\Webapi\Controller\Rest\SynchronousRequestProcessor
+
+
+
diff --git a/app/design/adminhtml/Magento/backend/web/css/source/_components.less b/app/design/adminhtml/Magento/backend/web/css/source/_components.less
index 3f9f0ed00c5ed..5eb044426b86b 100644
--- a/app/design/adminhtml/Magento/backend/web/css/source/_components.less
+++ b/app/design/adminhtml/Magento/backend/web/css/source/_components.less
@@ -22,3 +22,4 @@
@import 'components/_file-uploader.less';
@import 'components/_image-uploader.less';
@import 'components/_slider.less';
+@import 'components/_url_input.less';
\ No newline at end of file
diff --git a/app/design/adminhtml/Magento/backend/web/css/source/components/_url_input.less b/app/design/adminhtml/Magento/backend/web/css/source/components/_url_input.less
new file mode 100644
index 0000000000000..26d963b020107
--- /dev/null
+++ b/app/design/adminhtml/Magento/backend/web/css/source/components/_url_input.less
@@ -0,0 +1,32 @@
+// /**
+// * Copyright © Magento, Inc. All rights reserved.
+// * See COPYING.txt for license details.
+// */
+
+//
+// Components -> Url Input
+// _____________________________________________
+.url-input-container {
+
+ .url-input-select {
+ float: left;
+ max-width: 7.5em;
+ min-width: 7.5em;
+ }
+
+
+ .url-input-element-linked-element {
+ float: left;
+ margin-left: 1.5em;
+ width: calc(~'100% - 9em');
+ }
+
+ .url-input-setting {
+ clear: both;
+ display: block;
+ &:before {
+ content: "";
+ clear: both;
+ }
+ }
+}
diff --git a/app/design/adminhtml/Magento/backend/web/css/source/forms/_fields.less b/app/design/adminhtml/Magento/backend/web/css/source/forms/_fields.less
index e29efd13b1688..59675de698787 100644
--- a/app/design/adminhtml/Magento/backend/web/css/source/forms/_fields.less
+++ b/app/design/adminhtml/Magento/backend/web/css/source/forms/_fields.less
@@ -279,7 +279,7 @@
// Hide group legend and show first field label instead
legend {
&.admin__field-label {
- opacity: 0;
+ opacity: 1;
}
}
diff --git a/app/design/frontend/Magento/blank/etc/view.xml b/app/design/frontend/Magento/blank/etc/view.xml
index 8264e3111de88..78fb54c0b54e4 100644
--- a/app/design/frontend/Magento/blank/etc/view.xml
+++ b/app/design/frontend/Magento/blank/etc/view.xml
@@ -260,7 +260,6 @@
- Lib::jquery/jquery.min.js
- Lib::jquery/jquery-ui-1.9.2.js
- - Lib::jquery/jquery.ba-hashchange.min.js
- Lib::jquery/jquery.details.js
- Lib::jquery/jquery.details.min.js
- Lib::jquery/jquery.hoverIntent.js
diff --git a/app/design/frontend/Magento/luma/etc/view.xml b/app/design/frontend/Magento/luma/etc/view.xml
index 349224a34022c..08e6883da995e 100644
--- a/app/design/frontend/Magento/luma/etc/view.xml
+++ b/app/design/frontend/Magento/luma/etc/view.xml
@@ -270,7 +270,6 @@
- Lib::jquery/jquery.min.js
- Lib::jquery/jquery-ui-1.9.2.js
- - Lib::jquery/jquery.ba-hashchange.min.js
- Lib::jquery/jquery.details.js
- Lib::jquery/jquery.details.min.js
- Lib::jquery/jquery.hoverIntent.js
diff --git a/app/design/frontend/Magento/rush/etc/view.xml b/app/design/frontend/Magento/rush/etc/view.xml
index 1f8b416e1af79..cb963250c5e6e 100644
--- a/app/design/frontend/Magento/rush/etc/view.xml
+++ b/app/design/frontend/Magento/rush/etc/view.xml
@@ -261,7 +261,6 @@
- Lib::jquery/jquery.min.js
- Lib::jquery/jquery-ui-1.9.2.js
- - Lib::jquery/jquery.ba-hashchange.min.js
- Lib::jquery/jquery.details.js
- Lib::jquery/jquery.details.min.js
- Lib::jquery/jquery.hoverIntent.js
diff --git a/dev/tests/acceptance/tests/_data/magentoStage.jpg b/dev/tests/acceptance/tests/_data/magentoStage.jpg
new file mode 100644
index 0000000000000..87c0f792c7982
Binary files /dev/null and b/dev/tests/acceptance/tests/_data/magentoStage.jpg differ
diff --git a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Catalog/Page/AdminConfigurationStoresPage.xml b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Backend/Page/AdminConfigurationStoresPage.xml
similarity index 76%
rename from dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Catalog/Page/AdminConfigurationStoresPage.xml
rename to dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Backend/Page/AdminConfigurationStoresPage.xml
index bd706a8150bb7..08448464b4c4a 100644
--- a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Catalog/Page/AdminConfigurationStoresPage.xml
+++ b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Backend/Page/AdminConfigurationStoresPage.xml
@@ -11,4 +11,7 @@
+
+
+
diff --git a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Catalog/ActionGroup/RestoreLayoutSettingActionGroup.xml b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Catalog/ActionGroup/RestoreLayoutSettingActionGroup.xml
new file mode 100644
index 0000000000000..b9119a5ab9ff2
--- /dev/null
+++ b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Catalog/ActionGroup/RestoreLayoutSettingActionGroup.xml
@@ -0,0 +1,15 @@
+
+
+
+
+
+
+
+
+
diff --git a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Catalog/Section/AdminCategoryBasicFieldSection.xml b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Catalog/Section/AdminCategoryBasicFieldSection.xml
index e905bfd01c711..9539bda75b01e 100644
--- a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Catalog/Section/AdminCategoryBasicFieldSection.xml
+++ b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Catalog/Section/AdminCategoryBasicFieldSection.xml
@@ -20,6 +20,10 @@
+
diff --git a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Catalog/Section/AdminProductFormSection.xml b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Catalog/Section/AdminProductFormSection.xml
index 2599116bcc469..7483df63b60dd 100644
--- a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Catalog/Section/AdminProductFormSection.xml
+++ b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Catalog/Section/AdminProductFormSection.xml
@@ -28,6 +28,10 @@
+
diff --git a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Catalog/Test/AdminCreateCategoryTest.xml b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Catalog/Test/AdminCreateCategoryTest.xml
index 9db691eafef62..bf867ad3016f0 100644
--- a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Catalog/Test/AdminCreateCategoryTest.xml
+++ b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Catalog/Test/AdminCreateCategoryTest.xml
@@ -37,4 +37,36 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Catalog/Test/AdminCreateSimpleProductTest.xml b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Catalog/Test/AdminCreateSimpleProductTest.xml
index 14e2478e9df14..37a7aa6278307 100644
--- a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Catalog/Test/AdminCreateSimpleProductTest.xml
+++ b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Catalog/Test/AdminCreateSimpleProductTest.xml
@@ -39,4 +39,33 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Cms/ActionGroup/AssertCMSBlockContentActionGroup.xml b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Cms/ActionGroup/AssertCMSBlockContentActionGroup.xml
new file mode 100644
index 0000000000000..c45e0036e719a
--- /dev/null
+++ b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Cms/ActionGroup/AssertCMSBlockContentActionGroup.xml
@@ -0,0 +1,24 @@
+
+
+
+
+
+
+ {{_defaultBlock.title}}
+ grabTextFromTitle
+
+
+
+
+
+ {{_defaultBlock.content}}
+ grabTextFromContent
+
+
+
diff --git a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Cms/ActionGroup/AssertCMSPageContentActionGroup.xml b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Cms/ActionGroup/AssertCMSPageContentActionGroup.xml
new file mode 100644
index 0000000000000..10a51aadd09b5
--- /dev/null
+++ b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Cms/ActionGroup/AssertCMSPageContentActionGroup.xml
@@ -0,0 +1,26 @@
+
+
+
+
+
+
+ {{_duplicatedCMSPage.title}}
+ grabTextFromTitle
+
+
+
+
+ {{_duplicatedCMSPage.content}}
+ grabTextFromContent
+
+
+
+
+
+
diff --git a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Cms/ActionGroup/AssignBlockToCMSPageActionGroup.xml b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Cms/ActionGroup/AssignBlockToCMSPageActionGroup.xml
index 5c787549ab9d0..d5efbe4b258ea 100644
--- a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Cms/ActionGroup/AssignBlockToCMSPageActionGroup.xml
+++ b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Cms/ActionGroup/AssignBlockToCMSPageActionGroup.xml
@@ -14,7 +14,7 @@
-
+
@@ -45,6 +45,8 @@
+
+
diff --git a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Cms/ActionGroup/CMSActionGroup.xml b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Cms/ActionGroup/CMSActionGroup.xml
index 40d0833e34b67..0639837a50f13 100644
--- a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Cms/ActionGroup/CMSActionGroup.xml
+++ b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Cms/ActionGroup/CMSActionGroup.xml
@@ -13,7 +13,7 @@
-
+
@@ -32,7 +32,7 @@
-
+
diff --git a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Cms/ActionGroup/DeleteImageFromStorageActionGroup.xml b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Cms/ActionGroup/DeleteImageFromStorageActionGroup.xml
new file mode 100644
index 0000000000000..c4af2bc850635
--- /dev/null
+++ b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Cms/ActionGroup/DeleteImageFromStorageActionGroup.xml
@@ -0,0 +1,22 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Cms/ActionGroup/FillOutBlockContentActionGroup.xml b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Cms/ActionGroup/FillOutBlockContentActionGroup.xml
new file mode 100644
index 0000000000000..c593103f95676
--- /dev/null
+++ b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Cms/ActionGroup/FillOutBlockContentActionGroup.xml
@@ -0,0 +1,16 @@
+
+
+
+
+
+
+
+
+
+
diff --git a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Cms/ActionGroup/FillOutCMSPageContentActionGroup.xml b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Cms/ActionGroup/FillOutCMSPageContentActionGroup.xml
new file mode 100644
index 0000000000000..bbda1f49f0187
--- /dev/null
+++ b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Cms/ActionGroup/FillOutCMSPageContentActionGroup.xml
@@ -0,0 +1,17 @@
+
+
+
+
+
+
+
+
+
+
+
diff --git a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Cms/ActionGroup/NavigateToMediaFolderActionGroup.xml b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Cms/ActionGroup/NavigateToMediaFolderActionGroup.xml
new file mode 100644
index 0000000000000..c886ab306cf92
--- /dev/null
+++ b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Cms/ActionGroup/NavigateToMediaFolderActionGroup.xml
@@ -0,0 +1,19 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Cms/ActionGroup/RestoreLayoutSettingActionGroup.xml b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Cms/ActionGroup/RestoreLayoutSettingActionGroup.xml
new file mode 100644
index 0000000000000..2e2acb8ac316f
--- /dev/null
+++ b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Cms/ActionGroup/RestoreLayoutSettingActionGroup.xml
@@ -0,0 +1,15 @@
+
+
+
+
+
+
+
+
+
diff --git a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Cms/Data/CmsPageData.xml b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Cms/Data/CmsPageData.xml
index 49a96bdc27ed2..324d937df95b6 100644
--- a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Cms/Data/CmsPageData.xml
+++ b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Cms/Data/CmsPageData.xml
@@ -14,6 +14,12 @@
Sample page content. Yada yada yada.
test-page-
+
+ testpage
+ Test Content Heading
+ Sample page content. Yada yada yada.
+ testpage-
+
Test CMS Page
Test Content Heading
diff --git a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Cms/Section/BlockNewPageActionsSection.xml b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Cms/Section/BlockNewPageActionsSection.xml
deleted file mode 100644
index b196bee7981c5..0000000000000
--- a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Cms/Section/BlockNewPageActionsSection.xml
+++ /dev/null
@@ -1,15 +0,0 @@
-
-
-
-
-
-
diff --git a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Cms/Section/BlockNewPageBasicFieldsSection.xml b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Cms/Section/BlockNewPageBasicFieldsSection.xml
deleted file mode 100644
index abeec47cf7f30..0000000000000
--- a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Cms/Section/BlockNewPageBasicFieldsSection.xml
+++ /dev/null
@@ -1,16 +0,0 @@
-
-
-
-
-
-
diff --git a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Cms/Section/BlockNewPageContentSection.xml b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Cms/Section/BlockNewPageContentSection.xml
deleted file mode 100644
index 1c42d3817d246..0000000000000
--- a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Cms/Section/BlockNewPageContentSection.xml
+++ /dev/null
@@ -1,14 +0,0 @@
-
-
-
-
-
-
diff --git a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Cms/Section/CmsNewBlockBlockActionsSection.xml b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Cms/Section/CmsNewBlockBlockActionsSection.xml
index 569256d8f918f..9918be3846263 100644
--- a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Cms/Section/CmsNewBlockBlockActionsSection.xml
+++ b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Cms/Section/CmsNewBlockBlockActionsSection.xml
@@ -9,6 +9,19 @@
+
+
+
diff --git a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Cms/Section/CmsNewBlockBlockBasicFieldsSection.xml b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Cms/Section/CmsNewBlockBlockBasicFieldsSection.xml
index 78d9dad4eedd6..e57abf7f1025e 100644
--- a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Cms/Section/CmsNewBlockBlockBasicFieldsSection.xml
+++ b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Cms/Section/CmsNewBlockBlockBasicFieldsSection.xml
@@ -13,4 +13,11 @@
+
diff --git a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Cms/Section/CmsNewPagePageActionsSection.xml b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Cms/Section/CmsNewPagePageActionsSection.xml
index 68242033d8c18..3ceef6d422782 100644
--- a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Cms/Section/CmsNewPagePageActionsSection.xml
+++ b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Cms/Section/CmsNewPagePageActionsSection.xml
@@ -9,7 +9,18 @@
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Cms/Section/CmsNewPagePageBasicFieldsSection.xml b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Cms/Section/CmsNewPagePageBasicFieldsSection.xml
index dd3328dfcb522..cb2b5f0d9c947 100644
--- a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Cms/Section/CmsNewPagePageBasicFieldsSection.xml
+++ b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Cms/Section/CmsNewPagePageBasicFieldsSection.xml
@@ -10,5 +10,7 @@
xsi:noNamespaceSchemaLocation="../../../../../../vendor/magento/magento2-functional-testing-framework/src/Magento/FunctionalTestingFramework/Page/etc/SectionObject.xsd">
diff --git a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Cms/Section/CmsNewPagePageContentSection.xml b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Cms/Section/CmsNewPagePageContentSection.xml
index 4e794aa412e1b..fefd047de6148 100644
--- a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Cms/Section/CmsNewPagePageContentSection.xml
+++ b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Cms/Section/CmsNewPagePageContentSection.xml
@@ -12,7 +12,6 @@
-
+
diff --git a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Cms/Section/CmsPagesPageActionsSection.xml b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Cms/Section/CmsPagesPageActionsSection.xml
index c302a029792e9..7d4b06ff6d947 100644
--- a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Cms/Section/CmsPagesPageActionsSection.xml
+++ b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Cms/Section/CmsPagesPageActionsSection.xml
@@ -9,16 +9,21 @@
-
+
-
-
-
+
+
+
-
+
+
+
+
+
+
diff --git a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Cms/Test/AdminAddImageToWYSIWYGBlockCest.xml b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Cms/Test/AdminAddImageToWYSIWYGBlockCest.xml
index 00673747c7c99..586be48618437 100644
--- a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Cms/Test/AdminAddImageToWYSIWYGBlockCest.xml
+++ b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Cms/Test/AdminAddImageToWYSIWYGBlockCest.xml
@@ -21,14 +21,18 @@
+
-
-
-
-
+
+
+
+
+
+
+
@@ -39,59 +43,25 @@
-
+
-
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
diff --git a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Cms/Test/AdminAddImageToWYSIWYGCMSCest.xml b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Cms/Test/AdminAddImageToWYSIWYGCMSPageCest.xml
similarity index 83%
rename from dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Cms/Test/AdminAddImageToWYSIWYGCMSCest.xml
rename to dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Cms/Test/AdminAddImageToWYSIWYGCMSPageCest.xml
index b82d1836aa603..626654b462833 100644
--- a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Cms/Test/AdminAddImageToWYSIWYGCMSCest.xml
+++ b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Cms/Test/AdminAddImageToWYSIWYGCMSPageCest.xml
@@ -20,13 +20,14 @@
+
-
-
-
+
+
+
@@ -40,7 +41,6 @@
-
@@ -48,13 +48,16 @@
+
+
-
+
+
diff --git a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Cms/Test/AdminAddVariableToWYSIWYGBlockCest.xml b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Cms/Test/AdminAddVariableToWYSIWYGBlockCest.xml
index 464a708e0f70b..497185362add0 100644
--- a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Cms/Test/AdminAddVariableToWYSIWYGBlockCest.xml
+++ b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Cms/Test/AdminAddVariableToWYSIWYGBlockCest.xml
@@ -20,6 +20,7 @@
+
@@ -34,10 +35,13 @@
-
-
-
-
+
+
+
+
+
+
+
@@ -77,12 +81,13 @@
-
+
+
-
+
-
+
@@ -109,7 +114,9 @@
-
+
+
+
@@ -132,8 +139,9 @@
-
+
+
diff --git a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Cms/Test/AdminAddVariableToWYSIWYGCMSCest.xml b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Cms/Test/AdminAddVariableToWYSIWYGCMSCest.xml
index 33115159e2f71..779703abea839 100644
--- a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Cms/Test/AdminAddVariableToWYSIWYGCMSCest.xml
+++ b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Cms/Test/AdminAddVariableToWYSIWYGCMSCest.xml
@@ -77,6 +77,8 @@
+
+
diff --git a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Cms/Test/AdminAddWidgetToWYSIWYGBlockCest.xml b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Cms/Test/AdminAddWidgetToWYSIWYGBlockCest.xml
index c3c76271597ff..bcb4b9141a903 100644
--- a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Cms/Test/AdminAddWidgetToWYSIWYGBlockCest.xml
+++ b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Cms/Test/AdminAddWidgetToWYSIWYGBlockCest.xml
@@ -43,7 +43,8 @@
-
+
+
@@ -64,6 +65,8 @@
+
+
@@ -73,7 +76,7 @@
-
+
diff --git a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Cms/Test/AdminAddWidgetToWYSIWYGWithCMSPageLinkTypeCest.xml b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Cms/Test/AdminAddWidgetToWYSIWYGWithCMSPageLinkTypeCest.xml
index 3317b4143033c..d8ed745dcbb2d 100644
--- a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Cms/Test/AdminAddWidgetToWYSIWYGWithCMSPageLinkTypeCest.xml
+++ b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Cms/Test/AdminAddWidgetToWYSIWYGWithCMSPageLinkTypeCest.xml
@@ -56,6 +56,8 @@
+
+
diff --git a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Cms/Test/AdminAddWidgetToWYSIWYGWithCMSStaticBlockTypeCest.xml b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Cms/Test/AdminAddWidgetToWYSIWYGWithCMSStaticBlockTypeCest.xml
index c0dfe18d7bcf6..fd3e78115a409 100644
--- a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Cms/Test/AdminAddWidgetToWYSIWYGWithCMSStaticBlockTypeCest.xml
+++ b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Cms/Test/AdminAddWidgetToWYSIWYGWithCMSStaticBlockTypeCest.xml
@@ -57,6 +57,8 @@
+
+
diff --git a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Cms/Test/AdminAddWidgetToWYSIWYGWithCatalogCategoryLinkTypeCest.xml b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Cms/Test/AdminAddWidgetToWYSIWYGWithCatalogCategoryLinkTypeCest.xml
index 03b9499a2a962..9788d6836fb7f 100644
--- a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Cms/Test/AdminAddWidgetToWYSIWYGWithCatalogCategoryLinkTypeCest.xml
+++ b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Cms/Test/AdminAddWidgetToWYSIWYGWithCatalogCategoryLinkTypeCest.xml
@@ -53,6 +53,8 @@
+
+
diff --git a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Cms/Test/AdminAddWidgetToWYSIWYGWithCatalogProductLinkTypeCest.xml b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Cms/Test/AdminAddWidgetToWYSIWYGWithCatalogProductLinkTypeCest.xml
index 622d29ebb196c..0ad3533bfc658 100644
--- a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Cms/Test/AdminAddWidgetToWYSIWYGWithCatalogProductLinkTypeCest.xml
+++ b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Cms/Test/AdminAddWidgetToWYSIWYGWithCatalogProductLinkTypeCest.xml
@@ -60,6 +60,8 @@
+
+
diff --git a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Cms/Test/AdminAddWidgetToWYSIWYGWithCatalogProductListTypeCest.xml b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Cms/Test/AdminAddWidgetToWYSIWYGWithCatalogProductListTypeCest.xml
index 52dccc139c48f..2a23d7420f82b 100644
--- a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Cms/Test/AdminAddWidgetToWYSIWYGWithCatalogProductListTypeCest.xml
+++ b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Cms/Test/AdminAddWidgetToWYSIWYGWithCatalogProductListTypeCest.xml
@@ -64,6 +64,8 @@
+
+
diff --git a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Cms/Test/AdminAddWidgetToWYSIWYGWithRecentlyComparedProductsTypeCest.xml b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Cms/Test/AdminAddWidgetToWYSIWYGWithRecentlyComparedProductsTypeCest.xml
index 367d166fe502e..0531320cddee2 100644
--- a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Cms/Test/AdminAddWidgetToWYSIWYGWithRecentlyComparedProductsTypeCest.xml
+++ b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Cms/Test/AdminAddWidgetToWYSIWYGWithRecentlyComparedProductsTypeCest.xml
@@ -58,6 +58,8 @@
+
+
diff --git a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Cms/Test/AdminAddWidgetToWYSIWYGWithRecentlyViewedProductsTypeCest.xml b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Cms/Test/AdminAddWidgetToWYSIWYGWithRecentlyViewedProductsTypeCest.xml
index 143033c98e9f6..4e3ddb5ee4786 100644
--- a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Cms/Test/AdminAddWidgetToWYSIWYGWithRecentlyViewedProductsTypeCest.xml
+++ b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Cms/Test/AdminAddWidgetToWYSIWYGWithRecentlyViewedProductsTypeCest.xml
@@ -56,6 +56,8 @@
+
+
diff --git a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Cms/Test/AdminCreateCmsBlockTest.xml b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Cms/Test/AdminCreateCmsBlockTest.xml
new file mode 100644
index 0000000000000..77965cfedfd4d
--- /dev/null
+++ b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Cms/Test/AdminCreateCmsBlockTest.xml
@@ -0,0 +1,49 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Cms/Test/AdminCreateCmsPageTest.xml b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Cms/Test/AdminCreateCmsPageTest.xml
index f8b3c3733a827..3bdd57ef2b9c8 100644
--- a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Cms/Test/AdminCreateCmsPageTest.xml
+++ b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Cms/Test/AdminCreateCmsPageTest.xml
@@ -27,7 +27,7 @@
-
+
@@ -35,7 +35,9 @@
-
+
+
+
@@ -43,4 +45,75 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Cms/Test/AdminSwitchWYSIWYGOptionsCest.xml b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Cms/Test/AdminSwitchWYSIWYGOptionsCest.xml
index 56edb80d7f759..23ad8faccce58 100644
--- a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Cms/Test/AdminSwitchWYSIWYGOptionsCest.xml
+++ b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Cms/Test/AdminSwitchWYSIWYGOptionsCest.xml
@@ -16,7 +16,11 @@
+
+
+
+
@@ -41,6 +45,8 @@
+
+
@@ -66,6 +72,8 @@
+
+
diff --git a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Cms/Test/VerifyTinyMCEv4IsNativeWYSIWYGOnBlockCest.xml b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Cms/Test/VerifyTinyMCEv4IsNativeWYSIWYGOnBlockCest.xml
index adcc522cbf8ba..0e220bbb4a13f 100644
--- a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Cms/Test/VerifyTinyMCEv4IsNativeWYSIWYGOnBlockCest.xml
+++ b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Cms/Test/VerifyTinyMCEv4IsNativeWYSIWYGOnBlockCest.xml
@@ -38,12 +38,13 @@
-
+
+
-
+
-
+
@@ -75,6 +76,8 @@
+
+
@@ -84,7 +87,7 @@
-
+
diff --git a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Cms/Test/VerifyTinyMCEv4IsNativeWYSIWYGOnCMSPageCest.xml b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Cms/Test/VerifyTinyMCEv4IsNativeWYSIWYGOnCMSPageCest.xml
index 7978faec189db..b6b58537dc380 100644
--- a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Cms/Test/VerifyTinyMCEv4IsNativeWYSIWYGOnCMSPageCest.xml
+++ b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Cms/Test/VerifyTinyMCEv4IsNativeWYSIWYGOnCMSPageCest.xml
@@ -25,7 +25,7 @@
-
+
@@ -40,6 +40,8 @@
+
+
diff --git a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Config/ActionGroup/GeneralConfigurationActionGroup.xml b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Config/ActionGroup/GeneralConfigurationActionGroup.xml
new file mode 100644
index 0000000000000..9a990e88455f9
--- /dev/null
+++ b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Config/ActionGroup/GeneralConfigurationActionGroup.xml
@@ -0,0 +1,17 @@
+
+
+
+
+
+
+
+
+
+
+
diff --git a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Config/ActionGroup/RestoreLayoutSettingActionGroup.xml b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Config/ActionGroup/RestoreLayoutSettingActionGroup.xml
new file mode 100644
index 0000000000000..ed0b1a352eb86
--- /dev/null
+++ b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Config/ActionGroup/RestoreLayoutSettingActionGroup.xml
@@ -0,0 +1,17 @@
+
+
+
+
+
+
+
+
+
+
+
diff --git a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Config/Section/ContentManagementSection.xml b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Config/Section/GeneralSection.xml
similarity index 63%
rename from dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Config/Section/ContentManagementSection.xml
rename to dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Config/Section/GeneralSection.xml
index fab936eabc0bf..a8025085204bd 100644
--- a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Config/Section/ContentManagementSection.xml
+++ b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Config/Section/GeneralSection.xml
@@ -17,4 +17,13 @@
+
+
diff --git a/dev/tests/api-functional/framework/Magento/TestFramework/Annotation/ApiDataFixture.php b/dev/tests/api-functional/framework/Magento/TestFramework/Annotation/ApiDataFixture.php
index cff7bd4b221f7..bd83cdcaf3fb1 100644
--- a/dev/tests/api-functional/framework/Magento/TestFramework/Annotation/ApiDataFixture.php
+++ b/dev/tests/api-functional/framework/Magento/TestFramework/Annotation/ApiDataFixture.php
@@ -139,7 +139,8 @@ protected function _applyFixtures(array $fixtures)
*/
protected function _revertFixtures()
{
- foreach ($this->_appliedFixtures as $fixture) {
+ $appliedFixtures = array_reverse($this->_appliedFixtures);
+ foreach ($appliedFixtures as $fixture) {
if (is_callable($fixture)) {
$fixture[1] .= 'Rollback';
if (is_callable($fixture)) {
diff --git a/dev/tests/api-functional/testsuite/Magento/ConfigurableProduct/Api/OptionRepositoryTest.php b/dev/tests/api-functional/testsuite/Magento/ConfigurableProduct/Api/OptionRepositoryTest.php
index 9c1caefd174e0..43d5a5b63b8a0 100644
--- a/dev/tests/api-functional/testsuite/Magento/ConfigurableProduct/Api/OptionRepositoryTest.php
+++ b/dev/tests/api-functional/testsuite/Magento/ConfigurableProduct/Api/OptionRepositoryTest.php
@@ -7,6 +7,9 @@
namespace Magento\ConfigurableProduct\Api;
+use Magento\TestFramework\Helper\Bootstrap;
+use Magento\Eav\Api\AttributeRepositoryInterface;
+
class OptionRepositoryTest extends \Magento\TestFramework\TestCase\WebapiAbstract
{
const SERVICE_NAME = 'configurableProductOptionRepositoryV1';
@@ -138,6 +141,12 @@ public function testDelete()
*/
public function testAdd()
{
+ /** @var AttributeRepositoryInterface $attributeRepository */
+ $attributeRepository = Bootstrap::getObjectManager()->create(AttributeRepositoryInterface::class);
+
+ /** @var \Magento\Eav\Api\Data\AttributeInterface $attribute */
+ $attribute = $attributeRepository->get('catalog_product', 'test_configurable');
+
$productSku = 'simple';
$serviceInfo = [
'rest' => [
@@ -151,7 +160,7 @@ public function testAdd()
]
];
$option = [
- 'attribute_id' => 'test_configurable',
+ 'attribute_id' => $attribute->getAttributeId(),
'label' => 'Test',
'values' => [
[
diff --git a/dev/tests/functional/tests/app/Magento/Cms/Test/Block/Adminhtml/Block/Edit/FormPageActions.php b/dev/tests/functional/tests/app/Magento/Cms/Test/Block/Adminhtml/Block/Edit/FormPageActions.php
new file mode 100644
index 0000000000000..ce9d2fd665235
--- /dev/null
+++ b/dev/tests/functional/tests/app/Magento/Cms/Test/Block/Adminhtml/Block/Edit/FormPageActions.php
@@ -0,0 +1,50 @@
+_rootElement->find($this->toggleButton, Locator::SELECTOR_CSS)->click();
+ parent::save();
+ }
+}
diff --git a/dev/tests/functional/tests/app/Magento/Cms/Test/Block/Adminhtml/Page/Edit/FormPageActions.php b/dev/tests/functional/tests/app/Magento/Cms/Test/Block/Adminhtml/Page/Edit/FormPageActions.php
new file mode 100644
index 0000000000000..c0abe83a0737c
--- /dev/null
+++ b/dev/tests/functional/tests/app/Magento/Cms/Test/Block/Adminhtml/Page/Edit/FormPageActions.php
@@ -0,0 +1,50 @@
+_rootElement->find($this->toggleButton, Locator::SELECTOR_CSS)->click();
+ parent::save();
+ }
+}
diff --git a/dev/tests/functional/tests/app/Magento/Cms/Test/Page/Adminhtml/CmsBlockEdit.xml b/dev/tests/functional/tests/app/Magento/Cms/Test/Page/Adminhtml/CmsBlockEdit.xml
index 372b61e54252f..768a7e5228b89 100644
--- a/dev/tests/functional/tests/app/Magento/Cms/Test/Page/Adminhtml/CmsBlockEdit.xml
+++ b/dev/tests/functional/tests/app/Magento/Cms/Test/Page/Adminhtml/CmsBlockEdit.xml
@@ -8,6 +8,6 @@
-
+
diff --git a/dev/tests/functional/tests/app/Magento/Cms/Test/Page/Adminhtml/CmsBlockNew.xml b/dev/tests/functional/tests/app/Magento/Cms/Test/Page/Adminhtml/CmsBlockNew.xml
index eff9b275bf65b..e19928d66a428 100644
--- a/dev/tests/functional/tests/app/Magento/Cms/Test/Page/Adminhtml/CmsBlockNew.xml
+++ b/dev/tests/functional/tests/app/Magento/Cms/Test/Page/Adminhtml/CmsBlockNew.xml
@@ -7,7 +7,7 @@
-->
-
+
diff --git a/dev/tests/functional/tests/app/Magento/Cms/Test/Page/Adminhtml/CmsPageNew.xml b/dev/tests/functional/tests/app/Magento/Cms/Test/Page/Adminhtml/CmsPageNew.xml
index d088d48a4f3d0..1f82af342704b 100644
--- a/dev/tests/functional/tests/app/Magento/Cms/Test/Page/Adminhtml/CmsPageNew.xml
+++ b/dev/tests/functional/tests/app/Magento/Cms/Test/Page/Adminhtml/CmsPageNew.xml
@@ -8,7 +8,7 @@
-
+
diff --git a/dev/tests/integration/testsuite/Magento/CatalogUrlRewrite/Observer/ProductProcessUrlRewriteSavingObserverTest.php b/dev/tests/integration/testsuite/Magento/CatalogUrlRewrite/Observer/ProductProcessUrlRewriteSavingObserverTest.php
new file mode 100644
index 0000000000000..34f873df71abb
--- /dev/null
+++ b/dev/tests/integration/testsuite/Magento/CatalogUrlRewrite/Observer/ProductProcessUrlRewriteSavingObserverTest.php
@@ -0,0 +1,230 @@
+objectManager = \Magento\TestFramework\Helper\Bootstrap::getObjectManager();
+ }
+
+ /**
+ * @param array $filter
+ * @return array
+ */
+ private function getActualResults(array $filter)
+ {
+ /** @var \Magento\UrlRewrite\Model\UrlFinderInterface $urlFinder */
+ $urlFinder = $this->objectManager->get(\Magento\UrlRewrite\Model\UrlFinderInterface::class);
+ $actualResults = [];
+ foreach ($urlFinder->findAllByData($filter) as $url) {
+ $actualResults[] = [
+ 'request_path' => $url->getRequestPath(),
+ 'target_path' => $url->getTargetPath(),
+ 'is_auto_generated' => (int)$url->getIsAutogenerated(),
+ 'redirect_type' => $url->getRedirectType(),
+ 'store_id' => $url->getStoreId()
+ ];
+ }
+ return $actualResults;
+ }
+
+ /**
+ * @magentoDataFixture Magento/CatalogUrlRewrite/_files/product_rewrite_multistore.php
+ * @magentoAppIsolation enabled
+ */
+ public function testUrlKeyHasChangedInGlobalContext()
+ {
+ /** @var \Magento\Catalog\Api\ProductRepositoryInterface $productRepository*/
+ $productRepository = $this->objectManager->create(\Magento\Catalog\Api\ProductRepositoryInterface::class);
+ /** @var \Magento\Catalog\Model\Product $product*/
+ $product = $productRepository->get('product1');
+
+ /** @var StoreManagerInterface $storeManager */
+ $storeManager = $this->objectManager->get(StoreManagerInterface::class);
+ $storeManager->setCurrentStore(0);
+
+ $testStore = $storeManager->getStore('test');
+ $productFilter = [
+ UrlRewrite::ENTITY_TYPE => 'product',
+ ];
+
+ $expected = [
+ [
+ 'request_path' => "product-1.html",
+ 'target_path' => "catalog/product/view/id/" . $product->getId(),
+ 'is_auto_generated' => 1,
+ 'redirect_type' => 0,
+ 'store_id' => 1,
+ ],
+ [
+ 'request_path' => "product-1.html",
+ 'target_path' => "catalog/product/view/id/" . $product->getId(),
+ 'is_auto_generated' => 1,
+ 'redirect_type' => 0,
+ 'store_id' => $testStore->getId(),
+ ],
+ ];
+ $actual = $this->getActualResults($productFilter);
+ foreach ($expected as $row) {
+ $this->assertContains($row, $actual);
+ }
+
+ $product->setData('save_rewrites_history', true);
+ $product->setUrlKey('new-url');
+ $product->save();
+
+ $expected = [
+ [
+ 'request_path' => "new-url.html",
+ 'target_path' => "catalog/product/view/id/" . $product->getId(),
+ 'is_auto_generated' => 1,
+ 'redirect_type' => 0,
+ 'store_id' => 1,
+ ],
+ [
+ 'request_path' => "new-url.html",
+ 'target_path' => "catalog/product/view/id/" . $product->getId(),
+ 'is_auto_generated' => 1,
+ 'redirect_type' => 0,
+ 'store_id' => $testStore->getId(),
+ ],
+ [
+ 'request_path' => "product-1.html",
+ 'target_path' => "new-url.html",
+ 'is_auto_generated' => 0,
+ 'redirect_type' => 301,
+ 'store_id' => 1,
+ ],
+ [
+ 'request_path' => "product-1.html",
+ 'target_path' => "new-url.html",
+ 'is_auto_generated' => 0,
+ 'redirect_type' => 301,
+ 'store_id' => $testStore->getId(),
+ ],
+ ];
+
+ $actual = $this->getActualResults($productFilter);
+ foreach ($expected as $row) {
+ $this->assertContains($row, $actual);
+ }
+ }
+
+ /**
+ * @magentoDataFixture Magento/CatalogUrlRewrite/_files/product_rewrite_multistore.php
+ * @magentoAppIsolation enabled
+ */
+ public function testUrlKeyHasChangedInStoreviewContextWithPermanentRedirection()
+ {
+ /** @var \Magento\Catalog\Api\ProductRepositoryInterface $productRepository*/
+ $productRepository = $this->objectManager->create(\Magento\Catalog\Api\ProductRepositoryInterface::class);
+ /** @var \Magento\Catalog\Model\Product $product*/
+ $product = $productRepository->get('product1');
+
+ /** @var StoreManagerInterface $storeManager */
+ $storeManager = $this->objectManager->get(StoreManagerInterface::class);
+ $storeManager->setCurrentStore(1);
+
+ $testStore = $storeManager->getStore('test');
+
+ $productFilter = [
+ UrlRewrite::ENTITY_TYPE => 'product',
+ ];
+
+ $product->setData('save_rewrites_history', true);
+ $product->setUrlKey('new-url');
+ $product->save();
+
+ $expected = [
+ [
+ 'request_path' => "new-url.html",
+ 'target_path' => "catalog/product/view/id/" . $product->getId(),
+ 'is_auto_generated' => 1,
+ 'redirect_type' => 0,
+ 'store_id' => 1,
+ ],
+ [
+ 'request_path' => "product-1.html",
+ 'target_path' => "catalog/product/view/id/" . $product->getId(),
+ 'is_auto_generated' => 1,
+ 'redirect_type' => 0,
+ 'store_id' => $testStore->getId(),
+ ],
+ [
+ 'request_path' => "product-1.html",
+ 'target_path' => "new-url.html",
+ 'is_auto_generated' => 0,
+ 'redirect_type' => 301,
+ 'store_id' => 1,
+ ],
+ ];
+
+ $actual = $this->getActualResults($productFilter);
+ foreach ($expected as $row) {
+ $this->assertContains($row, $actual);
+ }
+ }
+
+ /**
+ * @magentoDataFixture Magento/CatalogUrlRewrite/_files/product_rewrite_multistore.php
+ * @magentoAppIsolation enabled
+ */
+ public function testUrlKeyHasChangedInStoreviewContextWithoutPermanentRedirection()
+ {
+ /** @var \Magento\Catalog\Api\ProductRepositoryInterface $productRepository*/
+ $productRepository = $this->objectManager->create(\Magento\Catalog\Api\ProductRepositoryInterface::class);
+ /** @var \Magento\Catalog\Model\Product $product*/
+ $product = $productRepository->get('product1');
+
+ /** @var StoreManagerInterface $storeManager */
+ $storeManager = $this->objectManager->get(StoreManagerInterface::class);
+ $storeManager->setCurrentStore(1);
+
+ $testStore = $storeManager->getStore('test');
+
+ $productFilter = [
+ UrlRewrite::ENTITY_TYPE => 'product',
+ ];
+
+ $product->setData('save_rewrites_history', false);
+ $product->setUrlKey('new-url');
+ $product->save();
+
+ $expected = [
+ [
+ 'request_path' => "new-url.html",
+ 'target_path' => "catalog/product/view/id/" . $product->getId(),
+ 'is_auto_generated' => 1,
+ 'redirect_type' => 0,
+ 'store_id' => 1,
+ ],
+ [
+ 'request_path' => "product-1.html",
+ 'target_path' => "catalog/product/view/id/" . $product->getId(),
+ 'is_auto_generated' => 1,
+ 'redirect_type' => 0,
+ 'store_id' => $testStore->getId(),
+ ],
+ ];
+
+ $actual = $this->getActualResults($productFilter);
+ foreach ($expected as $row) {
+ $this->assertContains($row, $actual);
+ }
+ }
+}
diff --git a/dev/tests/integration/testsuite/Magento/CatalogUrlRewrite/_files/product_rewrite_multistore.php b/dev/tests/integration/testsuite/Magento/CatalogUrlRewrite/_files/product_rewrite_multistore.php
new file mode 100644
index 0000000000000..e86a998ebe82c
--- /dev/null
+++ b/dev/tests/integration/testsuite/Magento/CatalogUrlRewrite/_files/product_rewrite_multistore.php
@@ -0,0 +1,40 @@
+loadArea(\Magento\Backend\App\Area\FrontNameResolver::AREA_CODE);
+
+require __DIR__ . '/../../Store/_files/store.php';
+
+/** @var $installer CategorySetup */
+$objectManager = Bootstrap::getObjectManager();
+$installer = $objectManager->create(CategorySetup::class);
+$storeManager = $objectManager->get(StoreManagerInterface::class);
+$storeManager->setCurrentStore(0);
+
+/** @var $product \Magento\Catalog\Model\Product */
+$product = $objectManager->create(\Magento\Catalog\Model\Product::class);
+$product->setTypeId(\Magento\Catalog\Model\Product\Type::TYPE_SIMPLE)
+ ->setAttributeSetId($installer->getAttributeSetId('catalog_product', 'Default'))
+ ->setStoreId(0)
+ ->setWebsiteIds([1])
+ ->setName('Product1')
+ ->setSku('product1')
+ ->setPrice(10)
+ ->setWeight(18)
+ ->setStockData(['use_config_manage_stock' => 0])
+ ->setUrlKey('product-1')
+ ->setVisibility(\Magento\Catalog\Model\Product\Visibility::VISIBILITY_BOTH)
+ ->setStatus(\Magento\Catalog\Model\Product\Attribute\Source\Status::STATUS_ENABLED);
+
+/** @var ProductRepositoryInterface $productRepository */
+$productRepository = $objectManager->get(ProductRepositoryInterface::class);
+$productRepository->save($product);
diff --git a/dev/tests/integration/testsuite/Magento/CatalogUrlRewrite/_files/product_rewrite_multistore_rollback.php b/dev/tests/integration/testsuite/Magento/CatalogUrlRewrite/_files/product_rewrite_multistore_rollback.php
new file mode 100644
index 0000000000000..1ac9fbf63b118
--- /dev/null
+++ b/dev/tests/integration/testsuite/Magento/CatalogUrlRewrite/_files/product_rewrite_multistore_rollback.php
@@ -0,0 +1,12 @@
+assertSessionMessages(
- $this->equalTo(['The coupon code "test" is not valid.']),
+ $this->equalTo(['The coupon code "test" is not valid.']),
\Magento\Framework\Message\MessageInterface::TYPE_ERROR
);
}
diff --git a/dev/tests/integration/testsuite/Magento/ConfigurableProduct/Controller/CartTest.php b/dev/tests/integration/testsuite/Magento/ConfigurableProduct/Controller/CartTest.php
index f9776b2264ff3..4e0b74ba0f901 100644
--- a/dev/tests/integration/testsuite/Magento/ConfigurableProduct/Controller/CartTest.php
+++ b/dev/tests/integration/testsuite/Magento/ConfigurableProduct/Controller/CartTest.php
@@ -91,7 +91,7 @@ public function testExecuteForConfigurableLastOption()
);
$this->assertSessionMessages(
- $this->equalTo(['The coupon code "test" is not valid.']),
+ $this->equalTo(['The coupon code "test" is not valid.']),
\Magento\Framework\Message\MessageInterface::TYPE_ERROR
);
}
diff --git a/dev/tests/integration/testsuite/Magento/Cron/Model/ScheduleTest.php b/dev/tests/integration/testsuite/Magento/Cron/Model/ScheduleTest.php
index 4e31ea1f18a3a..7b64eb36050f6 100644
--- a/dev/tests/integration/testsuite/Magento/Cron/Model/ScheduleTest.php
+++ b/dev/tests/integration/testsuite/Magento/Cron/Model/ScheduleTest.php
@@ -54,6 +54,27 @@ public function testTryLockJobAlreadyLockedFails()
$this->assertFalse($schedule->tryLockJob());
}
+ /**
+ * If the job is already locked but lock time less than 1 day ago, attempting to lock it again should fail
+ */
+ public function testTryLockJobAlreadyLockedSucceeds()
+ {
+ $offsetInThePast = 2*24*60*60;
+
+ $oldSchedule = $this->scheduleFactory->create()
+ ->setCronExpr("* * * * *")
+ ->setJobCode("test_job")
+ ->setStatus(Schedule::STATUS_RUNNING)
+ ->setCreatedAt(strftime('%Y-%m-%d %H:%M:%S', $this->dateTime->gmtTimestamp() - $offsetInThePast))
+ ->setScheduledAt(strftime('%Y-%m-%d %H:%M', $this->dateTime->gmtTimestamp() - $offsetInThePast + 60))
+ ->setExecutedAt(strftime('%Y-%m-%d %H:%M', $this->dateTime->gmtTimestamp() - $offsetInThePast + 61));
+ $oldSchedule->save();
+
+ $schedule = $this->createSchedule("test_job", Schedule::STATUS_PENDING);
+
+ $this->assertTrue($schedule->tryLockJob());
+ }
+
/**
* If there's a job already locked, should not be able to lock another job
*/
diff --git a/dev/tests/integration/testsuite/Magento/Deploy/_files/zoom1/etc/view.xml b/dev/tests/integration/testsuite/Magento/Deploy/_files/zoom1/etc/view.xml
index 17026f9ce77ec..37a45fbbfe430 100644
--- a/dev/tests/integration/testsuite/Magento/Deploy/_files/zoom1/etc/view.xml
+++ b/dev/tests/integration/testsuite/Magento/Deploy/_files/zoom1/etc/view.xml
@@ -12,7 +12,6 @@
- Lib::jquery/jquery.min.js
- Lib::jquery/jquery-ui-1.9.2.js
- - Lib::jquery/jquery.ba-hashchange.min.js
- Lib::jquery/jquery.details.js
- Lib::jquery/jquery.details.min.js
- Lib::jquery/jquery.hoverIntent.js
diff --git a/dev/tests/integration/testsuite/Magento/Directory/Model/Country/Postcode/ValidatorTest.php b/dev/tests/integration/testsuite/Magento/Directory/Model/Country/Postcode/ValidatorTest.php
index d75f49995f441..b65aa7734f2da 100644
--- a/dev/tests/integration/testsuite/Magento/Directory/Model/Country/Postcode/ValidatorTest.php
+++ b/dev/tests/integration/testsuite/Magento/Directory/Model/Country/Postcode/ValidatorTest.php
@@ -133,7 +133,7 @@ public function getPostcodesDataProvider()
['countryId' => 'IL', 'postcode' => '12345'],
['countryId' => 'IT', 'postcode' => '12345'],
['countryId' => 'JP', 'postcode' => '123-4567'],
- ['countryId' => 'JP', 'postcode' => '123'],
+ ['countryId' => 'JP', 'postcode' => '1234567'],
['countryId' => 'JE', 'postcode' => 'TY8 9PL'],
['countryId' => 'KZ', 'postcode' => '123456'],
['countryId' => 'KE', 'postcode' => '12345'],
diff --git a/dev/tests/integration/testsuite/Magento/Quote/Model/QuoteManagementTest.php b/dev/tests/integration/testsuite/Magento/Quote/Model/QuoteManagementTest.php
index b3e8605b54792..0b0071beb5133 100644
--- a/dev/tests/integration/testsuite/Magento/Quote/Model/QuoteManagementTest.php
+++ b/dev/tests/integration/testsuite/Magento/Quote/Model/QuoteManagementTest.php
@@ -8,18 +8,22 @@
use Magento\Catalog\Model\Product\Type;
use Magento\TestFramework\Helper\Bootstrap;
+/**
+ * Class for testing QuoteManagement model
+ */
class QuoteManagementTest extends \PHPUnit\Framework\TestCase
{
/**
* Create order with product that has child items
*
+ * @magentoAppIsolation enabled
* @magentoDataFixture Magento/Sales/_files/quote_with_bundle.php
*/
public function testSubmit()
{
/**
* Preconditions:
- * Load quote with Bundle product that has at least to child products
+ * Load quote with Bundle product that has at least two child products
*/
$objectManager = Bootstrap::getObjectManager();
/** @var \Magento\Quote\Model\Quote $quote */
@@ -28,8 +32,11 @@ public function testSubmit()
/** Execute SUT */
/** @var \Magento\Quote\Api\CartManagementInterface $model */
- $model = $objectManager->create(\Magento\Quote\Api\CartManagementInterface::class);
- $order = $model->submit($quote);
+ $cartManagement = $objectManager->create(\Magento\Quote\Api\CartManagementInterface::class);
+ /** @var \Magento\Sales\Api\OrderRepositoryInterface $orderRepository */
+ $orderRepository = $objectManager->create(\Magento\Sales\Api\OrderRepositoryInterface::class);
+ $orderId = $cartManagement->placeOrder($quote->getId());
+ $order = $orderRepository->get($orderId);
/** Check if SUT caused expected effects */
$orderItems = $order->getItems();
@@ -41,4 +48,45 @@ public function testSubmit()
}
}
}
+
+ /**
+ * Create order with product that has child items and one of them was deleted
+ *
+ * @magentoAppArea adminhtml
+ * @magentoAppIsolation enabled
+ * @magentoDataFixture Magento/Sales/_files/quote_with_bundle.php
+ */
+ public function testSubmitWithDeletedItem()
+ {
+ /**
+ * Preconditions:
+ * Load quote with Bundle product that have at least to child products
+ */
+ $objectManager = Bootstrap::getObjectManager();
+ /** @var \Magento\Catalog\Api\ProductRepositoryInterface $productRepository */
+ $productRepository = $objectManager->get(\Magento\Catalog\Api\ProductRepositoryInterface::class);
+ $product = $productRepository->get('simple-2');
+ $productRepository->delete($product);
+ /** @var \Magento\Quote\Model\Quote $quote */
+ $quote = $objectManager->create(\Magento\Quote\Model\Quote::class);
+ $quote->load('test01', 'reserved_order_id');
+
+ /** Execute SUT */
+ /** @var \Magento\Quote\Api\CartManagementInterface $model */
+ $cartManagement = $objectManager->create(\Magento\Quote\Api\CartManagementInterface::class);
+ /** @var \Magento\Sales\Api\OrderRepositoryInterface $orderRepository */
+ $orderRepository = $objectManager->create(\Magento\Sales\Api\OrderRepositoryInterface::class);
+ $orderId = $cartManagement->placeOrder($quote->getId());
+ $order = $orderRepository->get($orderId);
+
+ /** Check if SUT caused expected effects */
+ $orderItems = $order->getItems();
+ $this->assertCount(2, $orderItems);
+ foreach ($orderItems as $orderItem) {
+ if ($orderItem->getProductType() == Type::TYPE_SIMPLE) {
+ $this->assertNotEmpty($orderItem->getParentItem(), 'Parent is not set for child product');
+ $this->assertNotEmpty($orderItem->getParentItemId(), 'Parent is not set for child product');
+ }
+ }
+ }
}
diff --git a/dev/tests/integration/testsuite/Magento/Sales/_files/quote_with_bundle_rollback.php b/dev/tests/integration/testsuite/Magento/Sales/_files/quote_with_bundle_rollback.php
index 5a63a813caa96..c45e0aa4d9dc5 100644
--- a/dev/tests/integration/testsuite/Magento/Sales/_files/quote_with_bundle_rollback.php
+++ b/dev/tests/integration/testsuite/Magento/Sales/_files/quote_with_bundle_rollback.php
@@ -4,25 +4,29 @@
* See COPYING.txt for license details.
*/
+$objectManager = \Magento\TestFramework\Helper\Bootstrap::getObjectManager();
/** @var \Magento\Framework\Registry $registry */
-$registry = \Magento\TestFramework\Helper\Bootstrap::getObjectManager()->get(\Magento\Framework\Registry::class);
+$registry = $objectManager->get(\Magento\Framework\Registry::class);
$registry->unregister('isSecureArea');
$registry->register('isSecureArea', true);
+// Delete quote
/** @var $quote \Magento\Quote\Model\Quote */
-$quote = \Magento\TestFramework\Helper\Bootstrap::getObjectManager()->create(\Magento\Quote\Model\Quote::class);
+$quote = $objectManager->create(\Magento\Quote\Model\Quote::class);
$quote->load('test01', 'reserved_order_id');
if ($quote->getId()) {
$quote->delete();
}
-
-/** @var $product \Magento\Catalog\Model\Product */
-$productIds = [1, 2, 3];
-$product = \Magento\TestFramework\Helper\Bootstrap::getObjectManager()->create(\Magento\Catalog\Model\Product::class);
-foreach ($productIds as $productId) {
- $product->load($productId);
- if ($product->getId()) {
- $product->delete();
+// Delete products
+$productSkus = ['simple-1', 'simple-2', 'bundle-product'];
+/** @var Magento\Catalog\Api\ProductRepositoryInterface $productRepository */
+$productRepository = $objectManager->get(Magento\Catalog\Api\ProductRepositoryInterface::class);
+foreach ($productSkus as $sku) {
+ try {
+ $product = $productRepository->get($sku, false, null, true);
+ $productRepository->delete($product);
+ } catch (\Magento\Framework\Exception\NoSuchEntityException $e) {
+ //Product already removed
}
}
diff --git a/dev/tests/integration/testsuite/Magento/UrlRewrite/Controller/UrlRewriteTest.php b/dev/tests/integration/testsuite/Magento/UrlRewrite/Controller/UrlRewriteTest.php
index a356406a95a65..1ebbb35dd7dc4 100644
--- a/dev/tests/integration/testsuite/Magento/UrlRewrite/Controller/UrlRewriteTest.php
+++ b/dev/tests/integration/testsuite/Magento/UrlRewrite/Controller/UrlRewriteTest.php
@@ -5,7 +5,10 @@
*/
namespace Magento\UrlRewrite\Controller;
-class UrlRewriteTest extends \Magento\TestFramework\TestCase\AbstractController
+use Magento\TestFramework\TestCase\AbstractController;
+use Magento\Framework\App\Response\Http as HttpResponse;
+
+class UrlRewriteTest extends AbstractController
{
/**
* @magentoDataFixture Magento/UrlRewrite/_files/url_rewrite.php
@@ -16,17 +19,27 @@ class UrlRewriteTest extends \Magento\TestFramework\TestCase\AbstractController
*
* @param string $request
* @param string $redirect
+ * @param int $expectedCode
*
* @dataProvider requestDataProvider
*/
- public function testMatchUrlRewrite($request, $redirect)
- {
+ public function testMatchUrlRewrite(
+ string $request,
+ string $redirect,
+ int $expectedCode = 301
+ ) {
$this->dispatch($request);
- $code = $this->getResponse()->getHttpResponseCode();
- $location = $this->getResponse()->getHeader('Location')->getFieldValue();
+ /** @var HttpResponse $response */
+ $response = $this->getResponse();
+ $code = $response->getHttpResponseCode();
+ $location = $response->getHeader('Location')->getFieldValue();
- $this->assertEquals(301, $code, 'Invalid response code');
- $this->assertStringEndsWith($redirect, $location, 'Invalid location header');
+ $this->assertEquals($expectedCode, $code, 'Invalid response code');
+ $this->assertStringEndsWith(
+ $redirect,
+ $location,
+ 'Invalid location header'
+ );
}
public function requestDataProvider()
@@ -56,6 +69,12 @@ public function requestDataProvider()
'request' => '/page-similar/',
'redirect' => '/page-b',
],
+ 'Use Case #7: Rewrite during stores switching' => [
+ 'request' => '/page-c-on-2nd-store'
+ . '?___store=default&___from_store=fixture_second_store',
+ 'redirect' => '/page-c-on-1st-store',
+ 'expectedCode' => 302
+ ],
];
}
}
diff --git a/dev/tests/integration/testsuite/Magento/UrlRewrite/_files/url_rewrite.php b/dev/tests/integration/testsuite/Magento/UrlRewrite/_files/url_rewrite.php
index 37cb86aff3be8..8e82aa853d4a4 100644
--- a/dev/tests/integration/testsuite/Magento/UrlRewrite/_files/url_rewrite.php
+++ b/dev/tests/integration/testsuite/Magento/UrlRewrite/_files/url_rewrite.php
@@ -6,35 +6,62 @@
use \Magento\UrlRewrite\Model\OptionProvider;
use \Magento\UrlRewrite\Model\UrlRewrite;
+use \Magento\TestFramework\Helper\Bootstrap;
+use \Magento\Store\Model\StoreManagerInterface;
+use \Magento\Store\Model\Store;
+use \Magento\UrlRewrite\Model\ResourceModel\UrlRewrite as UrlRewriteResource;
+use \Magento\Framework\ObjectManagerInterface;
+use \Magento\Cms\Model\ResourceModel\Page as PageResource;
+use \Magento\Cms\Model\Page;
+
+/** Create fixture store */
+require dirname(dirname(__DIR__)) . '/Store/_files/second_store.php';
/** @var UrlRewrite $rewrite */
-/** @var \Magento\Framework\ObjectManagerInterface $objectManager */
-$objectManager = \Magento\TestFramework\Helper\Bootstrap::getObjectManager();
-/** @var \Magento\UrlRewrite\Model\ResourceModel\UrlRewrite $rewriteResource */
-$rewriteResource = $objectManager->create(\Magento\UrlRewrite\Model\ResourceModel\UrlRewrite::class);
-/** @var \Magento\Cms\Model\ResourceModel\Page $pageResource */
-$pageResource = $objectManager->create(\Magento\Cms\Model\ResourceModel\Page::class);
+/** @var ObjectManagerInterface $objectManager */
+$objectManager = Bootstrap::getObjectManager();
+/** @var UrlRewriteResource $rewriteResource */
+$rewriteResource = $objectManager->create(UrlRewriteResource::class);
+/** @var PageResource $pageResource */
+$pageResource = $objectManager->create(PageResource::class);
+/** @var StoreManagerInterface $storeManager */
+$storeManager = Bootstrap::getObjectManager()
+ ->get(StoreManagerInterface::class);
+/** @var Store $secondStore */
+$secondStore = Bootstrap::getObjectManager()->create(Store::class);
+$secondStore->load('fixture_second_store');
+$secondStoreId = $secondStore->getId();
$storeID = 1;
-/** @var $page \Magento\Cms\Model\Page */
-$page = \Magento\TestFramework\Helper\Bootstrap::getObjectManager()->create(\Magento\Cms\Model\Page::class);
+/** @var $page Page */
+$page = $objectManager->create(Page::class);
$page->setTitle('Cms Page A')
->setIdentifier('page-a')
- ->setStores([$storeID])
->setIsActive(1)
->setContent('Cms Page A
')
- ->setPageLayout('1column');
+ ->setPageLayout('1column')
+ ->setStores([$storeID, $secondStoreId]);
$pageResource->save($page);
-$page = \Magento\TestFramework\Helper\Bootstrap::getObjectManager()->create(\Magento\Cms\Model\Page::class);
+$page = $objectManager->create(Page::class);
$page->setTitle('Cms B')
->setIdentifier('page-b')
- ->setStores([$storeID])
->setIsActive(1)
->setContent('Cms Page B
')
->setPageLayout('1column')
- ->setCustomTheme('Magento/blank');
+ ->setCustomTheme('Magento/blank')
+ ->setStores([$storeID, $secondStoreId]);
+$pageResource->save($page);
+
+$page = $objectManager->create(Page::class);
+$page->setTitle('Cms C')
+ ->setIdentifier('page-c')
+ ->setIsActive(1)
+ ->setContent('Cms Page C
')
+ ->setPageLayout('1column')
+ ->setCustomTheme('Magento/blank')
+ ->setStores([$storeID, $secondStoreId]);
$pageResource->save($page);
$rewrite = $objectManager->create(UrlRewrite::class);
@@ -72,3 +99,21 @@
->setStoreId($storeID)
->setDescription('From age-similar with trailing slash to page-b');
$rewriteResource->save($rewrite);
+
+//Emulating auto-generated aliases (like the ones used for categories).
+//Rewrite rule for the 1st store.
+$rewrite = $objectManager->create(UrlRewrite::class);
+$rewrite->setEntityType('custom')
+ ->setRequestPath('page-c-on-1st-store')
+ ->setTargetPath('page-c')
+ ->setRedirectType(0)
+ ->setStoreId($storeID);
+$rewriteResource->save($rewrite);
+//Rewrite rule for the 2nd store.
+$rewrite = $objectManager->create(UrlRewrite::class);
+$rewrite->setEntityType('custom')
+ ->setRequestPath('page-c-on-2nd-store')
+ ->setTargetPath('page-c')
+ ->setRedirectType(0)
+ ->setStoreId($secondStoreId);
+$rewriteResource->save($rewrite);
diff --git a/dev/tests/js/jasmine/tests/app/code/Magento/Ui/base/js/form/element/url-input.test.js b/dev/tests/js/jasmine/tests/app/code/Magento/Ui/base/js/form/element/url-input.test.js
new file mode 100644
index 0000000000000..c0f55168a5496
--- /dev/null
+++ b/dev/tests/js/jasmine/tests/app/code/Magento/Ui/base/js/form/element/url-input.test.js
@@ -0,0 +1,76 @@
+/**
+ * Copyright © Magento, Inc. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+
+/*eslint max-nested-callbacks: 0*/
+
+define([
+ 'jquery',
+ 'Magento_Ui/js/form/element/url-input'
+], function ($, UrlInput) {
+ 'use strict';
+
+ describe('Magento_Ui/js/form/element/url-input', function () {
+ var component;
+
+ beforeEach(function () {
+ var params = {
+ dataScope: 'urlInput',
+ urlTypes: {
+ url: {
+ label: 'Test label',
+ component: 'Magento_Ui/js/form/element/abstract',
+ template: 'ui/form/element/input',
+ sortOrder: 40
+ },
+ testUrl: {
+ label: 'Test label 2',
+ component: 'Magento_Ui/js/form/element/abstract',
+ template: 'ui/form/element/input',
+ sortOrder: 10
+ }
+ }
+ };
+
+ component = new UrlInput(params);
+ });
+
+ describe('processLinkTypes method', function () {
+ it('check url types were set', function () {
+ expect(component.urlTypes).toBeDefined();
+ expect(component.urlTypes.hasOwnProperty('url'));
+ expect(component.urlTypes.hasOwnProperty('testUrl'));
+ });
+ });
+
+ describe('setOptions method', function () {
+ it('check that optons were set', function () {
+ var expectedOptions = [
+ {
+ value: 'testUrl',
+ label: 'Test label 2',
+ sortOrder: 10
+ },
+ {
+ value: 'url',
+ label: 'Test label',
+ sortOrder: 40
+ }
+ ];
+
+ expect(component.options()).toEqual(expectedOptions);
+ });
+ });
+
+ describe('createChildUrlInputComponent method', function () {
+ it('check linked element was set', function () {
+ expect(component.linkedElementInstances.url).not.toBeDefined();
+ component.createChildUrlInputComponent('url');
+ expect(component.linkedElementInstances.url).toBeDefined();
+ expect(component.getLinkedElementName()).toEqual(component.linkedElementInstances.url);
+ });
+ });
+
+ });
+});
diff --git a/dev/tests/static/get_github_changes.php b/dev/tests/static/get_github_changes.php
index 77dd88c4d001e..dba235c184e5c 100644
--- a/dev/tests/static/get_github_changes.php
+++ b/dev/tests/static/get_github_changes.php
@@ -42,6 +42,17 @@
$changedFiles = getChangedFiles($changes, $fileExtensions);
generateChangedFilesList($options['output-file'], $changedFiles);
saveChangedFileContent($repo);
+
+$additions = retrieveNewFilesAcrossForks($mainline, $repo, $options['branch']);
+$addedFiles = getChangedFiles($additions, $fileExtensions);
+$additionsFile = pathinfo($options['output-file']);
+$additionsFile = $additionsFile['dirname']
+ . DIRECTORY_SEPARATOR
+ . $additionsFile['filename']
+ . '.added.'
+ . $additionsFile['extension'];
+generateChangedFilesList($additionsFile, $addedFiles);
+
cleanup($repo, $mainline);
/**
@@ -143,7 +154,18 @@ function getRepo($options, $mainline)
*/
function retrieveChangesAcrossForks($mainline, GitRepo $repo, $branchName)
{
- return $repo->compareChanges($mainline, $branchName);
+ return $repo->compareChanges($mainline, $branchName, GitRepo::CHANGE_TYPE_ALL);
+}
+
+/**
+ * @param string $mainline
+ * @param GitRepo $repo
+ * @param string $branchName
+ * @return array
+ */
+function retrieveNewFilesAcrossForks($mainline, GitRepo $repo, $branchName)
+{
+ return $repo->compareChanges($mainline, $branchName, GitRepo::CHANGE_TYPE_ADDED);
}
/**
@@ -178,6 +200,10 @@ function validateInput(array $options, array $requiredOptions)
class GitRepo
// @codingStandardsIgnoreEnd
{
+ const CHANGE_TYPE_ADDED = 1;
+ const CHANGE_TYPE_MODIFIED = 2;
+ const CHANGE_TYPE_ALL = 3;
+
/**
* Absolute path to git project
*
@@ -274,9 +300,10 @@ public function getBranches($source = '--all')
*
* @param string $remoteAlias
* @param string $remoteBranch
+ * @param int $changesType
* @return array
*/
- public function compareChanges($remoteAlias, $remoteBranch)
+ public function compareChanges($remoteAlias, $remoteBranch, $changesType = self::CHANGE_TYPE_ALL)
{
if (!isset($this->remoteList[$remoteAlias])) {
throw new LogicException('Alias "' . $remoteAlias . '" is not defined');
@@ -288,7 +315,8 @@ public function compareChanges($remoteAlias, $remoteBranch)
? $this->filterChangedFiles(
$result,
$remoteAlias,
- $remoteBranch
+ $remoteBranch,
+ $changesType
)
: [];
}
@@ -299,50 +327,113 @@ public function compareChanges($remoteAlias, $remoteBranch)
* @param array $changes
* @param string $remoteAlias
* @param string $remoteBranch
+ * @param int $changesType
* @return array
*/
- protected function filterChangedFiles(array $changes, $remoteAlias, $remoteBranch)
- {
+ protected function filterChangedFiles(
+ array $changes,
+ $remoteAlias,
+ $remoteBranch,
+ $changesType = self::CHANGE_TYPE_ALL
+ ) {
$countScannedFiles = 0;
- $changedFilesMasks = [
- 'M' => "M\t",
- 'A' => "A\t"
- ];
+ $changedFilesMasks = $this->buildChangedFilesMask($changesType);
$filteredChanges = [];
foreach ($changes as $fileName) {
$countScannedFiles++;
if (($countScannedFiles % 5000) == 0) {
echo $countScannedFiles . " files scanned so far\n";
}
- foreach ($changedFilesMasks as $mask) {
- if (strpos($fileName, $mask) === 0) {
- $fileName = str_replace($mask, '', $fileName);
- $fileName = trim($fileName);
- if (!in_array($fileName, $filteredChanges) && is_file($this->workTree . '/' . $fileName)) {
- $result = $this->call(
- sprintf(
- 'diff HEAD %s/%s -- %s',
- $remoteAlias,
- $remoteBranch,
- $this->workTree . '/' . $fileName
- )
- );
- if ($result) {
- if (!(isset($this->changedContentFiles[$fileName]))) {
- $this->setChangedContentFile($result, $fileName);
- }
- $filteredChanges[] = $fileName;
- }
- }
- break;
- }
+
+ $changeTypeMask = $this->detectChangeTypeMask($fileName, $changedFilesMasks);
+ if (null === $changeTypeMask) {
+ continue;
}
+
+ $fileName = trim(substr($fileName, strlen($changeTypeMask)));
+ if (in_array($fileName, $filteredChanges)) {
+ continue;
+ }
+
+ $fileChanges = $this->getFileChangeDetails($fileName, $remoteAlias, $remoteBranch);
+ if (empty($fileChanges)) {
+ continue;
+ }
+
+ if (!(isset($this->changedContentFiles[$fileName]))) {
+ $this->setChangedContentFile($fileChanges, $fileName);
+ }
+ $filteredChanges[] = $fileName;
}
echo $countScannedFiles . " files scanned\n";
return $filteredChanges;
}
+ /**
+ * Build mask of git diff report
+ *
+ * @param int $changesType
+ * @return array
+ */
+ private function buildChangedFilesMask(int $changesType): array
+ {
+ $changedFilesMasks = [];
+ foreach ([
+ self::CHANGE_TYPE_ADDED => "A\t",
+ self::CHANGE_TYPE_MODIFIED => "M\t",
+ ] as $changeType => $changedFilesMask) {
+ if ($changeType & $changesType) {
+ $changedFilesMasks[] = $changedFilesMask;
+ }
+ }
+ return $changedFilesMasks;
+ }
+
+ /**
+ * Find one of the allowed modification mask returned by git diff.
+ * Example of change record: "A path/to/added_file"
+ *
+ * @param string $changeRecord
+ * @param array $allowedMasks
+ * @return string|null
+ */
+ private function detectChangeTypeMask(string $changeRecord, array $allowedMasks)
+ {
+ foreach ($allowedMasks as $mask) {
+ if (strpos($changeRecord, $mask) === 0) {
+ return $mask;
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Read detailed information about changes in a file
+ *
+ * @param string $fileName
+ * @param string $remoteAlias
+ * @param string $remoteBranch
+ * @return array
+ */
+ private function getFileChangeDetails(string $fileName, string $remoteAlias, string $remoteBranch): array
+ {
+ if (!is_file($this->workTree . '/' . $fileName)) {
+ return [];
+ }
+
+ $result = $this->call(
+ sprintf(
+ 'diff HEAD %s/%s -- %s',
+ $remoteAlias,
+ $remoteBranch,
+ $this->workTree . '/' . $fileName
+ )
+ );
+
+ return $result;
+ }
+
/**
* Set changed content for file.
*
diff --git a/dev/tests/static/testsuite/Magento/Test/Js/_files/blacklist/magento.txt b/dev/tests/static/testsuite/Magento/Test/Js/_files/blacklist/magento.txt
index 1c76dbe20cef2..a67c6c4630c44 100644
--- a/dev/tests/static/testsuite/Magento/Test/Js/_files/blacklist/magento.txt
+++ b/dev/tests/static/testsuite/Magento/Test/Js/_files/blacklist/magento.txt
@@ -25,5 +25,4 @@ lib/web/mage/adminhtml/tools.js
lib/web/mage/adminhtml/varienLoader.js
lib/web/magnifier/magnifier.js
lib/web/magnifier/magnify.js
-lib/web/varien/form.js
lib/web/varien/js.js
diff --git a/dev/tests/static/testsuite/Magento/Test/Legacy/_files/blacklist/obsolete_mage.php b/dev/tests/static/testsuite/Magento/Test/Legacy/_files/blacklist/obsolete_mage.php
index 24cc65eb8bf86..0f7231e19aeed 100644
--- a/dev/tests/static/testsuite/Magento/Test/Legacy/_files/blacklist/obsolete_mage.php
+++ b/dev/tests/static/testsuite/Magento/Test/Legacy/_files/blacklist/obsolete_mage.php
@@ -7,6 +7,7 @@
'dev/tests/static/testsuite/Magento/Test/Legacy/ObsoleteCodeTest.php',
'dev/tests/static/testsuite/Magento/Test/Integrity/ClassesTest.php',
'dev/tests/static/testsuite/Magento/Test/Legacy/_files/*obsolete*.php',
+ 'dev/tests/static/testsuite/Magento/Test/Legacy/_files/obsolete_classes.php',
'lib/internal/Magento/Framework/ObjectManager/Test/Unit/Factory/CompiledTest.php',
'dev/tests/integration/testsuite/Magento/Indexer/Model/Config/_files/result.php',
];
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 f1d202bb886c8..f75f89c05eaec 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
@@ -4212,6 +4212,8 @@
['Magento\Framework\Acl\CacheInterface'],
['Magento\Framework\Acl\Test\Unit\CacheTest'],
['Magento\Eav\Model\Entity\Attribute\Backend\Serialized'],
+ ['Magento\Cms\Block\Adminhtml\Block\Edit\ResetButton'],
+ ['Magento\Cms\Block\Adminhtml\Block\Edit\SaveAndContinueButton'],
['Magento\Fmework\MessageQueue\Config\Reader\Xml\Converter\DeprecatedFormat'],
[
'Magento\Framework\MessageQueue\Config\Converter',
@@ -4220,6 +4222,8 @@
['Magento\Framework\MessageQueue\Config\Reader', 'Magento\Framework\MessageQueue\Config\Reader\Xml'],
['Magento\Framework\MessageQueue\PublisherFactory'],
['Magento\Framework\MessageQueue\PublisherProxy'],
+ ['Magento\Cms\Block\Adminhtml\Page\Edit\SaveAndContinueButton'],
+ ['Magento\Cms\Block\Adminhtml\Page\Edit\ResetButton'],
['Magento\Search\Block\SearchData', 'Magento\AdvancedSearch\Block\SearchData'],
['Magento\Search\Block\Recommendations', 'Magento\AdvancedSearch\Block\Recommendations'],
['Magento\Search\Block\SearchDataInterface', 'Magento\AdvancedSearch\Block\SearchDataInterface'],
@@ -4230,5 +4234,5 @@
'Magento\Elasticsearch\Test\Unit\Model\SearchAdapter\ConnectionManagerTest',
'Magento\Elasticsearch\Test\Unit\SearchAdapter\ConnectionManagerTest'
],
- ['Zend_Feed', 'Zend\Feed'],
+ ['Zend_Feed', 'Zend\Feed']
];
diff --git a/dev/tests/static/testsuite/Magento/Test/Less/LiveCodeTest.php b/dev/tests/static/testsuite/Magento/Test/Less/LiveCodeTest.php
index c6bd53a806094..47d5df331e5cd 100644
--- a/dev/tests/static/testsuite/Magento/Test/Less/LiveCodeTest.php
+++ b/dev/tests/static/testsuite/Magento/Test/Less/LiveCodeTest.php
@@ -42,7 +42,7 @@ public static function setUpBeforeClass()
*/
public function testCodeStyle()
{
- $reportFile = self::$reportDir . '/less_report.txt';
+ $reportFile = self::$reportDir . '/csless_report.txt';
$wrapper = new LessWrapper();
$codeSniffer = new CodeSniffer(realpath(__DIR__ . '/_files/lesscs'), $reportFile, $wrapper);
@@ -56,10 +56,11 @@ public function testCodeStyle()
$result = $codeSniffer->run($this->filterFiles($fileList));
+ $report = file_exists($reportFile) ? file_get_contents($reportFile) : "";
$this->assertEquals(
0,
$result,
- "PHP Code Sniffer has found {$result} error(s): See detailed report in {$reportFile}"
+ "PHP Code Sniffer has found {$result} error(s): " . PHP_EOL . $report
);
}
diff --git a/dev/tests/static/testsuite/Magento/Test/Php/LiveCodeTest.php b/dev/tests/static/testsuite/Magento/Test/Php/LiveCodeTest.php
index a9140f5693b05..9a94962836c02 100644
--- a/dev/tests/static/testsuite/Magento/Test/Php/LiveCodeTest.php
+++ b/dev/tests/static/testsuite/Magento/Test/Php/LiveCodeTest.php
@@ -7,6 +7,7 @@
namespace Magento\Test\Php;
use Magento\Framework\App\Utility\Files;
+use Magento\Framework\Component\ComponentRegistrar;
use Magento\TestFramework\CodingStandard\Tool\CodeMessDetector;
use Magento\TestFramework\CodingStandard\Tool\CodeSniffer;
use Magento\TestFramework\CodingStandard\Tool\CodeSniffer\Wrapper;
@@ -110,30 +111,74 @@ public static function getWhitelist(
*/
private static function getChangedFilesList($changedFilesBaseDir)
{
- $changedFiles = [];
+ return self::getFilesFromListFile(
+ $changedFilesBaseDir,
+ 'changed_files*',
+ function () {
+ // if no list files, probably, this is the dev environment
+ @exec('git diff --name-only', $changedFiles);
+ @exec('git diff --cached --name-only', $addedFiles);
+ $changedFiles = array_unique(array_merge($changedFiles, $addedFiles));
+ return $changedFiles;
+ }
+ );
+ }
+
+ /**
+ * This method loads list of added files.
+ *
+ * @param string $changedFilesBaseDir
+ * @return string[]
+ */
+ private static function getAddedFilesList($changedFilesBaseDir)
+ {
+ return self::getFilesFromListFile(
+ $changedFilesBaseDir,
+ 'changed_files*.added.*',
+ function () {
+ // if no list files, probably, this is the dev environment
+ @exec('git diff --cached --name-only', $addedFiles);
+ return $addedFiles;
+ }
+ );
+ }
+
+ /**
+ * Read files from generated lists.
+ *
+ * @param string $listsBaseDir
+ * @param string $listFilePattern
+ * @param callable $noListCallback
+ * @return string[]
+ */
+ private static function getFilesFromListFile($listsBaseDir, $listFilePattern, $noListCallback)
+ {
+ $filesDefinedInList = [];
- $globFilesListPattern = ($changedFilesBaseDir ?: self::getChangedFilesBaseDir()) . '/_files/changed_files*';
+ $globFilesListPattern = ($listsBaseDir ?: self::getChangedFilesBaseDir())
+ . '/_files/' . $listFilePattern;
$listFiles = glob($globFilesListPattern);
if (count($listFiles)) {
foreach ($listFiles as $listFile) {
- $changedFiles = array_merge(
- $changedFiles,
+ $filesDefinedInList = array_merge(
+ $filesDefinedInList,
file($listFile, FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES)
);
}
} else {
- // if no list files, probably, this is the dev environment
- @exec('git diff --name-only', $changedFiles);
+ $filesDefinedInList = call_user_func($noListCallback);
}
array_walk(
- $changedFiles,
+ $filesDefinedInList,
function (&$file) {
$file = BP . '/' . $file;
}
);
- return $changedFiles;
+ $filesDefinedInList = array_values(array_unique($filesDefinedInList));
+
+ return $filesDefinedInList;
}
/**
@@ -287,12 +332,10 @@ public function testCopyPaste()
*/
public function testStrictTypes()
{
- $whiteList = self::getWhitelist(
- ['php'],
- '',
- '',
- '/_files/whitelist/strict_type.txt'
- );
+ $changedFiles = self::getAddedFilesList('');
+
+ $componentRegistrar = new ComponentRegistrar();
+ $directoriesToCheck = $componentRegistrar->getPaths(ComponentRegistrar::MODULE);
try {
$blackList = Files::init()->readLists(
self::getBaseFilesFolder() . '/_files/blacklist/strict_type.txt'
@@ -301,7 +344,11 @@ public function testStrictTypes()
// nothing matched black list
$blackList = [];
}
- $toBeTestedFiles = array_diff($whiteList, $blackList);
+
+ $toBeTestedFiles = array_diff(
+ self::filterFiles($changedFiles, ['php'], $directoriesToCheck),
+ $blackList
+ );
$filesMissingStrictTyping = [];
foreach ($toBeTestedFiles as $fileName) {
@@ -310,12 +357,13 @@ public function testStrictTypes()
$filesMissingStrictTyping[] = $fileName;
}
}
- $filesMissingStrictTypingString = implode(PHP_EOL, $filesMissingStrictTyping);
$this->assertEquals(
0,
count($filesMissingStrictTyping),
- "Following files are missing strict type declaration:" . PHP_EOL . $filesMissingStrictTypingString
+ "Following files are missing strict type declaration:"
+ . PHP_EOL
+ . implode(PHP_EOL, $filesMissingStrictTyping)
);
}
}
diff --git a/dev/tests/static/testsuite/Magento/Test/Php/_files/blacklist/strict_type.txt b/dev/tests/static/testsuite/Magento/Test/Php/_files/blacklist/strict_type.txt
index 5c5c380c4dd33..877583e5b6a29 100644
--- a/dev/tests/static/testsuite/Magento/Test/Php/_files/blacklist/strict_type.txt
+++ b/dev/tests/static/testsuite/Magento/Test/Php/_files/blacklist/strict_type.txt
@@ -1 +1 @@
-# Format: or simply
\ No newline at end of file
+# Format: or simply
diff --git a/dev/tests/static/testsuite/Magento/Test/Php/_files/whitelist/common.txt b/dev/tests/static/testsuite/Magento/Test/Php/_files/whitelist/common.txt
index 79c5074caa375..6f4dc68addcf6 100644
--- a/dev/tests/static/testsuite/Magento/Test/Php/_files/whitelist/common.txt
+++ b/dev/tests/static/testsuite/Magento/Test/Php/_files/whitelist/common.txt
@@ -1,6 +1,5 @@
# Format: or simply
* * /
-dev/tools/Magento
dev/tests
phpserver
pub
diff --git a/dev/tests/static/testsuite/Magento/Test/Php/_files/whitelist/strict_type.txt b/dev/tests/static/testsuite/Magento/Test/Php/_files/whitelist/strict_type.txt
deleted file mode 100644
index 9e2969f929c21..0000000000000
--- a/dev/tests/static/testsuite/Magento/Test/Php/_files/whitelist/strict_type.txt
+++ /dev/null
@@ -1,20 +0,0 @@
-# Format: or simply
-app/code/Magento/Inventory
-app/code/Magento/InventoryApi
-app/code/Magento/InventoryBundle
-app/code/Magento/InventoryCatalog
-app/code/Magento/InventoryCatalogSearch
-app/code/Magento/InventoryConfigurableProduct
-app/code/Magento/InventoryConfiguration
-app/code/Magento/InventoryConfigurationApi
-app/code/Magento/InventoryGroupedProduct
-app/code/Magento/InventoryImportExport
-app/code/Magento/InventoryIndexer
-app/code/Magento/InventoryLowQuantityNotification
-app/code/Magento/InventoryLowQuantityNotificationApi
-app/code/Magento/InventoryProductAlert
-app/code/Magento/InventoryReservations
-app/code/Magento/InventoryReservationsApi
-app/code/Magento/InventorySales
-app/code/Magento/InventorySalesApi
-app/code/Magento/InventoryShipping
diff --git a/dev/tools/Magento/Tools/Layout/processors/addItemRenderer.xsl b/dev/tools/Magento/Tools/Layout/processors/addItemRenderer.xsl
deleted file mode 100644
index 2519a007df081..0000000000000
--- a/dev/tools/Magento/Tools/Layout/processors/addItemRenderer.xsl
+++ /dev/null
@@ -1,27 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/dev/tools/Magento/Tools/Layout/processors/addToParentGroup.xsl b/dev/tools/Magento/Tools/Layout/processors/addToParentGroup.xsl
deleted file mode 100644
index 55ebf482702c2..0000000000000
--- a/dev/tools/Magento/Tools/Layout/processors/addToParentGroup.xsl
+++ /dev/null
@@ -1,36 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/dev/tools/Magento/Tools/Layout/processors/headBlocks.xsl b/dev/tools/Magento/Tools/Layout/processors/headBlocks.xsl
deleted file mode 100644
index 03a7f75b238d2..0000000000000
--- a/dev/tools/Magento/Tools/Layout/processors/headBlocks.xsl
+++ /dev/null
@@ -1,62 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- Magento\Theme\Block\Html\Head\Script
- Magento\Theme\Block\Html\Head\Css
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/dev/tools/Magento/Tools/Layout/processors/layoutArguments.xsl b/dev/tools/Magento/Tools/Layout/processors/layoutArguments.xsl
deleted file mode 100644
index 84edd36f43c0c..0000000000000
--- a/dev/tools/Magento/Tools/Layout/processors/layoutArguments.xsl
+++ /dev/null
@@ -1,150 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- object
-
-
-
- string
-
-
-
-
-
-
-
-
-
- url
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- array
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- options
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/dev/tools/Magento/Tools/Layout/processors/layoutGridContainer.xsl b/dev/tools/Magento/Tools/Layout/processors/layoutGridContainer.xsl
deleted file mode 100644
index 31473b68d677e..0000000000000
--- a/dev/tools/Magento/Tools/Layout/processors/layoutGridContainer.xsl
+++ /dev/null
@@ -1,50 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/dev/tools/Magento/Tools/Layout/processors/layoutHandles.xsl b/dev/tools/Magento/Tools/Layout/processors/layoutHandles.xsl
deleted file mode 100644
index d30a41a77224a..0000000000000
--- a/dev/tools/Magento/Tools/Layout/processors/layoutHandles.xsl
+++ /dev/null
@@ -1,57 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/dev/tools/Magento/Tools/Layout/processors/layoutLabels.xsl b/dev/tools/Magento/Tools/Layout/processors/layoutLabels.xsl
deleted file mode 100644
index e91d663141294..0000000000000
--- a/dev/tools/Magento/Tools/Layout/processors/layoutLabels.xsl
+++ /dev/null
@@ -1,32 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/dev/tools/Magento/Tools/Layout/processors/layoutReferences.xsl b/dev/tools/Magento/Tools/Layout/processors/layoutReferences.xsl
deleted file mode 100644
index f73264580793e..0000000000000
--- a/dev/tools/Magento/Tools/Layout/processors/layoutReferences.xsl
+++ /dev/null
@@ -1,53 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/dev/tools/Magento/Tools/Layout/processors/layoutTranslate.xsl b/dev/tools/Magento/Tools/Layout/processors/layoutTranslate.xsl
deleted file mode 100644
index dcf54d062d7cd..0000000000000
--- a/dev/tools/Magento/Tools/Layout/processors/layoutTranslate.xsl
+++ /dev/null
@@ -1,77 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- true
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- true
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/dev/tools/Magento/Tools/psr/phpcs_precommit_hook.sh b/dev/tools/Magento/Tools/psr/phpcs_precommit_hook.sh
deleted file mode 100755
index 229fb53f2547f..0000000000000
--- a/dev/tools/Magento/Tools/psr/phpcs_precommit_hook.sh
+++ /dev/null
@@ -1,103 +0,0 @@
-#!/bin/bash
-# PHP CodeSniffer pre-commit hook for git
-#
-
-PHPCS_BIN=/usr/bin/phpcs
-PHPCS_CODING_STANDARD=PSR2
-PHPCS_MEMORY_LIMIT=1024M
-PHPCS_IGNORE=
-PHPCS_EXTENSIONS=php,phtml
-PHPCS_ENCODING=utf-8
-TMP_STAGING=".tmp"
-
-# simple check if code sniffer is set up correctly
-if [ ! -x $PHPCS_BIN ]; then
- echo "PHP Code Sniffer is not available: $PHPCS_BIN"
- exit 1
-fi
-
-# if HEAD is available for comparison, otherwise use an empty tree object
-if git rev-parse --verify HEAD
-then
- against=HEAD
-else
- # Initial commit: diff against an empty tree object
- against=4b825dc642cb6eb9a060e54bf8d69288fbee4904
-fi
-
-FILES=$(git diff-index --name-only --cached --diff-filter=ACMR $against -- )
-
-if [ "$FILES" == "" ]; then
- exit 0
-fi
-
-# create temporary copy of staging area
-if [ -e $TMP_STAGING ]; then
- rm -rf $TMP_STAGING
-fi
-mkdir $TMP_STAGING
-
-# match files against whitelist
-FILES_TO_CHECK=""
-for FILE in $FILES
-do
- echo "$FILE" | egrep -q "$PHPCS_FILE_PATTERN"
- RETVAL=$?
- if [ "$RETVAL" -eq "0" ]
- then
- FILES_TO_CHECK="$FILES_TO_CHECK $FILE"
- fi
-done
-
-if [ "$FILES_TO_CHECK" == "" ]; then
- exit 0
-fi
-# execute the code sniffer
-if [ "$PHPCS_IGNORE" != "" ]; then
- IGNORE="--ignore=$PHPCS_IGNORE"
-else
- IGNORE=""
-fi
-
-if [ "$PHPCS_ENCODING" != "" ]; then
- ENCODING="--encoding=$PHPCS_ENCODING"
-else
- ENCODING=""
-fi
-
-if [ "$PHPCS_IGNORE_WARNINGS" == "1" ]; then
- IGNORE_WARNINGS="-n"
-else
- IGNORE_WARNINGS=""
-fi
-
-# Copy staged files to a processing folder
-STAGED_FILES=""
-
-for FILE in $FILES_TO_CHECK
-do
- ID=`git diff-index --cached HEAD -- $FILE | cut -d " " -f4`
-
- # create staged version of file in temporary staging area with the same
- # path as the original file so that the phpcs ignore filters can be applied
- mkdir -p "$TMP_STAGING/$(dirname $FILE)"
-
- git cat-file blob $ID > "$TMP_STAGING/$FILE"
- STAGED_FILES="$STAGED_FILES $TMP_STAGING/$FILE"
-
-done
-
-OUTPUT=$($PHPCS_BIN -n -s $IGNORE_WARNINGS --standard=$PHPCS_CODING_STANDARD -d memory_limit=$PHPCS_MEMORY_LIMIT $ENCODING --extensions=$PHPCS_EXTENSIONS $IGNORE $STAGED_FILES)
-RETVAL=$?
-
-# delete temporary copy of staging area
-rm -rf $TMP_STAGING
-
-if [ $RETVAL -ne 0 ]; then
- echo "Error Committing Files to Repository. PHP Code Sniffer errors detected:"
- echo ""
- echo ""
- echo "$OUTPUT"
-fi
-
-exit $RETVAL
diff --git a/lib/internal/Magento/Framework/App/DeploymentConfig/Writer/PhpFormatter.php b/lib/internal/Magento/Framework/App/DeploymentConfig/Writer/PhpFormatter.php
index 030fc72608161..d5a89c56b689f 100644
--- a/lib/internal/Magento/Framework/App/DeploymentConfig/Writer/PhpFormatter.php
+++ b/lib/internal/Magento/Framework/App/DeploymentConfig/Writer/PhpFormatter.php
@@ -12,9 +12,9 @@
class PhpFormatter implements FormatterInterface
{
/**
- * 2 space indentation for array formatting.
+ * 4 space indentation for array formatting.
*/
- const INDENT = ' ';
+ const INDENT = ' ';
/**
* Format deployment configuration.
@@ -39,7 +39,7 @@ public function format($data, array $comments = [])
* @param string $prefix
* @return string
*/
- private function formatData($data, $comments = [], $prefix = ' ')
+ private function formatData($data, $comments = [], $prefix = ' ')
{
$elements = [];
@@ -56,13 +56,12 @@ private function formatData($data, $comments = [], $prefix = ' ')
$elements[] = $prefix . " */";
}
- $elements[] = $prefix . $this->varExportShort($key) . ' => ' .
- (!is_array($value) ? $this->varExportShort($value) . ',' : '');
-
if (is_array($value)) {
- $elements[] = $prefix . '[';
- $elements[] = $this->formatData($value, [], ' ' . $prefix);
+ $elements[] = $prefix . $this->varExportShort($key) . ' => [';
+ $elements[] = $this->formatData($value, [], ' ' . $prefix);
$elements[] = $prefix . '],';
+ } else {
+ $elements[] = $prefix . $this->varExportShort($key) . ' => ' . $this->varExportShort($value) . ',';
}
}
return implode("\n", $elements);
diff --git a/lib/internal/Magento/Framework/App/Test/Unit/DeploymentConfig/Writer/PhpFormatterTest.php b/lib/internal/Magento/Framework/App/Test/Unit/DeploymentConfig/Writer/PhpFormatterTest.php
index cc673e084c3b2..1967a39fe4374 100644
--- a/lib/internal/Magento/Framework/App/Test/Unit/DeploymentConfig/Writer/PhpFormatterTest.php
+++ b/lib/internal/Magento/Framework/App/Test/Unit/DeploymentConfig/Writer/PhpFormatterTest.php
@@ -56,77 +56,67 @@ public function formatWithCommentDataProvider()
$expectedResult1 = <<
- [
- 's1' =>
- [
- 0 => 's11',
- 1 => 's12',
+ 'ns1' => [
+ 's1' => [
+ 0 => 's11',
+ 1 => 's12',
+ ],
+ 's2' => [
+ 0 => 's21',
+ 1 => 's22',
+ ],
],
- 's2' =>
- [
- 0 => 's21',
- 1 => 's22',
- ],
- ],
- /**
- * For the section: ns2
- * comment for namespace 2
- */
- 'ns2' =>
- [
- 's1' =>
- [
- 0 => 's11',
+ /**
+ * For the section: ns2
+ * comment for namespace 2
+ */
+ 'ns2' => [
+ 's1' => [
+ 0 => 's11',
+ ],
],
- ],
- 'ns3' => 'just text',
- 'ns4' => 'just text',
+ 'ns3' => 'just text',
+ 'ns4' => 'just text',
];
TEXT;
$expectedResult2 = <<
- [
- 's1' =>
- [
- 0 => 's11',
- 1 => 's12',
- ],
- 's2' =>
- [
- 0 => 's21',
- 1 => 's22',
+ /**
+ * For the section: ns1
+ * comment for' namespace 1
+ */
+ 'ns1' => [
+ 's1' => [
+ 0 => 's11',
+ 1 => 's12',
+ ],
+ 's2' => [
+ 0 => 's21',
+ 1 => 's22',
+ ],
],
- ],
- /**
- * For the section: ns2
- * comment for namespace 2.
- * Next comment for' namespace 2
- */
- 'ns2' =>
- [
- 's1' =>
- [
- 0 => 's11',
+ /**
+ * For the section: ns2
+ * comment for namespace 2.
+ * Next comment for' namespace 2
+ */
+ 'ns2' => [
+ 's1' => [
+ 0 => 's11',
+ ],
],
- ],
- /**
- * For the section: ns3
- * comment for" namespace 3
- */
- 'ns3' => 'just text',
- /**
- * For the section: ns4
- * comment for namespace 4
- */
- 'ns4' => 'just text',
+ /**
+ * For the section: ns3
+ * comment for" namespace 3
+ */
+ 'ns3' => 'just text',
+ /**
+ * For the section: ns4
+ * comment for namespace 4
+ */
+ 'ns4' => 'just text',
];
TEXT;
@@ -134,23 +124,23 @@ public function formatWithCommentDataProvider()
$expectedResult3 = << [
- 's1' => [
- 's11',
- 's12'
+ 'ns1' => [
+ 's1' => [
+ 's11',
+ 's12'
+ ],
+ 's2' => [
+ 's21',
+ 's22'
+ ]
+ ],
+ 'ns2' => [
+ 's1' => [
+ 's11'
+ ]
],
- 's2' => [
- 's21',
- 's22'
- ]
- ],
- 'ns2' => [
- 's1' => [
- 's11'
- ]
- ],
- 'ns3' => 'just text',
- 'ns4' => 'just text'
+ 'ns3' => 'just text',
+ 'ns4' => 'just text'
];
TEXT;
diff --git a/lib/internal/Magento/Framework/DB/Sql/ConcatExpression.php b/lib/internal/Magento/Framework/DB/Sql/ConcatExpression.php
index a0c3a803ca019..490e272d1a63a 100644
--- a/lib/internal/Magento/Framework/DB/Sql/ConcatExpression.php
+++ b/lib/internal/Magento/Framework/DB/Sql/ConcatExpression.php
@@ -65,7 +65,7 @@ public function __toString()
}
return sprintf(
'TRIM(%s)',
- $this->adapter->getConcatSql($columns, ' ')
+ $this->adapter->getConcatSql($columns, $this->separator)
);
}
}
diff --git a/lib/internal/Magento/Framework/Locale/Config.php b/lib/internal/Magento/Framework/Locale/Config.php
index 2a623deca082f..f17694a35b034 100644
--- a/lib/internal/Magento/Framework/Locale/Config.php
+++ b/lib/internal/Magento/Framework/Locale/Config.php
@@ -74,6 +74,7 @@ class Config implements \Magento\Framework\Locale\ConfigInterface
'lv_LV', /*Latvian (Latvia)*/
'mk_MK', /*Macedonian (Macedonia)*/
'mn_Cyrl_MN', /*Mongolian (Mongolia)*/
+ 'ms_MY', /*Malaysian (Malaysia)*/
'ms_Latn_MY', /*Malaysian (Malaysia)*/
'nl_BE', /*Dutch (Belgium)*/
'nl_NL', /*Dutch (Netherlands)*/
diff --git a/lib/internal/Magento/Framework/Model/ResourceModel/PredefinedId.php b/lib/internal/Magento/Framework/Model/ResourceModel/PredefinedId.php
new file mode 100644
index 0000000000000..ca9f1c72c06ac
--- /dev/null
+++ b/lib/internal/Magento/Framework/Model/ResourceModel/PredefinedId.php
@@ -0,0 +1,64 @@
+getConnection();
+ $select = $connection->select()
+ ->from($this->getMainTable(), [$this->getIdFieldName()])
+ ->where($this->getIdFieldName() . ' = ?', $object->getId())
+ ->limit(1);
+ return (bool)$connection->fetchOne($select);
+ }
+
+ /**
+ * Save New Object
+ *
+ * Overwrite default \Magento\Framework\Model\ResourceModel\Db\AbstractDb implementation of the saveNewObject
+ * @see \Magento\Framework\Model\ResourceModel\Db\AbstractDb::saveNewObject()
+ *
+ * @param \Magento\Framework\Model\AbstractModel $object
+ * @throws LocalizedException
+ * @return void
+ */
+ protected function saveNewObject(\Magento\Framework\Model\AbstractModel $object)
+ {
+ $bind = $this->_prepareDataForSave($object);
+ $this->getConnection()->insert($this->getMainTable(), $bind);
+
+ if ($this->_isPkAutoIncrement) {
+ $object->setId($this->getConnection()->lastInsertId($this->getMainTable()));
+ }
+
+ if ($this->_useIsObjectNew) {
+ $object->isObjectNew(false);
+ }
+ }
+}
diff --git a/lib/internal/Magento/Framework/MultiDimensionalIndexer/IndexName.php b/lib/internal/Magento/Framework/MultiDimensionalIndexer/IndexName.php
index 9bd06e3977638..48b7fb0bdd6e9 100644
--- a/lib/internal/Magento/Framework/MultiDimensionalIndexer/IndexName.php
+++ b/lib/internal/Magento/Framework/MultiDimensionalIndexer/IndexName.php
@@ -7,6 +7,9 @@
namespace Magento\Framework\MultiDimensionalIndexer;
+use Magento\Framework\Exception\LocalizedException;
+use Magento\Framework\Phrase;
+
/**
* Index Name object
*
@@ -32,10 +35,19 @@ class IndexName
/**
* @param string $indexId
* @param Dimension[] $dimensions
- * @param Alias $alias
+ * @param Alias $alias*
+ * @throws LocalizedException
*/
public function __construct(string $indexId, array $dimensions, Alias $alias)
{
+ foreach ($dimensions as $dimension) {
+ if (!$dimension instanceof Dimension) {
+ throw new LocalizedException(
+ new Phrase('Dimension have to be instance of Dimension class.')
+ );
+ }
+ }
+
$this->indexId = $indexId;
$this->dimensions = $dimensions;
$this->alias = $alias;
diff --git a/lib/internal/Magento/Framework/MultiDimensionalIndexer/README.md b/lib/internal/Magento/Framework/MultiDimensionalIndexer/README.md
index a5231a6c57629..fcaaba0ce6d1d 100644
--- a/lib/internal/Magento/Framework/MultiDimensionalIndexer/README.md
+++ b/lib/internal/Magento/Framework/MultiDimensionalIndexer/README.md
@@ -1 +1,11 @@
MultiDimensionalIndexer
+=======
+The **\Magento\Framework\MultiDimensionalIndexer** library provides functionality of multi-dimension index creation and
+handling.
+
+Library introduces a set of extension points which split monolithic index by specified Dimension (Scope), creating
+independent index (i.e. dedicated MySQL table) per each Dimension. Along with that library provides index name
+resolving mechanism based on provided scope. The Multi-Dimension indexes introduced for the sake of data scalability
+and ability to reindex data in the scope of particular Dimension only.
+
+Aliasing mechanism guarantees zero downtime to make Front-End responsive while Full Reindex being processed.
diff --git a/lib/internal/Magento/Framework/Registry.php b/lib/internal/Magento/Framework/Registry.php
index 825d550fc1507..d1bc227437d5f 100644
--- a/lib/internal/Magento/Framework/Registry.php
+++ b/lib/internal/Magento/Framework/Registry.php
@@ -8,7 +8,11 @@
/**
* Registry model. Used to manage values in registry
*
+ * Registry usage as a shared service introduces temporal, hard to detect coupling into system.
+ * It's usage should be avoid. Use service classes or data providers instead.
+ *
* @api
+ * @deprecated
*/
class Registry
{
@@ -24,6 +28,8 @@ class Registry
*
* @param string $key
* @return mixed
+ *
+ * @deprecated
*/
public function registry($key)
{
@@ -41,6 +47,8 @@ public function registry($key)
* @param bool $graceful
* @return void
* @throws \RuntimeException
+ *
+ * @deprecated
*/
public function register($key, $value, $graceful = false)
{
@@ -58,6 +66,8 @@ public function register($key, $value, $graceful = false)
*
* @param string $key
* @return void
+ *
+ * @deprecated
*/
public function unregister($key)
{
diff --git a/lib/internal/Magento/Framework/Session/SessionManager.php b/lib/internal/Magento/Framework/Session/SessionManager.php
index cfabff6955e49..3eef84b980914 100644
--- a/lib/internal/Magento/Framework/Session/SessionManager.php
+++ b/lib/internal/Magento/Framework/Session/SessionManager.php
@@ -504,18 +504,8 @@ public function regenerateId()
return $this;
}
- //@see http://php.net/manual/en/function.session-regenerate-id.php#53480 workaround
if ($this->isSessionExists()) {
- $oldSessionId = session_id();
- session_regenerate_id();
- $newSessionId = session_id();
- session_id($oldSessionId);
- session_destroy();
-
- $oldSession = $_SESSION;
- session_id($newSessionId);
- session_start();
- $_SESSION = $oldSession;
+ session_regenerate_id(true);
} else {
session_start();
}
diff --git a/lib/internal/Magento/Framework/Stdlib/Cookie/PhpCookieManager.php b/lib/internal/Magento/Framework/Stdlib/Cookie/PhpCookieManager.php
index de5503c144647..dff31a897e1ac 100644
--- a/lib/internal/Magento/Framework/Stdlib/Cookie/PhpCookieManager.php
+++ b/lib/internal/Magento/Framework/Stdlib/Cookie/PhpCookieManager.php
@@ -204,14 +204,14 @@ private function checkAbilityToSendCookie($name, $value)
$sizeOfCookie = $this->sizeOfCookie($name, $value);
- if ($numCookies > PhpCookieManager::MAX_NUM_COOKIES) {
+ if ($numCookies > static::MAX_NUM_COOKIES) {
$this->logger->warning(
new Phrase('Unable to send the cookie. Maximum number of cookies would be exceeded.'),
array_merge($_COOKIE, ['user-agent' => $this->httpHeader->getHttpUserAgent()])
);
}
- if ($sizeOfCookie > PhpCookieManager::MAX_COOKIE_SIZE) {
+ if ($sizeOfCookie > static::MAX_COOKIE_SIZE) {
throw new CookieSizeLimitReachedException(
new Phrase(
'Unable to send the cookie. Size of \'%name\' is %size bytes.',
diff --git a/lib/internal/Magento/Framework/Stdlib/Test/Unit/Cookie/PhpCookieManagerTest.php b/lib/internal/Magento/Framework/Stdlib/Test/Unit/Cookie/PhpCookieManagerTest.php
index 75b8eb2cec8d6..1ea942f5e9013 100644
--- a/lib/internal/Magento/Framework/Stdlib/Test/Unit/Cookie/PhpCookieManagerTest.php
+++ b/lib/internal/Magento/Framework/Stdlib/Test/Unit/Cookie/PhpCookieManagerTest.php
@@ -47,8 +47,6 @@ class PhpCookieManagerTest extends \PHPUnit\Framework\TestCase
const COOKIE_HTTP_ONLY = true;
const COOKIE_NOT_HTTP_ONLY = false;
const COOKIE_EXPIRE_END_OF_SESSION = 0;
- const MAX_NUM_COOKIES = 50;
- const MAX_COOKIE_SIZE = 4096;
/**
* Mapping from constant names to functions that handle the assertions.
@@ -499,7 +497,9 @@ public function testSetCookieSizeTooLarge()
);
$cookieValue = '';
- for ($i = 0; $i < self::MAX_COOKIE_SIZE + 1; $i++) {
+
+ $cookieManager = $this->cookieManager;
+ for ($i = 0; $i < $cookieManager::MAX_COOKIE_SIZE + 1; $i++) {
$cookieValue = $cookieValue . 'a';
}
@@ -527,8 +527,9 @@ public function testSetTooManyCookies()
$userAgent = 'some_user_agent';
- // Set self::MAX_NUM_COOKIES number of cookies in superglobal $_COOKIE.
- for ($i = count($_COOKIE); $i < self::MAX_NUM_COOKIES; $i++) {
+ $cookieManager = $this->cookieManager;
+ // Set $cookieManager::MAX_NUM_COOKIES number of cookies in superglobal $_COOKIE.
+ for ($i = count($_COOKIE); $i < $cookieManager::MAX_NUM_COOKIES; $i++) {
$_COOKIE['test_cookie_' . $i] = self::COOKIE_VALUE . '_' . $i;
}
diff --git a/lib/internal/Magento/Framework/Test/Unit/MultiDimensionalIndexer/IndexTableSwitcherTest.php b/lib/internal/Magento/Framework/Test/Unit/MultiDimensionalIndexer/IndexTableSwitcherTest.php
new file mode 100644
index 0000000000000..3a4e59275d1bf
--- /dev/null
+++ b/lib/internal/Magento/Framework/Test/Unit/MultiDimensionalIndexer/IndexTableSwitcherTest.php
@@ -0,0 +1,98 @@
+indexName = $this->createMock(IndexName::class);
+ $this->resourceConnection = $this->createMock(ResourceConnection::class);
+ $this->indexNameResolver = $this->createMock(IndexNameResolverInterface::class);
+ $this->adapter = $this->createMock(AdapterInterface::class);
+
+ $this->indexTableSwitcher = $objectManager->getObject(
+ IndexTableSwitcher::class,
+ [
+ 'resourceConnection' => $this->resourceConnection,
+ 'indexNameResolver' => $this->indexNameResolver,
+ ]
+ );
+ }
+
+ public function testSwitch()
+ {
+ $connectionName = 'testConnection';
+ $tableName = 'some_table_name';
+ $toRename =
+ [
+ [
+ 'oldName' => $tableName,
+ 'newName' => $tableName . '_outdated',
+ ],
+ [
+ 'oldName' => $tableName . '_replica',
+ 'newName' => $tableName,
+ ],
+ [
+ 'oldName' => $tableName . '_outdated',
+ 'newName' => $tableName . '_replica',
+ ],
+ ];
+
+ $this->resourceConnection->expects($this->once())->method('getConnection')
+ ->with($connectionName)->willReturn($this->adapter);
+ $this->indexNameResolver->expects($this->once())->method('resolveName')
+ ->with($this->indexName)->willReturn($tableName);
+ $this->adapter->expects($this->once())->method('renameTablesBatch')
+ ->with($toRename);
+
+ $this->indexTableSwitcher->switch($this->indexName, $connectionName);
+ }
+}
diff --git a/lib/internal/Magento/Framework/composer.json b/lib/internal/Magento/Framework/composer.json
index b442effe5ffda..8715af0e65896 100644
--- a/lib/internal/Magento/Framework/composer.json
+++ b/lib/internal/Magento/Framework/composer.json
@@ -24,7 +24,7 @@
"ext-xsl": "*",
"lib-libxml": "*",
"colinmollenhour/php-redis-session-abstract": "~1.3.8",
- "composer/composer": "1.4.1",
+ "composer/composer": "^1.4",
"magento/zendframework1": "~1.13.0",
"monolog/monolog": "^1.17",
"oyejorge/less.php": "~1.7.0",
diff --git a/lib/web/css/source/lib/_navigation.less b/lib/web/css/source/lib/_navigation.less
index 93101fd7c19b9..6ed3a9671ab13 100644
--- a/lib/web/css/source/lib/_navigation.less
+++ b/lib/web/css/source/lib/_navigation.less
@@ -324,6 +324,7 @@
.lib-css(text-decoration, @_nav-level0-item-text-decoration);
box-sizing: border-box;
position: relative;
+ display: inline-block;
&:hover, &.ui-state-focus {
.lib-css(background, @_nav-level0-item-background-color-hover);
diff --git a/lib/web/fotorama/fotorama.js b/lib/web/fotorama/fotorama.js
index 0947164e5b0f2..c86cd40198b2b 100644
--- a/lib/web/fotorama/fotorama.js
+++ b/lib/web/fotorama/fotorama.js
@@ -1218,6 +1218,14 @@ fotoramaVersion = '4.6.4';
}
function stubEvent($el, eventType) {
+ var isIOS = /ip(ad|hone|od)/i.test(window.navigator.userAgent);
+
+ if (isIOS && eventType === 'touchend') {
+ $el.on('touchend', function(e){
+ $DOCUMENT.trigger('mouseup', e);
+ })
+ }
+
$el.on(eventType, function (e) {
stopEvent(e, true);
@@ -1447,16 +1455,22 @@ fotoramaVersion = '4.6.4';
}
} else {
stopEvent(e);
- (options.onMove || noop).call(el, e, {touch: touchFLAG});
+ if (movedEnough(xDiff,yDiff)) {
+ (options.onMove || noop).call(el, e, {touch: touchFLAG});
+ }
}
- if (!moved && Math.sqrt(Math.pow(xDiff, 2) + Math.pow(yDiff, 2)) > tolerance) {
+ if (!moved && movedEnough(xDiff, yDiff) && Math.sqrt(Math.pow(xDiff, 2) + Math.pow(yDiff, 2)) > tolerance) {
moved = true;
}
tail.checked = tail.checked || xWin || yWin;
}
+ function movedEnough(xDiff, yDiff) {
+ return xDiff > yDiff && xDiff > 1.5;
+ }
+
function onEnd(e) {
(options.onTouchEnd || noop)();
diff --git a/lib/web/fotorama/fotorama.min.js b/lib/web/fotorama/fotorama.min.js
index 0139babea4bfe..1f9358e04696f 100644
--- a/lib/web/fotorama/fotorama.min.js
+++ b/lib/web/fotorama/fotorama.min.js
@@ -1,5 +1 @@
-/*!
- * Fotorama 4.6.4 | http://fotorama.io/license/
- */
-fotoramaVersion="4.6.4",function(a,b,c,d,e){"use strict";function Ba(a){var b="bez_"+d.makeArray(arguments).join("_").replace(".","p");if("function"!=typeof d.easing[b]){var c=function(a,b){var c=[null,null],d=[null,null],e=[null,null],f=function(f,g){return e[g]=3*a[g],d[g]=3*(b[g]-a[g])-e[g],c[g]=1-e[g]-d[g],f*(e[g]+f*(d[g]+f*c[g]))},g=function(a){return e[0]+a*(2*d[0]+3*c[0]*a)},h=function(a){for(var d,b=a,c=0;++c<14&&(d=f(b,0)-a,!(Math.abs(d)<.001));)b-=d/g(b);return b};return function(a){return f(h(a),1)}};d.easing[b]=function(b,d,e,f,g){return f*c([a[0],a[1]],[a[2],a[3]])(d/g)+e}}return b}function eb(){}function fb(a,b,c){return Math.max(isNaN(b)?-(1/0):b,Math.min(isNaN(c)?1/0:c,a))}function gb(a,b){return a.match(/ma/)&&a.match(/-?\d+(?!d)/g)[a.match(/3d/)?"vertical"===b?13:12:"vertical"===b?5:4]}function hb(a,b){return Ia?+gb(a.css("transform"),b):+a.css("vertical"===b?"top":"left").replace("px","")}function ib(a,b){var c={};if(Ia)switch(b){case"vertical":c.transform="translate3d(0, "+a+"px,0)";break;case"list":break;default:c.transform="translate3d("+a+"px,0,0)"}else"vertical"===b?c.top=a:c.left=a;return c}function jb(a){return{"transition-duration":a+"ms"}}function kb(a,b){return isNaN(a)?b:a}function lb(a,b){return kb(+String(a).replace(b||"px",""))}function mb(a){return/%$/.test(a)?lb(a,"%"):e}function nb(a,b){return kb(mb(a)/100*b,lb(a))}function ob(a){return(!isNaN(lb(a))||!isNaN(lb(a,"%")))&&a}function pb(a,b,c,d){return(a-(d||0))*(b+(c||0))}function qb(a,b,c,d){return-Math.round(a/(b+(c||0))-(d||0))}function rb(a){var b=a.data();if(!b.tEnd){var c=a[0],d={WebkitTransition:"webkitTransitionEnd",MozTransition:"transitionend",OTransition:"oTransitionEnd otransitionend",msTransition:"MSTransitionEnd",transition:"transitionend"};Rb(c,d[wa.prefixed("transition")],function(a){b.tProp&&a.propertyName.match(b.tProp)&&b.onEndFn()}),b.tEnd=!0}}function sb(a,b,c,d){var e,f=a.data();f&&(f.onEndFn=function(){e||(e=!0,clearTimeout(f.tT),c())},f.tProp=b,clearTimeout(f.tT),f.tT=setTimeout(function(){f.onEndFn()},1.5*d),rb(a))}function tb(a,b){var c=a.navdir||"horizontal";if(a.length){var d=a.data();Ia?(a.css(jb(0)),d.onEndFn=eb,clearTimeout(d.tT)):a.stop();var e=ub(b,function(){return hb(a,c)});return a.css(ib(e,c)),e}}function ub(){for(var a,b=0,c=arguments.length;b=c?"bottom":"top bottom":a<=b?"left":a>=c?"right":"left right")}function Ib(a,b,c){c=c||{},a.each(function(){var f,a=d(this),e=a.data();e.clickOn||(e.clickOn=!0,d.extend(hc(a,{onStart:function(a){f=a,(c.onStart||eb).call(this,a)},onMove:c.onMove||eb,onTouchEnd:c.onTouchEnd||eb,onEnd:function(a){a.moved||b.call(this,f)}}),{noMove:!0}))})}function Jb(a,b){return''+(b||"")+"
"}function Kb(a){return"."+a}function Lb(a){var b='';return b}function Mb(a){for(var b=a.length;b;){var c=Math.floor(Math.random()*b--),d=a[b];a[b]=a[c],a[c]=d}return a}function Nb(a){return"[object Array]"==Object.prototype.toString.call(a)&&d.map(a,function(a){return d.extend({},a)})}function Ob(a,b,c){a.scrollLeft(b||0).scrollTop(c||0)}function Pb(a){if(a){var b={};return d.each(a,function(a,c){b[a.toLowerCase()]=c}),b}}function Qb(a){if(a){var b=+a;return isNaN(b)?(b=a.split("/"),+b[0]/+b[1]||e):b}}function Rb(a,b,c,d){b&&(a.addEventListener?a.addEventListener(b,c,!!d):a.attachEvent("on"+b,c))}function Sb(a,b){return a>b.max?a=b.max:a=j-d?"horizontal"===g?-e.position().left:-e.position().top:(i+a.margin)*c<=Math.abs(d)?"horizontal"===g?-e.position().left+j-(i+a.margin):-e.position().top+j-(i+a.margin):d,h=Sb(h,b),h||0}function Ub(a){return!!a.getAttribute("disabled")}function Vb(a,b){return b?{disabled:a}:{tabindex:a*-1+"",disabled:a}}function Wb(a,b){Rb(a,"keyup",function(c){Ub(a)||13==c.keyCode&&b.call(a,c)})}function Xb(a,b){Rb(a,"focus",a.onfocusin=function(c){b.call(a,c)},!0)}function Yb(a,b){a.preventDefault?a.preventDefault():a.returnValue=!1,b&&a.stopPropagation&&a.stopPropagation()}function Zb(a){return a?">":"<"}function _b(a,b){var c=a.data(),e=Math.round(b.pos),f=function(){c&&c.sliding&&(c.sliding=!1),(b.onEnd||eb)()};"undefined"!=typeof b.overPos&&b.overPos!==b.pos&&(e=b.overPos);var g=d.extend(ib(e,b.direction),b.width&&{width:b.width},b.height&&{height:b.height});c&&c.sliding&&(c.sliding=!0),Ia?(a.css(d.extend(jb(b.time),g)),b.time>10?sb(a,"transform",f,b.time):f()):a.stop().animate(g,b.time,_a,f)}function ac(a,b,c,e,f,g){var h="undefined"!=typeof g;if(h||(f.push(arguments),Array.prototype.push.call(arguments,f.length),!(f.length>1))){a=a||d(a),b=b||d(b);var i=a[0],j=b[0],k="crossfade"===e.method,l=function(){if(!l.done){l.done=!0;var a=(h||f.shift())&&f.shift();a&&ac.apply(this,a),(e.onEnd||eb)(!!a)}},m=e.time/(g||1);c.removeClass(P+" "+O),a.stop().addClass(P),b.stop().addClass(O),k&&j&&a.fadeTo(0,0),a.fadeTo(k?m:0,1,k&&l),b.fadeTo(m,0,l),i&&k||j||l()}}function gc(a){var b=(a.touches||[])[0]||a;a._x=b.pageX||b.originalEvent.pageX,a._y=b.clientY||b.originalEvent.clientY,a._now=d.now()}function hc(a,c){function p(a){return i=d(a.target),f.checked=l=m=o=!1,g||f.flow||a.touches&&a.touches.length>1||a.which>1||bc&&bc.type!==a.type&&dc||(l=c.select&&i.is(c.select,e))?l:(k="touchstart"===a.type,m=i.is("a, a *",e),j=f.control,n=f.noMove||f.noSwipe||j?16:f.snap?0:4,gc(a),h=bc=a,cc=a.type.replace(/down|start/,"move").replace(/Down/,"Move"),(c.onStart||eb).call(e,a,{control:j,$target:i}),g=f.flow=!0,void(k&&!f.go||Yb(a)))}function q(a){if(a.touches&&a.touches.length>1||Na&&!a.isPrimary||cc!==a.type||!g)return g&&r(),void(c.onTouchEnd||eb)();gc(a);var b=Math.abs(a._x-h._x),d=Math.abs(a._y-h._y),i=b-d,j=(f.go||f.x||i>=0)&&!f.noSwipe,l=i<0;k&&!f.checked?(g=j)&&Yb(a):(Yb(a),(c.onMove||eb).call(e,a,{touch:k})),!o&&Math.sqrt(Math.pow(b,2)+Math.pow(d,2))>n&&(o=!0),f.checked=f.checked||j||l}function r(a){(c.onTouchEnd||eb)();var b=g;f.control=g=!1,b&&(f.flow=!1),!b||m&&!f.checked||(a&&Yb(a),dc=!0,clearTimeout(ec),ec=setTimeout(function(){dc=!1},1e3),(c.onEnd||eb).call(e,{moved:o,$target:i,control:j,touch:k,startEvent:h,aborted:!a||"MSPointerCancel"===a.type}))}function s(){f.flow||(f.flow=!0)}function t(){f.flow&&(f.flow=!1)}var g,h,i,j,k,l,m,n,o,e=a[0],f={};return Na?(Rb(e,"MSPointerDown",p),Rb(b,"MSPointerMove",q),Rb(b,"MSPointerCancel",r),Rb(b,"MSPointerUp",r)):(Rb(e,"touchstart",p),Rb(e,"touchmove",q),Rb(e,"touchend",r),Rb(b,"touchstart",s),Rb(b,"touchend",t),Rb(b,"touchcancel",t),Ca.on("scroll",t),a.on("mousedown pointerdown",p),Da.on("mousemove pointermove",q).on("mouseup pointerup",r)),fc=wa.touch?"a":"div",a.on("click",fc,function(a){f.checked&&Yb(a)}),f}function ic(a,b){function w(d,e){v=!0,g=h="vertical"===r?d._y:d._x,m=d._now,l=[[m,g]],i=j=f.noMove||e?0:tb(a,(b.getPos||eb)()),(b.onStart||eb).call(c,d)}function x(b,c){o=f.min,p=f.max,q=f.snap,r=f.direction||"horizontal",a.navdir=r,s=b.altKey,v=u=!1,t=c.control,t||e.sliding||w(b)}function y(d,e){f.noSwipe||(v||w(d),h="vertical"===r?d._y:d._x,l.push([d._now,h]),j=i-(g-h),k=Hb(j,o,p,r),j<=o?j=vb(j,o):j>=p&&(j=vb(j,p)),f.noMove||(a.css(ib(j,r)),u||(u=!0,e.touch||Na||a.addClass(ea)),(b.onMove||eb).call(c,d,{pos:j,edge:k})))}function z(e){if(!f.noSwipe||!e.moved){v||w(e.startEvent,!0),e.touch||Na||a.removeClass(ea),n=d.now();for(var k,m,t,x,y,z,A,B,D,g=n-Pa,u=null,C=Qa,E=b.friction,F=l.length-1;F>=0;F--){if(k=l[F][0],m=Math.abs(k-g),null===u||mt)break;t=m}A=fb(j,o,p);var G=x-h,H=G>=0,I=n-u,J=I>Pa,K=!J&&j!==i&&A===j;q&&(A=fb(Math[K?H?"floor":"ceil":"round"](j/q)*q,o,p),o=p=A),K&&(q||A===j)&&(D=-(G/I),C*=fb(Math.abs(D),b.timeLow,b.timeHigh),y=Math.round(j+D*C/E),q||(A=y),(!H&&y>p||H&&y',a,""].join(""),l.id=g,(m?l:n).innerHTML+=h,n.appendChild(l),m||(n.style.background="",n.style.overflow="hidden",k=f.style.overflow,f.style.overflow="hidden",f.appendChild(n)),i=c(l,a),m?l.parentNode.removeChild(l):(n.parentNode.removeChild(n),f.style.overflow=k),!!i},w={}.hasOwnProperty;x=A(w,"undefined")||A(w.call,"undefined")?function(a,b){return b in a&&A(a.constructor.prototype[b],"undefined")}:function(a,b){return w.call(a,b)},Function.prototype.bind||(Function.prototype.bind=function(b){var c=this;if("function"!=typeof c)throw new TypeError;var d=t.call(arguments,1),e=function(){if(this instanceof e){var a=function(){};a.prototype=c.prototype;var f=new a,g=c.apply(f,d.concat(t.call(arguments)));return Object(g)===g?g:f}return c.apply(b,d.concat(t.call(arguments)))};return e}),p.touch=function(){var c;return"ontouchstart"in a||a.DocumentTouch&&b instanceof DocumentTouch?c=!0:v(["@media (",l.join("touch-enabled),("),g,")","{#modernizr{top:9px;position:absolute}}"].join(""),function(a){c=9===a.offsetTop}),c},p.csstransforms3d=function(){var a=!!E("perspective");return a&&"webkitPerspective"in f.style&&v("@media (transform-3d),(-webkit-transform-3d){#modernizr{left:9px;position:absolute;height:3px;}}",function(b,c){a=9===b.offsetLeft&&3===b.offsetHeight}),a},p.csstransitions=function(){return E("transition")};for(var F in p)x(p,F)&&(u=F.toLowerCase(),e[u]=p[F](),s.push((e[u]?"":"no-")+u));return e.addTest=function(a,b){if("object"==typeof a)for(var d in a)x(a,d)&&e.addTest(d,a[d]);else{if(a=a.toLowerCase(),e[a]!==c)return e;b="function"==typeof b?b():b,"undefined"!=typeof enableClasses&&enableClasses&&(f.className+=" "+(b?"":"no-")+a),e[a]=b}return e},y(""),h=j=null,e._version=d,e._prefixes=l,e._domPrefixes=o,e._cssomPrefixes=n,e.testProp=function(a){return C([a])},e.testAllProps=E,e.testStyles=v,e.prefixed=function(a,b,c){return b?E(a,b,c):E(a,"pfx")},e}(a,b),xa={ok:!1,is:function(){return!1},request:function(){},cancel:function(){},event:"",prefix:""},ya="webkit moz o ms khtml".split(" ");if("undefined"!=typeof b.cancelFullScreen)xa.ok=!0;else for(var za=0,Aa=ya.length;za"):36===a.keyCode&&Zc("home")?(N.longPress.progress(),c="<<"):35===a.keyCode&&Zc("end")&&(N.longPress.progress(),c=">>")),(b||c)&&Yb(a),j={index:c,slow:a.altKey,user:!0},c&&(N.longPress.inProgress?N.showWhileLongPress(j):N.show(j))}),a&&Da.on(h,function(a){N.longPress.inProgress&&N.showEndLongPress({user:!0}),N.longPress.reset()}),N.index||Da.off(b).on(b,"textarea, input, select",function(a){!Fa.hasClass(g)&&a.stopPropagation()}),Ca.on(i,N.resize)):(Da.off(e),Ca.off(i))}function ad(a){a!==ad.f&&(a?(c.addClass(f+" "+P).before(va).before(ua),lc(N)):(va.detach(),ua.detach(),c.html(qa.urtext).removeClass(P),mc(N)),_c(a),ad.f=a)}function bd(){ea=N.data=ea||Nb(r.data)||Bb(c),ra=N.size=ea.length,ee.ok&&r.shuffle&&Mb(ea),Yc(),cc=id(cc),ra&&ad(!0)}function cd(){var a=ra<2||bc;Hc.noMove=a||wc,Hc.noSwipe=a||!r.swipe,!Ac&&Aa.toggleClass(y,!r.click&&!Hc.noMove&&!Hc.noSwipe),Na&&wa.toggleClass(p,!Hc.noSwipe)}function dd(a){a===!0&&(a=""),r.autoplay=Math.max(+a||Sa,1.5*zc)}function ed(a){a.navarrows&&"thumbs"===a.nav?(rb.show(),sb.show()):(rb.hide(),sb.hide())}function fd(a,b){return Math.floor(wa.width()/(b.thumbwidth+b.thumbmargin))}function gd(){function b(b,c){a[b?"add":"remove"].push(c)}r.nav&&"dots"!==r.nav||(r.navdir="horizontal"),N.options=r=Pb(r),bb=fd(wa,r),wc="crossfade"===r.transition||"dissolve"===r.transition,qc=r.loop&&(ra>2||wc&&(!Ac||"slide"!==Ac)),zc=+r.transitionduration||Qa,Cc="rtl"===r.direction,Dc=d.extend({},r.keyboard&&db,r.keyboard),ed(r);var a={add:[],remove:[]};ra>1?(rc=r.nav,tc="top"===r.navposition,a.remove.push(X),La.toggle(r.arrows)):(rc=!1,La.hide()),Ad(),Cd(),Bd(),r.autoplay&&dd(r.autoplay),xc=lb(r.thumbwidth)||Ua,yc=lb(r.thumbheight)||Ua,Ic.ok=Kc.ok=r.trackpad&&!Ma,cd(),Kd(r,[Fc]),sc="thumbs"===rc,Oa.filter(":hidden")&&rc&&Oa.show(),sc?(td(ra,"navThumb"),_a=eb,Vc=Za,Gb(ua,d.Fotorama.jst.style({w:xc,h:yc,b:r.thumbborderwidth,m:r.thumbmargin,s:O,q:!Ja})),Ra.addClass(L).removeClass(K)):"dots"===rc?(td(ra,"navDot"),_a=cb,Vc=Ya,Ra.addClass(K).removeClass(L)):(Oa.hide(),rc=!1,Ra.removeClass(L+" "+K)),rc&&(tc?Oa.insertBefore(ya):Oa.insertAfter(ya),xd.nav=!1,xd(_a,Ta,"nav")),uc=r.allowfullscreen,uc?(vb.prependTo(ya),vc=Ka&&"native"===uc):(vb.detach(),vc=!1),b(wc,l),b(!wc,m),b(!r.captions,s),b(Cc,q),b(r.arrows,t),Bc=r.shadows&&!Ma,b(!Bc,o),wa.addClass(a.add.join(" ")).removeClass(a.remove.join(" ")),Ec=d.extend({},r),$c()}function hd(a){return a<0?(ra+a%ra)%ra:a>=ra?a%ra:a}function id(a){return fb(a,0,ra-1)}function jd(a){return qc?hd(a):id(a)}function kd(a){return!!(a>0||qc)&&a-1}function ld(a){return!!(a1&&ea[f]===g)||g.html||g.deleted||g.video||k||(g.deleted=!0,N.splice(f,1))):(g[o]=p=q,j.$full=null,qd([f],b,c,!0))}function u(){d.Fotorama.measures[p]=n.measures=d.Fotorama.measures[p]||{width:l.width,height:l.height,ratio:l.width/l.height},pd(n.measures.width,n.measures.height,n.measures.ratio,f),m.off("load error").addClass(""+(k?ga:fa)).attr("aria-hidden","false").prependTo(h),h.hasClass(v)&&!h.hasClass(ma)&&h.attr("href",m.attr("src")),Fb(m,(d.isFunction(c)?c():c)||Fc),d.Fotorama.cache[p]=j.state="loaded",setTimeout(function(){h.trigger("f:load").removeClass(aa+" "+_).addClass(ba+" "+(k?ca:da)),"stage"===b?s("load"):(g.thumbratio===$a||!g.thumbratio&&r.thumbratio===$a)&&(g.thumbratio=n.measures.ratio,ce())},0)}function w(){var a=10;Eb(function(){return!Tc||!a--&&!Ma},function(){u()})}if(h){var k=N.fullScreen&&!j.$full&&"stage"===b;if(!j.$img||e||k){var l=new Image,m=d(l),n=m.data();j[k?"$full":"$img"]=m;var o="stage"===b?k?"full":"img":"thumb",p=g[o],q=k?g.img:g["stage"===b?"thumb":"img"];if("navThumb"===b&&(h=j.$wrap),!p)return void t();d.Fotorama.cache[p]?!function a(){"error"===d.Fotorama.cache[p]?t():"loaded"===d.Fotorama.cache[p]?setTimeout(w,0):setTimeout(a,100)}():(d.Fotorama.cache[p]="*",m.on("load",w).on("error",t)),j.state="",l.src=p,j.data.caption&&(l.alt=j.data.caption||""),j.data.full&&d(l).data("original",j.data.full),$b.isExpectedCaption(g,r.showcaption)&&d(l).attr("aria-labelledby",g.labelledby)}}})}function rd(){var a=dc[Xa];a&&!a.data().state&&(Ub.addClass(ta),a.on("f:load f:error",function(){a.off("f:load f:error"),Ub.removeClass(ta)}))}function sd(a){Wb(a,_d),Xb(a,function(){setTimeout(function(){Ob(Ra)},0),Fd({time:zc,guessIndex:d(this).data().eq,minMax:Jc})})}function td(a,b){od(a,b,function(a,c,e,f,g,h){if(!f){f=e[g]=wa[g].clone(),h=f.data(),h.data=e;var i=f[0],j="labelledby"+d.now();"stage"===b?(e.html&&d('').append(e._html?d(e.html).removeAttr("id").html(e._html):e.html).appendTo(f),e.id&&(j=e.id||j),e.labelledby=j,$b.isExpectedCaption(e,r.showcaption)&&d(d.Fotorama.jst.frameCaption({caption:e.caption,labelledby:j})).appendTo(f),e.video&&f.addClass(w).append(xb.clone()),Xb(i,function(){setTimeout(function(){Ob(ya)},0),Yd({index:h.eq,user:!0})}),Ba=Ba.add(f)):"navDot"===b?(sd(i),cb=cb.add(f)):"navThumb"===b&&(sd(i),h.$wrap=f.children(":first"),eb=eb.add(f),e.video&&h.$wrap.append(xb.clone()))}})}function ud(a,b){return a&&a.length&&Fb(a,b)}function vd(a){od(a,"stage",function(a,b,c,e,f,g){if(e){var h=hd(b);g.eq=h,Rc[Xa][h]=e.css(d.extend({left:wc?0:pb(b,Fc.w,r.margin,fc)},wc&&jb(0))),Db(e[0])&&(e.appendTo(Aa),Vd(c.$video)),ud(g.$img,Fc),ud(g.$full,Fc),!e.hasClass(v)||"false"===e.attr("aria-hidden")&&e.hasClass(W)||e.attr("aria-hidden","true")}})}function wd(a,b){var c,e;"thumbs"!==rc||isNaN(a)||(c=-a,e=-a+Fc.nw,"vertical"===r.navdir&&(a-=r.thumbheight,e=-a+Fc.h),eb.each(function(){var a=d(this),f=a.data(),g=f.eq,h=function(){return{h:yc,w:f.w}},i=h(),j="vertical"===r.navdir?f.t>e:f.l>e;i.w=f.w,f.l+f.wFc.w/3}function zd(a){return!(qc||cc+a&&cc-ra+a||bc)}function Ad(){var a=zd(0),b=zd(1);Ga.toggleClass(B,a).attr(Vb(a,!1)),Ha.toggleClass(B,b).attr(Vb(b,!1))}function Bd(){var a=!1,b=!1;if("thumbs"!==r.navtype||r.loop||(a=0==cc,b=cc==r.data.length-1),"slides"===r.navtype){var c=hb(Ta,r.navdir);a=c>=Jc.max,b=c<=Jc.min}rb.toggleClass(B,a).attr(Vb(a,!0)),sb.toggleClass(B,b).attr(Vb(b,!0))}function Cd(){Ic.ok&&(Ic.prevent={"<":zd(0),">":zd(1)})}function Dd(a){var c,d,e,f,b=a.data();sc?(c=b.l,d=b.t,e=b.w,f=b.h):(c=a.position().left,e=a.width());var g={c:c+e/2,min:-c+10*r.thumbmargin,max:-c+Fc.w-e-10*r.thumbmargin},h={c:d+f/2,min:-d+10*r.thumbmargin,max:-d+Fc.h-f-10*r.thumbmargin};return"vertical"===r.navdir?h:g}function Ed(a){var b=dc[Vc].data();_b(mb,{time:1.2*a,pos:"vertical"===r.navdir?b.t:b.l,width:b.w,height:b.h,direction:r.navdir})}function Fd(a){var d,e,f,g,h,i,j,k,b=ea[a.guessIndex][Vc],c=r.navtype;b&&("thumbs"===c?(d=Jc.min!==Jc.max,f=a.minMax||d&&Dd(dc[Vc]),g=d&&(a.keep&&Fd.t?Fd.l:fb((a.coo||Fc.nw/2)-Dd(b).c,f.min,f.max)),h=d&&(a.keep&&Fd.l?Fd.l:fb((a.coo||Fc.nw/2)-Dd(b).c,f.min,f.max)),i="vertical"===r.navdir?g:h,j=d&&fb(i,Jc.min,Jc.max)||0,e=1.1*a.time,_b(Ta,{time:e,pos:j,direction:r.navdir,onEnd:function(){wd(j,!0),Bd()}}),Ud(Ra,Hb(j,Jc.min,Jc.max,r.navdir)),Fd.l=i):(k=hb(Ta,r.navdir),e=1.11*a.time,j=Tb(r,Jc,a.guessIndex,k,b,Oa,r.navdir),_b(Ta,{time:e,pos:j,direction:r.navdir,onEnd:function(){wd(j,!0),Bd()}}),Ud(Ra,Hb(j,Jc.min,Jc.max,r.navdir))))}function Gd(){Hd(Vc),Qc[Vc].push(dc[Vc].addClass(W).attr("data-active",!0))}function Hd(a){for(var b=Qc[a];b.length;)b.shift().removeClass(W).attr("data-active",!1)}function Id(a){var b=Rc[a];d.each(ec,function(a,c){delete b[hd(c)]}),d.each(b,function(a,c){delete b[a],c.detach()})}function Jd(a){fc=gc=cc;var b=dc[Xa];b&&(Hd(Xa),Qc[Xa].push(b.addClass(W).attr("data-active",!0)),b.hasClass(v)&&b.attr("aria-hidden","false"),a||N.showStage.onEnd(!0),tb(Aa,0,!0),Id(Xa),vd(ec),md(),nd(),Wb(Aa[0],function(){c.hasClass(Z)||(N.requestFullScreen(),vb.focus())}))}function Kd(a,b){a&&d.each(b,function(b,c){c&&d.extend(c,{width:a.width||c.width,height:a.height,minwidth:a.minwidth,maxwidth:a.maxwidth,minheight:a.minheight,maxheight:a.maxheight,ratio:Qb(a.ratio)})})}function Ld(a,b){c.trigger(f+":"+a,[N,b])}function Md(){clearTimeout(Nd.t),Tc=1,r.stopautoplayontouch?N.stopAutoplay():Oc=!0}function Nd(){Tc&&(r.stopautoplayontouch||(Od(),Pd()),Nd.t=setTimeout(function(){Tc=0},Qa+Pa))}function Od(){Oc=!(!bc&&!Pc)}function Pd(){if(clearTimeout(Pd.t),Eb.stop(Pd.w),!r.autoplay||Oc)return void(N.autoplay&&(N.autoplay=!1,Ld("stopautoplay")));N.autoplay||(N.autoplay=!0,Ld("startautoplay"));var a=cc,b=dc[Xa].data();Pd.w=Eb(function(){return b.state||a!==cc},function(){Pd.t=setTimeout(function(){if(!Oc&&a===cc){var b=oc,c=ea[b][Xa].data();Pd.w=Eb(function(){return c.state||b!==oc},function(){Oc||b!==oc||N.show(qc?Zb(!Cc):oc)})}},r.autoplay)})}function Qd(a){var b;return"object"!=typeof a?(b=a,a={}):b=a.index,b=">"===b?gc+1:"<"===b?gc-1:"<<"===b?0:">>"===b?ra-1:b,b=isNaN(b)?e:b,b="undefined"==typeof b?cc||0:b}function Rd(a){N.activeIndex=cc=jd(a),kc=kd(cc),nc=ld(cc),oc=hd(cc+(Cc?-1:1)),ec=[cc,kc,nc],gc=qc?a:cc}function Sd(a){var b=Math.abs(hc-gc),c=ub(a.time,function(){return Math.min(zc*(1+(b-1)/12),2*zc)});return a.slow&&(c*=10),c}function Td(){N.fullScreen&&(N.fullScreen=!1,Ka&&xa.cancel(Q),Fa.removeClass(g),Ea.removeClass(g),c.removeClass(Z).insertAfter(va),Fc=d.extend({},Sc),Vd(bc,!0,!0),$d("x",!1),N.resize(),qd(ec,"stage"),Ob(Ca,Mc,Lc),Ld("fullscreenexit"))}function Ud(a,b){Bc&&(a.removeClass(S+" "+T),a.removeClass(U+" "+V),b&&!bc&&a.addClass(b.replace(/^|\s/g," "+R+"--")))}function Vd(a,b,c){b&&(wa.removeClass(k),bc=!1,cd()),a&&a!==bc&&(a.remove(),Ld("unloadvideo")),c&&(Od(),Pd())}function Wd(a){wa.toggleClass(n,a)}function Xd(a){if(!Hc.flow){var b=a?a.pageX:Xd.x,c=b&&!zd(yd(b))&&r.click;Xd.p!==c&&ya.toggleClass(z,c)&&(Xd.p=c,Xd.x=b)}}function Yd(a){clearTimeout(Yd.t),r.clicktransition&&r.clicktransition!==r.transition?setTimeout(function(){var b=r.transition;N.setOptions({transition:r.clicktransition}),Ac=b,Yd.t=setTimeout(function(){N.show(a)},10)},0):N.show(a)}function Zd(a,b){var e=a.target,f=d(e);f.hasClass(oa)?N.playVideo():e===wb?N.toggleFullScreen():bc?e===Rb&&Vd(bc,!0,!0):c.hasClass(Z)||N.requestFullScreen()}function $d(a,b){Hc[a]=Jc[a]=b}function _d(a){var b=d(this).data().eq;Yd("thumbs"===r.navtype?{index:b,slow:a.altKey,user:!0,coo:a._x-Ra.offset().left}:{index:b,slow:a.altKey,user:!0})}function ae(a){Yd({index:La.index(this)?">":"<",slow:a.altKey,user:!0})}function be(a){Xb(a,function(){setTimeout(function(){Ob(ya)},0),Wd(!1)})}function ce(){if(bd(),gd(),!ce.i){ce.i=!0;var a=r.startindex;cc=fc=gc=hc=pc=jd(a)||0}if(ra){if(de())return;bc&&Vd(bc,!0),ec=[],Id(Xa),ce.ok=!0,N.show({index:cc,time:0}),N.resize()}else N.destroy()}function de(){if(!de.f===Cc)return de.f=Cc,cc=ra-1-cc,N.reverse(),!0}function ee(){ee.ok&&(ee.ok=!1,Ld("ready"))}Ea=d("html"),Fa=d("body");var ea,ra,_a,bc,dc,ec,fc,gc,hc,kc,nc,oc,pc,qc,rc,sc,tc,uc,vc,wc,xc,yc,zc,Ac,Bc,Cc,Dc,Gc,Lc,Mc,Nc,Oc,Pc,Sc,Tc,Uc,Vc,N=this,O=d.now(),P=f+O,Q=c[0],ha=1,qa=c.data(),ua=d(""),va=d(Jb(Y)),wa=c.find(Kb(h)),ya=wa.find(Kb(u)),Aa=(ya[0],c.find(Kb(x))),Ba=d(),Ga=c.find(Kb(C)),Ha=c.find(Kb(D)),La=c.find(Kb(A)),Oa=c.find(Kb(F)),Ra=Oa.find(Kb(E)),Ta=Ra.find(Kb(G)),cb=d(),eb=d(),mb=(Aa.data(),Ta.data(),c.find(Kb(ka))),rb=c.find(Kb(ia)),sb=c.find(Kb(ja)),vb=c.find(Kb($)),wb=vb[0],xb=d(Jb(oa)),Cb=c.find(Kb(pa)),Rb=Cb[0],Ub=c.find(Kb(sa)),cc=!1,Ec={},Fc={},Hc={},Ic={},Jc={},Kc={},Qc={},Rc={},Wc=0,Xc=[];wa[Xa]=d(''),wa[Za]=d(d.Fotorama.jst.thumb()),wa[Ya]=d(d.Fotorama.jst.dots()),
- Qc[Xa]=[],Qc[Za]=[],Qc[Ya]=[],Rc[Xa]={},wa.addClass(Ia?j:i),qa.fotorama=this,N.startAutoplay=function(a){return N.autoplay?this:(Oc=Pc=!1,dd(a||r.autoplay),Pd(),this)},N.stopAutoplay=function(){return N.autoplay&&(Oc=Pc=!0,Pd()),this},N.showSlide=function(a){var c,b=hb(Ta,r.navdir),d=550,e="horizontal"===r.navdir?r.thumbwidth:r.thumbheight,f=function(){Bd()};"next"===a&&(c=b-(e+r.margin)*bb),"prev"===a&&(c=b+(e+r.margin)*bb),c=Sb(c,Jc),wd(c,!0),_b(Ta,{time:d,pos:c,direction:r.navdir,onEnd:f})},N.showWhileLongPress=function(a){if(!N.longPress.singlePressInProgress){var b=Qd(a);Rd(b);var c=Sd(a)/50,d=dc;N.activeFrame=dc=ea[cc];var e=d===dc&&!a.user;return N.showNav(e,a,c),this}},N.showEndLongPress=function(a){if(!N.longPress.singlePressInProgress){var b=Qd(a);Rd(b);var c=Sd(a)/50,d=dc;N.activeFrame=dc=ea[cc];var e=d===dc&&!a.user;return N.showStage(e,a,c),Nc="undefined"!=typeof hc&&hc!==cc,hc=cc,this}},N.showStage=function(a,b,c){Vd(bc,dc.i!==ea[hd(fc)].i),td(ec,"stage"),vd(Ma?[gc]:[gc,kd(gc),ld(gc)]),$d("go",!0),a||Ld("show",{user:b.user,time:c}),Oc=!0;var d=b.overPos,e=N.showStage.onEnd=function(c){if(!e.ok){if(e.ok=!0,c||Jd(!0),a||Ld("showend",{user:b.user}),!c&&Ac&&Ac!==r.transition)return N.setOptions({transition:Ac}),void(Ac=!1);rd(),qd(ec,"stage"),$d("go",!1),Cd(),Xd(),Od(),Pd(),N.fullScreen?(dc[Xa].find("."+ga).attr("aria-hidden",!1),dc[Xa].find("."+fa).attr("aria-hidden",!0)):(dc[Xa].find("."+ga).attr("aria-hidden",!0),dc[Xa].find("."+fa).attr("aria-hidden",!1))}};if(wc){var f=dc[Xa],g=ea[hc]&&cc!==hc?ea[hc][Xa]:null;ac(f,g,Ba,{time:c,method:r.transition,onEnd:e},Xc)}else _b(Aa,{pos:-pb(gc,Fc.w,r.margin,fc),overPos:d,time:c,onEnd:e});Ad()},N.showNav=function(a,b,c){if(Bd(),rc){Gd();var d=id(cc+fb(gc-hc,-1,1));Fd({time:c,coo:d!==cc&&b.coo,guessIndex:"undefined"!=typeof b.coo?d:cc,keep:a}),sc&&Ed(c)}},N.show=function(a){N.longPress.singlePressInProgress=!0;var b=Qd(a);Rd(b);var c=Sd(a),d=dc;N.activeFrame=dc=ea[cc];var e=d===dc&&!a.user;return N.showStage(e,a,c),N.showNav(e,a,c),Nc="undefined"!=typeof hc&&hc!==cc,hc=cc,N.longPress.singlePressInProgress=!1,this},N.requestFullScreen=function(){if(uc&&!N.fullScreen){var b=d((N.activeFrame||{}).$stageFrame||{}).hasClass("fotorama-video-container");if(b)return;Lc=Ca.scrollTop(),Mc=Ca.scrollLeft(),Ob(Ca),$d("x",!0),Sc=d.extend({},Fc),c.addClass(Z).appendTo(Fa.addClass(g)),Ea.addClass(g),Vd(bc,!0,!0),N.fullScreen=!0,vc&&xa.request(Q),N.resize(),qd(ec,"stage"),rd(),Ld("fullscreenenter"),"ontouchstart"in a||vb.focus()}return this},N.cancelFullScreen=function(){return vc&&xa.is()?xa.cancel(b):Td(),this},N.toggleFullScreen=function(){return N[(N.fullScreen?"cancel":"request")+"FullScreen"]()},N.resize=function(b){if(!ea)return this;var c=arguments[1]||0,e=arguments[2];bb=fd(wa,r),Kd(N.fullScreen?{width:d(a).width(),maxwidth:null,minwidth:null,height:d(a).height(),maxheight:null,minheight:null}:Pb(b),[Fc,e||N.fullScreen||r]);var f=Fc.width,g=Fc.height,h=Fc.ratio,i=Ca.height()-(rc?Ra.height():0);if(ob(f)&&(wa.css({width:""}),wa.css({height:""}),ya.css({width:""}),ya.css({height:""}),Aa.css({width:""}),Aa.css({height:""}),Ra.css({width:""}),Ra.css({height:""}),wa.css({minWidth:Fc.minwidth||0,maxWidth:Fc.maxwidth||ab}),"dots"===rc&&Oa.hide(),f=Fc.W=Fc.w=wa.width(),Fc.nw=rc&&nb(r.navwidth,f)||f,Aa.css({width:Fc.w,marginLeft:(Fc.W-Fc.w)/2}),g=nb(g,i),g=g||h&&f/h)){if(f=Math.round(f),g=Fc.h=Math.round(fb(g,nb(Fc.minheight,i),nb(Fc.maxheight,i))),ya.css({width:f,height:g}),"vertical"!==r.navdir||N.fullscreen||Ra.width(r.thumbwidth+2*r.thumbmargin),"horizontal"!==r.navdir||N.fullscreen||Ra.height(r.thumbheight+2*r.thumbmargin),"dots"===rc&&(Ra.width(f).height("auto"),Oa.show()),"vertical"===r.navdir&&N.fullScreen&&ya.css("height",Ca.height()),"horizontal"===r.navdir&&N.fullScreen&&ya.css("height",Ca.height()-Ra.height()),rc){switch(r.navdir){case"vertical":Oa.removeClass(J),Oa.removeClass(I),Oa.addClass(H),Ra.stop().animate({height:Fc.h,width:r.thumbwidth},c);break;case"list":Oa.removeClass(H),Oa.removeClass(J),Oa.addClass(I);break;default:Oa.removeClass(H),Oa.removeClass(I),Oa.addClass(J),Ra.stop().animate({width:Fc.nw},c)}Jd(),Fd({guessIndex:cc,time:c,keep:!0}),sc&&xd.nav&&Ed(c)}Gc=e||!0,ee.ok=!0,ee()}return Wc=ya.offset().left,$c(),this},N.setOptions=function(a){return d.extend(r,a),ce(),this},N.shuffle=function(){return ea&&Mb(ea)&&ce(),this},N.longPress={threshold:1,count:0,thumbSlideTime:20,progress:function(){this.inProgress||(this.count++,this.inProgress=this.count>this.threshold)},end:function(){this.inProgress&&(this.isEnded=!0)},reset:function(){this.count=0,this.inProgress=!1,this.isEnded=!1}},N.destroy=function(){return N.cancelFullScreen(),N.stopAutoplay(),ea=N.data=null,ad(),ec=[],Id(Xa),ce.ok=!1,this},N.playVideo=function(){var a=dc,b=a.video,c=cc;return"object"==typeof b&&a.videoReady&&(vc&&N.fullScreen&&N.cancelFullScreen(),Eb(function(){return!xa.is()||c!==cc},function(){c===cc&&(a.$video=a.$video||d(Jb(na)).append(Lb(b)),a.$video.appendTo(a[Xa]),wa.addClass(k),bc=a.$video,cd(),La.blur(),vb.blur(),Ld("loadvideo"))})),this},N.stopVideo=function(){return Vd(bc,!0,!0),this},N.spliceByIndex=function(a,b){b.i=a+1,b.img&&d.ajax({url:b.img,type:"HEAD",success:function(){ea.splice(a,1,b),ce()}})},ya.on("mousemove",Xd),Hc=ic(Aa,{onStart:Md,onMove:function(a,b){Ud(ya,b.edge)},onTouchEnd:Nd,onEnd:function(a){var b;if(Ud(ya),b=(Na&&!Uc||a.touch)&&r.arrows,(a.moved||b&&a.pos!==a.newPos&&!a.control)&&a.$target[0]!==vb[0]){var c=qb(a.newPos,Fc.w,r.margin,fc);N.show({index:c,time:wc?zc:a.time,overPos:a.overPos,user:!0})}else a.aborted||a.control||Zd(a.startEvent,b)},timeLow:1,timeHigh:1,friction:2,select:"."+X+", ."+X+" *",$wrap:ya,direction:"horizontal"}),Jc=ic(Ta,{onStart:Md,onMove:function(a,b){Ud(Ra,b.edge)},onTouchEnd:Nd,onEnd:function(a){function b(){Fd.l=a.newPos,Od(),Pd(),wd(a.newPos,!0),Bd()}if(a.moved)a.pos!==a.newPos?(Oc=!0,_b(Ta,{time:a.time,pos:a.newPos,overPos:a.overPos,direction:r.navdir,onEnd:b}),wd(a.newPos),Bc&&Ud(Ra,Hb(a.newPos,Jc.min,Jc.max,a.dir))):b();else{var c=a.$target.closest("."+M,Ta)[0];c&&_d.call(c,a.startEvent)}},timeLow:.5,timeHigh:2,friction:5,$wrap:Ra,direction:r.navdir}),Ic=jc(ya,{shift:!0,onEnd:function(a,b){Md(),Nd(),N.show({index:b,slow:a.altKey})}}),Kc=jc(Ra,{onEnd:function(a,b){Md(),Nd();var c=tb(Ta)+.25*b;Ta.css(ib(fb(c,Jc.min,Jc.max),r.navdir)),Bc&&Ud(Ra,Hb(c,Jc.min,Jc.max,r.navdir)),Kc.prevent={"<":c>=Jc.max,">":c<=Jc.min},clearTimeout(Kc.t),Kc.t=setTimeout(function(){Fd.l=c,wd(c,!0)},Pa),wd(c)}}),wa.hover(function(){setTimeout(function(){Tc||Wd(!(Uc=!0))},0)},function(){Uc&&Wd(!(Uc=!1))}),Ib(La,function(a){Yb(a),ae.call(this,a)},{onStart:function(){Md(),Hc.control=!0},onTouchEnd:Nd}),Ib(rb,function(a){Yb(a),"thumbs"===r.navtype?N.show("<"):N.showSlide("prev")}),Ib(sb,function(a){Yb(a),"thumbs"===r.navtype?N.show(">"):N.showSlide("next")}),La.each(function(){Wb(this,function(a){ae.call(this,a)}),be(this)}),Wb(wb,function(){c.hasClass(Z)?(N.cancelFullScreen(),Aa.focus()):(N.requestFullScreen(),vb.focus())}),be(wb),d.each("load push pop shift unshift reverse sort splice".split(" "),function(a,b){N[b]=function(){return ea=ea||[],"load"!==b?Array.prototype[b].apply(ea,arguments):arguments[0]&&"object"==typeof arguments[0]&&arguments[0].length&&(ea=Nb(arguments[0])),ce(),N}}),ce()},d.fn.fotorama=function(b){return this.each(function(){var c=this,e=d(this),f=e.data(),g=f.fotorama;g?g.setOptions(b,!0):Eb(function(){return!Cb(c)},function(){f.urtext=e.html(),new d.Fotorama(e,d.extend({},cb,a.fotoramaDefaults,b,f))})})},d.Fotorama.instances=[],d.Fotorama.cache={},d.Fotorama.measures={},d=d||{},d.Fotorama=d.Fotorama||{},d.Fotorama.jst=d.Fotorama.jst||{},d.Fotorama.jst.dots=function(a){var c="";va.escape;return c+=''},d.Fotorama.jst.frameCaption=function(a){var b,c="";va.escape;return c+='\r\n
'+(null==(b=a.caption)?"":b)+"
\r\n
\r\n"},d.Fotorama.jst.style=function(a){var b,c="";va.escape;return c+=".fotorama"+(null==(b=a.s)?"":b)+" .fotorama__nav--thumbs .fotorama__nav__frame{\r\npadding:"+(null==(b=a.m)?"":b)+"px;\r\nheight:"+(null==(b=a.h)?"":b)+"px}\r\n.fotorama"+(null==(b=a.s)?"":b)+" .fotorama__thumb-border{\r\nheight:"+(null==(b=a.h)?"":b)+"px;\r\nborder-width:"+(null==(b=a.b)?"":b)+"px;\r\nmargin-top:"+(null==(b=a.m)?"":b)+"px}"},d.Fotorama.jst.thumb=function(a){var c="";va.escape;return c+=''}}(window,document,location,"undefined"!=typeof jQuery&&jQuery);
\ No newline at end of file
+fotoramaVersion="4.6.4";(function(window,document,location,$,undefined){"use strict";var _fotoramaClass="fotorama",_fullscreenClass="fotorama__fullscreen",wrapClass=_fotoramaClass+"__wrap",wrapCss2Class=wrapClass+"--css2",wrapCss3Class=wrapClass+"--css3",wrapVideoClass=wrapClass+"--video",wrapFadeClass=wrapClass+"--fade",wrapSlideClass=wrapClass+"--slide",wrapNoControlsClass=wrapClass+"--no-controls",wrapNoShadowsClass=wrapClass+"--no-shadows",wrapPanYClass=wrapClass+"--pan-y",wrapRtlClass=wrapClass+"--rtl",wrapOnlyActiveClass=wrapClass+"--only-active",wrapNoCaptionsClass=wrapClass+"--no-captions",wrapToggleArrowsClass=wrapClass+"--toggle-arrows",stageClass=_fotoramaClass+"__stage",stageFrameClass=stageClass+"__frame",stageFrameVideoClass=stageFrameClass+"--video",stageShaftClass=stageClass+"__shaft",grabClass=_fotoramaClass+"__grab",pointerClass=_fotoramaClass+"__pointer",arrClass=_fotoramaClass+"__arr",arrDisabledClass=arrClass+"--disabled",arrPrevClass=arrClass+"--prev",arrNextClass=arrClass+"--next",navClass=_fotoramaClass+"__nav",navWrapClass=navClass+"-wrap",navShaftClass=navClass+"__shaft",navShaftVerticalClass=navWrapClass+"--vertical",navShaftListClass=navWrapClass+"--list",navShafthorizontalClass=navWrapClass+"--horizontal",navDotsClass=navClass+"--dots",navThumbsClass=navClass+"--thumbs",navFrameClass=navClass+"__frame",fadeClass=_fotoramaClass+"__fade",fadeFrontClass=fadeClass+"-front",fadeRearClass=fadeClass+"-rear",shadowClass=_fotoramaClass+"__shadow",shadowsClass=shadowClass+"s",shadowsLeftClass=shadowsClass+"--left",shadowsRightClass=shadowsClass+"--right",shadowsTopClass=shadowsClass+"--top",shadowsBottomClass=shadowsClass+"--bottom",activeClass=_fotoramaClass+"__active",selectClass=_fotoramaClass+"__select",hiddenClass=_fotoramaClass+"--hidden",fullscreenClass=_fotoramaClass+"--fullscreen",fullscreenIconClass=_fotoramaClass+"__fullscreen-icon",errorClass=_fotoramaClass+"__error",loadingClass=_fotoramaClass+"__loading",loadedClass=_fotoramaClass+"__loaded",loadedFullClass=loadedClass+"--full",loadedImgClass=loadedClass+"--img",grabbingClass=_fotoramaClass+"__grabbing",imgClass=_fotoramaClass+"__img",imgFullClass=imgClass+"--full",thumbClass=_fotoramaClass+"__thumb",thumbArrLeft=thumbClass+"__arr--left",thumbArrRight=thumbClass+"__arr--right",thumbBorderClass=thumbClass+"-border",htmlClass=_fotoramaClass+"__html",videoContainerClass=_fotoramaClass+"-video-container",videoClass=_fotoramaClass+"__video",videoPlayClass=videoClass+"-play",videoCloseClass=videoClass+"-close",horizontalImageClass=_fotoramaClass+"_horizontal_ratio",verticalImageClass=_fotoramaClass+"_vertical_ratio",fotoramaSpinnerClass=_fotoramaClass+"__spinner",spinnerShowClass=fotoramaSpinnerClass+"--show";var JQUERY_VERSION=$&&$.fn.jquery.split(".");if(!JQUERY_VERSION||JQUERY_VERSION[0]<1||JQUERY_VERSION[0]==1&&JQUERY_VERSION[1]<8){throw"Fotorama requires jQuery 1.8 or later and will not run without it."}var _={};var Modernizr=function(window,document,undefined){var version="2.8.3",Modernizr={},docElement=document.documentElement,mod="modernizr",modElem=document.createElement(mod),mStyle=modElem.style,inputElem,toString={}.toString,prefixes=" -webkit- -moz- -o- -ms- ".split(" "),omPrefixes="Webkit Moz O ms",cssomPrefixes=omPrefixes.split(" "),domPrefixes=omPrefixes.toLowerCase().split(" "),tests={},inputs={},attrs={},classes=[],slice=classes.slice,featureName,injectElementWithStyles=function(rule,callback,nodes,testnames){var style,ret,node,docOverflow,div=document.createElement("div"),body=document.body,fakeBody=body||document.createElement("body");if(parseInt(nodes,10)){while(nodes--){node=document.createElement("div");node.id=testnames?testnames[nodes]:mod+(nodes+1);div.appendChild(node)}}style=["",'"].join("");div.id=mod;(body?div:fakeBody).innerHTML+=style;fakeBody.appendChild(div);if(!body){fakeBody.style.background="";fakeBody.style.overflow="hidden";docOverflow=docElement.style.overflow;docElement.style.overflow="hidden";docElement.appendChild(fakeBody)}ret=callback(div,rule);if(!body){fakeBody.parentNode.removeChild(fakeBody);docElement.style.overflow=docOverflow}else{div.parentNode.removeChild(div)}return!!ret},_hasOwnProperty={}.hasOwnProperty,hasOwnProp;if(!is(_hasOwnProperty,"undefined")&&!is(_hasOwnProperty.call,"undefined")){hasOwnProp=function(object,property){return _hasOwnProperty.call(object,property)}}else{hasOwnProp=function(object,property){return property in object&&is(object.constructor.prototype[property],"undefined")}}if(!Function.prototype.bind){Function.prototype.bind=function bind(that){var target=this;if(typeof target!="function"){throw new TypeError}var args=slice.call(arguments,1),bound=function(){if(this instanceof bound){var F=function(){};F.prototype=target.prototype;var self=new F;var result=target.apply(self,args.concat(slice.call(arguments)));if(Object(result)===result){return result}return self}else{return target.apply(that,args.concat(slice.call(arguments)))}};return bound}}function setCss(str){mStyle.cssText=str}function setCssAll(str1,str2){return setCss(prefixes.join(str1+";")+(str2||""))}function is(obj,type){return typeof obj===type}function contains(str,substr){return!!~(""+str).indexOf(substr)}function testProps(props,prefixed){for(var i in props){var prop=props[i];if(!contains(prop,"-")&&mStyle[prop]!==undefined){return prefixed=="pfx"?prop:true}}return false}function testDOMProps(props,obj,elem){for(var i in props){var item=obj[props[i]];if(item!==undefined){if(elem===false)return props[i];if(is(item,"function")){return item.bind(elem||obj)}return item}}return false}function testPropsAll(prop,prefixed,elem){var ucProp=prop.charAt(0).toUpperCase()+prop.slice(1),props=(prop+" "+cssomPrefixes.join(ucProp+" ")+ucProp).split(" ");if(is(prefixed,"string")||is(prefixed,"undefined")){return testProps(props,prefixed)}else{props=(prop+" "+domPrefixes.join(ucProp+" ")+ucProp).split(" ");return testDOMProps(props,prefixed,elem)}}tests["touch"]=function(){var bool;if("ontouchstart"in window||window.DocumentTouch&&document instanceof DocumentTouch){bool=true}else{injectElementWithStyles(["@media (",prefixes.join("touch-enabled),("),mod,")","{#modernizr{top:9px;position:absolute}}"].join(""),function(node){bool=node.offsetTop===9})}return bool};tests["csstransforms3d"]=function(){var ret=!!testPropsAll("perspective");if(ret&&"webkitPerspective"in docElement.style){injectElementWithStyles("@media (transform-3d),(-webkit-transform-3d){#modernizr{left:9px;position:absolute;height:3px;}}",function(node,rule){ret=node.offsetLeft===9&&node.offsetHeight===3})}return ret};tests["csstransitions"]=function(){return testPropsAll("transition")};for(var feature in tests){if(hasOwnProp(tests,feature)){featureName=feature.toLowerCase();Modernizr[featureName]=tests[feature]();classes.push((Modernizr[featureName]?"":"no-")+featureName)}}Modernizr.addTest=function(feature,test){if(typeof feature=="object"){for(var key in feature){if(hasOwnProp(feature,key)){Modernizr.addTest(key,feature[key])}}}else{feature=feature.toLowerCase();if(Modernizr[feature]!==undefined){return Modernizr}test=typeof test=="function"?test():test;if(typeof enableClasses!=="undefined"&&enableClasses){docElement.className+=" "+(test?"":"no-")+feature}Modernizr[feature]=test}return Modernizr};setCss("");modElem=inputElem=null;Modernizr._version=version;Modernizr._prefixes=prefixes;Modernizr._domPrefixes=domPrefixes;Modernizr._cssomPrefixes=cssomPrefixes;Modernizr.testProp=function(prop){return testProps([prop])};Modernizr.testAllProps=testPropsAll;Modernizr.testStyles=injectElementWithStyles;Modernizr.prefixed=function(prop,obj,elem){if(!obj){return testPropsAll(prop,"pfx")}else{return testPropsAll(prop,obj,elem)}};return Modernizr}(window,document);var fullScreenApi={ok:false,is:function(){return false},request:function(){},cancel:function(){},event:"",prefix:""},browserPrefixes="webkit moz o ms khtml".split(" ");if(typeof document.cancelFullScreen!="undefined"){fullScreenApi.ok=true}else{for(var i=0,il=browserPrefixes.length;i=max?"bottom":"top bottom":pos<=min?"left":pos>=max?"right":"left right"}function smartClick($el,fn,_options){_options=_options||{};$el.each(function(){var $this=$(this),thisData=$this.data(),startEvent;if(thisData.clickOn)return;thisData.clickOn=true;$.extend(touch($this,{onStart:function(e){startEvent=e;(_options.onStart||noop).call(this,e)},onMove:_options.onMove||noop,onTouchEnd:_options.onTouchEnd||noop,onEnd:function(result){if(result.moved)return;fn.call(this,startEvent)}}),{noMove:true})})}function div(classes,child){return''+(child||"")+"
"}function cls(className){return"."+className}function createVideoFrame(videoItem){var frame='';return frame}function shuffle(array){var l=array.length;while(l){var i=Math.floor(Math.random()*l--);var t=array[l];array[l]=array[i];array[i]=t}return array}function clone(array){return Object.prototype.toString.call(array)=="[object Array]"&&$.map(array,function(frame){return $.extend({},frame)})}function lockScroll($el,left,top){$el.scrollLeft(left||0).scrollTop(top||0)}function optionsToLowerCase(options){if(options){var opts={};$.each(options,function(key,value){opts[key.toLowerCase()]=value});return opts}}function getRatio(_ratio){if(!_ratio)return;var ratio=+_ratio;if(!isNaN(ratio)){return ratio}else{ratio=_ratio.split("/");return+ratio[0]/+ratio[1]||undefined}}function addEvent(el,e,fn,bool){if(!e)return;el.addEventListener?el.addEventListener(e,fn,!!bool):el.attachEvent("on"+e,fn)}function validateRestrictions(position,restriction){if(position>restriction.max){position=restriction.max}else{if(position=wrapSize-offsetNav){if(dir==="horizontal"){position=-$guessNavFrame.position().left}else{position=-$guessNavFrame.position().top}}else{if((size+opt.margin)*guessIndex<=Math.abs(offsetNav)){if(dir==="horizontal"){position=-$guessNavFrame.position().left+wrapSize-(size+opt.margin)}else{position=-$guessNavFrame.position().top+wrapSize-(size+opt.margin)}}else{position=offsetNav}}position=validateRestrictions(position,navShaftTouchTail);return position||0}function elIsDisabled(el){return!!el.getAttribute("disabled")}function disableAttr(FLAG,disable){if(disable){return{disabled:FLAG}}else{return{tabindex:FLAG*-1+"",disabled:FLAG}}}function addEnterUp(el,fn){addEvent(el,"keyup",function(e){elIsDisabled(el)||e.keyCode==13&&fn.call(el,e)})}function addFocus(el,fn){addEvent(el,"focus",el.onfocusin=function(e){fn.call(el,e)},true)}function stopEvent(e,stopPropagation){e.preventDefault?e.preventDefault():e.returnValue=false;stopPropagation&&e.stopPropagation&&e.stopPropagation()}function stubEvent($el,eventType){var isIOS=/ip(ad|hone|od)/i.test(window.navigator.userAgent);if(isIOS&&eventType==="touchend"){$el.on("touchend",function(e){$DOCUMENT.trigger("mouseup",e)})}$el.on(eventType,function(e){stopEvent(e,true);return false})}function getDirectionSign(forward){return forward?">":"<"}var UTIL=function(){function setRatioClass($el,wh,ht){var rateImg=wh/ht;if(rateImg<=1){$el.parent().removeClass(horizontalImageClass);$el.parent().addClass(verticalImageClass)}else{$el.parent().removeClass(verticalImageClass);$el.parent().addClass(horizontalImageClass)}}function setThumbAttr($frame,value,searchAttr){var attr=searchAttr;if(!$frame.attr(attr)&&$frame.attr(attr)!==undefined){$frame.attr(attr,value)}if($frame.find("["+attr+"]").length){$frame.find("["+attr+"]").each(function(){$(this).attr(attr,value)})}}function isExpectedCaption(frameItem,isExpected,undefined){var expected=false,frameExpected;frameItem.showCaption===undefined||frameItem.showCaption===true?frameExpected=true:frameExpected=false;if(!isExpected){return false}if(frameItem.caption&&frameExpected){expected=true}return expected}return{setRatio:setRatioClass,setThumbAttr:setThumbAttr,isExpectedCaption:isExpectedCaption}}(UTIL||{},jQuery);function slide($el,options){var elData=$el.data(),elPos=Math.round(options.pos),onEndFn=function(){if(elData&&elData.sliding){elData.sliding=false}(options.onEnd||noop)()};if(typeof options.overPos!=="undefined"&&options.overPos!==options.pos){elPos=options.overPos}var translate=$.extend(getTranslate(elPos,options.direction),options.width&&{width:options.width},options.height&&{height:options.height});if(elData&&elData.sliding){elData.sliding=true}if(CSS3){$el.css($.extend(getDuration(options.time),translate));if(options.time>10){afterTransition($el,"transform",onEndFn,options.time)}else{onEndFn()}}else{$el.stop().animate(translate,options.time,BEZIER,onEndFn)}}function fade($el1,$el2,$frames,options,fadeStack,chain){var chainedFLAG=typeof chain!=="undefined";if(!chainedFLAG){fadeStack.push(arguments);Array.prototype.push.call(arguments,fadeStack.length);if(fadeStack.length>1)return}$el1=$el1||$($el1);$el2=$el2||$($el2);var _$el1=$el1[0],_$el2=$el2[0],crossfadeFLAG=options.method==="crossfade",onEndFn=function(){if(!onEndFn.done){onEndFn.done=true;var args=(chainedFLAG||fadeStack.shift())&&fadeStack.shift();args&&fade.apply(this,args);(options.onEnd||noop)(!!args)}},time=options.time/(chain||1);$frames.removeClass(fadeRearClass+" "+fadeFrontClass);$el1.stop().addClass(fadeRearClass);$el2.stop().addClass(fadeFrontClass);crossfadeFLAG&&_$el2&&$el1.fadeTo(0,0);$el1.fadeTo(crossfadeFLAG?time:0,1,crossfadeFLAG&&onEndFn);$el2.fadeTo(time,0,onEndFn);_$el1&&crossfadeFLAG||_$el2||onEndFn()}var lastEvent,moveEventType,preventEvent,preventEventTimeout,dragDomEl;function extendEvent(e){var touch=(e.touches||[])[0]||e;e._x=touch.pageX||touch.originalEvent.pageX;e._y=touch.clientY||touch.originalEvent.clientY;e._now=$.now()}function touch($el,options){var el=$el[0],tail={},touchEnabledFLAG,startEvent,$target,controlTouch,touchFLAG,targetIsSelectFLAG,targetIsLinkFlag,tolerance,moved;function onStart(e){$target=$(e.target);tail.checked=targetIsSelectFLAG=targetIsLinkFlag=moved=false;if(touchEnabledFLAG||tail.flow||e.touches&&e.touches.length>1||e.which>1||lastEvent&&lastEvent.type!==e.type&&preventEvent||(targetIsSelectFLAG=options.select&&$target.is(options.select,el)))return targetIsSelectFLAG;touchFLAG=e.type==="touchstart";targetIsLinkFlag=$target.is("a, a *",el);controlTouch=tail.control;tolerance=tail.noMove||tail.noSwipe||controlTouch?16:!tail.snap?4:0;extendEvent(e);startEvent=lastEvent=e;moveEventType=e.type.replace(/down|start/,"move").replace(/Down/,"Move");(options.onStart||noop).call(el,e,{control:controlTouch,$target:$target});touchEnabledFLAG=tail.flow=true;if(!touchFLAG||tail.go)stopEvent(e)}function onMove(e){if(e.touches&&e.touches.length>1||MS_POINTER&&!e.isPrimary||moveEventType!==e.type||!touchEnabledFLAG){touchEnabledFLAG&&onEnd();(options.onTouchEnd||noop)();return}extendEvent(e);var xDiff=Math.abs(e._x-startEvent._x),yDiff=Math.abs(e._y-startEvent._y),xyDiff=xDiff-yDiff,xWin=(tail.go||tail.x||xyDiff>=0)&&!tail.noSwipe,yWin=xyDiff<0;if(touchFLAG&&!tail.checked){if(touchEnabledFLAG=xWin){stopEvent(e)}}else{stopEvent(e);if(movedEnough(xDiff,yDiff)){(options.onMove||noop).call(el,e,{touch:touchFLAG})}}if(!moved&&movedEnough(xDiff,yDiff)&&Math.sqrt(Math.pow(xDiff,2)+Math.pow(yDiff,2))>tolerance){moved=true}tail.checked=tail.checked||xWin||yWin}function movedEnough(xDiff,yDiff){return xDiff>yDiff&&xDiff>1.5}function onEnd(e){(options.onTouchEnd||noop)();var _touchEnabledFLAG=touchEnabledFLAG;tail.control=touchEnabledFLAG=false;if(_touchEnabledFLAG){tail.flow=false}if(!_touchEnabledFLAG||targetIsLinkFlag&&!tail.checked)return;e&&stopEvent(e);preventEvent=true;clearTimeout(preventEventTimeout);preventEventTimeout=setTimeout(function(){preventEvent=false},1e3);(options.onEnd||noop).call(el,{moved:moved,$target:$target,control:controlTouch,touch:touchFLAG,startEvent:startEvent,aborted:!e||e.type==="MSPointerCancel"})}function onOtherStart(){if(tail.flow)return;tail.flow=true}function onOtherEnd(){if(!tail.flow)return;tail.flow=false}if(MS_POINTER){addEvent(el,"MSPointerDown",onStart);addEvent(document,"MSPointerMove",onMove);addEvent(document,"MSPointerCancel",onEnd);addEvent(document,"MSPointerUp",onEnd)}else{addEvent(el,"touchstart",onStart);addEvent(el,"touchmove",onMove);addEvent(el,"touchend",onEnd);addEvent(document,"touchstart",onOtherStart);addEvent(document,"touchend",onOtherEnd);addEvent(document,"touchcancel",onOtherEnd);$WINDOW.on("scroll",onOtherEnd);$el.on("mousedown pointerdown",onStart);$DOCUMENT.on("mousemove pointermove",onMove).on("mouseup pointerup",onEnd)}if(Modernizr.touch){dragDomEl="a"}else{dragDomEl="div"}$el.on("click",dragDomEl,function(e){tail.checked&&stopEvent(e)});return tail}function moveOnTouch($el,options){var el=$el[0],elData=$el.data(),tail={},startCoo,coo,startElPos,moveElPos,edge,moveTrack,startTime,endTime,min,max,snap,dir,slowFLAG,controlFLAG,moved,tracked;function startTracking(e,noStop){tracked=true;startCoo=coo=dir==="vertical"?e._y:e._x;startTime=e._now;moveTrack=[[startTime,startCoo]];startElPos=moveElPos=tail.noMove||noStop?0:stop($el,(options.getPos||noop)());(options.onStart||noop).call(el,e)}function onStart(e,result){min=tail.min;max=tail.max;snap=tail.snap,dir=tail.direction||"horizontal",$el.navdir=dir;slowFLAG=e.altKey;tracked=moved=false;controlFLAG=result.control;if(!controlFLAG&&!elData.sliding){startTracking(e)}}function onMove(e,result){if(!tail.noSwipe){if(!tracked){startTracking(e)}coo=dir==="vertical"?e._y:e._x;moveTrack.push([e._now,coo]);moveElPos=startElPos-(startCoo-coo);edge=findShadowEdge(moveElPos,min,max,dir);if(moveElPos<=min){moveElPos=edgeResistance(moveElPos,min)}else if(moveElPos>=max){moveElPos=edgeResistance(moveElPos,max)}if(!tail.noMove){$el.css(getTranslate(moveElPos,dir));if(!moved){moved=true;result.touch||MS_POINTER||$el.addClass(grabbingClass)}(options.onMove||noop).call(el,e,{pos:moveElPos,edge:edge})}}}function onEnd(result){if(tail.noSwipe&&result.moved)return;if(!tracked){startTracking(result.startEvent,true)}result.touch||MS_POINTER||$el.removeClass(grabbingClass);endTime=$.now();var _backTimeIdeal=endTime-TOUCH_TIMEOUT,_backTime,_timeDiff,_timeDiffLast,backTime=null,backCoo,virtualPos,limitPos,newPos,overPos,time=TRANSITION_DURATION,speed,friction=options.friction;for(var _i=moveTrack.length-1;_i>=0;_i--){_backTime=moveTrack[_i][0];_timeDiff=Math.abs(_backTime-_backTimeIdeal);if(backTime===null||_timeDiff<_timeDiffLast){backTime=_backTime;backCoo=moveTrack[_i][1]}else if(backTime===_backTimeIdeal||_timeDiff>_timeDiffLast){break}_timeDiffLast=_timeDiff}newPos=minMaxLimit(moveElPos,min,max);var cooDiff=backCoo-coo,forwardFLAG=cooDiff>=0,timeDiff=endTime-backTime,longTouchFLAG=timeDiff>TOUCH_TIMEOUT,swipeFLAG=!longTouchFLAG&&moveElPos!==startElPos&&newPos===moveElPos;if(snap){newPos=minMaxLimit(Math[swipeFLAG?forwardFLAG?"floor":"ceil":"round"](moveElPos/snap)*snap,min,max);min=max=newPos}if(swipeFLAG&&(snap||newPos===moveElPos)){speed=-(cooDiff/timeDiff);time*=minMaxLimit(Math.abs(speed),options.timeLow,options.timeHigh);virtualPos=Math.round(moveElPos+speed*time/friction);if(!snap){newPos=virtualPos}if(!forwardFLAG&&virtualPos>max||forwardFLAG&&virtualPos"),$anchor=$(div(hiddenClass)),$wrap=$fotorama.find(cls(wrapClass)),$stage=$wrap.find(cls(stageClass)),stage=$stage[0],$stageShaft=$fotorama.find(cls(stageShaftClass)),$stageFrame=$(),$arrPrev=$fotorama.find(cls(arrPrevClass)),$arrNext=$fotorama.find(cls(arrNextClass)),$arrs=$fotorama.find(cls(arrClass)),$navWrap=$fotorama.find(cls(navWrapClass)),$nav=$navWrap.find(cls(navClass)),$navShaft=$nav.find(cls(navShaftClass)),$navFrame,$navDotFrame=$(),$navThumbFrame=$(),stageShaftData=$stageShaft.data(),navShaftData=$navShaft.data(),$thumbBorder=$fotorama.find(cls(thumbBorderClass)),$thumbArrLeft=$fotorama.find(cls(thumbArrLeft)),$thumbArrRight=$fotorama.find(cls(thumbArrRight)),$fullscreenIcon=$fotorama.find(cls(fullscreenIconClass)),fullscreenIcon=$fullscreenIcon[0],$videoPlay=$(div(videoPlayClass)),$videoClose=$fotorama.find(cls(videoCloseClass)),videoClose=$videoClose[0],$spinner=$fotorama.find(cls(fotoramaSpinnerClass)),$videoPlaying,activeIndex=false,activeFrame,activeIndexes,repositionIndex,dirtyIndex,lastActiveIndex,prevIndex,nextIndex,nextAutoplayIndex,startIndex,o_loop,o_nav,o_navThumbs,o_navTop,o_allowFullScreen,o_nativeFullScreen,o_fade,o_thumbSide,o_thumbSide2,o_transitionDuration,o_transition,o_shadows,o_rtl,o_keyboard,lastOptions={},measures={},measuresSetFLAG,stageShaftTouchTail={},stageWheelTail={},navShaftTouchTail={},navWheelTail={},scrollTop,scrollLeft,showedFLAG,pausedAutoplayFLAG,stoppedAutoplayFLAG,toDeactivate={},toDetach={},measuresStash,touchedFLAG,hoverFLAG,navFrameKey,stageLeft=0,fadeStack=[];$wrap[STAGE_FRAME_KEY]=$('');$wrap[NAV_THUMB_FRAME_KEY]=$($.Fotorama.jst.thumb());$wrap[NAV_DOT_FRAME_KEY]=$($.Fotorama.jst.dots());toDeactivate[STAGE_FRAME_KEY]=[];toDeactivate[NAV_THUMB_FRAME_KEY]=[];toDeactivate[NAV_DOT_FRAME_KEY]=[];toDetach[STAGE_FRAME_KEY]={};$wrap.addClass(CSS3?wrapCss3Class:wrapCss2Class);fotoramaData.fotorama=this;function checkForVideo(){$.each(data,function(i,dataFrame){if(!dataFrame.i){dataFrame.i=dataFrameCount++;var video=findVideoId(dataFrame.video,true);if(video){var thumbs={};dataFrame.video=video;if(!dataFrame.img&&!dataFrame.thumb){thumbs=getVideoThumbs(dataFrame,data,that)}else{dataFrame.thumbsReady=true}updateData(data,{img:thumbs.img,thumb:thumbs.thumb},dataFrame.i,that)}}})}function allowKey(key){return o_keyboard[key]}function setStagePosition(){if($stage!==undefined){if(opts.navdir=="vertical"){var padding=opts.thumbwidth+opts.thumbmargin;$stage.css("left",padding);$arrNext.css("right",padding);$fullscreenIcon.css("right",padding);$wrap.css("width",$wrap.css("width")+padding);$stageShaft.css("max-width",$wrap.width()-padding)}else{$stage.css("left","");$arrNext.css("right","");$fullscreenIcon.css("right","");$wrap.css("width",$wrap.css("width")+padding);$stageShaft.css("max-width","")}}}function bindGlobalEvents(FLAG){var keydownCommon="keydown."+_fotoramaClass,localStamp=_fotoramaClass+stamp,keydownLocal="keydown."+localStamp,keyupLocal="keyup."+localStamp,resizeLocal="resize."+localStamp+" "+"orientationchange."+localStamp,showParams;if(FLAG){$DOCUMENT.on(keydownLocal,function(e){var catched,index;if($videoPlaying&&e.keyCode===27){catched=true;unloadVideo($videoPlaying,true,true)}else if(that.fullScreen||opts.keyboard&&!that.index){if(e.keyCode===27){catched=true;that.cancelFullScreen()}else if(e.shiftKey&&e.keyCode===32&&allowKey("space")||e.keyCode===37&&allowKey("left")||e.keyCode===38&&allowKey("up")&&$(":focus").attr("data-gallery-role")){that.longPress.progress();index="<"}else if(e.keyCode===32&&allowKey("space")||e.keyCode===39&&allowKey("right")||e.keyCode===40&&allowKey("down")&&$(":focus").attr("data-gallery-role")){that.longPress.progress();index=">"}else if(e.keyCode===36&&allowKey("home")){that.longPress.progress();index="<<"}else if(e.keyCode===35&&allowKey("end")){that.longPress.progress();index=">>"}}(catched||index)&&stopEvent(e);showParams={index:index,slow:e.altKey,user:true};index&&(that.longPress.inProgress?that.showWhileLongPress(showParams):that.show(showParams))});if(FLAG){$DOCUMENT.on(keyupLocal,function(e){if(that.longPress.inProgress){that.showEndLongPress({user:true})}that.longPress.reset()})}if(!that.index){$DOCUMENT.off(keydownCommon).on(keydownCommon,"textarea, input, select",function(e){!$BODY.hasClass(_fullscreenClass)&&e.stopPropagation()})}$WINDOW.on(resizeLocal,that.resize)}else{$DOCUMENT.off(keydownLocal);$WINDOW.off(resizeLocal)}}function appendElements(FLAG){if(FLAG===appendElements.f)return;if(FLAG){$fotorama.addClass(_fotoramaClass+" "+stampClass).before($anchor).before($style);addInstance(that)}else{$anchor.detach();$style.detach();$fotorama.html(fotoramaData.urtext).removeClass(stampClass);hideInstance(that)}bindGlobalEvents(FLAG);appendElements.f=FLAG}function setData(){data=that.data=data||clone(opts.data)||getDataFromHtml($fotorama);size=that.size=data.length;ready.ok&&opts.shuffle&&shuffle(data);checkForVideo();activeIndex=limitIndex(activeIndex);size&&appendElements(true)}function stageNoMove(){var _noMove=size<2||$videoPlaying;stageShaftTouchTail.noMove=_noMove||o_fade;stageShaftTouchTail.noSwipe=_noMove||!opts.swipe;!o_transition&&$stageShaft.toggleClass(grabClass,!opts.click&&!stageShaftTouchTail.noMove&&!stageShaftTouchTail.noSwipe);MS_POINTER&&$wrap.toggleClass(wrapPanYClass,!stageShaftTouchTail.noSwipe)}function setAutoplayInterval(interval){if(interval===true)interval="";opts.autoplay=Math.max(+interval||AUTOPLAY_INTERVAL,o_transitionDuration*1.5)}function updateThumbArrow(opt){if(opt.navarrows&&opt.nav==="thumbs"){$thumbArrLeft.show();$thumbArrRight.show()}else{$thumbArrLeft.hide();$thumbArrRight.hide()}}function getThumbsInSlide($el,opts){return Math.floor($wrap.width()/(opts.thumbwidth+opts.thumbmargin))}function setOptions(){if(!opts.nav||opts.nav==="dots"){opts.navdir="horizontal"}that.options=opts=optionsToLowerCase(opts);thumbsPerSlide=getThumbsInSlide($wrap,opts);o_fade=opts.transition==="crossfade"||opts.transition==="dissolve";o_loop=opts.loop&&(size>2||o_fade&&(!o_transition||o_transition!=="slide"));o_transitionDuration=+opts.transitionduration||TRANSITION_DURATION;o_rtl=opts.direction==="rtl";o_keyboard=$.extend({},opts.keyboard&&KEYBOARD_OPTIONS,opts.keyboard);updateThumbArrow(opts);var classes={add:[],remove:[]};function addOrRemoveClass(FLAG,value){classes[FLAG?"add":"remove"].push(value)}if(size>1){o_nav=opts.nav;o_navTop=opts.navposition==="top";classes.remove.push(selectClass);$arrs.toggle(opts.arrows)}else{o_nav=false;$arrs.hide()}arrsUpdate();stageWheelUpdate();thumbArrUpdate();if(opts.autoplay)setAutoplayInterval(opts.autoplay);o_thumbSide=numberFromMeasure(opts.thumbwidth)||THUMB_SIZE;o_thumbSide2=numberFromMeasure(opts.thumbheight)||THUMB_SIZE;stageWheelTail.ok=navWheelTail.ok=opts.trackpad&&!SLOW;stageNoMove();extendMeasures(opts,[measures]);o_navThumbs=o_nav==="thumbs";if($navWrap.filter(":hidden")&&!!o_nav){$navWrap.show()}if(o_navThumbs){frameDraw(size,"navThumb");$navFrame=$navThumbFrame;navFrameKey=NAV_THUMB_FRAME_KEY;setStyle($style,$.Fotorama.jst.style({w:o_thumbSide,h:o_thumbSide2,b:opts.thumbborderwidth,m:opts.thumbmargin,s:stamp,q:!COMPAT}));$nav.addClass(navThumbsClass).removeClass(navDotsClass)}else if(o_nav==="dots"){frameDraw(size,"navDot");$navFrame=$navDotFrame;navFrameKey=NAV_DOT_FRAME_KEY;$nav.addClass(navDotsClass).removeClass(navThumbsClass)}else{$navWrap.hide();o_nav=false;$nav.removeClass(navThumbsClass+" "+navDotsClass)}if(o_nav){if(o_navTop){$navWrap.insertBefore($stage)}else{$navWrap.insertAfter($stage)}frameAppend.nav=false;frameAppend($navFrame,$navShaft,"nav")}o_allowFullScreen=opts.allowfullscreen;if(o_allowFullScreen){$fullscreenIcon.prependTo($stage);o_nativeFullScreen=FULLSCREEN&&o_allowFullScreen==="native";stubEvent($fullscreenIcon,"touchend")}else{$fullscreenIcon.detach();o_nativeFullScreen=false}addOrRemoveClass(o_fade,wrapFadeClass);addOrRemoveClass(!o_fade,wrapSlideClass);addOrRemoveClass(!opts.captions,wrapNoCaptionsClass);addOrRemoveClass(o_rtl,wrapRtlClass);addOrRemoveClass(opts.arrows,wrapToggleArrowsClass);o_shadows=opts.shadows&&!SLOW;addOrRemoveClass(!o_shadows,wrapNoShadowsClass);$wrap.addClass(classes.add.join(" ")).removeClass(classes.remove.join(" "));lastOptions=$.extend({},opts);setStagePosition()}function normalizeIndex(index){return index<0?(size+index%size)%size:index>=size?index%size:index}function limitIndex(index){return minMaxLimit(index,0,size-1)}function edgeIndex(index){return o_loop?normalizeIndex(index):limitIndex(index)}function getPrevIndex(index){return index>0||o_loop?index-1:false}function getNextIndex(index){return index1&&data[index]===dataFrame&&!dataFrame.html&&!dataFrame.deleted&&!dataFrame.video&&!fullFLAG){dataFrame.deleted=true;that.splice(index,1)}}}function loaded(){$.Fotorama.measures[src]=imgData.measures=$.Fotorama.measures[src]||{width:img.width,height:img.height,ratio:img.width/img.height};setMeasures(imgData.measures.width,imgData.measures.height,imgData.measures.ratio,index);$img.off("load error").addClass(""+(fullFLAG?imgFullClass:imgClass)).attr("aria-hidden","false").prependTo($frame);if($frame.hasClass(stageFrameClass)&&!$frame.hasClass(videoContainerClass)){$frame.attr("href",$img.attr("src"))}fit($img,($.isFunction(specialMeasures)?specialMeasures():specialMeasures)||measures);$.Fotorama.cache[src]=frameData.state="loaded";setTimeout(function(){$frame.trigger("f:load").removeClass(loadingClass+" "+errorClass).addClass(loadedClass+" "+(fullFLAG?loadedFullClass:loadedImgClass));if(type==="stage"){triggerTriggerEvent("load")}else if(dataFrame.thumbratio===AUTO||!dataFrame.thumbratio&&opts.thumbratio===AUTO){dataFrame.thumbratio=imgData.measures.ratio;reset()}},0)}if(!src){error();return}function waitAndLoad(){var _i=10;waitFor(function(){return!touchedFLAG||!_i--&&!SLOW},function(){loaded()})}if(!$.Fotorama.cache[src]){$.Fotorama.cache[src]="*";$img.on("load",waitAndLoad).on("error",error)}else{(function justWait(){if($.Fotorama.cache[src]==="error"){error()}else if($.Fotorama.cache[src]==="loaded"){setTimeout(waitAndLoad,0)}else{setTimeout(justWait,100)}})()}frameData.state="";img.src=src;if(frameData.data.caption){img.alt=frameData.data.caption||""}if(frameData.data.full){$(img).data("original",frameData.data.full)}if(UTIL.isExpectedCaption(dataFrame,opts.showcaption)){$(img).attr("aria-labelledby",dataFrame.labelledby)}})}function updateFotoramaState(){var $frame=activeFrame[STAGE_FRAME_KEY];if($frame&&!$frame.data().state){$spinner.addClass(spinnerShowClass);$frame.on("f:load f:error",function(){$frame.off("f:load f:error");$spinner.removeClass(spinnerShowClass)})}}function addNavFrameEvents(frame){addEnterUp(frame,onNavFrameClick);addFocus(frame,function(){setTimeout(function(){lockScroll($nav)},0);slideNavShaft({time:o_transitionDuration,guessIndex:$(this).data().eq,minMax:navShaftTouchTail})})}function frameDraw(indexes,type){eachIndex(indexes,type,function(i,index,dataFrame,$frame,key,frameData){if($frame)return;$frame=dataFrame[key]=$wrap[key].clone();frameData=$frame.data();frameData.data=dataFrame;var frame=$frame[0],labelledbyValue="labelledby"+$.now();if(type==="stage"){if(dataFrame.html){$('').append(dataFrame._html?$(dataFrame.html).removeAttr("id").html(dataFrame._html):dataFrame.html).appendTo($frame)}if(dataFrame.id){labelledbyValue=dataFrame.id||labelledbyValue}dataFrame.labelledby=labelledbyValue;if(UTIL.isExpectedCaption(dataFrame,opts.showcaption)){$($.Fotorama.jst.frameCaption({caption:dataFrame.caption,labelledby:labelledbyValue})).appendTo($frame)}dataFrame.video&&$frame.addClass(stageFrameVideoClass).append($videoPlay.clone());addFocus(frame,function(){setTimeout(function(){lockScroll($stage)},0);clickToShow({index:frameData.eq,user:true})});$stageFrame=$stageFrame.add($frame)}else if(type==="navDot"){addNavFrameEvents(frame);$navDotFrame=$navDotFrame.add($frame)}else if(type==="navThumb"){addNavFrameEvents(frame);frameData.$wrap=$frame.children(":first");$navThumbFrame=$navThumbFrame.add($frame);if(dataFrame.video){frameData.$wrap.append($videoPlay.clone())}}})}function callFit($img,measuresToFit){return $img&&$img.length&&fit($img,measuresToFit)}function stageFramePosition(indexes){eachIndex(indexes,"stage",function(i,index,dataFrame,$frame,key,frameData){if(!$frame)return;var normalizedIndex=normalizeIndex(index);frameData.eq=normalizedIndex;toDetach[STAGE_FRAME_KEY][normalizedIndex]=$frame.css($.extend({left:o_fade?0:getPosByIndex(index,measures.w,opts.margin,repositionIndex)},o_fade&&getDuration(0)));if(isDetached($frame[0])){$frame.appendTo($stageShaft);unloadVideo(dataFrame.$video)}callFit(frameData.$img,measures);callFit(frameData.$full,measures);if($frame.hasClass(stageFrameClass)&&!($frame.attr("aria-hidden")==="false"&&$frame.hasClass(activeClass))){$frame.attr("aria-hidden","true")}})}function thumbsDraw(pos,loadFLAG){var leftLimit,rightLimit,exceedLimit;if(o_nav!=="thumbs"||isNaN(pos))return;leftLimit=-pos;rightLimit=-pos+measures.nw;if(opts.navdir==="vertical"){pos=pos-opts.thumbheight;rightLimit=-pos+measures.h}$navThumbFrame.each(function(){var $this=$(this),thisData=$this.data(),eq=thisData.eq,getSpecialMeasures=function(){return{h:o_thumbSide2,w:thisData.w}},specialMeasures=getSpecialMeasures(),exceedLimit=opts.navdir==="vertical"?thisData.t>rightLimit:thisData.l>rightLimit;specialMeasures.w=thisData.w;if(thisData.l+thisData.wmeasures.w/3}function disableDirrection(i){return!o_loop&&(!(activeIndex+i)||!(activeIndex-size+i))&&!$videoPlaying}function arrsUpdate(){var disablePrev=disableDirrection(0),disableNext=disableDirrection(1);$arrPrev.toggleClass(arrDisabledClass,disablePrev).attr(disableAttr(disablePrev,false));$arrNext.toggleClass(arrDisabledClass,disableNext).attr(disableAttr(disableNext,false))}function thumbArrUpdate(){var isLeftDisable=false,isRightDisable=false;if(opts.navtype==="thumbs"&&!opts.loop){activeIndex==0?isLeftDisable=true:isLeftDisable=false;activeIndex==opts.data.length-1?isRightDisable=true:isRightDisable=false}if(opts.navtype==="slides"){var pos=readPosition($navShaft,opts.navdir);pos>=navShaftTouchTail.max?isLeftDisable=true:isLeftDisable=false;pos<=navShaftTouchTail.min?isRightDisable=true:isRightDisable=false}$thumbArrLeft.toggleClass(arrDisabledClass,isLeftDisable).attr(disableAttr(isLeftDisable,true));$thumbArrRight.toggleClass(arrDisabledClass,isRightDisable).attr(disableAttr(isRightDisable,true))}function stageWheelUpdate(){if(stageWheelTail.ok){stageWheelTail.prevent={"<":disableDirrection(0),">":disableDirrection(1)}}}function getNavFrameBounds($navFrame){var navFrameData=$navFrame.data(),left,top,width,height;if(o_navThumbs){left=navFrameData.l;top=navFrameData.t;width=navFrameData.w;height=navFrameData.h}else{left=$navFrame.position().left;width=$navFrame.width()}var horizontalBounds={c:left+width/2,min:-left+opts.thumbmargin*10,max:-left+measures.w-width-opts.thumbmargin*10};var verticalBounds={c:top+height/2,min:-top+opts.thumbmargin*10,max:-top+measures.h-height-opts.thumbmargin*10};return opts.navdir==="vertical"?verticalBounds:horizontalBounds}function slideThumbBorder(time){var navFrameData=activeFrame[navFrameKey].data();slide($thumbBorder,{time:time*1.2,pos:opts.navdir==="vertical"?navFrameData.t:navFrameData.l,width:navFrameData.w,height:navFrameData.h,direction:opts.navdir})}function slideNavShaft(options){var $guessNavFrame=data[options.guessIndex][navFrameKey],typeOfAnimation=opts.navtype;var overflowFLAG,time,minMax,boundTop,boundLeft,l,pos,x;if($guessNavFrame){if(typeOfAnimation==="thumbs"){overflowFLAG=navShaftTouchTail.min!==navShaftTouchTail.max;minMax=options.minMax||overflowFLAG&&getNavFrameBounds(activeFrame[navFrameKey]);boundTop=overflowFLAG&&(options.keep&&slideNavShaft.t?slideNavShaft.l:minMaxLimit((options.coo||measures.nw/2)-getNavFrameBounds($guessNavFrame).c,minMax.min,minMax.max));boundLeft=overflowFLAG&&(options.keep&&slideNavShaft.l?slideNavShaft.l:minMaxLimit((options.coo||measures.nw/2)-getNavFrameBounds($guessNavFrame).c,minMax.min,minMax.max));l=opts.navdir==="vertical"?boundTop:boundLeft;pos=overflowFLAG&&minMaxLimit(l,navShaftTouchTail.min,navShaftTouchTail.max)||0;time=options.time*1.1;slide($navShaft,{time:time,pos:pos,direction:opts.navdir,onEnd:function(){thumbsDraw(pos,true);thumbArrUpdate()}});setShadow($nav,findShadowEdge(pos,navShaftTouchTail.min,navShaftTouchTail.max,opts.navdir));slideNavShaft.l=l}else{x=readPosition($navShaft,opts.navdir);time=options.time*1.11;pos=validateSlidePos(opts,navShaftTouchTail,options.guessIndex,x,$guessNavFrame,$navWrap,opts.navdir);slide($navShaft,{time:time,pos:pos,direction:opts.navdir,onEnd:function(){thumbsDraw(pos,true);thumbArrUpdate()}});setShadow($nav,findShadowEdge(pos,navShaftTouchTail.min,navShaftTouchTail.max,opts.navdir))}}}function navUpdate(){deactivateFrames(navFrameKey);toDeactivate[navFrameKey].push(activeFrame[navFrameKey].addClass(activeClass).attr("data-active",true))}function deactivateFrames(key){var _toDeactivate=toDeactivate[key];while(_toDeactivate.length){_toDeactivate.shift().removeClass(activeClass).attr("data-active",false)}}function detachFrames(key){var _toDetach=toDetach[key];$.each(activeIndexes,function(i,index){delete _toDetach[normalizeIndex(index)]});$.each(_toDetach,function(index,$frame){delete _toDetach[index];$frame.detach()})}function stageShaftReposition(skipOnEnd){repositionIndex=dirtyIndex=activeIndex;var $frame=activeFrame[STAGE_FRAME_KEY];if($frame){deactivateFrames(STAGE_FRAME_KEY);toDeactivate[STAGE_FRAME_KEY].push($frame.addClass(activeClass).attr("data-active",true));if($frame.hasClass(stageFrameClass)){$frame.attr("aria-hidden","false")}skipOnEnd||that.showStage.onEnd(true);stop($stageShaft,0,true);detachFrames(STAGE_FRAME_KEY);stageFramePosition(activeIndexes);setStageShaftMinmaxAndSnap();setNavShaftMinMax();addEnterUp($stageShaft[0],function(){if(!$fotorama.hasClass(fullscreenClass)){that.requestFullScreen();$fullscreenIcon.focus()}})}}function extendMeasures(options,measuresArray){if(!options)return;$.each(measuresArray,function(i,measures){if(!measures)return;$.extend(measures,{width:options.width||measures.width,height:options.height,minwidth:options.minwidth,maxwidth:options.maxwidth,minheight:options.minheight,maxheight:options.maxheight,ratio:getRatio(options.ratio)})})}function triggerEvent(event,extra){$fotorama.trigger(_fotoramaClass+":"+event,[that,extra])}function onTouchStart(){clearTimeout(onTouchEnd.t);touchedFLAG=1;if(opts.stopautoplayontouch){that.stopAutoplay()}else{pausedAutoplayFLAG=true}}function onTouchEnd(){if(!touchedFLAG)return;if(!opts.stopautoplayontouch){releaseAutoplay();changeAutoplay()}onTouchEnd.t=setTimeout(function(){touchedFLAG=0},TRANSITION_DURATION+TOUCH_TIMEOUT)}function releaseAutoplay(){pausedAutoplayFLAG=!!($videoPlaying||stoppedAutoplayFLAG)}function changeAutoplay(){clearTimeout(changeAutoplay.t);waitFor.stop(changeAutoplay.w);if(!opts.autoplay||pausedAutoplayFLAG){if(that.autoplay){that.autoplay=false;triggerEvent("stopautoplay")}return}if(!that.autoplay){that.autoplay=true;triggerEvent("startautoplay")}var _activeIndex=activeIndex;var frameData=activeFrame[STAGE_FRAME_KEY].data();changeAutoplay.w=waitFor(function(){return frameData.state||_activeIndex!==activeIndex},function(){changeAutoplay.t=setTimeout(function(){if(pausedAutoplayFLAG||_activeIndex!==activeIndex)return;var _nextAutoplayIndex=nextAutoplayIndex,nextFrameData=data[_nextAutoplayIndex][STAGE_FRAME_KEY].data();changeAutoplay.w=waitFor(function(){return nextFrameData.state||_nextAutoplayIndex!==nextAutoplayIndex},function(){if(pausedAutoplayFLAG||_nextAutoplayIndex!==nextAutoplayIndex)return;that.show(o_loop?getDirectionSign(!o_rtl):nextAutoplayIndex)})},opts.autoplay)})}that.startAutoplay=function(interval){if(that.autoplay)return this;pausedAutoplayFLAG=stoppedAutoplayFLAG=false;setAutoplayInterval(interval||opts.autoplay);changeAutoplay();return this};that.stopAutoplay=function(){if(that.autoplay){pausedAutoplayFLAG=stoppedAutoplayFLAG=true;changeAutoplay()}return this};that.showSlide=function(slideDir){var currentPosition=readPosition($navShaft,opts.navdir),pos,time=500*1.1,size=opts.navdir==="horizontal"?opts.thumbwidth:opts.thumbheight,onEnd=function(){thumbArrUpdate()};if(slideDir==="next"){pos=currentPosition-(size+opts.margin)*thumbsPerSlide}if(slideDir==="prev"){pos=currentPosition+(size+opts.margin)*thumbsPerSlide}pos=validateRestrictions(pos,navShaftTouchTail);thumbsDraw(pos,true);slide($navShaft,{time:time,pos:pos,direction:opts.navdir,onEnd:onEnd})};that.showWhileLongPress=function(options){if(that.longPress.singlePressInProgress){return}var index=calcActiveIndex(options);calcGlobalIndexes(index);var time=calcTime(options)/50;var _activeFrame=activeFrame;that.activeFrame=activeFrame=data[activeIndex];var silent=_activeFrame===activeFrame&&!options.user;that.showNav(silent,options,time);return this};that.showEndLongPress=function(options){if(that.longPress.singlePressInProgress){return}var index=calcActiveIndex(options);calcGlobalIndexes(index);var time=calcTime(options)/50;var _activeFrame=activeFrame;that.activeFrame=activeFrame=data[activeIndex];var silent=_activeFrame===activeFrame&&!options.user;that.showStage(silent,options,time);showedFLAG=typeof lastActiveIndex!=="undefined"&&lastActiveIndex!==activeIndex;lastActiveIndex=activeIndex;return this};function calcActiveIndex(options){var index;if(typeof options!=="object"){index=options;options={}}else{index=options.index}index=index===">"?dirtyIndex+1:index==="<"?dirtyIndex-1:index==="<<"?0:index===">>"?size-1:index;index=isNaN(index)?undefined:index;index=typeof index==="undefined"?activeIndex||0:index;return index}function calcGlobalIndexes(index){that.activeIndex=activeIndex=edgeIndex(index);prevIndex=getPrevIndex(activeIndex);nextIndex=getNextIndex(activeIndex);nextAutoplayIndex=normalizeIndex(activeIndex+(o_rtl?-1:1));activeIndexes=[activeIndex,prevIndex,nextIndex];dirtyIndex=o_loop?index:activeIndex}function calcTime(options){var diffIndex=Math.abs(lastActiveIndex-dirtyIndex),time=getNumber(options.time,function(){return Math.min(o_transitionDuration*(1+(diffIndex-1)/12),o_transitionDuration*2)});if(options.slow){time*=10}return time}that.showStage=function(silent,options,time){unloadVideo($videoPlaying,activeFrame.i!==data[normalizeIndex(repositionIndex)].i);frameDraw(activeIndexes,"stage");stageFramePosition(SLOW?[dirtyIndex]:[dirtyIndex,getPrevIndex(dirtyIndex),getNextIndex(dirtyIndex)]);updateTouchTails("go",true);silent||triggerEvent("show",{user:options.user,time:time});pausedAutoplayFLAG=true;var overPos=options.overPos;var onEnd=that.showStage.onEnd=function(skipReposition){if(onEnd.ok)return;onEnd.ok=true;skipReposition||stageShaftReposition(true);if(!silent){triggerEvent("showend",{user:options.user})}if(!skipReposition&&o_transition&&o_transition!==opts.transition){that.setOptions({transition:o_transition});o_transition=false;return}updateFotoramaState();loadImg(activeIndexes,"stage");updateTouchTails("go",false);stageWheelUpdate();stageCursor();releaseAutoplay();changeAutoplay();if(that.fullScreen){activeFrame[STAGE_FRAME_KEY].find("."+imgFullClass).attr("aria-hidden",false);activeFrame[STAGE_FRAME_KEY].find("."+imgClass).attr("aria-hidden",true)}else{activeFrame[STAGE_FRAME_KEY].find("."+imgFullClass).attr("aria-hidden",true);activeFrame[STAGE_FRAME_KEY].find("."+imgClass).attr("aria-hidden",false)}};if(!o_fade){slide($stageShaft,{pos:-getPosByIndex(dirtyIndex,measures.w,opts.margin,repositionIndex),overPos:overPos,time:time,onEnd:onEnd})}else{var $activeFrame=activeFrame[STAGE_FRAME_KEY],$prevActiveFrame=data[lastActiveIndex]&&activeIndex!==lastActiveIndex?data[lastActiveIndex][STAGE_FRAME_KEY]:null;fade($activeFrame,$prevActiveFrame,$stageFrame,{time:time,method:opts.transition,onEnd:onEnd},fadeStack)}arrsUpdate()};that.showNav=function(silent,options,time){thumbArrUpdate();if(o_nav){navUpdate();var guessIndex=limitIndex(activeIndex+minMaxLimit(dirtyIndex-lastActiveIndex,-1,1));slideNavShaft({time:time,coo:guessIndex!==activeIndex&&options.coo,guessIndex:typeof options.coo!=="undefined"?guessIndex:activeIndex,keep:silent});if(o_navThumbs)slideThumbBorder(time)}};that.show=function(options){that.longPress.singlePressInProgress=true;var index=calcActiveIndex(options);calcGlobalIndexes(index);var time=calcTime(options);var _activeFrame=activeFrame;that.activeFrame=activeFrame=data[activeIndex];var silent=_activeFrame===activeFrame&&!options.user;that.showStage(silent,options,time);that.showNav(silent,options,time);showedFLAG=typeof lastActiveIndex!=="undefined"&&lastActiveIndex!==activeIndex;lastActiveIndex=activeIndex;that.longPress.singlePressInProgress=false;return this};that.requestFullScreen=function(){if(o_allowFullScreen&&!that.fullScreen){var isVideo=$((that.activeFrame||{}).$stageFrame||{}).hasClass("fotorama-video-container");if(isVideo){return}scrollTop=$WINDOW.scrollTop();scrollLeft=$WINDOW.scrollLeft();lockScroll($WINDOW);updateTouchTails("x",true);measuresStash=$.extend({},measures);$fotorama.addClass(fullscreenClass).appendTo($BODY.addClass(_fullscreenClass));$HTML.addClass(_fullscreenClass);unloadVideo($videoPlaying,true,true);that.fullScreen=true;if(o_nativeFullScreen){fullScreenApi.request(fotorama)}that.resize();loadImg(activeIndexes,"stage");updateFotoramaState();triggerEvent("fullscreenenter");if(!("ontouchstart"in window)){$fullscreenIcon.focus()}}return this};function cancelFullScreen(){if(that.fullScreen){that.fullScreen=false;if(FULLSCREEN){fullScreenApi.cancel(fotorama)}$BODY.removeClass(_fullscreenClass);$HTML.removeClass(_fullscreenClass);$fotorama.removeClass(fullscreenClass).insertAfter($anchor);measures=$.extend({},measuresStash);unloadVideo($videoPlaying,true,true);updateTouchTails("x",false);that.resize();loadImg(activeIndexes,"stage");lockScroll($WINDOW,scrollLeft,scrollTop);triggerEvent("fullscreenexit")}}that.cancelFullScreen=function(){if(o_nativeFullScreen&&fullScreenApi.is()){fullScreenApi.cancel(document)}else{cancelFullScreen()}return this};that.toggleFullScreen=function(){return that[(that.fullScreen?"cancel":"request")+"FullScreen"]()};that.resize=function(options){if(!data)return this;var time=arguments[1]||0,setFLAG=arguments[2];thumbsPerSlide=getThumbsInSlide($wrap,opts);extendMeasures(!that.fullScreen?optionsToLowerCase(options):{width:$(window).width(),maxwidth:null,minwidth:null,height:$(window).height(),maxheight:null,minheight:null},[measures,setFLAG||that.fullScreen||opts]);var width=measures.width,height=measures.height,ratio=measures.ratio,windowHeight=$WINDOW.height()-(o_nav?$nav.height():0);if(measureIsValid(width)){$wrap.css({width:""});$wrap.css({height:""});$stage.css({width:""});$stage.css({height:""});$stageShaft.css({width:""});$stageShaft.css({height:""});$nav.css({width:""});$nav.css({height:""});$wrap.css({minWidth:measures.minwidth||0,maxWidth:measures.maxwidth||MAX_WIDTH});if(o_nav==="dots"){$navWrap.hide()}width=measures.W=measures.w=$wrap.width();measures.nw=o_nav&&numberFromWhatever(opts.navwidth,width)||width;$stageShaft.css({width:measures.w,marginLeft:(measures.W-measures.w)/2});height=numberFromWhatever(height,windowHeight);height=height||ratio&&width/ratio;if(height){width=Math.round(width);height=measures.h=Math.round(minMaxLimit(height,numberFromWhatever(measures.minheight,windowHeight),numberFromWhatever(measures.maxheight,windowHeight)));$stage.css({width:width,height:height});if(opts.navdir==="vertical"&&!that.fullscreen){$nav.width(opts.thumbwidth+opts.thumbmargin*2)}if(opts.navdir==="horizontal"&&!that.fullscreen){$nav.height(opts.thumbheight+opts.thumbmargin*2)}if(o_nav==="dots"){$nav.width(width).height("auto");$navWrap.show()}if(opts.navdir==="vertical"&&that.fullScreen){$stage.css("height",$WINDOW.height())}if(opts.navdir==="horizontal"&&that.fullScreen){$stage.css("height",$WINDOW.height()-$nav.height())}if(o_nav){switch(opts.navdir){case"vertical":$navWrap.removeClass(navShafthorizontalClass);$navWrap.removeClass(navShaftListClass);$navWrap.addClass(navShaftVerticalClass);$nav.stop().animate({height:measures.h,width:opts.thumbwidth},time);break;case"list":$navWrap.removeClass(navShaftVerticalClass);$navWrap.removeClass(navShafthorizontalClass);$navWrap.addClass(navShaftListClass);break;default:$navWrap.removeClass(navShaftVerticalClass);$navWrap.removeClass(navShaftListClass);$navWrap.addClass(navShafthorizontalClass);$nav.stop().animate({width:measures.nw},time);break}stageShaftReposition();slideNavShaft({guessIndex:activeIndex,time:time,keep:true});if(o_navThumbs&&frameAppend.nav)slideThumbBorder(time)}measuresSetFLAG=setFLAG||true;ready.ok=true;ready()}}stageLeft=$stage.offset().left;setStagePosition();return this};that.setOptions=function(options){$.extend(opts,options);reset();return this};that.shuffle=function(){data&&shuffle(data)&&reset();return this};function setShadow($el,edge){if(o_shadows){$el.removeClass(shadowsLeftClass+" "+shadowsRightClass);$el.removeClass(shadowsTopClass+" "+shadowsBottomClass);edge&&!$videoPlaying&&$el.addClass(edge.replace(/^|\s/g," "+shadowsClass+"--"))}}that.longPress={threshold:1,count:0,thumbSlideTime:20,progress:function(){if(!this.inProgress){this.count++;this.inProgress=this.count>this.threshold}},end:function(){if(this.inProgress){this.isEnded=true}},reset:function(){this.count=0;this.inProgress=false;this.isEnded=false}};that.destroy=function(){that.cancelFullScreen();that.stopAutoplay();data=that.data=null;appendElements();activeIndexes=[];detachFrames(STAGE_FRAME_KEY);reset.ok=false;return this};that.playVideo=function(){var dataFrame=activeFrame,video=dataFrame.video,_activeIndex=activeIndex;if(typeof video==="object"&&dataFrame.videoReady){o_nativeFullScreen&&that.fullScreen&&that.cancelFullScreen();waitFor(function(){return!fullScreenApi.is()||_activeIndex!==activeIndex},function(){if(_activeIndex===activeIndex){dataFrame.$video=dataFrame.$video||$(div(videoClass)).append(createVideoFrame(video));dataFrame.$video.appendTo(dataFrame[STAGE_FRAME_KEY]);$wrap.addClass(wrapVideoClass);$videoPlaying=dataFrame.$video;stageNoMove();$arrs.blur();$fullscreenIcon.blur();triggerEvent("loadvideo")}})}return this};that.stopVideo=function(){unloadVideo($videoPlaying,true,true);return this};that.spliceByIndex=function(index,newImgObj){newImgObj.i=index+1;newImgObj.img&&$.ajax({url:newImgObj.img,type:"HEAD",success:function(){data.splice(index,1,newImgObj);reset()}})};function unloadVideo($video,unloadActiveFLAG,releaseAutoplayFLAG){if(unloadActiveFLAG){$wrap.removeClass(wrapVideoClass);$videoPlaying=false;stageNoMove()}if($video&&$video!==$videoPlaying){$video.remove();triggerEvent("unloadvideo")}if(releaseAutoplayFLAG){releaseAutoplay();changeAutoplay()}}function toggleControlsClass(FLAG){$wrap.toggleClass(wrapNoControlsClass,FLAG)}function stageCursor(e){if(stageShaftTouchTail.flow)return;var x=e?e.pageX:stageCursor.x,pointerFLAG=x&&!disableDirrection(getDirection(x))&&opts.click;if(stageCursor.p!==pointerFLAG&&$stage.toggleClass(pointerClass,pointerFLAG)){stageCursor.p=pointerFLAG;stageCursor.x=x}}$stage.on("mousemove",stageCursor);function clickToShow(showOptions){clearTimeout(clickToShow.t);if(opts.clicktransition&&opts.clicktransition!==opts.transition){setTimeout(function(){var _o_transition=opts.transition;that.setOptions({transition:opts.clicktransition});o_transition=_o_transition;clickToShow.t=setTimeout(function(){that.show(showOptions)},10)},0)}else{that.show(showOptions)}}function onStageTap(e,toggleControlsFLAG){var target=e.target,$target=$(target);if($target.hasClass(videoPlayClass)){that.playVideo()}else if(target===fullscreenIcon){that.toggleFullScreen()}else if($videoPlaying){target===videoClose&&unloadVideo($videoPlaying,true,true)}else if(!$fotorama.hasClass(fullscreenClass)){that.requestFullScreen()}}function updateTouchTails(key,value){stageShaftTouchTail[key]=navShaftTouchTail[key]=value}stageShaftTouchTail=moveOnTouch($stageShaft,{onStart:onTouchStart,onMove:function(e,result){setShadow($stage,result.edge)},onTouchEnd:onTouchEnd,onEnd:function(result){var toggleControlsFLAG;setShadow($stage);toggleControlsFLAG=(MS_POINTER&&!hoverFLAG||result.touch)&&opts.arrows;if((result.moved||toggleControlsFLAG&&result.pos!==result.newPos&&!result.control)&&result.$target[0]!==$fullscreenIcon[0]){var index=getIndexByPos(result.newPos,measures.w,opts.margin,repositionIndex);that.show({index:index,time:o_fade?o_transitionDuration:result.time,overPos:result.overPos,user:true})}else if(!result.aborted&&!result.control){onStageTap(result.startEvent,toggleControlsFLAG)}},timeLow:1,timeHigh:1,friction:2,select:"."+selectClass+", ."+selectClass+" *",$wrap:$stage,direction:"horizontal"});navShaftTouchTail=moveOnTouch($navShaft,{onStart:onTouchStart,onMove:function(e,result){setShadow($nav,result.edge)},onTouchEnd:onTouchEnd,onEnd:function(result){function onEnd(){slideNavShaft.l=result.newPos;releaseAutoplay();changeAutoplay();thumbsDraw(result.newPos,true);thumbArrUpdate()}if(!result.moved){var target=result.$target.closest("."+navFrameClass,$navShaft)[0];target&&onNavFrameClick.call(target,result.startEvent)}else if(result.pos!==result.newPos){pausedAutoplayFLAG=true;slide($navShaft,{time:result.time,pos:result.newPos,overPos:result.overPos,direction:opts.navdir,onEnd:onEnd});thumbsDraw(result.newPos);o_shadows&&setShadow($nav,findShadowEdge(result.newPos,navShaftTouchTail.min,navShaftTouchTail.max,result.dir))}else{onEnd()}},timeLow:.5,timeHigh:2,friction:5,$wrap:$nav,direction:opts.navdir});stageWheelTail=wheel($stage,{shift:true,onEnd:function(e,direction){onTouchStart();onTouchEnd();that.show({index:direction,slow:e.altKey})}});navWheelTail=wheel($nav,{onEnd:function(e,direction){onTouchStart();onTouchEnd();var newPos=stop($navShaft)+direction*.25;$navShaft.css(getTranslate(minMaxLimit(newPos,navShaftTouchTail.min,navShaftTouchTail.max),opts.navdir));o_shadows&&setShadow($nav,findShadowEdge(newPos,navShaftTouchTail.min,navShaftTouchTail.max,opts.navdir));navWheelTail.prevent={"<":newPos>=navShaftTouchTail.max,">":newPos<=navShaftTouchTail.min};clearTimeout(navWheelTail.t);navWheelTail.t=setTimeout(function(){slideNavShaft.l=newPos;thumbsDraw(newPos,true)},TOUCH_TIMEOUT);thumbsDraw(newPos)}});$wrap.hover(function(){setTimeout(function(){if(touchedFLAG)return;toggleControlsClass(!(hoverFLAG=true))},0)},function(){if(!hoverFLAG)return;toggleControlsClass(!(hoverFLAG=false))});function onNavFrameClick(e){var index=$(this).data().eq;if(opts.navtype==="thumbs"){clickToShow({index:index,slow:e.altKey,user:true,coo:e._x-$nav.offset().left})}else{clickToShow({index:index,slow:e.altKey,user:true})}}function onArrClick(e){clickToShow({index:$arrs.index(this)?">":"<",slow:e.altKey,user:true})}smartClick($arrs,function(e){stopEvent(e);onArrClick.call(this,e)},{onStart:function(){onTouchStart();stageShaftTouchTail.control=true},onTouchEnd:onTouchEnd});smartClick($thumbArrLeft,function(e){stopEvent(e);if(opts.navtype==="thumbs"){that.show("<")}else{that.showSlide("prev")}});smartClick($thumbArrRight,function(e){stopEvent(e);if(opts.navtype==="thumbs"){that.show(">")}else{that.showSlide("next")}});function addFocusOnControls(el){addFocus(el,function(){setTimeout(function(){lockScroll($stage)},0);toggleControlsClass(false)})}$arrs.each(function(){addEnterUp(this,function(e){onArrClick.call(this,e)});addFocusOnControls(this)});addEnterUp(fullscreenIcon,function(){if($fotorama.hasClass(fullscreenClass)){that.cancelFullScreen();$stageShaft.focus()}else{that.requestFullScreen();$fullscreenIcon.focus()}});addFocusOnControls(fullscreenIcon);function reset(){setData();setOptions();if(!reset.i){reset.i=true;var _startindex=opts.startindex;activeIndex=repositionIndex=dirtyIndex=lastActiveIndex=startIndex=edgeIndex(_startindex)||0}if(size){if(changeToRtl())return;if($videoPlaying){unloadVideo($videoPlaying,true)}activeIndexes=[];detachFrames(STAGE_FRAME_KEY);reset.ok=true;that.show({index:activeIndex,time:0});that.resize()}else{that.destroy()}}function changeToRtl(){if(!changeToRtl.f===o_rtl){changeToRtl.f=o_rtl;activeIndex=size-1-activeIndex;that.reverse();return true}}$.each("load push pop shift unshift reverse sort splice".split(" "),function(i,method){that[method]=function(){data=data||[];if(method!=="load"){Array.prototype[method].apply(data,arguments)}else if(arguments[0]&&typeof arguments[0]==="object"&&arguments[0].length){data=clone(arguments[0])}reset();return that}});function ready(){if(ready.ok){ready.ok=false;triggerEvent("ready")}}reset()};$.fn.fotorama=function(opts){return this.each(function(){var that=this,$fotorama=$(this),fotoramaData=$fotorama.data(),fotorama=fotoramaData.fotorama;if(!fotorama){waitFor(function(){return!isHidden(that)},function(){fotoramaData.urtext=$fotorama.html();new $.Fotorama($fotorama,$.extend({},OPTIONS,window.fotoramaDefaults,opts,fotoramaData))})}else{fotorama.setOptions(opts,true)}})};$.Fotorama.instances=[];function calculateIndexes(){$.each($.Fotorama.instances,function(index,instance){instance.index=index})}function addInstance(instance){$.Fotorama.instances.push(instance);calculateIndexes()}function hideInstance(instance){$.Fotorama.instances.splice(instance.index,1);calculateIndexes()}$.Fotorama.cache={};$.Fotorama.measures={};$=$||{};$.Fotorama=$.Fotorama||{};$.Fotorama.jst=$.Fotorama.jst||{};$.Fotorama.jst.dots=function(v){var __t,__p="",__e=_.escape;__p+='';return __p};$.Fotorama.jst.frameCaption=function(v){var __t,__p="",__e=_.escape;__p+='\r\n
'+((__t=v.caption)==null?"":__t)+"
\r\n
\r\n";return __p};$.Fotorama.jst.style=function(v){var __t,__p="",__e=_.escape;__p+=".fotorama"+((__t=v.s)==null?"":__t)+" .fotorama__nav--thumbs .fotorama__nav__frame{\r\npadding:"+((__t=v.m)==null?"":__t)+"px;\r\nheight:"+((__t=v.h)==null?"":__t)+"px}\r\n.fotorama"+((__t=v.s)==null?"":__t)+" .fotorama__thumb-border{\r\nheight:"+((__t=v.h)==null?"":__t)+"px;\r\nborder-width:"+((__t=v.b)==null?"":__t)+"px;\r\nmargin-top:"+((__t=v.m)==null?"":__t)+"px}";return __p};$.Fotorama.jst.thumb=function(v){var __t,__p="",__e=_.escape;__p+='';return __p}})(window,document,location,typeof jQuery!=="undefined"&&jQuery);
\ No newline at end of file
diff --git a/lib/web/jquery/jquery-migrate.js b/lib/web/jquery/jquery-migrate.js
index 25b6c813146a3..d5ce9187d5bb5 100644
--- a/lib/web/jquery/jquery-migrate.js
+++ b/lib/web/jquery/jquery-migrate.js
@@ -1,13 +1,15 @@
/*!
- * jQuery Migrate - v1.2.1 - 2013-05-08
- * https://github.com/jquery/jquery-migrate
- * Copyright 2005, 2013 jQuery Foundation, Inc. and other contributors; Licensed MIT
+ * jQuery Migrate - v1.4.1 - 2016-05-19
+ * Copyright jQuery Foundation and other contributors
*/
(function( jQuery, window, undefined ) {
// See http://bugs.jquery.com/ticket/13335
// "use strict";
+jQuery.migrateVersion = "1.4.1";
+
+
var warnedAbout = {};
// List of warnings already given; public read only
@@ -17,8 +19,10 @@ jQuery.migrateWarnings = [];
// jQuery.migrateMute = false;
// Show a message on the console so devs know we're active
-if ( !jQuery.migrateMute && window.console && window.console.log ) {
- window.console.log("JQMIGRATE: Logging is active");
+if ( window.console && window.console.log ) {
+ window.console.log( "JQMIGRATE: Migrate is installed" +
+ ( jQuery.migrateMute ? "" : " with logging active" ) +
+ ", version " + jQuery.migrateVersion );
}
// Set to false to disable traces that appear with warnings
@@ -152,7 +156,7 @@ jQuery.attr = function( elem, name, value, pass ) {
// Warn only for attributes that can remain distinct from their properties post-1.9
if ( ruseDefault.test( lowerName ) ) {
- migrateWarn( "jQuery.fn.attr('" + lowerName + "') may use property instead of attribute" );
+ migrateWarn( "jQuery.fn.attr('" + lowerName + "') might use property instead of attribute" );
}
}
@@ -189,46 +193,114 @@ jQuery.attrHooks.value = {
var matched, browser,
oldInit = jQuery.fn.init,
+ oldFind = jQuery.find,
oldParseJSON = jQuery.parseJSON,
+ rspaceAngle = /^\s*,
+ rattrHashTest = /\[(\s*[-\w]+\s*)([~|^$*]?=)\s*([-\w#]*?#[-\w#]*)\s*\]/,
+ rattrHashGlob = /\[(\s*[-\w]+\s*)([~|^$*]?=)\s*([-\w#]*?#[-\w#]*)\s*\]/g,
// Note: XSS check is done below after string is trimmed
rquickExpr = /^([^<]*)(<[\w\W]+>)([^>]*)$/;
// $(html) "looks like html" rule change
jQuery.fn.init = function( selector, context, rootjQuery ) {
- var match;
+ var match, ret;
- if ( selector && typeof selector === "string" && !jQuery.isPlainObject( context ) &&
- (match = rquickExpr.exec( jQuery.trim( selector ) )) && match[ 0 ] ) {
- // This is an HTML string according to the "old" rules; is it still?
- if ( selector.charAt( 0 ) !== "<" ) {
- migrateWarn("$(html) HTML strings must start with '<' character");
- }
- if ( match[ 3 ] ) {
- migrateWarn("$(html) HTML text after last tag is ignored");
- }
- // Consistently reject any HTML-like string starting with a hash (#9521)
- // Note that this may break jQuery 1.6.x code that otherwise would work.
- if ( match[ 0 ].charAt( 0 ) === "#" ) {
- migrateWarn("HTML string cannot start with a '#' character");
- jQuery.error("JQMIGRATE: Invalid selector string (XSS)");
- }
- // Now process using loose rules; let pre-1.8 play too
- if ( context && context.context ) {
- // jQuery object as context; parseHTML expects a DOM object
- context = context.context;
+ if ( selector && typeof selector === "string" ) {
+ if ( !jQuery.isPlainObject( context ) &&
+ (match = rquickExpr.exec( jQuery.trim( selector ) )) && match[ 0 ] ) {
+
+ // This is an HTML string according to the "old" rules; is it still?
+ if ( !rspaceAngle.test( selector ) ) {
+ migrateWarn("$(html) HTML strings must start with '<' character");
+ }
+ if ( match[ 3 ] ) {
+ migrateWarn("$(html) HTML text after last tag is ignored");
+ }
+
+ // Consistently reject any HTML-like string starting with a hash (gh-9521)
+ // Note that this may break jQuery 1.6.x code that otherwise would work.
+ if ( match[ 0 ].charAt( 0 ) === "#" ) {
+ migrateWarn("HTML string cannot start with a '#' character");
+ jQuery.error("JQMIGRATE: Invalid selector string (XSS)");
+ }
+
+ // Now process using loose rules; let pre-1.8 play too
+ // Is this a jQuery context? parseHTML expects a DOM element (#178)
+ if ( context && context.context && context.context.nodeType ) {
+ context = context.context;
+ }
+
+ if ( jQuery.parseHTML ) {
+ return oldInit.call( this,
+ jQuery.parseHTML( match[ 2 ], context && context.ownerDocument ||
+ context || document, true ), context, rootjQuery );
+ }
}
- if ( jQuery.parseHTML ) {
- return oldInit.call( this, jQuery.parseHTML( match[ 2 ], context, true ),
- context, rootjQuery );
+ }
+
+ ret = oldInit.apply( this, arguments );
+
+ // Fill in selector and context properties so .live() works
+ if ( selector && selector.selector !== undefined ) {
+ // A jQuery object, copy its properties
+ ret.selector = selector.selector;
+ ret.context = selector.context;
+
+ } else {
+ ret.selector = typeof selector === "string" ? selector : "";
+ if ( selector ) {
+ ret.context = selector.nodeType? selector : context || document;
}
}
- return oldInit.apply( this, arguments );
+
+ return ret;
};
jQuery.fn.init.prototype = jQuery.fn;
+jQuery.find = function( selector ) {
+ var args = Array.prototype.slice.call( arguments );
+
+ // Support: PhantomJS 1.x
+ // String#match fails to match when used with a //g RegExp, only on some strings
+ if ( typeof selector === "string" && rattrHashTest.test( selector ) ) {
+
+ // The nonstandard and undocumented unquoted-hash was removed in jQuery 1.12.0
+ // First see if qS thinks it's a valid selector, if so avoid a false positive
+ try {
+ document.querySelector( selector );
+ } catch ( err1 ) {
+
+ // Didn't *look* valid to qSA, warn and try quoting what we think is the value
+ selector = selector.replace( rattrHashGlob, function( _, attr, op, value ) {
+ return "[" + attr + op + "\"" + value + "\"]";
+ } );
+
+ // If the regexp *may* have created an invalid selector, don't update it
+ // Note that there may be false alarms if selector uses jQuery extensions
+ try {
+ document.querySelector( selector );
+ migrateWarn( "Attribute selector with '#' must be quoted: " + args[ 0 ] );
+ args[ 0 ] = selector;
+ } catch ( err2 ) {
+ migrateWarn( "Attribute selector with '#' was not fixed: " + args[ 0 ] );
+ }
+ }
+ }
+
+ return oldFind.apply( this, args );
+};
+
+// Copy properties attached to original jQuery.find method (e.g. .attr, .isXML)
+var findProp;
+for ( findProp in oldFind ) {
+ if ( Object.prototype.hasOwnProperty.call( oldFind, findProp ) ) {
+ jQuery.find[ findProp ] = oldFind[ findProp ];
+ }
+}
+
// Let $.parseJSON(falsy_value) return null
jQuery.parseJSON = function( json ) {
- if ( !json && json !== null ) {
+ if ( !json ) {
migrateWarn("jQuery.parseJSON requires a valid JSON string");
return null;
}
@@ -274,6 +346,11 @@ if ( !jQuery.browser ) {
// Warn if the code tries to get jQuery.browser
migrateWarnProp( jQuery, "browser", jQuery.browser, "jQuery.browser is deprecated" );
+// jQuery.boxModel deprecated in 1.3, jQuery.support.boxModel deprecated in 1.7
+jQuery.boxModel = jQuery.support.boxModel = (document.compatMode === "CSS1Compat");
+migrateWarnProp( jQuery, "boxModel", jQuery.boxModel, "jQuery.boxModel is deprecated" );
+migrateWarnProp( jQuery.support, "boxModel", jQuery.support.boxModel, "jQuery.support.boxModel is deprecated" );
+
jQuery.sub = function() {
function jQuerySub( selector, context ) {
return new jQuerySub.fn.init( selector, context );
@@ -284,11 +361,10 @@ jQuery.sub = function() {
jQuerySub.fn.constructor = jQuerySub;
jQuerySub.sub = this.sub;
jQuerySub.fn.init = function init( selector, context ) {
- if ( context && context instanceof jQuery && !(context instanceof jQuerySub) ) {
- context = jQuerySub( context );
- }
-
- return jQuery.fn.init.call( this, selector, context, rootjQuerySub );
+ var instance = jQuery.fn.init.call( this, selector, context, rootjQuerySub );
+ return instance instanceof jQuerySub ?
+ instance :
+ jQuerySub( instance );
};
jQuerySub.fn.init.prototype = jQuerySub.fn;
var rootjQuerySub = jQuerySub(document);
@@ -296,6 +372,57 @@ jQuery.sub = function() {
return jQuerySub;
};
+// The number of elements contained in the matched element set
+jQuery.fn.size = function() {
+ migrateWarn( "jQuery.fn.size() is deprecated; use the .length property" );
+ return this.length;
+};
+
+
+var internalSwapCall = false;
+
+// If this version of jQuery has .swap(), don't false-alarm on internal uses
+if ( jQuery.swap ) {
+ jQuery.each( [ "height", "width", "reliableMarginRight" ], function( _, name ) {
+ var oldHook = jQuery.cssHooks[ name ] && jQuery.cssHooks[ name ].get;
+
+ if ( oldHook ) {
+ jQuery.cssHooks[ name ].get = function() {
+ var ret;
+
+ internalSwapCall = true;
+ ret = oldHook.apply( this, arguments );
+ internalSwapCall = false;
+ return ret;
+ };
+ }
+ });
+}
+
+jQuery.swap = function( elem, options, callback, args ) {
+ var ret, name,
+ old = {};
+
+ if ( !internalSwapCall ) {
+ migrateWarn( "jQuery.swap() is undocumented and deprecated" );
+ }
+
+ // Remember the old values, and insert the new ones
+ for ( name in options ) {
+ old[ name ] = elem.style[ name ];
+ elem.style[ name ] = options[ name ];
+ }
+
+ ret = callback.apply( elem, args || [] );
+
+ // Revert the old values
+ for ( name in options ) {
+ elem.style[ name ] = old[ name ];
+ }
+
+ return ret;
+};
+
// Ensure that $.ajax gets the new parseJSON defined in core.js
jQuery.ajaxSetup({
@@ -324,13 +451,7 @@ jQuery.fn.data = function( name ) {
};
-var rscriptType = /\/(java|ecma)script/i,
- oldSelf = jQuery.fn.andSelf || jQuery.fn.addBack;
-
-jQuery.fn.andSelf = function() {
- migrateWarn("jQuery.fn.andSelf() replaced by jQuery.fn.addBack()");
- return oldSelf.apply( this, arguments );
-};
+var rscriptType = /\/(java|ecma)script/i;
// Since jQuery.clean is used internally on older versions, we only shim if it's missing
if ( !jQuery.clean ) {
@@ -388,6 +509,7 @@ var eventAdd = jQuery.event.add,
oldToggle = jQuery.fn.toggle,
oldLive = jQuery.fn.live,
oldDie = jQuery.fn.die,
+ oldLoad = jQuery.fn.load,
ajaxEvents = "ajaxStart|ajaxStop|ajaxSend|ajaxComplete|ajaxError|ajaxSuccess",
rajaxEvent = new RegExp( "\\b(?:" + ajaxEvents + ")\\b" ),
rhoverHack = /(?:^|\s)hover(\.\S+|)\b/,
@@ -422,17 +544,35 @@ jQuery.event.remove = function( elem, types, handler, selector, mappedTypes ){
eventRemove.call( this, elem, hoverHack( types ) || "", handler, selector, mappedTypes );
};
-jQuery.fn.error = function() {
- var args = Array.prototype.slice.call( arguments, 0);
- migrateWarn("jQuery.fn.error() is deprecated");
- args.splice( 0, 0, "error" );
- if ( arguments.length ) {
- return this.bind.apply( this, args );
- }
- // error event should not bubble to window, although it does pre-1.7
- this.triggerHandler.apply( this, args );
- return this;
-};
+jQuery.each( [ "load", "unload", "error" ], function( _, name ) {
+
+ jQuery.fn[ name ] = function() {
+ var args = Array.prototype.slice.call( arguments, 0 );
+
+ // If this is an ajax load() the first arg should be the string URL;
+ // technically this could also be the "Anything" arg of the event .load()
+ // which just goes to show why this dumb signature has been deprecated!
+ // jQuery custom builds that exclude the Ajax module justifiably die here.
+ if ( name === "load" && typeof args[ 0 ] === "string" ) {
+ return oldLoad.apply( this, args );
+ }
+
+ migrateWarn( "jQuery.fn." + name + "() is deprecated" );
+
+ args.splice( 0, 0, name );
+ if ( arguments.length ) {
+ return this.bind.apply( this, args );
+ }
+
+ // Use .triggerHandler here because:
+ // - load and unload events don't need to bubble, only applied to window or image
+ // - error event should not bubble to window, although it does pre-1.7
+ // See http://bugs.jquery.com/ticket/11820
+ this.triggerHandler.apply( this, args );
+ return this;
+ };
+
+});
jQuery.fn.toggle = function( fn, fn2 ) {
@@ -501,7 +641,7 @@ jQuery.each( ajaxEvents.split("|"),
// The document needs no shimming; must be !== for oldIE
if ( elem !== document ) {
jQuery.event.add( document, name + "." + jQuery.guid, function() {
- jQuery.event.trigger( name, null, elem, true );
+ jQuery.event.trigger( name, Array.prototype.slice.call( arguments, 1 ), elem, true );
});
jQuery._data( this, name, jQuery.guid++ );
}
@@ -517,5 +657,97 @@ jQuery.each( ajaxEvents.split("|"),
}
);
+jQuery.event.special.ready = {
+ setup: function() {
+ if ( this === document ) {
+ migrateWarn( "'ready' event is deprecated" );
+ }
+ }
+};
+
+var oldSelf = jQuery.fn.andSelf || jQuery.fn.addBack,
+ oldFnFind = jQuery.fn.find;
+
+jQuery.fn.andSelf = function() {
+ migrateWarn("jQuery.fn.andSelf() replaced by jQuery.fn.addBack()");
+ return oldSelf.apply( this, arguments );
+};
+
+jQuery.fn.find = function( selector ) {
+ var ret = oldFnFind.apply( this, arguments );
+ ret.context = this.context;
+ ret.selector = this.selector ? this.selector + " " + selector : selector;
+ return ret;
+};
+
+
+// jQuery 1.6 did not support Callbacks, do not warn there
+if ( jQuery.Callbacks ) {
+
+ var oldDeferred = jQuery.Deferred,
+ tuples = [
+ // action, add listener, callbacks, .then handlers, final state
+ [ "resolve", "done", jQuery.Callbacks("once memory"),
+ jQuery.Callbacks("once memory"), "resolved" ],
+ [ "reject", "fail", jQuery.Callbacks("once memory"),
+ jQuery.Callbacks("once memory"), "rejected" ],
+ [ "notify", "progress", jQuery.Callbacks("memory"),
+ jQuery.Callbacks("memory") ]
+ ];
+
+ jQuery.Deferred = function( func ) {
+ var deferred = oldDeferred(),
+ promise = deferred.promise();
+
+ deferred.pipe = promise.pipe = function( /* fnDone, fnFail, fnProgress */ ) {
+ var fns = arguments;
+
+ migrateWarn( "deferred.pipe() is deprecated" );
+
+ return jQuery.Deferred(function( newDefer ) {
+ jQuery.each( tuples, function( i, tuple ) {
+ var fn = jQuery.isFunction( fns[ i ] ) && fns[ i ];
+ // deferred.done(function() { bind to newDefer or newDefer.resolve })
+ // deferred.fail(function() { bind to newDefer or newDefer.reject })
+ // deferred.progress(function() { bind to newDefer or newDefer.notify })
+ deferred[ tuple[1] ](function() {
+ var returned = fn && fn.apply( this, arguments );
+ if ( returned && jQuery.isFunction( returned.promise ) ) {
+ returned.promise()
+ .done( newDefer.resolve )
+ .fail( newDefer.reject )
+ .progress( newDefer.notify );
+ } else {
+ newDefer[ tuple[ 0 ] + "With" ](
+ this === promise ? newDefer.promise() : this,
+ fn ? [ returned ] : arguments
+ );
+ }
+ });
+ });
+ fns = null;
+ }).promise();
+
+ };
+
+ deferred.isResolved = function() {
+ migrateWarn( "deferred.isResolved is deprecated" );
+ return deferred.state() === "resolved";
+ };
+
+ deferred.isRejected = function() {
+ migrateWarn( "deferred.isRejected is deprecated" );
+ return deferred.state() === "rejected";
+ };
+
+ if ( func ) {
+ func.call( deferred, deferred );
+ }
+
+ return deferred;
+ };
+
+}
})( jQuery, window );
+
diff --git a/lib/web/jquery/jquery.ba-hashchange.min.js b/lib/web/jquery/jquery.ba-hashchange.min.js
deleted file mode 100644
index 3c607bae3d6ec..0000000000000
--- a/lib/web/jquery/jquery.ba-hashchange.min.js
+++ /dev/null
@@ -1,9 +0,0 @@
-/*
- * jQuery hashchange event - v1.3 - 7/21/2010
- * http://benalman.com/projects/jquery-hashchange-plugin/
- *
- * Copyright (c) 2010 "Cowboy" Ben Alman
- * Dual licensed under the MIT and GPL licenses.
- * http://benalman.com/about/license/
- */
-(function($,e,b){var c="hashchange",h=document,f,g=$.event.special,i=h.documentMode,d="on"+c in e&&(i===b||i>7);function a(j){j=j||location.href;return"#"+j.replace(/^[^#]*#?(.*)$/,"$1")}$.fn[c]=function(j){return j?this.bind(c,j):this.trigger(c)};$.fn[c].delay=50;g[c]=$.extend(g[c],{setup:function(){if(d){return false}$(f.start)},teardown:function(){if(d){return false}$(f.stop)}});f=(function(){var j={},p,m=a(),k=function(q){return q},l=k,o=k;j.start=function(){p||n()};j.stop=function(){p&&clearTimeout(p);p=b};function n(){var r=a(),q=o(m);if(r!==m){l(m=r,q);$(e).trigger(c)}else{if(q!==m){location.href=location.href.replace(/#.*/,"")+q}}p=setTimeout(n,$.fn[c].delay)}$.browser.msie&&!d&&(function(){var q,r;j.start=function(){if(!q){r=$.fn[c].src;r=r&&r+a();q=$('').hide().one("load",function(){r||l(a());n()}).attr("src",r||"javascript:0").insertAfter("body")[0].contentWindow;h.onpropertychange=function(){try{if(event.propertyName==="title"){q.document.title=h.title}}catch(s){}}}};j.stop=k;o=function(){return a(q.location.href)};l=function(v,s){var u=q.document,t=$.fn[c].domain;if(v!==s){u.title=h.title;u.open();t&&u.write('