Youtube Embed

This guide will show you how to add a custom Include for Youtube. We will show the implementation for the design, server and editor. This is more of a quick-guide where you can just copy and paste code. For a deeper understanding you can dive into server-customization and editor-customization

Design definition

In the design you will define the component.

module.exports = {
  name: 'youtube',
  label: 'Youtube',
  iconUrl: 'https://example.com/foo-icon',
  directives: [{
    name: 'youtubeInclude',
    type: 'include',
    service: 'youtubeIncludeService'
  }],
  // The innerHTML of the div containing the `doc-include` attribute
  // will be replaced by the return value of the service
  html: `
    <div doc-include="youtubeInclude">
      <div>Youtube Include</div>
    </div>
  `
}

Server - rendering the include and defining the service

In the server you will define the youtubeIncludeService

This service has one main job - rendering the include with parameters filled in the editor.

// app/server.js
liServer.features.register('custom-includes', require('app/includes'))

// app/includes/index.js
module.exports = async function (feature, server) {
  const includesApi = server.features.api('li-includes')

  // register the include service
  await includesApi.registerServices([
    require('../../plugins/includes/youtubeService')
  ])
}

// ../../plugins/includes/youtubeService.js
module.exports = {
  name: 'youtubeIncludeService',

  // define the possible parameters an include can recieve
  // this schema will be used to render a form for data input in the sidebar
  paramsSchema: [
    {
      type: 'li-text',
      handle: 'url',
      config: {
        maxLength: 200
      },
      ui: {
        component: 'liMetaTextareaForm',
        config: {
          label: 'Youtube settings',
          placeholder: 'Paste Embed Code or URL'
        }
      }
    }
  ],

  // define the default parameter
  defaultParams: {
    url: ''
  },

  // define the render mechanism
  rendering: {
    type: 'function',
    render: renderYoutube
  }
}

async function renderYoutube ({url}, options) {
  if (!url) {
    return options.preview
      ? {doNotRender: true} // render the placeholder in the editor
      : {html: ''} // do not render anything
  }

  // always extract the ID so the document only contains 'safe' HTML
  const videoId = getId(url)
  return {
    html: `<iframe width="560" height="315" src="//www.youtube.com/embed/${videoId}" frameborder="0" allowfullscreen></iframe>`
  }
}

// extracts the ID... This just serves an example
function getId (url) {
  const regExp = /^.*(youtu.be\/|v\/|u\/\w\/|embed\/|watch\?v=|&v=)([^#&?]*).*/
  const match = url.match(regExp)

  return (match && match[2].slice(0, 11))
    ? match[2].slice(0, 11)
    : null
}

Below you can see the sidebar generated by the defined paramsSchema: Rendered Sidebar

And once a user enters a link, the youtube component is complete: Rendered Youtube Include

Editor - Triggering a custom script

Youtube should already be rendering without any further integration. If your include does not render correctly, you might need to trigger rendering on changes. See the example here to learn how to run code when new content is injected into the document.