Skip to content

Commit 4e5d7bd

Browse files
authored
Merge pull request #1468 from adumesny/h5
h5: GridStackDDNative now support list of items
2 parents d1e0182 + 87d4b1c commit 4e5d7bd

File tree

5 files changed

+222
-118
lines changed

5 files changed

+222
-118
lines changed

demo/advance-h5.html

Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
<!DOCTYPE html>
2+
<html lang="en">
3+
4+
<head>
5+
<meta charset="utf-8">
6+
<meta http-equiv="X-UA-Compatible" content="IE=edge">
7+
<meta name="viewport" content="width=device-width, initial-scale=1">
8+
<title>Advanced grid demo</title>
9+
10+
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css">
11+
<link rel="stylesheet" href="demo.css" />
12+
13+
<script type="module" src="https://unpkg.com/ionicons@4.5.10-0/dist/ionicons/ionicons.esm.js"></script>
14+
<script nomodule="" src="https://unpkg.com/ionicons@4.5.10-0/dist/ionicons/ionicons.js"></script>
15+
16+
<script src="../dist/gridstack.h5.js"></script>
17+
18+
<style type="text/css">
19+
.grid-stack-item-removing {
20+
opacity: 0.8;
21+
filter: blur(5px);
22+
}
23+
#trash {
24+
background: rgba(255, 0, 0, 0.4);
25+
}
26+
</style>
27+
</head>
28+
29+
<body>
30+
<h1>Advanced Demo</h1>
31+
<div class="row">
32+
<div class="col-md-2 d-none d-md-block">
33+
<div id="trash" style="padding: 5px; margin-bottom: 15px;" class="text-center">
34+
<div>
35+
<ion-icon name="trash" style="font-size: 300%"></ion-icon>
36+
</div>
37+
<div>
38+
<span>Drop here to remove!</span>
39+
</div>
40+
</div>
41+
<div class="newWidget grid-stack-item">
42+
<div class="grid-stack-item-content" style="padding: 5px;">
43+
<div>
44+
<ion-icon name="add-circle" style="font-size: 300%"></ion-icon>
45+
</div>
46+
<div>
47+
<span>Drag me in the dashboard!</span>
48+
</div>
49+
</div>
50+
</div>
51+
</div>
52+
<div class="col-sm-12 col-md-10">
53+
<div class="grid-stack"></div>
54+
</div>
55+
</div>
56+
57+
<script type="text/javascript">
58+
59+
let grid = GridStack.init({
60+
alwaysShowResizeHandle: /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(
61+
navigator.userAgent
62+
),
63+
resizable: {
64+
handles: 'e, se, s, sw, w'
65+
},
66+
acceptWidgets: true,
67+
dragIn: '.newWidget', // class that can be dragged from outside
68+
dragInOptions: { revert: 'invalid', scroll: false, appendTo: 'body', helper: 'clone' },
69+
removable: '#trash', // drag-out delete class
70+
removeTimeout: 100,
71+
});
72+
73+
let items = [
74+
{x: 0, y: 0, width: 4, height: 2, content: '1'},
75+
{x: 4, y: 0, width: 4, height: 4, noMove: true, noResize: true, locked: true, content: 'I can\'t be moved or dragged!<br><ion-icon name="ios-lock" style="font-size:300%"></ion-icon>'},
76+
{x: 8, y: 0, width: 2, height: 2, minWidth: 2, noResize: true, content: '<p class="card-text text-center" style="margin-bottom: 0">Drag me!<p class="card-text text-center"style="margin-bottom: 0"><ion-icon name="hand" style="font-size: 300%"></ion-icon><p class="card-text text-center" style="margin-bottom: 0">...but don\'t resize me!'},
77+
{x: 10, y: 0, width: 2, height: 2, content: '4'},
78+
{x: 0, y: 2, width: 2, height: 2, content: '5'},
79+
{x: 2, y: 2, width: 2, height: 4, content: '6'},
80+
{x: 8, y: 2, width: 4, height: 2, content: '7'},
81+
{x: 0, y: 4, width: 2, height: 2, content: '8'},
82+
{x: 4, y: 4, width: 4, height: 2, content: '9'},
83+
{x: 8, y: 4, width: 2, height: 2, content: '10'},
84+
{x: 10, y: 4, width: 2, height: 2, content: '11'},
85+
];
86+
grid.load(items);
87+
88+
grid.on('added removed change', function(e, items) {
89+
let str = '';
90+
items.forEach(function(item) { str += ' (x,y)=' + item.x + ',' + item.y; });
91+
console.log(e.type + ' ' + items.length + ' items:' + str );
92+
});
93+
</script>
94+
</body>
95+
96+
</html>

