mirror of
https://github.com/tenrok/OverlayScrollbars.git
synced 2026-06-24 00:50:36 +03:00
improve domobserver code and tests
This commit is contained in:
@@ -28,7 +28,7 @@ interface DOMObserverOptionsBase {
|
|||||||
}
|
}
|
||||||
|
|
||||||
interface DOMContentObserverOptions extends 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;
|
_nestedTargetSelector?: string;
|
||||||
_ignoreContentChange?: DOMObserverIgnoreContentChange; // function which will prevent marking certain dom changes as content change if it returns true
|
_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
|
_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 {}
|
interface DOMTargetObserver extends DOMObserverBase {}
|
||||||
|
|
||||||
export type DOMObserverEventContentChange =
|
export type DOMObserverEventContentChange =
|
||||||
| Array<[StringNullUndefined, ((elms: Node[]) => string) | StringNullUndefined] | null | undefined>
|
| Array<[StringNullUndefined, ((elms: Node[]) => StringNullUndefined) | StringNullUndefined] | null | undefined>
|
||||||
| false
|
| false
|
||||||
| null
|
| null
|
||||||
| undefined;
|
| undefined;
|
||||||
@@ -90,22 +90,6 @@ export type DOMObserver<ContentObserver extends boolean> = ContentObserver exten
|
|||||||
const createEventContentChange = (target: Element, eventContentChange: DOMObserverEventContentChange, callback: (...args: any) => any) => {
|
const createEventContentChange = (target: Element, eventContentChange: DOMObserverEventContentChange, callback: (...args: any) => any) => {
|
||||||
let map: Map<Node, string> | undefined;
|
let map: Map<Node, string> | undefined;
|
||||||
let eventContentChangeRef: DOMObserverEventContentChange;
|
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 = () => {
|
const _destroy = () => {
|
||||||
if (map) {
|
if (map) {
|
||||||
map.forEach((eventName: string, elm: Node) => off(elm, eventName, callback));
|
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[]) => {
|
const _updateElements = (getElements?: (selector: string) => Node[]) => {
|
||||||
if (eventContentChangeRef) {
|
if (map && eventContentChangeRef) {
|
||||||
const eventElmList = eventContentChangeRef.reduce<Array<[Node[], string]>>((arr, item) => {
|
const eventElmList = eventContentChangeRef.reduce<Array<[Node[], string]>>((arr, item) => {
|
||||||
if (item) {
|
if (item) {
|
||||||
const selector = item[0];
|
const selector = item[0];
|
||||||
const eventName = item[1];
|
const eventNames = item[1];
|
||||||
const elements = eventName && selector && (getElements ? getElements(selector) : find(selector, target));
|
const elements = eventNames && selector && (getElements ? getElements(selector) : find(selector, target));
|
||||||
|
const parsedEventNames = isFunction(eventNames) ? eventNames(elements) : eventNames;
|
||||||
|
|
||||||
if (elements) {
|
if (elements && elements.length && parsedEventNames && isString(parsedEventNames)) {
|
||||||
push(arr, [elements, isFunction(eventName) ? eventName(elements) : eventName!], true);
|
push(arr, [elements, parsedEventNames.trim()], true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return arr;
|
return arr;
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
each(eventElmList, (item) => {
|
each(eventElmList, (item) =>
|
||||||
const elements = item[0];
|
each(item[0], (elm) => {
|
||||||
const eventName = item[1];
|
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) => {
|
if (changingExistingEntry) {
|
||||||
addEvent(elm, eventName);
|
off(elm, registredEventNames!, callback);
|
||||||
});
|
}
|
||||||
});
|
|
||||||
|
map!.set(elm, finalEventNames);
|
||||||
|
on(elm, finalEventNames, callback);
|
||||||
|
})
|
||||||
|
);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
const _updateEventContentChange = (newEventContentChange: DOMObserverEventContentChange) => {
|
const _updateEventContentChange = (newEventContentChange: DOMObserverEventContentChange) => {
|
||||||
|
|||||||
@@ -12,28 +12,28 @@ type RunEachItem = ((...args: any) => any | any[]) | null | undefined;
|
|||||||
*/
|
*/
|
||||||
export function each<T>(
|
export function each<T>(
|
||||||
array: Array<T> | ReadonlyArray<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>;
|
): Array<T> | ReadonlyArray<T>;
|
||||||
export function each<T>(
|
export function each<T>(
|
||||||
array: Array<T> | ReadonlyArray<T> | null | undefined,
|
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;
|
): Array<T> | ReadonlyArray<T> | null | undefined;
|
||||||
export function each<T>(
|
export function each<T>(
|
||||||
arrayLikeObject: ArrayLike<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>;
|
): ArrayLike<T>;
|
||||||
export function each<T>(
|
export function each<T>(
|
||||||
arrayLikeObject: ArrayLike<T> | null | undefined,
|
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;
|
): 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(
|
export function each(
|
||||||
obj: PlainObject | null | undefined,
|
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;
|
): PlainObject | null | undefined;
|
||||||
export function each<T>(
|
export function each<T>(
|
||||||
source: ArrayLike<T> | PlainObject | null | undefined,
|
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 {
|
): Array<T> | ReadonlyArray<T> | ArrayLike<T> | PlainObject | null | undefined {
|
||||||
if (isArrayLike(source)) {
|
if (isArrayLike(source)) {
|
||||||
for (let i = 0; i < source.length; i++) {
|
for (let i = 0; i < source.length; i++) {
|
||||||
|
|||||||
@@ -354,6 +354,8 @@ const addRemoveImgElmsFn = async () => {
|
|||||||
before();
|
before();
|
||||||
appendChildren(imgElmsSlot, imgHolder);
|
appendChildren(imgElmsSlot, imgHolder);
|
||||||
|
|
||||||
|
await timeout(250);
|
||||||
|
|
||||||
await waitForOrFailTest(() => {
|
await waitForOrFailTest(() => {
|
||||||
after();
|
after();
|
||||||
compare(2);
|
compare(2);
|
||||||
@@ -389,6 +391,8 @@ const addRemoveImgElmsFn = async () => {
|
|||||||
addMultipleItem();
|
addMultipleItem();
|
||||||
addMultipleItem();
|
addMultipleItem();
|
||||||
|
|
||||||
|
await timeout(250);
|
||||||
|
|
||||||
await waitForOrFailTest(() => {
|
await waitForOrFailTest(() => {
|
||||||
after();
|
after();
|
||||||
compare(2);
|
compare(2);
|
||||||
@@ -403,6 +407,45 @@ const addRemoveImgElmsFn = async () => {
|
|||||||
|
|
||||||
await addMultiple();
|
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'));
|
removeElements(document.querySelectorAll('.img'));
|
||||||
|
|
||||||
await timeout(250);
|
await timeout(250);
|
||||||
@@ -578,11 +621,13 @@ const start = async () => {
|
|||||||
|
|
||||||
targetDomObserver._update();
|
targetDomObserver._update();
|
||||||
targetDomObserver._destroy();
|
targetDomObserver._destroy();
|
||||||
|
targetDomObserver._destroy();
|
||||||
targetDomObserver._update();
|
targetDomObserver._update();
|
||||||
|
|
||||||
contentDomObserver._updateEventContentChange([]);
|
contentDomObserver._updateEventContentChange([]);
|
||||||
contentDomObserver._update();
|
contentDomObserver._update();
|
||||||
contentDomObserver._destroy();
|
contentDomObserver._destroy();
|
||||||
|
contentDomObserver._destroy();
|
||||||
contentDomObserver._updateEventContentChange([]);
|
contentDomObserver._updateEventContentChange([]);
|
||||||
contentDomObserver._update();
|
contentDomObserver._update();
|
||||||
};
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user