Skip to content

Commit b724c2e

Browse files
author
Matej Lednicky
committed
feat(DIST-193): Open popup using behavioral trigger
Popup can be opened on: - load (same as current 'auto-open' feature) - exit (allows modifying the sensitivity of threshold at the top of the page in pixels) - time (in milliseconds) - scroll (in percentage)
1 parent ff55333 commit b724c2e

File tree

12 files changed

+507
-16
lines changed

12 files changed

+507
-16
lines changed

.travis.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,7 @@ jobs:
8282
script:
8383
- yarn build
8484
- pip install --user awscli
85-
- yarn add @typeform/jarvis
85+
- yarn add @typeform/jarvis@10.4.0 # jarvis version pinned, latest version has a bug, we should unpin it when its fixed
8686
- DEBUG=jarvis yarn run jarvis deploy --path dist --preview --notify-preview
8787
- name: "Release to NPM"
8888
if: branch = master AND type = push
@@ -93,5 +93,5 @@ jobs:
9393
script:
9494
- yarn build
9595
- pip install --user awscli
96-
- yarn add @typeform/jarvis
96+
- yarn add @typeform/jarvis@10.4.0 # jarvis version pinned, latest version has a bug, we should unpin it when its fixed
9797
- DEBUG=jarvis jarvis deploy --path dist

demo/behavioral/exit.html

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
<!DOCTYPE html>
2+
<html>
3+
<head>
4+
<title>Open: exit</title>
5+
<style>
6+
#visual-threshold {
7+
position: fixed;
8+
top: 0;
9+
left: 0;
10+
width: 100%;
11+
height: 50px;
12+
background: rgba(255,0,0,0.2);
13+
pointer-events: none;
14+
}
15+
</style>
16+
</head>
17+
<body>
18+
<div id="visual-threshold"></div>
19+
<h1>This popup opens on exit intent</h1>
20+
<p>If a user wants to navigate away from your page, they usually need to access the browser toolbar.</p>
21+
<p>We detect mouse movement in top part of the page - if the mouse is moving "up", we open the popup.</p>
22+
<p>The popup is opened only once (on first detected exit intent).</p>
23+
<a
24+
id="popup"
25+
class="typeform-share"
26+
href="//betatests.typeform.com/to/Z9k3bK?disable-tracking=true"
27+
data-mode="drawer_right"
28+
data-open="exit"
29+
data-open-value="50"
30+
target="_blank"
31+
>
32+
Open the popup manually instead
33+
</a>
34+
35+
<h2>Technical stuff</h2>
36+
<p>This is not available for customization on "Share" page, but the embed lib allows it.</p>
37+
<form action="" method="get">
38+
<label for="threshold">Pixels from top</label>
39+
<input id="threshold" name="threshold" type="number" value="50" step="10" min="10" max="250" />
40+
<button type="submit">Set</button>
41+
</form>
42+
43+
<script>
44+
const param = window.location.search.match(/threshold=(\d+)/)
45+
if (param) {
46+
const thresholdValue = parseInt(param[1], 10);
47+
document.getElementById('popup').dataset.openValue = thresholdValue;
48+
document.getElementById('threshold').value = thresholdValue;
49+
document.getElementById('visual-threshold').style.height = thresholdValue + 'px';
50+
}
51+
</script>
52+
53+
<script type="text/javascript" src="../embed.js"></script>
54+
<script type="text/javascript" src="../demo.js"></script>
55+
</body>
56+
</html>

demo/behavioral/load.html

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
<!DOCTYPE html>
2+
<html>
3+
<head>
4+
<title>Open: load</title>
5+
</head>
6+
<body>
7+
<h1>This popup opens on page load</h1>
8+
<p>If you see this you very likely already closed the popup.</p>
9+
<p>If the popup did not open automatically something is broken.</p>
10+
<a
11+
class="typeform-share"
12+
href="//betatests.typeform.com/to/Z9k3bK?disable-tracking=true"
13+
data-mode="popup"
14+
data-open="load"
15+
data-open-value="1"
16+
target="_blank"
17+
>
18+
Open the popup manually instead
19+
</a>
20+
21+
<script type="text/javascript" src="../embed.js"></script>
22+
<script type="text/javascript" src="../demo.js"></script>
23+
</body>
24+
</html>

