Skip to content

Commit

Permalink
Merge branch 'main' into feat/next
Browse files Browse the repository at this point in the history
  • Loading branch information
scmmishra authored Sep 17, 2024
2 parents f4b26e7 + f92276a commit 0141024
Show file tree
Hide file tree
Showing 3 changed files with 80 additions and 5 deletions.
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@chatwoot/prosemirror-schema",
"version": "1.1.0-next",
"version": "1.1.1-next",
"description": "Schema setup for using prosemirror in chatwoot. Based on 👉 https://github.com/ProseMirror/prosemirror-example-setup/",
"main": "dist/index.es.js",
"scripts": {
Expand Down
25 changes: 21 additions & 4 deletions src/mentions/plugin.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,29 +6,46 @@
import { Plugin, PluginKey } from 'prosemirror-state';
import { Decoration, DecorationSet } from 'prosemirror-view';

export const triggerCharacters = char => $position => {
const regexp = new RegExp(`(?:^)?${char}[^\\s${char}]*`, 'g');
/**
* Creates a function to detect if the trigger character followed by a specified number of characters
* has been typed, starting from a new word, after a space, or after a newline.
* @param {string} char - The trigger character to detect.
* @param {number} [minChars=0] - The minimum number of characters that should follow the trigger character.
* @returns {Function} A function that takes a position object and returns the match if the condition is met.
*/
export const triggerCharacters = (char, minChars = 0) => $position => {
// Regular expression to find occurrences of 'char' followed by at least 'minChars' non-space characters.
// It matches these sequences starting from the beginning of the text or after a space.
const regexp = new RegExp(`(?:^)?${char}[^\\s${char}]{${minChars},}`, 'g');

// Get the position before the current cursor position in the document.
const textFrom = $position.before();
// Get the position at the end of the current node.
const textTo = $position.end();

// Get the text between the start of the node and the cursor position.
const text = $position.doc.textBetween(textFrom, textTo, '\0', '\0');

let match;

// eslint-disable-next-line
while ((match = regexp.exec(text))) {
// Check if the character before the match is a space, start of string, or null character
const prefix = match.input.slice(Math.max(0, match.index - 1), match.index);
if (!/^[\s\0]?$/.test(prefix)) {
// If the prefix is not empty, space, or null, skip this match
// eslint-disable-next-line
continue;
}

const from = match.index + $position.start();
let to = from + match[0].length;
const to = from + match[0].length;

if (from < $position.pos && to >= $position.pos) {
return { range: { from, to }, text: match[0] };
const fullMatch = match[0];
// Remove trigger char and trim
const trimmedText = fullMatch ? fullMatch.slice(char.length) : '';
return { range: { from, to }, text: trimmedText };
}
}
return null;
Expand Down
58 changes: 58 additions & 0 deletions src/plugins/image.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
import { Plugin } from "prosemirror-state";

/**
* Replaces an image node in the editor with a new image URL.
*
* @param {string} currentUrl - The current URL of the image to be replaced.
* @param {string} newUrl - The new URL to replace the current image with.
* @param {EditorView} view - The ProseMirror editor view.
*/
function replaceImage(currentUrl, newUrl, view) {
view.state.doc.descendants((node, pos) => {
if (node.type.name === "image" && node.attrs.src === currentUrl) {
const tr = view.state.tr.setNodeMarkup(pos, null, {
...node.attrs,
src: newUrl,
});
view.dispatch(tr);
}
});
}

/**
* Creates a ProseMirror plugin that handles image pasting and uploading.
*
* @param {Function} uploadImage - A function that takes an image URL and returns a Promise
* that resolves to the new URL after uploading.
* @returns {Plugin} A ProseMirror plugin that handles image pasting.
*/
const imagePastePlugin = (uploadImage) =>
new Plugin({
props: {
/**
* Handles the paste event in the editor.
*
* @param {EditorView} view - The ProseMirror editor view.
* @param {Event} event - The paste event.
* @param {Slice} slice - The ProseMirror Slice object representing the pasted content.
*/
handlePaste(view, event, slice) {
const imageUrls = [];
slice.content.descendants((node) => {
if (node.type.name === "image") {
imageUrls.push(node.attrs.src);
}
});
Promise.all(imageUrls.map(async (url) => {
try {
const newUrl = await uploadImage(url);
replaceImage(url, newUrl, view);
} catch (error) {
console.error("Error uploading image:", error);
}
}));
},
},
});

export default imagePastePlugin;

0 comments on commit 0141024

Please sign in to comment.