Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
96 changes: 96 additions & 0 deletions demo/advance-h5.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
<!DOCTYPE html>
<html lang="en">

<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Advanced grid demo</title>

<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css">
<link rel="stylesheet" href="demo.css" />

<script type="module" src="https://unpkg.com/ionicons@4.5.10-0/dist/ionicons/ionicons.esm.js"></script>
<script nomodule="" src="https://unpkg.com/ionicons@4.5.10-0/dist/ionicons/ionicons.js"></script>

<script src="../dist/gridstack.h5.js"></script>

<style type="text/css">
.grid-stack-item-removing {
opacity: 0.8;
filter: blur(5px);
}
#trash {
background: rgba(255, 0, 0, 0.4);
}
</style>
</head>

<body>
<h1>Advanced Demo</h1>
<div class="row">
<div class="col-md-2 d-none d-md-block">
<div id="trash" style="padding: 5px; margin-bottom: 15px;" class="text-center">
<div>
<ion-icon name="trash" style="font-size: 300%"></ion-icon>
</div>
<div>
<span>Drop here to remove!</span>
</div>
</div>
<div class="newWidget grid-stack-item">
<div class="grid-stack-item-content" style="padding: 5px;">
<div>
<ion-icon name="add-circle" style="font-size: 300%"></ion-icon>
</div>
<div>
<span>Drag me in the dashboard!</span>
</div>
</div>
</div>
</div>
<div class="col-sm-12 col-md-10">
<div class="grid-stack"></div>
</div>
</div>

<script type="text/javascript">

let grid = GridStack.init({
alwaysShowResizeHandle: /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(
navigator.userAgent
),
resizable: {
handles: 'e, se, s, sw, w'
},
acceptWidgets: true,
dragIn: '.newWidget', // class that can be dragged from outside
dragInOptions: { revert: 'invalid', scroll: false, appendTo: 'body', helper: 'clone' },
removable: '#trash', // drag-out delete class
removeTimeout: 100,
});

