Class: Inkcite::Renderer::Table

Inherits:
TableBase show all
Defined in:
lib/inkcite/renderer/table.rb

Constant Summary collapse

TR_TRANSITION =

Name of the attribute allowing a transition attribute to be placed on the automatically-added <tr> element.

:'tr-transition'
CLOSE_TABLE =
'/table'

Constants inherited from Responsive

Responsive::BUTTON, Responsive::DROP, Responsive::FILL, Responsive::FLUID, Responsive::FLUID_DROP, Responsive::FLUID_STACK, Responsive::HIDE, Responsive::IMAGE, Responsive::MOBILE_BACKGROUND, Responsive::MOBILE_BACKGROUND_COLOR, Responsive::MOBILE_BACKGROUND_IMAGE, Responsive::MOBILE_BACKGROUND_POSITION, Responsive::MOBILE_BACKGROUND_REPEAT, Responsive::MOBILE_BACKGROUND_SIZE, Responsive::MOBILE_BGCOLOR, Responsive::MOBILE_PADDING, Responsive::MOBILE_SRC, Responsive::SHOW, Responsive::SHOW_INLINE, Responsive::SWITCH, Responsive::SWITCH_UP, Responsive::TOGGLE

Constants inherited from Base

Base::BACKGROUND_COLOR, Base::BACKGROUND_GRADIENT, Base::BACKGROUND_IMAGE, Base::BACKGROUND_POSITION, Base::BACKGROUND_REPEAT, Base::BACKGROUND_SIZE, Base::BORDER_BOTTOM, Base::BORDER_COLLAPSE, Base::BORDER_LEFT, Base::BORDER_RADIUS, Base::BORDER_RIGHT, Base::BORDER_SPACING, Base::BORDER_TOP, Base::BOX_SHADOW, Base::DIMENSIONS, Base::DIRECTIONS, Base::FONT_FAMILY, Base::FONT_SIZE, Base::FONT_WEIGHT, Base::LETTER_SPACING, Base::LINE_HEIGHT, Base::LINK_COLOR, Base::MARGIN, Base::MARGIN_BOTTOM, Base::MARGIN_LEFT, Base::MARGIN_RIGHT, Base::MARGIN_TOP, Base::MAX_WIDTH, Base::NONE, Base::PADDING_X, Base::PADDING_Y, Base::POUND_SIGN, Base::TEXT_ALIGN, Base::TEXT_DECORATION, Base::TEXT_SHADOW, Base::TEXT_SHADOW_BLUR, Base::TEXT_SHADOW_OFFSET, Base::VERTICAL_ALIGN, Base::WEBKIT_ANIMATION, Base::WHITE_SPACE, Base::ZERO_WIDTH_NON_BREAKING_SPACE, Base::ZERO_WIDTH_SPACE

Instance Method Summary collapse

Methods inherited from Responsive

presets

Instance Method Details

#render(tag, opt, ctx) ⇒ Object



9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
# File 'lib/inkcite/renderer/table.rb', line 9

