@helveg/ngx-spreadsheet
Version:
Lightweight spreadsheet module for Angular
1 lines • 71.5 kB
Source Map (JSON)
{"version":3,"file":"helveg-ngx-spreadsheet.mjs","sources":["../../../projects/ngx-spreadsheet/src/lib/model/cell.ts","../../../projects/ngx-spreadsheet/src/lib/header-index-generator.ts","../../../projects/ngx-spreadsheet/src/lib/id-generator.ts","../../../projects/ngx-spreadsheet/src/lib/providers.ts","../../../projects/ngx-spreadsheet/src/lib/model/table.ts","../../../projects/ngx-spreadsheet/src/lib/csv-converter.ts","../../../projects/ngx-spreadsheet/src/lib/model/anchor.ts","../../../projects/ngx-spreadsheet/src/lib/model/range.ts","../../../projects/ngx-spreadsheet/src/lib/ngx-context-menu-item.component.ts","../../../projects/ngx-spreadsheet/src/lib/ngx-context-menu.component.ts","../../../projects/ngx-spreadsheet/src/lib/ngx-context-menu.component.html","../../../projects/ngx-spreadsheet/src/lib/content-editable.directive.ts","../../../projects/ngx-spreadsheet/src/lib/ngx-spreadsheet.component.ts","../../../projects/ngx-spreadsheet/src/lib/ngx-spreadsheet.component.html","../../../projects/ngx-spreadsheet/src/lib/ngx-spreadsheet.module.ts","../../../projects/ngx-spreadsheet/src/public-api.ts","../../../projects/ngx-spreadsheet/src/helveg-ngx-spreadsheet.ts"],"sourcesContent":["export class Cell {\n public id: string;\n constructor(\n public tableId: string,\n public row: number,\n public col: number,\n public value: string,\n public editable: boolean = false,\n ) {\n this.id = `${tableId}-${row}-${col}`;\n }\n\n public withRow(index: number): Cell {\n return new Cell(this.tableId, index, this.col, this.value, this.editable);\n }\n\n public withCol(index: number): Cell {\n return new Cell(this.tableId, this.row, index, this.value, this.editable);\n }\n}\n","const CHARS = [\n 'A',\n 'B',\n 'C',\n 'D',\n 'E',\n 'F',\n 'G',\n 'H',\n 'I',\n 'J',\n 'K',\n 'L',\n 'M',\n 'N',\n 'O',\n 'P',\n 'Q',\n 'R',\n 'S',\n 'T',\n 'U',\n 'V',\n 'W',\n 'X',\n 'Y',\n 'Z',\n];\nconst LENGTH = CHARS.length;\n\nexport const generateHeader = (index: number): string => {\n index -= 1;\n const remain = Math.floor(index / LENGTH);\n return remain > 0\n ? generateHeader(remain) + CHARS[index % LENGTH]\n : CHARS[index % LENGTH];\n};\n","const CHARS = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';\nconst LENGTH = CHARS.length;\n\nexport const generateId = (): string =>\n new Array(8)\n .fill(null)\n .map(() => CHARS.charAt(Math.floor(Math.random() * LENGTH)))\n .join('');\n","import { InjectionToken } from '@angular/core';\n\nexport const NSS_DEFAULT_ROWS = new InjectionToken<number>(\n 'NgxSpreadSheetDefaultRows',\n);\nexport const NSS_DEFAULT_COLS = new InjectionToken<number>(\n 'NgxSpreadSheetDefaultRows',\n);\n\nexport interface SpreadsheetIntl {\n INSERT_COLUMN_LEFT: string;\n INSERT_COLUMN_RIGHT: string;\n DELETE_COLUMN: string;\n DELETE_ROW: string;\n INSERT_ROW_BELOW: string;\n INSERT_ROW_ABOVE: string;\n}\n\nexport const NSS_I18N = new InjectionToken<SpreadsheetIntl>(\n 'NgxSpreadSheetInternationalization',\n);\n","import { Cell } from './cell';\nimport { generateHeader } from '../header-index-generator';\nimport { generateId } from '../id-generator';\nimport { inject, InjectionToken } from '@angular/core';\nimport { NSS_DEFAULT_COLS, NSS_DEFAULT_ROWS } from '../providers';\nimport type { DeepMergeLeafURI } from 'deepmerge-ts';\nimport { deepmergeCustom } from 'deepmerge-ts';\n\nconst noArrayDeepMerge = deepmergeCustom<{\n DeepMergeArraysURI: DeepMergeLeafURI;\n}>({\n mergeArrays: false,\n});\n\nexport interface ColumnOptions {\n header?: string;\n width?: number;\n}\n\nexport interface TableOptions {\n rows?: number;\n cols?: number;\n data?: any[][];\n columns?: ColumnOptions[];\n canInsertRows?: boolean;\n canInsertCols?: boolean;\n}\n\nexport type SettableTableOptions = keyof Table & keyof TableOptions;\n\nfunction getDefault<\n T extends InjectionToken<unknown>,\n K = T extends InjectionToken<infer K> ? K : never,\n>(token: T, defaultValue: K): K {\n try {\n return inject<K>(token, { optional: true }) ?? defaultValue;\n } catch (err) {\n console.warn(\n `You are creating a spreadsheet table outside of any injection context. ` +\n `Any configuration you have provided for ${token} can't be retrieved and ` +\n `the default value '${defaultValue}' will be used.`,\n );\n }\n return defaultValue;\n}\n\nexport class Table {\n private constructor(\n public readonly id: string,\n public head: string[],\n public body: Cell[][],\n public canInsertRows: boolean,\n public canInsertCols: boolean,\n protected options: TableOptions,\n ) {}\n\n public get data(): any[][] {\n return this.body.map((row) => row.map((cell) => cell.value));\n }\n\n public get editing(): boolean {\n return this.body.some((r) => r.some((c) => c.editable));\n }\n\n public recreate(options: TableOptions) {\n return Table.create(noArrayDeepMerge({}, this.options, options));\n }\n\n public static create(options: TableOptions) {\n options = noArrayDeepMerge({}, options);\n const tableId = generateId();\n const rows =\n options.data?.length ?? options.rows ?? getDefault(NSS_DEFAULT_ROWS, 10);\n const cols =\n options.data?.[0]?.length ??\n options.cols ??\n options.columns?.length ??\n getDefault(NSS_DEFAULT_COLS, 5);\n const emptyRow = Array(cols).fill(undefined);\n const head = emptyRow.map(\n (v, c) => options.columns?.[c]?.header ?? generateHeader(c + 1),\n );\n const body = Array(rows)\n .fill(undefined)\n .map((v, r) =>\n emptyRow.map(\n (v, c) => new Cell(tableId, r, c, options.data?.[r]?.[c] ?? ''),\n ),\n );\n return new Table(\n tableId,\n head,\n body,\n options.canInsertRows ?? true,\n options.canInsertCols ?? true,\n options,\n );\n }\n\n public findCell(row: number, col: number): Cell | null {\n for (const record of this.body) {\n for (const field of record) {\n if (field.row === row && field.col === col) {\n return field;\n }\n }\n }\n return null;\n }\n\n public findOrCreateCell(row: number, col: number): Cell | null {\n for (const record of this.body) {\n for (const field of record) {\n if (field.row === row && field.col === col) {\n return field;\n }\n }\n }\n const resize: { rows?: number; cols?: number } = {};\n if (this.rowCount <= row) {\n if (!this.canInsertRows) return null;\n resize.rows = row + 1;\n }\n if (this.colCount <= col) {\n if (!this.canInsertCols) return null;\n resize.cols = col + 1;\n }\n this.resize(resize);\n const cell = this.findCell(row, col);\n if (!cell) {\n throw new Error(\n `Unknown table error, could not find or create (${row}, ${col})`,\n );\n }\n return cell;\n }\n\n public insertColumn(colIndex: number): void {\n {\n const remains = this.head.slice(0, colIndex);\n const updates = Array(this.head.length - colIndex + 1)\n .fill('')\n .map((v, c) => generateHeader(c + 1 + colIndex));\n this.head = [...remains, ...updates];\n }\n {\n const body = [];\n for (let r = 0; r < this.body.length; r++) {\n const row = this.body[r];\n const above = row.slice(0, colIndex);\n const present = new Cell(this.id, r, colIndex, '');\n const below = row\n .slice(colIndex)\n .map((cell) => cell.withCol(cell.col + 1));\n const newRow = [...above, present, ...below];\n body.push(newRow);\n }\n this.body = body;\n }\n }\n\n public deleteColumn(colIndex: number): void {\n {\n const remains = this.head.slice(0, colIndex);\n const updates = this.head\n .slice(colIndex + 1)\n .map((v, c) => generateHeader(c + 1 + colIndex));\n this.head = [...remains, ...updates];\n }\n {\n const body = [];\n for (let r = 0; r < this.body.length; r++) {\n const row = this.body[r];\n const above = row.slice(0, colIndex);\n const below = row\n .slice(colIndex + 1)\n .map((cell) => cell.withCol(cell.col + 1));\n const newRow = [...above, ...below];\n body.push(newRow);\n }\n this.body = body;\n }\n }\n\n public insertRow(rowIndex: number): void {\n const above = this.body.slice(0, rowIndex);\n const present = Array(this.colCount)\n .fill('')\n .map((v, c) => new Cell(this.id, rowIndex, c, ''));\n const below = this.body\n .slice(rowIndex)\n .map((row) => row.map((cell) => cell.withRow(cell.row + 1)));\n this.body = [...above, present, ...below];\n }\n\n public deleteRow(rowIndex: number): void {\n const above = this.body.slice(0, rowIndex);\n const below = this.body\n .slice(rowIndex + 1)\n .map((row) => row.map((cell) => cell.withRow(cell.row + 1)));\n this.body = [...above, ...below];\n }\n\n public get rowCount(): number {\n return this.body.length;\n }\n\n public get colCount(): number {\n return this.head.length;\n }\n\n resize({ rows, cols }: { rows?: number; cols?: number }) {\n if (rows !== undefined) {\n while (this.rowCount < rows) {\n this.insertRow(this.rowCount);\n }\n }\n if (cols !== undefined) {\n while (this.colCount < cols) {\n this.insertColumn(this.colCount);\n }\n }\n }\n\n setOption<K extends keyof this & keyof TableOptions>(\n attr: K,\n value: this[K],\n ) {\n this.options[attr] = value;\n this[attr] = value;\n }\n}\n","const DELIMITER = '\\t';\nconst PARSE_PATTERN = new RegExp(\n '(\\\\' +\n DELIMITER +\n '|\\\\r?\\\\n|\\\\r|^)' +\n '(?:\"([^\"]*(?:\"\"[^\"]*)*)\"|' +\n '([^\"\\\\' +\n DELIMITER +\n '\\\\r\\\\n]*))',\n 'gi',\n);\n\nexport const csvToArray = (strData: string): string[][] => {\n if (strData.endsWith('\\r\\n')) {\n strData = strData.slice(0, strData.length - 2);\n }\n const arrData: string[][] = [[]];\n let arrMatches = null;\n while ((arrMatches = PARSE_PATTERN.exec(strData))) {\n const strMatchedDelimiter = arrMatches[1];\n if (strMatchedDelimiter.length && strMatchedDelimiter != DELIMITER) {\n arrData.push([]);\n }\n\n const strMatchedValue = arrMatches[2]\n ? arrMatches[2].replace(new RegExp('\"\"', 'g'), '\"')\n : arrMatches[3];\n\n arrData[arrData.length - 1].push(strMatchedValue);\n }\n return arrData;\n};\n","export class Anchor {\n constructor(\n public r: number,\n public c: number,\n ) {}\n}\n","import { Anchor } from './anchor';\n\nexport class Range {\n constructor(\n public r1: number,\n public c1: number,\n public r2: number,\n public c2: number,\n ) {}\n\n public calc(row: number, col: number): void {\n if (row < this.r1) {\n this.r1 = row;\n }\n if (row > this.r2) {\n this.r2 = row;\n }\n if (col < this.c1) {\n this.c1 = col;\n }\n if (col > this.c2) {\n this.c2 = col;\n }\n }\n\n public includes(row: number, col: number): boolean {\n return row >= this.r1 && row <= this.r2 && col >= this.c1 && col <= this.c2;\n }\n\n public equals(range: Range) {\n return (\n this.r1 === range.r1 &&\n this.c1 === range.c1 &&\n this.r2 === range.r2 &&\n this.c2 === range.c2\n );\n }\n\n public static of(\n row: number,\n col: number,\n row2: number = row,\n col2: number = col,\n ): Range {\n return new Range(row, col, row2, col2);\n }\n\n public static marge(a1: Anchor, a2: Anchor): Range {\n const r1 = a1.r < a2.r ? a1.r : a2.r;\n const r2 = a1.r > a2.r ? a1.r : a2.r;\n const c1 = a1.c < a2.c ? a1.c : a2.c;\n const c2 = a1.c > a2.c ? a1.c : a2.c;\n return new Range(r1, c1, r2, c2);\n }\n}\n","import { Component, EventEmitter, Input, Output } from '@angular/core';\n\n@Component({\n selector: 'ngx-context-menu-item',\n template: ''\n})\nexport class NgxContextMenuItemComponent {\n @Input()\n label?: string;\n @Input()\n disabled?: boolean;\n @Input()\n divider?: boolean;\n @Output()\n click = new EventEmitter<number>();\n\n clicked(index: number) {\n if (!this.disabled) {\n this.click.emit(index);\n }\n }\n}\n","import {\n Component,\n ContentChildren,\n ElementRef,\n EventEmitter,\n HostListener,\n Output,\n QueryList,\n ViewChild,\n} from '@angular/core';\nimport { NgxContextMenuItemComponent } from './ngx-context-menu-item.component';\n\n@Component({\n selector: 'ngx-context-menu',\n templateUrl: './ngx-context-menu.component.html',\n styleUrls: ['./ngx-context-menu.component.scss'],\n})\nexport class NgxContextMenuComponent {\n @ViewChild('menu', { static: true })\n menuElementRef!: ElementRef<HTMLElement>;\n\n @ContentChildren(NgxContextMenuItemComponent)\n itemTemplates!: QueryList<NgxContextMenuItemComponent>;\n\n @Output()\n closed = new EventEmitter();\n\n target: number = -1;\n\n public show(ev: MouseEvent, index: number): void {\n this.target = index;\n this.menuElement.style.display = 'flex';\n\n const menuTop =\n ev.clientY + this.menuHeight > this.documentHeight\n ? ev.pageY - this.menuHeight\n : ev.pageY;\n const menuLeft =\n ev.clientX + this.menuWidth > this.documentWidth\n ? ev.pageX - this.menuWidth\n : ev.pageX;\n this.menuElement.style.top = `${menuTop}px`;\n this.menuElement.style.left = `${menuLeft}px`;\n }\n\n @HostListener('document:click', ['$event'])\n click(): void {\n this.menuElement.style.display = 'none';\n this.closed.emit();\n }\n\n private get menuElement(): HTMLElement {\n return this.menuElementRef.nativeElement;\n }\n\n private get menuStyle(): CSSStyleDeclaration {\n return getComputedStyle(this.menuElement);\n }\n\n private get menuWidth(): number {\n return (\n this.menuElement.offsetWidth +\n parseInt(this.menuStyle.marginLeft) +\n parseInt(this.menuStyle.marginRight) +\n parseInt(this.menuStyle.paddingLeft) +\n parseInt(this.menuStyle.paddingRight)\n );\n }\n\n private get menuHeight(): number {\n return (\n this.menuElement.offsetHeight +\n parseInt(this.menuStyle.marginTop) +\n parseInt(this.menuStyle.marginBottom) +\n parseInt(this.menuStyle.paddingTop) +\n parseInt(this.menuStyle.paddingBottom)\n );\n }\n\n private get documentWidth(): number {\n return document.documentElement.clientWidth;\n }\n\n private get documentHeight(): number {\n return document.documentElement.clientHeight;\n }\n}\n","<div #menu class=\"menu\">\n <ng-container *ngFor=\"let item of itemTemplates\">\n <div class=\"item\" *ngIf=\"!item.divider; else divider\" (click)=\"item.clicked(target)\"\n [class.disabled]=\"item.disabled\">\n {{item.label}}\n </div>\n <ng-template #divider>\n <div class=\"divider\"></div>\n </ng-template>\n </ng-container>\n</div>","import {\n Directive,\n ElementRef,\n EventEmitter,\n HostListener,\n Input,\n Output,\n} from '@angular/core';\n\n@Directive({\n selector: '[nssContentEditable]',\n})\nexport class ContentEditableDirective {\n @Input()\n set content(value: string) {\n this.element.innerText = value || '';\n }\n @Output()\n contentChange = new EventEmitter<string>();\n\n constructor(private elementRef: ElementRef<HTMLElement>) {\n this.element.tabIndex = 0;\n }\n\n @HostListener('blur', ['$event.target.value'])\n blur() {\n this.contentChange.emit(this.element.innerText);\n }\n\n get element(): HTMLElement {\n return this.elementRef.nativeElement as HTMLElement;\n }\n}\n","import {\n Component,\n EventEmitter,\n HostListener,\n inject,\n Injector,\n Input,\n Output,\n runInInjectionContext,\n ViewChild,\n} from '@angular/core';\nimport { NgxContextMenuComponent } from './ngx-context-menu.component';\nimport { Subjectize } from 'subjectize';\nimport { merge, Observable, ReplaySubject } from 'rxjs';\nimport { distinctUntilChanged, map, scan } from 'rxjs/operators';\nimport { csvToArray } from './csv-converter';\nimport { Anchor, Cell, Range, Table } from './model';\nimport { ColumnOptions, SettableTableOptions } from './model/table';\nimport { NSS_I18N } from './providers';\nimport { deepmerge } from 'deepmerge-ts';\n\nfunction setPipe<K extends SettableTableOptions>(\n obs$: Observable<Table[K]>,\n attr: K,\n) {\n return obs$.pipe(\n map((value: Table[K]) => (table: Table) => {\n table.setOption(attr, value);\n return table;\n }),\n );\n}\n\n@Component({\n selector: 'ngx-spreadsheet',\n templateUrl: './ngx-spreadsheet.component.html',\n styleUrls: ['./ngx-spreadsheet.component.scss'],\n})\nexport class NgxSpreadsheetComponent {\n private readonly injector = inject(Injector);\n public readonly i18n = deepmerge(\n {\n INSERT_COLUMN_LEFT: 'Insert column left',\n INSERT_COLUMN_RIGHT: 'Insert column right',\n DELETE_COLUMN: 'Delete column',\n DELETE_ROW: 'Delete row',\n INSERT_ROW_BELOW: 'Insert row below',\n INSERT_ROW_ABOVE: 'Insert row above',\n },\n inject(NSS_I18N, { optional: true }) ?? {},\n );\n @ViewChild('theadMenu') theadContextMenu!: NgxContextMenuComponent;\n @ViewChild('tbodyMenu') tbodyContextMenu!: NgxContextMenuComponent;\n\n @Input() data: any[][] | null = null;\n @Output() dataChanged = new EventEmitter<any[][]>();\n @Input() rows: number | null = null;\n @Input() cols: number | null = null;\n @Input() columns: ColumnOptions[] | null = null;\n @Input() canInsertCols: boolean | null = null;\n @Input() canInsertRows: boolean | null = null;\n @Subjectize('data') data$ = new ReplaySubject<any[][]>(1);\n @Subjectize('rows') rows$ = new ReplaySubject<number>(1);\n @Subjectize('cols') cols$ = new ReplaySubject<number>(1);\n @Subjectize('columns') columns$ = new ReplaySubject<ColumnOptions[]>(1);\n @Subjectize('canInsertRows') canInsertRows$ = new ReplaySubject<boolean>(1);\n @Subjectize('canInsertCols') canInsertCols$ = new ReplaySubject<boolean>(1);\n /**\n * The table observable integrates all the reactive pipes into a higher order scan that\n * can mutate or replace the table reference.\n */\n table$ = merge(\n setPipe(this.canInsertCols$, 'canInsertCols'),\n setPipe(this.canInsertRows$, 'canInsertRows'),\n // Data object reference changed, create new table based on data\n this.data$.pipe(map((data) => (table: Table) => table.recreate({ data }))),\n // Row input changed, resize table\n this.rows$.pipe(map((rows) => (table: Table) => table.resize({ rows }))),\n // Col input changed, resize table\n this.cols$.pipe(map((cols) => (table: Table) => table.resize({ cols }))),\n // Columns changed, recreate table\n this.columns$.pipe(\n map((columns) => (table: Table) => table.recreate({ columns })),\n ),\n ).pipe(\n scan(\n (table, modifier: (table: Table) => Table | void) =>\n (this.table =\n runInInjectionContext(this.injector, () => modifier(table)) ?? table),\n Table.create({}),\n ),\n distinctUntilChanged(),\n );\n\n @Output() copied = new EventEmitter<string>();\n\n table: Table | null = null;\n activatedCell: Cell | null = null;\n range: Range | null = null;\n anchor: Anchor | null = null;\n\n activeTheadIndex: number = -1;\n activeTbodyIndex: number = -1;\n\n @HostListener('mousedown', ['$event'])\n private onMouseDown(ev: MouseEvent): void {\n const { row, col, valid } = this.getPositionFromId(ev.target);\n if (!valid) {\n return;\n }\n this.range = Range.of(row, col);\n if (!ev.shiftKey || !this.anchor) {\n this.anchor = new Anchor(row, col);\n }\n }\n\n @HostListener('document:mousemove', ['$event'])\n private onMouseMove(ev: MouseEvent): void {\n if (!this.range || !this.anchor) {\n return;\n }\n const self = this.getPositionFromId(ev.target);\n if (self.valid) {\n const range = Range.marge({ r: self.row, c: self.col }, this.anchor);\n if (!this.range?.equals(range)) {\n this.range = range;\n }\n }\n }\n\n @HostListener('document:mouseup', ['$event'])\n private onMouseUp(ev: MouseEvent): void {\n if (ev.shiftKey && this.anchor) {\n const self = this.getPositionFromId(ev.target);\n if (self.valid) {\n const range = Range.marge({ r: self.row, c: self.col }, this.anchor);\n if (!this.range?.equals(range)) {\n this.range = range;\n }\n }\n }\n this.anchor = null;\n }\n\n @HostListener('document:keydown', ['$event'])\n private onKeyDown(ev: KeyboardEvent): void {\n const key = ev.key.toLowerCase();\n const isCtrl = (ev.ctrlKey && !ev.metaKey) || (!ev.ctrlKey && ev.metaKey);\n if (!this.table) {\n return;\n }\n\n if (!this.anchor && ev.shiftKey && this.activatedCell) {\n const { row, col } = this.activatedCell;\n this.anchor = new Anchor(row, col);\n }\n\n if (key === 'enter' && this.activatedCell) {\n const { row, col, editable } = this.activatedCell;\n ev.preventDefault();\n this.moveTo(row + 1, col, false);\n } else if (key === 'tab' && this.activatedCell) {\n ev.preventDefault();\n const { rowCount, colCount } = this.table;\n const { row, col, editable } = this.activatedCell;\n const next = ev.shiftKey ? col - 1 : col + 1;\n if (next < 0 && row > 0) {\n this.moveTo(row - 1, colCount - 1, false);\n } else if (next >= colCount && row < rowCount) {\n this.moveTo(row + 1, 0, false);\n } else {\n this.moveTo(row, next, false);\n }\n } else if (key === 'f2') {\n this.setEditable(ev, true);\n } else if (key === 'escape') {\n this.setEditable(ev, false);\n } else if (key === 'a' && isCtrl) {\n this.selectAll(ev);\n } else if (key === 'c' && isCtrl) {\n this.copy();\n } else if (key === 'v' && isCtrl) {\n this.paste();\n } else if (key === 'delete') {\n this.delete();\n } else if (\n this.activatedCell &&\n !this.activatedCell.editable &&\n /^.$/u.test(key)\n ) {\n this.activatedCell.value = '';\n this.setEditable(ev, true);\n this.forceFocus(ev.target as HTMLElement);\n }\n this.blockArrowKeys(ev);\n }\n\n private blockArrowKeys(ev: KeyboardEvent) {\n if (ev.key.toLowerCase().startsWith('arrow')) {\n ev.stopPropagation();\n ev.preventDefault();\n }\n }\n\n @HostListener('document:keyup', ['$event'])\n private onKeyUp(ev: KeyboardEvent): void {\n if (!this.activatedCell || this.activatedCell.editable) {\n return;\n }\n if (!ev.shiftKey) {\n this.anchor = null;\n }\n const { row, col } = this.activatedCell;\n switch (ev.key.toLowerCase()) {\n case 'arrowup':\n this.moveTo(row - 1, col, ev.shiftKey);\n break;\n case 'arrowdown':\n this.moveTo(row + 1, col, ev.shiftKey);\n break;\n case 'arrowleft':\n this.moveTo(row, col - 1, ev.shiftKey);\n break;\n case 'arrowright':\n this.moveTo(row, col + 1, ev.shiftKey);\n break;\n }\n this.blockArrowKeys(ev);\n }\n\n trackByCell(index: number, value: Cell): string | null {\n return value ? value.id : null;\n }\n\n clickHeader(colIndex: number): void {\n const rowLength = this.table?.body.length || 0;\n if (rowLength > 0) {\n this.range = Range.of(0, colIndex, rowLength, colIndex);\n }\n }\n\n clickRow(rowIndex: number): void {\n if (!this.table) {\n return;\n }\n if (rowIndex >= 0 && rowIndex < this.table.body.length) {\n const cols = this.table.body[rowIndex];\n this.range = Range.of(rowIndex, 0, rowIndex, cols.length);\n }\n }\n\n focus(ev: FocusEvent): void {\n const found = this.findCellByEventTarget(ev.target);\n this.activatedCell = found;\n }\n\n blur(ev: FocusEvent): void {\n const found = this.findCellByEventTarget(ev.target);\n if (found) {\n found.editable = false;\n }\n }\n\n cellMouseUp(ev: Event, target: Cell): void {\n const td = ev.target as HTMLTableCellElement;\n if (target === this.activatedCell) {\n target.editable = true;\n }\n }\n\n setValue(ev: Event, target: Cell): void {\n const value = (ev.target as HTMLTableCellElement).innerText || '';\n target.value = value;\n }\n\n setEditable(ev: Event, editable: boolean): void {\n ev.stopPropagation();\n const found = this.findCellByEventTarget(ev.target);\n if (found) {\n found.editable = editable;\n }\n }\n\n showTheadMenu(ev: MouseEvent, index: number) {\n ev.stopPropagation();\n this.theadContextMenu.show(ev, index);\n // Return false to prevent browser from opening its own context menu on top\n return false;\n }\n\n showTbodyMenu(ev: MouseEvent, index: number) {\n ev.stopPropagation();\n this.tbodyContextMenu.show(ev, index);\n // Return false to prevent browser from opening its own context menu on top\n return false;\n }\n\n private moveTo(row: number, col: number, shiftKey: boolean): void {\n if (!this.table) {\n return;\n }\n const { rowCount, colCount } = this.table;\n const resize: { rows?: number; cols?: number } = {};\n if (rowCount <= row && this.table.canInsertRows) {\n resize.rows = row + 1;\n }\n if (colCount <= col && this.table.canInsertCols) {\n resize.cols = col + 1;\n }\n this.table.resize(resize);\n const { body } = this.table;\n if (row >= 0 && row < body.length) {\n const cols = body[row];\n if (col >= 0 && col < cols.length) {\n const cell = cols[col];\n setTimeout(() => {\n const e = document.getElementById(cell.id);\n if (e) {\n this.forceFocus(e);\n }\n });\n if (shiftKey && this.range && this.anchor) {\n this.range = Range.marge(this.anchor, { r: row, c: col });\n } else {\n this.range = Range.of(cell.row, cell.col);\n }\n }\n }\n }\n\n private forceFocus(el: HTMLElement) {\n el.focus();\n const s = window.getSelection();\n const r = document.createRange();\n r.setStart(el, el.childElementCount);\n r.setEnd(el, el.childElementCount);\n s?.removeAllRanges();\n s?.addRange(r);\n }\n\n private findCellByEventTarget(target: EventTarget | null): Cell | null {\n const { row, col, valid } = this.getPositionFromId(target);\n return valid ? this.table?.findCell(row, col) || null : null;\n }\n\n private getPositionFromId(target: EventTarget | null): {\n row: number;\n col: number;\n valid: boolean;\n } {\n const element = target as HTMLTableCellElement;\n if (!this.table || !element?.id?.match(/(\\w+)-(\\d+)-(\\d+)/)) {\n return { row: NaN, col: NaN, valid: false };\n }\n const valid = RegExp.$1 === this.table.id;\n const row = parseInt(RegExp.$2 || '', 10);\n const col = parseInt(RegExp.$3 || '', 10);\n return { row, col, valid };\n }\n\n private copy(): void {\n if (!this.table || !this.range) {\n return;\n }\n const lines = [];\n for (let r = this.range.r1; r <= this.range.r2; r++) {\n const line = [];\n for (let c = this.range.c1; c <= this.range.c2; c++) {\n const cell = this.table.findCell(r, c);\n if (cell) {\n const value = cell.value.match(/[\\t\\n\\r \"]+/)\n ? '\"' + cell.value.split('\"').join('\"\"') + '\"'\n : cell.value;\n line.push(value);\n }\n }\n lines.push(line.join('\\t'));\n }\n const text = lines.join('\\n');\n if (text) {\n navigator.clipboard.writeText(text).then(() => this.copied.emit(text));\n }\n }\n\n private paste(): void {\n if (!this.table || !this.range) {\n return;\n }\n const { r1, c1, r2, c2 } = this.range;\n navigator.clipboard.readText().then((data) => {\n const ar = csvToArray(data);\n if (!ar.length) {\n return;\n }\n if (ar.length === 1 && ar[0].length === 1) {\n // There is only 1 pasted value, paste it everywhere\n const clipboardText = ar[0][0];\n for (let r = r1; r <= r2; r++) {\n for (let c = c1; c <= c2; c++) {\n const cell = this.table!.findCell(r, c);\n if (cell) {\n cell.value = clipboardText;\n }\n }\n }\n } else {\n let mr: number = 0,\n mc: number = 0;\n for (let r = 0, tableRow = r1; r < ar.length; r++, tableRow++) {\n const row = ar[r];\n for (let c = 0, tableCol = c1; c < row.length; c++, tableCol++) {\n const col = row[c];\n const cell = this.table!.findOrCreateCell(tableRow, tableCol);\n if (cell) {\n cell.value = col;\n mr = Math.max(cell.row, mr);\n mc = Math.max(cell.col, mc);\n }\n }\n }\n this.range = Range.of(r1, c1, mr, mc);\n }\n });\n this.dataChanged.emit(this.table.data);\n }\n\n private delete(): void {\n if (!this.table || !this.range) {\n return;\n }\n const { r1, c1, r2, c2 } = this.range;\n for (let r = r1; r <= r2; r++) {\n for (let c = c1; c <= c2; c++) {\n const cell = this.table.findCell(r, c);\n if (cell) {\n cell.value = '';\n }\n }\n }\n this.dataChanged.emit(this.table.data);\n }\n\n updateValue(table: Table, cell: any, $event: string) {\n if (cell.value != $event) {\n cell.value = $event;\n this.dataChanged.emit(table.data);\n }\n }\n\n selectAll(event$?: Event) {\n if (!this.table || this.table.editing) {\n return;\n }\n this.range = Range.of(0, 0, this.table.rowCount, this.table.colCount);\n if (event$) {\n event$.stopPropagation();\n event$.preventDefault();\n }\n }\n\n newRow(col: number) {\n if (!this.table) return;\n this.table.resize({ rows: this.table.rowCount + 1 });\n this.activatedCell = this.table.findCell(this.table.rowCount - 1, col);\n this.range = new Range(\n this.table.rowCount - 1,\n col,\n this.table.rowCount - 1,\n col,\n );\n setTimeout(() => {\n if (this.activatedCell) {\n const el = document.getElementById(this.activatedCell.id);\n if (el) {\n this.forceFocus(el);\n }\n }\n });\n }\n}\n","<ng-container *ngrxLet=\"table$ as table\">\n <div class=\"container\">\n <table #htmlTable>\n <!--Table header-->\n <thead>\n <tr>\n <!--Empty top left header cell-->\n <th></th>\n <!--Column header cells-->\n <th\n *ngFor=\"let col of table.head; let c = index\"\n (click)=\"clickHeader(c)\"\n (contextmenu)=\"showTheadMenu($event, c)\"\n (mouseenter)=\"activeTheadIndex = c\"\n (mouseleave)=\"activeTheadIndex = -1\"\n >\n {{ col }}\n </th>\n </tr>\n </thead>\n <!--Table body-->\n <tbody style=\"overflow-y: auto\">\n <!--Table rows-->\n <tr *ngFor=\"let row of table.body; let r = index\">\n <!--Row header cell-->\n <th\n (click)=\"clickRow(r)\"\n (contextmenu)=\"showTbodyMenu($event, r)\"\n (mouseenter)=\"activeTbodyIndex = r\"\n (mouseleave)=\"activeTbodyIndex = -1\"\n >\n {{ r + 1 }}\n </th>\n <!--Table data cell-->\n <td\n [id]=\"cell.id\"\n *ngFor=\"let cell of row; let c = index; trackBy: trackByCell\"\n [class.focus]=\"cell === activatedCell\"\n [class.sel]=\"range?.includes(cell.row, cell.col)\"\n nssContentEditable\n [content]=\"cell.value\"\n (contentChange)=\"updateValue(table, cell, $event)\"\n (focus)=\"focus($event)\"\n (blur)=\"blur($event)\"\n (mousedown)=\"cellMouseUp($event, cell)\"\n [attr.contenteditable]=\"cell.editable\"\n ></td>\n </tr>\n <!--New data row, click to increase row size-->\n <tr *ngIf=\"table.canInsertRows\">\n <th>*</th>\n <td\n *ngFor=\"let _ of [].constructor(table.colCount); let i = index\"\n (click)=\"newRow(i)\"\n ></td>\n </tr>\n </tbody>\n </table>\n </div>\n <!--Column header context menu-->\n <ngx-context-menu #theadMenu (closed)=\"activeTheadIndex = -1\">\n <ngx-context-menu-item\n [label]=\"i18n.INSERT_COLUMN_LEFT\"\n (click)=\"table.insertColumn($event)\"\n >\n </ngx-context-menu-item>\n <ngx-context-menu-item\n [label]=\"i18n.INSERT_COLUMN_RIGHT\"\n (click)=\"table.insertColumn($event + 1)\"\n >\n </ngx-context-menu-item>\n <ngx-context-menu-item [divider]=\"true\"></ngx-context-menu-item>\n <ngx-context-menu-item\n [label]=\"i18n.DELETE_COLUMN\"\n [disabled]=\"table.colCount <= 1\"\n (click)=\"table.deleteColumn($event)\"\n >\n </ngx-context-menu-item>\n </ngx-context-menu>\n\n <!--Row header context menu-->\n <ngx-context-menu #tbodyMenu (closed)=\"activeTbodyIndex = -1\">\n <ngx-context-menu-item\n [label]=\"i18n.INSERT_ROW_ABOVE\"\n (click)=\"table.insertRow($event)\"\n >\n </ngx-context-menu-item>\n <ngx-context-menu-item\n [label]=\"i18n.INSERT_ROW_BELOW\"\n (click)=\"table.insertRow($event + 1)\"\n >\n </ngx-context-menu-item>\n <ngx-context-menu-item [divider]=\"true\"></ngx-context-menu-item>\n <ngx-context-menu-item\n [label]=\"i18n.DELETE_ROW\"\n [disabled]=\"table.rowCount <= 1\"\n (click)=\"table.deleteRow($event)\"\n >\n </ngx-context-menu-item>\n </ngx-context-menu>\n</ng-container>\n","import { CommonModule } from '@angular/common';\nimport { NgModule } from '@angular/core';\nimport { ContentEditableDirective } from './content-editable.directive';\nimport { NgxContextMenuItemComponent } from './ngx-context-menu-item.component';\nimport { NgxContextMenuComponent } from './ngx-context-menu.component';\nimport { NgxSpreadsheetComponent } from './ngx-spreadsheet.component';\nimport { LetDirective } from '@ngrx/component';\n\n@NgModule({\n declarations: [\n NgxSpreadsheetComponent,\n NgxContextMenuComponent,\n NgxContextMenuItemComponent,\n ContentEditableDirective,\n ],\n imports: [CommonModule, LetDirective],\n exports: [NgxSpreadsheetComponent],\n})\nexport class NgxSpreadsheetModule {}\n","/*\n * Public API Surface of ngx-spreadsheet\n */\n\nexport * from './lib/model/table';\nexport * from './lib/ngx-spreadsheet.component';\nexport * from './lib/ngx-spreadsheet.module';\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public-api';\n"],"names":["CHARS","LENGTH","i3.NgxContextMenuComponent","i4.NgxContextMenuItemComponent","i5.ContentEditableDirective"],"mappings":"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