mirror of
https://github.com/tenrok/OverlayScrollbars.git
synced 2026-06-10 04:52:29 +03:00
improve domobserver code and tests
This commit is contained in:
@@ -28,7 +28,7 @@ interface DOMObserverOptionsBase {
|
||||
}
|
||||
|
||||
interface DOMContentObserverOptions extends DOMObserverOptionsBase {
|
||||
_eventContentChange?: DOMObserverEventContentChange; // [selector, eventname | function returning eventname]
|
||||
_eventContentChange?: DOMObserverEventContentChange; // [selector, eventname(s) | function returning eventname(s)] -> eventnames divided by whitespaces
|
||||
_nestedTargetSelector?: string;
|
||||
_ignoreContentChange?: DOMObserverIgnoreContentChange; // function which will prevent marking certain dom changes as content change if it returns true
|
||||
_ignoreNestedTargetChange?: DOMObserverIgnoreTargetChange; // a function which will prevent marking certain attributes as changed on nested targets if it returns true
|
||||
@@ -50,7 +50,7 @@ interface DOMContentObserver extends DOMObserverBase {
|
||||
interface DOMTargetObserver extends DOMObserverBase {}
|
||||
|
||||
export type DOMObserverEventContentChange =
|
||||
| Array<[StringNullUndefined, ((elms: Node[]) => string) | StringNullUndefined] | null | undefined>
|
||||
| Array<[StringNullUndefined, ((elms: Node[]) => StringNullUndefined) | StringNullUndefined] | null | undefined>
|
||||
| false
|
||||
| null
|
||||
| undefined;
|
||||
@@ -90,22 +90,6 @@ export type DOMObserver<ContentObserver extends boolean> = ContentObserver exten
|
||||
const createEventContentChange = (target: Element, eventContentChange: DOMObserverEventContentChange, callback: (...args: any) => any) => {
|
||||
let map: Map<Node, string> | undefined;
|
||||
let eventContentChangeRef: DOMObserverEventContentChange;
|
||||
const addEvent = (elm: Node, eventName: string) => {
|
||||
if (map) {
|
||||
const entry = map.get(elm);
|
||||
const newEntry = isUndefined(entry);
|
||||
const changedExistingEntry = !newEntry && eventName !== entry;
|
||||
const register = newEntry || changedExistingEntry;
|
||||
|
||||
if (changedExistingEntry) {
|
||||
off(elm, entry!, callback);
|
||||
}
|
||||
if (register) {
|
||||
map.set(elm, eventName);
|
||||
on(elm, eventName, callback);
|
||||
}
|
||||
}
|
||||
};
|
||||
const _destroy = () => {
|
||||
if (map) {
|
||||
map.forEach((eventName: string, elm: Node) => off(elm, eventName, callback));
|
||||
@@ -113,28 +97,37 @@ const createEventContentChange = (target: Element, eventContentChange: DOMObserv
|
||||
}
|
||||
};
|
||||
const _updateElements = (getElements?: (selector: string) => Node[]) => {
|
||||
if (eventContentChangeRef) {
|
||||
if (map && eventContentChangeRef) {
|
||||
const eventElmList = eventContentChangeRef.reduce<Array<[Node[], string]>>((arr, item) => {
|
||||
if (item) {
|
||||
const selector = item[0];
|
||||
const eventName = item[1];
|
||||
const elements = eventName && selector && (getElements ? getElements(selector) : find(selector, target));
|
||||
const eventNames = item[1];
|
||||
const elements = eventNames && selector && (getElements ? getElements(selector) : find(selector, target));
|
||||
const parsedEventNames = isFunction(eventNames) ? eventNames(elements) : eventNames;
|
||||
|
||||
if (elements) {
|
||||
push(arr, [elements, isFunction(eventName) ? eventName(elements) : eventName!], true);
|
||||
if (elements && elements.length && parsedEventNames && isString(parsedEventNames)) {
|
||||
push(arr, [elements, parsedEventNames.trim()], true);
|
||||
}
|
||||
}
|
||||
return arr;
|
||||
}, []);
|
||||
|
||||
each(eventElmList, (item) => {
|
||||
const elements = item[0];
|
||||
const eventName = item[1];
|
||||
each(eventElmList, (item) =>
|
||||
each(item[0], (elm) => {
|
||||
const eventNames = item[1];
|
||||
const registredEventNames = map!.get(elm);
|
||||
const newEntry = isUndefined(registredEventNames);
|
||||
const changingExistingEntry = !newEntry && eventNames !== registredEventNames;
|
||||
const finalEventNames = changingExistingEntry ? `${registredEventNames} ${eventNames}` : eventNames;
|
||||
|
||||
each(elements, (elm) => {
|
||||
addEvent(elm, eventName);
|
||||
});
|
||||
});
|
||||
if (changingExistingEntry) {
|
||||
off(elm, registredEventNames!, callback);
|
||||
}
|
||||
|
||||
map!.set(elm, finalEventNames);
|
||||
on(elm, finalEventNames, callback);
|
||||
})
|
||||
);
|
||||
}
|
||||
};
|
||||
const _updateEventContentChange = (newEventContentChange: DOMObserverEventContentChange) => {
|
||||
|
||||
@@ -12,28 +12,28 @@ type RunEachItem = ((...args: any) => any | any[]) | null | undefined;
|
||||
*/
|
||||
export function each<T>(
|
||||
array: Array<T> | ReadonlyArray<T>,
|
||||
callback: (value: T, indexOrKey: number, source: Array<T>) => boolean | void
|
||||
callback: (value: T, indexOrKey: number, source: Array<T>) => boolean | unknown
|
||||
): Array<T> | ReadonlyArray<T>;
|
||||
export function each<T>(
|
||||
array: Array<T> | ReadonlyArray<T> | null | undefined,
|
||||
callback: (value: T, indexOrKey: number, source: Array<T>) => boolean | void
|
||||
callback: (value: T, indexOrKey: number, source: Array<T>) => boolean | unknown
|
||||
): Array<T> | ReadonlyArray<T> | null | undefined;
|
||||
export function each<T>(
|
||||
arrayLikeObject: ArrayLike<T>,
|
||||
callback: (value: T, indexOrKey: number, source: ArrayLike<T>) => boolean | void
|
||||
callback: (value: T, indexOrKey: number, source: ArrayLike<T>) => boolean | unknown
|
||||
): ArrayLike<T>;
|
||||
export function each<T>(
|
||||
arrayLikeObject: ArrayLike<T> | null | undefined,
|
||||
callback: (value: T, indexOrKey: number, source: ArrayLike<T>) => boolean | void
|
||||
callback: (value: T, indexOrKey: number, source: ArrayLike<T>) => boolean | unknown
|
||||
): ArrayLike<T> | null | undefined;
|
||||
export function each(obj: PlainObject, callback: (value: any, indexOrKey: string, source: PlainObject) => boolean | void): PlainObject;
|
||||
export function each(obj: PlainObject, callback: (value: any, indexOrKey: string, source: PlainObject) => boolean | unknown): PlainObject;
|
||||
export function each(
|
||||
obj: PlainObject | null | undefined,
|
||||
callback: (value: any, indexOrKey: string, source: PlainObject) => boolean | void
|
||||
callback: (value: any, indexOrKey: string, source: PlainObject) => boolean | unknown
|
||||
): PlainObject | null | undefined;
|
||||
export function each<T>(
|
||||
source: ArrayLike<T> | PlainObject | null | undefined,
|
||||
callback: (value: T, indexOrKey: any, source: any) => boolean | void
|
||||
callback: (value: T, indexOrKey: any, source: any) => boolean | unknown
|
||||
): Array<T> | ReadonlyArray<T> | ArrayLike<T> | PlainObject | null | undefined {
|
||||
if (isArrayLike(source)) {
|
||||
for (let i = 0; i < source.length; i++) {
|
||||
|
||||
@@ -354,6 +354,8 @@ const addRemoveImgElmsFn = async () => {
|
||||
before();
|
||||
appendChildren(imgElmsSlot, imgHolder);
|
||||
|
||||
await timeout(250);
|
||||
|
||||
await waitForOrFailTest(() => {
|
||||
after();
|
||||
compare(2);
|
||||
@@ -389,6 +391,8 @@ const addRemoveImgElmsFn = async () => {
|
||||
addMultipleItem();
|
||||
addMultipleItem();
|
||||
|
||||
await timeout(250);
|
||||
|
||||
await waitForOrFailTest(() => {
|
||||
after();
|
||||
compare(2);
|
||||
@@ -403,6 +407,45 @@ const addRemoveImgElmsFn = async () => {
|
||||
|
||||
await addMultiple();
|
||||
|
||||
// remove load event from image test
|
||||
const addChanged = async (
|
||||
newEventContentChange: Array<[string | null | undefined, (() => string | null | undefined) | string | null | undefined] | null | undefined>
|
||||
) => {
|
||||
contentDomObserver._updateEventContentChange(newEventContentChange);
|
||||
|
||||
const img = new Image(1, 1);
|
||||
img.src = 'data:image/gif;base64,R0lGODlhAQABAAD/ACwAAAAAAQABAAACADs=';
|
||||
|
||||
const { before, after, compare } = changedThrough(domContentObserverObservations);
|
||||
const imgHolder = createDiv('img');
|
||||
appendChildren(imgHolder, img);
|
||||
|
||||
before();
|
||||
appendChildren(imgElmsSlot, imgHolder);
|
||||
|
||||
await timeout(250);
|
||||
|
||||
await waitForOrFailTest(() => {
|
||||
after();
|
||||
compare(1);
|
||||
});
|
||||
|
||||
contentDomObserver._updateEventContentChange(contentChangeArr);
|
||||
};
|
||||
|
||||
await addChanged([
|
||||
['img', 'something'],
|
||||
['img', 'something2'],
|
||||
['img', null],
|
||||
['img', undefined],
|
||||
['img', () => 'hi'],
|
||||
['img', () => null],
|
||||
['img', () => undefined],
|
||||
null,
|
||||
undefined,
|
||||
]);
|
||||
await addChanged([]);
|
||||
|
||||
removeElements(document.querySelectorAll('.img'));
|
||||
|
||||
await timeout(250);
|
||||
@@ -578,11 +621,13 @@ const start = async () => {
|
||||
|
||||
targetDomObserver._update();
|
||||
targetDomObserver._destroy();
|
||||
targetDomObserver._destroy();
|
||||
targetDomObserver._update();
|
||||
|
||||
contentDomObserver._updateEventContentChange([]);
|
||||
contentDomObserver._update();
|
||||
contentDomObserver._destroy();
|
||||
contentDomObserver._destroy();
|
||||
contentDomObserver._updateEventContentChange([]);
|
||||
contentDomObserver._update();
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user