Skip to content

Commit

Permalink
resolves #453 overhaul images support (#472)
Browse files Browse the repository at this point in the history
  • Loading branch information
ggrossetie authored May 10, 2023
1 parent 19cfd09 commit 5f86229
Show file tree
Hide file tree
Showing 10 changed files with 1,575 additions and 928 deletions.
2 changes: 0 additions & 2 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -28,5 +28,3 @@ build/
test/doctest/source-coderay.html
# - pygments is unsupported on JRuby
test/doctest/source-pygments.html
# - contains invalid content
test/doctest/with-docinfo-shared.html
27 changes: 27 additions & 0 deletions examples/images/sample.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
15 changes: 15 additions & 0 deletions examples/svg-images-docinfo-revealjs.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
<style>
svg rect,
svg ellipse,
svg path {
transition: transform 330ms ease-in-out
}
svg rect:hover,
svg ellipse:hover {
transform: translateX(5px);
}

svg path:hover {
transform: translateX(-5px);
}
</style>
41 changes: 41 additions & 0 deletions examples/svg-images.adoc
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
= SVG Images
:imagesdir: images/
:docinfo: private

== Options for SVG images

When the image target is an SVG, the `options` attribute (often abbreviated as `opts`) on the macro accepts one of the following values to control how the SVG is referenced:

* _none_ (default)
* `interactive`
* `inline`

The following slide demonstrates the impact these options have.

== None (default)

Observe that the SVG does not respond to the hover event.

[literal]
image::sample.svg[Static,300]

image::sample.svg[Static,300]

== Interactive

Observe that the color changes when hovering over the SVG.

[literal]
image::sample.svg[Interactive,300,opts=interactive]

image::sample.svg[Interactive,300,opts=interactive]

== Inline

Observe that the color changes when hovering over the SVG.
The SVG also inherits CSS from the document stylesheets.

[literal]
image::sample.svg[Embedded,300,opts=inline]

image::sample.svg[Embedded,300,opts=inline]
1,846 changes: 958 additions & 888 deletions lib/asciidoctor-revealjs/converter.rb

Large diffs are not rendered by default.

106 changes: 105 additions & 1 deletion templates/helpers.rb
Original file line number Diff line number Diff line change
Expand Up @@ -193,6 +193,94 @@ def section_title(sec = self)
end
end

# Retrieves the built-in html5 converter.
#
# Returns the instance of the Asciidoctor::Converter::Html5Converter
# associated with this node.
def html5_converter
converter.instance_variable_get("@delegate_converter")
end

