|
15 | 15 |
|
16 | 16 | NORM_PREFIX = "norm:" |
17 | 17 |
|
| 18 | +MAX_TABLE_ROWS = 12 # Max rows of a table displayed in a cell. |
| 19 | + |
18 | 20 | ################################### |
19 | 21 | # Classes for Normative Rule Tags # |
20 | 22 | ################################### |
@@ -1016,7 +1018,7 @@ def html_chapter_table(f, table_num, chapter_name, nr_defs, tags, tag_fname2url) |
1016 | 1018 |
|
1017 | 1019 | unless nr.description.nil? |
1018 | 1020 | f.puts(%Q{ <tr>}) unless row_started |
1019 | | - f.puts(%Q{ <td>#{html_convert_newlines(nr.description)}</td>}) |
| 1021 | + f.puts(%Q{ <td>#{convert_newlines_to_html(nr.description)}</td>}) |
1020 | 1022 | f.puts(%Q{ <td>Rule's "description" property</td>}) |
1021 | 1023 | f.puts(%Q{ </tr>}) |
1022 | 1024 | row_started = false |
@@ -1052,8 +1054,7 @@ def html_chapter_table(f, table_num, chapter_name, nr_defs, tags, tag_fname2url) |
1052 | 1054 | html_fname = tag_fname2url[tag.tag_filename] |
1053 | 1055 | fatal("No fname tag to HTML mapping (-tag2url cmd line arg) for tag fname #{tag.tag_filename} for tag name #{tag.name}") if html_fname.nil? |
1054 | 1056 |
|
1055 | | - tag_text = html_convert_newlines(limit_table_rows(Adoc2HTML::convert(tag.text))) |
1056 | | - |
| 1057 | + tag_text = convert_newlines_to_html(convert_tags_tables_to_html(Adoc2HTML::convert(tag.text))) |
1057 | 1058 |
|
1058 | 1059 | # Convert adoc links to normative text in tag text to html links. |
1059 | 1060 | # |
@@ -1139,14 +1140,104 @@ def html_script(f) |
1139 | 1140 | ) |
1140 | 1141 | end |
1141 | 1142 |
|
| 1143 | +# Convert the tagged text containing entire tables. Uses format created by "tags" Asciidoctor backend. |
| 1144 | +# |
| 1145 | +# Two possible formats: |
| 1146 | +# |
| 1147 | +# Without heading: |
| 1148 | +# |
| 1149 | +# === |
| 1150 | +# | ABC | DEF |
| 1151 | +# |GHI |JKL |
| 1152 | +# === |
| 1153 | +# |
| 1154 | +# Actual string from tags: "===\n| ABC | DEF\n|GHI |JKL\n===" |
| 1155 | +# |
| 1156 | +# With heading: |
| 1157 | +# |
| 1158 | +# | H1 | H2 |
| 1159 | +# === |
| 1160 | +# | GHI | JKL |
| 1161 | +# === |
| 1162 | +# |
| 1163 | +# Actual string from tags: "| H1 | H2\n===\n| GHI | JKL\n===" |
| 1164 | + |
| 1165 | +def convert_tags_tables_to_html(text) |
| 1166 | + raise ArgumentError, "Expected String for text but was passed a #{text}.class" unless text.is_a?(String) |
| 1167 | + |
| 1168 | + ret = text # Default to input |
| 1169 | + |
| 1170 | + text.gsub(/(.*?)===\n(.+)\n===/m) do |
| 1171 | + # Found a "tags" formatted table |
| 1172 | + heading = $1.chomp # Remove trailing newline |
| 1173 | + rows = $2.split("\n") # Split into array of rows |
| 1174 | + |
| 1175 | + ret = "<table>".dup # Start html table |
| 1176 | + |
| 1177 | + # Add heading if present |
| 1178 | + heading_cells = extract_tags_table_cells(heading) |
| 1179 | + unless heading_cells.empty? |
| 1180 | + ret << "<thead>" |
| 1181 | + ret << "<tr>" |
| 1182 | + ret << heading_cells.map { |cell| "<th>#{cell}</th>" }.join("") |
| 1183 | + ret << "</tr>" |
| 1184 | + ret << "</thead>" |
| 1185 | + end |
| 1186 | + |
| 1187 | + # Add each row |
| 1188 | + ret << "<tbody>" |
| 1189 | + rows.each_with_index do |row,index| |
| 1190 | + if index < MAX_TABLE_ROWS |
| 1191 | + ret << "<tr>" |
| 1192 | + row_cells = extract_tags_table_cells(row) |
| 1193 | + ret << row_cells.map { |cell| "<td>#{cell}</td>" }.join("") |
| 1194 | + ret << "</tr>" |
| 1195 | + elsif index == MAX_TABLE_ROWS |
| 1196 | + ret << "<tr>" |
| 1197 | + row_cells = extract_tags_table_cells(row) |
| 1198 | + ret << row_cells.map { |cell| "<td>...</td>" }.join("") |
| 1199 | + ret << "</tr>" |
| 1200 | + end |
| 1201 | + end |
| 1202 | + |
| 1203 | + ret << "</tbody>" |
| 1204 | + ret << "</table>" # End html table |
| 1205 | + end |
| 1206 | + |
| 1207 | + return ret |
| 1208 | +end |
| 1209 | + |
| 1210 | +# Return array of table columns from one row/header of a table. |
| 1211 | +def extract_tags_table_cells(text) |
| 1212 | + raise ArgumentError, "Expected String for text but was passed a #{text}.class" unless text.is_a?(String) |
| 1213 | + |
| 1214 | + # This pattern matches strings that: |
| 1215 | + # - Start with a non-pipe, non-whitespace character |
| 1216 | + # - Then contain zero or more non-pipe characters (can include internal spaces) |
| 1217 | + # - End with a non-pipe, non-whitespace character |
| 1218 | + # |
| 1219 | + # All leading/trailing whitespace is removed. |
| 1220 | + # |
| 1221 | + # Examples: |
| 1222 | + # "| H1 | H2".scan(/[^|\s][^|]*[^|\s]/) |
| 1223 | + # => ["H1", "H2"] |
| 1224 | + # |
| 1225 | + # "| ABC | DEF GHI |".scan(/[^|\s][^|]*[^|\s]/) |
| 1226 | + # => ["ABC", "DEF GHI"] # Note: internal space preserved |
| 1227 | + # |
| 1228 | + # "| Name | Value |".scan(/[^|\s][^|]*[^|\s]/) |
| 1229 | + # => ["Name", "Value"] # Leading/trailing spaces removed |
| 1230 | + text.scan(/[^|\s][^|]*[^|\s]/) |
| 1231 | +end |
| 1232 | + |
1142 | 1233 | # Cleanup the tag text to be suitably displayed. |
1143 | 1234 | def limit_table_rows(text) |
1144 | 1235 | raise ArgumentError, "Expected String for text but was passed a #{text}.class" unless text.is_a?(String) |
1145 | 1236 |
|
1146 | 1237 | # This is the detection pattern for an entire table being tagged from the "tags.rb" AsciiDoctor backend. |
1147 | 1238 | if text.end_with?("\n===") |
1148 | 1239 | # Limit table size displayed. |
1149 | | - truncate_after_newlines(text, 12) |
| 1240 | + truncate_after_newlines(text, MAX_TABLE_ROWS) |
1150 | 1241 | else |
1151 | 1242 | text |
1152 | 1243 | end |
@@ -1181,7 +1272,7 @@ def count_parameters(defs) |
1181 | 1272 | end |
1182 | 1273 |
|
1183 | 1274 | # Convert newlines to <br>. |
1184 | | -def html_convert_newlines(text) |
| 1275 | +def convert_newlines_to_html(text) |
1185 | 1276 | raise ArgumentError, "Expected String for text but was passed a #{text}.class" unless text.is_a?(String) |
1186 | 1277 |
|
1187 | 1278 | text.gsub(/\n/, '<br>') |
|
0 commit comments