///<reference path="./GC.Spread.Sheets.d.ts" /> import { Component, Input, OnChanges, SimpleChanges, AfterViewInit, QueryList, ContentChildren, OnDestroy, Output, EventEmitter, ElementRef, Inject, NgModule } from '@angular/core'; import { CommonModule } from '@angular/common'; @Component({ selector: 'gc-column', template: ` <ng-content></ng-content> ` }) export class ColumnComponent implements OnChanges { private changes: any = {}; private sheet: GC.Spread.Sheets.Worksheet; private index: number; //indicate all inputs @Input() width: number; @Input() dataField: string; @Input() headerText: string; @Input() visible: boolean; @Input() resizable: boolean; @Input() autoFit: boolean; @Input() style: GC.Spread.Sheets.Style; @Input() cellType: GC.Spread.Sheets.CellTypes.Base; @Input() headerStyle: GC.Spread.Sheets.Style; @Input() formatter: any; public onAttached(sheet: GC.Spread.Sheets.Worksheet, index: number): void { this.sheet = sheet; this.index = index; this.onColumnChanged(); } private onColumnChanged() { if (this.sheet) { let sheet = this.sheet; sheet.suspendPaint(); sheet.suspendEvent(); let changes = this.changes; for (let changeName in changes) { let newValue = changes[changeName].currentValue; if (newValue === null || newValue === void 0) { continue; } switch (changeName) { case 'width': sheet.setColumnWidth(this.index, newValue); break; case 'visible': sheet.setColumnVisible(this.index, newValue); break; case 'resizable': sheet.setColumnResizable(this.index, newValue); break; case 'autoFit': if (newValue) { sheet.autoFitColumn(this.index); } break; case 'style': sheet.setStyle(-1, this.index, newValue); break; case 'headerStyle': sheet.setStyle(-1, this.index, newValue, GC.Spread.Sheets.SheetArea.colHeader); break; case 'cellType': sheet.setCellType(-1, this.index, newValue); break; case 'formatter': sheet.setFormatter(-1, this.index, newValue, GC.Spread.Sheets.SheetArea.viewport); break; } } sheet.resumeEvent(); sheet.resumePaint(); } } ngOnChanges(changes: SimpleChanges) { this.changes = {}; let changesCache = this.changes; for (let changeName in changes) { changesCache[changeName] = changes[changeName]; } this.onColumnChanged(); } } @Component({ selector: 'gc-worksheet', template: ` <ng-content></ng-content> ` }) export class WorksheetComponent implements OnChanges, AfterViewInit { private sheet: GC.Spread.Sheets.Worksheet; @ContentChildren(ColumnComponent) columns: QueryList<ColumnComponent>; //indicate all inputs @Input() rowCount: number; @Input() colCount: number; @Input() dataSource: any; @Input() name: string; @Input() frozenColumnCount: number; @Input() frozenRowCount: number; @Input() frozenTrailingRowCount: number; @Input() frozenTrailingColumnCount: number; @Input() allowCellOverflow: boolean; @Input() frozenlineColor: string; @Input() sheetTabColor: string; @Input() selectionPolicy: number; @Input() selectionUnit: number; @Input() zoom: number; @Input() currentTheme: string; @Input() clipBoardOptions: number; @Input() rowHeaderVisible: boolean; @Input() colHeaderVisible: boolean; @Input() rowHeaderAutoText: number; @Input() colHeaderAutoText: number; @Input() rowHeaderAutoTextIndex: number; @Input() colHeaderAutoTextIndex: number; @Input() isProtected: boolean; @Input() showRowOutline: boolean; @Input() showColumnOutline: boolean; @Input() selectionBackColor: string; @Input() selectionBorderColor: string; @Input() defaultStyle: GC.Spread.Sheets.Style; @Input() rowOutlineInfo: any[]; @Input() columnOutlineInfo: any[]; @Input() autoGenerateColumns: boolean; constructor() { this.sheet = new GC.Spread.Sheets.Worksheet(""); } public onAttached(): void { let sheet = this.sheet; sheet.suspendPaint(); sheet.suspendEvent(); if (this.dataSource) { sheet.setDataSource(this.dataSource); this.columns.forEach((columnComponent: ColumnComponent, index: number) => { if (columnComponent.dataField) { sheet.bindColumn(index, { name: columnComponent.dataField, displayName: columnComponent.headerText }); } }); } if (this.columns.length > 0) { sheet.setColumnCount(this.columns.length); this.columns.forEach((columnComponent: ColumnComponent, index: number) => { columnComponent.onAttached(this.sheet, index); }); } sheet.resumeEvent(); sheet.resumePaint(); } public getSheet() { return this.sheet; } ngOnChanges(changes: SimpleChanges) { let sheet = this.sheet; sheet.suspendPaint(); sheet.suspendEvent(); for (let changeName in changes) { let newValue = changes[changeName].currentValue; if (newValue === null || newValue === void 0) { continue; } switch (changeName) { case "rowCount": sheet.setRowCount(newValue); break; case "colCount": sheet.setColumnCount(newValue); break; case "name": sheet.name(newValue); break; case "frozenColumnCount": sheet.frozenColumnCount(newValue); break; case "frozenRowCount": sheet.frozenRowCount(newValue); break; case "frozenTrailingRowCount": sheet.frozenTrailingRowCount(newValue); break; case "frozenTrailingColumnCount": sheet.frozenTrailingColumnCount(newValue); break; case "selectionPolicy": sheet.selectionPolicy(newValue); break; case "selectionUnit": sheet.selectionUnit(newValue); break; case "zoom": sheet.zoom(newValue); break; case "currentTheme": sheet.currentTheme(newValue); break; case "defaultStyle": sheet.setDefaultStyle(newValue); break; case "rowOutlineInfo": newValue.forEach((item: any) => { sheet.rowOutlines.group(item.index, item.count); }); sheet.repaint(); break; case "columnOutlineInfo": newValue.forEach((item: any) => { sheet.columnOutlines.group(item.index, item.count); }); sheet.repaint(); break; case "showRowOutline": sheet.showRowOutline(newValue); break; case "showColumnOutline": sheet.showColumnOutline(newValue); break; case "dataSource": sheet.setDataSource(newValue); break; case "autoGenerateColumns": sheet[changeName] = newValue; default: sheet.options[changeName] = newValue; } } sheet.resumeEvent(); sheet.resumePaint(); } ngAfterViewInit() { this.columns.changes.subscribe(() => { this.onAttached() }); } ngOnDestroy() { let sheet = this.sheet; let spread = sheet ? sheet.getParent() : null; if (spread) { let sheetIndex = spread.getSheetIndex(sheet.name()); if (sheetIndex !== void 0) { spread.removeSheet(sheetIndex); } } } } @Component({ selector: 'gc-spread-sheets', template: ` <div [ngStyle]="style" [ngClass]="hostClass"> <ng-content></ng-content> </div> ` }) export class SpreadSheetsComponent implements OnChanges, AfterViewInit, OnDestroy { private elRef: ElementRef; private spread: GC.Spread.Sheets.Workbook; private spreadOptions: any[]; style = { width: '800px', height: '600px' }; // indicate all options @Input() allowUserResize: boolean; @Input() allowUserZoom: boolean; @Input() allowUserEditFormula: boolean; @Input() allowUserDragFill: boolean; @Input() allowUserDragDrop: boolean; @Input() highlightInvalidData: boolean; @Input() newTabVisible: boolean; @Input() tabStripVisible: boolean; @Input() tabEditable: boolean; @Input() autoFitType: number; @Input() referenceStyle: number; @Input() backColor: string; @Input() grayAreaBackColor: string; @Input() showVerticalScrollbar: boolean; @Input() showHorizontalScrollbar: boolean; @Input() hostStyle: any; // used for get styles form parent host DIV @Input() hostClass: string; @Input() name: string; @Input() backgroundImage: string; @Input() backgroundImageLayout: number; @Input() showScrollTip: number; @Input() showResizeTip: number; @Input() showDragDropTip: boolean; @Input() showDragFillTip: boolean; //outputs events @Output() workbookInitialized = new EventEmitter<any>(); @Output() validationError = new EventEmitter<any>(); @Output() cellClick = new EventEmitter<any>(); @Output() cellDoubleClick = new EventEmitter<any>(); @Output() enterCell = new EventEmitter<any>(); @Output() leaveCell = new EventEmitter<any>(); @Output() valueChanged = new EventEmitter<any>(); @Output() topRowChanged = new EventEmitter<any>(); @Output() leftColumnChanged = new EventEmitter<any>(); @Output() invalidOperation = new EventEmitter<any>(); @Output() rangeFiltering = new EventEmitter<any>(); @Output() rangeFiltered = new EventEmitter<any>(); @Output() tableFiltering = new EventEmitter<any>(); @Output() tableFiltered = new EventEmitter<any>(); @Output() rangeSorting = new EventEmitter<any>(); @Output() rangeSorted = new EventEmitter<any>(); @Output() clipboardChanging = new EventEmitter<any>(); @Output() clipboardChanged = new EventEmitter<any>(); @Output() clipboardPasting = new EventEmitter<any>(); @Output() clipboardPasted = new EventEmitter<any>(); @Output() columnWidthChanging = new EventEmitter<any>(); @Output() columnWidthChanged = new EventEmitter<any>(); @Output() rowHeightChanging = new EventEmitter<any>(); @Output() rowHeightChanged = new EventEmitter<any>(); @Output() dragDropBlock = new EventEmitter<any>(); @Output() dragDropBlockCompleted = new EventEmitter<any>(); @Output() dragFillBlock = new EventEmitter<any>(); @Output() dragFillBlockCompleted = new EventEmitter<any>(); @Output() editStarting = new EventEmitter<any>(); @Output() editChange = new EventEmitter<any>(); @Output() editEnding = new EventEmitter<any>(); @Output() editEnd = new EventEmitter<any>(); @Output() editEnded = new EventEmitter<any>(); @Output() rangeGroupStateChanging = new EventEmitter<any>(); @Output() rangeGroupStateChanged = new EventEmitter<any>(); @Output() selectionChanging = new EventEmitter<any>(); @Output() selectionChanged = new EventEmitter<any>(); @Output() sheetTabClick = new EventEmitter<any>(); @Output() sheetTabDoubleClick = new EventEmitter<any>(); @Output() sheetNameChanging = new EventEmitter<any>(); @Output() sheetNameChanged = new EventEmitter<any>(); @Output() userZooming = new EventEmitter<any>(); @Output() userFormulaEntered = new EventEmitter<any>(); @Output() cellChanged = new EventEmitter<any>(); @Output() columnChanged = new EventEmitter<any>(); @Output() rowChanged = new EventEmitter<any>(); @Output() activeSheetChanging = new EventEmitter<any>(); @Output() activeSheetChanged = new EventEmitter<any>(); @Output() sparklineChanged = new EventEmitter<any>(); @Output() rangeChanged = new EventEmitter<any>(); @Output() buttonClicked = new EventEmitter<any>(); @Output() editorStatusChanged = new EventEmitter<any>(); @Output() floatingObjectChanged = new EventEmitter<any>(); @Output() floatingObjectSelectionChanged = new EventEmitter<any>(); @Output() pictureChanged = new EventEmitter<any>(); @Output() floatingObjectRemoving = new EventEmitter<any>(); @Output() floatingObjectRemoved = new EventEmitter<any>(); @Output() pictureSelectionChanged = new EventEmitter<any>(); @Output() floatingObjectLoaded = new EventEmitter<any>(); @Output() touchToolStripOpening = new EventEmitter<any>(); @Output() commentChanged = new EventEmitter<any>(); @Output() commentRemoving = new EventEmitter<any>(); @Output() commentRemoved = new EventEmitter<any>(); @Output() slicerChanged = new EventEmitter<any>(); @ContentChildren(WorksheetComponent) sheets: QueryList<WorksheetComponent>; constructor(@Inject(ElementRef) elRef: ElementRef) { this.elRef = elRef; } ngAfterViewInit() { let elRef = this.elRef; let dom = <HTMLElement>elRef.nativeElement; let hostElement = dom.querySelector('div'); this.spread = new GC.Spread.Sheets.Workbook(hostElement, { sheetCount: 0 }); this.setSpreadOptions(); this.initSheets(); this.sheets.changes.subscribe((changes) => { this.onSheetsChanged(changes) }) // may change sheets using bingidng. this.bindCustomEvent(this.spread); this.workbookInitialized.emit({ spread: this.spread }); } private onSheetsChanged(sheetComponents: QueryList<WorksheetComponent>) { let spread = this.spread; spread.suspendPaint(); if (sheetComponents) { sheetComponents.forEach((sheetComponent: WorksheetComponent, index: number) => { let sheet = sheetComponent.getSheet(); if (sheet && !sheet.getParent()) { spread.addSheet(index, sheetComponent.getSheet()); sheetComponent.onAttached(); } }); } spread.resumePaint(); } private initSheets() { let sheets = this.sheets; let spread = this.spread; spread.clearSheets(); sheets.forEach((sheetComponent, index) => { spread.addSheet(index, sheetComponent.getSheet()); sheetComponent.onAttached(); }); // when there is no sheet, add default sheet to spread if (sheets.length === 0) { this.spread.addSheet(0, new GC.Spread.Sheets.Worksheet("")); } } private bindCustomEvent(spread: GC.Spread.Sheets.Workbook) { let customEventNameSpace = '.ng'; let events = ['ValidationError', 'CellClick', 'CellDoubleClick', 'EnterCell', 'LeaveCell', 'ValueChanged', 'TopRowChanged', 'LeftColumnChanged', 'InvalidOperation', 'RangeFiltering', 'RangeFiltered', 'TableFiltering', 'TableFiltered', 'RangeSorting', 'RangeSorted', 'ClipboardChanging', 'ClipboardChanged', 'ClipboardPasting', 'ClipboardPasted', 'ColumnWidthChanging', 'ColumnWidthChanged', 'RowHeightChanging', 'RowHeightChanged', 'DragDropBlock', 'DragDropBlockCompleted', 'DragFillBlock', 'DragFillBlockCompleted', 'EditStarting', 'EditChange', 'EditEnding', 'EditEnd', 'EditEnded', 'RangeGroupStateChanging', 'RangeGroupStateChanged', 'SelectionChanging', 'SelectionChanged', 'SheetTabClick', 'SheetTabDoubleClick', 'SheetNameChanging', 'SheetNameChanged', 'UserZooming', 'UserFormulaEntered', 'CellChanged', 'ColumnChanged', 'RowChanged', 'ActiveSheetChanging', 'ActiveSheetChanged', 'SparklineChanged', 'RangeChanged', 'ButtonClicked', 'EditorStatusChanged', 'FloatingObjectChanged', 'FloatingObjectSelectionChanged', 'PictureChanged', 'FloatingObjectRemoving', 'FloatingObjectRemoved', 'PictureSelectionChanged', 'FloatingObjectLoaded', 'TouchToolStripOpening', 'CommentChanged', 'CommentRemoving', 'CommentRemoved', 'SlicerChanged']; events.forEach((event) => { spread.bind(event + customEventNameSpace, (event: any, data: any) => { let eventType = event.type; let camelCaseEvent = eventType[0].toLowerCase() + eventType.substr(1); this[camelCaseEvent].emit(data); }); }); } setSpreadOptions() { let spread = this.spread; if (!this.spread) { return; } spread.suspendEvent(); spread.suspendPaint(); let options = this.spreadOptions; options && options.forEach((option) => { if (option.name === 'name') { spread.name = option.value; } else { spread.options[option.name] = option.value; } }); spread.resumePaint(); spread.resumeEvent(); } ngOnChanges(changes: SimpleChanges) { let options = []; for (let changeName in changes) { let newValue = changes[changeName].currentValue; if (newValue !== null && newValue !== void 0) { switch (changeName) { case 'hostStyle': this.style = newValue; break; case 'hostClass': break; default: options.push({ name: changeName, value: newValue }); } } } this.spreadOptions = options; this.setSpreadOptions(); } ngOnDestroy() { this.spread.destroy(); } } @NgModule({ imports: [CommonModule], declarations: [SpreadSheetsComponent, WorksheetComponent, ColumnComponent], exports: [SpreadSheetsComponent, WorksheetComponent, ColumnComponent] }) export class SpreadSheetsModule { }