Class: Markly::Renderer::HTML
- Defined in:
- lib/markly/renderer/html.rb
Overview
Renders Markdown node trees as HTML.
Constant Summary collapse
- TABLE_CELL_ALIGNMENT =
{ left: ' align="left"', right: ' align="right"', center: ' align="center"' }.freeze
Instance Attribute Summary
Attributes inherited from Generic
Class Method Summary collapse
-
.anchor_for(node) ⇒ Object
Generates a normalized anchor from a node's plain-text content.
Instance Method Summary collapse
-
#anchor_for(node) ⇒ Object
Generates a normalized anchor from a node's plain-text content.
-
#blockquote(node) ⇒ Object
Renders a blockquote node.
-
#code(node) ⇒ Object
Renders an inline code node and its optional language metadata.
-
#code_block(node) ⇒ Object
Renders a code block and its optional language metadata.
-
#document(_) ⇒ Object
Renders a complete document and closes any generated sections.
-
#emph(node) ⇒ Object
Renders an emphasized inline node.
-
#footnote_definition(node) ⇒ Object
Renders a footnote definition and records its backlink target.
-
#footnote_reference(node) ⇒ Object
Renders a footnote reference linking to its definition.
-
#header(node) ⇒ Object
Renders a heading node, optionally wrapped in an anchored section.
-
#hrule(node) ⇒ Object
Renders a thematic-break node.
-
#html(node) ⇒ Object
Renders or omits a raw block-level HTML node according to the flags.
-
#id_for(node) ⇒ Object
Returns an escaped HTML id attribute for a heading node.
-
#image(node) ⇒ Object
Renders an image node with plain-text alternative content.
-
#initialize(ids: false, headings: nil, tight: false, **options) ⇒ HTML
constructor
Initializes an HTML renderer.
-
#inline_html(node) ⇒ Object
Renders or omits a raw inline HTML node according to the flags.
-
#linebreak(_node) ⇒ Object
Renders a hard line break.
-
#link(node) ⇒ Object
Renders a link node with escaped destination and title attributes.
-
#list(node) ⇒ Object
Renders an ordered or unordered list node.
-
#list_item(node) ⇒ Object
Renders a list-item node, including task-list attributes when present.
-
#paragraph(node) ⇒ Object
Renders a paragraph node.
-
#softbreak(_) ⇒ Object
Renders a soft line break according to the configured flags.
-
#strikethrough(_) ⇒ Object
Renders a strikethrough node.
-
#strong(node) ⇒ Object
Renders a strongly emphasized inline node.
-
#table(node) ⇒ Object
Renders a table node and initializes its column alignments.
-
#table_cell(node) ⇒ Object
Renders a table cell using the current column alignment.
-
#table_header(node) ⇒ Object
Renders a table-header row.
-
#table_row(node) ⇒ Object
Renders a table row, opening the table body when necessary.
-
#tasklist(node) ⇒ Object
Returns the HTML fragment required for a task-list item.
-
#text(node) ⇒ Object
Renders an escaped text node.
Methods inherited from Generic
#Whether the renderer is emitting plain text.=, #Whether the renderer is inside a tight container.=, #block, #container, #cr, #out, #plain, #reference_def, #render
Constructor Details
#initialize(ids: false, headings: nil, tight: false, **options) ⇒ HTML
Initializes an HTML renderer.
27 28 29 30 31 32 33 34 35 36 37 |
# File 'lib/markly/renderer/html.rb', line 27 def initialize(ids: false, headings: nil, tight: false, **) super(**) # Initialize heading tracker if IDs are enabled @headings = headings || (ids ? Headings.new : nil) @section = nil @tight = tight @footnotes = {} end |
Class Method Details
.anchor_for(node) ⇒ Object
Generates a normalized anchor from a node's plain-text content.
65 66 67 68 69 70 71 72 73 |
# File 'lib/markly/renderer/html.rb', line 65 def self.anchor_for(node) # Convert to plaintext, strip trailing whitespace, convert to lowercase: text = node.to_plaintext.chomp.downcase # Replace sequences of whitespace with hyphens: text.gsub!(/\s+/, "-") return text end |
Instance Method Details
#anchor_for(node) ⇒ Object
Generates a normalized anchor from a node's plain-text content.
79 80 81 |
# File 'lib/markly/renderer/html.rb', line 79 def anchor_for(node) self.class.anchor_for(node) end |
#blockquote(node) ⇒ Object
Renders a blockquote node.
174 175 176 177 178 179 180 |
# File 'lib/markly/renderer/html.rb', line 174 def blockquote(node) block do container("<blockquote#{source_position(node)}>\n", "</blockquote>") do out(:children) end end end |
#code(node) ⇒ Object
Renders an inline code node and its optional language metadata.
288 289 290 291 292 293 294 295 |
# File 'lib/markly/renderer/html.rb', line 288 def code(node) language = node.code_language out("<code") out(' class="language-', language, '"') if language out(">") out(escape_html(node.string_content)) out("</code>") end |
#code_block(node) ⇒ Object
Renders a code block and its optional language metadata.
194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 |
# File 'lib/markly/renderer/html.rb', line 194 def code_block(node) block do language = node.code_language if flag_enabled?(GITHUB_PRE_LANG) out("<pre#{source_position(node)}") out(' lang="', language, '"') if language out("><code>") else out("<pre#{source_position(node)}><code") if language out(' class="language-', language, '">') else out(">") end end out(escape_html(node.string_content)) out("</code></pre>") end end |
#document(_) ⇒ Object
Renders a complete document and closes any generated sections.
42 43 44 45 46 47 |
# File 'lib/markly/renderer/html.rb', line 42 def document(_) @section = false super out("</ol>\n</section>\n") if @written_footnote_ix out("</section>") if @section end |
#emph(node) ⇒ Object
Renders an emphasized inline node.
242 243 244 |
# File 'lib/markly/renderer/html.rb', line 242 def emph(node) out("<em>", :children, "</em>") end |
#footnote_definition(node) ⇒ Object
Renders a footnote definition and records its backlink target.
387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 |
# File 'lib/markly/renderer/html.rb', line 387 def footnote_definition(node) unless @footnote_ix out("<section class=\"footnotes\" data-footnotes>\n<ol>\n") @footnote_ix = 0 end @footnote_ix += 1 label = node.string_content @footnotes[@footnote_ix] = label out("<li id=\"fn-#{label}\">\n", :children) out("\n") if out_footnote_backref out("</li>\n") # </ol> # </section> end |
#footnote_reference(node) ⇒ Object
Renders a footnote reference linking to its definition.
377 378 379 380 381 382 |
# File 'lib/markly/renderer/html.rb', line 377 def footnote_reference(node) label = node.parent_footnote_def.string_content out("<sup class=\"footnote-ref\"><a href=\"#fn-#{label}\" id=\"fnref-#{label}\" data-footnote-ref>#{node.string_content}</a></sup>") # out(node.to_html) end |
#header(node) ⇒ Object
Renders a heading node, optionally wrapped in an anchored section.
86 87 88 89 90 91 92 93 94 95 96 |
# File 'lib/markly/renderer/html.rb', line 86 def header(node) block do if @headings out("</section>") if @section @section = true out("<section#{id_for(node)}>") end out("<h", node.header_level, "#{source_position(node)}>", :children, "</h", node.header_level, ">") end end |
#hrule(node) ⇒ Object
Renders a thematic-break node.
185 186 187 188 189 |
# File 'lib/markly/renderer/html.rb', line 185 def hrule(node) block do out("<hr#{source_position(node)} />") end end |
#html(node) ⇒ Object
Renders or omits a raw block-level HTML node according to the flags.
218 219 220 221 222 223 224 225 226 |
# File 'lib/markly/renderer/html.rb', line 218 def html(node) block do if flag_enabled?(UNSAFE) out(tagfilter(node.string_content)) else out("<!-- raw HTML omitted -->") end end end |
#id_for(node) ⇒ Object
Returns an escaped HTML id attribute for a heading node.
53 54 55 56 57 58 59 |
# File 'lib/markly/renderer/html.rb', line 53 def id_for(node) if @headings anchor = @headings.anchor_for(node) # `CGI.escape_html` is not exposed by `cgi/escape` on Ruby 3.4: return " id=\"#{CGI.escapeHTML anchor}\"" end end |
#image(node) ⇒ Object
Renders an image node with plain-text alternative content.
269 270 271 272 273 274 275 276 |
# File 'lib/markly/renderer/html.rb', line 269 def image(node) out('<img src="', escape_href(node.url), '"') plain do out(' alt="', :children, '"') end out(' title="', escape_html(node.title), '"') if node.title && !node.title.empty? out(" />") end |
#inline_html(node) ⇒ Object
Renders or omits a raw inline HTML node according to the flags.
231 232 233 234 235 236 237 |
# File 'lib/markly/renderer/html.rb', line 231 def inline_html(node) if flag_enabled?(UNSAFE) out(tagfilter(node.string_content)) else out("<!-- raw HTML omitted -->") end end |
#linebreak(_node) ⇒ Object
Renders a hard line break.
300 301 302 |
# File 'lib/markly/renderer/html.rb', line 300 def linebreak(_node) out("<br />\n") end |
#link(node) ⇒ Object
Renders a link node with escaped destination and title attributes.
260 261 262 263 264 |
# File 'lib/markly/renderer/html.rb', line 260 def link(node) out('<a href="', node.url.nil? ? "" : escape_href(node.url), '"') out(' title="', escape_html(node.title), '"') if node.title && !node.title.empty? out(">", :children, "</a>") end |
#list(node) ⇒ Object
Renders an ordered or unordered list node.
120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 |
# File 'lib/markly/renderer/html.rb', line 120 def list(node) old_tight = @tight @tight = node.list_tight block do if node.list_type == :bullet_list container("<ul#{source_position(node)}>\n", "</ul>") do out(:children) end else start = if node.list_start == 1 "<ol#{source_position(node)}>\n" else "<ol start=\"#{node.list_start}\"#{source_position(node)}>\n" end container(start, "</ol>") do out(:children) end end end @tight = old_tight end |
#list_item(node) ⇒ Object
Renders a list-item node, including task-list attributes when present.
147 148 149 150 151 152 153 154 |
# File 'lib/markly/renderer/html.rb', line 147 def list_item(node) block do tasklist_data = tasklist(node) container("<li#{source_position(node)}#{tasklist_data}>#{' ' if tasklist?(node)}", "</li>") do out(:children) end end end |
#paragraph(node) ⇒ Object
Renders a paragraph node.
101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 |
# File 'lib/markly/renderer/html.rb', line 101 def paragraph(node) if @tight && node.parent.type != :blockquote out(:children) else block do container("<p#{source_position(node)}>", "</p>") do out(:children) if node.parent.type == :footnote_definition && node.next.nil? out(" ") out_footnote_backref end end end end end |
#softbreak(_) ⇒ Object
Renders a soft line break according to the configured flags.
307 308 309 310 311 312 313 314 315 |
# File 'lib/markly/renderer/html.rb', line 307 def softbreak(_) if flag_enabled?(HARD_BREAKS) out("<br />\n") elsif flag_enabled?(NO_BREAKS) out(" ") else out("\n") end end |
#strikethrough(_) ⇒ Object
Renders a strikethrough node.
370 371 372 |
# File 'lib/markly/renderer/html.rb', line 370 def strikethrough(_) out("<del>", :children, "</del>") end |
#strong(node) ⇒ Object
Renders a strongly emphasized inline node.
249 250 251 252 253 254 255 |
# File 'lib/markly/renderer/html.rb', line 249 def strong(node) if node.parent.nil? || node.parent.type == node.type out(:children) else out("<strong>", :children, "</strong>") end end |
#table(node) ⇒ Object
Renders a table node and initializes its column alignments.
320 321 322 323 324 325 326 |
# File 'lib/markly/renderer/html.rb', line 320 def table(node) @alignments = node.table_alignments @needs_close_tbody = false out("<table#{source_position(node)}>\n", :children) out("</tbody>\n") if @needs_close_tbody out("</table>\n") end |
#table_cell(node) ⇒ Object
Renders a table cell using the current column alignment.
361 362 363 364 365 |
# File 'lib/markly/renderer/html.rb', line 361 def table_cell(node) align = TABLE_CELL_ALIGNMENT.fetch(@alignments[@column_index], "") out(@in_header ? "<th#{align}#{source_position(node)}>" : "<td#{align}#{source_position(node)}>", :children, @in_header ? "</th>\n" : "</td>\n") @column_index += 1 end |
#table_header(node) ⇒ Object
Renders a table-header row.
331 332 333 334 335 336 337 |
# File 'lib/markly/renderer/html.rb', line 331 def table_header(node) @column_index = 0 @in_header = true out("<thead>\n<tr#{source_position(node)}>\n", :children, "</tr>\n</thead>\n") @in_header = false end |
#table_row(node) ⇒ Object
Renders a table row, opening the table body when necessary.
342 343 344 345 346 347 348 349 |
# File 'lib/markly/renderer/html.rb', line 342 def table_row(node) @column_index = 0 if !@in_header && !@needs_close_tbody @needs_close_tbody = true out("<tbody>\n") end out("<tr#{source_position(node)}>\n", :children, "</tr>\n") end |
#tasklist(node) ⇒ Object
Returns the HTML fragment required for a task-list item.
160 161 162 163 164 165 166 167 168 169 |
# File 'lib/markly/renderer/html.rb', line 160 def tasklist(node) return "" unless tasklist?(node) state = if checked?(node) 'checked="" disabled=""' else 'disabled=""' end "><input type=\"checkbox\" #{state} /" end |
#text(node) ⇒ Object
Renders an escaped text node.
281 282 283 |
# File 'lib/markly/renderer/html.rb', line 281 def text(node) out(escape_html(node.string_content)) end |