Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions src/gridstack-dd.ts
Original file line number Diff line number Diff line change
Expand Up @@ -422,6 +422,8 @@ GridStack.prototype._prepareDragDropByNode = function(node: GridStackNode): Grid
if (node._lastTriedX === x && node._lastTriedY === y) return;
} else if (event.type === 'resize') {
if (x < 0) return;
// Scrolling page if needed
Utils.updateScrollResize(event as MouseEvent, el, cellHeight);
w = Math.round(ui.size.width / cellWidth);
h = Math.round(ui.size.height / cellHeight);
if (w === node.w && h === node.h) return;
Expand Down
25 changes: 22 additions & 3 deletions src/h5/dd-resizable.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
import { DDResizableHandle } from './dd-resizable-handle';
import { DDBaseImplement, HTMLElementExtendOpt } from './dd-base-impl';
import { DDUtils } from './dd-utils';
import { Utils } from '../utils';
import { DDUIData, Rect, Size } from '../types';

// TODO: merge with DDDragOpt
Expand Down Expand Up @@ -37,6 +38,12 @@ export class DDResizable extends DDBaseImplement implements HTMLElementExtendOpt
/** @internal */
private temporalRect: Rect;
/** @internal */
private scrollY: number;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

do we need that in JQ version as well ?

/** @internal */
private scrolled: number;
/** @internal */
private scrollEl: HTMLElement;
/** @internal */
private startEvent: MouseEvent;
/** @internal value saved in the same order as _originStyleProp[] */
private elOriginStyleVal: string[];
Expand Down Expand Up @@ -152,6 +159,8 @@ export class DDResizable extends DDBaseImplement implements HTMLElementExtendOpt
/** @internal */
private _resizeStart(event: MouseEvent): DDResizable {
this.originalRect = this.el.getBoundingClientRect();
this.scrollEl = Utils.getScrollParent(this.el);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

reset this in destroy()

this.scrollY = this.scrollEl.scrollTop;
this.startEvent = event;
this._setupHelper();
this._applyChange();
Expand All @@ -166,6 +175,7 @@ export class DDResizable extends DDBaseImplement implements HTMLElementExtendOpt

/** @internal */
private _resizing(event: MouseEvent, dir: string): DDResizable {
this.scrolled = this.scrollEl.scrollTop - this.scrollY;
this.temporalRect = this._getChange(event, dir);
this._applyChange();
const ev = DDUtils.initEvent<MouseEvent>(event, { type: 'resize', target: this.el });
Expand All @@ -188,6 +198,8 @@ export class DDResizable extends DDBaseImplement implements HTMLElementExtendOpt
delete this.startEvent;
delete this.originalRect;
delete this.temporalRect;
delete this.scrollY;
delete this.scrolled;
return this;
}

Expand Down Expand Up @@ -218,10 +230,11 @@ export class DDResizable extends DDBaseImplement implements HTMLElementExtendOpt
const oEvent = this.startEvent;
const newRect = { // Note: originalRect is a complex object, not a simple Rect, so copy out.
width: this.originalRect.width,
height: this.originalRect.height,
height: this.originalRect.height + this.scrolled,
left: this.originalRect.left,
top: this.originalRect.top
top: this.originalRect.top - this.scrolled
};

const offsetH = event.clientX - oEvent.clientX;
const offsetV = event.clientY - oEvent.clientY;

Expand Down Expand Up @@ -293,7 +306,13 @@ export class DDResizable extends DDBaseImplement implements HTMLElementExtendOpt
private _ui = (): DDUIData => {
const containmentEl = this.el.parentElement;
const containmentRect = containmentEl.getBoundingClientRect();
const rect = this.temporalRect || this.originalRect;
const newRect = { // Note: originalRect is a complex object, not a simple Rect, so copy out.
width: this.originalRect.width,
height: this.originalRect.height + this.scrolled,
left: this.originalRect.left,
top: this.originalRect.top - this.scrolled
};
const rect = this.temporalRect || newRect;
return {
position: {
left: rect.left - containmentRect.left,
Expand Down
40 changes: 33 additions & 7 deletions src/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -280,15 +280,15 @@ export class Utils {

/** @internal */
static getScrollParent(el: HTMLElement): HTMLElement {
let returnEl;
if (el === null) {
returnEl = null;
} else if (el.scrollHeight > el.clientHeight) {
returnEl = el;
if (el === null) return document.documentElement;
const style = getComputedStyle(el);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is getComputedStyle() better than checking the simple el.scrollHeight > el.clientHeight because you want to remember what parent MIGHT scroll later ? (in case you don't already scroll ?) - please add comment.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, also with el.scrollHeight > el.clientHeight sometimes is selecting a non scrollable parent.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

interesting. didn't think that would be possible... but I realize the call you have return the first that could scroll which is safer anyway... but always return the doc as least, which might not scroll so it should return NULL and have that be handled ideally...

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Exactly, the best option would be returning NULL when there isn't a scrollable parent but in this case, we need to prevent gridstack to continue growing.

I was using the example float.html to check my changes. I think in this example the ideal would be that gridstack stops growing when there is no more page because the element that is scrolling is the document not the container that wraps gridstack.

Copy link
Contributor Author

@hbcarlos hbcarlos Jan 3, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

And we need to manually prevent gridstack to grow because:
In my case, I have two screens one on top of another and I have the browser with the webpage with gridstack on the screen above.
Captura de pantalla 2021-01-03 a las 8 24 12

When I try to resize or drag and drop an item to the bottom my mouse continue on the screen bellow so gridstack still growing even when the page can't scroll. Once I stop there is no scrollable parent so the documentElement is resized to wrap everything.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

well we have a maxRow to prevent grid from growing past that size, but you are saying that if none of the parents can scroll (by default divs will auto scroll unless you have overflow: hidden or something) then we should stop growing so we don't clip, which makes sense... Looks like you are checking for overflow | overflow-y for and auto or scroll
you don't need 2 screens to test this. browser smaller than full screen will do that too...

if you want to take a stab at it that would be great. _prepareDragDropByNode() should cache if we can not v-scroll and prevent move/size past the max somehow.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'll take a look at this over the week (probably weekend, I'm quite busy right now) :)

const overflowRegex = /(auto|scroll)/;

if (overflowRegex.test(style.overflow + style.overflowY)) {
return el;
} else {
returnEl = this.getScrollParent(el.parentElement);
return this.getScrollParent(el.parentElement);
}
return returnEl;
}

/** @internal */
Expand Down Expand Up @@ -327,5 +327,31 @@ export class Utils {
}
}
}

/**
* @internal
*
* Function used to scroll the page.
*
* @param event `MouseEvent` that triggers the resize
* @param el `HTMLElement` that's being resized
* @param distance Distance to scroll
*/
static updateScrollResize(event: MouseEvent, el: HTMLElement, distance: number): void {
const scrollEl = this.getScrollParent(el);
const height = scrollEl.clientHeight;

const top = event.clientY < distance;
const bottom = event.clientY > height - distance;

if (top) {
// This also can be done with a timeout to keep scrolling while the mouse is
// in the scrolling zone. (will have smoother behavior)
scrollEl.scrollBy({ behavior: 'smooth', top: event.clientY - distance});

} else if (bottom) {
scrollEl.scrollBy({ behavior: 'smooth', top: distance - (height - event.clientY)});
}
}
}