./tools/rdoc-to-md --only=actiontext -a

This commit is contained in:
Hartley McGuire 2024-01-24 19:08:44 -05:00
parent 195d80199f
commit 1ecac5b8d3
No known key found for this signature in database
GPG Key ID: E823FC1403858A82
31 changed files with 316 additions and 238 deletions

@ -1,5 +1,7 @@
# frozen_string_literal: true
# :markup: markdown
require "rails-html-sanitizer"
module ActionText

@ -1,5 +1,7 @@
# frozen_string_literal: true
# :markup: markdown
require "active_support/core_ext/object/try"
require "action_view/helpers/tags/placeholderable"
@ -7,20 +9,24 @@ module ActionText
module TagHelper
cattr_accessor(:id, instance_accessor: false) { 0 }
# Returns a +trix-editor+ tag that instantiates the Trix JavaScript editor as well as a hidden field
# that Trix will write to on changes, so the content will be sent on form submissions.
# Returns a `trix-editor` tag that instantiates the Trix JavaScript editor as
# well as a hidden field that Trix will write to on changes, so the content will
# be sent on form submissions.
#
# ==== Options
# * <tt>:class</tt> - Defaults to "trix-content" so that default styles will be applied.
# Setting this to a different value will prevent default styles from being applied.
# * <tt>[:data][:direct_upload_url]</tt> - Defaults to +rails_direct_uploads_url+.
# * <tt>[:data][:blob_url_template]</tt> - Defaults to <tt>rails_service_blob_url(":signed_id", ":filename")</tt>.
# #### Options
# * `:class` - Defaults to "trix-content" so that default styles will be
# applied. Setting this to a different value will prevent default styles
# from being applied.
# * `[:data][:direct_upload_url]` - Defaults to `rails_direct_uploads_url`.
# * `[:data][:blob_url_template]` - Defaults to
# `rails_service_blob_url(":signed_id", ":filename")`.
#
# ==== Example
#
# rich_text_area_tag "content", message.content
# # <input type="hidden" name="content" id="trix_input_post_1">
# # <trix-editor id="content" input="trix_input_post_1" class="trix-content" ...></trix-editor>
# #### Example
#
# rich_text_area_tag "content", message.content
# # <input type="hidden" name="content" id="trix_input_post_1">
# # <trix-editor id="content" input="trix_input_post_1" class="trix-content" ...></trix-editor>
def rich_text_area_tag(name, value = nil, options = {})
options = options.symbolize_keys
form = options.delete(:form)
@ -56,23 +62,27 @@ def render
end
module FormHelper
# Returns a +trix-editor+ tag that instantiates the Trix JavaScript editor as well as a hidden field
# that Trix will write to on changes, so the content will be sent on form submissions.
# Returns a `trix-editor` tag that instantiates the Trix JavaScript editor as
# well as a hidden field that Trix will write to on changes, so the content will
# be sent on form submissions.
#
# ==== Options
# * <tt>:class</tt> - Defaults to "trix-content" which ensures default styling is applied.
# * <tt>:value</tt> - Adds a default value to the HTML input tag.
# * <tt>[:data][:direct_upload_url]</tt> - Defaults to +rails_direct_uploads_url+.
# * <tt>[:data][:blob_url_template]</tt> - Defaults to <tt>rails_service_blob_url(":signed_id", ":filename")</tt>.
# #### Options
# * `:class` - Defaults to "trix-content" which ensures default styling is
# applied.
# * `:value` - Adds a default value to the HTML input tag.
# * `[:data][:direct_upload_url]` - Defaults to `rails_direct_uploads_url`.
# * `[:data][:blob_url_template]` - Defaults to
# `rails_service_blob_url(":signed_id", ":filename")`.
#
# ==== Example
# rich_text_area :message, :content
# # <input type="hidden" name="message[content]" id="message_content_trix_input_message_1">
# # <trix-editor id="content" input="message_content_trix_input_message_1" class="trix-content" ...></trix-editor>
#
# rich_text_area :message, :content, value: "<h1>Default message</h1>"
# # <input type="hidden" name="message[content]" id="message_content_trix_input_message_1" value="<h1>Default message</h1>">
# # <trix-editor id="content" input="message_content_trix_input_message_1" class="trix-content" ...></trix-editor>
# #### Example
# rich_text_area :message, :content
# # <input type="hidden" name="message[content]" id="message_content_trix_input_message_1">
# # <trix-editor id="content" input="message_content_trix_input_message_1" class="trix-content" ...></trix-editor>
#
# rich_text_area :message, :content, value: "<h1>Default message</h1>"
# # <input type="hidden" name="message[content]" id="message_content_trix_input_message_1" value="<h1>Default message</h1>">
# # <trix-editor id="content" input="message_content_trix_input_message_1" class="trix-content" ...></trix-editor>
def rich_text_area(object_name, method, options = {})
Tags::ActionText.new(object_name, method, self, options).render
end
@ -81,9 +91,9 @@ def rich_text_area(object_name, method, options = {})
class FormBuilder
# Wraps ActionView::Helpers::FormHelper#rich_text_area for form builders:
#
# <%= form_with model: @message do |f| %>
# <%= f.rich_text_area :content %>
# <% end %>
# <%= form_with model: @message do |f| %>
# <%= f.rich_text_area :content %>
# <% end %>
#
# Please refer to the documentation of the base helper for details.
def rich_text_area(method, options = {})

