[BUGFIX] Add possibility to define crop variants per table 51/51951/11
authorHelmut Hummel <typo3@helhum.io>
Thu, 2 Mar 2017 13:14:31 +0000 (14:14 +0100)
committerHelmut Hummel <typo3@helhum.io>
Tue, 7 Mar 2017 15:48:25 +0000 (16:48 +0100)
Currently it is not possible to define crop variants per
table or content type. This makes this feature a lot less useful
as it could be.

Add a form data provider to make this possible.

Also fix the issue that the full size image is used instead of
a smaller variant in the interface and hide the cropping
tool if no image size can be determined (happens for some SVGs).

Focus area now also works when no cover areas are defined.

Resolves: #80105
Resolves: #80157
Resolves: #79961
Releases: master
Change-Id: I3333a59c84b6f55f7bf300663ea2ff52bf70e698
Reviewed-on: https://review.typo3.org/51951
Reviewed-by: Georg Ringer <georg.ringer@gmail.com>
Tested-by: Georg Ringer <georg.ringer@gmail.com>
Tested-by: TYPO3com <no-reply@typo3.com>
Reviewed-by: Joerg Boesche <typo3@joergboesche.de>
Tested-by: Joerg Boesche <typo3@joergboesche.de>
Reviewed-by: Helmut Hummel <typo3@helhum.io>
Tested-by: Helmut Hummel <typo3@helhum.io>
typo3/sysext/backend/Classes/Form/FormDataProvider/TcaOverrideChildCroppingConfiguration.php [new file with mode: 0644]
typo3/sysext/backend/Resources/Private/Templates/ImageManipulation/ImageManipulationElement.html
typo3/sysext/backend/Resources/Private/Templates/ImageManipulation/ImageManipulationWizard.html
typo3/sysext/backend/Resources/Private/TypeScript/ImageManipulation.ts
typo3/sysext/backend/Resources/Public/JavaScript/ImageManipulation.js
typo3/sysext/core/Configuration/DefaultConfiguration.php
typo3/sysext/core/Documentation/Changelog/8.6/Feature-75880-ImplementMultipleCroppingVariantsInImageManipulationTool.rst
typo3/sysext/lang/Resources/Private/Language/locallang_wizards.xlf

diff --git a/typo3/sysext/backend/Classes/Form/FormDataProvider/TcaOverrideChildCroppingConfiguration.php b/typo3/sysext/backend/Classes/Form/FormDataProvider/TcaOverrideChildCroppingConfiguration.php
new file mode 100644 (file)
index 0000000..3f63e88
--- /dev/null
@@ -0,0 +1,44 @@
+<?php
+declare(strict_types=1);
+namespace TYPO3\CMS\Backend\Form\FormDataProvider;
+
+/*
+ * This file is part of the TYPO3 CMS project.
+ *
+ * It is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License, either version 2
+ * of the License, or any later version.
+ *
+ * For the full copyright and license information, please read the
+ * LICENSE.txt file that was distributed with this source code.
+ *
+ * The TYPO3 project - inspiring people to share!
+ */
+
+use TYPO3\CMS\Backend\Form\FormDataProviderInterface;
+
+/**
+ * Override cropping configuration of child (mostly sys_file_reference) TCA
+ */
+class TcaOverrideChildCroppingConfiguration extends AbstractItemProvider implements FormDataProviderInterface
+{
+    /**
+     * @param array $result
+     * @return array
+     */
+    public function addData(array $result)
+    {
+        if (isset($result['inlineParentConfig']['overrideCropVariants'])
+            && is_array($result['inlineParentConfig']['overrideCropVariants'])) {
+            foreach ($result['inlineParentConfig']['overrideCropVariants'] as $fieldName => $cropVariantsConfig) {
+                if (
+                    isset($result['processedTca']['columns'][$fieldName]['config']['type'])
+                    && $result['processedTca']['columns'][$fieldName]['config']['type'] === 'imageManipulation'
+                ) {
+                    $result['processedTca']['columns'][$fieldName]['config']['cropVariants'] = $cropVariantsConfig;
+                }
+            }
+        }
+        return $result;
+    }
+}
index 1644a76..51ac543 100644 (file)
@@ -3,7 +3,7 @@
        <f:layout name="ImageManipulation" />
 
        <f:section name="Main">
