// func(S) -> S static new ThreadLocal htmlTable2_cellEncoder; // htmlEncode = true static S htmlTable2(O data, O... _) { bool htmlEncode = optPar htmlEncode(_, true); bool useBr = boolPar useBr(_); Map paramsByColName = cast optPar paramsByColName(_); O[] tdParams = cast optPar tdParams(_); SS replaceHeaders = cast optPar replaceHeaders(_); // prepare table new L> rows; new L cols; if (data instanceof L) { for (O x : (L) data) pcall { rows.add(dataToTable_makeRow(x, cols)); } } else if (data instanceof Map) { Map map = cast data; for (O key : map.keySet()) { O value = map.get(key); rows.add(litlist(structureOrText(key), structureOrText(value))); } } else print("Unknown data type: " + data); // get table width int w = 0; for (L row : rows) w = max(w, l(row)); // construct HTML for table new StringBuilder buf; buf.append(hopeningtag('table, paramsPlus((O[]) optPar tableParams(_), border := html_valueLessParam())) + "\n"); // title buf.append("\n"); for (S cell : padList(cols, w, "?")) buf.append(" " + htmlTable2_encodeCell( getOrKeep(replaceHeaders, cell), htmlEncode, useBr) + "\n"); buf.append("\n"); // data for (L row : rows) { buf.append("\n"); int i = 0; for (S cell : padList(row, w, "")) { S col = get(cols, i++); O[] params = paramsPlus(tdParams, mapGet(paramsByColName, col)); buf.append(" " + tag('td, htmlTable2_encodeCell(cell, htmlEncode, useBr), params) + "\n"); } buf.append("\n"); } buf.append("\n"); ret buf.toString(); } static S htmlTable2_encodeCell(S cell, boolean useHtmlEncode, boolean useBr) { if (htmlTable2_cellEncoder! != null) ret (S) callF(htmlTable2_cellEncoder!, cell); if (useHtmlEncode) cell = htmlEncode2(cell); if (useBr) cell = nlToBr(cell); ret cell; }