@ -1,5 +1,7 @@
# frozen_string_literal: true
# :markup: markdown
module ActionText
class EncryptedRichText < RichText
encrypts :body

@ -1,5 +1,7 @@
# frozen_string_literal: true
# :markup: markdown
module ActionText
class Record < ActiveRecord::Base # :nodoc:
self.abstract_class = true

@ -1,37 +1,40 @@
# frozen_string_literal: true
# :markup: markdown
module ActionText
# = Action Text \RichText
# # Action Text RichText
#
# The RichText record holds the content produced by the Trix editor in a serialized +body+ attribute.
# It also holds all the references to the embedded files, which are stored using Active Storage.
# This record is then associated with the Active Record model the application desires to have
# rich text content using the +has_rich_text+ class method.
# The RichText record holds the content produced by the Trix editor in a
# serialized `body` attribute. It also holds all the references to the embedded
# files, which are stored using Active Storage. This record is then associated
# with the Active Record model the application desires to have rich text content
# using the `has_rich_text` class method.
#
# class Message < ActiveRecord::Base
# has_rich_text :content
# end
# class Message < ActiveRecord::Base
# has_rich_text :content
# end
#
# message = Message.create!(content: "<h1>Funny times!</h1>")
# message.content #=> #<ActionText::RichText....
# message.content.to_s # => "<h1>Funny times!</h1>"
# message.content.to_plain_text # => "Funny times!"
# message = Message.create!(content: "<h1>Funny times!</h1>")
# message.content #=> #<ActionText::RichText....
# message.content.to_s # => "<h1>Funny times!</h1>"
# message.content.to_plain_text # => "Funny times!"
#
# message = Message.create!(content: "<div onclick='action()'>safe<script>unsafe</script></div>")
# message.content #=> #<ActionText::RichText....
# message.content.to_s # => "<div>safeunsafe</div>"
# message.content.to_plain_text # => "safeunsafe"
# message = Message.create!(content: "<div onclick='action()'>safe<script>unsafe</script></div>")
# message.content #=> #<ActionText::RichText....
# message.content.to_s # => "<div>safeunsafe</div>"
# message.content.to_plain_text # => "safeunsafe"
class RichText < Record
##
# :method: to_s
#
# Safely transforms RichText into an HTML String.
#
# message = Message.create!(content: "<h1>Funny times!</h1>")
# message.content.to_s # => "<h1>Funny times!</h1>"
# message = Message.create!(content: "<h1>Funny times!</h1>")
# message.content.to_s # => "<h1>Funny times!</h1>"
#
# message = Message.create!(content: "<div onclick='action()'>safe<script>unsafe</script></div>")
# message.content.to_s # => "<div>safeunsafe</div>"
# message = Message.create!(content: "<div onclick='action()'>safe<script>unsafe</script></div>")
# message.content.to_s # => "<div>safeunsafe</div>"
serialize :body, coder: ActionText::Content
delegate :to_s, :nil?, to: :body
@ -43,32 +46,33 @@ class RichText < Record
self.embeds = body.attachables.grep(ActiveStorage::Blob).uniq if body.present?
end
# Returns a plain-text version of the markup contained by the +body+ attribute,
# Returns a plain-text version of the markup contained by the `body` attribute,
# with tags removed but HTML entities encoded.
#
# message = Message.create!(content: "<h1>Funny times!</h1>")
# message.content.to_plain_text # => "Funny times!"
# message = Message.create!(content: "<h1>Funny times!</h1>")
# message.content.to_plain_text # => "Funny times!"
#
# NOTE: that the returned string is not HTML safe and should not be rendered in browsers.
# NOTE: that the returned string is not HTML safe and should not be rendered in
# browsers.
#
# message = Message.create!(content: "&lt;script&gt;alert()&lt;/script&gt;")
# message.content.to_plain_text # => "<script>alert()</script>"
# message = Message.create!(content: "&lt;script&gt;alert()&lt;/script&gt;")
# message.content.to_plain_text # => "<script>alert()</script>"
def to_plain_text
body&.to_plain_text.to_s
end
# Returns the +body+ attribute in a format that makes it editable in the Trix
# Returns the `body` attribute in a format that makes it editable in the Trix
# editor. Previews of attachments are rendered inline.
#
# content = "<h1>Funny Times!</h1><figure data-trix-attachment='{\"sgid\":\"..."\}'></figure>"
# message = Message.create!(content: content)
# message.content.to_trix_html # =>
# # <div class="trix-content">
# # <h1>Funny times!</h1>
# # <figure data-trix-attachment='{\"sgid\":\"..."\}'>
# # <img src="http://example.org/rails/active_storage/.../funny.jpg">
# # </figure>
# # </div>
# content = "<h1>Funny Times!</h1><figure data-trix-attachment='{\"sgid\":\"..."\}'></figure>"
# message = Message.create!(content: content)
# message.content.to_trix_html # =>
# # <div class="trix-content">
# # <h1>Funny times!</h1>
# # <figure data-trix-attachment='{\"sgid\":\"..."\}'>
# # <img src="http://example.org/rails/active_storage/.../funny.jpg">
# # </figure>
# # </div>
def to_trix_html
body&.to_trix_html
end