-               <f:if condition="{isAllowedFileExtension}">
+               <f:if condition="{isAllowedFileExtension} && {image.properties.width}">
                        <f:then>
                                <f:if condition="{config.readOnly}">
                                        <f:else>
                        </f:then>
                        <f:else>
                                <div class="media-body">
-                                       <p>
-                                               <em>
-                                                       <f:translate id="LLL:EXT:lang/Resources/Private/Language/locallang_wizards.xlf:imwizard.supported-types-message" /><br/>
-                                                       {config.allowedExtensions -> f:format.case(mode: 'upper')}
-                                               </em>
-                                       </p>
+                               <f:if condition="{image.properties.width}">
+                                       <f:then>
+                                               <p>
+                                                       <em>
+                                                               <f:translate id="LLL:EXT:lang/Resources/Private/Language/locallang_wizards.xlf:imwizard.supported-types-message" /><br/>
+                                                               {config.allowedExtensions -> f:format.case(mode: 'upper')}
+                                                       </em>
+                                               </p>
+                                       </f:then>
+                                       <f:else>
+                                               <h4 class="alert-title">
+                                                       <f:translate key="LLL:EXT:lang/Resources/Private/Language/locallang_wizards.xlf:imwizard.no-image-dimensions"/>
+                                               </h4>
+                                               <p class="alert-message">
+                                                       <f:translate key="LLL:EXT:lang/Resources/Private/Language/locallang_wizards.xlf:imwizard.no-image-dimensions-message"/>
+                                               </p>
+                                       </f:else>
+                               </f:if>
                                </div>
                        </f:else>
                </f:if>
index fd9e97a..767dc56 100644 (file)
        xmlns:core="http://typo3.org/ns/TYPO3/CMS/Core/ViewHelpers">
 
        <f:section name="Main">
-               <f:if condition="{image.properties.width}">
-                       <f:then>
-                               <div class="modal-header">
-                                       <button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">×</span>
-                                       </button>
-                                       <h4 class="modal-title">
-                                               {f:render(partial: 'ModalTitle', section:'Main', arguments: _all)}
-                                       </h4>
+               <div class="modal-header">
+                       <button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">×</span>
+                       </button>
+                       <h4 class="modal-title">
+                               {f:render(partial: 'ModalTitle', section:'Main', arguments: _all)}
+                       </h4>
+               </div>
+               <div class="cropper modal-panel">
+                       <div class="modal-panel-body">
+                               <div id="t3js-crop-image-container" class="cropper-image-container">
+                                       <f:image image="{image}" maxWidth="1000" maxHeight="1000" id="t3js-crop-image" class="cropper-image-container-image" additionalAttributes="{data-original-width: image.properties.width, data-original-height: image.properties.height}" />
                                </div>
