diff --git a/Build/Sources/TypeScript/backend/image-manipulation.ts b/Build/Sources/TypeScript/backend/image-manipulation.ts index 06dc438da9d..66e7d954888 100644 --- a/Build/Sources/TypeScript/backend/image-manipulation.ts +++ b/Build/Sources/TypeScript/backend/image-manipulation.ts @@ -444,8 +444,8 @@ class ImageManipulation { const minCroppedWidth = 15; const minCroppedHeight = 15; - let width = Math.ceil(e.detail.width); - let height = Math.ceil(e.detail.height); + let width = Math.floor(e.detail.width); + let height = Math.floor(e.detail.height); if (width < minCroppedWidth || height < minCroppedHeight) { width = Math.max(minCroppedHeight, height); diff --git a/typo3/sysext/backend/Resources/Public/JavaScript/image-manipulation.js b/typo3/sysext/backend/Resources/Public/JavaScript/image-manipulation.js index 9ff542dc936..be39672b111 100644 --- a/typo3/sysext/backend/Resources/Public/JavaScript/image-manipulation.js +++ b/typo3/sysext/backend/Resources/Public/JavaScript/image-manipulation.js @@ -10,7 +10,7 @@ * * The TYPO3 project - inspiring people to share! */ -import{html}from"lit";import{unsafeHTML}from"lit/directives/unsafe-html.js";import{styleMap}from"lit/directives/style-map.js";import AjaxRequest from"@typo3/core/ajax/ajax-request.js";import RegularEvent from"@typo3/core/event/regular-event.js";import FormEngineValidation from"@typo3/backend/form-engine-validation.js";import Cropper from"cropperjs";import{default as Modal}from"@typo3/backend/modal.js";import"@typo3/backend/element/spinner-element.js";import{renderNodes}from"@typo3/core/lit-helper.js";import{Offset}from"@typo3/backend/element/draggable-resizable-element.js";class ImageManipulation{constructor(){this.initialized=!1,this.triggerListener=null,this.cropImageSelector="#t3js-crop-image",this.coverAreaSelector=".t3js-cropper-cover-area",this.cropInfoSelector=".t3js-cropper-info-crop",this.focusAreaSelector="#t3js-cropper-focus-area",this.defaultFocusArea={height:1/3,width:1/3,x:0,y:0},this.defaultOpts={autoCrop:!0,autoCropArea:.7,dragMode:"crop",guides:!0,responsive:!0,viewMode:1,zoomable:!1,checkCrossOrigin:!1},this.cropBuiltHandler=()=>{this.initialized=!0;const t=this.cropper.getImageData(),e=this.currentModal.querySelector(this.cropImageSelector);this.currentModal.querySelector(".cropper-canvas img")?.classList.remove("cropper-hide"),this.imageOriginalSizeFactor=parseInt(e.dataset.originalWidth,10)/t.naturalWidth,this.cropVariantTriggers.forEach((e=>{const r=e.dataset.cropVariantId,a=this.convertRelativeToAbsoluteCropArea(this.data[r].cropArea,t),i=Object.assign({},this.data[r],{cropArea:a});this.updatePreviewThumbnail(i,e)})),this.currentCropVariant.cropArea=this.convertRelativeToAbsoluteCropArea(this.currentCropVariant.cropArea,t),this.cropBox=this.currentModal.querySelector(".cropper-crop-box"),this.setCropArea(this.currentCropVariant.cropArea),this.currentCropVariant.coverAreas&&this.initCoverAreas(this.cropBox,this.currentCropVariant.coverAreas),this.currentCropVariant.focusArea&&(ImageManipulation.isEmptyObject(this.currentCropVariant.focusArea)&&(this.currentCropVariant.focusArea=Object.assign({},this.defaultFocusArea)),this.focusAreaEl?.remove(),this.initFocusArea(this.cropBox)),this.currentCropVariant.selectedRatio&&this.currentModal.querySelector(`[data-bs-option='${this.currentCropVariant.selectedRatio}']`)?.classList.add("active")},this.cropMoveHandler=t=>{if(!this.initialized)return;let e=Math.ceil(t.detail.width),r=Math.ceil(t.detail.height);(e<15||r<15)&&(e=Math.max(15,r),r=Math.max(15,e),this.cropper.setData({width:e,height:r})),this.currentCropVariant.cropArea=Object.assign({},this.currentCropVariant.cropArea,{width:Math.floor(e),height:Math.floor(r),x:Math.floor(t.detail.x),y:Math.floor(t.detail.y)}),this.focusAreaEl&&this.currentCropVariant?.focusArea&&(this.focusAreaEl.offset=this.convertAreaToOffset(this.currentCropVariant.focusArea,this.cropBox)),this.updatePreviewThumbnail(this.currentCropVariant,this.activeCropVariantTrigger),this.updateCropVariantData(this.currentCropVariant);const a=Math.round(this.currentCropVariant.cropArea.width*this.imageOriginalSizeFactor),i=Math.round(this.currentCropVariant.cropArea.height*this.imageOriginalSizeFactor);this.cropInfo.innerText=`${a}×${i} px`}}static wait(t,e){window.setTimeout(t,e)}static toCssPercent(t){return 100*t+"%"}static serializeCropVariants(t){return JSON.stringify(t,((t,e)=>"id"===t||"title"===t||"allowedAspectRatios"===t||"coverAreas"===t?void 0:e))}static isEmptyObject(t){return!t||"object"!=typeof t||0===Object.keys(t).length||"{}"===JSON.stringify(t)}static resolvePointerEventNames(){const t="undefined"!=typeof window&&void 0!==window.document,e=!(!t||!window.document.documentElement)&&"ontouchstart"in window.document.documentElement,r=!!t&&"PointerEvent"in window,a=e?["touchmove"]:["mousemove"],i=e?["touchstart"]:["mousedown"],o=e?["touchend","touchcancel"]:["mouseup"];return{touchStart:i,touchMove:a,touchEnd:o,pointerDown:r?["pointerdown"]:i,pointerMove:r?["pointermove"]:a,pointerUp:r?["pointerup","pointercancel"]:o}}initializeTrigger(){this.triggerListener||(this.triggerListener=new RegularEvent("click",((t,e)=>{t.preventDefault(),this.trigger=e,this.show()})),this.triggerListener.delegateTo(document,".t3js-image-manipulation-trigger"))}async initializeCropperModal(){const t=this.currentModal.querySelector(this.cropImageSelector);await new Promise((e=>{t.complete?e():t.addEventListener("load",(()=>e()))})),this.init()}show(){const t=this.trigger.dataset,e=t.modalTitle,r=t.buttonPreviewText,a=t.buttonDismissText,i=t.buttonSaveText,o=t.url,s=JSON.parse(t.payload);this.currentModal=Modal.advanced({additionalCssClasses:["modal-image-manipulation","cropper"],buttons:[{btnClass:"btn-default float-start",name:"preview",icon:"actions-view",text:r},{btnClass:"btn-default",name:"dismiss",icon:"actions-close",text:a},{btnClass:"btn-primary",name:"save",icon:"actions-document-save",text:i}],content:html``,size:Modal.sizes.full,style:Modal.styles.dark,title:e,staticBackdrop:!0}),this.currentModal.addEventListener("typo3-modal-shown",(()=>{new AjaxRequest(o).post(s).then((async t=>{const e=await t.resolve();this.currentModal.templateResultContent=html`${unsafeHTML(e)}`,this.currentModal.updateComplete.then((()=>this.initializeCropperModal()))}))})),this.currentModal.addEventListener("typo3-modal-hide",(()=>{this.destroy()}))}init(){const t=this.currentModal.querySelector(this.cropImageSelector),e=this.trigger.dataset.cropVariants;if(!e)throw new TypeError("ImageManipulation: No cropVariants data found for image");this.data=ImageManipulation.isEmptyObject(this.data)?JSON.parse(e):this.data,this.cropVariantTriggers=this.currentModal.querySelectorAll(".t3js-crop-variant-trigger"),this.activeCropVariantTrigger=this.currentModal.querySelector(".t3js-crop-variant-trigger.is-active"),this.cropInfo=this.currentModal.querySelector(this.cropInfoSelector),this.currentCropVariant=this.data[this.activeCropVariantTrigger.dataset.cropVariantId],this.cropVariantTriggers.forEach((t=>t.addEventListener("click",(t=>{if(t.currentTarget.classList.contains("is-active"))return t.stopPropagation(),void t.preventDefault();this.activeCropVariantTrigger.classList.remove("is-active"),t.currentTarget.classList.add("is-active"),this.activeCropVariantTrigger=t.currentTarget;const e=this.data[this.activeCropVariantTrigger.dataset.cropVariantId],r=this.cropper.getImageData();e.cropArea=this.convertRelativeToAbsoluteCropArea(e.cropArea,r),this.currentCropVariant=Object.assign({},e),this.update(e)})))),new RegularEvent("click",((t,e)=>{const r=e.dataset.bsOption,a=Object.assign({},this.currentCropVariant),i=a.allowedAspectRatios[r];this.setAspectRatio(i),this.setCropArea(a.cropArea),this.currentCropVariant=Object.assign({},a,{selectedRatio:r}),this.update(this.currentCropVariant)})).delegateTo(this.currentModal,"label[data-method=setAspectRatio]"),new RegularEvent("click",(()=>this.save(this.data))).delegateTo(this.currentModal,"button[name=save]"),this.trigger.dataset.previewUrl?new RegularEvent("click",(()=>this.openPreview(this.data))).delegateTo(this.currentModal,"button[name=preview]"):this.currentModal.querySelectorAll("button[name=preview]").forEach((t=>t.style.display="none")),new RegularEvent("click",(()=>this.currentModal.hideModal())).delegateTo(this.currentModal,"button[name=dismiss]"),new RegularEvent("click",((t,e)=>{const r=this.cropper.getImageData(),a=e.dataset.cropVariant;if(t.preventDefault(),t.stopPropagation(),!a)throw new TypeError("TYPO3 Cropper: No cropVariant data attribute found on reset element.");const i=JSON.parse(a),o=this.convertRelativeToAbsoluteCropArea(i.cropArea,r);this.currentCropVariant=Object.assign({},i,{cropArea:o}),this.update(this.currentCropVariant)})).delegateTo(this.currentModal,"button[name=reset]"),ImageManipulation.isEmptyObject(this.currentCropVariant.cropArea)&&(this.defaultOpts=Object.assign({autoCropArea:1},this.defaultOpts)),this.cropper=new Cropper(t,Object.assign({},this.defaultOpts,{ready:()=>{this.cropBuiltHandler(),this.update(this.currentCropVariant)},crop:this.cropMoveHandler.bind(this),data:this.currentCropVariant.cropArea}))}update(t){const e=Object.assign({},t),r=t.allowedAspectRatios[t.selectedRatio];this.currentModal.querySelector("[data-bs-option].active")?.classList.remove("active"),this.currentModal.querySelector(`[data-bs-option="${t.selectedRatio}"]`)?.classList.add("active"),this.setAspectRatio(r),this.setCropArea(e.cropArea),this.currentCropVariant=Object.assign({},e,t),this.cropBox?.querySelector(this.coverAreaSelector)?.remove(),this.cropBox?.querySelectorAll(this.focusAreaSelector)?.length>0&&this.focusAreaEl.remove(),t.focusArea&&(ImageManipulation.isEmptyObject(t.focusArea)&&(this.currentCropVariant.focusArea=Object.assign({},this.defaultFocusArea)),this.focusAreaEl?.remove(),this.initFocusArea(this.cropBox)),t.coverAreas&&this.initCoverAreas(this.cropBox,this.currentCropVariant.coverAreas),this.updatePreviewThumbnail(this.currentCropVariant,this.activeCropVariantTrigger)}initFocusArea(t){this.focusAreaEl=document.createElement("typo3-backend-draggable-resizable"),this.focusAreaEl.window=this.currentModal.ownerDocument.defaultView,this.focusAreaEl.offset=this.convertAreaToOffset(this.currentCropVariant.focusArea,t),this.focusAreaEl.container=t,this.focusAreaEl.pointerEventNames=ImageManipulation.resolvePointerEventNames(),this.focusAreaEl.addEventListener("draggable-resizable-started",(()=>{this.cropper.disable()})),this.focusAreaEl.addEventListener("draggable-resizable-updated",(()=>{const e=this.currentCropVariant.coverAreas,r=this.convertOffsetToArea(this.focusAreaEl.offset,t),a=this.focusAreaEl.querySelector(this.focusAreaSelector);this.checkFocusAndCoverAreasCollision(r,e)?a.classList.add("has-nodrop"):a.classList.remove("has-nodrop")})),this.focusAreaEl.addEventListener("draggable-resizable-finished",(e=>{const r=this.currentCropVariant.coverAreas,a=this.convertOffsetToArea(this.focusAreaEl.offset,t);this.checkFocusAndCoverAreasCollision(a,r)?this.focusAreaEl.revert(e.detail.originOffset):this.scaleAndMoveFocusArea(a);this.focusAreaEl.querySelector(this.focusAreaSelector).classList.remove("has-nodrop"),this.cropper.enable()})),t.appendChild(this.focusAreaEl),this.scaleAndMoveFocusArea(this.currentCropVariant.focusArea)}initCoverAreas(t,e){e.forEach((e=>{const r={height:ImageManipulation.toCssPercent(e.height),left:ImageManipulation.toCssPercent(e.x),top:ImageManipulation.toCssPercent(e.y),width:ImageManipulation.toCssPercent(e.width)},a=html` +import{html}from"lit";import{unsafeHTML}from"lit/directives/unsafe-html.js";import{styleMap}from"lit/directives/style-map.js";import AjaxRequest from"@typo3/core/ajax/ajax-request.js";import RegularEvent from"@typo3/core/event/regular-event.js";import FormEngineValidation from"@typo3/backend/form-engine-validation.js";import Cropper from"cropperjs";import{default as Modal}from"@typo3/backend/modal.js";import"@typo3/backend/element/spinner-element.js";import{renderNodes}from"@typo3/core/lit-helper.js";import{Offset}from"@typo3/backend/element/draggable-resizable-element.js";class ImageManipulation{constructor(){this.initialized=!1,this.triggerListener=null,this.cropImageSelector="#t3js-crop-image",this.coverAreaSelector=".t3js-cropper-cover-area",this.cropInfoSelector=".t3js-cropper-info-crop",this.focusAreaSelector="#t3js-cropper-focus-area",this.defaultFocusArea={height:1/3,width:1/3,x:0,y:0},this.defaultOpts={autoCrop:!0,autoCropArea:.7,dragMode:"crop",guides:!0,responsive:!0,viewMode:1,zoomable:!1,checkCrossOrigin:!1},this.cropBuiltHandler=()=>{this.initialized=!0;const t=this.cropper.getImageData(),e=this.currentModal.querySelector(this.cropImageSelector);this.currentModal.querySelector(".cropper-canvas img")?.classList.remove("cropper-hide"),this.imageOriginalSizeFactor=parseInt(e.dataset.originalWidth,10)/t.naturalWidth,this.cropVariantTriggers.forEach((e=>{const r=e.dataset.cropVariantId,a=this.convertRelativeToAbsoluteCropArea(this.data[r].cropArea,t),i=Object.assign({},this.data[r],{cropArea:a});this.updatePreviewThumbnail(i,e)})),this.currentCropVariant.cropArea=this.convertRelativeToAbsoluteCropArea(this.currentCropVariant.cropArea,t),this.cropBox=this.currentModal.querySelector(".cropper-crop-box"),this.setCropArea(this.currentCropVariant.cropArea),this.currentCropVariant.coverAreas&&this.initCoverAreas(this.cropBox,this.currentCropVariant.coverAreas),this.currentCropVariant.focusArea&&(ImageManipulation.isEmptyObject(this.currentCropVariant.focusArea)&&(this.currentCropVariant.focusArea=Object.assign({},this.defaultFocusArea)),this.focusAreaEl?.remove(),this.initFocusArea(this.cropBox)),this.currentCropVariant.selectedRatio&&this.currentModal.querySelector(`[data-bs-option='${this.currentCropVariant.selectedRatio}']`)?.classList.add("active")},this.cropMoveHandler=t=>{if(!this.initialized)return;let e=Math.floor(t.detail.width),r=Math.floor(t.detail.height);(e<15||r<15)&&(e=Math.max(15,r),r=Math.max(15,e),this.cropper.setData({width:e,height:r})),this.currentCropVariant.cropArea=Object.assign({},this.currentCropVariant.cropArea,{width:Math.floor(e),height:Math.floor(r),x:Math.floor(t.detail.x),y:Math.floor(t.detail.y)}),this.focusAreaEl&&this.currentCropVariant?.focusArea&&(this.focusAreaEl.offset=this.convertAreaToOffset(this.currentCropVariant.focusArea,this.cropBox)),this.updatePreviewThumbnail(this.currentCropVariant,this.activeCropVariantTrigger),this.updateCropVariantData(this.currentCropVariant);const a=Math.round(this.currentCropVariant.cropArea.width*this.imageOriginalSizeFactor),i=Math.round(this.currentCropVariant.cropArea.height*this.imageOriginalSizeFactor);this.cropInfo.innerText=`${a}×${i} px`}}static wait(t,e){window.setTimeout(t,e)}static toCssPercent(t){return 100*t+"%"}static serializeCropVariants(t){return JSON.stringify(t,((t,e)=>"id"===t||"title"===t||"allowedAspectRatios"===t||"coverAreas"===t?void 0:e))}static isEmptyObject(t){return!t||"object"!=typeof t||0===Object.keys(t).length||"{}"===JSON.stringify(t)}static resolvePointerEventNames(){const t="undefined"!=typeof window&&void 0!==window.document,e=!(!t||!window.document.documentElement)&&"ontouchstart"in window.document.documentElement,r=!!t&&"PointerEvent"in window,a=e?["touchmove"]:["mousemove"],i=e?["touchstart"]:["mousedown"],o=e?["touchend","touchcancel"]:["mouseup"];return{touchStart:i,touchMove:a,touchEnd:o,pointerDown:r?["pointerdown"]:i,pointerMove:r?["pointermove"]:a,pointerUp:r?["pointerup","pointercancel"]:o}}initializeTrigger(){this.triggerListener||(this.triggerListener=new RegularEvent("click",((t,e)=>{t.preventDefault(),this.trigger=e,this.show()})),this.triggerListener.delegateTo(document,".t3js-image-manipulation-trigger"))}async initializeCropperModal(){const t=this.currentModal.querySelector(this.cropImageSelector);await new Promise((e=>{t.complete?e():t.addEventListener("load",(()=>e()))})),this.init()}show(){const t=this.trigger.dataset,e=t.modalTitle,r=t.buttonPreviewText,a=t.buttonDismissText,i=t.buttonSaveText,o=t.url,s=JSON.parse(t.payload);this.currentModal=Modal.advanced({additionalCssClasses:["modal-image-manipulation","cropper"],buttons:[{btnClass:"btn-default float-start",name:"preview",icon:"actions-view",text:r},{btnClass:"btn-default",name:"dismiss",icon:"actions-close",text:a},{btnClass:"btn-primary",name:"save",icon:"actions-document-save",text:i}],content:html``,size:Modal.sizes.full,style:Modal.styles.dark,title:e,staticBackdrop:!0}),this.currentModal.addEventListener("typo3-modal-shown",(()=>{new AjaxRequest(o).post(s).then((async t=>{const e=await t.resolve();this.currentModal.templateResultContent=html`${unsafeHTML(e)}`,this.currentModal.updateComplete.then((()=>this.initializeCropperModal()))}))})),this.currentModal.addEventListener("typo3-modal-hide",(()=>{this.destroy()}))}init(){const t=this.currentModal.querySelector(this.cropImageSelector),e=this.trigger.dataset.cropVariants;if(!e)throw new TypeError("ImageManipulation: No cropVariants data found for image");this.data=ImageManipulation.isEmptyObject(this.data)?JSON.parse(e):this.data,this.cropVariantTriggers=this.currentModal.querySelectorAll(".t3js-crop-variant-trigger"),this.activeCropVariantTrigger=this.currentModal.querySelector(".t3js-crop-variant-trigger.is-active"),this.cropInfo=this.currentModal.querySelector(this.cropInfoSelector),this.currentCropVariant=this.data[this.activeCropVariantTrigger.dataset.cropVariantId],this.cropVariantTriggers.forEach((t=>t.addEventListener("click",(t=>{if(t.currentTarget.classList.contains("is-active"))return t.stopPropagation(),void t.preventDefault();this.activeCropVariantTrigger.classList.remove("is-active"),t.currentTarget.classList.add("is-active"),this.activeCropVariantTrigger=t.currentTarget;const e=this.data[this.activeCropVariantTrigger.dataset.cropVariantId],r=this.cropper.getImageData();e.cropArea=this.convertRelativeToAbsoluteCropArea(e.cropArea,r),this.currentCropVariant=Object.assign({},e),this.update(e)})))),new RegularEvent("click",((t,e)=>{const r=e.dataset.bsOption,a=Object.assign({},this.currentCropVariant),i=a.allowedAspectRatios[r];this.setAspectRatio(i),this.setCropArea(a.cropArea),this.currentCropVariant=Object.assign({},a,{selectedRatio:r}),this.update(this.currentCropVariant)})).delegateTo(this.currentModal,"label[data-method=setAspectRatio]"),new RegularEvent("click",(()=>this.save(this.data))).delegateTo(this.currentModal,"button[name=save]"),this.trigger.dataset.previewUrl?new RegularEvent("click",(()=>this.openPreview(this.data))).delegateTo(this.currentModal,"button[name=preview]"):this.currentModal.querySelectorAll("button[name=preview]").forEach((t=>t.style.display="none")),new RegularEvent("click",(()=>this.currentModal.hideModal())).delegateTo(this.currentModal,"button[name=dismiss]"),new RegularEvent("click",((t,e)=>{const r=this.cropper.getImageData(),a=e.dataset.cropVariant;if(t.preventDefault(),t.stopPropagation(),!a)throw new TypeError("TYPO3 Cropper: No cropVariant data attribute found on reset element.");const i=JSON.parse(a),o=this.convertRelativeToAbsoluteCropArea(i.cropArea,r);this.currentCropVariant=Object.assign({},i,{cropArea:o}),this.update(this.currentCropVariant)})).delegateTo(this.currentModal,"button[name=reset]"),ImageManipulation.isEmptyObject(this.currentCropVariant.cropArea)&&(this.defaultOpts=Object.assign({autoCropArea:1},this.defaultOpts)),this.cropper=new Cropper(t,Object.assign({},this.defaultOpts,{ready:()=>{this.cropBuiltHandler(),this.update(this.currentCropVariant)},crop:this.cropMoveHandler.bind(this),data:this.currentCropVariant.cropArea}))}update(t){const e=Object.assign({},t),r=t.allowedAspectRatios[t.selectedRatio];this.currentModal.querySelector("[data-bs-option].active")?.classList.remove("active"),this.currentModal.querySelector(`[data-bs-option="${t.selectedRatio}"]`)?.classList.add("active"),this.setAspectRatio(r),this.setCropArea(e.cropArea),this.currentCropVariant=Object.assign({},e,t),this.cropBox?.querySelector(this.coverAreaSelector)?.remove(),this.cropBox?.querySelectorAll(this.focusAreaSelector)?.length>0&&this.focusAreaEl.remove(),t.focusArea&&(ImageManipulation.isEmptyObject(t.focusArea)&&(this.currentCropVariant.focusArea=Object.assign({},this.defaultFocusArea)),this.focusAreaEl?.remove(),this.initFocusArea(this.cropBox)),t.coverAreas&&this.initCoverAreas(this.cropBox,this.currentCropVariant.coverAreas),this.updatePreviewThumbnail(this.currentCropVariant,this.activeCropVariantTrigger)}initFocusArea(t){this.focusAreaEl=document.createElement("typo3-backend-draggable-resizable"),this.focusAreaEl.window=this.currentModal.ownerDocument.defaultView,this.focusAreaEl.offset=this.convertAreaToOffset(this.currentCropVariant.focusArea,t),this.focusAreaEl.container=t,this.focusAreaEl.pointerEventNames=ImageManipulation.resolvePointerEventNames(),this.focusAreaEl.addEventListener("draggable-resizable-started",(()=>{this.cropper.disable()})),this.focusAreaEl.addEventListener("draggable-resizable-updated",(()=>{const e=this.currentCropVariant.coverAreas,r=this.convertOffsetToArea(this.focusAreaEl.offset,t),a=this.focusAreaEl.querySelector(this.focusAreaSelector);this.checkFocusAndCoverAreasCollision(r,e)?a.classList.add("has-nodrop"):a.classList.remove("has-nodrop")})),this.focusAreaEl.addEventListener("draggable-resizable-finished",(e=>{const r=this.currentCropVariant.coverAreas,a=this.convertOffsetToArea(this.focusAreaEl.offset,t);this.checkFocusAndCoverAreasCollision(a,r)?this.focusAreaEl.revert(e.detail.originOffset):this.scaleAndMoveFocusArea(a);this.focusAreaEl.querySelector(this.focusAreaSelector).classList.remove("has-nodrop"),this.cropper.enable()})),t.appendChild(this.focusAreaEl),this.scaleAndMoveFocusArea(this.currentCropVariant.focusArea)}initCoverAreas(t,e){e.forEach((e=>{const r={height:ImageManipulation.toCssPercent(e.height),left:ImageManipulation.toCssPercent(e.x),top:ImageManipulation.toCssPercent(e.y),width:ImageManipulation.toCssPercent(e.width)},a=html`
`;this.renderElements(a,t)}))}updatePreviewThumbnail(t,e){const r=e.querySelector(".t3js-cropper-preview-thumbnail-crop-area"),a=e.querySelector(".t3js-cropper-preview-thumbnail-crop-image"),i=e.querySelector(".t3js-cropper-preview-thumbnail-focus-area"),o=this.cropper.getImageData();Object.assign(r.style,{height:ImageManipulation.toCssPercent(t.cropArea.height/o.naturalHeight),left:ImageManipulation.toCssPercent(t.cropArea.x/o.naturalWidth),top:ImageManipulation.toCssPercent(t.cropArea.y/o.naturalHeight),width:ImageManipulation.toCssPercent(t.cropArea.width/o.naturalWidth)}),t.focusArea&&Object.assign(i.style,{height:ImageManipulation.toCssPercent(t.focusArea.height),left:ImageManipulation.toCssPercent(t.focusArea.x),top:ImageManipulation.toCssPercent(t.focusArea.y),width:ImageManipulation.toCssPercent(t.focusArea.width)});const s=getComputedStyle(r),n={width:s.getPropertyValue("width"),height:s.getPropertyValue("height"),left:s.getPropertyValue("left"),top:s.getPropertyValue("top")};Object.assign(a.style,{height:parseFloat(n.height)*(1/(t.cropArea.height/o.naturalHeight))+"px",margin:-1*parseFloat(n.left)+"px",marginTop:-1*parseFloat(n.top)+"px",width:parseFloat(n.width)*(1/(t.cropArea.width/o.naturalWidth))+"px"})}scaleAndMoveFocusArea(t){this.currentCropVariant.focusArea=t,this.updatePreviewThumbnail(this.currentCropVariant,this.activeCropVariantTrigger),this.updateCropVariantData(this.currentCropVariant)}updateCropVariantData(t){const e=this.cropper.getImageData(),r=this.convertAbsoluteToRelativeCropArea(t.cropArea,e);this.data[t.id]=Object.assign({},t,{cropArea:r})}setAspectRatio(t){this.cropper.setAspectRatio(t.value)}setCropArea(t){const e=this.currentCropVariant.allowedAspectRatios[this.currentCropVariant.selectedRatio];0===e.value?this.cropper.setData({height:t.height,width:t.width,x:t.x,y:t.y}):this.cropper.setData({height:t.height,width:t.height*e.value,x:t.x,y:t.y})}checkFocusAndCoverAreasCollision(t,e){return!!e&&e.some((e=>t.x{const i=t[a],o=this.convertRelativeToAbsoluteCropArea(i.cropArea,r),s=this.trigger.closest(".form-group").querySelector(`.t3js-image-manipulation-preview[data-crop-variant-id="${a}"]`),n=this.trigger.closest(".form-group").querySelector(`.t3js-image-manipulation-selected-ratio[data-crop-variant-id="${a}"]`);if(!(s instanceof HTMLElement))return;let c=s.getBoundingClientRect().width,h=parseInt(s.dataset.previewHeight,10);const l=o.width/o.height,p=c/l;p>h?c=h*l:h=p,c>o.width&&(c=o.width,h=o.height);const u=c/o.width,d={height:r.naturalHeight*u+"px",left:-o.x*u+"px",top:-o.y*u+"px",width:r.naturalWidth*u+"px"},g=html`