diff --git a/Controller/Adminhtml/Ajax/Free/Image.php b/Controller/Adminhtml/Ajax/Free/Image.php index e210282..2784a18 100644 --- a/Controller/Adminhtml/Ajax/Free/Image.php +++ b/Controller/Adminhtml/Ajax/Free/Image.php @@ -76,7 +76,7 @@ public function execute() */ private function defaultTransformWithFreeTransform($freeTransform) { - $transformation = $this->configuration->getDefaultTransformation(); + $transformation = $this->configuration->getDefaultTransformation(true); if ($freeTransform) { $transformation->withFreeform(Freeform::fromString($freeTransform)); diff --git a/Core/CloudinaryImageProvider.php b/Core/CloudinaryImageProvider.php index 218a883..f8f6d54 100644 --- a/Core/CloudinaryImageProvider.php +++ b/Core/CloudinaryImageProvider.php @@ -134,7 +134,7 @@ public function retrieveTransformed(Image $image, Transformation $transformation 'sign_url' => $this->configuration->getUseSignedUrls(), 'version' => 1 ] - ); + ) . '?_i=AB'; if (!$this->configuration->isEnabledProductGallery()) { //Handle with use-root-path if necessary: diff --git a/Helper/ProductGalleryHelper.php b/Helper/ProductGalleryHelper.php index 9e9c309..8e3103c 100644 --- a/Helper/ProductGalleryHelper.php +++ b/Helper/ProductGalleryHelper.php @@ -94,6 +94,7 @@ public function getCloudinaryPGOptions($refresh = false, $ignoreDisabled = false unset($this->cloudinaryPGoptions['custom_free_params']); } $this->cloudinaryPGoptions['cloudName'] = $this->getCloudName(); + $this->cloudinaryPGoptions['queryParam'] = 'AB'; } return $this->cloudinaryPGoptions; diff --git a/Model/Config/Source/Dropdown/FreeTransformBehavior.php b/Model/Config/Source/Dropdown/FreeTransformBehavior.php new file mode 100644 index 0000000..2ed10c1 --- /dev/null +++ b/Model/Config/Source/Dropdown/FreeTransformBehavior.php @@ -0,0 +1,22 @@ + 'add', + 'label' => 'Add', + ], + [ + 'value' => 'override', + 'label' => 'Override', + ], + ]; + } +} diff --git a/Model/Configuration.php b/Model/Configuration.php index e579895..b065444 100644 --- a/Model/Configuration.php +++ b/Model/Configuration.php @@ -44,6 +44,8 @@ class Configuration implements ConfigurationInterface const CONFIG_PATH_DEFAULT_FETCH_FORMAT = 'cloudinary/transformations/cloudinary_fetch_format'; const CONFIG_PATH_DEFAULT_IMAGE = 'cloudinary/transformations/cloudinary_default_image'; const CONFIG_PATH_GLOBAL_FREEFORM = 'cloudinary/transformations/cloudinary_free_transform_global'; + const CONFIG_PATH_GLOBAL_FREEFORM_PRODUCTS = 'cloudinary/transformations/cloudinary_free_transform_global_products'; + const CONFIG_PATH_GLOBAL_FREEFORM_PRODUCTS_BEHAVIOR = 'cloudinary/transformations/cloudinary_free_transform_global_products_behavior'; //= Lazyload const XML_PATH_LAZYLOAD_ENABLED = 'cloudinary/lazyload/enabled'; @@ -231,15 +233,24 @@ public function getCredentials() } /** + * @param bool $isProduct * @return Transformation */ - public function getDefaultTransformation() + public function getDefaultTransformation($isProduct = false) { + if ($isProduct && ($globalFreeform = $this->getDefaultGlobalFreeformProducts())) { + if ($this->getDefaultGlobalFreeformProductsBehavior() === 'add') { + $globalFreeform = $this->getDefaultGlobalFreeform() . ',' . $globalFreeform; + } + } else { + $globalFreeform = $this->getDefaultGlobalFreeform(); + } + return Transformation::builder() ->withGravity(Gravity::fromString($this->getDefaultGravity())) ->withQuality(Quality::fromString($this->getImageQuality())) ->withFetchFormat(FetchFormat::fromString($this->getFetchFormat())) - ->withFreeform(Freeform::fromString($this->getDefaultGlobalFreeform())) + ->withFreeform(Freeform::fromString($globalFreeform)) ->withDpr(Dpr::fromString($this->getImageDpr())) ->withDefaultImage(DefaultImage::fromString($this->getCloudinaryDefaultImage())); } @@ -252,6 +263,22 @@ private function getDefaultGlobalFreeform() return (string) $this->configReader->getValue(self::CONFIG_PATH_GLOBAL_FREEFORM); } + /** + * @return string + */ + private function getDefaultGlobalFreeformProducts() + { + return (string) $this->configReader->getValue(self::CONFIG_PATH_GLOBAL_FREEFORM_PRODUCTS); + } + + /** + * @return string + */ + private function getDefaultGlobalFreeformProductsBehavior() + { + return (string) $this->configReader->getValue(self::CONFIG_PATH_GLOBAL_FREEFORM_PRODUCTS_BEHAVIOR); + } + /** * @return boolean */ @@ -575,11 +602,15 @@ public function getMagentoPlatformVersion() */ public function parseCloudinaryUrl($url, $publicId = null) { + $parsedUrlParts = $this->mbParseUrl($url); + $url = preg_replace('/\?.*/', '', $url); + $parsed = [ "orig_url" => $url, - "scheme" => null, - "host" => null, - "path" => null, + "scheme" => isset($parsedUrlParts["scheme"]) ? $parsedUrlParts["scheme"] : null, + "host" => isset($parsedUrlParts["host"]) ? $parsedUrlParts["host"] : null, + "path" => isset($parsedUrlParts["path"]) ? $parsedUrlParts["path"] : null, + "query" => isset($parsedUrlParts["query"]) ? $parsedUrlParts["query"] : null, "extension" => \pathinfo($url, PATHINFO_EXTENSION), "type" => null, "cloudName" => null, @@ -593,10 +624,6 @@ public function parseCloudinaryUrl($url, $publicId = null) "thumbnail_url" => null, ]; - $parsed["scheme"] = $this->mbParseUrl($url, PHP_URL_SCHEME); - $parsed["host"] = $this->mbParseUrl($url, PHP_URL_HOST); - $parsed["path"] = $this->mbParseUrl($url, PHP_URL_PATH); - $_url = ltrim($parsed["path"], '/'); $_url = preg_replace('/\.[^.]+$/', '', $_url); diff --git a/Model/GraphQLResolver/ProductAttributeCldResolver.php b/Model/GraphQLResolver/ProductAttributeCldResolver.php new file mode 100644 index 0000000..5520e6f --- /dev/null +++ b/Model/GraphQLResolver/ProductAttributeCldResolver.php @@ -0,0 +1,42 @@ +productGalleryManagement = $productGalleryManagement; + } + + /** + * @inheritdoc + */ + public function resolve(Field $field, $context, ResolveInfo $info, array $value = null, array $args = null) + { + $productId = $value['sku']; + $productMediaStr = $this->productGalleryManagement->getProductMedia($productId); + $jsonDecoder = new \Magento\Framework\Serialize\Serializer\Json(); + $productMedia = $jsonDecoder->unserialize($productMediaStr); + return $productMedia['data']; + } + } \ No newline at end of file diff --git a/Plugin/Catalog/Block/Product/ImageFactory.php b/Plugin/Catalog/Block/Product/ImageFactory.php index 1feb1bb..657f364 100644 --- a/Plugin/Catalog/Block/Product/ImageFactory.php +++ b/Plugin/Catalog/Block/Product/ImageFactory.php @@ -216,10 +216,10 @@ function () use ($imageBlock) { private function createTransformation(array $imageMiscParams) { $dimensions = $this->getDimensions($imageMiscParams); - $transform = $this->configuration->getDefaultTransformation()->withDimensions($dimensions); + $transform = $this->configuration->getDefaultTransformation(true)->withDimensions($dimensions); if (isset($imageMiscParams['keep_frame'])) { - $this->keepFrame = ($imageMiscParams['keep_frame'] === 'frame') ? true : false; + $this->keepFrame = (bool) $imageMiscParams['keep_frame']; } if ($this->keepFrame) { diff --git a/Plugin/Catalog/Model/Product/Image/UrlBuilder.php b/Plugin/Catalog/Model/Product/Image/UrlBuilder.php index 2d38ab4..60268a0 100644 --- a/Plugin/Catalog/Model/Product/Image/UrlBuilder.php +++ b/Plugin/Catalog/Model/Product/Image/UrlBuilder.php @@ -179,10 +179,10 @@ private function createTransformation(array $imageMiscParams) $imageMiscParams['image_height'] = (isset($imageMiscParams['image_height'])) ? $imageMiscParams['image_height'] : null; $imageMiscParams['image_width'] = (isset($imageMiscParams['image_width'])) ? $imageMiscParams['image_width'] : null; $dimensions = $this->dimensions ?: Dimensions::fromWidthAndHeight($imageMiscParams['image_width'], $imageMiscParams['image_height']); - $transform = $this->configuration->getDefaultTransformation()->withDimensions($dimensions); + $transform = $this->configuration->getDefaultTransformation(true)->withDimensions($dimensions); if (isset($imageMiscParams['keep_frame'])) { - $this->keepFrame = ($imageMiscParams['keep_frame'] === 'frame') ? true : false; + $this->keepFrame = (bool) $imageMiscParams['keep_frame']; } if ($this->keepFrame) { diff --git a/Ui/DataProvider/Product/Form/Modifier/Product.php b/Ui/DataProvider/Product/Form/Modifier/Product.php index ec2d268..71b5943 100644 --- a/Ui/DataProvider/Product/Form/Modifier/Product.php +++ b/Ui/DataProvider/Product/Form/Modifier/Product.php @@ -2,17 +2,17 @@ namespace Cloudinary\Cloudinary\Ui\DataProvider\Product\Form\Modifier; -use Cloudinary\Cloudinary\Core\Image; use Cloudinary\Cloudinary\Core\CloudinaryImageProvider; use Cloudinary\Cloudinary\Core\ConfigurationInterface; +use Cloudinary\Cloudinary\Core\Image; use Cloudinary\Cloudinary\Core\Image\Transformation; use Cloudinary\Cloudinary\Core\Image\Transformation\Freeform; -use Magento\Catalog\Model\Locator\LocatorInterface; -use Magento\Catalog\Ui\DataProvider\Product\Form\Modifier\AbstractModifier; -use Magento\Ui\Component\Form; use Cloudinary\Cloudinary\Model\TransformationFactory; +use Magento\Catalog\Model\Locator\LocatorInterface; use Magento\Catalog\Model\Product\Gallery\Entry; +use Magento\Catalog\Ui\DataProvider\Product\Form\Modifier\AbstractModifier; use Magento\Framework\UrlInterface; +use Magento\Ui\Component\Form; class Product extends AbstractModifier { @@ -102,11 +102,10 @@ public function modifyMeta(array $meta) 'collapsible' => true, 'opened' => false, 'componentType' => Form\Fieldset::NAME, - 'sortOrder' => - $this->getNextGroupSortOrder( - $meta, - static::GROUP_CONTENT, - static::SORT_ORDER + 'sortOrder' => $this->getNextGroupSortOrder( + $meta, + static::GROUP_CONTENT, + static::SORT_ORDER ), ], ], @@ -223,7 +222,7 @@ private function injectImageUrls(array $images) */ private function defaultTransformWithFreeTransform($freeTransform) { - $transformation = $this->configuration->getDefaultTransformation(); + $transformation = $this->configuration->getDefaultTransformation(true); if ($freeTransform) { $transformation->withFreeform(Freeform::fromString($freeTransform)); diff --git a/composer.json b/composer.json index cb537ae..4b1b87b 100644 --- a/composer.json +++ b/composer.json @@ -2,7 +2,7 @@ "name": "cloudinary/cloudinary-magento2", "description": "Cloudinary Magento 2 Integration.", "type": "magento2-module", - "version": "1.16.1", + "version": "1.17.0", "license": "MIT", "require": { "cloudinary/cloudinary_php": "^1.20.0" diff --git a/etc/adminhtml/system.xml b/etc/adminhtml/system.xml index af50f58..7ff03b4 100644 --- a/etc/adminhtml/system.xml +++ b/etc/adminhtml/system.xml @@ -42,7 +42,10 @@ - Automatically upload your existing Magento images to your Cloudinary account when an image is requested by a user. Once enabled, click the button below to map your Magento media directory to your Cloudinary account. + Automatically upload your existing Magento images to your Cloudinary account when an image is requested by a user. Once enabled, click the button below to map your Magento media directory to your Cloudinary account.

+

Note: Disabling auto upload mapping from Magento will not remove the configuration from Cloudinary. To completely disable your auto upload mapping, navigate to your Cloudinary Upload settings and clear the Auto upload mapping that corresponds to your Magento URLs.

]]> +
Magento\Config\Model\Config\Source\Yesno
@@ -84,7 +87,20 @@ Custom transformations will be added to the default image transformations settings chosen above.
For information about the full range of transforms available see the Cloudinary documentation.
You may need to clear or rebuild the Magento block and full page caches to see the changes in the front end.]]>
Cloudinary\Cloudinary\Model\Config\Backend\Free + cloudinary/transformations/cloudinary_free_transform_global +
+ + + for products only.
+ *Set the behavior of this field on the dropdown below.]]>
+ Cloudinary\Cloudinary\Model\Config\Backend\Free + cloudinary/transformations/cloudinary_free_transform_global_products +
+ + + Cloudinary\Cloudinary\Model\Config\Source\Dropdown\FreeTransformBehavior Cloudinary\Cloudinary\Block\Adminhtml\Form\Field\Free + cloudinary/transformations/cloudinary_free_transform_global_products_behavior diff --git a/etc/config.xml b/etc/config.xml index 2a6615e..14c5437 100644 --- a/etc/config.xml +++ b/etc/config.xml @@ -7,6 +7,7 @@ 1 auto 2.0 + add 1 diff --git a/etc/module.xml b/etc/module.xml index 9f63733..a4b59f0 100644 --- a/etc/module.xml +++ b/etc/module.xml @@ -1,6 +1,6 @@ - + diff --git a/etc/schema.graphqls b/etc/schema.graphqls new file mode 100644 index 0000000..8d2e385 --- /dev/null +++ b/etc/schema.graphqls @@ -0,0 +1,12 @@ +type CloudinaryData { + image: String + small_image: String + thumbnail: String + media_gallery: [String] +} + +interface ProductInterface { + cld_data: CloudinaryData + @resolver(class: "\\Cloudinary\\Cloudinary\\Model\\GraphQLResolver\\ProductAttributeCldResolver") + @doc(description: "Cloudinary urls generated for product images") +} \ No newline at end of file diff --git a/marketplace.composer.json b/marketplace.composer.json index 7f77c21..d1f8008 100644 --- a/marketplace.composer.json +++ b/marketplace.composer.json @@ -1,18 +1,18 @@ { - "name": "cloudinary/cloudinary", - "description": "Cloudinary Magento 2 Integration.", - "type": "magento2-module", - "version": "1.16.1", - "license": "MIT", - "require": { - "cloudinary/cloudinary_php": "^1.20.0" - }, - "autoload": { - "files": [ - "registration.php" - ], - "psr-4": { - "Cloudinary\\Cloudinary\\": "" - } + "name": "cloudinary/cloudinary", + "description": "Cloudinary Magento 2 Integration.", + "type": "magento2-module", + "version": "1.17.0", + "license": "MIT", + "require": { + "cloudinary/cloudinary_php": "^1.20.0" + }, + "autoload": { + "files": [ + "registration.php" + ], + "psr-4": { + "Cloudinary\\Cloudinary\\": "" } + } } \ No newline at end of file diff --git a/view/adminhtml/templates/config/free.phtml b/view/adminhtml/templates/config/free.phtml index 95b8ef0..82b49cc 100644 --- a/view/adminhtml/templates/config/free.phtml +++ b/view/adminhtml/templates/config/free.phtml @@ -18,5 +18,5 @@
", "ajaxKey": "getFormKey() ?>"}}'> + data-mage-init='{"cloudinaryFreeTransform":{"previewButtonId": "#cloudinary_free_transform_preview_button", "transformInputFieldId": "#cloudinary_transformations_cloudinary_free_transform_global", "transformInputProductsFieldId": "#cloudinary_transformations_cloudinary_free_transform_global_products", "transformInputProductsBehaviorFieldId": "#cloudinary_transformations_cloudinary_free_transform_global_products_behavior", "ajaxUrl": "getUrl('cloudinary/ajax_free/sample') ?>", "ajaxKey": "getFormKey() ?>"}}'>
diff --git a/view/adminhtml/ui_component/pagebuilder_base_form_with_background_video.xml b/view/adminhtml/ui_component/pagebuilder_base_form_with_background_video.xml new file mode 100644 index 0000000..2b74c1a --- /dev/null +++ b/view/adminhtml/ui_component/pagebuilder_base_form_with_background_video.xml @@ -0,0 +1,18 @@ + + +
+
+ + + + Video URLs can be links to videos on YouTube, Vimeo or Cloudinary, or HTTP(S) links to files with valid video extensions (we recommend .mp4) + + + +
+
diff --git a/view/adminhtml/ui_component/pagebuilder_video_form.xml b/view/adminhtml/ui_component/pagebuilder_video_form.xml index c64340f..81ef393 100644 --- a/view/adminhtml/ui_component/pagebuilder_video_form.xml +++ b/view/adminhtml/ui_component/pagebuilder_video_form.xml @@ -6,15 +6,13 @@ */ -->
-
- +
+ - - true - - text - - YouTube, Vimeo and Cloudinary are supported + + Video URLs can be links to videos on YouTube, Vimeo or Cloudinary, or HTTP(S) links to files with valid video extensions (we recommend .mp4) + + Video URLs can be links to videos on YouTube, Vimeo or Cloudinary, or HTTP(S) links to files with valid video extensions (we recommend .mp4)
diff --git a/view/adminhtml/web/css/source/_module.less b/view/adminhtml/web/css/source/_module.less index 642d941..b3e98a9 100644 --- a/view/adminhtml/web/css/source/_module.less +++ b/view/adminhtml/web/css/source/_module.less @@ -1,5 +1,5 @@ .cloudinary-configuration-tab .admin__page-nav-title strong:before { - background-image: url("Cloudinary_Cloudinary::images/cloudinary_icon_for_white_bg.svg"); + background-image: url("Cloudinary_Cloudinary::images/cloudinary_cloud_glyph_regular.svg"); background-size: contain; background-repeat: no-repeat; background-position: center center; @@ -31,7 +31,7 @@ padding: 6px 14px 6px 50px; &:before { - background-image: url("Cloudinary_Cloudinary::images/cloudinary_icon_for_blue_bg.svg"); + background-image: url("Cloudinary_Cloudinary::images/cloudinary_cloud_glyph_white.svg"); background-repeat: no-repeat; background-size: contain; background-position: center; diff --git a/view/adminhtml/web/js/cloudinary-free.js b/view/adminhtml/web/js/cloudinary-free.js index 374c9b8..e98ed72 100644 --- a/view/adminhtml/web/js/cloudinary-free.js +++ b/view/adminhtml/web/js/cloudinary-free.js @@ -9,46 +9,60 @@ define( 'cloudinary.cloudinaryFreeTransform', { currentTransform: '', + currentTransformProducts: '', + currentTransformBehavior: '', getTransformText: function() { - return $(this.options.transformInputFieldId).val(); + return $(this.options.transformInputFieldId).val() || ''; }, - getImageHtml: function(src) { - var id = 'cloudinary_custom_transform_preview_image', - style = 'width: auto; height: auto; max-width: 500px; max-height: 500px; min-height: 50px;', + getTransformProductsText: function() { + return $(this.options.transformInputProductsFieldId).val() || ''; + }, + + getTransformBehavior: function() { + return $(this.options.transformInputProductsBehaviorFieldId).val(); + }, + + getImageHtml: function(src, header) { + if (!src) { + return ''; + } + var cls = 'cloudinary_custom_transform_preview_image', + style = 'width: auto; height: auto; max-width: 350px; max-height: 350px; min-height: 50px;', + header = header || '', footer = '

Image size restricted for viewing purposes

'; - return '' + footer; + return header + '' + footer; }, getErrorHtml: function(message) { return '
  • ' + message + '
'; }, - updatePreviewImage: function(url) { - var $image = $('#cloudinary_custom_transform_preview_image'); - - if (!$image.length) { - $('#cloudinary_custom_transform_preview').html(this.getImageHtml(url)); - } else { - $image.attr('src', url); - } + updatePreviewImage: function(url, url2) { + $('#cloudinary_custom_transform_preview').html( + this.getImageHtml(url, '

Global Custom Transformation Preview

') + + this.getImageHtml(url2, '

Products Custom Transformation Preview

') + ); }, updatePreview: function() { - var self = this; + var self = this, + transformations_string = ""; if (!self.isPreviewActive()) { return; } self.currentTransform = self.getTransformText(); + self.currentTransformProducts = self.getTransformProductsText(); + self.currentTransformBehavior = self.getTransformBehavior(); self.setPreviewActiveState(false); $.ajax({ url: this.options.ajaxUrl, data: { - free: self.getTransformText(), + free: self.currentTransform, form_key: self.options.ajaxKey }, type: 'post', @@ -56,7 +70,33 @@ define( showLoader: true }).done( function(response) { - self.updatePreviewImage(response.url); + if ((transformations_string = self.currentTransformProducts)) { + if (self.currentTransformBehavior === 'add') { + transformations_string = self.currentTransform + ',' + transformations_string; + } + var globalResURL = response.url; + $.ajax({ + url: self.options.ajaxUrl, + data: { + free: transformations_string, + form_key: self.options.ajaxKey + }, + type: 'post', + dataType: 'json', + showLoader: true + }).done( + function(response) { + self.updatePreviewImage(globalResURL, response.url); + } + ).fail( + function(result) { + $('#cloudinary_custom_transform_preview').html(self.getErrorHtml(result.responseJSON.error)); + } + ); + } else { + return self.updatePreviewImage(response.url); + transformations_string = self.getTransformText(); + } } ).fail( function(result) { @@ -66,7 +106,14 @@ define( }, setPreviewActiveState: function(state) { - if (state && (this.currentTransform !== this.getTransformText())) { + if ( + state && + ( + this.currentTransform !== this.getTransformText() || + this.currentTransformProducts !== this.getTransformProductsText() || + (this.getTransformProductsText() && this.currentTransformBehavior !== this.getTransformBehavior()) + ) + ) { $(this.options.previewButtonId).removeClass('disabled'); } else { $(this.options.previewButtonId).addClass('disabled'); @@ -92,6 +139,18 @@ define( self.setPreviewActiveState(true); } ); + $(this.options.transformInputProductsFieldId).on( + 'change keydown paste input', + function() { + self.setPreviewActiveState(true); + } + ); + $(this.options.transformInputProductsBehaviorFieldId).on( + 'change', + function() { + self.setPreviewActiveState(true); + } + ); } } diff --git a/view/adminhtml/web/js/cloudinary-media-library-modal.js b/view/adminhtml/web/js/cloudinary-media-library-modal.js index 2377a50..fde8b08 100644 --- a/view/adminhtml/web/js/cloudinary-media-library-modal.js +++ b/view/adminhtml/web/js/cloudinary-media-library-modal.js @@ -115,7 +115,7 @@ define([ asset.asset_derived_image_url .replace(new RegExp('^.*cloudinary.com/(' + this.options.cloudinaryMLoptions.cloud_name + '/)?' + asset.resource_type + '/' + asset.type + '/'), '') .replace(/\.[^/.]+$/, '') - .replace(new RegExp('\/' + widget.escapeRegex(encodeURI(asset.public_id)) + '$'), '') + .replace(new RegExp('\/' + widget.escapeRegex(encodeURI(decodeURI(asset.public_id))) + '$'), '') .replace(new RegExp('\/v[0-9]{1,10}$'), '') .replace(new RegExp('\/'), ','); if (widget.options.useDerived) { @@ -126,7 +126,7 @@ define([ asset.asset_image_url = asset.asset_url .replace(/\.[^/.]+$/, "") .replace(new RegExp('\/v[0-9]{1,10}\/'), '/') - .replace(new RegExp('\/(' + widget.escapeRegex(encodeURI(asset.public_id)) + ')$'), '/so_auto/$1.jpg'); + .replace(new RegExp('\/(' + widget.escapeRegex(encodeURI(decodeURI(asset.public_id))) + ')$'), '/so_auto/$1.jpg'); } $.ajax({ url: widget.options.imageUploaderUrl, @@ -212,4 +212,4 @@ define([ }); return $.mage.cloudinaryMediaLibraryModal; -}); \ No newline at end of file +}); diff --git a/view/adminhtml/web/js/form/element/validator-rules-mixin.js b/view/adminhtml/web/js/form/element/validator-rules-mixin.js index 445945f..b33b223 100644 --- a/view/adminhtml/web/js/form/element/validator-rules-mixin.js +++ b/view/adminhtml/web/js/form/element/validator-rules-mixin.js @@ -20,6 +20,7 @@ define([ } return function(validator) { + validator.addRule( 'validate-video-url', function(href) { @@ -29,10 +30,35 @@ define([ href = (href || '').replace(/^\s+/, '').replace(/\s+$/, ''); - return validateIsUrl(href) && (href.match(/youtube\.com|youtu\.be/) || href.match(/vimeo\.com/) || href.match(/cloudinary\.com/)); + return validateIsUrl(href) && ( + href.match(/youtube\.com|youtu\.be/) || + href.match(/vimeo\.com/) || + href.match(/cloudinary\.com/) || + href.match(/\.(mp4|ogv|webm)(?!\w)/) + ); + }, + $.mage.__('Please enter a valid video URL. Valid URLs have a video file extension (.mp4, .webm, .ogv) or links to videos on YouTube, Vimeo or Cloudinary.')//eslint-disable-line max-len + ); + + validator.addRule( + 'validate-video-source', + function (href) { + if (utils.isEmptyNoTrim(href)) { + return true; + } + + href = (href || '').replace(/^\s+/, '').replace(/\s+$/, ''); + + return validateIsUrl(href) && ( + href.match(/youtube\.com|youtu\.be/) || + href.match(/vimeo\.com/) || + href.match(/cloudinary\.com/) || + href.match(/\.(mp4|ogv|webm)(?!\w)/) + ); }, - $.mage.__('Please enter a valid video URL.') + $.mage.__('Please enter a valid video URL. Valid URLs have a video file extension (.mp4, .webm, .ogv) or links to videos on YouTube, Vimeo or Cloudinary.')//eslint-disable-line max-len ); + return validator; }; -}); \ No newline at end of file +}); diff --git a/view/adminhtml/web/js/get-video-information.js b/view/adminhtml/web/js/get-video-information.js index 9cee8d7..db001c9 100644 --- a/view/adminhtml/web/js/get-video-information.js +++ b/view/adminhtml/web/js/get-video-information.js @@ -110,44 +110,45 @@ define( /** * Abstract play command */ - play: function() { + play: function () { this._player.play(); }, /** * Abstract pause command */ - pause: function() { + pause: function () { this._player.pause(); }, /** * Abstract stop command */ - stop: function() { + stop: function () { this._player.stop(); }, /** * Abstract playing command */ - playing: function() { + playing: function () { return this._player.playing(); }, /** * Abstract destroying command */ - destroy: function() { - this._player.destroy(); + destroy: function () { + if (this._player) { + this._player.destroy(); + } }, /** * Calculates ratio for responsive videos - * * @private */ - _calculateRatio: function() { + _calculateRatio: function () { if (!this._responsive) { return; } @@ -314,43 +315,40 @@ define( } ); - $.widget( - 'mage.videoVimeo', $.mage.productVideoLoader, { + $.widget('mage.videoVimeo', $.mage.productVideoLoader, { - /** - * Initialize the Vimeo widget - * - * @private - */ - _create: function() { - var timestamp, - src, - additionalParams; + /** + * Initialize the Vimeo widget + * @private + */ + _create: function () { + var timestamp, + src, + additionalParams; - this._initialize(); - timestamp = new Date().getTime(); + this._initialize(); + timestamp = new Date().getTime(); - if (this._autoplay) { - additionalParams += '&autoplay=1'; - } + if (this._autoplay) { + additionalParams += '&autoplay=1'; + } - src = 'https://player.vimeo.com/video/' + - this._code + '?api=1&player_id=vimeo' + - this._code + - timestamp + - additionalParams; - this.element.append( - $('