Skip to content

Commit 82f5437

Browse files
committed
Update approach to use postMessage and wait for ready signal before sending data to cloud
1 parent 100da7b commit 82f5437

1 file changed

Lines changed: 42 additions & 24 deletions

File tree

src/plots/plots.js

Lines changed: 42 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ var formatLocale = require('d3-format').formatLocale;
66
var isNumeric = require('fast-isnumeric');
77
var b64encode = require('base64-arraybuffer');
88

9+
var version = require('../version').version;
910
var Registry = require('../registry');
1011
var PlotSchema = require('../plot_api/plot_schema');
1112
var Template = require('../plot_api/plot_template');
@@ -201,40 +202,57 @@ function positionPlayWithData(gd, container) {
201202
}
202203

203204
plots.sendDataToCloud = function(gd) {
204-
var destUrl = (window.PLOTLYENV || {}).BASE_URL || gd._context.plotlyServerURL;
205-
if(!destUrl) {
205+
var baseUrl = (window.PLOTLYENV || {}).BASE_URL || gd._context.plotlyServerURL;
206+
if(!baseUrl) {
206207
console.error('No destination URL provided (plotlyServerURL is not set)');
207208
return;
208209
}
209210

211+
// Plotly Cloud origin, used to validate incoming messages and to target outgoing ones.
212+
var cloudOrigin;
213+
try {
214+
cloudOrigin = new URL(baseUrl).origin;
215+
} catch(e) {
216+
console.error('Invalid plotlyServerURL: ' + baseUrl);
217+
return;
218+
}
219+
220+
// The page that handles login and signals back when authentication succeeds.
221+
var uploadUrl = baseUrl.replace(/\/+$/, '') + '/upload';
222+
210223
gd.emit('plotly_beforeexport');
211224

212-
var hiddenformDiv = d3.select(gd)
213-
.append('div')
214-
.attr('id', 'hiddenform')
215-
.style('display', 'none');
225+
// Build the request body: the chart JSON plus the plotly.js version used to
226+
// generate it, so Cloud can host the chart with a compatible plotly.js version.
227+
var chart = JSON.parse(plots.graphJson(gd, false, 'keepdata'));
228+
chart.version = version;
229+
230+
// Open the Cloud login page in a new tab. We keep a reference so we can post
231+
// the chart back to it once Cloud reports that authentication succeeded.
232+
var cloudWindow = window.open(uploadUrl, '_blank');
233+
if(!cloudWindow) {
234+
console.error('Unable to open Plotly Cloud (the popup may have been blocked)');
235+
gd.emit('plotly_afterexport');
236+
return;
237+
}
216238

217-
var hiddenform = hiddenformDiv
218-
.append('form')
219-
.attr({
220-
action: destUrl,
221-
method: 'post',
222-
target: '_blank'
223-
});
239+
var handleMessage = function(event) {
240+
// Only trust messages coming from the Cloud origin.
241+
if(event.origin !== cloudOrigin) return;
224242

225-
var hiddenformInput = hiddenform
226-
.append('input')
227-
.attr({
228-
type: 'text',
229-
name: 'data'
230-
});
243+
if(event.data && event.data.type === 'authenticated') {
244+
cloudWindow.postMessage({
245+
type: 'chart',
246+
chart: chart
247+
}, cloudOrigin);
248+
249+
window.removeEventListener('message', handleMessage);
250+
gd.emit('plotly_afterexport');
251+
}
252+
};
231253

232-
hiddenformInput.node().value = plots.graphJson(gd, false, 'keepdata');
233-
console.log(`sending chart object to ${destUrl}`);
234-
hiddenform.node().submit();
235-
hiddenformDiv.remove();
254+
window.addEventListener('message', handleMessage);
236255

237-
gd.emit('plotly_afterexport');
238256
return false;
239257
};
240258

0 commit comments

Comments
 (0)