gridstack
Version:
TypeScript/JS lib for dashboard layout and creation, responsive, mobile support, no external dependencies, with many wrappers (React, Angular, Vue, Ember, knockout...)
331 lines • 14.9 kB
JavaScript
"use strict";
/**
* dd-resizable.ts 12.0.0
* Copyright (c) 2021-2024 Alain Dumesny - see GridStack root license
*/
var __extends = (this && this.__extends) || (function () {
var extendStatics = function (d, b) {
extendStatics = Object.setPrototypeOf ||
({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
function (d, b) { for (var p in b) if (Object.prototype.hasOwnProperty.call(b, p)) d[p] = b[p]; };
return extendStatics(d, b);
};
return function (d, b) {
if (typeof b !== "function" && b !== null)
throw new TypeError("Class extends value " + String(b) + " is not a constructor or null");
extendStatics(d, b);
function __() { this.constructor = d; }
d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
};
})();
Object.defineProperty(exports, "__esModule", { value: true });
exports.DDResizable = void 0;
var dd_resizable_handle_1 = require("./dd-resizable-handle");
var dd_base_impl_1 = require("./dd-base-impl");
var utils_1 = require("./utils");
var dd_manager_1 = require("./dd-manager");
var DDResizable = exports.DDResizable = /** @class */ (function (_super) {
__extends(DDResizable, _super);
// have to be public else complains for HTMLElementExtendOpt ?
function DDResizable(el, option) {
if (option === void 0) { option = {}; }
var _this = _super.call(this) || this;
_this.el = el;
_this.option = option;
/** @internal */
_this.rectScale = { x: 1, y: 1 };
/** @internal */
_this._ui = function () {
var containmentEl = _this.el.parentElement;
var containmentRect = containmentEl.getBoundingClientRect();
var newRect = {
width: _this.originalRect.width,
height: _this.originalRect.height + _this.scrolled,
left: _this.originalRect.left,
top: _this.originalRect.top - _this.scrolled
};
var rect = _this.temporalRect || newRect;
return {
position: {
left: (rect.left - containmentRect.left) * _this.rectScale.x,
top: (rect.top - containmentRect.top) * _this.rectScale.y
},
size: {
width: rect.width * _this.rectScale.x,
height: rect.height * _this.rectScale.y
}
/* Gridstack ONLY needs position set above... keep around in case.
element: [this.el], // The object representing the element to be resized
helper: [], // TODO: not support yet - The object representing the helper that's being resized
originalElement: [this.el],// we don't wrap here, so simplify as this.el //The object representing the original element before it is wrapped
originalPosition: { // The position represented as { left, top } before the resizable is resized
left: this.originalRect.left - containmentRect.left,
top: this.originalRect.top - containmentRect.top
},
originalSize: { // The size represented as { width, height } before the resizable is resized
width: this.originalRect.width,
height: this.originalRect.height
}
*/
};
};
// create var event binding so we can easily remove and still look like TS methods (unlike anonymous functions)
_this._mouseOver = _this._mouseOver.bind(_this);
_this._mouseOut = _this._mouseOut.bind(_this);
_this.enable();
_this._setupAutoHide(_this.option.autoHide);
_this._setupHandlers();
return _this;
}
DDResizable.prototype.on = function (event, callback) {
_super.prototype.on.call(this, event, callback);
};
DDResizable.prototype.off = function (event) {
_super.prototype.off.call(this, event);
};
DDResizable.prototype.enable = function () {
_super.prototype.enable.call(this);
this.el.classList.remove('ui-resizable-disabled');
this._setupAutoHide(this.option.autoHide);
};
DDResizable.prototype.disable = function () {
_super.prototype.disable.call(this);
this.el.classList.add('ui-resizable-disabled');
this._setupAutoHide(false);
};
DDResizable.prototype.destroy = function () {
this._removeHandlers();
this._setupAutoHide(false);
delete this.el;
_super.prototype.destroy.call(this);
};
DDResizable.prototype.updateOption = function (opts) {
var _this = this;
var updateHandles = (opts.handles && opts.handles !== this.option.handles);
var updateAutoHide = (opts.autoHide && opts.autoHide !== this.option.autoHide);
Object.keys(opts).forEach(function (key) { return _this.option[key] = opts[key]; });
if (updateHandles) {
this._removeHandlers();
this._setupHandlers();
}
if (updateAutoHide) {
this._setupAutoHide(this.option.autoHide);
}
return this;
};
/** @internal turns auto hide on/off */
DDResizable.prototype._setupAutoHide = function (auto) {
if (auto) {
this.el.classList.add('ui-resizable-autohide');
// use mouseover and not mouseenter to get better performance and track for nested cases
this.el.addEventListener('mouseover', this._mouseOver);
this.el.addEventListener('mouseout', this._mouseOut);
}
else {
this.el.classList.remove('ui-resizable-autohide');
this.el.removeEventListener('mouseover', this._mouseOver);
this.el.removeEventListener('mouseout', this._mouseOut);
if (dd_manager_1.DDManager.overResizeElement === this) {
delete dd_manager_1.DDManager.overResizeElement;
}
}
return this;
};
/** @internal */
// eslint-disable-next-line @typescript-eslint/no-unused-vars
DDResizable.prototype._mouseOver = function (e) {
// console.log(`${count++} pre-enter ${(this.el as GridItemHTMLElement).gridstackNode._id}`)
// already over a child, ignore. Ideally we just call e.stopPropagation() but see https://github.com/gridstack/gridstack.js/issues/2018
if (dd_manager_1.DDManager.overResizeElement || dd_manager_1.DDManager.dragElement)
return;
dd_manager_1.DDManager.overResizeElement = this;
// console.log(`${count++} enter ${(this.el as GridItemHTMLElement).gridstackNode._id}`)
this.el.classList.remove('ui-resizable-autohide');
};
/** @internal */
// eslint-disable-next-line @typescript-eslint/no-unused-vars
DDResizable.prototype._mouseOut = function (e) {
// console.log(`${count++} pre-leave ${(this.el as GridItemHTMLElement).gridstackNode._id}`)
if (dd_manager_1.DDManager.overResizeElement !== this)
return;
delete dd_manager_1.DDManager.overResizeElement;
// console.log(`${count++} leave ${(this.el as GridItemHTMLElement).gridstackNode._id}`)
this.el.classList.add('ui-resizable-autohide');
};
/** @internal */
DDResizable.prototype._setupHandlers = function () {
var _this = this;
this.handlers = this.option.handles.split(',')
.map(function (dir) { return dir.trim(); })
.map(function (dir) { return new dd_resizable_handle_1.DDResizableHandle(_this.el, dir, {
start: function (event) {
_this._resizeStart(event);
},
stop: function (event) {
_this._resizeStop(event);
},
move: function (event) {
_this._resizing(event, dir);
}
}); });
return this;
};
/** @internal */
DDResizable.prototype._resizeStart = function (event) {
this.sizeToContent = utils_1.Utils.shouldSizeToContent(this.el.gridstackNode, true); // strick true only and not number
this.originalRect = this.el.getBoundingClientRect();
this.scrollEl = utils_1.Utils.getScrollElement(this.el);
this.scrollY = this.scrollEl.scrollTop;
this.scrolled = 0;
this.startEvent = event;
this._setupHelper();
this._applyChange();
var ev = utils_1.Utils.initEvent(event, { type: 'resizestart', target: this.el });
if (this.option.start) {
this.option.start(ev, this._ui());
}
this.el.classList.add('ui-resizable-resizing');
this.triggerEvent('resizestart', ev);
return this;
};
/** @internal */
DDResizable.prototype._resizing = function (event, dir) {
this.scrolled = this.scrollEl.scrollTop - this.scrollY;
this.temporalRect = this._getChange(event, dir);
this._applyChange();
var ev = utils_1.Utils.initEvent(event, { type: 'resize', target: this.el });
if (this.option.resize) {
this.option.resize(ev, this._ui());
}
this.triggerEvent('resize', ev);
return this;
};
/** @internal */
DDResizable.prototype._resizeStop = function (event) {
var ev = utils_1.Utils.initEvent(event, { type: 'resizestop', target: this.el });
// Remove style attr now, so the stop handler can rebuild style attrs
this._cleanHelper();
if (this.option.stop) {
this.option.stop(ev); // Note: ui() not used by gridstack so don't pass
}
this.el.classList.remove('ui-resizable-resizing');
this.triggerEvent('resizestop', ev);
delete this.startEvent;
delete this.originalRect;
delete this.temporalRect;
delete this.scrollY;
delete this.scrolled;
return this;
};
/** @internal */
DDResizable.prototype._setupHelper = function () {
var _this = this;
this.elOriginStyleVal = DDResizable._originStyleProp.map(function (prop) { return _this.el.style[prop]; });
this.parentOriginStylePosition = this.el.parentElement.style.position;
var parent = this.el.parentElement;
var dragTransform = utils_1.Utils.getValuesFromTransformedElement(parent);
this.rectScale = {
x: dragTransform.xScale,
y: dragTransform.yScale
};
if (getComputedStyle(this.el.parentElement).position.match(/static/)) {
this.el.parentElement.style.position = 'relative';
}
this.el.style.position = 'absolute';
this.el.style.opacity = '0.8';
return this;
};
/** @internal */
DDResizable.prototype._cleanHelper = function () {
var _this = this;
DDResizable._originStyleProp.forEach(function (prop, i) {
_this.el.style[prop] = _this.elOriginStyleVal[i] || null;
});
this.el.parentElement.style.position = this.parentOriginStylePosition || null;
return this;
};
/** @internal */
DDResizable.prototype._getChange = function (event, dir) {
var oEvent = this.startEvent;
var newRect = {
width: this.originalRect.width,
height: this.originalRect.height + this.scrolled,
left: this.originalRect.left,
top: this.originalRect.top - this.scrolled
};
var offsetX = event.clientX - oEvent.clientX;
var offsetY = this.sizeToContent ? 0 : event.clientY - oEvent.clientY; // prevent vert resize
var moveLeft;
var moveUp;
if (dir.indexOf('e') > -1) {
newRect.width += offsetX;
}
else if (dir.indexOf('w') > -1) {
newRect.width -= offsetX;
newRect.left += offsetX;
moveLeft = true;
}
if (dir.indexOf('s') > -1) {
newRect.height += offsetY;
}
else if (dir.indexOf('n') > -1) {
newRect.height -= offsetY;
newRect.top += offsetY;
moveUp = true;
}
var constrain = this._constrainSize(newRect.width, newRect.height, moveLeft, moveUp);
if (Math.round(newRect.width) !== Math.round(constrain.width)) { // round to ignore slight round-off errors
if (dir.indexOf('w') > -1) {
newRect.left += newRect.width - constrain.width;
}
newRect.width = constrain.width;
}
if (Math.round(newRect.height) !== Math.round(constrain.height)) {
if (dir.indexOf('n') > -1) {
newRect.top += newRect.height - constrain.height;
}
newRect.height = constrain.height;
}
return newRect;
};
/** @internal constrain the size to the set min/max values */
DDResizable.prototype._constrainSize = function (oWidth, oHeight, moveLeft, moveUp) {
var o = this.option;
var maxWidth = (moveLeft ? o.maxWidthMoveLeft : o.maxWidth) || Number.MAX_SAFE_INTEGER;
var minWidth = o.minWidth / this.rectScale.x || oWidth;
var maxHeight = (moveUp ? o.maxHeightMoveUp : o.maxHeight) || Number.MAX_SAFE_INTEGER;
var minHeight = o.minHeight / this.rectScale.y || oHeight;
var width = Math.min(maxWidth, Math.max(minWidth, oWidth));
var height = Math.min(maxHeight, Math.max(minHeight, oHeight));
return { width: width, height: height };
};
/** @internal */
DDResizable.prototype._applyChange = function () {
var _a;
var _this = this;
var containmentRect = { left: 0, top: 0, width: 0, height: 0 };
if (this.el.style.position === 'absolute') {
var containmentEl = this.el.parentElement;
var left = (_a = containmentEl.getBoundingClientRect(), _a.left), top_1 = _a.top;
containmentRect = { left: left, top: top_1, width: 0, height: 0 };
}
if (!this.temporalRect)
return this;
Object.keys(this.temporalRect).forEach(function (key) {
var value = _this.temporalRect[key];
var scaleReciprocal = key === 'width' || key === 'left' ? _this.rectScale.x : key === 'height' || key === 'top' ? _this.rectScale.y : 1;
_this.el.style[key] = (value - containmentRect[key]) * scaleReciprocal + 'px';
});
return this;
};
/** @internal */
DDResizable.prototype._removeHandlers = function () {
this.handlers.forEach(function (handle) { return handle.destroy(); });
delete this.handlers;
return this;
};
/** @internal */
DDResizable._originStyleProp = ['width', 'height', 'position', 'left', 'top', 'opacity', 'zIndex'];
return DDResizable;
}(dd_base_impl_1.DDBaseImplement));
//# sourceMappingURL=dd-resizable.js.map