Skip to content
GitLab
Menu
Projects
Groups
Snippets
Loading...
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
Menu
Open sidebar
lib
react-ag-qeditor
Commits
d232d707
Commit
d232d707
authored
Jul 04, 2025
by
Яков
Browse files
update
parent
79263e8a
Changes
2
Hide whitespace changes
Inline
Side-by-side
package.json
View file @
d232d707
{
{
"name"
:
"react-ag-qeditor"
,
"name"
:
"react-ag-qeditor"
,
"version"
:
"1.0.9
6
"
,
"version"
:
"1.0.9
7
"
,
"description"
:
"WYSIWYG html editor"
,
"description"
:
"WYSIWYG html editor"
,
"author"
:
"atma"
,
"author"
:
"atma"
,
"license"
:
"
MIT
"
,
"license"
:
"
MIT
"
,
...
...
src/extensions/Image.jsx
View file @
d232d707
...
@@ -11,6 +11,13 @@ const ResizableImageTemplate = ({ node, updateAttributes, editor, getPos, select
...
@@ -11,6 +11,13 @@ const ResizableImageTemplate = ({ node, updateAttributes, editor, getPos, select
const
wrapperRef
=
useRef
(
null
);
const
wrapperRef
=
useRef
(
null
);
const
[
showAlignMenu
,
setShowAlignMenu
]
=
useState
(
false
);
const
[
showAlignMenu
,
setShowAlignMenu
]
=
useState
(
false
);
const
isInitialized
=
useRef
(
false
);
const
isInitialized
=
useRef
(
false
);
const
[
isResizing
,
setIsResizing
]
=
useState
(
false
);
// Получаем ширину редактора для масштабирования изображений
const
getEditorWidth
=
()
=>
{
const
editorElement
=
editor
?.
options
?.
element
?.
closest
(
'
.atma-editor-content
'
);
return
editorElement
?
editorElement
.
clientWidth
:
null
;
};
// Генерация уникального ID при создании
// Генерация уникального ID при создании
useEffect
(()
=>
{
useEffect
(()
=>
{
...
@@ -36,8 +43,27 @@ const ResizableImageTemplate = ({ node, updateAttributes, editor, getPos, select
...
@@ -36,8 +43,27 @@ const ResizableImageTemplate = ({ node, updateAttributes, editor, getPos, select
const
initImageSize
=
()
=>
{
const
initImageSize
=
()
=>
{
try
{
try
{
const
width
=
node
.
attrs
.
width
||
imgRef
.
current
.
naturalWidth
;
const
editorWidth
=
getEditorWidth
();
const
height
=
node
.
attrs
.
height
||
imgRef
.
current
.
naturalHeight
;
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
)
{
if
(
width
>
0
&&
height
>
0
)
{
updateAttributes
({
updateAttributes
({
width
:
Math
.
round
(
width
),
width
:
Math
.
round
(
width
),
...
@@ -66,7 +92,7 @@ const ResizableImageTemplate = ({ node, updateAttributes, editor, getPos, select
...
@@ -66,7 +92,7 @@ const ResizableImageTemplate = ({ node, updateAttributes, editor, getPos, select
e
.
preventDefault
();
e
.
preventDefault
();
e
.
stopPropagation
();
e
.
stopPropagation
();
// Явно устанавливаем выделение перед началом ресайза
setIsResizing
(
true
);
editor
.
commands
.
setNodeSelection
(
getPos
());
editor
.
commands
.
setNodeSelection
(
getPos
());
const
startWidth
=
node
.
attrs
.
width
||
imgRef
.
current
.
naturalWidth
;
const
startWidth
=
node
.
attrs
.
width
||
imgRef
.
current
.
naturalWidth
;
...
@@ -109,7 +135,7 @@ const ResizableImageTemplate = ({ node, updateAttributes, editor, getPos, select
...
@@ -109,7 +135,7 @@ const ResizableImageTemplate = ({ node, updateAttributes, editor, getPos, select
const
onMouseUp
=
()
=>
{
const
onMouseUp
=
()
=>
{
window
.
removeEventListener
(
'
mousemove
'
,
onMouseMove
);
window
.
removeEventListener
(
'
mousemove
'
,
onMouseMove
);
window
.
removeEventListener
(
'
mouseup
'
,
onMouseUp
);
window
.
removeEventListener
(
'
mouseup
'
,
onMouseUp
);
// Явно восстанавливаем выделение после ресайза
setIsResizing
(
false
);
editor
.
commands
.
setNodeSelection
(
getPos
());
editor
.
commands
.
setNodeSelection
(
getPos
());
editor
.
commands
.
focus
();
editor
.
commands
.
focus
();
};
};
...
@@ -124,38 +150,62 @@ const ResizableImageTemplate = ({ node, updateAttributes, editor, getPos, select
...
@@ -124,38 +150,62 @@ const ResizableImageTemplate = ({ node, updateAttributes, editor, getPos, select
editor
.
commands
.
focus
();
editor
.
commands
.
focus
();
};
};
const
getWrapperStyle
=
()
=>
({
const
getWrapperStyle
=
()
=>
{
display
:
'
inline-block
'
,
const
baseStyle
=
{
lineHeight
:
0
,
margin
:
'
0.5rem 0
'
,
position
:
'
relative
'
,
outline
:
selected
?
`1px dashed
${
BORDER_COLOR
}
`
:
'
none
'
,
verticalAlign
:
'
top
'
,
...(
node
.
attrs
.
align
===
'
left
'
&&
{
float
:
'
left
'
,
marginRight
:
'
1rem
'
}),
...(
node
.
attrs
.
align
===
'
right
'
&&
{
float
:
'
right
'
,
marginLeft
:
'
1rem
'
}),
...(
node
.
attrs
.
align
===
'
center
'
&&
{
display
:
'
block
'
,
marginLeft
:
'
auto
'
,
marginRight
:
'
auto
'
,
textAlign
:
'
center
'
}),
...(
node
.
attrs
.
align
===
'
text
'
&&
{
display
:
'
inline-block
'
,
display
:
'
inline-block
'
,
float
:
'
none
'
,
lineHeight
:
0
,
margin
:
'
0 0.2rem
'
,
position
:
'
relative
'
,
verticalAlign
:
'
middle
'
outline
:
(
selected
||
isResizing
)
?
`1px dashed
${
BORDER_COLOR
}
`
:
'
none
'
,
})
verticalAlign
:
'
top
'
,
});
margin
:
'
0.5rem 0
'
,
};
// Для выравнивания по центру
if
(
node
.
attrs
.
align
===
'
center
'
)
{
return
{
...
baseStyle
,
display
:
'
block
'
,
marginLeft
:
'
auto
'
,
marginRight
:
'
auto
'
,
width
:
node
.
attrs
.
width
?
`
${
node
.
attrs
.
width
}
px`
:
'
fit-content
'
,
maxWidth
:
'
100%
'
,
textAlign
:
'
center
'
};
}
// Для других вариантов выравнивания
return
{
...
baseStyle
,
...(
node
.
attrs
.
align
===
'
left
'
&&
{
float
:
'
left
'
,
marginRight
:
'
1rem
'
,
width
:
node
.
attrs
.
width
?
`
${
node
.
attrs
.
width
}
px`
:
'
auto
'
,
}),
...(
node
.
attrs
.
align
===
'
right
'
&&
{
float
:
'
right
'
,
marginLeft
:
'
1rem
'
,
width
:
node
.
attrs
.
width
?
`
${
node
.
attrs
.
width
}
px`
:
'
auto
'
,
}),
...(
node
.
attrs
.
align
===
'
text
'
&&
{
display
:
'
inline-block
'
,
float
:
'
none
'
,
margin
:
'
0 0.2rem
'
,
verticalAlign
:
'
middle
'
,
width
:
node
.
attrs
.
width
?
`
${
node
.
attrs
.
width
}
px`
:
'
auto
'
,
}),
};
};
const
getImageStyle
=
()
=>
({
const
getImageStyle
=
()
=>
({
width
:
node
.
attrs
.
width
?
`
${
node
.
attrs
.
width
}
px`
:
'
auto
'
,
width
:
node
.
attrs
.
width
?
`
${
node
.
attrs
.
width
}
px`
:
'
auto
'
,
height
:
node
.
attrs
.
height
?
`
${
node
.
attrs
.
height
}
px`
:
'
auto
'
,
height
:
'
auto
'
,
// Автоматическая высота для сохранения пропорций
maxWidth
:
'
100%
'
,
maxWidth
:
'
100%
'
,
display
:
'
block
'
,
display
:
'
block
'
,
cursor
:
'
default
'
,
cursor
:
'
default
'
,
userSelect
:
'
none
'
,
userSelect
:
'
none
'
,
margin
:
node
.
attrs
.
align
===
'
center
'
?
'
0 auto
'
:
'
0
'
,
margin
:
node
.
attrs
.
align
===
'
center
'
?
'
0 auto
'
:
'
0
'
,
verticalAlign
:
node
.
attrs
.
align
===
'
text
'
?
'
middle
'
:
'
top
'
verticalAlign
:
node
.
attrs
.
align
===
'
text
'
?
'
middle
'
:
'
top
'
,
objectFit
:
'
contain
'
// Сохраняем пропорции изображения
});
});
return
(
return
(
...
@@ -173,12 +223,31 @@ const ResizableImageTemplate = ({ node, updateAttributes, editor, getPos, select
...
@@ -173,12 +223,31 @@ const ResizableImageTemplate = ({ node, updateAttributes, editor, getPos, select
<
img
<
img
{
...
node
.
attrs
}
{
...
node
.
attrs
}
ref
=
{
imgRef
}
ref
=
{
imgRef
}
draggable
=
{
true
}
// обязательно true для работы dragstart
draggable
=
{
true
}
style
=
{
getImageStyle
()
}
style
=
{
getImageStyle
()
}
onLoad
=
{
()
=>
{
onLoad
=
{
()
=>
{
if
(
imgRef
.
current
&&
!
isInitialized
.
current
)
{
if
(
imgRef
.
current
&&
!
isInitialized
.
current
)
{
const
width
=
imgRef
.
current
.
naturalWidth
;
const
editorWidth
=
getEditorWidth
();
const
height
=
imgRef
.
current
.
naturalHeight
;
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
({
updateAttributes
({
width
:
Math
.
round
(
width
),
width
:
Math
.
round
(
width
),
height
:
Math
.
round
(
height
),
height
:
Math
.
round
(
height
),
...
@@ -189,7 +258,7 @@ const ResizableImageTemplate = ({ node, updateAttributes, editor, getPos, select
...
@@ -189,7 +258,7 @@ const ResizableImageTemplate = ({ node, updateAttributes, editor, getPos, select
}
}
}
}
/>
/>
{
selected
&&
(
{
(
selected
||
isResizing
)
&&
(
<
Fragment
>
<
Fragment
>
{
[
'
nw
'
,
'
ne
'
,
'
sw
'
,
'
se
'
].
map
(
dir
=>
(
{
[
'
nw
'
,
'
ne
'
,
'
sw
'
,
'
se
'
].
map
(
dir
=>
(
<
div
<
div
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
.
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment