Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: Adds image support for message signature (#7827)
Co-authored-by: Shivam Mishra <scm.mymail@gmail.com>
- Loading branch information
Showing
8 changed files
with
217 additions
and
5 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
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,40 @@ | ||
/** | ||
* Determines the appropriate node and position to insert an image in the editor. | ||
* | ||
* Based on the current editor state and the provided image URL, this function finds out the correct node (either | ||
* a standalone image node or an image wrapped in a paragraph) and its respective position in the editor. | ||
* | ||
* 1. If the current node is a paragraph and doesn't contain an image or text, the image is inserted directly into it. | ||
* 2. If the current node isn't a paragraph or it's a paragraph containing text, the image will be wrapped | ||
* in a new paragraph and then inserted. | ||
* 3. If the current node is a paragraph containing an image, the new image will be inserted directly into it. | ||
* | ||
* @param {Object} editorState - The current state of the editor. It provides necessary details like selection, schema, etc. | ||
* @param {string} fileUrl - The URL of the image to be inserted into the editor. | ||
* @returns {Object|null} An object containing details about the node to be inserted and its position. It returns null if no image node can be created. | ||
* @property {Node} node - The ProseMirror node to be inserted (either an image node or a paragraph containing the image). | ||
* @property {number} pos - The position where the new node should be inserted in the editor. | ||
*/ | ||
|
||
export const findNodeToInsertImage = (editorState, fileUrl) => { | ||
const { selection, schema } = editorState; | ||
const { nodes } = schema; | ||
const currentNode = selection.$from.node(); | ||
const { | ||
type: { name: typeName }, | ||
content: { size, content }, | ||
} = currentNode; | ||
|
||
const imageNode = nodes.image.create({ src: fileUrl }); | ||
|
||
if (!imageNode) return null; | ||
|
||
const isInParagraph = typeName === 'paragraph'; | ||
const needsNewLine = | ||
!content.some(n => n.type.name === 'image') && size !== 0 ? 1 : 0; | ||
|
||
return { | ||
node: isInParagraph ? imageNode : nodes.paragraph.create({}, imageNode), | ||
pos: selection.from + needsNewLine, | ||
}; | ||
}; |
100 changes: 100 additions & 0 deletions
100
app/javascript/dashboard/helper/specs/messageEditorHelper.spec.js
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,100 @@ | ||
import { findNodeToInsertImage } from '../messageEditorHelper'; | ||
|
||
describe('findNodeToInsertImage', () => { | ||
let mockEditorState; | ||
|
||
beforeEach(() => { | ||
mockEditorState = { | ||
selection: { | ||
$from: { | ||
node: jest.fn(() => ({})), | ||
}, | ||
from: 0, | ||
}, | ||
schema: { | ||
nodes: { | ||
image: { | ||
create: jest.fn(attrs => ({ type: { name: 'image' }, attrs })), | ||
}, | ||
paragraph: { | ||
create: jest.fn((_, node) => ({ | ||
type: { name: 'paragraph' }, | ||
content: [node], | ||
})), | ||
}, | ||
}, | ||
}, | ||
}; | ||
}); | ||
|
||
it('should insert image directly into an empty paragraph', () => { | ||
const mockNode = { | ||
type: { name: 'paragraph' }, | ||
content: { size: 0, content: [] }, | ||
}; | ||
mockEditorState.selection.$from.node.mockReturnValueOnce(mockNode); | ||
|
||
const result = findNodeToInsertImage(mockEditorState, 'image-url'); | ||
expect(result).toEqual({ | ||
node: { type: { name: 'image' }, attrs: { src: 'image-url' } }, | ||
pos: 0, | ||
}); | ||
}); | ||
|
||
it('should insert image directly into a paragraph without an image but with other content', () => { | ||
const mockNode = { | ||
type: { name: 'paragraph' }, | ||
content: { | ||
size: 1, | ||
content: [ | ||
{ | ||
type: { name: 'text' }, | ||
}, | ||
], | ||
}, | ||
}; | ||
mockEditorState.selection.$from.node.mockReturnValueOnce(mockNode); | ||
mockEditorState.selection.from = 1; | ||
|
||
const result = findNodeToInsertImage(mockEditorState, 'image-url'); | ||
expect(result).toEqual({ | ||
node: { type: { name: 'image' }, attrs: { src: 'image-url' } }, | ||
pos: 2, // Because it should insert after the text, on a new line. | ||
}); | ||
}); | ||
|
||
it("should wrap image in a new paragraph when the current node isn't a paragraph", () => { | ||
const mockNode = { | ||
type: { name: 'not-a-paragraph' }, | ||
content: { size: 0, content: [] }, | ||
}; | ||
mockEditorState.selection.$from.node.mockReturnValueOnce(mockNode); | ||
|
||
const result = findNodeToInsertImage(mockEditorState, 'image-url'); | ||
expect(result.node.type.name).toBe('paragraph'); | ||
expect(result.node.content[0].type.name).toBe('image'); | ||
expect(result.node.content[0].attrs.src).toBe('image-url'); | ||
expect(result.pos).toBe(0); | ||
}); | ||
|
||
it('should insert a new image directly into the paragraph that already contains an image', () => { | ||
const mockNode = { | ||
type: { name: 'paragraph' }, | ||
content: { | ||
size: 1, | ||
content: [ | ||
{ | ||
type: { name: 'image', attrs: { src: 'existing-image-url' } }, | ||
}, | ||
], | ||
}, | ||
}; | ||
mockEditorState.selection.$from.node.mockReturnValueOnce(mockNode); | ||
mockEditorState.selection.from = 1; | ||
|
||
const result = findNodeToInsertImage(mockEditorState, 'image-url'); | ||
expect(result.node.type.name).toBe('image'); | ||
expect(result.node.attrs.src).toBe('image-url'); | ||
expect(result.pos).toBe(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
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