demo/behavioral/scroll.html

Lines changed: 151 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,151 @@
1+
<!DOCTYPE html>
2+
<html>
3+
<head>
4+
<title>Open: scroll</title>
5+
<style>
6+
.scroll-indicator {
7+
position: fixed;
8+
top: 0;
9+
right: 0;
10+
text-align: right;
11+
padding: 20px;
12+
background: black;
13+
color: white;
14+
}
15+
.lorem-ipsum {
16+
opacity: 0.25;
17+
}
18+
</style>
19+
</head>
20+
<body>
21+
<div class="scroll-indicator">
22+
The popup will open at <span id="percent">30</span>%<br/>
23+
You scrolled <span id="scroll-pixels">0</span>px, that is <span id="scroll-percentage">0.00</span>% of the page
24+
</div>
25+
<h1>This popup opens on scroll - at <span id="percent-title">30</span>%</h1>
26+
<p>The popup is opened automatically when you scroll past given percentage of the page height.</p>
27+
<p>The popup is opened only once (when you scroll past the given percentage for the first time).</p>
28+
<a
29+
id="popup"
30+
class="typeform-share"
31+
href="//betatests.typeform.com/to/Z9k3bK?disable-tracking=true"
32+
data-mode="drawer_left"
33+
data-open="scroll"
34+
data-open-value="30"
35+
target="_blank"
36+
>
37+
Open the popup manually instead
38+
</a>
39+
40+
<h2>Customize the percentage</h2>
41+
<p>This can be set on "Share" page as well.</p>
42+
<form action="" method="get">
43+
<label for="threshold">Percent</label>
44+
<input id="threshold" name="percent" type="number" value="30" step="10" min="10" />
45+
<button type="submit">Set</button>
46+
</form>
47+
48+
<script>
49+
const param = window.location.search.match(/percent=(\d+)/)
50+
if (param) {
51+
const percent = parseInt(param[1], 10);
52+
document.getElementById('popup').dataset.openValue = percent;
53+
document.getElementById('threshold').value = percent;
54+
document.getElementById('percent').innerHTML = percent;
55+
document.getElementById('percent-title').innerHTML = percent;
56+
}
57+
document.addEventListener('scroll', function() {
58+
const offsetTop = window.pageYOffset || document.documentElement.scrollTop
59+
const clientTop = document.documentElement.clientTop || 0
60+
const scrollTopPixels = offsetTop - clientTop
61+
const scrollTopPercentage = scrollTopPixels / document.body.clientHeight * 100
62+
document.getElementById('scroll-pixels').innerHTML = scrollTopPixels;
63+
document.getElementById('scroll-percentage').innerHTML = (Math.round(scrollTopPercentage * 100) / 100).toFixed(2);
64+
})
65+
</script>
66+
67+
<script type="text/javascript" src="../embed.js"></script>
68+
<script type="text/javascript" src="../demo.js"></script>
69+
70+
<div class="lorem-ipsum">
71+
<h2>Random text to make the page long</h2>
72+
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed viverra aliquam augue vitae volutpat. Integer eu turpis elit.</p>
73+
<p>Mauris nec lobortis metus. Quisque commodo quis neque sed volutpat. Integer a bibendum ante, at dapibus arcu.</p>
74+
<p>Curabitur at suscipit enim. Aliquam ut urna nunc. Praesent nisl elit, iaculis nec lectus vitae, posuere aliquet velit.</p>
75+
<p>Aenean id porttitor nisi. Phasellus vel fermentum elit. In ut maximus risus, quis lobortis elit.</p>
76+
<p>Phasellus pellentesque placerat turpis ac semper. Duis ligula enim, vulputate sed erat vitae, vehicula bibendum turpis.</p>
77+
<p>Donec nibh purus, vehicula at mauris volutpat, placerat molestie diam.</p>
78+
<p>Mauris tristique posuere ipsum vitae venenatis. Donec ut orci id massa ullamcorper pulvinar.</p>
79+
<p>Morbi pulvinar ante mauris, at sollicitudin lorem molestie sit amet. Morbi tellus nisi, rutrum ut lectus et, luctus eleifend mi.</p>
80+
<p>Quisque felis enim, blandit in convallis in, bibendum non metus. Proin consectetur ut ante nec malesuada.</p>
81+
<p>Pellentesque interdum id metus condimentum varius. Nullam fringilla lacinia posuere.</p>
82+
<p>Morbi pellentesque ante vitae tellus ullamcorper sollicitudin. Proin leo dolor, molestie quis diam id, tempor ullamcorper diam.</p>
83+
<p>Donec sed pulvinar nunc, et posuere purus. Morbi ornare, diam eget blandit molestie, massa leo sollicitudin nisi.</p>
84+
<p>Id tempus ex nisi quis lectus. Etiam laoreet dui est, quis tempus augue pharetra et. Nullam sed elit turpis.</p>
85+
<p>Donec et mi tellus. Aliquam ut interdum dolor. Aliquam dapibus velit non nunc porttitor finibus.</p>
86+
<p>Proin elementum risus et molestie aliquam.</p>
87+
<p>Duis a egestas lectus, sed mattis nisl. Ut ultricies id mi vel varius. Donec nec laoreet orci.</p>
88+
<p>Morbi pulvinar ante mauris, at sollicitudin lorem molestie sit amet. Morbi tellus nisi, rutrum ut lectus et, luctus eleifend mi.</p>
89+
<p>Quisque felis enim, blandit in convallis in, bibendum non metus. Proin consectetur ut ante nec malesuada.</p>
90+
<p>Pellentesque interdum id metus condimentum varius. Nullam fringilla lacinia posuere.</p>
91+
<p>Morbi pellentesque ante vitae tellus ullamcorper sollicitudin. Proin leo dolor, molestie quis diam id, tempor ullamcorper diam.</p>
92+
<p>Donec sed pulvinar nunc, et posuere purus. Morbi ornare, diam eget blandit molestie, massa leo sollicitudin nisi.</p>
93+
<p>Id tempus ex nisi quis lectus. Etiam laoreet dui est, quis tempus augue pharetra et. Nullam sed elit turpis.</p>
94+
<p>Donec et mi tellus. Aliquam ut interdum dolor. Aliquam dapibus velit non nunc porttitor finibus.</p>
95+
<p>Proin elementum risus et molestie aliquam.</p>
96+
<p>Phasellus sagittis iaculis nisi at molestie. Aliquam id justo orci. Aenean cursus nulla sit amet lectus consequat vestibulum.</p>
97+
<p>In volutpat neque at egestas pellentesque. Vivamus in viverra eros, non facilisis mi.</p>
98+
<p>Suspendisse sed metus molestie dolor convallis porta eu vitae mauris. Curabitur pharetra, lorem non tincidunt sollicitudin.</p>
99+
<p>Odio tortor consequat nisi, et feugiat lectus odio sit amet nisi. Curabitur et tempor purus.</p>
100+
<p>Maecenas commodo lorem augue, sed varius est maximus auctor. Proin finibus justo eu ante bibendum mollis.</p>
101+
<p>Proin laoreet dapibus lorem a euismod. Integer dignissim eleifend efficitur. Pellentesque vitae pellentesque nisl.</p>
102+
<p>Suspendisse vitae sem vitae risus sollicitudin sagittis ac sed urna.</p>
103+
<p>In hac habitasse platea dictumst. Nulla sit amet mauris elit. Maecenas consectetur imperdiet nisl, a vestibulum lectus maximus vel.</p>
104+
<p>Nulla sagittis tempus arcu id vestibulum. Donec at nulla congue, luctus orci sit amet, scelerisque ante.</p>
105+
<p>Praesent faucibus, lacus et varius cursus, turpis nibh scelerisque est, sit amet lacinia sapien metus vitae tellus.</p>
106+
<p>Phasellus pellentesque placerat turpis ac semper. Duis ligula enim, vulputate sed erat vitae, vehicula bibendum turpis.</p>
107+
<p>Donec nibh purus, vehicula at mauris volutpat, placerat molestie diam.</p>
108+
<p>Mauris tristique posuere ipsum vitae venenatis. Donec ut orci id massa ullamcorper pulvinar.</p>
109+
<p>Mauris aliquam erat feugiat ligula faucibus, eu imperdiet ante molestie.</p>
110+
<p>Donec convallis, nisi at molestie fringilla, mi dolor suscipit risus, vitae gravida nulla libero vitae urna.</p>
111+
<p>Vestibulum id nisi mauris. In faucibus vitae massa eget feugiat. Morbi in arcu congue, iaculis eros ac, fermentum purus.</p>
112+
<p>Fusce lectus tortor, facilisis tincidunt varius ac, sodales quis eros. Pellentesque quis nulla a nisl feugiat pretium.</p>
113+
<p>Duis et magna finibus, hendrerit ligula non, rutrum nunc.</p>
114+
<p>Pellentesque interdum id metus condimentum varius. Nullam fringilla lacinia posuere.</p>
115+
<p>Morbi pellentesque ante vitae tellus ullamcorper sollicitudin. Proin leo dolor, molestie quis diam id, tempor ullamcorper diam.</p>
116+
<p>Donec sed pulvinar nunc, et posuere purus. Morbi ornare, diam eget blandit molestie, massa leo sollicitudin nisi.</p>
117+
<p>Id tempus ex nisi quis lectus. Etiam laoreet dui est, quis tempus augue pharetra et. Nullam sed elit turpis.</p>
118+
<p>Donec et mi tellus. Aliquam ut interdum dolor. Aliquam dapibus velit non nunc porttitor finibus.</p>
119+
<p>Proin elementum risus et molestie aliquam.</p>
120+
<p>Phasellus sagittis iaculis nisi at molestie. Aliquam id justo orci. Aenean cursus nulla sit amet lectus consequat vestibulum.</p>
121+
<p>In volutpat neque at egestas pellentesque. Vivamus in viverra eros, non facilisis mi.</p>
122+
<p>Suspendisse sed metus molestie dolor convallis porta eu vitae mauris. Curabitur pharetra, lorem non tincidunt sollicitudin.</p>
123+
<p>Odio tortor consequat nisi, et feugiat lectus odio sit amet nisi. Curabitur et tempor purus.</p>
124+
<p>Maecenas commodo lorem augue, sed varius est maximus auctor. Proin finibus justo eu ante bibendum mollis.</p>
125+
<p>Proin laoreet dapibus lorem a euismod. Integer dignissim eleifend efficitur. Pellentesque vitae pellentesque nisl.</p>
126+
<p>Suspendisse vitae sem vitae risus sollicitudin sagittis ac sed urna.</p>
127+
<p>In hac habitasse platea dictumst. Nulla sit amet mauris elit. Maecenas consectetur imperdiet nisl, a vestibulum lectus maximus vel.</p>
128+
<p>Nulla sagittis tempus arcu id vestibulum. Donec at nulla congue, luctus orci sit amet, scelerisque ante.</p>
129+
<p>Praesent faucibus, lacus et varius cursus, turpis nibh scelerisque est, sit amet lacinia sapien metus vitae tellus.</p>
130+
<p>Phasellus pellentesque placerat turpis ac semper. Duis ligula enim, vulputate sed erat vitae, vehicula bibendum turpis.</p>
131+
<p>Donec nibh purus, vehicula at mauris volutpat, placerat molestie diam.</p>
132+
<p>Mauris tristique posuere ipsum vitae venenatis. Donec ut orci id massa ullamcorper pulvinar.</p>
133+
<p>Morbi pulvinar ante mauris, at sollicitudin lorem molestie sit amet. Morbi tellus nisi, rutrum ut lectus et, luctus eleifend mi.</p>
134+
<p>Quisque felis enim, blandit in convallis in, bibendum non metus. Proin consectetur ut ante nec malesuada.</p>
135+
<p>Pellentesque interdum id metus condimentum varius. Nullam fringilla lacinia posuere.</p>
136+
<p>Morbi pellentesque ante vitae tellus ullamcorper sollicitudin. Proin leo dolor, molestie quis diam id, tempor ullamcorper diam.</p>
137+
<p>Donec sed pulvinar nunc, et posuere purus. Morbi ornare, diam eget blandit molestie, massa leo sollicitudin nisi.</p>
138+
<p>Id tempus ex nisi quis lectus. Etiam laoreet dui est, quis tempus augue pharetra et. Nullam sed elit turpis.</p>
139+
<p>Donec et mi tellus. Aliquam ut interdum dolor. Aliquam dapibus velit non nunc porttitor finibus.</p>
140+
<p>Proin elementum risus et molestie aliquam.</p>
141+
<p>Phasellus sagittis iaculis nisi at molestie. Aliquam id justo orci. Aenean cursus nulla sit amet lectus consequat vestibulum.</p>
142+
<p>In volutpat neque at egestas pellentesque. Vivamus in viverra eros, non facilisis mi.</p>
143+
<p>Suspendisse sed metus molestie dolor convallis porta eu vitae mauris. Curabitur pharetra, lorem non tincidunt sollicitudin.</p>
144+
<p>Odio tortor consequat nisi, et feugiat lectus odio sit amet nisi. Curabitur et tempor purus.</p>
145+
<p>Maecenas commodo lorem augue, sed varius est maximus auctor. Proin finibus justo eu ante bibendum mollis.</p>
146+
<p>Proin laoreet dapibus lorem a euismod. Integer dignissim eleifend efficitur. Pellentesque vitae pellentesque nisl.</p>
147+
<p>Suspendisse vitae sem vitae risus sollicitudin sagittis ac sed urna.</p>
148+
<p>Mauris aliquam erat feugiat ligula faucibus, eu imperdiet ante molestie.</p>
149+
</div>
150+
</body>
151+
</html>

