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.
Files changed (45) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +43 -124
  3. data/MIT-LICENSE +1 -1
  4. data/README.md +2 -2
  5. data/app/assets/javascripts/actiontext.esm.js +889 -0
  6. data/app/assets/javascripts/actiontext.js +55 -73
  7. data/app/assets/javascripts/trix.js +13612 -5170
  8. data/app/assets/stylesheets/trix.css +67 -30
  9. data/app/helpers/action_text/content_helper.rb +28 -4
  10. data/app/helpers/action_text/tag_helper.rb +44 -30
  11. data/app/models/action_text/encrypted_rich_text.rb +4 -2
  12. data/app/models/action_text/record.rb +2 -0
  13. data/app/models/action_text/rich_text.rb +66 -6
  14. data/app/views/action_text/attachables/_content_attachment.html.erb +3 -0
  15. data/db/migrate/20180528164100_create_action_text_tables.rb +1 -1
  16. data/lib/action_text/attachable.rb +71 -5
  17. data/lib/action_text/attachables/content_attachment.rb +22 -18
  18. data/lib/action_text/attachables/missing_attachable.rb +19 -3
  19. data/lib/action_text/attachables/remote_image.rb +2 -0
  20. data/lib/action_text/attachment.rb +45 -2
  21. data/lib/action_text/attachment_gallery.rb +2 -0
  22. data/lib/action_text/attachments/caching.rb +2 -0
  23. data/lib/action_text/attachments/minification.rb +2 -0
  24. data/lib/action_text/attachments/trix_conversion.rb +2 -0
  25. data/lib/action_text/attribute.rb +40 -21
  26. data/lib/action_text/content.rb +68 -3
  27. data/lib/action_text/deprecator.rb +9 -0
  28. data/lib/action_text/encryption.rb +2 -0
  29. data/lib/action_text/engine.rb +17 -9
  30. data/lib/action_text/fixture_set.rb +35 -33
  31. data/lib/action_text/fragment.rb +8 -3
  32. data/lib/action_text/gem_version.rb +5 -3
  33. data/lib/action_text/html_conversion.rb +3 -1
  34. data/lib/action_text/plain_text_conversion.rb +8 -1
  35. data/lib/action_text/rendering.rb +7 -2
  36. data/lib/action_text/serialization.rb +2 -0
  37. data/lib/action_text/system_test_helper.rb +20 -17
  38. data/lib/action_text/trix_attachment.rb +4 -2
  39. data/lib/action_text/version.rb +3 -1
  40. data/lib/action_text.rb +19 -0
  41. data/lib/generators/action_text/install/install_generator.rb +29 -5
  42. data/lib/generators/action_text/install/templates/actiontext.css +0 -4
  43. data/lib/rails/generators/test_unit/install_generator.rb +2 -0
  44. data/package.json +7 -7
  45. 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
- def as_json(*)
67
- super.merge("attachable_sgid" => persisted? ? attachable_sgid : nil)
68
- end
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
- if node["content-type"]
10
- if matches = node["content-type"].match(/vnd\.rubyonrails\.(.+)\.html/)
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 :name
18
- validates_inclusion_of :name, in: %w( horizontal-rule )
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
- case name
22
- when "horizontal-rule"
23
- " ┄ "
24
- else
25
- " "
26
- end
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
- def to_trix_content_attachment_partial_path
34
- "action_text/attachables/content_attachments/#{name.underscore}"
35
- end
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
- module MissingAttachable
7
+ class MissingAttachable
6
8
  extend ActiveModel::Naming
7
9
 
8
- def self.to_partial_path
9
- "action_text/attachables/missing_attachable"
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,5 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ # :markup: markdown
4
+
3
5
  module ActionText
4
6
  module Attachables
5
7
  class RemoteImage
@@ -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.map { |name| [ name.underscore, node[name] ] }.to_h.compact
137
+ @node_attributes ||= ATTRIBUTES.to_h { |name| [ name.underscore, node[name] ] }.compact
95
138
  end
96
139
 
97
140
  def attachable_attributes
@@ -1,5 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ # :markup: markdown
4
+
3
5
  module ActionText
4
6
  class AttachmentGallery
5
7
  include ActiveModel::Model
@@ -1,5 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ # :markup: markdown
4
+
3
5
  module ActionText
4
6
  module Attachments
5
7
  module Caching
@@ -1,5 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ # :markup: markdown
4
+
3
5
  module ActionText
4
6
  module Attachments
5
7
  module Minification
@@ -1,5 +1,7 @@
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
@@ -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 attachments for a single named rich text attribute.
9
- # This dependent attribute is lazily instantiated and will be auto-saved when it's been changed. Example:
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
- # class Message < ActiveRecord::Base
12
- # has_rich_text :content
13
- # end
27
+ # If you wish to preload the dependent RichText model, you can use the named
28
+ # scope:
14
29
  #
15
- # message = Message.create!(content: "<h1>Funny times!</h1>")
16
- # message.content? #=> true
17
- # message.content.to_s # => "<h1>Funny times!</h1>"
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
- # The dependent RichText model will also automatically process attachments links as sent via the Trix-powered editor.
21
- # These attachments are associated with the RichText model using Active Storage.
34
+ # #### Options
22
35
  #
23
- # If you wish to preload the dependent RichText model, you can use the named scope:
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
- # Message.all.with_rich_text_content # Avoids N+1 queries when you just want the body, not the attachments.
26
- # Message.all.with_rich_text_content_and_embeds # Avoids N+1 queries when you just want the body and attachments.
27
- # Message.all.with_all_rich_text # Loads all rich text associations.
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
- # * <tt>:encrypted</tt> - Pass true to encrypt the rich text attribute. The encryption will be non-deterministic. See
32
- # +ActiveRecord::Encryption::EncryptableRecord.encrypts+. Default: false.
33
- def has_rich_text(name, encrypted: false)
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
- eager_load(rich_text_association_names)
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
@@ -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("&lt;script&gt;alert()&lt;/script&gt;")
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} #{to_s.truncate(25).inspect}>"
166
+ "#<#{self.class.name} #{to_html.truncate(25).inspect}>"
104
167
  end
105
168
 
106
169
  def ==(other)
107
- if other.is_a?(self.class)
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
@@ -0,0 +1,9 @@
1
+ # frozen_string_literal: true
2
+
3
+ # :markup: markdown
4
+
5
+ module ActionText
6
+ def self.deprecator # :nodoc:
7
+ @deprecator ||= ActiveSupport::Deprecation.new
8
+ end
9
+ end
@@ -1,5 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ # :markup: markdown
4
+
3
5
  module ActionText
4
6
  module Encryption
5
7
  def encrypt
@@ -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 |abstract_controller|
55
- ActiveSupport.on_load(abstract_controller) do
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
- ActiveSupport.on_load(:action_text_content) do
63
- self.default_renderer = Class.new(ActionController::Base).renderer
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