我正在尝试在所见即所得的 Trix 和渲染内容中显示带有 ActionText on Rails 6 的嵌入式视频。但是 ActionText 渲染器过滤所有原始 html 代码并强制我使用 JS 在渲染内容中显示 iframe,这在 Trix 中不起作用。
我遵循了 Basecamp 的一位开发人员在此处给出的说明:https ://github.com/rails/actiontext/issues/37#issuecomment-451627370 。第 1 步到第 3 步有效,但是当 ActionText 呈现我的部分时,它会过滤 iframe。
创建 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"
添加嵌入功能的刺激控制器(迫切需要重构)
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();
},
});
}
});
}
}
嵌入模型
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
创建嵌入的控制器
def create
@embed = Embed.create!(params.require(:embed).permit(:content))
respond_to do |format|
format.json
end
end
响应 ajax 调用以创建嵌入的 jbuilder 视图
json.extract! @embed, :content
json.sgid @embed.attachable_sgid
json.content render(partial: "editorial/embeds/embed", locals: { embed: @embed }, formats: [:html])
嵌入 HTML 部分(苗条)
.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
最后是显示带有嵌入的文章内容时显示 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 中正确显示,但在渲染视图中不正确显示。