Open UnivocalHoneyBadger opened 4 years ago
Yes, pasting in table should be processed specially. In my product, I forked quilljs and processed this in clipboard module(onCapturePaste). But there, I can not find a proper way to process.
I agree it's quite tricky. What could work is adding a paste
eventListener where you access the text\html
and find all instances of <p>
and replace them with something else. Maybe with the help of a clipboard matcher we could properly turn each line into cell divs.
How does this suggestion sound, and please correct me if I'm wrong:
Find all instances of <p>
and </p>
in text/html
data of the paste
event, replace it with a tag like (for example) <celldiv>
.
Then by using a matcher you let the clipboard itself process it for you into the element you want. Here's the documentation about matchers: https://quilljs.com/docs/modules/clipboard/#addmatcher
As far as I know, I think the matchers is used to handle that how quill convert DOM element to content, they are always some pure functions, it may not be suitable for this.
I have already fixed this issue in my company project. As you said, adding a paste
eventListener, processing pasted delta
if current selection is an instance of TableCellLine
.
Here is the code:
onCapturePaste(e) {
if (e.defaultPrevented || !this.quill.isEnabled()) return;
const range = this.quill.getSelection(true);
// Process pasting in table-cell-line before
const [thisLeaf] = this.quill.getLine(range.index)
if (thisLeaf && thisLeaf.constructor.name === 'TableCellLine') {
e.preventDefault();
const html = e.clipboardData.getData('text/html');
const text = e.clipboardData.getData('text/plain');
const files = Array.from(e.clipboardData.files || []);
if (!html && files.length > 0) {
this.quill.uploader.upload(range, files);
} else {
this.onTableCellPaste(range, { html, text });
}
return;
}
// ............bypass quill origin code
}
onTableCellPaste
is the function processing default converted delta:
onTableCellPaste (range, {text, html}) {
const [line] = this.quill.getLine(range.index)
const lineFormats = line.formats()
const formats = this.quill.getFormat(range.index);
let pastedDelta = this.convert({ text, html }, formats);
pastedDelta = pastedDelta.reduce((newDelta, op) => {
if (op.insert && typeof op.insert === 'string') {
const lines = []
let insertStr = op.insert
let start = 0
for (let i = 0; i < op.insert.length; i++) {
if (insertStr.charAt(i) === '\n') {
if (i === 0) {
lines.push('\n')
} else {
lines.push(insertStr.substring(start, i))
lines.push('\n')
}
start = i + 1
}
}
const tailStr = insertStr.substring(start)
if (tailStr) lines.push(tailStr)
lines.forEach(text => {
text === '\n'
? newDelta.insert('\n', extend(
{},
op.attributes,
lineFormats
))
: newDelta.insert(text, op.attributes)
})
} else {
newDelta.insert(op.insert, op.attributes)
}
return newDelta
}, new Delta())
debug.log('onTableCellPaste', pastedDelta, { text, html });
const delta = new Delta()
.retain(range.index)
.delete(range.length)
.concat(pastedDelta);
this.quill.updateContents(delta, Quill.sources.USER);
this.quill.setSelection(
delta.length() - range.length,
Quill.sources.SILENT,
);
this.quill.scrollIntoView();
}
The delta of multiple lines is merged in only one insertion:
{
insert: first line \n second line \n third line,
attributes: { foo: foo }
}
It caused the problem.
Back to quill-better-table
module, I have not found a proper way to fix it.
If I add a new paste
eventListener, I need to make sure that the new listener must execute before the old one.
Maybe there is a better way to fix it? I will try adding a new paste
eventListener first, if you have some other better way, help me please~:)
Does any body has any fix or work-around for this issue?
When copying multiple lines into the table it breaks. I think that due to the clipboard module, each line is seen as a delta insert which does not check against the table and simply inserts it in between.
Here's a GIF that shows what happened:![0VcWUYUNUu](https://user-images.githubusercontent.com/17876954/70221634-04467800-1749-11ea-90f9-a89a674c94d3.gif)
Here's what the clipboard text/html data returned:
Here's what the clipboard text/plain data returned:
test\ntest
Edit: This also breaks the showTableTools function