define(["./Grid", "dojo/_base/declare", "put-selector/put"], function(Grid, declare, put){ // summary: // This module supports parsing grid structure information from an HTML table. // This module does NOT support ColumnSets; see GridWithColumnSetsFromHtml // name of data attribute to check for column properties var bagName = "data-dgrid-column"; function getSubRowsFromDom(domNode){ // summary: // generate columns from DOM. Should this be in here, or a separate module? var columns = [], // to be pushed upon / returned trs = domNode.getElementsByTagName("tr"), trslen = trs.length, getCol = GridFromHtml.utils.getColumnFromCell, rowColumns, tr, ths, thslen; for(var i = 0; i < trslen; i++){ rowColumns = []; columns.push(rowColumns); tr = trs[i]; ths = tr.getElementsByTagName("th"), thslen = ths.length; for(var j = 0; j < thslen; j++){ rowColumns.push(getCol(ths[j])); } } if(tr){ // NOTE: this assumes that applicable TRs were ONLY found under one // grouping element (e.g. thead) domNode.removeChild(tr.parentNode); } return columns; } var GridFromHtml = declare(Grid, { configStructure: function(){ // summary: // Configure subRows based on HTML originally in srcNodeRef if(!this._checkedTrs){ this._checkedTrs = true; this.subRows = getSubRowsFromDom(this.srcNodeRef, this.subRows); } return this.inherited(arguments); }, create: function(params, srcNodeRef){ // We need to replace srcNodeRef, presumably a table, with a div. // (Otherwise we'll generate highly invalid markup, which IE doesn't like) var div = document.createElement("div"), id = srcNodeRef.id, style = srcNodeRef.getAttribute("style"); // Copy some commonly-used attributes... if(id){ this.id = id; } // will be propagated in List's create div.className = srcNodeRef.className; style && div.setAttribute("style", style); // replace srcNodeRef in DOM with the div srcNodeRef.parentNode.replaceChild(div, srcNodeRef); (params = params || {}).srcNodeRef = srcNodeRef; // call inherited with the new node // (but configStructure will look at srcNodeRef) this.inherited(arguments, [params, div]); // destroy srcNodeRef for good now that we're done with it put(srcNodeRef, "!"); } }); // hang some utility functions, potentially useful for extensions GridFromHtml.utils = { // Functions for getting various types of values from HTML attributes getBoolFromAttr: function(node, attr){ // used for e.g. sortable var val = node.getAttribute(attr); return val && val !== "false"; }, getNumFromAttr: function(node, attr){ // used for e.g. rowSpan, colSpan var val = node.getAttribute(attr); val = val && Number(val); return isNaN(val) ? undefined : val; }, getPropsFromNode: function(node){ // used to pull properties out of bag e.g. "data-dgrid-column". var obj, str = node.getAttribute(bagName); if(!str){ return {}; } // no props bag specified! // Yes, eval is evil, but this is ultimately the same thing that // dojo.parser does for objects. try{ obj = eval("(" + str + ")"); }catch(e){ throw new Error("Error in " + bagName + " {" + str + "}: " + e.toString()); } return obj; }, // Function for aggregating th attributes into column properties getColumnFromCell: function(th){ var getNum = GridFromHtml.utils.getNumFromAttr, obj, tmp; // Look for properties in data attribute. // It's imperative that we hold on to this object as returned, as the // object may be augmented further by other sources, // e.g. Grid adding the grid property to reference the instance. obj = GridFromHtml.utils.getPropsFromNode(th); // inspect standard attributes, but data attribute takes precedence obj.label = "label" in obj ? obj.label : th.innerHTML; obj.field = obj.field || th.className || th.innerHTML; if(!obj.className && th.className){ obj.className = th.className; } if(!obj.rowSpan && (tmp = getNum(th, "rowspan"))){ obj.rowSpan = tmp; } if(!obj.colSpan && (tmp = getNum(th, "colspan"))){ obj.colSpan = tmp; } return obj; } }; return GridFromHtml; });