@trudb/tru-common-lib 0.2.540 → 0.2.543
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
|
}
|
|
@@ -6293,7 +6315,8 @@ class TruCardColumn {
|
|
|
6293
6315
|
}
|
|
6294
6316
|
if (this.inactiveVisible)
|
|
6295
6317
|
columns = columns.concat(inactiveWithParent);
|
|
6296
|
-
columns = columns.
|
|
6318
|
+
columns = columns.filter(column => !emptyParents.some(emptyParent => column.Ref === emptyParent.Ref));
|
|
6319
|
+
columns = columns.concat(emptyParents);
|
|
6297
6320
|
if (this.unassignedVisible && !this.unassignedLocked)
|
|
6298
6321
|
columns = columns.concat(activeWithoutParent);
|
|
6299
6322
|
if (this.unassignedVisible && this.unassignedLocked)
|
|
@@ -7252,7 +7275,9 @@ class TruDataGridClipboard {
|
|
|
7252
7275
|
copiedCellValue = null;
|
|
7253
7276
|
copiedCellEntity = null;
|
|
7254
7277
|
copiedCellParams = null;
|
|
7278
|
+
copiedCellText = null;
|
|
7255
7279
|
copiedRows = [];
|
|
7280
|
+
copiedRowsText = null;
|
|
7256
7281
|
gridElement = null;
|
|
7257
7282
|
constructor(util, formatter, uiNotification, modelPropertyLookup) {
|
|
7258
7283
|
this.util = util;
|
|
@@ -7268,6 +7293,46 @@ class TruDataGridClipboard {
|
|
|
7268
7293
|
else
|
|
7269
7294
|
return this.formatter.excelFormula(propertyConfig.formatter(controlConfig));
|
|
7270
7295
|
};
|
|
7296
|
+
normalizeClipboardText = (value) => String(value ?? '').replace(/\r\n/g, '\n').replace(/\r/g, '\n').replace(/\n$/, '');
|
|
7297
|
+
readClipboardText = async () => {
|
|
7298
|
+
if (!navigator.clipboard?.readText)
|
|
7299
|
+
throw new Error('The browser does not support reading from the clipboard.');
|
|
7300
|
+
return navigator.clipboard.readText();
|
|
7301
|
+
};
|
|
7302
|
+
parseExternalCellValue = (clipboardText, controlConfig) => {
|
|
7303
|
+
const value = this.normalizeClipboardText(clipboardText);
|
|
7304
|
+
const currentValue = controlConfig.$;
|
|
7305
|
+
const property = controlConfig.property;
|
|
7306
|
+
const typeName = property?.typeName;
|
|
7307
|
+
if (!value && property?.isNullable)
|
|
7308
|
+
return null;
|
|
7309
|
+
const isDate = currentValue instanceof Date || typeName === 'date' || typeName === 'date-time';
|
|
7310
|
+
if (isDate) {
|
|
7311
|
+
const isoDate = /^(\d{4})-(\d{1,2})-(\d{1,2})$/.exec(value);
|
|
7312
|
+
const parsedValue = isoDate
|
|
7313
|
+
? new Date(Number(isoDate[1]), Number(isoDate[2]) - 1, Number(isoDate[3]))
|
|
7314
|
+
: new Date(value);
|
|
7315
|
+
if (isNaN(parsedValue.getTime()))
|
|
7316
|
+
throw new Error('Clipboard data is not a valid date.');
|
|
7317
|
+
return parsedValue;
|
|
7318
|
+
}
|
|
7319
|
+
const numericTypes = ['primary-key', 'integer', 'big-integer', 'decimal', 'usa-dollars', 'percentage', 'scientific', 'foreign-key', 'user-foreign-key'];
|
|
7320
|
+
if (typeof currentValue === 'number' || numericTypes.includes(typeName)) {
|
|
7321
|
+
const numericText = value.replace(/[$,%\s]/g, '');
|
|
7322
|
+
const parsedValue = Number(numericText);
|
|
7323
|
+
if (!numericText || !Number.isFinite(parsedValue))
|
|
7324
|
+
throw new Error('Clipboard data is not a valid number.');
|
|
7325
|
+
return typeName === 'percentage' && value.includes('%') ? parsedValue / 100 : parsedValue;
|
|
7326
|
+
}
|
|
7327
|
+
if (typeof currentValue === 'boolean') {
|
|
7328
|
+
if (/^(true|yes|1)$/i.test(value))
|
|
7329
|
+
return true;
|
|
7330
|
+
if (/^(false|no|0)$/i.test(value))
|
|
7331
|
+
return false;
|
|
7332
|
+
throw new Error('Clipboard data is not a valid yes/no value.');
|
|
7333
|
+
}
|
|
7334
|
+
return value;
|
|
7335
|
+
};
|
|
7271
7336
|
removeBorderAnimation = () => {
|
|
7272
7337
|
var elementsWithAnimatedBorders = this.gridElement?.querySelectorAll('.animated-border');
|
|
7273
7338
|
if (elementsWithAnimatedBorders && elementsWithAnimatedBorders.length)
|
|
@@ -7307,6 +7372,7 @@ class TruDataGridClipboard {
|
|
|
7307
7372
|
this.copiedCellData = copiedCellData;
|
|
7308
7373
|
this.copiedCellValue = copiedCellData[columnName].$;
|
|
7309
7374
|
this.copiedCellEntity = copiedCellEntity;
|
|
7375
|
+
this.copiedCellText = this.normalizeClipboardText(params.value);
|
|
7310
7376
|
this.removeBorderAnimation();
|
|
7311
7377
|
this.addCellBorderAnimation();
|
|
7312
7378
|
try {
|
|
@@ -7316,28 +7382,49 @@ class TruDataGridClipboard {
|
|
|
7316
7382
|
console.error('Failed to copy text: ', err);
|
|
7317
7383
|
}
|
|
7318
7384
|
};
|
|
7319
|
-
pasteCell = (params, pastedCellData, pastedCell) => {
|
|
7385
|
+
pasteCell = async (params, pastedCellData, pastedCell) => {
|
|
7320
7386
|
let colDef = params.colDef;
|
|
7321
7387
|
let columnName = colDef.field;
|
|
7322
|
-
let copiedCellDataTypeName = this.copiedCellData[this.copiedCellParams?.colDef?.field].property.typeName;
|
|
7323
|
-
let pastedCellDataTypeName = pastedCellData[params.colDef?.field].property.typeName;
|
|
7324
7388
|
if (!colDef.editable) {
|
|
7325
7389
|
this.uiNotification.error('Cannot paste into a non-editable column: ' + colDef.field);
|
|
7326
7390
|
return;
|
|
7327
7391
|
}
|
|
7328
|
-
|
|
7329
|
-
|
|
7392
|
+
let clipboardText;
|
|
7393
|
+
try {
|
|
7394
|
+
clipboardText = this.normalizeClipboardText(await this.readClipboardText());
|
|
7395
|
+
}
|
|
7396
|
+
catch (err) {
|
|
7397
|
+
this.uiNotification.error('Unable to read data from the system clipboard.');
|
|
7330
7398
|
return;
|
|
7331
7399
|
}
|
|
7400
|
+
const pastedCellConfig = pastedCellData[columnName];
|
|
7401
|
+
const isInternalCopy = this.copiedCellText !== null && clipboardText === this.copiedCellText;
|
|
7402
|
+
if (isInternalCopy && this.copiedCellData && this.copiedCellParams) {
|
|
7403
|
+
const copiedColumnName = this.copiedCellParams.colDef?.field;
|
|
7404
|
+
const copiedCellDataTypeName = this.copiedCellData[copiedColumnName].property.typeName;
|
|
7405
|
+
const pastedCellDataTypeName = pastedCellConfig.property.typeName;
|
|
7406
|
+
if (copiedCellDataTypeName !== pastedCellDataTypeName) {
|
|
7407
|
+
this.uiNotification.error('Clipboard data type does not match the current cell data type: ' + copiedCellDataTypeName + ' vs ' + pastedCellDataTypeName);
|
|
7408
|
+
return;
|
|
7409
|
+
}
|
|
7410
|
+
pastedCellConfig.$ = this.copiedCellValue;
|
|
7411
|
+
}
|
|
7332
7412
|
else {
|
|
7333
|
-
|
|
7334
|
-
|
|
7335
|
-
|
|
7413
|
+
try {
|
|
7414
|
+
pastedCellConfig.$ = this.parseExternalCellValue(clipboardText, pastedCellConfig);
|
|
7415
|
+
}
|
|
7416
|
+
catch (err) {
|
|
7417
|
+
this.uiNotification.error(err.message);
|
|
7418
|
+
return;
|
|
7419
|
+
}
|
|
7336
7420
|
}
|
|
7421
|
+
this.removeBorderAnimation();
|
|
7422
|
+
params.api.refreshCells({ force: true });
|
|
7337
7423
|
};
|
|
7338
7424
|
copyRow = async (tableName, columnDefs, copiedRows, includeHeaders = false) => {
|
|
7339
7425
|
this.tableName = tableName;
|
|
7340
7426
|
this.copiedRows = copiedRows;
|
|
7427
|
+
this.copiedRowsText = null;
|
|
7341
7428
|
this.removeBorderAnimation();
|
|
7342
7429
|
this.addRowBorderAnimation();
|
|
7343
7430
|
if (copiedRows.length) {
|
|
@@ -7363,6 +7450,7 @@ class TruDataGridClipboard {
|
|
|
7363
7450
|
});
|
|
7364
7451
|
multiRowString += rowPropertyValues.join('\t') + '\n';
|
|
7365
7452
|
});
|
|
7453
|
+
this.copiedRowsText = this.normalizeClipboardText(multiRowString);
|
|
7366
7454
|
try {
|
|
7367
7455
|
await navigator.clipboard.writeText(multiRowString);
|
|
7368
7456
|
}
|
|
@@ -7371,7 +7459,19 @@ class TruDataGridClipboard {
|
|
|
7371
7459
|
}
|
|
7372
7460
|
}
|
|
7373
7461
|
};
|
|
7374
|
-
pasteRow = (gridApi, config, selectedRows) => {
|
|
7462
|
+
pasteRow = async (gridApi, config, selectedRows) => {
|
|
7463
|
+
let clipboardText;
|
|
7464
|
+
try {
|
|
7465
|
+
clipboardText = this.normalizeClipboardText(await this.readClipboardText());
|
|
7466
|
+
}
|
|
7467
|
+
catch (err) {
|
|
7468
|
+
this.uiNotification.error('Unable to read data from the system clipboard.');
|
|
7469
|
+
return;
|
|
7470
|
+
}
|
|
7471
|
+
if (this.copiedRowsText === null || clipboardText !== this.copiedRowsText) {
|
|
7472
|
+
this.uiNotification.error('External row data cannot be pasted as an internal grid row copy. Paste into an individual cell instead.');
|
|
7473
|
+
return;
|
|
7474
|
+
}
|
|
7375
7475
|
if (this.tableName !== config.tableName) {
|
|
7376
7476
|
this.uiNotification.error('Clipboard data does not match the current table name: ' + this.tableName + ' vs ' + config.tableName);
|
|
7377
7477
|
return;
|
|
@@ -9126,13 +9226,15 @@ class TruDataGrid {
|
|
|
9126
9226
|
this.dataGridClipboard.copyRow(this.config.tableName, columnDefs, selectedRows);
|
|
9127
9227
|
}
|
|
9128
9228
|
else if (params.column.isPinned() && event.ctrlKey && event.code === 'KeyV') {
|
|
9129
|
-
|
|
9229
|
+
event.preventDefault();
|
|
9230
|
+
void this.dataGridClipboard.pasteRow(this.api, this.config, this.api.getSelectedRows());
|
|
9130
9231
|
}
|
|
9131
9232
|
else if (!params.column.isPinned() && event.ctrlKey && event.code === 'KeyC') {
|
|
9132
9233
|
this.dataGridClipboard.copyCell(params, this.config.tableName, params.colDef?.field, params.data, params.data.$entity);
|
|
9133
9234
|
}
|
|
9134
9235
|
else if (!params.column.isPinned() && event.ctrlKey && event.code === 'KeyV') {
|
|
9135
|
-
|
|
9236
|
+
event.preventDefault();
|
|
9237
|
+
void this.dataGridClipboard.pasteCell(params, params.data, params.data.$entity);
|
|
9136
9238
|
}
|
|
9137
9239
|
};
|
|
9138
9240
|
onCellMouseOver(e) {
|