-
Notifications
You must be signed in to change notification settings - Fork 3
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
2 changed files
with
68 additions
and
21 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,31 +1,78 @@ | ||
import { OutputData as RichTextData } from '@editorjs/editorjs'; | ||
|
||
export const handleMsUnorderedList = ( | ||
export const handleMsPasteFormatting = ( | ||
event: ClipboardEvent | ||
): RichTextData | undefined => { | ||
const text = event.clipboardData?.getData('text'); | ||
// If there is no text, or the text has no list return undefined and continue native paste propagation | ||
if (!text || !hasWordListMarkers(text)) { | ||
return; | ||
} | ||
|
||
// Match any line that starts with "•\t" followed by anything until the end of the line | ||
const matches = text?.match(/•\t(.*)/g); | ||
const parsedLines = text.split('\n').map((line) => { | ||
if (isUnorderedList(line)) { | ||
return { type: 'ul', text: line.replace(/•\t/, '') }; | ||
} | ||
if (isOrderedList(line)) { | ||
return { type: 'ol', text: line.replace(/^\d+\.\s/, '') }; | ||
} | ||
if (line === '\r') { | ||
return { type: 'break', text: line }; | ||
} | ||
return { type: 'p', text: line }; | ||
}); | ||
|
||
if (!matches) { | ||
return undefined; | ||
} | ||
// If there are matches, prevent default actions, then create an array of strings without the "•\t" prefix | ||
const listItems = matches.map((item) => item.replace(/•\t/, '')); | ||
const groupedLines = groupSiblingsBy(parsedLines, (line) => line.type); | ||
|
||
const blocks = groupedLines.map((lines) => { | ||
const type = lines[0]!.type; | ||
const textLines = lines.map((line) => line.text); | ||
|
||
if (type === 'ol') { | ||
return createListBlock(textLines, 'ordered'); | ||
} | ||
if (type === 'ul') { | ||
return createListBlock(textLines, 'unordered'); | ||
} | ||
return createParagraphBlock(textLines); | ||
}); | ||
|
||
// Now create a new object that conforms to the structure of RichTextData | ||
// Assumption is that all the list items should be part of a single unordered list | ||
return { | ||
time: Date.now(), | ||
blocks: [ | ||
{ | ||
type: 'list', | ||
data: { | ||
style: 'unordered', | ||
items: listItems, | ||
}, | ||
}, | ||
], | ||
blocks, | ||
}; | ||
}; | ||
|
||
const groupSiblingsBy = <T>(items: readonly T[], by: (item: T) => unknown) => | ||
items.reduce((acc: T[][], cur: T) => { | ||
// If it's the first item or different from the last, start a new group | ||
if (!acc.length || by(acc.at(-1)![0]!) !== by(cur)) { | ||
acc.push([cur]); | ||
} else { | ||
// Otherwise, add it to the current group | ||
acc.at(-1)!.push(cur); | ||
} | ||
return acc; | ||
}, []); | ||
|
||
const createParagraphBlock = (text: string[]) => ({ | ||
type: 'paragraph', | ||
data: { | ||
text: text.join(' '), | ||
}, | ||
}); | ||
|
||
const createListBlock = (items: string[], style: 'unordered' | 'ordered') => ({ | ||
type: 'list', | ||
data: { | ||
style: style, | ||
items: items, | ||
}, | ||
}); | ||
|
||
const hasWordListMarkers = (text: string) => | ||
isUnorderedList(text) || isOrderedList(text); | ||
|
||
const isUnorderedList = (text: string) => /•\t(.*)/.test(text); | ||
|
||
const isOrderedList = (text: string) => /^\d+\.\s(.*)/.test(text); |