Permalink
Cannot retrieve contributors at this time
Fetching contributors…
| /*! | |
| * Web Experience Toolkit (WET) / Boîte à outils de l'expérience Web (BOEW) | |
| * wet-boew.github.com/wet-boew/License-eng.txt / wet-boew.github.com/wet-boew/Licence-fra.txt | |
| */ | |
| /** | |
| * Table Parser - Table usability - Core plugin | |
| * | |
| * @author: Pierre Dubois | |
| * | |
| */ | |
| /*global jQuery: false*/ | |
| (function ($) { | |
| "use strict"; | |
| var _pe = window.pe || { | |
| fn : {} | |
| }; | |
| _pe.fn.parsertable = { | |
| onParserError: undefined, | |
| parse : function (elm) { | |
| var obj = elm, | |
| // Event handler for issue error found durring the table parsing process | |
| errorTrigger = function (numerr, obj) { | |
| // FYI - 31 Type of Error can be raised | |
| if (typeof _pe.fn.parsertable.onParserError === "function") { | |
| _pe.fn.parsertable.onParserError(numerr, obj); | |
| } | |
| // $(obj).trigger('parser.table.error', err, obj); | |
| // console.log("Trigger ERROR: " + err); // Debug Mode | |
| }, | |
| groupZero = { | |
| allParserObj: [], | |
| nbDescriptionRow: 0 // To remove ?? | |
| }, | |
| colgroupFrame = [], | |
| columnFrame = [], | |
| uidElem = 0, | |
| currentRowLevel = 0, | |
| currentRowPos = 0, | |
| spannedRow = [], | |
| tableCellWidth = 0, | |
| headerRowGroupCompleted = false, | |
| summaryRowGroupEligible = false, | |
| currentRowHeader = [], | |
| currentTbodyID, | |
| theadRowStack = [], | |
| stackRowHeader = false, | |
| // Row Group Variable | |
| rowgroupHeaderRowStack = [], | |
| currentRowGroup, | |
| currentRowGroupElement, | |
| lstRowGroup = [], | |
| rowgroupheadercalled = false, | |
| hasTfoot = $(obj).has('tfoot'), | |
| lastHeadingSummaryColPos, | |
| previousDataHeadingColPos, | |
| tfootOnProcess = false, | |
| hassumMode = false; | |
| // elm need to be a table | |
| if ($(elm).get(0).nodeName.toLowerCase() !== 'table') { | |
| errorTrigger(1, elm); | |
| return; | |
| } | |
| // Check if this table was already parsed, if yes we exit by throwing an error | |
| if ($(obj).tblparser) { | |
| errorTrigger(2, obj); | |
| return; | |
| } | |
| // Check for hassum mode | |
| hassumMode = $(elm).hasClass('hassum'); | |
| /* | |
| +-----------------------------------------------------+ | |
| | FYI - Here the value and signification of each type | | |
| +-------+---------------+-----------------------------+ | |
| | Type | Signification | Technicality | |
| +-------+---------------+------------------------------ | |
| | 1 | Header | TH element only | |
| +-------+---------------+------------------------------ | |
| | 2 | Data | TD element only | |
| +-------+---------------+------------------------------ | |
| | 3 | Summary | TD element and TD of type 2 exist | |
| +-------+---------------+------------------------------ | |
| | 4 | Key | TD element applicable to right TH, Only available on row | |
| +-------+---------------+------------------------------ | |
| | 5 | Description | TD element applicable to left or top TH | |
| +-------+---------------+------------------------------ | |
| | 6 | Layout | Can be only: Top Left cell or/and Summmary group intersection | |
| +-------+---------------+------------------------------ | |
| | 7 | Header Group | TH element only, visual heading grouping, this type are an extension of the type 1 | |
| +-------+---------------+------------------------------ | |
| */ | |
| $(obj).data().tblparser = groupZero; | |
| groupZero.colgroup = colgroupFrame; | |
| if (!groupZero.rowgroup) { | |
| groupZero.rowgroup = []; | |
| } | |
| if (!groupZero.lstrowgroup) { | |
| // groupZero.lstrowgroup = []; | |
| groupZero.lstrowgroup = lstRowGroup; | |
| } | |
| groupZero.elem = obj; | |
| groupZero.uid = uidElem; | |
| uidElem += 1; // Set the uid for the groupZero | |
| groupZero.colcaption = {}; // Group Cell Header at level 0, scope=col | |
| groupZero.colcaption.uid = uidElem; | |
| uidElem += 1; | |
| groupZero.colcaption.elem = undefined; | |
| groupZero.colcaption.type = 7; | |
| groupZero.colcaption.dataset = []; | |
| groupZero.colcaption.summaryset = []; | |
| groupZero.rowcaption = {}; // Group Cell Header at level 0, scope=row | |
| groupZero.rowcaption.uid = uidElem; | |
| uidElem += 1; | |
| groupZero.rowcaption.elem = undefined; | |
| groupZero.rowcaption.type = 7; | |
| groupZero.rowcaption.dataset = []; | |
| groupZero.rowcaption.summaryset = []; | |
| groupZero.col = []; | |
| function processCaption(elem) { | |
| groupZero.colcaption.elem = elem; | |
| groupZero.rowcaption.elem = elem; | |
| var groupheadercell = { | |
| colcaption: groupZero.colcaption, | |
| rowcaption: groupZero.rowcaption, | |
| elem: elem | |
| }, | |
| caption, | |
| captionFound, | |
| description = []; | |
| // Extract the caption vs the description | |
| // There are 2 techniques, | |
| // Recommanded is encapsulate the caption with "strong" | |
| // Use Details/Summary element | |
| // Use a simple paragraph | |
| if ($(elem).children().length > 0) { | |
| // Use the contents function to retreive the caption | |
| $(elem).contents().filter(function () { | |
| if (!caption && this.nodeType === 3) { // Text Node | |
| // Doesn't matter what it is, but this will be considerated as the caption | |
| // if is not empty | |
| caption = $(this).text().replace(/^\s+|\s+$/g, ""); | |
| if (caption.length !== 0) { | |
| caption = this; | |
| captionFound = true; | |
| return; | |
| } | |
| caption = false; | |
| } else if (!caption && this.nodeType === 1) { | |
| // Doesn't matter what it is, the first children element will be considerated as the caption | |
| caption = this; | |
| return; | |
| } | |
| }); | |
| // Use the children function to retreive the description | |
| $(elem).children().filter(function () { | |
| // if the caption are an element, we should ignore the first one | |
| if (captionFound) { | |
| description.push(this); | |
| } else { | |
| captionFound = true; | |
| } | |
| }); | |
| } else { | |
| caption = elem; | |
| } | |
| // console.log(caption); | |
| // Move the descriptin in a wrapper if there is more than one element | |
| if (description.length > 1) { | |
| groupheadercell.description = $(description); | |
| } else if (description.length === 1) { | |
| groupheadercell.description = description[0]; | |
| } | |
| if (caption) { | |
| groupheadercell.caption = caption; | |
| } | |
| groupheadercell.groupZero = groupZero; | |
| groupheadercell.type = 1; | |
| groupZero.groupheadercell = groupheadercell; | |
| $(elem).data().tblparser = groupheadercell; | |
| } | |
| function processColgroup(elem, nbvirtualcol) { | |
| // if elem is undefined, this mean that is an big empty colgroup | |
| // nbvirtualcol if defined is used to create the virtual colgroup | |
| var colgroup = { | |
| elem: {}, | |
| start: 0, | |
| end: 0, | |
| col: [], | |
| groupZero: groupZero | |
| }, | |
| colgroupspan = 0, | |
| width, | |
| i, | |
| _ilen, | |
| col; | |
| colgroup.elem = elem; | |
| if (elem) { | |
| $(elem).data().tblparser = colgroup; | |
| } | |
| colgroup.uid = uidElem; | |
| uidElem += 1; | |
| groupZero.allParserObj.push(colgroup); | |
| if (colgroupFrame.length !== 0) { | |
| colgroup.start = colgroupFrame[colgroupFrame.length - 1].end + 1; | |
| } else { | |
| colgroup.start = 1; | |
| } | |
| // Add any exist structural col element | |
| if (elem) { | |
| $('col', elem).each(function () { | |
| var $this = $(this), | |
| width = $this.attr('span') !== undefined ? parseInt($this.attr('span'), 10) : 1, | |
| col = { | |
| elem: {}, | |
| start: 0, | |
| end: 0, | |
| groupZero: groupZero | |
| }; | |
| col.uid = uidElem; | |
| uidElem += 1; | |
| groupZero.allParserObj.push(col); | |
| col.start = colgroup.start + colgroupspan; | |
| col.end = colgroup.start + colgroupspan + width - 1; // Minus one because the default value was already calculated | |
| col.elem = this; | |
| col.groupZero = groupZero; | |
| $this.data().tblparser = col; | |
| colgroup.col.push(col); | |
| columnFrame.push(col); | |
| colgroupspan += width; | |
| }); | |
| } | |
| // If no col element check for the span attribute | |
| if (colgroup.col.length === 0) { | |
| if (elem) { | |
| width = $(elem).attr('span') !== undefined ? parseInt($(elem).attr('span'), 10) : 1; | |
| } else if (typeof nbvirtualcol === "number") { | |
| width = nbvirtualcol; | |
| } else { | |
| errorTrigger(31); | |
| return; | |
| } | |
| colgroupspan += width; | |
| // Create virtual column | |
| for (i = colgroup.start, _ilen = (colgroup.start + colgroupspan); i < _ilen; i += 1) { | |
| col = { | |
| start: 0, | |
| end: 0, | |
| groupZero: groupZero, | |
| elem: undefined | |
| }; | |
| col.uid = uidElem; | |
| uidElem += 1; | |
| groupZero.allParserObj.push(col); | |
| col.start = i; | |
| col.end = i; | |
| colgroup.col.push(col); | |
| columnFrame.push(col); | |
| } | |
| } | |
| colgroup.end = colgroup.start + colgroupspan - 1; | |
| colgroupFrame.push(colgroup); | |
| } | |
| function processRowgroupHeader(colgroupHeaderColEnd) { // thead row group processing | |
| var i, _ilen, | |
| j, _jlen, | |
| m, _mlen, | |
| tmpStack = [], | |
| tmpStackCurr, | |
| tmpStackCell, | |
| dataColgroup, | |
| dataColumns, | |
| colgroup, | |
| col, | |
| hcolgroup, | |
| lstRealColgroup, | |
| currColPos, | |
| currColgroupStructure, | |
| colFrmId, | |
| bigTotalColgroupFound, | |
| theadRSNext, | |
| theadRSNextCell, | |
| cell, | |
| gzCol, | |
| theadRS; | |
| if (groupZero.colgrouphead || rowgroupheadercalled) { | |
| return; // Prevent multiple call | |
| } | |
| rowgroupheadercalled = true; | |
| if (colgroupHeaderColEnd && colgroupHeaderColEnd > 0) { | |
| // The first colgroup must match the colgroupHeaderColEnd | |
| if (colgroupFrame.length > 0 && (colgroupFrame[0].start !== 1 || (colgroupFrame[0].end !== colgroupHeaderColEnd && colgroupFrame[0].end !== (colgroupHeaderColEnd + 1)))) { | |
| errorTrigger(3); | |
| // Destroy any existing colgroup, because they are not valid | |
| colgroupFrame = []; | |
| } | |
| } else { | |
| colgroupHeaderColEnd = 0; // This mean that are no colgroup designated to be a colgroup header | |
| } | |
| // console.log('Call ProcessRowGroupHeader'); | |
| // Associate any descriptive cell to his top header | |
| for (i = 0, _ilen = theadRowStack.length; i < _ilen; i += 1) { | |
| theadRS = theadRowStack[i]; | |
| if (!theadRS.type) { | |
| theadRS.type = 1; | |
| } | |
| for (j = 0, _jlen = theadRS.cell.length; j < _jlen; j += 1) { | |
| cell = theadRowStack[i].cell[j]; | |
| cell.scope = "col"; | |
| // check if we have a layout cell at the top, left | |
| if (i === 0 && j === 0 && $(cell.elem).html().length === 0) { | |
| // That is a layout cell | |
| cell.type = 6; // Layout cell | |
| if (!groupZero.layoutCell) { | |
| groupZero.layoutCell = []; | |
| } | |
| groupZero.layoutCell.push(cell); | |
| j = cell.width - 1; | |
| if (j >= _jlen) { | |
| break; | |
| } | |
| } | |
| // Check the next row to see if they have a corresponding description cell | |
| theadRSNext = theadRowStack[i + 1]; | |
| theadRSNextCell = (theadRSNext ? theadRSNext.cell[j] : ""); | |
| if (!cell.descCell && | |
| cell.elem.nodeName.toLowerCase() === 'th' && | |
| !cell.type && | |
| theadRSNext && | |
| theadRSNext.uid !== cell.uid && | |
| theadRSNextCell && | |
| !theadRSNextCell.type && | |
| theadRSNextCell.elem.nodeName.toLowerCase() === 'td' && | |
| theadRSNextCell.width === cell.width && | |
| theadRSNextCell.height === 1) { | |
| theadRSNext.type = 5; // Mark the next row as a row description | |
| theadRSNextCell.type = 5; // Mark the cell as a cell description | |
| theadRSNextCell.row = theadRS; | |
| cell.descCell = theadRSNextCell; | |
| // Add the description cell to the complete listing | |
| if (!groupZero.desccell) { | |
| groupZero.desccell = []; | |
| } | |
| groupZero.desccell.push(theadRSNextCell); | |
| j = cell.width - 1; | |
| if (j >= _jlen) { | |
| break; | |
| } | |
| } | |
| if (!cell.type) { | |
| cell.type = 1; | |
| } | |
| } | |
| } | |
| // Clean the theadRowStack by removing any descriptive row | |
| for (i = 0, _ilen = theadRowStack.length; i < _ilen; i += 1) { | |
| theadRS = theadRowStack[i]; | |
| if (theadRS.type === 5) { | |
| // Check if all the cell in it are set to the type 5 | |
| for (j = 0, _jlen = theadRS.cell.length; j < _jlen; j += 1) { | |
| cell = theadRS.cell[j]; | |
| if (cell.type !== 5 && cell.type !== 6 && cell.height === 1) { | |
| errorTrigger(4, cell.elem); | |
| } | |
| // Check the row before and modify their height value | |
| if (cell.uid === theadRowStack[i - 1].cell[j].uid) { | |
| cell.height -= 1; | |
| } | |
| } | |
| groupZero.nbDescriptionRow += 1; | |
| } else { | |
| tmpStack.push(theadRS); | |
| } | |
| } | |
| groupZero.colgrp = []; // Array based on level as indexes for columns and group headers | |
| // Parser any cell in the colgroup header | |
| if (colgroupHeaderColEnd > 0 && (colgroupFrame.length === 1 || colgroupFrame.length === 0)) { | |
| // There are no colgroup element defined, All the cell will be considerated to be a data cell | |
| // Data Colgroup | |
| dataColgroup = {}; | |
| dataColumns = []; | |
| colgroup = { | |
| start: (colgroupHeaderColEnd + 1), | |
| end: tableCellWidth, | |
| col: [], | |
| groupZero: groupZero, | |
| elem: undefined, | |
| type: 2 // Set colgroup data type | |
| }; | |
| colgroup.uid = uidElem; | |
| uidElem += 1; | |
| groupZero.allParserObj.push(colgroup); | |
| if (colgroup.start > colgroup.end) { | |
| errorTrigger(5); | |
| } | |
| dataColgroup = colgroup; | |
| // Create the column | |
| // Create virtual column | |
| for (i = colgroup.start, _ilen = colgroup.end; i <= _ilen; i += 1) { | |
| col = { | |
| start: 0, | |
| end: 0, | |
| groupZero: groupZero, | |
| elem: undefined | |
| }; | |
| col.uid = uidElem; | |
| uidElem += 1; | |
| groupZero.allParserObj.push(col); | |
| if (!groupZero.col) { | |
| groupZero.col = []; | |
| } | |
| dataColumns.push(col); | |
| col.start = i; | |
| col.end = i; | |
| col.groupstruct = colgroup; | |
| colgroup.col.push(col); | |
| columnFrame.push(col); // Check to remove "columnFrame" | |
| } | |
| // Default Level => 1 | |
| groupZero.colgrp[1] = []; | |
| groupZero.colgrp[1].push(groupZero.colcaption); | |
| // Header Colgroup | |
| if (colgroupHeaderColEnd > 0) { | |
| hcolgroup = { | |
| start: 1, | |
| elem: undefined, | |
| end: colgroupHeaderColEnd, | |
| col: [], | |
| groupZero: groupZero, | |
| type: 1 // Set colgroup data type | |
| }; | |
| hcolgroup.uid = uidElem; | |
| uidElem += 1; | |
| groupZero.allParserObj.push(hcolgroup); | |
| colgroupFrame.push(hcolgroup); | |
| colgroupFrame.push(dataColgroup); | |
| groupZero.colcaption.dataset = dataColgroup.col; | |
| // Create the column | |
| // Create virtual column | |
| for (i = hcolgroup.start, _ilen = hcolgroup.end; i <= _ilen; i += 1) { | |
| col = { | |
| start: 0, | |
| end: 0, | |
| groupZero: groupZero, | |
| elem: undefined | |
| }; | |
| col.uid = uidElem; | |
| uidElem += 1; | |
| groupZero.allParserObj.push(col); | |
| if (!groupZero.col) { | |
| groupZero.col = []; | |
| } | |
| groupZero.col.push(col); | |
| col.start = i; | |
| col.end = i; | |
| col.groupstruct = hcolgroup; | |
| hcolgroup.col.push(col); | |
| columnFrame.push(col); | |
| } | |
| for (i = 0, _ilen = dataColumns.length; i < _ilen; i += 1) { | |
| groupZero.col.push(dataColumns[i]); | |
| } | |
| } | |
| if (colgroupFrame.length === 0) { | |
| colgroupFrame.push(dataColgroup); | |
| groupZero.colcaption.dataset = dataColgroup.col; | |
| } | |
| // Set the header for each column | |
| for (i = 0, _ilen = groupZero.col.length; i < _ilen; i += 1) { | |
| gzCol = groupZero.col[i]; | |
| gzCol.header = []; | |
| for (j = 0, _jlen = tmpStack.length; j < _jlen; j += 1) { | |
| for (m = gzCol.start, _mlen = gzCol.end; m <= _mlen; m += 1) { | |
| if ((j === 0 || (j > 0 && tmpStack[j].cell[m - 1].uid !== tmpStack[j - 1].cell[m - 1].uid)) && tmpStack[j].cell[m - 1].type === 1) { | |
| gzCol.header.push(tmpStack[j].cell[m - 1]); | |
| } | |
| } | |
| } | |
| } | |
| } else { | |
| // They exist colgroup element, | |
| // | |
| // ----------------------------------------------------- | |
| // | |
| // Build data column group based on the data column group and summary column group. | |
| // | |
| // Suggestion: In the future, may be allow the use of a HTML5 data or CSS Option to force a colgroup to be a data group instead of a summary group | |
| // | |
| // ----------------------------------------------------- | |
| // | |
| lstRealColgroup = []; // List of real colgroup | |
| currColPos = (colgroupHeaderColEnd === 0 ? 1 : colgroupFrame[0].end + 1); // Set the current column position | |
| colgroup = { | |
| start: currColPos, | |
| end: undefined, | |
| col: [], | |
| row: [], | |
| type: 2 // Set colgroup data type, that is the initial colgroup type | |
| }; | |
| currColgroupStructure = []; | |
| colFrmId = 0; | |
| bigTotalColgroupFound = false; | |
| $.each(colgroupFrame, function () { | |
| var curColgroupFrame = this, | |
| groupLevel, | |
| cgrp, | |
| parentHeader, | |
| summaryAttached; | |
| colFrmId += 1; | |
| if (bigTotalColgroupFound || groupZero.colgrp[0]) { | |
| errorTrigger(6, curColgroupFrame); | |
| return; | |
| } | |
| $.each(curColgroupFrame.col, function () { | |
| var column = this; | |
| if (!groupZero.col) { | |
| groupZero.col = []; | |
| } | |
| groupZero.col.push(column); | |
| column.type = 1; | |
| column.groupstruct = curColgroupFrame; | |
| }); | |
| if (curColgroupFrame.start < currColPos) { | |
| if (colgroupHeaderColEnd !== curColgroupFrame.end) { | |
| errorTrigger(7, curColgroupFrame); | |
| } | |
| // Skip this colgroup, this should happened only once and should represent the header colgroup | |
| // Assign the headers for this group | |
| for (i = 0, _ilen = curColgroupFrame.col.length; i < _ilen; i += 1) { | |
| gzCol = curColgroupFrame.col[i]; | |
| gzCol.header = []; | |
| for (j = 0, _jlen = tmpStack.length; j < _jlen; j += 1) { | |
| for (m = gzCol.start, _mlen = gzCol.end; m <= _mlen; m += 1) { | |
| if ((j === 0 || (j > 0 && tmpStack[j].cell[m - 1].uid !== tmpStack[j - 1].cell[m - 1].uid)) && tmpStack[j].cell[m - 1].type === 1) { | |
| gzCol.header.push(tmpStack[j].cell[m - 1]); | |
| } | |
| } | |
| } | |
| } | |
| return; | |
| } | |
| groupLevel = undefined; | |
| // Get the colgroup level | |
| for (i = 0, _ilen = tmpStack.length; i < _ilen; i += 1) { | |
| tmpStackCell = tmpStack[i].cell[curColgroupFrame.end - 1]; | |
| if (!tmpStackCell && curColgroupFrame.end > tmpStack[i].cell.length) { | |
| errorTrigger(7); // Number of column are not corresponding to the table width | |
| break; | |
| } | |
| if ((tmpStackCell.colpos + tmpStackCell.width - 1) === curColgroupFrame.end && (tmpStackCell.colpos >= curColgroupFrame.start)) { | |
| if (!groupLevel || groupLevel > (i + 1)) { | |
| groupLevel = (i + 1); // would equal at the current data cell level. The lowest row level win | |
| } | |
| } | |
| } | |
| if (!groupLevel) { | |
| groupLevel = 1; // Default colgroup data Level, this happen when there is no column header, (same as no thead) | |
| // errorTrigger(8, "Impossible to find the colgroup level, Check you colgroup definition or/and your table structure"); // That happened if we don't able to find an ending cell at the ending colgroup position. | |
| } | |
| // All the cells at higher level (Bellow the group level found) of witch one found, need to be inside the colgroup | |
| for (i = (groupLevel - 1), _ilen = tmpStack.length; i < _ilen; i += 1) { | |
| tmpStackCurr = tmpStack[i]; | |
| // Test each cell in that group | |
| for (j = curColgroupFrame.start - 1, _jlen = curColgroupFrame.end; j < _jlen; j += 1) { | |
| tmpStackCell = tmpStackCurr.cell[j]; | |
| if (tmpStackCell.colpos < curColgroupFrame.start || (tmpStackCell.colpos + tmpStackCell.width - 1) > curColgroupFrame.end) { | |
| errorTrigger(9); | |
| return; | |
| } | |
| } | |
| } | |
| // Add virtual colgroup Based on the top header | |
| for (i = currColgroupStructure.length, _ilen = (groupLevel - 1); i < _ilen; i += 1) { | |
| tmpStackCell = tmpStack[i].cell[curColgroupFrame.start - 1]; | |
| // Use the top cell at level minus 1, that cell must be larger | |
| if (tmpStackCell.uid !== tmpStack[i].cell[curColgroupFrame.end - 1].uid || | |
| tmpStackCell.colpos > curColgroupFrame.start || | |
| tmpStackCell.colpos + tmpStackCell.width - 1 < curColgroupFrame.end) { | |
| errorTrigger(10); | |
| return; | |
| } | |
| // Convert the header in a group header cell | |
| cgrp = tmpStackCell; | |
| cgrp.level = (i + 1); | |
| cgrp.start = cgrp.colpos; | |
| cgrp.end = cgrp.colpos + cgrp.width - 1; | |
| cgrp.type = 7; // Group Header Cell | |
| currColgroupStructure.push(cgrp); | |
| if (!groupZero.virtualColgroup) { | |
| groupZero.virtualColgroup = []; | |
| } | |
| groupZero.virtualColgroup.push(cgrp); | |
| // Add the group into the level colgroup perspective | |
| if (!groupZero.colgrp[(i + 1)]) { | |
| groupZero.colgrp[(i + 1)] = []; | |
| } | |
| groupZero.colgrp[(i + 1)].push(cgrp); | |
| } | |
| // Set the header list for the current group | |
| curColgroupFrame.header = []; | |
| for (i = groupLevel - (groupLevel >= 2 ? 2 : 1); i < tmpStack.length; i += 1) { | |
| for (j = curColgroupFrame.start; j <= curColgroupFrame.end; j += 1) { | |
| if (tmpStack[i].cell[j - 1].rowpos === i + 1) { | |
| curColgroupFrame.header.push(tmpStack[i].cell[j - 1]); | |
| // Attach the current colgroup to this header | |
| tmpStack[i].cell[j - 1].colgroup = curColgroupFrame; | |
| } | |
| j += tmpStack[i].cell[j - 1].width - 1; | |
| } | |
| } | |
| // Assign the parent header to the current header | |
| parentHeader = []; | |
| for (i = 0; i < currColgroupStructure.length - 1; i += 1) { | |
| parentHeader.push(currColgroupStructure[i]); | |
| } | |
| curColgroupFrame.parentHeader = parentHeader; | |
| // Check to set if this group are a data group | |
| if (currColgroupStructure.length < groupLevel) { | |
| // This colgroup are a data colgroup | |
| // The current colgroup are a data colgroup | |
| if (!curColgroupFrame.type) { | |
| curColgroupFrame.type = 2; // Set Data group type | |
| curColgroupFrame.level = groupLevel; | |
| } | |
| currColgroupStructure.push(curColgroupFrame); | |
| // Add the group into the level colgroup perspective | |
| if (!groupZero.colgrp[groupLevel]) { | |
| groupZero.colgrp[groupLevel] = []; | |
| } | |
| groupZero.colgrp[groupLevel].push(curColgroupFrame); | |
| } | |
| // | |
| // Preparing the current stack for the next colgroup and set if the current are a summary group | |
| // | |
| // Check if we need to pop out the current header colgroup | |
| summaryAttached = false; | |
| for (i = currColgroupStructure.length - 1; i >= 0; i -= 1) { | |
| if (currColgroupStructure[i].end <= curColgroupFrame.end) { | |
| if (currColgroupStructure[i].level < groupLevel && theadRowStack.length > 0) { | |
| curColgroupFrame.type = 3; | |
| } | |
| // Attach the Summary group to the colgroup poped if current colgroup are type 3 | |
| if (curColgroupFrame.type === 3 && !summaryAttached) { | |
| currColgroupStructure[currColgroupStructure.length - 1].summary = curColgroupFrame; | |
| summaryAttached = true; // This are used to do not attach a summary of level 4 to an inapropriate level 1 for exampled | |
| } | |
| currColgroupStructure.pop(); | |
| } | |
| } | |
| if (!hassumMode) { | |
| curColgroupFrame.type = 2; | |
| } | |
| // Catch the second and the third possible grouping at level 1 | |
| if (groupLevel === 1 && groupZero.colgrp[1] && groupZero.colgrp[1].length > 1 && theadRowStack.length > 0) { | |
| // Check if in the group at level 1 if we don't already have a summary colgroup | |
| for (i = 0; i < groupZero.colgrp[1].length; i += 1) { | |
| if (groupZero.colgrp[1][i].type === 3) { | |
| // Congrat, we found the last possible colgroup, | |
| curColgroupFrame.level = 0; | |
| if (!groupZero.colgrp[0]) { | |
| groupZero.colgrp[0] = []; | |
| } | |
| groupZero.colgrp[0].push(curColgroupFrame); | |
| groupZero.colgrp[1].pop(); | |
| bigTotalColgroupFound = true; | |
| break; | |
| } | |
| } | |
| if (hassumMode) { | |
| curColgroupFrame.type = 3; | |
| } | |
| } | |
| // Set the representative header "caption" element for a group at level 0 | |
| if (curColgroupFrame.level === 1 && curColgroupFrame.type === 2) { | |
| curColgroupFrame.repheader = 'caption'; | |
| } | |
| if (!groupZero.col) { | |
| groupZero.col = []; | |
| } | |
| $.each(curColgroupFrame.col, function () { | |
| var column = this; | |
| column.type = curColgroupFrame.type; | |
| column.level = curColgroupFrame.level; | |
| column.groupstruct = curColgroupFrame; | |
| column.header = []; | |
| // Find the lowest header that would represent this column | |
| for (j = (groupLevel - 1); j < tmpStack.length; j += 1) { | |
| for (i = (curColgroupFrame.start - 1); i < curColgroupFrame.end; i += 1) { | |
| if ((tmpStack[j].cell[i].colpos >= column.start && | |
| tmpStack[j].cell[i].colpos <= column.end) || | |
| (tmpStack[j].cell[i].colpos <= column.start && | |
| (tmpStack[j].cell[i].colpos + tmpStack[j].cell[i].width - 1) >= column.end) || | |
| ((tmpStack[j].cell[i].colpos + tmpStack[j].cell[i].width - 1) <= column.start && | |
| (tmpStack[j].cell[i].colpos + tmpStack[j].cell[i].width - 1) >= column.end)) { | |
| if (column.header.length === 0 || (column.header.length > 0 && column.header[column.header.length - 1].uid !== tmpStack[j].cell[i].uid)) { | |
| // This are the header that would represent this column | |
| column.header.push(tmpStack[j].cell[i]); | |
| tmpStack[j].cell[i].level = curColgroupFrame.level; | |
| } | |
| } | |
| } | |
| } | |
| }); | |
| }); | |
| if (!groupZero.virtualColgroup) { | |
| groupZero.virtualColgroup = []; | |
| } | |
| // Set the Virtual Group Header Cell, if any | |
| $.each(groupZero.virtualColgroup, function () { | |
| var vGroupHeaderCell = this; | |
| // Set the headerLevel at the appropriate column | |
| for (i = (vGroupHeaderCell.start - 1); i < vGroupHeaderCell.end; i += 1) { | |
| if (!groupZero.col[i].headerLevel) { | |
| groupZero.col[i].headerLevel = []; | |
| } | |
| groupZero.col[i].headerLevel.push(vGroupHeaderCell); | |
| } | |
| }); | |
| } | |
| // Associate the colgroup Header in the group Zero | |
| if (colgroupFrame.length > 0 && colgroupHeaderColEnd > 0) { | |
| groupZero.colgrouphead = colgroupFrame[0]; | |
| groupZero.colgrouphead.type = 1; // Set the first colgroup type :-) | |
| } | |
| } | |
| function finalizeRowGroup() { | |
| // Check if the current rowgroup has been go in the rowgroup setup, if not we do | |
| if (!currentRowGroup.type || !currentRowGroup.level) { | |
| // Colgroup Setup, | |
| rowgroupSetup(); | |
| } | |
| // console.log('Row Group Finalization'); | |
| // If the current row group are a data group, check each row if we can found a pattern about to increment the data level for this row group | |
| // Update, if needed, each row and cell to take in consideration the new row group level | |
| // Add the row group in the groupZero Collection | |
| lstRowGroup.push(currentRowGroup); | |
| currentRowGroup = {}; | |
| } | |
| function initiateRowGroup() { | |
| // console.log('Row Group Initialization'); | |
| // Finalisation of any exisiting row group | |
| if (currentRowGroup && currentRowGroup.type) { | |
| finalizeRowGroup(); | |
| } | |
| // Initialisation of the a new row group | |
| currentRowGroup = {}; | |
| currentRowGroup.elem = currentRowGroupElement; | |
| currentRowGroup.row = []; | |
| currentRowGroup.headerlevel = []; | |
| currentRowGroup.groupZero = groupZero; | |
| currentRowGroup.uid = uidElem; | |
| uidElem += 1; | |
| //currentRowGroup.type = 2 // (1 if elem is a thead or if detected in the table, 2 default, 3 if summary data) // FYI Here the existance of the "type" property is used to determined the real type of row group | |
| } | |
| function rowgroupSetup(forceDataGroup) { | |
| var i, | |
| previousRowGroup, | |
| tmpHeaderLevel; | |
| if (tfootOnProcess) { | |
| currentRowGroup.type = 3; | |
| currentRowGroup.level = 0; | |
| rowgroupHeaderRowStack = []; | |
| return; | |
| } | |
| // Check if the current row group, already have some row, if yes this is a new row group | |
| if (rowgroupHeaderRowStack.length > 0) { | |
| // if more than 0 cell in the stack, mark this row group as a data row group and create the new row group (can be only virtual) | |
| if (currentRowGroup && currentRowGroup.type && currentRowGroup.row.length > 0) { | |
| currentRowGroupElement = {}; | |
| initiateRowGroup(); | |
| } | |
| // We have a data row group | |
| currentRowGroup.type = 2; | |
| // Set the group header cell | |
| currentRowGroup.row = rowgroupHeaderRowStack; | |
| for (i = 0; i < rowgroupHeaderRowStack.length; i += 1) { | |
| // if (rowgroupHeaderRowStack[i].cell.length !== 1) { | |
| // errorTrigger(11, "Seem to have a row header for the data that have 2 or more cell inside it"); | |
| // } | |
| rowgroupHeaderRowStack[i].cell[0].type = 7; | |
| rowgroupHeaderRowStack[i].cell[0].scope = "row"; | |
| rowgroupHeaderRowStack[i].cell[0].row = rowgroupHeaderRowStack[i]; | |
| currentRowGroup.headerlevel.push(rowgroupHeaderRowStack[i].cell[0]); | |
| } | |
| } | |
| // if no cell in the stack but first row group, mark this row group as a data row group | |
| // console.log('rowgroupHeaderRowStack.length: ' + rowgroupHeaderRowStack.length); | |
| // console.log(currentRowGroup); | |
| // console.log('lstRowGroup.length: ' + lstRowGroup.length); | |
| if (rowgroupHeaderRowStack.length === 0 && | |
| // (!currentRowGroup || (currentRowGroup.type && currentRowGroup.type === 1)) && | |
| lstRowGroup.length === 0) { | |
| if (currentRowGroup.type && currentRowGroup.type === 1) { | |
| currentRowGroupElement = {}; | |
| initiateRowGroup(); | |
| } | |
| // This is the first data row group at level 1 | |
| currentRowGroup.type = 2; | |
| currentRowGroup.level = 1; // Default Row Group Level | |
| } | |
| // if no cell in the stack and not the first row group, this are a summary group | |
| // This is only valid if the first colgroup is a header colgroup. | |
| //console.log('rowgroupHeaderRowStack.length: ' + rowgroupHeaderRowStack.length + ' lstRowGroup.length: ' + lstRowGroup.length + ' currentRowGroup.type: ' + currentRowGroup.type); | |
| // console.log(' colgroupFrame[0]: ' + colgroupFrame[0] + ' colgroupFrame[0].type: ' + colgroupFrame[0].type + ' forceDataGroup: ' + forceDataGroup); | |
| if (rowgroupHeaderRowStack.length === 0 && lstRowGroup.length > 0 && !currentRowGroup.type && colgroupFrame[0] && (colgroupFrame[0].type === 1 || (!colgroupFrame[0].type && colgroupFrame.length > 0)) && !forceDataGroup) { | |
| currentRowGroup.type = 3; | |
| } else { | |
| currentRowGroup.type = 2; | |
| // currentRowGroup.level = 1; // Default Row Group Level | |
| } | |
| if (currentRowGroup.type === 3 && !hassumMode) { | |
| currentRowGroup.type = 2; | |
| currentRowGroup.level = lstRowGroup[lstRowGroup.length - 1].level; | |
| } | |
| // Set the Data Level for this row group | |
| // Calculate the appropriate row group level based on the previous rowgroup | |
| // * a Summary Group decrease the row group level | |
| // * a Data Group increase the row group level based of his number of row group header and the previous row group level | |
| // * Dont forget to set the appropriate level to each group header cell inside this row group. | |
| if (!currentRowGroup.level) { | |
| // Get the level of the previous group | |
| if (lstRowGroup.length > 0) { | |
| previousRowGroup = lstRowGroup[lstRowGroup.length - 1]; | |
| if (currentRowGroup.type === 2) { | |
| // Data Group | |
| if (currentRowGroup.headerlevel.length === previousRowGroup.headerlevel.length) { | |
| // Same Level as the previous one | |
| currentRowGroup.level = previousRowGroup.level; | |
| } else if (currentRowGroup.headerlevel.length < previousRowGroup.headerlevel.length) { | |
| // add the missing group heading cell | |
| tmpHeaderLevel = currentRowGroup.headerlevel; | |
| currentRowGroup.headerlevel = []; | |
| for (i = 0; i < (previousRowGroup.headerlevel.length - currentRowGroup.headerlevel.length); i += 1) { | |
| currentRowGroup.headerlevel.push(previousRowGroup.headerlevel[i]); | |
| } | |
| for (i = 0; i < tmpHeaderLevel.length; i += 1) { | |
| currentRowGroup.headerlevel.push(tmpHeaderLevel[i]); | |
| } | |
| currentRowGroup.level = previousRowGroup.level; | |
| } else if (currentRowGroup.headerlevel.length > previousRowGroup.headerlevel.length) { | |
| // This are a new set of heading, the level equal the number of group header cell found | |
| currentRowGroup.level = currentRowGroup.headerlevel.length + 1; | |
| } | |
| } else if (currentRowGroup.type === 3) { | |
| // Summary Group | |
| if (previousRowGroup.type === 3) { | |
| currentRowGroup.level = previousRowGroup.level - 1; | |
| } else { | |
| currentRowGroup.level = previousRowGroup.level; | |
| } | |
| if (currentRowGroup.level < 0) { | |
| // This is an error, Last summary row group was already found. | |
| errorTrigger(12); | |
| } | |
| // Set the header level with the previous row group | |
| for (i = 0; i < previousRowGroup.headerlevel.length; i += 1) { | |
| if (previousRowGroup.headerlevel[i].level < currentRowGroup.level) { | |
| currentRowGroup.headerlevel.push(previousRowGroup.headerlevel[i]); | |
| } | |
| } | |
| } else { | |
| // Error | |
| currentRowGroup.level = "Error, not calculated"; | |
| errorTrigger(13); | |
| } | |
| } else { | |
| currentRowGroup.level = 1 + rowgroupHeaderRowStack.length; | |
| } | |
| } | |
| // Ensure that each row group cell heading have their level set | |
| for (i = 0; i < currentRowGroup.headerlevel.length; i += 1) { | |
| currentRowGroup.headerlevel[i].level = i + 1; | |
| currentRowGroup.headerlevel[i].rowlevel = currentRowGroup.headerlevel[i].level; | |
| } | |
| rowgroupHeaderRowStack = []; // reset the row header stack | |
| if (currentRowGroup.level === undefined || currentRowGroup.level < 0) { | |
| errorTrigger(14, currentRowGroup.elem); | |
| } | |
| } | |
| function processRow(elem) { | |
| // In this function there are a possible confusion about the colgroup variable name used here vs the real colgroup table, In this function the colgroup is used when there are no header cell. | |
| currentRowPos += 1; | |
| var columnPos = 1, | |
| lastCellType = "", | |
| lastHeadingColPos = false, | |
| cells = $(elem).children(), | |
| row = { | |
| colgroup: [], // === Build from colgroup object == | |
| cell: [], // === Build from Cell Object == | |
| elem: elem, // Row Structure jQuery element | |
| rowpos: currentRowPos | |
| }, | |
| colgroup, | |
| fnPreProcessGroupHeaderCell, | |
| fnPreProcessGroupDataCell, | |
| fnParseSpannedRowCell, | |
| headingRowCell, | |
| rowheader, | |
| colKeyCell, | |
| i, | |
| j, | |
| isDataCell, | |
| isDataColgroupType, | |
| createGenericColgroup; | |
| $(elem).data().tblparser = row; | |
| row.uid = uidElem; | |
| uidElem += 1; | |
| row.groupZero = groupZero; | |
| groupZero.allParserObj.push(row); | |
| colgroup = { | |
| cell: [], | |
| cgsummary: undefined, // ?? Not sure because this will be better in the data colgroup object ?? Summary Colgroup Associated | |
| type: false // 1 === header, 2 === data, 3 === summary, 4 === key, 5 === description, 6 === layout, 7 === group header | |
| }; | |
| colgroup.uid = uidElem; | |
| uidElem += 1; | |
| groupZero.allParserObj.push(colgroup); | |
| fnPreProcessGroupHeaderCell = function (headerCell) { | |
| if (!colgroup.type) { | |
| colgroup.type = 1; | |
| } | |
| if (colgroup.type !== 1) { | |
| // Creation of a new colgroup | |
| row.colgroup.push(colgroup); // Add the previous colgroup | |
| // Create a new colgroup | |
| colgroup = { | |
| cell: [], | |
| type: 1 | |
| }; | |
| colgroup.uid = uidElem; | |
| uidElem += 1; | |
| groupZero.allParserObj.push(colgroup); | |
| } | |
| colgroup.cell.push(headerCell); | |
| lastHeadingColPos = headerCell.colpos + headerCell.width - 1; | |
| }; | |
| fnPreProcessGroupDataCell = function (dataCell) { | |
| if (!colgroup.type) { | |
| colgroup.type = 2; | |
| } | |
| // Check if we need to create a summary colgroup (Based on the top colgroup definition) | |
| if (colgroup.type !== 2) { | |
| // Creation of a new colgroup | |
| row.colgroup.push(colgroup); // Add the previous colgroup | |
| // Create a new colgroup | |
| colgroup = { | |
| cell: [], | |
| type: 2 | |
| }; | |
| colgroup.uid = uidElem; | |
| uidElem += 1; | |
| groupZero.allParserObj.push(colgroup); | |
| } | |
| colgroup.cell.push(dataCell); | |
| }; | |
| fnParseSpannedRowCell = function () { | |
| var i; | |
| // Check for spanned row | |
| $.each(spannedRow, function () { | |
| if (this.colpos === columnPos && this.spanHeight > 0 && (this.height + this.rowpos - this.spanHeight === currentRowPos)) { | |
| if (this.elem.nodeName.toLowerCase() === 'th') { | |
| fnPreProcessGroupHeaderCell(this); | |
| } | |
| if (this.elem.nodeName.toLowerCase() === 'td') { | |
| fnPreProcessGroupDataCell(this); | |
| } | |
| this.spanHeight -= 1; | |
| // Increment the column position | |
| columnPos += this.width; | |
| // Add the column | |
| for (i = 1; i <= this.width; i += 1) { | |
| row.cell.push(this); | |
| } | |
| lastCellType = this.elem.nodeName.toLowerCase(); | |
| } | |
| }); | |
| }; | |
| fnParseSpannedRowCell(); // This are for any row that have spanned row in is first cells | |
| // Read the row | |
| $.each(cells, function () { | |
| var $this = $(this), | |
| width = $this.attr('colspan') !== undefined ? parseInt($this.attr('colspan'), 10) : 1, | |
| height = $this.attr('rowspan') !== undefined ? parseInt($this.attr('rowspan'), 10) : 1, | |
| headerCell, | |
| dataCell, | |
| i; | |
| switch (this.nodeName.toLowerCase()) { | |
| case 'th': // cell header | |
| headerCell = { | |
| rowpos: currentRowPos, | |
| colpos: columnPos, | |
| width: width, | |
| height: height, | |
| data: [], | |
| summary: [], | |
| elem: this | |
| }; | |
| $this.data().tblparser = headerCell; | |
| headerCell.groupZero = groupZero; | |
| headerCell.uid = uidElem; | |
| uidElem += 1; | |
| groupZero.allParserObj.push(headerCell); | |
| fnPreProcessGroupHeaderCell(headerCell); | |
| headerCell.parent = colgroup; | |
| // Check if needs to be added to the spannedRow collection | |
| if (height > 1) { | |
| headerCell.spanHeight = height - 1; | |
| spannedRow.push(headerCell); | |
| } | |
| // Increment the column position | |
| columnPos += headerCell.width; | |
| for (i = 1; i <= width; i += 1) { | |
| row.cell.push(headerCell); | |
| } | |
| // Check for any spanned cell | |
| fnParseSpannedRowCell(); | |
| break; | |
| case 'td': // data cell | |
| dataCell = { | |
| rowpos: currentRowPos, | |
| colpos: columnPos, | |
| width: width, | |
| height: height, | |
| elem: this | |
| }; | |
| $this.data().tblparser = dataCell; | |
| dataCell.groupZero = groupZero; | |
| dataCell.uid = uidElem; | |
| uidElem += 1; | |
| groupZero.allParserObj.push(dataCell); | |
| fnPreProcessGroupDataCell(dataCell); | |
| dataCell.parent = colgroup; | |
| // Check if needs to be added to the spannedRow collection | |
| if (height > 1) { | |
| dataCell.spanHeight = height - 1; | |
| spannedRow.push(dataCell); | |
| } | |
| // Increment the column position | |
| columnPos += dataCell.width; | |
| for (i = 1; i <= width; i += 1) { | |
| row.cell.push(dataCell); | |
| } | |
| // Check for any spanned cell | |
| fnParseSpannedRowCell(); | |
| break; | |
| default: | |
| errorTrigger(15, this); | |
| break; | |
| } | |
| lastCellType = this.nodeName.toLowerCase(); | |
| }); | |
| // Check for any spanned cell | |
| fnParseSpannedRowCell(); | |
| // Check if this the number of column for this row are equal to the other | |
| if (tableCellWidth === 0) { | |
| // If not already set, we use the first row as a guideline | |
| tableCellWidth = row.cell.length; | |
| } | |
| if (tableCellWidth !== row.cell.length) { | |
| row.spannedRow = spannedRow; | |
| errorTrigger(16, row.elem); | |
| } | |
| // Check if we are into a thead rowgroup, if yes we stop here. | |
| if (stackRowHeader) { | |
| theadRowStack.push(row); | |
| return; | |
| } | |
| // Add the last colgroup | |
| row.colgroup.push(colgroup); | |
| // | |
| // Diggest the row | |
| // | |
| if (lastCellType === 'th') { | |
| // Digest the row header | |
| row.type = 1; | |
| // | |
| // Check the validity of this header row | |
| // | |
| if (row.colgroup.length === 2 && currentRowPos === 1) { | |
| // Check if the first is a data colgroup with only one cell | |
| if (row.colgroup[0].type === 2 && row.colgroup[0].cell.length === 1) { | |
| // Valid row header for the row group header | |
| // REQUIRED: That cell need to be empty | |
| if ($(row.colgroup[0].cell[0].elem).html().length === 0) { | |
| // console.log('This is a valide row for the rowgroup header with a layout cell'); | |
| // We stack the row | |
| theadRowStack.push(row); | |
| return; // We do not go further | |
| } | |
| errorTrigger(17); | |
| } else { | |
| // Invalid row header | |
| errorTrigger(18); | |
| } | |
| } | |
| if (row.colgroup.length === 1) { | |
| if (row.colgroup[0].cell.length > 1) { | |
| // this is a row associated to a header row group | |
| if (!headerRowGroupCompleted) { | |
| // Good row | |
| // console.log('This is an valid row header for the header row group'); | |
| // We stack the row | |
| theadRowStack.push(row); | |
| return; // We do not go further | |
| } | |
| // Bad row, remove the row or split the table | |
| errorTrigger(18); | |
| } else { | |
| if (currentRowPos !== 1 || row.cell[0].uid === row.cell[row.cell.length - 1].uid) { | |
| // Stack the row found for the rowgroup header | |
| rowgroupHeaderRowStack.push(row); | |
| // This will be processed on the first data row | |
| // console.log('this header row will be considerated to be a rowgroup header row'); | |
| headerRowGroupCompleted = true; // End of any header row group (thead) | |
| return; | |
| } | |
| errorTrigger(18); | |
| } | |
| } | |
| if (row.colgroup.length > 1 && currentRowPos !== 1) { | |
| errorTrigger(21); | |
| } | |
| // | |
| // If Valid, process the row | |
| // | |
| } else { | |
| // Digest the data row or summary row | |
| row.type = 2; | |
| // This mark the end of any row group header (thead) | |
| headerRowGroupCompleted = true; | |
| // Check if this row is considerated as a description row for a header | |
| if (rowgroupHeaderRowStack.length > 0 && row.cell[0].uid === row.cell[row.cell.length - 1].uid) { | |
| // Horay this row are a description cell for the preceding heading | |
| row.type = 5; | |
| row.cell[0].type = 5; | |
| row.cell[0].row = row; | |
| if (!row.cell[0].describe) { | |
| row.cell[0].describe = []; | |
| } | |
| rowgroupHeaderRowStack[rowgroupHeaderRowStack.length - 1].cell[0].descCell = row.cell[0]; | |
| row.cell[0].describe.push(rowgroupHeaderRowStack[rowgroupHeaderRowStack.length - 1].cell[0]); | |
| if (!groupZero.desccell) { | |
| groupZero.desccell = []; | |
| } | |
| groupZero.desccell.push(row.cell[0]); | |
| // FYI - We do not push this row in any stack because this row is a description row | |
| return; // Stop the processing for this row | |
| } | |
| // | |
| // Process any row used to defined the rowgroup label | |
| // | |
| if (rowgroupHeaderRowStack.length > 0 || !currentRowGroup.type) { | |
| rowgroupSetup(); | |
| } | |
| row.type = currentRowGroup.type; | |
| row.level = currentRowGroup.level; | |
| if (colgroupFrame[0] && lastHeadingColPos && colgroupFrame[0].end !== lastHeadingColPos && colgroupFrame[0].end === (lastHeadingColPos + 1)) { | |
| lastHeadingColPos += 1; // Adjust if required, the lastHeadingColPos if colgroup are present, that would be the first colgroup | |
| } | |
| row.lastHeadingColPos = lastHeadingColPos; | |
| if (!currentRowGroup.lastHeadingColPos) { | |
| currentRowGroup.lastHeadingColPos = lastHeadingColPos; | |
| } | |
| if (!previousDataHeadingColPos) { | |
| previousDataHeadingColPos = lastHeadingColPos; | |
| } | |
| row.rowgroup = currentRowGroup; | |
| if (currentRowGroup.lastHeadingColPos !== lastHeadingColPos) { | |
| if ((!lastHeadingSummaryColPos && currentRowGroup.lastHeadingColPos < lastHeadingColPos) || (lastHeadingSummaryColPos && lastHeadingSummaryColPos === lastHeadingColPos)) { | |
| // This is a virtual summary row group | |
| // Check for residual rowspan, there can not have cell that overflow on two or more rowgroup | |
| $.each(spannedRow, function () { | |
| if (this.spanHeight > 0) { | |
| // That row are spanned in 2 different row group | |
| errorTrigger(29, this); | |
| } | |
| }); | |
| spannedRow = []; // Cleanup of any spanned row | |
| rowgroupHeaderRowStack = []; // Remove any rowgroup header found. | |
| currentRowHeader = []; | |
| currentTbodyID += 1; | |
| finalizeRowGroup(); | |
| currentRowGroupElement = undefined; | |
| initiateRowGroup(); | |
| rowgroupSetup(); | |
| row.type = currentRowGroup.type; // Reset the current row type | |
| } else if (lastHeadingSummaryColPos && previousDataHeadingColPos === lastHeadingColPos) { | |
| // This is a virtual data row group | |
| // Check for residual rowspan, there can not have cell that overflow on two or more rowgroup | |
| $.each(spannedRow, function () { | |
| if (this.spanHeight > 0) { | |
| // That row are spanned in 2 different row group | |
| errorTrigger(29, this); | |
| } | |
| }); | |
| spannedRow = []; // Cleanup of any spanned row | |
| rowgroupHeaderRowStack = []; // Remove any rowgroup header found. | |
| currentRowHeader = []; | |
| currentTbodyID += 1; | |
| finalizeRowGroup(); | |
| currentRowGroupElement = undefined; | |
| initiateRowGroup(); | |
| rowgroupSetup(true); | |
| row.type = currentRowGroup.type; // Reset the current row type | |
| errorTrigger(34, row.elem); | |
| } else { | |
| errorTrigger(32); | |
| } | |
| } | |
| if (!currentRowGroup.lastHeadingColPos) { | |
| currentRowGroup.lastHeadingColPos = lastHeadingColPos; | |
| } | |
| if (currentRowGroup.type === 3 && !lastHeadingSummaryColPos) { | |
| lastHeadingSummaryColPos = lastHeadingColPos; | |
| } | |
| // Build the initial colgroup structure | |
| // If an cell header exist in that row.... | |
| if (lastHeadingColPos) { | |
| // Process the heading colgroup associated to this row. | |
| headingRowCell = []; | |
| rowheader = undefined; // This are the most precise cell header for this row | |
| colKeyCell = []; | |
| for (i = 0; i < lastHeadingColPos; i += 1) { | |
| // Check for description cell or key cell | |
| if (row.cell[i].elem.nodeName.toLowerCase() === "td") { | |
| if (!row.cell[i].type && row.cell[i - 1] && !(row.cell[i - 1].descCell) && row.cell[i - 1].type === 1 && row.cell[i - 1].height === row.cell[i].height) { | |
| row.cell[i].type = 5; | |
| row.cell[i - 1].descCell = row.cell[i]; | |
| if (!row.cell[i].describe) { | |
| row.cell[i].describe = []; | |
| } | |
| row.cell[i].describe.push(row.cell[i - 1]); | |
| if (!row.desccell) { | |
| row.desccell = []; | |
| } | |
| row.desccell.push(row.cell[i]); | |
| if (!groupZero.desccell) { | |
| groupZero.desccell = []; | |
| } | |
| groupZero.desccell.push(row.cell[i]); | |
| row.cell[i].scope = "row"; // Specify the scope of this description cell | |
| } | |
| // Check if this cell can be an key cell associated to an cell heading | |
| if (!row.cell[i].type) { | |
| colKeyCell.push(row.cell[i]); | |
| } | |
| } | |
| // Set for the most appropriate header that can represent this row | |
| if (row.cell[i].elem.nodeName.toLowerCase() === "th") { | |
| row.cell[i].type = 1; // Mark the cell to be an header cell | |
| row.cell[i].scope = "row"; | |
| if (rowheader && rowheader.uid !== row.cell[i].uid) { | |
| if (rowheader.height >= row.cell[i].height) { | |
| if (rowheader.height === row.cell[i].height) { | |
| errorTrigger(23); | |
| } | |
| // The current cell are a child of the previous rowheader | |
| if (!rowheader.subheader) { | |
| rowheader.subheader = []; | |
| rowheader.isgroup = true; | |
| } | |
| rowheader.subheader.push(row.cell[i]); | |
| // Change the current row header | |
| rowheader = row.cell[i]; | |
| headingRowCell.push(row.cell[i]); | |
| } else { | |
| // This case are either paralel heading of growing header, this are an error. | |
| errorTrigger(24); | |
| } | |
| } | |
| if (!rowheader) { | |
| rowheader = row.cell[i]; | |
| headingRowCell.push(row.cell[i]); | |
| } | |
| for (j = 0; j < colKeyCell.length; j += 1) { | |
| if (!(colKeyCell[j].type) && !(row.cell[i].keycell) && colKeyCell[j].height === row.cell[i].height) { | |
| colKeyCell[j].type = 4; | |
| row.cell[i].keycell = colKeyCell[j]; | |
| if (!row.keycell) { | |
| row.keycell = []; | |
| } | |
| row.keycell.push(colKeyCell[j]); | |
| if (!groupZero.keycell) { | |
| groupZero.keycell = []; | |
| } | |
| groupZero.keycell.push(colKeyCell[j]); | |
| if (!colKeyCell[j].describe) { | |
| colKeyCell[j].describe = []; | |
| } | |
| colKeyCell[j].describe.push(row.cell[i]); | |
| } | |
| } | |
| /*$.each(colKeyCell, function () { | |
| if (!(this.type) && !(row.cell[i].keycell) && this.height === row.cell[i].height) { | |
| this.type = 4; | |
| row.cell[i].keycell = this; | |
| if (!row.keycell) { | |
| row.keycell = []; | |
| } | |
| row.keycell.push(this); | |
| if (!groupZero.keycell) { | |
| groupZero.keycell = []; | |
| } | |
| groupZero.keycell.push(this); | |
| } | |
| });*/ | |
| } | |
| } | |
| // All the cell that have no "type" in the colKeyCell collection are problematic cells | |
| $.each(colKeyCell, function () { | |
| if (!(this.type)) { | |
| errorTrigger(25); | |
| if (!row.errorcell) { | |
| row.errorcell = []; | |
| } | |
| row.errorcell.push(this); | |
| } | |
| }); | |
| row.header = headingRowCell; | |
| } else { | |
| // There are only at least one colgroup, | |
| // Any colgroup tag defined but be equal or greater than 0. | |
| // if colgroup tag defined, they are all data colgroup. | |
| lastHeadingColPos = 0; | |
| if (colgroupFrame.length === 0) { | |
| processColgroup(undefined, tableCellWidth); | |
| } | |
| } | |
| // | |
| // Process the table row heading and colgroup if required | |
| // | |
| processRowgroupHeader(lastHeadingColPos); | |
| row.headerset = (currentRowGroup.headerlevel || []); | |
| /*if (colgroupFrame.length !== 0) { | |
| // We check the first colgroup to know if a colgroup type has been defined | |
| if (!(colgroupFrame[0].type)) { | |
| // processRowgroupHeader(lastHeadingColPos); | |
| // Match the already defined colgroup tag with the table rowgroup heading section | |
| // If the table don't have a rowgroup heading section and nothing found for colgroup heading, let all the colgroup to be a datagroup | |
| // If the table don't have a row group heading section but have a colgroup heading, the first group must match the founded colgroup heading, the second colgroup will be a datagroup and the third will be a summary colgroup. It would be the same if only one row are found in the rowgroup heading section. | |
| } | |
| }*/ | |
| /* else { | |
| // processRowgroupHeader(lastHeadingColPos); | |
| // If the table have a table rowgroup heading section, let that to be transformed into colgroup | |
| // The number of colgroup level are directly related to the number of row heading included in the thead or tbody. | |
| // If the table don't have a heading section, let run the code, the colgroup would be created later | |
| }*/ | |
| if (lastHeadingColPos !== 0) { | |
| lastHeadingColPos = colgroupFrame[0].end; // colgroupFrame must be defined here | |
| } | |
| // | |
| // Associate the data cell type with the colgroup if any, | |
| // Process the data cell. There are a need to have at least one data cell per data row. | |
| if (!row.datacell) { | |
| row.datacell = []; | |
| } | |
| for (i = lastHeadingColPos; i < row.cell.length; i += 1) { | |
| isDataCell = true; | |
| isDataColgroupType = true; | |
| for (j = (lastHeadingColPos === 0 ? 0 : 1); j < colgroupFrame.length; j += 1) { // If colgroup, the first are always header colgroup | |
| if (colgroupFrame[j].start <= row.cell[i].colpos && row.cell[i].colpos <= colgroupFrame[j].end) { | |
| if (row.type === 3 || colgroupFrame[j].type === 3) { | |
| row.cell[i].type = 3; // Summary Cell | |
| } else { | |
| row.cell[i].type = 2; | |
| } | |
| // Test if this cell is a layout cell | |
| if (row.type === 3 && colgroupFrame[j].type === 3 && ($(row.cell[i].elem).text().length === 0)) { | |
| row.cell[i].type = 6; | |
| if (!groupZero.layoutCell) { | |
| groupZero.layoutCell = []; | |
| } | |
| groupZero.layoutCell.push(row.cell[i]); | |
| } | |
| row.cell[i].collevel = colgroupFrame[j].level; | |
| row.datacell.push(row.cell[i]); | |
| } | |
| isDataColgroupType = !isDataColgroupType; | |
| } | |
| if (colgroupFrame.length === 0) { | |
| // There are no colgroup definition, this cell are set to be a datacell | |
| row.cell[i].type = 2; | |
| row.datacell.push(row.cell[i]); | |
| } | |
| // Add row header when the cell is span into more than one row | |
| if (row.cell[i].rowpos < currentRowPos) { | |
| if (!row.cell[i].addrowheaders) { | |
| row.cell[i].addrowheaders = []; // addrowheaders for additional row headers | |
| } | |
| if (row.header) { | |
| for (j = 0; j < row.header.length; j += 1) { | |
| if ((row.header[j].rowpos === currentRowPos && row.cell[i].addrowheaders.length === 0) || (row.header[j].rowpos === currentRowPos && row.cell[i].addrowheaders[row.cell[i].addrowheaders.length - 1].uid !== row.header[j].uid)) { | |
| row.cell[i].addrowheaders.push(row.header[j]); // Add the current header | |
| } | |
| } | |
| } | |
| } | |
| } | |
| createGenericColgroup = (colgroupFrame.length === 0); | |
| if (colgroupFrame.length === 0) { | |
| // processRowgroupHeader(lastHeadingColPos); | |
| createGenericColgroup = false; | |
| } | |
| // Add the cell in his appropriate column | |
| if (!groupZero.col) { | |
| groupZero.col = []; | |
| } | |
| for (i = 0; i < groupZero.col.length; i += 1) { | |
| for (j = (groupZero.col[i].start - 1); j < groupZero.col[i].end; j += 1) { | |
| if (!groupZero.col[i].cell) { | |
| groupZero.col[i].cell = []; | |
| } | |
| // Be sure to do not include twice the same cell for a column spanned in 2 or more column | |
| if (!(j > (groupZero.col[i].start - 1) && groupZero.col[i].cell[groupZero.col[i].cell.length - 1].uid === row.cell[j].uid)) { | |
| if (row.cell[j]) { | |
| groupZero.col[i].cell.push(row.cell[j]); | |
| if (!row.cell[j].col) { | |
| row.cell[j].col = groupZero.col[i]; | |
| } | |
| } else { | |
| errorTrigger(35); | |
| } | |
| } | |
| } | |
| } | |
| // Associate the row with the cell and Colgroup/Col association | |
| for (i = 0; i < row.cell.length; i += 1) { | |
| if (!row.cell[i].row) { | |
| row.cell[i].row = row; | |
| } | |
| row.cell[i].rowlevel = currentRowGroup.level; | |
| row.cell[i].rowlevelheader = currentRowGroup.headerlevel; | |
| row.cell[i].rowgroup = currentRowGroup; | |
| if (i > 0 && row.cell[i - 1].uid === row.cell[i].uid && row.cell[i].type !== 1 && row.cell[i].type !== 5 && row.cell[i].rowpos === currentRowPos && row.cell[i].colpos <= i) { | |
| if (!row.cell[i].addcolheaders) { | |
| row.cell[i].addcolheaders = []; // addcolheaders for additional col headers | |
| } | |
| // Add the column header if required | |
| if (groupZero.col[i] && groupZero.col[i].header) { | |
| for (j = 0; j < groupZero.col[i].header.length; j += 1) { | |
| if (groupZero.col[i].header[j].colpos === (i + 1)) { | |
| row.cell[i].addcolheaders.push(groupZero.col[i].header[j]); // Add the current header | |
| } | |
| } | |
| } | |
| } | |
| } | |
| summaryRowGroupEligible = true; | |
| } | |
| currentRowLevel += 1; | |
| // Add the row to the groupZero | |
| if (!groupZero.row) { | |
| groupZero.row = []; | |
| } | |
| groupZero.row.push(row); | |
| currentRowGroup.row.push(row); | |
| delete row.colgroup; | |
| } // End processRow function | |
| // | |
| // Main Entry For The Table Parsing | |
| // | |
| if (hasTfoot) { | |
| // If there is a tfoot element, be sure to add it at the end of all the tbody. FYI - HTML 5 spec allow now tfoot to be at the end | |
| $('tfoot', obj).appendTo($('tbody:last', obj).parent()); | |
| } | |
| $(obj).children().each(function () { | |
| var $this = $(this), | |
| nodeName = this.nodeName.toLowerCase(); | |
| if (nodeName === 'caption') { | |
| processCaption(this); | |
| } else if (nodeName === 'colgroup') { | |
| processColgroup(this); | |
| } else if (nodeName === 'thead') { | |
| currentRowGroupElement = this; | |
| // The table should not have any row at this point | |
| if (theadRowStack.length !== 0 || (groupZero.row && groupZero.row.length > 0)) { | |
| errorTrigger(26, this); | |
| } | |
| $(this).data("tblparser", groupZero); | |
| stackRowHeader = true; | |
| // This is the rowgroup header, Colgroup type can not be defined here | |
| $(this).children().each(function () { | |
| if (this.nodeName.toLowerCase() !== 'tr') { | |
| // ERROR | |
| errorTrigger(27, this); | |
| } | |
| processRow(this); | |
| }); | |
| stackRowHeader = false; | |
| // Here it's not possible to Diggest the thead and the colgroup because we need the first data row to be half processed before | |
| } else if (nodeName === 'tbody' || nodeName === 'tfoot') { | |
| if (nodeName === 'tfoot') { | |
| tfootOnProcess = true; | |
| } | |
| // Currently there are no specific support for tfoot element, the tfoot is understood as a normal tbody | |
| currentRowGroupElement = this; | |
| initiateRowGroup(); | |
| $this.data().tblparser = currentRowGroup; | |
| /* | |
| * | |
| * | |
| * | |
| * First tbody = data | |
| * All tbody with header === data | |
| * Subsequent tbody without header === summary | |
| * | |
| */ | |
| // $this.data("tblparser", currentRowHeader); | |
| // New row group | |
| $this.children().each(function () { | |
| if (this.nodeName.toLowerCase() !== 'tr') { | |
| // ERROR | |
| errorTrigger(27, this); | |
| return; | |
| } | |
| processRow(this); | |
| }); | |
| finalizeRowGroup(); | |
| // Check for residual rowspan, there can not have cell that overflow on two or more rowgroup | |
| $.each(spannedRow, function () { | |
| if (this.spanHeight > 0) { | |
| // That row are spanned in 2 different row group | |
| errorTrigger(29, this); | |
| } | |
| }); | |
| spannedRow = []; // Cleanup of any spanned row | |
| rowgroupHeaderRowStack = []; // Remove any rowgroup header found. | |
| currentRowHeader = []; | |
| currentTbodyID += 1; | |
| } else if (nodeName === 'tr') { | |
| // This are suppose to be a simple table | |
| processRow(this); | |
| } else { | |
| // There is a DOM Structure error | |
| errorTrigger(30, this); | |
| } | |
| }); | |
| groupZero.theadRowStack = theadRowStack; | |
| delete groupZero.colgroupFrame; | |
| groupZero.colgrouplevel = groupZero.colgrp; | |
| delete groupZero.colgrp; | |
| } // end of exec | |
| }; | |
| window.pe = _pe; | |
| return _pe; | |
| }(jQuery)); |