gridstack 10.3.0 → 11.0.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 +37 -3
- package/dist/angular/README.md +47 -25
- package/dist/angular/{esm2020 → esm2022}/gridstack-angular.mjs +5 -5
- package/dist/angular/esm2022/index.mjs +8 -0
- package/dist/angular/esm2022/lib/base-widget.mjs +34 -0
- package/dist/angular/esm2022/lib/gridstack-item.component.mjs +72 -0
- package/dist/angular/esm2022/lib/gridstack.component.mjs +300 -0
- package/dist/angular/esm2022/lib/gridstack.module.mjs +39 -0
- package/dist/angular/{fesm2020 → fesm2022}/gridstack-angular.mjs +400 -369
- package/dist/angular/fesm2022/gridstack-angular.mjs.map +1 -0
- package/dist/angular/index.d.ts +4 -5
- package/dist/angular/lib/base-widget.d.ts +18 -16
- package/dist/angular/lib/gridstack-item.component.d.ts +37 -37
- package/dist/angular/lib/gridstack.component.d.ts +135 -129
- package/dist/angular/lib/gridstack.module.d.ts +10 -10
- package/dist/angular/src/base-widget.ts +36 -0
- package/dist/angular/src/gridstack-item.component.ts +82 -0
- package/dist/angular/src/gridstack.component.ts +312 -0
- package/dist/angular/src/gridstack.module.ts +32 -0
- package/dist/dd-base-impl.d.ts +2 -2
- package/dist/dd-base-impl.js +2 -2
- package/dist/dd-base-impl.js.map +1 -1
- package/dist/dd-draggable.d.ts +7 -16
- package/dist/dd-draggable.js +23 -34
- package/dist/dd-draggable.js.map +1 -1
- package/dist/dd-droppable.d.ts +2 -2
- package/dist/dd-droppable.js +2 -2
- package/dist/dd-droppable.js.map +1 -1
- package/dist/dd-element.d.ts +5 -5
- package/dist/dd-element.js +2 -2
- package/dist/dd-element.js.map +1 -1
- package/dist/dd-gridstack.d.ts +5 -5
- package/dist/dd-gridstack.js +8 -8
- package/dist/dd-gridstack.js.map +1 -1
- package/dist/dd-manager.d.ts +2 -2
- package/dist/dd-manager.js +2 -2
- package/dist/dd-manager.js.map +1 -1
- package/dist/dd-resizable-handle.d.ts +2 -2
- package/dist/dd-resizable-handle.js +3 -3
- package/dist/dd-resizable-handle.js.map +1 -1
- package/dist/dd-resizable.d.ts +4 -2
- package/dist/dd-resizable.js +15 -10
- package/dist/dd-resizable.js.map +1 -1
- package/dist/dd-touch.d.ts +2 -2
- package/dist/dd-touch.js +2 -2
- package/dist/dd-touch.js.map +1 -1
- package/dist/es5/dd-base-impl.d.ts +2 -2
- package/dist/es5/dd-base-impl.js +2 -2
- package/dist/es5/dd-base-impl.js.map +1 -1
- package/dist/es5/dd-draggable.d.ts +7 -16
- package/dist/es5/dd-draggable.js +20 -29
- package/dist/es5/dd-draggable.js.map +1 -1
- package/dist/es5/dd-droppable.d.ts +2 -2
- package/dist/es5/dd-droppable.js +2 -2
- package/dist/es5/dd-droppable.js.map +1 -1
- package/dist/es5/dd-element.d.ts +5 -5
- package/dist/es5/dd-element.js +2 -2
- package/dist/es5/dd-element.js.map +1 -1
- package/dist/es5/dd-gridstack.d.ts +5 -5
- package/dist/es5/dd-gridstack.js +9 -6
- package/dist/es5/dd-gridstack.js.map +1 -1
- package/dist/es5/dd-manager.d.ts +2 -2
- package/dist/es5/dd-manager.js +2 -2
- package/dist/es5/dd-manager.js.map +1 -1
- package/dist/es5/dd-resizable-handle.d.ts +2 -2
- package/dist/es5/dd-resizable-handle.js +2 -2
- package/dist/es5/dd-resizable-handle.js.map +1 -1
- package/dist/es5/dd-resizable.d.ts +4 -2
- package/dist/es5/dd-resizable.js +13 -8
- package/dist/es5/dd-resizable.js.map +1 -1
- package/dist/es5/dd-touch.d.ts +2 -2
- package/dist/es5/dd-touch.js +2 -2
- 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 +2 -2
- package/dist/es5/gridstack-all.js.map +1 -1
- package/dist/es5/gridstack-engine.d.ts +2 -2
- package/dist/es5/gridstack-engine.js +5 -5
- package/dist/es5/gridstack-engine.js.map +1 -1
- package/dist/es5/gridstack-poly.js +2 -2
- package/dist/es5/gridstack.d.ts +22 -17
- package/dist/es5/gridstack.js +170 -142
- package/dist/es5/gridstack.js.map +1 -1
- package/dist/es5/types.d.ts +16 -8
- package/dist/es5/types.js +3 -10
- package/dist/es5/types.js.map +1 -1
- package/dist/es5/utils.d.ts +6 -2
- package/dist/es5/utils.js +43 -8
- package/dist/es5/utils.js.map +1 -1
- package/dist/gridstack-all.js +1 -1
- package/dist/gridstack-all.js.LICENSE.txt +2 -2
- package/dist/gridstack-all.js.map +1 -1
- package/dist/gridstack-engine.d.ts +2 -2
- package/dist/gridstack-engine.js +61 -61
- package/dist/gridstack-engine.js.map +1 -1
- package/dist/gridstack-extra.css +1 -1
- package/dist/gridstack.css +2 -2
- package/dist/gridstack.d.ts +22 -17
- package/dist/gridstack.js +255 -227
- package/dist/gridstack.js.map +1 -1
- package/dist/src/gridstack-extra.scss +25 -0
- package/dist/src/gridstack.scss +157 -0
- package/dist/types.d.ts +16 -8
- package/dist/types.js +2 -9
- package/dist/types.js.map +1 -1
- package/dist/utils.d.ts +6 -2
- package/dist/utils.js +57 -25
- package/dist/utils.js.map +1 -1
- package/doc/CHANGES.md +16 -0
- package/doc/README.md +18 -23
- package/package.json +3 -2
- package/.github/FUNDING.yml +0 -12
- package/angular/.editorconfig +0 -16
- package/angular/.vscode/extensions.json +0 -4
- package/angular/.vscode/launch.json +0 -20
- package/angular/.vscode/tasks.json +0 -42
- package/angular/README.md +0 -170
- package/angular/README_build.md +0 -27
- package/angular/angular.json +0 -135
- package/angular/package.json +0 -40
- package/angular/projects/lib/README.md +0 -24
- package/angular/projects/lib/ng-package.json +0 -7
- package/angular/projects/lib/package.json +0 -11
- package/angular/projects/lib/tsconfig.lib.json +0 -15
- package/angular/projects/lib/tsconfig.lib.prod.json +0 -10
- package/angular/projects/lib/tsconfig.spec.json +0 -17
- package/dist/angular/esm2020/lib/base-widget.mjs +0 -30
- package/dist/angular/esm2020/lib/gridstack-item.component.mjs +0 -68
- package/dist/angular/esm2020/lib/gridstack.component.mjs +0 -280
- package/dist/angular/esm2020/lib/gridstack.module.mjs +0 -39
- package/dist/angular/esm2020/public-api.mjs +0 -8
- package/dist/angular/fesm2015/gridstack-angular.mjs +0 -420
- package/dist/angular/fesm2015/gridstack-angular.mjs.map +0 -1
- package/dist/angular/fesm2020/gridstack-angular.mjs.map +0 -1
- package/dist/angular/package.json +0 -31
- package/dist/angular/public-api.d.ts +0 -4
|
@@ -0,0 +1,312 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* gridstack.component.ts 11.0.0
|
|
3
|
+
* Copyright (c) 2022-2024 Alain Dumesny - see GridStack root license
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import { AfterContentInit, Component, ContentChildren, ElementRef, EventEmitter, Input,
|
|
7
|
+
OnDestroy, OnInit, Output, QueryList, Type, ViewChild, ViewContainerRef, reflectComponentType, ComponentRef } from '@angular/core';
|
|
8
|
+
import { Subscription } from 'rxjs';
|
|
9
|
+
import { GridHTMLElement, GridItemHTMLElement, GridStack, GridStackNode, GridStackOptions, GridStackWidget } from 'gridstack';
|
|
10
|
+
|
|
11
|
+
import { GridItemCompHTMLElement, GridstackItemComponent } from './gridstack-item.component';
|
|
12
|
+
import { BaseWidget } from './base-widget';
|
|
13
|
+
|
|
14
|
+
/** events handlers emitters signature for different events */
|
|
15
|
+
export type eventCB = {event: Event};
|
|
16
|
+
export type elementCB = {event: Event, el: GridItemHTMLElement};
|
|
17
|
+
export type nodesCB = {event: Event, nodes: GridStackNode[]};
|
|
18
|
+
export type droppedCB = {event: Event, previousNode: GridStackNode, newNode: GridStackNode};
|
|
19
|
+
|
|
20
|
+
export type NgCompInputs = {[key: string]: any};
|
|
21
|
+
|
|
22
|
+
/** extends to store Ng Component selector, instead/inAddition to content */
|
|
23
|
+
export interface NgGridStackWidget extends GridStackWidget {
|
|
24
|
+
/** Angular tag selector for this component to create at runtime */
|
|
25
|
+
selector?: string;
|
|
26
|
+
/** serialized data for the component input fields */
|
|
27
|
+
input?: NgCompInputs;
|
|
28
|
+
/** nested grid options */
|
|
29
|
+
subGridOpts?: NgGridStackOptions;
|
|
30
|
+
}
|
|
31
|
+
export interface NgGridStackNode extends GridStackNode {
|
|
32
|
+
selector?: string; // component type to create as content
|
|
33
|
+
}
|
|
34
|
+
export interface NgGridStackOptions extends GridStackOptions {
|
|
35
|
+
children?: NgGridStackWidget[];
|
|
36
|
+
subGridOpts?: NgGridStackOptions;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/** store element to Ng Class pointer back */
|
|
40
|
+
export interface GridCompHTMLElement extends GridHTMLElement {
|
|
41
|
+
_gridComp?: GridstackComponent;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/** selector string to runtime Type mapping */
|
|
45
|
+
export type SelectorToType = {[key: string]: Type<Object>};
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* HTML Component Wrapper for gridstack, in combination with GridstackItemComponent for the items
|
|
49
|
+
*/
|
|
50
|
+
@Component({
|
|
51
|
+
selector: 'gridstack',
|
|
52
|
+
template: `
|
|
53
|
+
<!-- content to show when when grid is empty, like instructions on how to add widgets -->
|
|
54
|
+
<ng-content select="[empty-content]" *ngIf="isEmpty"></ng-content>
|
|
55
|
+
<!-- where dynamic items go -->
|
|
56
|
+
<ng-template #container></ng-template>
|
|
57
|
+
<!-- where template items go -->
|
|
58
|
+
<ng-content></ng-content>
|
|
59
|
+
`,
|
|
60
|
+
styles: [`
|
|
61
|
+
:host { display: block; }
|
|
62
|
+
`],
|
|
63
|
+
// changeDetection: ChangeDetectionStrategy.OnPush, // IFF you want to optimize and control when ChangeDetection needs to happen...
|
|
64
|
+
})
|
|
65
|
+
export class GridstackComponent implements OnInit, AfterContentInit, OnDestroy {
|
|
66
|
+
|
|
67
|
+
/** track list of TEMPLATE grid items so we can sync between DOM and GS internals */
|
|
68
|
+
@ContentChildren(GridstackItemComponent) public gridstackItems?: QueryList<GridstackItemComponent>;
|
|
69
|
+
/** container to append items dynamically */
|
|
70
|
+
@ViewChild('container', { read: ViewContainerRef, static: true}) public container?: ViewContainerRef;
|
|
71
|
+
|
|
72
|
+
/** initial options for creation of the grid */
|
|
73
|
+
@Input() public set options(val: GridStackOptions) { this._options = val; }
|
|
74
|
+
/** return the current running options */
|
|
75
|
+
public get options(): GridStackOptions { return this._grid?.opts || this._options || {}; }
|
|
76
|
+
|
|
77
|
+
/** true while ng-content with 'no-item-content' should be shown when last item is removed from a grid */
|
|
78
|
+
@Input() public isEmpty?: boolean;
|
|
79
|
+
|
|
80
|
+
/** individual list of GridStackEvent callbacks handlers as output
|
|
81
|
+
* otherwise use this.grid.on('name1 name2 name3', callback) to handle multiple at once
|
|
82
|
+
* see https://github.com/gridstack/gridstack.js/blob/master/demo/events.js#L4
|
|
83
|
+
*
|
|
84
|
+
* Note: camel casing and 'CB' added at the end to prevent @angular-eslint/no-output-native
|
|
85
|
+
* eg: 'change' would trigger the raw CustomEvent so use different name.
|
|
86
|
+
*/
|
|
87
|
+
@Output() public addedCB = new EventEmitter<nodesCB>();
|
|
88
|
+
@Output() public changeCB = new EventEmitter<nodesCB>();
|
|
89
|
+
@Output() public disableCB = new EventEmitter<eventCB>();
|
|
90
|
+
@Output() public dragCB = new EventEmitter<elementCB>();
|
|
91
|
+
@Output() public dragStartCB = new EventEmitter<elementCB>();
|
|
92
|
+
@Output() public dragStopCB = new EventEmitter<elementCB>();
|
|
93
|
+
@Output() public droppedCB = new EventEmitter<droppedCB>();
|
|
94
|
+
@Output() public enableCB = new EventEmitter<eventCB>();
|
|
95
|
+
@Output() public removedCB = new EventEmitter<nodesCB>();
|
|
96
|
+
@Output() public resizeCB = new EventEmitter<elementCB>();
|
|
97
|
+
@Output() public resizeStartCB = new EventEmitter<elementCB>();
|
|
98
|
+
@Output() public resizeStopCB = new EventEmitter<elementCB>();
|
|
99
|
+
|
|
100
|
+
/** return the native element that contains grid specific fields as well */
|
|
101
|
+
public get el(): GridCompHTMLElement { return this.elementRef.nativeElement; }
|
|
102
|
+
|
|
103
|
+
/** return the GridStack class */
|
|
104
|
+
public get grid(): GridStack | undefined { return this._grid; }
|
|
105
|
+
|
|
106
|
+
/** ComponentRef of ourself - used by dynamic object to correctly get removed */
|
|
107
|
+
public ref: ComponentRef<GridstackComponent> | undefined;
|
|
108
|
+
|
|
109
|
+
/**
|
|
110
|
+
* stores the selector -> Type mapping, so we can create items dynamically from a string.
|
|
111
|
+
* Unfortunately Ng doesn't provide public access to that mapping.
|
|
112
|
+
*/
|
|
113
|
+
public static selectorToType: SelectorToType = {};
|
|
114
|
+
/** add a list of ng Component to be mapped to selector */
|
|
115
|
+
public static addComponentToSelectorType(typeList: Array<Type<Object>>) {
|
|
116
|
+
typeList.forEach(type => GridstackComponent.selectorToType[ GridstackComponent.getSelector(type) ] = type);
|
|
117
|
+
}
|
|
118
|
+
/** return the ng Component selector */
|
|
119
|
+
public static getSelector(type: Type<Object>): string {
|
|
120
|
+
return reflectComponentType(type)!.selector;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
protected _options?: GridStackOptions;
|
|
124
|
+
protected _grid?: GridStack;
|
|
125
|
+
protected _sub: Subscription | undefined;
|
|
126
|
+
protected loaded?: boolean;
|
|
127
|
+
|
|
128
|
+
constructor(
|
|
129
|
+
// protected readonly zone: NgZone,
|
|
130
|
+
// protected readonly cd: ChangeDetectorRef,
|
|
131
|
+
protected readonly elementRef: ElementRef<GridCompHTMLElement>,
|
|
132
|
+
) {
|
|
133
|
+
this.el._gridComp = this;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
public ngOnInit(): void {
|
|
137
|
+
// init ourself before any template children are created since we track them below anyway - no need to double create+update widgets
|
|
138
|
+
this.loaded = !!this.options?.children?.length;
|
|
139
|
+
this._grid = GridStack.init(this._options, this.el);
|
|
140
|
+
delete this._options; // GS has it now
|
|
141
|
+
|
|
142
|
+
this.checkEmpty();
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
/** wait until after all DOM is ready to init gridstack children (after angular ngFor and sub-components run first) */
|
|
146
|
+
public ngAfterContentInit(): void {
|
|
147
|
+
// track whenever the children list changes and update the layout...
|
|
148
|
+
this._sub = this.gridstackItems?.changes.subscribe(() => this.updateAll());
|
|
149
|
+
// ...and do this once at least unless we loaded children already
|
|
150
|
+
if (!this.loaded) this.updateAll();
|
|
151
|
+
this.hookEvents(this.grid);
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
public ngOnDestroy(): void {
|
|
155
|
+
this.unhookEvents(this._grid);
|
|
156
|
+
this._sub?.unsubscribe();
|
|
157
|
+
this._grid?.destroy();
|
|
158
|
+
delete this._grid;
|
|
159
|
+
delete this.el._gridComp;
|
|
160
|
+
delete this.container;
|
|
161
|
+
delete this.ref;
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
/**
|
|
165
|
+
* called when the TEMPLATE list of items changes - get a list of nodes and
|
|
166
|
+
* update the layout accordingly (which will take care of adding/removing items changed by Angular)
|
|
167
|
+
*/
|
|
168
|
+
public updateAll() {
|
|
169
|
+
if (!this.grid) return;
|
|
170
|
+
const layout: GridStackWidget[] = [];
|
|
171
|
+
this.gridstackItems?.forEach(item => {
|
|
172
|
+
layout.push(item.options);
|
|
173
|
+
item.clearOptions();
|
|
174
|
+
});
|
|
175
|
+
this.grid.load(layout); // efficient that does diffs only
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
/** check if the grid is empty, if so show alternative content */
|
|
179
|
+
public checkEmpty() {
|
|
180
|
+
if (!this.grid) return;
|
|
181
|
+
const isEmpty = !this.grid.engine.nodes.length;
|
|
182
|
+
if (isEmpty === this.isEmpty) return;
|
|
183
|
+
this.isEmpty = isEmpty;
|
|
184
|
+
// this.cd.detectChanges();
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
/** get all known events as easy to use Outputs for convenience */
|
|
188
|
+
protected hookEvents(grid?: GridStack) {
|
|
189
|
+
if (!grid) return;
|
|
190
|
+
grid
|
|
191
|
+
.on('added', (event: Event, nodes: GridStackNode[]) => { this.checkEmpty(); this.addedCB.emit({event, nodes}); })
|
|
192
|
+
.on('change', (event: Event, nodes: GridStackNode[]) => this.changeCB.emit({event, nodes}))
|
|
193
|
+
.on('disable', (event: Event) => this.disableCB.emit({event}))
|
|
194
|
+
.on('drag', (event: Event, el: GridItemHTMLElement) => this.dragCB.emit({event, el}))
|
|
195
|
+
.on('dragstart', (event: Event, el: GridItemHTMLElement) => this.dragStartCB.emit({event, el}))
|
|
196
|
+
.on('dragstop', (event: Event, el: GridItemHTMLElement) => this.dragStopCB.emit({event, el}))
|
|
197
|
+
.on('dropped', (event: Event, previousNode: GridStackNode, newNode: GridStackNode) => this.droppedCB.emit({event, previousNode, newNode}))
|
|
198
|
+
.on('enable', (event: Event) => this.enableCB.emit({event}))
|
|
199
|
+
.on('removed', (event: Event, nodes: GridStackNode[]) => { this.checkEmpty(); this.removedCB.emit({event, nodes}); })
|
|
200
|
+
.on('resize', (event: Event, el: GridItemHTMLElement) => this.resizeCB.emit({event, el}))
|
|
201
|
+
.on('resizestart', (event: Event, el: GridItemHTMLElement) => this.resizeStartCB.emit({event, el}))
|
|
202
|
+
.on('resizestop', (event: Event, el: GridItemHTMLElement) => this.resizeStopCB.emit({event, el}))
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
protected unhookEvents(grid?: GridStack) {
|
|
206
|
+
if (!grid) return;
|
|
207
|
+
grid.off('added change disable drag dragstart dragstop dropped enable removed resize resizestart resizestop');
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
/**
|
|
212
|
+
* can be used when a new item needs to be created, which we do as a Angular component, or deleted (skip)
|
|
213
|
+
**/
|
|
214
|
+
export function gsCreateNgComponents(host: GridCompHTMLElement | HTMLElement, n: NgGridStackNode, add: boolean, isGrid: boolean): HTMLElement | undefined {
|
|
215
|
+
if (add) {
|
|
216
|
+
//
|
|
217
|
+
// create the component dynamically - see https://angular.io/docs/ts/latest/cookbook/dynamic-component-loader.html
|
|
218
|
+
//
|
|
219
|
+
if (!host) return;
|
|
220
|
+
if (isGrid) {
|
|
221
|
+
// TODO: figure out how to create ng component inside regular Div. need to access app injectors...
|
|
222
|
+
// if (!container) {
|
|
223
|
+
// const hostElement: Element = host;
|
|
224
|
+
// const environmentInjector: EnvironmentInjector;
|
|
225
|
+
// grid = createComponent(GridstackComponent, {environmentInjector, hostElement})?.instance;
|
|
226
|
+
// }
|
|
227
|
+
|
|
228
|
+
const gridItemComp = (host.parentElement as GridItemCompHTMLElement)?._gridItemComp;
|
|
229
|
+
if (!gridItemComp) return;
|
|
230
|
+
// check if gridItem has a child component with 'container' exposed to create under..
|
|
231
|
+
const container = (gridItemComp.childWidget as any)?.container || gridItemComp.container;
|
|
232
|
+
const gridRef = container?.createComponent(GridstackComponent);
|
|
233
|
+
const grid = gridRef?.instance;
|
|
234
|
+
if (!grid) return;
|
|
235
|
+
grid.ref = gridRef;
|
|
236
|
+
grid.options = n;
|
|
237
|
+
return grid.el;
|
|
238
|
+
} else {
|
|
239
|
+
const gridComp = (host as GridCompHTMLElement)._gridComp;
|
|
240
|
+
const gridItemRef = gridComp?.container?.createComponent(GridstackItemComponent);
|
|
241
|
+
const gridItem = gridItemRef?.instance;
|
|
242
|
+
if (!gridItem) return;
|
|
243
|
+
gridItem.ref = gridItemRef
|
|
244
|
+
|
|
245
|
+
// define what type of component to create as child, OR you can do it GridstackItemComponent template, but this is more generic
|
|
246
|
+
const selector = n.selector;
|
|
247
|
+
const type = selector ? GridstackComponent.selectorToType[selector] : undefined;
|
|
248
|
+
if (type) {
|
|
249
|
+
// shared code to create our selector component
|
|
250
|
+
const createComp = () => {
|
|
251
|
+
const childWidget = gridItem.container?.createComponent(type)?.instance as BaseWidget;
|
|
252
|
+
// if proper BaseWidget subclass, save it and load additional data
|
|
253
|
+
if (childWidget && typeof childWidget.serialize === 'function' && typeof childWidget.deserialize === 'function') {
|
|
254
|
+
gridItem.childWidget = childWidget;
|
|
255
|
+
childWidget.deserialize(n);
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
const lazyLoad = n.lazyLoad || n.grid?.opts?.lazyLoad && n.lazyLoad !== false;
|
|
260
|
+
if (lazyLoad) {
|
|
261
|
+
if (!n.visibleObservable) {
|
|
262
|
+
n.visibleObservable = new IntersectionObserver(([entry]) => { if (entry.isIntersecting) {
|
|
263
|
+
n.visibleObservable?.disconnect();
|
|
264
|
+
delete n.visibleObservable;
|
|
265
|
+
createComp();
|
|
266
|
+
}});
|
|
267
|
+
window.setTimeout(() => n.visibleObservable?.observe(gridItem.el)); // wait until callee sets position attributes
|
|
268
|
+
}
|
|
269
|
+
} else createComp();
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
return gridItem.el;
|
|
273
|
+
}
|
|
274
|
+
} else {
|
|
275
|
+
//
|
|
276
|
+
// REMOVE - have to call ComponentRef:destroy() for dynamic objects to correctly remove themselves
|
|
277
|
+
// Note: this will destroy all children dynamic components as well: gridItem -> childWidget
|
|
278
|
+
//
|
|
279
|
+
if (isGrid) {
|
|
280
|
+
const grid = (n.el as GridCompHTMLElement)?._gridComp;
|
|
281
|
+
if (grid?.ref) grid.ref.destroy();
|
|
282
|
+
else grid?.ngOnDestroy();
|
|
283
|
+
} else {
|
|
284
|
+
const gridItem = (n.el as GridItemCompHTMLElement)?._gridItemComp;
|
|
285
|
+
if (gridItem?.ref) gridItem.ref.destroy();
|
|
286
|
+
else gridItem?.ngOnDestroy();
|
|
287
|
+
}
|
|
288
|
+
}
|
|
289
|
+
return;
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
/**
|
|
293
|
+
* called for each item in the grid - check if additional information needs to be saved.
|
|
294
|
+
* Note: since this is options minus gridstack protected members using Utils.removeInternalForSave(),
|
|
295
|
+
* this typically doesn't need to do anything. However your custom Component @Input() are now supported
|
|
296
|
+
* using BaseWidget.serialize()
|
|
297
|
+
*/
|
|
298
|
+
export function gsSaveAdditionalNgInfo(n: NgGridStackNode, w: NgGridStackWidget) {
|
|
299
|
+
const gridItem = (n.el as GridItemCompHTMLElement)?._gridItemComp;
|
|
300
|
+
if (gridItem) {
|
|
301
|
+
const input = gridItem.childWidget?.serialize();
|
|
302
|
+
if (input) {
|
|
303
|
+
w.input = input;
|
|
304
|
+
}
|
|
305
|
+
return;
|
|
306
|
+
}
|
|
307
|
+
// else check if Grid
|
|
308
|
+
const grid = (n.el as GridCompHTMLElement)?._gridComp;
|
|
309
|
+
if (grid) {
|
|
310
|
+
//.... save any custom data
|
|
311
|
+
}
|
|
312
|
+
}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* gridstack.component.ts 11.0.0
|
|
3
|
+
* Copyright (c) 2022-2024 Alain Dumesny - see GridStack root license
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import { NgModule } from "@angular/core";
|
|
7
|
+
import { CommonModule } from '@angular/common';
|
|
8
|
+
|
|
9
|
+
import { GridStack } from "gridstack";
|
|
10
|
+
import { GridstackComponent, gsCreateNgComponents, gsSaveAdditionalNgInfo } from "./gridstack.component";
|
|
11
|
+
import { GridstackItemComponent } from "./gridstack-item.component";
|
|
12
|
+
|
|
13
|
+
@NgModule({
|
|
14
|
+
imports: [
|
|
15
|
+
CommonModule,
|
|
16
|
+
],
|
|
17
|
+
declarations: [
|
|
18
|
+
GridstackComponent,
|
|
19
|
+
GridstackItemComponent,
|
|
20
|
+
],
|
|
21
|
+
exports: [
|
|
22
|
+
GridstackComponent,
|
|
23
|
+
GridstackItemComponent,
|
|
24
|
+
],
|
|
25
|
+
})
|
|
26
|
+
export class GridstackModule {
|
|
27
|
+
constructor() {
|
|
28
|
+
// set globally our method to create the right widget type
|
|
29
|
+
GridStack.addRemoveCB = gsCreateNgComponents;
|
|
30
|
+
GridStack.saveCB = gsSaveAdditionalNgInfo;
|
|
31
|
+
}
|
|
32
|
+
}
|
package/dist/dd-base-impl.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* dd-base-impl.ts
|
|
3
|
-
* Copyright (c) 2021-
|
|
2
|
+
* dd-base-impl.ts 11.0.0
|
|
3
|
+
* Copyright (c) 2021-2024 Alain Dumesny - see GridStack root license
|
|
4
4
|
*/
|
|
5
5
|
export type EventCallback = (event: Event) => boolean | void;
|
|
6
6
|
export declare abstract class DDBaseImplement {
|
package/dist/dd-base-impl.js
CHANGED
package/dist/dd-base-impl.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"dd-base-impl.js","sourceRoot":"","sources":["../src/dd-base-impl.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAGH,MAAM,OAAgB,eAAe;IAArC;QAME,gBAAgB;QACN,mBAAc,GAEpB,EAAE,CAAC;IA0BT,CAAC;IAlCC,mHAAmH;IACnH,IAAW,QAAQ,KAAgB,OAAO,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC;IASpD,EAAE,CAAC,KAAa,EAAE,QAAuB;QAC9C,IAAI,CAAC,cAAc,CAAC,KAAK,CAAC,GAAG,QAAQ,CAAC;IACxC,CAAC;IAEM,GAAG,CAAC,KAAa;QACtB,OAAO,IAAI,CAAC,cAAc,CAAC,KAAK,CAAC,CAAC;IACpC,CAAC;IAEM,MAAM;QACX,IAAI,CAAC,SAAS,GAAG,KAAK,CAAC;IACzB,CAAC;IAEM,OAAO;QACZ,IAAI,CAAC,SAAS,GAAG,IAAI,CAAC;IACxB,CAAC;IAEM,OAAO;QACZ,OAAO,IAAI,CAAC,cAAc,CAAC;IAC7B,CAAC;IAEM,YAAY,CAAC,SAAiB,EAAE,KAAY;QACjD,IAAI,CAAC,IAAI,CAAC,QAAQ,IAAI,IAAI,CAAC,cAAc,IAAI,IAAI,CAAC,cAAc,CAAC,SAAS,CAAC;YACzE,OAAO,IAAI,CAAC,cAAc,CAAC,SAAS,CAAC,CAAC,KAAK,CAAC,CAAC;IACjD,CAAC;CACF","sourcesContent":["/**\n * dd-base-impl.ts
|
|
1
|
+
{"version":3,"file":"dd-base-impl.js","sourceRoot":"","sources":["../src/dd-base-impl.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAGH,MAAM,OAAgB,eAAe;IAArC;QAME,gBAAgB;QACN,mBAAc,GAEpB,EAAE,CAAC;IA0BT,CAAC;IAlCC,mHAAmH;IACnH,IAAW,QAAQ,KAAgB,OAAO,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC;IASpD,EAAE,CAAC,KAAa,EAAE,QAAuB;QAC9C,IAAI,CAAC,cAAc,CAAC,KAAK,CAAC,GAAG,QAAQ,CAAC;IACxC,CAAC;IAEM,GAAG,CAAC,KAAa;QACtB,OAAO,IAAI,CAAC,cAAc,CAAC,KAAK,CAAC,CAAC;IACpC,CAAC;IAEM,MAAM;QACX,IAAI,CAAC,SAAS,GAAG,KAAK,CAAC;IACzB,CAAC;IAEM,OAAO;QACZ,IAAI,CAAC,SAAS,GAAG,IAAI,CAAC;IACxB,CAAC;IAEM,OAAO;QACZ,OAAO,IAAI,CAAC,cAAc,CAAC;IAC7B,CAAC;IAEM,YAAY,CAAC,SAAiB,EAAE,KAAY;QACjD,IAAI,CAAC,IAAI,CAAC,QAAQ,IAAI,IAAI,CAAC,cAAc,IAAI,IAAI,CAAC,cAAc,CAAC,SAAS,CAAC;YACzE,OAAO,IAAI,CAAC,cAAc,CAAC,SAAS,CAAC,CAAC,KAAK,CAAC,CAAC;IACjD,CAAC;CACF","sourcesContent":["/**\n * dd-base-impl.ts 11.0.0\n * Copyright (c) 2021-2024 Alain Dumesny - see GridStack root license\n */\n\nexport type EventCallback = (event: Event) => boolean|void;\nexport abstract class DDBaseImplement {\n /** returns the enable state, but you have to call enable()/disable() to change (as other things need to happen) */\n public get disabled(): boolean { return this._disabled; }\n\n /** @internal */\n protected _disabled: boolean; // initial state to differentiate from false\n /** @internal */\n protected _eventRegister: {\n [eventName: string]: EventCallback;\n } = {};\n\n public on(event: string, callback: EventCallback): void {\n this._eventRegister[event] = callback;\n }\n\n public off(event: string): void {\n delete this._eventRegister[event];\n }\n\n public enable(): void {\n this._disabled = false;\n }\n\n public disable(): void {\n this._disabled = true;\n }\n\n public destroy(): void {\n delete this._eventRegister;\n }\n\n public triggerEvent(eventName: string, event: Event): boolean|void {\n if (!this.disabled && this._eventRegister && this._eventRegister[eventName])\n return this._eventRegister[eventName](event);\n }\n}\n\nexport interface HTMLElementExtendOpt<T> {\n el: HTMLElement;\n option: T;\n updateOption(T): DDBaseImplement;\n}\n"]}
|
package/dist/dd-draggable.d.ts
CHANGED
|
@@ -1,29 +1,20 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* dd-draggable.ts
|
|
3
|
-
* Copyright (c) 2021-
|
|
2
|
+
* dd-draggable.ts 11.0.0
|
|
3
|
+
* Copyright (c) 2021-2024 Alain Dumesny - see GridStack root license
|
|
4
4
|
*/
|
|
5
5
|
import { DDBaseImplement, HTMLElementExtendOpt } from './dd-base-impl';
|
|
6
|
-
import { GridItemHTMLElement,
|
|
7
|
-
export interface DDDraggableOpt {
|
|
8
|
-
appendTo?: string | HTMLElement;
|
|
9
|
-
handle?: string;
|
|
10
|
-
helper?: 'clone' | HTMLElement | ((event: Event) => HTMLElement);
|
|
11
|
-
cancel?: string;
|
|
12
|
-
start?: (event: Event, ui: DDUIData) => void;
|
|
13
|
-
stop?: (event: Event) => void;
|
|
14
|
-
drag?: (event: Event, ui: DDUIData) => void;
|
|
15
|
-
}
|
|
6
|
+
import { GridItemHTMLElement, DDDragOpt } from './types';
|
|
16
7
|
type DDDragEvent = 'drag' | 'dragstart' | 'dragstop';
|
|
17
|
-
export declare class DDDraggable extends DDBaseImplement implements HTMLElementExtendOpt<
|
|
8
|
+
export declare class DDDraggable extends DDBaseImplement implements HTMLElementExtendOpt<DDDragOpt> {
|
|
18
9
|
el: GridItemHTMLElement;
|
|
19
|
-
option:
|
|
10
|
+
option: DDDragOpt;
|
|
20
11
|
helper: HTMLElement;
|
|
21
|
-
constructor(el: GridItemHTMLElement, option?:
|
|
12
|
+
constructor(el: GridItemHTMLElement, option?: DDDragOpt);
|
|
22
13
|
on(event: DDDragEvent, callback: (event: DragEvent) => void): void;
|
|
23
14
|
off(event: DDDragEvent): void;
|
|
24
15
|
enable(): void;
|
|
25
16
|
disable(forDestroy?: boolean): void;
|
|
26
17
|
destroy(): void;
|
|
27
|
-
updateOption(opts:
|
|
18
|
+
updateOption(opts: DDDragOpt): DDDraggable;
|
|
28
19
|
}
|
|
29
20
|
export {};
|
package/dist/dd-draggable.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* dd-draggable.ts
|
|
3
|
-
* Copyright (c) 2021-
|
|
2
|
+
* dd-draggable.ts 11.0.0
|
|
3
|
+
* Copyright (c) 2021-2024 Alain Dumesny - see GridStack root license
|
|
4
4
|
*/
|
|
5
5
|
import { DDManager } from './dd-manager';
|
|
6
6
|
import { Utils } from './utils';
|
|
@@ -22,8 +22,9 @@ class DDDraggable extends DDBaseImplement {
|
|
|
22
22
|
yOffset: 0
|
|
23
23
|
};
|
|
24
24
|
// get the element that is actually supposed to be dragged by
|
|
25
|
-
|
|
26
|
-
|
|
25
|
+
const handleName = option?.handle?.substring(1);
|
|
26
|
+
const n = el.gridstackNode;
|
|
27
|
+
this.dragEls = !handleName || el.classList.contains(handleName) ? [el] : (n?.subGrid ? [el.querySelector(option.handle) || el] : Array.from(el.querySelectorAll(option.handle)));
|
|
27
28
|
if (this.dragEls.length === 0) {
|
|
28
29
|
this.dragEls = [el];
|
|
29
30
|
}
|
|
@@ -98,13 +99,6 @@ class DDDraggable extends DDBaseImplement {
|
|
|
98
99
|
if (e.target.closest(this.option.cancel))
|
|
99
100
|
return true;
|
|
100
101
|
}
|
|
101
|
-
// REMOVE: why would we get the event if it wasn't for us or child ?
|
|
102
|
-
// make sure we are clicking on a drag handle or child of it...
|
|
103
|
-
// Note: we don't need to check that's handle is an immediate child, as mouseHandled will prevent parents from also handling it (lowest wins)
|
|
104
|
-
// let className = this.option.handle.substring(1);
|
|
105
|
-
// let el = e.target as HTMLElement;
|
|
106
|
-
// while (el && !el.classList.contains(className)) { el = el.parentElement; }
|
|
107
|
-
// if (!el) return;
|
|
108
102
|
this.mouseDownEvent = e;
|
|
109
103
|
delete this.dragging;
|
|
110
104
|
delete DDManager.dragElement;
|
|
@@ -113,8 +107,8 @@ class DDDraggable extends DDBaseImplement {
|
|
|
113
107
|
document.addEventListener('mousemove', this._mouseMove, { capture: true, passive: true }); // true=capture, not bubble
|
|
114
108
|
document.addEventListener('mouseup', this._mouseUp, true);
|
|
115
109
|
if (isTouch) {
|
|
116
|
-
e.
|
|
117
|
-
e.
|
|
110
|
+
e.currentTarget.addEventListener('touchmove', touchmove);
|
|
111
|
+
e.currentTarget.addEventListener('touchend', touchend);
|
|
118
112
|
}
|
|
119
113
|
e.preventDefault();
|
|
120
114
|
// preventDefault() prevents blur event which occurs just after mousedown event.
|
|
@@ -137,7 +131,7 @@ class DDDraggable extends DDBaseImplement {
|
|
|
137
131
|
/** @internal called when the main page (after successful mousedown) receives a move event to drag the item around the screen */
|
|
138
132
|
_mouseMove(e) {
|
|
139
133
|
// console.log(`${count++} move ${e.x},${e.y}`)
|
|
140
|
-
|
|
134
|
+
const s = this.mouseDownEvent;
|
|
141
135
|
this.lastDrag = e;
|
|
142
136
|
if (this.dragging) {
|
|
143
137
|
this._dragFollow(e);
|
|
@@ -159,14 +153,14 @@ class DDDraggable extends DDBaseImplement {
|
|
|
159
153
|
this.dragging = true;
|
|
160
154
|
DDManager.dragElement = this;
|
|
161
155
|
// if we're dragging an actual grid item, set the current drop as the grid (to detect enter/leave)
|
|
162
|
-
|
|
156
|
+
const grid = this.el.gridstackNode?.grid;
|
|
163
157
|
if (grid) {
|
|
164
158
|
DDManager.dropElement = grid.el.ddElement.ddDroppable;
|
|
165
159
|
}
|
|
166
160
|
else {
|
|
167
161
|
delete DDManager.dropElement;
|
|
168
162
|
}
|
|
169
|
-
this.helper = this._createHelper(
|
|
163
|
+
this.helper = this._createHelper();
|
|
170
164
|
this._setupHelperContainmentStyle();
|
|
171
165
|
this.dragTransform = Utils.getValuesFromTransformedElement(this.helperContainment);
|
|
172
166
|
this.dragOffset = this._getDragOffset(e, this.el, this.helperContainment);
|
|
@@ -187,8 +181,8 @@ class DDDraggable extends DDBaseImplement {
|
|
|
187
181
|
document.removeEventListener('mousemove', this._mouseMove, true);
|
|
188
182
|
document.removeEventListener('mouseup', this._mouseUp, true);
|
|
189
183
|
if (isTouch) {
|
|
190
|
-
e.
|
|
191
|
-
e.
|
|
184
|
+
e.currentTarget.removeEventListener('touchmove', touchmove, true);
|
|
185
|
+
e.currentTarget.removeEventListener('touchend', touchend, true);
|
|
192
186
|
}
|
|
193
187
|
if (this.dragging) {
|
|
194
188
|
delete this.dragging;
|
|
@@ -199,12 +193,9 @@ class DDDraggable extends DDBaseImplement {
|
|
|
199
193
|
delete DDManager.dropElement;
|
|
200
194
|
}
|
|
201
195
|
this.helperContainment.style.position = this.parentOriginStylePosition || null;
|
|
202
|
-
if (this.helper
|
|
203
|
-
this.
|
|
204
|
-
|
|
205
|
-
else {
|
|
206
|
-
this.helper.remove();
|
|
207
|
-
}
|
|
196
|
+
if (this.helper !== this.el)
|
|
197
|
+
this.helper.remove(); // hide now
|
|
198
|
+
this._removeHelperStyle();
|
|
208
199
|
const ev = Utils.initEvent(e, { target: this.el, type: 'dragstop' });
|
|
209
200
|
if (this.option.stop) {
|
|
210
201
|
this.option.stop(ev); // NOTE: destroy() will be called when removing item, so expect NULL ptr after!
|
|
@@ -254,10 +245,10 @@ class DDDraggable extends DDBaseImplement {
|
|
|
254
245
|
}
|
|
255
246
|
}
|
|
256
247
|
/** @internal create a clone copy (or user defined method) of the original drag item if set */
|
|
257
|
-
_createHelper(
|
|
248
|
+
_createHelper() {
|
|
258
249
|
let helper = this.el;
|
|
259
250
|
if (typeof this.option.helper === 'function') {
|
|
260
|
-
helper = this.option.helper(
|
|
251
|
+
helper = this.option.helper(this.el);
|
|
261
252
|
}
|
|
262
253
|
else if (this.option.helper === 'clone') {
|
|
263
254
|
helper = Utils.cloneNode(this.el);
|
|
@@ -265,9 +256,7 @@ class DDDraggable extends DDBaseImplement {
|
|
|
265
256
|
if (!document.body.contains(helper)) {
|
|
266
257
|
Utils.appendTo(helper, this.option.appendTo === 'parent' ? this.el.parentElement : this.option.appendTo);
|
|
267
258
|
}
|
|
268
|
-
|
|
269
|
-
this.dragElementOriginStyle = DDDraggable.originStyleProp.map(prop => this.el.style[prop]);
|
|
270
|
-
}
|
|
259
|
+
this.dragElementOriginStyle = DDDraggable.originStyleProp.map(prop => this.el.style[prop]);
|
|
271
260
|
return helper;
|
|
272
261
|
}
|
|
273
262
|
/** @internal set the fix position of the dragged item */
|
|
@@ -293,16 +282,16 @@ class DDDraggable extends DDBaseImplement {
|
|
|
293
282
|
/** @internal restore back the original style before dragging */
|
|
294
283
|
_removeHelperStyle() {
|
|
295
284
|
this.helper.classList.remove('ui-draggable-dragging');
|
|
296
|
-
|
|
285
|
+
const node = this.helper?.gridstackNode;
|
|
297
286
|
// don't bother restoring styles if we're gonna remove anyway...
|
|
298
287
|
if (!node?._isAboutToRemove && this.dragElementOriginStyle) {
|
|
299
|
-
|
|
288
|
+
const helper = this.helper;
|
|
300
289
|
// don't animate, otherwise we animate offseted when switching back to 'absolute' from 'fixed'.
|
|
301
290
|
// TODO: this also removes resizing animation which doesn't have this issue, but others.
|
|
302
291
|
// Ideally both would animate ('move' would immediately restore 'absolute' and adjust coordinate to match,
|
|
303
292
|
// then trigger a delay (repaint) to restore to final dest with animate) but then we need to make sure 'resizestop'
|
|
304
293
|
// is called AFTER 'transitionend' event is received (see https://github.com/gridstack/gridstack.js/issues/2033)
|
|
305
|
-
|
|
294
|
+
const transition = this.dragElementOriginStyle['transition'] || null;
|
|
306
295
|
helper.style.transition = this.dragElementOriginStyle['transition'] = 'none'; // can't be NULL #1973
|
|
307
296
|
DDDraggable.originStyleProp.forEach(prop => helper.style[prop] = this.dragElementOriginStyle[prop] || null);
|
|
308
297
|
setTimeout(() => helper.style.transition = transition, 50); // recover animation from saved vars after a pause (0 isn't enough #1973)
|
|
@@ -312,7 +301,7 @@ class DDDraggable extends DDBaseImplement {
|
|
|
312
301
|
}
|
|
313
302
|
/** @internal updates the top/left position to follow the mouse */
|
|
314
303
|
_dragFollow(e) {
|
|
315
|
-
|
|
304
|
+
const containmentRect = { left: 0, top: 0 };
|
|
316
305
|
// if (this.helper.style.position === 'absolute') { // we use 'fixed'
|
|
317
306
|
// const { left, top } = this.helperContainment.getBoundingClientRect();
|
|
318
307
|
// containmentRect = { left, top };
|
|
@@ -370,6 +359,6 @@ class DDDraggable extends DDBaseImplement {
|
|
|
370
359
|
}
|
|
371
360
|
}
|
|
372
361
|
/** @internal properties we change during dragging, and restore back */
|
|
373
|
-
DDDraggable.originStyleProp = ['transition', 'pointerEvents', 'position', 'left', 'top', 'minWidth', 'willChange'];
|
|
362
|
+
DDDraggable.originStyleProp = ['width', 'height', 'transform', 'transform-origin', 'transition', 'pointerEvents', 'position', 'left', 'top', 'minWidth', 'willChange'];
|
|
374
363
|
export { DDDraggable };
|
|
375
364
|
//# sourceMappingURL=dd-draggable.js.map
|