@ -1,31 +1,33 @@
# frozen_string_literal: true
# :markup: markdown
module ActionText
# = Action Text \Attachable
# # Action Text Attachable
#
# Include this module to make a record attachable to an ActionText::Content.
#
# class Person < ApplicationRecord
# include ActionText::Attachable
# end
# class Person < ApplicationRecord
# include ActionText::Attachable
# end
#
# person = Person.create! name: "Javan"
# html = %Q(<action-text-attachment sgid="#{person.attachable_sgid}"></action-text-attachment>)
# content = ActionText::Content.new(html)
# content.attachables # => [person]
# person = Person.create! name: "Javan"
# html = %Q(<action-text-attachment sgid="#{person.attachable_sgid}"></action-text-attachment>)
# content = ActionText::Content.new(html)
# content.attachables # => [person]
module Attachable
extend ActiveSupport::Concern
LOCATOR_NAME = "attachable"
class << self
# Extracts the +ActionText::Attachable+ from the attachment HTML node:
# Extracts the `ActionText::Attachable` from the attachment HTML node:
#
# person = Person.create! name: "Javan"
# html = %Q(<action-text-attachment sgid="#{person.attachable_sgid}"></action-text-attachment>)
# fragment = ActionText::Fragment.wrap(html)
# attachment_node = fragment.find_all(ActionText::Attachment.tag_name).first
# ActionText::Attachable.from_node(attachment_node) # => person
# person = Person.create! name: "Javan"
# html = %Q(<action-text-attachment sgid="#{person.attachable_sgid}"></action-text-attachment>)
# fragment = ActionText::Fragment.wrap(html)
# attachment_node = fragment.find_all(ActionText::Attachment.tag_name).first
# ActionText::Attachable.from_node(attachment_node) # => person
def from_node(node)
if attachable = attachable_from_sgid(node["sgid"])
attachable
@ -57,23 +59,23 @@ def from_attachable_sgid(sgid)
ActionText::Attachable.from_attachable_sgid(sgid, only: self)
end
# Returns the path to the partial that is used for rendering missing attachables.
# Defaults to "action_text/attachables/missing_attachable".
# Returns the path to the partial that is used for rendering missing
# attachables. Defaults to "action_text/attachables/missing_attachable".
#
# Override to render a different partial:
#
# class User < ApplicationRecord
# def self.to_missing_attachable_partial_path
# "users/missing_attachable"
# class User < ApplicationRecord
# def self.to_missing_attachable_partial_path
# "users/missing_attachable"
# end
# end
# end
def to_missing_attachable_partial_path
ActionText::Attachables::MissingAttachable::DEFAULT_PARTIAL_PATH
end
end
# Returns the Signed Global ID for the attachable. The purpose of the ID is
# set to 'attachable' so it can't be reused for other purposes.
# Returns the Signed Global ID for the attachable. The purpose of the ID is set
# to 'attachable' so it can't be reused for other purposes.
def attachable_sgid
to_sgid(expires_in: nil, for: LOCATOR_NAME).to_s
end
@ -98,30 +100,30 @@ def previewable_attachable?
false
end
# Returns the path to the partial that is used for rendering the attachable
# in Trix. Defaults to +to_partial_path+.
# Returns the path to the partial that is used for rendering the attachable in
# Trix. Defaults to `to_partial_path`.
#
# Override to render a different partial:
#
# class User < ApplicationRecord
# def to_trix_content_attachment_partial_path
# "users/trix_content_attachment"
# class User < ApplicationRecord
# def to_trix_content_attachment_partial_path
# "users/trix_content_attachment"
# end
# end
# end
def to_trix_content_attachment_partial_path
to_partial_path
end
# Returns the path to the partial that is used for rendering the attachable.
# Defaults to +to_partial_path+.
# Defaults to `to_partial_path`.
#
# Override to render a different partial:
#
# class User < ApplicationRecord
# def to_attachable_partial_path
# "users/attachable"
# class User < ApplicationRecord
# def to_attachable_partial_path
# "users/attachable"
# end
# end
# end
def to_attachable_partial_path
to_partial_path
end

