1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
6 * TablePrinter is a helper to format a table as ASCII art or an HTML table.
8 * Usage: call addRow() and addCell() repeatedly to specify the data.
10 * addHeaderCell() can optionally be called to specify header cells for a
11 * single header row. The header row appears at the top of an HTML formatted
12 * table, and uses thead and th tags. In ascii tables, the header is separated
13 * from the table body by a partial row of dashes.
15 * setTitle() can optionally be used to set a title that is displayed before
16 * the header row. In HTML tables, it uses the title class and in ascii tables
17 * it's between two rows of dashes.
19 * Once all the fields have been input, call toText() to format it as text or
20 * toHTML() to format it as HTML.
22 var TablePrinter
= (function() {
28 function TablePrinter() {
30 this.hasHeaderRow_
= false;
32 // Number of cells automatically added at the start of new rows.
33 this.newRowCellIndent_
= 0;
36 TablePrinter
.prototype = {
38 * Sets the number of blank cells to add after each call to addRow.
40 setNewRowCellIndent: function(newRowCellIndent
) {
41 this.newRowCellIndent_
= newRowCellIndent
;
49 for (var i
= 0; i
< this.newRowCellIndent_
; ++i
)
54 * Adds a column to the current row, setting its value to cellText.
56 * @return {!TablePrinterCell} the cell that was added.
58 addCell: function(cellText
) {
59 var r
= this.rows_
[this.rows_
.length
- 1];
60 var cell
= new TablePrinterCell(cellText
);
66 * Sets the title displayed at the top of a table. Titles are optional.
68 setTitle: function(title
) {
73 * Adds a header row, if not already present, and adds a new column to it,
74 * setting its contents to |headerText|.
76 * @return {!TablePrinterCell} the cell that was added.
78 addHeaderCell: function(headerText
) {
79 // Insert empty new row at start of |rows_| if currently no header row.
80 if (!this.hasHeaderRow_
) {
81 this.rows_
.splice(0, 0, []);
82 this.hasHeaderRow_
= true;
84 var cell
= new TablePrinterCell(headerText
);
85 this.rows_
[0].push(cell
);
90 * Returns the maximum number of columns this table contains.
92 getNumColumns: function() {
94 for (var i
= 0; i
< this.rows_
.length
; ++i
) {
95 numColumns
= Math
.max(numColumns
, this.rows_
[i
].length
);
101 * Returns the cell at position (rowIndex, columnIndex), or null if there is
104 getCell_: function(rowIndex
, columnIndex
) {
105 if (rowIndex
>= this.rows_
.length
)
107 var row
= this.rows_
[rowIndex
];
108 if (columnIndex
>= row
.length
)
110 return row
[columnIndex
];
114 * Returns true if searchString can be found entirely within a cell.
117 * @param {string} string String to search for, must be lowercase.
118 * @return {boolean} True if some cell contains searchString.
120 search: function(searchString
) {
121 var numColumns
= this.getNumColumns();
122 for (var r
= 0; r
< this.rows_
.length
; ++r
) {
123 for (var c
= 0; c
< numColumns
; ++c
) {
124 var cell
= this.getCell_(r
, c
);
127 if (cell
.text
.toLowerCase().indexOf(searchString
) != -1)
135 * Prints a formatted text representation of the table data to the
136 * node |parent|. |spacing| indicates number of extra spaces, if any,
137 * to add between columns.
139 toText: function(spacing
, parent
) {
140 var pre
= addNode(parent
, 'pre');
141 var numColumns
= this.getNumColumns();
143 // Figure out the maximum width of each column.
144 var columnWidths
= [];
145 columnWidths
.length
= numColumns
;
146 for (var i
= 0; i
< numColumns
; ++i
)
149 // If header row is present, temporarily add a spacer row to |rows_|.
150 if (this.hasHeaderRow_
) {
151 var headerSpacerRow
= [];
152 for (var c
= 0; c
< numColumns
; ++c
) {
153 var cell
= this.getCell_(0, c
);
156 var spacerStr
= makeRepeatedString('-', cell
.text
.length
);
157 headerSpacerRow
.push(new TablePrinterCell(spacerStr
));
159 this.rows_
.splice(1, 0, headerSpacerRow
);
162 var numRows
= this.rows_
.length
;
163 for (var c
= 0; c
< numColumns
; ++c
) {
164 for (var r
= 0; r
< numRows
; ++r
) {
165 var cell
= this.getCell_(r
, c
);
166 if (cell
&& !cell
.allowOverflow
) {
167 columnWidths
[c
] = Math
.max(columnWidths
[c
], cell
.text
.length
);
174 // Print title, if present.
176 var titleSpacerStr
= makeRepeatedString('-', this.title_
.length
);
177 out
.push(titleSpacerStr
);
179 out
.push(this.title_
);
181 out
.push(titleSpacerStr
);
186 var spacingStr
= makeRepeatedString(' ', spacing
);
187 for (var r
= 0; r
< numRows
; ++r
) {
188 for (var c
= 0; c
< numColumns
; ++c
) {
189 var cell
= this.getCell_(r
, c
);
191 // Pad the cell with spaces to make it fit the maximum column width.
192 var padding
= columnWidths
[c
] - cell
.text
.length
;
193 var paddingStr
= makeRepeatedString(' ', padding
);
196 out
.push(paddingStr
);
198 // Output all previous text, and clear |out|.
199 addTextNode(pre
, out
.join(''));
202 var linkNode
= addNodeWithText(pre
, 'a', cell
.text
);
203 linkNode
.href
= cell
.link
;
207 if (!cell
.alignRight
)
208 out
.push(paddingStr
);
209 out
.push(spacingStr
);
215 // Remove spacer row under the header row, if one was added.
216 if (this.hasHeaderRow_
)
217 this.rows_
.splice(1, 1);
219 addTextNode(pre
, out
.join(''));
223 * Adds a new HTML table to the node |parent| using the specified style.
225 toHTML: function(parent
, style
) {
226 var numRows
= this.rows_
.length
;
227 var numColumns
= this.getNumColumns();
229 var table
= addNode(parent
, 'table');
230 table
.setAttribute('class', style
);
232 var thead
= addNode(table
, 'thead');
233 var tbody
= addNode(table
, 'tbody');
235 // Add title, if needed.
237 var tableTitleRow
= addNode(thead
, 'tr');
238 var tableTitle
= addNodeWithText(tableTitleRow
, 'th', this.title_
);
239 tableTitle
.colSpan
= numColumns
;
240 tableTitle
.classList
.add('title');
243 // Fill table body, adding header row first, if needed.
244 for (var r
= 0; r
< numRows
; ++r
) {
247 if (r
== 0 && this.hasHeaderRow_
) {
248 row
= addNode(thead
, 'tr');
251 row
= addNode(tbody
, 'tr');
254 for (var c
= 0; c
< numColumns
; ++c
) {
255 var cell
= this.getCell_(r
, c
);
257 var tableCell
= addNode(row
, cellType
, cell
.text
);
259 tableCell
.alignRight
= true;
260 // If allowing overflow on the rightmost cell of a row,
261 // make the cell span the rest of the columns. Otherwise,
263 if (cell
.allowOverflow
&& !this.getCell_(r
, c
+ 1))
264 tableCell
.colSpan
= numColumns
- c
;
266 var linkNode
= addNodeWithText(tableCell
, 'a', cell
.text
);
267 linkNode
.href
= cell
.link
;
269 addTextNode(tableCell
, cell
.text
);
279 * Links are only used in HTML tables.
281 function TablePrinterCell(value
) {
282 this.text
= '' + value
;
284 this.alignRight
= false;
285 this.allowOverflow
= false;