/*
 * 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!
 */
import{html as u}from"lit";import{unsafeHTML as E}from"lit/directives/unsafe-html.js";import{styleMap as g}from"lit/directives/style-map.js";import S from"@typo3/core/ajax/ajax-request.js";import l from"@typo3/core/event/regular-event.js";import O from"@typo3/backend/form-engine-validation.js";import C from"cropperjs";import m from"@typo3/backend/modal.js";import"@typo3/backend/element/spinner-element.js";import{renderNodes as V}from"@typo3/core/lit-helper.js";import{topLevelModuleImport as x}from"@typo3/backend/utility/top-level-module-import.js";import{Offset as R}from"@typo3/backend/offset.js";class n{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="typo3-backend-draggable-resizable",this.focusAreaVisualElementSelector="typo3-backend-draggable-resizable .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(),r=this.currentModal.querySelector(this.cropImageSelector);this.currentModal.querySelector(".cropper-canvas img")?.classList.remove("cropper-hide"),this.imageOriginalSizeFactor=parseInt(r.dataset.originalWidth,10)/t.naturalWidth,this.cropVariantTriggers.forEach(e=>{const i=e.dataset.cropVariantId,s=this.convertRelativeToAbsoluteCropArea(this.data[i].cropArea,t),a=Object.assign({},this.data[i],{cropArea:s});this.updatePreviewThumbnail(a,e),this.currentModal.querySelector(`[data-crop-variant-container="${a.id}"]`)?.querySelector(`[data-bs-option="${a.selectedRatio}"]`)?.classList.add("active")}),this.currentCropVariant.cropArea=this.convertRelativeToAbsoluteCropArea(this.currentCropVariant.cropArea,t),this.cropBox=this.currentModal.querySelector(".cropper-crop-box"),this.currentCropVariant.selectedRatio&&this.currentModal.querySelector(`[data-bs-option='${this.currentCropVariant.selectedRatio}']`)?.classList.add("active")},this.cropMoveHandler=t=>{if(!this.initialized)return;const r=15,e=15;let i=Math.floor(t.detail.width),s=Math.floor(t.detail.height);(i<r||s<e)&&(i=Math.max(e,s),s=Math.max(r,i),this.cropper.setData({width:i,height:s})),this.currentCropVariant.cropArea=Object.assign({},this.currentCropVariant.cropArea,{width:Math.floor(i),height:Math.floor(s),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),o=Math.round(this.currentCropVariant.cropArea.height*this.imageOriginalSizeFactor);this.cropInfo.innerText=`${a}\xD7${o} px`}}static wait(t,r){window.setTimeout(t,r)}static toCssPercent(t){return`${t*100}%`}static serializeCropVariants(t){return JSON.stringify(t,(e,i)=>e==="id"||e==="title"||e==="allowedAspectRatios"||e==="coverAreas"?void 0:i)}static isEmptyObject(t){return!t||typeof t!="object"||Object.keys(t).length===0||JSON.stringify(t)==="{}"}static resolvePointerEventNames(){const t=typeof window<"u"&&typeof window.document<"u",r=t&&window.document.documentElement?"ontouchstart"in window.document.documentElement:!1,e=t?"PointerEvent"in window:!1,i=r?["touchmove"]:["mousemove"],s=r?["touchstart"]:["mousedown"],a=r?["touchend","touchcancel"]:["mouseup"];return{touchStart:s,touchMove:i,touchEnd:a,pointerDown:e?["pointerdown"]:s,pointerMove:e?["pointermove"]:i,pointerUp:e?["pointerup","pointercancel"]:a}}initializeTrigger(){this.triggerListener||(this.triggerListener=new l("click",(t,r)=>{t.preventDefault(),this.trigger=r,this.show()}),this.triggerListener.delegateTo(document,".t3js-image-manipulation-trigger"))}async initializeCropperModal(){const t=this.currentModal.querySelector(this.cropImageSelector);await new Promise(r=>{t.complete?r():t.addEventListener("load",()=>r())}),this.init()}show(){const t=this.trigger.dataset,r=t.modalTitle,e=t.buttonPreviewText,i=t.buttonDismissText,s=t.buttonSaveText,a=t.url,o=JSON.parse(t.payload);this.currentModal=m.advanced({additionalCssClasses:["modal-image-manipulation","cropper"],buttons:[{btnClass:"btn-default float-start",name:"preview",icon:"actions-view",text:e},{btnClass:"btn-default",name:"dismiss",icon:"actions-close",text:i},{btnClass:"btn-primary",name:"save",icon:"actions-document-save",text:s}],content:u`<div class=modal-loading><typo3-backend-spinner size=large></typo3-backend-spinner></div>`,size:m.sizes.full,style:m.styles.dark,title:r,staticBackdrop:!0}),this.currentModal.addEventListener("typo3-modal-shown",()=>{new S(a).post(o).then(async c=>{const h=await c.resolve();this.currentModal.templateResultContent=u`${E(h)}`,this.currentModal.updateComplete.then(()=>this.initializeCropperModal())})}),this.currentModal.addEventListener("typo3-modal-hide",()=>{this.destroy()})}init(){const t=this.currentModal.querySelector(this.cropImageSelector),r=this.trigger.dataset.cropVariants;if(!r)throw new TypeError("ImageManipulation: No cropVariants data found for image");this.data=n.isEmptyObject(this.data)?JSON.parse(r):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(e=>e.addEventListener("click",i=>{if(i.currentTarget.classList.contains("is-active")){i.stopPropagation(),i.preventDefault();return}this.activeCropVariantTrigger.classList.remove("is-active"),i.currentTarget.classList.add("is-active"),this.activeCropVariantTrigger=i.currentTarget;const s=this.data[this.activeCropVariantTrigger.dataset.cropVariantId],a=this.cropper.getImageData();s.cropArea=this.convertRelativeToAbsoluteCropArea(s.cropArea,a),this.currentCropVariant=Object.assign({},s),this.update(s)})),new l("click",(e,i)=>{const s=i.dataset.bsOption;this.handleAspectRatioChange(s)}).delegateTo(this.currentModal,"label[data-method=setAspectRatio]"),new l("keydown",(e,i)=>{if(!["Enter","Space"].includes(e.code))return;e.preventDefault(),e.stopImmediatePropagation();const s=i.closest('label[data-method="setAspectRatio"]'),a=s.dataset.bsOption;s.querySelector("input").checked=!0,this.handleAspectRatioChange(a)}).delegateTo(this.currentModal,'label[data-method="setAspectRatio"] input[type="radio"]'),new l("click",()=>this.save(this.data)).delegateTo(this.currentModal,"button[name=save]"),this.trigger.dataset.previewUrl?new l("click",()=>this.openPreview(this.data)).delegateTo(this.currentModal,"button[name=preview]"):this.currentModal.querySelectorAll("button[name=preview]").forEach(e=>e.style.display="none"),new l("click",()=>this.currentModal.hideModal()).delegateTo(this.currentModal,"button[name=dismiss]"),new l("click",(e,i)=>{const s=this.cropper.getImageData(),a=i.dataset.cropVariant;if(e.preventDefault(),e.stopPropagation(),!a)throw new TypeError("TYPO3 Cropper: No cropVariant data attribute found on reset element.");const o=JSON.parse(a),c=this.convertRelativeToAbsoluteCropArea(o.cropArea,s);this.currentCropVariant=Object.assign({},o,{cropArea:c}),this.update(this.currentCropVariant)}).delegateTo(this.currentModal,"button[name=reset]"),n.isEmptyObject(this.currentCropVariant.cropArea)&&(this.defaultOpts=Object.assign({autoCropArea:1},this.defaultOpts)),this.cropper=new C(t,Object.assign({},this.defaultOpts,{ready:()=>{this.cropBuiltHandler(),this.update(this.currentCropVariant)},crop:this.cropMoveHandler.bind(this),data:this.currentCropVariant.cropArea}))}handleAspectRatioChange(t){const r=Object.assign({},this.currentCropVariant),e=r.allowedAspectRatios[t];this.setAspectRatio(e),this.setCropArea(r.cropArea),this.currentCropVariant=Object.assign({},r,{selectedRatio:t}),this.update(this.currentCropVariant)}async update(t){const r=Object.assign({},t),e=t.allowedAspectRatios[t.selectedRatio];this.cropInfo=this.currentModal.querySelector(`[data-crop-variant-container="${t.id}"]`)?.querySelector(this.cropInfoSelector),this.currentModal.querySelector(`[data-crop-variant-container="${t.id}"]`)?.querySelector("[data-bs-option].active")?.classList.remove("active"),this.currentModal.querySelector(`[data-crop-variant-container="${t.id}"]`)?.querySelector(`[data-bs-option="${t.selectedRatio}"]`)?.classList.add("active"),this.setAspectRatio(e),this.setCropArea(r.cropArea),this.currentCropVariant=Object.assign({},r,t),this.cropBox?.querySelectorAll(this.coverAreaSelector)?.forEach(i=>i.remove()),this.cropBox?.querySelectorAll(this.focusAreaSelector)?.forEach(i=>i.remove()),t.focusArea?(n.isEmptyObject(t.focusArea)&&(this.currentCropVariant.focusArea=Object.assign({},this.defaultFocusArea)),this.focusAreaEl=this.initFocusArea(this.cropBox)):this.focusAreaEl=null,t.coverAreas&&this.initCoverAreas(this.cropBox,this.currentCropVariant.coverAreas),this.updatePreviewThumbnail(this.currentCropVariant,this.activeCropVariantTrigger)}initFocusArea(t){x("@typo3/backend/element/draggable-resizable-element.js");const r=top.document.createElement("typo3-backend-draggable-resizable");return r.setAttribute("offset",JSON.stringify(this.convertAreaToOffset(this.currentCropVariant.focusArea,t))),r.setAttribute("pointereventnames",JSON.stringify(n.resolvePointerEventNames())),r.addEventListener("draggable-resizable-started",()=>{this.cropper.disable()}),r.addEventListener("draggable-resizable-updated",()=>{const e=this.currentCropVariant.coverAreas,i=this.convertOffsetToArea(r.offset,t),s=r.querySelector(this.focusAreaVisualElementSelector);this.checkFocusAndCoverAreasCollision(i,e)?s.classList.add("has-nodrop"):s.classList.remove("has-nodrop")}),r.addEventListener("draggable-resizable-finished",e=>{const i=this.currentCropVariant.coverAreas,s=this.convertOffsetToArea(r.offset,t);this.checkFocusAndCoverAreasCollision(s,i)?r.revert(e.detail.originOffset):this.scaleAndMoveFocusArea(s),r.querySelector(this.focusAreaVisualElementSelector).classList.remove("has-nodrop"),this.cropper.enable()}),t.appendChild(r),this.scaleAndMoveFocusArea(this.currentCropVariant.focusArea),r}initCoverAreas(t,r){r.forEach(e=>{const i={height:n.toCssPercent(e.height),left:n.toCssPercent(e.x),top:n.toCssPercent(e.y),width:n.toCssPercent(e.width)},s=u`<div class="cropper-cover-area t3js-cropper-cover-area" style=${g(i)}></div>`;this.renderElements(s,t)})}updatePreviewThumbnail(t,r){const e=r.querySelector(".t3js-cropper-preview-thumbnail-crop-area"),i=r.querySelector(".t3js-cropper-preview-thumbnail-crop-image"),s=r.querySelector(".t3js-cropper-preview-thumbnail-focus-area"),a=this.cropper.getImageData();Object.assign(e.style,{height:n.toCssPercent(t.cropArea.height/a.naturalHeight),left:n.toCssPercent(t.cropArea.x/a.naturalWidth),top:n.toCssPercent(t.cropArea.y/a.naturalHeight),width:n.toCssPercent(t.cropArea.width/a.naturalWidth)}),t.focusArea&&Object.assign(s.style,{height:n.toCssPercent(t.focusArea.height),left:n.toCssPercent(t.focusArea.x),top:n.toCssPercent(t.focusArea.y),width:n.toCssPercent(t.focusArea.width)});const o=getComputedStyle(e),c={width:o.getPropertyValue("width"),height:o.getPropertyValue("height"),left:o.getPropertyValue("left"),top:o.getPropertyValue("top")};Object.assign(i.style,{height:`${parseFloat(c.height)*(1/(t.cropArea.height/a.naturalHeight))}px`,margin:`${-1*parseFloat(c.left)}px`,marginTop:`${-1*parseFloat(c.top)}px`,width:`${parseFloat(c.width)*(1/(t.cropArea.width/a.naturalWidth))}px`})}scaleAndMoveFocusArea(t){this.currentCropVariant.focusArea=t,this.updatePreviewThumbnail(this.currentCropVariant,this.activeCropVariantTrigger),this.updateCropVariantData(this.currentCropVariant)}updateCropVariantData(t){const r=this.cropper.getImageData(),e=this.convertAbsoluteToRelativeCropArea(t.cropArea,r);this.data[t.id]=Object.assign({},t,{cropArea:e})}setAspectRatio(t){this.cropper.setAspectRatio(t.value)}setCropArea(t){const r=this.currentCropVariant.allowedAspectRatios[this.currentCropVariant.selectedRatio];r.value===0?this.cropper.setData({height:t.height,width:t.width,x:t.x,y:t.y}):this.cropper.setData({height:t.height,width:t.height*r.value,x:t.x,y:t.y})}checkFocusAndCoverAreasCollision(t,r){return r?r.some(e=>t.x<e.x+e.width&&e.x<t.x+t.width&&t.y<e.y+e.height&&e.y<t.height+t.y):!1}convertAbsoluteToRelativeCropArea(t,r){const{height:e,width:i,x:s,y:a}=t;return{height:e/r.naturalHeight,width:i/r.naturalWidth,x:s/r.naturalWidth,y:a/r.naturalHeight}}convertRelativeToAbsoluteCropArea(t,r){const{height:e,width:i,x:s,y:a}=t;return{height:e*r.naturalHeight,width:i*r.naturalWidth,x:s*r.naturalWidth,y:a*r.naturalHeight}}setPreviewImages(t){const r=this.cropper.image,e=this.cropper.getImageData();Object.keys(t).forEach(i=>{const s=t[i],a=this.convertRelativeToAbsoluteCropArea(s.cropArea,e),o=this.trigger.closest(".form-group").querySelector(`.t3js-image-manipulation-preview[data-crop-variant-id="${i}"]`),c=this.trigger.closest(".form-group").querySelector(`.t3js-image-manipulation-selected-ratio[data-crop-variant-id="${i}"]`);if(!(o instanceof HTMLElement))return;let h=o.getBoundingClientRect().width,d=parseInt(o.dataset.previewHeight,10);const f=a.width/a.height,v=h/f;v>d?h=d*f:d=v,h>a.width&&(h=a.width,d=a.height);const p=h/a.width,A={height:`${e.naturalHeight*p}px`,left:`${-a.x*p}px`,top:`${-a.y*p}px`,width:`${e.naturalWidth*p}px`},y={width:`${h}px`,height:`${d}px`},b=u`<span class="thumbnail thumbnail-status"> <div class=cropper-preview-container style=${g(y)}><img src=${r.src} style=${g(A)}></div> </span>`;for(;o.firstChild;)o.removeChild(o.firstChild);this.renderElements(b,o);const T=this.currentModal.ownerDocument.defaultView,w=this.currentModal.querySelector(`.t3-js-ratio-title[data-ratio-id="${s.id}${s.selectedRatio}"]`);c instanceof HTMLElement&&w instanceof T.HTMLElement&&(c.innerText=w.innerText)})}openPreview(t){const r=n.serializeCropVariants(t);let e=this.trigger.dataset.previewUrl;e=e+(e.includes("?")?"&":"?")+"cropVariants="+encodeURIComponent(r),window.open(e,"TYPO3ImageManipulationPreview")}save(t){const r=n.serializeCropVariants(t),e=document.querySelector(`#${this.trigger.dataset.field}`);this.trigger.dataset.cropVariants=JSON.stringify(t),this.setPreviewImages(t),e.value=r,O.markFieldAsChanged(e),this.currentModal.hideModal()}destroy(){this.currentModal&&(this.cropper instanceof C&&this.cropper.destroy(),this.initialized=!1,this.cropper=null,this.currentModal=null,this.data=null)}convertAreaToOffset(t,r){const e=r.getBoundingClientRect();return new R(t.x*e.width,t.y*e.height,t.width*e.width,t.height*e.height)}convertOffsetToArea(t,r){const e=r.getBoundingClientRect();return{x:t.left/e.width,y:t.top/e.height,width:t.width/e.width,height:t.height/e.height}}renderElements(t,r,e){const i=V(t);return Array.from(i).filter(a=>a instanceof HTMLElement).forEach(a=>r.appendChild(a)),e?r.querySelector(e):null}}var M=new n;export{M as default};
