diff options
author | Javan Makhmali <javan@javan.us> | 2018-10-03 12:46:05 -0400 |
---|---|---|
committer | Javan Makhmali <javan@javan.us> | 2018-10-03 12:46:05 -0400 |
commit | 7a993324342d5542dcb40902eed097f7eaac3f1b (patch) | |
tree | cd40e095c25d0c8e21d3d83f54371b5b71d61131 /lib/action_text | |
parent | 60fe928d2f536249d297e92f31d9c126d3035df5 (diff) | |
download | rails-7a993324342d5542dcb40902eed097f7eaac3f1b.tar.gz rails-7a993324342d5542dcb40902eed097f7eaac3f1b.tar.bz2 rails-7a993324342d5542dcb40902eed097f7eaac3f1b.zip |
WIP: Image gallery support
Diffstat (limited to 'lib/action_text')
-rw-r--r-- | lib/action_text/attachment_gallery.rb | 62 | ||||
-rw-r--r-- | lib/action_text/content.rb | 65 |
2 files changed, 120 insertions, 7 deletions
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 |