Quill: Add ability to resize videos that are inserted

Created on 20 Sep 2017  路  13Comments  路  Source: quilljs/quill

This was previously raised in #1283 and closed. I'm still not finding a particularly satisfactory way to set height and width of videos (which currently display really small).

Attempt one
This was suggested in #1283. I added height and width attributes to ql-video.
Problem for me is that I am using Quill to create content that might have various # of columns, so fixed pixels wont work for me. I need percentages, and I need the height to be a percentage of the width. I can't do this with pure CSS on the iframe element. I could do this if someone could help me understand how to modify the Video blot to wrap the iframe in another classed div.

Attempt two
Taking inspiration from the word count tutorial I created a module which listened for changes and then looked for all the ql-video divs, set their width to 100%, then measured that width in pixels then set the height to 56% of the width (for 16:9 aspect ratio). Seemed like overkill at the time but hey. Problem was that this style information isn't saved with the content and so when Quill is rendered a second time, well my height and width and blown away.

Attempt three
Merged an open pull request to add this functionality to quill-image-resize module. Super promising, but could seem to get the modified plugin working (it exported the iFrame resize module is undefined.

Any help appreciated.And adding my vote that image/video resizing should probably be part of core, I would have though it was not an uncommon use case.

Most helpful comment

following up on the above responsive embedding post, you can create a custom wrapper Blot and use the above css:

import Quill from 'quill'

const QuillVideo = Quill.import('formats/video')
const BlockEmbed = Quill.import('blots/block/embed')

const VIDEO_ATTRIBUTES = ['height', 'width']

// provides a custom div wrapper around the default Video blot
class Video extends BlockEmbed {
  static create (value) {
    const iframeNode = QuillVideo.create(value)
    const node = super.create()
    node.appendChild(iframeNode)
    return node
  }

  static formats (domNode) {
    const iframe = domNode.getElementsByTagName('iframe')[0]
    return VIDEO_ATTRIBUTES.reduce(function (formats, attribute) {
      if (iframe.hasAttribute(attribute)) {
        formats[attribute] = iframe.getAttribute(attribute)
      }
      return formats
    }, {})
  }

  static value (domNode) {
    return domNode.getElementsByTagName('iframe')[0].getAttribute('src')
  }

  format (name, value) {
    if (VIDEO_ATTRIBUTES.indexOf(name) > -1) {
      if (value) { this.domNode.setAttribute(name, value) }
      else { this.domNode.removeAttribute(name) }
    }
    else { super.format(name, value) }
  }
}

Video.blotName = 'video'
Video.className = 'ql-video-wrapper'
Video.tagName = 'DIV'

Quill.register(Video, true)

note: I set the className to ql-video-wrapper instead of embed-container so adjust the css accordingly

All 13 comments

I want to set the video autoplay false and loop false , any one have some ideas?

You can create an embed blot with whatever structure you want so going off attempt 1 you can do: https://codepen.io/quill/pen/OxbqbQ. Then not sure what CSS things you had in mind.

I made a little repo to allow video resize with iframe. I just started messing with Quill this week, so there may be better ways to do it, but it works so that's nice.

https://github.com/lancetipton04/quill-video-resize

@lancetipton Thank you for that. I tested it with a react component. It works! But, texts get wrapped up inside the iframe... Is there anyway to prevent this?

@nfabacus I'm not sure what you mean by text get wrapped up inside the iframe. Can you show me an example?

@lancetipton Here is what I mean
capture

Also, what is the best way to disable the video resize mode? Even if I make the editor readonly, resize does not stop and I cannot click to play the video. Any hint will be appreciated.

Here is my repo: quill-video-resize branch
https://github.com/nfabacus/react-quill-experiment/tree/quill-video-resize

Thank you

hmm.. does not seem to be happening to me. Let me take a look and see what I find.

@nfabacus Just submitted a pull request to your repo. Let me know if that fixes if for you.

@lancetipton Yes, I just checked the branch. It works! Thank you very much for fixing the issue. I will study what you did with the code.

@guateandrew Yes, you can get the height to be a percentage of the width with CSS, not directly on the iframe element, but on surrounding divs, like this:

<div style="width:100%">
   <div style="height:0px; padding-bottom:56.25%; position:relative;">
      <iframe src="..." style="position:absolute; left:0px; top:0px; width:100%; height:100%;"></iframe>
   </div>
</div>

Here, the 56.25% represents the 16/9 proportion.

Any working open source module for resizing embedded videos? I tried many options, but without luck :(

For responsive embedding
If it helps anyone I'm using JS to add a container to .ql-video elements and styling them with CSS

var videos = document.querySelectorAll('.ql-video')
for (let i = 0; i < videos.length; i++) {
  var embedContainer = document.createElement('div')
  embedContainer.setAttribute('class', 'embed-container')
  var parent = videos[i].parentNode
  parent.insertBefore(embedContainer, videos[i])
  embedContainer.appendChild(videos[i])
}
.embed-container 
  position: relative
  padding-bottom: 56.25%
  height: 0
  overflow: hidden
  max-width: 100%

.embed-container iframe, .embed-container object, .embed-container embed
  position: absolute
  top: 0
  left: 0
  width: 100%
  height: 100%

following up on the above responsive embedding post, you can create a custom wrapper Blot and use the above css:

import Quill from 'quill'

const QuillVideo = Quill.import('formats/video')
const BlockEmbed = Quill.import('blots/block/embed')

const VIDEO_ATTRIBUTES = ['height', 'width']

// provides a custom div wrapper around the default Video blot
class Video extends BlockEmbed {
  static create (value) {
    const iframeNode = QuillVideo.create(value)
    const node = super.create()
    node.appendChild(iframeNode)
    return node
  }

  static formats (domNode) {
    const iframe = domNode.getElementsByTagName('iframe')[0]
    return VIDEO_ATTRIBUTES.reduce(function (formats, attribute) {
      if (iframe.hasAttribute(attribute)) {
        formats[attribute] = iframe.getAttribute(attribute)
      }
      return formats
    }, {})
  }

  static value (domNode) {
    return domNode.getElementsByTagName('iframe')[0].getAttribute('src')
  }

  format (name, value) {
    if (VIDEO_ATTRIBUTES.indexOf(name) > -1) {
      if (value) { this.domNode.setAttribute(name, value) }
      else { this.domNode.removeAttribute(name) }
    }
    else { super.format(name, value) }
  }
}

Video.blotName = 'video'
Video.className = 'ql-video-wrapper'
Video.tagName = 'DIV'

Quill.register(Video, true)

note: I set the className to ql-video-wrapper instead of embed-container so adjust the css accordingly

Was this page helpful?
0 / 5 - 0 ratings

Related issues

Yves-K picture Yves-K  路  3Comments

Kivylius picture Kivylius  路  3Comments

rsdrsd picture rsdrsd  路  3Comments

markstewie picture markstewie  路  3Comments

lastmjs picture lastmjs  路  3Comments