Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix Manual{Row,Column}Move backlight position when CSS transform is used #10485

Closed
wants to merge 4 commits into from
Closed
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
8 changes: 8 additions & 0 deletions .changelogs/10482.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
{
"issuesOrigin": "private",
"title": "Fixed table size and misalignment issue when the table runs in element that uses CSS `transform: scale` option.",
"type": "fixed",
"issueOrPR": 10482,
"breaking": false,
"framework": "none"
}
3 changes: 1 addition & 2 deletions handsontable/src/3rdparty/walkontable/src/border.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ import {
addClass,
hasClass,
removeClass,
getComputedStyle,
getTrimmingContainer,
innerWidth,
innerHeight,
Expand Down Expand Up @@ -502,7 +501,7 @@ class Border {
}
}

const style = getComputedStyle(fromTD, rootWindow);
const style = rootWindow.getComputedStyle(fromTD);

if (parseInt(style.borderTopWidth, 10) > 0) {
top += 1;
Expand Down
6 changes: 3 additions & 3 deletions handsontable/src/3rdparty/walkontable/src/table/master.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import {
getStyle,
getComputedStyle,
getTrimmingContainer,
isVisible,
} from './../../../../helpers/dom/element';
Expand Down Expand Up @@ -43,7 +42,8 @@ class MasterTable extends Table {
const trimmingOverflow = getStyle(trimmingElement, 'overflow', rootWindow);
const holderStyle = this.holder.style;
const { scrollWidth, scrollHeight } = trimmingElement;
let { width, height } = trimmingElement.getBoundingClientRect();
let width = trimmingElement.offsetWidth;
let height = trimmingElement.offsetHeight;
const overflow = ['auto', 'hidden', 'scroll'];

if (trimmingElementParent && overflow.includes(trimmingOverflow)) {
Expand All @@ -63,7 +63,7 @@ class MasterTable extends Table {
trimmingElementParent.appendChild(cloneNode);
}

const cloneHeight = parseInt(getComputedStyle(cloneNode, rootWindow).height, 10);
const cloneHeight = parseInt(rootWindow.getComputedStyle(cloneNode).height, 10);

trimmingElementParent.removeChild(cloneNode);

Expand Down
3 changes: 1 addition & 2 deletions handsontable/src/editors/baseEditor/baseEditor.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ import {
hasHorizontalScrollbar,
outerWidth,
outerHeight,
getComputedStyle,
} from '../../helpers/dom/element';

export const EDITOR_TYPE = 'base';
Expand Down Expand Up @@ -551,7 +550,7 @@ export class BaseEditor {
cellStartOffset = TD.offsetLeft + firstColumnOffset - horizontalScrollPosition;
}

const cellComputedStyle = getComputedStyle(this.TD, this.hot.rootWindow);
const cellComputedStyle = this.hot.rootWindow.getComputedStyle(this.TD);
const borderPhysicalWidthProp = this.hot.isRtl() ? 'borderRightWidth' : 'borderLeftWidth';
const inlineStartBorderCompensation = parseInt(cellComputedStyle[borderPhysicalWidthProp], 10) > 0 ? 0 : 1;
const topBorderCompensation = parseInt(cellComputedStyle.borderTopWidth, 10) > 0 ? 0 : 1;
Expand Down
5 changes: 2 additions & 3 deletions handsontable/src/editors/textEditor/textEditor.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ import EventManager from '../../eventManager';
import { isMobileBrowser, isEdge, isIOS } from '../../helpers/browser';
import {
addClass,
getComputedStyle,
setCaretPosition,
hasClass,
removeClass,
Expand Down Expand Up @@ -354,13 +353,13 @@ export class TextEditor extends BaseEditor {
this.textareaParentStyle[this.hot.isRtl() ? 'right' : 'left'] = `${start}px`;
this.showEditableElement();

const cellComputedStyle = getComputedStyle(this.TD, this.hot.rootWindow);
const cellComputedStyle = this.hot.rootWindow.getComputedStyle(this.TD);

this.TEXTAREA.style.fontSize = cellComputedStyle.fontSize;
this.TEXTAREA.style.fontFamily = cellComputedStyle.fontFamily;
this.TEXTAREA.style.backgroundColor = this.TD.style.backgroundColor;

const textareaComputedStyle = getComputedStyle(this.TEXTAREA);
const textareaComputedStyle = this.hot.rootWindow.getComputedStyle(this.TEXTAREA);

const horizontalPadding = parseInt(textareaComputedStyle.paddingLeft, 10) +
parseInt(textareaComputedStyle.paddingRight, 10);
Expand Down
16 changes: 2 additions & 14 deletions handsontable/src/helpers/dom/element.js
Original file line number Diff line number Diff line change
Expand Up @@ -528,7 +528,7 @@ export function getTrimmingContainer(base) {
return el;
}

const computedStyle = getComputedStyle(el, rootWindow);
const computedStyle = rootWindow.getComputedStyle(el);
const allowedProperties = ['scroll', 'hidden', 'auto'];
const property = computedStyle.getPropertyValue('overflow');
const propertyY = computedStyle.getPropertyValue('overflow-y');
Expand Down Expand Up @@ -576,7 +576,7 @@ export function getStyle(element, prop, rootWindow = window) {
return styleProp;
}

const computedStyle = getComputedStyle(element, rootWindow);
const computedStyle = rootWindow.getComputedStyle(element);

if (computedStyle[prop] !== '' && computedStyle[prop] !== void 0) {
return computedStyle[prop];
Expand Down Expand Up @@ -606,18 +606,6 @@ export function matchesCSSRules(element, rule) {
return result;
}

/**
* Returns a computed style object for the provided element. (Needed if style is declared in external stylesheet).
*
* @param {HTMLElement} element An element to get style from.
* @param {Window} [rootWindow] The document window owner.
* @returns {IEElementStyle|CssStyle} Elements computed style object.
*/
// eslint-disable-next-line no-restricted-globals
export function getComputedStyle(element, rootWindow = window) {
return element.currentStyle || rootWindow.getComputedStyle(element);
}

/**
* Returns the element's outer width.
*
Expand Down
20 changes: 16 additions & 4 deletions handsontable/src/helpers/dom/event.js
Original file line number Diff line number Diff line change
Expand Up @@ -46,23 +46,35 @@ export function isLeftClick(event) {
* @returns {{ x: number, y: number }}
*/
export function offsetRelativeTo(event, untilElement) {
let element = event.target;
const isRtl = window.getComputedStyle(element).direction === 'rtl'; // eslint-disable-line
const offset = {
x: event.offsetX,
x: isRtl ? element.offsetWidth - event.offsetX : event.offsetX,
y: event.offsetY,
};
let element = event.target;

if (!(untilElement instanceof HTMLElement) ||
element !== untilElement && element.contains(untilElement)) {
return offset;
}

while (element !== untilElement) {
offset.x += element.offsetLeft;
offset.y += element.offsetTop;
if (isRtl) {
offset.x += (element.offsetParent.offsetWidth - element.offsetWidth - element.offsetLeft);
} else {
offset.x += element.offsetLeft;
}

offset.y += element.offsetTop;
element = element.offsetParent;
}

if (offset.x < 0) {
offset.x = 0;
}
if (offset.y < 0) {
offset.y = 0;
}

return offset;
}
27 changes: 8 additions & 19 deletions handsontable/src/plugins/manualColumnMove/manualColumnMove.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { BasePlugin } from '../base';
import Hooks from '../../pluginHooks';
import { arrayReduce } from '../../helpers/array';
import { addClass, removeClass, offset, hasClass, outerWidth } from '../../helpers/dom/element';
import { addClass, removeClass, offset, hasClass } from '../../helpers/dom/element';
import { offsetRelativeTo } from '../../helpers/dom/event';
import { rangeEach } from '../../helpers/number';
import EventManager from '../../eventManager';
Expand Down Expand Up @@ -424,21 +424,8 @@ export class ManualColumnMove extends BasePlugin {
const tbodyOffsetLeft = wtTable.TBODY.offsetLeft;
const backlightElemMarginStart = this.backlight.getOffset().start;
const backlightElemWidth = this.backlight.getSize().width;
const mouseOffsetStart = priv.target.clickOffsetXRelativeToTable;
let rowHeaderWidth = 0;
let mouseOffsetStart = 0;

if (this.hot.isRtl()) {
const rootWindow = this.hot.rootWindow;
const containerWidth = outerWidth(this.hot.rootElement);
const gridMostRightPos = rootWindow.innerWidth - priv.rootElementOffset - containerWidth;

mouseOffsetStart = rootWindow.innerWidth - priv.target.eventPageX - gridMostRightPos -
(scrollableElement.scrollX === void 0 ? scrollStart : 0);

} else {
mouseOffsetStart = priv.target.eventPageX -
(priv.rootElementOffset - (scrollableElement.scrollX === void 0 ? scrollStart : 0));
}

if (priv.hasRowHeaders) {
rowHeaderWidth = this.hot.view._wt.wtOverlays.inlineStartOverlay.clone.wtTable.getColumnHeader(-1).offsetWidth;
Expand Down Expand Up @@ -564,7 +551,7 @@ export class ManualColumnMove extends BasePlugin {

const eventOffsetX = TD.firstChild ? offsetRelativeTo(event, TD.firstChild).x : event.offsetX;

priv.target.eventPageX = event.pageX;
priv.target.clickOffsetXRelativeToTable = offsetRelativeTo(event, this.hot.rootElement).x;
priv.hoveredColumn = coords.col;
priv.target.TD = TD;
priv.target.col = coords.col;
Expand All @@ -578,8 +565,7 @@ export class ManualColumnMove extends BasePlugin {
const topPos = wtTable.holder.scrollTop + wtTable.getColumnHeaderHeight(0) + 1;
const fixedColumnsStart = coords.col < priv.fixedColumnsStart;
const horizontalScrollPosition = this.hot.view._wt.wtOverlays.inlineStartOverlay.getOverlayOffset();
const offsetX = Math.abs(eventOffsetX - (this.hot.isRtl() ? TD.offsetWidth : 0));
const inlineOffset = this.getColumnsWidth(start, coords.col - 1) + offsetX;
const inlineOffset = this.getColumnsWidth(start, coords.col - 1) + eventOffsetX;
const inlinePos = this.getColumnsWidth(countColumnsFrom, start - 1) +
(fixedColumnsStart ? horizontalScrollPosition : 0) + inlineOffset;

Expand Down Expand Up @@ -609,7 +595,10 @@ export class ManualColumnMove extends BasePlugin {
return;
}

priv.target.eventPageX = event.pageX;
if (!event.target.contains(this.hot.rootElement)) {
priv.target.clickOffsetXRelativeToTable = offsetRelativeTo(event, this.hot.rootElement).x;
}

this.refreshPositions();
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,10 +45,10 @@ describe('manualRowMove', () => {
.simulate('mousedown')
.simulate('mouseup')
.simulate('mousedown', {
clientX: TH.offset().top + (TH.outerHeight() / 2)
clientY: TH.offset().top + (TH.outerHeight() / 2)
})
.simulate('mousemove', {
clientX: TH.offset().top + (TH.outerHeight() / 2)
clientY: TH.offset().top + (TH.outerHeight() / 2)
});

const backlight = spec().$container.find('.ht__manualRowMove--backlight');
Expand Down
23 changes: 11 additions & 12 deletions handsontable/src/plugins/manualRowMove/manualRowMove.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import { BasePlugin } from '../base';
import Hooks from '../../pluginHooks';
import { arrayReduce } from '../../helpers/array';
import { addClass, removeClass, offset, getTrimmingContainer } from '../../helpers/dom/element';
import { addClass, removeClass } from '../../helpers/dom/element';
import { offsetRelativeTo } from '../../helpers/dom/event';
import { rangeEach } from '../../helpers/number';
import EventManager from '../../eventManager';
import BacklightUI from './ui/backlight';
Expand Down Expand Up @@ -436,14 +437,7 @@ export class ManualRowMove extends BasePlugin {

const wtTable = this.hot.view._wt.wtTable;
const TD = priv.target.TD;
const rootElement = this.hot.rootElement;
const rootElementOffset = offset(rootElement);
const trimmingContainer = getTrimmingContainer(rootElement);
const tableScroll = wtTable.holder.scrollTop;
const trimmingContainerScroll = this.hot.rootWindow !== trimmingContainer ? trimmingContainer.scrollTop : 0;

const pixelsAbove = rootElementOffset.top - trimmingContainerScroll;
const pixelsRelToTableStart = priv.target.eventPageY - pixelsAbove + tableScroll;
const pixelsRelToTableStart = priv.target.clickOffsetYRelativeToTable;
const hiderHeight = wtTable.hider.offsetHeight;
const tbodyOffsetTop = wtTable.TBODY.offsetTop;
const backlightElemMarginTop = this.backlight.getOffset().top;
Expand Down Expand Up @@ -553,13 +547,15 @@ export class ManualRowMove extends BasePlugin {
controller.row = true;
priv.pressed = true;

priv.target.eventPageY = event.pageY;
const eventOffsetY = TD.firstChild ? offsetRelativeTo(event, TD.firstChild).y : event.offsetY;

priv.target.clickOffsetYRelativeToTable = offsetRelativeTo(event, this.hot.rootElement).y;
priv.target.coords = coords;
priv.target.TD = TD;
priv.rowsToMove = this.prepareRowsToMoving();

const leftPos = wtTable.holder.scrollLeft + wtViewport.getRowHeaderWidth();
const topOffset = this.getRowsHeight(start, coords.row - 1) + event.offsetY;
const topOffset = this.getRowsHeight(start, coords.row - 1) + eventOffsetY;

this.backlight.setPosition(null, leftPos);
this.backlight.setSize(wtTable.hider.offsetWidth - leftPos, this.getRowsHeight(start, end));
Expand Down Expand Up @@ -589,7 +585,10 @@ export class ManualRowMove extends BasePlugin {
return;
}

priv.target.eventPageY = event.pageY;
if (!event.target.contains(this.hot.rootElement)) {
priv.target.clickOffsetYRelativeToTable = offsetRelativeTo(event, this.hot.rootElement).y;
}

this.refreshPositions();
}

Expand Down
14 changes: 14 additions & 0 deletions visual-tests/tests/render-in-css-transform.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import { test } from '../src/test-runner';
import { helpers } from '../src/helpers';

test(__filename, async({ page }) => {
const table = page.locator(helpers.selectors.mainTable);

await table.waitFor();

await page.evaluate('document.body.style = "transform: scale(0.75);"');
await page.screenshot({ path: helpers.screenshotPath() });

await page.evaluate('document.body.style = "transform: scale(0.5);"');
await page.screenshot({ path: helpers.screenshotPath() });
});
Loading