{# ---------- PAC-INFO MACROS ---------- #} {# These macros render semantic HTML with light class hooks. #} {%- macro key_value_table(pairs) -%} {# pairs: iterable of (key, value) 2-tuples - NOT a dict.items()-only call, so callers with non-unique/empty labels (e.g. several attributes sharing a blank label) don't silently lose rows the way collapsing into a dict first would. #} {%- for k, v in pairs -%} {%- if k != "key" -%} {%- endif -%} {%- endfor -%}
{{ k }} {{ render_text(v) }}
{%- endmacro -%} {%- macro category_block(category) -%}
{{ category.__class__.__name__ }}
{{ key_value_table(category.segments_as_dict().items()) }}
{%- endmacro -%} {# Renamed from service_table_section/services_table - neither name matched what they render (both emit
s, not s), and the pairing read backwards (the "table" was the inner piece, the "section" wrapped it). #} {%- macro service_links(services) %}
{%- for s in services -%} {{ s.service_name }} {%- endfor -%}
{%- endmacro -%} {%- macro service_group_block(user_handover_group) -%}
from {{ user_handover_group.origin }}
{{ service_links(user_handover_group.services)}}
{%- endmacro -%} {%- macro reference(value, label=None, card_request_params=dict(), target_class=None, display_label=True) %}
{% if display_label %} {# The card above is the primary content; the label is always a real link too, on top of it - route_pac_id_url_for lets an issuer route it through their own page instead of linking straight to the PAC-ID's own URL. #} {% if route_pac_id_url_for is defined %} {{ label or value }} {% else %} {{ label or value }} {% endif %} {% endif %} {% if pac_card_url_for is defined %}
{% endif %}
{%- endmacro %} {# A PacInfo.Document (name, key, url) - the uniform shape safety_data_sheet/ certificate_of_analysis return regardless of whether the source was an attribute or a user handover Service. Distinct from attribute_row() since Document has no .value_list/.label to match that macro's Attribute-shaped interface. #} {%- macro document_row(document) -%} {%- endmacro -%} {%- macro attribute_row(a) -%} {%- endmacro -%} {%- macro attribute_group_block(ag) -%}
{{ ag.group_label }}
{%- if dev_mode %}

(from {{ ag.origin }})

{%- endif %}
{{ document.name }} {{ document.url }}
{% if is_reference(a.key) %} {{ reference(a.key, a.label)}} {% elif is_url(a.key) %} {{ a.label }} {% else %} {{ a.label }} {% endif %}
{{a.key}}
{% for value in a.value_list%} {%- if is_image(value) -%}
{{ label|e }}
{{ label }}
{%- elif is_reference(value) -%} {# Checked before is_url - a PAC-ID is itself a valid URL, so a bare (non-pyReference) PAC-ID string would otherwise always hit the generic link branch below and never reach the card. #} {{ reference(value)}} {%- elif is_url(value) -%} {# Same icon+label format as service_links' elements - reuses its classes rather than a parallel set, since the look is meant to be identical. #} {{ value }} {%- else -%} {{ render_text(value) }} {%- endif -%} {% if not loop.last %}
{% endif %} {% endfor%}
{%- for a in ag.attributes.values() -%} {{ attribute_row(a) }} {%- endfor -%}
{%- endmacro -%} {%- macro data_table_inline(dt) -%} {# Renders your DataTable structure; expects filters: is_data_table(dt) #} {%- if dt.data | length == 1 -%} {%- for i in range(dt.col_names | length) -%} {%- endfor -%}
{{ dt.col_names[i] }} {{ dt.data[0][i] }}
{%- else -%} {%- for rn in dt.col_names -%} {%- endfor -%} {%- for row in dt.data -%} {%- for e in row -%} {%- endfor -%} {%- endfor -%}
{{ rn }}
{{ e }}
{%- endif -%} {%- endmacro -%} {%- macro attached_data_block(attached_data) -%}
{%- for name, trex in attached_data.items() -%} {{ attached_data_trex(name, trex) }} {%- endfor -%}
{%- endmacro -%} {# One pictogram for a GHS0x code, using the bundled static image. resolve_static_image() only searches flat filenames directly in the static root (Path(base_name).stem strips any directory component before it even searches) - no subdirectory, no extension needed, it tries svg/png/jpg/jpeg/ webp itself. Supplier-provided images (see PacInfo.explicit_pictogram_image_urls) aren't matched to a particular code - they're rendered as their own separate images by pictogram_strip below. #} {%- macro pictogram_image(code) -%} {{ pictogram_name(code) }} {%- endmacro -%} {# Shown once above the hazard/precautionary statement table (see PacInfo.safety_pictogram_codes) rather than repeated per row - a hazard statement's pictogram is a property of the substance as a whole, and several codes commonly share the same one (e.g. H300/H310/H330 are all Skull-and-crossbones). explicit_image_urls are supplier-provided pictogram images (Resource-valued GHS_PICTOGRAM attribute values) - rendered in addition to the code-derived images, not matched against any particular code. #} {%- macro pictogram_strip(codes, explicit_image_urls=[]) -%} {%- if codes or explicit_image_urls -%}
{%- for code in codes -%} {{ pictogram_image(code) }} {%- endfor -%} {%- for url in explicit_image_urls -%} {%- endfor -%}
{%- endif -%} {%- endmacro -%} {# GHS hazard/precautionary statement rows - code beside its full text. Resolution (code extraction + labfreed/utilities/ghs/ghs_statements.json lookup) now happens in PacInfo.hazard_statements/precautionary_statements, not here - these macros just render the already-resolved HazardStatement/PrecautionaryStatement (code, text, text_origin). text is None when the code isn't in that table (e.g. an EU-specific EUH code, not part of the UN GHS document it was sourced from) and text_origin is always 'Predefined' for now - falls back to the bare code until attribute-delivered text is wired up - see developer-docs/design-choices.md. #} {# th/td classes match every other key/value table (key_value_table, attribute_row) - same 1/3-2/3 column widths and label bolding from .lf-table--kv, for free, no GHS-specific CSS needed. #} {%- macro hazard_statement_row(statement) -%} {{ statement.code }} {{ statement.text or statement.code }} {%- endmacro -%} {%- macro precautionary_statement_row(statement) -%} {{ statement.code }} {{ statement.text or statement.code }} {%- endmacro -%} {%- macro attached_data_trex(name, trex) %}
{{ name }}
{%- for k, v in trex.items() -%} {%- endfor -%}
{{ k }} {%- if is_data_table(v) -%} {{ data_table_inline(v) }} {%- else -%} {{ v }} {%- endif -%}
{% endmacro %}