Commit bbaa6d76 by Яков

fix

parent d232d707
{
"name": "react-ag-qeditor",
"version": "1.0.97",
"version": "1.0.98",
"description": "WYSIWYG html editor",
"author": "atma",
"license": "MIT",
......
......@@ -13,21 +13,78 @@ const ResizableImageTemplate = ({ node, updateAttributes, editor, getPos, select
const isInitialized = useRef(false);
const [isResizing, setIsResizing] = useState(false);
// Получаем ширину редактора для масштабирования изображений
const getEditorWidth = () => {
// Получаем текущую ширину редактора и доступное пространство
const getEditorDimensions = () => {
const editorElement = editor?.options?.element?.closest('.atma-editor-content');
return editorElement ? editorElement.clientWidth : null;
if (!editorElement) return { width: Infinity, availableSpace: Infinity };
const editorWidth = editorElement.clientWidth;
const imgElement = imgRef.current;
let availableSpace = editorWidth;
if (imgElement) {
const imgRect = imgElement.getBoundingClientRect();
const editorRect = editorElement.getBoundingClientRect();
if (node.attrs.align === 'center') {
const leftSpace = imgRect.left - editorRect.left;
const rightSpace = editorRect.right - imgRect.right;
availableSpace = Math.min(editorWidth, (leftSpace + rightSpace + imgRect.width));
console.log(leftSpace, rightSpace, availableSpace);
} else if (node.attrs.align === 'right') {
availableSpace = imgRect.left - editorRect.left + node.attrs.width;
} else if (node.attrs.align === 'left' || node.attrs.align === 'text') {
availableSpace = editorRect.right - imgRect.left;
}
}
return { width: editorWidth, availableSpace };
};
// Безопасное обновление атрибутов с учетом выравнивания и границ
const safeUpdateAttributes = (newAttrs) => {
const { width: editorWidth, availableSpace } = getEditorDimensions();
let { width, height, align } = { ...node.attrs, ...newAttrs };
const newAlign = newAttrs.align || align;
// При изменении выравнивания проверяем доступное пространство
if (newAlign && newAlign !== align) {
const maxWidth = availableSpace;
if (width > maxWidth) {
const ratio = maxWidth / width;
width = maxWidth;
height = Math.round(height * ratio);
}
} else {
// Для обычного обновления размеров
const maxWidth = availableSpace;
if (width > maxWidth) {
const ratio = maxWidth / width;
width = maxWidth;
height = Math.round(height * ratio);
}
}
// Проверяем минимальный размер
if (width < MIN_WIDTH) {
const ratio = MIN_WIDTH / width;
width = MIN_WIDTH;
height = Math.round(height * ratio);
}
updateAttributes({ width, height, ...newAttrs });
};
// Генерация уникального ID при создании
// Инициализация изображения
useEffect(() => {
if (!node.attrs['data-node-id']) {
updateAttributes({
safeUpdateAttributes({
'data-node-id': `img-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`
});
}
}, [node.attrs['data-node-id'], updateAttributes]);
}, [node.attrs['data-node-id']]);
// Обработка кликов вне изображения
useEffect(() => {
const handleClickOutside = (event) => {
if (wrapperRef.current && !wrapperRef.current.contains(event.target) && selected) {
......@@ -38,40 +95,22 @@ const ResizableImageTemplate = ({ node, updateAttributes, editor, getPos, select
return () => document.removeEventListener('mousedown', handleClickOutside);
}, [selected, editor, getPos]);
// Загрузка и инициализация изображения
useEffect(() => {
if (!imgRef.current || isInitialized.current) return;
const initImageSize = () => {
try {
const editorWidth = getEditorWidth();
const { width: editorWidth } = getEditorDimensions();
const naturalWidth = imgRef.current.naturalWidth;
const naturalHeight = imgRef.current.naturalHeight;
let width = node.attrs.width || naturalWidth;
let height = node.attrs.height || naturalHeight;
// Масштабируем изображение, если оно шире редактора
if (editorWidth && width > editorWidth) {
const ratio = editorWidth / width;
width = editorWidth;
height = Math.round(height * ratio);
}
// Проверяем минимальный размер
if (width < MIN_WIDTH) {
const ratio = MIN_WIDTH / width;
width = MIN_WIDTH;
height = Math.round(height * ratio);
}
if (width > 0 && height > 0) {
updateAttributes({
width: Math.round(width),
height: Math.round(height),
'data-node-id': node.attrs['data-node-id'] || Math.random().toString(36).substr(2, 9)
});
isInitialized.current = true;
}
safeUpdateAttributes({
width: naturalWidth,
height: naturalHeight,
'data-node-id': node.attrs['data-node-id'] || Math.random().toString(36).substr(2, 9)
});
isInitialized.current = true;
} catch (error) {
console.warn('Error initializing image size:', error);
}
......@@ -86,8 +125,9 @@ const ResizableImageTemplate = ({ node, updateAttributes, editor, getPos, select
return () => {
if (imgRef.current) imgRef.current.onload = null;
};
}, [node.attrs.width, node.attrs.height, updateAttributes, node.attrs['data-node-id']]);
}, [node.attrs.width, node.attrs.height, node.attrs['data-node-id']]);
// Обработка ресайза изображения
const handleResizeStart = (direction) => (e) => {
e.preventDefault();
e.stopPropagation();
......@@ -100,36 +140,49 @@ const ResizableImageTemplate = ({ node, updateAttributes, editor, getPos, select
const aspectRatio = startWidth / startHeight;
const startX = e.clientX;
const startY = e.clientY;
const { width: editorWidth, availableSpace } = getEditorDimensions();
const onMouseMove = (e) => {
const deltaX = e.clientX - startX;
const deltaY = e.clientY - startY;
let newWidth, newHeight;
const maxWidth = node.attrs.align === 'center' ? editorWidth : availableSpace;
if (node.attrs.align === 'center') {
if (direction.includes('n') || direction.includes('s')) {
const scale = direction.includes('s') ? 1 : -1;
newHeight = Math.max(startHeight + deltaY * scale, MIN_WIDTH);
newWidth = Math.round(newHeight * aspectRatio);
newWidth = Math.min(Math.round(newHeight * aspectRatio), maxWidth);
newHeight = Math.round(newWidth / aspectRatio);
} else {
const scale = direction.includes('e') ? 1 : -1;
newWidth = Math.max(startWidth + deltaX * scale, MIN_WIDTH);
newWidth = Math.min(
Math.max(startWidth + deltaX * scale, MIN_WIDTH),
maxWidth
);
newHeight = Math.round(newWidth / aspectRatio);
}
} else {
if (direction.includes('e') || direction.includes('w')) {
const scale = direction.includes('e') ? 1 : -1;
newWidth = Math.max(startWidth + deltaX * scale, MIN_WIDTH);
newWidth = Math.min(
Math.max(startWidth + deltaX * scale, MIN_WIDTH),
maxWidth
);
newHeight = Math.round(newWidth / aspectRatio);
} else {
const scale = direction.includes('s') ? 1 : -1;
newHeight = Math.max(startHeight + deltaY * scale, MIN_WIDTH);
newWidth = Math.round(newHeight * aspectRatio);
newWidth = Math.min(
Math.round(newHeight * aspectRatio),
maxWidth
);
newHeight = Math.round(newWidth / aspectRatio);
}
}
updateAttributes({ width: newWidth, height: newHeight });
safeUpdateAttributes({ width: newWidth, height: newHeight });
};
const onMouseUp = () => {
......@@ -144,12 +197,15 @@ const ResizableImageTemplate = ({ node, updateAttributes, editor, getPos, select
window.addEventListener('mouseup', onMouseUp);
};
// Изменение выравнивания с автоматическим масштабированием
const handleAlign = (align) => {
updateAttributes({ align });
safeUpdateAttributes({ align });
safeUpdateAttributes({ align });
setShowAlignMenu(false);
editor.commands.focus();
};
// Стили для обертки изображения
const getWrapperStyle = () => {
const baseStyle = {
display: 'inline-block',
......@@ -160,7 +216,6 @@ const ResizableImageTemplate = ({ node, updateAttributes, editor, getPos, select
margin: '0.5rem 0',
};
// Для выравнивания по центру
if (node.attrs.align === 'center') {
return {
...baseStyle,
......@@ -173,7 +228,6 @@ const ResizableImageTemplate = ({ node, updateAttributes, editor, getPos, select
};
}
// Для других вариантов выравнивания
return {
...baseStyle,
...(node.attrs.align === 'left' && {
......@@ -196,16 +250,17 @@ const ResizableImageTemplate = ({ node, updateAttributes, editor, getPos, select
};
};
// Стили для самого изображения
const getImageStyle = () => ({
width: node.attrs.width ? `${node.attrs.width}px` : 'auto',
height: 'auto', // Автоматическая высота для сохранения пропорций
height: 'auto',
maxWidth: '100%',
display: 'block',
cursor: 'default',
userSelect: 'none',
margin: node.attrs.align === 'center' ? '0 auto' : '0',
verticalAlign: node.attrs.align === 'text' ? 'middle' : 'top',
objectFit: 'contain' // Сохраняем пропорции изображения
objectFit: 'contain'
});
return (
......@@ -227,30 +282,13 @@ const ResizableImageTemplate = ({ node, updateAttributes, editor, getPos, select
style={getImageStyle()}
onLoad={() => {
if (imgRef.current && !isInitialized.current) {
const editorWidth = getEditorWidth();
const { width: editorWidth } = getEditorDimensions();
const naturalWidth = imgRef.current.naturalWidth;
const naturalHeight = imgRef.current.naturalHeight;
let width = naturalWidth;
let height = naturalHeight;
// Масштабируем изображение, если оно шире редактора
if (editorWidth && width > editorWidth) {
const ratio = editorWidth / width;
width = editorWidth;
height = Math.round(height * ratio);
}
// Проверяем минимальный размер
if (width < MIN_WIDTH) {
const ratio = MIN_WIDTH / width;
width = MIN_WIDTH;
height = Math.round(height * ratio);
}
updateAttributes({
width: Math.round(width),
height: Math.round(height),
safeUpdateAttributes({
width: naturalWidth,
height: naturalHeight,
'data-node-id': node.attrs['data-node-id'] || Math.random().toString(36).substr(2, 9)
});
isInitialized.current = true;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment