Class: Inkcite::Renderer::Link

Inherits:
ContainerBase show all
Defined in:
lib/inkcite/renderer/link.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

Class Method Summary collapse

Instance Method Summary collapse

Methods inherited from Responsive

presets

Class Method Details

.process(id, href, force, ctx) ⇒ Object



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
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
# File 'lib/inkcite/renderer/link.rb', line 103

def self.process id, href, force, ctx

  # Initially assume a blank target isn't needed
  target_blank = false

  # If a URL wasn't provided in the HTML, then check to see if there is
  # a link declared in the project's links_tsv file.  If so, we need to
  # duplicate it so that tagging doesn't get applied multiple times.
  if href.blank?
    links_tsv_href = ctx.links_tsv[id]
    href = links_tsv_href unless links_tsv_href.blank?
  end

  # Always duplicate the string provided just to make sure we're not
  # modifying a frozen link or adding tagging to a previously tagged HREF.
  href = href.dup if href

  # True if the href is missing.  If so, we may try to look it up by it's ID
  # or we'll insert a default TBD link.
  missing = href.blank?

  # True if it's a link deeper into the content.
  hash = !missing && href.starts_with?(POUND_SIGN)

  # True if this is a mailto link.
  mailto = !missing && !hash && href.starts_with?(MAILTO)

  # Only perform special processing on the link if it's TBD or not a link to
  # something in the page.
  unless hash || mailto

    if id.blank?

      # Generate a placeholder ID and warn the user about it.
      id = "link#{ctx.links.size + 1}"
      ctx.error 'Link missing ID', { :href => href }

    else

      # Check to see if we've encountered an auto-incrementing link ID (e.g. event++)
      # Replace the ++ with a unique count for this ID prefix.
      id = id.gsub(PLUS_PLUS, ctx.unique_id(id).to_s) if id.end_with?(PLUS_PLUS)

    end

    # Get the HREF that we have previously encountered for this ID.  When not blank
    # we'll sanity check that the URL is the same.
    last_href = ctx.links[id]

    if missing

      # If we don't have a URL, check to see if we've encountered this
      href = last_href || ctx[MISSING_LINK_HREF]

      ctx.error 'Link missing href', { :id => id } unless last_href

    else

      # Ensure the validity of the URL in the link to prevent problems -
      # e.g. unexpected carriage return in the href.
      ctx.error('Link href appears to be invalid', { :id => id, :href => href }) unless force || valid?(href)

      # Optionally tag the link's query string for post-send log analytics.
      href = add_tagging(id, href, ctx)

      if last_href.blank?

        # Associate the href with it's ID in case we bump into this link again.
        ctx.links[id] = href

      elsif last_href != href

        # It saves everyone a lot of time if you alert them that an ID appears multiple times
        # in the email and with mismatched URLs.
        ctx.error 'Link href mismatch', { :id => id, :expected => last_href, :found => href }

      end

    end

    # Optionally replace the href with an ESP trackable url.  Gotta do this after
    # the link has been stored in the context because we don't want trackable
    # URLs interfering with the links file.
    href = add_tracking(id, href, ctx)

    target_blank = true

  end

  [ id, href, target_blank ]
end

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
# File 'lib/inkcite/renderer/link.rb', line 5

def render tag, opt, ctx

  tag_stack = ctx.tag_stack(:a)

  if tag == '/a'

    # Grab the attributes of the opening tag.
    opening = tag_stack.pop

    # Nothing to do in the
    return '' if ctx.text?

    html = '</a>'

    # Check to see if the declaration has been marked as a block
    # element and if so, close the div.
    html << '</div>' if opening[:div]

    return html
  end

  # Push the link's options onto the tag stack so that we can have
  # access to its attributes when we close it.
  tag_stack << opt

  # Get the currently open table cell and see if link color is
  # overridden in there.
  td_parent = ctx.tag_stack(:td).opts
  table_parent = ctx.tag_stack(:table).opts

  # Choose a color from the parameters or inherit from the parent td, table or context.
  opt[:color] = detect(opt[:color], td_parent[:link], table_parent[:link], ctx[LINK_COLOR])

  a = Element.new('a')

  # Mixes the attributes common to all container elements
  # including font, background color, border, etc.
  mix_all a, opt, ctx

  id, href, target_blank = Link.process(opt[:id], opt[:href], opt[:force], ctx)

  a[:target] = BLANK if target_blank

  # Make sure that these types of links have quotes.
  href = quote(href) unless ctx.text?

  # Set the href attribute to the resolved href.
  a[:href] = href

  # Links never get any text decoration.
  a.style[TEXT_DECORATION] = NONE

  # Force the display: block attribute if the boolean block parameter has
  # been specified.
  a.style[:display] = :block if opt[:block]

  if ctx.browser?

    # Programmatically we can install onclick listeners for hosted versions.
    # Check to see if one is specified and the Javascript is permitted in
    # this version.
    onclick = opt[:onclick]
    a[:onclick] = quote(onclick) unless onclick.blank?

  end

  html = ''

  if ctx.text?
    html << a[:href]

  else

    klass = opt[:class]
    a.classes << klass unless klass.blank?

    mix_responsive a, opt, ctx

    # Some responsive modes (e.g. button) change the display type from in-line
    # to block.  This change can cause unexpected whitespace or other unexpected
    # layout changes.  Outlook doesn't support block display on link elements
    # so the best workaround is simply to wrap the element in <div> tags.
    if a.responsive_styles.any?(&:block?)
      html << '<div>'

      # Remember that we made this element block-display so that we can append
      # the extra div when we close the tag.
      opt[:div] = true

    end

    html << a.to_s

  end

  html
end