-                               <div class="cropper modal-panel">
-                                       <div class="modal-panel-body">
-                                               <div id="t3js-crop-image-container" class="cropper-image-container">
-                                                       <f:image image="{image}" id="t3js-crop-image" class="cropper-image-container-image" additionalAttributes="{data-original-width: image.properties.width, data-original-height: image.properties.height}" />
-                                               </div>
-                                       </div>
-                                       <div class="modal-panel-sidebar modal-panel-sidebar-right">
-                                               <div class="modal-body">
-                                                       <div class="panel-group" id="accordion-cropper-variants" role="tablist" aria-multiselectable="true">
-                                                               <f:for each="{cropVariants}" as="cropVariant" iteration="cropVariantIterator">
-                                                                       <div class="panel panel-default">
-                                                                               <div class="panel-heading" role="tab" id="cropper-accordion-heading-{cropVariantIterator.cycle}">
-                                                                                       <h4 class="panel-title">
-                                                                                               <a role="button" data-toggle="collapse" data-parent="#accordion-cropper-variants"
-                                                                                                        href="#cropper-collapse-{cropVariantIterator.cycle}"
-                                                                                                        aria-expanded="{f:if(condition:cropVariantIterator.isFirst, then:'true', else:'false')}"
-                                                                                                        aria-controls="cropper-collapse-{cropVariantIterator.cycle}"
-                                                                                                        class="t3js-crop-variant-trigger {f:if(condition:cropVariantIterator.isFirst, then:'is-active', else:'collapsed')}"
-                                                                                                        data-crop-variant-id="{cropVariant.id}"
-                                                                                                        data-crop-variant>
-                                                                                               <span><i class="fa fa-chevron-{f:if(condition:cropVariantIterator.isFirst, then:'up', else:'down')}"
-                                                                                                                                aria-hidden="true"></i> {cropVariant.title -> f:translate(id: cropVariant.title)}</span>
-                                                                                                       <div
-                                                                                                               class="cropper-preview-thumbnail {f:if(condition:'{image.properties.width}>{image.properties.height}', then:'wide', else: 'tall')}">
-                                                                                                               <img class="cropper-preview-thumbnail-image"
-                                                                                                                                src="{f:uri.image(image:image, maxWidth:'300', maxHeight: '300')}">
-                                                                                                               <div class="cropper-preview-thumbnail-crop-area t3js-cropper-preview-thumbnail-crop-area">
-                                                                                                                       <img src="{f:uri.image(image:image, maxWidth:'300', maxHeight: '300')}"
-                                                                                                                                        class="cropper-preview-thumbnail-crop-image t3js-cropper-preview-thumbnail-crop-image">
-                                                                                                                       <div class="cropper-preview-thumbnail-focus-area t3js-cropper-preview-thumbnail-focus-area"></div>
-                                                                                                               </div>
-                                                                                                       </div>
-                                                                                               </a>
-                                                                                       </h4>
-                                                                               </div>
-                                                                               <div id="cropper-collapse-{cropVariantIterator.cycle}"
-                                                                                                class="panel-collapse collapse {f:if(condition:cropVariantIterator.isFirst, then:'in')}"
-                                                                                                role="tabpanel"
-                                                                                                aria-labelledby="cropper-accordion-heading-{cropVariantIterator.cycle}">
-                                                                                       <div class="panel-body">
-                                                                                               <form class="form">
-                                                                                                       <div class="form-group">
-                                                                                                               <f:if condition="{cropVariant.allowedAspectRatios}">
-                                                                                                                       <label for="ratio-{cropVariantIterator.cycle}">
-                                                                                                                               <f:translate id="LLL:EXT:lang/Resources/Private/Language/locallang_wizards.xlf:imwizard.aspect-ratio"/>
-                                                                                                                       </label>
-                                                                                                                       <div id="ratio-{cropVariantIterator.cycle}" class="ratio-buttons t3js-ratio-buttons"
-                                                                                                                                        data-toggle="buttons">
-                                                                                                                               <f:for each="{cropVariant.allowedAspectRatios}" as="ratio" iteration="ratioIterator">
-                                                                                                                                       <label class="btn btn-secondary" data-method="setAspectRatio" data-option="{ratio.id}" title="{f:translate(id:'LLL:EXT:lang/Resources/Private/Language/locallang_wizards.xlf:imwizard.set-aspect-ratio')}">
-                                                                                                                                               <input
-                                                                                                                                                       class="sr-only" id="aspectRatio-{cropVariantIterator.cycle}-{ratioIterator.cycle}"
-                                                                                                                                                       name="aspectRatio-{cropVariantIterator.cycle}-{ratioIterator.cycle}" value="{cropVariant.id}"
-                                                                                                                                                       type="radio">
-                                                                                                                                               <span>{ratio.title -> f:translate(id: ratio.title)}</span> <i class="fa fa-check"></i></label>
-                                                                                                                               </f:for>
-                                                                                                                       </div>
-                                                                                                               </f:if>
-                                                                                                               <label><f:translate key="LLL:EXT:lang/Resources/Private/Language/locallang_wizards.xlf:imwizard.selection" /></label>
-                                                                                                               <div class="table-fit-block">
-                                                                                                                       <table class="table table-no-borders table-transparent">
-                                                                                                                               <tr>
-                                                                                                                                       <td class="t3js-cropper-info-crop"></td>
-                                                                                                                               </tr>
-                                                                                                                       </table>
-                                                                                                               </div>
-                                                                                                               <button class="btn btn-secondary" data-method="reset" data-crop-variant="{cropVariant -> f:format.json()}"
-                                                                                                                                               title="{f:translate(key:'LLL:EXT:lang/Resources/Private/Language/locallang_wizards.xlf:imwizard.reset')}">
-                                                                                                                       <i class="fa fa-refresh"></i>
-                                                                                                                       {f:translate(key:'LLL:EXT:lang/Resources/Private/Language/locallang_wizards.xlf:imwizard.reset')}
-                                                                                                               </button>
+                       </div>
+                       <div class="modal-panel-sidebar modal-panel-sidebar-right">
+                               <div class="modal-body">
+                                       <div class="panel-group" id="accordion-cropper-variants" role="tablist" aria-multiselectable="true">
+                                               <f:for each="{cropVariants}" as="cropVariant" iteration="cropVariantIterator">
+                                                       <div class="panel panel-default">
+                                                               <div class="panel-heading" role="tab" id="cropper-accordion-heading-{cropVariantIterator.cycle}">
+                                                                       <h4 class="panel-title">
+                                                                               <a role="button" data-toggle="collapse" data-parent="#accordion-cropper-variants"
+                                                                                        href="#cropper-collapse-{cropVariantIterator.cycle}"
+                                                                                        aria-expanded="{f:if(condition:cropVariantIterator.isFirst, then:'true', else:'false')}"
+                                                                                        aria-controls="cropper-collapse-{cropVariantIterator.cycle}"
+                                                                                        class="t3js-crop-variant-trigger {f:if(condition:cropVariantIterator.isFirst, then:'is-active', else:'collapsed')}"
+                                                                                        data-crop-variant-id="{cropVariant.id}"
+                                                                                        data-crop-variant>
+                                                                               <span><i class="fa fa-chevron-{f:if(condition:cropVariantIterator.isFirst, then:'up', else:'down')}"
+                                                                                                                aria-hidden="true"></i> {cropVariant.title -> f:translate(id: cropVariant.title)}</span>
+                                                                                       <div
+                                                                                               class="cropper-preview-thumbnail {f:if(condition:'{image.properties.width}>{image.properties.height}', then:'wide', else: 'tall')}">
+                                                                                               <img class="cropper-preview-thumbnail-image"
+                                                                                                                src="{f:uri.image(image:image, maxWidth:'300', maxHeight: '300')}">
+                                                                                               <div class="cropper-preview-thumbnail-crop-area t3js-cropper-preview-thumbnail-crop-area">
+                                                                                                       <img src="{f:uri.image(image:image, maxWidth:'300', maxHeight: '300')}"
+                                                                                                                        class="cropper-preview-thumbnail-crop-image t3js-cropper-preview-thumbnail-crop-image">
+                                                                                                       <div class="cropper-preview-thumbnail-focus-area t3js-cropper-preview-thumbnail-focus-area"></div>
+                                                                                               </div>
+                                                                                       </div>
+                                                                               </a>
+                                                                       </h4>
+                                                               </div>
+                                                               <div id="cropper-collapse-{cropVariantIterator.cycle}"
+                                                                                class="panel-collapse collapse {f:if(condition:cropVariantIterator.isFirst, then:'in')}"
+                                                                                role="tabpanel"
+                                                                                aria-labelledby="cropper-accordion-heading-{cropVariantIterator.cycle}">
+                                                                       <div class="panel-body">
+                                                                               <form class="form">
+                                                                                       <div class="form-group">
+                                                                                               <f:if condition="{cropVariant.allowedAspectRatios}">
+                                                                                                       <label for="ratio-{cropVariantIterator.cycle}">
+                                                                                                               <f:translate id="LLL:EXT:lang/Resources/Private/Language/locallang_wizards.xlf:imwizard.aspect-ratio"/>
+                                                                                                       </label>
+                                                                                                       <div id="ratio-{cropVariantIterator.cycle}" class="ratio-buttons t3js-ratio-buttons"
+                                                                                                                        data-toggle="buttons">
+                                                                                                               <f:for each="{cropVariant.allowedAspectRatios}" as="ratio" iteration="ratioIterator">
+                                                                                                                       <label class="btn btn-secondary" data-method="setAspectRatio" data-option="{ratio.id}" title="{f:translate(id:'LLL:EXT:lang/Resources/Private/Language/locallang_wizards.xlf:imwizard.set-aspect-ratio')}">
+                                                                                                                               <input
+                                                                                                                                       class="sr-only" id="aspectRatio-{cropVariantIterator.cycle}-{ratioIterator.cycle}"
+                                                                                                                                       name="aspectRatio-{cropVariantIterator.cycle}-{ratioIterator.cycle}" value="{cropVariant.id}"
+                                                                                                                                       type="radio">
+                                                                                                                               <span>{ratio.title -> f:translate(id: ratio.title)}</span> <i class="fa fa-check"></i></label>
+                                                                                                               </f:for>
                                                                                                        </div>