demo/behavioral/time.html

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
<!DOCTYPE html>
2+
<html>
3+
<head>
4+
<title>Open: time</title>
5+
</head>
6+
<body>
7+
<h1>This popup opens in <span id="seconds">5</span> seconds</h1>
8+
<p>The popup is opened automatically after the given time has passed.</p>
9+
<a
10+
id="popup"
11+
class="typeform-share"
12+
href="//betatests.typeform.com/to/Z9k3bK?disable-tracking=true"
13+
data-mode="drawer_right"
14+
data-open="time"
15+
data-open-value="5000"
16+
target="_blank"
17+
>
18+
Open the popup manually instead
19+
</a>
20+
21+
<h2>Customize the time</h2>
22+
<p>This can be set on "Share" page as well.</p>
23+
<form action="" method="get">
24+
<label for="time">Milliseconds</label>
25+
<input id="time" name="ms" type="number" value="5000" step="1000" min="1000" />
26+
<button type="submit">Set</button>
27+
</form>
28+
29+
<script>
30+
const param = window.location.search.match(/ms=(\d+)/)
31+
if (param) {
32+
const ms = parseInt(param[1], 10);
33+
document.getElementById('popup').dataset.openValue = ms;
34+
document.getElementById('time').value = ms;
35+
document.getElementById('seconds').innerHTML = Math.round(ms / 1000);
36+
}
37+
</script>
38+
39+
<script type="text/javascript" src="../embed.js"></script>
40+
<script type="text/javascript" src="../demo.js"></script>
41+
</body>
42+
</html>

