【问题标题】:How to embed an iframe with ActionText/Trix on Ruby on Rails?如何在 Ruby on Rails 上嵌入带有 ActionText/Trix 的 iframe?
【发布时间】:2020-05-18 10:56:04
【问题描述】:

我找不到实现嵌入 youtube/vimeo 视频功能的方法是 actiontext/trix。

这就是我想要实现的目标:

GIF来源:https://github.com/basecamp/trix/issues/206#issuecomment-198479999

我查看了所有类似的问题/解决方案,但似乎没有任何答案:

我们如何使用 Ruby on Rails 将 iframe 与 actiontext/trix 正确嵌入?

【问题讨论】:

    标签: ruby-on-rails trix actiontext


    【解决方案1】:

    我看过 Chris Oliver 在 RailsConf2020 上关于 Action Text 的演讲,这里是一步一步的答案:

    _thumbnail.html.erb

    app/views/youtubes/_thumbnail.html.erb
    <div>
      <%= image_tag youtube.thumbnail_url, style: "max-width:400px" %>
    </div>
    

    _youtube.html.erb

    app/views/youtubes/_youtube.html.erb
    <div>
      <iframe id="ytplayer" type="text/html" width="640" height="360" src="https://www.youtube.com/embed/<%= youtube.id %>" frameborder="0"></iframe>
    </div>
    

    应用程序.js

    #packs/application.js
    import "youtube"
    

    应用程序.rb

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

    routes.rb

      resources :youtube, only: :show
    

    youtube.js

    #javascript/youtube.js
    import Trix from "trix"
    import Rails from "@rails/ujs"
    
    let lang = Trix.config.lang;
    Trix.config.toolbar = {
      getDefaultHTML: function() {
        return `
        <div class="trix-button-row">
          <span class="trix-button-group trix-button-group--text-tools" data-trix-button-group="text-tools">
            <button type="button" class="trix-button trix-button--icon trix-button--icon-bold" data-trix-attribute="bold" data-trix-key="b" title="${lang.bold}" tabindex="-1">${lang.bold}</button>
            <button type="button" class="trix-button trix-button--icon trix-button--icon-italic" data-trix-attribute="italic" data-trix-key="i" title="${lang.italic}" tabindex="-1">${lang.italic}</button>
            <button type="button" class="trix-button trix-button--icon trix-button--icon-strike" data-trix-attribute="strike" title="${lang.strike}" tabindex="-1">${lang.strike}</button>
            <button type="button" class="trix-button trix-button--icon trix-button--icon-link" data-trix-attribute="href" data-trix-action="link" data-trix-key="k" title="${lang.link}" tabindex="-1">${lang.link}</button>
          </span>
          <span class="trix-button-group trix-button-group--block-tools" data-trix-button-group="block-tools">
            <button type="button" class="trix-button trix-button--icon trix-button--icon-heading-1" data-trix-attribute="heading1" title="${lang.heading1}" tabindex="-1">${lang.heading1}</button>
            <button type="button" class="trix-button trix-button--icon trix-button--icon-quote" data-trix-attribute="quote" title="${lang.quote}" tabindex="-1">${lang.quote}</button>
            <button type="button" class="trix-button trix-button--icon trix-button--icon-code" data-trix-attribute="code" title="${lang.code}" tabindex="-1">${lang.code}</button>
            <button type="button" class="trix-button trix-button--icon trix-button--icon-bullet-list" data-trix-attribute="bullet" title="${lang.bullets}" tabindex="-1">${lang.bullets}</button>
            <button type="button" class="trix-button trix-button--icon trix-button--icon-number-list" data-trix-attribute="number" title="${lang.numbers}" tabindex="-1">${lang.numbers}</button>
            <button type="button" class="trix-button trix-button--icon trix-button--icon-decrease-nesting-level" data-trix-action="decreaseNestingLevel" title="${lang.outdent}" tabindex="-1">${lang.outdent}</button>
            <button type="button" class="trix-button trix-button--icon trix-button--icon-increase-nesting-level" data-trix-action="increaseNestingLevel" title="${lang.indent}" tabindex="-1">${lang.indent}</button>
          </span>
          <span class="trix-button-group trix-button-group--file-tools" data-trix-button-group="file-tools">
            <button type="button" class="trix-button trix-button--icon trix-button--icon-attach" data-trix-action="attachFiles" title="${lang.attachFiles}" tabindex="-1">${lang.attachFiles}</button>
          </span>
          <span class="trix-button-group-spacer"></span>
          <span class="trix-button-group trix-button-group--history-tools" data-trix-button-group="history-tools">
            <button type="button" class="trix-button trix-button--icon trix-button--icon-undo" data-trix-action="undo" data-trix-key="z" title="${lang.undo}" tabindex="-1">${lang.undo}</button>
            <button type="button" class="trix-button trix-button--icon trix-button--icon-redo" data-trix-action="redo" data-trix-key="shift+z" title="${lang.redo}" tabindex="-1">${lang.redo}</button>
          </span>
        </div>
        <div class="trix-dialogs" data-trix-dialogs>
          <div class="trix-dialog trix-dialog--link" data-trix-dialog="href" data-trix-dialog-attribute="href">
            <div class="trix-dialog__link-fields">
              <input type="url" name="href" class="trix-input trix-input--dialog" placeholder="${lang.urlPlaceholder}" aria-label="${lang.url}" required data-trix-input>
              <div class="flex">
                <input type="button" class="btn btn-secondary btn-small mr-1" value="${lang.link}" data-trix-method="setAttribute">
                <input type="button" class="btn btn-tertiary outline btn-small" value="${lang.unlink}" data-trix-method="removeAttribute">
              </div>
            </div>
            <div data-behavior="embed_container">
              <div class="link_to_embed link_to_embed--new">
                Would you like to embed media from this site?
                <input class="btn btn-tertiary outline btn-small ml-3" type="button" data-behavior="embed_url" value="Yes, embed it">
              </div>
            </div>
          </div>
        </div>
      `
      }
    }
    
    class EmbedController {
      constructor(element) {
        this.pattern = /^https:\/\/([^\.]+\.)?youtube\.com\/watch\?v=(.*)/
    
        this.element = element
        this.editor = element.editor
        this.toolbar = element.toolbarElement
        this.hrefElement = this.toolbar.querySelector("[data-trix-input][name='href']")
        this.embedContainerElement = this.toolbar.querySelector("[data-behavior='embed_container']")
        this.embedElement = this.toolbar.querySelector("[data-behavior='embed_url']")
    
        this.reset()
        this.installEventHandlers()
      }
    
      installEventHandlers() {
        this.hrefElement.addEventListener("input", this.didInput.bind(this))
        this.hrefElement.addEventListener("focusin", this.didInput.bind(this))
        this.embedElement.addEventListener("click", this.embed.bind(this))
      }
    
      didInput(event) {
        let value = event.target.value.trim()
        let matches = value.match(this.pattern)
        console.log(value,matches)
    
        // When patterns are loaded, we can just fetch the embed code
        if (matches != null) {
          this.fetch(matches[2])
    
        // No embed code, just reset the form
        } else {
          this.reset()
        }
      }
    
      fetch(value) {
        Rails.ajax({
          url: `/youtube/${encodeURIComponent(value)}`,
          type: 'get',
          error: this.reset.bind(this),
          success: this.showEmbed.bind(this)
        })
      }
    
      embed(event) {
        if (this.currentEmbed == null) { return }
    
        let attachment = new Trix.Attachment(this.currentEmbed)
        this.editor.insertAttachment(attachment)
        this.element.focus()
      }
    
      showEmbed(embed) {
        this.currentEmbed = embed
        this.embedContainerElement.style.display = "block"
      }
    
      reset() {
        this.embedContainerElement.style.display = "none"
        this.currentEmbed = null
      }
    }
    
    document.addEventListener("trix-initialize", function(event) {
      new EmbedController(event.target)
    })
    

    youtube.rb

    #models/youtube.rb
    class Youtube
      include ActiveModel::Model
      include ActiveModel::Attributes
      include GlobalID::Identification
      include ActionText::Attachable
    
      attribute :id
    
      def self.find(id)
        new(id: id)
      end
    
      def thumbnail_url
        "http://i3.ytimg.com/vi/#{id}/maxresdefault.jpg"
      end
    
      def to_trix_content_attachment_partial_path
        "youtubes/thumbnail"
      end
    end
    

    youtube_controller.rb

    #controllers/youtube_controller.rb
    class YoutubeController < ApplicationController
      def show
        @youtube = Youtube.new(id: params[:id])
        render json: {
          sgid: @youtube.attachable_sgid,
          content: render_to_string(partial: "youtubes/thumbnail", locals: { youtube: @youtube }, formats: [:html])
        }
      end
    end
    

    也可以在这里找到: https://gist.github.com/yshmarov/90377ba51f14df09df03e6442cd7412e

    【讨论】:

    【解决方案2】:

    对于 Rails 6.1.0,您必须像这样将 iframe 标签列入白名单:

     # config/application.rb
     Rails::Html::WhiteListSanitizer.allowed_tags << "iframe"
    

    【讨论】:

      【解决方案3】:

      查看 Chris Oliver 在 RailsConf2020 上关于 Action Text 的演讲。他回顾了这个确切的场景。

      【讨论】:

        猜你喜欢
        • 2022-10-19
        • 2020-06-24
        • 2020-11-01
        • 2020-07-29
        • 2013-03-04
        • 1970-01-01
        • 2012-01-16
        • 2019-11-24
        • 1970-01-01
        相关资源
        最近更新 更多