-
-
Notifications
You must be signed in to change notification settings - Fork 126
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
fix: depth issues in BulletedList, TodoList and NumberedList (#418)
* fix: depth issues in BulletedList with md serialize/deserialize; closes #345 * chore: remove console.log * fix: list item children as list-item Descendant type * update email examples (#391) ## Description Added the ability to add Loom & Wistia videos in the Video plugin. Note that I'm not used to Typescrpt at all, so I might need some help with this if you see issues. Fixes # (issue) ## Type of change Please tick the relevant option. - [ ] Bug fix (non-breaking change which fixes an issue) - [x ] New feature (non-breaking change which adds functionality) - [ ] Breaking change (fix or feature that would cause existing functionality to not work as expected) - [ ] This change requires a documentation update ## Checklist: - [ ] I have performed a self-review of my own code - [ ] I have commented on my code, particularly in hard-to-understand areas - [ ] I have made corresponding changes to the documentation - [ ] My changes generate no new warnings - [ ] I have checked my code and corrected any misspellings * Improvements for loom and wistia videos (#402) * update email examples ## Description Added the ability to add Loom & Wistia videos in the Video plugin. Note that I'm not used to Typescrpt at all, so I might need some help with this if you see issues. Fixes # (issue) ## Type of change Please tick the relevant option. - [ ] Bug fix (non-breaking change which fixes an issue) - [x ] New feature (non-breaking change which adds functionality) - [ ] Breaking change (fix or feature that would cause existing functionality to not work as expected) - [ ] This change requires a documentation update ## Checklist: - [ ] I have performed a self-review of my own code - [ ] I have commented on my code, particularly in hard-to-understand areas - [ ] I have made corresponding changes to the documentation - [ ] My changes generate no new warnings - [ ] I have checked my code and corrected any misspellings * fixes for loom and wistia providers --------- Co-authored-by: 5andu <[email protected]> * Update deserialize.ts (#415) * fix types * add smooth selection between block * fix: changes after review plus clean empty nodes * fix: nested TodoList items --------- Co-authored-by: Alexandru Golovatenco <[email protected]> Co-authored-by: Akhmed Ibragimov <[email protected]> Co-authored-by: 5andu <[email protected]> Co-authored-by: Vaishnav Deore <[email protected]>
- Loading branch information
1 parent
96fc42e
commit 16e4625
Showing
5 changed files
with
155 additions
and
84 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
138 changes: 138 additions & 0 deletions
138
packages/core/editor/src/parsers/deserializeListNodes.ts
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 |
---|---|---|
@@ -0,0 +1,138 @@ | ||
import {generateId} from '../utils/generateId'; | ||
import {YooEditor, YooptaBlockData} from '../editor/types'; | ||
import {deserializeTextNodes} from './deserializeTextNodes'; | ||
import {Descendant} from 'slate'; | ||
|
||
type ListHTMLElement = HTMLUListElement | HTMLOListElement | Element; | ||
|
||
type DeserializeListBlockOptions = { | ||
depth?: number; | ||
type: 'TodoList' | 'NumberedList' | 'BulletedList'; | ||
align: YooptaBlockData['meta']['align']; | ||
}; | ||
|
||
// recursive function to parse nested lists and return list of Blocks | ||
export function deserializeListNodes( | ||
editor: YooEditor, | ||
listEl: ListHTMLElement, | ||
options: DeserializeListBlockOptions, | ||
): YooptaBlockData[] { | ||
const deserializedListBlocks: YooptaBlockData[] = []; | ||
const depth = typeof options.depth === 'number' ? options.depth : 0; | ||
|
||
if (listEl.nodeName === 'UL' || listEl.nodeName === 'OL') { | ||
const listItems = Array.from(listEl.children).filter((el) => el.nodeName === 'LI'); | ||
|
||
// check if the list is a TodoList or not | ||
const isTodoList = listItems.some((listItem) => { | ||
const hasCheckbox = listItem.querySelector('input[type="checkbox"]'); | ||
const textContent = listItem.textContent || ''; | ||
const hasBrackets = /\[\s*[xX\s]?\s*\]/.test(textContent); | ||
return hasCheckbox || hasBrackets; | ||
}); | ||
|
||
if (isTodoList && options.type !== 'TodoList') { | ||
return deserializedListBlocks; | ||
} | ||
|
||
if (!isTodoList && options.type === 'TodoList') { | ||
return deserializedListBlocks; | ||
} | ||
|
||
listItems.forEach((listItem) => { | ||
const textContent = listItem.textContent || ''; | ||
let blockData: YooptaBlockData | null = null; | ||
|
||
if (options.type === 'TodoList') { | ||
// check if the list item has a checkbox input or brackets `[]` in the text content | ||
const checkbox = listItem.querySelector('input[type="checkbox"]') as HTMLInputElement | null; | ||
const checked = checkbox ? checkbox.checked : /\[\s*[xX]\s*\]/.test(textContent); | ||
|
||
const cleanText = textContent | ||
.replace(/\[\s*[xX\s]?\s*\]/, '') | ||
.replace(/\u00a0/g, ' ') | ||
.trim(); | ||
|
||
blockData = { | ||
id: generateId(), | ||
type: 'TodoList', | ||
value: [ | ||
{ | ||
id: generateId(), | ||
type: 'todo-list', | ||
children: deserializeTextNodes(editor, listItem.childNodes), | ||
props: { nodeType: 'block', checked }, | ||
}, | ||
], | ||
meta: { order: 0, depth, align: options.align }, | ||
}; | ||
} else { | ||
const listType = options.type === 'NumberedList' ? 'numbered-list' : 'bulleted-list'; | ||
blockData = { | ||
id: generateId(), | ||
type: options.type, | ||
value: [ | ||
{ | ||
id: generateId(), | ||
type: listType, | ||
children: deserializeTextNodes(editor, listItem.childNodes), | ||
props: { nodeType: 'block' }, | ||
}, | ||
], | ||
meta: { order: 0, depth, align: options.align }, | ||
}; | ||
} | ||
|
||
if (blockData) { | ||
const cleanedData = { | ||
...blockData, | ||
value: sanitizeTextNodes(blockData.value), | ||
} | ||
|
||
deserializedListBlocks.push(cleanedData); | ||
} | ||
|
||
const nestedLists = Array.from(listItem.children).filter((el) => (el.nodeName === 'UL' || el.nodeName === 'OL')); | ||
|
||
// if the list item has nested lists, then parse them recursively by increasing the depth | ||
if (nestedLists.length > 0) { | ||
nestedLists.forEach((nestedList) => { | ||
const nestedBlocks = deserializeListNodes(editor, nestedList as ListHTMLElement, { | ||
...options, | ||
depth: depth + 1, | ||
}); | ||
deserializedListBlocks.push(...nestedBlocks); | ||
}); | ||
} | ||
}); | ||
} | ||
|
||
return deserializedListBlocks; | ||
} | ||
|
||
function sanitizeTextNodes(descendants: Descendant[]): Descendant[] { | ||
return descendants | ||
.map((descendant) => { | ||
if ('children' in descendant) { | ||
// Recursively clean nested children | ||
return { | ||
...descendant, | ||
children: sanitizeTextNodes(descendant.children), | ||
}; | ||
} | ||
|
||
// Only include text nodes that has content | ||
if ('text' in descendant) { | ||
// Clean text content for todo lists or empty text nodes | ||
const cleanText = descendant.text | ||
.replace(/\[\s*[xX\s]?\s*\]/, '') // Remove [] for todo lists | ||
.replace(/\u00a0/g, ' ') // Replace non-breaking spaces | ||
.trim(); | ||
|
||
return cleanText ? { ...descendant, text: cleanText } : null; // Remove if empty | ||
} | ||
|
||
return descendant; | ||
}) | ||
.filter(Boolean) as Descendant[]; | ||
} |
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
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