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
18e10c9c
Commit
18e10c9c
authored
May 20, 2026
by
Яков
Browse files
update fix issue
parent
09d32905
Changes
6
Hide whitespace changes
Inline
Side-by-side
package.json
View file @
18e10c9c
{
{
"name"
:
"react-ag-qeditor"
,
"name"
:
"react-ag-qeditor"
,
"version"
:
"1.1.4
8
"
,
"version"
:
"1.1.4
9
"
,
"description"
:
"WYSIWYG html editor"
,
"description"
:
"WYSIWYG html editor"
,
"author"
:
"atma"
,
"author"
:
"atma"
,
"license"
:
"
MIT
"
,
"license"
:
"
MIT
"
,
...
...
src/QEditor.jsx
View file @
18e10c9c
...
@@ -641,31 +641,27 @@ const QEditor = ({
...
@@ -641,31 +641,27 @@ const QEditor = ({
},
},
insertToggleBlock
:
{
insertToggleBlock
:
{
title
:
'
Раскрывающийся список
'
,
title
:
'
Раскрывающийся список
'
,
onClick
:
()
=>
onClick
:
()
=>
{
editor
.
commands
.
insertContent
([
const
{
state
,
view
}
=
editor
{
const
{
$from
}
=
state
.
selection
type
:
'
toggleBlock
'
,
attrs
:
{
// Всегда вставляем после текущего блока верхнего уровня,
title
:
'
Заголовок
'
,
// а не в позицию курсора — иначе insertContent может «съесть»
open
:
true
,
// пустой параграф, разделяющий два раскрывающихся списка.
},
const
insertPos
=
$from
.
after
(
Math
.
min
(
$from
.
depth
,
1
))
content
:
[
{
const
schema
=
state
.
schema
type
:
'
paragraph
'
,
const
toggleNode
=
schema
.
nodes
.
toggleBlock
.
create
(
content
:
[
{
title
:
'
Заголовок
'
,
open
:
true
},
{
schema
.
nodes
.
paragraph
.
create
(
type
:
'
text
'
,
null
,
text
:
'
Введите подробности...
'
,
schema
.
text
(
'
Введите подробности...
'
)
},
)
],
)
},
const
paraNode
=
schema
.
nodes
.
paragraph
.
create
()
],
},
view
.
dispatch
(
state
.
tr
.
insert
(
insertPos
,
[
toggleNode
,
paraNode
]))
{
},
type
:
'
paragraph
'
,
content
:
[],
},
]),
},
},
toggleTableBorders
:
{
toggleTableBorders
:
{
...
@@ -795,7 +791,7 @@ const QEditor = ({
...
@@ -795,7 +791,7 @@ const QEditor = ({
)
)
}
}
const
getUploader
=
({
accept
=
'
*
'
,
...
o
},
custom_url
=
''
)
=>
{
const
getUploader
=
({
accept
=
'
*
'
,
processingMessage
=
null
,
...
o
},
custom_url
=
''
)
=>
{
let
url
=
uploadOptions
.
url
let
url
=
uploadOptions
.
url
let
multiple
=
true
let
multiple
=
true
if
(
o
.
afterParams
&&
o
.
afterParams
.
length
>
0
)
{
if
(
o
.
afterParams
&&
o
.
afterParams
.
length
>
0
)
{
...
@@ -817,6 +813,7 @@ const QEditor = ({
...
@@ -817,6 +813,7 @@ const QEditor = ({
accept
=
{
accept
}
accept
=
{
accept
}
action
=
{
custom_url
.
length
>
0
?
custom_url
:
url
}
action
=
{
custom_url
.
length
>
0
?
custom_url
:
url
}
errorMessage
=
{
uploadOptions
.
errorMessage
}
errorMessage
=
{
uploadOptions
.
errorMessage
}
processingMessage
=
{
processingMessage
}
onSuccess
=
{
(
file
,
html
)
=>
{
onSuccess
=
{
(
file
,
html
)
=>
{
if
(
typeof
file
!==
"
undefined
"
)
{
if
(
typeof
file
!==
"
undefined
"
)
{
const
_uploadedPaths
=
[...
uploadedPaths
]
const
_uploadedPaths
=
[...
uploadedPaths
]
...
@@ -1019,7 +1016,8 @@ const QEditor = ({
...
@@ -1019,7 +1016,8 @@ const QEditor = ({
<
Fragment
>
<
Fragment
>
{
getUploader
({
{
getUploader
({
accept
:
'
application/pdf
'
,
accept
:
'
application/pdf
'
,
afterParams
:
[
'
no_convert=1
'
]
afterParams
:
[
'
no_convert=1
'
],
processingMessage
:
'
Распознаём текст PDF, подождите...
'
},
'
/ru/pdf-to-text/
'
)
}
},
'
/ru/pdf-to-text/
'
)
}
</
Fragment
>
</
Fragment
>
)
)
...
...
src/components/Uploader.js
View file @
18e10c9c
...
@@ -102,6 +102,10 @@ export default class Uploader extends React.Component {
...
@@ -102,6 +102,10 @@ export default class Uploader extends React.Component {
}
}
}
}
get
processingMessage
()
{
return
this
.
props
.
processingMessage
;
}
render
()
{
render
()
{
let
{
disabledFileUpload
,
isUpload
,
progress
,
dropFiles
}
=
this
.
state
;
let
{
disabledFileUpload
,
isUpload
,
progress
,
dropFiles
}
=
this
.
state
;
...
@@ -113,6 +117,12 @@ export default class Uploader extends React.Component {
...
@@ -113,6 +117,12 @@ export default class Uploader extends React.Component {
{
this
.
state
.
html
.
length
>
0
?
<
div
dangerouslySetInnerHTML
=
{{
__html
:
this
.
state
.
html
}}
/
>
{
this
.
state
.
html
.
length
>
0
?
<
div
dangerouslySetInnerHTML
=
{{
__html
:
this
.
state
.
html
}}
/
>
:
:
<>
<>
{
isUpload
&&
this
.
processingMessage
&&
(
<
div
className
=
'
atma-editor-uploader-processing
'
>
<
span
className
=
'
atma-editor-uploader-processing-spinner
'
/>
{
this
.
processingMessage
}
<
/div
>
)}
<
div
className
=
{
'
atma-editor-uploader-uitems
'
}
>
<
div
className
=
{
'
atma-editor-uploader-uitems
'
}
>
{
{
Object
.
keys
(
this
.
state
.
files
).
map
((
uid
,
i
)
=>
(
Object
.
keys
(
this
.
state
.
files
).
map
((
uid
,
i
)
=>
(
...
@@ -223,5 +233,6 @@ Uploader.defaultProps = {
...
@@ -223,5 +233,6 @@ Uploader.defaultProps = {
type
:
''
,
type
:
''
,
onSuccess
:
()
=>
{},
onSuccess
:
()
=>
{},
errorMessage
:
null
,
errorMessage
:
null
,
modalType
:
null
modalType
:
null
,
processingMessage
:
null
};
};
src/extensions/Image.jsx
View file @
18e10c9c
...
@@ -458,7 +458,10 @@ const ResizableImageTemplate = ({ node, updateAttributes, editor, getPos, select
...
@@ -458,7 +458,10 @@ const ResizableImageTemplate = ({ node, updateAttributes, editor, getPos, select
const
imageContent
=
(
const
imageContent
=
(
<>
<>
<
img
<
img
{
...
node
.
attrs
}
src
=
{
node
.
attrs
.
src
}
alt
=
{
node
.
attrs
.
alt
||
undefined
}
title
=
{
node
.
attrs
.
title
||
undefined
}
data
-
node
-
id
=
{
node
.
attrs
[
'
data-node-id
'
]
||
undefined
}
ref
=
{
imgRef
}
ref
=
{
imgRef
}
draggable
=
{
true
}
draggable
=
{
true
}
style
=
{
getImageStyle
()
}
style
=
{
getImageStyle
()
}
...
...
src/extensions/ToggleBlock.js
View file @
18e10c9c
...
@@ -184,7 +184,46 @@ const ToggleBlock = Node.create({
...
@@ -184,7 +184,46 @@ const ToggleBlock = Node.create({
},
},
addProseMirrorPlugins
()
{
addProseMirrorPlugins
()
{
const
buildGapFix
=
(
state
)
=>
{
const
doc
=
state
.
doc
const
tr
=
state
.
tr
let
additionalOffset
=
0
let
pos
=
1
for
(
let
i
=
0
;
i
<
doc
.
childCount
-
1
;
i
++
)
{
const
node
=
doc
.
child
(
i
)
const
nextNode
=
doc
.
child
(
i
+
1
)
pos
+=
node
.
nodeSize
if
(
node
.
type
.
name
===
'
toggleBlock
'
&&
nextNode
.
type
.
name
===
'
toggleBlock
'
)
{
tr
.
insert
(
pos
+
additionalOffset
,
state
.
schema
.
nodes
.
paragraph
.
create
()
)
additionalOffset
+=
2
}
}
return
additionalOffset
>
0
?
tr
:
null
}
return
[
return
[
new
Plugin
({
key
:
new
PluginKey
(
'
toggleBlockGap
'
),
view
(
editorView
)
{
// Fix adjacent toggle blocks present in initially loaded content
const
tr
=
buildGapFix
(
editorView
.
state
)
if
(
tr
)
editorView
.
dispatch
(
tr
)
return
{}
},
appendTransaction
(
transactions
,
_oldState
,
newState
)
{
if
(
!
transactions
.
some
(
tr
=>
tr
.
docChanged
))
return
null
return
buildGapFix
(
newState
)
}
}),
new
Plugin
({
new
Plugin
({
key
:
new
PluginKey
(
'
toggleBlockPaste
'
),
key
:
new
PluginKey
(
'
toggleBlockPaste
'
),
props
:
{
props
:
{
...
...
src/index.scss
View file @
18e10c9c
...
@@ -234,6 +234,10 @@ body{
...
@@ -234,6 +234,10 @@ body{
// }
// }
//}
//}
@keyframes atma-spin {
to { transform: rotate(360deg); }
}
.atma-editor {
.atma-editor {
position: relative;
position: relative;
border-radius: 8px;
border-radius: 8px;
...
@@ -814,6 +818,30 @@ body{
...
@@ -814,6 +818,30 @@ body{
}
}
&-processing{
display: flex;
align-items: center;
gap: 10px;
padding: 12px 16px;
margin-bottom: 12px;
background: #f0f7ff;
border: 1px solid #bae0ff;
border-radius: 8px;
color: #1677ff;
font-size: 14px;
}
&-processing-spinner{
display: inline-block;
width: 16px;
height: 16px;
border: 2px solid #bae0ff;
border-top-color: #1677ff;
border-radius: 50%;
flex-shrink: 0;
animation: atma-spin 0.8s linear infinite;
}
&-progress{
&-progress{
display: flex;
display: flex;
position: relative;
position: relative;
...
...
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