Search code examples
vue.jsvuejs3wysiwygquillvue-quill-editor

Quill Editor switches to RTL language direction when decorated with "ref" property


I've created a text-editor vue component with quill editor and configured it to display data from a database inside its input field. For that I need the ref="quill" property on the <quill-editor> element together with a watcher. Problem is that as soon as I add the property, the editor switches to bi-directional (right-to-left) language direction.

text-editor.vue:

<template>
  <div id="text-editor" class="text-editor">
    <quill-editor ref="quill" :modules="modules" :toolbar="toolbar" v-model:content="store.re.body" contentType="html"/>
  </div>
</template>


<script setup>
import BlotFormatter from 'quill-blot-formatter'
import store from "../../../js/store";
import {ref, watch} from "vue";

store.re.body = ''

const modules = {
    module: BlotFormatter,
}

const toolbar = [
    [{ 'header': [1, 2, 3, 4, 5, 6, false] }],
    [{ 'size': ['small', false, 'large', 'huge'] }],
    ['bold', 'italic', 'underline', 'strike'],
    ['blockquote', 'code-block'],
    [{ 'align': [] }],
    [{ 'list': 'ordered'}, { 'list': 'bullet' }],
    [{ 'color': [] }, { 'background': [] }],
    [{ 'font': [] }],
    ['link', 'image', 'video'],
    ['clean']
];

const quill = ref(null)

watch(() => store.re.body, newValue => quill.value.setHTML(newValue))

</script>

enter image description here

I've tried changing it with CSS but it didn't help:

.ql-editor { direction: ltr }

The css-property is applied to quill but the language direction stays RTL.

Adding [{ 'direction': 'ltr' }] to the toolbar object does not help either. Any idea how to debug this?


Solution

  • The issue isn't caused by adding a ref to <quill-editor>.

    This looks like vue-quill#52. The author tried to fix it in this patch, but that only broke editor updates via v-model:content. You used setHTML() to workaround that issue, but cursor-reset bug was still active. Then, typing anything would cause text to be prepended, making it only appear to be RTL.

    As a workaround, you could move the cursor to the end of the line and re-focus:

    watch(
      () => store.re.body,
      newValue => {
        quill.value.setHTML(newValue)
    
        // Workaround https://github.com/vueup/vue-quill/issues/52
        // move cursor to end
        nextTick(() => {
          let q = quill.value.getQuill()
          q.setSelection(newValue.length, 0, 'api')
          q.focus()
        })
      }
    )
    

    demo 1

    However, this reveals a new problem in that deleting text from the middle of the editor causes the cursor to jump to the end. We need a way to update store.re.body and move the cursor only when the update is from the v-model. Otherwise, the external update (from the other component's fetch) should not move the cursor.

    You can implement that behavior as follows:

    1. Replace the <quill-editor>'s v-model:content with a new content ref.

    2. Watch the content ref, updating store.re.body with the new value. Also track this new value as newContent.

    3. In the watch on store.re.body, ignore the new value if it's equal to newContent.

    <template>                          1️⃣
      <quill-editor v-model:content="content" ⋯/>
    </template>
    <script setup>
             1️⃣
    const content = ref('')
    
    2️⃣
    let newContent = ''
    watch(content, newValue => {
      newContent = newValue
      store.re.body = newValue
    })
    
    watch(
      () => store.re.body,
      newValue => {
        3️⃣
        if (newContent === newValue) return
    
        ⋮ /* setHTML() and move cursor to end */
      }
    })
    </script>
    

    demo 2