如何使用 ActionText 显示嵌入视频 [英] How to display embed video with ActionText

查看:69
本文介绍了如何使用 ActionText 显示嵌入视频的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试在 Rails 6 上使用 ActionText 在 WYSIWYG Trix 和渲染内容中显示嵌入式视频.但是 ActionText 渲染器会过滤所有原始 html 代码并强制我使用 JS 来显示渲染内容中的 iframe,这在 Trix 中不起作用.

我按照 Basecamp 的开发人员之一给出的说明进行操作:https://github.com/rails/actiontext/issues/37#issuecomment-451627370.第 1 步到第 3 步有效,但是当 ActionText 呈现我的部分时,它会过滤 iframe.

创建所见即所得的表单

= form_for(article, url: url, method: method) do |a|= a.label:内容= a.rich_text_area :content, data: { controller: "articles", target: "articles.field", embeds_path: editorial_publication_embeds_path(@publication, format: :json) }= a.submit submit_text, class:"btn full"

添加嵌入功能的 Stimulus 控制器(急需重构)

import { Controller } from "stimulus";从trix"导入 Trix;$.ajaxSetup({标题:{"X-CSRF-Token": $('meta[name="csrf-token"]').attr("content"),},});导出默认类扩展控制器{静态目标 = ["字段"];连接() {this.editor = this.fieldTarget.editor;常量按钮HTML ='<button type="button" class="trix-button" data-trix-attribute="embed" data-trix-action="embed" title="Embed" tabindex="-1">Media</按钮>';const buttonGroup = this.fieldTarget.toolbarElement.querySelector(.trix-button-group--block-tools");const dialogHml = `<div class="trix-dialog trix-dialog--link" data-trix-dialog="embed" data-trix-dialog-attribute="embed"><div class="trix-dialog__link-fields"><input type="text" name="embed" class="trix-input trix-input--dialog" placeholder="粘贴您的视频或声音网址" aria-label="嵌入代码" required="" data-trix-input="" disabled="disabled"><div class="trix-button-group"><input type="button" class="trix-button trix-button--dialog" data-trix-custom="add-embed" value="Add">

`;const dialogGroup = this.fieldTarget.toolbarElement.querySelector(.trix 对话");buttonGroup.insertAdjacentHTML("beforeend", buttonHTML);dialogGroup.insertAdjacentHTML("beforeend", dialogHml);文档.querySelector('[data-trix-action="embed"]').addEventListener("点击", event => {const dialog = document.querySelector('[data-trix-dialog="embed"]');const embedInput = document.querySelector('[name="embed"]');如果(event.target.classList.contains(trix-active")){event.target.classList.remove("trix-active");dialog.classList.remove("trix-active");删除 dialog.dataset.trixActive;embedInput.setAttribute("disabled", "disabled");} 别的 {event.target.classList.add("trix-active");dialog.classList.add("trix-active");dialog.dataset.trixActive = "";embedInput.removeAttribute("禁用");embedInput.focus();}});文档.querySelector('[data-trix-custom="add-embed"]').addEventListener("点击", event => {const content = document.querySelector('[name="embed"]').value;如果(内容){$.ajax({方法:POST",url: document.querySelector("[data-embeds-path]").dataset.embedsPath,数据: {嵌入:{内容,},},成功:({ content, sgid }) =>{const 附件 = 新 Trix.Attachment({内容,sgd,});this.editor.insertAttachment(attachment);this.editor.insertLineBreak();},});}});}}

嵌入模型

class Embed <申请记录包括 ActionText::Attachable验证:内容,存在:真after_validation :fetch_oembed_datadef to_partial_path编辑/嵌入/嵌入"结尾def fetch_oembed_data网址 =案例内容当/youtube/"https://www.youtube.com/oembed?url=#{content}&format=json"当/soundcloud/"https://soundcloud.com/oembed?url=#{content}&format=json"当/推特/https://publish.twitter.com/oembed?url=#{content}"结尾res = RestClient.get urljson = JSON.parse(res.body, object_class: OpenStruct)self.height = json.heightself.author_url = json.author_urlself.thumbnail_url = json.thumbnail_urlself.width = json.widthself.author_name = json.author_nameself.thumbnail_height = json.thumbnail_heightself.title = json.titleself.version = json.versionself.provider_url = json.provider_urlself.thumbnail_width = json.thumbnail_widthself.embed_type = json.typeself.provider_name = json.provider_nameself.html = json.html结尾结尾

创建嵌入的控制器

 def create@embed = Embed.create!(params.require(:embed).permit(:content))response_to do |格式|格式.json结尾结尾

响应 ajax 调用以创建 Embed 的 jbuilder 视图

json.extract!@嵌入,:内容json.sgid @embed.attachable_sgidjson.content 渲染(部分:编辑/嵌入/嵌入",本地人:{嵌入:@embed},格式:[:html])

嵌入的 HTML 部分(超薄)

.youtube-embed.embed.内容= image_tag(embed.thumbnail_url) 如果 embed.thumbnail_url.present?p = "从#{embed.provider_name} (#{embed.content}) 嵌入"p.embed-html = embed.html

最后是显示带有嵌入的文章内容时显示 iframe 的 JS 代码

$(document).ready(() => {$(".embed").each(function(i, embed) {const $embed = $(embed);const p = $embed.find(".content").replaceWith($embed.find(".embed-html").text());});});

如果我将嵌入部分更改为

== embed.html

它在 WYSIWYG 中正确显示,但在渲染视图中不显示.

解决方案

需要在allowed_tags中添加iframe,在application.rb中添加如下代码:

config.to_prepare 做ActionText::ContentHelper.allowed_tags <<iframe"结尾

I am trying to display embedded videos with ActionText on Rails 6, both in the WYSIWYG Trix, and in the rendered content. But the ActionText renderer filters all raw html code and forces me to use JS to display the iframes in the rendered content, which doesnt work in Trix.

I followed the instructions given here by one of Basecamp's dev : https://github.com/rails/actiontext/issues/37#issuecomment-451627370. Step 1 through 3 work, but when ActionText renders my partial it filters the iframe.

The form creating the WYSIYWG

= form_for(article, url: url, method: method) do |a|
  = a.label :content
  = a.rich_text_area :content, data: { controller: "articles", target: "articles.field", embeds_path: editorial_publication_embeds_path(@publication, format: :json) }
  = a.submit submit_text, class:"btn full"

The Stimulus controller adding the embed functionality (in dire need of a refactor)

import { Controller } from "stimulus";
import Trix from "trix";

$.ajaxSetup({
  headers: {
    "X-CSRF-Token": $('meta[name="csrf-token"]').attr("content"),
  },
});

export default class extends Controller {
  static targets = ["field"];

  connect() {
    this.editor = this.fieldTarget.editor; 

    const buttonHTML =
      '<button type="button" class="trix-button" data-trix-attribute="embed" data-trix-action="embed" title="Embed" tabindex="-1">Media</button>';
    const buttonGroup = this.fieldTarget.toolbarElement.querySelector(
      ".trix-button-group--block-tools"
    );
    const dialogHml = `<div class="trix-dialog trix-dialog--link" data-trix-dialog="embed" data-trix-dialog-attribute="embed">
    <div class="trix-dialog__link-fields">
      <input type="text" name="embed" class="trix-input trix-input--dialog" placeholder="Paste your video or sound url" aria-label="embed code" required="" data-trix-input="" disabled="disabled">
      <div class="trix-button-group">
        <input type="button" class="trix-button trix-button--dialog" data-trix-custom="add-embed" value="Add">
      </div>
    </div>
  </div>`;
    const dialogGroup = this.fieldTarget.toolbarElement.querySelector(
      ".trix-dialogs"
    );
    buttonGroup.insertAdjacentHTML("beforeend", buttonHTML);
    dialogGroup.insertAdjacentHTML("beforeend", dialogHml);
    document
      .querySelector('[data-trix-action="embed"]')
      .addEventListener("click", event => {
        const dialog = document.querySelector('[data-trix-dialog="embed"]');
        const embedInput = document.querySelector('[name="embed"]');
        if (event.target.classList.contains("trix-active")) {
          event.target.classList.remove("trix-active");
          dialog.classList.remove("trix-active");
          delete dialog.dataset.trixActive;
          embedInput.setAttribute("disabled", "disabled");
        } else {
          event.target.classList.add("trix-active");
          dialog.classList.add("trix-active");
          dialog.dataset.trixActive = "";
          embedInput.removeAttribute("disabled");
          embedInput.focus();
        }
      });
    document
      .querySelector('[data-trix-custom="add-embed"]')
      .addEventListener("click", event => {
        const content = document.querySelector('[name="embed"]').value;
        if (content) {
          $.ajax({
            method: "POST",
            url: document.querySelector("[data-embeds-path]").dataset
              .embedsPath,
            data: {
              embed: {
                content,
              },
            },
            success: ({ content, sgid }) => {
              const attachment = new Trix.Attachment({
                content,
                sgid,
              });
              this.editor.insertAttachment(attachment);
              this.editor.insertLineBreak();
            },
          });
        }
      });
  }
}

The Embed model

class Embed < ApplicationRecord
  include ActionText::Attachable

  validates :content, presence: true

  after_validation :fetch_oembed_data

  def to_partial_path
    "editorial/embeds/embed"
  end

  def fetch_oembed_data
    url =
      case content
      when /youtube/
        "https://www.youtube.com/oembed?url=#{content}&format=json"
      when /soundcloud/
        "https://soundcloud.com/oembed?url=#{content}&format=json"
      when /twitter/
        "https://publish.twitter.com/oembed?url=#{content}"
      end
    res = RestClient.get url
    json = JSON.parse(res.body, object_class: OpenStruct)
    self.height = json.height
    self.author_url = json.author_url
    self.thumbnail_url = json.thumbnail_url
    self.width = json.width
    self.author_name = json.author_name
    self.thumbnail_height = json.thumbnail_height
    self.title = json.title
    self.version = json.version
    self.provider_url = json.provider_url
    self.thumbnail_width = json.thumbnail_width
    self.embed_type = json.type
    self.provider_name = json.provider_name
    self.html = json.html
  end
end

The controller creating the Embed

  def create
    @embed = Embed.create!(params.require(:embed).permit(:content))
    respond_to do |format|
      format.json
    end
  end

The jbuilder view responding to the ajax call to create the Embed

json.extract! @embed, :content

json.sgid @embed.attachable_sgid
json.content render(partial: "editorial/embeds/embed", locals: { embed: @embed }, formats: [:html])

The Embed HTML partial (slim)

.youtube-embed.embed
  .content
    = image_tag(embed.thumbnail_url) if embed.thumbnail_url.present?
    p = "Embed from #{embed.provider_name} (#{embed.content})"
    p.embed-html = embed.html

And finally the JS code displaying the iframes when the Article's content with Embeds inside is displayed

$(document).ready(() => {
  $(".embed").each(function(i, embed) {
    const $embed = $(embed);
    const p = $embed
      .find(".content")
      .replaceWith($embed.find(".embed-html").text());
  });
});

If I change the Embed partial to

== embed.html

It displays properly in the WYSIWYG but not in the rendered view.

解决方案

You need to add iframe to allowed_tags, add the following code in application.rb:

config.to_prepare do
  ActionText::ContentHelper.allowed_tags << "iframe"
end

这篇关于如何使用 ActionText 显示嵌入视频的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
其他开发最新文章
热门教程
热门工具
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