Skip to content

Commit 9d8420a

Browse files
authored
Merge pull request #33 from GleapSDK/Tours
Tours
2 parents 54a015d + 6062e3f commit 9d8420a

File tree

10 files changed

+1774
-9
lines changed

10 files changed

+1774
-9
lines changed

build/index.js

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

demo/main.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ Gleap.setWSApiUrl("ws://0.0.0.0:8080");
66

77
// Gleap.setLanguage("en");
88

9-
Gleap.initialize("ogWhNhuiZcGWrva5nlDS8l7a78OfaLlV");
9+
Gleap.initialize("81IAthSlhI4XfQTtedQ0d3OXt5WYynOX");
1010

1111
/*Gleap.setUrlHandler((url, newTab) => {
1212
alert("URL: " + url + " newTab: " + newTab);

package.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "gleap",
3-
"version": "12.1.3",
3+
"version": "12.2.0",
44
"main": "build/index.js",
55
"scripts": {
66
"start": "webpack serve",
@@ -61,4 +61,4 @@
6161
"\\.(css|less)$": "<rootDir>/scripts/testMock.js"
6262
}
6363
}
64-
}
64+
}

published/12.2.0/index.js

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

published/latest/index.js

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/Gleap.js

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ import GleapBannerManager from "./GleapBannerManager";
2323
import GleapAudioManager from "./GleapAudioManager";
2424
import GleapTagManager from "./GleapTagManager";
2525
import GleapAdminManager from "./GleapAdminManager";
26+
import GleapProductTours from "./GleapProductTours";
2627

2728
if (typeof HTMLCanvasElement !== "undefined" && HTMLCanvasElement.prototype && HTMLCanvasElement.prototype.__originalGetContext === undefined) {
2829
HTMLCanvasElement.prototype.__originalGetContext =
@@ -1027,13 +1028,26 @@ class Gleap {
10271028
}
10281029
} else if (action.actionType === "banner") {
10291030
Gleap.showBanner(action);
1031+
} else if (action.actionType === "tour") {
1032+
Gleap.startProductTourWithConfig(action.id, action.data);
10301033
} else {
10311034
Gleap.showSurvey(action.actionType, action.format);
10321035
}
10331036
}
10341037
}
10351038
}
10361039

1040+
static startProductTourWithConfig(tourId, config) {
1041+
GleapProductTours.getInstance().startWithConfig(tourId, config, (data) => {
1042+
const comData = {
1043+
tourId: data.tourId,
1044+
};
1045+
1046+
GleapEventManager.notifyEvent("productTourCompleted", comData);
1047+
Gleap.trackEvent(`tour-${data.tourId}-completed`, comData);
1048+
});
1049+
}
1050+
10371051
static showBanner(data) {
10381052
try {
10391053
GleapBannerManager.getInstance().showBanner(data);

src/GleapAdminManager.js

Lines changed: 25 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11

22
export default class GleapAdminManager {
33
libraryInstance = null;
4+
lastUrl = undefined;
45

56
// GleapAdminManager singleton
67
static instance;
@@ -11,6 +12,27 @@ export default class GleapAdminManager {
1112
return this.instance;
1213
}
1314

15+
logCurrentPage() {
16+
const currentUrl = window.location.href;
17+
if (currentUrl && currentUrl !== this.lastUrl) {
18+
this.lastUrl = currentUrl;
19+
20+
this.sendMessage({
21+
name: "page-changed",
22+
data: {
23+
page: currentUrl,
24+
}
25+
});
26+
}
27+
}
28+
29+
startPageListener() {
30+
const self = this;
31+
setInterval(function () {
32+
self.logCurrentPage();
33+
}, 1000);
34+
}
35+
1436
loadScript(url, callback) {
1537
var script = document.createElement('script');
1638
script.type = 'text/javascript';
@@ -76,14 +98,14 @@ export default class GleapAdminManager {
7698
if (data.name === "navigate") {
7799
self.libraryInstance.stopPicker();
78100
}
79-
} catch (exp) {
80-
console.log(exp);
81-
}
101+
} catch (exp) { }
82102
});
83103

84104
this.sendMessage({
85105
name: "init",
86106
});
107+
108+
this.startPageListener();
87109
}
88110

89111
sendMessage(data) {

src/GleapProductTours.js

Lines changed: 163 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,163 @@
1+
import { loadIcon } from "./UI";
2+
import GleapTours from "./GleapTours";
3+
4+
export default class GleapProductTours {
5+
productTourData = undefined;
6+
productTourId = undefined;
7+
onCompletion = undefined;
8+
9+
// GleapReplayRecorder singleton
10+
static instance;
11+
static getInstance() {
12+
if (!this.instance) {
13+
this.instance = new GleapProductTours();
14+
return this.instance;
15+
} else {
16+
return this.instance;
17+
}
18+
}
19+
20+
constructor() { }
21+
22+
startWithConfig(tourId, config, onCompletion) {
23+
this.productTourId = tourId;
24+
this.productTourData = config;
25+
this.onCompletion = onCompletion;
26+
27+
return this.start();
28+
}
29+
30+
start() {
31+
const config = this.productTourData;
32+
if (!config) {
33+
return;
34+
}
35+
36+
const steps = config.steps;
37+
const self = this;
38+
39+
var driverSteps = [];
40+
41+
for (let i = 0; i < steps.length; i++) {
42+
const step = steps[i];
43+
44+
var message = "";
45+
46+
if (step.type === "video-pointer") {
47+
message = `<div class="gleap-tour-video">
48+
<video class="gleap-tour-video-obj">
49+
<source src="${step.videoUrl}" type="video/mp4">
50+
</video>
51+
<div class="gleap-tour-video-playpause">${loadIcon("play")}</div>
52+
</div>`;
53+
} else {
54+
var senderHTML = ``;
55+
if (step.sender && step.sender.name) {
56+
senderHTML = `<div class="gleap-tour-sender">
57+
<div class="gleap-tour-sender-image" style="background-image: url('${step.sender.profileImageUrl}');"></div>
58+
<div class="gleap-tour-sender-name">${step.sender.name}</div>
59+
</div>`;
60+
}
61+
62+
message = `${senderHTML}<div class="gleap-tour-message">${step.message}</div>`;
63+
}
64+
65+
var driverStep = {
66+
popover: {
67+
description: message,
68+
popoverClass: `gleap-tour-popover-${step.type}`,
69+
},
70+
}
71+
if (step.selector && step.selector.length > 0) {
72+
driverStep.element = step.selector;
73+
}
74+
driverSteps.push(driverStep);
75+
}
76+
77+
const gleapTourObj = GleapTours({
78+
showProgress: true,
79+
steps: driverSteps,
80+
allowClose: config.allowClose,
81+
nextBtnText: config.nextText,
82+
doneBtnText: config.doneText,
83+
showButtons: [
84+
'next',
85+
'close'
86+
],
87+
onDestroyStarted: () => {
88+
if (!gleapTourObj.hasNextStep()) {
89+
gleapTourObj.destroy();
90+
91+
if (self.onCompletion) {
92+
self.onCompletion({
93+
tourId: self.productTourId
94+
});
95+
}
96+
}
97+
},
98+
onPopoverRender: (popoverElement) => {
99+
// Fix for images and videos.
100+
if (popoverElement) {
101+
const mediaElements = document.querySelectorAll('.gleap-tour-popover-description img, .gleap-tour-popover-description video');
102+
103+
const performRequentialRefresh = () => {
104+
setTimeout(() => {
105+
gleapTourObj.refresh();
106+
}, 750);
107+
};
108+
109+
for (let i = 0; i < mediaElements.length; i++) {
110+
const mediaElement = mediaElements[i];
111+
if (mediaElement.tagName === 'IMG') {
112+
mediaElement.addEventListener('load', () => {
113+
performRequentialRefresh();
114+
});
115+
mediaElement.addEventListener('error', () => {
116+
performRequentialRefresh();
117+
});
118+
} else if (mediaElement.tagName === 'VIDEO') {
119+
mediaElement.addEventListener('canplaythrough', () => {
120+
performRequentialRefresh();
121+
});
122+
mediaElement.addEventListener('error', () => {
123+
performRequentialRefresh();
124+
});
125+
}
126+
}
127+
}
128+
129+
// Video player controller.
130+
const playButtonElem = document.querySelector('.gleap-tour-video-playpause');
131+
if (playButtonElem) {
132+
playButtonElem.addEventListener('click', () => {
133+
const playingClass = 'gleap-tour-video--playing';
134+
const videoElement = playButtonElem.previousElementSibling;
135+
const videoContainer = playButtonElem.closest('.gleap-tour-video');
136+
137+
const onVideoEnded = () => {
138+
videoElem.innerHTML = loadIcon("play");
139+
videoContainer.classList.remove(playingClass);
140+
};
141+
142+
if (videoElement.paused) {
143+
videoElement.play();
144+
playButtonElem.innerHTML = loadIcon("pause");
145+
videoContainer.classList.add(playingClass);
146+
147+
// Add event listener for video ended
148+
videoElement.addEventListener('ended', onVideoEnded);
149+
} else {
150+
videoElement.pause();
151+
playButtonElem.innerHTML = loadIcon("play");
152+
videoContainer.classList.remove(playingClass);
153+
154+
// Remove event listener for video ended
155+
videoElement.removeEventListener('ended', onVideoEnded);
156+
}
157+
});
158+
}
159+
}
160+
});
161+
gleapTourObj.drive();
162+
}
163+
}

0 commit comments

Comments
 (0)