def convert_inline_image(node = self)
target = node.target
if (node.type || 'image') == 'icon'
if (icons = node.document.attr 'icons') == 'font'
i_class_attr_val = %(#{node.attr(:set, 'fa')} fa-#{target})
i_class_attr_val = %(#{i_class_attr_val} fa-#{node.attr 'size'}) if node.attr? 'size'
if node.attr? 'flip'
i_class_attr_val = %(#{i_class_attr_val} fa-flip-#{node.attr 'flip'})
elsif node.attr? 'rotate'
i_class_attr_val = %(#{i_class_attr_val} fa-rotate-#{node.attr 'rotate'})
end
attrs = (node.attr? 'title') ? %( title="#{node.attr 'title'}") : ''
img = %(<i class="#{i_class_attr_val}"#{attrs}></i>)
elsif icons
attrs = (node.attr? 'width') ? %( width="#{node.attr 'width'}") : ''
attrs = %(#{attrs} height="#{node.attr 'height'}") if node.attr? 'height'
attrs = %(#{attrs} title="#{node.attr 'title'}") if node.attr? 'title'
img = %(<img src="#{src = node.icon_uri target}" alt="#{encode_attribute_value node.alt}"#{attrs}>)
else
img = %([#{node.alt}&#93;)
end
else
html_attrs = (node.attr? 'width') ? %( width="#{node.attr 'width'}") : ''
html_attrs = %(#{html_attrs} height="#{node.attr 'height'}") if node.attr? 'height'
html_attrs = %(#{html_attrs} title="#{node.attr 'title'}") if node.attr? 'title'
img, src = img_tag(node, target, html_attrs)
end
img_link(node, src, img)
end

def convert_image(node = self)
# When the stretch class is present, block images will take the most space
# they can take. Setting width and height can override that.
# We pinned the 100% to height to avoid aspect ratio breakage and since
# widescreen monitors are the most popular, chances are that height will
# be the biggest constraint
if node.has_role?('stretch') && !(node.attr?(:width) || node.attr?(:height))
height_value = "100%"
elsif node.attr? 'height'
height_value = node.attr 'height'
else
height_value = nil
end
html_attrs = (node.attr? 'width') ? %( width="#{node.attr 'width'}") : ''
html_attrs = %(#{html_attrs} height="#{height_value}") if height_value
html_attrs = %(#{html_attrs} title="#{node.attr 'title'}") if node.attr? 'title'
html_attrs = %(#{html_attrs} style="background: #{node.attr :background}") if node.attr? 'background'
img, src = img_tag(node, node.attr('target'), html_attrs)
img_link(node, src, img)
end

def img_tag(node = self, target, html_attrs)
if ((node.attr? 'format', 'svg') || (target.include? '.svg')) && node.document.safe < ::Asciidoctor::SafeMode::SECURE
if node.option? 'inline'
img = (html5_converter.read_svg_contents node, target) || %(<span class="alt">#{node.alt}</span>)
elsif node.option? 'interactive'
fallback = (node.attr? 'fallback') ? %(<img src="#{node.image_uri node.attr 'fallback'}" alt="#{encode_attribute_value node.alt}"#{html_attrs}>) : %(<span class="alt">#{node.alt}</span>)
img = %(<object type="image/svg+xml" data="#{src = node.image_uri target}"#{html_attrs}>#{fallback}</object>)
else
img = %(<img src="#{src = node.image_uri target}" alt="#{encode_attribute_value node.alt}"#{html_attrs}>)
end
else
img = %(<img src="#{src = node.image_uri target}" alt="#{encode_attribute_value node.alt}"#{html_attrs}>)
end

[img, src]
end

# Wrap the <img> element in a <a> element if the link attribute is defined
def img_link(node = self, src, content)
if (node.attr? 'link') && ((href_attr_val = node.attr 'link') != 'self' || (href_attr_val = src))
if (link_preview_value = bool_data_attr :link_preview)
data_preview_attr = %( data-preview-link="#{link_preview_value == true ? "" : link_preview_value}")
end
return %(<a class="image" href="#{href_attr_val}"#{(append_link_constraint_attrs node).join}#{data_preview_attr}>#{content}</a>)
end

content
end

def revealjs_dependencies(document, node, revealjsdir)
dependencies = []
dependencies << "{ src: '#{revealjsdir}/plugin/zoom/zoom.js', async: true, callback: function () { Reveal.registerPlugin(RevealZoom) } }" unless (node.attr? 'revealjs_plugin_zoom', 'disabled')
Expand All @@ -201,7 +289,6 @@ def revealjs_dependencies(document, node, revealjsdir)
dependencies.join(",\n ")
end


# Between delimiters (--) is code taken from asciidoctor-bespoke 1.0.0.alpha.1
# Licensed under MIT, Copyright (C) 2015-2016 Dan Allen and the Asciidoctor Project
#--
Expand Down Expand Up @@ -276,6 +363,23 @@ def yield_content key, opts = {}
nil
end

# Copied from asciidoctor/lib/asciidoctor/converter/html5.rb (method is private)
def append_link_constraint_attrs node, attrs = []
rel = 'nofollow' if node.option? 'nofollow'
if (window = node.attributes['window'])
attrs << %( target="#{window}")
attrs << (rel ? %( rel="#{rel} noopener") : ' rel="noopener"') if window == '_blank' || (node.option? 'noopener')
elsif rel
attrs << %( rel="#{rel}")
end
attrs
end

# Copied from asciidoctor/lib/asciidoctor/converter/html5.rb (method is private)
def encode_attribute_value val
(val.include? '"') ? (val.gsub '"', '&quot;') : val
end

# Copied from asciidoctor/lib/asciidoctor/converter/semantic-html5.rb which is not yet shipped
# @todo remove this code when the new converter becomes available in the main gem
def generate_authors node
Expand Down
17 changes: 1 addition & 16 deletions templates/image.html.slim
Original file line number Diff line number Diff line change
@@ -1,21 +1,6 @@
- width = (attr? :width) ? (attr :width) : nil
- height = (attr? :height) ? (attr :height) : nil

/ When the stretch class is present, block images will take the most space
/ they can take. Setting width and height can override that.
/ We pinned the 100% to height to avoid aspect ratio breakage and since
/ widescreen monitors are the most popular, chances are that height will
/ be the biggest constraint
- if (has_role? 'stretch') && !((attr? :width) || (attr? :height))
- height = "100%"

- unless attributes[1] == 'background' || attributes[1] == 'canvas'
- inline_style = [("text-align: #{attr :align}" if attr? :align),("float: #{attr :float}" if attr? :float)].compact.join('; ')
= html_tag('div', { :id => @id, :class => ['imageblock', role, ('fragment' if (option? :step) || (attr? 'step'))], :style => inline_style }.merge(data_attrs(@attributes)))
- if attr? :link
a.image href=(attr :link) target=(attr :window) data-preview-link=(bool_data_attr :link_preview)
img src=image_uri(attr :target) alt=(attr :alt) width=(width) height=(height) style=((attr? :background) ? "background: #{attr :background}" : nil)
- else
img src=image_uri(attr :target) alt=(attr :alt) width=(width) height=(height) style=((attr? :background) ? "background: #{attr :background}" : nil)
= convert_image
- if title?
.title=captioned_title
21 changes: 1 addition & 20 deletions templates/inline_image.html.slim
Original file line number Diff line number Diff line change
@@ -1,21 +1,2 @@
= html_tag('span', { :class => [@type, role, ('fragment' if (option? :step) || (attr? 'step'))], :style => ("float: #{attr :float}" if attr? :float) }.merge(data_attrs(@attributes)))
- if @type == 'icon' && (@document.attr? :icons, 'font')
- style_class = [(attr :set, 'fa'), "fa-#{@target}", ("fa-#{attr :size}" if attr? :size), ("fa-rotate-#{attr :rotate}" if attr? :rotate), ("fa-flip-#{attr :flip}" if attr? :flip)]
- if attr? :link
a.image href=(attr :link) target=(attr :window) data-preview-link=(bool_data_attr :link_preview)
i class=style_class title=(attr :title)
- else
i class=style_class title=(attr :title)
- elsif @type == 'icon' && !(@document.attr? :icons)
- if attr? :link
a.image href=(attr :link) target=(attr :window) data-preview-link=(bool_data_attr :link_preview)
|[#{attr :alt}]
- else
|[#{attr :alt}]
- else
- src = (@type == 'icon' ? (icon_uri @target) : (image_uri @target))
- if attr? :link
a.image href=(attr :link) target=(attr :window) data-preview-link=(bool_data_attr :link_preview)
img src=src alt=(attr :alt) width=(attr :width) height=(attr :height) title=(attr :title)
- else
img src=src alt=(attr :alt) width=(attr :width) height=(attr :height) title=(attr :title)
= convert_inline_image
2 changes: 1 addition & 1 deletion test/doctest/links.html
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ <h2>With iFrame Preview Overlay</h2>
<section id="_image_block_with_a_link">
<h2>Image Block with a Link</h2>
<div class="slide-content">
<div class="imageblock"><a class="image" href="https://montrehack.ca/" target="_blank"><img alt="70s" src="images/70s.jpg"></a></div>
<div class="imageblock"><a class="image" href="https://montrehack.ca/" rel="noopener" target="_blank"><img alt="70s" src="images/70s.jpg"></a></div>
</div>
</section>
<section id="_image_block_with_a_link_with_iframe_preview">
Expand Down
Loading

0 comments on commit 5f86229

Please sign in to comment.