3 Copyright 2012 Yahoo! Inc. All rights reserved.
4 Licensed under the BSD License.
5 http://yuilibrary.com/license/
7 YUI.add('datatable-column-widths', function(Y) {
10 Adds basic, programmatic column width support to DataTable via column
11 configuration property `width` and method `table.setColumnWidth(id, width);`.
14 @submodule datatable-column-widths
17 var isNumber = Y.Lang.isNumber,
18 arrayIndex = Y.Array.indexOf;
20 Y.Features.add('table', 'badColWidth', {
22 var body = Y.one('body'),
26 // In modern browsers, <col style="width:X"> will make columns,
27 // *including padding and borders* X wide. The cell content width
28 // is reduced. In old browsers and all Opera versions to date, the
29 // col's width style is passed to the cells, which causes cell
30 // padding/border to bloat the rendered width.
31 node = body.insertBefore(
32 '<table style="position:absolute;visibility:hidden;border:0 none">' +
33 '<colgroup><col style="width:9px"></colgroup>' +
37 'font:normal 2px/2px arial;' +
39 '.' + // Just something to give the cell dimension
40 '</td></tr></tbody>' +
42 body.get('firstChild'));
44 broken = node.one('td').getComputedStyle('width') !== '1px';
54 _API docs for this extension are included in the DataTable class._
56 Adds basic, programmatic column width support to DataTable. Note, this does not
57 add support for truncated columns. Due to the way HTML tables render, column
58 width is more like a "recommended width". Column content wider than the
59 assigned width will cause the column to expand, despite the configured width.
60 Similarly if the table is too narrow to fit the column with the configured
61 column width, the column width will be reduced.
63 To set a column width, either add a `width` value to the column configuration
64 or call the `setColumnWidth(id, width)` method.
66 Note, assigning column widths is possible without this module, as each cell is
67 decorated with a class appropriate for that column which you can statically
68 target in your site's CSS.
70 To achieve absolute column widths, with content truncation, you can either:
72 1. Use this module, configure *all* columns to have `width`s, then add
73 `table-layout: fixed;` to your CSS for the appropriate `<table>`, or
74 2. Wrap the contents of all cells in the column with a `<div>` (using a
75 `cellTemplate` or `formatter`), assign the div's style `width`, then assign
76 the column `width` or add a CSS `width` to the column class created by
79 <pre><code>.yui3-datatable .yui3-datatable-col-foo {
83 .yui3-datatable .yui3-datatable-col-foo .yui3-datatable-liner {
90 <pre><code>var table = new Y.DataTable({
95 '<td class="{className}">' +
96 '<div class="yui3-datatable-liner">{content}</div>' +
105 To add a liner to all columns, either provide a custom `bodyView` to the
106 DataTable constructor or update the default `bodyView`'s `CELL_TEMPLATE` like
109 <pre><code>table.on('renderBody', function (e) {
110 e.view.CELL_TEMPLATE = e.view.CELL_TEMPLATE.replace(/\{content\}/,
111 '<div class="yui3-datatable-liner">{content}</div>');
115 Keep in mind that DataTable skins apply cell `padding`, so assign your CSS
116 `width`s accordingly or override the `padding` style for that column's `<td>`s
117 to 0, and add `padding` to the liner `<div>`'s styles as shown above.
119 @class DataTable.ColumnWidths
123 function ColumnWidths() {}
125 Y.mix(ColumnWidths.prototype, {
127 The HTML template used to create the table's `<col>`s.
129 @property COL_TEMPLATE
134 COL_TEMPLATE: '<col/>',
137 The HTML template used to create the table's `<colgroup>`.
139 @property COLGROUP_TEMPLATE
141 @default '<colgroup/>'
144 COLGROUP_TEMPLATE: '<colgroup/>',
147 Assigns the style width of the `<col>` representing the column identifed by
148 `id` and updates the column configuration.
150 Pass the empty string for `width` to return a column to auto sizing.
152 This does not trigger a `columnsChange` event today, but I can be convinced
155 @method setColumnWidth
156 @param {Number|String|Object} id The column config object or key, name, or
157 index of a column in the host's `_displayColumns` array.
158 @param {Number|String} width CSS width value. Numbers are treated as pixels
163 setColumnWidth: function (id, width) {
164 var col = this.getColumn(id),
165 index = col && arrayIndex(this._displayColumns, col);
168 if (isNumber(width)) {
174 this._setColumnWidth(index, width);
180 //----------------------------------------------------------------------------
181 // Protected properties and methods
182 //----------------------------------------------------------------------------
185 Renders the table's `<colgroup>` and populates the `_colgroupNode` property.
187 @method _createColumnGroup
191 _createColumnGroup: function () {
192 return Y.Node.create(this.COLGROUP_TEMPLATE);
196 Hooks up to the rendering lifecycle to also render the `<colgroup>` and
197 subscribe to `columnChange` events.
203 initializer: function (config) {
204 this.after('renderTable', function (e) {
205 this._uiSetColumns();
207 this.after('columnsChange', this._uiSetColumns);
212 Sets a columns's `<col>` element width style. This is needed to get around
213 browser rendering differences.
215 The colIndex corresponds to the item index of the `<col>` in the table's
218 To unset the width, pass a falsy value for the `width`.
220 @method _setColumnWidth
221 @param {Number} colIndex The display column index
222 @param {Number|String} width The desired width
226 // TODO: move this to a conditional module
227 _setColumnWidth: function (colIndex, width) {
228 // Opera (including Opera Next circa 1/13/2012) and IE7- pass on the
229 // width style to the cells directly, allowing padding and borders to
230 // expand the rendered width. Chrome 16, Safari 5.1.1, and FF 3.6+ all
231 // make the rendered width equal the col's style width, reducing the
232 // cells' calculated width.
233 var colgroup = this._colgroupNode,
234 col = colgroup && colgroup.all('col').item(colIndex),
235 firstRow, cell, getCStyle;
238 if (width && isNumber(width)) {
242 col.setStyle('width', width);
244 // Adjust the width for browsers that make
245 // td.style.width === col.style.width
246 if (width && Y.Features.test('table', 'badColWidth')) {
247 firstRow = this._tbodyNode && this._tbodyNode.one('tr');
248 cell = firstRow && firstRow.all('td').item(colIndex);
251 getCStyle = function (prop) {
252 return parseInt(cell.getComputedStyle(prop), 10)|0;
255 col.setStyle('width',
257 parseInt(width, 10) -
258 getCStyle('paddingLeft') -
259 getCStyle('paddingRight') -
260 getCStyle('borderLeftWidth') -
261 getCStyle('borderRightWidth') + 'px');
269 Populates the table's `<colgroup>` with a `<col>` per item in the `columns`
270 attribute without children. It is assumed that these are the columns that
271 have data cells renderered for them.
273 @method _uiSetColumns
277 _uiSetColumns: function () {
278 var template = this.COL_TEMPLATE,
279 colgroup = this._colgroupNode,
280 columns = this._displayColumns,
284 colgroup = this._colgroupNode = this._createColumnGroup();
286 this._tableNode.insertBefore(
288 this._tableNode.one('> thead, > tfoot, > tbody'));
293 for (i = 0, len = columns.length; i < len; ++i) {
295 colgroup.append(template);
297 this._setColumnWidth(i, columns[i].width);
302 Y.DataTable.ColumnWidths = ColumnWidths;
304 Y.Base.mix(Y.DataTable, [ColumnWidths]);
307 }, '3.5.0' ,{requires:['datatable-base']});