Use colspan on td instead of divs for hierarchical tables (#39948)
Address Firefox table-rendering issues in docs. Refactor to use colspan to provide table cells which can vary in width and indentation; the outermost has the greatest colspan, and each nested key has a colspan of one less than the parent, with padding cells for indentation. Apply styling to table cells to get the table height to work without hacks or browser-specific styling. Simplify the markup and CSS by removing extra divs. Use two passes over the options, return values, and return facts in the Jinja2 module-docs template: one to determine the maximum nesting depth to compute the maximum colspan needed, plus one to lay out the rows.pull/4420/head
parent
91fd98a2bd
commit
fa5c0282a4
|
@ -421,51 +421,17 @@ table {
|
||||||
max-width: 100%;
|
max-width: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.documentation-table td.elbow-placeholder {
|
||||||
.outer-elbow-container {
|
|
||||||
display: flex;
|
|
||||||
height: 100%;
|
|
||||||
flex-direction: row;
|
|
||||||
}
|
|
||||||
|
|
||||||
.elbow-placeholder {
|
|
||||||
border-left: 1px solid #000;
|
border-left: 1px solid #000;
|
||||||
height: 100%;
|
border-top: 0px;
|
||||||
width: 30px;
|
width: 30px;
|
||||||
|
min-width: 30px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.elbow-key {
|
.documentation-table th, .documentation-table td {
|
||||||
height: 100%;
|
|
||||||
padding: 4px;
|
|
||||||
border-top: 1px solid #000;
|
|
||||||
flex-grow: 1;
|
|
||||||
border-left: 1px solid #000;
|
|
||||||
}
|
|
||||||
|
|
||||||
.elbow-blocker {
|
|
||||||
height: 0;
|
|
||||||
overflow: hidden;
|
|
||||||
}
|
|
||||||
|
|
||||||
.return-value-column {
|
|
||||||
height: 1px
|
|
||||||
}
|
|
||||||
|
|
||||||
.return-value-column td {
|
|
||||||
height: inherit
|
|
||||||
}
|
|
||||||
|
|
||||||
@-moz-document url-prefix() {
|
|
||||||
.return-value-column td {
|
|
||||||
height: 100%
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.cell-border {
|
|
||||||
padding: 4px;
|
padding: 4px;
|
||||||
border-left: 1px solid #000;
|
border-left: 1px solid #000;
|
||||||
border-top: 1px solid #000;
|
border-top: 1px solid #000;
|
||||||
height: 100%;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.documentation-table {
|
.documentation-table {
|
||||||
|
|
|
@ -4867,50 +4867,17 @@ table {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.outer-elbow-container {
|
.documentation-table td.elbow-placeholder {
|
||||||
display: flex;
|
|
||||||
height: 100%;
|
|
||||||
flex-direction: row;
|
|
||||||
}
|
|
||||||
|
|
||||||
.elbow-placeholder {
|
|
||||||
border-left: 1px solid #000;
|
border-left: 1px solid #000;
|
||||||
height: 100%;
|
border-top: 0px;
|
||||||
width: 30px;
|
width: 30px;
|
||||||
|
min-width: 30px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.elbow-key {
|
.documentation-table th, .documentation-table td {
|
||||||
height: 100%;
|
|
||||||
padding: 4px;
|
|
||||||
border-top: 1px solid #000;
|
|
||||||
flex-grow: 1;
|
|
||||||
border-left: 1px solid #000;
|
|
||||||
}
|
|
||||||
|
|
||||||
.elbow-blocker {
|
|
||||||
height: 0;
|
|
||||||
overflow: hidden;
|
|
||||||
}
|
|
||||||
|
|
||||||
.return-value-column {
|
|
||||||
height: 1px
|
|
||||||
}
|
|
||||||
|
|
||||||
.return-value-column td {
|
|
||||||
height: inherit
|
|
||||||
}
|
|
||||||
|
|
||||||
@-moz-document url-prefix() {
|
|
||||||
.return-value-column td {
|
|
||||||
height: 100%
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.cell-border {
|
|
||||||
padding: 4px;
|
padding: 4px;
|
||||||
border-left: 1px solid #000;
|
border-left: 1px solid #000;
|
||||||
border-top: 1px solid #000;
|
border-top: 1px solid #000;
|
||||||
height: 100%;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.documentation-table {
|
.documentation-table {
|
||||||
|
|
|
@ -88,33 +88,41 @@ Parameters
|
||||||
.. raw:: html
|
.. raw:: html
|
||||||
|
|
||||||
<table border=0 cellpadding=0 class="documentation-table">
|
<table border=0 cellpadding=0 class="documentation-table">
|
||||||
|
{# Pre-compute the nesting depth to allocate columns #}
|
||||||
|
{% set ns = namespace(maxdepth=1) %}
|
||||||
|
{% for key, value in options|dictsort recursive %}
|
||||||
|
{% set ns.maxdepth = [loop.depth, ns.maxdepth] | max %}
|
||||||
|
{% if value.suboptions %}
|
||||||
|
{% if value.suboptions.items %}
|
||||||
|
@{ loop(value.suboptions.items()) }@
|
||||||
|
{% elif value.suboptions[0].items %}
|
||||||
|
@{ loop(value.suboptions[0].items()) }@
|
||||||
|
{% endif %}
|
||||||
|
{% endif %}
|
||||||
|
{% endfor %}
|
||||||
{# Header of the documentation #}
|
{# Header of the documentation #}
|
||||||
<tr>
|
<tr>
|
||||||
<th class="head"><div class="cell-border">Parameter</div></th>
|
<th colspan="@{ ns.maxdepth }@">Parameter</th>
|
||||||
<th class="head"><div class="cell-border">Choices/<font color="blue">Defaults</font></div></th>
|
<th>Choices/<font color="blue">Defaults</font></th>
|
||||||
{% if plugin_type != 'module' %}
|
{% if plugin_type != 'module' %}
|
||||||
<th class="head"><div class="cell-border">Configuration</div></th>
|
<th>Configuration</th>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
<th class="head" width="100%"><div class="cell-border">Comments</div></th>
|
<th width="100%">Comments</th>
|
||||||
</tr>
|
</tr>
|
||||||
{% for key, value in options|dictsort recursive %}
|
{% for key, value in options|dictsort recursive %}
|
||||||
<tr class="return-value-column">
|
<tr>
|
||||||
{# parameter name with required and/or introduced label #}
|
{# indentation based on nesting level #}
|
||||||
<td>
|
|
||||||
<div class="outer-elbow-container">
|
|
||||||
{% for i in range(1, loop.depth) %}
|
{% for i in range(1, loop.depth) %}
|
||||||
<div class="elbow-placeholder"> </div>
|
<td class="elbow-placeholder"></td>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
<div class="elbow-key">
|
{# parameter name with required and/or introduced label #}
|
||||||
|
<td colspan="@{ ns.maxdepth - loop.depth0 }@">
|
||||||
<b>@{ key }@</b>
|
<b>@{ key }@</b>
|
||||||
{% if value.get('required', False) %}<br/><div style="font-size: small; color: red">required</div>{% endif %}
|
{% if value.get('required', False) %}<br/><div style="font-size: small; color: red">required</div>{% endif %}
|
||||||
{% if value.version_added %}<br/><div style="font-size: small; color: darkgreen">(added in @{value.version_added}@)</div>{% endif %}
|
{% if value.version_added %}<br/><div style="font-size: small; color: darkgreen">(added in @{value.version_added}@)</div>{% endif %}
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</td>
|
</td>
|
||||||
{# default / choices #}
|
{# default / choices #}
|
||||||
<td>
|
<td>
|
||||||
<div class="cell-border">
|
|
||||||
{# Turn boolean values in 'yes' and 'no' values #}
|
{# Turn boolean values in 'yes' and 'no' values #}
|
||||||
{% if value.default is sameas true %}
|
{% if value.default is sameas true %}
|
||||||
{% set _x = value.update({'default': 'yes'}) %}
|
{% set _x = value.update({'default': 'yes'}) %}
|
||||||
|
@ -146,12 +154,10 @@ Parameters
|
||||||
{% if value.default is defined and value.default not in value.choices %}
|
{% if value.default is defined and value.default not in value.choices %}
|
||||||
<b>Default:</b><br/><div style="color: blue">@{ value.default | escape }@</div>
|
<b>Default:</b><br/><div style="color: blue">@{ value.default | escape }@</div>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</div>
|
|
||||||
</td>
|
</td>
|
||||||
{# configuration #}
|
{# configuration #}
|
||||||
{% if plugin_type != 'module' %}
|
{% if plugin_type != 'module' %}
|
||||||
<td>
|
<td>
|
||||||
<div class="cell-border">
|
|
||||||
{% if 'ini' in value %}
|
{% if 'ini' in value %}
|
||||||
<div> ini entries:
|
<div> ini entries:
|
||||||
{% for ini in value.ini %}
|
{% for ini in value.ini %}
|
||||||
|
@ -169,12 +175,10 @@ Parameters
|
||||||
<div>var: @{ myvar.name }@</div>
|
<div>var: @{ myvar.name }@</div>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</div>
|
|
||||||
</td>
|
</td>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{# description #}
|
{# description #}
|
||||||
<td>
|
<td>
|
||||||
<div class="cell-border">
|
|
||||||
{% if value.description is string %}
|
{% if value.description is string %}
|
||||||
<div>@{ value.description | replace('\n', '\n ') | html_ify }@</div>
|
<div>@{ value.description | replace('\n', '\n ') | html_ify }@</div>
|
||||||
{% else %}
|
{% else %}
|
||||||
|
@ -185,7 +189,6 @@ Parameters
|
||||||
{% if 'aliases' in value and value.aliases %}
|
{% if 'aliases' in value and value.aliases %}
|
||||||
<div style="font-size: small; color: darkgreen"><br/>aliases: @{ value.aliases|join(', ') }@</div>
|
<div style="font-size: small; color: darkgreen"><br/>aliases: @{ value.aliases|join(', ') }@</div>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</div>
|
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
{% if value.suboptions %}
|
{% if value.suboptions %}
|
||||||
|
@ -242,27 +245,34 @@ Facts returned by this module are added/updated in the ``hostvars`` host facts a
|
||||||
.. raw:: html
|
.. raw:: html
|
||||||
|
|
||||||
<table border=0 cellpadding=0 class="documentation-table">
|
<table border=0 cellpadding=0 class="documentation-table">
|
||||||
|
{# Pre-compute the nesting depth to allocate columns #}
|
||||||
|
{% set ns = namespace(maxdepth=1) %}
|
||||||
|
{% for key, value in returnfacts|dictsort recursive %}
|
||||||
|
{% set ns.maxdepth = [loop.depth, ns.maxdepth] | max %}
|
||||||
|
{% if value.contains %}
|
||||||
|
{% if value.contains.items %}
|
||||||
|
@{ loop(value.contains.items()) }@
|
||||||
|
{% elif value.contains[0].items %}
|
||||||
|
@{ loop(value.contains[0].items()) }@
|
||||||
|
{% endif %}
|
||||||
|
{% endif %}
|
||||||
|
{% endfor %}
|
||||||
<tr>
|
<tr>
|
||||||
<th class="head"><div class="cell-border">Fact</div></th>
|
<th colspan="@{ ns.maxdepth }@">Fact</th>
|
||||||
<th class="head"><div class="cell-border">Returned</div></th>
|
<th>Returned</th>
|
||||||
<th class="head" width="100%"><div class="cell-border">Description</div></th>
|
<th width="100%">Description</th>
|
||||||
</tr>
|
</tr>
|
||||||
{% for key, value in returnfacts|dictsort recursive %}
|
{% for key, value in returnfacts|dictsort recursive %}
|
||||||
<tr class="return-value-column">
|
<tr>
|
||||||
<td>
|
|
||||||
<div class="outer-elbow-container">
|
|
||||||
{% for i in range(1, loop.depth) %}
|
{% for i in range(1, loop.depth) %}
|
||||||
<div class="elbow-placeholder"> </div>
|
<td class="elbow-placeholder"></td>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
<div class="elbow-key">
|
<td colspan="@{ ns.maxdepth - loop.depth0 }@" colspan="@{ ns.maxdepth - loop.depth0 }@">
|
||||||
<b>@{ key }@</b>
|
<b>@{ key }@</b>
|
||||||
<br/><div style="font-size: small; color: red">@{ value.type }@</div>
|
<br/><div style="font-size: small; color: red">@{ value.type }@</div>
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</td>
|
</td>
|
||||||
<td><div class="cell-border">@{ value.returned | html_ify }@</div></td>
|
<td>@{ value.returned | html_ify }@</td>
|
||||||
<td>
|
<td>
|
||||||
<div class="cell-border">
|
|
||||||
{% if value.description is string %}
|
{% if value.description is string %}
|
||||||
<div>@{ value.description | html_ify }@
|
<div>@{ value.description | html_ify }@
|
||||||
</div>
|
</div>
|
||||||
|
@ -278,7 +288,6 @@ Facts returned by this module are added/updated in the ``hostvars`` host facts a
|
||||||
{# TODO: The sample should be escaped, using | escape or | htmlify, but both mess things up beyond repair with dicts #}
|
{# TODO: The sample should be escaped, using | escape or | htmlify, but both mess things up beyond repair with dicts #}
|
||||||
<div style="font-size: smaller; color: blue; word-wrap: break-word; word-break: break-all;">@{ value.sample | replace('\n', '\n ') | html_ify }@</div>
|
<div style="font-size: smaller; color: blue; word-wrap: break-word; word-break: break-all;">@{ value.sample | replace('\n', '\n ') | html_ify }@</div>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</div>
|
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
{# ---------------------------------------------------------
|
{# ---------------------------------------------------------
|
||||||
|
@ -308,27 +317,33 @@ Common return values are documented :ref:`here <common_return_values>`, the foll
|
||||||
.. raw:: html
|
.. raw:: html
|
||||||
|
|
||||||
<table border=0 cellpadding=0 class="documentation-table">
|
<table border=0 cellpadding=0 class="documentation-table">
|
||||||
|
{% set ns = namespace(maxdepth=1) %}
|
||||||
|
{% for key, value in returndocs|dictsort recursive %}
|
||||||
|
{% set ns.maxdepth = [loop.depth, ns.maxdepth] | max %}
|
||||||
|
{% if value.contains %}
|
||||||
|
{% if value.contains.items %}
|
||||||
|
@{ loop(value.contains.items()) }@
|
||||||
|
{% elif value.contains[0].items %}
|
||||||
|
@{ loop(value.contains[0].items()) }@
|
||||||
|
{% endif %}
|
||||||
|
{% endif %}
|
||||||
|
{% endfor %}
|
||||||
<tr>
|
<tr>
|
||||||
<th class="head"><div class="cell-border">Key</div></th>
|
<th colspan="@{ ns.maxdepth }@">Key</th>
|
||||||
<th class="head"><div class="cell-border">Returned</div></th>
|
<th>Returned</th>
|
||||||
<th class="head" width="100%"><div class="cell-border">Description</div></th>
|
<th width="100%">Description</th>
|
||||||
</tr>
|
</tr>
|
||||||
{% for key, value in returndocs|dictsort recursive %}
|
{% for key, value in returndocs|dictsort recursive %}
|
||||||
<tr class="return-value-column">
|
<tr>
|
||||||
<td>
|
|
||||||
<div class="outer-elbow-container">
|
|
||||||
{% for i in range(1, loop.depth) %}
|
{% for i in range(1, loop.depth) %}
|
||||||
<div class="elbow-placeholder"> </div>
|
<td class="elbow-placeholder"> </td>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
<div class="elbow-key">
|
<td colspan="@{ ns.maxdepth - loop.depth0 }@">
|
||||||
<b>@{ key }@</b>
|
<b>@{ key }@</b>
|
||||||
<br/><div style="font-size: small; color: red">@{ value.type }@</div>
|
<br/><div style="font-size: small; color: red">@{ value.type }@</div>
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</td>
|
</td>
|
||||||
<td><div class="cell-border">@{ value.returned | html_ify }@</div></td>
|
<td>@{ value.returned | html_ify }@</td>
|
||||||
<td>
|
<td>
|
||||||
<div class="cell-border">
|
|
||||||
{% if value.description is string %}
|
{% if value.description is string %}
|
||||||
<div>@{ value.description | html_ify |indent(4)}@</div>
|
<div>@{ value.description | html_ify |indent(4)}@</div>
|
||||||
{% else %}
|
{% else %}
|
||||||
|
@ -342,7 +357,6 @@ Common return values are documented :ref:`here <common_return_values>`, the foll
|
||||||
{# TODO: The sample should be escaped, using |escape or |htmlify, but both mess things up beyond repair with dicts #}
|
{# TODO: The sample should be escaped, using |escape or |htmlify, but both mess things up beyond repair with dicts #}
|
||||||
<div style="font-size: smaller; color: blue; word-wrap: break-word; word-break: break-all;">@{ value.sample | replace('\n', '\n ') | html_ify }@</div>
|
<div style="font-size: smaller; color: blue; word-wrap: break-word; word-break: break-all;">@{ value.sample | replace('\n', '\n ') | html_ify }@</div>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</div>
|
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
{# ---------------------------------------------------------
|
{# ---------------------------------------------------------
|
||||||
|
|
Loading…
Reference in New Issue