@ -1,5 +1,7 @@
# frozen_string_literal: true
# :markup: markdown
module ActionText
module Attachables
class ContentAttachment # :nodoc:

@ -1,5 +1,7 @@
# frozen_string_literal: true
# :markup: markdown
module ActionText
module Attachables
class MissingAttachable

@ -1,5 +1,7 @@
# frozen_string_literal: true
# :markup: markdown
module ActionText
module Attachables
class RemoteImage

@ -1,19 +1,21 @@
# frozen_string_literal: true
# :markup: markdown
require "active_support/core_ext/object/try"
module ActionText
# = Action Text \Attachment
# # Action Text Attachment
#
# Attachments serialize attachables to HTML or plain text.
#
# class Person < ApplicationRecord
# include ActionText::Attachable
# end
# class Person < ApplicationRecord
# include ActionText::Attachable
# end
#
# attachable = Person.create! name: "Javan"
# attachment = ActionText::Attachment.from_attachable(attachable)
# attachment.to_html # => "<action-text-attachment sgid=\"BAh7CEk..."
# attachable = Person.create! name: "Javan"
# attachment = ActionText::Attachment.from_attachable(attachable)
# attachment.to_html # => "<action-text-attachment sgid=\"BAh7CEk..."
class Attachment
include Attachments::TrixConversion, Attachments::Minification, Attachments::Caching
@ -82,29 +84,29 @@ def with_full_attributes
# Converts the attachment to plain text.
#
# attachable = ActiveStorage::Blob.find_by filename: "racecar.jpg"
# attachment = ActionText::Attachment.from_attachable(attachable)
# attachment.to_plain_text # => "[racecar.jpg]"
# attachable = ActiveStorage::Blob.find_by filename: "racecar.jpg"
# attachment = ActionText::Attachment.from_attachable(attachable)
# attachment.to_plain_text # => "[racecar.jpg]"
#
# Use the +caption+ when set:
# Use the `caption` when set:
#
# attachment = ActionText::Attachment.from_attachable(attachable, caption: "Vroom vroom")
# attachment.to_plain_text # => "[Vroom vroom]"
# attachment = ActionText::Attachment.from_attachable(attachable, caption: "Vroom vroom")
# attachment.to_plain_text # => "[Vroom vroom]"
#
# The presentation can be overridden by implementing the
# +attachable_plain_text_representation+ method:
# `attachable_plain_text_representation` method:
#
# class Person < ApplicationRecord
# include ActionText::Attachable
# class Person < ApplicationRecord
# include ActionText::Attachable
#
# def attachable_plain_text_representation
# "[#{name}]"
# def attachable_plain_text_representation
# "[#{name}]"
# end
# end
# end
#
# attachable = Person.create! name: "Javan"
# attachment = ActionText::Attachment.from_attachable(attachable)
# attachment.to_plain_text # => "[Javan]"
# attachable = Person.create! name: "Javan"
# attachment = ActionText::Attachment.from_attachable(attachable)
# attachment.to_plain_text # => "[Javan]"
def to_plain_text
if respond_to?(:attachable_plain_text_representation)
attachable_plain_text_representation(caption)
@ -115,9 +117,9 @@ def to_plain_text
# Converts the attachment to HTML.
#
# attachable = Person.create! name: "Javan"
# attachment = ActionText::Attachment.from_attachable(attachable)
# attachment.to_html # => "<action-text-attachment sgid=\"BAh7CEk...
# attachable = Person.create! name: "Javan"
# attachment = ActionText::Attachment.from_attachable(attachable)
# attachment.to_html # => "<action-text-attachment sgid=\"BAh7CEk...
def to_html
HtmlConversion.node_to_html(node)
end

