Class: Inkcite::Renderer::Td

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

Constant Summary

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



5
6
7
8
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
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
# File 'lib/inkcite/renderer/td.rb', line 5

def render tag, opt, ctx

  html = ''

  # Tracks the depth of currently open TD elements.
  tag_stack = ctx.tag_stack(:td)

  # Grab the attributes of the parent table so that the TD can inherit
  # specific values like padding, valign, responsiveness, etc.
  table_opt = ctx.parent_opts(:table)
  table_mobile = table_opt[:mobile]

  # Check to see if the parent table was set to fluid-drop which causes
  # the table cells to be wrapped in <div> elements and floated to
  # cause them to display more responsively on Android Mail and Gmail apps.
  #
  # Fluid-Hybrid TD courtesy of @moonstrips and our friends at Campaign Monitor
  # https://www.campaignmonitor.com/blog/email-marketing/2014/07/creating-a-centred-responsive-design-without-media-queries/
  is_fluid_drop = is_fluid_drop?(table_mobile)

  if tag == CLOSE_TD

    # Retrieve the opts that were used to open this TD.
    open_opt = tag_stack.pop

    # Normal HTML produced by the Helper to close the cell.
    html << '</td>'

    # If the td was originally opened with fluid-drop, we need to do a fair
    # bit of cleanup...
    if is_fluid_drop

      # Close the
      html << '</tr></table>'

      # Close the floating, responsive div.
      html << '{/div}'

      # Close the conditional cell
      html << if_mso('</td>')

    end

  else

    # Push this tag onto the stack so that child elements (e.g. links)
    # can have access to its attributes.
    tag_stack << opt

    td = Element.new('td')

    # Check to see if a width has been specified for this element.  The
    # width is critical to Fluid-Hybrid drop.
    width = opt[:width].to_i

    # Check for vertical alignment applied to either the TD or to the
    # parent Table.
    valign = detect(opt[:valign], table_opt[:valign])
    td[:valign] = valign unless valign.blank?

    # It is a best-practice to declare the same padding on all cells in a
    # table.  Check to see if padding was declared on the parent.
    padding = get_padding(table_opt)
    td.style[:padding] = px(padding) if padding > 0

    # Apply the no-wrap attribute if provided.
    td[:nowrap] = true if opt[:nowrap]

    mobile = opt[:mobile]

    # If the table defines mobile-padding, then apply the correct mobile
    # style to this td - and its !important if there is padding on
    # the td already.
    mobile_padding = table_opt[MOBILE_PADDING] || opt[MOBILE_PADDING]
    td.mobile_style[:padding] = px(mobile_padding) unless mobile_padding.blank? || mobile == HIDE

    # Need to handle Fluid-Drop HTML injection here before the rest of the
    # TD is formalized.  Fluid-Drop removes the width attribute of the cell
    # as it is wrapped in a 100%-width table.
    if is_fluid_drop

      # Width must be specified for Fluid-Drop cells.  Vertical-alignment is
      # also important but should have been preset by the Table Helper if it
      # was omitted by the designer.
      ctx.error("Width is a required attribute when #{table_mobile} is specified", opt) unless width > 0
      ctx.error("Vertical alignment should be specified when #{table_mobile} is specified", opt) if valign.blank?

      # Conditional Outlook cell to prevent the 100%-wide table within from
      # stretching beyond the max-width.  Also, valign necessary to get float
      # elements to align properly.
      html << if_mso(Element.new('td', :width => width, :valign => valign))

      # Per @campaignmonitor, the secret to the Fluid-Drop trick is to wrap the
      # floating table in a div with "display: inline-block" - which means that
      # they'll obey the text-align property on the parent cell (text-align affects
      # all inline or inline-block elements in a container).
      # https://www.campaignmonitor.com/blog/email-marketing/2014/07/creating-a-centred-responsive-design-without-media-queries/

      div_mobile = mobile == HIDE ? HIDE : FILL
      html << %Q({div width=#{width} display=inline-block valign=#{valign} mobile="#{div_mobile}"})

      # One last wrapper table within the div.  This 100%-wide table is also where any
      # padding applied to the elements belongs.
      html << Element.new('table', :cellpadding => padding, :cellspacing => 0, :border => 0, :width => '100%').to_s
      html << '<tr>'

      # Remove the width attribute from the TDs declaration.
      opt.delete(:width)

      # The TD nested within the floating div and additional table will inherit center-aligned
      # text which means fluid-drop cells would have a default layout inconsistent with a regular
      # TD - which will typically be left-aligned.  So, unless otherwise specified, presume that
      # the TD should have left-aligned text.
      opt[:align] = 'left' if opt[:align].blank?

      mobile = ''

    end

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

    # Force the td to collapse to a single pixel to support images that
    # are less than 15 pixels.
    opt.merge!({
            :font => NONE,
            :color => NONE,
            FONT_SIZE => 1,
            LINE_HEIGHT => 1
        }) if opt[:flush]

    # Custom handling for text align on TDs rather than Base's mix_text_align
    # because if possible, using align= rather than a style keeps emails
    # smaller.  But for left-aligned text, you gotta use a style because
    # you know, Outlook.
    align = opt[:align]
    unless align.blank?
      td[:align] = align

      # Must use style to reinforce left-align text in certain email clients.
      # All other alignments are accepted naturally.
      td.style[TEXT_ALIGN] = align if align == LEFT

    end

    rowspan = opt[:rowspan].to_i
    td[:rowspan] = rowspan if rowspan > 0

    mix_font td, opt, ctx, table_opt

    # In Fluid-Drop, the font-size is set to zero to overcome Outlook rendering
    # problems so it is important to warn the designer that they need to set
    # it back to a reasonable size on the TD element.
    # TODO [JDH 11/14/2015] Decide if the warning re: font-size should ever
    # be restored based on whether or not users are finding it confusing.

    if mobile.blank?

      # If the cell doesn't define it's own responsive behavior, check to
      # see if it inherits from its parent table.  DROP and SWITCH declared
      # at the table-level descend to their tds.
      pm = table_opt[:mobile]
      mobile = pm if pm == DROP || pm == SWITCH

    end

    mix_responsive td, opt, ctx, mobile

    html << td.to_s

  end

  html
end