Skip to content

Commit 1c5bc14

Browse files
author
Alain Dumesny
committed
new setColumn() heuristics
* complete re-write of the `setColumn()` code that moves/sizes widgets. we now do a reasonable job positioning widgets (especially 1 column), and we remember positions for each column layout to going from 12 -> 1 -> 12 will bring it exactly back for example! * new column.html test case (now that it works) to be published. * fixed bunch of bugs I found with overlapping widgets (going to 2 or 1 column) * fixed bug where default (empty) option when adding a widget would render it at (0,0) overlapping any existing widgets. added `_readAttr()/_writeAttr()` to help there. * unit test greatly updated with exact location expected of widgets (not that I agree with location) better fix than #809 fixing responsive.html will come next...
1 parent f7e46c5 commit 1c5bc14

File tree

10 files changed

+301
-138
lines changed

10 files changed

+301
-138
lines changed

demo/column.html

Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
<!DOCTYPE html>
2+
<html lang="en">
3+
<head>
4+
<meta charset="utf-8">
5+
<meta http-equiv="X-UA-Compatible" content="IE=edge">
6+
<meta name="viewport" content="width=device-width, initial-scale=1">
7+
<title>Column grid demo</title>
8+
9+
<link rel="stylesheet" href="../demo/demo.css"/>
10+
<link rel="stylesheet" href="../dist/gridstack-extra.css"/>
11+
12+
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js"></script>
13+
<script src="../dist/jquery-ui.min.js"></script>
14+
<script src="../src/gridstack.js"></script>
15+
<script src="../src/gridstack.jQueryUI.js"></script>
16+
</head>
17+
<body>
18+
<div class="container-fluid">
19+
<h1>setColumn() grid demo</h1>
20+
<a class="btn btn-primary" id="add-widget" href="#">Add Widget</a>
21+
<a class="btn btn-primary" id="1column" href="#">1 Column</a>
22+
<a class="btn btn-primary" id="2column" href="#">2 Column</a>
23+
<a class="btn btn-primary" id="3column" href="#">3 Column</a>
24+
<a class="btn btn-primary" id="4column" href="#">4 Column</a>
25+
<a class="btn btn-primary" id="6column" href="#">6 Column</a>
26+
<a class="btn btn-primary" id="8column" href="#">8 Column</a>
27+
<a class="btn btn-primary" id="10column" href="#">10 Column</a>
28+
<a class="btn btn-primary" id="12column" href="#">12 Column</a>
29+
<br><br>
30+
<div class="grid-stack"></div>
31+
</div>
32+
33+
<script type="text/javascript">
34+
$(function () {
35+
var $grid = $('.grid-stack');
36+
$grid.gridstack({float: true});
37+
grid = $grid.data('gridstack');
38+
39+
$grid.on('added', (e, items) => log(' added ', items));
40+
$grid.on('removed', (e, items) => log(' removed ', items));
41+
$grid.on('change', (e, items) => log(' change ', items));
42+
function log(type, items) {
43+
if (!items) { return; }
44+
var str = '';
45+
for (let i=0; i<items.length && items[i]; i++) { str += ' (x,y)=' + items[i].x + ',' + items[i].y; }
46+
console.log(type + items.length + ' items.' + str );
47+
}
48+
49+
var items = [
50+
{x: 0, y: 4, width: 12, height: 1},
51+
{x: 5, y: 3, width: 2, height: 1},
52+
{x: 1, y: 3, width: 4, height: 1},
53+
{x: 0, y: 0, width: 1, height: 1},
54+
{}, // autoPosition testing
55+
{x: 5, y: 0, width: 1, height: 1},
56+
{x: 2, y: 0, width: 2, height: 1},
57+
{x: 0, y: 0, width: 2, height: 2}
58+
];
59+
var count = 0;
60+
grid.batchUpdate();
61+
for (count=0; count<3; count++) {
62+
grid.addWidget($('<div><div class="grid-stack-item-content">' + count + '</div></div>'), items.pop());
63+
};
64+
grid.commit();
65+
66+
$('#add-widget').click(() => {
67+
var node = items.pop() || {
68+
x: Math.round(12 * Math.random()),
69+
y: Math.round(5 * Math.random()),
70+
width: Math.round(1 + 3 * Math.random()),
71+
height: Math.round(1 + 3 * Math.random())
72+
};
73+
grid.addWidget($('<div><div class="grid-stack-item-content">' + count++ + '</div></div>'), node);
74+
});
75+
76+
$('#1column').click(() => { grid.setColumn(1); });
77+
$('#2column').click(() => { grid.setColumn(2); });
78+
$('#3column').click(() => { grid.setColumn(3); });
79+
$('#4column').click(() => { grid.setColumn(4); });
80+
$('#6column').click(() => { grid.setColumn(6); });
81+
$('#6column').click(() => { grid.setColumn(6); });
82+
$('#8column').click(() => { grid.setColumn(8); });
83+
$('#10column').click(() => { grid.setColumn(10); });
84+
$('#12column').click(() => { grid.setColumn(12); });
85+
});
86+
</script>
87+
</body>
88+
</html>