def render tag, opt, ctx

  html = ''

  # We're either going to be pushing a newly opened table onto this stack
  # or we're popping the open opts off of it.
  tag_stack = ctx.tag_stack(:table)

  if tag == CLOSE_TABLE

    # Pop the opts used when the table was originally opened.  Then grab the
    # mobile attribute. If this is a fluid table, we'll need to do close some
    # of the additional tags injected when it was opened.
    open_opt = tag_stack.pop
    open_mobile = open_opt[:mobile]

    # If the table was declared as Fluid-Hybrid Drop, then there are some additional
    # elements that need to be closed before the regular row-table closure that
    # the Table helper normally produces.
    if is_fluid_drop?(open_mobile)

      # Close the interior conditional table for Outlook that contains the floating blocks.
      html << if_mso('</tr></table>')

      # Close what @campaignmonitor calls the "secret weapon" cell that typically aligns
      # the text horizontally and vertically aligns the floating elements.
      html << '</td>' # Styled
    end

    # Normal Inkcite Helper close HTML.
    html << '</tr></table>'

    # Close the conditional table for Output that contains the entire fluid layout.
    html << if_mso('</td></tr></table>') if is_fluid?(open_mobile)

  else

    # Push this table onto the stack which will make it's declaration
    # available to its child TDs.
    tag_stack << opt

    table = Element.new(tag, { :border => 0, :cellspacing => 0 })

    # Grab the responsive mobile klass that is assigned to this table, if any.
    mobile = opt[:mobile]

    # Check if fluid-drop has been specified.  This will force a lot more HTML to
    # be produced for this table and its child TDs.
    is_fluid_drop = is_fluid_drop?(mobile)

    # Inherit base cell attributes - border, background color and image, etc.
    mix_all table, opt, ctx
    mix_margins table, opt, ctx
    mix_text_shadow table, opt, ctx

    # Conveniently accept padding (easier to type and consistent with CSS) or
    # cellpadding which must always be declared.
    #
    # If Fluid-Drop is enabled, padding is always zero at this top-level table
    # and will be applied in the TD renderer when it creates a new table to
    # wrap itself in.
    table[:cellpadding] = is_fluid_drop ? 0 : get_padding(opt)

    # Conveniently accept both float and align to mean the same thing.
    align = opt[:align] || opt[:float]
    table[:align] = align unless align.blank?

    mix_border_radius table, opt, ctx

    border_collapse = opt[BORDER_COLLAPSE]
    table.style[BORDER_COLLAPSE] = border_collapse unless border_collapse.blank?

    # For both fluid and fluid-drop share certain setup which is performed here.
    if is_fluid?(mobile)

      # Width must always be specified on fluid tables, like it is for images.
      # Warn the designer if a width has not been supplied in pixels.
      width = opt[:width].to_i
      ctx.error("Width is a required attribute when '#{mobile}' is applied to a {table}", opt) unless width > 0

      # Fluid table method courtesy of @campaignmonitor - assign the max-width in
      # pixels and set the normal width to 100%.
      # https://www.campaignmonitor.com/blog/email-marketing/2014/07/creating-a-centred-responsive-design-without-media-queries/
      table.style[MAX_WIDTH] = px(width)
      table[:width] = '100%'

      # Outlook (and Lotus Notes, if you can believe it) doesn't support max-width
      # so we need to wrap the entire fluid table in a conditional table that
      # ensures layout displays within the actual maximum pixels width.
      html << if_mso(Element.new('table', {
                  :align => opt[:align], :border => 0, :cellspacing => 0, :cellpadding => 0, :width => opt[:width].to_i
              }) + '<tr><td>')

    elsif mobile == DROP || mobile == SWITCH

      # When a Table is configured to have it's cells DROP then it
      # actually needs to FILL on mobile and it's child Tds will
      # be DROP'd.  Override the local mobile klass so the child Tds
      # see the parent as DROP.
      mobile = FILL

    end

    mix_responsive table, opt, ctx, mobile

    html << table.to_s

    tr = Element.new('tr')

    # Check for a row transition which is necessary to facilitate
    # cross-column animation - e.g. tr-transition="all .5s cubic-bezier(0.075, 0.82, 0.165, 1)"
    tr_transition = opt[TR_TRANSITION]
    tr.style[:transition] = tr_transition unless none?(tr_transition)

    html << tr.to_s

    if is_fluid_drop

      # Fluid-Drop tables need a default alignment specified which is inherited
      # by the child TD elements if not otherwise specified.
      #
      # 11/8/2015: For reasons I don't understand, if the table is not valigned
      # middle by default, then we lose the ability to valign-middle individual
      # TD children.  So, if we force 'middle' here, then the TDs can override
      # with 'top' or 'bottom' alignment when desired.
      valign = opt[:valign] ||= 'middle'

      # According to @campaignmonitor this is the secret weapon of Fluid-Hyrbid
      # drop which wraps the floating elements and centers them appropriately.
      # https://www.campaignmonitor.com/blog/email-marketing/2014/07/creating-a-centred-responsive-design-without-media-queries/
      #
      # The zero-size font addresses a rendering problem in Outlook:
      # https://css-tricks.com/fighting-the-space-between-inline-block-elements/
      fluid_td = Element.new('td', :style => { TEXT_ALIGN => :center, VERTICAL_ALIGN => opt[:valign], FONT_SIZE => 0 })

      # If fluid-stack is specified, then reverse the order of the columns to make
      # the right-most orient to the top.
      # http://webdesign.tutsplus.com/tutorials/creating-a-future-proof-responsive-email-without-media-queries--cms-23919
      fluid_td[:dir] = :rtl if mobile == FLUID_STACK

      html << fluid_td.to_s

      # Lastly, Outlook needs yet another conditional table that will be used
      # to contain the floating blocks.  The TD elements are generated by
      # each of the columns within this Fluid-Drop table.
      html << if_mso(Element.new('table', :width => '100%', :align => :center, :cellpadding => 0, :cellspacing => 0, :border => 0) + '<tr>')

    end

  end

  html
end