Files
blockly/core/utils/style.ts
dependabot[bot] 2546b01d70 chore(deps): Bump prettier from 2.8.8 to 3.0.0 (#7322)
* chore(deps): Bump prettier from 2.8.8 to 3.0.0

Bumps [prettier](https://github.com/prettier/prettier) from 2.8.8 to 3.0.0.
- [Release notes](https://github.com/prettier/prettier/releases)
- [Changelog](https://github.com/prettier/prettier/blob/main/CHANGELOG.md)
- [Commits](https://github.com/prettier/prettier/compare/2.8.8...3.0.0)

---
updated-dependencies:
- dependency-name: prettier
  dependency-type: direct:development
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>

* chore: Reformat using Prettier v3.0 defaults

The main change is to add trailing commas to the last line of
block-formatted function calls.

---------

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Christopher Allen <cpcallen+git@google.com>
2023-07-25 14:56:10 +00:00

221 lines
7.8 KiB
TypeScript

/**
* @license
* Copyright 2019 Google LLC
* SPDX-License-Identifier: Apache-2.0
*/
import * as goog from '../../closure/goog/goog.js';
goog.declareModuleId('Blockly.utils.style');
import {Coordinate} from './coordinate.js';
import {Rect} from './rect.js';
import {Size} from './size.js';
/**
* Gets the height and width of an element.
* Similar to Closure's goog.style.getSize
*
* @param element Element to get size of.
* @returns Object with width/height properties.
*/
export function getSize(element: Element): Size {
return TEST_ONLY.getSizeInternal(element);
}
/**
* Private version of getSize for stubbing in tests.
*/
function getSizeInternal(element: Element): Size {
if (getComputedStyle(element, 'display') !== 'none') {
return getSizeWithDisplay(element);
}
// Evaluate size with a temporary element.
// AnyDuringMigration because: Property 'style' does not exist on type
// 'Element'.
const style = (element as AnyDuringMigration).style;
const originalDisplay = style.display;
const originalVisibility = style.visibility;
const originalPosition = style.position;
style.visibility = 'hidden';
style.position = 'absolute';
style.display = 'inline';
const offsetWidth = (element as HTMLElement).offsetWidth;
const offsetHeight = (element as HTMLElement).offsetHeight;
style.display = originalDisplay;
style.position = originalPosition;
style.visibility = originalVisibility;
return new Size(offsetWidth, offsetHeight);
}
/**
* Gets the height and width of an element when the display is not none.
*
* @param element Element to get size of.
* @returns Object with width/height properties.
*/
function getSizeWithDisplay(element: Element): Size {
const offsetWidth = (element as HTMLElement).offsetWidth;
const offsetHeight = (element as HTMLElement).offsetHeight;
return new Size(offsetWidth, offsetHeight);
}
/**
* Retrieves a computed style value of a node. It returns empty string
* if the property requested is an SVG one and it has not been
* explicitly set (firefox and webkit).
*
* Copied from Closure's goog.style.getComputedStyle
*
* @param element Element to get style of.
* @param property Property to get (camel-case).
* @returns Style value.
*/
export function getComputedStyle(element: Element, property: string): string {
const styles = window.getComputedStyle(element);
// element.style[..] is undefined for browser specific styles
// as 'filter'.
return (
(styles as AnyDuringMigration)[property] ||
styles.getPropertyValue(property)
);
}
/**
* Returns a Coordinate object relative to the top-left of the HTML document.
* Similar to Closure's goog.style.getPageOffset
*
* @param el Element to get the page offset for.
* @returns The page offset.
*/
export function getPageOffset(el: Element): Coordinate {
const pos = new Coordinate(0, 0);
const box = el.getBoundingClientRect();
const documentElement = document.documentElement;
// Must add the scroll coordinates in to get the absolute page offset
// of element since getBoundingClientRect returns relative coordinates to
// the viewport.
const scrollCoord = new Coordinate(
window.pageXOffset || documentElement.scrollLeft,
window.pageYOffset || documentElement.scrollTop,
);
pos.x = box.left + scrollCoord.x;
pos.y = box.top + scrollCoord.y;
return pos;
}
/**
* Calculates the viewport coordinates relative to the document.
* Similar to Closure's goog.style.getViewportPageOffset
*
* @returns The page offset of the viewport.
*/
export function getViewportPageOffset(): Coordinate {
const body = document.body;
const documentElement = document.documentElement;
const scrollLeft = body.scrollLeft || documentElement.scrollLeft;
const scrollTop = body.scrollTop || documentElement.scrollTop;
return new Coordinate(scrollLeft, scrollTop);
}
/**
* Gets the computed border widths (on all sides) in pixels
* Copied from Closure's goog.style.getBorderBox
*
* @param element The element to get the border widths for.
* @returns The computed border widths.
*/
export function getBorderBox(element: Element): Rect {
const left = parseFloat(getComputedStyle(element, 'borderLeftWidth'));
const right = parseFloat(getComputedStyle(element, 'borderRightWidth'));
const top = parseFloat(getComputedStyle(element, 'borderTopWidth'));
const bottom = parseFloat(getComputedStyle(element, 'borderBottomWidth'));
return new Rect(top, bottom, left, right);
}
/**
* Changes the scroll position of `container` with the minimum amount so
* that the content and the borders of the given `element` become visible.
* If the element is bigger than the container, its top left corner will be
* aligned as close to the container's top left corner as possible.
* Copied from Closure's goog.style.scrollIntoContainerView
*
* @param element The element to make visible.
* @param container The container to scroll. If not set, then the document
* scroll element will be used.
* @param opt_center Whether to center the element in the container.
* Defaults to false.
*/
export function scrollIntoContainerView(
element: Element,
container: Element,
opt_center?: boolean,
) {
const offset = getContainerOffsetToScrollInto(element, container, opt_center);
container.scrollLeft = offset.x;
container.scrollTop = offset.y;
}
/**
* Calculate the scroll position of `container` with the minimum amount so
* that the content and the borders of the given `element` become visible.
* If the element is bigger than the container, its top left corner will be
* aligned as close to the container's top left corner as possible.
* Copied from Closure's goog.style.getContainerOffsetToScrollInto
*
* @param element The element to make visible.
* @param container The container to scroll. If not set, then the document
* scroll element will be used.
* @param opt_center Whether to center the element in the container.
* Defaults to false.
* @returns The new scroll position of the container.
*/
export function getContainerOffsetToScrollInto(
element: Element,
container: Element,
opt_center?: boolean,
): Coordinate {
// Absolute position of the element's border's top left corner.
const elementPos = getPageOffset(element);
// Absolute position of the container's border's top left corner.
const containerPos = getPageOffset(container);
const containerBorder = getBorderBox(container);
// Relative pos. of the element's border box to the container's content box.
const relX = elementPos.x - containerPos.x - containerBorder.left;
const relY = elementPos.y - containerPos.y - containerBorder.top;
// How much the element can move in the container, i.e. the difference between
// the element's bottom-right-most and top-left-most position where it's
// fully visible.
const elementSize = getSizeWithDisplay(element);
const spaceX = container.clientWidth - elementSize.width;
const spaceY = container.clientHeight - elementSize.height;
let scrollLeft = container.scrollLeft;
let scrollTop = container.scrollTop;
if (opt_center) {
// All browsers round non-integer scroll positions down.
scrollLeft += relX - spaceX / 2;
scrollTop += relY - spaceY / 2;
} else {
// This formula was designed to give the correct scroll values in the
// following cases:
// - element is higher than container (spaceY < 0) => scroll down by relY
// - element is not higher that container (spaceY >= 0):
// - it is above container (relY < 0) => scroll up by abs(relY)
// - it is below container (relY > spaceY) => scroll down by relY - spaceY
// - it is in the container => don't scroll
scrollLeft += Math.min(relX, Math.max(relX - spaceX, 0));
scrollTop += Math.min(relY, Math.max(relY - spaceY, 0));
}
return new Coordinate(scrollLeft, scrollTop);
}
export const TEST_ONLY = {
getSizeInternal,
};