@@ -12,19 +12,25 @@ const arrowRightIcon = `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 448
1212</svg>` ;
1313
1414function estimateReadTime ( text ) {
15+ if ( typeof window === "undefined" ) return ;
16+
1517 const wordsPerSecond = 3.6 ; // Average reading speed
1618 const wordCount = text . split ( / \s + / ) . filter ( ( word ) => word . length > 0 ) . length ;
1719 const readTimeInSeconds = Math . ceil ( wordCount / wordsPerSecond ) ;
1820 return readTimeInSeconds + 1 ;
1921}
2022
2123function htmlToPlainText ( html ) {
24+ if ( typeof window === "undefined" ) return ;
25+
2226 const tempDiv = document . createElement ( "div" ) ;
2327 tempDiv . innerHTML = html ;
2428 return tempDiv . textContent || "" ;
2529}
2630
2731function scrollToElement ( element ) {
32+ if ( typeof window === "undefined" ) return ;
33+
2834 if ( element ) {
2935 element . scrollIntoView ( {
3036 behavior : "smooth" ,
@@ -35,6 +41,8 @@ function scrollToElement(element) {
3541}
3642
3743function performClickAnimation ( posX , posY ) {
44+ if ( typeof window === "undefined" ) return ;
45+
3846 const wave = document . createElement ( "div" ) ;
3947 wave . className = "click-wave" ;
4048 wave . style . left = `${ posX - 17 } px` ;
@@ -46,6 +54,8 @@ function performClickAnimation(posX, posY) {
4654}
4755
4856function waitForElement ( selector , timeout = 5000 ) {
57+ if ( typeof window === "undefined" ) return ;
58+
4959 const pollInterval = 100 ;
5060 const maxAttempts = timeout / pollInterval ;
5161 let attempts = 0 ;
@@ -65,6 +75,8 @@ function waitForElement(selector, timeout = 5000) {
6575}
6676
6777function smoothScrollToY ( yPosition ) {
78+ if ( typeof window === "undefined" ) return ;
79+
6880 const viewportHeight = window . innerHeight ;
6981 const targetScrollPosition = yPosition - viewportHeight / 2 ;
7082 window . scrollTo ( {
@@ -74,6 +86,8 @@ function smoothScrollToY(yPosition) {
7486}
7587
7688async function canPlayAudio ( ) {
89+ if ( typeof window === "undefined" ) return ;
90+
7791 const audio = new Audio (
7892 "data:audio/wav;base64,UklGRigAAABXQVZFZm10IBAAAAABAAEARKwAABCxAgAEABAAZGF0YQAAAAA="
7993 ) ;
@@ -87,6 +101,8 @@ async function canPlayAudio() {
87101
88102// Helper: Check if an element is fully visible in the viewport.
89103function isElementFullyVisible ( el ) {
104+ if ( typeof window === "undefined" ) return ;
105+
90106 const rect = el . getBoundingClientRect ( ) ;
91107 return (
92108 rect . top >= 0 &&
@@ -98,6 +114,8 @@ function isElementFullyVisible(el) {
98114
99115// Helper: Get scrollable ancestors of an element.
100116function getScrollableAncestors ( el ) {
117+ if ( typeof window === "undefined" ) return ;
118+
101119 let ancestors = [ ] ;
102120 let current = el . parentElement ;
103121 while ( current ) {
@@ -142,32 +160,35 @@ export default class GleapCopilotTours {
142160
143161 constructor ( ) {
144162 const self = this ;
145- this . _scrollListeners = [ ] ;
146- this . _currentAnchor = null ;
147- this . _currentStep = null ;
148- this . _scrollDebounceTimer = null ;
149-
150- window . addEventListener ( "resize" , ( ) => {
151- if (
152- self . productTourId &&
153- self . currentActiveIndex >= 0 &&
154- self . productTourData &&
155- self . productTourData . steps
156- ) {
157- const steps = self . productTourData . steps ;
158- const currentStep = steps [ self . currentActiveIndex ] ;
163+
164+ if ( typeof window !== "undefined" ) {
165+ this . _scrollListeners = [ ] ;
166+ this . _currentAnchor = null ;
167+ this . _currentStep = null ;
168+ this . _scrollDebounceTimer = null ;
169+
170+ window . addEventListener ( "resize" , ( ) => {
159171 if (
160- currentStep &&
161- currentStep . selector &&
162- currentStep . selector !== ""
172+ self . productTourId &&
173+ self . currentActiveIndex >= 0 &&
174+ self . productTourData &&
175+ self . productTourData . steps
163176 ) {
164- self . updatePointerPosition (
165- document . querySelector ( currentStep . selector ) ,
166- currentStep
167- ) ;
177+ const steps = self . productTourData . steps ;
178+ const currentStep = steps [ self . currentActiveIndex ] ;
179+ if (
180+ currentStep &&
181+ currentStep . selector &&
182+ currentStep . selector !== ""
183+ ) {
184+ self . updatePointerPosition (
185+ document . querySelector ( currentStep . selector ) ,
186+ currentStep
187+ ) ;
188+ }
168189 }
169- }
170- } ) ;
190+ } ) ;
191+ }
171192 }
172193
173194 disable ( ) {
@@ -176,6 +197,7 @@ export default class GleapCopilotTours {
176197 }
177198
178199 startWithConfig ( tourId , config , onCompleteCallback = undefined ) {
200+ if ( typeof window === "undefined" ) return ;
179201 if ( this . productTourId ) return ;
180202 this . productTourId = tourId ;
181203 this . productTourData = config ;
@@ -185,6 +207,7 @@ export default class GleapCopilotTours {
185207 }
186208
187209 storeUncompletedTour ( ) {
210+ if ( typeof window === "undefined" ) return ;
188211 if ( this . productTourId && this . productTourData ) {
189212 try {
190213 let data = JSON . parse (
@@ -208,6 +231,7 @@ export default class GleapCopilotTours {
208231
209232 // Attach scroll listeners with a debounce to update the pointer position after scrolling stops.
210233 attachScrollListeners ( anchor , currentStep ) {
234+ if ( typeof window === "undefined" ) return ;
211235 if ( ! anchor ) return ;
212236 const scrollableAncestors = getScrollableAncestors ( anchor ) ;
213237 // Also include window.
@@ -226,6 +250,7 @@ export default class GleapCopilotTours {
226250
227251 // Remove scroll listeners and clear debounce timer.
228252 removeScrollListeners ( ) {
253+ if ( typeof window === "undefined" ) return ;
229254 if ( this . _scrollListeners && this . _scrollListeners . length > 0 ) {
230255 this . _scrollListeners . forEach ( ( { el, handler } ) => {
231256 el . removeEventListener ( "scroll" , handler ) ;
@@ -242,6 +267,7 @@ export default class GleapCopilotTours {
242267 // 1. Scroll the element into view.
243268 // 2. After the element is fully visible (or after a maximum delay), update the pointer position to point towards the element.
244269 updatePointerPosition ( anchor , currentStep ) {
270+ if ( typeof window === "undefined" ) return ;
245271 try {
246272 const container =
247273 this . _pointerContainer || document . getElementById ( pointerContainerId ) ;
@@ -310,6 +336,7 @@ export default class GleapCopilotTours {
310336 }
311337
312338 cleanup ( ) {
339+ if ( typeof window === "undefined" ) return ;
313340 document . body . classList . add ( "gl-copilot-fade-out" ) ;
314341 setTimeout ( ( ) => {
315342 if ( this . _pointerContainer ) {
@@ -331,6 +358,8 @@ export default class GleapCopilotTours {
331358 }
332359
333360 setupCopilotTour ( ) {
361+ if ( typeof window === "undefined" ) return ;
362+
334363 let styleNode = document . getElementById ( styleId ) ;
335364 if ( ! styleNode ) {
336365 styleNode = document . createElement ( "style" ) ;
@@ -657,6 +686,7 @@ export default class GleapCopilotTours {
657686 }
658687
659688 start ( ) {
689+ if ( typeof window === "undefined" ) return ;
660690 const config = this . productTourData ;
661691 if ( ! config ) return ;
662692 canPlayAudio ( ) . then ( ( supported ) => {
@@ -669,13 +699,16 @@ export default class GleapCopilotTours {
669699 }
670700
671701 completeTour ( success = true ) {
702+ if ( typeof window === "undefined" ) return ;
672703 this . cleanup ( ) ;
673704 if ( this . onCompleteCallback ) {
674705 this . onCompleteCallback ( success ) ;
675706 }
676707 }
677708
678709 renderNextStep ( ) {
710+ if ( typeof window === "undefined" ) return ;
711+
679712 if ( this . disabled ) return ;
680713 const self = this ;
681714 const config = this . productTourData ;
0 commit comments