Skip to content

Commit 873d646

Browse files
committed
feat: new DOM feature HandleElementCSSBoxFeature
BREAKING CHANGE: elementSizeFeature has been replaced with its instanciable counterpart, HandleElementCSSBoxFeature. If you need the whole document size, consider HandleHTMLDimensionsFeature.
1 parent 25ed358 commit 873d646

File tree

2 files changed

+228
-0
lines changed

2 files changed

+228
-0
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,141 @@
1+
import script from './HandleElementCSSBoxFeature.webjs';
2+
import { FeatureBuilder } from '../FeatureBuilder';
3+
import type { DOMElementRequest, PropDefinition } from '../types';
4+
import type { FeatureConstructor } from '../Feature';
5+
6+
/**
7+
* An object describing customization for the dimensions feature.
8+
*
9+
* @public
10+
*/
11+
export interface HandleElementCSSBoxDimensionsOptions {
12+
/**
13+
* The element to target. This argument is required.
14+
*/
15+
target: DOMElementRequest;
16+
/**
17+
* When no elements are found matching the target, should the script
18+
* raise an error?
19+
*
20+
* @defaultValue false
21+
*/
22+
shouldThrowWhenNotFound?: boolean;
23+
}
24+
25+
/**
26+
* @public
27+
*/
28+
export interface CSSBox {
29+
width: number;
30+
height: number;
31+
}
32+
33+
/**
34+
* Computed styles which affect the CSS Box dimensions.
35+
* See {@link https://developer.mozilla.org/docs/Web/API/Window/getComputedStyle | window.getComputedStyle()}.
36+
*
37+
* @public
38+
*/
39+
export interface CSSBoxDimensionsComputedStyle {
40+
paddingTop: number;
41+
paddingBottom: number;
42+
paddingLeft: number;
43+
paddingRight: number;
44+
borderTopWidth: number;
45+
borderBottomWidth: number;
46+
borderLeftWidth: number;
47+
borderRightWidth: number;
48+
marginTop: number;
49+
marginBottom: number;
50+
marginLeft: number;
51+
marginRight: number;
52+
}
53+
54+
/**
55+
* An object describing an element CSS Box dimensions, see
56+
* {@link https://drafts.csswg.org/css2/#box-model | CSS 2 (Box model)}.
57+
*
58+
* @remarks
59+
*
60+
* This object scalar units are CSS pixels.
61+
*
62+
* @public
63+
*/
64+
export interface ElementCSSBoxDimensions {
65+
/**
66+
* A box formed by `scrollWidth` and `scrollHeight` element properties.
67+
*
68+
* @remarks
69+
* The box is formed with all the space occupied by element's children, even
70+
* when overflowing. The element padding, border and scrollbar are not
71+
* counted. See
72+
* {@link https://drafts.csswg.org/cssom-view/#dom-element-scrollwidth},
73+
* `scrollWidth` and `scrollHeight` for a reference.
74+
*/
75+
scrollBox: CSSBox;
76+
/**
77+
* The border box as specified in the
78+
* {@link https://drafts.csswg.org/css-box-3/#valdef-box-border-box | CSS Box Model}.
79+
*
80+
* @remarks
81+
* Margin, padding and content boxes can be derived from
82+
* {@link ElementCSSBoxDimensions.computedStyle}.
83+
*/
84+
borderBox: CSSBox;
85+
/**
86+
* The computed box style. See
87+
* {@link https://developer.mozilla.org/docs/Web/API/Window/getComputedStyle | window.getComputedStyle()}.
88+
*
89+
* @remarks
90+
* Be aware that the computed vertical margins might collapse in the
91+
* viewport. See
92+
* {@link https://drafts.csswg.org/css2/#collapsing-margins | CSS 2 (collapsing margins)}
93+
*/
94+
computedStyle: CSSBoxDimensionsComputedStyle;
95+
/**
96+
* The width of the horizontal scrollbar.
97+
*
98+
* @remarks
99+
* In the CSS Box model, scrollbars are part of the content box.
100+
*/
101+
horizontalScrollbarWidth: number;
102+
/**
103+
* The width of the vertical scrollbar.
104+
*
105+
* @remarks
106+
* In the CSS Box model, scrollbars are part of the content box.
107+
*/
108+
verticalScrollbarWidth: number;
109+
}
110+
111+
const defaultOptions: HandleElementCSSBoxDimensionsOptions = {
112+
shouldThrowWhenNotFound: false
113+
} as HandleElementCSSBoxDimensionsOptions;
114+
115+
/**
116+
* This feature enables receiving the CSS Box dimensions of an element
117+
* identified by `tagName` in the `WebView` pixels unit. The first element
118+
* matching the provided tagName is retained. A new event will be triggered on
119+
* every resize.
120+
*
121+
* @public
122+
*/
123+
export const HandleElementCSSBoxFeature: FeatureConstructor<
124+
HandleElementCSSBoxDimensionsOptions,
125+
[
126+
PropDefinition<{
127+
onDOMElementCSSBoxDimensions?: (e: ElementCSSBoxDimensions) => void;
128+
}>
129+
]
130+
> = new FeatureBuilder({
131+
script,
132+
defaultOptions,
133+
className: 'HandleElementCSSBoxFeature',
134+
featureIdentifier:
135+
'org.formidable-webview/webshell.handle-element-cssbox-dimensions'
136+
})
137+
.withEventHandlerProp<
138+
ElementCSSBoxDimensions,
139+
'onDOMElementCSSBoxDimensions'
140+
>('onDOMElementCSSBoxDimensions')
141+
.build();
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
function HandleElementCSSBoxFeature(context) {
2+
var postMessage = context.postMessage;
3+
var options = context.options || {};
4+
var target = options.target;
5+
var shouldThrowWhenNotFound = options.shouldThrowWhenNotFound === true;
6+
7+
if (!target || (typeof target !== 'string' && typeof target !== 'object')) {
8+
throw new Error('Missing or wrong type for required target option');
9+
}
10+
11+
var postSize = context.makeCallbackSafe(function () {
12+
var element = context.getDOMSelection(target, false);
13+
if (element != null) {
14+
var clientRect = element.getBoundingClientRect(),
15+
styles = getComputedStyle(element),
16+
paddingLeft = context.numericFromPxString(styles.paddingLeft),
17+
paddingRight = context.numericFromPxString(styles.paddingRight),
18+
paddingTop = context.numericFromPxString(styles.paddingTop),
19+
paddingBottom = context.numericFromPxString(styles.paddingBottom),
20+
borderLeftWidth = context.numericFromPxString(styles.borderLeftWidth),
21+
borderRightWidth = context.numericFromPxString(styles.borderRightWidth),
22+
borderTopWidth = context.numericFromPxString(styles.borderTopWidth),
23+
borderBottomWidth = context.numericFromPxString(
24+
styles.borderBottomWidth
25+
),
26+
marginLeft = context.numericFromPxString(styles.marginLeft),
27+
marginRight = context.numericFromPxString(styles.marginRight),
28+
marginTop = context.numericFromPxString(styles.marginTop),
29+
marginBottom = context.numericFromPxString(styles.marginBottom),
30+
borderBoxWidth = clientRect.width,
31+
borderBoxHeight = clientRect.height,
32+
horizontalScrollbarWidth = element.offsetHeight - element.clientHeight,
33+
verticalScrollbarWidth = element.offsetWidth - element.clientWidth,
34+
scrollBoxWidth = element.scrollWidth,
35+
scrollBoxHeight = element.scrollHeight;
36+
var dimensions = {
37+
scrollBox: {
38+
width: scrollBoxWidth,
39+
height: scrollBoxHeight
40+
},
41+
borderBox: {
42+
width: borderBoxWidth,
43+
height: borderBoxHeight
44+
},
45+
computedStyle: {
46+
paddingTop: paddingTop,
47+
paddingBottom: paddingBottom,
48+
paddingLeft: paddingLeft,
49+
paddingRight: paddingRight,
50+
borderTopWidth: borderTopWidth,
51+
borderBottomWidth: borderBottomWidth,
52+
borderLeftWidth: borderLeftWidth,
53+
borderRightWidth: borderRightWidth,
54+
marginTop: marginTop,
55+
marginBottom: marginBottom,
56+
marginLeft: marginLeft,
57+
marginRight: marginRight
58+
},
59+
horizontalScrollbarWidth: horizontalScrollbarWidth,
60+
verticalScrollbarWidth: verticalScrollbarWidth
61+
};
62+
postMessage(dimensions);
63+
} else if (shouldThrowWhenNotFound) {
64+
throw new Error(
65+
"Couldn't find an element for target " + JSON.stringify(target)
66+
);
67+
}
68+
});
69+
postSize();
70+
window.addEventListener('resize', postSize);
71+
// trigger when DOM changes
72+
var MutationObserver =
73+
window['MutationObserver'] || window['WebKitMutationObserver'];
74+
if (MutationObserver) {
75+
var observer = new MutationObserver(postSize);
76+
observer.observe(document, {
77+
subtree: true,
78+
attributes: true
79+
});
80+
} else {
81+
// That is a last resort fallback for older browsers
82+
context.warn(
83+
"This browser doesn't support MutationObserver. Falling back to an interval."
84+
);
85+
setInterval(postSize, 200);
86+
}
87+
}

0 commit comments

Comments
 (0)