-                                                                                               </form>
+                                                                                               </f:if>
+                                                                                               <label><f:translate key="LLL:EXT:lang/Resources/Private/Language/locallang_wizards.xlf:imwizard.selection" /></label>
+                                                                                               <div class="table-fit-block">
+                                                                                                       <table class="table table-no-borders table-transparent">
+                                                                                                               <tr>
+                                                                                                                       <td class="t3js-cropper-info-crop"></td>
+                                                                                                               </tr>
+                                                                                                       </table>
+                                                                                               </div>
+                                                                                               <button class="btn btn-secondary" data-method="reset" data-crop-variant="{cropVariant -> f:format.json()}"
+                                                                                                                               title="{f:translate(key:'LLL:EXT:lang/Resources/Private/Language/locallang_wizards.xlf:imwizard.reset')}">
+                                                                                                       <i class="fa fa-refresh"></i>
+                                                                                                       {f:translate(key:'LLL:EXT:lang/Resources/Private/Language/locallang_wizards.xlf:imwizard.reset')}
+                                                                                               </button>
                                                                                        </div>
-                                                                               </div>
+                                                                               </form>
                                                                        </div>
-                                                               </f:for>
+                                                               </div>
                                                        </div>
-                                               </div>
+                                               </f:for>
                                        </div>
                                </div>
