diff --git a/src/gridstack.ts b/src/gridstack.ts
index f298c4958..2bc195d46 100644
--- a/src/gridstack.ts
+++ b/src/gridstack.ts
@@ -55,10 +55,10 @@ export class GridStack {
* multiple grids initialization at once.
* @param options grid options (optional)
* @param elOrString element to convert to a grid (default to '.grid-stack' class selector)
- *
+ *
* @example
* const grid = GridStack.init();
- *
+ *
* Note: the HTMLElement (of type GridHTMLElement) will store a `gridstack: GridStack` value that can be retrieve later
* const grid = document.querySelector('.grid-stack').gridstack;
*/
@@ -83,7 +83,7 @@ export class GridStack {
* Will initialize a list of elements (given a selector) and return an array of grids.
* @param options grid options (optional)
* @param selector element to convert to grids (default to '.grid-stack' class selector)
- *
+ *
* @example
* const grids = GridStack.initAll();
* grids.forEach(...)
@@ -113,6 +113,7 @@ export class GridStack {
public opts: GridstackOptions;
/** @internal */
+ private placeholder: HTMLElement;
private $el: JQuery; // TODO: legacy code
private $placeholder: JQuery;
private oneColumnMode: boolean;
@@ -128,11 +129,9 @@ export class GridStack {
* @param el
* @param opts
*/
- public constructor(el: GridStackElement, opts: GridstackOptions) {
- opts = opts || {};
-
+ public constructor(el: GridHTMLElement, opts: GridstackOptions = { }) {
this.$el = $(el); // legacy code
- this.el = this.$el.get(0); // exposed HTML element to the user
+ this.el = el; // exposed HTML element to the user
obsoleteOpts(opts, 'width', 'column', 'v0.5.3');
obsoleteOpts(opts, 'height', 'maxRow', 'v0.5.3');
@@ -150,13 +149,14 @@ export class GridStack {
opts.minRow = opts.maxRow = opts.row;
delete opts.row;
}
- const rowAttr = parseInt(this.$el.attr('data-gs-row'));
+
+ const rowAttr = Utils.toNumber(el.getAttribute('data-gs-row'));
// elements attributes override any passed options (like CSS style) - merge the two together
const defaults: GridstackOptions = {
- column: parseInt(this.$el.attr('data-gs-column')) || 12,
- minRow: rowAttr ? rowAttr : parseInt(this.$el.attr('data-gs-min-row')) || 0,
- maxRow: rowAttr ? rowAttr : parseInt(this.$el.attr('data-gs-max-row')) || 0,
+ column: Utils.toNumber(el.getAttribute('data-gs-column')) || 12,
+ minRow: rowAttr ? rowAttr : Utils.toNumber(el.getAttribute('data-gs-min-row')) || 0,
+ maxRow: rowAttr ? rowAttr : Utils.toNumber(el.getAttribute('data-gs-max-row')) || 0,
itemClass: 'grid-stack-item',
placeholderClass: 'grid-stack-placeholder',
placeholderText: '',
@@ -169,7 +169,7 @@ export class GridStack {
float: false,
staticGrid: false,
_class: 'grid-stack-instance-' + (Math.random() * 10000).toFixed(0),
- animate: Boolean(this.$el.attr('data-gs-animate')) || false,
+ animate: Utils.toBool(el.getAttribute('data-gs-animate')) || false,
alwaysShowResizeHandle: opts.alwaysShowResizeHandle || false,
resizable: Utils.defaults(opts.resizable || {}, {
autoHide: !(opts.alwaysShowResizeHandle || false),
@@ -195,6 +195,7 @@ export class GridStack {
oneColumnModeDomSort: opts.oneColumnModeDomSort,
ddPlugin: null
};
+
this.opts = Utils.defaults(opts, defaults);
if (this.opts.ddPlugin === false) {
@@ -207,18 +208,21 @@ export class GridStack {
if (this.opts.rtl === 'auto') {
this.opts.rtl = this.$el.css('direction') === 'rtl';
+ this.opts.rtl = el.style.direction === 'rtl';
}
if (this.opts.rtl) {
this.$el.addClass('grid-stack-rtl');
+ this.el.classList.add('grid-stack-rtl');
}
this.opts._isNested = this.$el.closest('.' + opts.itemClass).length > 0;
if (this.opts._isNested) {
this.$el.addClass('grid-stack-nested');
+ this.el.classList.add('grid-stack-nested');
}
- this.isAutoCellHeight = (this.opts.cellHeight === 'auto');
+ this.isAutoCellHeight = this.opts.cellHeight === 'auto';
if (this.isAutoCellHeight) {
// make the cell square initially
this.cellHeight(this.cellWidth(), true);
@@ -228,6 +232,7 @@ export class GridStack {
this.verticalMargin(this.opts.verticalMargin, true);
this.$el.addClass(this.opts._class);
+ this.el.classList.add(this.opts._class);
this._setStaticClass();
@@ -246,12 +251,12 @@ export class GridStack {
.attr('data-gs-y', n.y)
.attr('data-gs-width', n.width)
.attr('data-gs-height', n.height);
- }
- });
- this._updateStyles(maxHeight + 10);
- },
- this.opts.float,
- this.opts.maxRow);
+ }
+ });
+ this._updateStyles(maxHeight + 10);
+ },
+ this.opts.float,
+ this.opts.maxRow);
if (this.opts.auto) {
const elements = [];
@@ -276,9 +281,19 @@ export class GridStack {
'
' +
'
' + this.opts.placeholderText + '
').hide();
+ let placeholderChild = document.createElement('div');
+ placeholderChild.className = 'placeholder-content';
+
+ let placeholder = document.createElement('div');
+ placeholder.classList.add(this.opts.placeholderClass, this.opts.itemClass);
+ placeholder.style.display = 'none'
+ placeholder.appendChild(placeholderChild);
+
+ this.placeholder = placeholder;
+
this._updateContainerHeight();
- $(window).resize(this.onResizeHandler);
+ $(window).resize(this.onResizeHandler.bind(this));
this.onResizeHandler();
if (!this.opts.staticGrid && typeof this.opts.removable === 'string') {
@@ -293,7 +308,7 @@ export class GridStack {
if (!node || node._grid !== this) {
return;
}
- el.data('inTrashZone', true);
+ el.dataset.inTrashZone = true;
this._setupRemovingTimeout(el);
})
.on(trashZone, 'dropout', (event, ui) => {
@@ -302,7 +317,7 @@ export class GridStack {
if (!node || node._grid !== this) {
return;
}
- el.data('inTrashZone', false);
+ el.dataset.inTrashZone = false;
this._clearRemovingTimeout(el);
});
}
@@ -328,7 +343,7 @@ export class GridStack {
public addWidget(el: GridStackElement, options? : GridstackWidget): HTMLElement;
/**
- * Creates new widget and returns it.
+ * Creates new widget and returns it.
* Legacy: Spelled out version of the widgets options, recommend use new version instead.
*
* @example
@@ -349,28 +364,35 @@ export class GridStack {
*/
public addWidget(el: GridStackElement, x? : number | GridstackWidget, y?: number, width?: number, height?: number, autoPosition?: boolean,
minWidth?: number, maxWidth?: number, minHeight?: number, maxHeight?: number, id?: numberOrString): HTMLElement {
- // new way of calling with an object - make sure all items have been properly initialized
- if (x === undefined || typeof x === 'object') {
- // Tempting to initialize the passed in opt with default and valid values, but this break knockout demos
- // as the actual value are filled in when _prepareElement() calls el.attr('data-gs-xyz) before adding the node.
- // opt = this.engine._prepareNode(opt);
- x = x || {};
- } else {
- // old legacy way of calling with items spelled out - call us back with single object instead (so we can properly initialized values)
- return this.addWidget(el, {x: x, y: y, width: width, height: height, autoPosition: autoPosition,
- minWidth: minWidth, maxWidth: maxWidth, minHeight: minHeight, maxHeight: maxHeight, id: id});
- }
+ // new way of calling with an object - make sure all items have been properly initialized
+ if (x === undefined || typeof x === 'object') {
+ // Tempting to initialize the passed in opt with default and valid values, but this break knockout demos
+ // as the actual value are filled in when _prepareElement() calls el.attr('data-gs-xyz) before adding the node.
+ // opt = this.engine._prepareNode(opt);
+ x = (x || { }) as GridstackWidget;
+ } else {
+ // old legacy way of calling with items spelled out - call us back with single object instead (so we can properly initialized values)
+ return this.addWidget(el, { x, y, width, height, autoPosition, minWidth, maxWidth, minHeight, maxHeight, id });
+ }
- const $el = $(el);
- this._writeAttr(el, x);
- this.$el.append(el);
- return this.makeWidget(el);
+ if (typeof el === 'string') {
+ let doc = document.implementation.createHTMLDocument();
+ doc.body.innerHTML = el;
+ el = doc.body.children[0] as HTMLElement;
}
+ // const $el = $(el);
+ this._writeAttr(el, x);
+ this.$el.append(el);
+ this.el.appendChild(el);
+
+ return this.makeWidget(el);
+ }
+
/**
* Initializes batch updates. You will see no changes until `commit()` method is called.
*/
- public batchUpdate() {
+ public batchUpdate(): void {
this.engine.batchUpdate();
}
@@ -382,10 +404,16 @@ export class GridStack {
return this.opts.cellHeight as number;
}
// compute the height taking margin into account (each row has margin other than last one)
- const o = this.$el.children('.' + this.opts.itemClass).first();
- const height = parseInt(o.attr('data-gs-height'));
- const verticalMargin = this.opts.verticalMargin as number;
- return Math.round((o.outerHeight() - (height - 1) * verticalMargin) / height);
+ // const o = this.$el.children('.' + this.opts.itemClass).first();
+ // const height = parseInt(o.attr('data-gs-height'));
+ // const verticalMargin = this.opts.verticalMargin as number;
+ // return Math.round((o.outerHeight() - (height - 1) * verticalMargin) / height);
+
+ let el = this.el.querySelector(`.${this.opts.itemClass}`) as HTMLElement;
+ let height = Utils.toNumber(el.getAttribute('data-gs-height'));
+ let verticalMargin = this.opts.verticalMargin as number;
+
+ return Math.round((el.offsetHeight - (height - 1) * verticalMargin) / height);
}
/**
@@ -399,7 +427,7 @@ export class GridStack {
* @example
* grid.cellHeight(grid.cellWidth() * 1.2);
*/
- public cellHeight(val: numberOrString, noUpdate?: boolean) {
+ public cellHeight(val: numberOrString, noUpdate?: boolean): void {
const heightData = Utils.parseHeight(val);
if (this.opts.cellHeightUnit === heightData.unit && this.opts.cellHeight === heightData.height) {
return ;
@@ -423,7 +451,7 @@ export class GridStack {
/**
* Finishes batch updates. Updates DOM nodes. You must call it after batchUpdate.
*/
- public commit() {
+ public commit(): void {
this.engine.commit();
this._triggerRemoveEvent();
this._triggerAddEvent();
@@ -431,7 +459,7 @@ export class GridStack {
};
/** re-layout grid items to reclaim any empty space */
- public compact() {
+ public compact(): void {
this.engine.compact();
this._triggerChangeEvent();
}
@@ -442,7 +470,7 @@ export class GridStack {
* Requires `gridstack-extra.css` or `gridstack-extra.min.css` for [1-11],
* else you will need to generate correct CSS (see https://github.com/gridstack/gridstack.js#change-grid-columns)
* @param column - Integer > 0 (default 12).
- * @param doNotPropagate if true existing widgets will not be updated (optional)
+ * @param doNotPropagate if true existing widgets will not be updated (optional)
*/
public column(column: number, doNotPropagate?: boolean) {
if (this.opts.column === column) { return; }
@@ -489,7 +517,7 @@ export class GridStack {
* Destroys a grid instance.
* @param detachGrid if false nodes and grid will not be removed from the DOM (Optional. Default true).
*/
- public destroy(detachGrid?: boolean) {
+ public destroy(detachGrid?: boolean): void {
$(window).off('resize', this.onResizeHandler);
this.disable();
if (detachGrid !== undefined && !detachGrid) {
@@ -510,7 +538,7 @@ export class GridStack {
* grid.enableMove(false);
* grid.enableResize(false);
*/
- public disable() {
+ public disable(): void {
this.enableMove(false);
this.enableResize(false);
this.$el.trigger('disable');
@@ -522,7 +550,7 @@ export class GridStack {
* grid.enableMove(true);
* grid.enableResize(true);
*/
- public enable() {
+ public enable(): void {
this.enableMove(true);
this.enableResize(true);
this.$el.trigger('enable');
@@ -535,10 +563,11 @@ export class GridStack {
* @param includeNewWidgets will force new widgets to be draggable as per
* doEnable`s value by changing the disableDrag grid option (default: true).
*/
- public enableMove(doEnable: boolean, includeNewWidgets = true) {
+ public enableMove(doEnable: boolean, includeNewWidgets = true): void {
this.$el.children('.' + this.opts.itemClass).each((index, el) => {
this.movable(el, doEnable);
- })
+ });
+
if (includeNewWidgets) {
this.opts.disableDrag = !doEnable;
}
@@ -566,7 +595,7 @@ export class GridStack {
this.engine.float = val;
this._triggerChangeEvent();
}
-
+
/**
* get the current float mode
*/
@@ -643,11 +672,16 @@ export class GridStack {
* grid.makeWidget('gsi-1');
*/
public makeWidget(el: GridStackElement): HTMLElement {
+ if (typeof el === 'string') {
+ el = document.querySelector(`#${el}`) as HTMLElement;
+ }
+
this._prepareElement(el, true);
this._updateContainerHeight();
this._triggerAddEvent();
this._triggerChangeEvent();
- return $(el).get(0);
+
+ return el;
}
/**
@@ -754,7 +788,7 @@ export class GridStack {
* @param x new position x. If value is null or undefined it will be ignored.
* @param y new position y. If value is null or undefined it will be ignored.
*/
- public move(el: GridStackElement, x: number, y: number) {
+ public move(el: GridStackElement, x: number, y: number): void {
this._updateElement(el, (el, node) => {
x = (x !== null && x !== undefined) ? x : node.x;
y = (y !== null && y !== undefined) ? y : node.y;
@@ -769,16 +803,16 @@ export class GridStack {
* @param name of the event (see possible values) or list of names space separated
* @param callback function called with event and optional second/third param
* (see README documentation for each signature).
- *
+ *
* @example
* grid.on('added', function(e, items) { log('added ', items)} );
* or
* grid.on('added removed change', function(e, items) { log(e.type, items)} );
- *
+ *
* Note: in some cases it is the same as calling native handler and parsing the event.
* grid.el.addEventListener('added', function(event) { log('added ', event.detail)} );
*/
- public on(eventName: GridStackEvent, callback: (event: CustomEvent, arg2?: GridStackNode[] | Object, arg3?: Object) => void) {
+ public on(eventName: GridStackEvent, callback: (event: CustomEvent, arg2?: GridStackNode[] | Record, arg3?: Record) => void) {
if (eventName === 'change' || eventName === 'added' || eventName === 'removed' || eventName === 'enable' || eventName === 'disable') {
// native CustomEvent handlers - cash the generic handlers so we can remove
const noData = (eventName === 'enable' || eventName === 'disable');
@@ -852,7 +886,7 @@ export class GridStack {
* @param width new dimensions width. If value is null or undefined it will be ignored.
* @param height new dimensions height. If value is null or undefined it will be ignored.
*/
- public resize(el: GridStackElement, width: number, height: number) {
+ public resize(el: GridStackElement, width: number, height: number): void {
this._updateElement(el, (el, node) => {
width = (width !== null && width !== undefined) ? width : node.width;
height = (height !== null && height !== undefined) ? height : node.height;
@@ -884,11 +918,13 @@ export class GridStack {
* Toggle the grid animation state. Toggles the `grid-stack-animate` class.
* @param doAnimate if true the grid will animate.
*/
- public setAnimation(doAnimate: boolean) {
+ public setAnimation(doAnimate: boolean): void {
if (doAnimate) {
this.$el.addClass('grid-stack-animate');
+ this.el.classList.add('grid-stack-animate');
} else {
this.$el.removeClass('grid-stack-animate');
+ this.el.classList.remove('grid-stack-animate');
}
}
@@ -896,8 +932,8 @@ export class GridStack {
* Toggle the grid static state. Also toggle the grid-stack-static class.
* @param staticValue if true the grid become static.
*/
- public setStatic(staticValue: boolean) {
- this.opts.staticGrid = (staticValue === true);
+ public setStatic(staticValue: boolean): void {
+ this.opts.staticGrid = staticValue === true;
this.enableMove(!staticValue);
this.enableResize(!staticValue);
this._setStaticClass();
@@ -911,7 +947,7 @@ export class GridStack {
* @param width new dimensions width. If value is null or undefined it will be ignored.
* @param height new dimensions height. If value is null or undefined it will be ignored.
*/
- public update(el: GridStackElement, x: number, y: number, width: number, height: number) {
+ public update(el: GridStackElement, x: number, y: number, width: number, height: number): void {
this._updateElement(el, (el, node) => {
x = (x !== null && x !== undefined) ? x : node.x;
y = (y !== null && y !== undefined) ? y : node.y;
@@ -928,7 +964,7 @@ export class GridStack {
* @param value new vertical margin value
* @param noUpdate (optional) if true, styles will not be updated
*/
- public verticalMargin(value: numberOrString, noUpdate?: boolean) {
+ public verticalMargin(value: numberOrString, noUpdate?: boolean): void {
const heightData = Utils.parseHeight(value);
if (this.opts.verticalMarginUnit === heightData.unit && this.opts.maxRow === heightData.height) {
@@ -969,7 +1005,7 @@ export class GridStack {
return this.engine.canBePlacedWithRespectToHeight(node);
}
- private _triggerChangeEvent(skipLayoutChange?: boolean) {
+ private _triggerChangeEvent(skipLayoutChange?: boolean): void {
if (this.engine.batchMode) { return; }
const elements = this.engine.getDirtyNodes(true); // verify they really changed
if (elements && elements.length) {
@@ -1060,7 +1096,7 @@ export class GridStack {
}
if (maxHeight > this._styles._max) {
- for (var i = this._styles._max; i < maxHeight; ++i) {
+ for (let i = this._styles._max; i < maxHeight; ++i) {
Utils.insertCSSRule(this._styles,
prefix + '[data-gs-height="' + (i + 1) + '"]',
'height: ' + getHeight(i + 1, i) + ';',
@@ -1141,8 +1177,6 @@ export class GridStack {
* prepares the element for drag&drop
**/
private _prepareElementsByNode(el, node) {
- el = $(el)
-
// variables used/cashed between the 3 start/move/end methods, in addition to node passed above
let cellWidth;
let cellFullHeight; // internal cellHeight + v-margin
@@ -1151,20 +1185,33 @@ export class GridStack {
/** called when item starts moving/resizing */
const onStartMoving = function(event, ui) {
self.$el.append(self.$placeholder);
+ self.el.append(self.placeholder);
self.engine.cleanNodes();
self.engine.beginUpdate(node);
cellWidth = self.cellWidth();
const strictCellHeight = self.getCellHeight(); // heigh without v-margin
// compute height with v-margin (Note: we add 1 margin as last row is missing it)
cellFullHeight = (self.$el.height() + self.getVerticalMargin()) / parseInt(self.$el.attr('data-gs-current-row'));
- const o = $(this);
+
+ let { target } = event;
+ // const o = $(this);
+
+
self.$placeholder
- .attr('data-gs-x', o.attr('data-gs-x'))
- .attr('data-gs-y', o.attr('data-gs-y'))
- .attr('data-gs-width', o.attr('data-gs-width'))
- .attr('data-gs-height', o.attr('data-gs-height'))
+ .attr('data-gs-x', target.getAttribute('data-gs-x'))
+ .attr('data-gs-y', target.getAttribute('data-gs-y'))
+ .attr('data-gs-width', target.getAttribute('data-gs-width'))
+ .attr('data-gs-height', target.getAttribute('data-gs-height'))
.show();
+
+ self.placeholder.setAttribute('data-gs-x', target.getAttribute('data-gs-x'));
+ self.placeholder.setAttribute('data-gs-y', target.getAttribute('data-gs-y'));
+ self.placeholder.setAttribute('data-gs-width', target.getAttribute('data-gs-width'));
+ self.placeholder.setAttribute('data-gs-height', target.getAttribute('data-gs-height'));
+ self.placeholder.style.display = '';
+
node.el = self.$placeholder.get(0);
+ // node.el = self.placeholder;
node._beforeDragX = node.x;
node._beforeDragY = node.y;
node._prevYPix = ui.position.top;
@@ -1176,7 +1223,14 @@ export class GridStack {
self.dd.resizable(el, 'option', 'minHeight', (strictCellHeight * minHeight) + (minHeight - 1) * verticalMargin);
if (event.type === 'resizestart') {
- o.find('.grid-stack-item').trigger('resizestart');
+ let itemElement = target.querySelector('.grid-stack-item');
+ if (itemElement) {
+ let ev = document.createEvent('HTMLEvents');
+ ev.initEvent('resizestart', true, false);
+ target.querySelector('.grid-stack-item').dispatchEvent(event);
+ }
+
+ // o.find('.grid-stack-item').trigger('resizestart');
}
}
@@ -1190,8 +1244,8 @@ export class GridStack {
if (event.type === 'drag') {
const distance = ui.position.top - node._prevYPix;
node._prevYPix = ui.position.top;
- Utils.updateScrollPosition(el[0], ui, distance);
- if (el.data('inTrashZone') || x < 0 || x >= self.engine.column || y < 0 ||
+ Utils.updateScrollPosition(el, ui, distance);
+ if (el.dataset.inTrashZone || x < 0 || x >= self.engine.column || y < 0 ||
(!self.engine.float && y > self.engine.getRow())) {
if (!node._temporaryRemoved) {
if (self.opts.removable === true) {
@@ -1252,60 +1306,80 @@ export class GridStack {
}
/** called when the item stops moving/resizing */
- const onEndMoving = function(event, ui) {
- const o = $(this);
- if (!o.get(0).gridstackNode) {
+ const onEndMoving = function(event): void {
+ let { target } = event;
+ // const o = $(this);
+ if (!target.gridstackNode) {
return;
}
// const forceNotify = false; what is the point of calling 'change' event with no data, when the 'removed' event is already called ?
self.$placeholder.detach();
- node.el = o.get(0);
+ node.el = target; // o.get(0);
self.$placeholder.hide();
if (node._isAboutToRemove) {
// forceNotify = true;
- const gridToNotify = el.get(0).gridstackNode._grid;
+ const gridToNotify = el.gridstackNode._grid;
gridToNotify._triggerRemoveEvent();
- delete el.get(0).gridstackNode;
+ delete el.gridstackNode;
el.remove();
} else {
self._clearRemovingTimeout(el);
if (!node._temporaryRemoved) {
- Utils.removePositioningStyles(o);
- o
- .attr('data-gs-x', node.x)
- .attr('data-gs-y', node.y)
- .attr('data-gs-width', node.width)
- .attr('data-gs-height', node.height);
+ Utils.removePositioningStyles(target);
+ target.setAttribute('data-gs-x', node.x);
+ target.setAttribute('data-gs-y', node.y);
+ target.setAttribute('data-gs-width', node.width);
+ target.setAttribute('data-gs-height', node.height);
+ // o
+ // .attr('data-gs-x', node.x)
+ // .attr('data-gs-y', node.y)
+ // .attr('data-gs-width', node.width)
+ // .attr('data-gs-height', node.height);
} else {
- Utils.removePositioningStyles(o);
- o
- .attr('data-gs-x', node._beforeDragX)
- .attr('data-gs-y', node._beforeDragY)
- .attr('data-gs-width', node.width)
- .attr('data-gs-height', node.height);
+ // Utils.removePositioningStyles(o);
+ // o
+ // .attr('data-gs-x', node._beforeDragX)
+ // .attr('data-gs-y', node._beforeDragY)
+ // .attr('data-gs-width', node.width)
+ // .attr('data-gs-height', node.height);
+ Utils.removePositioningStyles(target);
+ target.setAttribute('data-gs-x', node._beforeDragX);
+ target.setAttribute('data-gs-y', node._beforeDragY);
+ target.setAttribute('data-gs-width', node.width);
+ target.setAttribute('data-gs-height', node.height);
+
node.x = node._beforeDragX;
node.y = node._beforeDragY;
node._temporaryRemoved = false;
self.engine.addNode(node);
}
}
+
self._updateContainerHeight();
self._triggerChangeEvent();
self.engine.endUpdate();
- const nestedGrids = o.find('.grid-stack');
+ // const nestedGrids = o.find('.grid-stack');
+ let nestedGrids = target.querySelectorAll('.grid-stack');
if (nestedGrids.length && event.type === 'resizestop') {
nestedGrids.each((index, el) => {
el.gridstack.onResizeHandler();
});
- o.find('.grid-stack-item').trigger('resizestop');
- o.find('.grid-stack-item').trigger('gsresizestop');
+
+ self._triggerNativeEvent(target, '.grid-stack-item', 'resizestop');
+ self._triggerNativeEvent(target, '.grid-stack-item', 'gsresizestop');
+
+ // o.find('.grid-stack-item').trigger('resizestop');
+ // o.find('.grid-stack-item').trigger('gsresizestop');
}
+
if (event.type === 'resizestop') {
- self.$el.trigger('gsresizestop', o);
+ self._triggerNativeEvent(self.el, null, 'gsresizestop');
+
+ // self.$el.trigger('gsresizestop', o);
}
}
@@ -1324,67 +1398,97 @@ export class GridStack {
if (node.noMove || this.opts.disableDrag || this.opts.staticGrid) {
this.dd.draggable(el, 'disable');
}
+
if (node.noResize || this.opts.disableResize || this.opts.staticGrid) {
this.dd.resizable(el, 'disable');
}
+
this._writeAttr(el, node);
}
- private _prepareElement(el, triggerAddEvent?: boolean) {
+ _triggerNativeEvent(el: HTMLElement, selector: string, eventName: string): void {
+ let elements = el.querySelectorAll(selector);
+ if (elements.length) {
+ let event = document.createEvent('HTMLEvents');
+ event.initEvent(eventName, true, false);
+
+ Array.from(elements).map(x => x.dispatchEvent(event));
+ }
+ }
+
+ private _prepareElement(el: GridItemHTMLElement, triggerAddEvent?: boolean): void {
triggerAddEvent = triggerAddEvent !== undefined ? triggerAddEvent : false;
- el = $(el);
+ // el = $(el);
- el.addClass(this.opts.itemClass);
- let node = this._readAttr(el, {el: el.get(0), _grid: this});
+ el.classList.add(this.opts.itemClass);
+ // TODO: What was being passed in as widget here?
+ // let node = this._readAttr(el, { el, _grid: this });
+ let node = this._readAttr(el, { });
node = this.engine.addNode(node, triggerAddEvent);
- el.get(0).gridstackNode = node;
+ el.gridstackNode = node;
this._prepareElementsByNode(el, node);
}
/** call to write any default attributes back to element */
- private _writeAttr(el, node) {
- const $el = $(el);
- node = node || {}
- // Note: passing null removes the attr in jquery
- if (node.x !== undefined) { el.attr('data-gs-x', node.x); }
- if (node.y !== undefined) { el.attr('data-gs-y', node.y); }
- if (node.width !== undefined) { el.attr('data-gs-width', node.width); }
- if (node.height !== undefined) { el.attr('data-gs-height', node.height); }
- if (node.autoPosition !== undefined) { el.attr('data-gs-auto-position', node.autoPosition ? true : null); }
- if (node.minWidth !== undefined) { el.attr('data-gs-min-width', node.minWidth); }
- if (node.maxWidth !== undefined) { el.attr('data-gs-max-width', node.maxWidth); }
- if (node.minHeight !== undefined) { el.attr('data-gs-min-height', node.minHeight); }
- if (node.maxHeight !== undefined) { el.attr('data-gs-max-height', node.maxHeight); }
- if (node.noResize !== undefined) { el.attr('data-gs-no-resize', node.noResize ? true : null); }
- if (node.noMove !== undefined) { el.attr('data-gs-no-move', node.noMove ? true : null); }
- if (node.locked !== undefined) { el.attr('data-gs-locked', node.locked ? true : null); }
- if (node.resizeHandles !== undefined) { el.attr('data-gs-resize-handles', node.resizeHandles); }
- if (node.id !== undefined) { el.attr('data-gs-id', node.id); }
+ private _writeAttr(el: HTMLElement, node: GridstackWidget = { }): void {
+ if (node.x !== undefined) { el.setAttribute('data-gs-x', `${node.x}`); }
+ if (node.y !== undefined) { el.setAttribute('data-gs-y', `${node.y}`); }
+ if (node.width !== undefined) { el.setAttribute('data-gs-width', `${node.width}`); }
+ if (node.height !== undefined) { el.setAttribute('data-gs-height', `${node.height}`); }
+ if (node.autoPosition) {
+ el.setAttribute('data-gs-auto-position', 'true');
+ } else {
+ el.removeAttribute('data-gs-auto-position');
+ }
+
+ if (node.minWidth !== undefined) { el.setAttribute('data-gs-min-width', `${node.minWidth}`); }
+ if (node.maxWidth !== undefined) { el.setAttribute('data-gs-max-width', `${node.maxWidth}`); }
+ if (node.minHeight !== undefined) { el.setAttribute('data-gs-min-height', `${node.minHeight}`); }
+ if (node.maxHeight !== undefined) { el.setAttribute('data-gs-max-height', `${node.maxHeight}`); }
+ if (node.noResize) {
+ el.setAttribute('data-gs-no-resize', 'true');
+ } else {
+ el.removeAttribute('data-gs-no-resize');
+ }
+
+ if (node.noMove) {
+ el.setAttribute('data-gs-no-move', 'true');
+ } else {
+ el.removeAttribute('data-gs-no-move');
+ }
+
+ if (node.locked) {
+ el.setAttribute('data-gs-locked', 'true');
+ } else {
+ el.removeAttribute('data-gs-locked');
+ }
+
+ if (node.resizeHandles !== undefined) { el.setAttribute('data-gs-resize-handles', node.resizeHandles); }
+ if (node.id !== undefined) { el.setAttribute('data-gs-id', `${node.id}`); }
}
/** call to write any default attributes back to element */
- private _readAttr(el, node) {
- const $el = $(el);
- node = node || {};
- node.x = el.attr('data-gs-x');
- node.y = el.attr('data-gs-y');
- node.width = el.attr('data-gs-width');
- node.height = el.attr('data-gs-height');
- node.autoPosition = Utils.toBool(el.attr('data-gs-auto-position'));
- node.maxWidth = el.attr('data-gs-max-width');
- node.minWidth = el.attr('data-gs-min-width');
- node.maxHeight = el.attr('data-gs-max-height');
- node.minHeight = el.attr('data-gs-min-height');
- node.noResize = Utils.toBool(el.attr('data-gs-no-resize'));
- node.noMove = Utils.toBool(el.attr('data-gs-no-move'));
- node.locked = Utils.toBool(el.attr('data-gs-locked'));
- node.resizeHandles = el.attr('data-gs-resize-handles');
- node.id = el.attr('data-gs-id');
+ private _readAttr(el: HTMLElement, node: GridstackWidget = { }): GridstackWidget {
+ node.x = Utils.toNumber(el.getAttribute('data-gs-x'));
+ node.y = Utils.toNumber(el.getAttribute('data-gs-y'));
+ node.width = Utils.toNumber(el.getAttribute('data-gs-width'));
+ node.height = Utils.toNumber(el.getAttribute('data-gs-height'));
+ node.maxWidth = Utils.toNumber(el.getAttribute('data-gs-max-width'));
+ node.minWidth = Utils.toNumber(el.getAttribute('data-gs-min-width'));
+ node.maxHeight = Utils.toNumber(el.getAttribute('data-gs-max-height'));
+ node.minHeight = Utils.toNumber(el.getAttribute('data-gs-min-height'));
+ node.autoPosition = Utils.toBool(el.getAttribute('data-gs-auto-position'));
+ node.noResize = Utils.toBool(el.getAttribute('data-gs-no-resize'));
+ node.noMove = Utils.toBool(el.getAttribute('data-gs-no-move'));
+ node.locked = Utils.toBool(el.getAttribute('data-gs-locked'));
+ node.resizeHandles = el.getAttribute('data-gs-resize-handles');
+ node.id = el.getAttribute('data-gs-id');
+
return node;
}
- private _updateElement(el, callback) {
+ private _updateElement(el, callback): void {
el = $(el).first();
const node = el.gridstackNode;
if (!node) { return; }
diff --git a/src/utils.ts b/src/utils.ts
index 2ea0300f1..bf9e95fe3 100644
--- a/src/utils.ts
+++ b/src/utils.ts
@@ -49,10 +49,10 @@ export function obsoleteAttr(el: HTMLElement, oldName: string, newName: string,
/**
* Utility methods
*/
-export namespace Utils {
+export class Utils {
/** returns true if a and b overlap */
- export function isIntercepted(a: GridstackWidget, b: GridstackWidget): boolean {
+ static isIntercepted(a: GridstackWidget, b: GridstackWidget): boolean {
return !(a.x + a.width <= b.x || b.x + b.width <= a.x || a.y + a.height <= b.y || b.y + b.height <= a.y);
}
@@ -62,19 +62,19 @@ export namespace Utils {
* @param dir 1 for asc, -1 for desc (optional)
* @param width width of the grid. If undefined the width will be calculated automatically (optional).
**/
- export function sort(nodes: GridStackNode[], dir?: number, column?: number): GridStackNode[] {
+ static sort(nodes: GridStackNode[], dir?: number, column?: number): GridStackNode[] {
if (!column) {
const widths = nodes.map(function (node) { return node.x + node.width; });
column = Math.max.apply(Math, widths);
}
if (dir === -1)
- return sortBy(nodes, (n) => -(n.x + n.y * column));
+ return this.sortBy(nodes, (n) => -(n.x + n.y * column));
else
- return sortBy(nodes, (n) => (n.x + n.y * column));
+ return this.sortBy(nodes, (n) => (n.x + n.y * column));
}
- export function createStylesheet(id: string, parent?: HTMLElement): CSSStyleSheet {
+ static createStylesheet(id: string, parent?: HTMLElement): CSSStyleSheet {
const style: HTMLStyleElement = document.createElement('style');
style.setAttribute('type', 'text/css');
style.setAttribute('data-gs-style-id', id);
@@ -88,13 +88,13 @@ export namespace Utils {
return style.sheet as CSSStyleSheet;
}
- export function removeStylesheet(id: string) {
+ static removeStylesheet(id: string) {
const el = document.querySelector('STYLE[data-gs-style-id=' + id + ']');
if (!el) return;
el.parentNode.removeChild(el);
}
- export function insertCSSRule(sheet: CSSStyleSheet, selector: string, rules: string, index: number) {
+ static insertCSSRule(sheet: CSSStyleSheet, selector: string, rules: string, index: number) {
if (typeof sheet.insertRule === 'function') {
sheet.insertRule(selector + '{' + rules + '}', index);
} else if (typeof sheet.addRule === 'function') {
@@ -102,7 +102,7 @@ export namespace Utils {
}
}
- export function toBool(v: any): boolean {
+ static toBool(v: any): boolean {
if (typeof v === 'boolean') {
return v;
}
@@ -113,7 +113,13 @@ export namespace Utils {
return Boolean(v);
}
- export function parseHeight(val: numberOrString) {
+ static toNumber(value: null | string): number | null {
+ return value === null || value.length === 0
+ ? null
+ : Number(value);
+ }
+
+ static parseHeight(val: numberOrString) {
let height: number;
let heightUnit = 'px';
if (typeof val === 'string') {
@@ -129,7 +135,7 @@ export namespace Utils {
return { height: height, unit: heightUnit }
}
- export function without(array, item) {
+ static without(array, item) {
const index = array.indexOf(item);
if (index !== -1) {
@@ -140,7 +146,7 @@ export namespace Utils {
return array;
}
- export function sortBy(array, getter) {
+ static sortBy(array, getter) {
return array.slice(0).sort(function (left, right) {
const valueLeft = getter(left);
const valueRight = getter(right);
@@ -153,11 +159,11 @@ export namespace Utils {
});
}
- export function defaults(target, arg1) {
+ static defaults(target, arg1) {
const sources = Array.prototype.slice.call(arguments, 1);
sources.forEach(function (source) {
- for (var prop in source) {
+ for (let prop in source) {
if (source.hasOwnProperty(prop) && (!target.hasOwnProperty(prop) || target[prop] === undefined)) {
target[prop] = source[prop];
}
@@ -167,11 +173,11 @@ export namespace Utils {
return target;
}
- export function clone(target) {
+ static clone(target) {
return {...target}; // was $.extend({}, target)
}
- export function throttle(callback, delay) {
+ static throttle(callback, delay) {
let isWaiting = false;
return function () {
@@ -183,8 +189,8 @@ export namespace Utils {
}
}
- export function removePositioningStyles(el) {
- const style = el[0].style;
+ static removePositioningStyles(el) {
+ const style = el.style;
if (style.position) {
style.removeProperty('position');
}
@@ -202,19 +208,19 @@ export namespace Utils {
}
}
- export function getScrollParent(el) {
+ static getScrollParent(el) {
let returnEl;
if (el === null) {
returnEl = null;
} else if (el.scrollHeight > el.clientHeight) {
returnEl = el;
} else {
- returnEl = getScrollParent(el.parentNode);
+ returnEl = this.getScrollParent(el.parentNode);
}
return returnEl;
}
- export function updateScrollPosition(el, ui, distance) {
+ static updateScrollPosition(el, ui, distance) {
// is widget in view?
const rect = el.getBoundingClientRect();
const innerHeightOrClientHeight = (window.innerHeight || document.documentElement.clientHeight);
@@ -226,7 +232,7 @@ export namespace Utils {
// to get entire widget on screen
const offsetDiffDown = rect.bottom - innerHeightOrClientHeight;
const offsetDiffUp = rect.top;
- const scrollEl = getScrollParent(el);
+ const scrollEl = this.getScrollParent(el);
if (scrollEl !== null) {
const prevScroll = scrollEl.scrollTop;
if (rect.top < 0 && distance < 0) {
@@ -249,4 +255,4 @@ export namespace Utils {
}
}
}
-}
\ No newline at end of file
+}