README.md 9.29 KB
Newer Older
Pavel Reznikov's avatar
Pavel Reznikov committed
1
2
3
gridstack.js
============

Pavel Reznikov's avatar
Pavel Reznikov committed
4
5
gridstack.js is a jQuery plugin for widget layout. This is drag-and-drop multi-column grid. It allows you to build 
draggable responsive bootstrap v3 friendly layouts. It also works great with [knockout.js](http://knockoutjs.com)
Pavel Reznikov's avatar
Pavel Reznikov committed
6

Pavel Reznikov's avatar
readme    
Pavel Reznikov committed
7
Inspired by [gridster.js](http://gridster.net). Built with love.
Pavel Reznikov's avatar
Pavel Reznikov committed
8
9
10
11

Demo
====

Pavel Reznikov's avatar
Pavel Reznikov committed
12
Please visit http://troolee.github.io/gridstack.js/ for demo.
Pavel Reznikov's avatar
Pavel Reznikov committed
13
14
15
16


Usage
=====
Pavel Reznikov's avatar
readme    
Pavel Reznikov committed
17

Pavel Reznikov's avatar
Pavel Reznikov committed
18
19
## Requirements

Pavel Reznikov's avatar
Pavel Reznikov committed
20
* http://underscorejs.org (>= 1.7.0)
Pavel Reznikov's avatar
typo    
Pavel Reznikov committed
21
22
* http://jquery.com (>= 1.11.0) 
* http://jqueryui.com (>= 1.11.0). Minimum required components: Core, Widget, Mouse, Draggable, Resizable
Pavel Reznikov's avatar
Pavel Reznikov committed
23
* (Optional) http://knockoutjs.com (>= 3.2.0)
Pavel Reznikov's avatar
license    
Pavel Reznikov committed
24

Pavel Reznikov's avatar
Pavel Reznikov committed
25
26
27
## Basic usage

```html
28
29
30
31
32
<div class="grid-stack">
    <div class="grid-stack-item" 
        data-gs-x="0" data-gs-y="0" 
        data-gs-width="4" data-gs-height="2">
            <div class="grid-stack-item-content"></div>
Pavel Reznikov's avatar
Pavel Reznikov committed
33
    </div>
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
    <div class="grid-stack-item" 
        data-gs-x="4" data-gs-y="0" 
        data-gs-width="4" data-gs-height="4">
            <div class="grid-stack-item-content"></div>
    </div>
</div>

<script type="text/javascript">
$(function () {
    var options = {
        cell_height: 80,
        vertical_margin: 10
    };
    $('.grid-stack').gridstack(options);
});
</script>
Pavel Reznikov's avatar
Pavel Reznikov committed
50
51
```

Pavel Reznikov's avatar
Pavel Reznikov committed
52
53
## Options

Pavel Reznikov's avatar
Pavel Reznikov committed
54
55
56
- `animate` - turns animation on (default: `false`)
- `auto` - if `false` it tells to do not initialize existing items (default: `true`)
- `cell_height` - one cell height (default: `60`)
Pavel Reznikov's avatar
Pavel Reznikov committed
57
- `handle` - draggable handle selector (default: `'.grid-stack-item-content'`)
Pavel Reznikov's avatar
Pavel Reznikov committed
58
- `height` - maximum rows amount. Default is `0` which means no maximum rows
Pavel Reznikov's avatar
Pavel Reznikov committed
59
- `float` - enable floating widgets (default: `false`)
Pavel Reznikov's avatar
Pavel Reznikov committed
60
- `item_class` - widget class (default: `'grid-stack-item'`)
Pavel Reznikov's avatar
Pavel Reznikov committed
61
- `min_width` - minimal width. If window width is less grid will be shown in one-column mode (default: `768`)
Pavel Reznikov's avatar
Pavel Reznikov committed
62
- `placeholder_class` - class for placeholder (default: `'grid-stack-placeholder'`)
Pavel Reznikov's avatar
Pavel Reznikov committed
63
64
- `vertical_margin` - vertical gap size (default: `20`)
- `width` - amount of columns (default: `12`)
Pavel Reznikov's avatar
Pavel Reznikov committed
65

Pavel Reznikov's avatar
Pavel Reznikov committed
66
67
## Grid attributes

Pavel Reznikov's avatar
Pavel Reznikov committed
68
69
70
- `data-gs-animate` - turns animation on 
- `data-gs-width` - amount of columns
- `data-gs-height` - maximum rows amount. Default is `0` which means no maximum rows.
Pavel Reznikov's avatar
Pavel Reznikov committed
71

Pavel Reznikov's avatar
Pavel Reznikov committed
72
73
74
75
76
77
## Item attributes

- `data-gs-x`, `data-gs-y` - element position
- `data-gs-width`, `data-gs-height` - element size
- `data-gs-max-width`, `data-gs-min-width`, `data-gs-max-height`, `data-gs-min-height` - element constraints
- `data-gs-no-resize` - disable element resizing
Pavel Reznikov's avatar
Pavel Reznikov committed
78
- `data-gs-no-move` - disable element moving 
Pavel Reznikov's avatar
Pavel Reznikov committed
79
80
- `data-gs-auto-position` - tells to ignore `data-gs-x` and `data-gs-y` attributes and to place element to the first 
    available position
Pavel Reznikov's avatar
Pavel Reznikov committed
81
82
83
- `data-gs-locked` - the widget will be locked. It means another widgets couldn't move it during dragging or resizing.
The widget is still can be dragged or resized. You need to add `data-gs-no-resize` and `data-gs-no-move` attributes
to completely lock the widget.
Pavel Reznikov's avatar
Pavel Reznikov committed
84
85
86
    
## Events

Pavel Reznikov's avatar
Pavel Reznikov committed
87
### onchange(items)
Pavel Reznikov's avatar
Pavel Reznikov committed
88
89
90
91

Occurs when widgets change their position/size

```javascript
92
93
94
var serialize_widget_map = function (items) {
    console.log(items);
};
Pavel Reznikov's avatar
samples    
Pavel Reznikov committed
95

96
97
98
$('.grid-stack').on('change', function (e, items) {
    serialize_widget_map(items);
});
Pavel Reznikov's avatar
Pavel Reznikov committed
99
100
```

Pavel Reznikov's avatar
Pavel Reznikov committed
101
102
103
### ondragstart(event, ui)

```javascript
104
105
106
107
$('.grid-stack').on('dragstart', function (event, ui) {
    var grid = this;
    var element = event.target;
});
Pavel Reznikov's avatar
Pavel Reznikov committed
108
109
110
111
112
```

### ondragstop(event, ui)

```javascript
113
114
115
116
$('.grid-stack').on('dragstop', function (event, ui) {
    var grid = this;
    var element = event.target;
});
Pavel Reznikov's avatar
Pavel Reznikov committed
117
118
119
120
121
```

### onresizestart(event, ui)

```javascript
122
123
124
125
$('.grid-stack').on('resizestart', function (event, ui) {
    var grid = this;
    var element = event.target;
});
Pavel Reznikov's avatar
Pavel Reznikov committed
126
127
128
129
130
```

### onresizestop(event, ui)

```javascript
131
132
133
134
$('.grid-stack').on('resizestop', function (event, ui) {
    var grid = this;
    var element = event.target;
});
Pavel Reznikov's avatar
Pavel Reznikov committed
135
136
137
```


Pavel Reznikov's avatar
Pavel Reznikov committed
138
139
140
141
142
143
144
145
146
147
148
149
150
## API

### add_widget(el, x, y, width, height, auto_position)

Creates new widget.

Parameters:

- `el` - widget to add
- `x`, `y`, `width`, `height` - widget position/dimensions (Optional)
- `auto_position` - if `true` then `x`, `y` parameters will be ignored and widget will be places on the first available
position

Pavel Reznikov's avatar
Pavel Reznikov committed
151
152
153
Widget will be always placed even if result height will be more then grid height. You need to use `will_it_fit` method
before call `add_widget` for additional check.

Pavel Reznikov's avatar
Pavel Reznikov committed
154
```javascript
Pavel Reznikov's avatar
Pavel Reznikov committed
155
$('.grid-stack').gridstack();
Pavel Reznikov's avatar
Pavel Reznikov committed
156

Pavel Reznikov's avatar
Pavel Reznikov committed
157
var grid = $('.grid-stack').data('gridstack');
Pavel Reznikov's avatar
Pavel Reznikov committed
158
159
160
grid.add_widget(el, 0, 0, 3, 2, true);
```

Pavel Reznikov's avatar
Pavel Reznikov committed
161
162
163
164
165
166
167
### locked(el, val)

Locks/unlocks widget.

- `el` - widget to modify.
- `val` - if `true` widget will be locked. 

Pavel Reznikov's avatar
Pavel Reznikov committed
168
169
170
171
172
173
### remove_widget(el)

Removes widget from the grid.

Parameters:

Pavel Reznikov's avatar
samples    
Pavel Reznikov committed
174
- `el` - widget to remove
Pavel Reznikov's avatar
Pavel Reznikov committed
175

176
177
178
179
### remove_all()

Removes all widgets from the grid.

180
181
182
183
184
185
186
### resize(el, width, \[height\])

Changes widget size

Parameters:

- `el` - widget to resize
Pavel Reznikov's avatar
Pavel Reznikov committed
187
- `width`, `height` - new dimensions. If value is `null` or `undefined` it will be ignored.
188
189
190
191
192
193
194
195

### move(el, x, \[y\])

Changes widget position

Parameters:

- `el` - widget to move
Pavel Reznikov's avatar
Pavel Reznikov committed
196
- `x`, `y` - new position. If value is `null` or `undefined` it will be ignored.
197

198
199
200
201
202
203
204
205
206
207
208
209
### resizable(el, val)

Enables/Disables resizing.

- `el` - widget to modify
- `val` - if `true` widget will be resizable. 

### movable(el, val)

Enables/Disables moving.

- `el` - widget to modify
210
- `val` - if `true` widget will be draggable.
Pavel Reznikov's avatar
Pavel Reznikov committed
211
212
213
214
215
216
217
218
219
220
221

### will_it_fit(x, y, width, height, auto_position)

Returns `true` if the `height` of the grid will be less the vertical constraint. Always returns `true` if grid doesn't
have `height` constraint.

```javascript
if (grid.will_it_fit(new_node.x, new_node.y, new_node.width, new_node.height, true)) {
    grid.add_widget(new_node.x, new_node.y, new_node.width, new_node.height, true);
}
else {
Pavel Reznikov's avatar
typo    
Pavel Reznikov committed
222
    alert('Not enough free space to place the widget');
Pavel Reznikov's avatar
Pavel Reznikov committed
223
224
}
```
225
 
Pavel Reznikov's avatar
Pavel Reznikov committed
226

227
228
229
230
231
232
233
234
## Utils

### GridStackUI.Utils.sort(nodes, \[dir\], \[width\])

Sorts array of nodes

- `nodes` - array to sort
- `dir` - `1` for asc, `-1` for desc
Pavel Reznikov's avatar
Pavel Reznikov committed
235
- `width` - width of the grid. If `undefined` the width will be calculated automatically.
236

Pavel Reznikov's avatar
Pavel Reznikov committed
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
## Use with knockout.js

```javascript
ko.components.register('dashboard-grid', {
    viewModel: {
        createViewModel: function (params, componentInfo) {
            var ViewModel = function (params, componentInfo) {
                var grid = null;

                this.widgets = params.widgets;

                this.afterAddWidget = function (items) {
                    _.each(items, function (item) {
                        item = $(item);

                        if (grid == null) {
                            grid = $(componentInfo.element).find('.grid-stack').gridstack({
                                auto: false
                            }).data('gridstack');
                        }

                        grid.add_widget(item);
259
260
261
                        ko.utils.domNodeDisposal.addDisposeCallback(item[0], function () {
                            grid.remove_widget(item);
                        });
Pavel Reznikov's avatar
Pavel Reznikov committed
262
263
264
265
266
267
268
269
270
271
272
                    }, this);
                };

            };

            return new ViewModel(params, componentInfo);
        }
    },
    template: [
        '<div class="grid-stack">',
        '   <!-- ko foreach: widgets, afterRender: afterAddWidget -->',
Pavel Reznikov's avatar
Pavel Reznikov committed
273
274
275
276
277
        '       <div class="grid-stack-item" data-bind="attr: {',
        '               \'data-gs-x\': x, \'data-gs-y\': y,',
        '               \'data-gs-width\': width, \'data-gs-height\': height}">',
        '           <span data-bind="text: $index"></span>',
        '       </div>',
Pavel Reznikov's avatar
Pavel Reznikov committed
278
279
280
281
282
283
284
285
286
287
288
289
290
        '   <!-- /ko -->',
        '</div>'
    ].join('\n')
});
```

and HTML:

```html
<div data-bind="component: {name: 'dashboard-grid', params: $data}"></div>
```


291
292
293
Changes
=======

Pavel Reznikov's avatar
Pavel Reznikov committed
294
#### v0.2.1
Pavel Reznikov's avatar
Pavel Reznikov committed
295

Pavel Reznikov's avatar
Pavel Reznikov committed
296
- add widgets locking (issue #19)
Pavel Reznikov's avatar
Pavel Reznikov committed
297
298
- add `will_it_fit` API method
- fix auto-positioning (issue #20)
Pavel Reznikov's avatar
Pavel Reznikov committed
299
- add animation (thanks to @ishields)
Pavel Reznikov's avatar
Pavel Reznikov committed
300
- fix `y` coordinate calculation when dragging (issue #18)
Pavel Reznikov's avatar
Pavel Reznikov committed
301
- fix `remove_widget` (issue #16)
Pavel Reznikov's avatar
Pavel Reznikov committed
302
- minor fixes
Pavel Reznikov's avatar
Pavel Reznikov committed
303
304


Pavel Reznikov's avatar
Pavel Reznikov committed
305
#### v0.2.0 (2014-11-30)
Pavel Reznikov's avatar
Pavel Reznikov committed
306

Pavel Reznikov's avatar
Pavel Reznikov committed
307
- add `height` option
Pavel Reznikov's avatar
Pavel Reznikov committed
308
- auto-generate css rules (widgets `height` and `top`)
Pavel Reznikov's avatar
Pavel Reznikov committed
309
310
- add `GridStackUI.Utils.sort` utility function
- add `remove_all` API method
311
- add `resize` and `move` API methods 
312
313
- add `resizable` and `movable` API methods
- add `data-gs-no-move` attribute
Pavel Reznikov's avatar
Pavel Reznikov committed
314
315
- add `float` option
- fix default css rule for inner content
Pavel Reznikov's avatar
Pavel Reznikov committed
316
- minor fixes
Pavel Reznikov's avatar
Pavel Reznikov committed
317

318
319
#### v0.1.0 (2014-11-18)

Pavel Reznikov's avatar
Pavel Reznikov committed
320
321
Very first version.

322

Pavel Reznikov's avatar
license    
Pavel Reznikov committed
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
License
=======

The MIT License (MIT)

Copyright (c) 2014 Pavel Reznikov

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.