awareness on quill editor
This commit is contained in:
parent
27e3ed525b
commit
e9e38db606
5 changed files with 79 additions and 10 deletions
|
@ -35,6 +35,14 @@ export default defineComponent({
|
|||
localStorage.removeItem("refresh_token");
|
||||
});
|
||||
}
|
||||
window.addEventListener("online", function (e) {
|
||||
e.preventDefault();
|
||||
});
|
||||
},
|
||||
beforeUnmount() {
|
||||
window.removeEventListener("online", function (e) {
|
||||
e.preventDefault();
|
||||
});
|
||||
},
|
||||
});
|
||||
</script>
|
||||
|
|
|
@ -2,7 +2,14 @@
|
|||
<div class="flex flex-col">
|
||||
<div class="flex flex-row gap-2 items-center">
|
||||
<label :for="title">{{ title }}</label>
|
||||
<lottie-player src="/typing_animation.json" class="w-fit h-5" loop autoplay />
|
||||
<lottie-player
|
||||
v-if="currentEditors.length != 0"
|
||||
src="/typing_animation.json"
|
||||
class="w-fit h-5"
|
||||
loop
|
||||
autoplay
|
||||
v-tippy="currentEditors.map((c) => c.username).join(', ')"
|
||||
/>
|
||||
</div>
|
||||
<QuillEditor
|
||||
:id="title"
|
||||
|
@ -11,6 +18,8 @@
|
|||
contentType="html"
|
||||
:options="{ modules: moduleOptions }"
|
||||
@ready="initEditor"
|
||||
@selectionChange="selectionChange"
|
||||
@blur="blured"
|
||||
/>
|
||||
<!--
|
||||
:enable="can('create', 'operation', 'mission')"
|
||||
|
@ -28,7 +37,7 @@ import { QuillBinding } from "y-quill";
|
|||
import { moduleOptions } from "@/helpers/quillConfig";
|
||||
import * as Y from "yjs";
|
||||
import "@lottiefiles/lottie-player";
|
||||
import { Awareness } from "@/helpers/awareness";
|
||||
import { Awareness, type AwarenessActions, type EditorRange, type EditorState } from "@/helpers/awareness";
|
||||
</script>
|
||||
|
||||
<script lang="ts">
|
||||
|
@ -39,7 +48,7 @@ export default defineComponent({
|
|||
required: true,
|
||||
},
|
||||
awareness: {
|
||||
type: Object as PropType<Partial<Awareness>>,
|
||||
type: Object as PropType<Awareness>,
|
||||
required: true,
|
||||
},
|
||||
title: {
|
||||
|
@ -53,18 +62,64 @@ export default defineComponent({
|
|||
cursors: undefined as undefined | QuillCursors,
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
currentEditors() {
|
||||
return this.awareness.getEditorObjsByField(this.title);
|
||||
},
|
||||
},
|
||||
mounted() {
|
||||
this.awareness.emitter.on("change", this.handleChange);
|
||||
this.awareness.emitter.on("clear", this.clear);
|
||||
},
|
||||
beforeUnmount() {
|
||||
if (this.binding) {
|
||||
this.binding.destroy();
|
||||
this.binding = undefined;
|
||||
}
|
||||
this.awareness.emitter.off("change", this.handleChange);
|
||||
this.awareness.emitter.off("clear", this.clear);
|
||||
},
|
||||
methods: {
|
||||
initEditor(quill: Quill) {
|
||||
quill.history.clear();
|
||||
this.binding = new QuillBinding(this.text, quill); // TODO: awareness
|
||||
this.binding = new QuillBinding(this.text, quill);
|
||||
this.cursors = quill.getModule("cursors") as QuillCursors;
|
||||
},
|
||||
selectionChange({ range, oldRange, source }: { range: EditorRange; oldRange: any; source: string }) {
|
||||
if (range != null) {
|
||||
this.awareness.publishMyState({
|
||||
field: this.title,
|
||||
range: range,
|
||||
});
|
||||
}
|
||||
},
|
||||
blured() {
|
||||
this.awareness.publishMyState({
|
||||
field: "blured user",
|
||||
});
|
||||
},
|
||||
handleChange(
|
||||
d: {
|
||||
socketId: string;
|
||||
action: AwarenessActions;
|
||||
} & EditorState
|
||||
) {
|
||||
if (d.action == "remove") {
|
||||
this.cursors?.removeCursor(d.socketId);
|
||||
}
|
||||
if (d.field == this.title) {
|
||||
let user = this.awareness.getEditor(d.socketId);
|
||||
if (!user || !d.range) return;
|
||||
this.cursors?.createCursor(d.socketId, user.username, user.color);
|
||||
this.cursors?.moveCursor(d.socketId, d.range);
|
||||
this.cursors?.toggleFlag(d.socketId, true);
|
||||
} else if (d.field == "blured user") {
|
||||
this.cursors?.removeCursor(d.socketId);
|
||||
}
|
||||
},
|
||||
clear() {
|
||||
this.cursors?.clearCursors();
|
||||
},
|
||||
},
|
||||
});
|
||||
</script>
|
||||
|
|
|
@ -75,15 +75,11 @@ export default defineComponent({
|
|||
focused() {
|
||||
this.awareness.publishMyState({
|
||||
field: this.title,
|
||||
cursor: undefined,
|
||||
range: undefined,
|
||||
});
|
||||
},
|
||||
blured() {
|
||||
this.awareness.publishMyState({
|
||||
field: "blured user",
|
||||
cursor: undefined,
|
||||
range: undefined,
|
||||
});
|
||||
},
|
||||
},
|
||||
|
|
|
@ -9,8 +9,12 @@ export interface Editor {
|
|||
|
||||
export interface EditorState {
|
||||
field: string;
|
||||
cursor: any;
|
||||
range: any;
|
||||
cursor?: number;
|
||||
range?: EditorRange;
|
||||
}
|
||||
export interface EditorRange {
|
||||
index: number;
|
||||
length: number;
|
||||
}
|
||||
|
||||
export type AwarenessActions = "update" | "remove";
|
||||
|
@ -18,6 +22,7 @@ export type AwarenessActions = "update" | "remove";
|
|||
export type AwarenessEvents = {
|
||||
update: { data: EditorState };
|
||||
change: { socketId: string; action: AwarenessActions } & EditorState;
|
||||
clear: void;
|
||||
};
|
||||
|
||||
export class Awareness {
|
||||
|
@ -73,6 +78,7 @@ export class Awareness {
|
|||
public reset() {
|
||||
this.editors.clear();
|
||||
this.editorStates.clear();
|
||||
this.emitter.emit("clear");
|
||||
}
|
||||
|
||||
public destroy() {
|
||||
|
|
|
@ -149,3 +149,7 @@ summary::-webkit-details-marker {
|
|||
@apply !order-1;
|
||||
}
|
||||
}
|
||||
|
||||
.ql-cursor-caret-container {
|
||||
z-index: 1 !important;
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue