improve code

This commit is contained in:
Rene
2021-04-14 22:43:09 +02:00
parent ea052b3001
commit ae5d08bc37
5 changed files with 46 additions and 21 deletions
@@ -72,6 +72,7 @@ const emptyStylePropsToZero = (stlyeObj: StyleObject, baseStyle?: StyleObject) =
{ ...baseStyle } { ...baseStyle }
); );
// TODO: observer textarea attrs if textarea
// TODO: tabindex, open etc. // TODO: tabindex, open etc.
const attrs = ['id', 'class', 'style', 'open']; const attrs = ['id', 'class', 'style', 'open'];
const paddingInfoFallback: PaddingInfo = { const paddingInfoFallback: PaddingInfo = {
@@ -44,7 +44,7 @@ export interface DOMObserverOptions {
_ignoreContentChange?: DOMObserverIgnoreContentChange; _ignoreContentChange?: DOMObserverIgnoreContentChange;
} }
export interface DOMObserver { export interface DOMObserver {
_disconnect: () => void; _destroy: () => void;
_updateEventContentChange: (newEventContentChange?: DOMObserverEventContentChange) => void; _updateEventContentChange: (newEventContentChange?: DOMObserverEventContentChange) => void;
_update: () => void; _update: () => void;
} }
@@ -52,18 +52,21 @@ export interface DOMObserver {
// const styleChangingAttributes = ['id', 'class', 'style', 'open']; // const styleChangingAttributes = ['id', 'class', 'style', 'open'];
// const mutationObserverAttrsTextarea = ['wrap', 'cols', 'rows']; // const mutationObserverAttrsTextarea = ['wrap', 'cols', 'rows'];
const createEventContentChange = ( /**
target: Element, * Creates a set of helper functions to observe events of elements inside the target element.
eventContentChange: DOMObserverEventContentChange, * @param target The target element of which the children elements shall be observed. (not only direct children but also nested ones)
map: Map<Node, string>, * @param eventContentChange The event content change array. (array of tuples: selector and eventname(s))
callback: (...args: any) => any * @param callback Callback which is called if one of the elements emits the corresponding event.
) => { * @returns A object which contains a set of helper functions to destroy and update the observation of elements.
*/
const createEventContentChange = (target: Element, eventContentChange: DOMObserverEventContentChange, callback: (...args: any) => any) => {
let map: Map<Node, string> | undefined;
let eventContentChangeRef: DOMObserverEventContentChange; let eventContentChangeRef: DOMObserverEventContentChange;
const addEvent = (elm: Node, eventName: string) => { const addEvent = (elm: Node, eventName: string) => {
const entry = map.get(elm); const entry = map!.get(elm);
const newEntry = isUndefined(entry); const newEntry = isUndefined(entry);
const registerEvent = () => { const registerEvent = () => {
map.set(elm, eventName); map!.set(elm, eventName);
on(elm, eventName, callback); on(elm, eventName, callback);
}; };
@@ -75,10 +78,10 @@ const createEventContentChange = (
} }
}; };
const _destroy = () => { const _destroy = () => {
map.forEach((eventName: string, elm: Node) => { map!.forEach((eventName: string, elm: Node) => {
off(elm, eventName, callback); off(elm, eventName, callback);
}); });
map.clear(); map!.clear();
}; };
const _updateElements = (getElements?: (selector: string) => Node[]) => { const _updateElements = (getElements?: (selector: string) => Node[]) => {
if (eventContentChangeRef) { if (eventContentChangeRef) {
@@ -105,23 +108,31 @@ const createEventContentChange = (
}); });
} }
}; };
const _update = (newEventContentChange: DOMObserverEventContentChange) => { const _updateEventContentChange = (newEventContentChange: DOMObserverEventContentChange) => {
map = map || new Map<Node, string>();
eventContentChangeRef = newEventContentChange; eventContentChangeRef = newEventContentChange;
_destroy(); _destroy();
_updateElements(); _updateElements();
}; };
if (eventContentChange) { if (eventContentChange) {
_update(eventContentChange); _updateEventContentChange(eventContentChange);
} }
return { return {
_destroy, _destroy,
_updateElements, _updateElements,
_update, _updateEventContentChange,
}; };
}; };
/**
* Creates a DOM observer which observes DOM changes to either the target element or its children. (not only direct children but also nested ones)
* @param target The element which shall be observed.
* @param callback The callback which gets called if a change was detected.
* @param options The options for DOM change detection.
* @returns A object which represents the instance of the DOM observer.
*/
export const createDOMObserver = ( export const createDOMObserver = (
target: HTMLElement, target: HTMLElement,
callback: (targetChangedAttrs: string[], targetStyleChanged: boolean, contentChanged: boolean) => any, callback: (targetChangedAttrs: string[], targetStyleChanged: boolean, contentChanged: boolean) => any,
@@ -138,13 +149,12 @@ export const createDOMObserver = (
_ignoreContentChange, _ignoreContentChange,
} = options || {}; } = options || {};
const { const {
_updateElements: updateEventContentChangeElements,
_destroy: destroyEventContentChange, _destroy: destroyEventContentChange,
_update: updateEventContentChange, _updateElements: updateEventContentChangeElements,
_updateEventContentChange: updateEventContentChange,
} = createEventContentChange( } = createEventContentChange(
target, target,
_observeContent && _eventContentChange, _observeContent && _eventContentChange,
new Map<Node, string>(),
debounce(() => { debounce(() => {
if (isConnected) { if (isConnected) {
callback([], false, true); callback([], false, true);
@@ -155,7 +165,7 @@ export const createDOMObserver = (
// MutationObserver // MutationObserver
const finalAttributes = _attributes || []; const finalAttributes = _attributes || [];
const finalStyleChangingAttributes = _styleChangingAttributes || []; const finalStyleChangingAttributes = _styleChangingAttributes || [];
const observedAttributes = finalAttributes.concat(finalStyleChangingAttributes); // TODO: observer textarea attrs if textarea const observedAttributes = finalAttributes.concat(finalStyleChangingAttributes);
const observerCallback = (mutations: MutationRecord[]) => { const observerCallback = (mutations: MutationRecord[]) => {
const ignoreTargetChange = _ignoreTargetChange || noop; const ignoreTargetChange = _ignoreTargetChange || noop;
const ignoreContentChange = _ignoreContentChange || noop; const ignoreContentChange = _ignoreContentChange || noop;
@@ -199,6 +209,7 @@ export const createDOMObserver = (
}); });
if (childListChanged && !isEmptyArray(totalAddedNodes)) { if (childListChanged && !isEmptyArray(totalAddedNodes)) {
// adds / removes the new elements from the event content change
updateEventContentChangeElements((selector) => updateEventContentChangeElements((selector) =>
totalAddedNodes.reduce<Node[]>((arr, node) => { totalAddedNodes.reduce<Node[]>((arr, node) => {
push(arr, find(selector, node)); push(arr, find(selector, node));
@@ -224,7 +235,7 @@ export const createDOMObserver = (
isConnected = true; isConnected = true;
return { return {
_disconnect: () => { _destroy: () => {
if (isConnected) { if (isConnected) {
destroyEventContentChange(); destroyEventContentChange();
mutationObserver.disconnect(); mutationObserver.disconnect();
@@ -63,6 +63,13 @@ const scrollAmount = 3333333;
const directionIsRTL = (elm: HTMLElement): boolean => style(elm, 'direction') === 'rtl'; const directionIsRTL = (elm: HTMLElement): boolean => style(elm, 'direction') === 'rtl';
const domRectHasDimensions = (rect?: DOMRectReadOnly) => rect && (rect.height || rect.width); const domRectHasDimensions = (rect?: DOMRectReadOnly) => rect && (rect.height || rect.width);
/**
* Creates a size observer which observes any size, padding, margin and border changes of the target element. Depending on the options also direction and appear can be observed.
* @param target The target element which shall be observed.
* @param onSizeChangedCallback The callback which gets called after a size change was detected.
* @param options The options for size detection, whether to observe also direction and appear.
* @returns A object which represents the instance of the size observer.
*/
export const createSizeObserver = ( export const createSizeObserver = (
target: HTMLElement, target: HTMLElement,
onSizeChangedCallback: (directionIsRTLCache?: CacheValues<boolean>) => any, onSizeChangedCallback: (directionIsRTLCache?: CacheValues<boolean>) => any,
@@ -22,6 +22,12 @@ export interface TrinsicObserver {
}; };
} }
/**
* Creates a trinsic observer which observes changes to intrinsic or extrinsic sizing for the height of the target element.
* @param target The element which shall be observed.
* @param onTrinsicChangedCallback The callback which gets called after a change was detected.
* @returns A object which represents the instance of the trinsic observer.
*/
export const createTrinsicObserver = ( export const createTrinsicObserver = (
target: HTMLElement, target: HTMLElement,
onTrinsicChangedCallback: (heightIntrinsic: CacheValues<boolean>) => any onTrinsicChangedCallback: (heightIntrinsic: CacheValues<boolean>) => any
@@ -1,6 +1,6 @@
<div id="controls"> <div id="controls">
<button id="ioPolyfill">ResizeObserver polyfill</button> <button id="roPolyfill">IntersectionObserver polyfill</button>
<button id="roPolyfill">IntersectionObserver polyfill</button><br /> <button id="ioPolyfill">ResizeObserver polyfill</button><br />
<label for="display">display</label> <label for="display">display</label>
<select name="display" id="display"> <select name="display" id="display">
<option value="displayBlock">block</option> <option value="displayBlock">block</option>