Skip to content

Commit

Permalink
fix: ensure HTML ID attributes are unique
Browse files Browse the repository at this point in the history
  • Loading branch information
BenGale93 committed Feb 12, 2025
1 parent 3d6ad09 commit 6635b4b
Show file tree
Hide file tree
Showing 5 changed files with 56 additions and 24 deletions.
25 changes: 18 additions & 7 deletions great_tables/_utils_render_html.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
from ._gt_data import GroupRowInfo, GTData, Styles
from ._spanners import spanners_print_matrix
from ._tbl_data import _get_cell, cast_frame_to_string, replace_null_frame
from ._text import _process_text, _process_text_id
from ._text import BaseText, _process_text, _process_text_id
from ._utils import heading_has_subtitle, heading_has_title, seq_groups


Expand Down Expand Up @@ -41,6 +41,14 @@ def _flatten_styles(styles: Styles, wrap: bool = False) -> str | None:
return None


def _create_element_id(table_id: str | None, element_id: str | BaseText | None) -> str:
# Given a table ID, element IDs are prepended by it to ensure the resulting HTML
# has unique IDs.
new_table_id = table_id or ""
processed_id = _process_text_id(element_id)
return f"{new_table_id} {processed_id}" if new_table_id and processed_id else processed_id


def create_heading_component_h(data: GTData) -> str:
title = data._heading.title
subtitle = data._heading.subtitle
Expand Down Expand Up @@ -150,6 +158,9 @@ def create_columns_component_h(data: GTData) -> str:
# Initialize the column headings list
table_col_headings = []

# Extract the table ID to ensure subsequent IDs are unique
table_id = data._options.table_id.value

# If there are no spanners, then we have to create the cells for the stubhead label
# (if present) and for the column headings
if spanner_row_count == 0:
Expand All @@ -163,7 +174,7 @@ def create_columns_component_h(data: GTData) -> str:
colspan=len(stub_layout),
style=_flatten_styles(styles_stubhead),
scope="colgroup" if len(stub_layout) > 1 else "col",
id=_process_text_id(stub_label),
id=_create_element_id(table_id, stub_label),
)
)

Expand All @@ -180,7 +191,7 @@ def create_columns_component_h(data: GTData) -> str:
colspan=1,
style=_flatten_styles(styles_column_labels + styles_i),
scope="col",
id=_process_text_id(info.column_label),
id=_create_element_id(table_id, info.column_label),
)
)

Expand Down Expand Up @@ -225,7 +236,7 @@ def create_columns_component_h(data: GTData) -> str:
colspan=len(stub_layout),
style=_flatten_styles(styles_stubhead),
scope="colgroup" if len(stub_layout) > 1 else "col",
id=_process_text_id(stub_label),
id=_create_element_id(table_id, stub_label),
)
)

Expand Down Expand Up @@ -258,7 +269,7 @@ def create_columns_component_h(data: GTData) -> str:
colspan=1,
style=_flatten_styles(styles_column_labels + styles_i),
scope="col",
id=_process_text_id(h_info.column_label),
id=_create_element_id(table_id, h_info.column_label),
)
)

Expand Down Expand Up @@ -286,7 +297,7 @@ def create_columns_component_h(data: GTData) -> str:
colspan=colspans[ii],
style=_flatten_styles(styles_column_labels + styles_i),
scope="colgroup" if colspans[ii] > 1 else "col",
id=_process_text_id(spanner_ids_level_1_index[ii]),
id=_create_element_id(table_id, spanner_ids_level_1_index[ii]),
)
)

Expand Down Expand Up @@ -318,7 +329,7 @@ def create_columns_component_h(data: GTData) -> str:
colspan=1,
style=_flatten_styles(styles_column_labels + styles_i),
scope="col",
id=_process_text_id(remaining_headings_labels[j]),
id=_create_element_id(table_id, remaining_headings_labels[j]),
)
)

