@trudb/tru-common-lib 0.2.542 → 0.2.544
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
|
@@ -2757,13 +2757,24 @@ class TruSearchViewBase {
|
|
|
2757
2757
|
}
|
|
2758
2758
|
onPkeyCellDoubleClicked = (gridConfig) => {
|
|
2759
2759
|
if (this.hasDetailView) {
|
|
2760
|
+
let clickedEntity = gridConfig.data?.$entity;
|
|
2761
|
+
if (!clickedEntity) {
|
|
2762
|
+
return;
|
|
2763
|
+
}
|
|
2760
2764
|
let entities = [];
|
|
2761
|
-
gridConfig.api.
|
|
2762
|
-
|
|
2763
|
-
|
|
2765
|
+
for (let i = 0; i < gridConfig.api.getDisplayedRowCount(); i++) {
|
|
2766
|
+
let rowNode = gridConfig.api.getDisplayedRowAtIndex(i);
|
|
2767
|
+
if (rowNode?.data?.$entity) {
|
|
2768
|
+
entities.push(rowNode.data.$entity);
|
|
2769
|
+
}
|
|
2770
|
+
}
|
|
2771
|
+
let entityIndex = entities.indexOf(clickedEntity);
|
|
2772
|
+
if (entityIndex < 0) {
|
|
2773
|
+
return;
|
|
2774
|
+
}
|
|
2764
2775
|
let windowAddViewEventArgs = new TruDesktopViewConfig();
|
|
2765
2776
|
windowAddViewEventArgs.entities = entities;
|
|
2766
|
-
windowAddViewEventArgs.entityIndex =
|
|
2777
|
+
windowAddViewEventArgs.entityIndex = entityIndex;
|
|
2767
2778
|
windowAddViewEventArgs.componentName = this.tableName + 'DetailView';
|
|
2768
2779
|
this.windowEventHandler.addView(windowAddViewEventArgs);
|
|
2769
2780
|
this.view.active = false;
|
|
@@ -5141,13 +5152,24 @@ class TruSearchResultViewBase {
|
|
|
5141
5152
|
}
|
|
5142
5153
|
onPkeyCellDoubleClicked = (gridConfig) => {
|
|
5143
5154
|
if (this.hasDetailView) {
|
|
5155
|
+
let clickedEntity = gridConfig.data?.$entity;
|
|
5156
|
+
if (!clickedEntity) {
|
|
5157
|
+
return;
|
|
5158
|
+
}
|
|
5144
5159
|
let entities = [];
|
|
5145
|
-
gridConfig.api.
|
|
5146
|
-
|
|
5147
|
-
|
|
5160
|
+
for (let i = 0; i < gridConfig.api.getDisplayedRowCount(); i++) {
|
|
5161
|
+
let rowNode = gridConfig.api.getDisplayedRowAtIndex(i);
|
|
5162
|
+
if (rowNode?.data?.$entity) {
|
|
5163
|
+
entities.push(rowNode.data.$entity);
|
|
5164
|
+
}
|
|
5165
|
+
}
|
|
5166
|
+
let entityIndex = entities.indexOf(clickedEntity);
|
|
5167
|
+
if (entityIndex < 0) {
|
|
5168
|
+
return;
|
|
5169
|
+
}
|
|
5148
5170
|
let windowAddViewEventArgs = new TruDesktopViewConfig();
|
|
5149
5171
|
windowAddViewEventArgs.entities = entities;
|
|
5150
|
-
windowAddViewEventArgs.entityIndex =
|
|
5172
|
+
windowAddViewEventArgs.entityIndex = entityIndex;
|
|
5151
5173
|
windowAddViewEventArgs.componentName = this.tableName + 'DetailView';
|
|
5152
5174
|
this.truWindowEventHandler.addView(windowAddViewEventArgs);
|
|
5153
5175
|
}
|
|
@@ -6855,9 +6877,7 @@ class TruDataGridCellRenderer {
|
|
|
6855
6877
|
};
|
|
6856
6878
|
init(params) {
|
|
6857
6879
|
params.eGridCell.innerHTML = '';
|
|
6858
|
-
|
|
6859
|
-
if (params.value === null)
|
|
6860
|
-
value = '';
|
|
6880
|
+
const value = params.value ?? '';
|
|
6861
6881
|
if (params.colDef.cellEditor && params.colDef.cellEditor.name === "StdRichTextList") {
|
|
6862
6882
|
var p = document.createElement('div');
|
|
6863
6883
|
p.innerHTML = value;
|
|
@@ -7253,7 +7273,9 @@ class TruDataGridClipboard {
|
|
|
7253
7273
|
copiedCellValue = null;
|
|
7254
7274
|
copiedCellEntity = null;
|
|
7255
7275
|
copiedCellParams = null;
|
|
7276
|
+
copiedCellText = null;
|
|
7256
7277
|
copiedRows = [];
|
|
7278
|
+
copiedRowsText = null;
|
|
7257
7279
|
gridElement = null;
|
|
7258
7280
|
constructor(util, formatter, uiNotification, modelPropertyLookup) {
|
|
7259
7281
|
this.util = util;
|
|
@@ -7269,6 +7291,46 @@ class TruDataGridClipboard {
|
|
|
7269
7291
|
else
|
|
7270
7292
|
return this.formatter.excelFormula(propertyConfig.formatter(controlConfig));
|
|
7271
7293
|
};
|
|
7294
|
+
normalizeClipboardText = (value) => String(value ?? '').replace(/\r\n/g, '\n').replace(/\r/g, '\n').replace(/\n$/, '');
|
|
7295
|
+
readClipboardText = async () => {
|
|
7296
|
+
if (!navigator.clipboard?.readText)
|
|
7297
|
+
throw new Error('The browser does not support reading from the clipboard.');
|
|
7298
|
+
return navigator.clipboard.readText();
|
|
7299
|
+
};
|
|
7300
|
+
parseExternalCellValue = (clipboardText, controlConfig) => {
|
|
7301
|
+
const value = this.normalizeClipboardText(clipboardText);
|
|
7302
|
+
const currentValue = controlConfig.$;
|
|
7303
|
+
const property = controlConfig.property;
|
|
7304
|
+
const typeName = property?.typeName;
|
|
7305
|
+
if (!value && property?.isNullable)
|
|
7306
|
+
return null;
|
|
7307
|
+
const isDate = currentValue instanceof Date || typeName === 'date' || typeName === 'date-time';
|
|
7308
|
+
if (isDate) {
|
|
7309
|
+
const isoDate = /^(\d{4})-(\d{1,2})-(\d{1,2})$/.exec(value);
|
|
7310
|
+
const parsedValue = isoDate
|
|
7311
|
+
? new Date(Number(isoDate[1]), Number(isoDate[2]) - 1, Number(isoDate[3]))
|
|
7312
|
+
: new Date(value);
|
|
7313
|
+
if (isNaN(parsedValue.getTime()))
|
|
7314
|
+
throw new Error('Clipboard data is not a valid date.');
|
|
7315
|
+
return parsedValue;
|
|
7316
|
+
}
|
|
7317
|
+
const numericTypes = ['primary-key', 'integer', 'big-integer', 'decimal', 'usa-dollars', 'percentage', 'scientific', 'foreign-key', 'user-foreign-key'];
|
|
7318
|
+
if (typeof currentValue === 'number' || numericTypes.includes(typeName)) {
|
|
7319
|
+
const numericText = value.replace(/[$,%\s]/g, '');
|
|
7320
|
+
const parsedValue = Number(numericText);
|
|
7321
|
+
if (!numericText || !Number.isFinite(parsedValue))
|
|
7322
|
+
throw new Error('Clipboard data is not a valid number.');
|
|
7323
|
+
return typeName === 'percentage' && value.includes('%') ? parsedValue / 100 : parsedValue;
|
|
7324
|
+
}
|
|
7325
|
+
if (typeof currentValue === 'boolean') {
|
|
7326
|
+
if (/^(true|yes|1)$/i.test(value))
|
|
7327
|
+
return true;
|
|
7328
|
+
if (/^(false|no|0)$/i.test(value))
|
|
7329
|
+
return false;
|
|
7330
|
+
throw new Error('Clipboard data is not a valid yes/no value.');
|
|
7331
|
+
}
|
|
7332
|
+
return value;
|
|
7333
|
+
};
|
|
7272
7334
|
removeBorderAnimation = () => {
|
|
7273
7335
|
var elementsWithAnimatedBorders = this.gridElement?.querySelectorAll('.animated-border');
|
|
7274
7336
|
if (elementsWithAnimatedBorders && elementsWithAnimatedBorders.length)
|
|
@@ -7308,6 +7370,7 @@ class TruDataGridClipboard {
|
|
|
7308
7370
|
this.copiedCellData = copiedCellData;
|
|
7309
7371
|
this.copiedCellValue = copiedCellData[columnName].$;
|
|
7310
7372
|
this.copiedCellEntity = copiedCellEntity;
|
|
7373
|
+
this.copiedCellText = this.normalizeClipboardText(params.value);
|
|
7311
7374
|
this.removeBorderAnimation();
|
|
7312
7375
|
this.addCellBorderAnimation();
|
|
7313
7376
|
try {
|
|
@@ -7317,28 +7380,49 @@ class TruDataGridClipboard {
|
|
|
7317
7380
|
console.error('Failed to copy text: ', err);
|
|
7318
7381
|
}
|
|
7319
7382
|
};
|
|
7320
|
-
pasteCell = (params, pastedCellData, pastedCell) => {
|
|
7383
|
+
pasteCell = async (params, pastedCellData, pastedCell) => {
|
|
7321
7384
|
let colDef = params.colDef;
|
|
7322
7385
|
let columnName = colDef.field;
|
|
7323
|
-
let copiedCellDataTypeName = this.copiedCellData[this.copiedCellParams?.colDef?.field].property.typeName;
|
|
7324
|
-
let pastedCellDataTypeName = pastedCellData[params.colDef?.field].property.typeName;
|
|
7325
7386
|
if (!colDef.editable) {
|
|
7326
7387
|
this.uiNotification.error('Cannot paste into a non-editable column: ' + colDef.field);
|
|
7327
7388
|
return;
|
|
7328
7389
|
}
|
|
7329
|
-
|
|
7330
|
-
|
|
7390
|
+
let clipboardText;
|
|
7391
|
+
try {
|
|
7392
|
+
clipboardText = this.normalizeClipboardText(await this.readClipboardText());
|
|
7393
|
+
}
|
|
7394
|
+
catch (err) {
|
|
7395
|
+
this.uiNotification.error('Unable to read data from the system clipboard.');
|
|
7331
7396
|
return;
|
|
7332
7397
|
}
|
|
7398
|
+
const pastedCellConfig = pastedCellData[columnName];
|
|
7399
|
+
const isInternalCopy = this.copiedCellText !== null && clipboardText === this.copiedCellText;
|
|
7400
|
+
if (isInternalCopy && this.copiedCellData && this.copiedCellParams) {
|
|
7401
|
+
const copiedColumnName = this.copiedCellParams.colDef?.field;
|
|
7402
|
+
const copiedCellDataTypeName = this.copiedCellData[copiedColumnName].property.typeName;
|
|
7403
|
+
const pastedCellDataTypeName = pastedCellConfig.property.typeName;
|
|
7404
|
+
if (copiedCellDataTypeName !== pastedCellDataTypeName) {
|
|
7405
|
+
this.uiNotification.error('Clipboard data type does not match the current cell data type: ' + copiedCellDataTypeName + ' vs ' + pastedCellDataTypeName);
|
|
7406
|
+
return;
|
|
7407
|
+
}
|
|
7408
|
+
pastedCellConfig.$ = this.copiedCellValue;
|
|
7409
|
+
}
|
|
7333
7410
|
else {
|
|
7334
|
-
|
|
7335
|
-
|
|
7336
|
-
|
|
7411
|
+
try {
|
|
7412
|
+
pastedCellConfig.$ = this.parseExternalCellValue(clipboardText, pastedCellConfig);
|
|
7413
|
+
}
|
|
7414
|
+
catch (err) {
|
|
7415
|
+
this.uiNotification.error(err.message);
|
|
7416
|
+
return;
|
|
7417
|
+
}
|
|
7337
7418
|
}
|
|
7419
|
+
this.removeBorderAnimation();
|
|
7420
|
+
params.api.refreshCells({ force: true });
|
|
7338
7421
|
};
|
|
7339
7422
|
copyRow = async (tableName, columnDefs, copiedRows, includeHeaders = false) => {
|
|
7340
7423
|
this.tableName = tableName;
|
|
7341
7424
|
this.copiedRows = copiedRows;
|
|
7425
|
+
this.copiedRowsText = null;
|
|
7342
7426
|
this.removeBorderAnimation();
|
|
7343
7427
|
this.addRowBorderAnimation();
|
|
7344
7428
|
if (copiedRows.length) {
|
|
@@ -7364,6 +7448,7 @@ class TruDataGridClipboard {
|
|
|
7364
7448
|
});
|
|
7365
7449
|
multiRowString += rowPropertyValues.join('\t') + '\n';
|
|
7366
7450
|
});
|
|
7451
|
+
this.copiedRowsText = this.normalizeClipboardText(multiRowString);
|
|
7367
7452
|
try {
|
|
7368
7453
|
await navigator.clipboard.writeText(multiRowString);
|
|
7369
7454
|
}
|
|
@@ -7372,7 +7457,19 @@ class TruDataGridClipboard {
|
|
|
7372
7457
|
}
|
|
7373
7458
|
}
|
|
7374
7459
|
};
|
|
7375
|
-
pasteRow = (gridApi, config, selectedRows) => {
|
|
7460
|
+
pasteRow = async (gridApi, config, selectedRows) => {
|
|
7461
|
+
let clipboardText;
|
|
7462
|
+
try {
|
|
7463
|
+
clipboardText = this.normalizeClipboardText(await this.readClipboardText());
|
|
7464
|
+
}
|
|
7465
|
+
catch (err) {
|
|
7466
|
+
this.uiNotification.error('Unable to read data from the system clipboard.');
|
|
7467
|
+
return;
|
|
7468
|
+
}
|
|
7469
|
+
if (this.copiedRowsText === null || clipboardText !== this.copiedRowsText) {
|
|
7470
|
+
this.uiNotification.error('External row data cannot be pasted as an internal grid row copy. Paste into an individual cell instead.');
|
|
7471
|
+
return;
|
|
7472
|
+
}
|
|
7376
7473
|
if (this.tableName !== config.tableName) {
|
|
7377
7474
|
this.uiNotification.error('Clipboard data does not match the current table name: ' + this.tableName + ' vs ' + config.tableName);
|
|
7378
7475
|
return;
|
|
@@ -9127,27 +9224,36 @@ class TruDataGrid {
|
|
|
9127
9224
|
this.dataGridClipboard.copyRow(this.config.tableName, columnDefs, selectedRows);
|
|
9128
9225
|
}
|
|
9129
9226
|
else if (params.column.isPinned() && event.ctrlKey && event.code === 'KeyV') {
|
|
9130
|
-
|
|
9227
|
+
event.preventDefault();
|
|
9228
|
+
void this.dataGridClipboard.pasteRow(this.api, this.config, this.api.getSelectedRows());
|
|
9131
9229
|
}
|
|
9132
9230
|
else if (!params.column.isPinned() && event.ctrlKey && event.code === 'KeyC') {
|
|
9133
9231
|
this.dataGridClipboard.copyCell(params, this.config.tableName, params.colDef?.field, params.data, params.data.$entity);
|
|
9134
9232
|
}
|
|
9135
9233
|
else if (!params.column.isPinned() && event.ctrlKey && event.code === 'KeyV') {
|
|
9136
|
-
|
|
9234
|
+
event.preventDefault();
|
|
9235
|
+
void this.dataGridClipboard.pasteCell(params, params.data, params.data.$entity);
|
|
9137
9236
|
}
|
|
9138
9237
|
};
|
|
9139
9238
|
onCellMouseOver(e) {
|
|
9140
|
-
let targetElement = e
|
|
9141
|
-
|
|
9142
|
-
|
|
9239
|
+
let targetElement = e?.event?.target;
|
|
9240
|
+
const fieldName = e?.colDef?.field;
|
|
9241
|
+
const rowData = e?.data;
|
|
9242
|
+
const propertyConfig = fieldName ? rowData?.[fieldName] : undefined;
|
|
9143
9243
|
let propertyPathParts = [];
|
|
9144
|
-
if (propertyConfig?.propertyPath.includes('.')) {
|
|
9244
|
+
if (typeof propertyConfig?.propertyPath === 'string' && propertyConfig.propertyPath.includes('.')) {
|
|
9145
9245
|
propertyPathParts = this.getPropertyPathParts(propertyConfig.propertyPath);
|
|
9146
9246
|
}
|
|
9147
|
-
let entityToValidate =
|
|
9148
|
-
|
|
9247
|
+
let entityToValidate = rowData?.$entity ?? null;
|
|
9248
|
+
for (const propertyPathPart of propertyPathParts) {
|
|
9249
|
+
entityToValidate = entityToValidate?.[propertyPathPart] ?? null;
|
|
9250
|
+
if (entityToValidate === null)
|
|
9251
|
+
break;
|
|
9252
|
+
}
|
|
9253
|
+
if (targetElement?.classList &&
|
|
9254
|
+
propertyConfig?.propertyName &&
|
|
9149
9255
|
!targetElement.classList.contains('ag-cell-popup-editing') &&
|
|
9150
|
-
entityToValidate
|
|
9256
|
+
entityToValidate?.entityAspect?.hasValidationErrors === true) {
|
|
9151
9257
|
if (!targetElement.classList.contains('ag-cell'))
|
|
9152
9258
|
targetElement = targetElement.closest('.ag-cell');
|
|
9153
9259
|
if (targetElement && targetElement.classList.contains('invalid')) {
|