@flourish/sdk 3.20.0 → 4.1.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 CHANGED
@@ -487,3 +487,24 @@ Called whenever the user changes a data table or setting in the visualisation ed
487
487
  An object into which Flourish will put the data from user-editable data tables. Usually your code will initialise `data` as an empty object `{}`, and read from it in the `draw()` and `update()` functions.
488
488
 
489
489
  Each property is a `dataset`: an array containing an object for each row in the relevant data table. The structure of each `dataset` is defined in the [data bindings of the `template.yml`](#data-bindings), and the data is loaded from the tables in the [`data/`](#data) directory.
490
+
491
+ ### `.screenshot(opts, takeScreenshot)`
492
+ Called whenever the user has clicked "Download image" in the visualisation editor. This function gets called just before the image is downloaded and allows you to prepare the visualisation to be downloaded as an image. This is useful for example for disabling a template's animation, or converting HTML elements to SVG elements for SVG export.
493
+
494
+ The method has 2 arguments:
495
+ - `opts` – an object with information about the image to be downloaded
496
+ ```js
497
+ {
498
+ download: true
499
+ filename: ""
500
+ format: "png" // can be png, svg or jpeg
501
+ height: "575"
502
+ scale: 1
503
+ width: "796"
504
+ }
505
+ ```
506
+ - `takeScreenshot` – the Flourish screenshot function. This can be called after you've made amendments to your visualisation. Returns a promise which gets fired when the screenshot is finished, the callback takes two arguments for when the screenshot has succeeded or failed respectively, which can be used to undo any changes you made for the screenshot.
507
+
508
+ ```js
509
+ takeScreenshot().then(onSuccess, onFail)
510
+ ```
package/RELEASE_NOTES.md CHANGED
@@ -1,3 +1,16 @@
1
+ # 4.1.0
2
+ * Allow SDK CLI token based authentication.
3
+
4
+ # 4.0.0
5
+ * This is purely a Node.js compatibility break; it’s a major version change, because the SDK is
6
+ no longer compatible with old versions of Node.js: it now requires at least version 13.2.
7
+ There are no functional changes in this release.
8
+
9
+ # 3.20.1
10
+ * Use version 1.7.3 of the shell-quote package, to avoid a security issue that doesn’t
11
+ really affect us in this context, but could trigger spurious security warnings
12
+ (https://snyk.io/test/npm/shell-quote/1.6.1)
13
+
1
14
  # 3.20.0
2
15
  * Add the `html` setting type, which gives you a rich text editor for a settings value
3
16
 
package/bin/flourish.js CHANGED
@@ -20,6 +20,9 @@ const OPTS = {
20
20
 
21
21
  // Only relevant for admin users
22
22
  "as",
23
+
24
+ // Login option
25
+ "token",
23
26
  ],
24
27
 
25
28
  default: {
package/lib/cmd/help.js CHANGED
@@ -28,7 +28,7 @@ Commands:
28
28
  flourish [-h|--help|help] [topic]
29
29
  flourish history [--full] template_id
30
30
  flourish list [--full] [template id]
31
- flourish login [email_address]
31
+ flourish login ( [email_address] | --token [token] )
32
32
  flourish logout
33
33
  flourish new directory_name
34
34
  flourish publish [template_directory]
package/lib/cmd/login.js CHANGED
@@ -34,6 +34,19 @@ exports.command = function login(args) {
34
34
  });
35
35
  }
36
36
 
37
+ function getToken() {
38
+ return new Promise(function(resolve, reject) {
39
+ if (args.token) {
40
+ resolve(args.token);
41
+ return;
42
+ }
43
+ read({ prompt: "SDK Token: ", silent: true }, function(error, token) {
44
+ if (error) return reject(error);
45
+ resolve(token);
46
+ });
47
+ });
48
+ }
49
+
37
50
  function login(email, password) {
38
51
  return sdk.request(args, "user/login", { email: email, password: password })
39
52
  .then((response) => {
@@ -47,6 +60,24 @@ exports.command = function login(args) {
47
60
  .catch((error) => log.die("Failed to save SDK token", error.message));
48
61
  });
49
62
  }
63
+ async function loginWithToken(sdk_token) {
64
+ try {
65
+ await sdk.setSdkToken(args, sdk_token);
66
+ const user_info = await sdk.request(args, "user/whoami", {});
67
+ return user_info;
68
+ }
69
+ catch (e) {
70
+ log.die("Failed to save SDK token", e.message);
71
+ }
72
+ }
73
+ if ("token" in args) {
74
+ getToken().then((token) => {
75
+ loginWithToken(token).then(user_info => {
76
+ log.victory("Logged in as " + user_info.email);
77
+ }).catch(error => log.die("Failed to save SDK token", error.message));
78
+ });
79
+ return;
80
+ }
50
81
 
51
82
  getEmail()
52
83
  .then((email) => Promise.all([email, getPassword()]))
@@ -55,7 +86,9 @@ exports.command = function login(args) {
55
86
  };
56
87
 
57
88
  exports.help = `
58
- flourish login [email_address]
89
+ Usage:
90
+ flourish login [email]
91
+ flourish login --token [token]
59
92
 
60
93
  Log in to Flourish. You will be prompted for a password.
61
94
 
package/lib/sdk.js CHANGED
@@ -21,6 +21,7 @@ const sdk_tokens_file = path.join(process.env.HOME || process.env.USERPROFILE, "
21
21
  const YAML_DUMP_OPTS = { flowLevel: 4 };
22
22
  const SDK_VERSION = require("../package.json").version;
23
23
  const SDK_MAJOR_VERSION = semver.parse(SDK_VERSION)[0];
24
+ const SDK_MAJOR_VERSION_COMPAT = 3; // Flourish templates built for SDK version 3 are compatible with the current version
24
25
 
25
26
  function getSdkToken(server_opts) {
26
27
  return new Promise(function(resolve, reject) {
@@ -525,7 +526,7 @@ function checkTemplateVersion(template_dir) {
525
526
  if (!template_sdk_version) {
526
527
  throw new Error("Template does not specify an sdk_version");
527
528
  }
528
- if (template_sdk_version < SDK_MAJOR_VERSION) {
529
+ if (template_sdk_version < SDK_MAJOR_VERSION_COMPAT) {
529
530
  throw new Error("This template was built for an older version of Flourish. Try running 'flourish upgrade'");
530
531
  }
531
532
  if (template_sdk_version > SDK_MAJOR_VERSION) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@flourish/sdk",
3
- "version": "3.20.0",
3
+ "version": "4.1.0",
4
4
  "description": "The Flourish SDK",
5
5
  "module": "src/index.js",
6
6
  "scripts": {
@@ -16,13 +16,13 @@
16
16
  "license": "SEE LICENSE IN LICENSE.md",
17
17
  "repository": "kiln/flourish-sdk",
18
18
  "dependencies": {
19
- "@flourish/interpreter": "^6.0.4",
19
+ "@flourish/interpreter": "^8.0.0",
20
20
  "@flourish/semver": "^1.0.1",
21
21
  "@flourish/transform-data": "^2.1.0",
22
22
  "@handlebars/allow-prototype-access": "^1.0.3",
23
23
  "@rollup/plugin-commonjs": "^17.1.0",
24
24
  "archiver": "^5.0.2",
25
- "chokidar": "^3.4.3",
25
+ "chokidar": "^3.5.3",
26
26
  "cross-spawn": "^7.0.3",
27
27
  "d3-dsv": "^2.0.0",
28
28
  "express": "^4.17.1",
@@ -32,26 +32,26 @@
32
32
  "minimist": "^1.2.6",
33
33
  "ncp": "^2.0.0",
34
34
  "node-fetch": "^2.6.7",
35
- "parse5": "^6.0.1",
35
+ "parse5": "^7.1.2",
36
36
  "picocolors": "^1.0.0",
37
37
  "read": "^1.0.7",
38
38
  "resolve": "^1.18.1",
39
39
  "rewrite-links": "^1.1.0",
40
40
  "rollup-plugin-terser": "^7.0.2",
41
- "shell-quote": "^1.7.2",
41
+ "shell-quote": "^1.7.3",
42
42
  "tmp": "^0.2.1",
43
43
  "ws": "^7.4.6"
44
44
  },
45
45
  "devDependencies": {
46
46
  "@rollup/plugin-node-resolve": "^9.0.0",
47
47
  "d3-request": "^1.0.6",
48
- "mocha": "^9.2.0",
49
- "npm-audit-resolver": "^2.3.0",
48
+ "mocha": "^10.0.0",
49
+ "npm-audit-resolver": "^3.0.0-7",
50
50
  "rollup": "^2.32.1",
51
51
  "sinon": "^9.2.0",
52
- "tempy": "^1.0.0"
52
+ "tempy": "^3.0.0"
53
53
  },
54
54
  "engines": {
55
- "node": ">=8.3"
55
+ "node": ">=13.2"
56
56
  }
57
57
  }
package/server/columns.js CHANGED
@@ -1,7 +1,7 @@
1
1
  /* * * * * * GENERATED FILE - DO NOT EDIT * * * * * *
2
2
  * * * * * * GENERATED FILE - DO NOT EDIT * * * * * *
3
3
  * * * * * * GENERATED FILE - DO NOT EDIT * * * * * */
4
-
4
+
5
5
  'use strict';
6
6
 
7
7
  Object.defineProperty(exports, '__esModule', { value: true });
@@ -1,7 +1,7 @@
1
+ "use strict";
1
2
  const BEFORE = `
2
3
  window.addEventListener("message", function(event) {
3
4
  `;
4
-
5
5
  const CHECK_ORIGIN = `
6
6
  var a = document.createElement("a");
7
7
  a.href = event.origin;
@@ -12,8 +12,9 @@ const CHECK_ORIGIN = `
12
12
  || (a.hostname.match(/\\.flourish\\.rocks$/) && window.location.hostname.match(/\\.flourish\\.rocks$/))
13
13
  || (a.hostname.match(/\\.flourish\\.studio$/) && window.location.hostname.match(/\\.flourish\\.studio$/))
14
14
  || (a.hostname == "app.flourish.studio" && window.location.hostname == "flourish-user-templates.com")
15
+ || (a.hostname == "flourish-user-preview.com" && window.location.hostname == "flourish-user-templates.com")
15
16
  || (${"" /* Cope with previously-published stories, that are still on the old domain,
16
- that have been republished (hence rerendered to use the new template URLs) */}
17
+ that have been republished (hence rerendered to use the new template URLs) */}
17
18
  (a.hostname == "public.flourish.studio" && window.location.hostname == "flo.uri.sh")
18
19
  || (a.hostname == "public.flourish.rocks" && window.location.hostname == "staging-flo.uri.sh")
19
20
  || (a.hostname == "public.dev.flourish.rocks" && window.location.hostname == "dev-flo.uri.sh")
@@ -21,7 +22,6 @@ const CHECK_ORIGIN = `
21
22
 
22
23
  if (!origin_okay) return;
23
24
  `;
24
-
25
25
  const AFTER = `
26
26
  var message = event.data;
27
27
  var port = event.ports[0];
@@ -122,7 +122,6 @@ const AFTER = `
122
122
  }
123
123
  }, false);
124
124
  `;
125
-
126
125
  const VALIDATE = `
127
126
  if (template && template.draw && template.draw.length != 0) {
128
127
  console.warn("The draw() function should be declared with no parameters");
@@ -131,7 +130,7 @@ if (template && template.update && template.update.length != 0) {
131
130
  console.warn("The update() function should be declared with no parameters");
132
131
  }
133
132
  `;
134
-
135
133
  exports.withOriginCheck = BEFORE + CHECK_ORIGIN + AFTER;
136
134
  exports.withoutOriginCheck = BEFORE + AFTER;
137
135
  exports.validate = VALIDATE;
136
+ //# sourceMappingURL=comms_js.js.map
package/server/data.js CHANGED
@@ -6,11 +6,7 @@
6
6
 
7
7
  Object.defineProperty(exports, '__esModule', { value: true });
8
8
 
9
- var createInterpreter = require('@flourish/interpreter');
10
-
11
- function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; }
12
-
13
- var createInterpreter__default = /*#__PURE__*/_interopDefaultLegacy(createInterpreter);
9
+ var interpreter$1 = require('@flourish/interpreter');
14
10
 
15
11
  // Polyfills for IE11 and Edge
16
12
 
@@ -61,7 +57,7 @@ function extractData(data_binding, data_by_id, column_types_by_id, template_data
61
57
 
62
58
  function getInterpreter(data_table_id, column_index) {
63
59
  const { type_id } = getInterpretationIds(data_table_id, column_index);
64
- if (type_id) return createInterpreter__default["default"].getInterpretation(type_id);
60
+ if (type_id) return interpreter$1.createInterpreter.getInterpretation(type_id);
65
61
  }
66
62
 
67
63
  for (var data_table_id in column_types_by_id) {
@@ -143,6 +139,7 @@ function extractData(data_binding, data_by_id, column_types_by_id, template_data
143
139
  function parse(b, column_index, string_value) {
144
140
  if (!b.template_data_binding.data_type) return string_value;
145
141
  var interpreter = getInterpreter(b.data_table_id, column_index);
142
+ if (interpreter && interpreter.type == "number") string_value = stripCommonFixes(string_value);
146
143
  var result = interpreter ? interpreter.parse(string_value) : string_value;
147
144
 
148
145
  // We require our marshalled data to be JSON-serialisable,
@@ -246,7 +243,7 @@ function trimWhitespace(data) {
246
243
 
247
244
 
248
245
  var ERROR_STRINGS = ["#DIV/0", "#N/A", "#NAME?", "#NULL!", "#NUM!", "#REF!", "#VALUE!", "#ERROR!"];
249
- var interpreter = createInterpreter__default["default"]().nMax(Infinity).nFailingValues(8).failureFraction(0.1);
246
+ var interpreter = interpreter$1.createInterpreter().nMax(Infinity).nFailingValues(8).failureFraction(0.1);
250
247
 
251
248
 
252
249
  function stripCommonFixes(str) {
@@ -257,7 +254,7 @@ function stripCommonFixes(str) {
257
254
 
258
255
  function transposeNestedArray(nested_array) {
259
256
  var n_inner = nested_array.length;
260
- var n_outer = nested_array[0].length;
257
+ var n_outer = n_inner > 0 ? nested_array[0].length : 0;
261
258
  var transposed_array = [];
262
259
 
263
260
  for (var i = 0; i < n_outer; i++) {
@@ -299,6 +296,7 @@ exports.getRandomSeededSample = getRandomSeededSample;
299
296
  exports.getSlicedData = getSlicedData;
300
297
  exports.interpretColumn = interpretColumn;
301
298
  exports.mulberry32 = mulberry32;
299
+ exports.stripCommonFixes = stripCommonFixes;
302
300
  exports.transposeNestedArray = transposeNestedArray;
303
301
  exports.trimTrailingEmptyRows = trimTrailingEmptyRows;
304
302
  exports.trimWhitespace = trimWhitespace;
package/server/index.js CHANGED
@@ -25,7 +25,7 @@ const crypto = require("crypto"),
25
25
  const { allowInsecurePrototypeAccess } = require("@handlebars/allow-prototype-access");
26
26
  const handlebars = allowInsecurePrototypeAccess(require("handlebars"));
27
27
 
28
- const TA = require("parse5/lib/tree-adapters/default.js");
28
+ const { defaultTreeAdapter: TA } = require("parse5");
29
29
 
30
30
  // Generate a static prefix randomly
31
31
  //
@@ -1,100 +1,86 @@
1
1
  "use strict";
2
-
3
2
  const URL = require("url");
4
-
5
- const parse5 = require("parse5"),
6
- RewriteLinks = require("rewrite-links");
7
-
8
- const TA = require("parse5/lib/tree-adapters/default.js");
9
-
3
+ const parse5 = require("parse5"), RewriteLinks = require("rewrite-links");
4
+ const { defaultTreeAdapter: TA } = require("parse5");
10
5
  function findChild(node, nodeName, ok_if_not_found) {
11
- for (const child of TA.getChildNodes(node)) {
12
- if (child.nodeName == nodeName) return child;
13
- }
14
- if (ok_if_not_found) return null;
15
- throw new Error("Node not found: " + nodeName);
6
+ for (const child of TA.getChildNodes(node)) {
7
+ if (child.nodeName == nodeName)
8
+ return child;
9
+ }
10
+ if (ok_if_not_found)
11
+ return null;
12
+ throw new Error("Node not found: " + nodeName);
16
13
  }
17
-
18
14
  function findHtmlNode(document) {
19
- return findChild(document, "html");
15
+ return findChild(document, "html");
20
16
  }
21
-
22
17
  function findHead(document) {
23
- return findChild(findHtmlNode(document), "head");
18
+ return findChild(findHtmlNode(document), "head");
24
19
  }
25
-
26
20
  function findBody(document) {
27
- return findChild(findHtmlNode(document), "body");
21
+ return findChild(findHtmlNode(document), "body");
28
22
  }
29
-
30
23
  function replaceTitle(document, title) {
31
- const head = findHead(document);
32
- let title_node = findChild(head, "title", true);
33
-
34
- if (title_node) {
35
- for (const child of TA.getChildNodes(title_node)) {
36
- TA.detachNode(child);
37
- }
38
- }
39
- else {
40
- title_node = TA.createElement("title", head.namespaceURI, []);
41
- TA.appendChild(head, title_node);
42
- }
43
-
44
- TA.insertText(title_node, title);
24
+ const head = findHead(document);
25
+ let title_node = findChild(head, "title", true);
26
+ if (title_node) {
27
+ for (const child of TA.getChildNodes(title_node)) {
28
+ TA.detachNode(child);
29
+ }
30
+ }
31
+ else {
32
+ title_node = TA.createElement("title", head.namespaceURI, []);
33
+ TA.appendChild(head, title_node);
34
+ }
35
+ TA.insertText(title_node, title);
45
36
  }
46
-
47
37
  function appendFragmentToBody(document, fragment) {
48
- const body = findBody(document);
49
- for (const child of TA.getChildNodes(fragment)) {
50
- TA.appendChild(body, child);
51
- }
38
+ const body = findBody(document);
39
+ for (const child of TA.getChildNodes(fragment)) {
40
+ TA.appendChild(body, child);
41
+ }
52
42
  }
53
-
54
43
  function insertOembedLink(document, oembed_url) {
55
- const head = findHead(document);
56
- const link_node = TA.createElement("link", head.namespaceURI, [
57
- { name: "rel", value: "alternate" },
58
- { name: "type", value: "application/json+oembed" },
59
- { name: "href", value: oembed_url }
60
- ]);
61
- TA.appendChild(head, link_node);
44
+ const head = findHead(document);
45
+ const link_node = TA.createElement("link", head.namespaceURI, [
46
+ { name: "rel", value: "alternate" },
47
+ { name: "type", value: "application/json+oembed" },
48
+ { name: "href", value: oembed_url }
49
+ ]);
50
+ TA.appendChild(head, link_node);
62
51
  }
63
-
64
52
  function insertCanonicalLink(document, canonical_url) {
65
- const head = findHead(document);
66
- const link_node = TA.createElement("link", head.namespaceURI, [
67
- { name: "rel", value: "canonical" },
68
- { name: "href", value: canonical_url }
69
- ]);
70
- TA.appendChild(head, link_node);
53
+ const head = findHead(document);
54
+ const link_node = TA.createElement("link", head.namespaceURI, [
55
+ { name: "rel", value: "canonical" },
56
+ { name: "href", value: canonical_url }
57
+ ]);
58
+ TA.appendChild(head, link_node);
71
59
  }
72
-
73
60
  function rewriteLinks(document, static_prefix) {
74
- if (!static_prefix.endsWith("/")) static_prefix += "/";
75
- const rewriter = new RewriteLinks(function(url) {
76
- // We don’t want to rewrite URLs that are just fragment identifiers
77
- if (url.startsWith("#")) return url;
78
-
79
- // ... or relative self-links
80
- if (url == "" || url == ".") return url;
81
-
82
- return URL.resolve(static_prefix, url); // eslint-disable-line node/no-deprecated-api
83
- });
84
-
85
- return rewriter.rewriteDocument(document);
61
+ if (!static_prefix.endsWith("/"))
62
+ static_prefix += "/";
63
+ const rewriter = new RewriteLinks(function (url) {
64
+ // We don’t want to rewrite URLs that are just fragment identifiers
65
+ if (url.startsWith("#"))
66
+ return url;
67
+ // ... or relative self-links
68
+ if (url == "" || url == ".")
69
+ return url;
70
+ return URL.resolve(static_prefix, url); // eslint-disable-line node/no-deprecated-api
71
+ });
72
+ return rewriter.rewriteDocument(document);
86
73
  }
87
-
88
- function render(template_text, params) {
89
- const document = parse5.parse(template_text),
90
- script_fragment = params.parsed_script || parse5.parseFragment(params.script);
91
-
92
- replaceTitle(document, params.title);
93
- if (params.canonical_url) insertCanonicalLink(document, params.canonical_url);
94
- if (params.oembed_url) insertOembedLink(document, params.oembed_url);
95
- appendFragmentToBody(document, script_fragment);
96
- return rewriteLinks(document, params.static)
97
- .then(parse5.serialize.bind(parse5));
74
+ async function render(template_text, params) {
75
+ const document = parse5.parse(template_text), script_fragment = params.parsed_script || parse5.parseFragment(params.script);
76
+ replaceTitle(document, params.title);
77
+ if (params.canonical_url)
78
+ insertCanonicalLink(document, params.canonical_url);
79
+ if (params.oembed_url)
80
+ insertOembedLink(document, params.oembed_url);
81
+ appendFragmentToBody(document, script_fragment);
82
+ const rewritten_document = await rewriteLinks(document, params.static);
83
+ return parse5.serialize(rewritten_document);
98
84
  }
99
-
100
85
  exports.render = render;
86
+ //# sourceMappingURL=index_html.js.map
package/server/json.js CHANGED
@@ -1,7 +1,7 @@
1
1
  /* * * * * * GENERATED FILE - DO NOT EDIT * * * * * *
2
2
  * * * * * * GENERATED FILE - DO NOT EDIT * * * * * *
3
3
  * * * * * * GENERATED FILE - DO NOT EDIT * * * * * */
4
-
4
+
5
5
  'use strict';
6
6
 
7
7
  Object.defineProperty(exports, '__esModule', { value: true });
@@ -3,13 +3,25 @@
3
3
  <head>
4
4
  <meta charset="utf-8">
5
5
  <meta name="viewport" content="width=device-width, initial-scale=1,user-scalable=no">
6
- <title>Flourish | Data Visualisation &amp; Storytelling</title>
6
+
7
+ <script type="text/javascript">
8
+ function OptanonWrapper() {
9
+ OneTrust.OnConsentChanged(() => {
10
+ document.cookie = `OptanonAlertBoxClosed=${new Date().toISOString()};`
11
+ + "SameSite=None;"
12
+ + "Secure;"
13
+ + `expires=${new Date(Date.now() + 1000 * 60 * 60 * 24 * 365).toUTCString()};`;
14
+ });
15
+ }
16
+ </script>
17
+
18
+ <title>Flourish | Data Visualization &amp; Storytelling</title>
7
19
 
8
20
  <script>if ("ontouchstart" in window) { document.documentElement.classList.add("is-touch"); }</script>
9
21
 
10
22
 
11
23
  <link rel="stylesheet" type="text/css" href="/sdk.css">
12
- <script src="/script.js" charset="utf-8"></script>
24
+ <script data-ot-ignore src="/script.js" charset="utf-8"></script>
13
25
  </head>
14
26
  <body class="sdk">
15
27
  <div class="row header no-select" style="padding-left:10px">
@@ -17,10 +29,9 @@
17
29
  </div>
18
30
  <div class="row editor-bar">
19
31
  <div id="preview-menu" class="row-menu left no-select">
20
-
21
- <a id="full-preview" href="preview" target="_blank" class="menu-item clickable popup" data-popup-head="Full preview in new window" aria-label="Full preview in new window">
22
- <i class="fa fa-expand"></i>
23
- </a>
32
+ <a id="full-preview" href="preview" target="_blank" class="menu-item clickable popup" data-popup-head="Full preview in new window" aria-label="Full preview in new window">
33
+ <i class="fa fa-expand"></i>
34
+ </a>
24
35
  <div id="editor-previews">
25
36
  <span id="editor-auto" data-target="auto" class="menu-item preview-mode clickable selected popup" data-popup-head="Preview using available width">
26
37
  <i class="fa fa-tv"></i>
@@ -55,7 +66,7 @@
55
66
  <p class="empty-label"></p>
56
67
  <p class="empty-details"></p>
57
68
  </div>
58
- <iframe id="preview" sandbox="allow-same-origin allow-scripts allow-downloads" src="about:blank" data-testid="visualisation-iframe" aria-label="Visualisation preview"></iframe>
69
+ <iframe id="preview" sandbox="allow-same-origin allow-scripts allow-downloads" src="about:blank" data-testid="visualisation-iframe" aria-label="Visualization preview"></iframe>
59
70
  <div id="resize-overlay"></div>
60
71
  <div id="resize-handle-container">
61
72
  <div id="resize-handle"></div>
package/site/embedded.js CHANGED
@@ -1,2 +1,2 @@
1
- !function(){"use strict";var e,t,n=!1;function i(e){if(n&&window.top!==window.self){var t=window;"srcdoc"===t.location.pathname&&(t=t.parent);var i,o=(i={},window._Flourish_template_id&&(i.template_id=window._Flourish_template_id),window.Flourish&&window.Flourish.app&&window.Flourish.app.loaded_template_id&&(i.template_id=window.Flourish.app.loaded_template_id),window._Flourish_visualisation_id&&(i.visualisation_id=window._Flourish_visualisation_id),window.Flourish&&window.Flourish.app&&window.Flourish.app.loaded_visualisation&&(i.visualisation_id=window.Flourish.app.loaded_visualisation.id),window.Flourish&&window.Flourish.app&&window.Flourish.app.story&&(i.story_id=window.Flourish.app.story.id,i.slide_count=window.Flourish.app.story.slides.length),window.Flourish&&window.Flourish.app&&window.Flourish.app.current_slide&&(i.slide_index=window.Flourish.app.current_slide.index+1),i),r={sender:"Flourish",method:"customerAnalytics"};for(var a in o)o.hasOwnProperty(a)&&(r[a]=o[a]);for(var a in e)e.hasOwnProperty(a)&&(r[a]=e[a]);t.parent.postMessage(JSON.stringify(r),"*")}}function o(e){if("function"!=typeof e)throw new Error("Analytics callback is not a function");window.Flourish._analytics_listeners.push(e)}function r(){n=!0;[{event_name:"click",action_name:"click",use_capture:!0},{event_name:"keydown",action_name:"key_down",use_capture:!0},{event_name:"mouseenter",action_name:"mouse_enter",use_capture:!1},{event_name:"mouseleave",action_name:"mouse_leave",use_capture:!1}].forEach((function(e){document.body.addEventListener(e.event_name,(function(){i({action:e.action_name})}),e.use_capture)}))}function a(){if(null==e){var t=function(){var e=window.location;"about:srcdoc"==e.href&&(e=window.parent.location);var t={};return function(e,n,i){for(;i=n.exec(e);)t[decodeURIComponent(i[1])]=decodeURIComponent(i[2])}(e.search.substring(1).replace(/\+/g,"%20"),/([^&=]+)=?([^&]*)/g),t}();e="referrer"in t?/^https:\/\/medium.com\//.test(t.referrer):!("auto"in t)}return e}function s(e){var t=e||window.innerWidth;return t>999?650:t>599?575:400}function l(e,n){if(window.top!==window.self){var i=window;if("srcdoc"==i.location.pathname&&(i=i.parent),t)return e=parseInt(e,10),void i.parent.postMessage({sentinel:"amp",type:"embed-size",height:e},"*");var o={sender:"Flourish",context:"iframe.resize",method:"resize",height:e,src:i.location.toString()};if(n)for(var r in n)o[r]=n[r];i.parent.postMessage(JSON.stringify(o),"*")}}function d(){return(-1!==navigator.userAgent.indexOf("Safari")||-1!==navigator.userAgent.indexOf("iPhone"))&&-1==navigator.userAgent.indexOf("Chrome")}function u(e){return"string"==typeof e||e instanceof String}function c(e){return"warn"!==e.method?(console.warn("BUG: validateWarnMessage called for method"+e.method),!1):!(null!=e.message&&!u(e.message))&&!(null!=e.explanation&&!u(e.explanation))}function h(e){return"resize"!==e.method?(console.warn("BUG: validateResizeMessage called for method"+e.method),!1):!!u(e.src)&&(!!u(e.context)&&!!("number"==typeof(t=e.height)?!isNaN(t)&&t>=0:u(t)&&/\d/.test(t)&&/^[0-9]*(\.[0-9]*)?(cm|mm|Q|in|pc|pt|px|em|ex|ch|rem|lh|vw|vh|vmin|vmax|%)?$/i.test(t)));var t}function f(e){throw new Error("Validation for setSetting is not implemented yet; see issue #4328")}function w(e){return"customerAnalytics"===e.method||(console.warn("BUG: validateCustomerAnalyticsMessage called for method"+e.method),!1)}function p(e){return"request-upload"!==e.method?(console.warn("BUG: validateResizeMessage called for method"+e.method),!1):!!u(e.name)&&!(null!=e.accept&&!u(e.accept))}function m(e,t){var n=function(e){for(var t={warn:c,resize:h,setSetting:f,customerAnalytics:w,"request-upload":p},n={},i=0;i<e.length;i++){var o=e[i];if(!t[o])throw new Error("No validator found for method "+o);n[o]=t[o]}return n}(t);window.addEventListener("message",(function(t){if(null!=t.source&&(t.origin===document.location.origin||t.origin.match(/\/\/localhost:\d+$|\/\/flourish-api\.com$|\.flourish\.(?:local(:\d+)?|net|rocks|studio)$|\.uri\.sh$|\/\/flourish-user-templates\.com$/))){var i;try{i=JSON.parse(t.data)}catch(e){return void console.warn("Unexpected non-JSON message: "+JSON.stringify(t.data))}if("Flourish"===i.sender)if(i.method)if(Object.prototype.hasOwnProperty.call(n,i.method))if(n[i.method](i)){for(var o=document.querySelectorAll("iframe"),r=0;r<o.length;r++)if(o[r].contentWindow==t.source||o[r].contentWindow==t.source.parent)return void e(i,o[r]);console.warn("could not find frame",i)}else console.warn("Validation failed for the message",i);else console.warn("No validator implemented for message",i);else console.warn("The 'method' property was missing from message",i)}})),d()&&(window.addEventListener("resize",g),g())}function g(){for(var e=document.querySelectorAll(".flourish-embed"),t=0;t<e.length;t++){var n=e[t];if(!n.getAttribute("data-width")){var i=n.querySelector("iframe");if(i){var o=window.getComputedStyle(n),r=n.offsetWidth-parseFloat(o.paddingLeft)-parseFloat(o.paddingRight);i.style.width=r+"px"}}}}function v(e,t,n,i,o){var r=document.createElement("iframe");if(r.setAttribute("scrolling","no"),r.setAttribute("frameborder","0"),r.setAttribute("title","Interactive or visual content"),r.setAttribute("sandbox","allow-same-origin allow-forms allow-scripts allow-downloads allow-popups allow-popups-to-escape-sandbox allow-top-navigation-by-user-activation"),t.appendChild(r),r.offsetParent||"fixed"===getComputedStyle(r).position)_(e,t,r,n,i,o);else{var a={embed_url:e,container:t,iframe:r,width:n,height:i,play_on_load:o};if(window._flourish_poll_items?window._flourish_poll_items.push(a):window._flourish_poll_items=[a],window._flourish_poll_items.length>1)return r;var s=setInterval((function(){window._flourish_poll_items=window._flourish_poll_items.filter((function(e){return!e.iframe.offsetParent||(_(e.embed_url,e.container,e.iframe,e.width,e.height,e.play_on_load),!1)})),window._flourish_poll_items.length||clearInterval(s)}),500)}return r}function _(e,t,n,i,o,r){var a;return i&&"number"==typeof i?(a=i,i+="px"):i&&i.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]*$/)&&(a=parseFloat(i)),o&&"number"==typeof o&&(o+="px"),i?n.style.width=i:d()?n.style.width=t.offsetWidth+"px":n.style.width="100%",!!o||(e.match(/\?/)?e+="&auto=1":e+="?auto=1",o=s(a||n.offsetWidth)+"px"),o&&("%"===o.charAt(o.length-1)&&(o=parseFloat(o)/100*t.parentNode.offsetHeight+"px"),n.style.height=o),n.setAttribute("src",e+(r?"#play-on-load":"")),n}function y(e){return!Array.isArray(e)&&"object"==typeof e&&null!=e}function F(e,t){for(var n in t)y(e[n])&&y(t[n])?F(e[n],t[n]):e[n]=t[n];return e}!function(){var e,n=window.top===window.self,u=n?null:(t="#amp=1"==window.location.hash,{createEmbedIframe:v,isFixedHeight:a,getHeightForBreakpoint:s,startEventListeners:m,notifyParentWindow:l,isSafari:d,initCustomerAnalytics:r,addAnalyticsListener:o,sendCustomerAnalyticsMessage:i}),c=!0;function h(){var t;Flourish.fixed_height||(null!=e?t=e:c&&(t=u.getHeightForBreakpoint()),t!==window.innerHeight&&u.notifyParentWindow(t))}function f(){h(),window.addEventListener("resize",h)}Flourish.warn=function(e){if("string"==typeof e&&(e={message:e}),n||"editor"!==Flourish.environment)console.warn(e.message);else{var t={sender:"Flourish",method:"warn",message:e.message,explanation:e.explanation};window.parent.postMessage(JSON.stringify(t),"*")}},Flourish.uploadImage=function(e){if(n||"story_editor"!==Flourish.environment)throw"Invalid upload request";var t={sender:"Flourish",method:"request-upload",name:e.name,accept:e.accept};window.parent.postMessage(JSON.stringify(t),"*")},Flourish.setSetting=function(e,t){if("editor"===Flourish.environment||"sdk"===Flourish.environment){var n={sender:"Flourish",method:"setSetting",name:e,value:t};window.parent.postMessage(JSON.stringify(n),"*")}else if("story_editor"===Flourish.environment){var i={};i[e]=t,F(window.template.state,function(e){var t={};for(var n in e){for(var i=t,o=n.indexOf("."),r=0;o>=0;o=n.indexOf(".",r=o+1)){var a=n.substring(r,o);a in i||(i[a]={}),i=i[a]}i[n.substring(r)]=e[n]}return t}(i))}},Flourish.setHeight=function(t){Flourish.fixed_height||(e=t,c=null==t,h())},Flourish.checkHeight=function(){if(!n){var e=Flourish.__container_height;null!=e?(Flourish.fixed_height=!0,u.notifyParentWindow(e)):u.isFixedHeight()?Flourish.fixed_height=!0:(Flourish.fixed_height=!1,h())}},Flourish.fixed_height=n||u.isFixedHeight(),Flourish.enableCustomerAnalytics=function(){u&&u.initCustomerAnalytics()},"loading"===document.readyState?document.addEventListener("DOMContentLoaded",f):f()}()}();
1
+ !function(){"use strict";var e,t,i=!1;function n(e){if(i&&window.top!==window.self){var t=window;"srcdoc"===t.location.pathname&&(t=t.parent);var n,o=(n={},window._Flourish_template_id&&(n.template_id=window._Flourish_template_id),window.Flourish&&window.Flourish.app&&window.Flourish.app.loaded_template_id&&(n.template_id=window.Flourish.app.loaded_template_id),window._Flourish_visualisation_id&&(n.visualisation_id=window._Flourish_visualisation_id),window.Flourish&&window.Flourish.app&&window.Flourish.app.loaded_visualisation&&(n.visualisation_id=window.Flourish.app.loaded_visualisation.id),window.Flourish&&window.Flourish.app&&window.Flourish.app.story&&(n.story_id=window.Flourish.app.story.id,n.slide_count=window.Flourish.app.story.slides.length),window.Flourish&&window.Flourish.app&&window.Flourish.app.current_slide&&(n.slide_index=window.Flourish.app.current_slide.index+1),n),r={sender:"Flourish",method:"customerAnalytics"};for(var a in o)o.hasOwnProperty(a)&&(r[a]=o[a]);for(var a in e)e.hasOwnProperty(a)&&(r[a]=e[a]);t.parent.postMessage(JSON.stringify(r),"*")}}function o(e){if("function"!=typeof e)throw new Error("Analytics callback is not a function");window.Flourish._analytics_listeners.push(e)}function r(){i=!0;[{event_name:"click",action_name:"click",use_capture:!0},{event_name:"keydown",action_name:"key_down",use_capture:!0},{event_name:"mouseenter",action_name:"mouse_enter",use_capture:!1},{event_name:"mouseleave",action_name:"mouse_leave",use_capture:!1}].forEach((function(e){document.body.addEventListener(e.event_name,(function(){n({action:e.action_name})}),e.use_capture)}))}function a(){if(null==e){var t=function(){var e=window.location;"about:srcdoc"==e.href&&(e=window.parent.location);var t={};return function(e,i,n){for(;n=i.exec(e);)t[decodeURIComponent(n[1])]=decodeURIComponent(n[2])}(e.search.substring(1).replace(/\+/g,"%20"),/([^&=]+)=?([^&]*)/g),t}();e="referrer"in t?/^https:\/\/medium.com\//.test(t.referrer):!("auto"in t)}return e}function s(e){var t=e||window.innerWidth;return t>999?650:t>599?575:400}function l(e){if(e&&window.top!==window.self){var t=window;"srcdoc"==t.location.pathname&&(t=t.parent);var i={sender:"Flourish",method:"scrolly"};if(e)for(var n in e)i[n]=e[n];t.parent.postMessage(JSON.stringify(i),"*")}}function d(e,i){if(window.top!==window.self){var n=window;if("srcdoc"==n.location.pathname&&(n=n.parent),t)return e=parseInt(e,10),void n.parent.postMessage({sentinel:"amp",type:"embed-size",height:e},"*");var o={sender:"Flourish",context:"iframe.resize",method:"resize",height:e,src:n.location.toString()};if(i)for(var r in i)o[r]=i[r];n.parent.postMessage(JSON.stringify(o),"*")}}function u(){return(-1!==navigator.userAgent.indexOf("Safari")||-1!==navigator.userAgent.indexOf("iPhone"))&&-1==navigator.userAgent.indexOf("Chrome")}function c(e){return"string"==typeof e||e instanceof String}function h(e){return"warn"!==e.method?(console.warn("BUG: validateWarnMessage called for method"+e.method),!1):!(null!=e.message&&!c(e.message))&&!(null!=e.explanation&&!c(e.explanation))}function f(e){return"resize"!==e.method?(console.warn("BUG: validateResizeMessage called for method"+e.method),!1):!!c(e.src)&&(!!c(e.context)&&!!("number"==typeof(t=e.height)?!isNaN(t)&&t>=0:c(t)&&/\d/.test(t)&&/^[0-9]*(\.[0-9]*)?(cm|mm|Q|in|pc|pt|px|em|ex|ch|rem|lh|vw|vh|vmin|vmax|%)?$/i.test(t)));var t}function p(e){throw new Error("Validation for setSetting is not implemented yet; see issue #4328")}function m(e){return"scrolly"!==e.method?(console.warn("BUG: validateScrolly called for method"+e.method),!1):!!Array.isArray(e.slides)}function w(e){return"customerAnalytics"===e.method||(console.warn("BUG: validateCustomerAnalyticsMessage called for method"+e.method),!1)}function g(e){return"request-upload"!==e.method?(console.warn("BUG: validateResizeMessage called for method"+e.method),!1):!!c(e.name)&&!(null!=e.accept&&!c(e.accept))}function y(e,t){var i=function(e){for(var t={warn:h,resize:f,setSetting:p,customerAnalytics:w,"request-upload":g,scrolly:m},i={},n=0;n<e.length;n++){var o=e[n];if(!t[o])throw new Error("No validator found for method "+o);i[o]=t[o]}return i}(t);window.addEventListener("message",(function(t){if(null!=t.source&&(t.origin===document.location.origin||t.origin.match(/\/\/localhost:\d+$|\/\/(?:public|app)\.flourish.devlocal$|\/\/flourish-api\.com$|\.flourish\.(?:local(:\d+)?|net|rocks|studio)$|\.uri\.sh$|\/\/flourish-user-templates\.com$/))){var n;try{n=JSON.parse(t.data)}catch(e){return void console.warn("Unexpected non-JSON message: "+JSON.stringify(t.data))}if("Flourish"===n.sender)if(n.method)if(Object.prototype.hasOwnProperty.call(i,n.method))if(i[n.method](n)){for(var o=document.querySelectorAll("iframe"),r=0;r<o.length;r++)if(o[r].contentWindow==t.source||o[r].contentWindow==t.source.parent)return void e(n,o[r]);console.warn("could not find frame",n)}else console.warn("Validation failed for the message",n);else console.warn("No validator implemented for message",n);else console.warn("The 'method' property was missing from message",n)}})),u()&&(window.addEventListener("resize",v),v())}function v(){for(var e=document.querySelectorAll(".flourish-embed"),t=0;t<e.length;t++){var i=e[t];if(!i.getAttribute("data-width")){var n=i.querySelector("iframe");if(n){var o=window.getComputedStyle(i),r=i.offsetWidth-parseFloat(o.paddingLeft)-parseFloat(o.paddingRight);n.style.width=r+"px"}}}}function _(e,t){var i=e.parentNode;if(i.classList.contains("fl-scrolly-wrapper"))console.warn("createScrolly is being called more than once per story. This should not happen.");else{i.classList.add("fl-scrolly-wrapper"),i.style.position="relative",i.style.paddingBottom="1px",i.style.transform="translate3d(0, 0, 0)",e.style.position="sticky";var n=i.getAttribute("data-height")||null;n||(n="80vh",e.style.height=n),e.style.top="calc(50vh - "+n+"/2)";var o=i.querySelector(".flourish-credit");o&&(o.style.position="sticky",o.style.top="calc(50vh + "+n+"/2)"),t.forEach((function(e,t){var n=document.createElement("div");n.setAttribute("data-slide",t),n.classList.add("fl-scrolly-caption"),n.style.position="relative",n.style.transform="translate3d(0,0,0)",n.style.textAlign="center",n.style.maxWidth="500px",n.style.height="auto",n.style.marginTop="0",n.style.marginBottom="100vh",n.style.marginLeft="auto",n.style.marginRight="auto";var o=document.createElement("div");o.innerHTML=e,o.style.display="inline-block",o.style.paddingTop="1.25em",o.style.paddingRight="1.25em",o.style.paddingBottom="1.25em",o.style.paddingLeft="1.25em",o.style.background="rgba(255,255,255,0.9)",o.style.boxShadow="0px 0px 10px rgba(0,0,0,0.2)",o.style.borderRadius="10px",o.style.textAlign="center",o.style.maxWidth="100%",o.style.margin="0 20px",o.style.overflowX="hidden",n.appendChild(o),i.appendChild(n)})),function(e){for(var t=new IntersectionObserver((function(t){t.forEach((function(t){if(t.isIntersecting){var i=e.querySelector("iframe");i&&(i.src=i.src.replace(/#slide-.*/,"")+"#slide-"+t.target.getAttribute("data-slide"))}}))}),{rootMargin:"0px 0px -0% 0px"}),i=e.querySelectorAll(".fl-scrolly-caption"),n=0;n<i.length;n++)t.observe(i[n]);e.querySelectorAll(".fl-scrolly-caption img").forEach((function(e){e.style.maxWidth="100%"}))}(i)}}function F(e,t,i,n,o){var r=document.createElement("iframe");if(r.setAttribute("scrolling","no"),r.setAttribute("frameborder","0"),r.setAttribute("title","Interactive or visual content"),r.setAttribute("sandbox","allow-same-origin allow-forms allow-scripts allow-downloads allow-popups allow-popups-to-escape-sandbox allow-top-navigation-by-user-activation"),t.appendChild(r),r.offsetParent||"fixed"===getComputedStyle(r).position)x(e,t,r,i,n,o);else{var a={embed_url:e,container:t,iframe:r,width:i,height:n,play_on_load:o};if(window._flourish_poll_items?window._flourish_poll_items.push(a):window._flourish_poll_items=[a],window._flourish_poll_items.length>1)return r;var s=setInterval((function(){window._flourish_poll_items=window._flourish_poll_items.filter((function(e){return!e.iframe.offsetParent||(x(e.embed_url,e.container,e.iframe,e.width,e.height,e.play_on_load),!1)})),window._flourish_poll_items.length||clearInterval(s)}),500)}return r}function x(e,t,i,n,o,r){var a;return n&&"number"==typeof n?(a=n,n+="px"):n&&n.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]*$/)&&(a=parseFloat(n)),o&&"number"==typeof o&&(o+="px"),n?i.style.width=n:u()?i.style.width=t.offsetWidth+"px":i.style.width="100%",!!o||(e.match(/\?/)?e+="&auto=1":e+="?auto=1",o=s(a||i.offsetWidth)+"px"),o&&("%"===o.charAt(o.length-1)&&(o=parseFloat(o)/100*t.parentNode.offsetHeight+"px"),i.style.height=o),i.setAttribute("src",e+(r?"#play-on-load":"")),i}function b(e){return!Array.isArray(e)&&"object"==typeof e&&null!=e}function A(e,t){for(var i in t)b(e[i])&&b(t[i])?A(e[i],t[i]):e[i]=t[i];return e}!function(){var e,i=window.top===window.self,c=i?null:(t="#amp=1"==window.location.hash,{createEmbedIframe:F,isFixedHeight:a,getHeightForBreakpoint:s,startEventListeners:y,notifyParentWindow:d,initScrolly:l,createScrolly:_,isSafari:u,initCustomerAnalytics:r,addAnalyticsListener:o,sendCustomerAnalyticsMessage:n}),h=!0;function f(){var t;Flourish.fixed_height||(null!=e?t=e:h&&(t=c.getHeightForBreakpoint()),t!==window.innerHeight&&c.notifyParentWindow(t))}function p(){-1!==window.location.search.indexOf("enable_customer_analytics=1")&&Flourish.enableCustomerAnalytics(),f(),window.addEventListener("resize",f)}Flourish.warn=function(e){if("string"==typeof e&&(e={message:e}),i||"editor"!==Flourish.environment)console.warn(e.message);else{var t={sender:"Flourish",method:"warn",message:e.message,explanation:e.explanation};window.parent.postMessage(JSON.stringify(t),"*")}},Flourish.uploadImage=function(e){if(i||"story_editor"!==Flourish.environment)throw"Invalid upload request";var t={sender:"Flourish",method:"request-upload",name:e.name,accept:e.accept};window.parent.postMessage(JSON.stringify(t),"*")},Flourish.setSetting=function(e,t){if("editor"===Flourish.environment||"sdk"===Flourish.environment){var i={sender:"Flourish",method:"setSetting",name:e,value:t};window.parent.postMessage(JSON.stringify(i),"*")}else if("story_editor"===Flourish.environment){var n={};n[e]=t,A(window.template.state,function(e){var t={};for(var i in e){for(var n=t,o=i.indexOf("."),r=0;o>=0;o=i.indexOf(".",r=o+1)){var a=i.substring(r,o);a in n||(n[a]={}),n=n[a]}n[i.substring(r)]=e[i]}return t}(n))}},Flourish.setHeight=function(t){Flourish.fixed_height||(e=t,h=null==t,f())},Flourish.checkHeight=function(){if(!i){var e=Flourish.__container_height;null!=e?(Flourish.fixed_height=!0,c.notifyParentWindow(e)):c.isFixedHeight()?Flourish.fixed_height=!0:(Flourish.fixed_height=!1,f())}},Flourish.fixed_height=i||c.isFixedHeight(),Flourish.enableCustomerAnalytics=function(){c&&c.initCustomerAnalytics()},"loading"===document.readyState?document.addEventListener("DOMContentLoaded",p):p()}()}();
2
2
  //# sourceMappingURL=embedded.js.map
Binary file
Binary file