Expand Down
14 changes: 7 additions & 7 deletions tests/__snapshots__/test_export.ambr
Original file line number Diff line number Diff line change
Expand Up @@ -60,9 +60,9 @@
</tr>
<tr class="gt_col_headings">
<th class="gt_col_heading gt_columns_bottom_border gt_left" rowspan="1" colspan="1" scope="col" id=""></th>
<th class="gt_col_heading gt_columns_bottom_border gt_right" rowspan="1" colspan="1" scope="col" id="num">num</th>
<th class="gt_col_heading gt_columns_bottom_border gt_left" rowspan="1" colspan="1" scope="col" id="char">char</th>
<th class="gt_col_heading gt_columns_bottom_border gt_right" rowspan="1" colspan="1" scope="col" id="currency">currency</th>
<th class="gt_col_heading gt_columns_bottom_border gt_right" rowspan="1" colspan="1" scope="col" id="test_table num">num</th>
<th class="gt_col_heading gt_columns_bottom_border gt_left" rowspan="1" colspan="1" scope="col" id="test_table char">char</th>
<th class="gt_col_heading gt_columns_bottom_border gt_right" rowspan="1" colspan="1" scope="col" id="test_table currency">currency</th>
</tr>
</thead>
<tbody class="gt_table_body">
Expand Down Expand Up @@ -143,8 +143,8 @@
<thead style="border-style: none;">

<tr class="gt_col_headings" style="border-style: none;background-color: transparent;border-top-style: solid;border-top-width: 2px;border-top-color: #D3D3D3;border-bottom-style: solid;border-bottom-width: 2px;border-bottom-color: #D3D3D3;border-left-style: none;border-left-width: 1px;border-left-color: #D3D3D3;border-right-style: none;border-right-width: 1px;border-right-color: #D3D3D3;">
<th class="gt_col_heading gt_columns_bottom_border gt_right" id="num" rowspan="1" colspan="1" scope="col" style="border-style: none;color: #333333;background-color: #FFFFFF;font-size: 100%;font-weight: normal;text-transform: inherit;border-left-style: none;border-left-width: 1px;border-left-color: #D3D3D3;border-right-style: none;border-right-width: 1px;border-right-color: #D3D3D3;vertical-align: bottom;padding-top: 5px;padding-bottom: 5px;padding-left: 5px;padding-right: 5px;overflow-x: hidden;text-align: right;font-variant-numeric: tabular-nums;">num</th>
<th class="gt_col_heading gt_columns_bottom_border gt_left" id="char" rowspan="1" colspan="1" scope="col" style="border-style: none;color: #333333;background-color: #FFFFFF;font-size: 100%;font-weight: normal;text-transform: inherit;border-left-style: none;border-left-width: 1px;border-left-color: #D3D3D3;border-right-style: none;border-right-width: 1px;border-right-color: #D3D3D3;vertical-align: bottom;padding-top: 5px;padding-bottom: 5px;padding-left: 5px;padding-right: 5px;overflow-x: hidden;text-align: left;">char</th>
<th class="gt_col_heading gt_columns_bottom_border gt_right" id="test_table_small num" rowspan="1" colspan="1" scope="col" style="border-style: none;color: #333333;background-color: #FFFFFF;font-size: 100%;font-weight: normal;text-transform: inherit;border-left-style: none;border-left-width: 1px;border-left-color: #D3D3D3;border-right-style: none;border-right-width: 1px;border-right-color: #D3D3D3;vertical-align: bottom;padding-top: 5px;padding-bottom: 5px;padding-left: 5px;padding-right: 5px;overflow-x: hidden;text-align: right;font-variant-numeric: tabular-nums;">num</th>
<th class="gt_col_heading gt_columns_bottom_border gt_left" id="test_table_small char" rowspan="1" colspan="1" scope="col" style="border-style: none;color: #333333;background-color: #FFFFFF;font-size: 100%;font-weight: normal;text-transform: inherit;border-left-style: none;border-left-width: 1px;border-left-color: #D3D3D3;border-right-style: none;border-right-width: 1px;border-right-color: #D3D3D3;vertical-align: bottom;padding-top: 5px;padding-bottom: 5px;padding-left: 5px;padding-right: 5px;overflow-x: hidden;text-align: left;">char</th>
</tr>
</thead>
<tbody class="gt_table_body" style="border-style: none;border-top-style: solid;border-top-width: 2px;border-top-color: #D3D3D3;border-bottom-style: solid;border-bottom-width: 2px;border-bottom-color: #D3D3D3;">
Expand Down Expand Up @@ -176,8 +176,8 @@
<thead style="border-style: none;">

