actiontext 6.1.3.1 → 7.0.0.alpha1
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.
Potentially problematic release.
This version of actiontext might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/CHANGELOG.md +19 -74
- data/MIT-LICENSE +1 -1
- data/README.md +4 -0
- data/app/assets/javascripts/actiontext.js +880 -0
- data/app/assets/javascripts/trix.js +5278 -0
- data/app/assets/stylesheets/trix.css +375 -0
- data/app/helpers/action_text/content_helper.rb +17 -3
- data/app/helpers/action_text/tag_helper.rb +5 -7
- data/app/models/action_text/encrypted_rich_text.rb +9 -0
- data/app/models/action_text/record.rb +1 -1
- data/app/models/action_text/rich_text.rb +4 -0
- data/app/views/action_text/contents/_content.html.erb +1 -0
- data/app/views/layouts/action_text/contents/_content.html.erb +3 -0
- data/db/migrate/20180528164100_create_action_text_tables.rb +14 -2
- data/lib/action_text/attachable.rb +4 -0
- data/lib/action_text/attachment.rb +4 -4
- data/lib/action_text/attachment_gallery.rb +14 -9
- data/lib/action_text/attachments/caching.rb +1 -1
- data/lib/action_text/attachments/minification.rb +1 -1
- data/lib/action_text/attachments/trix_conversion.rb +1 -1
- data/lib/action_text/attribute.rb +18 -2
- data/lib/action_text/content.rb +7 -3
- data/lib/action_text/encryption.rb +38 -0
- data/lib/action_text/engine.rb +18 -0
- data/lib/action_text/fixture_set.rb +49 -0
- data/lib/action_text/gem_version.rb +4 -4
- data/lib/action_text/rendering.rb +1 -1
- data/lib/action_text/trix_attachment.rb +3 -3
- data/lib/action_text.rb +1 -0
- data/lib/generators/action_text/install/install_generator.rb +28 -35
- data/lib/generators/action_text/install/templates/actiontext.css +35 -0
- data/package.json +13 -3
- metadata +25 -19
- data/app/views/action_text/content/_layout.html.erb +0 -3
- data/lib/generators/action_text/install/templates/actiontext.scss +0 -36
@@ -0,0 +1 @@
|
|
1
|
+
<%= render_action_text_content(content) %>
|
@@ -1,13 +1,25 @@
|
|
1
1
|
class CreateActionTextTables < ActiveRecord::Migration[6.0]
|
2
2
|
def change
|
3
|
-
|
3
|
+
# Use Active Record's configured type for primary and foreign keys
|
4
|
+
primary_key_type, foreign_key_type = primary_and_foreign_key_types
|
5
|
+
|
6
|
+
create_table :action_text_rich_texts, id: primary_key_type do |t|
|
4
7
|
t.string :name, null: false
|
5
8
|
t.text :body, size: :long
|
6
|
-
t.references :record, null: false, polymorphic: true, index: false
|
9
|
+
t.references :record, null: false, polymorphic: true, index: false, type: foreign_key_type
|
7
10
|
|
8
11
|
t.timestamps
|
9
12
|
|
10
13
|
t.index [ :record_type, :record_id, :name ], name: "index_action_text_rich_texts_uniqueness", unique: true
|
11
14
|
end
|
12
15
|
end
|
16
|
+
|
17
|
+
private
|
18
|
+
def primary_and_foreign_key_types
|
19
|
+
config = Rails.configuration.generators
|
20
|
+
setting = config.options[config.orm][:primary_key_type]
|
21
|
+
primary_key_type = setting || :primary_key
|
22
|
+
foreign_key_type = setting || :bigint
|
23
|
+
[primary_key_type, foreign_key_type]
|
24
|
+
end
|
13
25
|
end
|
@@ -6,8 +6,8 @@ module ActionText
|
|
6
6
|
class Attachment
|
7
7
|
include Attachments::TrixConversion, Attachments::Minification, Attachments::Caching
|
8
8
|
|
9
|
-
|
10
|
-
|
9
|
+
mattr_accessor :tag_name, default: "action-text-attachment"
|
10
|
+
|
11
11
|
ATTRIBUTES = %w( sgid content-type url href filename filesize width height previewable presentation caption )
|
12
12
|
|
13
13
|
class << self
|
@@ -20,7 +20,7 @@ module ActionText
|
|
20
20
|
end
|
21
21
|
|
22
22
|
def from_attachables(attachables)
|
23
|
-
Array(attachables).
|
23
|
+
Array(attachables).filter_map { |attachable| from_attachable(attachable) }
|
24
24
|
end
|
25
25
|
|
26
26
|
def from_attachable(attachable, attributes = {})
|
@@ -38,7 +38,7 @@ module ActionText
|
|
38
38
|
private
|
39
39
|
def node_from_attributes(attributes)
|
40
40
|
if attributes = process_attributes(attributes).presence
|
41
|
-
ActionText::HtmlConversion.create_element(
|
41
|
+
ActionText::HtmlConversion.create_element(tag_name, attributes)
|
42
42
|
end
|
43
43
|
end
|
44
44
|
|
@@ -4,6 +4,9 @@ module ActionText
|
|
4
4
|
class AttachmentGallery
|
5
5
|
include ActiveModel::Model
|
6
6
|
|
7
|
+
TAG_NAME = "div"
|
8
|
+
private_constant :TAG_NAME
|
9
|
+
|
7
10
|
class << self
|
8
11
|
def fragment_by_canonicalizing_attachment_galleries(content)
|
9
12
|
fragment_by_replacing_attachment_gallery_nodes(content) do |node|
|
@@ -20,12 +23,12 @@ module ActionText
|
|
20
23
|
end
|
21
24
|
|
22
25
|
def find_attachment_gallery_nodes(content)
|
23
|
-
Fragment.wrap(content).find_all(
|
26
|
+
Fragment.wrap(content).find_all(selector).select do |node|
|
24
27
|
node.children.all? do |child|
|
25
28
|
if child.text?
|
26
29
|
/\A(\n|\ )*\z/.match?(child.text)
|
27
30
|
else
|
28
|
-
child.matches?
|
31
|
+
child.matches? attachment_selector
|
29
32
|
end
|
30
33
|
end
|
31
34
|
end
|
@@ -34,6 +37,14 @@ module ActionText
|
|
34
37
|
def from_node(node)
|
35
38
|
new(node)
|
36
39
|
end
|
40
|
+
|
41
|
+
def attachment_selector
|
42
|
+
"#{ActionText::Attachment.tag_name}[presentation=gallery]"
|
43
|
+
end
|
44
|
+
|
45
|
+
def selector
|
46
|
+
"#{TAG_NAME}:has(#{attachment_selector} + #{attachment_selector})"
|
47
|
+
end
|
37
48
|
end
|
38
49
|
|
39
50
|
attr_reader :node
|
@@ -43,7 +54,7 @@ module ActionText
|
|
43
54
|
end
|
44
55
|
|
45
56
|
def attachments
|
46
|
-
@attachments ||= node.css(
|
57
|
+
@attachments ||= node.css(ActionText::AttachmentGallery.attachment_selector).map do |node|
|
47
58
|
ActionText::Attachment.from_node(node).with_full_attributes
|
48
59
|
end
|
49
60
|
end
|
@@ -55,11 +66,5 @@ module ActionText
|
|
55
66
|
def inspect
|
56
67
|
"#<#{self.class.name} size=#{size.inspect}>"
|
57
68
|
end
|
58
|
-
|
59
|
-
TAG_NAME = "div"
|
60
|
-
ATTACHMENT_SELECTOR = "#{ActionText::Attachment::SELECTOR}[presentation=gallery]"
|
61
|
-
SELECTOR = "#{TAG_NAME}:has(#{ATTACHMENT_SELECTOR} + #{ATTACHMENT_SELECTOR})"
|
62
|
-
|
63
|
-
private_constant :TAG_NAME, :ATTACHMENT_SELECTOR, :SELECTOR
|
64
69
|
end
|
65
70
|
end
|
@@ -7,7 +7,7 @@ module ActionText
|
|
7
7
|
|
8
8
|
class_methods do
|
9
9
|
def fragment_by_minifying_attachments(content)
|
10
|
-
Fragment.wrap(content).replace(ActionText::Attachment
|
10
|
+
Fragment.wrap(content).replace(ActionText::Attachment.tag_name) do |node|
|
11
11
|
node.tap { |n| n.inner_html = "" }
|
12
12
|
end
|
13
13
|
end
|
@@ -28,7 +28,7 @@ module ActionText
|
|
28
28
|
private
|
29
29
|
def trix_attachment_content
|
30
30
|
if partial_path = attachable.try(:to_trix_content_attachment_partial_path)
|
31
|
-
ActionText::Content.render(partial: partial_path, object: self, as: model_name.element)
|
31
|
+
ActionText::Content.render(partial: partial_path, formats: :html, object: self, as: model_name.element)
|
32
32
|
end
|
33
33
|
end
|
34
34
|
end
|
@@ -24,7 +24,13 @@ module ActionText
|
|
24
24
|
#
|
25
25
|
# Message.all.with_rich_text_content # Avoids N+1 queries when you just want the body, not the attachments.
|
26
26
|
# Message.all.with_rich_text_content_and_embeds # Avoids N+1 queries when you just want the body and attachments.
|
27
|
-
|
27
|
+
# Message.all.with_all_rich_text # Loads all rich text associations.
|
28
|
+
#
|
29
|
+
# === Options
|
30
|
+
#
|
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)
|
28
34
|
class_eval <<-CODE, __FILE__, __LINE__ + 1
|
29
35
|
def #{name}
|
30
36
|
rich_text_#{name} || build_rich_text_#{name}
|
@@ -39,12 +45,22 @@ module ActionText
|
|
39
45
|
end
|
40
46
|
CODE
|
41
47
|
|
48
|
+
rich_text_class_name = encrypted ? "ActionText::EncryptedRichText" : "ActionText::RichText"
|
42
49
|
has_one :"rich_text_#{name}", -> { where(name: name) },
|
43
|
-
class_name:
|
50
|
+
class_name: rich_text_class_name, as: :record, inverse_of: :record, autosave: true, dependent: :destroy
|
44
51
|
|
45
52
|
scope :"with_rich_text_#{name}", -> { includes("rich_text_#{name}") }
|
46
53
|
scope :"with_rich_text_#{name}_and_embeds", -> { includes("rich_text_#{name}": { embeds_attachments: :blob }) }
|
47
54
|
end
|
55
|
+
|
56
|
+
# Eager load all dependent RichText models in bulk.
|
57
|
+
def with_all_rich_text
|
58
|
+
eager_load(rich_text_association_names)
|
59
|
+
end
|
60
|
+
|
61
|
+
def rich_text_association_names
|
62
|
+
reflect_on_all_associations(:has_one).collect(&:name).select { |n| n.start_with?("rich_text_") }
|
63
|
+
end
|
48
64
|
end
|
49
65
|
end
|
50
66
|
end
|
data/lib/action_text/content.rb
CHANGED
@@ -58,7 +58,7 @@ module ActionText
|
|
58
58
|
end
|
59
59
|
|
60
60
|
def render_attachments(**options, &block)
|
61
|
-
content = fragment.replace(ActionText::Attachment
|
61
|
+
content = fragment.replace(ActionText::Attachment.tag_name) do |node|
|
62
62
|
block.call(attachment_for_node(node, **options))
|
63
63
|
end
|
64
64
|
self.class.new(content, canonicalize: false)
|
@@ -84,7 +84,11 @@ module ActionText
|
|
84
84
|
end
|
85
85
|
|
86
86
|
def to_rendered_html_with_layout
|
87
|
-
render
|
87
|
+
render layout: "action_text/contents/content", partial: to_partial_path, formats: :html, locals: { content: self }
|
88
|
+
end
|
89
|
+
|
90
|
+
def to_partial_path
|
91
|
+
"action_text/contents/content"
|
88
92
|
end
|
89
93
|
|
90
94
|
def to_s
|
@@ -107,7 +111,7 @@ module ActionText
|
|
107
111
|
|
108
112
|
private
|
109
113
|
def attachment_nodes
|
110
|
-
@attachment_nodes ||= fragment.find_all(ActionText::Attachment
|
114
|
+
@attachment_nodes ||= fragment.find_all(ActionText::Attachment.tag_name)
|
111
115
|
end
|
112
116
|
|
113
117
|
def attachment_gallery_nodes
|
@@ -0,0 +1,38 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module ActionText
|
4
|
+
module Encryption
|
5
|
+
def encrypt
|
6
|
+
transaction do
|
7
|
+
super
|
8
|
+
encrypt_rich_texts if has_encrypted_rich_texts?
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
def decrypt
|
13
|
+
transaction do
|
14
|
+
super
|
15
|
+
decrypt_rich_texts if has_encrypted_rich_texts?
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
private
|
20
|
+
def encrypt_rich_texts
|
21
|
+
encryptable_rich_texts.each(&:encrypt)
|
22
|
+
end
|
23
|
+
|
24
|
+
def decrypt_rich_texts
|
25
|
+
encryptable_rich_texts.each(&:decrypt)
|
26
|
+
end
|
27
|
+
|
28
|
+
def has_encrypted_rich_texts?
|
29
|
+
encryptable_rich_texts.present?
|
30
|
+
end
|
31
|
+
|
32
|
+
def encryptable_rich_texts
|
33
|
+
@encryptable_rich_texts ||= self.class.rich_text_association_names
|
34
|
+
.filter_map { |attribute_name| send(attribute_name) }
|
35
|
+
.find_all { |record| record.is_a?(ActionText::EncryptedRichText) }
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
data/lib/action_text/engine.rb
CHANGED
@@ -12,9 +12,23 @@ module ActionText
|
|
12
12
|
isolate_namespace ActionText
|
13
13
|
config.eager_load_namespaces << ActionText
|
14
14
|
|
15
|
+
config.action_text = ActiveSupport::OrderedOptions.new
|
16
|
+
config.action_text.attachment_tag_name = "action-text-attachment"
|
17
|
+
config.autoload_once_paths = %W(
|
18
|
+
#{root}/app/helpers
|
19
|
+
#{root}/app/models
|
20
|
+
)
|
21
|
+
|
15
22
|
initializer "action_text.attribute" do
|
16
23
|
ActiveSupport.on_load(:active_record) do
|
17
24
|
include ActionText::Attribute
|
25
|
+
prepend ActionText::Encryption
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
initializer "action_text.asset" do
|
30
|
+
if Rails.application.config.respond_to?(:assets)
|
31
|
+
Rails.application.config.assets.precompile += %w( actiontext.js trix.js trix.css )
|
18
32
|
end
|
19
33
|
end
|
20
34
|
|
@@ -64,5 +78,9 @@ module ActionText
|
|
64
78
|
include ActionText::SystemTestHelper
|
65
79
|
end
|
66
80
|
end
|
81
|
+
|
82
|
+
initializer "action_text.configure" do |app|
|
83
|
+
ActionText::Attachment.tag_name = app.config.action_text.attachment_tag_name
|
84
|
+
end
|
67
85
|
end
|
68
86
|
end
|
@@ -1,7 +1,56 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
module ActionText
|
4
|
+
# Fixtures are a way of organizing data that you want to test against; in
|
5
|
+
# short, sample data.
|
6
|
+
#
|
7
|
+
# To learn more about fixtures, read the
|
8
|
+
# {ActiveRecord::FixtureSet}[rdoc-ref:ActiveRecord::FixtureSet] documentation.
|
9
|
+
#
|
10
|
+
# === YAML
|
11
|
+
#
|
12
|
+
# Like other Active Record-backed models, ActionText::RichText records inherit
|
13
|
+
# from ActiveRecord::Base instances and therefore can be populated by
|
14
|
+
# fixtures.
|
15
|
+
#
|
16
|
+
# Consider a hypothetical <tt>Article</tt> model class, its related fixture
|
17
|
+
# data, as well as fixture data for related ActionText::RichText records:
|
18
|
+
#
|
19
|
+
# # app/models/article.rb
|
20
|
+
# class Article < ApplicationRecord
|
21
|
+
# has_rich_text :content
|
22
|
+
# end
|
23
|
+
#
|
24
|
+
# # tests/fixtures/articles.yml
|
25
|
+
# first:
|
26
|
+
# title: An Article
|
27
|
+
#
|
28
|
+
# # tests/fixtures/action_text/rich_texts.yml
|
29
|
+
# first_content:
|
30
|
+
# record: first (Article)
|
31
|
+
# name: content
|
32
|
+
# body: <div>Hello, world.</div>
|
33
|
+
#
|
34
|
+
# When processed, Active Record will insert database records for each fixture
|
35
|
+
# entry and will ensure the Action Text relationship is intact.
|
4
36
|
class FixtureSet
|
37
|
+
# Fixtures support Action Text attachments as part of their <tt>body</tt>
|
38
|
+
# HTML.
|
39
|
+
#
|
40
|
+
# === Examples
|
41
|
+
#
|
42
|
+
# For example, consider a second <tt>Article</tt> record that mentions the
|
43
|
+
# first as part of its <tt>content</tt> HTML:
|
44
|
+
#
|
45
|
+
# # tests/fixtures/articles.yml
|
46
|
+
# second:
|
47
|
+
# title: Another Article
|
48
|
+
#
|
49
|
+
# # tests/fixtures/action_text/rich_texts.yml
|
50
|
+
# second_content:
|
51
|
+
# record: second (Article)
|
52
|
+
# name: content
|
53
|
+
# body: <div>Hello, <%= ActionText::FixtureSet.attachment("articles", :first) %></div>
|
5
54
|
def self.attachment(fixture_set_name, label, column_type: :integer)
|
6
55
|
signed_global_id = ActiveRecord::FixtureSet.signed_global_id fixture_set_name, label,
|
7
56
|
column_type: column_type, for: ActionText::Attachable::LOCATOR_NAME
|
@@ -9,9 +9,9 @@ module ActionText
|
|
9
9
|
ATTRIBUTES = %w( sgid contentType url href filename filesize width height previewable content ) + COMPOSED_ATTRIBUTES
|
10
10
|
ATTRIBUTE_TYPES = {
|
11
11
|
"previewable" => ->(value) { value.to_s == "true" },
|
12
|
-
"filesize" => ->(value) { Integer(value.to_s)
|
13
|
-
"width" => ->(value) { Integer(value.to_s
|
14
|
-
"height" => ->(value) { Integer(value.to_s
|
12
|
+
"filesize" => ->(value) { Integer(value.to_s, exception: false) || value },
|
13
|
+
"width" => ->(value) { Integer(value.to_s, exception: false) },
|
14
|
+
"height" => ->(value) { Integer(value.to_s, exception: false) },
|
15
15
|
:default => ->(value) { value.to_s }
|
16
16
|
}
|
17
17
|
|