@ -1,5 +1,7 @@
# frozen_string_literal: true
# :markup: markdown
module ActionText
class AttachmentGallery
include ActiveModel::Model

@ -1,5 +1,7 @@
# frozen_string_literal: true
# :markup: markdown
module ActionText
module Attachments
module Caching

@ -1,5 +1,7 @@
# frozen_string_literal: true
# :markup: markdown
module ActionText
module Attachments
module Minification

@ -1,5 +1,7 @@
# frozen_string_literal: true
# :markup: markdown
require "active_support/core_ext/object/try"
module ActionText

@ -1,44 +1,52 @@
# frozen_string_literal: true
# :markup: markdown
module ActionText
module Attribute
extend ActiveSupport::Concern
class_methods do
# Provides access to a dependent RichText model that holds the body and attachments for a single named rich text attribute.
# This dependent attribute is lazily instantiated and will be auto-saved when it's been changed. Example:
# Provides access to a dependent RichText model that holds the body and
# attachments for a single named rich text attribute. This dependent attribute
# is lazily instantiated and will be auto-saved when it's been changed. Example:
#
# class Message < ActiveRecord::Base
# has_rich_text :content
# end
# class Message < ActiveRecord::Base
# has_rich_text :content
# end
#
# message = Message.create!(content: "<h1>Funny times!</h1>")
# message.content? #=> true
# message.content.to_s # => "<h1>Funny times!</h1>"
# message.content.to_plain_text # => "Funny times!"
# message = Message.create!(content: "<h1>Funny times!</h1>")
# message.content? #=> true
# message.content.to_s # => "<h1>Funny times!</h1>"
# message.content.to_plain_text # => "Funny times!"
#
# The dependent RichText model will also automatically process attachments links as sent via the Trix-powered editor.
# These attachments are associated with the RichText model using Active Storage.
# The dependent RichText model will also automatically process attachments links
# as sent via the Trix-powered editor. These attachments are associated with the
# RichText model using Active Storage.
#
# If you wish to preload the dependent RichText model, you can use the named scope:
# If you wish to preload the dependent RichText model, you can use the named
# scope:
#
# Message.all.with_rich_text_content # Avoids N+1 queries when you just want the body, not the attachments.
# Message.all.with_rich_text_content_and_embeds # Avoids N+1 queries when you just want the body and attachments.
# Message.all.with_all_rich_text # Loads all rich text associations.
# Message.all.with_rich_text_content # Avoids N+1 queries when you just want the body, not the attachments.
# Message.all.with_rich_text_content_and_embeds # Avoids N+1 queries when you just want the body and attachments.
# Message.all.with_all_rich_text # Loads all rich text associations.
#
# ==== Options
# #### Options
#
# * <tt>:encrypted</tt> - Pass true to encrypt the rich text attribute. The encryption will be non-deterministic. See
# +ActiveRecord::Encryption::EncryptableRecord.encrypts+. Default: false.
# * `:encrypted` - Pass true to encrypt the rich text attribute. The
# encryption will be non-deterministic. See
# `ActiveRecord::Encryption::EncryptableRecord.encrypts`. Default: false.
#
# * <tt>:strict_loading</tt> - Pass true to force strict loading. When
# omitted, <tt>strict_loading:</tt> will be set to the value of the
# <tt>strict_loading_by_default</tt> class attribute (false by default).
# * `:strict_loading` - Pass true to force strict loading. When omitted,
# `strict_loading:` will be set to the value of the
# `strict_loading_by_default` class attribute (false by default).
#
# Note: Action Text relies on polymorphic associations, which in turn store class names in the database.
# When renaming classes that use <tt>has_rich_text</tt>, make sure to also update the class names in the
# <tt>action_text_rich_texts.record_type</tt> polymorphic type column of
# the corresponding rows.
#
# Note: Action Text relies on polymorphic associations, which in turn store
# class names in the database. When renaming classes that use `has_rich_text`,
# make sure to also update the class names in the
# `action_text_rich_texts.record_type` polymorphic type column of the
# corresponding rows.
def has_rich_text(name, encrypted: false, strict_loading: strict_loading_by_default)
class_eval <<-CODE, __FILE__, __LINE__ + 1
def #{name}