<tr class="gt_col_headings" style="border-style: none;background-color: transparent;border-top-style: solid;border-top-width: 2px;border-top-color: #D3D3D3;border-bottom-style: solid;border-bottom-width: 2px;border-bottom-color: #D3D3D3;border-left-style: none;border-left-width: 1px;border-left-color: #D3D3D3;border-right-style: none;border-right-width: 1px;border-right-color: #D3D3D3;">
<th class="gt_col_heading gt_columns_bottom_border gt_right" id="num" rowspan="1" colspan="1" scope="col" style="border-style: none;color: #333333;background-color: #FFFFFF;font-size: 100%;font-weight: normal;text-transform: inherit;border-left-style: none;border-left-width: 1px;border-left-color: #D3D3D3;border-right-style: none;border-right-width: 1px;border-right-color: #D3D3D3;vertical-align: bottom;padding-top: 5px;padding-bottom: 5px;padding-left: 5px;padding-right: 5px;overflow-x: hidden;text-align: right;font-variant-numeric: tabular-nums;">num</th>
<th class="gt_col_heading gt_columns_bottom_border gt_left" id="char" rowspan="1" colspan="1" scope="col" style="border-style: none;color: #333333;background-color: #FFFFFF;font-size: 100%;font-weight: normal;text-transform: inherit;border-left-style: none;border-left-width: 1px;border-left-color: #D3D3D3;border-right-style: none;border-right-width: 1px;border-right-color: #D3D3D3;vertical-align: bottom;padding-top: 5px;padding-bottom: 5px;padding-left: 5px;padding-right: 5px;overflow-x: hidden;text-align: left;">char</th>
<th class="gt_col_heading gt_columns_bottom_border gt_right" id="test_table_small num" rowspan="1" colspan="1" scope="col" style="border-style: none;color: #333333;background-color: #FFFFFF;font-size: 100%;font-weight: normal;text-transform: inherit;border-left-style: none;border-left-width: 1px;border-left-color: #D3D3D3;border-right-style: none;border-right-width: 1px;border-right-color: #D3D3D3;vertical-align: bottom;padding-top: 5px;padding-bottom: 5px;padding-left: 5px;padding-right: 5px;overflow-x: hidden;text-align: right;font-variant-numeric: tabular-nums;">num</th>
<th class="gt_col_heading gt_columns_bottom_border gt_left" id="test_table_small char" rowspan="1" colspan="1" scope="col" style="border-style: none;color: #333333;background-color: #FFFFFF;font-size: 100%;font-weight: normal;text-transform: inherit;border-left-style: none;border-left-width: 1px;border-left-color: #D3D3D3;border-right-style: none;border-right-width: 1px;border-right-color: #D3D3D3;vertical-align: bottom;padding-top: 5px;padding-bottom: 5px;padding-left: 5px;padding-right: 5px;overflow-x: hidden;text-align: left;">char</th>
</tr>
</thead>
<tbody class="gt_table_body" style="border-style: none;border-top-style: solid;border-top-width: 2px;border-top-color: #D3D3D3;border-bottom-style: solid;border-bottom-width: 2px;border-bottom-color: #D3D3D3;">
Expand Down
20 changes: 10 additions & 10 deletions tests/__snapshots__/test_repr.ambr
Original file line number Diff line number Diff line change
Expand Up @@ -53,8 +53,8 @@
<thead>

<tr class="gt_col_headings">
<th class="gt_col_heading gt_columns_bottom_border gt_right" rowspan="1" colspan="1" scope="col" id="x">x</th>
<th class="gt_col_heading gt_columns_bottom_border gt_right" rowspan="1" colspan="1" scope="col" id="y">y</th>
<th class="gt_col_heading gt_columns_bottom_border gt_right" rowspan="1" colspan="1" scope="col" id="test x">x</th>
<th class="gt_col_heading gt_columns_bottom_border gt_right" rowspan="1" colspan="1" scope="col" id="test y">y</th>
</tr>
</thead>
<tbody class="gt_table_body">
Expand Down Expand Up @@ -129,8 +129,8 @@
<thead>

<tr class="gt_col_headings">
<th class="gt_col_heading gt_columns_bottom_border gt_right" rowspan="1" colspan="1" scope="col" id="x">x</th>
<th class="gt_col_heading gt_columns_bottom_border gt_right" rowspan="1" colspan="1" scope="col" id="y">y</th>
<th class="gt_col_heading gt_columns_bottom_border gt_right" rowspan="1" colspan="1" scope="col" id="test x">x</th>
<th class="gt_col_heading gt_columns_bottom_border gt_right" rowspan="1" colspan="1" scope="col" id="test y">y</th>
</tr>
</thead>
<tbody class="gt_table_body">
Expand Down Expand Up @@ -211,8 +211,8 @@
<thead>