-                               <div class="modal-footer">
-                                       <button class="btn btn-default pull-left" data-method="preview" title="Preview"><i
-                                               class="fa fa-eye"></i>
-                                               Preview
-                                       </button>
-                                       <button class="btn btn-default" data-method="dismiss"
-                                                                       title="{f:translate(key:'LLL:EXT:lang/Resources/Private/Language/locallang_wizards.xlf:imwizard.cancel')}">
-                                               <i class="fa fa-remove"></i>
-                                               {f:translate(key:'LLL:EXT:lang/Resources/Private/Language/locallang_wizards.xlf:imwizard.cancel')}
-                                       </button>
-                                       <button class="btn btn-primary" data-method="save"
-                                                                       title="{f:translate(key:'LLL:EXT:lang/Resources/Private/Language/locallang_wizards.xlf:imwizard.accept')}">
-                                               <i class="fa fa-check"></i>
-                                               {f:translate(key:'LLL:EXT:lang/Resources/Private/Language/locallang_wizards.xlf:imwizard.accept')}
-                                       </button>
-                               </div>
-                       </f:then>
-                       <f:else>
-                               <div class="alert alert-danger">
-                                       <h4 class="alert-title">
-                                               <f:translate key="LLL:EXT:lang/Resources/Private/Language/locallang_wizards.xlf:imwizard.no-image-found"/>
-                                       </h4>
-                                       <p class="alert-message">
-                                               <f:translate key="LLL:EXT:lang/Resources/Private/Language/locallang_wizards.xlf:imwizard.no-image-found-message"/>
-                                       </p>
-                               </div>
-                       </f:else>
-               </f:if>
+                       </div>
+               </div>
+               <div class="modal-footer">
+                       <button class="btn btn-default pull-left" data-method="preview" title="Preview"><i
+                               class="fa fa-eye"></i>
+                               Preview
+                       </button>
+                       <button class="btn btn-default" data-method="dismiss"
+                                                       title="{f:translate(key:'LLL:EXT:lang/Resources/Private/Language/locallang_wizards.xlf:imwizard.cancel')}">
+                               <i class="fa fa-remove"></i>
+                               {f:translate(key:'LLL:EXT:lang/Resources/Private/Language/locallang_wizards.xlf:imwizard.cancel')}
+                       </button>
+                       <button class="btn btn-primary" data-method="save"
+                                                       title="{f:translate(key:'LLL:EXT:lang/Resources/Private/Language/locallang_wizards.xlf:imwizard.accept')}">
+                               <i class="fa fa-check"></i>
+                               {f:translate(key:'LLL:EXT:lang/Resources/Private/Language/locallang_wizards.xlf:imwizard.accept')}
+                       </button>
+               </div>
        </f:section>
 </html>
