Skip to content

Commit

Permalink
Add column width classes to markdown tables with 2-5 columns
Browse files Browse the repository at this point in the history
The idea is, for tables with x columns, we add classes to make them equal width:

- 2 columns: w-50
- 3 columns: w-33
- 4 columns: w-25
- 5 columns: w-20

Two notable exceptions here:

1. Once your table is more than 6 columns, I am assuming it's too
   weird and I am not going to add presumptive classnames to your table.
2. If your table is "complex", such that it renders as HTML, this
   function doesn't work. Seems like an okay assumption, as complex
   tables are also weird.
  • Loading branch information
pcraig3 committed Sep 19, 2024
1 parent 71061dc commit 335d738
Show file tree
Hide file tree
Showing 3 changed files with 72 additions and 8 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ The format is based on Keep a Changelog, and this project adheres to Semantic Ve

### Changed

- Add default width classes to markdown tables with 2-5 cols
- Updated column headers on NOFO index table
- "Top" link on nofo_edit page is always visible
- Appearing and disappearing was causing issues
Expand Down
24 changes: 24 additions & 0 deletions bloom_nofos/nofos/nofo.py
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,30 @@ def _has_colspan_or_rowspan_not_one(tag):

return super().convert_table(el, text, convert_as_inline)

def convert_th(self, el, text, convert_as_inline):
# automatically add width classes to table headers based on number of <th> elements
def _determine_width_class_from_th_siblings(th_count=0):
# Determine the width class based on the number of <th> elements in the first table row
width_class = ""
if th_count == 2:
width_class = "w-50"
elif th_count == 3:
width_class = "w-33"
elif th_count == 4:
width_class = "w-25"
elif th_count == 5:
width_class = "w-20"

return width_class

th_count = len(el.parent.find_all("th"))
# Add the class to the text if a class was determined
width_class = _determine_width_class_from_th_siblings(th_count)
if width_class:
text = f"{text.strip()} {{: .{width_class} }}"

return super().convert_th(el, text, convert_as_inline)


# Create shorthand method for conversion
def md(html, **options):
Expand Down
55 changes: 47 additions & 8 deletions bloom_nofos/nofos/test_nofo.py
Original file line number Diff line number Diff line change
Expand Up @@ -149,6 +149,53 @@ def test_table_with_nested_html(self):
self.assertEqual(md_body.strip(), pretty_html)


class TablesAndStuffInTablesConverterTHSest(TestCase):
def test_table_0_ths(self):
html = "<table><tr><td>TD 1</td><td>TD 2</td></tr><tr><td>Cell 1</td><td>Cell 2</td></th></table>"
expected_markdown = "| TD 1 | TD 2 |\n| --- | --- |\n| Cell 1 | Cell 2 |"
md_body = md(html)
self.assertEqual(md_body.strip(), expected_markdown.strip())

def test_table_1_th(self):
html = "<table><tr><th>TH 1</th></tr><tr><td>Cell 1</td></th></table>"
expected_markdown = "| TH 1 |\n| --- |\n| Cell 1 |"
md_body = md(html)
self.assertEqual(md_body.strip(), expected_markdown.strip())

def test_table_2_ths(self):
html = "<table><tr><th>TH 1</th><th>TH 2</th></tr><tr><td>Cell 1</td><td>Cell 2</td></th></table>"
expected_markdown = (
"| TH 1 {: .w-50 } | TH 2 {: .w-50 } |\n| --- | --- |\n| Cell 1 | Cell 2 |"
)
md_body = md(html)
self.assertEqual(md_body.strip(), expected_markdown.strip())

def test_table_3_ths(self):
html = "<table><tr><th>TH 1</th><th>TH 2</th><th>TH 3</th></tr><tr><td>Cell 1</td><td>Cell 2</td><td>Cell 3</td></th></table>"
expected_markdown = "| TH 1 {: .w-33 } | TH 2 {: .w-33 } | TH 3 {: .w-33 } |\n| --- | --- | --- |\n| Cell 1 | Cell 2 | Cell 3 |"
md_body = md(html)
self.assertEqual(md_body.strip(), expected_markdown.strip())

