From 7d3ce99a6f848718a2d3ff29335ae7bbf5827079 Mon Sep 17 00:00:00 2001 From: Brian Campbell Date: Thu, 31 May 2018 13:58:33 -0400 Subject: [PATCH] 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. (cherry picked from commit fa5c0282a4816c4dd48e80b983ffc1e14506a1f5) --- .../sphinx_rtd_theme/static/css/theme.css | 42 +-- .../docsite/_themes/srtd/static/css/theme.css | 41 +-- docs/templates/plugin.rst.j2 | 294 +++++++++--------- 3 files changed, 162 insertions(+), 215 deletions(-) diff --git a/docs/docsite/_themes/sphinx_rtd_theme/static/css/theme.css b/docs/docsite/_themes/sphinx_rtd_theme/static/css/theme.css index e20a3466eff..15fd8915f14 100644 --- a/docs/docsite/_themes/sphinx_rtd_theme/static/css/theme.css +++ b/docs/docsite/_themes/sphinx_rtd_theme/static/css/theme.css @@ -421,51 +421,17 @@ table { max-width: 100%; } - -.outer-elbow-container { - display: flex; - height: 100%; - flex-direction: row; -} - -.elbow-placeholder { +.documentation-table td.elbow-placeholder { border-left: 1px solid #000; - height: 100%; + border-top: 0px; width: 30px; + min-width: 30px; } -.elbow-key { - 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 { +.documentation-table th, .documentation-table td { padding: 4px; border-left: 1px solid #000; border-top: 1px solid #000; - height: 100%; } .documentation-table { diff --git a/docs/docsite/_themes/srtd/static/css/theme.css b/docs/docsite/_themes/srtd/static/css/theme.css index fc4d036c6f5..8694ee7a2ed 100644 --- a/docs/docsite/_themes/srtd/static/css/theme.css +++ b/docs/docsite/_themes/srtd/static/css/theme.css @@ -4867,50 +4867,17 @@ table { } } -.outer-elbow-container { - display: flex; - height: 100%; - flex-direction: row; -} - -.elbow-placeholder { +.documentation-table td.elbow-placeholder { border-left: 1px solid #000; - height: 100%; + border-top: 0px; width: 30px; + min-width: 30px; } -.elbow-key { - 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 { +.documentation-table th, .documentation-table td { padding: 4px; border-left: 1px solid #000; border-top: 1px solid #000; - height: 100%; } .documentation-table { diff --git a/docs/templates/plugin.rst.j2 b/docs/templates/plugin.rst.j2 index 421e681c571..a928d327589 100644 --- a/docs/templates/plugin.rst.j2 +++ b/docs/templates/plugin.rst.j2 @@ -88,104 +88,107 @@ Parameters .. raw:: html + {# 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 #} - - + + {% if plugin_type != 'module' %} - + {% endif %} - + {% for key, value in options|dictsort recursive %} - + + {# indentation based on nesting level #} + {% for i in range(1, loop.depth) %} + + {% endfor %} {# parameter name with required and/or introduced label #} - {# default / choices #} {# configuration #} {% if plugin_type != 'module' %} {% endif %} {# description #} {% if value.suboptions %} @@ -242,43 +245,49 @@ Facts returned by this module are added/updated in the ``hostvars`` host facts a .. raw:: html
Parameter
Choices/Defaults
ParameterChoices/Defaults
Configuration
Configuration
Comments
Comments
-
- {% for i in range(1, loop.depth) %} -
 
- {% endfor %} -
- @{ key }@ - {% if value.get('required', False) %}
required
{% endif %} - {% if value.version_added %}
(added in @{value.version_added}@)
{% endif %} -
-
+
+ @{ key }@ + {% if value.get('required', False) %}
required
{% endif %} + {% if value.version_added %}
(added in @{value.version_added}@)
{% endif %}
-
- {# Turn boolean values in 'yes' and 'no' values #} - {% if value.default is sameas true %} - {% set _x = value.update({'default': 'yes'}) %} - {% elif value.default is sameas false %} - {% set _x = value.update({'default': 'no'}) %} - {% endif %} - {% if value.type == 'bool' %} - {% set _x = value.update({'choices': ['no', 'yes']}) %} - {% endif %} - {# Show possible choices and highlight details #} - {% if value.choices %} -
    Choices: - {% for choice in value.choices %} - {# Turn boolean values in 'yes' and 'no' values #} - {% if choice is sameas true %} - {% set choice = 'yes' %} - {% elif choice is sameas false %} - {% set choice = 'no' %} - {% endif %} - {% if (value.default is string and value.default == choice) or (value.default is iterable and value.default is not string and choice in value.default) %} -
  • @{ choice | escape }@ ←
  • - {% else %} -
  • @{ choice | escape }@
  • - {% endif %} - {% endfor %} -
- {% endif %} - {# Show default value, when multiple choice or no choices #} - {% if value.default is defined and value.default not in value.choices %} - Default:
@{ value.default | escape }@
- {% endif %} -
+ {# Turn boolean values in 'yes' and 'no' values #} + {% if value.default is sameas true %} + {% set _x = value.update({'default': 'yes'}) %} + {% elif value.default is sameas false %} + {% set _x = value.update({'default': 'no'}) %} + {% endif %} + {% if value.type == 'bool' %} + {% set _x = value.update({'choices': ['no', 'yes']}) %} + {% endif %} + {# Show possible choices and highlight details #} + {% if value.choices %} +
    Choices: + {% for choice in value.choices %} + {# Turn boolean values in 'yes' and 'no' values #} + {% if choice is sameas true %} + {% set choice = 'yes' %} + {% elif choice is sameas false %} + {% set choice = 'no' %} + {% endif %} + {% if (value.default is string and value.default == choice) or (value.default is iterable and value.default is not string and choice in value.default) %} +
  • @{ choice | escape }@ ←
  • + {% else %} +
  • @{ choice | escape }@
  • + {% endif %} + {% endfor %} +
+ {% endif %} + {# Show default value, when multiple choice or no choices #} + {% if value.default is defined and value.default not in value.choices %} + Default:
@{ value.default | escape }@
+ {% endif %}
-
- {% if 'ini' in value %} -
ini entries: - {% for ini in value.ini %} -

[@{ ini.section }@ ]
@{ ini.key }@ = @{ value.default | default('VALUE') }@

- {% endfor %} -
- {% endif %} - {% if 'env' in value %} - {% for env in value.env %} -
env:@{ env.name }@
+ {% if 'ini' in value %} +
ini entries: + {% for ini in value.ini %} +

[@{ ini.section }@ ]
@{ ini.key }@ = @{ value.default | default('VALUE') }@

{% endfor %} - {% endif %} - {% if 'vars' in value %} - {% for myvar in value.vars %} -
var: @{ myvar.name }@
- {% endfor %} - {% endif %} -
+
+ {% endif %} + {% if 'env' in value %} + {% for env in value.env %} +
env:@{ env.name }@
+ {% endfor %} + {% endif %} + {% if 'vars' in value %} + {% for myvar in value.vars %} +
var: @{ myvar.name }@
+ {% endfor %} + {% endif %}
-
- {% if value.description is string %} -
@{ value.description | replace('\n', '\n ') | html_ify }@
- {% else %} - {% for desc in value.description %} -
@{ desc | replace('\n', '\n ') | html_ify }@
- {% endfor %} - {% endif %} - {% if 'aliases' in value and value.aliases %} -

aliases: @{ value.aliases|join(', ') }@
- {% endif %} -
+ {% if value.description is string %} +
@{ value.description | replace('\n', '\n ') | html_ify }@
+ {% else %} + {% for desc in value.description %} +
@{ desc | replace('\n', '\n ') | html_ify }@
+ {% endfor %} + {% endif %} + {% if 'aliases' in value and value.aliases %} +

aliases: @{ value.aliases|join(', ') }@
+ {% endif %}
+ {# 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 %} - - - + + + {% for key, value in returnfacts|dictsort recursive %} - - + {% for i in range(1, loop.depth) %} + + {% endfor %} + - + {# --------------------------------------------------------- @@ -308,41 +317,46 @@ Common return values are documented :ref:`here `, the foll .. raw:: html
Fact
Returned
Description
FactReturnedDescription
-
- {% for i in range(1, loop.depth) %} -
 
- {% endfor %} -
- @{ key }@ -
@{ value.type }@
-
-
+
+ @{ key }@ +
@{ value.type }@
@{ value.returned | html_ify }@
@{ value.returned | html_ify }@ -
- {% if value.description is string %} -
@{ value.description | html_ify }@ + {% if value.description is string %} +
@{ value.description | html_ify }@ +
+ {% else %} + {% for desc in value.description %} +
@{ desc | html_ify }@
- {% else %} - {% for desc in value.description %} -
@{ desc | html_ify }@ -
- {% endfor %} - {% endif %} -
- {% if value.sample is defined and value.sample %} -
Sample:
- {# TODO: The sample should be escaped, using | escape or | htmlify, but both mess things up beyond repair with dicts #} -
@{ value.sample | replace('\n', '\n ') | html_ify }@
- {% endif %} -
+ {% endfor %} + {% endif %} +
+ {% if value.sample is defined and value.sample %} +
Sample:
+ {# TODO: The sample should be escaped, using | escape or | htmlify, but both mess things up beyond repair with dicts #} +
@{ value.sample | replace('\n', '\n ') | html_ify }@
+ {% endif %}
+ {% 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 %} - - - + + + {% for key, value in returndocs|dictsort recursive %} - - + {% for i in range(1, loop.depth) %} + + {% endfor %} + - + {# ---------------------------------------------------------
Key
Returned
Description
KeyReturnedDescription
-
- {% for i in range(1, loop.depth) %} -
 
- {% endfor %} -
- @{ key }@ -
@{ value.type }@
-
-
+
  + @{ key }@ +
@{ value.type }@
@{ value.returned | html_ify }@
@{ value.returned | html_ify }@ -
- {% if value.description is string %} -
@{ value.description | html_ify |indent(4)}@
- {% else %} - {% for desc in value.description %} -
@{ desc | html_ify |indent(4)}@
- {% endfor %} - {% endif %} -
- {% if value.sample is defined and value.sample %} -
Sample:
- {# TODO: The sample should be escaped, using |escape or |htmlify, but both mess things up beyond repair with dicts #} -
@{ value.sample | replace('\n', '\n ') | html_ify }@
- {% endif %} -
+ {% if value.description is string %} +
@{ value.description | html_ify |indent(4)}@
+ {% else %} + {% for desc in value.description %} +
@{ desc | html_ify |indent(4)}@
+ {% endfor %} + {% endif %} +
+ {% if value.sample is defined and value.sample %} +
Sample:
+ {# TODO: The sample should be escaped, using |escape or |htmlify, but both mess things up beyond repair with dicts #} +
@{ value.sample | replace('\n', '\n ') | html_ify }@
+ {% endif %}