actiontext 7.0.8.1 → 7.2.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +43 -124
- data/MIT-LICENSE +1 -1
- data/README.md +2 -2
- data/app/assets/javascripts/actiontext.esm.js +889 -0
- data/app/assets/javascripts/actiontext.js +55 -73
- data/app/assets/javascripts/trix.js +13612 -5170
- data/app/assets/stylesheets/trix.css +67 -30
- data/app/helpers/action_text/content_helper.rb +28 -4
- data/app/helpers/action_text/tag_helper.rb +44 -30
- data/app/models/action_text/encrypted_rich_text.rb +4 -2
- data/app/models/action_text/record.rb +2 -0
- data/app/models/action_text/rich_text.rb +66 -6
- data/app/views/action_text/attachables/_content_attachment.html.erb +3 -0
- data/db/migrate/20180528164100_create_action_text_tables.rb +1 -1
- data/lib/action_text/attachable.rb +71 -5
- data/lib/action_text/attachables/content_attachment.rb +22 -18
- data/lib/action_text/attachables/missing_attachable.rb +19 -3
- data/lib/action_text/attachables/remote_image.rb +2 -0
- data/lib/action_text/attachment.rb +45 -2
- data/lib/action_text/attachment_gallery.rb +2 -0
- data/lib/action_text/attachments/caching.rb +2 -0
- data/lib/action_text/attachments/minification.rb +2 -0
- data/lib/action_text/attachments/trix_conversion.rb +2 -0
- data/lib/action_text/attribute.rb +40 -21
- data/lib/action_text/content.rb +68 -3
- data/lib/action_text/deprecator.rb +9 -0
- data/lib/action_text/encryption.rb +2 -0
- data/lib/action_text/engine.rb +17 -9
- data/lib/action_text/fixture_set.rb +35 -33
- data/lib/action_text/fragment.rb +8 -3
- data/lib/action_text/gem_version.rb +5 -3
- data/lib/action_text/html_conversion.rb +3 -1
- data/lib/action_text/plain_text_conversion.rb +8 -1
- data/lib/action_text/rendering.rb +7 -2
- data/lib/action_text/serialization.rb +2 -0
- data/lib/action_text/system_test_helper.rb +20 -17
- data/lib/action_text/trix_attachment.rb +4 -2
- data/lib/action_text/version.rb +3 -1
- data/lib/action_text.rb +19 -0
- data/lib/generators/action_text/install/install_generator.rb +29 -5
- data/lib/generators/action_text/install/templates/actiontext.css +0 -4
- data/lib/rails/generators/test_unit/install_generator.rb +2 -0
- data/package.json +7 -7
- metadata +21 -18
@@ -1,12 +1,33 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
# :markup: markdown
|
4
|
+
|
3
5
|
module ActionText
|
6
|
+
# # Action Text Attachable
|
7
|
+
#
|
8
|
+
# Include this module to make a record attachable to an ActionText::Content.
|
9
|
+
#
|
10
|
+
# class Person < ApplicationRecord
|
11
|
+
# include ActionText::Attachable
|
12
|
+
# end
|
13
|
+
#
|
14
|
+
# person = Person.create! name: "Javan"
|
15
|
+
# html = %Q(<action-text-attachment sgid="#{person.attachable_sgid}"></action-text-attachment>)
|
16
|
+
# content = ActionText::Content.new(html)
|
17
|
+
# content.attachables # => [person]
|
4
18
|
module Attachable
|
5
19
|
extend ActiveSupport::Concern
|
6
20
|
|
7
21
|
LOCATOR_NAME = "attachable"
|
8
22
|
|
9
23
|
class << self
|
24
|
+
# Extracts the `ActionText::Attachable` from the attachment HTML node:
|
25
|
+
#
|
26
|
+
# person = Person.create! name: "Javan"
|
27
|
+
# html = %Q(<action-text-attachment sgid="#{person.attachable_sgid}"></action-text-attachment>)
|
28
|
+
# fragment = ActionText::Fragment.wrap(html)
|
29
|
+
# attachment_node = fragment.find_all(ActionText::Attachment.tag_name).first
|
30
|
+
# ActionText::Attachable.from_node(attachment_node) # => person
|
10
31
|
def from_node(node)
|
11
32
|
if attachable = attachable_from_sgid(node["sgid"])
|
12
33
|
attachable
|
@@ -15,7 +36,7 @@ module ActionText
|
|
15
36
|
elsif attachable = ActionText::Attachables::RemoteImage.from_node(node)
|
16
37
|
attachable
|
17
38
|
else
|
18
|
-
ActionText::Attachables::MissingAttachable
|
39
|
+
ActionText::Attachables::MissingAttachable.new(node["sgid"])
|
19
40
|
end
|
20
41
|
end
|
21
42
|
|
@@ -37,8 +58,24 @@ module ActionText
|
|
37
58
|
def from_attachable_sgid(sgid)
|
38
59
|
ActionText::Attachable.from_attachable_sgid(sgid, only: self)
|
39
60
|
end
|
61
|
+
|
62
|
+
# Returns the path to the partial that is used for rendering missing
|
63
|
+
# attachables. Defaults to "action_text/attachables/missing_attachable".
|
64
|
+
#
|
65
|
+
# Override to render a different partial:
|
66
|
+
#
|
67
|
+
# class User < ApplicationRecord
|
68
|
+
# def self.to_missing_attachable_partial_path
|
69
|
+
# "users/missing_attachable"
|
70
|
+
# end
|
71
|
+
# end
|
72
|
+
def to_missing_attachable_partial_path
|
73
|
+
ActionText::Attachables::MissingAttachable::DEFAULT_PARTIAL_PATH
|
74
|
+
end
|
40
75
|
end
|
41
76
|
|
77
|
+
# Returns the Signed Global ID for the attachable. The purpose of the ID is set
|
78
|
+
# to 'attachable' so it can't be reused for other purposes.
|
42
79
|
def attachable_sgid
|
43
80
|
to_sgid(expires_in: nil, for: LOCATOR_NAME).to_s
|
44
81
|
end
|
@@ -63,14 +100,30 @@ module ActionText
|
|
63
100
|
false
|
64
101
|
end
|
65
102
|
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
103
|
+
# Returns the path to the partial that is used for rendering the attachable in
|
104
|
+
# Trix. Defaults to `to_partial_path`.
|
105
|
+
#
|
106
|
+
# Override to render a different partial:
|
107
|
+
#
|
108
|
+
# class User < ApplicationRecord
|
109
|
+
# def to_trix_content_attachment_partial_path
|
110
|
+
# "users/trix_content_attachment"
|
111
|
+
# end
|
112
|
+
# end
|
70
113
|
def to_trix_content_attachment_partial_path
|
71
114
|
to_partial_path
|
72
115
|
end
|
73
116
|
|
117
|
+
# Returns the path to the partial that is used for rendering the attachable.
|
118
|
+
# Defaults to `to_partial_path`.
|
119
|
+
#
|
120
|
+
# Override to render a different partial:
|
121
|
+
#
|
122
|
+
# class User < ApplicationRecord
|
123
|
+
# def to_attachable_partial_path
|
124
|
+
# "users/attachable"
|
125
|
+
# end
|
126
|
+
# end
|
74
127
|
def to_attachable_partial_path
|
75
128
|
to_partial_path
|
76
129
|
end
|
@@ -86,5 +139,18 @@ module ActionText
|
|
86
139
|
attrs[:height] = attachable_metadata[:height]
|
87
140
|
end.compact
|
88
141
|
end
|
142
|
+
|
143
|
+
private
|
144
|
+
def attribute_names_for_serialization
|
145
|
+
super + ["attachable_sgid"]
|
146
|
+
end
|
147
|
+
|
148
|
+
def read_attribute_for_serialization(key)
|
149
|
+
if key == "attachable_sgid"
|
150
|
+
persisted? ? super : nil
|
151
|
+
else
|
152
|
+
super
|
153
|
+
end
|
154
|
+
end
|
89
155
|
end
|
90
156
|
end
|
@@ -1,38 +1,42 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
# :markup: markdown
|
4
|
+
|
3
5
|
module ActionText
|
4
6
|
module Attachables
|
5
|
-
class ContentAttachment
|
7
|
+
class ContentAttachment # :nodoc:
|
6
8
|
include ActiveModel::Model
|
7
9
|
|
8
10
|
def self.from_node(node)
|
9
|
-
|
10
|
-
|
11
|
-
attachment = new(name: matches[1])
|
12
|
-
attachment if attachment.valid?
|
13
|
-
end
|
14
|
-
end
|
11
|
+
attachment = new(content_type: node["content-type"], content: node["content"])
|
12
|
+
attachment if attachment.valid?
|
15
13
|
end
|
16
14
|
|
17
|
-
attr_accessor :
|
18
|
-
|
15
|
+
attr_accessor :content_type, :content
|
16
|
+
|
17
|
+
validates_format_of :content_type, with: /html/
|
18
|
+
validates_presence_of :content
|
19
19
|
|
20
20
|
def attachable_plain_text_representation(caption)
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
21
|
+
content_instance.fragment.source
|
22
|
+
end
|
23
|
+
|
24
|
+
def to_html
|
25
|
+
@to_html ||= content_instance.render(content_instance)
|
26
|
+
end
|
27
|
+
|
28
|
+
def to_s
|
29
|
+
to_html
|
27
30
|
end
|
28
31
|
|
29
32
|
def to_partial_path
|
30
33
|
"action_text/attachables/content_attachment"
|
31
34
|
end
|
32
35
|
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
+
private
|
37
|
+
def content_instance
|
38
|
+
@content_instance ||= ActionText::Content.new(content)
|
39
|
+
end
|
36
40
|
end
|
37
41
|
end
|
38
42
|
end
|
@@ -1,12 +1,28 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
# :markup: markdown
|
4
|
+
|
3
5
|
module ActionText
|
4
6
|
module Attachables
|
5
|
-
|
7
|
+
class MissingAttachable
|
6
8
|
extend ActiveModel::Naming
|
7
9
|
|
8
|
-
|
9
|
-
|
10
|
+
DEFAULT_PARTIAL_PATH = "action_text/attachables/missing_attachable"
|
11
|
+
|
12
|
+
def initialize(sgid)
|
13
|
+
@sgid = SignedGlobalID.parse(sgid, for: ActionText::Attachable::LOCATOR_NAME)
|
14
|
+
end
|
15
|
+
|
16
|
+
def to_partial_path
|
17
|
+
if model
|
18
|
+
model.to_missing_attachable_partial_path
|
19
|
+
else
|
20
|
+
DEFAULT_PARTIAL_PATH
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
def model
|
25
|
+
@sgid&.model_name.to_s.safe_constantize
|
10
26
|
end
|
11
27
|
end
|
12
28
|
end
|
@@ -1,14 +1,27 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
# :markup: markdown
|
4
|
+
|
3
5
|
require "active_support/core_ext/object/try"
|
4
6
|
|
5
7
|
module ActionText
|
8
|
+
# # Action Text Attachment
|
9
|
+
#
|
10
|
+
# Attachments serialize attachables to HTML or plain text.
|
11
|
+
#
|
12
|
+
# class Person < ApplicationRecord
|
13
|
+
# include ActionText::Attachable
|
14
|
+
# end
|
15
|
+
#
|
16
|
+
# attachable = Person.create! name: "Javan"
|
17
|
+
# attachment = ActionText::Attachment.from_attachable(attachable)
|
18
|
+
# attachment.to_html # => "<action-text-attachment sgid=\"BAh7CEk..."
|
6
19
|
class Attachment
|
7
20
|
include Attachments::TrixConversion, Attachments::Minification, Attachments::Caching
|
8
21
|
|
9
22
|
mattr_accessor :tag_name, default: "action-text-attachment"
|
10
23
|
|
11
|
-
ATTRIBUTES = %w( sgid content-type url href filename filesize width height previewable presentation caption )
|
24
|
+
ATTRIBUTES = %w( sgid content-type url href filename filesize width height previewable presentation caption content )
|
12
25
|
|
13
26
|
class << self
|
14
27
|
def fragment_by_canonicalizing_attachments(content)
|
@@ -69,6 +82,31 @@ module ActionText
|
|
69
82
|
self.class.from_attributes(full_attributes, attachable)
|
70
83
|
end
|
71
84
|
|
85
|
+
# Converts the attachment to plain text.
|
86
|
+
#
|
87
|
+
# attachable = ActiveStorage::Blob.find_by filename: "racecar.jpg"
|
88
|
+
# attachment = ActionText::Attachment.from_attachable(attachable)
|
89
|
+
# attachment.to_plain_text # => "[racecar.jpg]"
|
90
|
+
#
|
91
|
+
# Use the `caption` when set:
|
92
|
+
#
|
93
|
+
# attachment = ActionText::Attachment.from_attachable(attachable, caption: "Vroom vroom")
|
94
|
+
# attachment.to_plain_text # => "[Vroom vroom]"
|
95
|
+
#
|
96
|
+
# The presentation can be overridden by implementing the
|
97
|
+
# `attachable_plain_text_representation` method:
|
98
|
+
#
|
99
|
+
# class Person < ApplicationRecord
|
100
|
+
# include ActionText::Attachable
|
101
|
+
#
|
102
|
+
# def attachable_plain_text_representation
|
103
|
+
# "[#{name}]"
|
104
|
+
# end
|
105
|
+
# end
|
106
|
+
#
|
107
|
+
# attachable = Person.create! name: "Javan"
|
108
|
+
# attachment = ActionText::Attachment.from_attachable(attachable)
|
109
|
+
# attachment.to_plain_text # => "[Javan]"
|
72
110
|
def to_plain_text
|
73
111
|
if respond_to?(:attachable_plain_text_representation)
|
74
112
|
attachable_plain_text_representation(caption)
|
@@ -77,6 +115,11 @@ module ActionText
|
|
77
115
|
end
|
78
116
|
end
|
79
117
|
|
118
|
+
# Converts the attachment to HTML.
|
119
|
+
#
|
120
|
+
# attachable = Person.create! name: "Javan"
|
121
|
+
# attachment = ActionText::Attachment.from_attachable(attachable)
|
122
|
+
# attachment.to_html # => "<action-text-attachment sgid=\"BAh7CEk...
|
80
123
|
def to_html
|
81
124
|
HtmlConversion.node_to_html(node)
|
82
125
|
end
|
@@ -91,7 +134,7 @@ module ActionText
|
|
91
134
|
|
92
135
|
private
|
93
136
|
def node_attributes
|
94
|
-
@node_attributes ||= ATTRIBUTES.
|
137
|
+
@node_attributes ||= ATTRIBUTES.to_h { |name| [ name.underscore, node[name] ] }.compact
|
95
138
|
end
|
96
139
|
|
97
140
|
def attachable_attributes
|
@@ -1,36 +1,53 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
# :markup: markdown
|
4
|
+
|
3
5
|
module ActionText
|
4
6
|
module Attribute
|
5
7
|
extend ActiveSupport::Concern
|
6
8
|
|
7
9
|
class_methods do
|
8
|
-
# Provides access to a dependent RichText model that holds the body and
|
9
|
-
#
|
10
|
+
# Provides access to a dependent RichText model that holds the body and
|
11
|
+
# attachments for a single named rich text attribute. This dependent attribute
|
12
|
+
# is lazily instantiated and will be auto-saved when it's been changed. Example:
|
13
|
+
#
|
14
|
+
# class Message < ActiveRecord::Base
|
15
|
+
# has_rich_text :content
|
16
|
+
# end
|
17
|
+
#
|
18
|
+
# message = Message.create!(content: "<h1>Funny times!</h1>")
|
19
|
+
# message.content? #=> true
|
20
|
+
# message.content.to_s # => "<h1>Funny times!</h1>"
|
21
|
+
# message.content.to_plain_text # => "Funny times!"
|
22
|
+
#
|
23
|
+
# The dependent RichText model will also automatically process attachments links
|
24
|
+
# as sent via the Trix-powered editor. These attachments are associated with the
|
25
|
+
# RichText model using Active Storage.
|
10
26
|
#
|
11
|
-
#
|
12
|
-
#
|
13
|
-
# end
|
27
|
+
# If you wish to preload the dependent RichText model, you can use the named
|
28
|
+
# scope:
|
14
29
|
#
|
15
|
-
#
|
16
|
-
#
|
17
|
-
#
|
18
|
-
# message.content.to_plain_text # => "Funny times!"
|
30
|
+
# Message.all.with_rich_text_content # Avoids N+1 queries when you just want the body, not the attachments.
|
31
|
+
# Message.all.with_rich_text_content_and_embeds # Avoids N+1 queries when you just want the body and attachments.
|
32
|
+
# Message.all.with_all_rich_text # Loads all rich text associations.
|
19
33
|
#
|
20
|
-
#
|
21
|
-
# These attachments are associated with the RichText model using Active Storage.
|
34
|
+
# #### Options
|
22
35
|
#
|
23
|
-
#
|
36
|
+
# * `:encrypted` - Pass true to encrypt the rich text attribute. The
|
37
|
+
# encryption will be non-deterministic. See
|
38
|
+
# `ActiveRecord::Encryption::EncryptableRecord.encrypts`. Default: false.
|
24
39
|
#
|
25
|
-
#
|
26
|
-
#
|
27
|
-
#
|
40
|
+
# * `:strict_loading` - Pass true to force strict loading. When omitted,
|
41
|
+
# `strict_loading:` will be set to the value of the
|
42
|
+
# `strict_loading_by_default` class attribute (false by default).
|
28
43
|
#
|
29
|
-
# === Options
|
30
44
|
#
|
31
|
-
#
|
32
|
-
#
|
33
|
-
|
45
|
+
# Note: Action Text relies on polymorphic associations, which in turn store
|
46
|
+
# class names in the database. When renaming classes that use `has_rich_text`,
|
47
|
+
# make sure to also update the class names in the
|
48
|
+
# `action_text_rich_texts.record_type` polymorphic type column of the
|
49
|
+
# corresponding rows.
|
50
|
+
def has_rich_text(name, encrypted: false, strict_loading: strict_loading_by_default)
|
34
51
|
class_eval <<-CODE, __FILE__, __LINE__ + 1
|
35
52
|
def #{name}
|
36
53
|
rich_text_#{name} || build_rich_text_#{name}
|
@@ -47,7 +64,8 @@ module ActionText
|
|
47
64
|
|
48
65
|
rich_text_class_name = encrypted ? "ActionText::EncryptedRichText" : "ActionText::RichText"
|
49
66
|
has_one :"rich_text_#{name}", -> { where(name: name) },
|
50
|
-
class_name: rich_text_class_name, as: :record, inverse_of: :record, autosave: true, dependent: :destroy
|
67
|
+
class_name: rich_text_class_name, as: :record, inverse_of: :record, autosave: true, dependent: :destroy,
|
68
|
+
strict_loading: strict_loading
|
51
69
|
|
52
70
|
scope :"with_rich_text_#{name}", -> { includes("rich_text_#{name}") }
|
53
71
|
scope :"with_rich_text_#{name}_and_embeds", -> { includes("rich_text_#{name}": { embeds_attachments: :blob }) }
|
@@ -55,9 +73,10 @@ module ActionText
|
|
55
73
|
|
56
74
|
# Eager load all dependent RichText models in bulk.
|
57
75
|
def with_all_rich_text
|
58
|
-
|
76
|
+
includes(rich_text_association_names)
|
59
77
|
end
|
60
78
|
|
79
|
+
# Returns the names of all rich text associations.
|
61
80
|
def rich_text_association_names
|
62
81
|
reflect_on_all_associations(:has_one).collect(&:name).select { |n| n.start_with?("rich_text_") }
|
63
82
|
end
|
data/lib/action_text/content.rb
CHANGED
@@ -1,11 +1,32 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
# :markup: markdown
|
4
|
+
|
3
5
|
module ActionText
|
6
|
+
# # Action Text Content
|
7
|
+
#
|
8
|
+
# The `ActionText::Content` class wraps an HTML fragment to add support for
|
9
|
+
# parsing, rendering and serialization. It can be used to extract links and
|
10
|
+
# attachments, convert the fragment to plain text, or serialize the fragment to
|
11
|
+
# the database.
|
12
|
+
#
|
13
|
+
# The ActionText::RichText record serializes the `body` attribute as
|
14
|
+
# `ActionText::Content`.
|
15
|
+
#
|
16
|
+
# class Message < ActiveRecord::Base
|
17
|
+
# has_rich_text :content
|
18
|
+
# end
|
19
|
+
#
|
20
|
+
# message = Message.create!(content: "<h1>Funny times!</h1>")
|
21
|
+
# body = message.content.body # => #<ActionText::Content "<div class=\"trix-conte...">
|
22
|
+
# body.to_s # => "<h1>Funny times!</h1>"
|
23
|
+
# body.to_plain_text # => "Funny times!"
|
4
24
|
class Content
|
5
|
-
include Rendering, Serialization
|
25
|
+
include Rendering, Serialization, ContentHelper
|
6
26
|
|
7
27
|
attr_reader :fragment
|
8
28
|
|
29
|
+
delegate :deconstruct, to: :fragment
|
9
30
|
delegate :blank?, :empty?, :html_safe, :present?, to: :to_html # Delegating to to_html to avoid including the layout
|
10
31
|
|
11
32
|
class << self
|
@@ -26,10 +47,21 @@ module ActionText
|
|
26
47
|
end
|
27
48
|
end
|
28
49
|
|
50
|
+
# Extracts links from the HTML fragment:
|
51
|
+
#
|
52
|
+
# html = '<a href="http://example.com/">Example</a>'
|
53
|
+
# content = ActionText::Content.new(html)
|
54
|
+
# content.links # => ["http://example.com/"]
|
29
55
|
def links
|
30
56
|
@links ||= fragment.find_all("a[href]").map { |a| a["href"] }.uniq
|
31
57
|
end
|
32
58
|
|
59
|
+
# Extracts +ActionText::Attachment+s from the HTML fragment:
|
60
|
+
#
|
61
|
+
# attachable = ActiveStorage::Blob.first
|
62
|
+
# html = %Q(<action-text-attachment sgid="#{attachable.attachable_sgid}" caption="Captioned"></action-text-attachment>)
|
63
|
+
# content = ActionText::Content.new(html)
|
64
|
+
# content.attachments # => [#<ActionText::Attachment attachable=#<ActiveStorage::Blob...
|
33
65
|
def attachments
|
34
66
|
@attachments ||= attachment_nodes.map do |node|
|
35
67
|
attachment_for_node(node)
|
@@ -46,6 +78,12 @@ module ActionText
|
|
46
78
|
@gallery_attachments ||= attachment_galleries.flat_map(&:attachments)
|
47
79
|
end
|
48
80
|
|
81
|
+
# Extracts +ActionText::Attachable+s from the HTML fragment:
|
82
|
+
#
|
83
|
+
# attachable = ActiveStorage::Blob.first
|
84
|
+
# html = %Q(<action-text-attachment sgid="#{attachable.attachable_sgid}" caption="Captioned"></action-text-attachment>)
|
85
|
+
# content = ActionText::Content.new(html)
|
86
|
+
# content.attachables # => [attachable]
|
49
87
|
def attachables
|
50
88
|
@attachables ||= attachment_nodes.map do |node|
|
51
89
|
ActionText::Attachable.from_node(node)
|
@@ -59,6 +97,10 @@ module ActionText
|
|
59
97
|
|
60
98
|
def render_attachments(**options, &block)
|
61
99
|
content = fragment.replace(ActionText::Attachment.tag_name) do |node|
|
100
|
+
if node.key?("content")
|
101
|
+
sanitized_content = sanitize_content_attachment(node.remove_attribute("content").to_s)
|
102
|
+
node["content"] = sanitized_content if sanitized_content.present?
|
103
|
+
end
|
62
104
|
block.call(attachment_for_node(node, **options))
|
63
105
|
end
|
64
106
|
self.class.new(content, canonicalize: false)
|
@@ -71,6 +113,20 @@ module ActionText
|
|
71
113
|
self.class.new(content, canonicalize: false)
|
72
114
|
end
|
73
115
|
|
116
|
+
# Returns a plain-text version of the markup contained by the content, with tags
|
117
|
+
# removed but HTML entities encoded.
|
118
|
+
#
|
119
|
+
# content = ActionText::Content.new("<h1>Funny times!</h1>")
|
120
|
+
# content.to_plain_text # => "Funny times!"
|
121
|
+
#
|
122
|
+
# content = ActionText::Content.new("<div onclick='action()'>safe<script>unsafe</script></div>")
|
123
|
+
# content.to_plain_text # => "safeunsafe"
|
124
|
+
#
|
125
|
+
# NOTE: that the returned string is not HTML safe and should not be rendered in
|
126
|
+
# browsers.
|
127
|
+
#
|
128
|
+
# content = ActionText::Content.new("<script>alert()</script>")
|
129
|
+
# content.to_plain_text # => "<script>alert()</script>"
|
74
130
|
def to_plain_text
|
75
131
|
render_attachments(with_full_attributes: false, &:to_plain_text).fragment.to_plain_text
|
76
132
|
end
|
@@ -91,6 +147,13 @@ module ActionText
|
|
91
147
|
"action_text/contents/content"
|
92
148
|
end
|
93
149
|
|
150
|
+
# Safely transforms Content into an HTML String.
|
151
|
+
#
|
152
|
+
# content = ActionText::Content.new(content: "<h1>Funny times!</h1>")
|
153
|
+
# content.to_s # => "<h1>Funny times!</h1>"
|
154
|
+
#
|
155
|
+
# content = ActionText::Content.new("<div onclick='action()'>safe<script>unsafe</script></div>")
|
156
|
+
# content.to_s # => "<div>safeunsafe</div>"
|
94
157
|
def to_s
|
95
158
|
to_rendered_html_with_layout
|
96
159
|
end
|
@@ -100,11 +163,13 @@ module ActionText
|
|
100
163
|
end
|
101
164
|
|
102
165
|
def inspect
|
103
|
-
"#<#{self.class.name} #{
|
166
|
+
"#<#{self.class.name} #{to_html.truncate(25).inspect}>"
|
104
167
|
end
|
105
168
|
|
106
169
|
def ==(other)
|
107
|
-
if
|
170
|
+
if self.class == other.class
|
171
|
+
to_html == other.to_html
|
172
|
+
elsif other.is_a?(self.class)
|
108
173
|
to_s == other.to_s
|
109
174
|
end
|
110
175
|
end
|
data/lib/action_text/engine.rb
CHANGED
@@ -1,5 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
# :markup: markdown
|
4
|
+
|
3
5
|
require "rails"
|
4
6
|
require "action_controller/railtie"
|
5
7
|
require "active_record/railtie"
|
@@ -19,6 +21,10 @@ module ActionText
|
|
19
21
|
#{root}/app/models
|
20
22
|
)
|
21
23
|
|
24
|
+
initializer "action_text.deprecator", before: :load_environment_config do |app|
|
25
|
+
app.deprecators[:action_text] = ActionText.deprecator
|
26
|
+
end
|
27
|
+
|
22
28
|
initializer "action_text.attribute" do
|
23
29
|
ActiveSupport.on_load(:active_record) do
|
24
30
|
include ActionText::Attribute
|
@@ -28,7 +34,7 @@ module ActionText
|
|
28
34
|
|
29
35
|
initializer "action_text.asset" do
|
30
36
|
if Rails.application.config.respond_to?(:assets)
|
31
|
-
Rails.application.config.assets.precompile += %w( actiontext.js trix.js trix.css )
|
37
|
+
Rails.application.config.assets.precompile += %w( actiontext.js actiontext.esm.js trix.js trix.css )
|
32
38
|
end
|
33
39
|
end
|
34
40
|
|
@@ -51,20 +57,16 @@ module ActionText
|
|
51
57
|
end
|
52
58
|
|
53
59
|
initializer "action_text.helper" do
|
54
|
-
%i[action_controller_base action_mailer].each do |
|
55
|
-
ActiveSupport.on_load(
|
60
|
+
%i[action_controller_base action_mailer].each do |base|
|
61
|
+
ActiveSupport.on_load(base) do
|
56
62
|
helper ActionText::Engine.helpers
|
57
63
|
end
|
58
64
|
end
|
59
65
|
end
|
60
66
|
|
61
67
|
initializer "action_text.renderer" do
|
62
|
-
|
63
|
-
|
64
|
-
end
|
65
|
-
|
66
|
-
%i[action_controller_base action_mailer].each do |abstract_controller|
|
67
|
-
ActiveSupport.on_load(abstract_controller) do
|
68
|
+
%i[action_controller_base action_mailer].each do |base|
|
69
|
+
ActiveSupport.on_load(base) do
|
68
70
|
around_action do |controller, action|
|
69
71
|
ActionText::Content.with_renderer(controller, &action)
|
70
72
|
end
|
@@ -82,5 +84,11 @@ module ActionText
|
|
82
84
|
initializer "action_text.configure" do |app|
|
83
85
|
ActionText::Attachment.tag_name = app.config.action_text.attachment_tag_name
|
84
86
|
end
|
87
|
+
|
88
|
+
config.after_initialize do |app|
|
89
|
+
if klass = app.config.action_text.sanitizer_vendor
|
90
|
+
ActionText::ContentHelper.sanitizer = klass.safe_list_sanitizer.new
|
91
|
+
end
|
92
|
+
end
|
85
93
|
end
|
86
94
|
end
|