aboutsummaryrefslogtreecommitdiffstats
path: root/lib
diff options
context:
space:
mode:
authorJavan Makhmali <javan@javan.us>2018-10-03 12:46:05 -0400
committerJavan Makhmali <javan@javan.us>2018-10-03 12:46:05 -0400
commit7a993324342d5542dcb40902eed097f7eaac3f1b (patch)
treecd40e095c25d0c8e21d3d83f54371b5b71d61131 /lib
parent60fe928d2f536249d297e92f31d9c126d3035df5 (diff)
downloadrails-7a993324342d5542dcb40902eed097f7eaac3f1b.tar.gz
rails-7a993324342d5542dcb40902eed097f7eaac3f1b.tar.bz2
rails-7a993324342d5542dcb40902eed097f7eaac3f1b.zip
WIP: Image gallery support
Diffstat (limited to 'lib')
-rw-r--r--lib/action_text.rb1
-rw-r--r--lib/action_text/attachment_gallery.rb62
-rw-r--r--lib/action_text/content.rb65
3 files changed, 121 insertions, 7 deletions
diff --git a/lib/action_text.rb b/lib/action_text.rb
index 0559dce2ba..4182cacb8a 100644
--- a/lib/action_text.rb
+++ b/lib/action_text.rb
@@ -8,6 +8,7 @@ module ActionText
mattr_accessor(:renderer)
autoload :Attachable
+ autoload :AttachmentGallery
autoload :Attachment
autoload :Attribute
autoload :Content
diff --git a/lib/action_text/attachment_gallery.rb b/lib/action_text/attachment_gallery.rb
new file mode 100644
index 0000000000..6f690551e6
--- /dev/null
+++ b/lib/action_text/attachment_gallery.rb
@@ -0,0 +1,62 @@
+module ActionText
+ class AttachmentGallery
+ include ActiveModel::Model
+
+ class << self
+ def fragment_by_canonicalizing_attachment_galleries(content)
+ fragment_by_replacing_attachment_gallery_nodes(content) do |node|
+ "<#{TAG_NAME}>#{node.inner_html}</#{TAG_NAME}>"
+ end
+ end
+
+ def fragment_by_replacing_attachment_gallery_nodes(content)
+ Fragment.wrap(content).update do |source|
+ find_attachment_gallery_nodes(source).each do |node|
+ node.replace(yield(node).to_s)
+ end
+ end
+ end
+
+ def find_attachment_gallery_nodes(content)
+ Fragment.wrap(content).find_all(SELECTOR).select do |node|
+ node.children.all? do |child|
+ if child.text?
+ child.text =~ /\A(\n|\ )*\z/
+ else
+ child.matches? ATTACHMENT_SELECTOR
+ end
+ end
+ end
+ end
+
+ def from_node(node)
+ new(node)
+ end
+ end
+
+ attr_reader :node
+
+ def initialize(node)
+ @node = node
+ end
+
+ def attachments
+ @attachments ||= node.css(ATTACHMENT_SELECTOR).map do |node|
+ ActionText::Attachment.from_node(node).with_full_attributes
+ end
+ end
+
+ def size
+ attachments.size
+ end
+
+ def inspect
+ "#<#{self.class.name} size=#{size.inspect}>"
+ end
+
+ private
+ TAG_NAME = "div"
+ ATTACHMENT_SELECTOR = "#{ActionText::Attachment::SELECTOR}[presentation=gallery]"
+ SELECTOR = "#{TAG_NAME}:has(#{ATTACHMENT_SELECTOR} + #{ATTACHMENT_SELECTOR})"
+ end
+end
diff --git a/lib/action_text/content.rb b/lib/action_text/content.rb
index 22b52cff1c..71d9e98657 100644
--- a/lib/action_text/content.rb
+++ b/lib/action_text/content.rb
@@ -6,8 +6,22 @@ module ActionText
delegate :blank?, :empty?, :html_safe, :present?, to: :to_html # Delegating to to_html to avoid including the layout
- def initialize(content = nil)
- @fragment = ActionText::Attachment.fragment_by_canonicalizing_attachments(content)
+ class << self
+ def fragment_by_canonicalizing_content(content)
+ fragment = ActionText::Attachment.fragment_by_canonicalizing_attachments(content)
+ fragment = ActionText::AttachmentGallery.fragment_by_canonicalizing_attachment_galleries(fragment)
+ fragment
+ end
+ end
+
+ def initialize(content = nil, options = {})
+ options.with_defaults! canonicalize: true
+
+ if options[:canonicalize]
+ @fragment = self.class.fragment_by_canonicalizing_content(content)
+ else
+ @fragment = ActionText::Fragment.wrap(content)
+ end
end
def links
@@ -20,6 +34,16 @@ module ActionText
end
end
+ def attachment_galleries
+ @attachment_galleries ||= attachment_gallery_nodes.map do |node|
+ attachment_gallery_for_node(node)
+ end
+ end
+
+ def gallery_attachments
+ @gallery_attachments ||= attachment_galleries.flat_map(&:attachments)
+ end
+
def attachables
@attachables ||= attachment_nodes.map do |node|
ActionText::Attachable.from_node(node)
@@ -32,13 +56,21 @@ module ActionText
end
def render_attachments(**options, &block)
- fragment.replace(ActionText::Attachment::SELECTOR) do |node|
+ content = fragment.replace(ActionText::Attachment::SELECTOR) do |node|
block.call(attachment_for_node(node, **options))
end
+ self.class.new(content, canonicalize: false)
+ end
+
+ def render_attachment_galleries(**options, &block)
+ content = ActionText::AttachmentGallery.fragment_by_replacing_attachment_gallery_nodes(fragment) do |node|
+ block.call(attachment_gallery_for_node(node, **options))
+ end
+ self.class.new(content, canonicalize: false)
end
def to_plain_text
- render_attachments(with_full_attributes: false, &:to_plain_text).to_plain_text
+ render_attachments(with_full_attributes: false, &:to_plain_text).fragment.to_plain_text
end
def to_trix_html
@@ -46,19 +78,30 @@ module ActionText
end
def to_html
+ fragment.to_html
+ end
+
+ def to_rendered_html
render_attachments do |attachment|
attachment.node.tap do |node|
node.inner_html = ActionText.renderer.render(attachment)
end
+ end.render_attachment_galleries do |attachment_gallery|
+ ActionText.renderer.render(layout: attachment_gallery, object: attachment_gallery, formats: "html") do
+ attachment_gallery.attachments.map do |attachment|
+ attachment.node.inner_html = ActionText.renderer.render(attachment)
+ attachment.to_html
+ end.join("").html_safe
+ end
end.to_html
end
- def to_html_with_layout
- ActionText.renderer.render(partial: "action_text/content/layout", locals: { document: to_html })
+ def to_rendered_html_with_layout
+ ActionText.renderer.render(partial: "action_text/content/layout", locals: { document: to_rendered_html })
end
def to_s
- to_html_with_layout
+ to_rendered_html_with_layout
end
def as_json(*)
@@ -80,9 +123,17 @@ module ActionText
@attachment_nodes ||= fragment.find_all(ActionText::Attachment::SELECTOR)
end
+ def attachment_gallery_nodes
+ @attachment_gallery_nodes ||= ActionText::AttachmentGallery.find_attachment_gallery_nodes(fragment)
+ end
+
def attachment_for_node(node, with_full_attributes: true)
attachment = ActionText::Attachment.from_node(node)
with_full_attributes ? attachment.with_full_attributes : attachment
end
+
+ def attachment_gallery_for_node(node, **options)
+ ActionText::AttachmentGallery.from_node(node)
+ end
end
end