src/dragdrop/gridstack-dd-native.ts

Lines changed: 77 additions & 78 deletions
Original file line numberDiff line numberDiff line change
@@ -6,131 +6,130 @@
66
* gridstack.js may be freely distributed under the MIT license.
77
*/
88
import { DDManager } from './dd-manager';
9-
import { DDElement } from './dd-element';
9+
import { DDElement, DDElementHost } from './dd-element';
1010

1111
import { GridStackElement } from '../gridstack';
1212
import { GridStackDD, DDOpts, DDKey, DDDropOpt, DDCallback, DDValue } from '../gridstack-dd';
1313
import { GridItemHTMLElement, DDDragInOpt } from '../types';
14+
import { Utils } from '../utils';
1415

1516
/**
1617
* HTML 5 Native DragDrop based drag'n'drop plugin.
1718
*/
1819
export class GridStackDDNative extends GridStackDD {
1920

2021
public resizable(el: GridItemHTMLElement, opts: DDOpts, key?: DDKey, value?: DDValue): GridStackDDNative {
21-
let dEl = this.getGridStackDDElement(el);
22-
if (opts === 'disable' || opts === 'enable') {
23-
dEl.ddResizable[opts]();
24-
} else if (opts === 'destroy') {
25-
if (dEl.ddResizable) {
26-
dEl.cleanResizable();
27-
}
28-
} else if (opts === 'option') {
29-
dEl.setupResizable({ [key]: value });
30-
} else {
31-
const grid = el.gridstackNode.grid;
32-
let handles = dEl.el.getAttribute('gs-resize-handles') ? dEl.el.getAttribute('gs-resize-handles') : grid.opts.resizable.handles;
33-
dEl.setupResizable({
34-
...grid.opts.resizable,
35-
...{ handles: handles },
36-
...{
37-
start: opts.start,
38-
stop: opts.stop,
39-
resize: opts.resize
22+
this.getDDElements(el).forEach(dEl => {
23+
if (opts === 'disable' || opts === 'enable') {
24+
dEl.ddResizable[opts]();
25+
} else if (opts === 'destroy') {
26+
if (dEl.ddResizable) {
27+
dEl.cleanResizable();
4028
}
41-
});
42-
}
29+
} else if (opts === 'option') {
30+
dEl.setupResizable({ [key]: value });
31+
} else {
32+
const grid = dEl.el.gridstackNode.grid;
33+
let handles = dEl.el.getAttribute('gs-resize-handles') ? dEl.el.getAttribute('gs-resize-handles') : grid.opts.resizable.handles;
34+
dEl.setupResizable({
35+
...grid.opts.resizable,
36+
...{ handles: handles },
37+
...{
38+
start: opts.start,
39+
stop: opts.stop,
40+
resize: opts.resize
41+
}
42+
});
43+
}
44+
});
4345
return this;
4446
}
4547

4648
public draggable(el: GridItemHTMLElement, opts: DDOpts, key?: DDKey, value?: DDValue): GridStackDDNative {
47-
const dEl = this.getGridStackDDElement(el);
48-
if (opts === 'disable' || opts === 'enable') {
49-
dEl.ddDraggable && dEl.ddDraggable[opts]();
50-
} else if (opts === 'destroy') {
51-
if (dEl.ddDraggable) { // error to call destroy if not there
52-
dEl.cleanDraggable();
53-
}
54-
} else if (opts === 'option') {
55-
dEl.setupDraggable({ [key]: value });
56-
} else {
57-
const grid = el.gridstackNode.grid;
58-
dEl.setupDraggable({
59-
...grid.opts.draggable,
60-
...{
61-
containment: (grid.opts._isNested && !grid.opts.dragOut)
62-
? grid.el.parentElement
63-
: (grid.opts.draggable.containment || null),
64-
start: opts.start,
65-
stop: opts.stop,
66-
drag: opts.drag
49+
this.getDDElements(el).forEach(dEl => {
50+
if (opts === 'disable' || opts === 'enable') {
51+
dEl.ddDraggable && dEl.ddDraggable[opts]();
52+
} else if (opts === 'destroy') {
53+
if (dEl.ddDraggable) { // error to call destroy if not there
54+
dEl.cleanDraggable();
6755
}
68-
});
69-
}
56+
} else if (opts === 'option') {
57+
dEl.setupDraggable({ [key]: value });
58+
} else {
59+
const grid = dEl.el.gridstackNode.grid;
60+
dEl.setupDraggable({
61+
...grid.opts.draggable,
62+
...{
63+
containment: (grid.opts._isNested && !grid.opts.dragOut)
64+
? grid.el.parentElement
65+
: (grid.opts.draggable.containment || null),
66+
start: opts.start,
67+
stop: opts.stop,
68+
drag: opts.drag
69+
}
70+
});
71+
}
72+
});
7073
return this;
7174
}
7275

7376
public dragIn(el: GridStackElement, opts: DDDragInOpt): GridStackDDNative {
74-
let dEl = this.getGridStackDDElement(el);
75-
dEl.setupDraggable(opts);
77+
this.getDDElements(el).forEach(dEl => dEl.setupDraggable(opts));
7678
return this;
7779
}
7880

7981
public droppable(el: GridItemHTMLElement, opts: DDOpts | DDDropOpt, key?: DDKey, value?: DDValue): GridStackDDNative {
80-
let dEl = this.getGridStackDDElement(el);
8182
if (typeof opts.accept === 'function' && !opts._accept) {
8283
opts._accept = opts.accept;
8384
opts.accept = (el) => opts._accept(el);
8485
}
85-
if (opts === 'disable' || opts === 'enable') {
86-
dEl.ddDroppable && dEl.ddDroppable[opts]();
87-
} else if (opts === 'destroy') {
88-
if (dEl.ddDroppable) { // error to call destroy if not there
89-
dEl.cleanDroppable();
86+
this.getDDElements(el).forEach(dEl => {
87+
if (opts === 'disable' || opts === 'enable') {
88+
dEl.ddDroppable && dEl.ddDroppable[opts]();
89+
} else if (opts === 'destroy') {
90+
if (dEl.ddDroppable) { // error to call destroy if not there
91+
dEl.cleanDroppable();
92+
}
93+
} else if (opts === 'option') {
94+
dEl.setupDroppable({ [key]: value });
95+
} else {
96+
dEl.setupDroppable(opts);
9097
}
91-
} else if (opts === 'option') {
92-
dEl.setupDroppable({ [key]: value });
93-
} else {
94-
dEl.setupDroppable(opts);
95-
}
98+
});
9699
return this;
97100
}
98101

102+
/** true if at least one of them is droppable */
99103
public isDroppable(el: GridItemHTMLElement): boolean {
100-
const dEl = this.getGridStackDDElement(el);
101-
return !!(dEl.ddDroppable);
104+
return this.getDDElements(el).some(dEl => !!(dEl.ddDroppable));
102105
}
103106

107+
/** true if at least one of them is draggable */
104108
public isDraggable(el: GridStackElement): boolean {
105-
const dEl = this.getGridStackDDElement(el);
106-
return !!(dEl.ddDraggable);
109+
return this.getDDElements(el).some(dEl => !!(dEl.ddDraggable));
107110
}
108111

109112
public on(el: GridItemHTMLElement, name: string, callback: DDCallback): GridStackDDNative {
110-
let dEl = this.getGridStackDDElement(el);
111-
dEl.on(name, (event: Event) => {
112-
callback(
113-
event,
114-
DDManager.dragElement ? DDManager.dragElement.el : event.target as GridItemHTMLElement,
115-
DDManager.dragElement ? DDManager.dragElement.helper : null)
116-
});
113+
this.getDDElements(el).forEach(dEl =>
114+
dEl.on(name, (event: Event) => {
115+
callback(
116+
event,
117+
DDManager.dragElement ? DDManager.dragElement.el : event.target as GridItemHTMLElement,
118+
DDManager.dragElement ? DDManager.dragElement.helper : null)
119+
})
120+
);
117121
return this;
118122
}
119123

120124
public off(el: GridItemHTMLElement, name: string): GridStackDD {
121-
let dEl = this.getGridStackDDElement(el);
122-
dEl.off(name);
125+
this.getDDElements(el).forEach(dEl => dEl.off(name));
123126
return this;
124127
}
125128

126-
private getGridStackDDElement(el: GridStackElement): DDElement {
127-
let dEl;
128-
if (typeof el === 'string') {
129-
dEl = document.querySelector(el as string);
130-
} else {
131-
dEl = el;
132-
}
133-
return dEl.ddElement ? dEl.ddElement: DDElement.init(dEl);
129+
private getDDElements(els: GridStackElement): DDElement[] {
130+
let list = Utils.getElements(els) as DDElementHost[];
131+
if (!list.length) { return []; }
132+
return list.map(e => e.ddElement || DDElement.init(e));
134133
}
135134
}
136135

src/gridstack.ts

Lines changed: 8 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88

99
import { GridStackEngine } from './gridstack-engine';
1010
import { obsoleteOpts, obsoleteOptsDel, obsoleteAttr, obsolete, Utils, HeightData } from './utils';
11-
import { GridItemHTMLElement, GridStackWidget, GridStackNode, GridStackOptions, numberOrString, ColumnOptions, DDUIData } from './types';
11+
import { GridStackElement, GridItemHTMLElement, GridStackWidget, GridStackNode, GridStackOptions, numberOrString, ColumnOptions, DDUIData } from './types';
1212
import { GridStackDD } from './gridstack-dd';
1313

1414
// export all dependent file as well to make it easier for users to just import the main file
@@ -17,8 +17,6 @@ export * from './utils';
1717
export * from './gridstack-engine';
1818
export * from './gridstack-dd';
1919

20-
export type GridStackElement = string | HTMLElement | GridItemHTMLElement;
21-
2220
export interface GridHTMLElement extends HTMLElement {
2321
gridstack?: GridStack; // grid's parent DOM element points back to grid class
2422
}
@@ -1766,48 +1764,19 @@ export class GridStack {
17661764

17671765
/** @internal convert a potential selector into actual element */
17681766
private static getElement(els: GridStackElement = '.grid-stack-item'): GridItemHTMLElement {
1769-
if (typeof els === 'string') {
1770-
if (!els.length) { return null}
1771-
if (els[0] === '#') {
1772-
return document.getElementById(els.substring(1));
1773-
}
1774-
if (els[0] === '.') {
1775-
return document.querySelector(els);
1776-
}
1777-
1778-
// if we start with a digit, assume it's an id (error calling querySelector('#1')) as class are not valid CSS
1779-
if(!isNaN(+els[0])) { // start with digit
1780-
return document.getElementById(els);
1781-
}
1782-
1783-
// finally try string, then id then class
1784-
let el = document.querySelector(els);
1785-
if (!el) { el = document.getElementById(els) }
1786-
if (!el) { el = document.querySelector('.' + els) }
1787-
return el as GridItemHTMLElement;
1788-
}
1789-
return els;
1767+
return Utils.getElement(els);
17901768
}
1791-
1792-
/** @internal convert a potential selector into actual list of elements */
1769+
/** @internal */
17931770
private static getElements(els: GridStackElement = '.grid-stack-item'): GridItemHTMLElement[] {
1794-
if (typeof els === 'string') {
1795-
let list = document.querySelectorAll(els);
1796-
if (!list.length && els[0] !== '.' && els[0] !== '#') {
1797-
list = document.querySelectorAll('.' + els);
1798-
if (!list.length) { list = document.querySelectorAll('#' + els) }
1799-
}
1800-
return Array.from(list) as GridItemHTMLElement[];
1801-
}
1802-
return [els];
1771+
return Utils.getElements(els);
18031772
}
18041773
/** @internal */
1805-
private static getGridElement(els: string | HTMLElement = '.grid-stack'): GridHTMLElement {
1806-
return GridStack.getElement(els) as GridHTMLElement;
1774+
private static getGridElement(els: GridStackElement): GridHTMLElement {
1775+
return GridStack.getElement(els);
18071776
}
18081777
/** @internal */
1809-
private static getGridElements(els: string | HTMLElement = '.grid-stack'): GridHTMLElement[] {
1810-
return GridStack.getElements(els) as GridHTMLElement[];
1778+
private static getGridElements(els: string): GridHTMLElement[] {
1779+
return Utils.getElements(els);
18111780
}
18121781

18131782
/** @internal initialize margin top/bottom/left/right and units */

src/types.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,8 @@ export interface GridItemHTMLElement extends HTMLElement {
2424
_gridstackNodeOrig?: GridStackNode;
2525
}
2626

27+
export type GridStackElement = string | HTMLElement | GridItemHTMLElement;
28+
2729
/**
2830
* Defines the options for a Grid
2931
*/

0 commit comments

Comments
 (0)