Skip to content

Commit

Permalink
refactor: create mei validation class
Browse files Browse the repository at this point in the history
Refs: #100
  • Loading branch information
kunfang98927 committed Jul 5, 2024
1 parent 8ed5054 commit 27b1a36
Show file tree
Hide file tree
Showing 9 changed files with 328 additions and 157 deletions.
27 changes: 27 additions & 0 deletions assets/css/style.css
Original file line number Diff line number Diff line change
Expand Up @@ -665,3 +665,30 @@ a:hover {
width: 100%;
height: 100%;
}

/* ----------------------- */
/* Section: Invalid Cell
/* ----------------------- */

.invalid-container {
display: flex;
align-items: flex-start;
background-color: #ffbeba !important;
justify-content: space-between;
}

.tooltip-icon {
width: 20px;
margin: 5px;
}

.tooltip-text {
display: none;
position: absolute;
background-color: white;
border: 1px solid black;
padding: 5px;
z-index: 1;
width: 30vw;
color: black;
}
4 changes: 4 additions & 0 deletions assets/img/info-icon.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
4 changes: 1 addition & 3 deletions src/Editor/ColumnTools.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import * as Validation from '../Validation';

export class ColumnTools {
public validationInProgress = false;
Expand All @@ -22,8 +21,7 @@ export class ColumnTools {
} else if (headers[i].includes('mei')) {
columns.push({
data: headers[i],
validator: Validation.meiValidator,
allowInvalid: true,
renderer: 'meiRenderer',
});
} else {
columns.push({
Expand Down
107 changes: 70 additions & 37 deletions src/Editor/CressTable.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import Handsontable from 'handsontable';
import * as Validation from '../Validation';
import { ImageHandler } from './ImageHandler';
import { ExportHandler } from './ExportHandler';
import { ImageTools } from './ImageTools';
import { MeiTools } from './MeiTools';
import { ValidationTools, updateStatus } from './ValidationTools';
import { ExportTools } from './ExportTools';
import { ColumnTools } from './ColumnTools';
import { updateAttachment } from '../Dashboard/Storage';
import { setSavedStatus } from '../utils/Unsaved';
Expand All @@ -24,16 +25,20 @@ const changeHooks: TableEvent[] = [
export class CressTable {
private table: Handsontable;
private images: any[] = []; // Array to store images
private imageHandler: ImageHandler;
private exportHandler: ExportHandler;
private imageTools: ImageTools;
private meiTools: MeiTools;
private validationTools: ValidationTools;
private exportTools: ExportTools;
private ColumnTools: ColumnTools;

constructor(id: string, inputHeader: string[], body: any[]) {
const container = document.getElementById('hot-container');

// Initialize handlers
this.imageHandler = new ImageHandler(this.images);
this.exportHandler = new ExportHandler();
// Initialize Toolss
this.imageTools = new ImageTools(this.images);
this.meiTools = new MeiTools();
this.validationTools = new ValidationTools();
this.exportTools = new ExportTools();
this.ColumnTools = new ColumnTools(inputHeader);

// Convert all quote signs to inch marks in mei data
Expand All @@ -42,7 +47,13 @@ export class CressTable {
// Register the custom image renderer
Handsontable.renderers.registerRenderer(
'imgRenderer',
this.imageHandler.imgRender.bind(this.imageHandler),
this.imageTools.imgRender.bind(this.imageTools),
);

// Register the custom mei renderer
Handsontable.renderers.registerRenderer(
'meiRenderer',
this.meiTools.meiRender.bind(this.meiTools),
);

// Prepare table configuration
Expand All @@ -53,7 +64,11 @@ export class CressTable {

// Process images
let inputImgHeader = inputHeader.find((header) => header.includes('image'));
this.imageHandler.storeImages(inputImgHeader, body);
this.imageTools.storeImages(inputImgHeader, body);

// Process mei data
let inputMeiHeader = inputHeader.find((header) => header.includes('mei'));
this.meiTools.initMeiData(inputMeiHeader, body);

// Initialize table
this.table = new Handsontable(container, {
Expand All @@ -79,13 +94,7 @@ export class CressTable {
dropdownMenu: true,
className: 'table-menu-btn',
licenseKey: 'non-commercial-and-evaluation',
afterChange(_, source) {
if (source == 'loadData') {
this.validateCells();
}
},
beforeValidate: (value) => this.setProcessStatus(value),
afterValidate: (isValid) => this.setResultStatus(isValid),
afterChange: this.afterChange,
});

this.initFileListener(id, inputHeader, body, headers);
Expand All @@ -100,13 +109,13 @@ export class CressTable {
) {
const exportPlugin = this.table.getPlugin('exportFile');
document.getElementById('export-to-csv').addEventListener('click', () => {
this.exportHandler.exportToCsv(exportPlugin);
this.exportTools.exportToCsv(exportPlugin);
});

document
.getElementById('export-to-excel')
.addEventListener('click', async () => {
await this.exportHandler.exportToExcel(
await this.exportTools.exportToExcel(
inputHeader,
body,
headers,
Expand Down Expand Up @@ -139,24 +148,24 @@ export class CressTable {
});
}

private setProcessStatus(value: any) {
if (!this.ColumnTools.validationInProgress) {
this.ColumnTools.validationInProgress = true;
Validation.updateStatus('processing');
}
// Update `pendingValidations` if value is not empty
if (value) this.ColumnTools.pendingValidations++;
}

private setResultStatus(isValid: boolean) {
if (!isValid) this.ColumnTools.hasInvalid = true;
this.ColumnTools.pendingValidations--;
if (this.ColumnTools.pendingValidations === 0) {
this.ColumnTools.validationInProgress = false;
Validation.updateStatus('done', this.ColumnTools.hasInvalid);
this.ColumnTools.hasInvalid = false;
}
}
// private setProcessStatus(value: any) {
// if (!this.ColumnTools.validationInProgress) {
// this.ColumnTools.validationInProgress = true;
// updateStatus('processing');
// }
// // Update `pendingValidations` if value is not empty
// if (value) this.ColumnTools.pendingValidations++;
// }

// private setResultStatus(isValid: boolean) {
// if (!isValid) this.ColumnTools.hasInvalid = true;
// this.ColumnTools.pendingValidations--;
// if (this.ColumnTools.pendingValidations === 0) {
// this.ColumnTools.validationInProgress = false;
// updateStatus('done', this.ColumnTools.hasInvalid);
// this.ColumnTools.hasInvalid = false;
// }
// }

private initChangeListener() {
changeHooks.forEach((hook) => {
Expand All @@ -165,4 +174,28 @@ export class CressTable {
});
});
}

afterChange = (changes, source) => {
if (source == 'loadData') {
// Validate mei data and update the validation status
this.meiTools.getMeiData().forEach((mei) => {
this.validationTools.meiValidator(mei.mei).then(([isValid, errorMsg]) => {
this.meiTools.updateMeiData(mei.row, mei.mei, isValid, errorMsg);
this.table.render();
});
});
} else {
changes?.forEach(([row, prop, oldValue, newValue]) => {
if (prop === 'mei' && oldValue !== newValue) {
// validate the new edited mei data and update the validation status
this.meiTools.updateMeiData(row, newValue, undefined, undefined);
this.table.render();
this.validationTools.meiValidator(newValue).then(([isValid, errorMsg]) => {
this.meiTools.updateMeiData(row, undefined, isValid, errorMsg);
this.table.render();
});
}
});
}
};
}
2 changes: 1 addition & 1 deletion src/Editor/ExportHandler.ts → src/Editor/ExportTools.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { saveAs } from 'file-saver';

export class ExportHandler {
export class ExportTools {
exportToCsv(exportPlugin: any) {
exportPlugin.downloadFile('csv', {
bom: true,
Expand Down
2 changes: 1 addition & 1 deletion src/Editor/ImageHandler.ts → src/Editor/ImageTools.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import Handsontable from 'handsontable';

export class ImageHandler {
export class ImageTools {
private images: any[];

constructor(images: any[]) {
Expand Down
109 changes: 109 additions & 0 deletions src/Editor/MeiTools.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
import Handsontable from 'handsontable';

export class MeiTools {
private meiData: any[];

constructor() {
this.meiData = [];
}

// Mei Initialization
public initMeiData(inputMeiHeader: string, body: any[]) {
body.forEach((row, rowIndex) => {
const mei = row[inputMeiHeader];
if (mei) {
this.meiData.push({
mei,
row: rowIndex,
isValid: null,
errorMsg: null,
});
}
});
}

// Getters
public getMeiData() {
return this.meiData;
}

// Update the mei data
public updateMeiData(
row: number,
mei?: string,
isValid?: boolean,
errorMsg?: string[]
) {
const meiData = this.meiData.find((meiData) => meiData.row === row);
if (meiData) {
if (mei !== undefined) {
meiData.mei = mei;
}
if (isValid !== undefined) {
meiData.isValid = isValid;
}
if (errorMsg !== undefined) {
meiData.errorMsg = errorMsg;
}
} else {
this.meiData.push({
row,
mei: mei ?? meiData.mei,
isValid: isValid ?? meiData.isValid,
errorMsg: errorMsg ?? meiData.errorMsg,
});
}
}

// Mei Renderer Functions
meiRender(
instance: Handsontable,
td: HTMLElement,
row: number,
col: number,
prop: string,
value: any,
cellProperties: Handsontable.CellProperties,
) {
Handsontable.dom.empty(td);

const mei = this.meiData.find((mei) => mei.row === row);
if (mei) {

if (mei.isValid === false) {

// container for the invalid cell
const invalidContainer = document.createElement('div');
invalidContainer.className = 'invalid-container';

// mei data
const meiData = document.createElement('span');
meiData.textContent = mei.mei;
invalidContainer.appendChild(meiData);

// tooltip icon and text
const tooltipIcon = document.createElement('img');
tooltipIcon.src = './Cress-gh/assets/img/info-icon.svg';
tooltipIcon.className = 'tooltip-icon';
invalidContainer.appendChild(tooltipIcon);
const tooltipText = document.createElement('span');
tooltipText.className = 'tooltip-text';
tooltipText.textContent = mei.errorMsg.join('\n\n');
invalidContainer.appendChild(tooltipText);
tooltipIcon.addEventListener('mouseover', () => {
tooltipText.style.display = 'block';
});
tooltipIcon.addEventListener('mouseout', () => {
tooltipText.style.display = 'none';
});

td.appendChild(invalidContainer);
} else {
td.textContent = mei.mei;
}
}

return td;
}

}
Loading

0 comments on commit 27b1a36

Please sign in to comment.