From 4e459fb582df0fbf74e94a31bc60bac4201e8b02 Mon Sep 17 00:00:00 2001 From: Ben Silverman Date: Thu, 5 Sep 2024 10:31:23 -0400 Subject: [PATCH] Use templates to render rich text pages (#512) --- app/helpers/export_helper.rb | 19 +++++ app/models/concerns/exportable.rb | 112 ++++++++---------------------- app/views/exports/page.html.erb | 50 +++++++++++++ 3 files changed, 99 insertions(+), 82 deletions(-) create mode 100644 app/helpers/export_helper.rb create mode 100644 app/views/exports/page.html.erb diff --git a/app/helpers/export_helper.rb b/app/helpers/export_helper.rb new file mode 100644 index 00000000..6925ae65 --- /dev/null +++ b/app/helpers/export_helper.rb @@ -0,0 +1,19 @@ +module ExportHelper + def self.sanitize_filename(filename) + filename.gsub(/[\x00\/\\:\*\?\"<>\|]/, "_").strip + end + def self.get_path(document_id, current_depth) + # get a relative URL to a document by id, taking into account the current location + document = Document.find(document_id) + filename = self.sanitize_filename(document.title).parameterize + path_segments = ["#{filename}.html"] + while document[:parent_type] != "Project" + # back out from the target document until we hit the project root + document = document.parent + path_segments.unshift(self.sanitize_filename(document[:title])) + end + to_project_root = current_depth > 0 ? Array.new(current_depth, "..").join("/") + "/" : "" + path = to_project_root + path_segments.join("/") + return path + end +end diff --git a/app/models/concerns/exportable.rb b/app/models/concerns/exportable.rb index cf80fe12..09a3fd93 100644 --- a/app/models/concerns/exportable.rb +++ b/app/models/concerns/exportable.rb @@ -13,31 +13,12 @@ module Exportable extend ActiveSupport::Concern - def sanitize_filename(filename) - filename.gsub(/[\x00\/\\:\*\?\"<>\|]/, "_").strip - end - def recursively_deflate_folder(folder, zipfile_path, zipfile, depth) zipfile.mkdir(zipfile_path) subdir = folder.contents_children self.write_zip_entries(subdir, zipfile_path, zipfile, depth + 1) end - def get_path(document_id, current_depth) - # get a relative URL to a document by id, taking into account the current location - document = Document.find(document_id) - filename = sanitize_filename(document.title).parameterize - path_segments = ["#{filename}.html"] - while document[:parent_type] != "Project" - # back out from the target document until we hit the project root - document = document.parent - path_segments.unshift(sanitize_filename(document[:title])) - end - to_project_root = current_depth > 0 ? Array.new(current_depth, "..").join("/") + "/" : "" - path = to_project_root + path_segments.join("/") - return path - end - def html_filename(path) path = Pathname.new(path) dir, base = path.split @@ -49,7 +30,7 @@ def html_filename(path) def write_zip_entries(entries, path, zipfile, depth) entries.each do |child| - name = sanitize_filename(child.title) + name = ExportHelper.sanitize_filename(child.title) zipfile_path = path == '' ? name : File.join(path, name) if child.instance_of? DocumentFolder # create folder AND index entry for folder item @@ -66,68 +47,35 @@ def write_zip_entries(entries, path, zipfile, depth) # create an html file for all non-folder items zipfile_path = html_filename(zipfile_path) - zipfile.get_output_stream(zipfile_path) { |html_outfile| - html_outfile.write('') - html_outfile.write("") - if child.document_kind == "canvas" - # images page - if child[:content] && child[:content]["tileSources"] - for img_url in child.image_urls - html_outfile.write("#{img_url}
") - end - else - for img_url in child.image_urls - html_outfile.write("
") - end - end - elsif child.document_kind == "text" - # text page - # TODO: handle multicolumn layout - # render text documents from prosemirror/storyblok to html - renderer = Storyblok::Richtext::HtmlRenderer.new - renderer.add_mark(Storyblok::Richtext::Marks::Color) - renderer.add_mark(Storyblok::Richtext::Marks::Em) - renderer.add_mark(Storyblok::Richtext::Marks::FontFamily) - renderer.add_mark(Storyblok::Richtext::Marks::FontSize) - renderer.add_mark(Storyblok::Richtext::Marks::Highlight) - renderer.add_mark(Storyblok::Richtext::Marks::Strikethrough) - renderer.add_mark(Storyblok::Richtext::Marks::TextStyle) - renderer.add_node(Storyblok::Richtext::Nodes::Image) - renderer.add_node(Storyblok::Richtext::Nodes::Paragraph) + if child.document_kind == "text" + # text page + # TODO: handle multicolumn layout + # render text documents from prosemirror/storyblok to html + renderer = Storyblok::Richtext::HtmlRenderer.new + renderer.add_mark(Storyblok::Richtext::Marks::Color) + renderer.add_mark(Storyblok::Richtext::Marks::Em) + renderer.add_mark(Storyblok::Richtext::Marks::FontFamily) + renderer.add_mark(Storyblok::Richtext::Marks::FontSize) + renderer.add_mark(Storyblok::Richtext::Marks::Highlight) + renderer.add_mark(Storyblok::Richtext::Marks::Strikethrough) + renderer.add_mark(Storyblok::Richtext::Marks::TextStyle) + renderer.add_node(Storyblok::Richtext::Nodes::Image) + renderer.add_node(Storyblok::Richtext::Nodes::Paragraph) - html = renderer.render(child[:content]) - html_outfile.write(html) - else - # TODO: determine if there are any of these - html_outfile.write(child.document_kind) - end + content = renderer.render(child[:content]) + end - # add highlights to footer - if child.highlight_map.present? - styles = ["li:target { border: 1px solid blue; }"] - html_outfile.write("") - html_outfile.write("") - end - html_outfile.write("") + html = render_template_to_string( + Rails.root.join("app", "views", "exports", "page.html.erb"), + { + highlights: child.highlight_map, + images: child.image_urls, + content: (content || "").html_safe, + depth: depth, + }, + ) + zipfile.get_output_stream(zipfile_path) { |html_outfile| + html_outfile.write(html) } if ["DocumentFolder", "Project"].include? child.parent_type # only add direct descendants of project or folder to index @@ -148,10 +96,10 @@ def export @index = { children: [], title: self.title } @index_cursor = @index[:children] - # t = Tempfile.new("#{sanitize_filename(self.title)}.zip") + # t = Tempfile.new("#{ExportHelper.sanitize_filename(self.title)}.zip") # path = t.path - path = "/Users/ben/Downloads/#{sanitize_filename(self.title)}-#{Time.now.to_s}.zip" + path = "/Users/ben/Downloads/#{ExportHelper.sanitize_filename(self.title)}-#{Time.now.to_s}.zip" Zip::File.open(path, ::Zip::File::CREATE) do |zipfile| self.write_zip_entries(self.contents_children, '', zipfile, depth=0) diff --git a/app/views/exports/page.html.erb b/app/views/exports/page.html.erb new file mode 100644 index 00000000..23d90dd0 --- /dev/null +++ b/app/views/exports/page.html.erb @@ -0,0 +1,50 @@ + + +
+ <% @images.each do |image| %> + <%= image %> +
+ <% end %> + <%= @content %> +
+ <% if @highlights %> + + <% end %> +