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
f754ac73
Commit
f754ac73
authored
Feb 05, 2026
by
Яков
Browse files
fix image
parent
e21301e8
Changes
2
Show whitespace changes
Inline
Side-by-side
package.json
View file @
f754ac73
{
{
"name"
:
"react-ag-qeditor"
,
"name"
:
"react-ag-qeditor"
,
"version"
:
"1.1.2
6
"
,
"version"
:
"1.1.2
7
"
,
"description"
:
"WYSIWYG html editor"
,
"description"
:
"WYSIWYG html editor"
,
"author"
:
"atma"
,
"author"
:
"atma"
,
"license"
:
"
MIT
"
,
"license"
:
"
MIT
"
,
...
...
src/extensions/Image.jsx
View file @
f754ac73
...
@@ -23,26 +23,35 @@ const ResizableImageTemplate = ({ node, updateAttributes, editor, getPos, select
...
@@ -23,26 +23,35 @@ const ResizableImageTemplate = ({ node, updateAttributes, editor, getPos, select
// Добавляем прозрачный нулевой пробел после изображения
// Добавляем прозрачный нулевой пробел после изображения
useEffect
(()
=>
{
useEffect
(()
=>
{
if
(
!
editor
||
!
getPos
)
return
;
if
(
!
editor
||
!
getPos
||
editor
.
isDestroyed
)
return
let
pos
;
let
pos
try
{
try
{
pos
=
getPos
();
pos
=
getPos
()
if
(
typeof
pos
!==
'
number
'
)
return
;
}
catch
{
}
catch
(
e
)
{
return
console
.
warn
(
'
getPos() failed:
'
,
e
);
return
;
}
}
if
(
typeof
pos
!==
'
number
'
)
return
const
doc
=
editor
.
state
.
doc
;
const
{
doc
}
=
editor
.
state
const
node
=
doc
.
nodeAt
(
pos
)
if
(
!
node
||
node
.
type
.
name
!==
'
image
'
)
return
if
(
doc
.
nodeSize
>
pos
&&
doc
.
nodeAt
(
pos
)?.
textContent
!==
'
\
u200B
'
)
{
const
next
=
doc
.
nodeAt
(
pos
+
node
.
nodeSize
)
editor
.
commands
.
insertContentAt
(
pos
+
1
,
{
if
(
next
?.
isText
&&
next
.
text
===
'
\
u200B
'
)
return
type
:
'
text
'
,
text
:
'
\
u200B
'
requestAnimationFrame
(()
=>
{
});
if
(
editor
.
isDestroyed
)
return
}
},
[
editor
,
getPos
]);
try
{
const
p
=
getPos
()
const
n
=
editor
.
state
.
doc
.
nodeAt
(
p
)
if
(
!
n
||
n
.
type
.
name
!==
'
image
'
)
return
editor
.
commands
.
insertContentAt
(
p
+
n
.
nodeSize
,
'
\
u200B
'
)
}
catch
{}
})
},
[])
// Получаем текущую ширину редактора и доступное пространство
// Получаем текущую ширину редактора и доступное пространство
...
@@ -79,38 +88,84 @@ const ResizableImageTemplate = ({ node, updateAttributes, editor, getPos, select
...
@@ -79,38 +88,84 @@ const ResizableImageTemplate = ({ node, updateAttributes, editor, getPos, select
// Безопасное обновление атрибутов с учетом выравнивания и границ
// Безопасное обновление атрибутов с учетом выравнивания и границ
const
safeUpdateAttributes
=
(
newAttrs
)
=>
{
const
clamp
=
(
v
,
min
,
max
)
=>
Math
.
min
(
max
,
Math
.
max
(
min
,
v
))
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
);
}
}
// Проверяем минимальный размер
const
safeUpdateAttributes
=
(
patch
)
=>
{
if
(
width
<
MIN_WIDTH
)
{
if
(
!
editor
||
editor
.
isDestroyed
)
return
const
ratio
=
MIN_WIDTH
/
width
;
width
=
MIN_WIDTH
;
height
=
Math
.
round
(
height
*
ratio
);
}
updateAttributes
({
width
,
height
,
...
newAttrs
});
let
pos
};
try
{
pos
=
getPos
()
}
catch
{
return
}
if
(
typeof
pos
!==
'
number
'
)
return
const
currentNode
=
editor
.
state
.
doc
.
nodeAt
(
pos
)
if
(
!
currentNode
||
currentNode
.
type
.
name
!==
'
image
'
)
return
const
base
=
currentNode
.
attrs
||
{}
// 1) сохраняем то, что не хотим потерять
const
keep
=
{
align
:
base
.
align
,
border
:
base
.
border
,
borderColor
:
base
.
borderColor
,
borderWidth
:
base
.
borderWidth
,
borderRadius
:
base
.
borderRadius
,
}
// 2) кандидат на апдейт
let
next
=
{
...
keep
,
...
base
,
...
patch
}
// 3) нормализуем размеры (границы)
const
minW
=
80
const
maxW
=
1600
const
minH
=
40
const
maxH
=
2000
if
(
next
.
width
!=
null
)
next
.
width
=
clamp
(
Number
(
next
.
width
)
||
0
,
minW
,
maxW
)
if
(
next
.
height
!=
null
)
next
.
height
=
clamp
(
Number
(
next
.
height
)
||
0
,
minH
,
maxH
)
// 4) нормализуем align (чтобы не улетало в мусор)
const
allowedAlign
=
new
Set
([
'
left
'
,
'
center
'
,
'
right
'
,
'
full
'
])
if
(
next
.
align
&&
!
allowedAlign
.
has
(
next
.
align
))
next
.
align
=
base
.
align
||
'
center
'
updateAttributes
(
next
)
}
//
// 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 });
// };
// Инициализация изображения
// Инициализация изображения
useEffect
(()
=>
{
useEffect
(()
=>
{
...
@@ -388,20 +443,20 @@ const ResizableImageTemplate = ({ node, updateAttributes, editor, getPos, select
...
@@ -388,20 +443,20 @@ const ResizableImageTemplate = ({ node, updateAttributes, editor, getPos, select
ref
=
{
imgRef
}
ref
=
{
imgRef
}
draggable
=
{
true
}
draggable
=
{
true
}
style
=
{
getImageStyle
()
}
style
=
{
getImageStyle
()
}
onLoad
=
{
()
=>
{
//
onLoad={() => {
if
(
imgRef
.
current
&&
!
isInitialized
.
current
&&
!
node
.
attrs
.
width
&&
!
node
.
attrs
.
height
)
{
//
if (imgRef.current && !isInitialized.current && !node.attrs.width && !node.attrs.height) {
const
{
width
:
editorWidth
}
=
getEditorDimensions
();
//
const { width: editorWidth } = getEditorDimensions();
const
naturalWidth
=
imgRef
.
current
.
naturalWidth
;
//
const naturalWidth = imgRef.current.naturalWidth;
const
naturalHeight
=
imgRef
.
current
.
naturalHeight
;
//
const naturalHeight = imgRef.current.naturalHeight;
//
safeUpdateAttributes
({
//
safeUpdateAttributes({
width
:
naturalWidth
,
//
width: naturalWidth,
height
:
naturalHeight
,
//
height: naturalHeight,
'
data-node-id
'
:
node
.
attrs
[
'
data-node-id
'
]
||
Math
.
random
().
toString
(
36
).
substr
(
2
,
9
)
//
'data-node-id': node.attrs['data-node-id'] || Math.random().toString(36).substr(2, 9)
});
//
});
isInitialized
.
current
=
true
;
//
isInitialized.current = true;
}
//
}
}
}
//
}}
/>
/>
{
{
node
.
attrs
.
frontAlt
?.
length
>
0
&&
node
.
attrs
.
frontAlt
?.
length
>
0
&&
...
...
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