@flourish/sdk 4.2.0 → 4.2.1
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/RELEASE_NOTES.md +3 -0
- package/lib/sdk.js +25 -5
- package/package.json +1 -1
- package/site/script.js +1 -1
- package/common/embed/credit.d.ts +0 -5
- package/common/embed/credit.js +0 -47
- package/common/embed/customer_analytics.d.ts +0 -5
- package/common/embed/customer_analytics.js +0 -114
- package/common/embed/embedding.d.ts +0 -25
- package/common/embed/embedding.js +0 -461
- package/common/embed/localizations.d.ts +0 -243
- package/common/embed/localizations.js +0 -90
- package/common/embed/parse_query_params.d.ts +0 -2
- package/common/embed/parse_query_params.js +0 -18
- package/common/package.json +0 -8
- package/common/tsconfig.sdk.tsbuildinfo +0 -1
- package/common/utils/columns.d.ts +0 -11
- package/common/utils/columns.js +0 -175
- package/common/utils/data.d.ts +0 -30
- package/common/utils/data.js +0 -279
- package/common/utils/json.d.ts +0 -3
- package/common/utils/json.js +0 -60
- package/common/utils/polyfills.d.ts +0 -0
- package/common/utils/polyfills.js +0 -30
- package/common/utils/state.d.ts +0 -7
- package/common/utils/state.js +0 -144
package/common/embed/credit.d.ts
DELETED
package/common/embed/credit.js
DELETED
|
@@ -1,47 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
-
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
-
};
|
|
5
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
exports.getLocalizedCreditTextAndUrl = exports.createFlourishCredit = void 0;
|
|
7
|
-
const localizations_1 = __importDefault(require("./localizations"));
|
|
8
|
-
function createFlourishCredit(credit_url, query_string, public_url, credit_text) {
|
|
9
|
-
credit_url = credit_url || "https://flourish.studio",
|
|
10
|
-
query_string = query_string || "?utm_source=api&utm_campaign=" + window.location.href,
|
|
11
|
-
public_url = public_url || "https://public.flourish.studio/",
|
|
12
|
-
credit_text = credit_text || "A Flourish data visualization";
|
|
13
|
-
var credit = document.createElement("div");
|
|
14
|
-
credit.setAttribute("class", "flourish-credit");
|
|
15
|
-
credit.setAttribute("style", "width:100%!important;margin:0 0 4px!important;text-align:right!important;font-family:Helvetica,sans-serif!important;color:#888!important;font-size:11px!important;font-weight:bold!important;font-style:normal!important;-webkit-font-smoothing:antialiased!important;box-shadow:none!important;");
|
|
16
|
-
var a = document.createElement("a");
|
|
17
|
-
a.setAttribute("href", credit_url + query_string);
|
|
18
|
-
a.setAttribute("target", "_top");
|
|
19
|
-
a.setAttribute("style", "display:inline-block!important;text-decoration:none!important;font:inherit!important;color:inherit!important;border:none!important;margin:0 5px!important;box-shadow:none!important;");
|
|
20
|
-
credit.appendChild(a);
|
|
21
|
-
var img = document.createElement("img");
|
|
22
|
-
img.setAttribute("alt", "Flourish logo");
|
|
23
|
-
img.setAttribute("src", public_url + "resources/bosh.svg");
|
|
24
|
-
img.setAttribute("style", "font:inherit!important;width:auto!important;height:12px!important;border:none!important;margin:0 2px 0!important;vertical-align:middle!important;display:inline-block!important;box-shadow:none!important;");
|
|
25
|
-
a.appendChild(img);
|
|
26
|
-
var span = document.createElement("span");
|
|
27
|
-
span.setAttribute("style", "font:inherit!important;color:#888!important;vertical-align:middle!important;display:inline-block!important;box-shadow:none!important;");
|
|
28
|
-
span.appendChild(document.createTextNode(credit_text));
|
|
29
|
-
a.appendChild(span);
|
|
30
|
-
return credit;
|
|
31
|
-
}
|
|
32
|
-
exports.createFlourishCredit = createFlourishCredit;
|
|
33
|
-
function getLocalizedCreditTextAndUrl(lang, credit_key) {
|
|
34
|
-
var credit_text, credit_url;
|
|
35
|
-
lang = lang || "en", credit_key = credit_key || "";
|
|
36
|
-
credit_text = localizations_1.default[lang].credits[credit_key] || localizations_1.default.en.credits[credit_key] || localizations_1.default.en.credits.default;
|
|
37
|
-
if (typeof credit_text == "object") {
|
|
38
|
-
if (credit_text.url)
|
|
39
|
-
credit_url = credit_text.url;
|
|
40
|
-
credit_text = credit_text.text;
|
|
41
|
-
}
|
|
42
|
-
return {
|
|
43
|
-
credit_text: credit_text,
|
|
44
|
-
credit_url: credit_url
|
|
45
|
-
};
|
|
46
|
-
}
|
|
47
|
-
exports.getLocalizedCreditTextAndUrl = getLocalizedCreditTextAndUrl;
|
|
@@ -1,5 +0,0 @@
|
|
|
1
|
-
export function sendCustomerAnalyticsMessage(message: any): void;
|
|
2
|
-
export function addAnalyticsListener(callback: any): void;
|
|
3
|
-
export function removeAnalyticsListener(callback: any): void;
|
|
4
|
-
export function dispatchAnalyticsEvent(message: any): void;
|
|
5
|
-
export function initCustomerAnalytics(): void;
|
|
@@ -1,114 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.initCustomerAnalytics = exports.dispatchAnalyticsEvent = exports.removeAnalyticsListener = exports.addAnalyticsListener = exports.sendCustomerAnalyticsMessage = void 0;
|
|
4
|
-
// Embedded code - must work in IE
|
|
5
|
-
var enabled = false;
|
|
6
|
-
function getLocationData() {
|
|
7
|
-
var data = {};
|
|
8
|
-
if (window._Flourish_template_id) {
|
|
9
|
-
data.template_id = window._Flourish_template_id;
|
|
10
|
-
}
|
|
11
|
-
if (window.Flourish && window.Flourish.app && window.Flourish.app.loaded_template_id) {
|
|
12
|
-
data.template_id = window.Flourish.app.loaded_template_id;
|
|
13
|
-
}
|
|
14
|
-
if (window._Flourish_visualisation_id) {
|
|
15
|
-
data.visualisation_id = window._Flourish_visualisation_id;
|
|
16
|
-
}
|
|
17
|
-
if (window.Flourish && window.Flourish.app && window.Flourish.app.loaded_visualisation) {
|
|
18
|
-
data.visualisation_id = window.Flourish.app.loaded_visualisation.id;
|
|
19
|
-
}
|
|
20
|
-
if (window.Flourish && window.Flourish.app && window.Flourish.app.story) {
|
|
21
|
-
data.story_id = window.Flourish.app.story.id;
|
|
22
|
-
data.slide_count = window.Flourish.app.story.slides.length;
|
|
23
|
-
}
|
|
24
|
-
if (window.Flourish && window.Flourish.app && window.Flourish.app.current_slide) {
|
|
25
|
-
// One indexed
|
|
26
|
-
data.slide_index = window.Flourish.app.current_slide.index + 1;
|
|
27
|
-
}
|
|
28
|
-
return data;
|
|
29
|
-
}
|
|
30
|
-
function sendCustomerAnalyticsMessage(message) {
|
|
31
|
-
if (!enabled)
|
|
32
|
-
return;
|
|
33
|
-
if (window.top === window.self)
|
|
34
|
-
return;
|
|
35
|
-
var embedded_window = window;
|
|
36
|
-
if (embedded_window.location.pathname === "srcdoc")
|
|
37
|
-
embedded_window = embedded_window.parent;
|
|
38
|
-
var location_data = getLocationData();
|
|
39
|
-
var message_with_metadata = {
|
|
40
|
-
sender: "Flourish",
|
|
41
|
-
method: "customerAnalytics"
|
|
42
|
-
};
|
|
43
|
-
for (var key in location_data) {
|
|
44
|
-
if (location_data.hasOwnProperty(key)) {
|
|
45
|
-
message_with_metadata[key] = location_data[key];
|
|
46
|
-
}
|
|
47
|
-
}
|
|
48
|
-
for (var key in message) {
|
|
49
|
-
if (message.hasOwnProperty(key)) {
|
|
50
|
-
message_with_metadata[key] = message[key];
|
|
51
|
-
}
|
|
52
|
-
}
|
|
53
|
-
embedded_window.parent.postMessage(JSON.stringify(message_with_metadata), "*");
|
|
54
|
-
}
|
|
55
|
-
exports.sendCustomerAnalyticsMessage = sendCustomerAnalyticsMessage;
|
|
56
|
-
function addAnalyticsListener(callback) {
|
|
57
|
-
if (typeof callback !== "function") {
|
|
58
|
-
throw new Error("Analytics callback is not a function");
|
|
59
|
-
}
|
|
60
|
-
window.Flourish._analytics_listeners.push(callback);
|
|
61
|
-
}
|
|
62
|
-
exports.addAnalyticsListener = addAnalyticsListener;
|
|
63
|
-
function removeAnalyticsListener(callback) {
|
|
64
|
-
if (typeof callback !== "function") {
|
|
65
|
-
throw new Error("Analytics callback is not a function");
|
|
66
|
-
}
|
|
67
|
-
window.Flourish._analytics_listeners = window.Flourish._analytics_listeners.filter(function (listener) {
|
|
68
|
-
return callback !== listener;
|
|
69
|
-
});
|
|
70
|
-
}
|
|
71
|
-
exports.removeAnalyticsListener = removeAnalyticsListener;
|
|
72
|
-
function dispatchAnalyticsEvent(message) {
|
|
73
|
-
// If the window.Flourish object hasn't been created by the customer, they
|
|
74
|
-
// can't be listening for analytics events
|
|
75
|
-
if (!window.Flourish)
|
|
76
|
-
return;
|
|
77
|
-
window.Flourish._analytics_listeners.forEach(function (listener) {
|
|
78
|
-
listener(message);
|
|
79
|
-
});
|
|
80
|
-
}
|
|
81
|
-
exports.dispatchAnalyticsEvent = dispatchAnalyticsEvent;
|
|
82
|
-
function initCustomerAnalytics() {
|
|
83
|
-
enabled = true;
|
|
84
|
-
var events = [
|
|
85
|
-
{
|
|
86
|
-
event_name: "click",
|
|
87
|
-
action_name: "click",
|
|
88
|
-
use_capture: true
|
|
89
|
-
},
|
|
90
|
-
{
|
|
91
|
-
event_name: "keydown",
|
|
92
|
-
action_name: "key_down",
|
|
93
|
-
use_capture: true
|
|
94
|
-
},
|
|
95
|
-
{
|
|
96
|
-
event_name: "mouseenter",
|
|
97
|
-
action_name: "mouse_enter",
|
|
98
|
-
use_capture: false
|
|
99
|
-
},
|
|
100
|
-
{
|
|
101
|
-
event_name: "mouseleave",
|
|
102
|
-
action_name: "mouse_leave",
|
|
103
|
-
use_capture: false
|
|
104
|
-
}
|
|
105
|
-
];
|
|
106
|
-
events.forEach(function (event) {
|
|
107
|
-
document.body.addEventListener(event.event_name, function () {
|
|
108
|
-
sendCustomerAnalyticsMessage({
|
|
109
|
-
action: event.action_name
|
|
110
|
-
});
|
|
111
|
-
}, event.use_capture);
|
|
112
|
-
});
|
|
113
|
-
}
|
|
114
|
-
exports.initCustomerAnalytics = initCustomerAnalytics;
|
|
@@ -1,25 +0,0 @@
|
|
|
1
|
-
export default initEmbedding;
|
|
2
|
-
declare function initEmbedding(): {
|
|
3
|
-
createEmbedIframe: typeof createEmbedIframe;
|
|
4
|
-
isFixedHeight: typeof isFixedHeight;
|
|
5
|
-
getHeightForBreakpoint: typeof getHeightForBreakpoint;
|
|
6
|
-
startEventListeners: typeof startEventListeners;
|
|
7
|
-
notifyParentWindow: typeof notifyParentWindow;
|
|
8
|
-
initScrolly: typeof initScrolly;
|
|
9
|
-
createScrolly: typeof createScrolly;
|
|
10
|
-
isSafari: typeof isSafari;
|
|
11
|
-
initCustomerAnalytics: typeof initCustomerAnalytics;
|
|
12
|
-
addAnalyticsListener: typeof addAnalyticsListener;
|
|
13
|
-
sendCustomerAnalyticsMessage: typeof sendCustomerAnalyticsMessage;
|
|
14
|
-
};
|
|
15
|
-
declare function createEmbedIframe(embed_url: any, container: any, width: any, height: any, play_on_load: any): any;
|
|
16
|
-
declare function isFixedHeight(): any;
|
|
17
|
-
declare function getHeightForBreakpoint(width: any): 650 | 575 | 400;
|
|
18
|
-
declare function startEventListeners(callback: any, allowed_methods: any, embed_domain: any): void;
|
|
19
|
-
declare function notifyParentWindow(height: any, opts: any): void;
|
|
20
|
-
declare function initScrolly(opts: any): void;
|
|
21
|
-
declare function createScrolly(iframe: any, slides: any): void;
|
|
22
|
-
declare function isSafari(): boolean;
|
|
23
|
-
import { initCustomerAnalytics } from "./customer_analytics";
|
|
24
|
-
import { addAnalyticsListener } from "./customer_analytics";
|
|
25
|
-
import { sendCustomerAnalyticsMessage } from "./customer_analytics";
|
|
@@ -1,461 +0,0 @@
|
|
|
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;
|