aggrid-8.x-1.x-dev/js/aggrid.widget.js
js/aggrid.widget.js
/**
* Behavior for 'aggrid_widget_type' widget.
*/
var aggrid = (function (me, $, Drupal, drupalSettings, once) {
me.name = "aggrid";
'use strict';
var aggridFieldName = [];
var aggridDataEdit = [];
var aggridValidationErrors = [];
var aggridValidationPrevWarning = [];
var aggridShowError = [];
var aggridPasteStart = [];
var eGridDiv = [];
var gridOptions = [];
// Math Function for truncate instead of rounding decimals.
Number.prototype.toFixedDown = function(digits) {
var re = new RegExp("(\\d+\\.\\d{" + digits + "})(\\d)"),
m = this.toString().match(re);
return m ? parseFloat(m[1]) : this.valueOf();
};
// Function to return an empty value to replace NaN or Infinity.
Number.prototype.setToEmptyIfNaN = function() {
if (this.toString() == 'NaN' || this.toString() == 'Infinity') {
return '';
}
return this;
};
// Settings:
// Get the license for aggrid.
const aggridLicense = drupalSettings.aggrid.settings.license_key;
// Get the general settings.
const aggridGSJSON = JSON.parse(drupalSettings.aggrid.settings.aggridgsjson);
// Get the Excel Styles.
const aggridExcelStyles = JSON.parse(drupalSettings.aggrid.settings.aggridexcelstyles);
// Get the global default options.
const aggridOpt = JSON.parse(drupalSettings.aggrid.settings.aggridoptions);
Drupal.aggridInstances = [];
Drupal.behaviors.aggridIntegration = {
attach: function (context) {
function makeJson(item) {
var aggridOutput = {};
aggridOutput = gridOptions[item].rowData;
// Write back to Drupal 'Value' field.
$('#' + aggridFieldName[item] + '_rowData').val(
JSON.stringify(aggridOutput)
.replace(/NaN/g, 0)
.replace(/Infinity/g, 0)
);
// Write back to Drupal previous warning list field.
$('#' + aggridFieldName[item] + '_prevwarninglist').val(
JSON.stringify(aggridValidationPrevWarning[item])
);
}
function smartJSONextend(obj1, obj2) {
// clone
var mergedObj = JSON.parse(JSON.stringify(obj1));
(function recurse(currMergedObj, currObj2) {
var key;
for (key in currObj2) {
if (currObj2.hasOwnProperty(key)) {
if (!currMergedObj[key]) {
currMergedObj[key] = undefined;
}
// if object, then dive in / recurse.
if (typeof currObj2[key] === 'object' && currObj2[key] !== null) {
// obj2 is nested and currMergedObj[key] is undefined, sync types.
if (!currMergedObj[key]) {
// obj2[key] ifArray.
if (currObj2[key].length !== undefined) {
currMergedObj[key] = [];
}
else {
currMergedObj[key] = {};
}
}
recurse(currMergedObj[key], currObj2[key]);
}
else {
// overwrite if obj2 is leaf and not nested.
currMergedObj[key] = currObj2[key];
}
}
}
})(mergedObj, obj2);
return mergedObj;
}
let selector = $('.aggrid-widget');
let idArray = [];
selector.each(function () {
idArray.push(this.id);
});
$.each(idArray, function (index, item) {
let aggridDiv;
let aggridId;
let colDefsValue;
let rowSettingsValue;
let rowDataValue;
let prevWarningValue;
let prevWarningAIDValue;
let acknowledge_prevwarnings_checkbox;
let acknowledge_prevwarnings_wrapper;
let addOptValue;
// variable used temporarily for full header name creation loop.
let tempList = [];
let aggridJSON_colDefs;
let aggridJSON_rowSettings;
let aggridJSON_rowData;
let aggridJSON_prevwarning;
let aggridJSON_addOpt;
// all field columns are placed in here.
let aggridFields;
// Will contain full header name for each.
let aggridFieldFullHeaderName = [];
// column field: parent - child - child.
// Will contain a label for each row if provided.
let aggridRowLabels = [];
// Set the aggrid div variable.
aggridDiv = $('#' + item);
// Set the aggrid id.
aggridId = aggridDiv[0].dataset.aggridId;
aggridFieldName[item] = aggridDiv.data('target');
aggridDataEdit[item] = aggridDiv.data('edit');
// Set the validation errors and previous warning variable for this aggrid.
aggridValidationErrors[item] = {};
aggridValidationPrevWarning[item] = {};
aggridShowError[item] = false;
aggridPasteStart[item] = false;
// If aggrid instance is already registered on Element. There is no
// need to register it again.
if (once('aggridDiv', '#' + item +'').length !== aggridDiv.length) {
return;
}
// Get the data from Drupal.
// Field Values.
rowDataValue = $('#' + aggridFieldName[item] + '_rowData').val();
prevWarningValue = $('#' + aggridFieldName[item] + '_prevwarning').val();
prevWarningAIDValue = $('#' + aggridFieldName[item] + '_prevwarningAID').val();
// Fields.
acknowledge_prevwarnings_checkbox = $('#' + aggridFieldName[item] + '_acknowledge_prevwarnings_checkbox');
acknowledge_prevwarnings_wrapper = $('#' + aggridFieldName[item] + '_acknowledge_prevwarnings_wrapper');
// Drupal Settings.
colDefsValue = drupalSettings.aggrid.settings[aggridFieldName[item]].columnDefs;
rowSettingsValue = drupalSettings.aggrid.settings[aggridFieldName[item]].rowSettings;
addOptValue = drupalSettings.aggrid.settings[aggridFieldName[item]].addOptions;
// If it's not blank, parse the json. otherwise, null.
aggridJSON_colDefs = colDefsValue ? JSON.parse(colDefsValue) : null;
aggridJSON_rowSettings = rowSettingsValue ? JSON.parse(rowSettingsValue) : null;
aggridJSON_rowData = rowDataValue ? JSON.parse(rowDataValue) : null;
aggridJSON_prevwarning = prevWarningValue ? JSON.parse(prevWarningValue) : null;
aggridJSON_addOpt = addOptValue ? JSON.parse(addOptValue) : null;
// If we have a global rowSettings default, then process things.
if (typeof aggridGSJSON['rowSettings'] !== 'undefined') {
// Merge the global rowSettings with the table rowSettings.
aggridJSON_rowSettings = smartJSONextend(aggridGSJSON['rowSettings'], aggridJSON_rowSettings);
}
function cellStyleFunc(params) {
return false;
}
function cellClassFunc(params) {
let ftName;
let cellClassVar = [];
let rscParamsRowId;
let rscParamsColDefField;
// Check if this is a pinned row or not.
if (typeof params.node.rowPinned === 'undefined') {
rscParamsRowId = params.node.id;
}
else {
rscParamsRowId =
params.node.rowPinned.substr(0, 1) + '-' + params.node.rowIndex;
}
rscParamsColDefField = params.colDef.field;
// Check for a cell setting and put to array
cellClassVar = rowSettingsCheck(
rscParamsRowId,
rscParamsColDefField,
'cellClass'
).split(" ");
// Check setting for cell, row, column, and then all columns.
// First available is priority.
ftName = rowSettingsCheck(
rscParamsRowId,
rscParamsColDefField,
'formatType'
);
// If the formatType and has an excelType, apply it.
if (
ftName !== '' &&
typeof aggridGSJSON.formatTypes[ftName] !== 'undefined' &&
aggridGSJSON.formatTypes[ftName].excelType !== 'undefined'
) {
cellClassVar.push(aggridGSJSON.formatTypes[ftName].excelType);
}
// Add if cell can be edited or not.
if (editableFunc(params)) {
cellClassVar.push("aggrid-cell-edit-ok");
}
else {
cellClassVar.push("aggrid-cell-edit-no");
}
return cellClassVar;
}
function colSpanFunc(params) {
let colSpanVar;
let rscParamsRowId;
let rscParamsColDefField;
if (typeof params.node.rowPinned === 'undefined') {
rscParamsRowId = params.node.id;
}
else {
rscParamsRowId = params.node.rowPinned.substr(0, 1) + '-' + params.node.rowIndex;
}
rscParamsColDefField = params.colDef.field;
// Check for a cell setting.
colSpanVar = rowSettingsCheck(
rscParamsRowId,
rscParamsColDefField,
'colSpan'
);
// If var is good, send it on. Otherwise, send default.
if (colSpanVar === '') {
colSpanVar = 1;
}
return colSpanVar;
}
function editableFunc(params) {
let rscParamsRowId;
let rscParamsColDefField;
if (typeof params.node.rowPinned === 'undefined') {
rscParamsRowId = params.node.id;
}
else {
rscParamsRowId = params.node.rowPinned.substr(0, 1) + '-' + params.node.rowIndex;
}
rscParamsColDefField = params.colDef.field;
let editableVar;
// Only check if editable when the grid is set to be editable.
// Otherwise, it's false.
if (aggridDataEdit[item]) {
// Check editable rowsetting.
editableVar = rowSettingsCheck(
rscParamsRowId,
rscParamsColDefField,
'editable'
);
// if the variable is blank, and grid editing is on, default to editable.
if (editableVar === '') {
editableVar = true;
}
}
else {
// grid is not editable then always send false.
editableVar = false;
}
// output.
return editableVar;
}
function getHeaderParentItems(data) {
if (typeof data !== 'undefined') {
tempList.push(data.getDefinition('headerName').headerName);
if (data.parent !== null) {
getHeaderParentItems(data.parent);
}
}
}
function getRowLabels() {
// Loop through each row and get fields assigned as isRowLabel.
$.each(gridOptions[item].rowData, function (row) {
tempList[row] = [];
$.each(aggridFields, function (count, field) {
if (rowSettingsCheck(row, field.colId,'isRowLabel') === true) {
tempList[row].push(gridOptions[item].rowData[row][field.colId]);
}
});
aggridRowLabels[row] = tempList[row]
.filter(function (e) {
return e;
})
.join(' - ');
});
}
function restrictInputFunc(params) {
// Only allow specific characters.
let ptName;
let rscParamsRowId;
let rscParamsColDefField;
let inputField = 'input.ag-cell-edit-input';
if (typeof params.node.rowPinned === 'undefined') {
rscParamsRowId = params.node.id;
}
else {
rscParamsRowId = params.node.rowPinned.substr(0, 1) + '-' + params.node.rowIndex;
}
rscParamsColDefField = params.colDef.field;
// Check setting for cell, row, column, and then all columns.
// First available is priority.
ptName = rowSettingsCheck(
rscParamsRowId,
rscParamsColDefField,
'parserType'
);
// If the ptName is set and restrictInput is available, move forward.
// Otherwise it's an error.
if (
ptName !== '' &&
typeof aggridGSJSON.parserTypes[ptName] !== 'undefined' &&
typeof aggridGSJSON.parserTypes[ptName].restrictInput !== 'undefined' &&
typeof aggridGSJSON.restrictInput[aggridGSJSON.parserTypes[ptName].restrictInput].regEx !== 'undefined'
) {
let regEx = new RegExp(aggridGSJSON.restrictInput[aggridGSJSON.parserTypes[ptName].restrictInput].regEx);
// Put a keydown trigger on the cell input (appears when a user is editing a cell).
$(inputField).on('keyup', function (e) {
if (typeof e.keyCode !== 'undefined' && e.keyCode !== 9) { // Ignore TAB for navigation purposes
this.value = this.value.replace(regEx, '');
}
}).trigger('keyup');
}
else {
// If the code reaches here, it's an error, so write the error to console.
let errorMsg = 'agGrid restrictInput Error: ';
// ptName is available but there are issues.
if (
ptName !== '' &&
typeof aggridGSJSON.parserTypes[ptName] === 'undefined'
) {
// parserType not found, tell the user.
console.log(
Drupal.t(
errorMsg + ptName + ' parserType not found.', {}, {
context: 'aggrid error parserType not found'
}
)
);
}
else if (
typeof aggridGSJSON.parserTypes[ptName] !== 'undefined' &&
typeof aggridGSJSON.parserTypes[ptName].restrictInput === 'undefined'
) {
// No restriction set on parserType. no error message.
}
else if (
typeof aggridGSJSON.parserTypes[ptName] !== 'undefined' &&
typeof aggridGSJSON.restrictInput[aggridGSJSON.parserTypes[ptName].restrictInput].regEx !== 'undefined'
) {
// Restriction set but no regEx defined.
console.log(
Drupal.t(errorMsg + ptName +
' regEx missing for restrictInput "jserr_restrictInput"', {
jserr_restrictInput: aggridGSJSON.parserTypes[ptName].restrictInput
}, {
context: 'aggrid error restrictInput missing regEx'
}
)
);
}
}
}
function rowSettingsCheck(rscParamsRowId, rscParamsColDefField, field) {
// Check values and return a result.
if (
aggridJSON_rowSettings !== null &&
aggridJSON_rowSettings !== ''
) {
if (
typeof aggridJSON_rowSettings[rscParamsRowId] !== 'undefined' &&
typeof aggridJSON_rowSettings[rscParamsRowId][rscParamsColDefField] !== 'undefined' &&
typeof aggridJSON_rowSettings[rscParamsRowId][rscParamsColDefField][field] !== 'undefined'
) {
return aggridJSON_rowSettings[rscParamsRowId][rscParamsColDefField][field];
}
else if (
typeof aggridJSON_rowSettings[rscParamsRowId] !== 'undefined' &&
typeof aggridJSON_rowSettings[rscParamsRowId].rowDefault !== 'undefined' &&
typeof aggridJSON_rowSettings[rscParamsRowId].rowDefault[field] !== 'undefined'
) {
return aggridJSON_rowSettings[rscParamsRowId].rowDefault[field];
}
else if (
typeof aggridJSON_rowSettings.default !== 'undefined' &&
typeof aggridJSON_rowSettings.default[rscParamsColDefField] !== 'undefined' &&
typeof aggridJSON_rowSettings.default[rscParamsColDefField][field] !== 'undefined'
) {
return aggridJSON_rowSettings.default[rscParamsColDefField][field];
}
else if (
typeof aggridJSON_rowSettings.default !== 'undefined' &&
typeof aggridJSON_rowSettings.default.rowDefault !== 'undefined' &&
typeof aggridJSON_rowSettings.default.rowDefault[field] !== 'undefined'
) {
return aggridJSON_rowSettings.default.rowDefault[field];
}
}
return ''; // all else fails, send blank.
}
function rowSpanFunc(params) {
let rowSpanVar;
let rscParamsRowId;
let rscParamsColDefField;
if (typeof params.node.rowPinned === 'undefined') {
rscParamsRowId = params.node.id;
}
else {
rscParamsRowId = params.node.rowPinned.substr(0, 1) + '-' + params.node.rowIndex;
}
rscParamsColDefField = params.colDef.field;
// Check for a cell setting.
rowSpanVar = rowSettingsCheck(
rscParamsRowId,
rscParamsColDefField,
'rowSpan'
);
// If var is good, send it on. Otherwise, send default.
if (rowSpanVar !== '') {
return rowSpanVar;
}
else {
return 1;
}
}
// Check previous year warning.
function prevWarningCheck(params) {
let pwJSON;
let ftName;
let ptName;
let paramsNodeId = params.node.id;
let paramsColumnColId = params.column.colId;
let constraintType_prevWarningJSON = {};
let value;
let rscParamsRowId;
let rscParamsColDefField;
let restrictInput;
let prevWarningAIDValueOther;
let prevWarningAIDAllowed;
if (typeof params.node.rowPinned === 'undefined') {
rscParamsRowId = params.node.id;
}
else {
rscParamsRowId =
params.node.rowPinned.substr(0, 1) + '-' + params.node.rowIndex;
}
rscParamsColDefField = params.colDef.field;
// Check setting for cell, row, column, and then all columns.
// First available is priority.
// Check for a cell setting and put to array
pwJSON = rowSettingsCheck(
rscParamsRowId,
rscParamsColDefField,
'previousWarningType'
);
cellClassVar = rowSettingsCheck(
rscParamsRowId,
rscParamsColDefField,
'cellClass'
).split(" ");
ftName = rowSettingsCheck(
rscParamsRowId,
rscParamsColDefField,
'formatType'
);
ptName = rowSettingsCheck(
rscParamsRowId,
rscParamsColDefField,
'parserType'
);
// Get restricted input type.
if (
ptName !== '' &&
pwJSON !== '' &&
typeof pwJSON.constraint !== 'undefined' &&
typeof pwJSON.prevWarnMsg !== 'undefined' &&
typeof aggridGSJSON.parserTypes[ptName] !== 'undefined' &&
typeof aggridGSJSON.parserTypes[ptName].restrictInput !== 'undefined'
) {
restrictInput = aggridGSJSON.parserTypes[ptName].restrictInput;
}
// Get other allowed previous aggrid ids.
prevWarningAIDValueOther = null;
prevWarningAIDAllowed = false;
if (
typeof aggridJSON['tablePrevAggridId'] !== 'undefined'
) { // Apply other aggrid id values from config.
prevWarningAIDValueOther = aggridJSON['tablePrevAggridId'];
prevWarningAIDValueOther.split(' ');
prevWarningAIDAllowed = prevWarningAIDValueOther.includes(prevWarningAIDValue);
}
// Check numeric previous warning threshold if editable numeric field.
if (
editableFunc(params) &&
(aggridId == prevWarningAIDValue || prevWarningAIDAllowed) &&
restrictInput === 'numeric'
) {
// Set current value from aggrid.
currentValue = params.newValue;
if (
typeof aggridJSON_prevwarning[rscParamsRowId] !== 'undefined' &&
typeof aggridJSON_prevwarning[rscParamsRowId][rscParamsColDefField] !== 'undefined'
) {
// Set the warning constraint.
let constIf = pwJSON.constraint;
// Set the warning value.
aggridPrevWarningValue = aggridJSON_prevwarning[rscParamsRowId][rscParamsColDefField];
// Check values for warning.
if (eval(constIf)) {
// Set variables for formatNumber.
let locale = 'en'; // Default to English (USA).
let options = {};
let ftItem = aggridGSJSON.formatTypes[ftName];
// Optional settings for NumberFormat for locale and options.
if (typeof ftItem.locale !== 'undefined') {
locale = ftItem.locale;
}
if (typeof ftItem.options !== 'undefined') {
options = ftItem.options;
}
// if it is a number, format it. otherwise, dont.
if ($.isNumeric(currentValue)) {
// Format based on locale and extra options.
currentValue = Intl.NumberFormat(locale, options).format(currentValue);
}
if ($.isNumeric(aggridPrevWarningValue)) {
// Format based on locale and extra options.
aggridPrevWarningValue = Intl.NumberFormat(locale, options).format(aggridPrevWarningValue);
}
// Get the warning from aggrid config.
prevWarnMsg = Drupal.t(
pwJSON.prevWarnMsg,
{
'@currentValue': currentValue,
'@aggridPrevWarningValue': aggridPrevWarningValue
},
{
context: 'Display aggrid cell validation previous warning messages to end users'
}
);
// Has a curValue, though it's not meeting requirements.
// Process it. Make sure our variable is ready for data.
constraintType_prevWarningJSON[paramsNodeId] = {};
constraintType_prevWarningJSON[paramsNodeId][paramsColumnColId] = {};
// Set the error values. old, new, and the message.
constraintType_prevWarningJSON[paramsNodeId][paramsColumnColId]['prevwarning'] = {
prevValue: aggridPrevWarningValue,
curValue: currentValue,
message: prevWarnMsg
};
// Merge without writing over objects.
aggridValidationPrevWarning[item] = smartJSONextend(
aggridValidationPrevWarning[item],
constraintType_prevWarningJSON
);
// Make sure validation error dialog is updated.
validationPrevWarningUpdate();
// Add warning class.
cellClassVar.push("ag-cell-warning");
// Refresh the grid.
gridOptions[item].api.refreshCells();
}
else {
validationPrevWarningClear(params);
validationPrevWarningUpdate();
}
}
}
}
// Check Previous year warning.
function validationPrevWarningCheck(paramsNodeId, paramsColumnColId) {
// return status of cell.
return aggridValidationPrevWarning[item] !== '' &&
typeof aggridValidationPrevWarning[item][paramsNodeId] !== 'undefined' &&
typeof aggridValidationPrevWarning[item][paramsNodeId][paramsColumnColId] !== 'undefined';
}
function validationPrevWarningShow(params) {
// show it.
$('#' + aggridFieldName[item] + '_prevwarningdialog').dialog({
dialogClass: 'aggrid-error-dialog',
height: 250,
width: 400,
// Add the 'open' event handler here
open: function(event, ui) {
let paramsNodeId = params.node.id;
let paramsColumnColId = params.column.colId;
let cellId = paramsNodeId + '-' + paramsColumnColId;
// jQuery object for the dialog's content area.
let dialogContentElement = $(this);
// Find the cell-id.
let targetElement = dialogContentElement.find('[cell-id="' + cellId +'"]');
if (targetElement.length > 0) {
// 2. Use native DOM's scrollIntoView() on the found element
// Access the native DOM element from the jQuery object: targetElement[0]
targetElement[0].scrollIntoView({
behavior: 'smooth', // Smooth scrolling animation
block: 'center', // Vertically align the element to the center of the view
inline: 'nearest' // Horizontally align if needed, scrolls minimal amount
});
// Add a temporary visual highlight to draw more attention.
targetElement.addClass('ag-cell-warning');
// Remove it after 5 seconds.
setTimeout(() => {targetElement.removeClass('ag-cell-warning');}, 5000);
}
else {
console.warn(`Element with cell-id="${targetCellIdToScrollTo}" not found in the dialog.`);
}
}
});
// reset show error on regular editing.
aggridShowError[item] = false;
}
// Clear the warning.
function validationPrevWarningClear(params) {
let paramsNodeId = params.node.id;
let paramsColumnColId = params.column.colId;
// Clear any previous error on ptName if available.
if (typeof aggridValidationPrevWarning[item][paramsNodeId] !== 'undefined' &&
typeof aggridValidationPrevWarning[item][paramsNodeId][paramsColumnColId] !== 'undefined') {
delete aggridValidationPrevWarning[item][paramsNodeId][paramsColumnColId];
// clear row if empty.
if ($.isEmptyObject(aggridValidationPrevWarning[item][paramsNodeId])) {
delete aggridValidationPrevWarning[item][paramsNodeId];
}
}
// Make sure validation warning dialog is updated.
validationPrevWarningUpdate();
}
function validationPrevWarningUpdate() {
let prevWarningRow = '';
let prevWarningRowCount = 0;
let prevWarningCount = 0;
let prevWarningText;
let prevWarningReq = true;
// loop through and get errors for dialog.
$.each(aggridValidationPrevWarning[item], function (rowindex) {
prevWarningRowCount += 1;
prevWarningRow += Drupal.t(
'<h3>Row jsprevwarn_rowNum: jsprevwarn_rowLabel</h3>', {
jsprevwarn_rowNum: Number(rowindex) + 1,
jsprevwarn_rowLabel: aggridRowLabels[rowindex]
}, {
context: 'Display aggrid cell validation warning list: row'
}
);
prevWarningRow += '<div>'; // Each row.
$.each(aggridValidationPrevWarning[item][rowindex],
function (fieldname) {
prevWarningCount += 1;
let cell_id = rowindex + "-" + fieldname;
prevWarningRow += '<div cell-id="' + cell_id + '">'; // Each cell.
prevWarningRow += Drupal.t(
'<h4>jsprevwarn_headerName</h4>', {
jsprevwarn_headerName: aggridFieldFullHeaderName[fieldname]
}, {
context: 'Display aggrid cell validation warning messages list: column'
}
);
$.each(
aggridValidationPrevWarning[item][rowindex][fieldname],
function (prevWarnType, prevWarnItems) {
// If NaN, then replace with [text].
if (prevWarnItems.curValue === 'NaN') {
prevWarnItems.curValue = '[text]';
}
// Add the error.
prevWarningRow += Drupal.t(
//"jsprevwarn_curValue" did not validate.
'<p>jsprevwarn_message</p>',
{
jsprevwarn_curValue: prevWarnItems.curValue,
jsprevwarn_Type: prevWarnType,
jsprevwarn_message: prevWarnItems.message
},
{
context: 'Display aggrid cell validation warning messages to end users'
}
);
}
);
prevWarningRow += '</div>'; // Each cell.
});
prevWarningRow += '</div>'; // Each row.
});
// if no previous data warnings, tell em.
if (prevWarningRow === '') {
// reset show error on regular editing.
prevWarningRow = '<h2>No previous data warning</h2>';
}
// change dialog html.
$('#' + aggridFieldName[item] + '_prevwarningdialog').html('<div>' + prevWarningRow + '</div>');
prevWarningText = '';
// Handle previous warning checkbox.
if (prevWarningCount > 0) {
// Try to get warning text from optional setting, otherwise use default.
if (
typeof aggridJSON['tablePrevWarning'] !== 'undefined' &&
typeof aggridJSON['tablePrevWarning']['text'] !== 'undefined'
) { // Apply warning text from config.
prevWarningText = aggridJSON['tablePrevWarning']['text'];
}
else { // Default warning text.
prevWarningText = 'Click here to accept the @prevWarningCount warning(s) on @prevWarningRowCount row(s).';
}
// Apply Drupal translate and any variable(s).
prevWarningText = Drupal.t(
prevWarningText,
{
'@prevWarningCount': prevWarningCount,
'@prevWarningRowCount': prevWarningRowCount
},
{
context: 'Display aggrid cell validation previous warning messages to end users'
}
);
// Try to get warning requirement boolean from optional setting, otherwise use default.
if (
typeof aggridJSON['tablePrevWarning'] !== 'undefined' &&
typeof aggridJSON['tablePrevWarning']['required'] !== 'undefined' &&
typeof aggridJSON['tablePrevWarning']['required'] == 'boolean' // boolean value required.
) {
prevWarningReq = aggridJSON['tablePrevWarning']['required'];
}
acknowledge_prevwarnings_wrapper
.removeAttr('hidden')
.removeClass('visually-hidden')
.removeAttr('aria-hidden');
acknowledge_prevwarnings_wrapper.find('input')
.removeAttr('hidden')
.removeClass('visually-hidden')
.removeClass('required');
// Set requirements.
if (prevWarningReq) {
acknowledge_prevwarnings_wrapper.find('input')
.attr('aria-required', true)
.prop('required', true);
}
// Write the label.
acknowledge_prevwarnings_wrapper.find('label')
.removeClass(['form-required'])
.text(prevWarningText);
}
else {
acknowledge_prevwarnings_wrapper
.attr('hidden', true)
.addClass('visually-hidden')
.attr('aria-hidden', true);
acknowledge_prevwarnings_wrapper.find('input')
.attr('hidden', true)
.addClass(['visually-hidden'])
.removeAttr('aria-required')
.prop('required', false)
.prop('checked', false);
acknowledge_prevwarnings_wrapper.find('label')
.removeClass(['form-required'])
.text(prevWarningText);
}
}
// Check error.
function validationErrorCheck(paramsNodeId, paramsColumnColId) {
// return status of cell.
return aggridValidationErrors[item] !== '' &&
typeof aggridValidationErrors[item][paramsNodeId] !== 'undefined' &&
typeof aggridValidationErrors[item][paramsNodeId][paramsColumnColId] !== 'undefined';
}
// Clear the error.
function validationErrorClear(params, ptName) {
let paramsNodeId = params.node.id;
let paramsColumnColId = params.column.colId;
// Clear any previous error on ptName if available.
if (ptName !== '' &&
typeof aggridValidationErrors[item][paramsNodeId] !== 'undefined' &&
typeof aggridValidationErrors[item][paramsNodeId][paramsColumnColId] !== 'undefined' &&
typeof aggridValidationErrors[item][paramsNodeId][paramsColumnColId][ptName] !== 'undefined') {
delete aggridValidationErrors[item][paramsNodeId][paramsColumnColId][ptName];
// Clear field if empty.
if ($.isEmptyObject(aggridValidationErrors[item][paramsNodeId][paramsColumnColId])) {
delete aggridValidationErrors[item][paramsNodeId][paramsColumnColId];
}
// clear row if empty.
if ($.isEmptyObject(aggridValidationErrors[item][paramsNodeId])) {
delete aggridValidationErrors[item][paramsNodeId];
}
// Make sure validation error dialog is updated.
validationErrorUpdate();
}
}
function validationErrorShow() {
// show it.
$('#' + aggridFieldName[item] + '_error').dialog({
dialogClass: 'aggrid-error-dialog',
height: 250,
width: 400
});
// reset show error on regular editing.
aggridShowError[item] = false;
}
function validationErrorUpdate() {
let errorRow = '';
// loop through and get errors for dialog.
$.each(aggridValidationErrors[item], function (rowindex) {
errorRow += Drupal.t(
'<h3>Row jserr_rowNum: jserr_rowLabel</h3>', {
jserr_rowNum: Number(rowindex) + 1,
jserr_rowLabel: aggridRowLabels[rowindex]
}, {
context: 'Display aggrid cell validation error list: row'
}
);
errorRow += '<div>';
$.each(aggridValidationErrors[item][rowindex],
function (fieldname) {
errorRow += Drupal.t(
'<h4>jserr_headerName</h4>', {
jserr_headerName: aggridFieldFullHeaderName[fieldname]
}, {
context: 'Display aggrid cell validation error messages list: column'
}
);
$.each(
aggridValidationErrors[item][rowindex][fieldname],
function (errType, errItems) {
// If NaN, then replace with [text].
if (errItems.newValue === 'NaN') {
errItems.newValue = '[text]';
}
// Add the error.
errorRow += Drupal.t(
'<p>"jserr_newValue" did not validate. jserr_message</p>',
{
jserr_newValue: errItems.newValue,
jserr_errType: errType,
jserr_message: errItems.message
},
{
context: 'Display aggrid cell validation error messages to end users'
}
);
}
);
});
errorRow += '</div>';
});
// if no errors, tell em.
if (errorRow === '') {
// reset show error on regular editing.
errorRow = '<h2>No validation errors</h2>';
}
// change dialog html.
$('#' + aggridFieldName[item] + '_error').html('<div>' + errorRow + '</div>');
}
function valueConstraintFunc(params) {
// valueConstraintFunc is executed from valueParserFunc after positive return.
let ctJSON;
let ftName;
let paramsNodeId = params.node.id;
let paramsColumnColId = params.column.colId;
let constraintType_errorJSON = {};
let value;
let rscParamsRowId;
let rscParamsColDefField;
if (typeof params.node.rowPinned === 'undefined') {
rscParamsRowId = params.node.id;
}
else {
rscParamsRowId = params.node.rowPinned.substr(0, 1) + '-' + params.node.rowIndex;
}
rscParamsColDefField = params.colDef.field;
// Check setting for cell, row, column, and then all columns.
// First available is priority.
ctJSON = rowSettingsCheck(
rscParamsRowId,
rscParamsColDefField,
'constraintType'
);
ftName = rowSettingsCheck(
rscParamsRowId,
rscParamsColDefField,
'formatType'
);
// If the ctName is set and constraint/errorMsg is available, move forward.
// Otherwise it's an error.
if (
ctJSON !== '' &&
typeof ctJSON.constraint !== 'undefined' &&
typeof ctJSON.errorMsg !== 'undefined'
) {
let constIf = ctJSON.constraint;
// Clear the current error for this item, if there is one.
validationErrorClear(params, 'constraint');
// Check the value against the constraint. if it's good, apply.
// Otherwise tell the user and flip back.
if (eval(constIf)) {
// We're good, let the new value go into place.
return params.newValue;
}
else {
// New value doesn't meet the constraint. Process.
if (params.newValue === '') {
// If delete, return nothing.
value = '';
if (ftName !== '' &&
typeof aggridGSJSON.formatTypes[ftName] !== 'undefined' &&
aggridGSJSON.formatTypes[ftName].type === 'number') {
// If delete and number, just change to zero.
value = 0;
}
return value;
}
else {
// Has a newValue, though it's not meeting requirements.
// Process it. Make sure our variable is ready for data.
constraintType_errorJSON[paramsNodeId] = {};
constraintType_errorJSON[paramsNodeId][paramsColumnColId] = {};
// Set the error values. old, new, and the message.
constraintType_errorJSON[paramsNodeId][paramsColumnColId]['constraint'] = {
oldValue: params.oldValue,
newValue: params.newValue,
message: ctJSON.errorMsg
};
// Merge without writing over objects.
aggridValidationErrors[item] = smartJSONextend(
aggridValidationErrors[item],
constraintType_errorJSON
);
// Make sure validation error dialog is updated.
validationErrorUpdate();
// Place the value and refresh the cells, this fixed an issue with multi copy and paste.
gridOptions[item].rowData[paramsNodeId][paramsColumnColId] = params.oldValue;
gridOptions[item].api.refreshCells();
// Make sure this is marked to show.
aggridShowError[item] = true;
// Show it.
validationErrorShow();
// Return it.
return params.oldValue;
}
}
}
else {
// If the code reaches here, it's an error, so write the error to console.
let errorMsg = 'agGrid constraintType Error: ';
// is available but there are issues.
if (
ctJSON === '' &&
typeof ctJSON === 'undefined' &&
typeof ctJSON.constraint === 'undefined' &&
typeof ctJSON.errorMsg === 'undefined'
) {
// found in aggridGSJSON, but missing the necessary objects.
console.log(
Drupal.t(
errorMsg + ' missing constraint or errorMsg', {}, {
context: 'aggrid error constraintType missing constraint or errorMsg'
}
)
);
}
// Error but return the newValue anyway.
return params.newValue;
}
}
// Change the value if needed when editing.
function valueConversion(params) {
let ftName;
let rscParamsRowId;
let rscParamsColDefField;
let inputField = 'input.ag-cell-edit-input';
if (params.node === null) {
rscParamsRowId = 0;
}
else if (typeof params.node.rowPinned === 'undefined') {
rscParamsRowId = params.node.id;
}
else {
rscParamsRowId = params.node.rowPinned.substr(0, 1) + '-' + params.node.rowIndex;
}
rscParamsColDefField = params.colDef.field;
// Check setting for cell, row, column, and then all columns.
// First available is priority.
ftName = rowSettingsCheck(
rscParamsRowId,
rscParamsColDefField,
'formatType'
);
// no ftName? error or no settings. Just allow any value.
if (
ftName !== '' &&
ftName.includes('numPer')
) {
// Change decimal to whole number percent.
if ($(inputField).length > 0) {
let curVal = params.value;
// If user is just clicking to edit, change decimal.
if (Number(curVal) === Number($(inputField).val())) {
$(inputField).val($(inputField).val() * 100).select();
}
}
}
}
// Format the values.
function valueFormatterFunc(params) {
let ftName;
let rscParamsRowId;
let rscParamsColDefField;
if (params.node === null) {
rscParamsRowId = 0;
}
else if (typeof params.node.rowPinned === 'undefined') {
rscParamsRowId = params.node.id;
}
else {
rscParamsRowId = params.node.rowPinned.substr(0, 1) + '-' + params.node.rowIndex;
}
rscParamsColDefField = params.colDef.field;
// Check setting for cell, row, column, and then all columns.
// First available is priority.
ftName = rowSettingsCheck(
rscParamsRowId,
rscParamsColDefField,
'formatType'
);
// no ftName? error or no setting. Just allow any value.
if (
ftName !== '' &&
typeof aggridGSJSON.formatTypes[ftName] !== 'undefined' &&
aggridGSJSON.formatTypes[ftName].type === 'number'
) {
// Set variables for formatNumber.
let locale = 'en'; // Default to English (USA).
let options = {};
let ftItem = aggridGSJSON.formatTypes[ftName];
// Optional settings for NumberFormat for locale and options.
if (typeof ftItem.locale !== 'undefined') {
locale = ftItem.locale;
}
if (typeof ftItem.options !== 'undefined') {
options = ftItem.options;
}
// Make number value NaN or Infinity just 0.
if (params.value === 'NaN' || params.value === 'Infinity'){
params.value = 0;
}
// if it is a number, format it. otherwise, dont.
if ($.isNumeric(params.value)) {
// Format based on locale and extra options.
return Intl.NumberFormat(locale, options).format(params.value);
}
else {
// Return without format.
return params.value;
}
}
else {
if (ftName !== '' && $.isNumeric(params.node.id)) {
console.log(
Drupal.t(
'agGrid formatType Error: jserr_ftName or "type" not found in function',
{
jserr_ftName: ftName
}
)
);
}
// Return without format.
return params.value;
}
}
function valueGetterFunc(params) {
let valueGetterItems;
let valueGot;
// Auto value change when needed.
let rscParamsRowId;
let rscParamsColDefField;
if (typeof params.node.rowPinned === 'undefined') {
rscParamsRowId = params.node.id;
}
else {
rscParamsRowId =
params.node.rowPinned.substr(0, 1) + '-' + params.node.rowIndex;
}
rscParamsColDefField = params.colDef.field;
// Check setting for cell, row, column, and then all columns.
// First available is priority.
valueGetterItems = rowSettingsCheck(
rscParamsRowId,
rscParamsColDefField,
'valueGetter'
);
// Exclude if getter is empty and exclude pinned row header and footer.
if (
valueGetterItems !== '' &&
typeof gridOptions[item].rowData[params.node.id] !== 'undefined' &&
typeof gridOptions[item].rowData[params.node.id][params.column.colId] !== 'undefined'
) {
// Return valueGetter.
valueGot = eval(valueGetterItems);
// Update the cell value.
if (gridOptions[item].rowData[params.node.id][params.column.colId] != valueGot) {
gridOptions[item].rowData[params.node.id][params.column.colId] = valueGot;
// If good and needs to be sent, send it.
valueSendFunc(params, valueGot);
makeJson(item); // Make sure the rowData output is updated.
// Return it
return valueGot;
}
}
// else, just return the current value.
return params.data[params.column.colId];
}
function valueParserFunc(params) {
let ptName;
let ftName;
let paramsNodeId = params.node.id;
let paramsColumnColId = params.column.colId;
let parserType_errorJSON = {};
let rscParamsRowId;
let rscParamsColDefField;
let restrictInput;
let newValue = params.newValue.valueOf();
let value = params.oldValue;
if (typeof params.node.rowPinned === 'undefined') {
rscParamsRowId = params.node.id;
}
else {
rscParamsRowId =
params.node.rowPinned.substr(0, 1) + '-' + params.node.rowIndex;
}
rscParamsColDefField = params.colDef.field;
// Check setting for cell, row, column, and then all columns.
// First available is priority.
ptName = rowSettingsCheck(
rscParamsRowId,
rscParamsColDefField,
'parserType'
);
// Check setting for cell, row, column, and then all columns.
// First available is priority.
ftName = rowSettingsCheck(
rscParamsRowId,
rscParamsColDefField,
'formatType'
);
// Get restricted input type.
if (
typeof aggridGSJSON.parserTypes[ptName] !== 'undefined' &&
typeof aggridGSJSON.parserTypes[ptName].restrictInput !== 'undefined'
) {
restrictInput = aggridGSJSON.parserTypes[ptName].restrictInput;
}
// Move forward if ptName is set and regEx/errorMsg is available.
// Otherwise it is an error.
if (
ptName !== '' &&
ptName !== 'dropdown' &&
typeof aggridGSJSON.parserTypes[ptName] !== 'undefined' &&
typeof aggridGSJSON.parserTypes[ptName].regEx !== 'undefined' &&
typeof aggridGSJSON.parserTypes[ptName].errorMsg !== 'undefined'
) {
let regEx = new RegExp(aggridGSJSON.parserTypes[ptName].regEx);
// Clear the current error for this item, if there is one.
validationErrorClear(params, ptName);
// Check the value against the regEx. if it is good, apply.
// Otherwise tell the user and flip back.
if (regEx.test(newValue)) {
// Update the cell value.
gridOptions[item].rowData[params.node.id][params.column.colId] = newValue;
params.newValue = newValue;
gridOptions[item].api.refreshCells();
// Value is potentially correct for the type, now check any
// constraints.
value = valueConstraintFunc(params);
// Check numeric warning threshold if editable numeric field.
prevWarningCheck(params);
// Change percentage to decimal.
if (ftName !== '' && ftName.includes('numPer') && Number(value) !== Number(params.oldValue)) {
// Add a large dec due to javascript precision division issue with decimals.
value = Number(value) + .000000000001
// Round it to drop off by 10 decimals.
value = (value / 100).toFixed(10);
// If paste, get the rowNode and update.
if (aggridPasteStart[item]) {
gridOptions[item].rowData[paramsNodeId][paramsColumnColId] = value;
gridOptions[item].api.refreshCells();
}
}
// If good and needs to be sent, send it.
valueSendFunc(params, value);
return value
}
else {
// New value does not meet the requirements. Process.
if (newValue === '') {
// If delete, just change to zero if number. Otherwise blank.
if (restrictInput === 'numeric') {
return 0;
}
else {
return newValue;
}
}
else {
// Has a newValue, though it is not meeting requirements.
// Process it. Make sure our variable is ready for data.
parserType_errorJSON[paramsNodeId] = {};
parserType_errorJSON[paramsNodeId][paramsColumnColId] = {};
parserType_errorJSON[paramsNodeId][paramsColumnColId][ptName] = {};
// Set the error values. old, new, and the message.
parserType_errorJSON[paramsNodeId][paramsColumnColId][ptName] = {
oldValue: params.oldValue,
newValue: newValue,
message: aggridGSJSON.parserTypes[ptName].errorMsg
};
// Merge without writing over objects.
aggridValidationErrors[item] = smartJSONextend(
parserType_errorJSON,
aggridValidationErrors[item]
);
// Make sure validation error dialog is updated.
validationErrorUpdate();
// Place the value and refresh the cells.
// this fixed an issue with multi copy and paste.
gridOptions[item].rowData[paramsNodeId][paramsColumnColId] = params.oldValue;
gridOptions[item].api.refreshCells();
// Make sure this is marked to show.
aggridShowError[item] = true;
// Show it.
validationErrorShow();
// Return it.
return value;
}
}
}
else if (
ptName === 'dropdown' &&
typeof aggridGSJSON.parserTypes[ptName] !== 'undefined' &&
aggridGSJSON.parserTypes[ptName].errorMsg !== 'undefined'
) {
// Process a dropdown check. if it is not in the values for
// cellEditorParams, then err.
// Clear the current error for this item, if there is one.
validationErrorClear(params, ptName);
if (
typeof params.colDef.cellEditorParams.values !== 'undefined' &&
params.colDef.cellEditorParams.values.indexOf(newValue) !== -1
) {
// Update the cell value.
gridOptions[item].rowData[params.node.id][params.column.colId] = newValue;
// Value is potentially correct for the type, now check any constraints.
value = valueConstraintFunc(params);
// If good and needs to be sent, send it.
valueSendFunc(params, value);
return value;
}
else {
// Has a newValue, though it is not meeting requirements. Process it.
gridOptions[item].rowData[paramsNodeId][paramsColumnColId] = params.oldValue;
gridOptions[item].api.refreshCells();
return value;
}
}
else {
// If the code reaches here, it is an error.
let errorMsg = 'agGrid parserType Error: ';
// ptName is available but there are issues.
if (
ptName !== '' ||
(ptName !== '' &&
typeof aggridGSJSON.parserTypes[ptName] === 'undefined')
) {
// not found in aggridGSJSON at all, tell the user.
console.log(
Drupal.t(
errorMsg + ptName + ' not found.', {}, {
context: 'aggrid error parserType not found'
}
)
);
}
else if (
ptName === '' &&
typeof aggridGSJSON.parserTypes === 'undefined' &&
typeof aggridGSJSON.parserTypes[ptName] === 'undefined' &&
typeof aggridGSJSON.parserTypes[ptName].regEx === 'undefined' &&
typeof aggridGSJSON.parserTypes[ptName].errorMsg === 'undefined'
) {
// found in aggridGSJSON, but missing the necessary objects.
console.log(
Drupal.t(
errorMsg + ptName + ' missing regEx or errorMsg', {}, {
context: 'aggrid error parserType missing regEx or errorMsg'
}
)
);
}
// Update the cell value.
gridOptions[item].rowData[params.node.id][params.column.colId] = newValue;
// Value is correct for type, check constraints.
value = valueConstraintFunc(params);
// If good and needs to be sent, send it.
valueSendFunc(params, value);
return value;
}
}
// Used with valueSend JSON item to send values to another aggrid on the same node.
function valueSendFunc(params, cellValue) {
let valueSendItems;
// Auto value change when needed.
let rscParamsRowId;
let rscParamsColDefField;
if (typeof params.node.rowPinned === 'undefined') {
rscParamsRowId = params.node.id;
}
else {
rscParamsRowId = params.node.rowPinned.substr(0, 1) + '-' + params.node.rowIndex;
}
rscParamsColDefField = params.colDef.field;
// Check setting for cell, row, column, and then all columns.
// First available is priority.
valueSendItems = rowSettingsCheck(
rscParamsRowId,
rscParamsColDefField,
'valueSend'
);
// Exclude if getter is empty and exclude pinned row header and footer.
if (
valueSendItems !== '' &&
typeof gridOptions[item].rowData[params.node.id] !== 'undefined' &&
typeof gridOptions[item].rowData[params.node.id][params.column.colId] !== 'undefined'
) {
$.each(valueSendItems, function(key, value){
// Look up the other grid and assign the variables.
let t = $('div[data-aggrid-id="' + value['aggrid_id'] + '"]').attr('id');
let i = (value['id'] == 'params.node.id') ? params.node.id : value['id'];
let f = (value['field'] == '[this]') ? params.column.colId : value['field'];
let g = gridOptions[t];
// Check if gridOption exists.F
if (typeof g !== 'undefined') {
let rowNode = g.api.getRowNode(i);
// Check if rowNode exists.
if (typeof rowNode !== 'undefined') {
if (f !== '') {
// Found... change the values and refresh.
rowNode.setDataValue(f, cellValue);
return true;
} else {
console.log(
Drupal.t(
'valueSend function on [' + params.node.id + '][' + params.column.colId + '] missing field name.', {}, {
context: 'aggrid error on valueSend'
}
)
);
}
} else {
console.log(
Drupal.t(
'valueSend function on [' + params.node.id + '][' + params.column.colId + '] row not found.', {}, {
context: 'aggrid error on valueSend'
}
)
);
}
} else {
console.log(
Drupal.t(
'valueSend function on [' + params.node.id + '][' + params.column.colId + '] missing row number.', {}, {
context: 'aggrid error on valueSend'
}
)
);
}
});
}
// Issue
return false;
}
// #######
// ####### Context Menu Items
// #######
function getContextMenuItems(params) {
let result = [
// built in copy item.
'copy',
'copyWithHeaders',
{
// custom item.
name: 'Excel Export (xls)',
action: function() {
onBtExport(params, 'xls');
},
icon: '<i class="ag-icon ag-icon-data" />'
},
{
// custom item.
name: 'CSV Export',
action: function() {
onBtExport(params, 'csv');
},
icon: '<i class="ag-icon ag-icon-data" />'
}
];
// Check if cell error. If error, give show box option.
if (validationErrorCheck(params.node.id, params.column.colId)) {
result.push({
// Show validation error box.
name: 'Show Error',
action: validationErrorShow,
icon: '<i class="ag-icon ag-icon-eye" />'
});
}
// Check if cell previous warning. If previous warning, give show box option.
if (validationPrevWarningCheck(params.node.id, params.column.colId)) {
result.push({
// Show validation previous warning box.
name: 'Show Previous Data Warning',
action: () => {validationPrevWarningShow(params);},
icon: '<i class="ag-icon ag-icon-eye" />'
});
}
return result;
}
function onBtExport(params, type) {
// Export Excel.
params.columnGroups = true;
if (type === 'xls') {
gridOptions[item].api.exportDataAsExcel(params);
}
else {
gridOptions[item].api.exportDataAsCsv(params);
}
}
// #######
// ####### Helper Functions
// #######
// Run for every cell.
/*
params = The ag-Grid params for loops.
passCellParams = (true/false) -- Optionally uses cellParams as the first parameter on cellFn.
cellFn = The function to run.
...cellParams = All paramters to run for the function.
*/
function runForEveryCell(params, passCellParams, cellFn, ...cellFnParams) {
let gridApi = params.api;
let columnApi = params.columnApi;
gridApi.forEachNode((rowNode, rowIndex) => {
let rowData = rowNode.data;
columnApi.getColumns().forEach((column) => {
let colId = column.getColId(); // Field name
let colDef = column.getColDef();
let value = rowData[colId];
let cellParams = {
data: rowData,
value: value,
newValue: value,
oldValue: undefined,
node: rowNode,
colDef: colDef,
column: column,
api: gridApi,
columnApi: columnApi,
context: gridApi.context,
};
// Only spread cellFnParams if not null.
if (passCellParams && cellFnParams && cellFnParams.length > 0) {
cellFn(cellParams, ...cellFnParams);
}
else if (passCellParams) { // passCellParams true but cellFnParams null.
cellFn(cellParams);
}
else if (cellFnParams && cellFnParams.length > 0) { // false passCellParams, but cellFnParams has value.
cellFn(...cellFnParams);
}
else { // finally, run without any arguments.
cellFn();
}
});
});
}
// Cleanup Paste.
function processCellFromClipboardFunc(params) {
// Set variables.
let ptName;
let rscParamsRowId;
let rscParamsColDefField;
let restrictInput;
// Set the value.
let dataValue = params.value;
if (typeof params.node.rowPinned === 'undefined') {
rscParamsRowId = params.node.id;
}
else {
rscParamsRowId = params.node.rowPinned.substr(0, 1) + '-' + params.node.rowIndex;
}
// Set the field.
rscParamsColDefField = params.column.colDef.field;
// Check setting for cell, row, column, and then all columns.
// First available is priority.
ptName = rowSettingsCheck(
rscParamsRowId,
rscParamsColDefField,
'parserType'
);
// Get restricted input type.
if (
typeof aggridGSJSON.parserTypes[ptName] !== 'undefined' &&
typeof aggridGSJSON.parserTypes[ptName].restrictInput !== 'undefined') {
restrictInput = aggridGSJSON.parserTypes[ptName].restrictInput;
}
// Trim the edges just to make sure.
dataValue = dataValue.trim();
// If number, do clean-up.
if (restrictInput === 'numeric' && dataValue !== '') {
// ==== Numbers.
// Remove dollar signs, percent, and commas.
dataValue = dataValue.replace(/[,$%]/g, '');
}
// If blank, make zero.
if (restrictInput === 'numeric' && (dataValue === '' || dataValue === null)) {
dataValue = 0;
}
// Update the params value.
return dataValue;
}
// Cleanup Copy.
function processCellForClipboardFunc(params) {
// Set variables.
let ptName;
let ftName;
let rscParamsRowId;
let rscParamsColDefField;
let restrictInput;
// Set the value.
let dataValue = params.value;
if (typeof params.node.rowPinned === 'undefined') {
rscParamsRowId = params.node.id;
}
else {
rscParamsRowId = params.node.rowPinned.substr(0, 1) + '-' + params.node.rowIndex;
}
// Set the field.
rscParamsColDefField = params.column.colDef.field;
// Check setting for cell, row, column, and then all columns.
// First available is priority.
ptName = rowSettingsCheck(
rscParamsRowId,
rscParamsColDefField,
'parserType'
);
ftName = rowSettingsCheck(
rscParamsRowId,
rscParamsColDefField,
'formatType'
);
// Get restricted input type
if (typeof aggridGSJSON.parserTypes[ptName] !== 'undefined' && typeof aggridGSJSON.parserTypes[ptName].restrictInput !== 'undefined') {
restrictInput = aggridGSJSON.parserTypes[ptName].restrictInput;
}
// If percent, then turn the decimal into a whole percent.
if (restrictInput === 'numeric' && ftName.includes('numPer')) {
dataValue = dataValue * 100;
}
// Update the params value.
return dataValue;
}
// For adding/removing a focus class.
function colFocusClass(params) {
if (params.column !== null) {
let colId = params.column.colId;
// Remove any current focus class.
$("div.aggrid-col-focus").removeClass("aggrid-col-focus");
// Add to current.
$("div[col-id='" + colId + "']").addClass("aggrid-col-focus");
}
}
function columnTotal(field, idFrom, idTo) {
// Used to help sum a spanning column total.
let rowCount;
let colCount;
let valColumnTotal = 0;
// Check if field is an array... if not, make it one.
if (!Array.isArray(field)) {
field = field.split(',');
}
// Check idFrom and idTo to make sure they are defined and correctly
// span vs an incorrect crossover.
if (
typeof idFrom !== 'undefined' &&
typeof idTo !== 'undefined' &&
idFrom >= 0 &&
idTo >= 0 &&
idFrom <= idTo
) {
// Loop through the span and sum the amounts.
for (rowCount = idFrom; rowCount <= idTo; rowCount++) {
for (colCount = 0; colCount <= field.length; colCount++) {
if ($.isNumeric(gridOptions[item].rowData[rowCount][field[colCount]])) {
valColumnTotal += Number(gridOptions[item].rowData[rowCount][field[colCount]]);
}
}
}
// return the sum.
return valColumnTotal;
}
else {
// Issue with the idFrom and idTo, tell the user and return zero.
console.log(
Drupal.t(
'agGrid columnTotal Error: jserr_field - Check idFrom & idTo for issues.',
{
jserr_field: field
},
{
context: 'aggrid error columnTotal idFrom & idTo not correct'
}
)
);
return 0;
}
}
// #######
// ####### Build ag-Grid
// #######
// Build JSON for ag-Grid.
var aggridJSON = {
columnDefs: aggridJSON_colDefs,
rowData: aggridJSON_rowData
};
// Merge Options Default + Grid options.
aggridJSON_addOpt = smartJSONextend(aggridOpt, aggridJSON_addOpt);
// Merge the grid.
aggridJSON = smartJSONextend(aggridJSON_addOpt, aggridJSON);
// Default Options for all ag-Grid.
var default_gridOptions = {
onGridReady: function(params) {
runForEveryCell(params, true, prevWarningCheck);
makeJson(item);
},
onCellFocused: function (params) {
colFocusClass(params);
},
onCellEditingStarted: function (params) {
restrictInputFunc(params);
valueConversion(params);
},
onCellEditingStopped: function (params) {
makeJson(item);
},
onCellValueChanged: function (params) {
if (aggridPasteStart[item]) {
valueParserFunc(params);
}
makeJson(item);
},
onPasteStart: function () {
aggridPasteStart[item] = true;
},
onPasteEnd: function (params) {
aggridShowError[item] = false;
aggridPasteStart[item] = false;
},
processCellFromClipboard: function(params) {
return processCellFromClipboardFunc(params);
},
processCellForClipboard: function(params) {
return processCellForClipboardFunc(params);
},
getContextMenuItems: getContextMenuItems,
excelStyles: aggridExcelStyles
};
let default_gridOptions_rowSettingsOptions = {};
default_gridOptions_rowSettingsOptions['defaultColDef'] = {};
// If rowSettings are available, add other functions.
if (aggridJSON_rowSettings !== null) {
// rowSettings is there, so get the setting.
default_gridOptions_rowSettingsOptions['defaultColDef'] = {
cellClass: cellClassFunc,
cellStyle: cellStyleFunc,
colSpan: colSpanFunc,
rowSpan: rowSpanFunc,
valueFormatter: valueFormatterFunc
};
// Only add editable, valueGetter, and valueParser on Edit = true.
if (aggridDataEdit[item]) {
let default_gridOptions_rowSettingsOptions_edit = {
cellClassRules: {
'aggrid-cell-error': function(params) {return validationErrorCheck(params.node.id, params.colDef.field);},
'aggrid-cell-warning': function(params) {return validationPrevWarningCheck(params.node.id, params.colDef.field);}
},
editable: editableFunc,
valueGetter: valueGetterFunc,
valueParser: valueParserFunc
};
default_gridOptions_rowSettingsOptions['defaultColDef'] =
$.extend(true,
default_gridOptions_rowSettingsOptions['defaultColDef'],
default_gridOptions_rowSettingsOptions_edit
);
}
}
else if (aggridDataEdit[item]) {
// No rowSettings and edit = true, so add some defaults.
default_gridOptions_rowSettingsOptions['defaultColDef'] = {
editable: true
};
}
// Merge grid options together.
gridOptions[item] = $.extend(
true,
default_gridOptions,
default_gridOptions_rowSettingsOptions
);
// Add the Default Options.
gridOptions[item] = $.extend(true, gridOptions[item], aggridJSON);
// Apply the license if it is available.
if (aggridLicense !== '' && agGrid.LicenseManager) {
agGrid.LicenseManager.setLicenseKey(aggridLicense);
}
// Get the ag-Grid Div and start it up.
eGridDiv[item] = document.querySelector('#' + item);
// create the grid passing in the div to use together with the columns
// & data we want to use
new agGrid.Grid(eGridDiv[item], gridOptions[item]);
// Make sure the grid columns fit.
gridOptions[item].api.sizeColumnsToFit();
// Auto resize when window shifts in size.
window.addEventListener('resize', function() {
setTimeout(function() {
gridOptions[item].api.sizeColumnsToFit();
})
});
// Apply all columns to this variable.
aggridFields = gridOptions[item].columnApi.getAllGridColumns();
// Loop through columns and get the FULL name for each field.
// Just run once for ag-Grid.
$.each(aggridFields, function (rowIndex) {
aggridFieldFullHeaderName[aggridFields[rowIndex].colId] = [];
tempList = [];
getHeaderParentItems(aggridFields[rowIndex]);
// Take collected headers, reverse them, separate by dashes.
// clear out blanks on up to a header with 3 rows.
aggridFieldFullHeaderName[aggridFields[rowIndex].colId] =
tempList
.reverse()
.filter(function (e) {
return e;
})
.join(' - ');
});
getRowLabels();
});
}
};
Drupal.behaviors.aggridHtmlIntegration = {
attach: function (context) {
// Make sure to only run once per page for each item.
var selector = $('.aggrid-html-widget');
var idArray = [];
selector.each(function () {
idArray.push(this.id);
});
$.each(idArray, function (index, item) {
// Set the aggrid Table variable.
let aggridTable = $('#' + item);
// Only run this once.
if (once('aggridTable', '#' + item +'').length !== aggridTable.length) {
return;
}
// Set variables for formatNumber.
let locale = 'en'; // Default to English (USA)
let options = {};
aggridTable.each(function () {
// Loop through headers and set width/min-width if available.
$('th', this).each(function () {
$(this).css('width', $(this).attr('data-width'));
$(this).css('min-width', $(this).attr('data-minWidth'));
});
// Loop through rows for formatting classes.
$('td', this).each(function () {
let td_value = $(this).text();
let td_class = "";
if ($(this).attr('class')) {
td_class = $(this).attr('class').split(' ');
}
if (td_value !== '' && td_value !== '+') {
for (let i in td_class) {
if (td_class[i].substring(0, 17) === 'aggrid-html-ftype') {
let ftName = td_class[i].substring(18);
let ftItem = aggridGSJSON.formatTypes[ftName];
// Optional settings for NumberFormat for locale and options.
if (typeof ftItem.locale !== 'undefined') {
locale = ftItem.locale;
}
if (typeof ftItem.options !== 'undefined') {
options = ftItem.options;
}
let formatter = new Intl.NumberFormat(locale, options);
$(this).text(formatter.format(td_value));
}
}
}
});
});
});
}
};
// All key events
$('.aggrid-widget').bind('keypress keydown keyup', function(e){
// No submit on aggrid with enter (allow enter cell for edit).
if (e.keyCode === 13) { e.preventDefault(); }
});
me.gridOptions = gridOptions;
return me;
})(aggrid || {}, jQuery, Drupal, drupalSettings, once);