<tr class="gt_col_headings">
<th class="gt_col_heading gt_columns_bottom_border gt_right" rowspan="1" colspan="1" scope="col" id="x">x</th>
<th class="gt_col_heading gt_columns_bottom_border gt_right" rowspan="1" colspan="1" scope="col" id="y">y</th>
<th class="gt_col_heading gt_columns_bottom_border gt_right" rowspan="1" colspan="1" scope="col" id="test x">x</th>
<th class="gt_col_heading gt_columns_bottom_border gt_right" rowspan="1" colspan="1" scope="col" id="test y">y</th>
</tr>
</thead>
<tbody class="gt_table_body">
Expand Down Expand Up @@ -290,8 +290,8 @@
<thead>

<tr class="gt_col_headings">
<th class="gt_col_heading gt_columns_bottom_border gt_right" rowspan="1" colspan="1" scope="col" id="x">x</th>
<th class="gt_col_heading gt_columns_bottom_border gt_right" rowspan="1" colspan="1" scope="col" id="y">y</th>
<th class="gt_col_heading gt_columns_bottom_border gt_right" rowspan="1" colspan="1" scope="col" id="test x">x</th>
<th class="gt_col_heading gt_columns_bottom_border gt_right" rowspan="1" colspan="1" scope="col" id="test y">y</th>
</tr>
</thead>
<tbody class="gt_table_body">
Expand Down Expand Up @@ -366,8 +366,8 @@
<thead>

<tr class="gt_col_headings">
<th class="gt_col_heading gt_columns_bottom_border gt_right" rowspan="1" colspan="1" scope="col" id="x">x</th>
<th class="gt_col_heading gt_columns_bottom_border gt_right" rowspan="1" colspan="1" scope="col" id="y">y</th>
<th class="gt_col_heading gt_columns_bottom_border gt_right" rowspan="1" colspan="1" scope="col" id="test x">x</th>
<th class="gt_col_heading gt_columns_bottom_border gt_right" rowspan="1" colspan="1" scope="col" id="test y">y</th>
</tr>
</thead>
<tbody class="gt_table_body">
Expand Down
15 changes: 15 additions & 0 deletions tests/__snapshots__/test_utils_render_html.ambr
Original file line number Diff line number Diff line change
Expand Up @@ -384,3 +384,18 @@
</tbody>
'''
# ---
# name: test_table_id_used_in_headers
'''
<tr class="gt_col_headings">
<th class="gt_col_heading gt_columns_bottom_border gt_right" rowspan="1" colspan="1" scope="col" id="test_id num">num</th>
<th class="gt_col_heading gt_columns_bottom_border gt_left" rowspan="1" colspan="1" scope="col" id="test_id char">char</th>
<th class="gt_col_heading gt_columns_bottom_border gt_left" rowspan="1" colspan="1" scope="col" id="test_id fctr">fctr</th>
<th class="gt_col_heading gt_columns_bottom_border gt_right" rowspan="1" colspan="1" scope="col" id="test_id date">date</th>
<th class="gt_col_heading gt_columns_bottom_border gt_right" rowspan="1" colspan="1" scope="col" id="test_id time">time</th>
<th class="gt_col_heading gt_columns_bottom_border gt_right" rowspan="1" colspan="1" scope="col" id="test_id datetime">datetime</th>
<th class="gt_col_heading gt_columns_bottom_border gt_right" rowspan="1" colspan="1" scope="col" id="test_id currency">currency</th>
<th class="gt_col_heading gt_columns_bottom_border gt_left" rowspan="1" colspan="1" scope="col" id="test_id row">row</th>
<th class="gt_col_heading gt_columns_bottom_border gt_left" rowspan="1" colspan="1" scope="col" id="test_id group">group</th>
</tr>
'''
# ---
6 changes: 6 additions & 0 deletions tests/test_utils_render_html.py
Original file line number Diff line number Diff line change
Expand Up @@ -240,3 +240,9 @@ def test_loc_kitchen_sink(snapshot):
html = new_gt.as_raw_html()
cleaned = html[html.index("<table") :]
assert cleaned == snapshot


def test_table_id_used_in_headers(snapshot):
new_gt = GT(exibble).with_id("test_id")

assert_rendered_columns(snapshot, new_gt)

0 comments on commit 6635b4b

Please sign in to comment.