1 | /***
|
2 | * A Resizer plugin that can be used to auto-resize a grid and/or resize with fixed dimensions.
|
3 | * When fixed height is defined, it will auto-resize only the width and vice versa with the width defined.
|
4 | * You can also choose to use the flag "enableAutoSizeColumns" if you want to the plugin to
|
5 | * automatically call the grid "autosizeColumns()" method after each resize.
|
6 | *
|
7 | * USAGE:
|
8 | *
|
9 | * Add the "slick.resizer.js" file and register it with the grid.
|
10 | *
|
11 | * You can specify certain options as arguments when instantiating the plugin like so:
|
12 | * var resizer = new Slick.Plugins.Resizer({
|
13 | * container: '#gridContainer',
|
14 | * rightPadding: 15,
|
15 | * bottomPadding: 20,
|
16 | * minHeight: 180,
|
17 | * minWidth: 300,
|
18 | * });
|
19 | * grid.registerPlugin(resizer);
|
20 | *
|
21 | *
|
22 | * The plugin exposes the following events:
|
23 | *
|
24 | * onGridAfterResize: Fired after the grid got resized. You can customize the menu or dismiss it by returning false.
|
25 | * Event args:
|
26 | * grid: Reference to the grid.
|
27 | * dimensions: Resized grid dimensions used
|
28 | *
|
29 | * onGridBeforeResize: Fired before the grid gets resized. You can customize the menu or dismiss it by returning false.
|
30 | * Event args:
|
31 | * grid: Reference to the grid.
|
32 | *
|
33 | *
|
34 | * @param {Object} options available plugin options that can be passed in the constructor:
|
35 | * container: (REQUIRED) DOM element selector of the page container, basically what element in the page will be used to calculate the available space
|
36 | * gridContainer: DOM element selector of the grid container, optional but when provided it will be resized with same size as the grid (typically a container holding the grid and extra custom footer/pagination)
|
37 | * applyResizeToContainer: Defaults to false, do we want to apply the resized dimentions to the grid container as well?
|
38 | * rightPadding: Defaults to 0, right side padding to remove from the total dimension
|
39 | * bottomPadding: Defaults to 20, bottom padding to remove from the total dimension
|
40 | * minHeight: Defaults to 180, minimum height of the grid
|
41 | * minWidth: Defaults to 300, minimum width of the grid
|
42 | * maxHeight: Maximum height of the grid
|
43 | * maxWidth: Maximum width of the grid
|
44 | * calculateAvailableSizeBy: Defaults to "window", which DOM element ("container" or "window") are we using to calculate the available size for the grid?
|
45 | *
|
46 | * @class Slick.Plugins.Resizer
|
47 | * @constructor
|
48 | */
|
49 |
|
50 | ;
|
51 |
|
52 | (function ($) {
|
53 | // register namespace
|
54 | $.extend(true, window, {
|
55 | "Slick": {
|
56 | "Plugins": {
|
57 | "Resizer": Resizer
|
58 | }
|
59 | }
|
60 | });
|
61 |
|
62 | function Resizer(options, fixedDimensions) {
|
63 | // global variables, height/width are in pixels
|
64 | var DATAGRID_MIN_HEIGHT = 180;
|
65 | var DATAGRID_MIN_WIDTH = 300;
|
66 | var DATAGRID_BOTTOM_PADDING = 20;
|
67 |
|
68 | var _self = this;
|
69 | var _fixedHeight;
|
70 | var _fixedWidth;
|
71 | var _grid;
|
72 | var _gridOptions;
|
73 | var _gridUid;
|
74 | var _lastDimensions;
|
75 | var _timer;
|
76 | var _resizePaused = false;
|
77 | var _gridDomElm;
|
78 | var _pageContainerElm;
|
79 | var _gridContainerElm;
|
80 | var _defaults = {
|
81 | bottomPadding: 20,
|
82 | applyResizeToContainer: false,
|
83 | minHeight: 180,
|
84 | minWidth: 300,
|
85 | rightPadding: 0
|
86 | };
|
87 |
|
88 | function init(grid) {
|
89 | options = $.extend(true, {}, _defaults, options);
|
90 | _grid = grid;
|
91 | _gridOptions = _grid.getOptions();
|
92 | _gridUid = _grid.getUID();
|
93 | _gridDomElm = $(_grid.getContainerNode());
|
94 | _pageContainerElm = $(options.container);
|
95 | if (options.gridContainer) {
|
96 | _gridContainerElm = $(options.gridContainer);
|
97 | }
|
98 |
|
99 | if (fixedDimensions) {
|
100 | _fixedHeight = fixedDimensions.height;
|
101 | _fixedWidth = fixedDimensions.width;
|
102 | }
|
103 |
|
104 | if (_gridOptions) {
|
105 | bindAutoResizeDataGrid();
|
106 | }
|
107 | }
|
108 |
|
109 | /** Bind an auto resize trigger on the datagrid, if that is enable then it will resize itself to the available space
|
110 | * Options: we could also provide a % factor to resize on each height/width independently
|
111 | */
|
112 | function bindAutoResizeDataGrid(newSizes) {
|
113 | // if we can't find the grid to resize, return without binding anything
|
114 | if (_gridDomElm !== undefined || _gridDomElm.offset() !== undefined) {
|
115 | // -- 1st resize the datagrid size at first load (we need this because the .on event is not triggered on first load)
|
116 | // -- also we add a slight delay (in ms) so that we resize after the grid render is done
|
117 | resizeGrid(0, newSizes, null);
|
118 |
|
119 | // -- 2nd bind a trigger on the Window DOM element, so that it happens also when resizing after first load
|
120 | // -- bind auto-resize to Window object only if it exist
|
121 | $(window).on('resize.grid.' + _gridUid, function (event) {
|
122 | _self.onGridBeforeResize.notify({ grid: _grid }, event, _self);
|
123 |
|
124 | // unless the resizer is paused, let's go and resize the grid
|
125 | if (!_resizePaused) {
|
126 | // for some yet unknown reason, calling the resize twice removes any stuttering/flickering
|
127 | // when changing the height and makes it much smoother experience
|
128 | resizeGrid(0, newSizes, event);
|
129 | resizeGrid(0, newSizes, event);
|
130 | }
|
131 | });
|
132 | }
|
133 | }
|
134 |
|
135 | /**
|
136 | * Calculate the datagrid new height/width from the available space, also consider that a % factor might be applied to calculation
|
137 | */
|
138 | function calculateGridNewDimensions() {
|
139 | if (!window || _pageContainerElm === undefined || _gridDomElm === undefined || _gridDomElm.offset() === undefined) {
|
140 | return null;
|
141 | }
|
142 |
|
143 | // calculate bottom padding
|
144 | var bottomPadding = (options && options.bottomPadding !== undefined) ? options.bottomPadding : DATAGRID_BOTTOM_PADDING;
|
145 |
|
146 | var gridHeight = 0;
|
147 | var gridOffsetTop = 0;
|
148 |
|
149 | // which DOM element are we using to calculate the available size for the grid?
|
150 | // defaults to "window"
|
151 | if (options.calculateAvailableSizeBy === 'container') {
|
152 | // uses the container's height to calculate grid height without any top offset
|
153 | gridHeight = _pageContainerElm.height() || 0;
|
154 | } else {
|
155 | // uses the browser's window height with its top offset to calculate grid height
|
156 | gridHeight = window.innerHeight || 0;
|
157 | var coordOffsetTop = _gridDomElm.offset();
|
158 | gridOffsetTop = (coordOffsetTop !== undefined) ? coordOffsetTop.top : 0;
|
159 | }
|
160 |
|
161 | var availableHeight = gridHeight - gridOffsetTop - bottomPadding;
|
162 | var availableWidth = _pageContainerElm.width() || window.innerWidth || 0;
|
163 | var maxHeight = options && options.maxHeight || undefined;
|
164 | var minHeight = (options && options.minHeight !== undefined) ? options.minHeight : DATAGRID_MIN_HEIGHT;
|
165 | var maxWidth = options && options.maxWidth || undefined;
|
166 | var minWidth = (options && options.minWidth !== undefined) ? options.minWidth : DATAGRID_MIN_WIDTH;
|
167 |
|
168 | var newHeight = availableHeight;
|
169 | var newWidth = (options && options.rightPadding) ? availableWidth - options.rightPadding : availableWidth;
|
170 |
|
171 | // optionally (when defined), make sure that grid height & width are within their thresholds
|
172 | if (newHeight < minHeight) {
|
173 | newHeight = minHeight;
|
174 | }
|
175 | if (maxHeight && newHeight > maxHeight) {
|
176 | newHeight = maxHeight;
|
177 | }
|
178 | if (newWidth < minWidth) {
|
179 | newWidth = minWidth;
|
180 | }
|
181 | if (maxWidth && newWidth > maxWidth) {
|
182 | newWidth = maxWidth;
|
183 | }
|
184 |
|
185 | // return the new dimensions unless a fixed height/width was defined
|
186 | return {
|
187 | height: _fixedHeight || newHeight,
|
188 | width: _fixedWidth || newWidth
|
189 | };
|
190 | }
|
191 |
|
192 | /** Destroy function when element is destroyed */
|
193 | function destroy() {
|
194 | _self.onGridBeforeResize.unsubscribe();
|
195 | _self.onGridAfterResize.unsubscribe();
|
196 | $(window).off('resize.grid.' + _gridUid);
|
197 | }
|
198 |
|
199 | /**
|
200 | * Return the last resize dimensions used by the service
|
201 | * @return {object} last dimensions (height: number, width: number)
|
202 | */
|
203 | function getLastResizeDimensions() {
|
204 | return _lastDimensions;
|
205 | }
|
206 |
|
207 | /**
|
208 | * Provide the possibility to pause the resizer for some time, until user decides to re-enabled it later if he wish to.
|
209 | * @param {boolean} isResizePaused are we pausing the resizer?
|
210 | */
|
211 | function pauseResizer(isResizePaused) {
|
212 | _resizePaused = isResizePaused;
|
213 | }
|
214 |
|
215 | /**
|
216 | * Resize the datagrid to fit the browser height & width.
|
217 | * @param {number} delay to wait before resizing, defaults to 0 (in milliseconds)
|
218 | * @param {object} newSizes can optionally be passed (height: number, width: number)
|
219 | * @param {object} event that triggered the resize, defaults to null
|
220 | * @return If the browser supports it, we can return a Promise that would resolve with the new dimensions
|
221 | */
|
222 | function resizeGrid(delay, newSizes, event) {
|
223 | // because of the javascript async nature, we might want to delay the resize a little bit
|
224 | delay = delay || 0;
|
225 |
|
226 | // return a Promise when supported by the browser
|
227 | if (typeof Promise === 'function') {
|
228 | return new Promise(function (resolve) {
|
229 | if (delay > 0) {
|
230 | clearTimeout(_timer);
|
231 | _timer = setTimeout(function () {
|
232 | resolve(resizeGridCallback(newSizes, event));
|
233 | }, delay);
|
234 | } else {
|
235 | resolve(resizeGridCallback(newSizes, event));
|
236 | }
|
237 | });
|
238 | } else {
|
239 | // OR no return when Promise isn't supported
|
240 | if (delay > 0) {
|
241 | clearTimeout(_timer);
|
242 | _timer = setTimeout(function () {
|
243 | resizeGridCallback(newSizes, event);
|
244 | }, delay);
|
245 | } else {
|
246 | resizeGridCallback(newSizes, event);
|
247 | }
|
248 | }
|
249 | }
|
250 |
|
251 | function resizeGridCallback(newSizes, event) {
|
252 | var lastDimensions = resizeGridWithDimensions(newSizes);
|
253 | _self.onGridAfterResize.notify({ grid: _grid, dimensions: lastDimensions }, event, _self);
|
254 | return lastDimensions;
|
255 | }
|
256 |
|
257 | function resizeGridWithDimensions(newSizes) {
|
258 | // calculate the available sizes with minimum height defined as a varant
|
259 | var availableDimensions = calculateGridNewDimensions();
|
260 |
|
261 | if ((newSizes || availableDimensions) && _gridDomElm && _gridDomElm.length > 0) {
|
262 | try {
|
263 | // get the new sizes, if new sizes are passed (not 0), we will use them else use available space
|
264 | // basically if user passes 1 of the dimension, let say he passes just the height,
|
265 | // we will use the height as a fixed height but the width will be resized by it's available space
|
266 | var newHeight = (newSizes && newSizes.height) ? newSizes.height : availableDimensions.height;
|
267 | var newWidth = (newSizes && newSizes.width) ? newSizes.width : availableDimensions.width;
|
268 |
|
269 | // apply these new height/width to the datagrid
|
270 | if (!_gridOptions.autoHeight) {
|
271 | _gridDomElm.height(newHeight);
|
272 | if (options.gridContainer && options.applyResizeToContainer) {
|
273 | _gridContainerElm.height(newHeight);
|
274 | }
|
275 | }
|
276 |
|
277 | _gridDomElm.width(newWidth);
|
278 | if (options.gridContainer && options.applyResizeToContainer) {
|
279 | _gridContainerElm.width(newWidth);
|
280 | }
|
281 |
|
282 | // resize the slickgrid canvas on all browser except some IE versions
|
283 | // exclude all IE below IE11
|
284 | // IE11 wants to be a better standard (W3C) follower (finally) they even changed their appName output to also have 'Netscape'
|
285 | if (new RegExp('MSIE [6-8]').exec(navigator.userAgent) === null && _grid && _grid.resizeCanvas) {
|
286 | _grid.resizeCanvas();
|
287 | }
|
288 |
|
289 | // also call the grid auto-size columns so that it takes available when going bigger
|
290 | if (_gridOptions && _gridOptions.enableAutoSizeColumns && _grid.autosizeColumns) {
|
291 | // make sure that the grid still exist (by looking if the Grid UID is found in the DOM tree) to avoid SlickGrid error "missing stylesheet"
|
292 | if (_gridUid && ($('.' + _gridUid).length > 0 || $(_gridDomElm).length > 0)) {
|
293 | _grid.autosizeColumns();
|
294 | }
|
295 | }
|
296 |
|
297 | // keep last resized dimensions & resolve them to the Promise
|
298 | _lastDimensions = {
|
299 | height: newHeight,
|
300 | width: newWidth
|
301 | };
|
302 | } catch (e) {
|
303 | destroy();
|
304 | }
|
305 | }
|
306 |
|
307 | return _lastDimensions;
|
308 | }
|
309 |
|
310 | $.extend(this, {
|
311 | "init": init,
|
312 | "destroy": destroy,
|
313 | "pluginName": "Resizer",
|
314 | "bindAutoResizeDataGrid": bindAutoResizeDataGrid,
|
315 | "getLastResizeDimensions": getLastResizeDimensions,
|
316 | "pauseResizer": pauseResizer,
|
317 | "resizeGrid": resizeGrid,
|
318 |
|
319 | "onGridAfterResize": new Slick.Event(),
|
320 | "onGridBeforeResize": new Slick.Event()
|
321 | });
|
322 | }
|
323 | })(jQuery);
|