demo/index.html

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616
</style>
1717
</head>
1818
<body>
19-
<div class="content">
19+
<p class="content">
2020
<h1>Typeform Embed Examples</h1>
2121

2222
<h2>Embed snippet</h2>
@@ -31,6 +31,15 @@ <h2>Embed snippet</h2>
3131
<li><a href="./absolute.html">Widget in absolutely positioned element</a></li>
3232
</ul>
3333

34+
<h2>Behavioral popups</h2>
35+
<p>Custom launch options:</p>
36+
<ul>
37+
<li><a href="./behavioral/load.html">On page load</a></li>
38+
<li><a href="./behavioral/exit.html">On exit intent</a></li>
39+
<li><a href="./behavioral/time.html">After a set time</a></li>
40+
<li><a href="./behavioral/scroll.html">After scrolling</a></li>
41+
</ul>
42+
3443
<h2>Embed API</h2>
3544
<ul>
3645
<li><a href="./widget-api.html">Widget</a></li>

src/core/attributes.js

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -44,10 +44,6 @@ const sanitizePopupAttributes = data => {
4444
obj.autoClose = submitCloseDelay
4545
}
4646

47-
if (data.autoOpen === '' || data.autoOpen === 'true') {
48-
obj.autoOpen = true
49-
}
50-
5147
if (data.hideHeaders === '' || data.hideHeaders === 'true') {
5248
obj.hideHeaders = true
5349
}
@@ -60,6 +56,13 @@ const sanitizePopupAttributes = data => {
6056
obj.hideScrollbars = true
6157
}
6258

