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
c79e85c3
Commit
c79e85c3
authored
Jun 27, 2025
by
Яков
Browse files
fix drag and drop
parent
dd70d3d0
Changes
2
Hide whitespace changes
Inline
Side-by-side
src/QEditor.jsx
View file @
c79e85c3
...
@@ -29,7 +29,7 @@ import Uploader from './components/Uploader'
...
@@ -29,7 +29,7 @@ import Uploader from './components/Uploader'
import
Video
from
'
./extensions/Video
'
import
Video
from
'
./extensions/Video
'
import
Iframe
from
'
./extensions/Iframe
'
import
Iframe
from
'
./extensions/Iframe
'
// import CustomLink from './extensions/CustomLink'
// import CustomLink from './extensions/CustomLink'
import
DragAndDrop
from
'
./extensions/DragAndDrop
'
import
{
DragAndDrop
}
from
'
./extensions/DragAndDrop
'
import
{
useReactMediaRecorder
}
from
'
react-media-recorder
'
import
{
useReactMediaRecorder
}
from
'
react-media-recorder
'
import
axios
from
'
axios
'
import
axios
from
'
axios
'
import
ReactStopwatch
from
'
react-stopwatch
'
import
ReactStopwatch
from
'
react-stopwatch
'
...
...
src/extensions/DragAndDrop.js
View file @
c79e85c3
import
{
Extension
}
from
"
@tiptap/core
"
;
import
{
Extension
}
from
'
@tiptap/core
'
;
import
{
Plugin
,
PluginKey
}
from
'
prosemirror-state
'
import
{
Plugin
,
PluginKey
}
from
'
prosemirror-state
'
;
import
axios
from
'
axios
'
import
{
EditorView
}
from
'
prosemirror-view
'
;
import
axios
from
'
axios
'
;
const
upload
=
async
(
file
)
=>
{
export
const
DragAndDrop
=
Extension
.
create
(
{
let
formData
=
new
FormData
();
name
:
'
dragAndDrop
'
,
formData
.
append
(
'
file
'
,
file
);
addOptions
()
{
const
headers
=
{
'
Content-Type
'
:
'
multipart/form-data
'
};
return
{
const
response
=
await
axios
.
post
(
global
.
uploadUrl
,
formData
,
{
headers
:
headers
}
);
uploadUrl
:
''
,
// URL для загрузки файлов
uploadHandler
:
null
,
// Альтернативный обработчик загрузки
types
:
[
'
image
'
],
// Поддерживаемые типы файлов
headers
:
{},
// Дополнительные заголовки
};
},
return
response
.
data
.
file_path
;
};
const
DragAndDrop
=
Extension
.
create
({
name
:
'
customDragAndDrop
'
,
addProseMirrorPlugins
()
{
addProseMirrorPlugins
()
{
if
(
!
this
.
options
.
uploadUrl
&&
!
this
.
options
.
uploadHandler
)
{
return
[];
}
const
isRealFile
=
(
item
)
=>
{
// Игнорируем текстовые форматы и специфичные для Word
if
(
item
.
type
.
startsWith
(
'
text/
'
)
||
item
.
type
.
startsWith
(
'
application/x-mso
'
)
||
item
.
type
===
'
text/html
'
||
item
.
type
===
'
text/rtf
'
)
{
return
false
;
}
// Разрешенные файловые типы
return
[
'
image/
'
,
'
video/
'
,
'
audio/
'
,
'
application/octet-stream
'
,
'
application/pdf
'
,
'
application/zip
'
].
some
(
type
=>
item
.
type
.
startsWith
(
type
));
};
const
uploadFile
=
async
(
file
)
=>
{
if
(
this
.
options
.
uploadHandler
)
{
return
await
this
.
options
.
uploadHandler
(
file
);
}
const
formData
=
new
FormData
();
formData
.
append
(
'
file
'
,
file
);
const
headers
=
{
'
Content-Type
'
:
'
multipart/form-data
'
,
...
this
.
options
.
headers
};
const
response
=
await
axios
.
post
(
this
.
options
.
uploadUrl
,
formData
,
{
headers
}
);
if
(
!
response
.
data
)
throw
new
Error
(
'
Upload failed
'
);
return
response
.
data
.
file_path
;
};
const
handleUpload
=
async
(
file
,
view
,
pos
)
=>
{
try
{
const
filePath
=
await
uploadFile
(
file
);
if
(
!
filePath
)
return
;
const
{
state
}
=
view
;
const
{
tr
}
=
state
;
let
node
;
if
(
file
.
type
.
startsWith
(
'
image/
'
)
&&
this
.
options
.
types
.
includes
(
'
image
'
))
{
node
=
state
.
schema
.
nodes
.
image
?.
create
({
src
:
filePath
});
}
else
if
(
file
.
type
.
startsWith
(
'
video/
'
)
&&
this
.
options
.
types
.
includes
(
'
video
'
))
{
node
=
state
.
schema
.
nodes
.
video
?.
create
({
src
:
filePath
});
}
else
if
(
file
.
type
.
startsWith
(
'
audio/
'
)
&&
this
.
options
.
types
.
includes
(
'
audio
'
))
{
node
=
state
.
schema
.
nodes
.
audio
?.
create
({
src
:
filePath
});
}
if
(
node
)
{
view
.
dispatch
(
tr
.
insert
(
pos
,
node
));
}
}
catch
(
error
)
{
console
.
error
(
'
Upload error:
'
,
error
);
}
};
return
[
return
[
new
Plugin
({
new
Plugin
({
key
:
new
PluginKey
(
'
customD
ragAndDrop
'
),
key
:
new
PluginKey
(
'
d
ragAndDrop
'
),
props
:
{
props
:
{
handleDOMEvents
:
{
handleDOMEvents
:
{
async
paste
(
view
,
event
)
{
drop
(
view
,
event
)
{
const
files
=
event
.
dataTransfer
?.
files
;
console
.
log
(
'
Clipboard types:
'
,
event
.
clipboardData
.
types
);
if
(
!
files
||
files
.
length
===
0
)
return
false
;
console
.
log
(
'
HTML data length:
'
,
event
.
clipboardData
.
getData
(
'
text/html
'
).
length
);
const
coordinates
=
view
.
posAtCoords
({
// let items = (event.clipboardData || event.originalEvent.clipboardData).items;
left
:
event
.
clientX
,
//
top
:
event
.
clientY
,
// for (let i = 0; i < items.length; i++){
});
// const { schema } = view.state;
if
(
!
coordinates
)
return
false
;
// const image = items[i].getAsFile();
//
event
.
preventDefault
();
// if (!image) {
// return
Array
.
from
(
files
).
forEach
(
file
=>
{
// }
if
(
isRealFile
({
kind
:
'
file
'
,
type
:
file
.
type
}))
{
//
handleUpload
(
file
,
view
,
coordinates
.
pos
);
// // event.preventDefault();
// const imageSrc = await upload(image);
//
// const node = schema.nodes.image.create({
// src: imageSrc,
// });
// const transaction = view.state.tr.replaceSelectionWith(node);
// view.dispatch(transaction)
// }
},
async
drop
(
view
,
event
)
{
const
hasFiles
=
event
.
dataTransfer
.
files
.
length
>
0
;
// Другой способ достать текст
// console.log(event.dataTransfer.items[0].getAsString( (i) => {
// console.log(i)
// }));
// console.log(hasFiles)
if
(
hasFiles
)
{
// event.preventDefault();
const
images
=
event
.
dataTransfer
.
files
;
const
{
schema
}
=
view
.
state
;
const
coordinates
=
view
.
posAtCoords
({
left
:
event
.
clientX
,
top
:
event
.
clientY
});
for
(
let
i
=
0
;
i
<
images
.
length
;
i
++
)
{
const
imageSrc
=
await
upload
(
images
[
i
]);
if
(
imageSrc
)
{
const
node
=
schema
.
nodes
.
image
.
create
({
src
:
imageSrc
});
const
transaction
=
view
.
state
.
tr
.
insert
(
coordinates
.
pos
,
node
);
view
.
dispatch
(
transaction
)
}
}
}
}
});
}
}
return
true
;
}
},
})
},
]
handlePaste
(
view
,
event
)
{
}
const
items
=
event
.
clipboardData
?.
items
;
});
if
(
!
items
)
return
false
;
// Проверяем наличие реальных файлов
const
files
=
Array
.
from
(
items
)
.
filter
(
item
=>
item
.
kind
===
'
file
'
&&
isRealFile
(
item
))
.
map
(
item
=>
item
.
getAsFile
())
.
filter
(
Boolean
);
if
(
files
.
length
===
0
)
return
false
;
event
.
preventDefault
();
export
default
DragAndDrop
;
const
{
state
}
=
view
;
const
pos
=
state
.
selection
.
$from
.
pos
;
files
.
forEach
(
file
=>
{
handleUpload
(
file
,
view
,
pos
);
});
return
true
;
},
},
}),
];
},
});
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