-
Notifications
You must be signed in to change notification settings - Fork 18
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #521 from performant-software/feature/511-basic-ex…
- Loading branch information
Showing
28 changed files
with
1,161 additions
and
51 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
module DownloadHelper | ||
def self.download_to_file(uri) | ||
begin | ||
stream = URI.open(uri, :read_timeout => 10) | ||
return stream if stream.respond_to?(:path) # Already file-like | ||
|
||
# Workaround when open(uri) doesn't return File | ||
Tempfile.new.tap do |file| | ||
file.binmode | ||
IO.copy_stream(stream, file) | ||
stream.close | ||
file.rewind | ||
end | ||
rescue Net::ReadTimeout | ||
return 'failed' | ||
end | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,132 @@ | ||
module ExportHelper | ||
def self.sanitize_filename(filename) | ||
filename.gsub(/[\x00\/\\:\*\?\"<>\|]/, "_").strip | ||
end | ||
|
||
def self.get_path(link, current_depth) | ||
document_id = link[:document_id] | ||
highlight_uid = link[:highlight_uid] | ||
# get a relative URL to a document by id, taking into account the current location | ||
begin | ||
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]).parameterize) | ||
end | ||
to_project_root = current_depth > 0 ? Array.new(current_depth, "..").join("/") + "/" : "" | ||
path = to_project_root + path_segments.join("/") | ||
if highlight_uid.present? | ||
# append #highlight_uid to url if present in order to target the highlight | ||
path = "#{path}#highlight-#{highlight_uid}" | ||
end | ||
return path | ||
rescue ActiveRecord::RecordNotFound | ||
return "#" | ||
end | ||
end | ||
|
||
def self.get_svg_styles(obj) | ||
# convert fabric object style properties to css | ||
styles = [ | ||
"stroke: #{obj['stroke']};", | ||
"fill: #{obj['fill'] || 'transparent'};", | ||
"stroke-width: 3px;", | ||
"stroke-linecap: #{obj['strokeLineCap'] || 'butt'};", | ||
"stroke-dashoffset: #{obj['strokeDashOffset'] || '0'};", | ||
"stroke-linejoin: #{obj['strokeLineJoin'] || 'miter'};", | ||
"stroke-miterlimit: #{obj['strokeMiterLimit'] || '4'};", | ||
"opacity: #{obj['opacity'] || '1'};", | ||
"visibility: #{obj['visible'] ? 'visible' : 'hidden'};", | ||
] | ||
styles.push("stroke-dasharray: #{obj['strokeDashArray']};") if obj['strokeDashArray'] | ||
styles.join(" ") | ||
end | ||
|
||
def self.get_svg_path(paths) | ||
# convert fabric object path property to svg path | ||
path = '' | ||
paths.each_with_index do |ls, i| | ||
path += " " unless i == 0 | ||
if ls[0] == "C" | ||
# C x1 y1, x2 y2, x y | ||
path += "#{ls[0]} #{ls[1]} #{ls[2]}, #{ls[3]} #{ls[4]}, #{ls[5]} #{ls[6]}" | ||
elsif ls[0] == "S" or ls[0] == "Q" | ||
# S x2 y2, x y || Q x1 y1, x y | ||
path += "#{ls[0]} #{ls[1]} #{ls[2]}, #{ls[3]} #{ls[4]}" | ||
else | ||
# M x y || L x y || T x y, etc | ||
path += ls.join(" ") | ||
end | ||
end | ||
path | ||
end | ||
|
||
def self.fabric_to_svg(highlights) | ||
# convert image annotation highlights (fabric objects) to svgs | ||
svgs = [] | ||
self.order_highlights(highlights, "canvas", nil).each do |uid, hl| | ||
svg_hash = JSON.parse(hl[:target]) | ||
elm = "#{svg_hash['type']}" | ||
if svg_hash["path"] | ||
# path | ||
elm += " d=\"#{self.get_svg_path(svg_hash['path'])}\"" | ||
elsif svg_hash["points"] | ||
# polyline | ||
elm += ' points="' | ||
elm += svg_hash["points"].map { |pt| "#{pt['x']},#{pt['y']}" }.join(" ") | ||
elm += '"' | ||
elsif svg_hash["type"] == "circle" | ||
# circle | ||
elm += " r=\"#{svg_hash['radius']}\"" | ||
cx = svg_hash["left"] | ||
cy = svg_hash["top"] | ||
if svg_hash["originX"] == "left" | ||
cx += svg_hash["radius"] | ||
cy += svg_hash["radius"] | ||
end | ||
elm += " cx=\"#{cx}\" cy=\"#{cy}\"" | ||
elsif svg_hash["type"] == "rect" | ||
# rect | ||
elm += " x=\"#{svg_hash['left']}\" y=\"#{svg_hash['top']}\"" | ||
elm += " width=\"#{svg_hash['width']}\" height=\"#{svg_hash['height']}\"" | ||
end | ||
# common styles | ||
elm += " style=\"#{self.get_svg_styles(svg_hash)}\"" | ||
svg_elm = "<#{elm} vector-effect=\"non-scaling-stroke\" />" | ||
# add link to highlight in footer | ||
svgs.push("<a id=\"highlight-#{uid}\" href=\"##{uid}\">#{svg_elm}</a>") | ||
end | ||
return svgs | ||
end | ||
|
||
def self.order_highlights(highlights, document_kind, content_html) | ||
if !content_html.present? and document_kind == "text" | ||
highlights | ||
elsif content_html.present? | ||
# text type document: order by position in text | ||
highlights.sort_by { |uid, hl| content_html.index(uid) || Float::INFINITY } | ||
elsif document_kind == "canvas" | ||
# canvas type document: order highlights by position on page (top to bottom, LTR) | ||
highlights.sort_by { |uid, hl| | ||
drawing = JSON.parse(hl[:target]) | ||
# divide page vertically into 50px blocks; consider all within 50px range to have equal y | ||
y = (drawing["top"] / 50).floor() | ||
# then sort by x, unmodified | ||
x = drawing["left"] | ||
[y, x] | ||
} | ||
end | ||
end | ||
|
||
def self.get_link_label(link) | ||
label = link[:document_title] | ||
if link[:excerpt] and link[:excerpt].length > 0 | ||
label = "<span>#{link[:title] ? link[:title] : link[:excerpt]}</span>" | ||
label += " in <em>#{link[:document_title]}</em>" | ||
end | ||
label | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.