Rich text editor Quill upload pictures and videos

image and video belong to Embeds in Quill formats. To insert pictures or videos into rich text, you need to use insertEmbed api.

insertEmbed

insertEmbed(index: Number, type: String, value: any, source: String = 'api'): Delta

To insert a picture, you need the location, content type, and url of the picture:

quill.insertEmbed(10, 'image', 'https://quilljs.com/images/cloud.png')

Get location:

const range = quill.getSelection();

Upload pictures

First, add image to the toolbar, and a hidden input element is needed to upload the image:

<template>
  <div>
    <div id="toolbar">
      <span class="ql-formats">
        <button class="ql-image"></button>
        <button class="ql-video"></button>
      </span>
    </div>
    <div id="editor">
      <p>Hello World!</p>
      <p>Some initial <strong>bold</strong> text</p>
      <p><br></p>
    </div>
    <input id="uploadImg" type="file" style="display:none" accept="image/png, image/jpeg, image/gif" @change="uploadImage">
  </div>
</template>

Add a handler for the image. When clicking, upload the image:

this.quill.getModule("toolbar").addHandler("image", this.uploadImageHandler)

handler:

    uploadImageHandler () {
      const input = document.querySelector('#uploadImg')
      input.value = ''
      input.click()
    },

Add onchange event to the input element, get the uploaded picture, upload the server, get the picture address, and insert the address into the editor:

  async uploadImage (event) {
      const form = new FormData()
      form.append('upload_file', event.target.files[0])
      const url = await $.ajax(...)  #Upload image access address
      const addImageRange = this.quill.getSelection()
      const newRange = 0 + (addImageRange !== null ? addImageRange.index : 0)
      this.quill.insertEmbed(newRange, 'image', url)
      this.quill.setSelection(1 + newRange)
    }

All codes:

<template>
  <div>
    <div id="toolbar">
      <span class="ql-formats">
        <button class="ql-image"></button>
        <button class="ql-video"></button>
      </span>
    </div>
    <div id="editor">
      <p>Hello World!</p>
      <p>Some initial <strong>bold</strong> text</p>
      <p><br></p>
    </div>
    <input id="uploadImg" type="file" style="display:none" accept="image/png, image/jpeg, image/gif" @change="uploadImage">
  </div>
</template>

<script>
import Quill from 'quill'

export default {
  name: "QuillEditor",
  mounted () {
    this.initQuill()
  },
  beforeDestroy () {
    this.quill = null
    delete this.quill
  },
  methods: {
    initQuill () {
      const quill = new Quill('#editor', {
        theme: 'snow',
        modules: {
          toolbar: '#toolbar'
        }
      })
      this.quill = quill
      this.quill.getModule("toolbar").addHandler("image", this.uploadImageHandler)
    },
    uploadImageHandler () {
      const input = document.querySelector('#uploadImg')
      input.value = ''
      input.click()
    },
    async uploadImage (event) {
      const form = new FormData()
      form.append('upload_file', event.target.files[0])
      const url = await $.ajax(...)
      const addImageRange = this.quill.getSelection()
      const newRange = 0 + (addImageRange !== null ? addImageRange.index : 0)
      this.quill.insertEmbed(newRange, 'image', url)
      this.quill.setSelection(1 + newRange)
    }
  }
}
</script>

Upload the video and make some changes:

<input id="uploadVideo" type="file" style="display:none" accept="video/*" @change="uploadVideo">
this.quill.getModule("toolbar").addHandler("video", this.uploadVideoHandler)
uploadVideoHandler () {...}
async uploadVideo (event) {...}

Customized Video

There is a problem with the default video upload. After the upload, the video is placed in iframe, which is not a problem in general. However, when using h5 page in an applet, the domain name in iframe needs to be added to the business domain name of the applet, otherwise access will be forbidden.

A better solution is to simply add a video element instead of iframe, which we need Customized A Video Embed.

const BlockEmbed = Quill.import('blots/block/embed')
class VideoBlot extends BlockEmbed {
  static create (value) {
    let node = super.create()
    node.setAttribute('src', value.url)
    node.setAttribute('controls', value.controls)
    node.setAttribute('width', value.width)
    node.setAttribute('height', value.height)
    node.setAttribute('webkit-playsinline', true)
    node.setAttribute('playsinline', true)
    node.setAttribute('x5-playsinline', true)
    return node;
  }

  static value (node) {
    return {
      url: node.getAttribute('src'),
      controls: node.getAttribute('controls'),
      width: node.getAttribute('width'),
      height: node.getAttribute('height')
    };
  }
}

Registration:

VideoBlot.blotName = 'simpleVideo'
VideoBlot.tagName = 'video'
Quill.register(VideoBlot)

Insert Embed:

      this.quill.insertEmbed(newRange, 'simpleVideo', {
        url,
        controls: 'controls',
        width: '100%',
        height: '100%'
      })

Add effect:

<video src="...mp4" controls="controls" width="100%" height="100%" webkit-playsinline="true" playsinline="true" x5-playsinline="true"></video>

Tags: Javascript

Posted on Wed, 04 Dec 2019 03:35:20 -0500 by Jamiek