let items = [
{x: 0, y: 0, width: 4, height: 2, content: '1'},
{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>'},
{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!'},
{x: 10, y: 0, width: 2, height: 2, content: '4'},
{x: 0, y: 2, width: 2, height: 2, content: '5'},
{x: 2, y: 2, width: 2, height: 4, content: '6'},
{x: 8, y: 2, width: 4, height: 2, content: '7'},
{x: 0, y: 4, width: 2, height: 2, content: '8'},
{x: 4, y: 4, width: 4, height: 2, content: '9'},
{x: 8, y: 4, width: 2, height: 2, content: '10'},
{x: 10, y: 4, width: 2, height: 2, content: '11'},
];
grid.load(items);

grid.on('added removed change', function(e, items) {
let str = '';
items.forEach(function(item) { str += ' (x,y)=' + item.x + ',' + item.y; });
console.log(e.type + ' ' + items.length + ' items:' + str );
});
</script>
</body>

</html>
155 changes: 77 additions & 78 deletions src/dragdrop/gridstack-dd-native.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,131 +6,130 @@
* gridstack.js may be freely distributed under the MIT license.
*/
import { DDManager } from './dd-manager';
import { DDElement } from './dd-element';
import { DDElement, DDElementHost } from './dd-element';

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

/**
* HTML 5 Native DragDrop based drag'n'drop plugin.
*/
export class GridStackDDNative extends GridStackDD {

public resizable(el: GridItemHTMLElement, opts: DDOpts, key?: DDKey, value?: DDValue): GridStackDDNative {
let dEl = this.getGridStackDDElement(el);
if (opts === 'disable' || opts === 'enable') {
dEl.ddResizable[opts]();
} else if (opts === 'destroy') {
if (dEl.ddResizable) {
dEl.cleanResizable();
}
} else if (opts === 'option') {
dEl.setupResizable({ [key]: value });
} else {
const grid = el.gridstackNode.grid;
let handles = dEl.el.getAttribute('gs-resize-handles') ? dEl.el.getAttribute('gs-resize-handles') : grid.opts.resizable.handles;
dEl.setupResizable({
...grid.opts.resizable,
...{ handles: handles },
...{
start: opts.start,
stop: opts.stop,
resize: opts.resize
this.getDDElements(el).forEach(dEl => {
if (opts === 'disable' || opts === 'enable') {
dEl.ddResizable[opts]();
} else if (opts === 'destroy') {
if (dEl.ddResizable) {
dEl.cleanResizable();
}
});
}
} else if (opts === 'option') {
dEl.setupResizable({ [key]: value });
} else {
const grid = dEl.el.gridstackNode.grid;
let handles = dEl.el.getAttribute('gs-resize-handles') ? dEl.el.getAttribute('gs-resize-handles') : grid.opts.resizable.handles;
dEl.setupResizable({
...grid.opts.resizable,
...{ handles: handles },
...{
start: opts.start,
stop: opts.stop,
resize: opts.resize
}
});
}
});
return this;
}

public draggable(el: GridItemHTMLElement, opts: DDOpts, key?: DDKey, value?: DDValue): GridStackDDNative {
const dEl = this.getGridStackDDElement(el);
if (opts === 'disable' || opts === 'enable') {
dEl.ddDraggable && dEl.ddDraggable[opts]();
} else if (opts === 'destroy') {
if (dEl.ddDraggable) { // error to call destroy if not there
dEl.cleanDraggable();
}
} else if (opts === 'option') {
dEl.setupDraggable({ [key]: value });
} else {
const grid = el.gridstackNode.grid;
dEl.setupDraggable({
...grid.opts.draggable,
...{
containment: (grid.opts._isNested && !grid.opts.dragOut)
? grid.el.parentElement
: (grid.opts.draggable.containment || null),
start: opts.start,
stop: opts.stop,
drag: opts.drag
this.getDDElements(el).forEach(dEl => {
if (opts === 'disable' || opts === 'enable') {
dEl.ddDraggable && dEl.ddDraggable[opts]();
} else if (opts === 'destroy') {
if (dEl.ddDraggable) { // error to call destroy if not there
dEl.cleanDraggable();
}
});
}
} else if (opts === 'option') {
dEl.setupDraggable({ [key]: value });
} else {
const grid = dEl.el.gridstackNode.grid;
dEl.setupDraggable({
...grid.opts.draggable,
...{
containment: (grid.opts._isNested && !grid.opts.dragOut)
? grid.el.parentElement
: (grid.opts.draggable.containment || null),
start: opts.start,
stop: opts.stop,
drag: opts.drag
}
});
}
});
return this;
}

public dragIn(el: GridStackElement, opts: DDDragInOpt): GridStackDDNative {
let dEl = this.getGridStackDDElement(el);
dEl.setupDraggable(opts);
this.getDDElements(el).forEach(dEl => dEl.setupDraggable(opts));
return this;
}

public droppable(el: GridItemHTMLElement, opts: DDOpts | DDDropOpt, key?: DDKey, value?: DDValue): GridStackDDNative {
let dEl = this.getGridStackDDElement(el);
if (typeof opts.accept === 'function' && !opts._accept) {
opts._accept = opts.accept;
opts.accept = (el) => opts._accept(el);
}
if (opts === 'disable' || opts === 'enable') {
dEl.ddDroppable && dEl.ddDroppable[opts]();
} else if (opts === 'destroy') {
if (dEl.ddDroppable) { // error to call destroy if not there
dEl.cleanDroppable();
this.getDDElements(el).forEach(dEl => {
if (opts === 'disable' || opts === 'enable') {
dEl.ddDroppable && dEl.ddDroppable[opts]();
} else if (opts === 'destroy') {
if (dEl.ddDroppable) { // error to call destroy if not there
dEl.cleanDroppable();
}
} else if (opts === 'option') {
dEl.setupDroppable({ [key]: value });
} else {
dEl.setupDroppable(opts);
}
} else if (opts === 'option') {
dEl.setupDroppable({ [key]: value });
} else {
dEl.setupDroppable(opts);
}
});
return this;
}

/** true if at least one of them is droppable */
public isDroppable(el: GridItemHTMLElement): boolean {
const dEl = this.getGridStackDDElement(el);
return !!(dEl.ddDroppable);
return this.getDDElements(el).some(dEl => !!(dEl.ddDroppable));
}

/** true if at least one of them is draggable */
public isDraggable(el: GridStackElement): boolean {
const dEl = this.getGridStackDDElement(el);
return !!(dEl.ddDraggable);
return this.getDDElements(el).some(dEl => !!(dEl.ddDraggable));
}

public on(el: GridItemHTMLElement, name: string, callback: DDCallback): GridStackDDNative {
let dEl = this.getGridStackDDElement(el);
dEl.on(name, (event: Event) => {
callback(
event,
DDManager.dragElement ? DDManager.dragElement.el : event.target as GridItemHTMLElement,
DDManager.dragElement ? DDManager.dragElement.helper : null)
});
this.getDDElements(el).forEach(dEl =>
dEl.on(name, (event: Event) => {
callback(
event,
DDManager.dragElement ? DDManager.dragElement.el : event.target as GridItemHTMLElement,
DDManager.dragElement ? DDManager.dragElement.helper : null)
})
);
return this;
}

public off(el: GridItemHTMLElement, name: string): GridStackDD {
let dEl = this.getGridStackDDElement(el);
dEl.off(name);
this.getDDElements(el).forEach(dEl => dEl.off(name));
return this;
}

private getGridStackDDElement(el: GridStackElement): DDElement {
let dEl;
if (typeof el === 'string') {
dEl = document.querySelector(el as string);
} else {
dEl = el;
}
return dEl.ddElement ? dEl.ddElement: DDElement.init(dEl);
private getDDElements(els: GridStackElement): DDElement[] {
let list = Utils.getElements(els) as DDElementHost[];
if (!list.length) { return []; }
return list.map(e => e.ddElement || DDElement.init(e));
}
}

Expand Down
47 changes: 8 additions & 39 deletions src/gridstack.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@

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

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

export type GridStackElement = string | HTMLElement | GridItemHTMLElement;

export interface GridHTMLElement extends HTMLElement {
gridstack?: GridStack; // grid's parent DOM element points back to grid class
}
Expand Down Expand Up @@ -1766,48 +1764,19 @@ export class GridStack {

/** @internal convert a potential selector into actual element */
private static getElement(els: GridStackElement = '.grid-stack-item'): GridItemHTMLElement {
if (typeof els === 'string') {
if (!els.length) { return null}
if (els[0] === '#') {
return document.getElementById(els.substring(1));
}
if (els[0] === '.') {
return document.querySelector(els);
}

// if we start with a digit, assume it's an id (error calling querySelector('#1')) as class are not valid CSS
if(!isNaN(+els[0])) { // start with digit
return document.getElementById(els);
}

// finally try string, then id then class
let el = document.querySelector(els);
if (!el) { el = document.getElementById(els) }
if (!el) { el = document.querySelector('.' + els) }
return el as GridItemHTMLElement;
}
return els;
return Utils.getElement(els);
}

/** @internal convert a potential selector into actual list of elements */
/** @internal */
private static getElements(els: GridStackElement = '.grid-stack-item'): GridItemHTMLElement[] {
if (typeof els === 'string') {
let list = document.querySelectorAll(els);
if (!list.length && els[0] !== '.' && els[0] !== '#') {
list = document.querySelectorAll('.' + els);
if (!list.length) { list = document.querySelectorAll('#' + els) }
}
return Array.from(list) as GridItemHTMLElement[];
}
return [els];
return Utils.getElements(els);
}
/** @internal */
private static getGridElement(els: string | HTMLElement = '.grid-stack'): GridHTMLElement {
return GridStack.getElement(els) as GridHTMLElement;
private static getGridElement(els: GridStackElement): GridHTMLElement {
return GridStack.getElement(els);
}
/** @internal */
private static getGridElements(els: string | HTMLElement = '.grid-stack'): GridHTMLElement[] {
return GridStack.getElements(els) as GridHTMLElement[];
private static getGridElements(els: string): GridHTMLElement[] {
return Utils.getElements(els);
}

/** @internal initialize margin top/bottom/left/right and units */
Expand Down
2 changes: 2 additions & 0 deletions src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@ export interface GridItemHTMLElement extends HTMLElement {
_gridstackNodeOrig?: GridStackNode;
}

export type GridStackElement = string | HTMLElement | GridItemHTMLElement;

/**
* Defines the options for a Grid
*/
Expand Down
Loading