define(["dojo/_base/kernel", "dojo/_base/declare", "dojo/on", "dojo/has", "put-selector/put", "./List", "./util/misc", "dojo/_base/sniff"], function(kernel, declare, listen, has, put, List, miscUtil){ var contentBoxSizing = has("ie") < 8 && !has("quirks"); var invalidClassChars = /[^\._a-zA-Z0-9-]/g; function appendIfNode(parent, subNode){ if(subNode && subNode.nodeType){ parent.appendChild(subNode); } } var Grid = declare(List, { columns: null, // cellNavigation: Boolean // This indicates that focus is at the cell level. This may be set to false to cause // focus to be at the row level, which is useful if you want only want row-level // navigation. cellNavigation: true, tabableHeader: true, showHeader: true, column: function(target){ // summary: // Get the column object by node, or event, or a columnId if(typeof target != "object"){ return this.columns[target]; }else{ return this.cell(target).column; } }, listType: "grid", cell: function(target, columnId){ // summary: // Get the cell object by node, or event, id, plus a columnId if(target.column && target.element){ return target; } if(target.target && target.target.nodeType){ // event target = target.target; } var element; if(target.nodeType){ var object; do{ if(this._rowIdToObject[target.id]){ break; } var colId = target.columnId; if(colId){ columnId = colId; element = target; break; } target = target.parentNode; }while(target && target != this.domNode); } if(!element && typeof columnId != "undefined"){ var row = this.row(target), rowElement = row && row.element; if(rowElement){ var elements = rowElement.getElementsByTagName("td"); for(var i = 0; i < elements.length; i++){ if(elements[i].columnId == columnId){ element = elements[i]; break; } } } } if(target != null){ return { row: row || this.row(target), column: columnId && this.column(columnId), element: element }; } }, createRowCells: function(tag, each, subRows, object){ // summary: // Generates the grid for each row (used by renderHeader and and renderRow) var row = put("table.dgrid-row-table[role=presentation]"), cellNavigation = this.cellNavigation, // IE < 9 needs an explicit tbody; other browsers do not tbody = (has("ie") < 9 || has("quirks")) ? put(row, "tbody") : row, tr, si, sl, i, l, // iterators subRow, column, id, extraClasses, className, cell, innerCell, colSpan, rowSpan; // used inside loops // Allow specification of custom/specific subRows, falling back to // those defined on the instance. subRows = subRows || this.subRows; for(si = 0, sl = subRows.length; si < sl; si++){ subRow = subRows[si]; // for single-subrow cases in modern browsers, TR can be skipped // http://jsperf.com/table-without-trs tr = put(tbody, "tr"); if(subRow.className){ put(tr, "." + subRow.className); } for(i = 0, l = subRow.length; i < l; i++){ // iterate through the columns column = subRow[i]; id = column.id; extraClasses = column.field ? ".field-" + column.field : ""; className = typeof column.className === "function" ? column.className(object) : column.className; if(className){ extraClasses += "." + className; } cell = put(tag + ( ".dgrid-cell.dgrid-cell-padding" + (id ? ".dgrid-column-" + id : "") + extraClasses.replace(/ +/g, ".") ).replace(invalidClassChars,"-") + "[role=" + (tag === "th" ? "columnheader" : "gridcell") + "]"); cell.columnId = id; if(contentBoxSizing){ // The browser (IE7-) does not support box-sizing: border-box, so we emulate it with a padding div innerCell = put(cell, "!dgrid-cell-padding div.dgrid-cell-padding");// remove the dgrid-cell-padding, and create a child with that class cell.contents = innerCell; }else{ innerCell = cell; } colSpan = column.colSpan; if(colSpan){ cell.colSpan = colSpan; } rowSpan = column.rowSpan; if(rowSpan){ cell.rowSpan = rowSpan; } each(innerCell, column); // add the td to the tr at the end for better performance tr.appendChild(cell); } } return row; }, left: function(cell, steps){ if(!cell.element){ cell = this.cell(cell); } return this.cell(this._move(cell, -(steps || 1), "dgrid-cell")); }, right: function(cell, steps){ if(!cell.element){ cell = this.cell(cell); } return this.cell(this._move(cell, steps || 1, "dgrid-cell")); }, renderRow: function(object, options){ var self = this; var row = this.createRowCells("td", function(td, column){ var data = object; // Support get function or field property (similar to DataGrid) if(column.get){ data = column.get(object); }else if("field" in column && column.field != "_item"){ data = data[column.field]; } if(column.renderCell){ // A column can provide a renderCell method to do its own DOM manipulation, // event handling, etc. appendIfNode(td, column.renderCell(object, data, td, options)); }else{ defaultRenderCell.call(column, object, data, td, options); } }, options && options.subRows, object); // row gets a wrapper div for a couple reasons: // 1. So that one can set a fixed height on rows (heights can't be set on