demo/float.html

Lines changed: 5 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -28,10 +28,7 @@ <h1>Float grid demo</h1>
2828

2929
<script type="text/javascript">
3030
$(function () {
31-
var options = {
32-
float: true
33-
};
34-
$('.grid-stack').gridstack(options);
31+
$('.grid-stack').gridstack({float: true});
3532

3633
new function () {
3734
this.items = [
@@ -46,10 +43,10 @@ <h1>Float grid demo</h1>
4643

4744
this.addNewWidget = function() {
4845
var node = this.items.pop() || {
49-
x: 12 * Math.random(),
50-
y: 5 * Math.random(),
51-
width: 1 + 3 * Math.random(),
52-
height: 1 + 3 * Math.random()
46+
x: Math.round(12 * Math.random()),
47+
y: Math.round(5 * Math.random()),
48+
width: Math.round(1 + 3 * Math.random()),
49+
height: Math.round(1 + 3 * Math.random())
5350
};
5451
this.grid.addWidget($('<div><div class="grid-stack-item-content"></div></div>'), node);
5552
return false;

demo/index.html

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,16 +6,17 @@
66
</head>
77
<body>
88
<ul>
9+
<li><a href="advance.html">Advance demo</a></li>
10+
<li><a href="anijs.html">AniJS demo</a></li>
11+
<li><a href="column.html">Column demo</a></li>
912
<li><a href="float.html">Float grid demo</a></li>
1013
<li><a href="knockout.html">Knockout.js demo</a></li>
1114
<li><a href="knockout2.html">Knockout.js demo (2)</a></li>
1215
<li><a href="nested.html">Nested grids demo</a></li>
16+
<li><a href="responsive.html">Resize grid (responsive) demo</a></li>
1317
<li><a href="right-to-left(rtl).html">Right-To-Left (RTL) demo</a></li>
1418
<li><a href="serialization.html">Serialization demo</a></li>
1519
<li><a href="two.html">Two grids demo</a></li>
16-
<li><a href="advance.html">Advance demo</a></li>
17-
<li><a href="responsive.html">Resize grid (responsive) demo</a></li>
18-
<li><a href="anijs.html">AniJS demo</a></li>
1920
</ul>
2021
</body>
2122
</html>

demo/responsive.html

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -43,11 +43,7 @@ <h1>Responsive grid demo</h1>
4343
return $('.device-' + alias).is(':visible');
4444
}
4545

46-
47-
var options = {
48-
float: false
49-
};
50-
$('.grid-stack').gridstack(options);
46+
$('.grid-stack').gridstack();
5147
function resizeGrid() {
5248
var grid = $('.grid-stack').data('gridstack');
5349
if (isBreakpoint('xs')) {

doc/CHANGES.md

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,10 @@ Change log
3232
- fixed callbacks to get either `added, removed, change` or combination if adding a node require also to change its (x,y) for example.
3333
Also you can now call `batchUpdate()` before calling a bunch of `addWidget()` and get a single event callback (more efficient).
3434
[#1096](https://github.com/gridstack/gridstack.js/pull/1096)
35-
- `removeAll()` is now much faster (no relayout) and calls `removed` event just once with a list
35+
- `removeAll()` is now much faster (no relayout) and calls `removed` event just once with a list [#1097](https://github.com/gridstack/gridstack.js/pull/1097)
36+
- `setColumn()` complete re-write and is no longer "Experimental". We now do a reasonable job at sizing/position the widgets (especially 1 column) and
37+
also now cache each column layout so you can go back to say 12 column and not loose original layout. [#1098](https://github.com/gridstack/gridstack.js/pull/1098)
38+
- fix bug where `addWidget(el)` (default values) would not render item at correct CSS location, and overlap item at (0,0) [#1098](https://github.com/gridstack/gridstack.js/pull/1098)
3639

3740
## v0.5.5 (2019-11-27)
3841

doc/README.md

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -445,9 +445,12 @@ Toggle the grid animation state. Toggles the `grid-stack-animate` class.
445445

446446
### setColumn(column, doNotPropagate)
447447

448-
(Experimental) Modify number of columns in the grid. Will attempt to update existing widgets to conform to new number of columns. Requires `gridstack-extra.css` or `gridstack-extra.min.css`.
448+
Modify number of columns in the grid. Will update existing widgets to conform to new number of columns,
449+
as well as cache the original layout so you can revert back to previous positions without loss.
450+
Requires `gridstack-extra.css` or `gridstack-extra.min.css` for [1-11],
451+
else you will need to generate correct CSS (see https://github.com/gridstack/gridstack.js#change-grid-columns)
449452

450-
- `column` - Integer between 1 and 12.
453+
- `column` - Integer > 0 (default 12).
451454
- `doNotPropagate` - if true existing widgets will not be updated.
452455

453456
### setStatic(staticValue)

spec/e2e/html/column.html

Lines changed: 0 additions & 53 deletions
This file was deleted.

spec/gridstack-spec.js

Lines changed: 81 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -295,7 +295,7 @@ describe('gridstack', function() {
295295
grid.setGridWidth(12); // old API
296296
expect(grid.opts.column).toBe(12);
297297
});
298-
it('should change column number, no relayout', function() {
298+
it('should SMALL change column number, no relayout', function() {
299299
var options = {
300300
column: 12
301301
};
@@ -314,21 +314,77 @@ describe('gridstack', function() {
314314
for (var j = 0; j < items.length; j++) {
315315
expect(parseInt($(items[j]).attr('data-gs-y'), 10)).toBe(0);
316316
}
317+
318+
grid.setColumn(12);
319+
expect(grid.opts.column).toBe(12);
320+
for (var j = 0; j < items.length; j++) {
321+
expect(parseInt($(items[j]).attr('data-gs-y'), 10)).toBe(0);
322+
}
317323
});
318324
it('should change column number and relayout items', function() {
319325
var options = {
320-
column: 12
326+
column: 12,
327+
float: true
321328
};
322329
$('.grid-stack').gridstack(options);
323330
var grid = $('.grid-stack').data('gridstack');
324-
var items = $('.grid-stack-item');
331+
var node1 = $('#item1').data('_gridstack_node');
332+
var node2 = $('#item2').data('_gridstack_node');
333+
// items start at 4x2 and 4x4
334+
expect(node1.x).toBe(0);
335+
expect(node1.y).toBe(0);
336+
expect(node1.width).toBe(4);
337+
expect(node1.height).toBe(2);
338+
339+
expect(node2.x).toBe(4);
340+
expect(node2.y).toBe(0);
341+
expect(node2.width).toBe(4);
342+
expect(node2.height).toBe(4);
325343

344+
// one column will have item1, item2
326345
grid.setColumn(1);
346+
node1 = $('#item1').data('_gridstack_node');
347+
node2 = $('#item2').data('_gridstack_node');
327348
expect(grid.opts.column).toBe(1);
328-
for (var j = 0; j < items.length; j++) {
329-
expect(parseInt($(items[j]).attr('data-gs-x'), 10)).toBe(0);
330-
// TODO: check Y position but I don't currently agree with order. [Alain]
331-
}
349+
expect(node1.x).toBe(0);
350+
expect(node1.y).toBe(0);
351+
expect(node1.width).toBe(1);
352+
expect(node1.height).toBe(2);
353+
354+
expect(node2.x).toBe(0);
355+
expect(node2.y).toBe(2);
356+
expect(node2.width).toBe(1);
357+
expect(node2.height).toBe(4);
358+
359+
// add default 1x1 item to the end (1 column)
360+
var el3 = grid.addWidget(widgetHTML);
361+
expect(el3).not.toBe(null);
362+
var node3 = $(el3).data('_gridstack_node');
363+
expect(node3.x).toBe(0);
364+
expect(node3.y).toBe(6);
365+
expect(node3.width).toBe(1);
366+
expect(node3.height).toBe(1);
367+
368+
// back to 12 column and initial layout (other than new item3)
369+
grid.setColumn(12);
370+
expect(grid.opts.column).toBe(12);
371+
node1 = $('#item1').data('_gridstack_node');
372+
node2 = $('#item2').data('_gridstack_node');
373+
node3 = $('#item3').data('_gridstack_node');
374+
expect(node1.x).toBe(0);
375+
expect(node1.y).toBe(0);
376+
expect(node1.width).toBe(4);
377+
expect(node1.height).toBe(2);
378+
379+
expect(node2.x).toBe(4);
380+
expect(node2.y).toBe(0);
381+
expect(node2.width).toBe(4);
382+
expect(node2.height).toBe(4);
383+
384+
expect(node3.x).toBe(0);
385+
expect(node3.y).toBe(6);
386+
expect(node3.width).toBe(12); // take entire row still
387+
expect(node3.height).toBe(1);
332388
});
333389
});
334390

@@ -1089,14 +1145,14 @@ describe('gridstack', function() {
10891145
expect($widget.attr('data-gs-max-height')).toBe(undefined);
10901146
expect($widget.attr('data-gs-id')).toBe('optionWidget');
10911147
});
1092-
it('should not autoPosition (correct X, missing Y)', function() {
1148+
it('should autoPosition (correct X, missing Y)', function() {
10931149
$('.grid-stack').gridstack();
10941150
var grid = $('.grid-stack').data('gridstack');
10951151
var widget = grid.addWidget(widgetHTML, {x: 8, height: 2, id: 'optionWidget'});
10961152
var $widget = $(widget);
10971153
expect(parseInt($widget.attr('data-gs-x'), 10)).toBe(8);
1098-
expect($widget.attr('data-gs-y')).toBe(undefined);
1099-
expect($widget.attr('data-gs-width')).toBe(undefined);
1154+
expect(parseInt($widget.attr('data-gs-y'), 10)).toBe(0);
1155+
expect(parseInt($widget.attr('data-gs-width'), 10)).toBe(1);
11001156
expect(parseInt($widget.attr('data-gs-height'), 10)).toBe(2);
11011157
expect($widget.attr('data-gs-auto-position')).toBe(undefined);
11021158
expect($widget.attr('data-gs-min-width')).toBe(undefined);
@@ -1105,6 +1161,21 @@ describe('gridstack', function() {
11051161
expect($widget.attr('data-gs-max-height')).toBe(undefined);
11061162
expect($widget.attr('data-gs-id')).toBe('optionWidget');
11071163
});
1164+
it('should autoPosition (empty options)', function() {
1165+
$('.grid-stack').gridstack();
1166+
var grid = $('.grid-stack').data('gridstack');
1167+
var widget = grid.addWidget(widgetHTML, {});
1168+
var $widget = $(widget);
1169+
expect(parseInt($widget.attr('data-gs-x'), 10)).toBe(8);
1170+
expect(parseInt($widget.attr('data-gs-y'), 10)).toBe(0);
1171+
expect(parseInt($widget.attr('data-gs-width'), 10)).toBe(1);
1172+
expect(parseInt($widget.attr('data-gs-height'), 10)).toBe(1);
1173+
expect($widget.attr('data-gs-auto-position')).toBe(undefined);
1174+
expect($widget.attr('data-gs-min-width')).toBe(undefined);
1175+
expect($widget.attr('data-gs-max-width')).toBe(undefined);
1176+
expect($widget.attr('data-gs-min-height')).toBe(undefined);
1177+
expect($widget.attr('data-gs-max-height')).toBe(undefined);
1178+
});
11081179

11091180
});
11101181

src/gridstack.d.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -275,8 +275,9 @@ interface GridStack {
275275
setAnimation(doAnimate: boolean): void;
276276

277277
/**
278-
* (Experimental) Modify number of columns in the grid. Will attempt to update existing widgets
279-
* to conform to new number of columns. Requires `gridstack-extra.css` or `gridstack-extra.min.css` for [1-11],
278+
* Modify number of columns in the grid. Will update existing widgets to conform to new number of columns,
279+
* as well as cache the original layout so you can revert back to previous positions without loss.
280+
* Requires `gridstack-extra.css` or `gridstack-extra.min.css` for [1-11],
280281
* else you will need to generate correct CSS (see https://github.com/gridstack/gridstack.js#change-grid-columns)
281282
* @param column - Integer > 0 (default 12).
282283
* @param doNotPropagate if true existing widgets will not be updated (optional)

0 commit comments

Comments
 (0)