igniteui-angular-sovn
Version:
Ignite UI for Angular is a dependency-free Angular toolkit for building modern web apps
126 lines (102 loc) • 4.35 kB
text/typescript
import { ExportUtilities } from '../exporter-common/export-utilities';
import { yieldingLoop } from '../../core/utils';
import { IColumnInfo } from '../exporter-common/base-export-service';
/**
* @hidden
*/
export class CharSeparatedValueData {
private _headerRecord = '';
private _dataRecords = '';
private _eor = '\r\n';
private _delimiter;
private _escapeCharacters = ['\r', '\n', '\r\n'];
private _delimiterLength = 1;
private _isSpecialData = false;
constructor(private _data: any[], valueDelimiter: string, private columns: IColumnInfo[] = []) {
this.setDelimiter(valueDelimiter);
}
public prepareData(key?: any[]) {
if (!this._data || this._data.length === 0) {
return '';
}
let keys = [];
if (key){
keys = key;
}else {
keys = ExportUtilities.getKeysFromData(this._data);
}
if (keys.length === 0) {
return '';
}
this._isSpecialData = ExportUtilities.isSpecialData(this._data[0]);
this._escapeCharacters.push(this._delimiter);
this._headerRecord = this.processHeaderRecord(keys, this._data.length);
this._dataRecords = this.processDataRecords(this._data, keys);
return this._headerRecord + this._dataRecords;
}
public prepareDataAsync(done: (result: string) => void) {
const columns = this.columns?.filter(c => !c.skip)
.sort((a, b) => a.startIndex - b.startIndex)
.sort((a, b) => a.pinnedIndex - b.pinnedIndex);
const keys = columns && columns.length ? columns.map(c => c.field) : ExportUtilities.getKeysFromData(this._data);
this._isSpecialData = ExportUtilities.isSpecialData(this._data[0]);
this._escapeCharacters.push(this._delimiter);
const headers = columns && columns.length ?
columns.map(c => c.header ?? c.field) :
keys;
this._headerRecord = this.processHeaderRecord(headers, this._data.length);
if (keys.length === 0 || ((!this._data || this._data.length === 0) && keys.length === 0)) {
done('');
} else {
this.processDataRecordsAsync(this._data, keys, (dr) => {
done(this._headerRecord + dr);
});
}
}
private processField(value, escapeChars): string {
let safeValue = ExportUtilities.hasValue(value) ? String(value) : '';
if (escapeChars.some((v) => safeValue.includes(v))) {
safeValue = `"${safeValue}"`;
}
return safeValue + this._delimiter;
}
private processHeaderRecord(keys, dataLength): string {
let recordData = '';
for (const keyName of keys) {
recordData += this.processField(keyName, this._escapeCharacters);
}
const result = recordData.slice(0, -this._delimiterLength);
return dataLength > 0 ? result + this._eor : result;
}
private processRecord(record, keys): string {
const recordData = new Array(keys.length);
for (let index = 0; index < keys.length; index++) {
const value = (record[keys[index]] !== undefined) ? record[keys[index]] : this._isSpecialData ? record : '';
recordData[index] = this.processField(value, this._escapeCharacters);
}
return recordData.join('').slice(0, -this._delimiterLength) + this._eor;
}
private processDataRecords(currentData, keys) {
const dataRecords = new Array(currentData.length);
for (let i = 0; i < currentData.length; i++) {
const row = currentData[i];
dataRecords[i] = this.processRecord(row, keys);
}
return dataRecords.join('');
}
private processDataRecordsAsync(currentData, keys, done: (result: string) => void) {
const dataRecords = new Array(currentData.length);
yieldingLoop(currentData.length, 1000,
(i) => {
const row = currentData[i];
dataRecords[i] = this.processRecord(row, keys);
},
() => {
done(dataRecords.join(''));
});
}
private setDelimiter(value) {
this._delimiter = value;
this._delimiterLength = value.length;
}
}