Class: Goodmail::Builder
- Inherits:
-
Object
- Object
- Goodmail::Builder
- Includes:
- ERB::Util
- Defined in:
- lib/goodmail/builder.rb
Overview
Builds the HTML content string based on DSL method calls.
Constant Summary collapse
- HTML_SANITIZER =
Initialize a basic sanitizer allowing only <a> tags with href
Rails::Html::SafeListSanitizer.new
- ALLOWED_TAGS =
%w(a).freeze
- ALLOWED_ATTRIBUTES =
%w(href).freeze
Instance Attribute Summary collapse
-
#parts ⇒ Object
readonly
Returns the value of attribute parts.
Instance Method Summary collapse
- #button(text, url) ⇒ Object
- #center(&block) ⇒ Object
-
#code_box(text) ⇒ Object
Adds a simple code box with background styling.
-
#html(raw_html_string) ⇒ Object
Allows inserting raw, trusted HTML.
-
#html_output ⇒ Object
Returns the collected HTML parts joined together.
- #image(src, alt = "", width: nil, height: nil) ⇒ Object
-
#initialize ⇒ Builder
constructor
A new instance of Builder.
- #line ⇒ Object
-
#price_row(name, price) ⇒ Object
Adds a simple price row as a styled paragraph.
- #sign(name = Goodmail.config.company_name) ⇒ Object
- #space(px = 16) ⇒ Object
-
#text(str) ⇒ Object
Adds a paragraph of text.
Constructor Details
#initialize ⇒ Builder
Returns a new instance of Builder.
20 21 22 |
# File 'lib/goodmail/builder.rb', line 20 def initialize @parts = [] end |
Instance Attribute Details
#parts ⇒ Object
Returns the value of attribute parts.
18 19 20 |
# File 'lib/goodmail/builder.rb', line 18 def parts @parts end |
Instance Method Details
#button(text, url) ⇒ Object
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 |
# File 'lib/goodmail/builder.rb', line 39 def (text, url) # Standard HTML button link = %(<a href="#{h url}" class="goodmail-button-link" style="color:#ffffff;">#{h text}</a>) # VML fallback for Outlook = <<~VML <v:roundrect xmlns:v="urn:schemas-microsoft-com:vml" xmlns:w="urn:schemas-microsoft-com:office:word" href="#{h url}" style="height:44px; v-text-anchor:middle; width:200px;" arcsize="10%" stroke="f" fillcolor="#{Goodmail.config.brand_color}"> <w:anchorlock/> <center style="color:#ffffff; font-family:sans-serif; font-size:14px; font-weight:bold;"> #{h text} </center> </v:roundrect> VML # MSO conditional wrapper mso_wrapper = <<~MSO <!--[if mso]> <table width="100%" cellpadding="0" cellspacing="0" border="0" style="border-spacing: 0; border-collapse: collapse; mso-table-lspace:0pt; mso-table-rspace:0pt;"><tr><td style="padding: 10px 0;" align="center"> #{.strip} </td></tr></table> <![endif]--> <!--[if !mso]><!--> #{} <!--<![endif]--> MSO # Final container div with class for primary CSS styling parts << %(<div class="goodmail-button" style="text-align: center; margin: 24px 0;">#{mso_wrapper.strip.html_safe}</div>) end |
#center(&block) ⇒ Object
122 123 124 |
# File 'lib/goodmail/builder.rb', line 122 def center(&block) wrap("div", "text-align:center;", &block) end |
#code_box(text) ⇒ Object
Adds a simple code box with background styling.
93 94 95 96 |
# File 'lib/goodmail/builder.rb', line 93 def code_box(text) # Re-added background/padding; content is simple, should survive Premailer plain text. parts << %(<p style="background:#F8F8F8; padding:20px; font-style:italic; text-align:center; color:#404040; margin:16px 0; border-radius: 4px;"><strong>#{h text}</strong></p>) end |
#html(raw_html_string) ⇒ Object
Allows inserting raw, trusted HTML. Use with extreme caution.
132 133 134 |
# File 'lib/goodmail/builder.rb', line 132 def html(raw_html_string) parts << raw_html_string.to_s end |
#html_output ⇒ Object
Returns the collected HTML parts joined together.
137 138 139 |
# File 'lib/goodmail/builder.rb', line 137 def html_output parts.join("\n") end |
#image(src, alt = "", width: nil, height: nil) ⇒ Object
66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 |
# File 'lib/goodmail/builder.rb', line 66 def image(src, alt = "", width: nil, height: nil) alt_text = alt.present? ? alt : Goodmail.config.company_name # Default alt text style = "max-width:100%; height:auto; display: block; margin: 0 auto;" style += " width:#{width}px;" if width style += " height:#{height}px;" if height # Standard image tag img_tag = %(<img class="goodmail-image" src="#{h src}" alt="#{h alt_text}" style="#{style}">) # MSO conditional wrapper for centering mso_wrapper = <<~MSO <!--[if mso]> <table role="presentation" width="100%" cellpadding="0" cellspacing="0" border="0" style="border-spacing:0; border-collapse:collapse; mso-table-lspace:0pt; mso-table-rspace:0pt;"><tr><td style="padding: 20px 0;" align="center"> <![endif]--> #{img_tag} <!--[if mso]> </td></tr></table> <![endif]--> MSO parts << mso_wrapper.strip.html_safe end |
#line ⇒ Object
126 127 128 129 |
# File 'lib/goodmail/builder.rb', line 126 def line # Use a class for easier styling via layout CSS parts << %(<hr class="goodmail-hr">) end |
#price_row(name, price) ⇒ Object
Adds a simple price row as a styled paragraph. NOTE: This does not create a table structure.
88 89 90 |
# File 'lib/goodmail/builder.rb', line 88 def price_row(name, price) parts << %(<p style="font-family: 'Helvetica Neue',Helvetica,Arial,sans-serif; font-size: 14px; font-weight:bold; text-align:center; border-top:1px solid #eaeaea; padding:14px 0; margin: 0;">#{h name} – #{h price}</p>) end |
#sign(name = Goodmail.config.company_name) ⇒ Object
103 104 105 106 |
# File 'lib/goodmail/builder.rb', line 103 def sign(name = Goodmail.config.company_name) # Use #777 for better contrast than #888 parts << %(<p style="margin:16px 0; line-height: 1.6;"><span style="color: #777;">– #{h name}</span></p>) end |
#space(px = 16) ⇒ Object
98 99 100 101 |
# File 'lib/goodmail/builder.rb', line 98 def space(px = 16) # Rely on CSS height for spacing, avoid if possible parts << %(<div style="height:#{Integer(px)}px; line-height: #{Integer(px)}px; font-size: 1px;"></div>) end |
#text(str) ⇒ Object
Adds a paragraph of text. Handles newline characters for
tags. Allows safe inline <a> tags with href attributes; strips other HTML.
28 29 30 31 32 33 34 35 36 37 |
# File 'lib/goodmail/builder.rb', line 28 def text(str) # Sanitize first, allowing only safe tags like <a> sanitized_content = HTML_SANITIZER.sanitize( str.to_s, # Ensure input is a string tags: ALLOWED_TAGS, attributes: ALLOWED_ATTRIBUTES ) # Then handle newlines and wrap in paragraph parts << tag(:p, sanitized_content.gsub(/\n/, "<br>"), style: "margin:16px 0; line-height: 1.6;") end |