summaryrefslogtreecommitdiff
path: root/lib/banzai/object_renderer.rb
diff options
context:
space:
mode:
Diffstat (limited to 'lib/banzai/object_renderer.rb')
-rw-r--r--lib/banzai/object_renderer.rb85
1 files changed, 85 insertions, 0 deletions
diff --git a/lib/banzai/object_renderer.rb b/lib/banzai/object_renderer.rb
new file mode 100644
index 00000000000..f0e4f28bf12
--- /dev/null
+++ b/lib/banzai/object_renderer.rb
@@ -0,0 +1,85 @@
+module Banzai
+ # Class for rendering multiple objects (e.g. Note instances) in a single pass.
+ #
+ # Rendered Markdown is stored in an attribute in every object based on the
+ # name of the attribute containing the Markdown. For example, when the
+ # attribute `note` is rendered the HTML is stored in `note_html`.
+ class ObjectRenderer
+ attr_reader :project, :user
+
+ # Make sure to set the appropriate pipeline in the `raw_context` attribute
+ # (e.g. `:note` for Note instances).
+ #
+ # project - A Project to use for rendering and redacting Markdown.
+ # user - The user viewing the Markdown/HTML documents, if any.
+ # context - A Hash containing extra attributes to use in the rendering
+ # pipeline.
+ def initialize(project, user = nil, raw_context = {})
+ @project = project
+ @user = user
+ @raw_context = raw_context
+ end
+
+ # Renders and redacts an Array of objects.
+ #
+ # objects - The objects to render
+ # attribute - The attribute containing the raw Markdown to render.
+ #
+ # Returns the same input objects.
+ def render(objects, attribute)
+ documents = render_objects(objects, attribute)
+ redacted = redact_documents(documents)
+
+ objects.each_with_index do |object, index|
+ object.__send__("#{attribute}_html=", redacted.fetch(index))
+ end
+
+ objects
+ end
+
+ # Renders the attribute of every given object.
+ def render_objects(objects, attribute)
+ objects.map do |object|
+ render_attribute(object, attribute)
+ end
+ end
+
+ # Redacts the list of documents.
+ #
+ # Returns an Array containing the redacted documents.
+ def redact_documents(documents)
+ redactor = Redactor.new(project, user)
+
+ redactor.redact(documents).map do |document|
+ document.to_html.html_safe
+ end
+ end
+
+ # Returns a Banzai context for the given object and attribute.
+ def context_for(object, attribute)
+ context = base_context.merge(cache_key: [object, attribute])
+
+ if object.respond_to?(:author)
+ context[:author] = object.author
+ end
+
+ context
+ end
+
+ # Renders the attribute of an object.
+ #
+ # Returns a `Nokogiri::HTML::Document`.
+ def render_attribute(object, attribute)
+ context = context_for(object, attribute)
+
+ string = object.__send__(attribute)
+ html = Banzai.render(string, context)
+
+ Banzai::Pipeline[:relative_link].to_document(html, context)
+ end
+
+ def base_context
+ @base_context ||= @raw_context.merge(current_user: user, project: project)
+ end
+ end
+end