class Inkcite::Renderer::Carousel
Interactive image carousel based on FreshInbox's technique freshinbox.com/resources/tools/carousel/
Usage:
{carousel width=450 height=280 href=“…”}
{carousel-img id="..." src="..."} {carousel-img id="..." src="..." href="..."} {carousel-img id="..." src="..."}
{/carousel}
Constants
- DEFAULT_BORDER_COLOR
- DEFAULT_HOVER_COLOR
Public Instance Methods
render(tag, opt, ctx)
click to toggle source
# File lib/inkcite/renderer/carousel.rb, line 37 def render tag, opt, ctx html = [] # Get a reference to the tag stack tag_stack = ctx.tag_stack :carousel # All the rendering heavylifting is done when the closing tag is encountered # meaning we've indexed each of the carousel-img entries between it and the # opening tag. if tag == '/carousel' # Remove the previously opened opts from the tag stack. open_opt = tag_stack.pop # Unique ID of this carousel to uniquely identify the classes uuid = open_opt[:uuid] # Link ID prefix carousel_id = open_opt[:id] # Width of the primary image width = open_opt[:width].to_i height = open_opt[:height].to_i ctx.error('Missing carousel dimensions', { :id => carousel_id, :width => width, :height => height }) if height <= 0 || width <= 0 # Grab the array of frames and count the total number of frames. frames = open_opt[:frames] total_frames = frames.count # This {table} Helper wraps the entire carousel. table = Element.new('table', :width => width, :class => 'crsl', :mobile => :fill) # Determine if a background color for the entire carousel has been specified # using either bgcolor or background-color. If so, pass it on to the table Helper. bgcolor = detect_bgcolor(open_opt) table[:bgcolor] = quote(bgcolor) unless none?(bgcolor) html << table.to_helper td = Element.new('td') mix_font td, open_opt, ctx html << td.to_s html << %q({not-outlook}) html << %q(<input type=radio class="crsl-radio" style="display:none !important;" checked>) html << %q({/not-outlook}) # Div to hold the carousel contents. html << %q({div}) html << %q({not-outlook}) html << Element.new('div', :class => %Q("crsl-wrap crsl-#{uuid}"), :style => { :width => pct(100), :height => px(0), MAX_HEIGHT => px(0), :overflow => :hidden, TEXT_ALIGN => :center }).to_s # Array of hidden radio buttons that manage which thumbnail is selected. total_frames.times do |n| box_index = total_frames - n html << %q(<label>) html << %Q(<input type="radio" name="crsl#{uuid}" class="crsl-radio-#{box_index}" style="display:none !important;"#{' checked' if box_index == 1}>) html << %q(<span>) end total_frames.times do |n| box_index = n + 1 frame_opt = frames[n] frame_id = frame_opt[:id] || "#{carousel_id}-#{box_index}" href = frame_opt[:href] || open_opt[:href] src = frame_opt[:src] caption = frame_opt[:caption] alt = frame_opt[:alt] || caption html << %Q(<div class="crsl-content-#{box_index} crsl-content">) html << %Q({a id="#{frame_id}" href="#{href}"}) unless href.blank? html << %Q({img src="#{src}" width=#{width} height=#{height} alt="#{alt}" max-height=0 mobile="fill"}) html << %q({/a}) unless href.blank? unless caption.blank? caption_div = Element.new('div', :class => 'crsl-caption', :style => { :padding => '5px 0 10px' }) mix_font caption_div, open_opt, ctx html << caption_div.to_s html << caption html << '</div>' end html << %q(</div>) end thumbnail_width = 50 thumnail_height = (thumbnail_width / width) * height.round(0) total_frames.times do |n| box_index = total_frames - n frame_opt = frames[n] src = frame_opt[:src] html << %q(<span class="crsl-thumb" style="display:none;">) html << %Q({img src="#{src}" width=#{width} height=#{height} max-height=0}) html << %q(</span>) html << %q(</span>) html << %q(</label>) end html << %q(</div>) html << %q({/not-outlook}) # Fallback fallback_frame_opt = frames[0] fallback_href = fallback_frame_opt[:href] || open_opt[:href] fallback_src = open_opt[OUTLOOK_SRC] || fallback_frame_opt[:src] html << %q(<div class="fallback"><div class="crsl-content">) html << %Q({a id="#{carousel_id}" href="#{fallback_href}"}{img src="#{fallback_src}" width=#{width} height=#{height} alt="#{fallback_frame_opt[:caption]}" mobile="fill"}{/a}) html << %q(</div></div>) html << '{/div}' html << '</td>' html << '{/table}' styles = [] if uuid == 1 styles << Inkcite::Renderer::Style.new('input', ctx, { :display => :none }) styles << Inkcite::Renderer::Style.new('.crsl-radio:checked + * .crsl-wrap', ctx, { :'height' => 'auto !important', MAX_HEIGHT => 'none !important;', :'line-height' => 0 }) styles << Inkcite::Renderer::Style.new('.crsl-wrap span', ctx, { :'font-size' => 0, :'line-height' => 0 }) styles << Inkcite::Renderer::Style.new('.crsl-radio:checked + * .crsl-wrap .crsl-content', ctx, { :'display' => 'none', MAX_HEIGHT => px(0), :'overflow' => 'hidden' }) styles << Inkcite::Renderer::Style.new('.crsl-wrap .crsl-thumb', ctx, { :cursor => 'pointer', :display => 'inline-block !important', :width => '17.5%', :margin => '1% 0.61%', :border => "2px solid #{DEFAULT_BORDER_COLOR}" }) # hide for thunderbird as it doesn't support checkboxes styles << Inkcite::Renderer::Style.new('.moz-text-html .crsl-thumb', ctx, { :display => 'none !important' }) styles << Inkcite::Renderer::Style.new('.crsl-wrap .crsl-thumb:hover', ctx, { :border => "2px solid #{DEFAULT_HOVER_COLOR}" }) styles << Inkcite::Renderer::Style.new('.crsl-wrap input:checked + span > span', ctx, { BORDER_COLOR => DEFAULT_HOVER_COLOR }) styles << Inkcite::Renderer::Style.new('.crsl-wrap .crsl-thumb img', ctx, { :width => '100%', :height => 'auto' }) styles << Inkcite::Renderer::Style.new('.crsl-wrap img', ctx, { MAX_HEIGHT => 'none !important' }) styles << Inkcite::Renderer::Style.new('.crsl-radio:checked + * .fallback', ctx, { :display => 'none !important', MAX_HEIGHT => px(0), :height => px(0), :overflow => 'hidden' }) end # Configurable border color border_color = open_opt[BORDER_COLOR] unless border_color.blank? border_color = hex(border_color) styles << Inkcite::Renderer::Style.new(".crsl-#{uuid} .crsl-thumb", ctx, { BORDER_COLOR => border_color }) if DEFAULT_BORDER_COLOR != border_color end # Configurable hover color hover_color = open_opt[:'hover-color'] unless hover_color.blank? hover_color = hex(hover_color) if DEFAULT_HOVER_COLOR != hover_color styles << Inkcite::Renderer::Style.new(".crsl-#{uuid} input:checked + span > span", ctx, { BORDER_COLOR => hover_color }) styles << Inkcite::Renderer::Style.new(".crsl-#{uuid} .crsl-thumb:hover", ctx, { BORDER_COLOR => hover_color }) end end frame_checked_style_name = total_frames.times.collect { |n| ".crsl-wrap .crsl-radio-#{n + 1}:checked + span .crsl-content-#{n + 1}" }.join(",\n") styles << Inkcite::Renderer::Style.new(frame_checked_style_name, ctx, { :display => 'block !important', MAX_HEIGHT => 'none !important', :overflow => 'visible !important' }) ctx.styles << styles.join("\n") unless styles.blank? else # Get a unique ID for this carousel opt[:uuid] = uuid = ctx.unique_id :carousel # Confirm that a unique ID prefix has been provided by the designer or # inherit one from the unique count. opt[:id] = "crsl#{uuid}" if opt[:id].blank? # Initialize the array of frames that will be collected and # assembled when this carousel close tag is encountered. opt[:frames] = [] # Push this carousel onto the stack as the parent of the # frames that will be enclosed. tag_stack << opt end html.join("\n") end