def test_table_4_ths(self):
html = "<table><tr><th>TH 1</th><th>TH 2</th><th>TH 3</th><th>TH 4</th></tr><tr><td>Cell 1</td><td>Cell 2</td><td>Cell 3</td><td>Cell 4</td></th></table>"
expected_markdown = "| TH 1 {: .w-25 } | TH 2 {: .w-25 } | TH 3 {: .w-25 } | TH 4 {: .w-25 } |\n| --- | --- | --- | --- |\n| Cell 1 | Cell 2 | Cell 3 | Cell 4 |"
md_body = md(html)
self.assertEqual(md_body.strip(), expected_markdown.strip())

def test_table_5_ths(self):
html = "<table><tr><th>TH 1</th><th>TH 2</th><th>TH 3</th><th>TH 4</th><th>TH 5</th></tr><tr><td>Cell 1</td><td>Cell 2</td><td>Cell 3</td><td>Cell 4</td><td>Cell 5</td></th></table>"
expected_markdown = "| TH 1 {: .w-20 } | TH 2 {: .w-20 } | TH 3 {: .w-20 } | TH 4 {: .w-20 } | TH 5 {: .w-20 } |\n| --- | --- | --- | --- | --- |\n| Cell 1 | Cell 2 | Cell 3 | Cell 4 | Cell 5 |"
md_body = md(html)
self.assertEqual(md_body.strip(), expected_markdown.strip())

def test_table_6_ths(self):
# no classnames on this one
html = "<table><tr><th>TH 1</th><th>TH 2</th><th>TH 3</th><th>TH 4</th><th>TH 5</th><th>TH 6</th></tr><tr><td>Cell 1</td><td>Cell 2</td><td>Cell 3</td><td>Cell 4</td><td>Cell 5</td><td>Cell 6</td></th></table>"
expected_markdown = "| TH 1 | TH 2 | TH 3 | TH 4 | TH 5 | TH 6 |\n| --- | --- | --- | --- | --- | --- |\n| Cell 1 | Cell 2 | Cell 3 | Cell 4 | Cell 5 | Cell 6 |"
md_body = md(html)
self.assertEqual(md_body.strip(), expected_markdown.strip())


class TablesAndStuffInTablesConverterOLSTest(TestCase):
maxDiff = None

Expand Down Expand Up @@ -190,14 +237,6 @@ def test_ol_inside_td_start_not_one(self):
md_body = md(html)
self.assertEqual(md_body.strip(), pretty_html)

def test_ol_inside_td_start_not_one(self):
html = '<table><tr><th>Header</th></tr><tr><td><ol start="3"><li>Item 1</li><li>Item 2</li></ol></td></tr></table>'
pretty_html = (
'| Header |\n| --- |\n| <ol start="3"><li>Item 1</li><li>Item 2</li></ol> |'
)
md_body = md(html)
self.assertEqual(md_body.strip(), pretty_html)

def test_table_with_ol_strip_classes_nested_html(self):
html = '<table class="c40"><tr class="c311"><td class="c68 c127" colspan="1" rowspan="1"><p class="c89"><span class="c6">Demonstrates the ability to comply with all applicable privacy and security standards by developing a PII plan that outlines the following:</span></p></td><td class="c168 c127" colspan="1" rowspan="1"><p class="c41 c104"><span class="c69 c67"></span></p></td></tr><tr class="c216"><td class="c31" colspan="1" rowspan="1"><ul class="c1 lst-kix_list_76-0"><li class="c33 li-bullet-0"><span class="c6">A process for ensuring compliance by all staff performing Navigator activities (as well as those who have access to sensitive information or PII related to your organization’s Navigator activities) with </span><span class="c7"><a class="c32" href="https://www.google.com">FFE privacy and security standards</a></span><span class="c6">, especially when using computers, laptops, tablets, smartphones, and other electronic devices.</span></li></ul></td><td class="c11" colspan="1" rowspan="1"><p class="c41"><span class="c51">5 points</span></p></td></tr></table>'
pretty_html = """| Demonstrates the ability to comply with all applicable privacy and security standards by developing a PII plan that outlines the following: | |\n| --- | --- |\n| <ul><li><span>A process for ensuring compliance by all staff performing Navigator activities (as well as those who have access to sensitive information or PII related to your organization’s Navigator activities) with </span><span><a href="https://www.google.com">FFE privacy and security standards</a></span><span>, especially when using computers, laptops, tablets, smartphones, and other electronic devices.</span></li></ul> | 5 points |"""
Expand Down

0 comments on commit 335d738

Please sign in to comment.