@ -1,24 +1,26 @@
# frozen_string_literal: true
# :markup: markdown
module ActionText
# = Action Text \Content
# # Action Text Content
#
# The +ActionText::Content+ class wraps an HTML fragment to add support for
# The `ActionText::Content` class wraps an HTML fragment to add support for
# parsing, rendering and serialization. It can be used to extract links and
# attachments, convert the fragment to plain text, or serialize the fragment
# to the database.
# attachments, convert the fragment to plain text, or serialize the fragment to
# the database.
#
# The ActionText::RichText record serializes the `body` attribute as
# +ActionText::Content+.
# `ActionText::Content`.
#
# class Message < ActiveRecord::Base
# has_rich_text :content
# end
# class Message < ActiveRecord::Base
# has_rich_text :content
# end
#
# message = Message.create!(content: "<h1>Funny times!</h1>")
# body = message.content.body # => #<ActionText::Content "<div class=\"trix-conte...">
# body.to_s # => "<h1>Funny times!</h1>"
# body.to_plain_text # => "Funny times!"
# message = Message.create!(content: "<h1>Funny times!</h1>")
# body = message.content.body # => #<ActionText::Content "<div class=\"trix-conte...">
# body.to_s # => "<h1>Funny times!</h1>"
# body.to_plain_text # => "Funny times!"
class Content
include Rendering, Serialization
@ -47,19 +49,19 @@ def initialize(content = nil, options = {})
# Extracts links from the HTML fragment:
#
# html = '<a href="http://example.com/">Example</a>'
# content = ActionText::Content.new(html)
# content.links # => ["http://example.com/"]
# html = '<a href="http://example.com/">Example</a>'
# content = ActionText::Content.new(html)
# content.links # => ["http://example.com/"]
def links
@links ||= fragment.find_all("a[href]").map { |a| a["href"] }.uniq
end
# Extracts +ActionText::Attachment+s from the HTML fragment:
#
# attachable = ActiveStorage::Blob.first
# html = %Q(<action-text-attachment sgid="#{attachable.attachable_sgid}" caption="Captioned"></action-text-attachment>)
# content = ActionText::Content.new(html)
# content.attachments # => [#<ActionText::Attachment attachable=#<ActiveStorage::Blob...
# attachable = ActiveStorage::Blob.first
# html = %Q(<action-text-attachment sgid="#{attachable.attachable_sgid}" caption="Captioned"></action-text-attachment>)
# content = ActionText::Content.new(html)
# content.attachments # => [#<ActionText::Attachment attachable=#<ActiveStorage::Blob...
def attachments
@attachments ||= attachment_nodes.map do |node|
attachment_for_node(node)
@ -78,10 +80,10 @@ def gallery_attachments
# Extracts +ActionText::Attachable+s from the HTML fragment:
#
# attachable = ActiveStorage::Blob.first
# html = %Q(<action-text-attachment sgid="#{attachable.attachable_sgid}" caption="Captioned"></action-text-attachment>)
# content = ActionText::Content.new(html)
# content.attachables # => [attachable]
# attachable = ActiveStorage::Blob.first
# html = %Q(<action-text-attachment sgid="#{attachable.attachable_sgid}" caption="Captioned"></action-text-attachment>)
# content = ActionText::Content.new(html)
# content.attachables # => [attachable]
def attachables
@attachables ||= attachment_nodes.map do |node|
ActionText::Attachable.from_node(node)
@ -107,19 +109,20 @@ def render_attachment_galleries(&block)
self.class.new(content, canonicalize: false)
end
# Returns a plain-text version of the markup contained by the content,
# with tags removed but HTML entities encoded.
# Returns a plain-text version of the markup contained by the content, with tags
# removed but HTML entities encoded.
#
# content = ActionText::Content.new("<h1>Funny times!</h1>")
# content.to_plain_text # => "Funny times!"
# content = ActionText::Content.new("<h1>Funny times!</h1>")
# content.to_plain_text # => "Funny times!"
#
# content = ActionText::Content.new("<div onclick='action()'>safe<script>unsafe</script></div>")
# content.to_plain_text # => "safeunsafe"
# content = ActionText::Content.new("<div onclick='action()'>safe<script>unsafe</script></div>")
# content.to_plain_text # => "safeunsafe"
#
# NOTE: that the returned string is not HTML safe and should not be rendered in browsers.
# NOTE: that the returned string is not HTML safe and should not be rendered in
# browsers.
#
# content = ActionText::Content.new("&lt;script&gt;alert()&lt;/script&gt;")
# content.to_plain_text # => "<script>alert()</script>"
# content = ActionText::Content.new("&lt;script&gt;alert()&lt;/script&gt;")
# content.to_plain_text # => "<script>alert()</script>"
def to_plain_text
render_attachments(with_full_attributes: false, &:to_plain_text).fragment.to_plain_text
end
@ -142,11 +145,11 @@ def to_partial_path
# Safely transforms Content into an HTML String.
#
# content = ActionText::Content.new(content: "<h1>Funny times!</h1>")
# content.to_s # => "<h1>Funny times!</h1>"
# content = ActionText::Content.new(content: "<h1>Funny times!</h1>")
# content.to_s # => "<h1>Funny times!</h1>"
#
# content = ActionText::Content.new("<div onclick='action()'>safe<script>unsafe</script></div>")
# content.to_s # => "<div>safeunsafe</div>"
# content = ActionText::Content.new("<div onclick='action()'>safe<script>unsafe</script></div>")
# content.to_s # => "<div>safeunsafe</div>"
def to_s
to_rendered_html_with_layout
end