index d16dab0..67a6bda 100644 (file)
@@ -151,6 +151,7 @@ class ImageManipulation {
   private cropperCanvas: JQuery;
   private cropInfo: JQuery;
   private cropImageContainerSelector: string = '#t3js-crop-image-container';
+  private imageOriginalSizeFactor: number;
   private cropImageSelector: string = '#t3js-crop-image';
   private coverAreaSelector: string = '.t3js-cropper-cover-area';
   private cropInfoSelector: string = '.t3js-cropper-info-crop';
@@ -394,6 +395,9 @@ class ImageManipulation {
    */
   private cropBuiltHandler = (): void => {
     const imageData: CropperImageData = this.cropper.cropper('getImageData');
+    const image: JQuery = this.currentModal.find(this.cropImageSelector);
+
+    this.imageOriginalSizeFactor = image.data('originalWidth') / imageData.naturalWidth;
 
     // Iterate over the crop variants and set up their respective preview
     this.cropVariantTriggers.each((index: number, elem: Element): void => {
@@ -455,7 +459,9 @@ class ImageManipulation {
     });
     this.updatePreviewThumbnail(this.currentCropVariant, this.activeCropVariantTrigger);
     this.updateCropVariantData(this.currentCropVariant);
-    this.cropInfo.text(`${this.currentCropVariant.cropArea.width}×${this.currentCropVariant.cropArea.height} px`);
+    const naturalWidth: number = Math.round(this.currentCropVariant.cropArea.width * this.imageOriginalSizeFactor);
+    const naturalHeight: number = Math.round(this.currentCropVariant.cropArea.height * this.imageOriginalSizeFactor);
+    this.cropInfo.text(`${naturalWidth}×${naturalHeight} px`);
   };
 
   /**
@@ -769,6 +775,9 @@ class ImageManipulation {
    * @return {boolean}
    */
   private checkFocusAndCoverAreasCollision(focusArea: Area, coverAreas: Area[]): boolean {
+    if (!coverAreas) {
+      return false;
+    }
     return coverAreas
       .some((coverArea: Area): boolean => {
         // noinspection OverlyComplexBooleanExpressionJS
index 75aacdb..a2cc2ed 100644 (file)
@@ -48,6 +48,8 @@ define(["require", "exports", "TYPO3/CMS/Core/Contrib/imagesloaded.pkgd.min", "T
              */
             this.cropBuiltHandler = function () {
                 var imageData = _this.cropper.cropper('getImageData');
+                var image = _this.currentModal.find(_this.cropImageSelector);
+                _this.imageOriginalSizeFactor = image.data('originalWidth') / imageData.naturalWidth;
                 // Iterate over the crop variants and set up their respective preview
                 _this.cropVariantTriggers.each(function (index, elem) {
                     var cropVariantId = $(elem).attr('data-crop-variant-id');
@@ -96,7 +98,9 @@ define(["require", "exports", "TYPO3/CMS/Core/Contrib/imagesloaded.pkgd.min", "T
                 });
                 _this.updatePreviewThumbnail(_this.currentCropVariant, _this.activeCropVariantTrigger);
                 _this.updateCropVariantData(_this.currentCropVariant);
-                _this.cropInfo.text(_this.currentCropVariant.cropArea.width + "\u00D7" + _this.currentCropVariant.cropArea.height + " px");
+                var naturalWidth = Math.round(_this.currentCropVariant.cropArea.width * _this.imageOriginalSizeFactor);
+                var naturalHeight = Math.round(_this.currentCropVariant.cropArea.height * _this.imageOriginalSizeFactor);
+                _this.cropInfo.text(naturalWidth + "\u00D7" + naturalHeight + " px");
             };
             /**
              * @method cropStartHandler
@@ -621,6 +625,9 @@ define(["require", "exports", "TYPO3/CMS/Core/Contrib/imagesloaded.pkgd.min", "T
          * @return {boolean}
          */
         ImageManipulation.prototype.checkFocusAndCoverAreasCollision = function (focusArea, coverAreas) {
+            if (!coverAreas) {
+                return false;
+            }
             return coverAreas
                 .some(function (coverArea) {
                 // noinspection OverlyComplexBooleanExpressionJS
index 880e248..b840389 100644 (file)
@@ -546,6 +546,14 @@ return [
                             \TYPO3\CMS\Backend\Form\FormDataProvider\TcaInlineConfiguration::class,
                         ],
                     ],
+                    \TYPO3\CMS\Backend\Form\FormDataProvider\TcaOverrideChildCroppingConfiguration::class => [
+                        'depends' => [
+                            \TYPO3\CMS\Backend\Form\FormDataProvider\InlineOverrideChildTca::class,
+                        ],
+                        'before' => [
+                            \TYPO3\CMS\Backend\Form\FormDataProvider\DatabaseRowDefaultValues::class,
+                        ],
+                    ],
                     \TYPO3\CMS\Backend\Form\FormDataProvider\TcaInputPlaceholders::class => [
                         'depends' => [
                             \TYPO3\CMS\Backend\Form\FormDataProvider\TcaInlineConfiguration::class,
index 1771296..0d181ae 100644 (file)
@@ -22,7 +22,7 @@ when rendering an image with the image view helper.
 The allowed crop areas are now also configured differently.
 The array key is used as identifier for the ratio and the label is specified with the "title"
 and the actual (floating point) ratio with the "value" key.
-The value **must** be of PHP type float, not only a string.
+The value **should** be of PHP type float, not only a string.
 
 .. code-block:: php
 
@@ -125,6 +125,61 @@ the crop area. The focus area cannot intersect with any of the cover areas.
            ],
        ]
 
+The above configuration examples are basically meant to add one single cropping configuration
+to sys_file_reference, which will then apply in every record, which reference images.
+
+It is however also possible to provide a configuration per content element. If you for example want a different
+cropping configuration for tt_content images, then you can add the following to your `image` field configuration of tt_content records:
+
+.. code-block:: php
+
+       'config' => [
+            'overrideCropVariants' => [
+               'crop' => [
+                  'mobile' => [
+                      'title' => 'LLL:EXT:ext_key/Resources/Private/Language/locallang.xlf:imageManipulation.mobile',
+                      'cropArea' => [
+                          'x' => 0.1,
+                          'y' => 0.1,
+                          'width' => 0.8,
+                          'height' => 0.8,
+                      ],
+                  ],
+               ],
+            ],
+       ]
+
+Please note, that you need to specify the target column name as array key. Most of the time this will be `crop`
+as this is the default field name for image manipulation in `sys_file_reference`
+
+It is also possible to set the cropping configuration only for a specific tt_content element type by using the
+`columnOverrides` feature:
+
+       $GLOBALS['TCA']['tt_content']['types']['textmedia']['columnsOverrides']['assets']['config']['overrideCropVariants'] = [
+           'crop' => [
+              'mobile' => [
+                  'title' => 'LLL:EXT:ext_key/Resources/Private/Language/locallang.xlf:imageManipulation.mobile',
+                  'cropArea' => [
+                      'x' => 0.1,
+                      'y' => 0.1,
+                      'width' => 0.8,
+                      'height' => 0.8,
+                  ],
+                  'allowedAspectRatios' => [
+                      '4:3' => [
+                          'title' => 'LLL:EXT:lang/Resources/Private/Language/locallang_wizards.xlf:imwizard.ratio.4_3',
+                          'value' => 4 / 3
+                      ],
+                      'NaN' => [
+                          'title' => 'LLL:EXT:lang/Resources/Private/Language/locallang_wizards.xlf:imwizard.ratio.free',
+                          'value' => 0.0
+                      ],
+                  ],
+              ],
+           ],
+   ];
+
+
 To render crop variants, the variants can be specified as argument to the image view helper:
 
 .. code-block:: html
index 6858a82..a1f4959 100644 (file)
                        <trans-unit id="imwizard.supported-types-message">
                                <source>Image manipulation is only available for supported types:</source>
                        </trans-unit>
-                       <trans-unit id="imwizard.no-image-found">
-                               <source>No image found</source>
+                       <trans-unit id="imwizard.no-image-dimensions">
+                               <source>No image dimensions could be determined.</source>
                        </trans-unit>
-                       <trans-unit id="imwizard.no-image-found-message">
-                               <source>No image found. Could also be that image is present but that the original dimensions are unknow.</source>
+                       <trans-unit id="imwizard.no-image-dimensions-message">
+                               <source>Unable to provide image manipulation, because original dimensions of the image are unknown.</source>
                        </trans-unit>
                        <trans-unit id="imwizard.image-manipulation">
                                <source>Image manipulation</source>