This is the continuation of my last Blog about adjusting columns of nested tables. After I managed to categorize all cells and thus assign them to a column, I should be able to size them now.
Years ago browsers had quite different techniques to format tables. There was the special table-layout: fixed;
CSS property that allowed to size cells. Nowadays browsers accept a fixed cell width even without that property, and when you set the width to both CSS width
and min-width
, the table layout also survives window resizes. Should you have tables that change their cell values "on the fly", it is also recommendable to set the max-width
, and with it overflow-x: hidden;
to avoid big contents hanging into other cells.
With colspan
cells there is special problem. I decided to not touch such cells at all, and until now this worked in all cases. But a prerequisite for that is that all nested tables are stretched to 100% width, so that the colspan-cells will spread between their sized neighbor cells.
From the tableColumnCategorizer
module's init()
call I get back a map of arrays, and every array represents all categorized elements of a certain nesting-level. I find the category of an element in its data-layout-category
attribute.
So now I can iterate the map, starting from deepest nesting level, going up to zero. On every level I can calculate the maximum cell width for every category (visible column). Subsequently I can size all cells of a category to their maximum. To cope also with colspan
cells, all nested tables are finally stretched to 100% width.
1 | "use strict"; |
For optimal encapsulation the module is split into private (var xxx = ..."
) and public (that.xxx = ..."
) functions. Mind that functions that do not yet exist, like that.setSize
, are called as if they would exist. JS makes this possible, but the function must be there at runtime.
The
calculateMaximums()
function receives an array of elements. It creates a map and uses the category of every element as key for it. For every category the maximum is calculated. The map is returned for further processing.The
calculateAndSize()
function sets the calculated maximum sizes to all elements with the according category.The
stretchNestedContainers()
function loops over given nested tables and sets 100% width to them. For each such table it makes sure that all parents up to the next categorized cell are also sized to 100%, else the 100% would make no sense. Note thatstretchElement()
is not implemented yet, because I do not yet decide to stretch the width, it could be the height too.The
init()
function first calls the givencategorizer
for a map of level arrays. It then counts the levels and loops them bottom-up. After callingcalculateAndSize()
with all of them it makes sure that all nested tables and their parents are sized to 100% width. It then returns, per given table, an object containing the level-array-map and the maximum level of that table (yes, JS does not provide the size of a map in a property!).
This module contains nothing specific to HTML TABLE, not even the functions to get and set sizes. That way it could be also used for adjusting row heights (mind that I named the function setSize
and not setWidth
). A specific module deriving this one will decide how the work is to be done, in this case by reading the JS property clientWidth
, and writing the CSS property width
.
1 | "use strict"; |
This synchronizes the column widths of nested TABLE elements, whereby the given top-element needs not to be a TABLE, it could also be a DIV.
The
getPaddingsLeftRight()
function calculates the horizontal paddings of an element. This is needed because I set the CSSwidth
from the read-only JS propertyclientWidth
, and this includes paddings, butwidth
does not.The
isElementToSize()
implementation makes sure that only elements withoutcolspan
are sized.The
getSize()
implementation uses theclientWidth
of an element. This includes the element's padding.The
setSize()
implementation turns the (maximum)clientWidth
into a CSSwidth
by subtracting horizontal paddings of the target element. Then it sets all three ofwidth, min-width, max-width
to the same pixel value. Additionally it prevents contents to be written into other cells by settingoverflow
to"hidden"
.The
getNestedContainers()
function uses thequerySelectorAll()
element function to retrieve all TABLE elements from given parent.The
stretchElement()
function resetsmin-width
andmax-width
, and then setswidth
to 100%.
To try this out, mark your test-TABLE with CSS class="layoutNestedTables"
and write following initialization-JS into your test page. Of course you also will need all code from predecessor Blog.
<script type="text/javascript">
"use strict";
var initLayout = function() {
var tables = document.getElementsByClassName("layoutNestedTables");
for (var i = 0; i < tables.length; i++) /* set tables invisible while layouting them */
tables[i].style.visibility = "hidden";
var categorizer = tableColumnCategorizer();
var columnAdjuster = nestedTablesColumnAdjuster(categorizer);
columnAdjuster.init(tables);
for (var i = 0; i < tables.length; i++) /* set tables visible again */
tables[i].style.visibility = "visible";
};
window.addEventListener("load", initLayout);
</script>
This sets all tables to adjust to invisible. Then it allocates a categorizer and an adjuster and makes them work. Finally all tables are set visible again. This is for avoiding probably slow layout work done before the user's eye.
The remaining topics for layout of nested tables are
Hope I will soon find time to document that all.
ɔ⃝ Fritz Ritzberger, 2016-02-07