gridstack 8.1.1 → 8.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +12 -11
- package/angular/.editorconfig +16 -0
- package/angular/.vscode/extensions.json +4 -0
- package/angular/.vscode/launch.json +20 -0
- package/angular/.vscode/tasks.json +42 -0
- package/{dist/ng → angular}/README.md +170 -154
- package/angular/README_build.md +27 -0
- package/angular/angular.json +132 -0
- package/angular/package.json +40 -0
- package/angular/projects/demo/.browserslistrc +16 -0
- package/angular/projects/demo/src/app/app.component.css +11 -0
- package/angular/projects/demo/src/app/app.component.html +78 -0
- package/angular/projects/demo/src/app/app.component.spec.ts +25 -0
- package/angular/projects/demo/src/app/app.component.ts +208 -0
- package/angular/projects/demo/src/app/app.module.ts +39 -0
- package/angular/projects/demo/src/app/dummy.component.ts +35 -0
- package/angular/projects/demo/src/app/ngFor.ts +131 -0
- package/angular/projects/demo/src/app/ngFor_cmd.ts +106 -0
- package/angular/projects/demo/src/app/simple.ts +46 -0
- package/angular/projects/demo/src/assets/.gitkeep +0 -0
- package/angular/projects/demo/src/environments/environment.prod.ts +3 -0
- package/angular/projects/demo/src/environments/environment.ts +16 -0
- package/angular/projects/demo/src/favicon.ico +0 -0
- package/angular/projects/demo/src/index.html +13 -0
- package/angular/projects/demo/src/main.ts +12 -0
- package/angular/projects/demo/src/polyfills.ts +53 -0
- package/angular/projects/demo/src/styles.css +4 -0
- package/angular/projects/demo/src/test.ts +26 -0
- package/angular/projects/demo/tsconfig.app.json +15 -0
- package/angular/projects/demo/tsconfig.spec.json +18 -0
- package/angular/projects/lib/README.md +24 -0
- package/angular/projects/lib/ng-package.json +7 -0
- package/angular/projects/lib/package.json +11 -0
- package/angular/projects/lib/src/lib/base-widget.ts +28 -0
- package/angular/projects/lib/src/lib/gridstack-item.component.ts +78 -0
- package/angular/projects/lib/src/lib/gridstack.component.ts +287 -0
- package/angular/projects/lib/src/lib/gridstack.module.ts +32 -0
- package/angular/projects/lib/src/public-api.ts +8 -0
- package/angular/projects/lib/src/test.ts +27 -0
- package/angular/projects/lib/tsconfig.lib.json +15 -0
- package/angular/projects/lib/tsconfig.lib.prod.json +10 -0
- package/angular/projects/lib/tsconfig.spec.json +17 -0
- package/dist/angular/README.md +170 -0
- package/dist/angular/esm2020/gridstack-angular.mjs +5 -0
- package/dist/angular/esm2020/lib/base-widget.mjs +30 -0
- package/dist/angular/esm2020/lib/gridstack-item.component.mjs +68 -0
- package/dist/angular/esm2020/lib/gridstack.component.mjs +278 -0
- package/dist/angular/esm2020/lib/gridstack.module.mjs +39 -0
- package/dist/angular/esm2020/public-api.mjs +8 -0
- package/dist/angular/fesm2015/gridstack-angular.mjs +418 -0
- package/dist/angular/fesm2015/gridstack-angular.mjs.map +1 -0
- package/dist/angular/fesm2020/gridstack-angular.mjs +413 -0
- package/dist/angular/fesm2020/gridstack-angular.mjs.map +1 -0
- package/dist/angular/index.d.ts +5 -0
- package/dist/angular/lib/base-widget.d.ts +16 -0
- package/dist/{ng → angular/lib}/gridstack-item.component.d.ts +37 -29
- package/dist/{ng → angular/lib}/gridstack.component.d.ts +129 -118
- package/dist/angular/lib/gridstack.module.d.ts +10 -0
- package/dist/angular/package.json +31 -0
- package/dist/angular/public-api.d.ts +4 -0
- package/dist/angular/src/base-widget.ts +28 -0
- package/dist/angular/src/gridstack-item.component.ts +78 -0
- package/dist/angular/src/gridstack.component.ts +287 -0
- package/dist/angular/src/gridstack.module.ts +32 -0
- package/dist/dd-base-impl.d.ts +1 -1
- package/dist/dd-base-impl.js +1 -1
- package/dist/dd-base-impl.js.map +1 -1
- package/dist/dd-draggable.d.ts +1 -1
- package/dist/dd-draggable.js +1 -1
- package/dist/dd-draggable.js.map +1 -1
- package/dist/dd-droppable.d.ts +1 -1
- package/dist/dd-droppable.js +1 -1
- package/dist/dd-droppable.js.map +1 -1
- package/dist/dd-element.d.ts +1 -1
- package/dist/dd-element.js +1 -1
- package/dist/dd-element.js.map +1 -1
- package/dist/dd-gridstack.d.ts +1 -1
- package/dist/dd-gridstack.js +1 -1
- package/dist/dd-gridstack.js.map +1 -1
- package/dist/dd-manager.d.ts +1 -1
- package/dist/dd-manager.js +1 -1
- package/dist/dd-manager.js.map +1 -1
- package/dist/dd-resizable-handle.d.ts +1 -1
- package/dist/dd-resizable-handle.js +1 -1
- package/dist/dd-resizable-handle.js.map +1 -1
- package/dist/dd-resizable.d.ts +1 -1
- package/dist/dd-resizable.js +1 -1
- package/dist/dd-resizable.js.map +1 -1
- package/dist/dd-touch.d.ts +1 -1
- package/dist/dd-touch.js +1 -1
- package/dist/dd-touch.js.map +1 -1
- package/dist/es5/dd-base-impl.d.ts +1 -1
- package/dist/es5/dd-base-impl.js +1 -1
- package/dist/es5/dd-base-impl.js.map +1 -1
- package/dist/es5/dd-draggable.d.ts +1 -1
- package/dist/es5/dd-draggable.js +1 -1
- package/dist/es5/dd-draggable.js.map +1 -1
- package/dist/es5/dd-droppable.d.ts +1 -1
- package/dist/es5/dd-droppable.js +1 -1
- package/dist/es5/dd-droppable.js.map +1 -1
- package/dist/es5/dd-element.d.ts +1 -1
- package/dist/es5/dd-element.js +1 -1
- package/dist/es5/dd-element.js.map +1 -1
- package/dist/es5/dd-gridstack.d.ts +1 -1
- package/dist/es5/dd-gridstack.js +1 -1
- package/dist/es5/dd-gridstack.js.map +1 -1
- package/dist/es5/dd-manager.d.ts +1 -1
- package/dist/es5/dd-manager.js +1 -1
- package/dist/es5/dd-manager.js.map +1 -1
- package/dist/es5/dd-resizable-handle.d.ts +1 -1
- package/dist/es5/dd-resizable-handle.js +1 -1
- package/dist/es5/dd-resizable-handle.js.map +1 -1
- package/dist/es5/dd-resizable.d.ts +1 -1
- package/dist/es5/dd-resizable.js +1 -1
- package/dist/es5/dd-resizable.js.map +1 -1
- package/dist/es5/dd-touch.d.ts +1 -1
- package/dist/es5/dd-touch.js +1 -1
- package/dist/es5/dd-touch.js.map +1 -1
- package/dist/es5/gridstack-all.js +1 -1
- package/dist/es5/gridstack-all.js.LICENSE.txt +1 -1
- package/dist/es5/gridstack-all.js.map +1 -1
- package/dist/es5/gridstack-engine.d.ts +1 -1
- package/dist/es5/gridstack-engine.js +1 -1
- package/dist/es5/gridstack-engine.js.map +1 -1
- package/dist/es5/gridstack-poly.js +1 -1
- package/dist/es5/gridstack.d.ts +8 -5
- package/dist/es5/gridstack.js +13 -7
- package/dist/es5/gridstack.js.map +1 -1
- package/dist/es5/types.d.ts +1 -1
- package/dist/es5/types.js +1 -1
- package/dist/es5/types.js.map +1 -1
- package/dist/es5/utils.d.ts +1 -1
- package/dist/es5/utils.js +1 -1
- package/dist/es5/utils.js.map +1 -1
- package/dist/gridstack-all.js +1 -1
- package/dist/gridstack-all.js.LICENSE.txt +1 -1
- package/dist/gridstack-all.js.map +1 -1
- package/dist/gridstack-engine.d.ts +1 -1
- package/dist/gridstack-engine.js +1 -1
- package/dist/gridstack-engine.js.map +1 -1
- package/dist/gridstack.css +1 -1
- package/dist/gridstack.d.ts +8 -5
- package/dist/gridstack.js +13 -7
- package/dist/gridstack.js.map +1 -1
- package/dist/src/gridstack-extra.scss +3 -3
- package/dist/src/gridstack.scss +1 -1
- package/dist/types.d.ts +1 -1
- package/dist/types.js +1 -1
- package/dist/types.js.map +1 -1
- package/dist/utils.d.ts +1 -1
- package/dist/utils.js +1 -1
- package/dist/utils.js.map +1 -1
- package/doc/CHANGES.md +11 -1
- package/package.json +3 -3
- package/dist/ng/gridstack-item.component.js +0 -65
- package/dist/ng/gridstack-item.component.js.map +0 -1
- package/dist/ng/gridstack.component.js +0 -245
- package/dist/ng/gridstack.component.js.map +0 -1
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "gridstack-lib",
|
|
3
|
+
"version": "0.0.0",
|
|
4
|
+
"scripts": {
|
|
5
|
+
"ng": "ng",
|
|
6
|
+
"start": "ng serve",
|
|
7
|
+
"build": "ng build",
|
|
8
|
+
"watch": "ng build --watch --configuration development",
|
|
9
|
+
"test": "ng test"
|
|
10
|
+
},
|
|
11
|
+
"private": true,
|
|
12
|
+
"dependencies": {
|
|
13
|
+
"@angular/animations": "^14.2.0",
|
|
14
|
+
"@angular/common": "^14.2.0",
|
|
15
|
+
"@angular/compiler": "^14.2.0",
|
|
16
|
+
"@angular/core": "^14.2.0",
|
|
17
|
+
"@angular/forms": "^14.2.0",
|
|
18
|
+
"@angular/platform-browser": "^14.2.0",
|
|
19
|
+
"@angular/platform-browser-dynamic": "^14.2.0",
|
|
20
|
+
"@angular/router": "^14.2.0",
|
|
21
|
+
"gridstack": "^8.1.2",
|
|
22
|
+
"rxjs": "~7.5.0",
|
|
23
|
+
"tslib": "^2.3.0",
|
|
24
|
+
"zone.js": "~0.11.4"
|
|
25
|
+
},
|
|
26
|
+
"devDependencies": {
|
|
27
|
+
"@angular-devkit/build-angular": "^14.2.11",
|
|
28
|
+
"@angular/cli": "~14.2.10",
|
|
29
|
+
"@angular/compiler-cli": "^14.2.0",
|
|
30
|
+
"@types/jasmine": "~4.0.0",
|
|
31
|
+
"jasmine-core": "~4.3.0",
|
|
32
|
+
"karma": "~6.4.0",
|
|
33
|
+
"karma-chrome-launcher": "~3.1.0",
|
|
34
|
+
"karma-coverage": "~2.2.0",
|
|
35
|
+
"karma-jasmine": "~5.1.0",
|
|
36
|
+
"karma-jasmine-html-reporter": "~2.0.0",
|
|
37
|
+
"ng-packagr": "^14.2.0",
|
|
38
|
+
"typescript": "~4.7.2"
|
|
39
|
+
}
|
|
40
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
# This file is used by the build system to adjust CSS and JS output to support the specified browsers below.
|
|
2
|
+
# For additional information regarding the format and rule options, please see:
|
|
3
|
+
# https://github.com/browserslist/browserslist#queries
|
|
4
|
+
|
|
5
|
+
# For the full list of supported browsers by the Angular framework, please see:
|
|
6
|
+
# https://angular.io/guide/browser-support
|
|
7
|
+
|
|
8
|
+
# You can see what browsers were selected by your queries by running:
|
|
9
|
+
# npx browserslist
|
|
10
|
+
|
|
11
|
+
last 1 Chrome version
|
|
12
|
+
last 1 Firefox version
|
|
13
|
+
last 2 Edge major versions
|
|
14
|
+
last 2 Safari major versions
|
|
15
|
+
last 2 iOS major versions
|
|
16
|
+
Firefox ESR
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
|
|
2
|
+
<div class="button-container">
|
|
3
|
+
<p class="pick-info">Pick a demo to load:</p>
|
|
4
|
+
<button (click)="onShow(0)" [class.active]="show===0">Simple</button>
|
|
5
|
+
<button (click)="onShow(1)" [class.active]="show===1">ngFor case</button>
|
|
6
|
+
<button (click)="onShow(2)" [class.active]="show===2">ngFor custom command</button>
|
|
7
|
+
<button (click)="onShow(3)" [class.active]="show===3">Component HTML template</button>
|
|
8
|
+
<button (click)="onShow(4)" [class.active]="show===4">Component ngFor</button>
|
|
9
|
+
<button (click)="onShow(5)" [class.active]="show===5">Component Dynamic</button>
|
|
10
|
+
<button (click)="onShow(6)" [class.active]="show===6">Nested Grid</button>
|
|
11
|
+
</div>
|
|
12
|
+
|
|
13
|
+
<div class="test-container">
|
|
14
|
+
<angular-simple-test *ngIf="show===0"></angular-simple-test>
|
|
15
|
+
<angular-ng-for-test *ngIf="show===1"></angular-ng-for-test>
|
|
16
|
+
<angular-ng-for-cmd-test *ngIf="show===2"></angular-ng-for-cmd-test>
|
|
17
|
+
|
|
18
|
+
<div *ngIf="show===3">
|
|
19
|
+
<p><b>COMPONENT template</b>: using DOM template to use components statically</p>
|
|
20
|
+
<button (click)="add()">add item</button>
|
|
21
|
+
<button (click)="delete()">remove item</button>
|
|
22
|
+
<button (click)="modify()">modify item</button>
|
|
23
|
+
<button (click)="newLayout()">new layout</button>
|
|
24
|
+
<gridstack [options]="gridOptions" (changeCB)="onChange($event)" (resizeStopCB)="onResizeStop($event)">
|
|
25
|
+
<gridstack-item gs-x="1" gs-y="0">item 1</gridstack-item>
|
|
26
|
+
<gridstack-item gs-x="3" gs-y="0" gs-w="2">item 2 wide</gridstack-item>
|
|
27
|
+
</gridstack>
|
|
28
|
+
</div>
|
|
29
|
+
|
|
30
|
+
<div *ngIf="show===4">
|
|
31
|
+
<p><b>COMPONENT ngFor</b>: Most complete example that uses Component wrapper for grid and gridItem</p>
|
|
32
|
+
<button (click)="addNgFor()">add item</button>
|
|
33
|
+
<button (click)="deleteNgFor()">remove item</button>
|
|
34
|
+
<button (click)="modifyNgFor()">modify item</button>
|
|
35
|
+
<button (click)="newLayoutNgFor()">new layout</button>
|
|
36
|
+
<gridstack [options]="gridOptions" (changeCB)="onChange($event)" (resizeStopCB)="onResizeStop($event)">
|
|
37
|
+
<gridstack-item *ngFor="let n of items; trackBy: identify" [options]="n">
|
|
38
|
+
</gridstack-item>
|
|
39
|
+
</gridstack>
|
|
40
|
+
</div>
|
|
41
|
+
|
|
42
|
+
<div *ngIf="show===5">
|
|
43
|
+
<p><b>COMPONENT dynamic</b>: Best example that uses Component wrapper and dynamic grid creation (drag between grids, from toolbar, etc...)</p>
|
|
44
|
+
<button (click)="add()">add item</button>
|
|
45
|
+
<button (click)="delete()">remove item</button>
|
|
46
|
+
<button (click)="modify()">modify item</button>
|
|
47
|
+
<button (click)="newLayout()">new layout</button>
|
|
48
|
+
<button (click)="saveGrid()">Save</button>
|
|
49
|
+
<button (click)="clearGrid()">Clear</button>
|
|
50
|
+
<button (click)="loadGrid()">Load</button>
|
|
51
|
+
<gridstack [options]="gridOptionsFull" (changeCB)="onChange($event)" (resizeStopCB)="onResizeStop($event)">
|
|
52
|
+
</gridstack>
|
|
53
|
+
</div>
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
<div *ngIf="show===6">
|
|
57
|
+
<p><b>Nested Grid</b>: shows nested component grids, like nested.html demo but with Ng Components</p>
|
|
58
|
+
<button (click)="add()">add item</button>
|
|
59
|
+
<button (click)="delete()">remove item</button>
|
|
60
|
+
<button (click)="modify()">modify item</button>
|
|
61
|
+
<button (click)="newLayout()">new layout</button>
|
|
62
|
+
<button (click)="saveGrid()">Save</button>
|
|
63
|
+
<button (click)="clearGrid()">Clear</button>
|
|
64
|
+
<button (click)="loadGrid()">Load</button>
|
|
65
|
+
<!-- TODO: addGrid() in code for testing instead ? -->
|
|
66
|
+
<gridstack [options]="nestedGridOptions" (changeCB)="onChange($event)" (resizeStopCB)="onResizeStop($event)">
|
|
67
|
+
<div empty-content>Add items here or reload the grid</div>
|
|
68
|
+
</gridstack>
|
|
69
|
+
</div>
|
|
70
|
+
|
|
71
|
+
<div class="grid-container"></div>
|
|
72
|
+
|
|
73
|
+
<div class="text-container">
|
|
74
|
+
<textarea #origTextArea cols="50" rows="50" readonly="readonly"></textarea>
|
|
75
|
+
<textarea #textArea cols="50" rows="50" readonly="readonly"></textarea>
|
|
76
|
+
</div>
|
|
77
|
+
|
|
78
|
+
</div>
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { TestBed } from '@angular/core/testing';
|
|
2
|
+
import { AppComponent } from './app.component';
|
|
3
|
+
|
|
4
|
+
describe('AppComponent', () => {
|
|
5
|
+
beforeEach(async () => {
|
|
6
|
+
await TestBed.configureTestingModule({
|
|
7
|
+
declarations: [
|
|
8
|
+
AppComponent
|
|
9
|
+
],
|
|
10
|
+
}).compileComponents();
|
|
11
|
+
});
|
|
12
|
+
|
|
13
|
+
it('should create the app', () => {
|
|
14
|
+
const fixture = TestBed.createComponent(AppComponent);
|
|
15
|
+
const app = fixture.componentInstance;
|
|
16
|
+
expect(app).toBeTruthy();
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
it('should have content', () => {
|
|
20
|
+
const fixture = TestBed.createComponent(AppComponent);
|
|
21
|
+
fixture.detectChanges();
|
|
22
|
+
const compiled = fixture.nativeElement as HTMLElement;
|
|
23
|
+
expect(compiled.querySelector('.pick-info')?.textContent).toContain('Pick a demo to load');
|
|
24
|
+
});
|
|
25
|
+
});
|
|
@@ -0,0 +1,208 @@
|
|
|
1
|
+
import { Component, OnInit, ViewChild, ElementRef } from '@angular/core';
|
|
2
|
+
import { GridStack, GridStackOptions, GridStackWidget } from 'gridstack';
|
|
3
|
+
import { AngularSimpleComponent } from './simple';
|
|
4
|
+
import { AngularNgForTestComponent } from './ngFor';
|
|
5
|
+
import { AngularNgForCmdTestComponent } from './ngFor_cmd';
|
|
6
|
+
|
|
7
|
+
// NOTE: local testing of file
|
|
8
|
+
// import { GridstackComponent, NgGridStackOptions, NgGridStackWidget, elementCB, gsCreateNgComponents, nodesCB } from './gridstack.component';
|
|
9
|
+
import { GridstackComponent, NgGridStackOptions, NgGridStackWidget, elementCB, gsCreateNgComponents, nodesCB } from 'gridstack/dist/angular';
|
|
10
|
+
|
|
11
|
+
// unique ids sets for each item for correct ngFor updating
|
|
12
|
+
let ids = 1;
|
|
13
|
+
@Component({
|
|
14
|
+
selector: 'app-root',
|
|
15
|
+
templateUrl: './app.component.html',
|
|
16
|
+
styleUrls: ['./app.component.css']
|
|
17
|
+
})
|
|
18
|
+
export class AppComponent implements OnInit {
|
|
19
|
+
|
|
20
|
+
@ViewChild(AngularSimpleComponent) case0Comp?: AngularSimpleComponent;
|
|
21
|
+
@ViewChild(AngularNgForTestComponent) case1Comp?: AngularNgForTestComponent;
|
|
22
|
+
@ViewChild(AngularNgForCmdTestComponent) case2Comp?: AngularNgForCmdTestComponent;
|
|
23
|
+
@ViewChild(GridstackComponent) gridComp?: GridstackComponent;
|
|
24
|
+
@ViewChild('origTextArea', {static: true}) origTextEl?: ElementRef<HTMLTextAreaElement>;
|
|
25
|
+
@ViewChild('textArea', {static: true}) textEl?: ElementRef<HTMLTextAreaElement>;
|
|
26
|
+
|
|
27
|
+
// which sample to show
|
|
28
|
+
public show = 5;
|
|
29
|
+
|
|
30
|
+
/** sample grid options and items to load... */
|
|
31
|
+
public items: GridStackWidget[] = [
|
|
32
|
+
{x: 0, y: 0, minW: 2},
|
|
33
|
+
{x: 1, y: 1},
|
|
34
|
+
{x: 2, y: 2},
|
|
35
|
+
];
|
|
36
|
+
public gridOptions: GridStackOptions = {
|
|
37
|
+
margin: 5,
|
|
38
|
+
float: true,
|
|
39
|
+
minRow: 1,
|
|
40
|
+
}
|
|
41
|
+
public gridOptionsFull: NgGridStackOptions = {
|
|
42
|
+
...this.gridOptions,
|
|
43
|
+
children: [{x:0, y:0, selector:'app-a'}, {x:1, y:0, selector:'app-b'}, {x:2, y:0, content:'plain html'}],
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
// nested grid options
|
|
47
|
+
private subOptions: GridStackOptions = {
|
|
48
|
+
cellHeight: 50, // should be 50 - top/bottom
|
|
49
|
+
column: 'auto', // size to match container. make sure to include gridstack-extra.min.css
|
|
50
|
+
acceptWidgets: true, // will accept .grid-stack-item by default
|
|
51
|
+
margin: 5,
|
|
52
|
+
};
|
|
53
|
+
private sub1: NgGridStackWidget[] = [ {x:0, y:0, selector:'app-a'}, {x:1, y:0, selector:'app-b'}, {x:2, y:0, selector:'app-c'}, {x:3, y:0}, {x:0, y:1}, {x:1, y:1}];
|
|
54
|
+
private sub2: NgGridStackWidget[] = [ {x:0, y:0}, {x:0, y:1, w:2}];
|
|
55
|
+
private subChildren: NgGridStackWidget[] = [
|
|
56
|
+
{x:0, y:0, content: 'regular item'},
|
|
57
|
+
{x:1, y:0, w:4, h:4, subGridOpts: {children: this.sub1, id:'sub1_grid', class: 'sub1', ...this.subOptions}},
|
|
58
|
+
{x:5, y:0, w:3, h:4, subGridOpts: {children: this.sub2, id:'sub2_grid', class: 'sub2', ...this.subOptions}},
|
|
59
|
+
]
|
|
60
|
+
public nestedGridOptions: NgGridStackOptions = { // main grid options
|
|
61
|
+
cellHeight: 50,
|
|
62
|
+
margin: 5,
|
|
63
|
+
minRow: 2, // don't collapse when empty
|
|
64
|
+
disableOneColumnMode: true,
|
|
65
|
+
acceptWidgets: true,
|
|
66
|
+
id: 'main',
|
|
67
|
+
children: this.subChildren
|
|
68
|
+
};
|
|
69
|
+
private serializedData?: NgGridStackOptions;
|
|
70
|
+
|
|
71
|
+
constructor() {
|
|
72
|
+
// give them content and unique id to make sure we track them during changes below...
|
|
73
|
+
[...this.items, ...this.subChildren, ...this.sub1, ...this.sub2].forEach((w: NgGridStackWidget) => {
|
|
74
|
+
if (!w.selector && !w.subGridOpts) w.content = `item ${ids}`;
|
|
75
|
+
w.id = String(ids++);
|
|
76
|
+
});
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
ngOnInit(): void {
|
|
80
|
+
this.onShow(this.show);
|
|
81
|
+
|
|
82
|
+
// TEST
|
|
83
|
+
// setTimeout(() => {
|
|
84
|
+
// if (!this.gridComp) return;
|
|
85
|
+
// this.saveGrid();
|
|
86
|
+
// // this.clearGrid();
|
|
87
|
+
// this.delete();
|
|
88
|
+
// this.delete();
|
|
89
|
+
// this.loadGrid();
|
|
90
|
+
// this.delete();
|
|
91
|
+
// this.delete();
|
|
92
|
+
// }, 500)
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
public onShow(val: number) {
|
|
96
|
+
this.show = val;
|
|
97
|
+
|
|
98
|
+
// set globally our method to create the right widget type
|
|
99
|
+
if (val < 3) GridStack.addRemoveCB = undefined;
|
|
100
|
+
else GridStack.addRemoveCB = gsCreateNgComponents;
|
|
101
|
+
|
|
102
|
+
// let the switch take affect then load the starting values (since we sometimes save())
|
|
103
|
+
setTimeout(() => {
|
|
104
|
+
let data;
|
|
105
|
+
switch(val) {
|
|
106
|
+
case 0: data = this.case0Comp?.items; break;
|
|
107
|
+
case 1: data = this.case1Comp?.items; break;
|
|
108
|
+
case 2: data = this.case2Comp?.items; break;
|
|
109
|
+
case 3: data = this.gridComp?.grid?.save(true, true); break;
|
|
110
|
+
case 4: data = this.items; break;
|
|
111
|
+
case 5: data = this.gridOptionsFull; break;
|
|
112
|
+
case 6: data = this.nestedGridOptions; break;
|
|
113
|
+
}
|
|
114
|
+
if (this.origTextEl) this.origTextEl.nativeElement.value = JSON.stringify(data, null, ' ');
|
|
115
|
+
});
|
|
116
|
+
if (this.textEl) this.textEl.nativeElement.value = '';
|
|
117
|
+
|
|
118
|
+
// if (val === 6 && !this.gridComp) {
|
|
119
|
+
// const cont: HTMLElement | null = document.querySelector('.grid-container');
|
|
120
|
+
// if (cont) GridStack.addGrid(cont, this.serializedData);
|
|
121
|
+
// }
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
/** called whenever items change size/position/etc.. */
|
|
125
|
+
public onChange(data: nodesCB) {
|
|
126
|
+
// TODO: update our TEMPLATE list to match ?
|
|
127
|
+
// NOTE: no need for dynamic as we can always use grid.save() to get latest layout, or grid.engine.nodes
|
|
128
|
+
console.log('change ', data.nodes.length > 1 ? data.nodes : data.nodes[0]);
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
public onResizeStop(data: elementCB) {
|
|
132
|
+
console.log('resizestop ', data.el.gridstackNode);
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
/**
|
|
136
|
+
* TEST dynamic grid operations - uses grid API directly (since we don't track structure that gets out of sync)
|
|
137
|
+
*/
|
|
138
|
+
public add() {
|
|
139
|
+
// TODO: BUG the content doesn't appear until widget is moved around (or another created). Need to force
|
|
140
|
+
// angular detection changes...
|
|
141
|
+
this.gridComp?.grid?.addWidget({x:3, y:0, w:2, content:`item ${ids}`, id:String(ids++)});
|
|
142
|
+
}
|
|
143
|
+
public delete() {
|
|
144
|
+
let grid = this.gridComp?.grid;
|
|
145
|
+
if (!grid) return;
|
|
146
|
+
let node = grid.engine.nodes[0];
|
|
147
|
+
// delete any children first before subGrid itself...
|
|
148
|
+
if (node?.subGrid && node.subGrid.engine.nodes.length) {
|
|
149
|
+
grid = node.subGrid;
|
|
150
|
+
node = grid.engine.nodes[0];
|
|
151
|
+
}
|
|
152
|
+
if (node) grid.removeWidget(node.el!);
|
|
153
|
+
}
|
|
154
|
+
public modify() {
|
|
155
|
+
this.gridComp?.grid?.update(this.gridComp?.grid.engine.nodes[0]?.el!, {w:3})
|
|
156
|
+
}
|
|
157
|
+
public newLayout() {
|
|
158
|
+
this.gridComp?.grid?.load([
|
|
159
|
+
{x:0, y:1, id:'1', minW:1, w:1}, // new size/constrain
|
|
160
|
+
{x:1, y:1, id:'2'},
|
|
161
|
+
// {x:2, y:1, id:'3'}, // delete item
|
|
162
|
+
{x:3, y:0, w:2, content:'new item'}, // new item
|
|
163
|
+
]);
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
/**
|
|
167
|
+
* ngFor case: TEST TEMPLATE operations - NOT recommended unless you have no GS creating/re-parenting
|
|
168
|
+
*/
|
|
169
|
+
public addNgFor() {
|
|
170
|
+
// new array isn't required as Angular detects changes to content with trackBy:identify()
|
|
171
|
+
// this.items = [...this.items, { x:3, y:0, w:3, content:`item ${ids}`, id:String(ids++) }];
|
|
172
|
+
this.items.push({x:3, y:0, w:2, content:`item ${ids}`, id:String(ids++)});
|
|
173
|
+
}
|
|
174
|
+
public deleteNgFor() {
|
|
175
|
+
this.items.pop();
|
|
176
|
+
}
|
|
177
|
+
public modifyNgFor() {
|
|
178
|
+
// this will not update the DOM nor trigger gridstackItems.changes for GS to auto-update, so set new option of the gridItem instead
|
|
179
|
+
// this.items[0].w = 3;
|
|
180
|
+
const gridItem = this.gridComp?.gridstackItems?.get(0);
|
|
181
|
+
if (gridItem) gridItem.options = {w:3};
|
|
182
|
+
}
|
|
183
|
+
public newLayoutNgFor() {
|
|
184
|
+
this.items = [
|
|
185
|
+
{x:0, y:1, id:'1', minW:1, w:1}, // new size/constrain
|
|
186
|
+
{x:1, y:1, id:'2'},
|
|
187
|
+
// {x:2, y:1, id:'3'}, // delete item
|
|
188
|
+
{x:3, y:0, w:2, content:'new item'}, // new item
|
|
189
|
+
];
|
|
190
|
+
}
|
|
191
|
+
public clearGrid() {
|
|
192
|
+
if (!this.gridComp) return;
|
|
193
|
+
this.gridComp.grid?.removeAll(true);
|
|
194
|
+
}
|
|
195
|
+
public saveGrid() {
|
|
196
|
+
this.serializedData = this.gridComp?.grid?.save(false, true) as GridStackOptions || ''; // no content, full options
|
|
197
|
+
if (this.textEl) this.textEl.nativeElement.value = JSON.stringify(this.serializedData, null, ' ');
|
|
198
|
+
}
|
|
199
|
+
public loadGrid() {
|
|
200
|
+
if (!this.gridComp) return;
|
|
201
|
+
GridStack.addGrid(this.gridComp.el, this.serializedData);
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
// ngFor TEMPLATE unique node id to have correct match between our items used and GS
|
|
205
|
+
public identify(index: number, w: GridStackWidget) {
|
|
206
|
+
return w.id; // or use index if no id is set and you only modify at the end...
|
|
207
|
+
}
|
|
208
|
+
}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { NgModule } from '@angular/core';
|
|
2
|
+
import { BrowserModule } from '@angular/platform-browser';
|
|
3
|
+
|
|
4
|
+
import { AppComponent } from './app.component';
|
|
5
|
+
import { AngularNgForTestComponent } from './ngFor';
|
|
6
|
+
import { AngularNgForCmdTestComponent } from './ngFor_cmd';
|
|
7
|
+
import { AngularSimpleComponent } from './simple';
|
|
8
|
+
import { AComponent, BComponent, CComponent } from './dummy.component';
|
|
9
|
+
|
|
10
|
+
// local testing
|
|
11
|
+
// import { GridstackModule } from './gridstack.module';
|
|
12
|
+
// import { GridstackComponent } from './gridstack.component';
|
|
13
|
+
import { GridstackModule, GridstackComponent } from 'gridstack/dist/angular';
|
|
14
|
+
|
|
15
|
+
@NgModule({
|
|
16
|
+
imports: [
|
|
17
|
+
BrowserModule,
|
|
18
|
+
GridstackModule,
|
|
19
|
+
],
|
|
20
|
+
declarations: [
|
|
21
|
+
AngularNgForCmdTestComponent,
|
|
22
|
+
AngularNgForTestComponent,
|
|
23
|
+
AngularSimpleComponent,
|
|
24
|
+
AppComponent,
|
|
25
|
+
AComponent,
|
|
26
|
+
BComponent,
|
|
27
|
+
CComponent,
|
|
28
|
+
],
|
|
29
|
+
exports: [
|
|
30
|
+
],
|
|
31
|
+
providers: [],
|
|
32
|
+
bootstrap: [AppComponent]
|
|
33
|
+
})
|
|
34
|
+
export class AppModule {
|
|
35
|
+
constructor() {
|
|
36
|
+
// register all our dynamic components created in the grid
|
|
37
|
+
GridstackComponent.addComponentToSelectorType([AComponent, BComponent, CComponent]);
|
|
38
|
+
}
|
|
39
|
+
}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* gridstack.component.ts 8.2.0
|
|
3
|
+
* Copyright (c) 2022 Alain Dumesny - see GridStack root license
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
// dummy testing component that will be grid items content
|
|
7
|
+
|
|
8
|
+
import { Component, OnDestroy, Input } from '@angular/core';
|
|
9
|
+
import { BaseWidget, NgCompInputs } from 'gridstack/dist/angular';
|
|
10
|
+
|
|
11
|
+
@Component({
|
|
12
|
+
selector: 'app-a',
|
|
13
|
+
template: 'Comp A {{text}}',
|
|
14
|
+
})
|
|
15
|
+
export class AComponent extends BaseWidget implements OnDestroy {
|
|
16
|
+
@Input() text: string = 'foo'; // test custom input data
|
|
17
|
+
public override serialize(): NgCompInputs | undefined { return this.text ? {text: this.text} : undefined; }
|
|
18
|
+
ngOnDestroy() {
|
|
19
|
+
console.log('Comp A destroyed'); // test to make sure cleanup happens
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
@Component({
|
|
24
|
+
selector: 'app-b',
|
|
25
|
+
template: 'Comp B',
|
|
26
|
+
})
|
|
27
|
+
export class BComponent extends BaseWidget {
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
@Component({
|
|
31
|
+
selector: 'app-c',
|
|
32
|
+
template: 'Comp C',
|
|
33
|
+
})
|
|
34
|
+
export class CComponent extends BaseWidget {
|
|
35
|
+
}
|
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Example using Angular ngFor to loop through items and create DOM items
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import { Component, AfterViewInit, Input, ViewChildren, QueryList, ElementRef } from '@angular/core';
|
|
6
|
+
import { GridItemHTMLElement, GridStack, GridStackNode, GridStackWidget, Utils } from 'gridstack';
|
|
7
|
+
|
|
8
|
+
// unique ids sets for each item for correct ngFor updating
|
|
9
|
+
let ids = 1;
|
|
10
|
+
|
|
11
|
+
@Component({
|
|
12
|
+
selector: "angular-ng-for-test",
|
|
13
|
+
template: `
|
|
14
|
+
<p><b>ngFor</b>: Example using Angular ngFor to loop through items and create DOM items. This track changes made to the array of items, waits for DOM rendering, then update GS</p>
|
|
15
|
+
<button (click)="add()">add item</button>
|
|
16
|
+
<button (click)="delete()">remove item</button>
|
|
17
|
+
<button (click)="modify()">modify item</button>
|
|
18
|
+
<button (click)="newLayout()">new layout</button>
|
|
19
|
+
<div class="grid-stack">
|
|
20
|
+
<!-- using angular templating to create DOM, otherwise an easier way is to simply call grid.load(items)
|
|
21
|
+
NOTE: this example is NOT complete as there are many more properties than listed (minW, maxW, etc....)
|
|
22
|
+
-->
|
|
23
|
+
<div *ngFor="let n of items; trackBy: identify"
|
|
24
|
+
class="grid-stack-item"
|
|
25
|
+
[attr.gs-id]="n.id"
|
|
26
|
+
[attr.gs-x]="n.x"
|
|
27
|
+
[attr.gs-y]="n.y"
|
|
28
|
+
[attr.gs-w]="n.w"
|
|
29
|
+
[attr.gs-h]="n.h"
|
|
30
|
+
#gridStackItem
|
|
31
|
+
>
|
|
32
|
+
<div class="grid-stack-item-content">item {{ n.id }}</div>
|
|
33
|
+
</div>
|
|
34
|
+
</div>
|
|
35
|
+
`,
|
|
36
|
+
// gridstack.min.css and other custom styles should be included in global styles.scss or here
|
|
37
|
+
})
|
|
38
|
+
export class AngularNgForTestComponent implements AfterViewInit {
|
|
39
|
+
/** list of HTML items that we track to know when the DOM has been updated to make/remove GS widgets */
|
|
40
|
+
@ViewChildren("gridStackItem") gridstackItems!: QueryList<ElementRef<GridItemHTMLElement>>;
|
|
41
|
+
|
|
42
|
+
/** set the items to display. */
|
|
43
|
+
@Input() public set items(list: GridStackWidget[]) {
|
|
44
|
+
this._items = list || [];
|
|
45
|
+
this._items.forEach(w => w.id = w.id || String(ids++)); // make sure a unique id is generated for correct ngFor loop update
|
|
46
|
+
}
|
|
47
|
+
public get items(): GridStackWidget[] { return this._items}
|
|
48
|
+
|
|
49
|
+
private grid!: GridStack;
|
|
50
|
+
public _items!: GridStackWidget[];
|
|
51
|
+
|
|
52
|
+
constructor() {
|
|
53
|
+
this.items = [
|
|
54
|
+
{x: 0, y: 0},
|
|
55
|
+
{x: 1, y: 1},
|
|
56
|
+
{x: 2, y: 2},
|
|
57
|
+
];
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
// wait until after DOM is ready to init gridstack - can't be ngOnInit() as angular ngFor needs to run first!
|
|
61
|
+
public ngAfterViewInit() {
|
|
62
|
+
this.grid = GridStack.init({
|
|
63
|
+
margin: 5,
|
|
64
|
+
float: true,
|
|
65
|
+
})
|
|
66
|
+
.on('change added', (event: Event, nodes: GridStackNode[]) => this.onChange(nodes));
|
|
67
|
+
|
|
68
|
+
// sync initial actual valued rendered (in case init() had to merge conflicts)
|
|
69
|
+
this.onChange();
|
|
70
|
+
|
|
71
|
+
/**
|
|
72
|
+
* this is called when the list of items changes - get a list of nodes and
|
|
73
|
+
* update the layout accordingly (which will take care of adding/removing items changed by Angular)
|
|
74
|
+
*/
|
|
75
|
+
this.gridstackItems.changes.subscribe(() => {
|
|
76
|
+
const layout: GridStackWidget[] = [];
|
|
77
|
+
this.gridstackItems.forEach(ref => {
|
|
78
|
+
const n = ref.nativeElement.gridstackNode || this.grid.makeWidget(ref.nativeElement).gridstackNode;
|
|
79
|
+
if (n) layout.push(n);
|
|
80
|
+
});
|
|
81
|
+
this.grid.load(layout); // efficient that does diffs only
|
|
82
|
+
})
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
/** Optional: called when given widgets are changed (moved/resized/added) - update our list to match.
|
|
86
|
+
* Note this is not strictly necessary as demo works without this
|
|
87
|
+
*/
|
|
88
|
+
public onChange(list = this.grid.engine.nodes) {
|
|
89
|
+
setTimeout(() => // prevent new 'added' items from ExpressionChangedAfterItHasBeenCheckedError. TODO: find cleaner way to sync outside Angular change detection ?
|
|
90
|
+
list.forEach(n => {
|
|
91
|
+
const item = this._items.find(i => i.id === n.id);
|
|
92
|
+
if (item) Utils.copyPos(item, n);
|
|
93
|
+
})
|
|
94
|
+
, 0);
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
/**
|
|
98
|
+
* CRUD operations
|
|
99
|
+
*/
|
|
100
|
+
public add() {
|
|
101
|
+
// new array isn't required as Angular seem to detect changes to content
|
|
102
|
+
// this.items = [...this.items, { x:3, y:0, w:3, id:String(ids++) }];
|
|
103
|
+
this.items.push({ x:3, y:0, w:3, id:String(ids++) });
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
public delete() {
|
|
107
|
+
this.items.pop();
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
public modify() {
|
|
111
|
+
// this will only update the DOM attr (from the ngFor loop in our template above)
|
|
112
|
+
// but not trigger gridstackItems.changes for GS to auto-update, so call GS update() instead
|
|
113
|
+
// this.items[0].w = 2;
|
|
114
|
+
const n = this.grid.engine.nodes[0];
|
|
115
|
+
if (n?.el) this.grid.update(n.el, {w:3});
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
public newLayout() {
|
|
119
|
+
this.items = [ // test updating existing and creating new one
|
|
120
|
+
{x:0, y:1, id:'1'},
|
|
121
|
+
{x:1, y:1, id:'2'},
|
|
122
|
+
// {x:2, y:1, id:3}, // delete item
|
|
123
|
+
{x:3, y:0, w:3}, // new item
|
|
124
|
+
];
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
// ngFor unique node id to have correct match between our items used and GS
|
|
128
|
+
identify(index: number, w: GridStackWidget) {
|
|
129
|
+
return w.id;
|
|
130
|
+
}
|
|
131
|
+
}
|