@flourish/sdk 4.1.0 → 4.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +15 -4
- package/RELEASE_NOTES.md +6 -0
- package/common/embed/credit.d.ts +5 -0
- package/common/embed/credit.js +47 -0
- package/common/embed/customer_analytics.d.ts +5 -0
- package/common/embed/customer_analytics.js +114 -0
- package/common/embed/embedding.d.ts +25 -0
- package/common/embed/embedding.js +461 -0
- package/common/embed/localizations.d.ts +243 -0
- package/common/embed/localizations.js +90 -0
- package/common/embed/parse_query_params.d.ts +2 -0
- package/common/embed/parse_query_params.js +18 -0
- package/common/package.json +8 -0
- package/common/tsconfig.sdk.tsbuildinfo +1 -0
- package/common/utils/columns.d.ts +11 -0
- package/common/utils/columns.js +175 -0
- package/common/utils/data.d.ts +30 -0
- package/common/utils/data.js +279 -0
- package/common/utils/json.d.ts +3 -0
- package/common/utils/json.js +60 -0
- package/common/utils/polyfills.d.ts +0 -0
- package/common/utils/polyfills.js +30 -0
- package/common/utils/state.d.ts +7 -0
- package/common/utils/state.js +144 -0
- package/lib/sdk.js +22 -3
- package/lib/validate_config.js +21 -10
- package/package.json +3 -6
- package/server/columns.js +1 -1
- package/server/comms_js.js +1 -0
- package/server/data.js +31 -6
- package/server/json.js +1 -1
- package/server/views/index.html +1 -1
- package/site/embedded.js +1 -1
- package/site/images/company.svg +5 -0
- package/site/images/icon-editable.svg +10 -0
- package/site/images/icon-presentation.svg +3 -0
- package/site/images/icon-private.svg +3 -0
- package/site/images/icon-sliders.svg +3 -0
- package/site/images/icon-upload.svg +3 -0
- package/site/images/icon-viewable.svg +3 -0
- package/site/images/refresh.svg +3 -0
- package/site/images/user.svg +3 -0
- package/site/images/visualisation_purpose.svg +3 -0
- package/site/images/visualisation_type.svg +3 -0
- package/site/script.js +2 -2
- package/site/sdk.css +1 -1
- package/test/lib/validate_config.js +45 -2
- package/utils/state.js +1 -1
|
@@ -0,0 +1,461 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/* This file is used by the story player, and must be IE-compatible */
|
|
3
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
4
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
5
|
+
};
|
|
6
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7
|
+
const customer_analytics_1 = require("./customer_analytics");
|
|
8
|
+
const parse_query_params_1 = __importDefault(require("./parse_query_params"));
|
|
9
|
+
var is_fixed_height;
|
|
10
|
+
var is_amp;
|
|
11
|
+
function isFixedHeight() {
|
|
12
|
+
if (is_fixed_height == undefined) {
|
|
13
|
+
var params = (0, parse_query_params_1.default)();
|
|
14
|
+
// "referrer" in params implies this is an Embedly embed
|
|
15
|
+
// Check whether embedding site is known to support dynamic resizing
|
|
16
|
+
if ("referrer" in params)
|
|
17
|
+
is_fixed_height = /^https:\/\/medium.com\//.test(params.referrer);
|
|
18
|
+
else
|
|
19
|
+
is_fixed_height = !("auto" in params);
|
|
20
|
+
}
|
|
21
|
+
return is_fixed_height;
|
|
22
|
+
}
|
|
23
|
+
function getHeightForBreakpoint(width) {
|
|
24
|
+
var breakpoint_width = width || window.innerWidth;
|
|
25
|
+
if (breakpoint_width > 999)
|
|
26
|
+
return 650;
|
|
27
|
+
if (breakpoint_width > 599)
|
|
28
|
+
return 575;
|
|
29
|
+
return 400;
|
|
30
|
+
}
|
|
31
|
+
function initScrolly(opts) {
|
|
32
|
+
if (!opts)
|
|
33
|
+
return;
|
|
34
|
+
if (window.top === window.self)
|
|
35
|
+
return;
|
|
36
|
+
var embedded_window = window;
|
|
37
|
+
if (embedded_window.location.pathname == "srcdoc")
|
|
38
|
+
embedded_window = embedded_window.parent;
|
|
39
|
+
var message = {
|
|
40
|
+
sender: "Flourish",
|
|
41
|
+
method: "scrolly",
|
|
42
|
+
};
|
|
43
|
+
if (opts) {
|
|
44
|
+
for (var name in opts)
|
|
45
|
+
message[name] = opts[name];
|
|
46
|
+
}
|
|
47
|
+
embedded_window.parent.postMessage(JSON.stringify(message), "*");
|
|
48
|
+
}
|
|
49
|
+
function notifyParentWindow(height, opts) {
|
|
50
|
+
if (window.top === window.self)
|
|
51
|
+
return;
|
|
52
|
+
var embedded_window = window;
|
|
53
|
+
if (embedded_window.location.pathname == "srcdoc")
|
|
54
|
+
embedded_window = embedded_window.parent;
|
|
55
|
+
if (is_amp) {
|
|
56
|
+
// Message is not stringified for AMP
|
|
57
|
+
height = parseInt(height, 10);
|
|
58
|
+
embedded_window.parent.postMessage({
|
|
59
|
+
sentinel: "amp",
|
|
60
|
+
type: "embed-size",
|
|
61
|
+
height: height,
|
|
62
|
+
}, "*");
|
|
63
|
+
return;
|
|
64
|
+
}
|
|
65
|
+
var message = {
|
|
66
|
+
sender: "Flourish",
|
|
67
|
+
context: "iframe.resize",
|
|
68
|
+
method: "resize",
|
|
69
|
+
height: height,
|
|
70
|
+
src: embedded_window.location.toString(),
|
|
71
|
+
};
|
|
72
|
+
if (opts) {
|
|
73
|
+
for (var name in opts)
|
|
74
|
+
message[name] = opts[name];
|
|
75
|
+
}
|
|
76
|
+
embedded_window.parent.postMessage(JSON.stringify(message), "*");
|
|
77
|
+
}
|
|
78
|
+
function isSafari() {
|
|
79
|
+
// Some example user agents:
|
|
80
|
+
// Safari iOS: Mozilla/5.0 (iPhone; CPU iPhone OS 12_1_3 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/12.0 Mobile/15E148 Safari/604.1
|
|
81
|
+
// Chrome OS X: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.98 Safari/537.36
|
|
82
|
+
// Embedded WkWebview on iOS: Mozilla/5.0 (iPhone; CPU iPhone OS 12_1_3 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Mobile/16D5039a
|
|
83
|
+
return (navigator.userAgent.indexOf("Safari") !== -1 || navigator.userAgent.indexOf("iPhone") !== -1) && navigator.userAgent.indexOf("Chrome") == -1;
|
|
84
|
+
}
|
|
85
|
+
function isString(s) {
|
|
86
|
+
return typeof s === "string" || s instanceof String;
|
|
87
|
+
}
|
|
88
|
+
function isPossibleHeight(n) {
|
|
89
|
+
if (typeof n === "number") {
|
|
90
|
+
return !isNaN(n) && (n >= 0);
|
|
91
|
+
}
|
|
92
|
+
else if (isString(n)) {
|
|
93
|
+
// First regex checks there is at least one digit in n and rejectsedge cases like "" and "px" that would pass second regex
|
|
94
|
+
// Given first regex, second regex makes sure that n is either a pure number or a number with a valid CSS unit
|
|
95
|
+
// Units based on https://developer.mozilla.org/en-US/docs/Learn/CSS/Building_blocks/Values_and_units#lengths plus %
|
|
96
|
+
return /\d/.test(n) && /^[0-9]*(\.[0-9]*)?(cm|mm|Q|in|pc|pt|px|em|ex|ch|rem|lh|vw|vh|vmin|vmax|%)?$/i.test(n);
|
|
97
|
+
}
|
|
98
|
+
return false;
|
|
99
|
+
}
|
|
100
|
+
function validateWarnMessage(message) {
|
|
101
|
+
if (message.method !== "warn") {
|
|
102
|
+
console.warn("BUG: validateWarnMessage called for method" + message.method);
|
|
103
|
+
return false;
|
|
104
|
+
}
|
|
105
|
+
if ((message.message != null) && !isString(message.message))
|
|
106
|
+
return false;
|
|
107
|
+
if ((message.explanation != null) && !isString(message.explanation))
|
|
108
|
+
return false;
|
|
109
|
+
return true;
|
|
110
|
+
}
|
|
111
|
+
function validateResizeMessage(message) {
|
|
112
|
+
if (message.method !== "resize") {
|
|
113
|
+
console.warn("BUG: validateResizeMessage called for method" + message.method);
|
|
114
|
+
return false;
|
|
115
|
+
}
|
|
116
|
+
if (!isString(message.src))
|
|
117
|
+
return false;
|
|
118
|
+
if (!isString(message.context))
|
|
119
|
+
return false;
|
|
120
|
+
if (!isPossibleHeight(message.height))
|
|
121
|
+
return false;
|
|
122
|
+
return true;
|
|
123
|
+
}
|
|
124
|
+
function validateSetSettingMessage(_message) {
|
|
125
|
+
throw new Error("Validation for setSetting is not implemented yet; see issue #4328");
|
|
126
|
+
}
|
|
127
|
+
function validateScrolly(message) {
|
|
128
|
+
if (message.method !== "scrolly") {
|
|
129
|
+
console.warn("BUG: validateScrolly called for method" + message.method);
|
|
130
|
+
return false;
|
|
131
|
+
}
|
|
132
|
+
if (!Array.isArray(message.slides))
|
|
133
|
+
return false;
|
|
134
|
+
return true;
|
|
135
|
+
}
|
|
136
|
+
function validateCustomerAnalyticsMessage(message) {
|
|
137
|
+
if (message.method !== "customerAnalytics") {
|
|
138
|
+
console.warn("BUG: validateCustomerAnalyticsMessage called for method" + message.method);
|
|
139
|
+
return false;
|
|
140
|
+
}
|
|
141
|
+
// We don't consume customer analytics messages; they're just passed
|
|
142
|
+
// on, and their structure is up to the customer, so there's no
|
|
143
|
+
// point in validating them.
|
|
144
|
+
return true;
|
|
145
|
+
}
|
|
146
|
+
function validateRequestUpload(message) {
|
|
147
|
+
if (message.method !== "request-upload") {
|
|
148
|
+
console.warn("BUG: validateResizeMessage called for method" + message.method);
|
|
149
|
+
return false;
|
|
150
|
+
}
|
|
151
|
+
// FIXME: when adding validation for setSetting (see above) we should
|
|
152
|
+
// also validate that this is a valid setting name of appropriate type
|
|
153
|
+
if (!isString(message.name))
|
|
154
|
+
return false;
|
|
155
|
+
if (!(message.accept == null || isString(message.accept)))
|
|
156
|
+
return false;
|
|
157
|
+
return true;
|
|
158
|
+
}
|
|
159
|
+
function getMessageValidators(methods) {
|
|
160
|
+
var available_message_validators = {
|
|
161
|
+
"warn": validateWarnMessage,
|
|
162
|
+
"resize": validateResizeMessage,
|
|
163
|
+
"setSetting": validateSetSettingMessage,
|
|
164
|
+
"customerAnalytics": validateCustomerAnalyticsMessage,
|
|
165
|
+
"request-upload": validateRequestUpload,
|
|
166
|
+
"scrolly": validateScrolly
|
|
167
|
+
};
|
|
168
|
+
var validators = {};
|
|
169
|
+
for (var i = 0; i < methods.length; i++) {
|
|
170
|
+
var method = methods[i];
|
|
171
|
+
if (available_message_validators[method]) {
|
|
172
|
+
validators[method] = available_message_validators[method];
|
|
173
|
+
}
|
|
174
|
+
else {
|
|
175
|
+
throw new Error("No validator found for method " + method);
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
return validators;
|
|
179
|
+
}
|
|
180
|
+
function startEventListeners(callback, allowed_methods, embed_domain) {
|
|
181
|
+
var message_validators = getMessageValidators(allowed_methods);
|
|
182
|
+
window.addEventListener("message", function (event) {
|
|
183
|
+
var is_accepted_event_origin = (function () {
|
|
184
|
+
if (event.origin == document.location.origin) {
|
|
185
|
+
return true;
|
|
186
|
+
}
|
|
187
|
+
// If company has configured a custom origin for downloaded projects, allow it
|
|
188
|
+
if (embed_domain) {
|
|
189
|
+
const origin = event.origin.toLowerCase();
|
|
190
|
+
embed_domain = embed_domain.toLowerCase();
|
|
191
|
+
// Allow the domain itself…
|
|
192
|
+
if (origin.endsWith("//" + embed_domain))
|
|
193
|
+
return true;
|
|
194
|
+
// and subdomains
|
|
195
|
+
if (origin.endsWith("." + embed_domain))
|
|
196
|
+
return true;
|
|
197
|
+
}
|
|
198
|
+
if (event.origin.match(/\/\/localhost:\d+$|\/\/(?:public|app)\.flourish.devlocal$|\/\/flourish-api\.com$|\.flourish\.(?:local(:\d+)?|net|rocks|studio)$|\.uri\.sh$|\/\/flourish-user-templates\.com$/)) {
|
|
199
|
+
return true;
|
|
200
|
+
}
|
|
201
|
+
return false;
|
|
202
|
+
})();
|
|
203
|
+
// event.source is null when the message is sent by an extension
|
|
204
|
+
// https://developer.mozilla.org/en-US/docs/Web/API/Window/postMessage#Using_window.postMessage_in_extensions
|
|
205
|
+
if (event.source == null)
|
|
206
|
+
return;
|
|
207
|
+
if (!is_accepted_event_origin)
|
|
208
|
+
return;
|
|
209
|
+
var message;
|
|
210
|
+
try {
|
|
211
|
+
message = typeof event.data === "object" ? event.data : JSON.parse(event.data);
|
|
212
|
+
}
|
|
213
|
+
catch (e) {
|
|
214
|
+
console.warn("Unexpected non-JSON message: " + JSON.stringify(event.data));
|
|
215
|
+
return;
|
|
216
|
+
}
|
|
217
|
+
if (message.sender !== "Flourish")
|
|
218
|
+
return;
|
|
219
|
+
if (!message.method) {
|
|
220
|
+
console.warn("The 'method' property was missing from message", message);
|
|
221
|
+
return;
|
|
222
|
+
}
|
|
223
|
+
if (!Object.prototype.hasOwnProperty.call(message_validators, message.method)) {
|
|
224
|
+
console.warn("No validator implemented for message", message);
|
|
225
|
+
return;
|
|
226
|
+
}
|
|
227
|
+
if (!message_validators[message.method](message)) {
|
|
228
|
+
console.warn("Validation failed for the message", message);
|
|
229
|
+
return;
|
|
230
|
+
}
|
|
231
|
+
var frames = document.querySelectorAll("iframe");
|
|
232
|
+
for (var i = 0; i < frames.length; i++) {
|
|
233
|
+
if (frames[i].contentWindow == event.source || frames[i].contentWindow == event.source.parent) {
|
|
234
|
+
callback(message, frames[i]);
|
|
235
|
+
return;
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
console.warn("could not find frame", message);
|
|
239
|
+
});
|
|
240
|
+
if (isSafari()) {
|
|
241
|
+
window.addEventListener("resize", onSafariWindowResize);
|
|
242
|
+
onSafariWindowResize();
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
function onSafariWindowResize() {
|
|
246
|
+
// Ensure all iframes without explicit width attribute are sized to fit their container
|
|
247
|
+
var containers = document.querySelectorAll(".flourish-embed");
|
|
248
|
+
for (var i = 0; i < containers.length; i++) {
|
|
249
|
+
var container = containers[i];
|
|
250
|
+
if (container.getAttribute("data-width"))
|
|
251
|
+
continue;
|
|
252
|
+
var iframe = container.querySelector("iframe");
|
|
253
|
+
// When embeds are dynamically loaded, we might have a container without a
|
|
254
|
+
// loaded iframe yet
|
|
255
|
+
if (!iframe)
|
|
256
|
+
continue;
|
|
257
|
+
var computed_style = window.getComputedStyle(container);
|
|
258
|
+
var width = container.offsetWidth - parseFloat(computed_style.paddingLeft) - parseFloat(computed_style.paddingRight);
|
|
259
|
+
iframe.style.width = width + "px";
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
function createScrolly(iframe, slides) {
|
|
263
|
+
var parent = iframe.parentNode;
|
|
264
|
+
// Fallback to avoid any situation where the scrolly gets initialised twice
|
|
265
|
+
if (parent.classList.contains("fl-scrolly-wrapper")) {
|
|
266
|
+
console.warn("createScrolly is being called more than once per story. This should not happen.");
|
|
267
|
+
return;
|
|
268
|
+
}
|
|
269
|
+
parent.classList.add("fl-scrolly-wrapper");
|
|
270
|
+
parent.style.position = "relative";
|
|
271
|
+
parent.style.paddingBottom = "1px";
|
|
272
|
+
parent.style.transform = "translate3d(0, 0, 0)"; // Workaround for Safari https://stackoverflow.com/questions/50224855/not-respecting-z-index-on-safari-with-position-sticky
|
|
273
|
+
iframe.style.position = "sticky";
|
|
274
|
+
var h = parent.getAttribute("data-height") || null;
|
|
275
|
+
if (!h) { // Scrollies require fixed height to work well, so if not height set …
|
|
276
|
+
h = "80vh"; // … use a sensible fallback
|
|
277
|
+
iframe.style.height = h; // And update the iframe height directly
|
|
278
|
+
}
|
|
279
|
+
iframe.style.top = "calc(50vh - " + h + "/2)";
|
|
280
|
+
var credit = parent.querySelector(".flourish-credit");
|
|
281
|
+
if (credit) {
|
|
282
|
+
credit.style.position = "sticky";
|
|
283
|
+
credit.style.top = "calc(50vh + " + h + "/2)";
|
|
284
|
+
}
|
|
285
|
+
slides.forEach(function (d, i) {
|
|
286
|
+
var has_content = typeof d == "string" && d.trim() != "";
|
|
287
|
+
var step = document.createElement("div");
|
|
288
|
+
step.setAttribute("data-slide", i);
|
|
289
|
+
step.classList.add("fl-scrolly-caption");
|
|
290
|
+
step.style.position = "relative";
|
|
291
|
+
step.style.transform = "translate3d(0,0,0)"; // Workaround for Safari https://stackoverflow.com/questions/50224855/not-respecting-z-index-on-safari-with-position-sticky
|
|
292
|
+
step.style.textAlign = "center";
|
|
293
|
+
step.style.maxWidth = "500px";
|
|
294
|
+
step.style.height = "auto";
|
|
295
|
+
step.style.marginTop = "0";
|
|
296
|
+
step.style.marginBottom = has_content ? "100vh" : "50vh";
|
|
297
|
+
step.style.marginLeft = "auto";
|
|
298
|
+
step.style.marginRight = "auto";
|
|
299
|
+
var caption = document.createElement("div");
|
|
300
|
+
caption.innerHTML = d;
|
|
301
|
+
caption.style.visibility = has_content ? "" : "hidden";
|
|
302
|
+
caption.style.display = "inline-block";
|
|
303
|
+
caption.style.paddingTop = "1.25em";
|
|
304
|
+
caption.style.paddingRight = "1.25em";
|
|
305
|
+
caption.style.paddingBottom = "1.25em";
|
|
306
|
+
caption.style.paddingLeft = "1.25em";
|
|
307
|
+
caption.style.background = "rgba(255,255,255,0.9)";
|
|
308
|
+
caption.style.boxShadow = "0px 0px 10px rgba(0,0,0,0.2)";
|
|
309
|
+
caption.style.borderRadius = "10px";
|
|
310
|
+
caption.style.textAlign = "center";
|
|
311
|
+
caption.style.maxWidth = "100%";
|
|
312
|
+
caption.style.margin = "0 20px";
|
|
313
|
+
caption.style.overflowX = "hidden";
|
|
314
|
+
step.appendChild(caption);
|
|
315
|
+
parent.appendChild(step);
|
|
316
|
+
});
|
|
317
|
+
initIntersection(parent);
|
|
318
|
+
}
|
|
319
|
+
function initIntersection(container) {
|
|
320
|
+
var t = "0%"; // Trigger when hits viewport; could be set by user in the future
|
|
321
|
+
var observer = new IntersectionObserver(function (entries) {
|
|
322
|
+
entries.forEach(function (entry) {
|
|
323
|
+
if (entry.isIntersecting) {
|
|
324
|
+
var iframe = container.querySelector("iframe");
|
|
325
|
+
if (iframe)
|
|
326
|
+
iframe.src = iframe.src.replace(/#slide-.*/, "") + "#slide-" + entry.target.getAttribute("data-slide");
|
|
327
|
+
}
|
|
328
|
+
});
|
|
329
|
+
}, { rootMargin: "0px 0px -" + t + " 0px" });
|
|
330
|
+
var steps = container.querySelectorAll(".fl-scrolly-caption");
|
|
331
|
+
for (var i = 0; i < steps.length; i++) {
|
|
332
|
+
observer.observe(steps[i]);
|
|
333
|
+
}
|
|
334
|
+
// Set a max width on any images in the captions, to avoid ugly overflowing
|
|
335
|
+
// in the rare cases where the
|
|
336
|
+
// This won't happen much, but it is possible to paste an image into a
|
|
337
|
+
// story caption, so better to handle this nicely since there's no other
|
|
338
|
+
// way for the user to set it.
|
|
339
|
+
var images = container.querySelectorAll(".fl-scrolly-caption img");
|
|
340
|
+
images.forEach(function (img) { img.style.maxWidth = "100%"; });
|
|
341
|
+
}
|
|
342
|
+
function createEmbedIframe(embed_url, container, width, height, play_on_load) {
|
|
343
|
+
var iframe = document.createElement("iframe");
|
|
344
|
+
iframe.setAttribute("scrolling", "no");
|
|
345
|
+
iframe.setAttribute("frameborder", "0");
|
|
346
|
+
iframe.setAttribute("title", "Interactive or visual content");
|
|
347
|
+
iframe.setAttribute("sandbox", "allow-same-origin allow-forms allow-scripts allow-downloads allow-popups allow-popups-to-escape-sandbox allow-top-navigation-by-user-activation");
|
|
348
|
+
container.appendChild(iframe);
|
|
349
|
+
// If the iframe doesn't have an offset parent, either the element or a parent
|
|
350
|
+
// is set to display: none. This can cause problems with visualisation loading, so
|
|
351
|
+
// we need to poll for the iframe being displayed before loading the visualisation.
|
|
352
|
+
// FIXME: In Chrome, fixed position elements also return null for `offsetParent`.
|
|
353
|
+
// The chances of an embed which is both position: fixed and display: none are
|
|
354
|
+
// pretty small, so fuhgeddaboudit . If it's an issue in the future, we'll have to
|
|
355
|
+
// recurse through the parent elements to make sure the iframe is displaying.
|
|
356
|
+
if (iframe.offsetParent || getComputedStyle(iframe).position === "fixed") {
|
|
357
|
+
setIframeContent(embed_url, container, iframe, width, height, play_on_load);
|
|
358
|
+
}
|
|
359
|
+
else {
|
|
360
|
+
var poll_item = {
|
|
361
|
+
embed_url: embed_url,
|
|
362
|
+
container: container,
|
|
363
|
+
iframe: iframe,
|
|
364
|
+
width: width,
|
|
365
|
+
height: height,
|
|
366
|
+
play_on_load: play_on_load
|
|
367
|
+
};
|
|
368
|
+
// If this is the first embed on the page which is isn't displayed, set up a
|
|
369
|
+
// list of hidden iframes to poll
|
|
370
|
+
if (!window._flourish_poll_items) {
|
|
371
|
+
window._flourish_poll_items = [poll_item];
|
|
372
|
+
}
|
|
373
|
+
else {
|
|
374
|
+
// Otherwise, add this to the list of iframes which are being polled
|
|
375
|
+
window._flourish_poll_items.push(poll_item);
|
|
376
|
+
}
|
|
377
|
+
if (window._flourish_poll_items.length > 1) {
|
|
378
|
+
// If there were already items in the array then we have already started
|
|
379
|
+
// polling in a different embed script, so we can return. This iframe will
|
|
380
|
+
// have its contents set by the other embed script.
|
|
381
|
+
return iframe;
|
|
382
|
+
}
|
|
383
|
+
// Poll to see whether any of the iframes have started displaying
|
|
384
|
+
var interval = setInterval(function () {
|
|
385
|
+
window._flourish_poll_items = window._flourish_poll_items.filter(function (item) {
|
|
386
|
+
if (!item.iframe.offsetParent) {
|
|
387
|
+
// It's still not displaying, so return true to leave it in the array
|
|
388
|
+
return true;
|
|
389
|
+
}
|
|
390
|
+
// It's displaying, so set the content, and return false to remove it from
|
|
391
|
+
// the array
|
|
392
|
+
setIframeContent(item.embed_url, item.container, item.iframe, item.width, item.height, item.play_on_load);
|
|
393
|
+
return false;
|
|
394
|
+
});
|
|
395
|
+
if (!window._flourish_poll_items.length) {
|
|
396
|
+
// All of the iframes are displaying, so we can stop polling. If another
|
|
397
|
+
// embed is added later, a new interval will be created by that embed script.
|
|
398
|
+
clearInterval(interval);
|
|
399
|
+
}
|
|
400
|
+
}, 500);
|
|
401
|
+
}
|
|
402
|
+
return iframe;
|
|
403
|
+
}
|
|
404
|
+
function setIframeContent(embed_url, container, iframe, width, height, play_on_load) {
|
|
405
|
+
var width_in_px;
|
|
406
|
+
if (width && typeof width === "number") {
|
|
407
|
+
width_in_px = width;
|
|
408
|
+
width = "" + width + "px";
|
|
409
|
+
}
|
|
410
|
+
// The regular expression below detects widths that have been explicitly
|
|
411
|
+
// expressed in px units. (It turns out CSS is more complicated than you may
|
|
412
|
+
// have realised.)
|
|
413
|
+
else if (width && width.match(/^[ \t\r\n\f]*([+-]?\d+|\d*\.\d+(?:[eE][+-]?\d+)?)(?:\\?[Pp]|\\0{0,4}[57]0(?:\r\n|[ \t\r\n\f])?)(?:\\?[Xx]|\\0{0,4}[57]8(?:\r\n|[ \t\r\n\f])?)[ \t\r\n\f]*$/)) {
|
|
414
|
+
width_in_px = parseFloat(width);
|
|
415
|
+
}
|
|
416
|
+
if (height && typeof height === "number")
|
|
417
|
+
height = "" + height + "px";
|
|
418
|
+
// Odd design decision in Safari means need to set fixed width rather than %
|
|
419
|
+
// as will try and size iframe to content otherwise. Must also set scrolling=no
|
|
420
|
+
if (width)
|
|
421
|
+
iframe.style.width = width;
|
|
422
|
+
else if (isSafari())
|
|
423
|
+
iframe.style.width = container.offsetWidth + "px";
|
|
424
|
+
else
|
|
425
|
+
iframe.style.width = "100%";
|
|
426
|
+
var fixed_height = !!height;
|
|
427
|
+
if (!fixed_height) {
|
|
428
|
+
if (embed_url.match(/\?/))
|
|
429
|
+
embed_url += "&auto=1";
|
|
430
|
+
else
|
|
431
|
+
embed_url += "?auto=1";
|
|
432
|
+
// For initial height, use our standard breakpoints, based on the explicit
|
|
433
|
+
// pixel width if we know it, or the iframe's measured width if not.
|
|
434
|
+
height = getHeightForBreakpoint(width_in_px || iframe.offsetWidth) + "px";
|
|
435
|
+
}
|
|
436
|
+
if (height) {
|
|
437
|
+
if (height.charAt(height.length - 1) === "%") {
|
|
438
|
+
height = (parseFloat(height) / 100) * container.parentNode.offsetHeight + "px";
|
|
439
|
+
}
|
|
440
|
+
iframe.style.height = height;
|
|
441
|
+
}
|
|
442
|
+
iframe.setAttribute("src", embed_url + (play_on_load ? "#play-on-load" : ""));
|
|
443
|
+
return iframe;
|
|
444
|
+
}
|
|
445
|
+
function initEmbedding() {
|
|
446
|
+
is_amp = window.location.hash == "#amp=1";
|
|
447
|
+
return {
|
|
448
|
+
createEmbedIframe: createEmbedIframe,
|
|
449
|
+
isFixedHeight: isFixedHeight,
|
|
450
|
+
getHeightForBreakpoint: getHeightForBreakpoint,
|
|
451
|
+
startEventListeners: startEventListeners,
|
|
452
|
+
notifyParentWindow: notifyParentWindow,
|
|
453
|
+
initScrolly: initScrolly,
|
|
454
|
+
createScrolly: createScrolly,
|
|
455
|
+
isSafari: isSafari,
|
|
456
|
+
initCustomerAnalytics: customer_analytics_1.initCustomerAnalytics,
|
|
457
|
+
addAnalyticsListener: customer_analytics_1.addAnalyticsListener,
|
|
458
|
+
sendCustomerAnalyticsMessage: customer_analytics_1.sendCustomerAnalyticsMessage
|
|
459
|
+
};
|
|
460
|
+
}
|
|
461
|
+
exports.default = initEmbedding;
|
|
@@ -0,0 +1,243 @@
|
|
|
1
|
+
declare namespace _default {
|
|
2
|
+
namespace de {
|
|
3
|
+
namespace credits {
|
|
4
|
+
const _default: string;
|
|
5
|
+
export { _default as default };
|
|
6
|
+
}
|
|
7
|
+
}
|
|
8
|
+
namespace en {
|
|
9
|
+
const credits_1: {
|
|
10
|
+
default: {
|
|
11
|
+
text: string;
|
|
12
|
+
url: string;
|
|
13
|
+
};
|
|
14
|
+
annotator: {
|
|
15
|
+
text: string;
|
|
16
|
+
url: string;
|
|
17
|
+
};
|
|
18
|
+
"bar-chart-race": {
|
|
19
|
+
text: string;
|
|
20
|
+
url: string;
|
|
21
|
+
};
|
|
22
|
+
"bubble-chart": {
|
|
23
|
+
text: string;
|
|
24
|
+
url: string;
|
|
25
|
+
};
|
|
26
|
+
cards: {
|
|
27
|
+
text: string;
|
|
28
|
+
url: string;
|
|
29
|
+
};
|
|
30
|
+
chart: {
|
|
31
|
+
text: string;
|
|
32
|
+
url: string;
|
|
33
|
+
};
|
|
34
|
+
chord: {
|
|
35
|
+
text: string;
|
|
36
|
+
url: string;
|
|
37
|
+
};
|
|
38
|
+
countdown: {
|
|
39
|
+
text: string;
|
|
40
|
+
url: string;
|
|
41
|
+
};
|
|
42
|
+
"data-explorer": {
|
|
43
|
+
text: string;
|
|
44
|
+
url: string;
|
|
45
|
+
};
|
|
46
|
+
draw: {
|
|
47
|
+
text: string;
|
|
48
|
+
url: string;
|
|
49
|
+
};
|
|
50
|
+
election: {
|
|
51
|
+
text: string;
|
|
52
|
+
url: string;
|
|
53
|
+
};
|
|
54
|
+
gantt: {
|
|
55
|
+
text: string;
|
|
56
|
+
url: string;
|
|
57
|
+
};
|
|
58
|
+
gauge: {
|
|
59
|
+
text: string;
|
|
60
|
+
url: string;
|
|
61
|
+
};
|
|
62
|
+
globe: {
|
|
63
|
+
text: string;
|
|
64
|
+
url: string;
|
|
65
|
+
};
|
|
66
|
+
heatmap: {
|
|
67
|
+
text: string;
|
|
68
|
+
url: string;
|
|
69
|
+
};
|
|
70
|
+
hierarchy: {
|
|
71
|
+
text: string;
|
|
72
|
+
url: string;
|
|
73
|
+
};
|
|
74
|
+
map: {
|
|
75
|
+
text: string;
|
|
76
|
+
url: string;
|
|
77
|
+
};
|
|
78
|
+
marimekko: {
|
|
79
|
+
text: string;
|
|
80
|
+
url: string;
|
|
81
|
+
};
|
|
82
|
+
model: {
|
|
83
|
+
text: string;
|
|
84
|
+
url: string;
|
|
85
|
+
};
|
|
86
|
+
network: {
|
|
87
|
+
text: string;
|
|
88
|
+
url: string;
|
|
89
|
+
};
|
|
90
|
+
"number-ticker": {
|
|
91
|
+
text: string;
|
|
92
|
+
url: string;
|
|
93
|
+
};
|
|
94
|
+
parliament: {
|
|
95
|
+
text: string;
|
|
96
|
+
url: string;
|
|
97
|
+
};
|
|
98
|
+
"photo-slider": {
|
|
99
|
+
text: string;
|
|
100
|
+
url: string;
|
|
101
|
+
};
|
|
102
|
+
pictogram: {
|
|
103
|
+
text: string;
|
|
104
|
+
url: string;
|
|
105
|
+
};
|
|
106
|
+
quiz: {
|
|
107
|
+
text: string;
|
|
108
|
+
url: string;
|
|
109
|
+
};
|
|
110
|
+
radar: {
|
|
111
|
+
text: string;
|
|
112
|
+
url: string;
|
|
113
|
+
};
|
|
114
|
+
ranking: {
|
|
115
|
+
text: string;
|
|
116
|
+
url: string;
|
|
117
|
+
};
|
|
118
|
+
sankey: {
|
|
119
|
+
text: string;
|
|
120
|
+
url: string;
|
|
121
|
+
};
|
|
122
|
+
scatter: {
|
|
123
|
+
text: string;
|
|
124
|
+
url: string;
|
|
125
|
+
};
|
|
126
|
+
slope: {
|
|
127
|
+
text: string;
|
|
128
|
+
url: string;
|
|
129
|
+
};
|
|
130
|
+
sports: {
|
|
131
|
+
text: string;
|
|
132
|
+
url: string;
|
|
133
|
+
};
|
|
134
|
+
survey: {
|
|
135
|
+
text: string;
|
|
136
|
+
url: string;
|
|
137
|
+
};
|
|
138
|
+
table: {
|
|
139
|
+
text: string;
|
|
140
|
+
url: string;
|
|
141
|
+
};
|
|
142
|
+
timeline: {
|
|
143
|
+
text: string;
|
|
144
|
+
url: string;
|
|
145
|
+
};
|
|
146
|
+
"text-annotator": {
|
|
147
|
+
text: string;
|
|
148
|
+
url: string;
|
|
149
|
+
};
|
|
150
|
+
tournament: {
|
|
151
|
+
text: string;
|
|
152
|
+
url: string;
|
|
153
|
+
};
|
|
154
|
+
"word-cloud": {
|
|
155
|
+
text: string;
|
|
156
|
+
url: string;
|
|
157
|
+
};
|
|
158
|
+
};
|
|
159
|
+
export { credits_1 as credits };
|
|
160
|
+
}
|
|
161
|
+
namespace es {
|
|
162
|
+
const credits_2: {
|
|
163
|
+
default: string;
|
|
164
|
+
bar_race: {
|
|
165
|
+
text: string;
|
|
166
|
+
url: string;
|
|
167
|
+
};
|
|
168
|
+
"bar-chart-race": {
|
|
169
|
+
text: string;
|
|
170
|
+
url: string;
|
|
171
|
+
};
|
|
172
|
+
};
|
|
173
|
+
export { credits_2 as credits };
|
|
174
|
+
}
|
|
175
|
+
namespace fr {
|
|
176
|
+
const credits_3: {
|
|
177
|
+
default: string;
|
|
178
|
+
bar_race: {
|
|
179
|
+
text: string;
|
|
180
|
+
url: string;
|
|
181
|
+
};
|
|
182
|
+
"bar-chart-race": {
|
|
183
|
+
text: string;
|
|
184
|
+
url: string;
|
|
185
|
+
};
|
|
186
|
+
};
|
|
187
|
+
export { credits_3 as credits };
|
|
188
|
+
}
|
|
189
|
+
namespace it {
|
|
190
|
+
const credits_4: {
|
|
191
|
+
default: string;
|
|
192
|
+
bar_race: {
|
|
193
|
+
text: string;
|
|
194
|
+
url: string;
|
|
195
|
+
};
|
|
196
|
+
"bar-chart-race": {
|
|
197
|
+
text: string;
|
|
198
|
+
url: string;
|
|
199
|
+
};
|
|
200
|
+
};
|
|
201
|
+
export { credits_4 as credits };
|
|
202
|
+
}
|
|
203
|
+
namespace mi {
|
|
204
|
+
const credits_5: {
|
|
205
|
+
default: string;
|
|
206
|
+
bar_race: {
|
|
207
|
+
text: string;
|
|
208
|
+
url: string;
|
|
209
|
+
};
|
|
210
|
+
"bar-chart-race": {
|
|
211
|
+
text: string;
|
|
212
|
+
url: string;
|
|
213
|
+
};
|
|
214
|
+
};
|
|
215
|
+
export { credits_5 as credits };
|
|
216
|
+
}
|
|
217
|
+
namespace nl {
|
|
218
|
+
const credits_6: {
|
|
219
|
+
default: string;
|
|
220
|
+
bar_race: {
|
|
221
|
+
text: string;
|
|
222
|
+
url: string;
|
|
223
|
+
};
|
|
224
|
+
"bar-chart-race": {
|
|
225
|
+
text: string;
|
|
226
|
+
url: string;
|
|
227
|
+
};
|
|
228
|
+
};
|
|
229
|
+
export { credits_6 as credits };
|
|
230
|
+
}
|
|
231
|
+
const pt: {
|
|
232
|
+
default: string;
|
|
233
|
+
bar_race: {
|
|
234
|
+
text: string;
|
|
235
|
+
url: string;
|
|
236
|
+
};
|
|
237
|
+
"bar-chart-race": {
|
|
238
|
+
text: string;
|
|
239
|
+
url: string;
|
|
240
|
+
};
|
|
241
|
+
};
|
|
242
|
+
}
|
|
243
|
+
export default _default;
|