mirror of
https://github.com/open-webui/open-webui.git
synced 2025-12-12 04:15:25 +00:00
enh: proper undo/redo note editor support
This commit is contained in:
parent
3b9d86de0b
commit
3bc5485867
4 changed files with 85 additions and 9 deletions
7
package-lock.json
generated
7
package-lock.json
generated
|
|
@ -24,6 +24,7 @@
|
|||
"@tiptap/extension-code-block-lowlight": "^2.11.9",
|
||||
"@tiptap/extension-floating-menu": "^2.25.0",
|
||||
"@tiptap/extension-highlight": "^2.10.0",
|
||||
"@tiptap/extension-history": "^2.25.1",
|
||||
"@tiptap/extension-link": "^2.25.0",
|
||||
"@tiptap/extension-placeholder": "^2.10.0",
|
||||
"@tiptap/extension-table": "^2.12.0",
|
||||
|
|
@ -3330,9 +3331,9 @@
|
|||
}
|
||||
},
|
||||
"node_modules/@tiptap/extension-history": {
|
||||
"version": "2.10.0",
|
||||
"resolved": "https://registry.npmjs.org/@tiptap/extension-history/-/extension-history-2.10.0.tgz",
|
||||
"integrity": "sha512-5aYOmxqaCnw7e7wmWqFZmkpYCxxDjEzFbgVI6WknqNwqeOizR4+YJf3aAt/lTbksLJe47XF+NBX51gOm/ZBCiw==",
|
||||
"version": "2.25.1",
|
||||
"resolved": "https://registry.npmjs.org/@tiptap/extension-history/-/extension-history-2.25.1.tgz",
|
||||
"integrity": "sha512-ZoxxOAObk1U8H3d+XEG0MjccJN0ViGIKEZqnLUSswmVweYPdkJG2WF2pEif9hpwJONslvLTKa+f8jwK5LEnJLQ==",
|
||||
"license": "MIT",
|
||||
"funding": {
|
||||
"type": "github",
|
||||
|
|
|
|||
|
|
@ -68,6 +68,7 @@
|
|||
"@tiptap/extension-code-block-lowlight": "^2.11.9",
|
||||
"@tiptap/extension-floating-menu": "^2.25.0",
|
||||
"@tiptap/extension-highlight": "^2.10.0",
|
||||
"@tiptap/extension-history": "^2.25.1",
|
||||
"@tiptap/extension-link": "^2.25.0",
|
||||
"@tiptap/extension-placeholder": "^2.10.0",
|
||||
"@tiptap/extension-table": "^2.12.0",
|
||||
|
|
|
|||
|
|
@ -50,16 +50,20 @@
|
|||
|
||||
import { onMount, onDestroy, tick, getContext } from 'svelte';
|
||||
import { createEventDispatcher } from 'svelte';
|
||||
import { socket } from '$lib/stores';
|
||||
|
||||
const i18n = getContext('i18n');
|
||||
const eventDispatch = createEventDispatcher();
|
||||
|
||||
import { Fragment, DOMParser } from 'prosemirror-model';
|
||||
import { EditorState, Plugin, PluginKey, TextSelection, Selection } from 'prosemirror-state';
|
||||
import { receiveTransaction, sendableSteps, getVersion } from 'prosemirror-collab';
|
||||
import { Step } from 'prosemirror-transform';
|
||||
import { Decoration, DecorationSet } from 'prosemirror-view';
|
||||
import { Editor } from '@tiptap/core';
|
||||
|
||||
import { AIAutocompletion } from './RichTextInput/AutoCompletion.js';
|
||||
import History from '@tiptap/extension-history';
|
||||
import Table from '@tiptap/extension-table';
|
||||
import TableRow from '@tiptap/extension-table-row';
|
||||
import TableHeader from '@tiptap/extension-table-header';
|
||||
|
|
@ -118,6 +122,75 @@
|
|||
export let largeTextAsFile = false;
|
||||
export let insertPromptAsRichText = false;
|
||||
|
||||
let isConnected = false;
|
||||
let collaborators = new Map();
|
||||
let version = 0;
|
||||
|
||||
// Custom collaboration plugin
|
||||
const collaborationPlugin = () => {
|
||||
return new Plugin({
|
||||
key: new PluginKey('collaboration'),
|
||||
state: {
|
||||
init: () => ({ version: 0 }),
|
||||
apply: (tr, pluginState) => {
|
||||
const newState = { ...pluginState };
|
||||
|
||||
if (tr.getMeta('collaboration')) {
|
||||
newState.version = tr.getMeta('collaboration').version;
|
||||
}
|
||||
|
||||
return newState;
|
||||
}
|
||||
},
|
||||
view: () => ({
|
||||
update: (view, prevState) => {
|
||||
const sendable = sendableSteps(view.state);
|
||||
if (sendable) {
|
||||
$socket.emit('document_steps', {
|
||||
document_id: documentId,
|
||||
user_id: userId,
|
||||
version: sendable.version,
|
||||
steps: sendable.steps.map((step) => step.toJSON()),
|
||||
clientID: sendable.clientID
|
||||
});
|
||||
}
|
||||
}
|
||||
})
|
||||
});
|
||||
};
|
||||
|
||||
function handleDocumentSteps(data) {
|
||||
if (data.user_id !== userId && editor) {
|
||||
const steps = data.steps.map((stepJSON) => Step.fromJSON(editor.schema, stepJSON));
|
||||
const tr = receiveTransaction(editor.state, steps, data.clientID);
|
||||
|
||||
if (tr) {
|
||||
editor.view.dispatch(tr);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function handleDocumentState(data) {
|
||||
version = data.version;
|
||||
if (data.content && editor) {
|
||||
editor.commands.setContent(data.content);
|
||||
}
|
||||
isConnected = true;
|
||||
}
|
||||
|
||||
function handleUserJoined(data) {
|
||||
collaborators.set(data.user_id, {
|
||||
name: data.user_name,
|
||||
color: data.user_color
|
||||
});
|
||||
collaborators = collaborators;
|
||||
}
|
||||
|
||||
function handleUserLeft(data) {
|
||||
collaborators.delete(data.user_id);
|
||||
collaborators = collaborators;
|
||||
}
|
||||
|
||||
let floatingMenuElement = null;
|
||||
let bubbleMenuElement = null;
|
||||
let element;
|
||||
|
|
|
|||
|
|
@ -772,16 +772,16 @@ Provide the enhanced notes in markdown format. Use markdown syntax for headings,
|
|||
/>
|
||||
|
||||
<div class="flex items-center gap-0.5 translate-x-1">
|
||||
{#if note.data?.versions?.length > 0}
|
||||
{#if editor}
|
||||
<div>
|
||||
<div class="flex items-center gap-0.5 self-center min-w-fit" dir="ltr">
|
||||
<button
|
||||
class="self-center p-1 hover:enabled:bg-black/5 dark:hover:enabled:bg-white/5 dark:hover:enabled:text-white hover:enabled:text-black rounded-md transition disabled:cursor-not-allowed disabled:text-gray-500 disabled:hover:text-gray-500"
|
||||
on:click={() => {
|
||||
versionNavigateHandler('prev');
|
||||
editor.chain().focus().undo().run();
|
||||
// versionNavigateHandler('prev');
|
||||
}}
|
||||
disabled={(versionIdx === null && note.data.versions.length === 0) ||
|
||||
versionIdx === 0}
|
||||
disabled={!editor.can().undo()}
|
||||
>
|
||||
<ArrowUturnLeft className="size-4" />
|
||||
</button>
|
||||
|
|
@ -789,9 +789,10 @@ Provide the enhanced notes in markdown format. Use markdown syntax for headings,
|
|||
<button
|
||||
class="self-center p-1 hover:enabled:bg-black/5 dark:hover:enabled:bg-white/5 dark:hover:enabled:text-white hover:enabled:text-black rounded-md transition disabled:cursor-not-allowed disabled:text-gray-500 disabled:hover:text-gray-500"
|
||||
on:click={() => {
|
||||
versionNavigateHandler('next');
|
||||
editor.chain().focus().redo().run();
|
||||
// versionNavigateHandler('next');
|
||||
}}
|
||||
disabled={versionIdx >= note.data.versions.length || versionIdx === null}
|
||||
disabled={!editor.can().redo()}
|
||||
>
|
||||
<ArrowUturnRight className="size-4" />
|
||||
</button>
|
||||
|
|
|
|||
Loading…
Reference in a new issue