mirror of
https://github.com/TryGhost/Ghost.git
synced 2024-12-26 04:13:30 +03:00
Prevented Escape from closing the image editor (#18505)
no issue `Escape` can often be hit when attempting to cancel or undo an action through muscle memory despite it not doing anything in Pintura except closing the modal and losing all changes - added `willClose` option to the Pintura modal settings which only returns `true` when we've detected a click on the close button
This commit is contained in:
parent
1775591472
commit
d812781888
@ -3,7 +3,7 @@ import {Config} from '../api/config';
|
||||
import {Setting} from '../api/settings';
|
||||
import {getGhostPaths} from '../utils/helpers';
|
||||
import {getSettingValues} from '../api/settings';
|
||||
import {useCallback, useEffect, useState} from 'react';
|
||||
import {useCallback, useEffect, useRef, useState} from 'react';
|
||||
import {useGlobalData} from '../components/providers/GlobalDataProvider';
|
||||
|
||||
interface PinturaEditorConfig {
|
||||
@ -42,6 +42,7 @@ declare global {
|
||||
labelButtonExport: string;
|
||||
};
|
||||
previewPad: boolean;
|
||||
willClose: () => boolean;
|
||||
}) => {
|
||||
on: (event: string, callback: (result: { dest: File }) => void) => void;
|
||||
};
|
||||
@ -58,6 +59,8 @@ export default function usePinturaEditor({
|
||||
const [pintura] = getSettingValues<boolean>(settings, ['pintura']);
|
||||
const [scriptLoaded, setScriptLoaded] = useState<boolean>(false);
|
||||
const [cssLoaded, setCssLoaded] = useState<boolean>(false);
|
||||
const [isOpen, setIsOpen] = useState<boolean>(false);
|
||||
const allowClose = useRef<boolean>(false);
|
||||
|
||||
let isEnabled = pintura && scriptLoaded && cssLoaded || false;
|
||||
const pinturaConfig = globalConfig?.pintura as { js?: string; css?: string };
|
||||
@ -205,7 +208,16 @@ export default function usePinturaEditor({
|
||||
locale: {
|
||||
labelButtonExport: 'Save and close'
|
||||
},
|
||||
previewPad: true
|
||||
previewPad: true,
|
||||
// Skip default Escape to close behaviour, only allow when the close button is clicked
|
||||
willClose: () => {
|
||||
if (allowClose.current) {
|
||||
setIsOpen(false);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
});
|
||||
|
||||
editor.on('loaderror', () => {
|
||||
@ -215,11 +227,32 @@ export default function usePinturaEditor({
|
||||
editor.on('process', (result) => {
|
||||
handleSave(result.dest);
|
||||
});
|
||||
|
||||
setIsOpen(true);
|
||||
}
|
||||
},
|
||||
[isEnabled]
|
||||
);
|
||||
|
||||
// Only allow closing the modal if the close button was clicked
|
||||
useEffect(() => {
|
||||
if (!isOpen) {
|
||||
return;
|
||||
}
|
||||
|
||||
const handleCloseClick = (event: MouseEvent) => {
|
||||
if (event.target instanceof Element && event.target.closest('.PinturaModal button[title="Close"]')) {
|
||||
allowClose.current = true;
|
||||
}
|
||||
};
|
||||
|
||||
window.addEventListener('click', handleCloseClick, {capture: true});
|
||||
|
||||
return () => {
|
||||
window.removeEventListener('click', handleCloseClick, {capture: true});
|
||||
};
|
||||
}, [isOpen]);
|
||||
|
||||
return {
|
||||
isEnabled,
|
||||
openEditor
|
||||
|
@ -10,8 +10,10 @@ export default class KoenigImageEditor extends Component {
|
||||
@service feature;
|
||||
@service settings;
|
||||
@service ghostPaths;
|
||||
|
||||
@tracked scriptLoaded = false;
|
||||
@tracked cssLoaded = false;
|
||||
@tracked allowClose = false;
|
||||
|
||||
@inject config;
|
||||
|
||||
@ -128,6 +130,11 @@ export default class KoenigImageEditor extends Component {
|
||||
this.loadImageEditorCSS();
|
||||
}
|
||||
|
||||
willDestroy() {
|
||||
super.willDestroy(...arguments);
|
||||
this.removeCloseHandler();
|
||||
}
|
||||
|
||||
@action
|
||||
async onUploadComplete(urlList) {
|
||||
if (this.args.saveUrl) {
|
||||
@ -136,9 +143,23 @@ export default class KoenigImageEditor extends Component {
|
||||
}
|
||||
}
|
||||
|
||||
@action
|
||||
willClose() {
|
||||
if (this.allowClose) {
|
||||
this.allowClose = false;
|
||||
this.removeCloseHandler();
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@action
|
||||
async handleClick(uploader) {
|
||||
if (this.isEditorEnabled && this.args.imageSrc) {
|
||||
this.allowClose = false;
|
||||
this.addCloseHandler();
|
||||
|
||||
// add a timestamp to the image src to bypass cache
|
||||
// avoids cors issues with cached images
|
||||
const imageUrl = new URL(this.args.imageSrc);
|
||||
@ -199,7 +220,8 @@ export default class KoenigImageEditor extends Component {
|
||||
],
|
||||
locale: {
|
||||
labelButtonExport: 'Save and close'
|
||||
}
|
||||
},
|
||||
willClose: this.willClose
|
||||
});
|
||||
|
||||
editor.on('loaderror', () => {
|
||||
@ -222,4 +244,19 @@ export default class KoenigImageEditor extends Component {
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@action
|
||||
handleCloseClick(event) {
|
||||
if (event.target.closest('.PinturaModal button[title="Close"]')) {
|
||||
this.allowClose = true;
|
||||
}
|
||||
}
|
||||
|
||||
addCloseHandler() {
|
||||
window.addEventListener('click', this.handleCloseClick, {capture: true});
|
||||
}
|
||||
|
||||
removeCloseHandler() {
|
||||
window.removeEventListener('click', this.handleCloseClick, {capture: true});
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user