/*! * * SpreadJS Wrapper Components for Angular 0.0.0 * * Copyright(c) GrapeCity, Inc. All rights reserved. * * Licensed under the SpreadJS Commercial License. * us.sales@grapecity.com * http://www.grapecity.com/licensing/grapecity/ * */ /// 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: ` ` }) 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) { const sheet = this.sheet; sheet.suspendPaint(); sheet.suspendEvent(); const changes = this.changes; for (const changeName in changes) { let newValue = changes[changeName].currentValue; if (newValue === null || newValue === void 0) { continue; } switch (changeName) { case 'width': newValue = parseInt(newValue, 10); sheet.setColumnWidth(this.index as number, newValue); break; case 'visible': sheet.setColumnVisible(this.index as number, newValue); break; case 'resizable': sheet.setColumnResizable(this.index as number, newValue); break; case 'autoFit': if (newValue) { sheet.autoFitColumn(this.index as number); } break; case 'style': sheet.setStyle(-1, this.index as number, newValue); break; case 'headerStyle': sheet.setStyle(-1, this.index as number, newValue, GC.Spread.Sheets.SheetArea.colHeader); break; case 'cellType': sheet.setCellType(-1, this.index as number, newValue); break; case 'formatter': sheet.setFormatter(-1, this.index as number, newValue, GC.Spread.Sheets.SheetArea.viewport); break; } } sheet.resumeEvent(); sheet.resumePaint(); } } ngOnChanges(changes: SimpleChanges) { this.changes = {}; const changesCache = this.changes; for (const changeName in changes) { changesCache[changeName] = changes[changeName]; } this.onColumnChanged(); } } @Component({ selector: 'gc-worksheet', template: ` ` }) export class WorksheetComponent implements OnChanges, AfterViewInit { private sheet: GC.Spread.Sheets.Worksheet; @ContentChildren(ColumnComponent) columns?: QueryList; //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 { const sheet = this.sheet; const columns = (this.columns as QueryList); sheet.suspendPaint(); sheet.suspendEvent(); if (this.dataSource) { sheet.setDataSource(this.dataSource); columns.forEach((columnComponent: ColumnComponent, index: number) => { if (columnComponent.dataField) { sheet.bindColumn(index, { name: columnComponent.dataField, displayName: columnComponent.headerText }); } }); } if (columns.length > 0) { sheet.setColumnCount(columns.length); columns.forEach((columnComponent: ColumnComponent, index: number) => { columnComponent.onAttached(this.sheet, index); }); } sheet.resumeEvent(); sheet.resumePaint(); } public getSheet() { return this.sheet; } ngOnChanges(changes: SimpleChanges) { const sheet = this.sheet; sheet.suspendPaint(); sheet.suspendEvent(); for (const changeName in changes) { const 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 as any)[changeName] = newValue; } } sheet.resumeEvent(); sheet.resumePaint(); } ngAfterViewInit() { (this.columns as QueryList).changes.subscribe(() => { this.onAttached(); }); } ngOnDestroy() { const sheet = this.sheet; const spread = sheet ? sheet.getParent() : null; if (spread) { const sheetIndex = spread.getSheetIndex(sheet.name()); if (sheetIndex !== void 0) { spread.removeSheet(sheetIndex); } } } } @Component({ selector: 'gc-spread-sheets', template: `
` }) 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() allowUserDragMerge?: boolean; @Input() allowUndo?: boolean; @Input() allowSheetReorder?: boolean; @Input() allowContextMenu?: boolean; @Input() allowUserDeselect?: boolean; @Input() allowCopyPasteExcelStyle?: boolean; @Input() allowExtendPasteRange?: boolean; @Input() cutCopyIndicatorVisible?: boolean; @Input() cutCopyIndicatorBorderColor?: string; @Input() copyPasteHeaderOptions?: number; @Input() defaultDragFillType?: number; @Input() enableFormulaTextbox?: boolean; @Input() highlightInvalidData?: boolean; @Input() newTabVisible?: boolean; @Input() tabStripVisible?: boolean; @Input() tabEditable?: boolean; @Input() tabStripRatio?: number; @Input() tabNavigationVisible?: boolean; @Input() autoFitType?: number; @Input() referenceStyle?: number; @Input() backColor?: string; @Input() grayAreaBackColor?: string; @Input() resizeZeroIndicator?: number; @Input() showVerticalScrollbar?: boolean; @Input() showHorizontalScrollbar?: boolean; @Input() scrollbarMaxAlign?: boolean; @Input() scrollIgnoreHidden?: boolean; @Input() hostStyle?: any; // used for get styles form parent host DIV @Input() hostClass?: string; @Input() hideSelection?: boolean; @Input() name?: string; @Input() backgroundImage?: string; @Input() backgroundImageLayout?: number; @Input() showScrollTip?: number; @Input() showResizeTip?: number; @Input() showDragDropTip?: boolean; @Input() showDragFillTip?: boolean; @Input() showDragFillSmartTag?: boolean; @Input() scrollbarShowMax?: boolean; @Input() useTouchLayout?: boolean; //outputs events @Output() workbookInitialized = new EventEmitter(); @Output() validationError = new EventEmitter(); @Output() cellClick = new EventEmitter(); @Output() cellDoubleClick = new EventEmitter(); @Output() enterCell = new EventEmitter(); @Output() leaveCell = new EventEmitter(); @Output() valueChanged = new EventEmitter(); @Output() topRowChanged = new EventEmitter(); @Output() leftColumnChanged = new EventEmitter(); @Output() invalidOperation = new EventEmitter(); @Output() rangeFiltering = new EventEmitter(); @Output() rangeFiltered = new EventEmitter(); @Output() tableFiltering = new EventEmitter(); @Output() tableFiltered = new EventEmitter(); @Output() rangeSorting = new EventEmitter(); @Output() rangeSorted = new EventEmitter(); @Output() clipboardChanging = new EventEmitter(); @Output() clipboardChanged = new EventEmitter(); @Output() clipboardPasting = new EventEmitter(); @Output() clipboardPasted = new EventEmitter(); @Output() columnWidthChanging = new EventEmitter(); @Output() columnWidthChanged = new EventEmitter(); @Output() rowHeightChanging = new EventEmitter(); @Output() rowHeightChanged = new EventEmitter(); @Output() dragDropBlock = new EventEmitter(); @Output() dragDropBlockCompleted = new EventEmitter(); @Output() dragFillBlock = new EventEmitter(); @Output() dragFillBlockCompleted = new EventEmitter(); @Output() editStarting = new EventEmitter(); @Output() editChange = new EventEmitter(); @Output() editEnding = new EventEmitter(); @Output() editEnd = new EventEmitter(); @Output() editEnded = new EventEmitter(); @Output() rangeGroupStateChanging = new EventEmitter(); @Output() rangeGroupStateChanged = new EventEmitter(); @Output() selectionChanging = new EventEmitter(); @Output() selectionChanged = new EventEmitter(); @Output() sheetTabClick = new EventEmitter(); @Output() sheetTabDoubleClick = new EventEmitter(); @Output() sheetNameChanging = new EventEmitter(); @Output() sheetNameChanged = new EventEmitter(); @Output() userZooming = new EventEmitter(); @Output() userFormulaEntered = new EventEmitter(); @Output() cellChanged = new EventEmitter(); @Output() columnChanged = new EventEmitter(); @Output() rowChanged = new EventEmitter(); @Output() activeSheetChanging = new EventEmitter(); @Output() activeSheetChanged = new EventEmitter(); @Output() sparklineChanged = new EventEmitter(); @Output() rangeChanged = new EventEmitter(); @Output() buttonClicked = new EventEmitter(); @Output() editorStatusChanged = new EventEmitter(); @Output() floatingObjectChanged = new EventEmitter(); @Output() floatingObjectSelectionChanged = new EventEmitter(); @Output() pictureChanged = new EventEmitter(); @Output() floatingObjectRemoving = new EventEmitter(); @Output() floatingObjectRemoved = new EventEmitter(); @Output() pictureSelectionChanged = new EventEmitter(); @Output() floatingObjectLoaded = new EventEmitter(); @Output() touchToolStripOpening = new EventEmitter(); @Output() commentChanged = new EventEmitter(); @Output() commentRemoving = new EventEmitter(); @Output() commentRemoved = new EventEmitter(); @Output() slicerChanged = new EventEmitter(); @ContentChildren(WorksheetComponent) sheets?: QueryList; constructor(@Inject(ElementRef) elRef: ElementRef) { this.elRef = elRef; } ngAfterViewInit() { const elRef = this.elRef; const dom = elRef.nativeElement as HTMLElement; const hostElement = dom.querySelector('div'); this.spread = new GC.Spread.Sheets.Workbook(hostElement, { sheetCount: 0 }); this.setSpreadOptions(); this.initSheets(); (this.sheets as QueryList).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) { const spread = (this.spread as GC.Spread.Sheets.Workbook); spread.suspendPaint(); if (sheetComponents) { sheetComponents.forEach((sheetComponent: WorksheetComponent, index: number) => { const sheet = sheetComponent.getSheet(); if (sheet && !sheet.getParent()) { spread.addSheet(index, sheetComponent.getSheet()); sheetComponent.onAttached(); } }); } spread.resumePaint(); } private initSheets() { const sheets = this.sheets as QueryList; const spread = this.spread as GC.Spread.Sheets.Workbook; 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) { spread.addSheet(0, new GC.Spread.Sheets.Worksheet('')); } } private bindCustomEvent(spread: GC.Spread.Sheets.Workbook) { const customEventNameSpace = '.ng'; const 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) => { const eventType = event.type; const camelCaseEvent = eventType[0].toLowerCase() + eventType.substr(1); (this as any)[camelCaseEvent].emit(data); }); }); } setSpreadOptions() { const spread = this.spread as GC.Spread.Sheets.Workbook; if (!this.spread) { return; } spread.suspendEvent(); spread.suspendPaint(); const options = this.spreadOptions; options && options.forEach((option) => { if (option.name === 'name') { spread.name = option.value; } else { (spread.options as any)[option.name] = option.value; } }); spread.resumePaint(); spread.resumeEvent(); } ngOnChanges(changes: SimpleChanges) { const options = []; for (const changeName in changes) { const 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 as GC.Spread.Sheets.Workbook).destroy(); } } @NgModule({ imports: [CommonModule], declarations: [SpreadSheetsComponent, WorksheetComponent, ColumnComponent], exports: [SpreadSheetsComponent, WorksheetComponent, ColumnComponent] }) export class SpreadSheetsModule { }