59+
if (data.open) {
60+
obj.open = data.open
61+
obj.openValue = data.openValue
62+
} else if (data.autoOpen === '' || data.autoOpen === 'true') { // legacy auto-open attribute
63+
obj.open = 'load'
64+
}
65+
6366
return obj
6467
}
6568

src/core/attributes.spec.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ describe('Attributes', () => {
1818
const popupOptions = {
1919
mode: 'popup',
2020
autoClose: 10,
21-
autoOpen: true,
21+
open: 'load',
2222
hideHeaders: true
2323
}
2424

src/core/make-popup.js

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -19,20 +19,22 @@ import Popup, {
1919
} from './views/popup'
2020
import MobileModal from './views/mobile-modal'
2121
import { getPostMessageHandler } from './utils/get-post-message-handler'
22+
import { handleAutoOpen } from './utils/popup-auto-open'
2223

2324
const DEFAULT_DRAWER_WIDTH = 800
2425

2526
const defaultOptions = {
2627
mode: POPUP,
27-
autoOpen: false,
2828
isModalOpen: false,
2929
autoClose: DEFAULT_AUTOCLOSE_TIMEOUT,
3030
hideFooter: false,
3131
hideHeaders: false,
3232
hideScrollbars: false,
3333
disableTracking: false,
3434
drawerWidth: DEFAULT_DRAWER_WIDTH,
35-
onSubmit: noop
35+
onSubmit: noop,
36+
open: null,
37+
openValue: null
3638
}
3739

3840
const queryStringKeys = {
@@ -129,9 +131,7 @@ export default function makePopup (url, options) {
129131
}
130132
}
131133

132-
if (options.autoOpen) {
133-
popup.open()
134-
}
134+
handleAutoOpen(popup, options.open, options.openValue)
135135

136136
return popup
137137
}

0 commit comments

Comments
 (0)