├── .gitignore ├── .npmignore ├── .vscode ├── settings.json └── tasks.json ├── README.md ├── SECURITY.md ├── components ├── css │ ├── SlickGrid.css │ └── SlickGrid.less ├── index.ts ├── js │ ├── interfaces.ts │ ├── selectionModel.ts │ ├── slickGrid.ts │ └── virtualizedCollection.ts └── typings │ └── slick.d.ts ├── examples └── basic_application │ ├── app.component.ts │ ├── app.module.ts │ ├── index.html │ ├── main.ts │ ├── styles.css │ └── systemjs.config.js ├── gulpfile.js ├── license.txt ├── package-lock.json ├── package.json ├── tsconfig.json ├── tslint.json └── typings.json /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | .DS_Store 3 | /typings 4 | dist 5 | out -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | gulpfile.js 2 | tsconfig.json 3 | tslint.json 4 | components 5 | .vscode 6 | typings.json 7 | examples 8 | dist -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "typescript.check.workspaceVersion": false 3 | } -------------------------------------------------------------------------------- /.vscode/tasks.json: -------------------------------------------------------------------------------- 1 | { 2 | // See https://go.microsoft.com/fwlink/?LinkId=733558 3 | // for the documentation about the tasks.json format 4 | "version": "0.1.0", 5 | "command": "gulp", 6 | "isShellCommand": true, 7 | "args": [ 8 | "--no-color" 9 | ], 10 | "tasks": [ 11 | { 12 | "taskName": "build", 13 | "args": [], 14 | "isBuildCommand": true, 15 | "isWatching": false, 16 | "problemMatcher": [ 17 | "$lessCompile", 18 | "$tsc", 19 | "$jshint" 20 | ] 21 | } 22 | ] 23 | } -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## Repository State 2 | 3 | The feature-set for angular2-slickgrid is incomplete. If there are missing features you would like, please submit an issue and/or create a pull request implementing the feature. 4 | 5 | ## Set up Node, npm, gulp and typings 6 | 7 | ### Node and npm 8 | **Windows and Mac OSX**: Download and install node from [nodejs.org](http://nodejs.org/) 9 | 10 | **Linux**: Install [using package manager](https://nodejs.org/en/download/package-manager/) 11 | 12 | From a terminal ensure at least node 5.4.1 and npm 3: 13 | ```bash 14 | $ node -v && npm -v 15 | v5.9.0 16 | 3.8.2 17 | ``` 18 | **Note**: To get npm version 3.8.2, you may need to update npm after installing node. To do that: 19 | ```bash 20 | [sudo] npm install npm -g 21 | ``` 22 | 23 | ### Gulp 24 | Install gulp-cli 25 | ```bash 26 | [sudo] npm install gulp-cli -g 27 | ``` 28 | From the root of the repo, install all of the build dependencies: 29 | ```bash 30 | [sudo] npm install --greedy 31 | ``` 32 | 33 | ### Typings 34 | #### Install Typings CLI utility 35 | `npm install typings --global` 36 | 37 | #### Install required typings to build this project 38 | `typings install` 39 | 40 | ## Build project 41 | Type `gulp build` from the command line or run build inside VSCode 42 | 43 | ## Examples 44 | Example applications using this component can be found in the examples folder. To run the examples, 45 | run `gulp compile:examples` (running `gulp build` will also compile the examples) then run `gulp serve`. This will launch a static server at the root of the project. 46 | Navigate a browser to `http://localhost:{port}/dist/{exampleName}` e.g `http://localhost:8080/dist/basic_application`. 47 | 48 | 49 | ## Contributing 50 | Because this project is meant to be used as an npm module, compiled files are checked into the repo. Before commiting run `gulp publish` (compiles 51 | everything except the examples). This should be removed once/if this is added to the npm registry. 52 | -------------------------------------------------------------------------------- /SECURITY.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | ## Security 4 | 5 | Microsoft takes the security of our software products and services seriously, which includes all source code repositories managed through our GitHub organizations, which include [Microsoft](https://github.com/Microsoft), [Azure](https://github.com/Azure), [DotNet](https://github.com/dotnet), [AspNet](https://github.com/aspnet), [Xamarin](https://github.com/xamarin), and [our GitHub organizations](https://opensource.microsoft.com/). 6 | 7 | If you believe you have found a security vulnerability in any Microsoft-owned repository that meets [Microsoft's definition of a security vulnerability](https://aka.ms/opensource/security/definition), please report it to us as described below. 8 | 9 | ## Reporting Security Issues 10 | 11 | **Please do not report security vulnerabilities through public GitHub issues.** 12 | 13 | Instead, please report them to the Microsoft Security Response Center (MSRC) at [https://msrc.microsoft.com/create-report](https://aka.ms/opensource/security/create-report). 14 | 15 | If you prefer to submit without logging in, send email to [secure@microsoft.com](mailto:secure@microsoft.com). If possible, encrypt your message with our PGP key; please download it from the [Microsoft Security Response Center PGP Key page](https://aka.ms/opensource/security/pgpkey). 16 | 17 | You should receive a response within 24 hours. If for some reason you do not, please follow up via email to ensure we received your original message. Additional information can be found at [microsoft.com/msrc](https://aka.ms/opensource/security/msrc). 18 | 19 | Please include the requested information listed below (as much as you can provide) to help us better understand the nature and scope of the possible issue: 20 | 21 | * Type of issue (e.g. buffer overflow, SQL injection, cross-site scripting, etc.) 22 | * Full paths of source file(s) related to the manifestation of the issue 23 | * The location of the affected source code (tag/branch/commit or direct URL) 24 | * Any special configuration required to reproduce the issue 25 | * Step-by-step instructions to reproduce the issue 26 | * Proof-of-concept or exploit code (if possible) 27 | * Impact of the issue, including how an attacker might exploit the issue 28 | 29 | This information will help us triage your report more quickly. 30 | 31 | If you are reporting for a bug bounty, more complete reports can contribute to a higher bounty award. Please visit our [Microsoft Bug Bounty Program](https://aka.ms/opensource/security/bounty) page for more details about our active programs. 32 | 33 | ## Preferred Languages 34 | 35 | We prefer all communications to be in English. 36 | 37 | ## Policy 38 | 39 | Microsoft follows the principle of [Coordinated Vulnerability Disclosure](https://aka.ms/opensource/security/cvd). 40 | 41 | 42 | -------------------------------------------------------------------------------- /components/css/SlickGrid.css: -------------------------------------------------------------------------------- 1 | .grid-cell-padding { 2 | padding: .5em .8em .4em 3 | } 4 | 5 | .grid-cell { 6 | border-top-style: none; 7 | color: var(--color-content, #101010); 8 | letter-spacing: .03em; 9 | border-color: var(--border-color-default, #000000); 10 | font-size: .95em; 11 | border-bottom-width: 1px; 12 | border-left-style: none; 13 | border-right-color: #ACACAC; 14 | border-right-style: dotted; 15 | padding: .5em .8em .4em 16 | } 17 | 18 | .grid { 19 | width: 100%; 20 | height: 100%; 21 | } 22 | 23 | .grid .slick-header-column { 24 | border-top-style: none; 25 | color: var(--color-content, #101010); 26 | letter-spacing: .03em; 27 | border-color: var(--border-color-default, #000000); 28 | font-size: .95em; 29 | border-bottom-width: 1px; 30 | border-left-style: none; 31 | border-right-color: #ACACAC; 32 | border-right-style: dotted; 33 | padding: .5em .8em .4em; 34 | background-color: var( --color-bg-content-header, #F5F5F5); 35 | border-bottom-color: #ACACAC 36 | } 37 | 38 | .grid .slick-cell { 39 | border-top-style: none; 40 | color: var(--color-content, #101010); 41 | letter-spacing: .03em; 42 | border-color: var(--border-color-default, #000000); 43 | font-size: .95em; 44 | border-bottom-width: 1px; 45 | border-left-style: none; 46 | border-right-color: #ACACAC; 47 | border-right-style: dotted; 48 | padding: .5em .8em .4em; 49 | background-color: var(--background-color, white); 50 | } 51 | 52 | .grid .slick-cell.selected { 53 | background-color: var(--color-cell-bg-grid-selected, rgb(173, 214, 255)); 54 | color: var(--color-content, #101010); 55 | } 56 | 57 | .grid .slick-cell.selected .grid-cell-value-container.missing-value { 58 | color: black 59 | } 60 | 61 | .grid .slick-cell.editable input { 62 | padding: .2em .65em .1em; 63 | letter-spacing: .03em; 64 | height: 100%; 65 | outline: none; 66 | border: none; 67 | color: inherit; 68 | background-color: transparent; 69 | } 70 | 71 | .grid .slick-cell.editable input:focus { 72 | outline-offset: 0 73 | } 74 | 75 | .grid .slick-cell .grid-cell-value-container { 76 | display: block; 77 | white-space: pre; 78 | width: 100%; 79 | overflow-x: hidden; 80 | text-overflow: ellipsis 81 | } 82 | 83 | .grid .slick-cell .grid-cell-value-container.override-cell { 84 | color: black 85 | } 86 | 87 | .grid .slick-cell .grid-cell-value-container.highlighted { 88 | color: black 89 | } 90 | 91 | .grid .slick-cell .grid-cell-value-container.blurred { 92 | color: #ABABAB 93 | } 94 | 95 | .grid .slick-cell .grid-cell-value-container.missing-value { 96 | color: lightgray 97 | } 98 | 99 | .grid .slick-cell .grid-cell-value-container.context { 100 | color: darkblue; 101 | font-style: italic 102 | } 103 | 104 | .grid .slick-cell .grid-cell-value-container.loading-cell { 105 | font-style: italic 106 | } 107 | 108 | .grid .slick-cell .grid-cell-value-container.right-justified { 109 | text-align: right 110 | } 111 | 112 | .grid input.editor-text { 113 | width: 100%; 114 | color: #000000 115 | } 116 | -------------------------------------------------------------------------------- /components/css/SlickGrid.less: -------------------------------------------------------------------------------- 1 | @grid-content-letter-spacing: 0.03em; 2 | 3 | .grid-cell-padding { 4 | padding: 0.5em 0.8em 0.4em; 5 | } 6 | 7 | .grid-cell { 8 | border-top-style: none; 9 | color: #101010; 10 | letter-spacing: @grid-content-letter-spacing; 11 | border-color: #EBECEC; 12 | font-size: 0.95em; 13 | border-bottom-width: 1px; 14 | border-left-style: none; 15 | border-right-color: #ACACAC; 16 | border-right-style: dotted; 17 | .grid-cell-padding; 18 | } 19 | 20 | .grid { 21 | width: 100%; 22 | height: 100%; 23 | 24 | .slick-header-column { 25 | .grid-cell; 26 | background-color: #F7F7F7; 27 | border-bottom-color: #ACACAC; 28 | } 29 | 30 | .slick-cell { 31 | .grid-cell; 32 | background-color: var(--grid-cell-color, #FFFFFF); 33 | 34 | &.selected { 35 | background-color: ~"var(--color-grid-selected)"; 36 | color: black; 37 | 38 | .grid-cell-value-container.missing-value { 39 | color: black; 40 | } 41 | } 42 | 43 | &.editable { 44 | input { 45 | padding: 0.2em 0.65em 0.1em; 46 | height: 100%; 47 | outline: none; 48 | border: none; 49 | color: inherit; 50 | background-color: transparent; 51 | letter-spacing: @grid-content-letter-spacing; 52 | &:focus { 53 | outline-offset: 0; 54 | } 55 | } 56 | } 57 | 58 | .grid-cell-value-container { 59 | display: block; 60 | white-space: pre; 61 | width: 100%; 62 | overflow-x: hidden; 63 | text-overflow: ellipsis; 64 | 65 | &.override-cell { 66 | color: black; 67 | } 68 | 69 | &.highlighted { 70 | color: black; 71 | } 72 | 73 | &.blurred { 74 | color: #ABABAB; 75 | } 76 | 77 | &.missing-value { 78 | color: lightgray; 79 | } 80 | 81 | &.context { 82 | color: darkblue; // need actual color and sign off on a way we want to distinguish source columns 83 | font-style: italic; 84 | } 85 | 86 | &.loading-cell { 87 | font-style: italic; 88 | } 89 | 90 | &.right-justified { 91 | text-align: right; 92 | } 93 | 94 | 95 | } 96 | 97 | } 98 | 99 | input.editor-text { 100 | width: 100%; 101 | color: #000000; 102 | } 103 | } 104 | 105 | .contextMenu { 106 | position: absolute; 107 | background: #007ACC; 108 | color: white; 109 | border: 1px solid gray; 110 | padding: 2px; 111 | display: inline-block; 112 | min-width: 100px; 113 | -moz-box-shadow: 2px 2px 2px silver; 114 | -webkit-box-shadow: 2px 2px 2px silver; 115 | z-index: 99999; 116 | 117 | li { 118 | padding: 4px 4px 4px 14px; 119 | list-style: none; 120 | cursor: pointer; 121 | } 122 | 123 | li:hover { 124 | background-color: white; 125 | color: #007ACC; 126 | text-decoration: underline; 127 | } 128 | } 129 | -------------------------------------------------------------------------------- /components/index.ts: -------------------------------------------------------------------------------- 1 | /*--------------------------------------------------------------------------------------------- 2 | * Copyright (c) Microsoft Corporation. All rights reserved. 3 | * Licensed under the MIT License. See License.txt in the project root for license information. 4 | *--------------------------------------------------------------------------------------------*/ 5 | export * from './js/interfaces'; 6 | export * from './js/selectionModel'; 7 | export * from './js/slickGrid'; 8 | export * from './js/virtualizedCollection'; 9 | -------------------------------------------------------------------------------- /components/js/interfaces.ts: -------------------------------------------------------------------------------- 1 | /*--------------------------------------------------------------------------------------------- 2 | * Copyright (c) Microsoft Corporation. All rights reserved. 3 | * Licensed under the MIT License. See License.txt in the project root for license information. 4 | *--------------------------------------------------------------------------------------------*/ 5 | import { Observable, Subject } from 'rxjs/Rx'; 6 | 7 | export enum NotificationType { 8 | Error, 9 | UpdateAvailable, 10 | UpdateDownloaded 11 | } 12 | 13 | export interface ISelectionRange { 14 | startRow: number; 15 | endRow: number; 16 | startColumn: number; 17 | endColumn: number; 18 | } 19 | 20 | export enum CollectionChange { 21 | ItemsReplaced 22 | } 23 | 24 | export interface IObservableCollection { 25 | getLength(): number; 26 | at(index: number): T; 27 | getRange(start: number, end: number): T[]; 28 | setCollectionChangedCallback(callback: (change: CollectionChange, startIndex: number, count: number) => void): void; 29 | resetWindowsAroundIndex(index: number): void; 30 | } 31 | 32 | export class CancellationToken { 33 | private _isCanceled: boolean = false; 34 | private _canceled: Subject = new Subject(); 35 | 36 | cancel(): void { 37 | this._isCanceled = true; 38 | this._canceled.next(undefined); 39 | } 40 | 41 | get isCanceled(): boolean { 42 | return this._isCanceled; 43 | } 44 | 45 | get canceled(): Observable { 46 | return this._canceled; 47 | } 48 | } 49 | 50 | export interface IGridColumnDefinition { 51 | id: string; 52 | type: number; 53 | } 54 | 55 | export interface ISlickColumn extends Slick.Column { 56 | isEditable?: boolean; 57 | } 58 | -------------------------------------------------------------------------------- /components/js/selectionModel.ts: -------------------------------------------------------------------------------- 1 | /*--------------------------------------------------------------------------------------------- 2 | * Copyright (c) Microsoft Corporation. All rights reserved. 3 | * Licensed under the MIT License. See License.txt in the project root for license information. 4 | *--------------------------------------------------------------------------------------------*/ 5 | import { ISelectionRange } from './interfaces'; 6 | 7 | export interface ISlickSelectionModel { 8 | range: Slick.Range[]; 9 | onSelectedRangesChanged: any; 10 | init(grid: any): void; 11 | destroy(): void; 12 | setSelectedRanges(ranges: Slick.Range[]): void; 13 | getSelectedRanges(): Slick.Range[]; 14 | } 15 | 16 | export class SelectionModel implements ISlickSelectionModel { 17 | 18 | constructor(private _rowSelectionModel: ISlickSelectionModel, 19 | private _handler: ISlickEventHandler, 20 | private _onSelectedRangesChanged: ISlickEvent, 21 | private _slickRangeFactory: (fromRow: number, fromCell: number, toRow: number, toCell: number) => Slick.Range) { } 22 | 23 | get range(): Slick.Range[] { 24 | return this._ranges; 25 | } 26 | 27 | get onSelectedRangesChanged(): ISlickEvent { 28 | return this._onSelectedRangesChanged; 29 | } 30 | 31 | init(grid: ISlickGrid): void { 32 | this._grid = grid; 33 | this._rowSelectionModel.init(grid); 34 | this._handler.subscribe(this._rowSelectionModel.onSelectedRangesChanged, (e, ranges) => { 35 | this.updateSelectedRanges(ranges); 36 | }); 37 | } 38 | 39 | destroy(): void { 40 | this._handler.unsubscribeAll(); 41 | this._rowSelectionModel.destroy(); 42 | } 43 | 44 | setSelectedRanges(ranges: Slick.Range[]): void { 45 | this._rowSelectionModel.setSelectedRanges(ranges); 46 | } 47 | 48 | getSelectedRanges(): Slick.Range[] { 49 | return this._rowSelectionModel.getSelectedRanges(); 50 | } 51 | 52 | changeSelectedRanges(selections: ISelectionRange[]): void { 53 | let slickRange = (selections || []).map(s => 54 | this._slickRangeFactory(s.startRow, s.startColumn, s.endRow - 1, s.endColumn - 1) 55 | ); 56 | this.updateSelectedRanges(slickRange); 57 | } 58 | 59 | toggleSingleColumnSelection(columnId: string): void { 60 | let newRanges = [this.getColumnRange(columnId)]; 61 | if (SelectionModel.areRangesIdentical(newRanges, this._ranges)) { 62 | this.clearSelection(); 63 | } else { 64 | this.setSingleColumnSelection(columnId); 65 | } 66 | } 67 | 68 | setSingleColumnSelection(columnId: string): void { 69 | this._lastSelectedColumnIndexSequence = [this._grid.getColumnIndex(columnId)]; 70 | this._grid.resetActiveCell(); 71 | this.updateSelectedRanges([this.getColumnRange(columnId)]); 72 | } 73 | 74 | toggleMultiColumnSelection(columnId: string): void { 75 | if (this.isColumnSelectionCurrently === false) { 76 | return this.toggleSingleColumnSelection(columnId); 77 | } 78 | let columnIndex = this._grid.getColumnIndex(columnId); 79 | let columnRange = this.getColumnRangeByIndex(columnIndex); 80 | let columnInRange = false; 81 | let newRanges = this._ranges.filter((value, index) => { 82 | if (value.fromCell === columnRange.fromCell && value.toCell === columnRange.toCell) { 83 | columnInRange = true; 84 | return false; 85 | } 86 | return true; 87 | }); 88 | this._lastSelectedColumnIndexSequence = this._lastSelectedColumnIndexSequence.filter(value => value !== columnIndex); 89 | 90 | if (columnInRange === false) { 91 | newRanges.push(columnRange); 92 | this._lastSelectedColumnIndexSequence.push(this._grid.getColumnIndex(columnId)); 93 | } 94 | 95 | this._grid.resetActiveCell(); 96 | this.updateSelectedRanges(newRanges); 97 | } 98 | 99 | extendMultiColumnSelection(columnId: string): void { 100 | if (this.isColumnSelectionCurrently === false 101 | || !this._lastSelectedColumnIndexSequence 102 | || this._lastSelectedColumnIndexSequence.length === 0) { 103 | return this.toggleSingleColumnSelection(columnId); 104 | } 105 | 106 | let columnIndex = this._grid.getColumnIndex(columnId); 107 | let lastSelectedColumnIndex = this._lastSelectedColumnIndexSequence[this._lastSelectedColumnIndexSequence.length - 1]; 108 | 109 | let start = Math.min(columnIndex, lastSelectedColumnIndex); 110 | let end = Math.max(columnIndex, lastSelectedColumnIndex); 111 | 112 | let newRanges = []; 113 | this._lastSelectedColumnIndexSequence = []; 114 | for (let i = start; i <= end; i++) { 115 | newRanges.push(this.getColumnRangeByIndex(i)); 116 | if (i !== lastSelectedColumnIndex) { 117 | this._lastSelectedColumnIndexSequence.push(i); 118 | } 119 | } 120 | this._lastSelectedColumnIndexSequence.push(lastSelectedColumnIndex); 121 | 122 | this._grid.resetActiveCell(); 123 | this.updateSelectedRanges(newRanges); 124 | } 125 | 126 | clearSelection(): void { 127 | this._lastSelectedColumnIndexSequence = []; 128 | this._grid.resetActiveCell(); 129 | this._rowSelectionModel.setSelectedRanges([]); 130 | } 131 | 132 | private _grid: ISlickGrid; 133 | private _ranges: Slick.Range[] = []; 134 | private _lastSelectedColumnIndexSequence: number[] = []; 135 | 136 | private static areRangesIdentical(lhs: Slick.Range[], rhs: Slick.Range[]): boolean { 137 | if (lhs && rhs && (lhs !== rhs) && lhs.length === rhs.length) { 138 | for (let i = 0; i < lhs.length; ++i) { 139 | if (lhs[i].fromRow !== rhs[i].fromRow 140 | || lhs[i].toRow !== rhs[i].toRow 141 | || lhs[i].fromCell !== rhs[i].fromCell 142 | || lhs[i].toCell !== rhs[i].toCell) { 143 | return false; 144 | } 145 | } 146 | return true; 147 | } 148 | return false; 149 | } 150 | 151 | private getColumnRange(columnId: string): Slick.Range { 152 | let columnIndex = this._grid.getColumnIndex(columnId); 153 | return this.getColumnRangeByIndex(columnIndex); 154 | } 155 | 156 | private getColumnRangeByIndex(columnIndex: number): Slick.Range { 157 | let rowCount = this._grid.getDataLength(); 158 | let lastRowToSelect = rowCount === 0 ? 0 : rowCount - 1 ; 159 | return this._slickRangeFactory(0, columnIndex, lastRowToSelect, columnIndex); 160 | } 161 | 162 | private get isColumnSelectionCurrently(): boolean { 163 | return this._ranges 164 | && this._ranges.length > 0 165 | && this._ranges.find(r => { 166 | let startAtFirstRow = r.fromRow === 0; 167 | let endAtLastRow = r.toRow === Math.max(0, this._grid.getDataLength() - 1); 168 | return !startAtFirstRow || !endAtLastRow || r.fromCell !== r.toCell; 169 | }) === undefined; 170 | } 171 | 172 | private updateSelectedRanges(ranges: Slick.Range[]): void { 173 | // Set focus to this grid if it's not already somewhere inside it. 174 | if (ranges && ranges.length !== 0 && this._grid && this._grid.getCanvasNode() && !this._grid.getCanvasNode().contains(document.activeElement)) { 175 | this._grid.focus(); 176 | } 177 | 178 | if (SelectionModel.areRangesIdentical(ranges, this._ranges)) { 179 | return; 180 | } 181 | 182 | this._ranges = ranges; 183 | this.onSelectedRangesChanged.notify(this._ranges); 184 | } 185 | } 186 | 187 | export interface ISlickEventHandler { 188 | subscribe(event: any, handler: any): void; 189 | unsubscribeAll(): void; 190 | } 191 | 192 | export interface ISlickEvent { 193 | notify(eventData: Slick.Range[]): void; 194 | subscribe(handler: (e: any, args: any) => void): void; 195 | } 196 | 197 | export interface ISlickGrid { 198 | getActiveCellNode(): any; 199 | getCanvasNode(): any; 200 | resetActiveCell(): void; 201 | focus(): void; 202 | getColumnIndex(columnId: string): number; 203 | getDataLength(): number; 204 | } 205 | -------------------------------------------------------------------------------- /components/js/slickGrid.ts: -------------------------------------------------------------------------------- 1 | /*--------------------------------------------------------------------------------------------- 2 | * Copyright (c) Microsoft Corporation. All rights reserved. 3 | * Licensed under the MIT License. See License.txt in the project root for license information. 4 | *--------------------------------------------------------------------------------------------*/ 5 | 6 | import { 7 | Component, Input, Output, Inject, forwardRef, OnChanges, OnInit, OnDestroy, ElementRef, SimpleChange, EventEmitter, 8 | ViewEncapsulation, HostListener, AfterViewInit 9 | } from '@angular/core'; 10 | import { Observable, Subscription } from 'rxjs/Rx'; 11 | import { IObservableCollection, CollectionChange, ISlickColumn } from './interfaces'; 12 | 13 | declare let Slick; 14 | 15 | ////////// Interfaces ///////////////////////////////////////////////////////// 16 | 17 | interface ISlickGridData { 18 | // https://github.com/mleibman/SlickGrid/wiki/DataView 19 | getLength(): number; 20 | getItem(index: number): any; 21 | getRange(start: number, end: number): any; // only available in the forked SlickGrid 22 | getItemMetadata(index: number): any; 23 | } 24 | 25 | ////////// Text Editors /////////////////////////////////////////////////////// 26 | 27 | export function getOverridableTextEditorClass(grid: SlickGrid): any { 28 | class OverridableTextEditor { 29 | private _textEditor: any; 30 | public keyCaptureList: number[]; 31 | 32 | constructor(private _args: any) { 33 | this._textEditor = new Slick.Editors.Text(_args); 34 | const END = 35; 35 | const HOME = 36; 36 | 37 | // These are the special keys the text editor should capture instead of letting 38 | // the grid handle them 39 | this.keyCaptureList = [END, HOME]; 40 | } 41 | 42 | destroy(): void { 43 | this._textEditor.destroy(); 44 | } 45 | 46 | focus(): void { 47 | this._textEditor.focus(); 48 | } 49 | 50 | getValue(): string { 51 | return this._textEditor.getValue(); 52 | } 53 | 54 | setValue(val): void { 55 | this._textEditor.setValue(val); 56 | } 57 | 58 | loadValue(item, rowNumber): void { 59 | if (grid.overrideCellFn) { 60 | let overrideValue = grid.overrideCellFn(rowNumber, this._args.column.id, item[this._args.column.id]); 61 | if (overrideValue !== undefined) { 62 | item[this._args.column.id] = overrideValue; 63 | } 64 | } 65 | this._textEditor.loadValue(item); 66 | } 67 | 68 | serializeValue(): string { 69 | return this._textEditor.serializeValue(); 70 | } 71 | 72 | applyValue(item, state): void { 73 | let activeRow = grid.activeCell.row; 74 | let currentRow = grid.dataRows.at(activeRow); 75 | let colIndex = grid.getColumnIndex(this._args.column.name); 76 | let dataLength: number = grid.dataRows.getLength(); 77 | 78 | // If this is not the "new row" at the very bottom 79 | if (activeRow !== dataLength) { 80 | currentRow[colIndex] = state; 81 | this._textEditor.applyValue(item, state); 82 | } 83 | } 84 | 85 | isValueChanged(): boolean { 86 | return this._textEditor.isValueChanged(); 87 | } 88 | 89 | validate(): any { 90 | let activeRow = grid.activeCell.row; 91 | let result: any = { valid: true, msg: undefined }; 92 | let colIndex: number = grid.getColumnIndex(this._args.column.name); 93 | let newValue: any = this._textEditor.getValue(); 94 | 95 | // TODO: It would be nice if we could support the isCellEditValid as a promise 96 | if (grid.isCellEditValid && !grid.isCellEditValid(activeRow, colIndex, newValue)) { 97 | result.valid = false; 98 | } 99 | 100 | return result; 101 | } 102 | } 103 | 104 | return OverridableTextEditor; 105 | } 106 | 107 | ////////// Implementation ///////////////////////////////////////////////////// 108 | 109 | @Component({ 110 | selector: 'slick-grid', 111 | template: '
', 112 | encapsulation: ViewEncapsulation.None 113 | }) 114 | export class SlickGrid implements OnChanges, OnInit, OnDestroy, AfterViewInit { 115 | 116 | @Input() columnDefinitions: ISlickColumn[]; 117 | @Input() dataRows: IObservableCollection<{}>; 118 | @Input() resized: Observable; 119 | @Input() highlightedCells: { row: number, column: number }[] = []; 120 | @Input() blurredColumns: string[] = []; 121 | @Input() contextColumns: string[] = []; 122 | @Input() columnsLoading: string[] = []; 123 | @Input() showHeader: boolean = true; 124 | @Input() enableColumnReorder: boolean = false; 125 | @Input() enableAsyncPostRender: boolean = false; 126 | @Input() selectionModel: string | Slick.SelectionModel = ''; 127 | @Input() plugins: Array> = []; 128 | @Input() enableEditing: boolean = false; 129 | @Input() topRowNumber: number; 130 | 131 | @Input() overrideCellFn: (rowNumber, columnId, value?, data?) => string; 132 | @Input() isCellEditValid: (row: number, column: number, newValue: any) => boolean; 133 | @Input() onBeforeAppendCell: (row: number, column: number) => string; 134 | 135 | @Output() loadFinished: EventEmitter = new EventEmitter(); 136 | 137 | // SLickGrid Events 138 | @Output() onContextMenu: EventEmitter = new EventEmitter(); 139 | @Output() onScroll: EventEmitter> = new EventEmitter>(); 140 | @Output() onActiveCellChanged: EventEmitter> = new EventEmitter>(); 141 | @Output() onBeforeEditCell: EventEmitter> = new EventEmitter>(); 142 | @Output() onCellChange: EventEmitter> = new EventEmitter>(); 143 | @Output() onRendered: EventEmitter> = new EventEmitter>(); 144 | 145 | @HostListener('focus') 146 | onFocus(): void { 147 | if (this._grid) { 148 | this._grid.focus(); 149 | } 150 | } 151 | 152 | @Input() public set rowHeight(val: number) { 153 | this._rowHeight = val; 154 | if (this._grid) { 155 | this._grid.setOptions({ rowHeight: this.rowHeight }); 156 | } 157 | } 158 | 159 | public get rowHeight(): number { 160 | return this._rowHeight; 161 | } 162 | 163 | private _rowHeight = 29; 164 | private _grid: Slick.Grid; 165 | private _gridColumns: ISlickColumn[]; 166 | private _columnNameToIndex: any; 167 | private _gridData: ISlickGridData; 168 | private _resizeSubscription: Subscription; 169 | private _gridSyncSubscription: Subscription; 170 | 171 | ////////// Constructor and Angular functions ////////////////////////////// 172 | 173 | constructor(@Inject(forwardRef(() => ElementRef)) private _el) { 174 | this._gridData = { 175 | getLength: (): number => { 176 | return this.dataRows && this._gridColumns ? this.dataRows.getLength() : 0; 177 | }, 178 | getItem: (index): any => { 179 | return !this.dataRows ? undefined : this.dataRows.at(index); 180 | }, 181 | getRange: (start, end): any => { 182 | return !this.dataRows ? undefined : this.dataRows.getRange(start, end); 183 | }, 184 | getItemMetadata: undefined 185 | }; 186 | } 187 | 188 | ngOnChanges(changes: { [propName: string]: SimpleChange }): void { 189 | let columnDefinitionChanges = changes['columnDefinitions']; 190 | let activeCell = this._grid ? this._grid.getActiveCell() : undefined; 191 | let hasGridStructureChanges = false; 192 | let wasEditing = this._grid ? !!this._grid.getCellEditor() : false; 193 | 194 | if (columnDefinitionChanges 195 | && !_.isEqual(columnDefinitionChanges.previousValue, columnDefinitionChanges.currentValue)) { 196 | this.updateSchema(); 197 | if (!this._grid) { 198 | this.initGrid(); 199 | } else { 200 | this._grid.resetActiveCell(); 201 | this._grid.setColumns(this._gridColumns); 202 | } 203 | hasGridStructureChanges = true; 204 | 205 | if (!columnDefinitionChanges.currentValue || columnDefinitionChanges.currentValue.length === 0) { 206 | activeCell = undefined; 207 | } 208 | if (activeCell) { 209 | let columnThatContainedActiveCell = columnDefinitionChanges.previousValue[Math.max(activeCell.cell - 1, 0)]; 210 | let newActiveColumnIndex = columnThatContainedActiveCell 211 | ? columnDefinitionChanges.currentValue.findIndex(c => c.id === columnThatContainedActiveCell.id) 212 | : -1; 213 | activeCell.cell = newActiveColumnIndex !== -1 ? newActiveColumnIndex + 1 : 0; 214 | } 215 | } 216 | 217 | if (changes['dataRows'] 218 | || (changes['highlightedCells'] && !_.isEqual(changes['highlightedCells'].currentValue, changes['highlightedCells'].previousValue)) 219 | || (changes['blurredColumns'] && !_.isEqual(changes['blurredColumns'].currentValue, changes['blurredColumns'].previousValue)) 220 | || (changes['columnsLoading'] && !_.isEqual(changes['columnsLoading'].currentValue, changes['columnsLoading'].previousValue))) { 221 | this.setCallbackOnDataRowsChanged(); 222 | this._grid.updateRowCount(); 223 | this._grid.setColumns(this._grid.getColumns()); 224 | this._grid.invalidateAllRows(); 225 | this._grid.render(); 226 | hasGridStructureChanges = true; 227 | } 228 | 229 | if (hasGridStructureChanges) { 230 | if (activeCell) { 231 | this._grid.setActiveCell(activeCell.row, activeCell.cell); 232 | } else { 233 | this._grid.resetActiveCell(); 234 | } 235 | } 236 | 237 | if (wasEditing && hasGridStructureChanges) { 238 | this._grid.editActiveCell(); 239 | } 240 | } 241 | 242 | ngOnInit(): void { 243 | // ngOnInit() will be called *after* the first time ngOnChanges() is called 244 | // so, grid must be there already 245 | if (this.topRowNumber === undefined) { 246 | this.topRowNumber = 0; 247 | } 248 | if (this.dataRows && this.dataRows.getLength() > 0) { 249 | this._grid.scrollRowToTop(this.topRowNumber); 250 | } 251 | 252 | if (this.resized) { 253 | // Re-rendering the grid is expensive. Throttle so we only do so every 100ms. 254 | this.resized.throttleTime(100) 255 | .subscribe(() => this.onResize()); 256 | } 257 | 258 | // subscribe to slick events 259 | // https://github.com/mleibman/SlickGrid/wiki/Grid-Events 260 | this.setupEvents(); 261 | } 262 | 263 | ngAfterViewInit(): void { 264 | this.loadFinished.emit(); 265 | } 266 | 267 | ngOnDestroy(): void { 268 | if (this._resizeSubscription !== undefined) { 269 | this._resizeSubscription.unsubscribe(); 270 | } 271 | if (this._gridSyncSubscription !== undefined) { 272 | this._gridSyncSubscription.unsubscribe(); 273 | } 274 | } 275 | 276 | ////////// Public functions - Add public API functions here ////////////// 277 | 278 | // Enables editing on the grid 279 | public enterEditSession(): void { 280 | this.changeEditSession(true); 281 | } 282 | 283 | // Disables editing on the grid 284 | public endEditSession(): void { 285 | this.changeEditSession(false); 286 | } 287 | 288 | // Called whenever the grid's selected rows change 289 | // Event args: { rows: number[] } 290 | public get onSelectedRowsChanged(): Slick.Event> { 291 | return this._grid.onSelectedRowsChanged; 292 | } 293 | 294 | // Returns an array of row indices corresponding to the currently selected rows. 295 | public getSelectedRows(): number[] { 296 | return this._grid.getSelectedRows(); 297 | } 298 | 299 | // Gets the column index of the column with the given name 300 | public getColumnIndex(name: string): number { 301 | return this._columnNameToIndex[name]; 302 | } 303 | 304 | // Gets a ISlickRange corresponding to the current selection on the grid 305 | public getSelectedRanges(): Slick.Range[] { 306 | let selectionModel = this._grid.getSelectionModel(); 307 | if (selectionModel && selectionModel.getSelectedRanges) { 308 | return selectionModel.getSelectedRanges(); 309 | } 310 | } 311 | 312 | // Registers a Slick plugin with the given name 313 | public registerPlugin(plugin: Slick.Plugin | string): void { 314 | if (typeof plugin === 'object') { 315 | this._grid.registerPlugin(plugin); 316 | } else if (typeof plugin === 'string' && Slick[plugin] && typeof Slick[plugin] === 'function') { 317 | this._grid.registerPlugin(new Slick[plugin]); 318 | } else { 319 | console.error(`Tried to register plugin ${plugin}, but none was found to be attached to Slick Grid or it was not a function. 320 | Please extend the Slick with the plugin as a function before registering`); 321 | } 322 | } 323 | 324 | // Set this grid to be the active grid 325 | public setActive(): void { 326 | this._grid.setActiveCell(0, 1); 327 | } 328 | 329 | // Set the grid's selection 330 | public set selection(ranges: Slick.Range[] | boolean) { 331 | if (typeof ranges === 'boolean') { 332 | if (ranges) { 333 | let rows = []; 334 | for (let i = 0; i < this._grid.getDataLength(); i++) { 335 | rows.push(i); 336 | } 337 | this._grid.setSelectedRows(rows); 338 | } else { 339 | this._grid.setSelectedRows([]); 340 | } 341 | } else { 342 | let selectionModel = this._grid.getSelectionModel(); 343 | if (selectionModel && selectionModel.setSelectedRanges) { 344 | selectionModel.setSelectedRanges(ranges); 345 | } 346 | } 347 | } 348 | 349 | ////////// Private functions ////////////////////////////////////////////// 350 | 351 | private initGrid(): void { 352 | // https://github.com/mleibman/SlickGrid/wiki/Grid-Options 353 | let options = { 354 | enableCellNavigation: true, 355 | enableColumnReorder: this.enableColumnReorder, 356 | renderRowWithRange: true, 357 | showHeader: this.showHeader, 358 | rowHeight: this.rowHeight, 359 | defaultColumnWidth: 120, 360 | editable: this.enableEditing, 361 | autoEdit: this.enableEditing, 362 | enableAddRow: false, // TODO change when we support enableAddRow 363 | enableAsyncPostRender: this.enableAsyncPostRender, 364 | editorFactory: { 365 | getEditor: (column: ISlickColumn) => this.getColumnEditor(column) 366 | }, 367 | formatterFactory: { 368 | getFormatter: this.getFormatter 369 | }, 370 | disableColumnBasedCellVirtualization: true, 371 | enableInGridTabNavigation: false 372 | }; 373 | 374 | this._grid = new Slick.Grid( 375 | this._el.nativeElement.getElementsByClassName('grid')[0], 376 | this._gridData, 377 | this._gridColumns, 378 | options); 379 | 380 | if (this.selectionModel) { 381 | if (typeof this.selectionModel === 'object') { 382 | this._grid.setSelectionModel(this.selectionModel); 383 | } else if (typeof this.selectionModel === 'string' && Slick[this.selectionModel] && typeof Slick[this.selectionModel] === 'function') { 384 | this._grid.setSelectionModel(new Slick[this.selectionModel]()); 385 | } else { 386 | console.error(`Tried to register selection model ${this.selectionModel}, 387 | but none was found to be attached to Slick Grid or it was not a function. 388 | Please extend the Slick namespace with the selection model as a function before registering`); 389 | } 390 | } 391 | 392 | for (let plugin of this.plugins) { 393 | this.registerPlugin(plugin); 394 | } 395 | 396 | this._columnNameToIndex = {}; 397 | for (let i = 0; i < this._gridColumns.length; i++) { 398 | this._columnNameToIndex[this._gridColumns[i].name] = i; 399 | } 400 | 401 | this.onResize(); 402 | } 403 | 404 | private changeEditSession(enabled: boolean): void { 405 | this.enableEditing = enabled; 406 | let options: any = this._grid.getOptions(); 407 | options.editable = enabled; 408 | options.enableAddRow = false; // TODO change to " options.enableAddRow = false;" when we support enableAddRow 409 | this._grid.setOptions(options); 410 | } 411 | 412 | private onResize(): void { 413 | if (this._grid !== undefined) { 414 | // this will make sure the grid header and body to be re-rendered 415 | this._grid.resizeCanvas(); 416 | } 417 | } 418 | 419 | private invalidateRange(start: number, end: number): void { 420 | let refreshedRows = _.range(start, end); 421 | this._grid.invalidateRows(refreshedRows, true); 422 | this._grid.render(); 423 | } 424 | 425 | private getColumnEditor(column: ISlickColumn): any { 426 | if (column.isEditable === false || typeof column.isEditable === 'undefined') { 427 | return undefined; 428 | } 429 | 430 | let columnId = column.id; 431 | let isColumnLoading = this.columnsLoading && this.columnsLoading.indexOf(columnId) !== -1; 432 | let canEditColumn = columnId !== undefined && !isColumnLoading; 433 | if (canEditColumn) { 434 | return getOverridableTextEditorClass(this); 435 | } 436 | return undefined; 437 | } 438 | 439 | private getFormatter = (column: any): any => { 440 | return (row, cell, value, columnDef, dataContext) => { 441 | let columnId = cell > 0 && this.columnDefinitions.length > cell - 1 ? this.columnDefinitions[cell - 1].id : undefined; 442 | if (columnId) { 443 | let isHighlighted = this.highlightedCells && !!this.highlightedCells.find(c => c.row === row && c.column + 1 === cell); 444 | let isColumnLoading = this.columnsLoading && this.columnsLoading.indexOf(columnId) !== -1; 445 | let isShadowed = this.blurredColumns && !!this.blurredColumns.find(c => c === columnId); 446 | let isContext = this.contextColumns && !!this.contextColumns.find(c => c === columnId); 447 | let overrideValue = this.overrideCellFn && this.overrideCellFn(row, columnId, value, dataContext); 448 | 449 | let valueToDisplay = (value + '').replace(/&/g, '&').replace(//g, '>'); 450 | let cellClasses = 'grid-cell-value-container'; 451 | 452 | /* tslint:disable:no-null-keyword */ 453 | let valueMissing = value === undefined || value === null; 454 | /* tslint:disable:no-null-keyword */ 455 | let isOverridden = overrideValue !== undefined && overrideValue !== null; 456 | 457 | if (valueMissing && !isOverridden) { 458 | cellClasses += ' missing-value'; 459 | } 460 | 461 | if (isColumnLoading === true && !isOverridden) { 462 | cellClasses += ' loading-cell'; 463 | valueToDisplay = ''; 464 | } 465 | 466 | if (isOverridden) { 467 | cellClasses += ' override-cell'; 468 | valueToDisplay = overrideValue; 469 | } 470 | 471 | if (isContext) { 472 | cellClasses += ' context'; 473 | } 474 | 475 | if (isHighlighted === true) { 476 | cellClasses += ' highlighted'; 477 | } 478 | 479 | if (isShadowed && !isHighlighted && !isOverridden) { 480 | cellClasses += ' blurred'; 481 | } 482 | 483 | return '' + valueToDisplay + ''; 484 | } 485 | 486 | }; 487 | } 488 | 489 | private setupEvents(): void { 490 | this._grid.onScroll.subscribe((e, args) => { 491 | this.onScroll.emit(args); 492 | }); 493 | this._grid.onCellChange.subscribe((e, args) => { 494 | this.onCellChange.emit(args); 495 | }); 496 | this._grid.onBeforeEditCell.subscribe((e, args) => { 497 | this.onBeforeEditCell.emit(args); 498 | }); 499 | // Subscribe to all active cell changes to be able to catch when we tab to the header on the next row 500 | this._grid.onActiveCellChanged.subscribe((e, args) => { 501 | // Emit that we've changed active cells 502 | this.onActiveCellChanged.emit(args); 503 | }); 504 | this._grid.onContextMenu.subscribe((e, args) => { 505 | this.onContextMenu.emit(e); 506 | }); 507 | this._grid.onBeforeAppendCell.subscribe((e, args) => { 508 | // Since we need to return a string here, we are using calling a function instead of event emitter like other events handlers 509 | return this.onBeforeAppendCell ? this.onBeforeAppendCell(args.row, args.cell) : undefined; 510 | }); 511 | this._grid.onRendered.subscribe((e, args) => { 512 | this.onRendered.emit(args); 513 | }); 514 | } 515 | 516 | private updateSchema(): void { 517 | if (!this.columnDefinitions) { 518 | return; 519 | } 520 | 521 | this._gridColumns = this.columnDefinitions; 522 | } 523 | 524 | private setCallbackOnDataRowsChanged(): void { 525 | if (this.dataRows) { 526 | // We must wait until we get the first set of dataRows before we enable editing or slickgrid will complain 527 | if (this.enableEditing) { 528 | this.enterEditSession(); 529 | } 530 | 531 | this.dataRows.setCollectionChangedCallback((change: CollectionChange, startIndex: number, count: number) => { 532 | this.renderGridDataRowsRange(startIndex, count); 533 | }); 534 | } 535 | } 536 | 537 | public get activeCell(): Slick.Cell { 538 | return this._grid.getActiveCell(); 539 | } 540 | 541 | private renderGridDataRowsRange(startIndex: number, count: number): void { 542 | let editor = this._grid.getCellEditor(); 543 | let oldValue = editor ? editor.getValue() : undefined; 544 | let wasValueChanged = editor ? editor.isValueChanged() : false; 545 | this.invalidateRange(startIndex, startIndex + count); 546 | let activeCell = this.activeCell; 547 | if (editor && activeCell.row >= startIndex && activeCell.row < startIndex + count) { 548 | if (oldValue && wasValueChanged) { 549 | editor.setValue(oldValue); 550 | } 551 | } 552 | } 553 | 554 | /* andresse: commented out 11/1/2016 due to minification issues 555 | private get finishGridEditingFn(): (e: any, args: any) => void { 556 | if (this._finishGridEditingFn === undefined) { 557 | this._finishGridEditingFn = ((e: any, args: any) => { 558 | if (e.ctrlKey === true 559 | && e.keyCode === 13 560 | && this.editableColumnIds 561 | && this.editableColumnIds.find(id => id === args.columnDef.id)) { 562 | // pressed [Ctrl + Enter] in the editing area 563 | this.editingFinished.next(undefined); 564 | } 565 | }).bind(this); 566 | } 567 | 568 | return this._finishGridEditingFn; 569 | } 570 | */ 571 | } 572 | -------------------------------------------------------------------------------- /components/js/virtualizedCollection.ts: -------------------------------------------------------------------------------- 1 | /*--------------------------------------------------------------------------------------------- 2 | * Copyright (c) Microsoft Corporation. All rights reserved. 3 | * Licensed under the MIT License. See License.txt in the project root for license information. 4 | *--------------------------------------------------------------------------------------------*/ 5 | import { IObservableCollection, CollectionChange } from './interfaces'; 6 | 7 | class LoadCancellationToken { 8 | isCancelled: boolean; 9 | } 10 | 11 | class DataWindow { 12 | private _dataSourceLength: number; 13 | private _data: TData[]; 14 | private _length: number = 0; 15 | private _offsetFromDataSource: number = -1; 16 | 17 | private loadFunction: (offset: number, count: number) => Promise; 18 | private lastLoadCancellationToken: LoadCancellationToken; 19 | private loadCompleteCallback: (start: number, end: number) => void; 20 | private placeholderItemGenerator: (index: number) => TData; 21 | 22 | constructor(dataSourceLength: number, 23 | loadFunction: (offset: number, count: number) => Promise, 24 | placeholderItemGenerator: (index: number) => TData, 25 | loadCompleteCallback: (start: number, end: number) => void) { 26 | this._dataSourceLength = dataSourceLength; 27 | this.loadFunction = loadFunction; 28 | this.placeholderItemGenerator = placeholderItemGenerator; 29 | this.loadCompleteCallback = loadCompleteCallback; 30 | } 31 | 32 | getStartIndex(): number { 33 | return this._offsetFromDataSource; 34 | } 35 | 36 | getEndIndex(): number { 37 | return this._offsetFromDataSource + this._length; 38 | } 39 | 40 | contains(dataSourceIndex: number): boolean { 41 | return dataSourceIndex >= this.getStartIndex() && dataSourceIndex < this.getEndIndex(); 42 | } 43 | 44 | getItem(index: number): TData { 45 | if (!this._data) { 46 | return this.placeholderItemGenerator(index); 47 | } 48 | return this._data[index - this._offsetFromDataSource]; 49 | } 50 | 51 | positionWindow(offset: number, length: number): void { 52 | this._offsetFromDataSource = offset; 53 | this._length = length; 54 | this._data = undefined; 55 | 56 | if (this.lastLoadCancellationToken) { 57 | this.lastLoadCancellationToken.isCancelled = true; 58 | } 59 | 60 | if (length === 0) { 61 | return; 62 | } 63 | 64 | let cancellationToken = new LoadCancellationToken(); 65 | this.lastLoadCancellationToken = cancellationToken; 66 | this.loadFunction(offset, length).then(data => { 67 | if (!cancellationToken.isCancelled) { 68 | this._data = data; 69 | this.loadCompleteCallback(this._offsetFromDataSource, this._offsetFromDataSource + this._length); 70 | } 71 | }); 72 | } 73 | } 74 | 75 | export class VirtualizedCollection implements IObservableCollection { 76 | 77 | private _length: number; 78 | private _windowSize: number; 79 | private _bufferWindowBefore: DataWindow; 80 | private _window: DataWindow; 81 | private _bufferWindowAfter: DataWindow; 82 | 83 | private collectionChangedCallback: (change: CollectionChange, startIndex: number, count: number) => void; 84 | 85 | constructor(windowSize: number, 86 | length: number, 87 | loadFn: (offset: number, count: number) => Promise, 88 | private _placeHolderGenerator: (index: number) => TData) { 89 | this._windowSize = windowSize; 90 | this._length = length; 91 | 92 | let loadCompleteCallback = (start: number, end: number) => { 93 | if (this.collectionChangedCallback) { 94 | this.collectionChangedCallback(CollectionChange.ItemsReplaced, start, end - start); 95 | } 96 | }; 97 | 98 | this._bufferWindowBefore = new DataWindow(length, loadFn, _placeHolderGenerator, loadCompleteCallback); 99 | this._window = new DataWindow(length, loadFn, _placeHolderGenerator, loadCompleteCallback); 100 | this._bufferWindowAfter = new DataWindow(length, loadFn, _placeHolderGenerator, loadCompleteCallback); 101 | } 102 | 103 | setCollectionChangedCallback(callback: (change: CollectionChange, startIndex: number, count: number) => void): void { 104 | this.collectionChangedCallback = callback; 105 | } 106 | 107 | getLength(): number { 108 | return this._length; 109 | } 110 | 111 | at(index: number): TData { 112 | return this.getRange(index, index + 1)[0]; 113 | } 114 | 115 | getRange(start: number, end: number): TData[] { 116 | 117 | // current data may contain placeholders 118 | let currentData = this.getRangeFromCurrent(start, end); 119 | 120 | // only shift window and make promise of refreshed data in following condition: 121 | if (start < this._bufferWindowBefore.getStartIndex() || end > this._bufferWindowAfter.getEndIndex()) { 122 | // jump, reset 123 | this.resetWindowsAroundIndex(start); 124 | } else if (end <= this._bufferWindowBefore.getEndIndex()) { 125 | // scroll up, shift up 126 | let windowToRecycle = this._bufferWindowAfter; 127 | this._bufferWindowAfter = this._window; 128 | this._window = this._bufferWindowBefore; 129 | this._bufferWindowBefore = windowToRecycle; 130 | let newWindowOffset = Math.max(0, this._window.getStartIndex() - this._windowSize); 131 | 132 | this._bufferWindowBefore.positionWindow(newWindowOffset, this._window.getStartIndex() - newWindowOffset); 133 | } else if (start >= this._bufferWindowAfter.getStartIndex()) { 134 | // scroll down, shift down 135 | let windowToRecycle = this._bufferWindowBefore; 136 | this._bufferWindowBefore = this._window; 137 | this._window = this._bufferWindowAfter; 138 | this._bufferWindowAfter = windowToRecycle; 139 | let newWindowOffset = Math.min(this._window.getStartIndex() + this._windowSize, this._length); 140 | let newWindowLength = Math.min(this._length - newWindowOffset, this._windowSize); 141 | 142 | this._bufferWindowAfter.positionWindow(newWindowOffset, newWindowLength); 143 | } 144 | 145 | return currentData; 146 | } 147 | 148 | private getRangeFromCurrent(start: number, end: number): TData[] { 149 | let currentData = []; 150 | for (let i = 0; i < end - start; i++) { 151 | currentData.push(this.getDataFromCurrent(start + i)); 152 | } 153 | 154 | return currentData; 155 | } 156 | 157 | private getDataFromCurrent(index: number): TData { 158 | if (this._bufferWindowBefore.contains(index)) { 159 | return this._bufferWindowBefore.getItem(index); 160 | } else if (this._bufferWindowAfter.contains(index)) { 161 | return this._bufferWindowAfter.getItem(index); 162 | } else if (this._window.contains(index)) { 163 | return this._window.getItem(index); 164 | } 165 | 166 | return this._placeHolderGenerator(index); 167 | } 168 | 169 | resetWindowsAroundIndex(index: number): void { 170 | 171 | let bufferWindowBeforeStart = Math.max(0, index - this._windowSize * 1.5); 172 | let bufferWindowBeforeEnd = Math.max(0, index - this._windowSize / 2); 173 | this._bufferWindowBefore.positionWindow(bufferWindowBeforeStart, bufferWindowBeforeEnd - bufferWindowBeforeStart); 174 | 175 | let mainWindowStart = bufferWindowBeforeEnd; 176 | let mainWindowEnd = Math.min(mainWindowStart + this._windowSize, this._length); 177 | this._window.positionWindow(mainWindowStart, mainWindowEnd - mainWindowStart); 178 | 179 | let bufferWindowAfterStart = mainWindowEnd; 180 | let bufferWindowAfterEnd = Math.min(bufferWindowAfterStart + this._windowSize, this._length); 181 | this._bufferWindowAfter.positionWindow(bufferWindowAfterStart, bufferWindowAfterEnd - bufferWindowAfterStart); 182 | } 183 | } 184 | -------------------------------------------------------------------------------- /components/typings/slick.d.ts: -------------------------------------------------------------------------------- 1 | // Generated by typings 2 | // Source: https://raw.githubusercontent.com/DefinitelyTyped/DefinitelyTyped/5607f54defce88bc52a0440288f434cafffdb5ce/slickgrid/index.d.ts 3 | interface DOMEvent extends Event {} 4 | 5 | declare namespace Slick { 6 | 7 | /** 8 | * slick.core.js 9 | **/ 10 | 11 | /** 12 | * An event object for passing data to event handlers and letting them control propagation. 13 | *

This is pretty much identical to how W3C and jQuery implement events.

14 | * @class EventData 15 | * @constructor 16 | **/ 17 | export class EventData { 18 | 19 | constructor(); 20 | 21 | /*** 22 | * Stops event from propagating up the DOM tree. 23 | * @method stopPropagation 24 | */ 25 | public stopPropagation(): void; 26 | 27 | /*** 28 | * Returns whether stopPropagation was called on this event object. 29 | * @method isPropagationStopped 30 | * @return {Boolean} 31 | */ 32 | public isPropagationStopped(): boolean; 33 | 34 | /*** 35 | * Prevents the rest of the handlers from being executed. 36 | * @method stopImmediatePropagation 37 | */ 38 | public stopImmediatePropagation(): void; 39 | 40 | /*** 41 | * Returns whether stopImmediatePropagation was called on this event object.\ 42 | * @method isImmediatePropagationStopped 43 | * @return {Boolean} 44 | */ 45 | public isImmediatePropagationStopped(): boolean; 46 | } 47 | 48 | /*** 49 | * A simple publisher-subscriber implementation. 50 | * @class Event 51 | * @constructor 52 | */ 53 | export class Event { 54 | 55 | constructor(); 56 | 57 | /*** 58 | * Adds an event handler to be called when the event is fired. 59 | *

Event handler will receive two arguments - an EventData and the data 60 | * object the event was fired with.

61 | * @method subscribe 62 | * @param fn {Function} Event handler. 63 | */ 64 | public subscribe(fn: (e: EventData, data: T) => any): void; 65 | public subscribe(fn: (e: DOMEvent, data: T) => any): void; 66 | 67 | /*** 68 | * Removes an event handler added with subscribe(fn). 69 | * @method unsubscribe 70 | * @param fn {Function} Event handler to be removed. 71 | */ 72 | public unsubscribe(fn: (e: EventData, data: T) => any): void; 73 | public unsubscribe(fn: (e: DOMEvent, data: T) => any): void; 74 | 75 | /*** 76 | * Fires an event notifying all subscribers. 77 | * @method notify 78 | * @param args {Object} Additional data object to be passed to all handlers. 79 | * @param e {EventData} 80 | * Optional. 81 | * An EventData object to be passed to all handlers. 82 | * For DOM events, an existing W3C/jQuery event object can be passed in. 83 | * @param scope {Object} 84 | * Optional. 85 | * The scope ("this") within which the handler will be executed. 86 | * If not specified, the scope will be set to the Event instance. 87 | * @return Last run callback result. 88 | * @note slick.core.Event.notify shows this method as returning a value, type is unknown. 89 | */ 90 | public notify(args?: T, e?: EventData, scope?: any): any; 91 | public notify(args?: T, e?: DOMEvent, scope?: any): any; 92 | 93 | } 94 | 95 | // todo: is this private? there are no comments in the code 96 | export class EventHandler { 97 | constructor(); 98 | 99 | public subscribe(event: EventData, handler: Function): EventHandler; 100 | public unsubscribe(event: EventData, handler: Function): EventHandler; 101 | public unsubscribeAll(): EventHandler; 102 | } 103 | 104 | /*** 105 | * A structure containing a range of cells. 106 | * @class Range 107 | **/ 108 | export class Range { 109 | 110 | /** 111 | * A structure containing a range of cells. 112 | * @constructor 113 | * @param fromRow {Integer} Starting row. 114 | * @param fromCell {Integer} Starting cell. 115 | * @param toRow {Integer} Optional. Ending row. Defaults to fromRow. 116 | * @param toCell {Integer} Optional. Ending cell. Defaults to fromCell. 117 | **/ 118 | constructor(fromRow: number, fromCell: number, toRow?: number, toCell?: number); 119 | 120 | /*** 121 | * @property fromRow 122 | * @type {Integer} 123 | */ 124 | public fromRow: number; 125 | 126 | /*** 127 | * @property fromCell 128 | * @type {Integer} 129 | */ 130 | public fromCell: number; 131 | 132 | /*** 133 | * @property toRow 134 | * @type {Integer} 135 | */ 136 | public toRow: number; 137 | 138 | /*** 139 | * @property toCell 140 | * @type {Integer} 141 | */ 142 | public toCell: number; 143 | 144 | /*** 145 | * Returns whether a range represents a single row. 146 | * @method isSingleRow 147 | * @return {Boolean} 148 | */ 149 | public isSingleRow(): boolean; 150 | 151 | /*** 152 | * Returns whether a range represents a single cell. 153 | * @method isSingleCell 154 | * @return {Boolean} 155 | */ 156 | public isSingleCell(): boolean; 157 | 158 | /*** 159 | * Returns whether a range contains a given cell. 160 | * @method contains 161 | * @param row {Integer} 162 | * @param cell {Integer} 163 | * @return {Boolean} 164 | */ 165 | public contains(row: number, cell: number): boolean; 166 | 167 | /*** 168 | * Returns a readable representation of a range. 169 | * @method toString 170 | * @return {String} 171 | */ 172 | public toString(): string; 173 | 174 | } 175 | 176 | /*** 177 | * A base class that all special / non-data rows (like Group and GroupTotals) derive from. 178 | * @class NonDataItem 179 | * @constructor 180 | */ 181 | export class NonDataRow { 182 | 183 | } 184 | 185 | /*** 186 | * Information about a group of rows. 187 | * @class Group 188 | * @extends Slick.NonDataItem 189 | * @constructor 190 | */ 191 | export class Group extends NonDataRow { 192 | 193 | constructor(); 194 | 195 | /** 196 | * Grouping level, starting with 0. 197 | * @property level 198 | * @type {Number} 199 | */ 200 | public level: number; 201 | 202 | /*** 203 | * Number of rows in the group. 204 | * @property count 205 | * @type {Integer} 206 | */ 207 | public count: number; 208 | 209 | /*** 210 | * Grouping value. 211 | * @property value 212 | * @type {Object} 213 | */ 214 | public value: any; 215 | 216 | /*** 217 | * Formatted display value of the group. 218 | * @property title 219 | * @type {String} 220 | */ 221 | public title: string; 222 | 223 | /*** 224 | * Whether a group is collapsed. 225 | * @property collapsed 226 | * @type {Boolean} 227 | */ 228 | public collapsed: boolean; 229 | 230 | /*** 231 | * GroupTotals, if any. 232 | * @property totals 233 | * @type {GroupTotals} 234 | */ 235 | public totals: GroupTotals; 236 | 237 | /** 238 | * Rows that are part of the group. 239 | * @property rows 240 | * @type {Array} 241 | */ 242 | public rows: T[]; 243 | 244 | /** 245 | * Sub-groups that are part of the group. 246 | * @property groups 247 | * @type {Array} 248 | */ 249 | public groups: Group[]; 250 | 251 | /** 252 | * A unique key used to identify the group. This key can be used in calls to DataView 253 | * collapseGroup() or expandGroup(). 254 | * @property groupingKey 255 | * @type {Object} 256 | */ 257 | public groupingKey: any; 258 | 259 | /*** 260 | * Compares two Group instances. 261 | * @method equals 262 | * @return {Boolean} 263 | * @param group {Group} Group instance to compare to. 264 | * todo: this is on the prototype (NonDataRow()) instance, not Group, maybe doesn't matter? 265 | */ 266 | public equals(group: Group): boolean; 267 | } 268 | 269 | /*** 270 | * Information about group totals. 271 | * An instance of GroupTotals will be created for each totals row and passed to the aggregators 272 | * so that they can store arbitrary data in it. That data can later be accessed by group totals 273 | * formatters during the display. 274 | * @class GroupTotals 275 | * @extends Slick.NonDataItem 276 | * @constructor 277 | */ 278 | export class GroupTotals extends NonDataRow { 279 | 280 | constructor(); 281 | 282 | /*** 283 | * Parent Group. 284 | * @param group 285 | * @type {Group} 286 | */ 287 | public group: Group; 288 | 289 | } 290 | 291 | /*** 292 | * A locking helper to track the active edit controller and ensure that only a single controller 293 | * can be active at a time. This prevents a whole class of state and validation synchronization 294 | * issues. An edit controller (such as SlickGrid) can query if an active edit is in progress 295 | * and attempt a commit or cancel before proceeding. 296 | * @class EditorLock 297 | * @constructor 298 | */ 299 | export class EditorLock { 300 | 301 | constructor(); 302 | 303 | /*** 304 | * Returns true if a specified edit controller is active (has the edit lock). 305 | * If the parameter is not specified, returns true if any edit controller is active. 306 | * @method isActive 307 | * @param editController {EditController} 308 | * @return {Boolean} 309 | */ 310 | public isActive(editController: Editors.Editor): boolean; 311 | 312 | /*** 313 | * Sets the specified edit controller as the active edit controller (acquire edit lock). 314 | * If another edit controller is already active, and exception will be thrown. 315 | * @method activate 316 | * @param editController {EditController} edit controller acquiring the lock 317 | */ 318 | public activate(editController: Editors.Editor): void; 319 | 320 | /*** 321 | * Unsets the specified edit controller as the active edit controller (release edit lock). 322 | * If the specified edit controller is not the active one, an exception will be thrown. 323 | * @method deactivate 324 | * @param editController {EditController} edit controller releasing the lock 325 | */ 326 | public deactivate(editController: Editors.Editor): void; 327 | 328 | /*** 329 | * Attempts to commit the current edit by calling "commitCurrentEdit" method on the active edit 330 | * controller and returns whether the commit attempt was successful (commit may fail due to validation 331 | * errors, etc.). Edit controller's "commitCurrentEdit" must return true if the commit has succeeded 332 | * and false otherwise. If no edit controller is active, returns true. 333 | * @method commitCurrentEdit 334 | * @return {Boolean} 335 | */ 336 | public commitCurrentEdit(): boolean; 337 | 338 | /*** 339 | * Attempts to cancel the current edit by calling "cancelCurrentEdit" method on the active edit 340 | * controller and returns whether the edit was successfully cancelled. If no edit controller is 341 | * active, returns true. 342 | * @method cancelCurrentEdit 343 | * @return {Boolean} 344 | */ 345 | public cancelCurrentEdit(): boolean; 346 | } 347 | 348 | /** 349 | * A global singleton editor lock. 350 | * @class GlobalEditorLock 351 | * @static 352 | * @constructor 353 | **/ 354 | export var GlobalEditorLock: EditorLock; 355 | 356 | /** 357 | * slick.grid.js 358 | **/ 359 | 360 | /** 361 | * Options which you can apply to the columns objects. 362 | **/ 363 | export interface Column { 364 | 365 | /** 366 | * This accepts a function of the form function(cellNode, row, dataContext, colDef) and is used to post-process the cell's DOM node / nodes 367 | * @param cellNode 368 | * @param row 369 | * @param dataContext 370 | * @param colDef 371 | * @return 372 | **/ 373 | asyncPostRender?: (cellNode:any, row:any, dataContext:any, colDef:any) => void; 374 | 375 | /** 376 | * Used by the the slick.rowMoveManager.js plugin for moving rows. Has no effect without the plugin installed. 377 | **/ 378 | behavior?: any; 379 | 380 | /** 381 | * In the "Add New" row, determines whether clicking cells in this column can trigger row addition. If true, clicking on the cell in this column in the "Add New" row will not trigger row addition. 382 | **/ 383 | cannotTriggerInsert?: boolean; 384 | 385 | /** 386 | * Accepts a string as a class name, applies that class to every row cell in the column. 387 | **/ 388 | cssClass?: string; 389 | 390 | /** 391 | * When set to true, the first user click on the header will do a descending sort. When set to false, the first user click on the header will do an ascending sort. 392 | **/ 393 | defaultSortAsc?: boolean; 394 | 395 | /** 396 | * The editor for cell edits {TextEditor, IntegerEditor, DateEditor...} See slick.editors.js 397 | **/ 398 | editor?: any; // typeof Editors.Editor; 399 | 400 | /** 401 | * The property name in the data object to pull content from. (This is assumed to be on the root of the data object.) 402 | **/ 403 | field?: string; 404 | 405 | /** 406 | * When set to false, clicking on a cell in this column will not select the row for that cell. The cells in this column will also be skipped during tab navigation. 407 | **/ 408 | focusable?: boolean; 409 | 410 | /** 411 | * This accepts a function of the form function(row, cell, value, columnDef, dataContext) and returns a formatted version of the data in each cell of this column. For example, setting formatter to function(r, c, v, cd, dc) { return "Hello!"; } would overwrite every value in the column with "Hello!" See defaultFormatter in slick.grid.js for an example formatter. 412 | * @param row 413 | * @param cell 414 | * @param value 415 | * @param columnDef 416 | * @param dataContext 417 | * @return 418 | **/ 419 | formatter?: Formatter; 420 | 421 | /** 422 | * Accepts a string as a class name, applies that class to the cell for the column header. 423 | **/ 424 | headerCssClass?: string; 425 | 426 | /** 427 | * A unique identifier for the column within the grid. 428 | **/ 429 | id?: string; 430 | 431 | /** 432 | * Set the maximum allowable width of this column, in pixels. 433 | **/ 434 | maxWidth?: number; 435 | 436 | /** 437 | * Set the minimum allowable width of this column, in pixels. 438 | **/ 439 | minWidth?: number; 440 | 441 | /** 442 | * The text to display on the column heading. 443 | **/ 444 | name?: string; 445 | 446 | /** 447 | * If set to true, whenever this column is resized, the entire table view will rerender. 448 | **/ 449 | rerenderOnResize?: boolean; 450 | 451 | /** 452 | * If false, column can no longer be resized. 453 | **/ 454 | resizable?: boolean; 455 | 456 | /** 457 | * If false, when a row is selected, the CSS class for selected cells ("selected" by default) is not applied to the cell in this column. 458 | **/ 459 | selectable?: boolean; 460 | 461 | /** 462 | * If true, the column will be sortable by clicking on the header. 463 | **/ 464 | sortable?: boolean; 465 | 466 | /** 467 | * If set to a non-empty string, a tooltip will appear on hover containing the string. 468 | **/ 469 | toolTip?: string; 470 | 471 | /** 472 | * Width of the column in pixels. (May often be overridden by things like minWidth, maxWidth, forceFitColumns, etc.) 473 | **/ 474 | width?: number; 475 | } 476 | 477 | export interface EditorFactory { 478 | getEditor(column: Column): Editors.Editor; 479 | } 480 | 481 | export interface FormatterFactory { 482 | getFormatter(column: Column): Formatter; 483 | } 484 | 485 | export interface GridOptions { 486 | 487 | /** 488 | * Makes cell editors load asynchronously after a small delay. This greatly increases keyboard navigation speed. 489 | **/ 490 | asyncEditorLoading?: boolean; 491 | 492 | /** 493 | * Delay after which cell editor is loaded. Ignored unless asyncEditorLoading is true. 494 | **/ 495 | asyncEditorLoadDelay?: number; 496 | 497 | /** 498 | * 499 | **/ 500 | asyncPostRenderDelay?: number; 501 | 502 | /** 503 | * Cell will not automatically go into edit mode when selected. 504 | **/ 505 | autoEdit?: boolean; 506 | 507 | /** 508 | * 509 | **/ 510 | autoHeight?: boolean; 511 | 512 | /** 513 | * A CSS class to apply to flashing cells via flashCell(). 514 | **/ 515 | cellFlashingCssClass?: string; 516 | 517 | /** 518 | * A CSS class to apply to cells highlighted via setHighlightedCells(). 519 | **/ 520 | cellHighlightCssClass?: string; 521 | 522 | /** 523 | * 524 | **/ 525 | dataItemColumnValueExtractor?: any; 526 | 527 | /** 528 | * 529 | **/ 530 | defaultColumnWidth?: number; 531 | 532 | /** 533 | * 534 | **/ 535 | defaultFormatter?: Formatter; 536 | 537 | /** 538 | * 539 | **/ 540 | editable?: boolean; 541 | 542 | /** 543 | * Not listed as a default under options in slick.grid.js 544 | **/ 545 | editCommandHandler?: any; // queueAndExecuteCommand 546 | 547 | /** 548 | * A factory object responsible to creating an editor for a given cell. Must implement getEditor(column). 549 | **/ 550 | editorFactory?: EditorFactory; 551 | 552 | /** 553 | * A Slick.EditorLock instance to use for controlling concurrent data edits. 554 | **/ 555 | editorLock?: EditorLock; 556 | 557 | /** 558 | * If true, a blank row will be displayed at the bottom - typing values in that row will add a new one. Must subscribe to onAddNewRow to save values. 559 | **/ 560 | enableAddRow?: boolean; 561 | 562 | /** 563 | * If true, async post rendering will occur and asyncPostRender delegates on columns will be called. 564 | **/ 565 | enableAsyncPostRender?: boolean; 566 | 567 | /** 568 | * *WARNING*: Not contained in SlickGrid 2.1, may be deprecated 569 | **/ 570 | enableCellRangeSelection?: any; 571 | 572 | /** 573 | * Appears to enable cell virtualisation for optimised speed with large datasets 574 | **/ 575 | enableCellNavigation?: boolean; 576 | 577 | /** 578 | * 579 | **/ 580 | enableColumnReorder?: boolean; 581 | 582 | /** 583 | * *WARNING*: Not contained in SlickGrid 2.1, may be deprecated 584 | **/ 585 | enableRowReordering?: any; 586 | 587 | /** 588 | * 589 | **/ 590 | enableTextSelectionOnCells?: boolean; 591 | 592 | /** 593 | * @see Example: Explicit Initialization 594 | **/ 595 | explicitInitialization?: boolean; 596 | 597 | /** 598 | * Force column sizes to fit into the container (preventing horizontal scrolling). Effectively sets column width to be 1/Number of Columns which on small containers may not be desirable 599 | **/ 600 | forceFitColumns?: boolean; 601 | 602 | /** 603 | * 604 | **/ 605 | forceSyncScrolling?: boolean; 606 | 607 | /** 608 | * A factory object responsible to creating a formatter for a given cell. Must implement getFormatter(column). 609 | **/ 610 | formatterFactory?: FormatterFactory; 611 | 612 | /** 613 | * Will expand the table row divs to the full width of the container, table cell divs will remain aligned to the left 614 | **/ 615 | fullWidthRows?: boolean; 616 | 617 | /** 618 | * 619 | **/ 620 | headerRowHeight?: number; 621 | 622 | /** 623 | * 624 | **/ 625 | leaveSpaceForNewRows?: boolean; 626 | 627 | /** 628 | * @see Example: Multi-Column Sort 629 | **/ 630 | multiColumnSort?: boolean; 631 | 632 | /** 633 | * 634 | **/ 635 | multiSelect?: boolean; 636 | 637 | /** 638 | * 639 | **/ 640 | rowHeight?: number; 641 | 642 | /** 643 | * 644 | **/ 645 | selectedCellCssClass?: string; 646 | 647 | /** 648 | * 649 | **/ 650 | showHeaderRow?: boolean; 651 | 652 | /** 653 | * If true, the column being resized will change its width as the mouse is dragging the resize handle. If false, the column will resize after mouse drag ends. 654 | **/ 655 | syncColumnCellResize?: boolean; 656 | 657 | /** 658 | * 659 | **/ 660 | topPanelHeight?: number; 661 | } 662 | 663 | export interface DataProvider { 664 | /** 665 | * Returns the number of data items in the set. 666 | */ 667 | getLength(): number; 668 | 669 | /** 670 | * Returns the item at a given index. 671 | * @param index 672 | */ 673 | getItem(index: number): T; 674 | 675 | /** 676 | * Returns the metadata for the item at a given index (optional). 677 | * @param index 678 | */ 679 | getItemMetadata?(index: number): RowMetadata; 680 | } 681 | 682 | export interface SlickData { 683 | // todo ? might be able to leave as empty 684 | } 685 | 686 | export interface RowMetadata { 687 | /** 688 | * One or more (space-separated) CSS classes to be added to the entire row. 689 | */ 690 | cssClasses?: string; 691 | 692 | /** 693 | * Whether or not any cells in the row can be set as "active". 694 | */ 695 | focusable?: boolean; 696 | 697 | /** 698 | * Whether or not a row or any cells in it can be selected. 699 | */ 700 | selectable?: boolean; 701 | 702 | /** 703 | * Metadata related to individual columns 704 | */ 705 | columns?: { 706 | /** 707 | * Metadata indexed by column id 708 | */ 709 | [index: string]: ColumnMetadata; 710 | /** 711 | * Metadata indexed by column index 712 | */ 713 | [index: number]: ColumnMetadata; 714 | } 715 | } 716 | 717 | export interface ColumnMetadata { 718 | /** 719 | * Whether or not a cell can be set as "active". 720 | */ 721 | focusable?: boolean; 722 | 723 | /** 724 | * Whether or not a cell can be selected. 725 | */ 726 | selectable?: boolean; 727 | 728 | /** 729 | * A custom cell formatter. 730 | */ 731 | formatter?: Formatter; 732 | 733 | /** 734 | * A custom cell editor. 735 | */ 736 | editor?: Slick.Editors.Editor; 737 | 738 | /** 739 | * Number of columns this cell will span. Can also contain "*" to indicate that the cell should span the rest of the row. 740 | */ 741 | colspan?: number|string; 742 | } 743 | 744 | /** 745 | * Selecting cells in SlickGrid is handled by a selection model. 746 | * Selection models are controllers responsible for handling user interactions and notifying subscribers of the changes in the selection. Selection is represented as an array of Slick.Range objects. 747 | * You can get the current selection model from the grid by calling getSelectionModel() and set a different one using setSelectionModel(selectionModel). By default, no selection model is set. 748 | * The grid also provides two helper methods to simplify development - getSelectedRows() and setSelectedRows(rowsArray), as well as an onSelectedRowsChanged event. 749 | * SlickGrid includes two pre-made selection models - Slick.CellSelectionModel and Slick.RowSelectionModel, but you can easily write a custom one. 750 | **/ 751 | export class SelectionModel { 752 | /** 753 | * An initializer function that will be called with an instance of the grid whenever a selection model is registered with setSelectionModel. The selection model can use this to initialize its state and subscribe to grid events. 754 | **/ 755 | init(grid: Grid): void; 756 | 757 | /** 758 | * A destructor function that will be called whenever a selection model is unregistered from the grid by a call to setSelectionModel with another selection model or whenever a grid with this selection model is destroyed. The selection model can use this destructor to unsubscribe from grid events and release all resources (remove DOM nodes, event listeners, etc.). 759 | **/ 760 | destroy(): void; 761 | 762 | onSelectedRangesChanged: Slick.Event; 763 | 764 | getSelectedRanges?(): Array; 765 | 766 | setSelectedRanges?(ranges: Array); 767 | } 768 | 769 | export class Grid { 770 | 771 | /** 772 | * Create an instance of the grid. 773 | * @param container Container node to create the grid in. This can be a DOM Element, a jQuery node, or a jQuery selector. 774 | * @param data Databinding source. This can either be a regular JavaScript array or a custom object exposing getItem(index) and getLength() functions. 775 | * @param columns An array of column definition objects. See Column Options for a list of options that can be included on each column definition object. 776 | * @param options Additional options. See Grid Options for a list of options that can be included. 777 | **/ 778 | constructor( 779 | container: string|HTMLElement|JQuery, 780 | data: T[]|DataProvider, 781 | columns: Column[], 782 | options: GridOptions); 783 | 784 | // #region Core 785 | 786 | /** 787 | * Initializes the grid. Called after plugins are registered. Normally, this is called by the constructor, so you don't need to call it. However, in certain cases you may need to delay the initialization until some other process has finished. In that case, set the explicitInitialization option to true and call the grid.init() manually. 788 | **/ 789 | public init(): void; 790 | 791 | /** 792 | * todo: no docs 793 | **/ 794 | public destroy(): void; 795 | 796 | /** 797 | * Returns an array of every data object, unless you're using DataView in which case it returns a DataView object. 798 | * @return 799 | **/ 800 | public getData(): any; 801 | //public getData(): T[]; 802 | // Issue: typescript limitation, cannot differentiate calls by return type only, so need to cast to DataView or T[]. 803 | //public getData(): DataView; 804 | 805 | /** 806 | * Returns the databinding item at a given position. 807 | * @param index Item index. 808 | * @return 809 | **/ 810 | public getDataItem(index: number): T; 811 | 812 | /** 813 | * Sets a new source for databinding and removes all rendered rows. Note that this doesn't render the new rows - you can follow it with a call to render() to do that. 814 | * @param newData New databinding source using a regular JavaScript array.. 815 | * @param scrollToTop If true, the grid will reset the vertical scroll position to the top of the grid. 816 | **/ 817 | public setData(newData: T[], scrollToTop: boolean): void; 818 | 819 | /** 820 | * Sets a new source for databinding and removes all rendered rows. Note that this doesn't render the new rows - you can follow it with a call to render() to do that. 821 | * @param newData New databinding source using a custom object exposing getItem(index) and getLength() functions. 822 | * @param scrollToTop If true, the grid will reset the vertical scroll position to the top of the grid. 823 | **/ 824 | public setData(newData: DataProvider, scrollToTop: boolean): void; 825 | 826 | /** 827 | * Returns the size of the databinding source. 828 | * @return 829 | **/ 830 | public getDataLength(): number; 831 | 832 | /** 833 | * Returns an object containing all of the Grid options set on the grid. See a list of Grid Options here. 834 | * @return 835 | **/ 836 | public getOptions(): GridOptions; 837 | 838 | /** 839 | * Returns an array of row indices corresponding to the currently selected rows. 840 | * @return 841 | **/ 842 | public getSelectedRows(): number[]; 843 | 844 | /** 845 | * Returns the current SelectionModel. See here for more information about SelectionModels. 846 | * @return 847 | **/ 848 | public getSelectionModel(): SelectionModel; 849 | 850 | public invalidateRows(rows: number[], keepEditor: boolean): void; 851 | 852 | /** 853 | * Extends grid options with a given hash. If an there is an active edit, the grid will attempt to commit the changes and only continue if the attempt succeeds. 854 | * @options An object with configuration options. 855 | **/ 856 | public setOptions(options: GridOptions): void; 857 | 858 | /** 859 | * Accepts an array of row indices and applies the current selectedCellCssClass to the cells in the row, respecting whether cells have been flagged as selectable. 860 | * @param rowsArray An array of row numbers. 861 | **/ 862 | public setSelectedRows(rowsArray: number[]): void; 863 | 864 | /** 865 | * Unregisters a current selection model and registers a new one. See the definition of SelectionModel for more information. 866 | * @selectionModel A SelectionModel. 867 | **/ 868 | public setSelectionModel(selectionModel: SelectionModel): void; // todo: don't know the type of the event data type 869 | 870 | // #endregion Core 871 | 872 | // #region Columns 873 | 874 | /** 875 | * Proportionately resizes all columns to fill available horizontal space. This does not take the cell contents into consideration. 876 | **/ 877 | public autosizeColumns(): void; 878 | 879 | /** 880 | * Returns the index of a column with a given id. Since columns can be reordered by the user, this can be used to get the column definition independent of the order: 881 | * @param id A column id. 882 | * @return 883 | **/ 884 | public getColumnIndex(id: string): number; 885 | 886 | /** 887 | * Returns an array of column definitions, containing the option settings for each individual column. 888 | * @return 889 | **/ 890 | public getColumns(): Column[]; 891 | 892 | /** 893 | * Returns an array of the widths of the columns 894 | * @return 895 | */ 896 | public getColumnWidths(): number[]; 897 | 898 | /** 899 | * Sets grid columns. Column headers will be recreated and all rendered rows will be removed. To rerender the grid (if necessary), call render(). 900 | * @param columnDefinitions An array of column definitions. 901 | **/ 902 | public setColumns(columnDefinitions: Column[]): void; 903 | 904 | public setColumnWidths(columnDefinitions: Column[]): void; 905 | 906 | /** 907 | * Accepts a columnId string and an ascending boolean. Applies a sort glyph in either ascending or descending form to the header of the column. Note that this does not actually sort the column. It only adds the sort glyph to the header. 908 | * @param columnId 909 | * @param ascending 910 | **/ 911 | public setSortColumn(columnId: string, ascending: boolean): void; 912 | 913 | /** 914 | * Accepts an array of objects in the form [ { columnId: [string], sortAsc: [boolean] }, ... ]. When called, this will apply a sort glyph in either ascending or descending form to the header of each column specified in the array. Note that this does not actually sort the column. It only adds the sort glyph to the header 915 | * @param cols 916 | **/ 917 | public setSortColumns(cols: { columnId: string; sortAsc: boolean }[]): void; 918 | 919 | /** 920 | * todo: no docs or comments available 921 | * @return 922 | **/ 923 | public getSortColumns(): { columnId: string; sortAsc: boolean }[]; 924 | 925 | /** 926 | * Updates an existing column definition and a corresponding header DOM element with the new title and tooltip. 927 | * @param columnId Column id. 928 | * @param title New column name. 929 | * @param toolTip New column tooltip. 930 | **/ 931 | public updateColumnHeader(columnId: string, title?: string, toolTip?: string): void; 932 | 933 | // #endregion Columns 934 | 935 | // #region Cells 936 | 937 | /** 938 | * Adds an "overlay" of CSS classes to cell DOM elements. SlickGrid can have many such overlays associated with different keys and they are frequently used by plugins. For example, SlickGrid uses this method internally to decorate selected cells with selectedCellCssClass (see options). 939 | * @param key A unique key you can use in calls to setCellCssStyles and removeCellCssStyles. If a hash with that key has already been set, an exception will be thrown. 940 | * @param hash A hash of additional cell CSS classes keyed by row number and then by column id. Multiple CSS classes can be specified and separated by space. 941 | * @example 942 | * { 943 | * 0: { 944 | * "number_column": "cell-bold", 945 | * "title_column": "cell-title cell-highlighted" 946 | * }, 947 | * 4: { 948 | * "percent_column": "cell-highlighted" 949 | * } 950 | * } 951 | **/ 952 | public addCellCssStyles(key: string, hash: CellCssStylesHash): void; 953 | 954 | /** 955 | * Returns true if you can click on a given cell and make it the active focus. 956 | * @param row A row index. 957 | * @param col A column index. 958 | * @return 959 | **/ 960 | public canCellBeActive(row: number, col: number): boolean; 961 | 962 | /** 963 | * Returns true if selecting the row causes this particular cell to have the selectedCellCssClass applied to it. A cell can be selected if it exists and if it isn't on an empty / "Add New" row and if it is not marked as "unselectable" in the column definition. 964 | * @param row A row index. 965 | * @param col A column index. 966 | * @return 967 | **/ 968 | public canCellBeSelected(row: number, col: number): boolean; 969 | 970 | /** 971 | * Attempts to switch the active cell into edit mode. Will throw an error if the cell is set to be not editable. Uses the specified editor, otherwise defaults to any default editor for that given cell. 972 | * @param editor A SlickGrid editor (see examples in slick.editors.js). 973 | **/ 974 | public editActiveCell(editor: Editors.Editor): void; 975 | 976 | /** 977 | * Flashes the cell twice by toggling the CSS class 4 times. 978 | * @param row A row index. 979 | * @param cell A column index. 980 | * @param speed (optional) - The milliseconds delay between the toggling calls. Defaults to 100 ms. 981 | **/ 982 | public flashCell(row: number, cell: number, speed?: number): void; 983 | 984 | /** 985 | * Returns an object representing the coordinates of the currently active cell: 986 | * @example 987 | * { 988 | * row: activeRow, 989 | * cell: activeCell 990 | * } 991 | * @return 992 | **/ 993 | public getActiveCell(): Cell; 994 | 995 | /** 996 | * 997 | */ 998 | public editActiveCell(editor?: Editors.Editor, preClickModeOn?: boolean): void; 999 | 1000 | /** 1001 | * Returns the DOM element containing the currently active cell. If no cell is active, null is returned. 1002 | * @return 1003 | **/ 1004 | public getActiveCellNode(): HTMLElement; 1005 | 1006 | /** 1007 | * Returns an object representing information about the active cell's position. All coordinates are absolute and take into consideration the visibility and scrolling position of all ancestors. 1008 | * @return 1009 | **/ 1010 | public getActiveCellPosition(): CellPosition; 1011 | 1012 | /** 1013 | * Accepts a key name, returns the group of CSS styles defined under that name. See setCellCssStyles for more info. 1014 | * @param key A string. 1015 | * @return 1016 | **/ 1017 | public getCellCssStyles(key: string): CellCssStylesHash; 1018 | 1019 | /** 1020 | * Returns the active cell editor. If there is no actively edited cell, null is returned. 1021 | * @return 1022 | **/ 1023 | public getCellEditor(): Editors.Editor; 1024 | 1025 | /** 1026 | * Returns a hash containing row and cell indexes from a standard W3C/jQuery event. 1027 | * @param e A standard W3C/jQuery event. 1028 | * @return 1029 | **/ 1030 | public getCellFromEvent(e: DOMEvent): Cell; 1031 | 1032 | /** 1033 | * Returns a hash containing row and cell indexes. Coordinates are relative to the top left corner of the grid beginning with the first row (not including the column headers). 1034 | * @param x An x coordinate. 1035 | * @param y A y coordinate. 1036 | * @return 1037 | **/ 1038 | public getCellFromPoint(x: number, y: number): Cell; 1039 | 1040 | /** 1041 | * Returns a DOM element containing a cell at a given row and cell. 1042 | * @param row A row index. 1043 | * @param cell A column index. 1044 | * @return 1045 | **/ 1046 | public getCellNode(row: number, cell: number): HTMLElement; 1047 | 1048 | /** 1049 | * Returns an object representing information about a cell's position. All coordinates are absolute and take into consideration the visibility and scrolling position of all ancestors. 1050 | * @param row A row index. 1051 | * @param cell A column index. 1052 | * @return 1053 | **/ 1054 | public getCellNodeBox(row: number, cell: number): CellPosition; 1055 | 1056 | /** 1057 | * Accepts a row integer and a cell integer, scrolling the view to the row where row is its row index, and cell is its cell index. Optionally accepts a forceEdit boolean which, if true, will attempt to initiate the edit dialogue for the field in the specified cell. 1058 | * Unlike setActiveCell, this scrolls the row into the viewport and sets the keyboard focus. 1059 | * @param row A row index. 1060 | * @param cell A column index. 1061 | * @param forceEdit If true, will attempt to initiate the edit dialogue for the field in the specified cell. 1062 | * @return 1063 | **/ 1064 | public gotoCell(row: number, cell: number, forceEdit?: boolean): void; 1065 | 1066 | /** 1067 | * todo: no docs 1068 | * @return 1069 | **/ 1070 | public getTopPanel(): HTMLElement; 1071 | 1072 | /** 1073 | * todo: no docs 1074 | * @param visible 1075 | **/ 1076 | public setTopPanelVisibility(visible: boolean): void; 1077 | 1078 | /** 1079 | * todo: no docs 1080 | * @param visible 1081 | **/ 1082 | public setHeaderRowVisibility(visible: boolean): void; 1083 | 1084 | /** 1085 | * todo: no docs 1086 | * @return 1087 | **/ 1088 | public getHeaderRow(): HTMLElement; 1089 | 1090 | public getScrollbarDimensions(): Dimension; 1091 | 1092 | /** 1093 | * todo: no docs, return type is probably wrong -> "return $header && $header[0]" 1094 | * @param columnId 1095 | * @return 1096 | **/ 1097 | public getHeaderRowColumn(columnId: string): Column; 1098 | 1099 | /** 1100 | * todo: no docs 1101 | * @return 1102 | **/ 1103 | public getGridPosition(): CellPosition; 1104 | 1105 | /** 1106 | * Switches the active cell one row down skipping unselectable cells. Returns a boolean saying whether it was able to complete or not. 1107 | * @return 1108 | **/ 1109 | public navigateDown(): boolean; 1110 | 1111 | /** 1112 | * Switches the active cell one cell left skipping unselectable cells. Unline navigatePrev, navigateLeft stops at the first cell of the row. Returns a boolean saying whether it was able to complete or not. 1113 | * @return 1114 | **/ 1115 | public navigateLeft(): boolean; 1116 | 1117 | /** 1118 | * Tabs over active cell to the next selectable cell. Returns a boolean saying whether it was able to complete or not. 1119 | * @return 1120 | **/ 1121 | public navigateNext(): boolean; 1122 | 1123 | /** 1124 | * Tabs over active cell to the previous selectable cell. Returns a boolean saying whether it was able to complete or not. 1125 | * @return 1126 | **/ 1127 | public navigatePrev(): boolean; 1128 | 1129 | /** 1130 | * Switches the active cell one cell right skipping unselectable cells. Unline navigateNext, navigateRight stops at the last cell of the row. Returns a boolean saying whether it was able to complete or not. 1131 | * @return 1132 | **/ 1133 | public navigateRight(): boolean; 1134 | 1135 | /** 1136 | * Switches the active cell one row up skipping unselectable cells. Returns a boolean saying whether it was able to complete or not. 1137 | * @return 1138 | **/ 1139 | public navigateUp(): boolean; 1140 | 1141 | /** 1142 | * Removes an "overlay" of CSS classes from cell DOM elements. See setCellCssStyles for more. 1143 | * @param key A string key. 1144 | **/ 1145 | public removeCellCssStyles(key: string): void; 1146 | 1147 | /** 1148 | * Resets active cell. 1149 | **/ 1150 | public resetActiveCell(): void; 1151 | 1152 | /** 1153 | * Sets an active cell. 1154 | * @param row A row index. 1155 | * @param cell A column index. 1156 | **/ 1157 | public setActiveCell(row: number, cell: number): void; 1158 | 1159 | /** 1160 | * Sets CSS classes to specific grid cells by calling removeCellCssStyles(key) followed by addCellCssStyles(key, hash). key is name for this set of styles so you can reference it later - to modify it or remove it, for example. hash is a per-row-index, per-column-name nested hash of CSS classes to apply. 1161 | * Suppose you have a grid with columns: 1162 | * ["login", "name", "birthday", "age", "likes_icecream", "favorite_cake"] 1163 | * ...and you'd like to highlight the "birthday" and "age" columns for people whose birthday is today, in this case, rows at index 0 and 9. (The first and tenth row in the grid). 1164 | * @param key A string key. Will overwrite any data already associated with this key. 1165 | * @param hash A hash of additional cell CSS classes keyed by row number and then by column id. Multiple CSS classes can be specified and separated by space. 1166 | **/ 1167 | public setCellCssStyles(key: string, hash: CellCssStylesHash): void; 1168 | 1169 | // #endregion Cells 1170 | 1171 | // #region Events 1172 | 1173 | public onScroll: Slick.Event>; 1174 | public onSort: Slick.Event>; 1175 | public onHeaderMouseEnter: Slick.Event>; 1176 | public onHeaderMouseLeave: Slick.Event>; 1177 | public onHeaderContextMenu: Slick.Event>; 1178 | public onHeaderClick: Slick.Event>; 1179 | public onHeaderCellRendered: Slick.Event>; 1180 | public onBeforeHeaderCellDestroy: Slick.Event>; 1181 | public onHeaderRowCellRendered: Slick.Event>; 1182 | public onBeforeHeaderRowCellDestroy: Slick.Event>; 1183 | public onMouseEnter: Slick.Event>; 1184 | public onMouseLeave: Slick.Event>; 1185 | public onClick: Slick.Event>; 1186 | public onDblClick: Slick.Event>; 1187 | public onContextMenu: Slick.Event>; 1188 | public onKeyDown: Slick.Event>; 1189 | public onAddNewRow: Slick.Event>; 1190 | public onValidationError: Slick.Event>; 1191 | public onColumnsReordered: Slick.Event>; 1192 | public onColumnsResized: Slick.Event>; 1193 | public onCellChange: Slick.Event>; 1194 | public onBeforeEditCell: Slick.Event>; 1195 | public onBeforeCellEditorDestroy: Slick.Event>; 1196 | public onBeforeDestroy: Slick.Event>; 1197 | public onActiveCellChanged: Slick.Event>; 1198 | public onActiveCellPositionChanged: Slick.Event>; 1199 | public onDragInit: Slick.Event>; 1200 | public onDragStart: Slick.Event>; 1201 | public onDrag: Slick.Event>; 1202 | public onDragEnd: Slick.Event>; 1203 | public onSelectedRowsChanged: Slick.Event>; 1204 | public onCellCssStylesChanged: Slick.Event>; 1205 | public onViewportChanged: Slick.Event>; 1206 | public onBeforeAppendCell: Slick.Event>; 1207 | public onRendered: Slick.Event>; 1208 | // #endregion Events 1209 | 1210 | // #region Plugins 1211 | 1212 | public registerPlugin(plugin: Plugin): void; 1213 | public unregisterPlugin(plugin: Plugin): void; 1214 | 1215 | // #endregion Plugins 1216 | 1217 | // #region Rendering 1218 | 1219 | public render(): void; 1220 | public invalidate(): void; 1221 | public invalidateRow(row: number): void; 1222 | public invalidateRows(rows: number[]): void; 1223 | public invalidateAllRows(): void; 1224 | public updateCell(row: number, cell: number): void; 1225 | public updateRow(row: number): void; 1226 | public getViewport(viewportTop?: number, viewportLeft?: number): Viewport; 1227 | public getRenderedRange(viewportTop?: number, viewportLeft?: number): Viewport; 1228 | public resizeCanvas(): void; 1229 | public updateRowCount(): void; 1230 | public scrollRowIntoView(row: number, doPaging: boolean): void; 1231 | public scrollRowToTop(row: number): void; 1232 | public scrollCellIntoView(row: number, cell: number, doPaging: boolean): void; 1233 | public getCanvasNode(): HTMLCanvasElement; 1234 | public focus(): void; 1235 | 1236 | // #endregion Rendering 1237 | 1238 | // #region Editors 1239 | 1240 | public getEditorLock(): EditorLock; 1241 | public getEditController(): { commitCurrentEdit():boolean; cancelCurrentEdit():boolean; }; 1242 | 1243 | // #endregion Editors 1244 | } 1245 | 1246 | export interface GridEventArgs { 1247 | grid: Grid; 1248 | } 1249 | 1250 | export interface OnCellCssStylesChangedEventArgs extends GridEventArgs { 1251 | key: string; 1252 | hash: CellCssStylesHash; 1253 | } 1254 | 1255 | export interface OnSelectedRowsChangedEventArgs extends GridEventArgs { 1256 | rows: number[]; 1257 | } 1258 | 1259 | export interface OnDragEndEventArgs extends GridEventArgs { 1260 | // todo: need to understand $canvas drag event parameter's 'dd' object 1261 | // the documentation is not enlightening 1262 | } 1263 | 1264 | export interface OnDragEventArgs extends GridEventArgs { 1265 | // todo: need to understand $canvas drag event parameter's 'dd' object 1266 | // the documentation is not enlightening 1267 | } 1268 | 1269 | export interface OnDragStartEventArgs extends GridEventArgs { 1270 | // todo: need to understand $canvas drag event parameter's 'dd' object 1271 | // the documentation is not enlightening 1272 | } 1273 | 1274 | export interface OnDragInitEventArgs extends GridEventArgs { 1275 | // todo: need to understand $canvas drag event parameter's 'dd' object 1276 | // the documentation is not enlightening 1277 | } 1278 | 1279 | export interface OnActiveCellPositionChangedEventArgs extends GridEventArgs { 1280 | 1281 | } 1282 | 1283 | export interface OnActiveCellChangedEventArgs extends GridEventArgs { 1284 | row: number; 1285 | cell: number; 1286 | } 1287 | 1288 | export interface OnBeforeDestroyEventArgs extends GridEventArgs { 1289 | 1290 | } 1291 | 1292 | export interface OnBeforeCellEditorDestroyEventArgs extends GridEventArgs { 1293 | editor: Editors.Editor; 1294 | } 1295 | 1296 | export interface OnBeforeEditCellEventArgs extends GridEventArgs { 1297 | row: number; 1298 | cell: number; 1299 | item: T; 1300 | column: Column; 1301 | } 1302 | 1303 | export interface OnCellChangeEventArgs extends GridEventArgs { 1304 | row: number; 1305 | cell: number; 1306 | item: T; 1307 | } 1308 | 1309 | export interface OnColumnsResizedEventArgs extends GridEventArgs { 1310 | 1311 | } 1312 | 1313 | export interface OnColumnsReorderedEventArgs extends GridEventArgs { 1314 | 1315 | } 1316 | 1317 | export interface OnValidationErrorEventArgs extends GridEventArgs { 1318 | editor: Editors.Editor; 1319 | cellNode: HTMLElement; 1320 | validationResults: ValidateResults; 1321 | row: number; 1322 | cell: number; 1323 | column: Column; 1324 | } 1325 | 1326 | export interface OnAddNewRowEventArgs extends GridEventArgs { 1327 | item: T; 1328 | column: Column; 1329 | } 1330 | 1331 | export interface OnKeyDownEventArgs extends GridEventArgs { 1332 | row: number; 1333 | cell: number; 1334 | } 1335 | 1336 | export interface OnContextMenuEventArgs extends GridEventArgs { 1337 | 1338 | } 1339 | 1340 | export interface OnDblClickEventArgs extends GridEventArgs { 1341 | row: number; 1342 | cell: number; 1343 | } 1344 | 1345 | export interface OnClickEventArgs extends GridEventArgs { 1346 | row: number; 1347 | cell: number; 1348 | } 1349 | 1350 | export interface OnMouseLeaveEventArgs extends GridEventArgs { 1351 | 1352 | } 1353 | 1354 | export interface OnMouseEnterEventArgs extends GridEventArgs { 1355 | 1356 | } 1357 | 1358 | export interface OnBeforeHeaderRowCellDestroyEventArgs extends GridEventArgs { 1359 | node: HTMLElement; // todo: might be JQuery instance 1360 | column: Column; 1361 | } 1362 | 1363 | export interface OnHeaderRowCellRenderedEventArgs extends GridEventArgs { 1364 | node: HTMLElement; // todo: might be JQuery instance 1365 | column: Column; 1366 | } 1367 | 1368 | export interface OnBeforeHeaderCellDestroyEventArgs extends GridEventArgs { 1369 | node: HTMLElement; // todo: might be JQuery instance 1370 | column: Column; 1371 | } 1372 | 1373 | export interface OnHeaderCellRenderedEventArgs extends GridEventArgs { 1374 | node: HTMLElement; // todo: might be JQuery instance 1375 | column: Column; 1376 | } 1377 | 1378 | export interface OnHeaderClickEventArgs extends GridEventArgs { 1379 | column: Column; 1380 | } 1381 | 1382 | export interface OnHeaderContextMenuEventArgs extends GridEventArgs { 1383 | column: Column; 1384 | } 1385 | 1386 | export interface OnHeaderMouseEventArgs extends GridEventArgs { 1387 | column: Column; 1388 | } 1389 | 1390 | export interface OnSortEventArgs extends GridEventArgs { 1391 | multiColumnSort: boolean; 1392 | 1393 | // Single column returned 1394 | sortCol?: Column; 1395 | sortAsc: boolean; 1396 | 1397 | // Multiple columns returned 1398 | sortCols?: SortColumn[]; 1399 | } 1400 | 1401 | export interface OnScrollEventArgs extends GridEventArgs { 1402 | scrollLeft: number; 1403 | scrollTop: number; 1404 | } 1405 | 1406 | export interface OnViewportChangedEventArgs extends GridEventArgs { 1407 | 1408 | } 1409 | 1410 | export interface OnBeforeAppendCellEventArgs extends GridEventArgs { 1411 | row: number; 1412 | cell: number; 1413 | value: any; 1414 | dataContext: any; 1415 | } 1416 | 1417 | export interface OnRenderedEventArgs extends GridEventArgs { 1418 | startRow: number; 1419 | endRow: number; 1420 | } 1421 | 1422 | export interface SortColumn { 1423 | sortCol: Column; 1424 | sortAsc: boolean; 1425 | } 1426 | 1427 | export interface Cell { 1428 | row: number; 1429 | cell: number; 1430 | } 1431 | 1432 | export interface CellPosition extends Position { 1433 | bottom: number; 1434 | height: number; 1435 | right: number; 1436 | visible: boolean; 1437 | width: number; 1438 | } 1439 | 1440 | export interface Dimension { 1441 | width: number, 1442 | height: number 1443 | } 1444 | 1445 | export interface Position { 1446 | top: number; 1447 | left: number; 1448 | } 1449 | 1450 | export interface CellCssStylesHash { 1451 | [index: number]: { 1452 | [id: string]: string; 1453 | } 1454 | } 1455 | 1456 | export interface Viewport { 1457 | top: number; 1458 | bottom: number; 1459 | leftPx: number; 1460 | rightPx: number; 1461 | } 1462 | 1463 | export interface ValidateResults { 1464 | valid: boolean; 1465 | msg: string; 1466 | } 1467 | 1468 | export module Editors { 1469 | 1470 | export interface EditorOptions { 1471 | column: Column; 1472 | container: HTMLElement; 1473 | grid: Grid; 1474 | } 1475 | 1476 | export class Editor { 1477 | constructor(args: EditorOptions); 1478 | public init(): void; 1479 | public destroy(): void; 1480 | public focus(): void; 1481 | public loadValue(item:any): void; // todo: typeof(item) 1482 | public applyValue(item:any, state: string): void; // todo: typeof(item) 1483 | public isValueChanged(): boolean; 1484 | public serializeValue(): any; 1485 | public validate(): ValidateResults; 1486 | public getValue(): string; 1487 | public setValue(val: string): void; 1488 | } 1489 | 1490 | export class Text extends Editor { 1491 | constructor(args: EditorOptions); 1492 | 1493 | public getValue(): string; 1494 | public setValue(val: string): void; 1495 | public serializeValue(): string; 1496 | } 1497 | 1498 | export class Integer extends Editor { 1499 | constructor(args: EditorOptions); 1500 | 1501 | public serializeValue(): number; 1502 | } 1503 | 1504 | export class Date extends Editor { 1505 | constructor(args: EditorOptions); 1506 | 1507 | public show(): void; 1508 | public hide(): void; 1509 | public position(position: Position): void; 1510 | public serializeValue(): string; 1511 | } 1512 | 1513 | export class YesNoSelect extends Editor { 1514 | constructor(args: EditorOptions); 1515 | 1516 | public serializeValue(): boolean; 1517 | } 1518 | 1519 | export class Checkbox extends Editor { 1520 | constructor(args: EditorOptions); 1521 | 1522 | public serializeValue(): boolean; 1523 | 1524 | } 1525 | export class PercentComplete extends Editor { 1526 | constructor(args: EditorOptions); 1527 | 1528 | public serializeValue(): number; 1529 | } 1530 | 1531 | export class LongText extends Editor { 1532 | constructor(args: EditorOptions); 1533 | 1534 | public handleKeyDown(e: DOMEvent): void; 1535 | public save(): void; 1536 | public cancel(): void; 1537 | public hide(): void; 1538 | public show(): void; 1539 | public position(position: Position): void; 1540 | public serializeValue(): string; 1541 | } 1542 | } 1543 | 1544 | export interface Formatter { 1545 | (row: number, cell: number, value: any, columnDef: Column, dataContext: SlickData): string; 1546 | } 1547 | 1548 | export module Formatters { 1549 | var PercentComplete: Formatter; 1550 | var PercentCompleteBar: Formatter; 1551 | var YesNo: Formatter; 1552 | var Checkmark: Formatter; 1553 | } 1554 | 1555 | export module Data { 1556 | 1557 | export interface DataViewOptions { 1558 | groupItemMetadataProvider?: GroupItemMetadataProvider; 1559 | inlineFilters?: boolean; 1560 | } 1561 | 1562 | /** 1563 | * Item -> Data by index 1564 | * Row -> Data by row 1565 | **/ 1566 | export class DataView implements DataProvider { 1567 | 1568 | constructor(options?: DataViewOptions); 1569 | 1570 | public beginUpdate(): void; 1571 | public endUpdate(): void; 1572 | public setPagingOptions(args: PagingOptions): void; 1573 | public getPagingInfo(): PagingOptions; 1574 | public getItems(): T[]; 1575 | public setItems(data: T[], objectIdProperty?: string): void; 1576 | public setFilter(filterFn: (item: T, args:any) => boolean): void; // todo: typeof(args) 1577 | public sort(comparer: Function, ascending: boolean): void; // todo: typeof(comparer), should be the same callback as Array.sort 1578 | public fastSort(field: string, ascending: boolean): void; 1579 | public fastSort(field: Function, ascending: boolean): void; // todo: typeof(field), should be the same callback as Array.sort 1580 | public reSort(): void; 1581 | public setGrouping(groupingInfos: GroupingOptions | GroupingOptions[]): void; 1582 | public getGrouping(): GroupingOptions[]; 1583 | 1584 | /** 1585 | * @deprecated 1586 | **/ 1587 | public groupBy(valueGetter:any, valueFormatter:any, sortComparer:any): void; 1588 | 1589 | /** 1590 | * @deprecated 1591 | **/ 1592 | public setAggregators(groupAggregators:any, includeCollapsed:any): void; 1593 | 1594 | /** 1595 | * @param level Optional level to collapse. If not specified, applies to all levels. 1596 | **/ 1597 | public collapseAllGroups(level?: number): void; 1598 | 1599 | /** 1600 | * @param level Optional level to collapse. If not specified, applies to all levels. 1601 | **/ 1602 | public expandAllGroups(level?: number): void; 1603 | 1604 | /** 1605 | * @param varArgs Either a Slick.Group's "groupingKey" property, or a 1606 | * variable argument list of grouping values denoting a unique path to the row. For 1607 | * example, calling collapseGroup('high', '10%') will collapse the '10%' subgroup of 1608 | * the 'high' setGrouping. 1609 | */ 1610 | public collapseGroup(...varArgs: string[]): void; 1611 | 1612 | /** 1613 | * @param varArgs Either a Slick.Group's "groupingKey" property, or a 1614 | * variable argument list of grouping values denoting a unique path to the row. For 1615 | * example, calling expandGroup('high', '10%') will expand the '10%' subgroup of 1616 | * the 'high' setGrouping. 1617 | */ 1618 | public expandGroup(...varArgs: string[]): void; 1619 | public getGroups(): Group[]; 1620 | public getIdxById(id: string): number; 1621 | public getRowById(id: string): number; 1622 | public getItemById(id: any): T; 1623 | public getItemByIdx(idx: number): T; 1624 | public mapRowsToIds(rowArray: T[]): string[]; 1625 | public setRefreshHints(hints: RefreshHints): void; 1626 | public setFilterArgs(args: any): void; 1627 | public refresh(): void; 1628 | public updateItem(id: string, item: T): void; 1629 | public insertItem(insertBefore: number, item: T): void; 1630 | public addItem(item: T): void; 1631 | public deleteItem(id: string): void; 1632 | public syncGridSelection(grid: Grid, preserveHidden: boolean): void; 1633 | public syncGridCellCssStyles(grid: Grid, key: string): void; 1634 | 1635 | public getLength(): number; 1636 | public getItem(index: number): T; 1637 | public getItemMetadata(index: number): RowMetadata; 1638 | 1639 | public onRowCountChanged: Slick.Event; 1640 | public onRowsChanged: Slick.Event; 1641 | public onPagingInfoChanged: Slick.Event; 1642 | } 1643 | 1644 | export interface GroupingOptions { 1645 | getter?: ((item?: T) => any) | string; 1646 | formatter?: (item?: T) => string; 1647 | comparer?: (a: Group, b: Group) => number; 1648 | predefinedValues?: any[]; // todo 1649 | aggregators?: Aggregators.Aggregator[]; 1650 | aggregateEmpty?: boolean; 1651 | aggregateCollapsed?: boolean; 1652 | aggregateChildGroups?: boolean; 1653 | collapsed?: boolean; 1654 | displayTotalsRow?: boolean; 1655 | } 1656 | 1657 | export interface PagingOptions { 1658 | pageSize?: number; 1659 | pageNum?: number; 1660 | totalRows?: number; 1661 | totalPages?: number; 1662 | } 1663 | 1664 | export interface RefreshHints { 1665 | isFilterNarrowing?: boolean; 1666 | isFilterExpanding?: boolean; 1667 | isFilterUnchanged?: boolean; 1668 | ignoreDiffsBefore?: boolean; 1669 | ignoreDiffsAfter?: boolean; 1670 | } 1671 | 1672 | export interface OnRowCountChangedEventData { 1673 | // empty 1674 | } 1675 | export interface OnRowsChangedEventData { 1676 | rows: number[]; 1677 | } 1678 | export interface OnPagingInfoChangedEventData extends PagingOptions { 1679 | 1680 | } 1681 | 1682 | export module Aggregators { 1683 | export class Aggregator { 1684 | public field: string; 1685 | public init(): void; 1686 | public accumulate(item: T): void; 1687 | public storeResult(groupTotals: GroupTotals): void; 1688 | } 1689 | 1690 | export class Avg extends Aggregator { 1691 | 1692 | } 1693 | 1694 | export class Min extends Aggregator { 1695 | 1696 | } 1697 | 1698 | export class Max extends Aggregator { 1699 | 1700 | } 1701 | 1702 | export class Sum extends Aggregator { 1703 | 1704 | } 1705 | } 1706 | 1707 | /*** 1708 | * Provides item metadata for group (Slick.Group) and totals (Slick.Totals) rows produced by the DataView. 1709 | * This metadata overrides the default behavior and formatting of those rows so that they appear and function 1710 | * correctly when processed by the grid. 1711 | * 1712 | * This class also acts as a grid plugin providing event handlers to expand & collapse groups. 1713 | * If "grid.registerPlugin(...)" is not called, expand & collapse will not work. 1714 | * 1715 | * @class GroupItemMetadataProvider 1716 | * @module Data 1717 | * @namespace Slick.Data 1718 | * @constructor 1719 | * @param options 1720 | */ 1721 | export class GroupItemMetadataProvider { 1722 | public init(): void; 1723 | public destroy(): void; 1724 | public getGroupRowMetadata(item?: Group): RowMetadata; 1725 | public getTotalsRowMetadata(item?: GroupTotals): RowMetadata; 1726 | } 1727 | 1728 | export interface GroupItemMetadataProviderOptions { 1729 | groupCssClass?: string; 1730 | groupTitleCssClass?: string; 1731 | totalsCssClass?: string; 1732 | groupFocusable?: boolean; 1733 | totalsFocusable?: boolean; 1734 | toggleCssClass?: string; 1735 | toggleExpandedCssCass?: string; 1736 | toggleCollapsedCssClass?: string; 1737 | enableExpandCollapse?: boolean; 1738 | } 1739 | 1740 | //export class RemoteModel { 1741 | // public data: any; 1742 | 1743 | // public clear(): any; 1744 | // public isDataLoaded(): any; 1745 | // public ensureData(): any; 1746 | // public reloadData(): any; 1747 | // public setSort(): any; 1748 | // public setSearch(): any; 1749 | 1750 | // public onDataLoading: Slick.Event; 1751 | // public onDataLoaded: Slick.Event; 1752 | 1753 | //} 1754 | 1755 | //export interface OnDataLoadingEventData { 1756 | 1757 | //} 1758 | 1759 | //export interface OnDataLoadedEventData { 1760 | 1761 | //} 1762 | } 1763 | 1764 | export class Plugin { 1765 | 1766 | constructor(options?: PluginOptions); 1767 | public init(grid: Grid): void; 1768 | public destroy(): void; 1769 | } 1770 | 1771 | export interface PluginOptions { 1772 | // extend your plugin options here 1773 | } 1774 | 1775 | } 1776 | -------------------------------------------------------------------------------- /examples/basic_application/app.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, OnInit } from '@angular/core'; 2 | import { IObservableCollection, 3 | VirtualizedCollection } from './../../out/index'; 4 | 5 | const numberOfColumns = 10; 6 | const numberOfRows = 200; 7 | 8 | @Component({ 9 | selector: 'my-app', 10 | template: ` 13 | ` 14 | }) 15 | export class AppComponent implements OnInit { 16 | private dataRows: IObservableCollection<{}>; 17 | private columnDefinitions: Slick.Column[]; 18 | // tslint:disable-next-line:no-unused-variable 19 | private selectionModel = 'CellSelectionModel'; 20 | 21 | ngOnInit(): void { 22 | // generate columns 23 | let columns: Slick.Column[] = []; 24 | for (let i = 0; i < numberOfColumns; i++) { 25 | columns.push({ 26 | id: i.toString(), 27 | name: i.toString() 28 | }); 29 | } 30 | let loadDataFunction = (offset: number, count: number): Promise<{}[]> => { 31 | return new Promise<{}[]>((resolve) => { 32 | let data: {}[] = []; 33 | for (let i = offset; i < offset + count; i++) { 34 | let row = {}; 35 | for (let j = 0; j < numberOfColumns; j++) { 36 | row[j.toString()] = `column ${j}; row ${i}`; 37 | } 38 | data.push(row); 39 | } 40 | resolve(data); 41 | }); 42 | }; 43 | this.dataRows = new VirtualizedCollection<{}>(50, 44 | numberOfRows, 45 | loadDataFunction, 46 | (index) => { 47 | return { values: []}; 48 | }); 49 | this.columnDefinitions = columns; 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /examples/basic_application/app.module.ts: -------------------------------------------------------------------------------- 1 | /* -------------------------------------------------------------------------------------------- 2 | * Copyright (c) Microsoft Corporation. All rights reserved. 3 | * Licensed under the MIT License. See License.txt in the project root for license information. 4 | * ------------------------------------------------------------------------------------------ */ 5 | import { NgModule } from '@angular/core'; 6 | import { BrowserModule } from '@angular/platform-browser'; 7 | 8 | import { SlickGrid } from './../../components/js/SlickGrid'; 9 | 10 | import { AppComponent } from './app.component'; 11 | 12 | @NgModule({ 13 | imports: [ 14 | BrowserModule 15 | ], 16 | declarations: [ AppComponent, SlickGrid ], 17 | bootstrap: [ AppComponent ] 18 | }) 19 | export class AppModule { } 20 | -------------------------------------------------------------------------------- /examples/basic_application/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | Loading... 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 27 | -------------------------------------------------------------------------------- /examples/basic_application/main.ts: -------------------------------------------------------------------------------- 1 | /* -------------------------------------------------------------------------------------------- 2 | * Copyright (c) Microsoft Corporation. All rights reserved. 3 | * Licensed under the MIT License. See License.txt in the project root for license information. 4 | * ------------------------------------------------------------------------------------------ */ 5 | /** 6 | * Bootstraps the angular module 7 | */ 8 | 9 | import { platformBrowserDynamic } from '@angular/platform-browser-dynamic'; 10 | import { AppModule } from './app.module'; 11 | platformBrowserDynamic().bootstrapModule(AppModule); 12 | -------------------------------------------------------------------------------- /examples/basic_application/styles.css: -------------------------------------------------------------------------------- 1 | :root { 2 | --background-color: white; 3 | } 4 | * { 5 | --color-content: #101010; 6 | --color-content-disabled: #a9a9a9; 7 | --color-error: #E81123; 8 | --color-success: #7CD300; 9 | --color-bg-header: hsla(0,0%,50%,.2); 10 | --color-bg-content-light: #ffffff; 11 | --color-bg-content-header: #F5F5F5; /* used for color of grid headers */ 12 | --color-cell-border-active: grey; 13 | --color-cell-bg-grid-selected: rgb(173, 214, 255); 14 | } 15 | 16 | a { 17 | color: #0078D7; 18 | } 19 | 20 | a:hover { 21 | color: #0b93ff; 22 | } 23 | 24 | /* grid styling */ 25 | 26 | slick-grid .grid .slick-cell.active { 27 | border: dotted 1px var(--color-cell-border-active); 28 | } 29 | 30 | slick-grid .grid .slick-cell.selected { 31 | background-color: var(--color-cell-bg-grid-selected); 32 | } 33 | 34 | .boxRow.content.horzBox.slickgrid { 35 | border: solid 1px #EEEEF2; 36 | } -------------------------------------------------------------------------------- /examples/basic_application/systemjs.config.js: -------------------------------------------------------------------------------- 1 | /** 2 | * System configuration for Angular 2 samples 3 | * Adjust as necessary for your application needs. 4 | */ 5 | (function(global) { 6 | var paths = { 7 | 'npm:': '/node_modules/' 8 | } 9 | // map tells the System loader where to look for things 10 | var map = { 11 | 'app': '/dist/basic_application', // 'dist', 12 | '@angular': 'npm:@angular', 13 | 'rxjs': 'npm:rxjs', 14 | 'json': 'npm:json.js', 15 | 'angular2-slickgrid': 'npm:angular2-slickgrid', 16 | '@angular/common': 'npm:@angular/common/bundles/common.umd.js', 17 | '@angular/compiler': 'npm:@angular/compiler/bundles/compiler.umd.js', 18 | '@angular/core': 'npm:@angular/core/bundles/core.umd.js', 19 | '@angular/forms': 'npm:@angular/forms/bundles/forms.umd.js', 20 | '@angular/http': 'npm:@angular/http/bundles/http.umd.js', 21 | '@angular/platform-browser': 'npm:@angular/platform-browser/bundles/platform-browser.umd.js', 22 | '@angular/platform-browser-dynamic': 'npm:@angular/platform-browser-dynamic/bundles/platform-browser-dynamic.umd.js', 23 | '@angular/router': 'npm:@angular/router/bundles/router.umd.js', 24 | '@angular/upgrade': 'npm:@angular/upgrade/bundles/upgrade.umd.js', 25 | 'angular-in-memory-web-api': 'npm:angular-in-memory-web-api/bundles/in-memory-web-api.umd.js' 26 | }; 27 | // packages tells the System loader how to load when no filename and/or no extension 28 | var packages = { 29 | 'app': { main: 'main.js', defaultExtension: 'js' }, 30 | }; 31 | var config = { 32 | paths: paths, 33 | map: map, 34 | packages: packages, 35 | defaultJSExtensions: true 36 | }; 37 | System.config(config); 38 | })(this); 39 | -------------------------------------------------------------------------------- /gulpfile.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | const gulp = require('gulp'); 3 | const del = require('del'); 4 | const ts = require('gulp-typescript'); 5 | const merge = require('merge2'); 6 | const connect = require('gulp-connect'); 7 | const tslint = require('tslint'); 8 | const gulpTslint = require('gulp-tslint'); 9 | const sm = require('gulp-sourcemaps'); 10 | 11 | const tsproj = ts.createProject('./tsconfig.json'); 12 | const exmapProj = ts.createProject('./tsconfig.json', { declaration: false }); 13 | 14 | gulp.task('compile:src', () => { 15 | let tsResult = gulp.src(['components/**/*.ts', 'typings/**/*.ts']) 16 | .pipe(sm.init()) 17 | .pipe(tsproj()); 18 | 19 | let css = gulp.src(['components/**/*.css']); 20 | 21 | return merge([ 22 | tsResult.dts.pipe(gulp.dest('./out/')), 23 | tsResult.js 24 | .pipe(sm.write('.')) 25 | .pipe(gulp.dest('./out/')), 26 | css.pipe(gulp.dest('./out/')) 27 | ]); 28 | }); 29 | 30 | gulp.task('compile:examples', (done) => { 31 | let promises = []; 32 | promises.push(new Promise((resolve) => { 33 | gulp.src(['examples/**/*.ts', 'typings/**/*.ts', 'components/typings/**/*.ts']) 34 | .pipe(exmapProj()) 35 | .pipe(gulp.dest('dist')) 36 | .on('end', () => { 37 | resolve(); 38 | }); 39 | })) 40 | 41 | promises.push(new Promise((resolve) => { 42 | gulp.src(['examples/**/*.html']) 43 | .pipe(gulp.dest('dist')) 44 | .on('end', () => { 45 | resolve(); 46 | }); 47 | 48 | })) 49 | 50 | promises.push(new Promise((resolve)=> { 51 | gulp.src(['examples/**/*.js']) 52 | .pipe(gulp.dest('dist')) 53 | .on('end', () => { 54 | resolve(); 55 | }); 56 | })); 57 | 58 | promises.push(new Promise((resolve)=> { 59 | gulp.src(['examples/**/*.css']) 60 | .pipe(gulp.dest('dist')) 61 | .on('end', () => { 62 | resolve(); 63 | }); 64 | })); 65 | 66 | Promise.all(promises).then(() => { 67 | done(); 68 | }); 69 | }); 70 | 71 | gulp.task('compile', gulp.series('compile:src', 'compile:examples')); 72 | 73 | gulp.task('lint:src', () => { 74 | const program = tslint.Linter.createProgram('tsconfig.json'); 75 | return gulp.src(['components/**/*.ts', '!components/typings/**/*']) 76 | .pipe((gulpTslint({ 77 | program, 78 | formatter: "verbose", 79 | rulesDirectory: "node_modules/tslint-microsoft-contrib" 80 | }))) 81 | .pipe(gulpTslint.report()); 82 | }); 83 | 84 | gulp.task('lint:examples', () => { 85 | const program = tslint.Linter.createProgram('tsconfig.json'); 86 | return gulp.src(['examples/**/*.ts']) 87 | .pipe((gulpTslint({ 88 | program, 89 | formatter: "verbose", 90 | rulesDirectory: "node_modules/tslint-microsoft-contrib" 91 | }))) 92 | .pipe(gulpTslint.report()); 93 | }); 94 | 95 | gulp.task('lint', gulp.series('lint:src', 'lint:examples')); 96 | 97 | gulp.task('serve', () => { 98 | connect.server(); 99 | }); 100 | 101 | gulp.task('clean', () => { 102 | return del(['out', 'dist', 'index.js', 'index.d.ts']) 103 | }); 104 | 105 | gulp.task('build', gulp.series('clean', 'lint', 'compile')); 106 | 107 | gulp.task('publish', gulp.series('clean', 'lint', 'compile:src')); 108 | -------------------------------------------------------------------------------- /license.txt: -------------------------------------------------------------------------------- 1 | ------------------------------------------ START OF LICENSE ----------------------------------------- 2 | microsoft-vscode-mssql 3 | Copyright (c) Microsoft Corporation 4 | All rights reserved. 5 | MIT License 6 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the ""Software""), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 7 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 8 | THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 9 | ----------------------------------------------- END OF LICENSE ------------------------------------------ 10 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "angular2-slickgrid", 3 | "version": "1.4.7", 4 | "description": "", 5 | "main": "out/index.js", 6 | "scripts": { 7 | "compile": "gulp compile", 8 | "serve": "gulp serve", 9 | "compile:examples": "gulp compile:examples" 10 | }, 11 | "author": "", 12 | "license": "ISC", 13 | "peerDependencies": { 14 | "@angular/common": "^4.1.3", 15 | "@angular/compiler": "^4.1.3", 16 | "@angular/core": "^4.1.3", 17 | "@angular/forms": "^4.1.3", 18 | "@angular/http": "^4.1.3", 19 | "@angular/platform-browser": "^4.1.3", 20 | "@angular/platform-browser-dynamic": "^4.1.3", 21 | "@angular/router": "^4.1.3", 22 | "@angular/upgrade": "^4.1.3", 23 | "core-js": "^2.4.1", 24 | "moment": "^2.15.1", 25 | "reflect-metadata": "^0.1.8", 26 | "rxjs": "^5.4.0", 27 | "slickgrid": "github:Microsoft/SlickGrid.ADS#2.3.43", 28 | "systemjs": "0.19.40", 29 | "underscore": "^1.8.3", 30 | "zone.js": "^0.8.4" 31 | }, 32 | "devDependencies": { 33 | "@angular/animations": "^4.1.3", 34 | "@angular/common": "^4.1.3", 35 | "@angular/compiler": "^4.1.3", 36 | "@angular/compiler-cli": "^4.1.3", 37 | "@angular/core": "^4.1.3", 38 | "@angular/forms": "^4.1.3", 39 | "@angular/http": "^4.1.3", 40 | "@angular/platform-browser": "^4.1.3", 41 | "@angular/platform-browser-dynamic": "^4.1.3", 42 | "@angular/platform-server": "^4.1.3", 43 | "@angular/router": "^4.1.3", 44 | "@angular/upgrade": "^4.1.3", 45 | "core-js": "^2.4.1", 46 | "del": "^2.2.1", 47 | "gulp": "^4.0.2", 48 | "gulp-connect": "^5.0.0", 49 | "gulp-sourcemaps": "^2.6.1", 50 | "gulp-tslint": "^8.1.4", 51 | "gulp-typescript": "^3.1.7", 52 | "jquery": "^3.6.0", 53 | "jquery-ui": "^1.12.1", 54 | "merge2": "^1.0.2", 55 | "moment": "^2.15.1", 56 | "reflect-metadata": "^0.1.8", 57 | "rxjs": "^5.4.0", 58 | "slickgrid": "github:Microsoft/SlickGrid.ADS#2.3.43", 59 | "systemjs": "0.19.40", 60 | "tsc": "^1.20150623.0", 61 | "tslint": "^5.16.0", 62 | "tslint-microsoft-contrib": "^5.2.0", 63 | "typescript": "^2.3.4", 64 | "underscore": "^1.8.3", 65 | "zone.js": "^0.8.4" 66 | }, 67 | "repository": { 68 | "type": "git", 69 | "url": "https://github.com/Microsoft/angular2-slickgrid.git" 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "allowUnusedLabels": false, 4 | "emitDecoratorMetadata": true, 5 | "experimentalDecorators": true, 6 | "declaration": true, 7 | "module": "commonjs", 8 | "target": "es6" 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /tslint.json: -------------------------------------------------------------------------------- 1 | { 2 | "rules": { 3 | "align": [ 4 | true, 5 | "parameters", 6 | "statements" 7 | ], 8 | "ban": false, 9 | "class-name": true, 10 | "comment-format": [ 11 | true, 12 | "check-space" 13 | ], 14 | "curly": true, 15 | "eofline": true, 16 | "forin": true, 17 | "jsdoc-format": true, 18 | "label-position": true, 19 | "max-line-length": [ 20 | true, 21 | 160 22 | ], 23 | "member-access": false, 24 | "member-ordering": [ 25 | false, 26 | "static-before-instance", 27 | "variables-before-functions" 28 | ], 29 | "no-any": false, 30 | "no-arg": true, 31 | "no-bitwise": true, 32 | "no-conditional-assignment": true, 33 | "no-consecutive-blank-lines": false, 34 | "no-console": [ 35 | true, 36 | "debug", 37 | "info", 38 | "time", 39 | "timeEnd", 40 | "trace" 41 | ], 42 | "no-construct": true, 43 | "no-constructor-vars": false, 44 | "no-debugger": true, 45 | "no-duplicate-variable": true, 46 | "no-empty": true, 47 | "no-inferrable-types": false, 48 | "no-internal-module": true, 49 | "no-require-imports": false, 50 | "no-shadowed-variable": true, 51 | "no-string-literal": false, 52 | "no-switch-case-fall-through": false, 53 | "no-trailing-whitespace": true, 54 | "no-unused-expression": false, 55 | "no-use-before-declare": true, 56 | "no-var-keyword": true, 57 | "no-var-requires": false, 58 | "object-literal-sort-keys": false, 59 | "one-line": [ 60 | true, 61 | "check-open-brace", 62 | "check-catch", 63 | "check-else", 64 | "check-finally", 65 | "check-whitespace" 66 | ], 67 | "radix": true, 68 | "semicolon": true, 69 | "switch-default": true, 70 | "trailing-comma": [ 71 | true, 72 | { 73 | "multiline": "never", 74 | "singleline": "never" 75 | } 76 | ], 77 | "triple-equals": [ 78 | true, 79 | "allow-null-check" 80 | ], 81 | "typedef": [ 82 | true, 83 | "call-signature", 84 | "property-declaration" 85 | ], 86 | "typedef-whitespace": [ 87 | true, 88 | { 89 | "call-signature": "nospace", 90 | "index-signature": "nospace", 91 | "parameter": "nospace", 92 | "property-declaration": "nospace", 93 | "variable-declaration": "nospace" 94 | } 95 | ], 96 | "use-strict": false, 97 | "whitespace": [ 98 | true, 99 | "check-branch", 100 | "check-decl", 101 | "check-operator", 102 | "check-separator", 103 | "check-type" 104 | ], 105 | // MSSDL Required Rules 106 | "no-banned-terms": true, 107 | "no-delete-expression": true, 108 | "no-disable-auto-sanitization": true, 109 | "no-document-domain": true, 110 | "no-duplicate-parameter-names": true, 111 | "no-eval": true, 112 | "no-exec-script": true, 113 | "no-octal-literal": true, 114 | // The actual SDL list includes no-reserved-keywords currently but this has been deprecated 115 | // in tslint-microsoft-contrib in favor of using the ban-keywords option below. So to avoid 116 | // making many unnecessary changes we just use ban-keywords here instead 117 | "no-reserved-keywords": false, 118 | "variable-name": { 119 | "options": [ 120 | "allow-leading-underscore", 121 | "ban-keywords" 122 | ] 123 | }, 124 | "no-string-based-set-immediate": true, 125 | "no-string-based-set-interval": true, 126 | "no-string-based-set-timeout": true 127 | } 128 | } -------------------------------------------------------------------------------- /typings.json: -------------------------------------------------------------------------------- 1 | { 2 | "globalDependencies": { 3 | "jquery": "registry:dt/jquery#1.10.0+20160929162922", 4 | "underscore": "registry:dt/underscore#1.8.3+20160908111004" 5 | } 6 | } 7 | --------------------------------------------------------------------------------