//============================================================================== // // Purpose: Builds a table, client-side. // //============================================================================== /* eslint no-redeclare: "off", no-unused-vars: "off", no-useless-assignment: "off" */ /*global JSON // Found in FontIconIds.js getRawFontId getFontNamePrefix FontIconId_Enum // SharedClientFunctions.js consoleLog consoleLogBlockOpen consoleLogBlockClose consoleLogJ htmlMultilineEncode htmlEncode trim // ShopSharedFunctions.js mjtElemData getObj saveScrollPos // ShopSharedFullFunctions.js checkAttribute */ //------------------------------------------------------------------------------ //------------------------------------------------------------------------------ function MWCellLinkDetail(options_) { var self = this; self.simpleLink = options_.simpleLink; self.doubleQuoteReadyJS = options_.doubleQuoteReadyJS; self.openInOtherWindow = !!options_.openInOtherWindow; self.dialogLink = !!options_.dialogLink; } //------------------------------------------------------------------------------ //------------------------------------------------------------------------------ function mwBuildSimpleLink(url_, openInOtherWindow_) { return new MWCellLinkDetail({ simpleLink: url_, openInOtherWindow: openInOtherWindow_ }); } //------------------------------------------------------------------------------ //------------------------------------------------------------------------------ function mwBuildLinkScript(doubleQuoteReadyJS_, openInOtherWindow_) { return new MWCellLinkDetail({ doubleQuoteReadyJS: doubleQuoteReadyJS_, openInOtherWindow: openInOtherWindow_ }); } //------------------------------------------------------------------------------ //------------------------------------------------------------------------------ function MWCustomCellSpec(options_) { if (null === options_ || typeof options_ === 'string') { options_ = { rawValue: options_ || '' }; } else { options_ = options_ || {}; } var self = this, colSpan = options_.colSpan || 1, rowSpan = options_.rowSpan || 1, strValueHTML = options_.valueHTML || htmlEncode(options_.rawValue || ''), cellId = (options_.cellId || '') + ''; self.getColSpan = function () { return colSpan; }; self.getRowSpan = function () { return rowSpan; }; self.getValueHTML = function () { return strValueHTML; }; self.getCellId = function () { return cellId; }; } //------------------------------------------------------------------------------ //------------------------------------------------------------------------------ function mwIsCustomCellSpecObject(object_) { if (object_ && typeof object_ === 'object' && object_.constructor && object_.constructor.name === 'MWCustomCellSpec') { return true; } } //------------------------------------------------------------------------------ //------------------------------------------------------------------------------ var g_nextGeneratedColLinkIdNum = 1; function MWColumn(options_) { options_ = options_ || {}; var self = this, sortInfo = options_.sortInfo; self.columnName = options_.columnName; self.simpleDisplayColumnPropertyName = options_.simpleDisplayColumnPropertyName; // Name of the property to grab from the array being rendered. self.simpleDisplayColumnNeedsMultilineEncoding = options_.simpleDisplayColumnNeedsMultilineEncoding; // If set for a simple display column, it will be htmlMultilineEncoded. self.simpleDisplayColumnIsAlreadyEncoded = options_.simpleDisplayColumnIsAlreadyEncoded; // If not set for a simple display column, it will be htmlEncoded. self.colLinkId = 'mwColLinkId.' + g_nextGeneratedColLinkIdNum++; // Function provided for custom rendering. Takes the following form: // // fnCustomRenderCellContents( // objRow_, // objColumn_, // array_, // rowIndex_) self.fnCustomRenderCellContents = options_.fnCustomRenderCellContents; self.customRenderCellParams = options_.customRenderCellParams; self.additionalCellClasses = options_.additionalCellClasses || ''; self.additionalHeaderClasses = options_.additionalHeaderClasses || ''; // If the sortInfo property includes a fnCustomSort property, and the // MWClientTable object has been linked to dom elements, the function will // be invoked as follows: // // sortInfo.fnCustomSort( // objMWColumn_, // The MWColumn object // ascending_, // Indicates whether the // // sort should be ascending // columnHeaderCell_) // Column header DOM element // // Otherwise, sorting relies on a data attribute associated with the row, // and a specific property on that object. By default, the attribute used // has the name 'data-rowData' and the property used will have the same // name as that given by the "simpleDisplayColumnPropertyName" option. // // If these defaults are appropriate for the sort, it's only necessary to // assign an empty object as the "sortInfo" property: // // { // ... // sortInfo: {}, // ... // } // // These defaults can be overridden by setting the "rowDataAttrName" // and "rowDataAttrPropertyName" properties on the sortInfo. // if (sortInfo) { self.sortInfo = sortInfo; sortInfo.rowDataAttrName = sortInfo.rowDataAttrName || 'data-rowData'; sortInfo.rowDataAttrPropertyName = sortInfo.rowDataAttrPropertyName || options_.simpleDisplayColumnPropertyName; } self.fnAdditionalCellClasses = options_.fnAdditionalCellClasses; // // When set, called to retrieve classes to add to the cell. Usage: // // fnAdditionalCellClasses( // objRow_, // objColumn_, // array_, // idxRow_) // // returns: // "classes to add to the cell" // self.fnBuildCellLinkDetail = options_.fnBuildCellLinkDetail; // // When set, used to build a link/click handler for the cells // of this column. Usage: // // fnBuildCellLinkDetail( // objRow_, // objColumn_, // array_, // rowIndex_) // // returns: // An instance of MWCellLinkDetail // (or nothing if no linking/scripting for the given cell) // // Sub-columns are used to support grouping headers. self.arrSubColumns = options_.arrSubColumns || []; } //------------------------------------------------------------------------------ //------------------------------------------------------------------------------ MWColumn.prototype.addSubColumn = function (objColumn_) { this.arrSubColumns.push(objColumn_); return objColumn_; }; //------------------------------------------------------------------------------ //------------------------------------------------------------------------------ MWColumn.prototype.getFlattenedColumnCount = function () { var self = this, arrSubColumns = self.arrSubColumns, idxSubColumn = 0, rc = 0; if (arrSubColumns.length) { for (idxSubColumn = 0; idxSubColumn < arrSubColumns.length; ++idxSubColumn) { rc += arrSubColumns[idxSubColumn].getFlattenedColumnCount(); } } else { rc = 1; } return rc; }; //------------------------------------------------------------------------------ //------------------------------------------------------------------------------ function flattenArrayOfColumnObjects(arrColumnObjects_, optionalLeafColumnArray_) { optionalLeafColumnArray_ = optionalLeafColumnArray_ || []; var idxColumn = 0; if (arrColumnObjects_.length) { for (idxColumn = 0; idxColumn < arrColumnObjects_.length; ++idxColumn) { arrColumnObjects_[idxColumn].flattenToEndOfArrayOfLeafColumns(optionalLeafColumnArray_); } } return optionalLeafColumnArray_; } //------------------------------------------------------------------------------ //------------------------------------------------------------------------------ MWColumn.prototype.flattenToEndOfArrayOfLeafColumns = function (optionalLeafColumnArray_) { optionalLeafColumnArray_ = optionalLeafColumnArray_ || []; var self = this, arrSubColumns = self.arrSubColumns; if (arrSubColumns.length) { flattenArrayOfColumnObjects(arrSubColumns, optionalLeafColumnArray_); } else { optionalLeafColumnArray_.push(self); } return optionalLeafColumnArray_; }; //------------------------------------------------------------------------------ //------------------------------------------------------------------------------ MWColumn.prototype.getColumnName = function () { return this.columnName; }; //------------------------------------------------------------------------------ //------------------------------------------------------------------------------ MWColumn.prototype.getCustomRenderCellParams= function () { return this.customRenderCellParams; }; //------------------------------------------------------------------------------ //------------------------------------------------------------------------------ MWColumn.prototype.buildCellContents = function (array_, rowIndex_) { var self = this, objRow = array_[rowIndex_], fnCustomRenderCellContents = self.fnCustomRenderCellContents, rc; if (fnCustomRenderCellContents) { rc = fnCustomRenderCellContents( objRow, self, // objColumn_ array_, rowIndex_); } else { // Simple column... var simpleDisplayColumnPropertyName = self.simpleDisplayColumnPropertyName, simpleDisplayColumnNeedsMultilineEncoding = self.simpleDisplayColumnNeedsMultilineEncoding, simpleDisplayColumnIsAlreadyEncoded = self.simpleDisplayColumnIsAlreadyEncoded, objPropertyValue = objRow ? objRow[simpleDisplayColumnPropertyName] : undefined; if (objPropertyValue !== undefined && objPropertyValue !== null) { rc = objPropertyValue.toString(); if (simpleDisplayColumnNeedsMultilineEncoding) { rc = htmlMultilineEncode(rc); } else if (true === simpleDisplayColumnIsAlreadyEncoded) { // no-op - already encoded } else { rc = htmlEncode(rc); } } else { rc = ''; } } return rc; }; //------------------------------------------------------------------------------ //------------------------------------------------------------------------------ function MWClientTable(options_) { options_ = options_ || {}; var self = this; self.noDataMessage = options_.noDataMessage || 'No Data'; self.arrColumns = options_.arrColumns || []; self.tableId = options_.tableId || ''; self.tableScrollName = options_.tableScrollName || ''; self.additionalTableClasses = options_.additionalTableClasses || ''; self.suppressReportTableClass = options_.suppressReportTableClass; self.suppressTableHeader = options_.suppressTableHeader; self.fnAdditionalRowClasses = options_.fnAdditionalRowClasses; self.cssClassPrefix = options_.cssClassPrefix; self.tableHeaderClass = options_.tableHeaderClass; self.suppressTableHeaderRowClass = options_.suppressTableHeaderRowClass; self.showTableIfNoData = options_.showTableIfNoData || false; // // When set, called to retrieve classes to add to the row. Usage: // // fnAdditionalRowClasses( // objRow_, // array_, // idxRow_, // cssClassPrefix_) // // returns: // "classes to add to the row" // self.fnOverrideGetRowClass = options_.fnOverrideGetRowClass; // // When set, called to retrieve the primary class to use for the row. Usage: // // fnOverrideGetRowClass( // objRow_, // array_, // idxRow_, // cssClassPrefix_) // // returns: // "primary class(es) to use for the row" // // When not set, "oddRow" and "evenRow" will be used // (with the table's "cssClassPrefix" prepended, if appropriate). // self.fnGetCheckDetailsForRow = options_.fnGetCheckDetailsForRow; // // When set, called to retrieve details about how to handle a given row's checkbox. Usage: // // fnGetCheckDetailsForRow( // objRow_, // array_, // idxRow_) // // returns: // { // value: "string-value-to-assign-cb", // checked: true if the cb should be checked. // } // self.flagCBsToFireOnChange = options_.flagCBsToFireOnChange; // When set, if the table includes a checkbox column, those checkboxes will // be configured to have the "fireOnChange_" parameter set when either of // "checkAllRows()" or "checkSingleRow()" is called. self.fnAdditionalRowAttrs = options_.fnAdditionalRowAttrs; // // When set, called to retrieve a string of additional attribute definitions. // // fnAdditionalRowAttrs( // objRow_, // array_, // idxRow_) // // returns: "data-attr1='' data-attr2='' ..." // // // Given a column object, this recursive function will build out an array // in which each successive element of the array corresponds to an array of // column objects that together define a single row of the overall, // potentially multi-rowed header. // self.internalExtendArrayOfHeaderRowColumnObjects = function (objColumn_, arrHeaderRowColumnObjects_, zeroBasedDepthIndex_) { if (zeroBasedDepthIndex_ > arrHeaderRowColumnObjects_.length - 1) { // We haven't yet added the row we're about to be dealing with, so add it now... arrHeaderRowColumnObjects_.push([]); } var self = this, idxSubColumn, arrSubColumns = objColumn_.arrSubColumns, arrCurrLevelColumns = arrHeaderRowColumnObjects_[zeroBasedDepthIndex_]; // Add this column arrCurrLevelColumns.push(objColumn_); // Add any subcolumns for (idxSubColumn = 0; idxSubColumn < arrSubColumns.length; ++idxSubColumn) { self.internalExtendArrayOfHeaderRowColumnObjects( arrSubColumns[idxSubColumn], // objColumn_ arrHeaderRowColumnObjects_, zeroBasedDepthIndex_ + 1); // 1 row deeper... } }; } //------------------------------------------------------------------------------ //------------------------------------------------------------------------------ MWClientTable.prototype.getTableId = function() { return this.tableId; }; //------------------------------------------------------------------------------ //------------------------------------------------------------------------------ MWClientTable.prototype.flattenToEndOfArrayOfLeafColumns = function () { return flattenArrayOfColumnObjects(this.arrColumns); }; //------------------------------------------------------------------------------ //------------------------------------------------------------------------------ MWClientTable.prototype.addColumn = function (objColumn_) { this.arrColumns.push(objColumn_); return objColumn_; }; //------------------------------------------------------------------------------ // // Removes the column. If found and removed, the column is returned. // If the column is included multiple times, it will be removed in each case. // //------------------------------------------------------------------------------ MWClientTable.prototype.removeColumn = function (objColumn_) { var arrColumns = this.arrColumns, i, rc; for (i = 0; i < arrColumns.length; ++i) { if (objColumn_ === arrColumns[i]) { arrColumns.splice( i, // start 1); // deleteCount rc = objColumn_; } } return rc; }; //------------------------------------------------------------------------------ //------------------------------------------------------------------------------ MWClientTable.prototype.buildArrayOfHeaderRowColumnObjects = function () { var self = this, rc = [], idxColumn, arrColumns = self.arrColumns; for (idxColumn = 0; idxColumn < arrColumns.length; ++idxColumn) { self.internalExtendArrayOfHeaderRowColumnObjects( arrColumns[idxColumn], // objColumn_ rc, // arrHeaderRowColumnObjects_ 0); // zeroBasedDepthIndex_ } return rc; }; //------------------------------------------------------------------------------ //------------------------------------------------------------------------------ MWClientTable.prototype.getCheckboxFunction = function () { return this.fnGetCheckDetailsForRow; }; //------------------------------------------------------------------------------ //------------------------------------------------------------------------------ MWClientTable.prototype.setCheckboxFunction = function (fnGetCheckDetailsForRow_) { this.fnGetCheckDetailsForRow = fnGetCheckDetailsForRow_; }; //------------------------------------------------------------------------------ //------------------------------------------------------------------------------ function mwGetTableCssClass(descendentElem_) { var objParentTable = checkAttribute(descendentElem_, 'data-mwClientTable'), strCssClassPrefix = (objParentTable ? objParentTable.getAttribute('data-cssClassPrefix') : '') || ''; return strCssClassPrefix; } //------------------------------------------------------------------------------ // This signature must match fnOverrideGetRowClass, hence the unused parameters. //------------------------------------------------------------------------------ function szStandardGetClientTableRowClass(objRow_, array_, idxRow_, cssClassPrefix_) { // As a sanity check, ensure that "cssClassPrefix_" is actually a string. cssClassPrefix_ = ( typeof cssClassPrefix_ !== 'string' ? '' : cssClassPrefix_) || ''; return cssClassPrefix_ + (idxRow_ % 2 ? 'evenRow' : 'oddRow'); } //------------------------------------------------------------------------------ //------------------------------------------------------------------------------ function mwApplyOddOrEvenClassToRow(objRow_, idxRow_, cssClassPrefix_) { if (objRow_.classList) { // As a sanity check, ensure that "cssClassPrefix_" is actually a string. cssClassPrefix_ = (typeof cssClassPrefix_ !== 'string' ? '' : cssClassPrefix_) || ''; // First, get rid of any exiting odd/even classes objRow_.classList.remove(cssClassPrefix_ + 'evenRow'); objRow_.classList.remove(cssClassPrefix_ + 'oddRow'); // Now add the correct one back objRow_.classList.add( szStandardGetClientTableRowClass( null, null, idxRow_, cssClassPrefix_)); } } //------------------------------------------------------------------------------ //------------------------------------------------------------------------------ function mwBuildSortAddendum(sortDir_) { var rc = ''; if (sortDir_) { rc = ' ' + '&#' + getRawFontId(sortDir_ === 1 ? FontIconId_Enum.fiiArrowSortUp : FontIconId_Enum.fiiArrowSortDown) + ';'; } return rc; } //------------------------------------------------------------------------------ //------------------------------------------------------------------------------ function mwSortClientColumn(columnHeaderCell_, sortInfo_, cssClassPrefix_) { var strRowDataAttrName = sortInfo_.rowDataAttrName, strRowDataAttrPropertyName = sortInfo_.rowDataAttrPropertyName, strRowDataValue, objRowData, idxVisible, objAncestor = columnHeaderCell_, strSortDir = columnHeaderCell_.getAttribute('data-mwSortDir'), tmpSortDir = strSortDir === '1' ? 1 : strSortDir === '-1' ? -1 : 0, tmpNewSortDir = tmpSortDir === 1 ? -1 : 1, strSortAddendum = mwBuildSortAddendum(tmpNewSortDir), objTable, trs, tr, idxRow, arrRowInfos = [], objColumn = mjtElemData(columnHeaderCell_, 'data-mwColLinkObj'), objSortInfo = objColumn ? objColumn.sortInfo || sortInfo_ : sortInfo_, fnCustomSort = objSortInfo ? objSortInfo.fnCustomSort : 0; while (objAncestor && !objTable) { if (objAncestor.nodeName === 'TABLE') { objTable = objAncestor; } else { objAncestor = objAncestor.parentNode; } } if (fnCustomSort) { fnCustomSort( objColumn, tmpNewSortDir === 1, // ascending_ columnHeaderCell_); } else { // Clear away the sort icon... objTable.querySelectorAll('.mwSortIcon').forEach( function (object_) { object_.parentNode.removeChild(object_); }); // ...and "sortSelected" indicator... objTable.querySelectorAll('.sortSelected').forEach( function (object_) { object_.className = object_.className.replace('sortSelected', ''); }); columnHeaderCell_.parentNode.querySelectorAll('[data-mwSortDir]').forEach( function (object_) { object_.setAttribute('data-mwSortDir', 0); }); columnHeaderCell_.setAttribute('data-mwSortDir', tmpNewSortDir); columnHeaderCell_.innerHTML = columnHeaderCell_.innerHTML + strSortAddendum; columnHeaderCell_.className = trim(columnHeaderCell_.className) + ' sortSelected'; trs = objTable.rows; for (idxRow = trs.length - 1; idxRow >= 0; --idxRow) { tr = trs[idxRow]; strRowDataValue = tr.getAttribute(strRowDataAttrName); if (strRowDataValue) { objRowData = JSON.parse(unescape(strRowDataValue)); arrRowInfos.push({ rowData: objRowData, idxRow: idxRow, tr: tr, parentNode: tr.parentNode }); tr.parentNode.removeChild(tr); } } arrRowInfos.sort( function (o1_, o2_) { var rd1 = o1_.rowData, p1 = rd1[strRowDataAttrPropertyName], rd2 = o2_.rowData, p2 = rd2[strRowDataAttrPropertyName], rc = 0; if (p1 === p2) { // Since the values compare equally, maintain the original // sort order by now comparing the original row indices. if (o1_.idxRow < o2_.idxRow) { rc = -1; } else if (o1_.idxRow > o2_.idxRow) { rc = 1; } else { rc = 0; } // Need to multiply by the new sort order (1/-1) so that if // we're sorting descending, the sort order maintenance will // hold. rc = tmpNewSortDir * rc; } else if (p1 === null || p1 === undefined) { rc = -1; } else if (p2 === null || p2 === undefined) { rc = 1; } else { if (sortInfo_.isNumber) { var f1 = parseFloat(p1), f2 = parseFloat(p2); rc = f1 === f2 ? 0 : f1 < f2 ? -1 : 1; } else { rc = p1.toString().toLowerCase().localeCompare(p2.toString()); } } return tmpNewSortDir === 1 ? rc : -rc; }); idxVisible = 0; arrRowInfos.forEach(function (objRowInfo_, index_) { objRowInfo_.parentNode.appendChild(objRowInfo_.tr); if (objRowInfo_.tr.style.display !== 'none') { mwApplyOddOrEvenClassToRow(objRowInfo_.tr, idxVisible, cssClassPrefix_); ++idxVisible; } }); } } //------------------------------------------------------------------------------ //------------------------------------------------------------------------------ MWClientTable.prototype.buildTableForArray = function (array_) { var self = this, tmpIsCB, tmpRowCount = array_ ? array_.length : 0, arrHeaderRowColumnObjects = self.buildArrayOfHeaderRowColumnObjects(), idxHeaderRow, strHeaderRowClassAttr, arrFlattenedLeafColumnObjects = self.flattenToEndOfArrayOfLeafColumns(), arrRemainingRowSpans = [0], // Keeps track of cells that have a rowspan specified. arrColumnsOfCurrentHeaderRow, fnGetCheckDetailsForRow = self.fnGetCheckDetailsForRow, tableId = self.tableId, tableScrollName = self.tableScrollName, idxCol, objRow, objColumn, idxRow, strCheckboxId, strCssClassPrefix = self.cssClassPrefix || '', fnAdditionalRowClasses = self.fnAdditionalRowClasses, fnAdditionalRowAttrs = self.fnAdditionalRowAttrs, strAdditionalRowClasses, strAdditionalCellClasses, strCellClassesAttr, strAdditionalTableClasses = self.additionalTableClasses, strReportTableClass = self.suppressReportTableClass ? '' : 'reportTable', strTableClassAddendum = strAdditionalTableClasses ? ' ' + trim(strAdditionalTableClasses) : '', fnGetRowClass = self.fnOverrideGetRowClass || szStandardGetClientTableRowClass, strAdditionalRowAttrs, tmpHeaderRowCount = arrHeaderRowColumnObjects.length, rc = '', fnBuildCellLinkDetail, objCellLinkDetail, strSimpleLink, doubleQuoteReadyJS, strCellOnClickAttr, strLeafRowSpanAttr, strTableHeaderClass = self.tableHeaderClass || 'headerRow', tmpSuppressTableHeaderRowClass = self.suppressTableHeaderRowClass, tmpShowTableIfNoData = self.showTableIfNoData; for (idxCol = 0; idxCol < arrHeaderRowColumnObjects.length; ++idxCol) { arrRemainingRowSpans[idxCol] = 0; } if ((tmpRowCount && arrHeaderRowColumnObjects.length) || tmpShowTableIfNoData) { rc += ''; // Render the header rows... if (!self.suppressTableHeader) { rc += ''; for (idxHeaderRow = 0; idxHeaderRow < tmpHeaderRowCount; ++idxHeaderRow) { strHeaderRowClassAttr = idxHeaderRow ? ' class="grouped-header"' : ''; rc += ''; if (idxHeaderRow + 1 < tmpHeaderRowCount) { // We haven't reached the last row of the header, so any leaf headers at this level // need to have a rowspan to extend past subsequent header rows... strLeafRowSpanAttr = 'rowspan="' + (tmpHeaderRowCount - idxHeaderRow) + '" '; } else { // We're at the absolute lowest level of the headers, however deep it goes. strLeafRowSpanAttr = ''; } if (fnGetCheckDetailsForRow && !idxHeaderRow) { // Including a checkbox column and this is the first header row... var tmpFlagAllRowsCBToFireOnChange = self.flagCBsToFireOnChange, strDoubleQuoteReadyOnClickAllRowsCBJS = "checkAllRows(" + "this" + ",'" + tableId + "'" + (tmpFlagAllRowsCBToFireOnChange ? ",undefined,undefined,true" : "") + ")"; rc += ''; } arrColumnsOfCurrentHeaderRow = arrHeaderRowColumnObjects[idxHeaderRow]; for (idxCol = 0; idxCol < arrColumnsOfCurrentHeaderRow.length; ++idxCol) { objColumn = arrColumnsOfCurrentHeaderRow[idxCol]; var tmpFlattenedColumnCount = objColumn.getFlattenedColumnCount(), objSortInfo = objColumn.sortInfo, tmpInitialSortDir = objSortInfo ? objSortInfo.initialSortDir : 0, strSortHeaderAddendum = mwBuildSortAddendum(tmpInitialSortDir), strSortDirAttr = tmpInitialSortDir ? 'data-mwSortDir="' + tmpInitialSortDir + '" ' : '', strHeaderClass = strCssClassPrefix + (objSortInfo ? 'headerSortableCol' : 'headerCol'), strSortOnClickAttr = objSortInfo ? "onclick=\"mwSortClientColumn(" + "this," + "JSON.parse(unescape('" + escape(JSON.stringify(objSortInfo)) + "')),"+ "'" + unescape(escape(strCssClassPrefix)) + "')\" " : ""; strAdditionalRowClasses = objColumn.additionalHeaderClasses ? ' ' + objColumn.additionalHeaderClasses : ''; if(tmpSuppressTableHeaderRowClass) { strHeaderClass = ''; } rc += ''; } rc += ''; } rc += ''; } if(!tmpRowCount) { if(arrFlattenedLeafColumnObjects && arrFlattenedLeafColumnObjects.length > 0) { rc += ''; } else { rc += ''; } } else { for (idxRow = 0; idxRow < tmpRowCount; ++idxRow) { objRow = array_[idxRow]; strAdditionalRowClasses = ''; if (fnAdditionalRowClasses) { var strFnAdditionalRowClasses = fnAdditionalRowClasses(array_[idxRow], array_, idxRow); if (strFnAdditionalRowClasses) { strAdditionalRowClasses = ' ' + strFnAdditionalRowClasses; } } strAdditionalRowAttrs = ''; if (fnAdditionalRowAttrs) { strAdditionalRowAttrs = ' ' + fnAdditionalRowAttrs(objRow, array_, idxRow); } rc += ''; if (fnGetCheckDetailsForRow) { // Is a checkbox function and this is the first column... var strCheckboxName = 'chkRow' + tableId, objCheckDetails = fnGetCheckDetailsForRow(objRow, array_, idxRow), strCBValue = objCheckDetails.value, tmpFlagCBsToFireOnChange = self.flagCBsToFireOnChange, strDoubleQuoteReadyOnClickCBJS = "checkSingleRow(" + "event" + ",this" + ",'" + tableId + "'" + (tmpFlagCBsToFireOnChange ? ",undefined,undefined,true" : "") + ")"; strCheckboxId = tableScrollName + "ChkRow" + tableId + idxRow; rc += ''; } for (idxCol = 0; idxCol < arrFlattenedLeafColumnObjects.length; ++idxCol) { if (arrRemainingRowSpans[idxCol]) { // This cell is part of a rowspan, so skip it... --arrRemainingRowSpans[idxCol]; } else { strCellOnClickAttr = ''; objColumn = arrFlattenedLeafColumnObjects[idxCol]; strCellClassesAttr = ''; strAdditionalCellClasses = ''; if (objColumn.additionalCellClasses) { strAdditionalCellClasses = objColumn.additionalCellClasses; } if (objColumn.fnAdditionalCellClasses) { strAdditionalCellClasses = trim( strAdditionalCellClasses + ' ' + objColumn.fnAdditionalCellClasses(array_[idxRow], objColumn, array_, idxRow)); } fnBuildCellLinkDetail = objColumn.fnBuildCellLinkDetail; if (fnBuildCellLinkDetail) { objCellLinkDetail = fnBuildCellLinkDetail( objRow, objColumn, array_, idxRow); } else { objCellLinkDetail = null; } var tmpIsDialogLink = 0; if (objCellLinkDetail) { tmpIsDialogLink = objCellLinkDetail.dialogLink; strSimpleLink = objCellLinkDetail.simpleLink; doubleQuoteReadyJS = objCellLinkDetail.doubleQuoteReadyJS; if (strSimpleLink || doubleQuoteReadyJS) { strAdditionalCellClasses = trim(strAdditionalCellClasses + ' linkedCell'); if (strSimpleLink) { if (objCellLinkDetail.openInOtherWindow) { strCellOnClickAttr = 'onclick="window.open(\'' + strSimpleLink + '\',\'_blank\');"'; } else if (tmpIsDialogLink) { strCellOnClickAttr = 'onclick="clickedDialogLink(\'' + strSimpleLink + '\');"'; } else { strCellOnClickAttr = 'onclick="window.location=\'' + strSimpleLink + '\';"'; } } else { strCellOnClickAttr = 'onclick="' + doubleQuoteReadyJS + '"'; } } } if (strAdditionalCellClasses) { strCellClassesAttr = ' class="' + strAdditionalCellClasses + '"'; } var objCellContents = objColumn.buildCellContents(array_, idxRow), tmpIsCustomCellSpecObject = mwIsCustomCellSpecObject(objCellContents), tmpColSpan = tmpIsCustomCellSpecObject ? objCellContents.getColSpan() : 1, strColSpanSpec = tmpColSpan === 1 ? '' : ' colspan="' + tmpColSpan + '"', tmpRowSpan = tmpIsCustomCellSpecObject ? objCellContents.getRowSpan() : 1, strRowSpanSpec = tmpRowSpan === 1 ? '' : ' rowspan="' + tmpRowSpan + '"', strCellContentsHTML = tmpIsCustomCellSpecObject ? objCellContents.getValueHTML() : objCellContents, strCellId = tmpIsCustomCellSpecObject ? objCellContents.getCellId() : '', strCellIdAttr = strCellId ? ' id="' + strCellId + '"' : ''; if (tmpRowSpan) { for (var i = 0; i < tmpColSpan; ++i) { // Take note of the rowspan for however may columns this cell spans. arrRemainingRowSpans[idxCol + i] = tmpRowSpan - 1; } } if (tmpIsCustomCellSpecObject) { objCellContents = strCellContentsHTML; } if (strSimpleLink && tmpIsDialogLink) { objCellContents = '' + objCellContents + ''; } rc += ''; if (fnGetCheckDetailsForRow && !idxCol) { // Include the label on the first column's value... rc += ''; } rc += ''; if (tmpColSpan > 1) { // Advance through this cells colspan... idxCol += tmpColSpan - 1; } } } } rc += ''; } rc += '
' + '' + ' 1 ? 'colspan="' + tmpFlattenedColumnCount + '" ' : strLeafRowSpanAttr) + strSortDirAttr + strSortOnClickAttr + 'data-mwColLinkId="' + objColumn.colLinkId + '" ' + 'class="' + strHeaderClass + strAdditionalRowClasses + '"' + '>' + objColumn.getColumnName() + strSortHeaderAddendum + '
' + htmlEncode(self.noDataMessage) + '
'+ htmlEncode(self.noDataMessage) + '
' + '' + '
'; } else { rc = htmlEncode(self.noDataMessage); } return rc; }; //------------------------------------------------------------------------------ //------------------------------------------------------------------------------ function mwFilterTableRows(table_, fnFilterRow_) { var idxRow, tr, idxVisibile = 0, // Check if the table was built using a style class prefix... strCssClassPrefix = mwGetTableCssClass(table_); for (idxRow = 0; idxRow < table_.rows.length; ++idxRow) { tr = table_.rows[idxRow]; if (tr.parentNode.nodeName !== 'THEAD') { // Ignore header rows when filtering... if (fnFilterRow_(tr)) { tr.style.display = ''; mwApplyOddOrEvenClassToRow(tr, idxVisibile, strCssClassPrefix); ++idxVisibile; } else { tr.style.display = 'none'; } } } } //------------------------------------------------------------------------------ // Filters rows to show if any cell in the row matches the filter text //------------------------------------------------------------------------------ function mwFilterTableRowsToFilterText(table_, filterText_) { var tmpCellIndex, strCapitilizedFilterText = filterText_.toUpperCase(); mwFilterTableRows( table_, function (objRow_) { for (tmpCellIndex = 0; tmpCellIndex < objRow_.cells.length; tmpCellIndex++) { var objCell = objRow_.cells[tmpCellIndex]; if (objCell) { var txtValue = objCell.textContent || objCell.innerText; if (txtValue.toUpperCase().indexOf(strCapitilizedFilterText) > -1) { return 1; } } } return 0; } ); } //------------------------------------------------------------------------------ //------------------------------------------------------------------------------ function mwRemoveTableRows(table_, fnShouldRemoveRow_) { var idxRow, tr, idxVisible = 0, // Check if the table was built using a style class prefix... strCssClassPrefix = mwGetTableCssClass(table_); for (idxRow = 0; idxRow < table_.rows.length; ++idxRow) { tr = table_.rows[idxRow]; if (tr.parentNode.nodeName !== 'THEAD') { // Ignore header rows when removing... if (!fnShouldRemoveRow_(tr)) { tr.style.display = ''; mwApplyOddOrEvenClassToRow(tr, idxVisible, strCssClassPrefix); ++idxVisible; } else { tr.remove(); //we've removed a row so we have to adjust our iterator //so the striping will finish running idxRow--; } } } } //------------------------------------------------------------------------------ //------------------------------------------------------------------------------ MWClientTable.prototype.linkTableObjectsToElement = function (objTableAncestorElement_) { var self = this, arrColumns = self.arrColumns, tmpIsTableElement = '1' === objTableAncestorElement_.getAttribute('data-mwClientTable'), objTableElement = tmpIsTableElement ? objTableAncestorElement_ : objTableAncestorElement_.querySelector('*[data-mwClientTable="1"]'), arrColumnElements, idxColumnElem, strColLinkId, objColumnElem, idxColumnObj; if (objTableElement) { mjtElemData(objTableElement, 'data-mwClientTableObject', this); arrColumnElements = objTableElement.querySelectorAll('[data-mwColLinkId]'); for (idxColumnElem = 0; idxColumnElem < arrColumnElements.length; ++idxColumnElem) { objColumnElem = arrColumnElements[idxColumnElem]; strColLinkId = objColumnElem.getAttribute('data-mwColLinkId'); if (strColLinkId) { for (idxColumnObj = 0; idxColumnObj < arrColumns.length; ++idxColumnObj) { if (arrColumns[idxColumnObj].colLinkId === strColLinkId) { mjtElemData(objColumnElem, 'data-mwColLinkObj', arrColumns[idxColumnObj]); } } } } } };