Skip to content

Commit

Permalink
Add quill paste matchers for MS Word
Browse files Browse the repository at this point in the history
for bullet and ordered lists
  • Loading branch information
daniel-eder committed Aug 1, 2022
1 parent 58916b6 commit d42a0be
Show file tree
Hide file tree
Showing 2 changed files with 57 additions and 0 deletions.
5 changes: 5 additions & 0 deletions frontend/components/Editor/index.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import standardToolbarContainer from '~/services/quill/standardToolbarContainer';
import dropOrPasteImageHandler from '~/services/quill/handlers/dropOrPasteImageHandler';
import msWordPasteMatchers from '~/services/quill/msWordPasteMatchers';
import uploadImageHandler from '~/services/quill/handlers/uploadImageHandler';
import markAsAnswerHandler from '~/services/quill/handlers/markAsAnswerHandler';
import codeBlockHandler from '~/services/quill/handlers/codeBlockHandler';
Expand Down Expand Up @@ -73,6 +74,10 @@ const bindings = {
handler: formulaHandler
},

clipboard: {
matchers: msWordPasteMatchers
}

// blurOnEsc: {
// key: 'Escape',
// handler: () => {
Expand Down
52 changes: 52 additions & 0 deletions frontend/services/quill/msWordPasteMatchers.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
// See https://github.com/quilljs/quill/issues/1225#issuecomment-1000785590

import Delta from 'quill-delta';

function matchMsWordList(node, delta) {
// Clone the operations
let ops = delta.ops.map((op) => Object.assign({}, op));

// Trim the front of the first op to remove the bullet/number
let bulletOp = ops.find((op) => op.insert && op.insert.trim().length);
if (!bulletOp) { return delta }

bulletOp.insert = bulletOp.insert.trimLeft();
let listPrefix = bulletOp.insert.match(/^.*?(^·|\.)/) || bulletOp.insert[0];
bulletOp.insert = bulletOp.insert.substring(listPrefix[0].length, bulletOp.insert.length);

// Trim the newline off the last op
let last = ops[ops.length-1];
last.insert = last.insert.substring(0, last.insert.length - 1);

// Determine the list type
let listType = listPrefix[0].length === 1 ? 'bullet' : 'ordered';

// Determine the list indent
let style = node.getAttribute('style').replace(/\n+/g, '');
let levelMatch = style.match(/level(\d+)/);
let indent = levelMatch ? levelMatch[1] - 1 : 0;

// Add the list attribute
ops.push({insert: '\n', attributes: {list: listType, indent}})

return new Delta(ops);
}

function maybeMatchMsWordList(node, delta) {
if (delta.ops[0].insert.trimLeft()[0] === '·') {
return matchMsWordList(node, delta);
}

return delta;
}

const msWordPasteMatchers = [
['p.MsoListParagraphCxSpFirst', matchMsWordList],
['p.MsoListParagraphCxSpMiddle', matchMsWordList],
['p.MsoListParagraphCxSpLast', matchMsWordList],
['p.MsoListParagraph', matchMsWordList],
['p.msolistparagraph', matchMsWordList],
['p.MsoNormal', maybeMatchMsWordList]
];

export default msWordPasteMatchers;

0 comments on commit d42a0be

Please sign in to comment.