0

I figured out how sync text value between clients using Yjs but I still can't handle cursor pos after text update. I use quasar framework so I can't apply one of this recomended text-editors by Yjs documentation. I do not need and special binding like characters size, color, bolding and on.

this is what I've got up to now

<q-input
 :modelValue="article"
 debounce="1000"
 ref="editor"
 type="textarea"
 @update:modelValue=" (e) => {
  updateText(article, e ) 
 }"
 @focus="showCursor()"
/>

<script setup lang='ts'>
/* main imports */
import { QInput } from 'quasar'
import { ref, nextTick } from 'vue'

/* yjs lib */
import * as Y from 'yjs'
import { SocketIOProvider } from 'y-socket.io'

/* fast-diff lib */
import diff, { Diff } from 'fast-diff'

/* Set Y instance and bind it with y.text extension */
const doc = new Y.Doc()
const doc_text = doc.getText('article')

/* Set provider to manage communication */
const provider = new SocketIOProvider(
  'http://localhost:1234',
  'example-document',
  doc,
  {
    autoConnect: true,
  }
)

/* Check if provider is connected */
const is_provider_connected = ref('')
provider.on('status', ({ status }: { status: string }) => {
  is_provider_connected.value = status
  article.value = doc_text.toString()
})

/* To get cursor position */
const editor = ref<QInput | null>(null)
function curetPos() {
   return editor.value?.getNativeElement().selectionStart
}
function showCursor(){
  setTimeout(()=>{
    relPos.value = Y.createRelativePositionFromTypeIndex(doc_text, curetPos())
  }, 1)
}

const relPos = ref()
const pos = ref()

/* intercept article change */
const article = ref('')
const diffResult = ref<Diff[]>()

function updateText(oldValue: string, newValue: string | number | null) {
  let consumerIndex = 0
  if (typeof newValue === 'string') {
    diffResult.value = diff(oldValue, newValue)

    diffResult.value.forEach((el) => {
      if (el[0] === 0) {
        consumerIndex += el[1].length
      } else if (el[0] === 1) {
        doc_text.insert(consumerIndex, el[1])
      } else if (el[0] === -1) {
        doc_text.delete(consumerIndex, el[1].length)
      }
    })
  }
}

doc.on('update', () => {
  article.value = doc_text.toString()
  if(relPos.value){
    pos.value= Y.createAbsolutePositionFromRelativePosition(relPos.value, doc)
    nextTick(()=>{
      editor.value?.getNativeElement().setSelectionRange(pos.value.index, pos.value.index)
    })
  }
})
</script> 

So as you see the main problem is the setting cursor pos after update.
First because update model is earlier then dom-el re-render and second is that someone could changed value while you still write the text.

O'Neil
  • 3,790
  • 4
  • 16
  • 30

0 Answers0