From 7451e52767e0b4b2bda68cddc414873d13e1bac2 Mon Sep 17 00:00:00 2001 From: Paul D'Ambra Date: Mon, 18 Nov 2024 17:24:48 +0100 Subject: [PATCH] fix: refactor native mutation observer implementation (#1535) --- src/entrypoints/dead-clicks-autocapture.ts | 3 +- src/utils/globals.ts | 7 +--- src/utils/type-utils.ts | 41 ++++++++-------------- 3 files changed, 17 insertions(+), 34 deletions(-) diff --git a/src/entrypoints/dead-clicks-autocapture.ts b/src/entrypoints/dead-clicks-autocapture.ts index a372bf563..496879686 100644 --- a/src/entrypoints/dead-clicks-autocapture.ts +++ b/src/entrypoints/dead-clicks-autocapture.ts @@ -5,7 +5,7 @@ import { autocaptureCompatibleElements, getEventTarget } from '../autocapture-ut import { DeadClickCandidate, DeadClicksAutoCaptureConfig, Properties } from '../types' import { autocapturePropertiesForElement } from '../autocapture' import { isElementInToolbar, isElementNode, isTag } from '../utils/element-utils' -import { NativeMutationObserver } from '../utils/globals' +import { getNativeMutationObserverImplementation } from '../utils/prototype-utils' function asClick(event: MouseEvent): DeadClickCandidate | null { const eventTarget = getEventTarget(event) @@ -67,6 +67,7 @@ class LazyLoadedDeadClicksAutocapture implements LazyLoadedDeadClicksAutocapture private _startMutationObserver(observerTarget: Node) { if (!this._mutationObserver) { + const NativeMutationObserver = getNativeMutationObserverImplementation(assignableWindow) this._mutationObserver = new NativeMutationObserver((mutations) => { this.onMutation(mutations) }) diff --git a/src/utils/globals.ts b/src/utils/globals.ts index 76ce214ad..377fe22b5 100644 --- a/src/utils/globals.ts +++ b/src/utils/globals.ts @@ -2,7 +2,6 @@ import { ErrorProperties } from '../extensions/exception-autocapture/error-conve import type { PostHog } from '../posthog-core' import { SessionIdManager } from '../sessionid' import { DeadClicksAutoCaptureConfig, ErrorEventArgs, ErrorMetadata, Properties } from '../types' -import { getNativeMutationObserverImplementation } from './prototype-utils' /* * Global helpers to protect access to browser globals in a way that is safer for different targets @@ -94,9 +93,5 @@ export const XMLHttpRequest = export const AbortController = global?.AbortController export const userAgent = navigator?.userAgent export const assignableWindow: AssignableWindow = win ?? ({} as any) -/** - * We have to sometimes load mutation observer from an iframe - * because Angular change detection really doesn't like sharing it - */ -export const NativeMutationObserver = getNativeMutationObserverImplementation(assignableWindow) + export { win as window } diff --git a/src/utils/type-utils.ts b/src/utils/type-utils.ts index fa0255d1b..37e04ba64 100644 --- a/src/utils/type-utils.ts +++ b/src/utils/type-utils.ts @@ -9,23 +9,20 @@ export const isArray = function (obj: any): obj is any[] { return toString.call(obj) === '[object Array]' } -export const isUint8Array = function (x: unknown): x is Uint8Array { - return toString.call(x) === '[object Uint8Array]' -} + // from a comment on http://dbj.org/dbj/?p=286 // fails on only one very rare and deliberate custom object: // let bomb = { toString : undefined, valueOf: function(o) { return "function BOMBA!"; }}; -export const isFunction = function (x: unknown): x is (...args: any[]) => any { +export const isFunction = (x: unknown): x is (...args: any[]) => any => { // eslint-disable-next-line posthog-js/no-direct-function-check return typeof x === 'function' } -export const isNativeFunction = function (x: unknown): x is (...args: any[]) => any { - return isFunction(x) && x.toString().indexOf('[native code]') !== -1 -} +export const isNativeFunction = (x: unknown): x is (...args: any[]) => any => + isFunction(x) && x.toString().indexOf('[native code]') !== -1 // When angular patches functions they pass the above `isNativeFunction` check -export const isAngularZonePatchedFunction = function (x: unknown): boolean { +export const isAngularZonePatchedFunction = (x: unknown): boolean => { if (!isFunction(x)) { return false } @@ -34,11 +31,11 @@ export const isAngularZonePatchedFunction = function (x: unknown): boolean { } // Underscore Addons -export const isObject = function (x: unknown): x is Record { +export const isObject = (x: unknown): x is Record => { // eslint-disable-next-line posthog-js/no-direct-object-check return x === Object(x) && !isArray(x) } -export const isEmptyObject = function (x: unknown): x is Record { +export const isEmptyObject = (x: unknown): x is Record => { if (isObject(x)) { for (const key in x) { if (hasOwnProperty.call(x, key)) { @@ -49,20 +46,16 @@ export const isEmptyObject = function (x: unknown): x is Record { } return false } -export const isUndefined = function (x: unknown): x is undefined { - return x === void 0 -} +export const isUndefined = (x: unknown): x is undefined => x === void 0 -export const isString = function (x: unknown): x is string { +export const isString = (x: unknown): x is string => { // eslint-disable-next-line posthog-js/no-direct-string-check return toString.call(x) == '[object String]' } -export const isEmptyString = function (x: unknown): boolean { - return isString(x) && x.trim().length === 0 -} +export const isEmptyString = (x: unknown): boolean => isString(x) && x.trim().length === 0 -export const isNull = function (x: unknown): x is null { +export const isNull = (x: unknown): x is null => { // eslint-disable-next-line posthog-js/no-direct-null-check return x === null } @@ -71,19 +64,13 @@ export const isNull = function (x: unknown): x is null { sometimes you want to check if something is null or undefined that's what this is for */ -export const isNullish = function (x: unknown): x is null | undefined { - return isUndefined(x) || isNull(x) -} +export const isNullish = (x: unknown): x is null | undefined => isUndefined(x) || isNull(x) -export const isDate = function (x: unknown): x is Date { - // eslint-disable-next-line posthog-js/no-direct-date-check - return toString.call(x) == '[object Date]' -} -export const isNumber = function (x: unknown): x is number { +export const isNumber = (x: unknown): x is number => { // eslint-disable-next-line posthog-js/no-direct-number-check return toString.call(x) == '[object Number]' } -export const isBoolean = function (x: unknown): x is boolean { +export const isBoolean = (x: unknown): x is boolean => { // eslint-disable-next-line posthog-js/no-direct-boolean-check return toString.call(x) === '[object Boolean]' }