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
2 changes: 1 addition & 1 deletion doc/CHANGES.md
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ Change log

## 3.1.0-dev

- TBD
- fix [1419](https://github.com/gridstack/gridstack.js/issues/1419) dragging into a fixed row grid works better (check if it will fit, else try to append, else won't insert)

## 3.1.0 (2020-12-4)

Expand Down
73 changes: 73 additions & 0 deletions spec/e2e/html/1419-maxrow1-cant-insert.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
<!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>1 row max</title>

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

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

<style type="text/css">
.sidebar {
background: rgba(0, 255, 0, 0.1);
height: 150px;
padding: 25px 0;
text-align: center;
}
.sidebar .grid-stack-item {
width: 120px;
height: 50px;
border: 2px dashed green;
text-align: center;
line-height: 35px;
z-index: 10;
background: rgba(0, 255, 0, 0.1);
cursor: default;
display: inline-block;
}
.sidebar .grid-stack-item .grid-stack-item-content {
background: none;
}
</style>
</head>
<body>
<div class="container-fluid">
<p>1 Row max should prevent dragging from outside to push down, only go to empty slot (until we have push right)</p>

<div class="row">
<div class="col-md-3">
<div class="sidebar">

<div class="grid-stack-item" gs-w="2" gs-h="1">
<div class="grid-stack-item-content">Drag me 2x1</div>
</div>
<div class="grid-stack-item" gs-w="1" gs-h="1">
<div class="grid-stack-item-content">Drag me</div>
</div>

</div>
</div>
<div class="col-md-9">
<div class="grid-stack"></div>
</div>
</div>
</div>
<script src="../../../demo/events.js"></script>
<script type="text/javascript">
let options = {
row: 1,
cellHeight: 120,
dragIn: '.sidebar .grid-stack-item', // class that can be dragged from outside
dragInOptions: { revert: 'invalid', scroll: false, appendTo: 'body', helper: 'clone' }, // clone
acceptWidgets: true
};
let grid = GridStack.init(options);
addEvents(grid);
grid.addWidget({x: 0});
</script>
</body>
</html>
135 changes: 68 additions & 67 deletions spec/gridstack-engine-spec.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,15 @@
import { GridStackEngine } from '../src/gridstack-engine';
import { GridStackNode } from '../src/types';

describe('gridstack engine', function() {
'use strict';
let engine;
let engine: GridStackEngine;
// old hacky JS code that's not happy in TS. just cast to `any` and skip warnings
let e: any = GridStackEngine;
let w: any = window;

let findNode = function(engine, id) {
return engine.nodes.find(function(i) { return i._id === id; });
return engine.nodes.find(function(i) { return i.id === id; });
};

it('should exist setup function.', function() {
Expand All @@ -19,24 +20,24 @@ describe('gridstack engine', function() {
describe('test constructor', function() {

it('should be setup properly', function() {
engine = new GridStackEngine(12);
engine = new GridStackEngine();
expect(engine.column).toEqual(12);
expect(engine.float).toEqual(false);
expect(engine.maxRow).toEqual(0);
expect(engine.maxRow).toEqual(undefined);
expect(engine.nodes).toEqual([]);
expect(engine.onchange).toEqual(undefined);
expect(engine.onChange).toEqual(undefined);
expect(engine.batchMode).toEqual(undefined);
});

it('should set params correctly.', function() {
let fkt = function() { };
let arr: any = [1,2,3];
engine = new GridStackEngine(1, fkt, true, 2, arr);
engine = new GridStackEngine({column: 1, onChange:fkt, float:true, maxRow:2, nodes:arr});
expect(engine.column).toEqual(1);
expect(engine.float).toBe(true);
expect(engine.maxRow).toEqual(2);
expect(engine.nodes).toEqual(arr);
expect(engine.onchange).toEqual(fkt);
expect(engine.onChange).toEqual(fkt);
expect(engine.batchMode).toEqual(undefined);
});
});
Expand All @@ -54,21 +55,21 @@ describe('gridstack engine', function() {
describe('test prepareNode', function() {

beforeAll(function() {
engine = new GridStackEngine(12);
engine = new GridStackEngine();
});
it('should prepare a node', function() {
expect(engine.prepareNode({}, false)).toEqual(jasmine.objectContaining({x: 0, y: 0, h: 1}));
expect(engine.prepareNode({x: 10}, false)).toEqual(jasmine.objectContaining({x: 10, y: 0, h: 1}));
expect(engine.prepareNode({x: -10}, false)).toEqual(jasmine.objectContaining({x: 0, y: 0, h: 1}));
expect(engine.prepareNode({y: 10}, false)).toEqual(jasmine.objectContaining({x: 0, y: 10, h: 1}));
expect(engine.prepareNode({y: -10}, false)).toEqual(jasmine.objectContaining({x: 0, y: 0, h: 1}));
expect(engine.prepareNode({}, false)).toEqual(jasmine.objectContaining({x: 0, y: 0, h: 1}));
expect(engine.prepareNode({x: 10}, false)).toEqual(jasmine.objectContaining({x: 10, y: 0, h: 1}));
expect(engine.prepareNode({x: -10}, false)).toEqual(jasmine.objectContaining({x: 0, y: 0, h: 1}));
expect(engine.prepareNode({y: 10}, false)).toEqual(jasmine.objectContaining({x: 0, y: 10, h: 1}));
expect(engine.prepareNode({y: -10}, false)).toEqual(jasmine.objectContaining({x: 0, y: 0, h: 1}));
expect(engine.prepareNode({w: 3}, false)).toEqual(jasmine.objectContaining({x: 0, y: 0, w: 3, h: 1}));
expect(engine.prepareNode({w: 100}, false)).toEqual(jasmine.objectContaining({x: 0, y: 0, w: 12, h: 1}));
expect(engine.prepareNode({w: 0}, false)).toEqual(jasmine.objectContaining({x: 0, y: 0, h: 1}));
expect(engine.prepareNode({w: -190}, false)).toEqual(jasmine.objectContaining({x: 0, y: 0, h: 1}));
expect(engine.prepareNode({h: 3}, false)).toEqual(jasmine.objectContaining({x: 0, y: 0, h: 3}));
expect(engine.prepareNode({h: 0}, false)).toEqual(jasmine.objectContaining({x: 0, y: 0, h: 1}));
expect(engine.prepareNode({h: -10}, false)).toEqual(jasmine.objectContaining({x: 0, y: 0, h: 1}));
expect(engine.prepareNode({w: 0}, false)).toEqual(jasmine.objectContaining({x: 0, y: 0, h: 1}));
expect(engine.prepareNode({w: -190}, false)).toEqual(jasmine.objectContaining({x: 0, y: 0, h: 1}));
expect(engine.prepareNode({h: 3}, false)).toEqual(jasmine.objectContaining({x: 0, y: 0, h: 3}));
expect(engine.prepareNode({h: 0}, false)).toEqual(jasmine.objectContaining({x: 0, y: 0, h: 1}));
expect(engine.prepareNode({h: -10}, false)).toEqual(jasmine.objectContaining({x: 0, y: 0, h: 1}));
expect(engine.prepareNode({x: 4, w: 10}, false)).toEqual(jasmine.objectContaining({x: 2, y: 0, w: 10, h: 1}));
expect(engine.prepareNode({x: 4, w: 10}, true)).toEqual(jasmine.objectContaining({x: 4, y: 0, w: 8, h: 1}));
});
Expand Down Expand Up @@ -123,7 +124,7 @@ describe('gridstack engine', function() {
describe('test isAreaEmpty', function() {

beforeAll(function() {
engine = new GridStackEngine(12, null, true);
engine = new GridStackEngine({float:true});
engine.nodes = [
engine.prepareNode({x: 3, y: 2, w: 3, h: 2})
];
Expand All @@ -143,11 +144,11 @@ describe('gridstack engine', function() {
describe('test cleanNodes/getDirtyNodes', function() {

beforeAll(function() {
engine = new GridStackEngine(12, null, true);
engine = new GridStackEngine({float:true});
engine.nodes = [
engine.prepareNode({x: 0, y: 0, idx: 1, _dirty: true}),
engine.prepareNode({x: 3, y: 2, w: 3, h: 2, idx: 2, _dirty: true}),
engine.prepareNode({x: 3, y: 7, w: 3, h: 2, idx: 3})
engine.prepareNode({x: 0, y: 0, id: 1, _dirty: true}),
engine.prepareNode({x: 3, y: 2, w: 3, h: 2, id: 2, _dirty: true}),
engine.prepareNode({x: 3, y: 7, w: 3, h: 2, id: 3})
];
});

Expand All @@ -158,8 +159,8 @@ describe('gridstack engine', function() {
it('should return all dirty nodes', function() {
let nodes = engine.getDirtyNodes();
expect(nodes.length).toEqual(2);
expect(nodes[0].idx).toEqual(1);
expect(nodes[1].idx).toEqual(2);
expect(nodes[0].id).toEqual(1);
expect(nodes[1].id).toEqual(2);
});

it('should\'n clean nodes if batchMode true', function() {
Expand All @@ -176,7 +177,7 @@ describe('gridstack engine', function() {

describe('test batchUpdate/commit', function() {
beforeAll(function() {
engine = new GridStackEngine(12);
engine = new GridStackEngine();
});

it('should work on not float grids', function() {
Expand Down Expand Up @@ -205,7 +206,7 @@ describe('gridstack engine', function() {
describe('test batchUpdate/commit', function() {

beforeAll(function() {
engine = new GridStackEngine(12, null, true);
engine = new GridStackEngine({float:true});
});

it('should work on float grids', function() {
Expand All @@ -227,31 +228,31 @@ describe('gridstack engine', function() {
callback: function() {}
};
spyOn(spy, 'callback');
engine = new GridStackEngine(12, spy.callback, true);
engine = new GridStackEngine({float:true, onChange: spy.callback});
engine.nodes = [
engine.prepareNode({x: 0, y: 0, idx: 1, _dirty: true}),
engine.prepareNode({x: 3, y: 2, w: 3, h: 2, idx: 2, _dirty: true}),
engine.prepareNode({x: 3, y: 7, w: 3, h: 2, idx: 3})
engine.prepareNode({x: 0, y: 0, id: 1, _dirty: true}),
engine.prepareNode({x: 3, y: 2, w: 3, h: 2, id: 2, _dirty: true}),
engine.prepareNode({x: 3, y: 7, w: 3, h: 2, id: 3})
];
});

it('should\'n be called if batchMode true', function() {
engine.batchMode = true;
engine._notify();
(engine as any)._notify();
expect(spy.callback).not.toHaveBeenCalled();
});

it('should by called with dirty nodes', function() {
engine._notify();
(engine as any)._notify();
expect(spy.callback).toHaveBeenCalledWith([
engine.nodes[0],
engine.nodes[1]
], true);
});

it('should by called with extra passed node to be removed', function() {
let n1 = {idx: -1};
engine._notify(n1);
let n1 = {id: -1};
(engine as any)._notify(n1);
expect(spy.callback).toHaveBeenCalledWith([
n1,
engine.nodes[0],
Expand All @@ -260,8 +261,8 @@ describe('gridstack engine', function() {
});

it('should by called with extra passed node to be removed and should maintain false parameter', function() {
let n1 = {idx: -1};
engine._notify(n1, false);
let n1 = {id: -1};
(engine as any)._notify(n1, false);
expect(spy.callback).toHaveBeenCalledWith([
n1,
engine.nodes[0],
Expand All @@ -273,62 +274,62 @@ describe('gridstack engine', function() {
describe('test _packNodes', function() {
describe('using not float mode', function() {
beforeEach(function() {
engine = new GridStackEngine(12, null, false);
engine = new GridStackEngine({float:false});
});

it('shouldn\'t pack one node with y coord eq 0', function() {
engine.nodes = [
{x: 0, y: 0, w:1, h:1,_id: 1},
{x: 0, y: 0, w:1, h:1, id: 1},
];
engine._packNodes();
expect(findNode(engine, 1)).toEqual(jasmine.objectContaining({x: 0, y: 0, h: 1}));
(engine as any)._packNodes();
expect(findNode(engine, 1)).toEqual(jasmine.objectContaining({x: 0, y: 0, h: 1}));
expect(findNode(engine, 1)._dirty).toBeFalsy();
});

it('should pack one node correctly', function() {
engine.nodes = [
{x: 0, y: 1, w:1, h:1,_id: 1},
{x: 0, y: 1, w:1, h:1, id: 1},
];
engine._packNodes();
expect(findNode(engine, 1)).toEqual(jasmine.objectContaining({x: 0, y: 0, _dirty: true}));
(engine as any)._packNodes();
expect(findNode(engine, 1)).toEqual(jasmine.objectContaining({x: 0, y: 0, _dirty: true}));
});

it('should pack nodes correctly', function() {
engine.nodes = [
{x: 0, y: 1, w:1, h:1,_id: 1},
{x: 0, y: 5, w:1, h:1,_id: 2},
{x: 0, y: 1, w:1, h:1, id: 1},
{x: 0, y: 5, w:1, h:1, id: 2},
];
engine._packNodes();
expect(findNode(engine, 1)).toEqual(jasmine.objectContaining({x: 0, y: 0, _dirty: true}));
expect(findNode(engine, 2)).toEqual(jasmine.objectContaining({x: 0, y: 1, _dirty: true}));
(engine as any)._packNodes();
expect(findNode(engine, 1)).toEqual(jasmine.objectContaining({x: 0, y: 0, _dirty: true}));
expect(findNode(engine, 2)).toEqual(jasmine.objectContaining({x: 0, y: 1, _dirty: true}));
});

it('should pack nodes correctly', function() {
engine.nodes = [
{x: 0, y: 5, w:1, h:1,_id: 1},
{x: 0, y: 1, w:1, h:1,_id: 2},
{x: 0, y: 5, w:1, h:1, id: 1},
{x: 0, y: 1, w:1, h:1, id: 2},
];
engine._packNodes();
expect(findNode(engine, 2)).toEqual(jasmine.objectContaining({x: 0, y: 0, _dirty: true}));
expect(findNode(engine, 1)).toEqual(jasmine.objectContaining({x: 0, y: 1, _dirty: true}));
(engine as any)._packNodes();
expect(findNode(engine, 2)).toEqual(jasmine.objectContaining({x: 0, y: 0, _dirty: true}));
expect(findNode(engine, 1)).toEqual(jasmine.objectContaining({x: 0, y: 1, _dirty: true}));
});

it('should respect locked nodes', function() {
engine.nodes = [
{x: 0, y: 1, w:1, h:1,_id: 1, locked: true},
{x: 0, y: 5, w:1, h:1,_id: 2},
{x: 0, y: 1, w:1, h:1, id: 1, locked: true},
{x: 0, y: 5, w:1, h:1, id: 2},
];
engine._packNodes();
expect(findNode(engine, 1)).toEqual(jasmine.objectContaining({x: 0, y: 1, h: 1}));
(engine as any)._packNodes();
expect(findNode(engine, 1)).toEqual(jasmine.objectContaining({x: 0, y: 1, h: 1}));
expect(findNode(engine, 1)._dirty).toBeFalsy();
expect(findNode(engine, 2)).toEqual(jasmine.objectContaining({x: 0, y: 2, _dirty: true}));
expect(findNode(engine, 2)).toEqual(jasmine.objectContaining({x: 0, y: 2, _dirty: true}));
});
});
});

describe('test isNodeChangedPosition', function() {
beforeAll(function() {
engine = new GridStackEngine(12);
engine = new GridStackEngine();
});
it('should return true for changed x', function() {
let widget = { x: 1, y: 2, w: 3, h: 4 };
Expand All @@ -354,19 +355,19 @@ describe('gridstack engine', function() {

describe('test locked widget', function() {
beforeAll(function() {
engine = new GridStackEngine(12);
engine = new GridStackEngine();
});
it('should add widgets around locked one', function() {
let nodes = [
{x: 0, y: 1, w: 12, h: 1, locked: 'yes', noMove: true, noResize: true, _id: 1},
{x: 1, y: 0, w: 2, h: 3, _id: 2}
let nodes: GridStackNode[] = [
{x: 0, y: 1, w: 12, h: 1, locked: true, noMove: true, noResize: true, id: 1},
{x: 1, y: 0, w: 2, h: 3, id: 2}
];
// add locked item
engine.addNode(nodes[0])
expect(findNode(engine, 1)).toEqual(jasmine.objectContaining({x: 0, y: 1, w: 12, h: 1, locked: 'yes'}));
expect(findNode(engine, 1)).toEqual(jasmine.objectContaining({x: 0, y: 1, w: 12, h: 1, locked: true}));
engine.addNode(nodes[1])
// add item that moves past locked one
expect(findNode(engine, 1)).toEqual(jasmine.objectContaining({x: 0, y: 1, w: 12, h: 1, locked: 'yes'}));
expect(findNode(engine, 1)).toEqual(jasmine.objectContaining({x: 0, y: 1, w: 12, h: 1, locked: true}));
expect(findNode(engine, 2)).toEqual(jasmine.objectContaining({x: 1, y: 2}));
// prevents moving locked item
let node1 = findNode(engine, 1);
Expand All @@ -382,7 +383,7 @@ describe('gridstack engine', function() {

describe('test compact', function() {
beforeAll(function() {
engine = new GridStackEngine(12);
engine = new GridStackEngine();
});
it('do nothing', function() {
engine.compact();
Expand Down
Loading