@ -1,5 +1,7 @@
# frozen_string_literal: true
# :markup: markdown
module ActionText
def self.deprecator # :nodoc:
@deprecator ||= ActiveSupport::Deprecation.new

@ -1,5 +1,7 @@
# frozen_string_literal: true
# :markup: markdown
module ActionText
module Encryption
def encrypt

@ -1,5 +1,7 @@
# frozen_string_literal: true
# :markup: markdown
require "rails"
require "action_controller/railtie"
require "active_record/railtie"

@ -1,62 +1,62 @@
# frozen_string_literal: true
# :markup: markdown
module ActionText
# = Action Text \FixtureSet
# # Action Text FixtureSet
#
# Fixtures are a way of organizing data that you want to test against; in
# short, sample data.
# Fixtures are a way of organizing data that you want to test against; in short,
# sample data.
#
# To learn more about fixtures, read the ActiveRecord::FixtureSet documentation.
#
# === YAML
# ### YAML
#
# Like other Active Record-backed models, ActionText::RichText records inherit
# from ActiveRecord::Base instances and can therefore be populated by
# fixtures.
# from ActiveRecord::Base instances and can therefore be populated by fixtures.
#
# Consider an <tt>Article</tt> class:
# Consider an `Article` class:
#
# class Article < ApplicationRecord
# has_rich_text :content
# end
# class Article < ApplicationRecord
# has_rich_text :content
# end
#
# To declare fixture data for the related <tt>content</tt>, first declare fixture
# data for <tt>Article</tt> instances in <tt>test/fixtures/articles.yml</tt>:
# To declare fixture data for the related `content`, first declare fixture data
# for `Article` instances in `test/fixtures/articles.yml`:
#
# first:
# title: An Article
# first:
# title: An Article
#
# Then declare the ActionText::RichText fixture data in
# <tt>test/fixtures/action_text/rich_texts.yml</tt>, making sure to declare
# each entry's <tt>record:</tt> key as a polymorphic relationship:
# `test/fixtures/action_text/rich_texts.yml`, making sure to declare each
# entry's `record:` key as a polymorphic relationship:
#
# first:
# record: first (Article)
# name: content
# body: <div>Hello, world.</div>
# first:
# record: first (Article)
# name: content
# body: <div>Hello, world.</div>
#
# When processed, Active Record will insert database records for each fixture
# entry and will ensure the Action Text relationship is intact.
class FixtureSet
# Fixtures support Action Text attachments as part of their <tt>body</tt>
# HTML.
# Fixtures support Action Text attachments as part of their `body` HTML.
#
# === Examples
# ### Examples
#
# For example, consider a second <tt>Article</tt> fixture declared in
# <tt>test/fixtures/articles.yml</tt>:
# For example, consider a second `Article` fixture declared in
# `test/fixtures/articles.yml`:
#
# second:
# title: Another Article
# second:
# title: Another Article
#
# You can attach a mention of <tt>articles(:first)</tt> to <tt>second</tt>'s
# <tt>content</tt> by embedding a call to <tt>ActionText::FixtureSet.attachment</tt>
# in the <tt>body:</tt> value in <tt>test/fixtures/action_text/rich_texts.yml</tt>:
# You can attach a mention of `articles(:first)` to `second`'s `content` by
# embedding a call to `ActionText::FixtureSet.attachment` in the `body:` value
# in `test/fixtures/action_text/rich_texts.yml`:
#
# second:
# record: second (Article)
# name: content
# body: <div>Hello, <%= ActionText::FixtureSet.attachment("articles", :first) %></div>
# second:
# record: second (Article)
# name: content
# body: <div>Hello, <%= ActionText::FixtureSet.attachment("articles", :first) %></div>
#
def self.attachment(fixture_set_name, label, column_type: :integer)
signed_global_id = ActiveRecord::FixtureSet.signed_global_id fixture_set_name, label,

