Skip to content

Commit

Permalink
Merge pull request #214 from alphagov/table-row-headings
Browse files Browse the repository at this point in the history
Implement row level table headings to allow accessible tables with row headings
  • Loading branch information
richardTowers authored Mar 12, 2021
2 parents 31393b5 + bfbd1d7 commit bff939f
Show file tree
Hide file tree
Showing 3 changed files with 89 additions and 0 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

- [#210: Fix issue with WCAG 2.1 success criterion 1.3.1 (Info and Relationships)](https://github.com/alphagov/tech-docs-gem/pull/210)
- [#209: Some search and keyboard navigation updates](https://github.com/alphagov/tech-docs-gem/pull/209)
- [#214: Implement row level table headings to allow accessible tables with row headings](https://github.com/alphagov/tech-docs-gem/pull/214)

### Ruby version bump

Expand Down
44 changes: 44 additions & 0 deletions lib/govuk_tech_docs/tech_docs_html_renderer.rb
Original file line number Diff line number Diff line change
Expand Up @@ -30,5 +30,49 @@ def table(header, body)
</table>
</div>)
end

def table_row(body)
# Post-processing the table_cell HTML to implement row headings.
#
# Doing this in table_row instead of table_cell is a hack.
#
# Ideally, we'd use the table_cell callback like:
#
# def table_cell(content, alignment, header)
# if header
# "<th>#{content}</th>"
# elsif content.start_with? "# "
# "<th scope="row">#{content.sub(/^# /, "")}</th>"
# else
# "<td>#{content}</td>"
# end
# end
#
# Sadly, Redcarpet's table_cell callback doesn't allow you to distinguish
# table cells and table headings until https://github.com/vmg/redcarpet/commit/27dfb2a738a23aadd286ac9e7ecd61c4545d29de
# (which is not yet released). This means we can't use the table_cell callback
# without breaking column headers, so we're having to hack it in table_row.

fragment = Nokogiri::HTML::DocumentFragment.parse(body)
fragment.children.each do |cell|
next unless cell.name == "td"
next if cell.children.empty?

first_child = cell.children.first
next unless first_child.text?

leading_text = first_child.content
next unless leading_text.start_with?("#")

cell.name = "th"
cell["scope"] = "row"
first_child.content = leading_text.sub(/# */, "")
end

tr = Nokogiri::XML::Node.new "tr", fragment
tr.children = fragment.children

tr.to_html
end
end
end
44 changes: 44 additions & 0 deletions spec/govuk_tech_docs/tech_docs_html_renderer_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
RSpec.describe GovukTechDocs::TechDocsHTMLRenderer do
let(:app) { double("app") }
let(:context) { double("context") }
let(:processor) {
allow(context).to receive(:app) { app }
allow(app).to receive(:api)
Redcarpet::Markdown.new(described_class.new(context: context), tables: true)
}

describe "#render a table" do
markdown_table = <<~MARKDOWN
| A | B |
|------|---|
|# C | D |
| E | F |
|# *G* | H |
MARKDOWN

it "treats cells in the heading row as headings" do
output = processor.render markdown_table

expect(output).to include("<th>A</th>")
expect(output).to include("<th>B</th>")
end

it "treats cells starting with # as row headings" do
output = processor.render markdown_table
expect(output).to include('<th scope="row">C</th>')
end

it "treats cells starting with # with more complex markup as row headings" do
output = processor.render markdown_table
expect(output).to match(/<th scope="row"><em>G<\/em>\s*<\/th>/)
end

it "treats other cells as ordinary cells" do
output = processor.render markdown_table
expect(output).to include("<td>D</td>")
expect(output).to include("<td>E</td>")
expect(output).to include("<td>F</td>")
expect(output).to include("<td>H</td>")
end
end
end

0 comments on commit bff939f

Please sign in to comment.