@syncfusion/ej2-spreadsheet
Version:
Feature-rich JavaScript Spreadsheet (Excel) control with built-in support for selection, editing, formatting, importing and exporting to Excel
558 lines (557 loc) • 21.9 kB
JavaScript
var __extends = (this && this.__extends) || (function () {
var extendStatics = function (d, b) {
extendStatics = Object.setPrototypeOf ||
({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };
return extendStatics(d, b);
};
return function (d, b) {
extendStatics(d, b);
function __() { this.constructor = d; }
d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
};
})();
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
return c > 3 && r && Object.defineProperty(target, key, r), r;
};
import { processIdx } from './data';
import { ConditionalFormat, getCellIndexes, moveOrDuplicateSheet, workbookFormulaOperation, duplicateSheetFilterHandler, moveSheetHandler, updateSortCollection } from '../common/index';
import { ProtectSettings, getCellAddress } from '../common/index';
import { isUndefined, ChildProperty, Property, Complex, Collection, extend, getUniqueID } from '@syncfusion/ej2-base';
/**
* Configures the range processing for the spreadsheet.
* ```html
* <div id='Spreadsheet'></div>
* ```
* ```typescript
* let spreadsheet: Spreadsheet = new Spreadsheet({
* sheets: [{
* name: 'First Sheet',
* ranges: [{ dataSource: defaultData }],
* rows: [{
* index: 30,
* cells: [{ index: 4, value: 'Total Amount:' },
* { formula: '=SUM(F2:F30)', style: { fontWeight: 'bold' } }]
* }]
* ...
* });
* spreadsheet.appendTo('#Spreadsheet');
* ```
*/
var Range = /** @class */ (function (_super) {
__extends(Range, _super);
function Range() {
return _super !== null && _super.apply(this, arguments) || this;
}
Range.prototype.setProperties = function (prop, muteOnChange) {
var _this = this;
if (this['parentObj'].isComplexArraySetter && this['controlParent'] && this['controlParent'].isAngular) {
if (Object.keys(prop).length) {
if (this['parentObj']['currRangeIdx'] === undefined) {
this['parentObj']['currRangeIdx'] = 0;
}
else {
this['parentObj']['currRangeIdx'] += 1;
}
var range = this['parentObj'].ranges[this['parentObj']['currRangeIdx']];
if (range && range.info) {
this.info = range.info;
}
setTimeout(function () {
if (_this['parentObj']['currRangeIdx'] !== undefined) {
delete _this['parentObj']['currRangeIdx'];
}
});
}
else if (this['controlParent'].tagObjects[0].instance && this['controlParent'].tagObjects[0].instance.hasChanges
&& !this['controlParent'].tagObjects[0].instance.isInitChanges) {
var sheetIdx = this['controlParent'].sheets.indexOf(this['parentObj']);
if (this['parentObj'].changedRangeIdx === undefined) {
var rangeIdx_1;
var tagObjects = this['controlParent'].tagObjects[0].instance.list[sheetIdx].tagObjects;
for (var i = 0; i < tagObjects.length; i++) {
if (tagObjects[i]['name'] === 'ranges') {
tagObjects[i]['instance'].list
.forEach(function (range, idx) {
if (range.hasChanges) {
rangeIdx_1 = idx;
}
});
break;
}
}
this['parentObj'].changedRangeIdx = rangeIdx_1;
}
}
}
_super.prototype.setProperties.call(this, prop, muteOnChange);
};
__decorate([
Property(null)
], Range.prototype, "dataSource", void 0);
__decorate([
Property('A1')
], Range.prototype, "startCell", void 0);
__decorate([
Property(null)
], Range.prototype, "query", void 0);
__decorate([
Property(null)
], Range.prototype, "fieldsOrder", void 0);
__decorate([
Property(true)
], Range.prototype, "showFieldAsHeader", void 0);
__decorate([
Property('')
], Range.prototype, "template", void 0);
__decorate([
Property('A1')
], Range.prototype, "address", void 0);
return Range;
}(ChildProperty));
export { Range };
/**
* Used range which contains end row index and end column index of the last used cell in sheet .
*/
var UsedRange = /** @class */ (function (_super) {
__extends(UsedRange, _super);
function UsedRange() {
return _super !== null && _super.apply(this, arguments) || this;
}
__decorate([
Property(0)
], UsedRange.prototype, "rowIndex", void 0);
__decorate([
Property(0)
], UsedRange.prototype, "colIndex", void 0);
return UsedRange;
}(ChildProperty));
export { UsedRange };
/**
* Configures the sheet behavior for the spreadsheet.
*/
var Sheet = /** @class */ (function (_super) {
__extends(Sheet, _super);
function Sheet() {
return _super !== null && _super.apply(this, arguments) || this;
}
__decorate([
Property(null)
], Sheet.prototype, "rows", void 0);
__decorate([
Property(null)
], Sheet.prototype, "columns", void 0);
__decorate([
Complex({}, ProtectSettings)
], Sheet.prototype, "protectSettings", void 0);
__decorate([
Collection([], Range)
], Sheet.prototype, "ranges", void 0);
__decorate([
Collection([], ConditionalFormat)
], Sheet.prototype, "conditionalFormats", void 0);
__decorate([
Property(0)
], Sheet.prototype, "index", void 0);
__decorate([
Property('')
], Sheet.prototype, "name", void 0);
__decorate([
Property(100)
], Sheet.prototype, "rowCount", void 0);
__decorate([
Property(100)
], Sheet.prototype, "colCount", void 0);
__decorate([
Property('A1:A1')
], Sheet.prototype, "selectedRange", void 0);
__decorate([
Property('A1')
], Sheet.prototype, "activeCell", void 0);
__decorate([
Complex({}, UsedRange)
], Sheet.prototype, "usedRange", void 0);
__decorate([
Property('A1')
], Sheet.prototype, "topLeftCell", void 0);
__decorate([
Property(true)
], Sheet.prototype, "showHeaders", void 0);
__decorate([
Property(true)
], Sheet.prototype, "showGridLines", void 0);
__decorate([
Property(false)
], Sheet.prototype, "isProtected", void 0);
__decorate([
Property('Visible')
], Sheet.prototype, "state", void 0);
__decorate([
Property(0)
], Sheet.prototype, "frozenRows", void 0);
__decorate([
Property(0)
], Sheet.prototype, "frozenColumns", void 0);
__decorate([
Property('A1')
], Sheet.prototype, "paneTopLeftCell", void 0);
__decorate([
Property('')
], Sheet.prototype, "password", void 0);
__decorate([
Property(null)
], Sheet.prototype, "standardHeight", void 0);
__decorate([
Property(false)
], Sheet.prototype, "isSheetCalculated", void 0);
return Sheet;
}(ChildProperty));
export { Sheet };
/**
* To get sheet index from address.
*
* @hidden
* @param {Workbook} context - Specifies the context.
* @param {string} name - Specifies the name.
* @returns {number} - To gget sheet index from address.
*/
export function getSheetIndex(context, name) {
var idx;
if (name.startsWith('\'') && name.endsWith('\'')) {
name = name.replace(/''/g, '\'').replace(/^'|'$/g, '');
}
for (var i = 0; i < context.sheets.length; i++) {
if (context.sheets[i].name.toLowerCase() === name.toLowerCase()) {
idx = i;
break;
}
}
return idx;
}
/**
* To get sheet index from sheet id.
*
* @hidden
* @param {Workbook} context - Specifies the context.
* @param {number} id - Specifies the id.
* @returns {number} - To get the sheet index from id.
*/
export function getSheetIndexFromId(context, id) {
var idx;
for (var i = 0; i < context.sheets.length; i++) {
if (context.sheets[i].id === id) {
idx = i;
break;
}
}
return idx;
}
/**
* To get sheet name from address.
*
* @hidden
* @param {string} address - Specifies the address.
* @returns {address} - To get Sheet Name From Address.
*/
export function getSheetNameFromAddress(address) {
var sheetRefIndex = address.lastIndexOf('!');
return sheetRefIndex > -1 ? address.substring(0, sheetRefIndex).replace(/'/gi, '') : address.replace(/'/gi, '');
}
/**
* To get sheet index from sheet name.
*
* @hidden
* @param {Object} context - Specifies the context.
* @param {string} name - Specifies the name.
* @param {SheetModel} info - Specifies the sheet info.
* @returns {number} - To get the sheet index by name.
*/
export function getSheetIndexByName(context, name, info) {
var len = info.length;
for (var i = 0; i < len; i++) {
if (info[i].sheet.toUpperCase() === name.toUpperCase()) {
return info[i].index;
}
}
return -1;
}
/**
* update selected range
*
* @hidden
* @param {Workbook} context - Specifies the context.
* @param {string} range - Specifies the range.
* @param {SheetModel} sheet - Specifies the sheet.
* @param {boolean} isMultiRange - Specifies the boolean value.
* @returns {void} - Update the selected range.
*/
export function updateSelectedRange(context, range, sheet, isMultiRange) {
if (sheet === void 0) { sheet = {}; }
context.setSheetPropertyOnMute(sheet, 'selectedRange', isMultiRange ? sheet.selectedRange + ' ' + range : range);
}
/**
* get selected range
*
* @hidden
* @param {SheetModel} sheet - Specifies the sheet.
* @returns {string} - Get selected range.
*/
export function getSelectedRange(sheet) {
return sheet && sheet.selectedRange || 'A1';
}
/**
* @hidden
* @param {Workbook} context - Specifies the context.
* @param {number} idx - Specifies the idx.
* @returns {SheetModel} - To get sheet.
*/
export function getSheet(context, idx) {
return context.sheets[idx];
}
/**
* @hidden
* @param {Workbook} context - Specifies the context.
* @returns {number} - To get sheet name count.
*/
export function getSheetNameCount(context) {
var name = [];
context.sheets.forEach(function (sheet) {
name.push(sheet.name.toLowerCase());
});
for (var i = 0; i < name.length; i++) {
if (name.indexOf('sheet' + context.sheetNameCount) > -1) {
context.sheetNameCount++;
}
else {
return context.sheetNameCount++;
}
}
return context.sheetNameCount++;
}
/**
* @hidden
* @param {SheetModel[]} sheets - Specifies the sheets.
* @returns {number} - To get sheet id.
*/
export function getMaxSheetId(sheets) {
var cnt = 0;
sheets.forEach(function (sheet) {
cnt = Math.max(sheet.id, cnt);
});
return cnt + 1;
}
/**
* @hidden
* @param {Workbook} context - Specifies the context.
* @param {SheetModel[]} sheet - Specifies the sheet.
* @param {boolean} isImport - Specifies is Import or not.
* @returns {void} - To initiate sheet.
*/
export function initSheet(context, sheet, isImport) {
var sheets = sheet ? sheet : context.sheets;
sheets.forEach(function (sheet) {
sheet.id = sheet.id || 0;
sheet.name = sheet.name || '';
context.setSheetPropertyOnMute(sheet, 'rowCount', sheet.rowCount || 100);
context.setSheetPropertyOnMute(sheet, 'colCount', sheet.colCount || 100);
context.setSheetPropertyOnMute(sheet, 'topLeftCell', sheet.topLeftCell || 'A1');
context.setSheetPropertyOnMute(sheet, 'activeCell', sheet.activeCell || 'A1');
context.setSheetPropertyOnMute(sheet, 'selectedRange', sheet.selectedRange || sheet.activeCell + ':' + sheet.activeCell);
context.setSheetPropertyOnMute(sheet, 'usedRange', sheet.usedRange || { rowIndex: 0, colIndex: 0 });
context.setSheetPropertyOnMute(sheet, 'ranges', sheet.ranges ? sheet.ranges : []);
context.setSheetPropertyOnMute(sheet, 'rows', (sheet.rows && extend([], sheet.rows, null, true)) || []);
context.setSheetPropertyOnMute(sheet, 'columns', sheet.columns || []);
context.setSheetPropertyOnMute(sheet, 'showHeaders', isUndefined(sheet.showHeaders) ? true : sheet.showHeaders);
context.setSheetPropertyOnMute(sheet, 'showGridLines', isUndefined(sheet.showGridLines) ? true : sheet.showGridLines);
context.setSheetPropertyOnMute(sheet, 'state', sheet.state || 'Visible');
sheet.maxHgts = sheet.maxHgts || [];
sheet.isImportProtected = sheet.isProtected && isImport;
sheet.protectSettings = sheet.protectSettings || { selectCells: false, formatCells: false, formatRows: false, formatColumns: false,
insertLink: false };
sheet.isProtected = sheet.isProtected || false;
if (!sheet.paneTopLeftCell || sheet.paneTopLeftCell === 'A1') {
sheet.frozenRows = sheet.frozenRows ? sheet.frozenRows : 0;
sheet.frozenColumns = sheet.frozenColumns ? sheet.frozenColumns : 0;
var indexes = getCellIndexes(sheet.topLeftCell);
context.setSheetPropertyOnMute(sheet, 'paneTopLeftCell', getCellAddress(sheet.frozenRows ? indexes[0] + sheet.frozenRows : indexes[0], sheet.frozenColumns ? indexes[1] + sheet.frozenColumns : indexes[1]));
}
processIdx(sheet.columns);
initRow(sheet.rows, isImport);
});
processIdx(sheets, true, context);
}
// function initRangeSettings(ranges: RangeModel[]): RangeModel[] {
// ranges.forEach((range: RangeModel) => {
// range.startCell = range.startCell || 'A1';
// range.address = range.address || 'A1';
// range.template = range.template || '';
// range.showFieldAsHeader = isUndefined(range.showFieldAsHeader) ? true : range.showFieldAsHeader;
// });
// return ranges;
// }
/**
* @param {RowModel[]} rows - Specifies the rows.
* @param {boolean} isImport - Specifies the operation is from Import or not.
* @returns {void} - Specifies the row.
*/
function initRow(rows, isImport) {
rows.forEach(function (row) {
if (row && row.cells) {
// Process cell indexes in ascending order when the import operation is performed.
processIdx(row.cells, null, undefined, isImport);
}
});
processIdx(rows, null, undefined, isImport);
}
/**
* get sheet name
*
* @param {Workbook} context - Specifies the context.
* @param {number} idx - Specifies the idx.
* @returns {string} - To get sheet name.
* @hidden
*/
export function getSheetName(context, idx) {
if (idx === void 0) { idx = context.activeSheetIndex; }
return getSheet(context, idx).name;
}
/**
* @param {Workbook} context - Specifies context
* @param {number} position - position to move a sheet in the list of sheets
* @param {number[]} sheetIndexes - Specifies the sheet indexes of the sheets which is to be moved
* @param {boolean} action - Specifies to trigger events
* @param {boolean} isFromUpdateAction - Specifies is from UpdateAction or not.
* @returns {void}
* @hidden
*/
export function moveSheet(context, position, sheetIndexes, action, isFromUpdateAction) {
var needRefresh = !!sheetIndexes;
sheetIndexes = sheetIndexes || [context.activeSheetIndex];
var sheetName = getSheetName(context);
position = getNextPrevVisibleSheetIndex(context.sheets, position, context.activeSheetIndex > position);
var args = {
action: 'moveSheet', eventArgs: { position: position, sheetIndexes: sheetIndexes, cancel: false }
};
if (action) {
context.trigger('actionBegin', args);
}
if (!args.eventArgs.cancel) {
context.notify(moveSheetHandler, { prevIndex: context.activeSheetIndex, currentIndex: position });
sheetIndexes.forEach(function (sIdx, idx) {
context.sheets.splice(position + idx, 0, context.sheets.splice(sIdx + (position > sIdx ? -1 * idx : 0), 1)[0]);
});
context.setProperties({
activeSheetIndex: isFromUpdateAction ? getSheetIndex(context, sheetName)
: (position > sheetIndexes[0] ? position - (sheetIndexes.length - 1) : position)
}, true);
context.notify(moveOrDuplicateSheet, { refresh: needRefresh });
if (action) {
delete args.eventArgs.cancel;
context.trigger('actionComplete', args);
}
}
}
/**
* @param {Workbook} context - Specifies context
* @param {number} sheetIndex - Specifies sheetIndex to be duplicated
* @param {boolean} action - Specifies to trigger events
* @param {boolean} isFromUpdateAction - Specifies is from updateAction.
* @returns {void}
* @hidden
*/
export function duplicateSheet(context, sheetIndex, action, isFromUpdateAction) {
sheetIndex = isUndefined(sheetIndex) ? context.activeSheetIndex : sheetIndex;
var args = {
action: 'duplicateSheet', eventArgs: { sheetIndex: sheetIndex, cancel: false }
};
if (action) {
context.trigger('actionBegin', args);
}
if (!args.eventArgs.cancel) {
var originalSheet = getSheet(context, sheetIndex);
var originalSheetName_1 = originalSheet.name;
var sheet_1 = extend({}, originalSheet.properties ?
originalSheet.properties : originalSheet, {}, true);
sheet_1.id = getMaxSheetId(context.sheets);
var name_1 = sheet_1.name;
if (/^\(\d+\)$/.test('(' + name_1.split(' (')[1])) {
name_1 = name_1.split(' (')[0];
}
var sheetNames_1 = [];
context.sheets.forEach(function (sheet) {
sheetNames_1.push(sheet.name);
});
for (var i = 2;; i++) {
var suffix = ' (' + i + ')';
if ((name_1 + suffix).length > 31) {
name_1 = name_1.slice(0, 31 - suffix.length);
}
if (sheetNames_1.indexOf(name_1 + suffix) === -1) {
sheet_1.name = name_1 + suffix;
break;
}
}
context.notify(duplicateSheetFilterHandler, { sheetIndex: sheetIndex, newSheetIndex: sheetIndex + 1 });
context.notify(updateSortCollection, { isDuplicate: true, curSheetIndex: sheetIndex, newSheetIndex: sheetIndex + 1 });
sheet_1.rows.forEach(function (row) {
if (!row || !row.cells) {
return;
}
row.cells.forEach(function (cell) {
if (!cell) {
return;
}
if (cell.image) {
var images = cell.image;
images.forEach(function (image) {
image.id = getUniqueID(context.element.id + '_overlay_picture_');
});
}
var charts = cell.chart;
if (charts) {
charts.forEach(function (chart) {
var lastIndex = chart.range.lastIndexOf('!');
var chartSheet = chart.range.substring(0, lastIndex);
var duplicateSheetName = sheet_1.name;
if (chartSheet.startsWith('\'') && chartSheet.endsWith('\'')) {
chartSheet = chartSheet.slice(1, -1);
duplicateSheetName = "'" + duplicateSheetName + "'";
}
if (chartSheet === originalSheetName_1) {
chart.range = duplicateSheetName + chart.range.substring(lastIndex);
chart.id = getUniqueID(chart.id || 'e_spreadsheet_chart');
}
});
}
});
});
context.createSheet(sheetIndex + 1, [sheet_1]);
context.notify(workbookFormulaOperation, { action: 'addSheet', sheetName: 'Sheet' + sheet_1.id, visibleName: sheet_1.name, sheetId: sheet_1.id });
if (!isFromUpdateAction) {
context.setProperties({ activeSheetIndex: sheetIndex + 1 }, true);
}
context.notify(moveOrDuplicateSheet, { refresh: true, isDuplicate: true });
if (action) {
delete args.eventArgs.cancel;
context.trigger('actionComplete', args);
}
}
}
/**
* @param {SheetModel[]} sheets - sheets of spreadsheet
* @param {number} startIndex - index of the sheet to search from
* @param {boolean} isPrevious - if set to `true`, its find the previous visible sheet index
* @returns {number} - return next visible sheet
*/
function getNextPrevVisibleSheetIndex(sheets, startIndex, isPrevious) {
for (var i = startIndex; isPrevious ? i >= 0 : i < sheets.length; isPrevious ? i-- : i++) {
if (!(sheets[i].state === 'Hidden' || sheets[i].state === 'VeryHidden')) {
startIndex = i;
break;
}
}
return startIndex;
}