@ -1,5 +1,7 @@
# frozen_string_literal: true
# :markup: markdown
module ActionText
class Fragment
class << self

@ -1,7 +1,9 @@
# frozen_string_literal: true
# :markup: markdown
module ActionText
# Returns the currently loaded version of Action Text as a +Gem::Version+.
# Returns the currently loaded version of Action Text as a `Gem::Version`.
def self.gem_version
Gem::Version.new VERSION::STRING
end

@ -1,5 +1,7 @@
# frozen_string_literal: true
# :markup: markdown
module ActionText
module HtmlConversion
extend self

@ -1,5 +1,7 @@
# frozen_string_literal: true
# :markup: markdown
module ActionText
module PlainTextConversion
extend self

@ -1,5 +1,7 @@
# frozen_string_literal: true
# :markup: markdown
require "active_support/concern"
require "active_support/core_ext/module/attribute_accessors_per_thread"

@ -1,5 +1,7 @@
# frozen_string_literal: true
# :markup: markdown
module ActionText
module Serialization
extend ActiveSupport::Concern

@ -1,34 +1,37 @@
# frozen_string_literal: true
# :markup: markdown
module ActionText
module SystemTestHelper
# Locates a Trix editor and fills it in with the given HTML.
#
# The editor can be found by:
# * its +id+
# * its +placeholder+
# * the text from its +label+ element
# * its +aria-label+
# * the +name+ of its input
# * its `id`
# * its `placeholder`
# * the text from its `label` element
# * its `aria-label`
# * the `name` of its input
#
#
# Examples:
#
# # <trix-editor id="message_content" ...></trix-editor>
# fill_in_rich_text_area "message_content", with: "Hello <em>world!</em>"
# # <trix-editor id="message_content" ...></trix-editor>
# fill_in_rich_text_area "message_content", with: "Hello <em>world!</em>"
#
# # <trix-editor placeholder="Your message here" ...></trix-editor>
# fill_in_rich_text_area "Your message here", with: "Hello <em>world!</em>"
# # <trix-editor placeholder="Your message here" ...></trix-editor>
# fill_in_rich_text_area "Your message here", with: "Hello <em>world!</em>"
#
# # <label for="message_content">Message content</label>
# # <trix-editor id="message_content" ...></trix-editor>
# fill_in_rich_text_area "Message content", with: "Hello <em>world!</em>"
# # <label for="message_content">Message content</label>
# # <trix-editor id="message_content" ...></trix-editor>
# fill_in_rich_text_area "Message content", with: "Hello <em>world!</em>"
#
# # <trix-editor aria-label="Message content" ...></trix-editor>
# fill_in_rich_text_area "Message content", with: "Hello <em>world!</em>"
# # <trix-editor aria-label="Message content" ...></trix-editor>
# fill_in_rich_text_area "Message content", with: "Hello <em>world!</em>"
#
# # <input id="trix_input_1" name="message[content]" type="hidden">
# # <trix-editor input="trix_input_1"></trix-editor>
# fill_in_rich_text_area "message[content]", with: "Hello <em>world!</em>"
# # <input id="trix_input_1" name="message[content]" type="hidden">
# # <trix-editor input="trix_input_1"></trix-editor>
# fill_in_rich_text_area "message[content]", with: "Hello <em>world!</em>"
def fill_in_rich_text_area(locator = nil, with:)
find(:rich_text_area, locator).execute_script("this.editor.loadHTML(arguments[0])", with.to_s)
end

@ -1,5 +1,7 @@
# frozen_string_literal: true
# :markup: markdown
module ActionText
class TrixAttachment
TAG_NAME = "figure"

@ -1,9 +1,11 @@
# frozen_string_literal: true
# :markup: markdown
require_relative "gem_version"
module ActionText
# Returns the currently loaded version of Action Text as a +Gem::Version+.
# Returns the currently loaded version of Action Text as a `Gem::Version`.
def self.version
gem_version
end

@ -1,5 +1,7 @@
# frozen_string_literal: true
# :markup: markdown
require "pathname"
require "json"
@ -73,8 +75,8 @@ def using_js_runtime?
end
def using_bun?
# Cannot assume yarn.lock has been generated yet so we look for
# a file known to be generated by the jsbundling-rails gem
# Cannot assume yarn.lock has been generated yet so we look for a file known to
# be generated by the jsbundling-rails gem
@using_bun ||= using_js_runtime? && Pathname(destination_root).join("bun.config.js").exist?
end

@ -1,5 +1,7 @@
# frozen_string_literal: true
# :markup: markdown
module TestUnit
module Generators
class InstallGenerator < ::Rails::Generators::Base