|
| 1 | +module Docs |
| 2 | + class Typst |
| 3 | + class CleanHtmlFilter < Filter |
| 4 | + def call |
| 5 | + # The container keeps the sidebar so internal_urls can crawl it. |
| 6 | + # Once we have collected all links, we keep only the page body. |
| 7 | + @doc = at_css('main') || raise("missing main on #{current_url}") |
| 8 | + |
| 9 | + css('.breadcrumbs', '.page-end-buttons', '.sources-link', '.tooltip-context', |
| 10 | + '.search', 'button.copy').remove |
| 11 | + |
| 12 | + # Category lists rely on CSS columns to separate names and descriptions. |
| 13 | + # We separate them with an em-dash to make them readable. |
| 14 | + css('.catgrid > li > a + span').each { |node| node.before(' — ') } |
| 15 | + |
| 16 | + # Adjacent type pills are unions, separated visually by the site's CSS. |
| 17 | + css('.pill + .pill').each { |node| node.before(' or ') } |
| 18 | + |
| 19 | + # Parameter types, modifiers, and defaults live inside headings. |
| 20 | + # Move them into a paragraph so headings stay readable. |
| 21 | + css('h1, h2, h3, h4, h5, h6').each do |heading| |
| 22 | + heading.css('> .additional-info', '> small').reverse_each do |node| |
| 23 | + node.css('small.mod').each { |modifier| modifier.after(' ') } |
| 24 | + node.css('> div').each do |types| |
| 25 | + types.name = 'span' |
| 26 | + types.after(' ') |
| 27 | + end |
| 28 | + node.name = 'p' |
| 29 | + heading.after(node) |
| 30 | + end |
| 31 | + end |
| 32 | + |
| 33 | + css('pre').each do |node| |
| 34 | + code = node.at_css('> code') |
| 35 | + language = code && code['data-lang'] |
| 36 | + if language |
| 37 | + # Prism doesn't support Typst yet, |
| 38 | + # but we leave the language annotation in case it's implemented later. |
| 39 | + language = 'typst' if language.start_with?('typ') |
| 40 | + node['data-language'] = language == 'sh' ? 'bash' : language |
| 41 | + end |
| 42 | + node.content = node.content |
| 43 | + end |
| 44 | + |
| 45 | + css('.code-definition').each do |node| |
| 46 | + node.css('div.arguments .overview-param').each { |param| param.before("\n ") } |
| 47 | + node.css('div.arguments').each do |args| |
| 48 | + args.add_child("\n") |
| 49 | + args.name = 'span' |
| 50 | + end |
| 51 | + node.name = 'pre' |
| 52 | + end |
| 53 | + |
| 54 | + # Open examples work without the source site's toggle scripts. |
| 55 | + css('details').each { |node| node['open'] = '' } |
| 56 | + css('summary img').remove |
| 57 | + |
| 58 | + # The original symbol picker needs JS to display character metadata. |
| 59 | + # A table retains every symbol and its anchor for offline lookup. |
| 60 | + css('.symbol-grid').each do |grid| |
| 61 | + table = Nokogiri::XML::Node.new('table', doc.document) |
| 62 | + table.inner_html = '<thead><tr><th>Name</th><th>Symbol</th><th>Unicode name</th><th>LaTeX</th></tr></thead><tbody></tbody>' |
| 63 | + body = table.at_css('tbody') |
| 64 | + grid.css('li[id]').each do |symbol| |
| 65 | + row = Nokogiri::XML::Node.new('tr', doc.document) |
| 66 | + row['id'] = symbol['id'] |
| 67 | + name = symbol.at_css('code') || raise("missing name for ##{symbol['id']} on #{current_url}") |
| 68 | + code = Nokogiri::XML::Node.new('code', doc.document) |
| 69 | + code.content = name.content |
| 70 | + cell = Nokogiri::XML::Node.new('td', doc.document) |
| 71 | + cell.add_child(code) |
| 72 | + row.add_child(cell) |
| 73 | + [symbol['data-value'], symbol['data-unic-name']].each do |value| |
| 74 | + cell = Nokogiri::XML::Node.new('td', doc.document) |
| 75 | + cell.content = value.to_s |
| 76 | + row.add_child(cell) |
| 77 | + end |
| 78 | + cell = Nokogiri::XML::Node.new('td', doc.document) |
| 79 | + if symbol['data-latex-name'].present? |
| 80 | + latex = Nokogiri::XML::Node.new('code', doc.document) |
| 81 | + latex.content = symbol['data-latex-name'] |
| 82 | + cell.add_child(latex) |
| 83 | + end |
| 84 | + row.add_child(cell) |
| 85 | + body.add_child(row) |
| 86 | + end |
| 87 | + grid.replace(table) |
| 88 | + end |
| 89 | + css('p:contains("Click on a")').each do |node| |
| 90 | + node.remove if node.content.include?('to copy it to the clipboard') |
| 91 | + end |
| 92 | + |
| 93 | + css('[class]', '[style]', '[aria-describedby]', '[data-lang]').each do |node| |
| 94 | + %w(class style aria-describedby data-lang).each { |attribute| node.remove_attribute(attribute) } |
| 95 | + end |
| 96 | + |
| 97 | + doc |
| 98 | + end |
| 99 | + end |
| 100 | + end |
| 101 | +end |
0 commit comments