-
-
Notifications
You must be signed in to change notification settings - Fork 2.4k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
fix(core): fix nodepos child lookup (#5038)
- Loading branch information
Showing
5 changed files
with
371 additions
and
2 deletions.
There are no files selected for viewing
Empty file.
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,251 @@ | ||
import './styles.scss' | ||
|
||
import Image from '@tiptap/extension-image' | ||
import { EditorContent, useEditor } from '@tiptap/react' | ||
import StarterKit from '@tiptap/starter-kit' | ||
import React, { useCallback, useState } from 'react' | ||
|
||
const mapNodePosToString = nodePos => `[${nodePos.node.type.name} ${nodePos.range.from}-${nodePos.range.to}] ${nodePos.textContent} | ${JSON.stringify(nodePos.node.attrs)}` | ||
|
||
export default () => { | ||
const editor = useEditor({ | ||
extensions: [ | ||
StarterKit, | ||
Image, | ||
], | ||
content: ` | ||
<h1>This is an example document to play around with the NodePos implementation of Tiptap.</h1> | ||
<p> | ||
This is a <strong>simple</strong> paragraph. | ||
</p> | ||
<img src="https://unsplash.it/200/200" alt="A 200x200 thumbnail from unsplash." /> | ||
<p> | ||
Here is another paragraph inside this document. | ||
</p> | ||
<blockquote> | ||
<p>Here we have a paragraph inside a blockquote.</p> | ||
</blockquote> | ||
<ul> | ||
<li> | ||
<p>Unsorted 1</p> | ||
</li> | ||
<li> | ||
<p>Unsorted 2</p> | ||
<ul> | ||
<li> | ||
<p>Unsorted 2.1</p> | ||
</li> | ||
<li> | ||
<p>Unsorted 2.2</p> | ||
</li> | ||
<li> | ||
<p>Unsorted 2.3</p> | ||
</li> | ||
</ul> | ||
</li> | ||
<li> | ||
<p>Unsorted 3</p> | ||
</li> | ||
</ul> | ||
<ol> | ||
<li> | ||
<p>Sorted 1</p> | ||
</li> | ||
<li> | ||
<p>Sorted 2</p> | ||
<ul> | ||
<li> | ||
<p>Sorted 2.1</p> | ||
</li> | ||
<li> | ||
<p>Sorted 2.2</p> | ||
</li> | ||
<li> | ||
<p>Sorted 2.3</p> | ||
</li> | ||
</ul> | ||
</li> | ||
<li> | ||
<p>Sorted 3</p> | ||
</li> | ||
</ol> | ||
<img src="https://unsplash.it/260/200" alt="A 260x200 thumbnail from unsplash." /> | ||
<blockquote> | ||
<p>Here we have another paragraph inside a blockquote.</p> | ||
</blockquote> | ||
`, | ||
}) | ||
|
||
const [foundNodes, setFoundNodes] = useState(null) | ||
|
||
const findParagraphs = useCallback(() => { | ||
const nodePositions = editor.$doc.querySelectorAll('paragraph') | ||
|
||
if (!nodePositions) { | ||
setFoundNodes(null) | ||
return | ||
} | ||
|
||
setFoundNodes(nodePositions) | ||
}, [editor]) | ||
|
||
const findListItems = useCallback(() => { | ||
const nodePositions = editor.$doc.querySelectorAll('listItem') | ||
|
||
if (!nodePositions) { | ||
setFoundNodes(null) | ||
return | ||
} | ||
|
||
setFoundNodes(nodePositions) | ||
}, [editor]) | ||
|
||
const findBulletList = useCallback(() => { | ||
const nodePositions = editor.$doc.querySelectorAll('bulletList') | ||
|
||
if (!nodePositions) { | ||
setFoundNodes(null) | ||
return | ||
} | ||
|
||
setFoundNodes(nodePositions) | ||
}, [editor]) | ||
|
||
const findOrderedList = useCallback(() => { | ||
const nodePositions = editor.$doc.querySelectorAll('orderedList') | ||
|
||
if (!nodePositions) { | ||
setFoundNodes(null) | ||
return | ||
} | ||
|
||
setFoundNodes(nodePositions) | ||
}, [editor]) | ||
|
||
const findBlockquote = useCallback(() => { | ||
const nodePositions = editor.$doc.querySelectorAll('blockquote') | ||
|
||
if (!nodePositions) { | ||
setFoundNodes(null) | ||
return | ||
} | ||
|
||
setFoundNodes(nodePositions) | ||
}, [editor]) | ||
|
||
const findImages = useCallback(() => { | ||
const nodePositions = editor.$doc.querySelectorAll('image') | ||
|
||
if (!nodePositions) { | ||
setFoundNodes(null) | ||
return | ||
} | ||
|
||
setFoundNodes(nodePositions) | ||
}, [editor]) | ||
|
||
const findFirstBlockquote = useCallback(() => { | ||
const nodePosition = editor.$doc.querySelector('blockquote') | ||
|
||
if (!nodePosition) { | ||
setFoundNodes(null) | ||
return | ||
} | ||
|
||
setFoundNodes([nodePosition]) | ||
}, [editor]) | ||
|
||
const findSquaredImage = useCallback(() => { | ||
const nodePosition = editor.$doc.querySelector('image', { src: 'https://unsplash.it/200/200' }) | ||
|
||
if (!nodePosition) { | ||
setFoundNodes(null) | ||
return | ||
} | ||
|
||
setFoundNodes([nodePosition]) | ||
}, [editor]) | ||
|
||
const findLandscapeImage = useCallback(() => { | ||
const nodePosition = editor.$doc.querySelector('image', { src: 'https://unsplash.it/260/200' }) | ||
|
||
if (!nodePosition) { | ||
setFoundNodes(null) | ||
return | ||
} | ||
|
||
setFoundNodes([nodePosition]) | ||
}, [editor]) | ||
|
||
const findFirstNode = useCallback(() => { | ||
const nodePosition = editor.$doc.firstChild | ||
|
||
if (!nodePosition) { | ||
setFoundNodes(null) | ||
return | ||
} | ||
|
||
setFoundNodes([nodePosition]) | ||
}, [editor]) | ||
|
||
const findLastNode = useCallback(() => { | ||
const nodePosition = editor.$doc.lastChild | ||
|
||
if (!nodePosition) { | ||
setFoundNodes(null) | ||
return | ||
} | ||
|
||
setFoundNodes([nodePosition]) | ||
}, [editor]) | ||
|
||
const findLastNodeOfFirstBulletList = useCallback(() => { | ||
const nodePosition = editor.$doc.querySelector('bulletList').lastChild | ||
|
||
if (!nodePosition) { | ||
setFoundNodes(null) | ||
return | ||
} | ||
|
||
setFoundNodes([nodePosition]) | ||
}, [editor]) | ||
|
||
const findNonexistentNode = useCallback(() => { | ||
const nodePosition = editor.$doc.querySelector('nonexistent') | ||
|
||
if (!nodePosition) { | ||
setFoundNodes(null) | ||
return | ||
} | ||
|
||
setFoundNodes([nodePosition]) | ||
}, [editor]) | ||
|
||
return ( | ||
<div> | ||
<div> | ||
<button data-testid="find-paragraphs" onClick={findParagraphs}>Find paragraphs</button> | ||
<button data-testid="find-listitems" onClick={findListItems}>Find list items</button> | ||
<button data-testid="find-bulletlists" onClick={findBulletList}>Find bullet lists</button> | ||
<button data-testid="find-orderedlists" onClick={findOrderedList}>Find ordered lists</button> | ||
<button data-testid="find-blockquotes" onClick={findBlockquote}>Find blockquotes</button> | ||
<button data-testid="find-images" onClick={findImages}>Find images</button> | ||
</div> | ||
<div> | ||
<button data-testid="find-first-blockquote" onClick={findFirstBlockquote}>Find first blockquote</button> | ||
<button data-testid="find-squared-image" onClick={findSquaredImage}>Find squared image</button> | ||
<button data-testid="find-landscape-image" onClick={findLandscapeImage}>Find landscape image</button> | ||
</div> | ||
<div> | ||
<button data-testid="find-first-node" onClick={findFirstNode}>Find first node</button> | ||
<button data-testid="find-last-node" onClick={findLastNode}>Find last node</button> | ||
<button data-testid="find-last-node-of-first-bullet-list" onClick={findLastNodeOfFirstBulletList}>Find last node of first bullet list</button> | ||
<button data-testid="find-nonexistent-node" onClick={findNonexistentNode}>Find nonexistent node</button> | ||
</div> | ||
<EditorContent editor={editor} /> | ||
{foundNodes ? <div data-testid="found-nodes">{foundNodes.map(n => ( | ||
<div data-testid="found-node" key={n.pos}>{mapNodePosToString(n)}</div> | ||
))}</div> : ''} | ||
</div> | ||
) | ||
} |
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,103 @@ | ||
context('/src/Examples/NodePos/React/', () => { | ||
beforeEach(() => { | ||
cy.visit('/src/Examples/NodePos/React/') | ||
}) | ||
|
||
it('should get paragraphs', () => { | ||
cy.get('.tiptap').then(() => { | ||
cy.get('button[data-testid="find-paragraphs"]').click() | ||
cy.get('div[data-testid="found-nodes"]').should('exist') | ||
cy.get('div[data-testid="found-node"]').should('have.length', 16) | ||
}) | ||
}) | ||
|
||
it('should get list items', () => { | ||
cy.get('.tiptap').then(() => { | ||
cy.get('button[data-testid="find-listitems"]').click() | ||
cy.get('div[data-testid="found-nodes"]').should('exist') | ||
cy.get('div[data-testid="found-node"]').should('have.length', 12) | ||
}) | ||
}) | ||
|
||
it('should get bullet lists', () => { | ||
cy.get('.tiptap').then(() => { | ||
cy.get('button[data-testid="find-bulletlists"]').click() | ||
cy.get('div[data-testid="found-nodes"]').should('exist') | ||
cy.get('div[data-testid="found-node"]').should('have.length', 3) | ||
}) | ||
}) | ||
|
||
it('should get ordered lists', () => { | ||
cy.get('.tiptap').then(() => { | ||
cy.get('button[data-testid="find-orderedlists"]').click() | ||
cy.get('div[data-testid="found-nodes"]').should('exist') | ||
cy.get('div[data-testid="found-node"]').should('have.length', 1) | ||
}) | ||
}) | ||
|
||
it('should get blockquotes', () => { | ||
cy.get('.tiptap').then(() => { | ||
cy.get('button[data-testid="find-blockquotes"]').click() | ||
cy.get('div[data-testid="found-nodes"]').should('exist') | ||
cy.get('div[data-testid="found-node"]').should('have.length', 2) | ||
}) | ||
}) | ||
|
||
it('should get images', () => { | ||
cy.get('.tiptap').then(() => { | ||
cy.get('button[data-testid="find-images"]').click() | ||
cy.get('div[data-testid="found-nodes"]').should('exist') | ||
cy.get('div[data-testid="found-node"]').should('have.length', 2) | ||
}) | ||
}) | ||
|
||
it('should get first blockquote', () => { | ||
cy.get('.tiptap').then(() => { | ||
cy.get('button[data-testid="find-first-blockquote"]').click() | ||
cy.get('div[data-testid="found-nodes"]').should('exist') | ||
cy.get('div[data-testid="found-node"]').should('have.length', 1) | ||
cy.get('div[data-testid="found-node"]').should('contain', 'Here we have a paragraph inside a blockquote.').should('not.contain', 'Here we have another paragraph inside a blockquote.') | ||
}) | ||
}) | ||
|
||
it('should get images by attributes', () => { | ||
cy.get('.tiptap').then(() => { | ||
cy.get('button[data-testid="find-squared-image"]').click() | ||
cy.get('div[data-testid="found-nodes"]').should('exist') | ||
cy.get('div[data-testid="found-node"]').should('have.length', 1) | ||
cy.get('div[data-testid="found-node"]').should('contain', 'https://unsplash.it/200/200') | ||
|
||
cy.get('button[data-testid="find-landscape-image"]').click() | ||
cy.get('div[data-testid="found-nodes"]').should('exist') | ||
cy.get('div[data-testid="found-node"]').should('have.length', 1) | ||
cy.get('div[data-testid="found-node"]').should('contain', 'https://unsplash.it/260/200') | ||
}) | ||
}) | ||
|
||
it('should find complex nodes', () => { | ||
cy.get('.tiptap').then(() => { | ||
cy.get('button[data-testid="find-first-node"]').click() | ||
cy.get('div[data-testid="found-nodes"]').should('exist') | ||
cy.get('div[data-testid="found-node"]').should('have.length', 1) | ||
cy.get('div[data-testid="found-node"]').should('contain', 'heading').should('contain', '{"level":1}') | ||
|
||
cy.get('button[data-testid="find-last-node"]').click() | ||
cy.get('div[data-testid="found-nodes"]').should('exist') | ||
cy.get('div[data-testid="found-node"]').should('have.length', 1) | ||
cy.get('div[data-testid="found-node"]').should('contain', 'blockquote') | ||
|
||
cy.get('button[data-testid="find-last-node-of-first-bullet-list"]').click() | ||
cy.get('div[data-testid="found-nodes"]').should('exist') | ||
cy.get('div[data-testid="found-node"]').should('have.length', 1) | ||
cy.get('div[data-testid="found-node"]').should('contain', 'listItem').should('contain', 'Unsorted 3') | ||
}) | ||
}) | ||
|
||
it('should not find nodes that do not exist in document', () => { | ||
cy.get('.tiptap').then(() => { | ||
cy.get('button[data-testid="find-nonexistent-node"]').click() | ||
cy.get('div[data-testid="found-nodes"]').should('not.exist') | ||
cy.get('div[data-testid="found-node"]').should('have.length', 0) | ||
}) | ||
}) | ||
}) |
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,15 @@ | ||
/* Basic editor styles */ | ||
.tiptap { | ||
> * + * { | ||
margin-top: 0.75em; | ||
} | ||
|
||
h1, | ||
h2, | ||
h3, | ||
h4, | ||
h5, | ||
h6 { | ||
line-height: 1.1; | ||
} | ||
} |
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