81
81
</template >
82
82
83
83
<script >
84
- import Vue , { ref , set , watch } from ' vue'
84
+ import Vue , { ref , set , shallowRef , watch } from ' vue'
85
85
import { getCurrentUser } from ' @nextcloud/auth'
86
86
import { loadState } from ' @nextcloud/initial-state'
87
87
import { emit , subscribe , unsubscribe } from ' @nextcloud/event-bus'
@@ -135,6 +135,7 @@ import { useDelayedFlag } from './Editor/useDelayedFlag.ts'
135
135
import { useEditorMethods } from ' ../composables/useEditorMethods.ts'
136
136
import { useSyntaxHighlighting } from ' ../composables/useSyntaxHighlighting.ts'
137
137
import { provideConnection } from ' ../composables/useConnection.ts'
138
+ import { Awareness } from ' y-protocols/awareness.js'
138
139
139
140
export default {
140
141
name: ' Editor' ,
@@ -163,7 +164,7 @@ export default {
163
164
// actual values without being reactive
164
165
Object .defineProperties (val, {
165
166
[SYNC_SERVICE ]: {
166
- get : () => this .$ syncService ,
167
+ get : () => this .syncService ,
167
168
},
168
169
[FILE ]: {
169
170
get : () => this .fileData ,
@@ -237,6 +238,7 @@ export default {
237
238
el .value .style .setProperty (' --widget-full-width' , ` ${ maxWidth} px` )
238
239
})
239
240
const ydoc = new Doc ()
241
+ const awareness = new Awareness (ydoc)
240
242
// Wrap the connection in an object so we can hand it to the Mention extension as a ref.
241
243
const wrappedConnection = provideConnection ()
242
244
const hasConnectionIssue = ref (false )
@@ -248,19 +250,62 @@ export default {
248
250
isRichEditor,
249
251
props,
250
252
)
253
+ const baseVersionEtag = shallowRef (null )
254
+ const syncService = shallowRef (null )
255
+ const connectSyncService = () => {
256
+ const guestName = localStorage .getItem (' nick' ) ?? ' '
257
+ const api = new SessionApi ({
258
+ guestName,
259
+ shareToken: props .shareToken ,
260
+ filePath: props .relativePath ,
261
+ })
262
+ syncService .value = new SyncService ({
263
+ api,
264
+ baseVersionEtag: baseVersionEtag .value ,
265
+ serialize: isRichEditor .value
266
+ ? (content ) =>
267
+ createMarkdownSerializer (editor .value ? .schema ).serialize (
268
+ content ?? editor .value ? .state .doc ,
269
+ )
270
+ : (content ) =>
271
+ serializePlainText (content ?? editor .value ? .state .doc ),
272
+ getDocumentState: () => getDocumentState (ydoc),
273
+ })
274
+ }
275
+ const syncProvider = shallowRef (null )
276
+
277
+ const extensions = [
278
+ Autofocus .configure ({ fileId: props .fileId }),
279
+ Collaboration .configure ({ document : ydoc }),
280
+ CollaborationCursor .configure ({ provider: { awareness } }),
281
+ ]
282
+ editor .value = isRichEditor
283
+ ? createRichEditor ({
284
+ ... wrappedConnection,
285
+ relativePath: props .relativePath ,
286
+ extensions,
287
+ isEmbedded: props .isEmbedded ,
288
+ })
289
+ : createPlainEditor ({ language, extensions })
290
+
251
291
return {
252
- wrappedConnection,
292
+ awareness,
293
+ baseVersionEtag,
294
+ connectSyncService,
295
+ editor,
253
296
el,
254
- width,
255
297
hasConnectionIssue,
256
- requireReconnect,
257
- editor,
258
- setEditable,
259
298
isPublic,
260
299
isRichEditor,
261
300
isRichWorkspace,
262
301
language,
263
302
lowlightLoaded,
303
+ requireReconnect,
304
+ setEditable,
305
+ syncProvider,
306
+ syncService,
307
+ width,
308
+ wrappedConnection,
264
309
ydoc,
265
310
}
266
311
},
@@ -388,24 +433,9 @@ export default {
388
433
// console.debug('ydoc update', update, origin, doc, tr)
389
434
// Y.logUpdate(update)
390
435
// });
391
- this .$providers = []
392
- this .$syncService = null
393
436
this .$attachmentResolver = null
394
437
if (this .active && this .hasDocumentParameters ) {
395
438
this .initSession ()
396
- const extensions = [
397
- Autofocus .configure ({ fileId: this .fileId }),
398
- Collaboration .configure ({ document : this .ydoc }),
399
- CollaborationCursor .configure ({ provider: this .$providers [0 ] }),
400
- ]
401
- this .editor = this .isRichEditor
402
- ? createRichEditor ({
403
- ... this .wrappedConnection ,
404
- relativePath: this .relativePath ,
405
- extensions,
406
- isEmbedded: this .isEmbedded ,
407
- })
408
- : createPlainEditor ({ language: this .language , extensions })
409
439
this .listenEditorEvents ()
410
440
}
411
441
},
@@ -420,50 +450,23 @@ export default {
420
450
unsubscribe (' text:translate-modal:show' , this .showTranslateModal )
421
451
if (this .dirty ) {
422
452
const timeout = new Promise ((resolve ) => setTimeout (resolve, 2000 ))
423
- await Promise .any ([timeout, this .$ syncService .save ()])
453
+ await Promise .any ([timeout, this .syncService .save ()])
424
454
}
425
455
await this .close ()
426
456
removeFromDebugging (this )
427
457
},
428
458
methods: {
429
459
initSession () {
430
- if (! this .hasDocumentParameters ) {
431
- this .emit (' error' , ' No valid file provided' )
432
- return
433
- }
434
- const guestName = localStorage .getItem (' nick' )
435
- ? localStorage .getItem (' nick' )
436
- : ' '
437
-
438
- const api = new SessionApi ({
439
- guestName,
440
- shareToken: this .shareToken ,
441
- filePath: this .relativePath ,
442
- })
443
-
444
- this .$syncService = new SyncService ({
445
- api,
446
- baseVersionEtag: this .$baseVersionEtag ,
447
- serialize: this .isRichEditor
448
- ? (content ) =>
449
- createMarkdownSerializer (this .editor ? .schema ).serialize (
450
- content ?? this .editor ? .state .doc ,
451
- )
452
- : (content ) =>
453
- serializePlainText (content ?? this .editor ? .state .doc ),
454
- getDocumentState: () => getDocumentState (this .ydoc ),
455
- })
456
-
460
+ this .connectSyncService ()
457
461
this .listenSyncServiceEvents ()
458
-
459
- const syncServiceProvider = createSyncServiceProvider ({
462
+ this .syncProvider = createSyncServiceProvider ({
460
463
ydoc: this .ydoc ,
461
- syncService: this .$ syncService ,
464
+ syncService: this .syncService ,
462
465
fileId: this .fileId ,
463
466
initialSession: this .initialSession ,
464
467
disableBC: true ,
468
+ awareness: this .awareness ,
465
469
})
466
- this .$providers .push (syncServiceProvider)
467
470
},
468
471
469
472
listenEditorEvents () {
@@ -481,7 +484,7 @@ export default {
481
484
},
482
485
483
486
listenSyncServiceEvents () {
484
- this .$ syncService
487
+ this .syncService
485
488
.on (' opened' , this .onOpened )
486
489
.on (' change' , this .onChange )
487
490
.on (' loaded' , this .onLoaded )
@@ -493,7 +496,7 @@ export default {
493
496
},
494
497
495
498
unlistenSyncServiceEvents () {
496
- this .$ syncService
499
+ this .syncService
497
500
.off (' opened' , this .onOpened )
498
501
.off (' change' , this .onChange )
499
502
.off (' loaded' , this .onLoaded )
@@ -567,7 +570,7 @@ export default {
567
570
this .editMode = ! document .readOnly && ! this .openReadOnlyEnabled
568
571
569
572
this .setEditable (this .editMode )
570
- this .lock = this .$ syncService .lock
573
+ this .lock = this .syncService .lock
571
574
localStorage .setItem (' nick' , this .currentSession .guestName )
572
575
this .$attachmentResolver = new AttachmentResolver ({
573
576
session: this .currentSession ,
@@ -594,15 +597,15 @@ export default {
594
597
onLoaded ({ document , documentSource, documentState }) {
595
598
// Fetch the document state after syntax highlights are loaded
596
599
this .lowlightLoaded .then (() => {
597
- this .$ syncService .startSync ()
600
+ this .syncService .startSync ()
598
601
if (! documentState) {
599
602
setInitialYjsState (this .ydoc , documentSource, {
600
603
isRichEditor: this .isRichEditor ,
601
604
})
602
605
}
603
606
})
604
607
605
- this .$ baseVersionEtag = document .baseVersionEtag
608
+ this .baseVersionEtag = document .baseVersionEtag
606
609
this .hasConnectionIssue = false
607
610
608
611
const session = this .currentSession
@@ -628,28 +631,28 @@ export default {
628
631
},
629
632
630
633
onCreate ({ editor }) {
631
- const proseMirrorMarkdown = this .$ syncService .serialize (editor .state .doc )
634
+ const proseMirrorMarkdown = this .syncService .serialize (editor .state .doc )
632
635
this .emit (' create:content' , {
633
636
markdown: proseMirrorMarkdown,
634
637
})
635
638
},
636
639
637
640
onUpdate ({ editor }) {
638
641
// this.debugContent(editor)
639
- const proseMirrorMarkdown = this .$ syncService .serialize (editor .state .doc )
642
+ const proseMirrorMarkdown = this .syncService .serialize (editor .state .doc )
640
643
this .emit (' update:content' , {
641
644
markdown: proseMirrorMarkdown,
642
645
})
643
646
},
644
647
645
648
onSync ({ steps, document }) {
646
649
this .hasConnectionIssue =
647
- this .$ syncService .backend .fetcher === 0
648
- || ! this .$providers [ 0 ] .wsconnected
649
- || this .$ syncService .pushError > 0
650
- if (this .$ syncService .pushError > 0 ) {
650
+ this .syncService .backend .fetcher === 0
651
+ || ! this .syncProvider ? .wsconnected
652
+ || this .syncService .pushError > 0
653
+ if (this .syncService .pushError > 0 ) {
651
654
// successfully received steps - so let's try and also push
652
- this .$ syncService .sendStepsNow ()
655
+ this .syncService .sendStepsNow ()
653
656
}
654
657
this .$nextTick (() => {
655
658
this .emit (' sync-service:sync' )
@@ -712,14 +715,14 @@ export default {
712
715
if (this .editor .can ().undo () || this .editor .can ().redo ()) {
713
716
this .dirty = state .dirty
714
717
if (this .dirty ) {
715
- this .$ syncService .autosave ()
718
+ this .syncService .autosave ()
716
719
}
717
720
}
718
721
}
719
722
},
720
723
721
724
onIdle () {
722
- this .$ syncService .close ()
725
+ this .syncService .close ()
723
726
this .idle = true
724
727
this .readOnly = true
725
728
this .editMode = false
@@ -749,7 +752,7 @@ export default {
749
752
},
750
753
751
754
onKeyboardSave () {
752
- this .$ syncService .save ()
755
+ this .syncService .save ()
753
756
},
754
757
755
758
onAddImageNode () {
@@ -761,21 +764,19 @@ export default {
761
764
},
762
765
763
766
async save () {
764
- await this .$ syncService .save ()
767
+ await this .syncService .save ()
765
768
},
766
769
767
770
async disconnect () {
768
- await this .$ syncService .close ()
771
+ await this .syncService .close ()
769
772
this .unlistenSyncServiceEvents ()
770
- this .$providers .forEach ((p ) => p? .destroy ())
771
- this .$providers = []
772
- this .$syncService = null
773
+ this .syncProvider ? .destroy ()
773
774
// disallow editing while still showing the content
774
775
this .readOnly = true
775
776
},
776
777
777
778
async close () {
778
- await this .$ syncService
779
+ await this .syncService
779
780
.sendRemainingSteps ()
780
781
.catch ((err ) =>
781
782
logger .warn (' Failed to send remaining steps' , { err }),
@@ -787,12 +788,10 @@ export default {
787
788
try {
788
789
this .unlistenEditorEvents ()
789
790
this .editor .destroy ()
790
- this .editor = undefined
791
791
} catch (error) {
792
792
logger .warn (' Failed to destroy editor' , { error })
793
793
}
794
794
}
795
- return true
796
795
},
797
796
798
797
/**
@@ -829,7 +828,7 @@ export default {
829
828
* @param {object} editor The Tiptap editor
830
829
*/
831
830
debugContent (editor ) {
832
- const proseMirrorMarkdown = this .$ syncService .serialize (editor .state .doc )
831
+ const proseMirrorMarkdown = this .syncService .serialize (editor .state .doc )
833
832
const markdownItHtml = markdownit .render (proseMirrorMarkdown)
834
833
835
834
logger .debug (
@@ -852,7 +851,7 @@ export default {
852
851
clientId: this .ydoc .clientID ,
853
852
pendingStructs: this .ydoc .store .pendingStructs ,
854
853
clientVectors: [],
855
- documentState: this .$ syncService? .getDocumentState (),
854
+ documentState: this .syncService ? .getDocumentState (),
856
855
}
857
856
for (const client of this .ydoc .store .clients .values ()) {
858
857
yjsData .clientVectors .push (client .at (- 1 ).id )
@@ -867,7 +866,7 @@ export default {
867
866
868
867
readOnlyToggled () {
869
868
if (this .editMode ) {
870
- this .$ syncService .save ()
869
+ this .syncService .save ()
871
870
}
872
871
this .editMode = ! this .editMode
873
872
this .setEditable (this .editMode )
@@ -916,7 +915,7 @@ export default {
916
915
},
917
916
918
917
saveBeforeUnload () {
919
- this .$ syncService? .saveViaSendBeacon ()
918
+ this .syncService ? .saveViaSendBeacon ()
920
919
},
921
920
},
922
921
}
0 commit comments