Skip to content

Commit

Permalink
fix: Allow window to be truly undefined (#895)
Browse files Browse the repository at this point in the history
  • Loading branch information
benjackwhite authored Nov 15, 2023
1 parent 4dc6e5f commit 4d23f2d
Show file tree
Hide file tree
Showing 22 changed files with 148 additions and 101 deletions.
2 changes: 1 addition & 1 deletion src/autocapture-utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,7 @@ export function shouldCaptureDomEvent(
event: Event,
autocaptureConfig: AutocaptureConfig | undefined = undefined
): boolean {
if (!el || isTag(el, 'html') || !isElementNode(el)) {
if (!window || !el || isTag(el, 'html') || !isElementNode(el)) {
return false
}

Expand Down
14 changes: 10 additions & 4 deletions src/autocapture.ts
Original file line number Diff line number Diff line change
Expand Up @@ -132,7 +132,7 @@ const autocapture = {

_extractCustomPropertyValue: function (customProperty: AutoCaptureCustomProperty): string {
const propValues: string[] = []
_each(document.querySelectorAll(customProperty['css_selector']), function (matchedElem) {
_each(document?.querySelectorAll(customProperty['css_selector']), function (matchedElem) {
let value

if (['input', 'select'].indexOf(matchedElem.tagName.toLowerCase()) > -1) {
Expand All @@ -153,7 +153,7 @@ const autocapture = {
const props: Properties = {} // will be deleted
_each(this._customProperties, (customProperty) => {
_each(customProperty['event_selectors'], (eventSelector) => {
const eventElements = document.querySelectorAll(eventSelector)
const eventElements = document?.querySelectorAll(eventSelector)
_each(eventElements, (eventElement) => {
if (_includes(targetElementList, eventElement) && shouldCaptureElement(eventElement)) {
props[customProperty['name']] = this._extractCustomPropertyValue(customProperty)
Expand Down Expand Up @@ -271,12 +271,18 @@ const autocapture = {
// only reason is to stub for unit tests
// since you can't override window.location props
_navigate: function (href: string): void {
if (!window) {
return
}
window.location.href = href
},

_addDomEventHandlers: function (instance: PostHog): void {
if (!window || !document) {
return
}
const handler = (e: Event) => {
e = e || window.event
e = e || window?.event
this._captureEvent(e, instance)
}
_register_event(document, 'submit', handler, false, true)
Expand Down Expand Up @@ -359,7 +365,7 @@ const autocapture = {
},

isBrowserSupported: function (): boolean {
return _isFunction(document.querySelectorAll)
return _isFunction(document?.querySelectorAll)
},
}

Expand Down
13 changes: 8 additions & 5 deletions src/extensions/exception-autocapture/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,8 @@ export const extendPostHog = (instance: PostHog, response: DecideResponse) => {
export class ExceptionObserver {
instance: PostHog
remoteEnabled: boolean | undefined
private originalOnErrorHandler: typeof window['onerror'] | null | undefined = undefined
private originalOnUnhandledRejectionHandler: typeof window['onunhandledrejection'] | null | undefined = undefined
private originalOnErrorHandler: Window['onerror'] | null | undefined = undefined
private originalOnUnhandledRejectionHandler: Window['onunhandledrejection'] | null | undefined = undefined

private errorsToIgnore: RegExp[] = []

Expand All @@ -28,7 +28,7 @@ export class ExceptionObserver {
}

startCapturing() {
if (!this.isEnabled() || (window.onerror as any)?.__POSTHOG_INSTRUMENTED__) {
if (!window || !this.isEnabled() || (window.onerror as any)?.__POSTHOG_INSTRUMENTED__) {
return
}

Expand Down Expand Up @@ -56,7 +56,7 @@ export class ExceptionObserver {
const errorProperties: ErrorProperties = unhandledRejectionToProperties(args)
this.sendExceptionEvent(errorProperties)

if (this.originalOnUnhandledRejectionHandler) {
if (window && this.originalOnUnhandledRejectionHandler) {
// eslint-disable-next-line prefer-rest-params
return this.originalOnUnhandledRejectionHandler.apply(window, args)
}
Expand All @@ -71,6 +71,9 @@ export class ExceptionObserver {
}

stopCapturing() {
if (!window) {
return
}
if (!_isUndefined(this.originalOnErrorHandler)) {
window.onerror = this.originalOnErrorHandler
this.originalOnErrorHandler = null
Expand All @@ -85,7 +88,7 @@ export class ExceptionObserver {
}

isCapturing() {
return !!(window.onerror as any)?.__POSTHOG_INSTRUMENTED__
return !!(window?.onerror as any)?.__POSTHOG_INSTRUMENTED__
}

isEnabled() {
Expand Down
6 changes: 3 additions & 3 deletions src/extensions/replay/sessionrecording.ts
Original file line number Diff line number Diff line change
Expand Up @@ -133,7 +133,7 @@ export class SessionRecording {
private get isRecordingEnabled() {
const enabled_server_side = !!this.instance.get_property(SESSION_RECORDING_ENABLED_SERVER_SIDE)
const enabled_client_side = !this.instance.config.disable_session_recording
return enabled_server_side && enabled_client_side
return window && enabled_server_side && enabled_client_side
}

private get isConsoleLogCaptureEnabled() {
Expand Down Expand Up @@ -192,7 +192,7 @@ export class SessionRecording {
this.stopRrweb = undefined
this.receivedDecide = false

window.addEventListener('beforeunload', () => {
window?.addEventListener('beforeunload', () => {
this._flushBuffer()
})

Expand Down Expand Up @@ -507,7 +507,7 @@ export class SessionRecording {
// so we catch all errors.
try {
if (eventName === '$pageview') {
const href = this._maskUrl(window.location.href)
const href = window ? this._maskUrl(window.location.href) : ''
if (!href) {
return
}
Expand Down
13 changes: 11 additions & 2 deletions src/extensions/surveys.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,11 @@ import {
} from '../posthog-surveys-types'

import { _isUndefined } from '../utils/type-utils'
import { window, document } from '../utils/globals'
import { window as _window, document as _document } from '../utils/globals'

// We cast the types here which is dangerous but protected by the top level generateSurveys call
const window = _window as Window & typeof globalThis
const document = _document as Document

const satisfiedEmoji =
'<svg class="emoji-svg" xmlns="http://www.w3.org/2000/svg" height="48" viewBox="0 -960 960 960" width="48"><path d="M626-533q22.5 0 38.25-15.75T680-587q0-22.5-15.75-38.25T626-641q-22.5 0-38.25 15.75T572-587q0 22.5 15.75 38.25T626-533Zm-292 0q22.5 0 38.25-15.75T388-587q0-22.5-15.75-38.25T334-641q-22.5 0-38.25 15.75T280-587q0 22.5 15.75 38.25T334-533Zm146 272q66 0 121.5-35.5T682-393h-52q-23 40-63 61.5T480.5-310q-46.5 0-87-21T331-393h-53q26 61 81 96.5T480-261Zm0 181q-83 0-156-31.5T197-197q-54-54-85.5-127T80-480q0-83 31.5-156T197-763q54-54 127-85.5T480-880q83 0 156 31.5T763-763q54 54 85.5 127T880-480q0 83-31.5 156T763-197q-54 54-127 85.5T480-80Zm0-400Zm0 340q142.375 0 241.188-98.812Q820-337.625 820-480t-98.812-241.188Q622.375-820 480-820t-241.188 98.812Q140-622.375 140-480t98.812 241.188Q337.625-140 480-140Z"/></svg>'
Expand Down Expand Up @@ -897,14 +901,19 @@ function showQuestion(n: number, surveyId: string) {
function nextQuestion(currentQuestionIdx: number, surveyId: string) {
// figure out which tab to display
const tabs = document
.getElementsByClassName(`PostHogSurvey${surveyId}`)[0]
?.getElementsByClassName(`PostHogSurvey${surveyId}`)[0]
?.shadowRoot?.querySelectorAll('.tab') as NodeListOf<HTMLElement>

tabs[currentQuestionIdx].style.display = 'none'
showQuestion(currentQuestionIdx + 1, surveyId)
}

// This is the main exported function
export function generateSurveys(posthog: PostHog) {
// NOTE: Important to ensure we never try and run surveys without a window environment
if (!document || !window) {
return
}
callSurveys(posthog, true)

// recalculate surveys every 3 seconds to check if URL or selectors have changed
Expand Down
20 changes: 13 additions & 7 deletions src/extensions/toolbar.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import { window, document, assignableWindow } from '../utils/globals'

// TRICKY: Many web frameworks will modify the route on load, potentially before posthog is initialized.
// To get ahead of this we grab it as soon as the posthog-js is parsed
const STATE_FROM_WINDOW = window.location
const STATE_FROM_WINDOW = window?.location
? _getHashParam(window.location.hash, '__posthog') || _getHashParam(location.hash, 'state')
: null

Expand Down Expand Up @@ -40,10 +40,16 @@ export class Toolbar {
* 2. From session storage under the key `toolbarParams` if the toolbar was initialized on a previous page
*/
maybeLoadToolbar(
location = window.location,
location: Location | undefined = undefined,
localStorage: Storage | undefined = undefined,
history = window.history
history: History | undefined = undefined
): boolean {
if (!window || !document) {
return false
}
location = location ?? window.location
history = history ?? window.history

try {
// Before running the code we check if we can access localStorage, if not we opt-out
if (!localStorage) {
Expand All @@ -55,7 +61,7 @@ export class Toolbar {
}

// If localStorage was undefined, and localStorage is supported we set the default value
localStorage = window.localStorage
localStorage = window?.localStorage
}

/**
Expand Down Expand Up @@ -114,7 +120,7 @@ export class Toolbar {
}

loadToolbar(params?: ToolbarParams): boolean {
if (assignableWindow['_postHogToolbarLoaded']) {
if (!window || assignableWindow['_postHogToolbarLoaded']) {
return false
}
// only load the toolbar once, even if there are multiple instances of PostHogLib
Expand Down Expand Up @@ -164,9 +170,9 @@ export class Toolbar {

/** @deprecated Use "maybeLoadToolbar" instead. */
maybeLoadEditor(
location = window.location,
location: Location | undefined = undefined,
localStorage: Storage | undefined = undefined,
history = window.history
history: History | undefined = undefined
): boolean {
return this.maybeLoadToolbar(location, localStorage, history)
}
Expand Down
4 changes: 2 additions & 2 deletions src/gdpr-utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -158,11 +158,11 @@ function _getStorageValue(token: string, options: GDPROptions) {
function _hasDoNotTrackFlagOn(options: GDPROptions) {
if (options && options.respectDnt) {
const win = (options && options.window) || window
const nav = win['navigator'] || {}
const nav = win?.navigator
let hasDntOn = false
_each(
[
nav['doNotTrack'], // standard
nav?.doNotTrack, // standard
(nav as any)['msDoNotTrack'],
(win as any)['doNotTrack'],
],
Expand Down
15 changes: 6 additions & 9 deletions src/loader-recorder-v2.ts
Original file line number Diff line number Diff line change
Expand Up @@ -454,14 +454,11 @@ export const getRecordNetworkPlugin: (options?: NetworkRecordOptions) => RecordP
}

// rrweb/networ@1 ends
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
window.rrweb = { record: rrwebRecord, version: 'v2', rrwebVersion: version }
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
window.rrwebConsoleRecord = { getRecordConsolePlugin }
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
window.getRecordNetworkPlugin = getRecordNetworkPlugin

if (window) {
;(window as any).rrweb = { record: rrwebRecord, version: 'v2', rrwebVersion: version }
;(window as any).rrwebConsoleRecord = { getRecordConsolePlugin }
;(window as any).getRecordNetworkPlugin = getRecordNetworkPlugin
}

export default rrwebRecord
10 changes: 4 additions & 6 deletions src/loader-recorder.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,9 @@ import { getRecordConsolePlugin } from 'rrweb-v1/es/rrweb/packages/rrweb/src/plu

import { window } from './utils/globals'

// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
window.rrweb = { record: rrwebRecord, version: 'v1', rrwebVersion: version }
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
window.rrwebConsoleRecord = { getRecordConsolePlugin }
if (window) {
;(window as any).rrweb = { record: rrwebRecord, version: 'v1', rrwebVersion: version }
;(window as any).rrwebConsoleRecord = { getRecordConsolePlugin }
}

export default rrwebRecord
7 changes: 3 additions & 4 deletions src/loader-surveys.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,9 @@
import { generateSurveys } from './extensions/surveys'

import { _isUndefined } from './utils/type-utils'
import { window } from './utils/globals'

const win: Window & typeof globalThis = _isUndefined(window) ? ({} as typeof window) : window

;(win as any).extendPostHogWithSurveys = generateSurveys
if (window) {
;(window as any).extendPostHogWithSurveys = generateSurveys
}

export default generateSurveys
24 changes: 13 additions & 11 deletions src/page-view.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ export class PageViewManager {

_createPageViewData(): PageViewData {
return {
pathname: window.location.pathname,
pathname: window?.location.pathname ?? '',
}
}

Expand Down Expand Up @@ -134,31 +134,33 @@ export class PageViewManager {
}

startMeasuringScrollPosition() {
window.addEventListener('scroll', this._updateScrollData)
window.addEventListener('scrollend', this._updateScrollData)
window.addEventListener('resize', this._updateScrollData)
window?.addEventListener('scroll', this._updateScrollData)
window?.addEventListener('scrollend', this._updateScrollData)
window?.addEventListener('resize', this._updateScrollData)
}

stopMeasuringScrollPosition() {
window.removeEventListener('scroll', this._updateScrollData)
window.removeEventListener('scrollend', this._updateScrollData)
window.removeEventListener('resize', this._updateScrollData)
window?.removeEventListener('scroll', this._updateScrollData)
window?.removeEventListener('scrollend', this._updateScrollData)
window?.removeEventListener('resize', this._updateScrollData)
}

_scrollHeight(): number {
return Math.max(0, window.document.documentElement.scrollHeight - window.document.documentElement.clientHeight)
return window
? Math.max(0, window.document.documentElement.scrollHeight - window.document.documentElement.clientHeight)
: 0
}

_scrollY(): number {
return window.scrollY || window.pageYOffset || window.document.documentElement.scrollTop || 0
return window ? window.scrollY || window.pageYOffset || window.document.documentElement.scrollTop || 0 : 0
}

_contentHeight(): number {
return window.document.documentElement.scrollHeight || 0
return window?.document.documentElement.scrollHeight || 0
}

_contentY(): number {
const clientHeight = window.document.documentElement.clientHeight || 0
const clientHeight = window?.document.documentElement.clientHeight || 0
return this._scrollY() + clientHeight
}
}
Expand Down
Loading

0 comments on commit 4d23f2d

Please sign in to comment.