diff --git a/src/components/modebar/manage.js b/src/components/modebar/manage.js index 1eb9341c0f6..194733598ca 100644 --- a/src/components/modebar/manage.js +++ b/src/components/modebar/manage.js @@ -64,7 +64,8 @@ module.exports = function manageModeBar(gd) { buttonGroups = getButtonGroups( gd, context.modeBarButtonsToRemove, - context.modeBarButtonsToAdd + context.modeBarButtonsToAdd, + context.showSendToCloud ); } @@ -73,7 +74,7 @@ module.exports = function manageModeBar(gd) { }; // logic behind which buttons are displayed by default -function getButtonGroups(gd, buttonsToRemove, buttonsToAdd) { +function getButtonGroups(gd, buttonsToRemove, buttonsToAdd, showSendToCloud) { var fullLayout = gd._fullLayout; var fullData = gd._fullData; @@ -104,7 +105,9 @@ function getButtonGroups(gd, buttonsToRemove, buttonsToAdd) { } // buttons common to all plot types - addGroup(['toImage', 'sendDataToCloud']); + var commonGroup = ['toImage']; + if(showSendToCloud) commonGroup.push('sendDataToCloud'); + addGroup(commonGroup); var zoomGroup = []; var hoverGroup = []; diff --git a/src/plot_api/plot_config.js b/src/plot_api/plot_config.js index 0f195c73db5..fe92027831a 100644 --- a/src/plot_api/plot_config.js +++ b/src/plot_api/plot_config.js @@ -90,12 +90,34 @@ module.exports = { */ showAxisRangeEntryBoxes: true, - // link to open this plot in plotly + /* + * Add a text link to open this plot in plotly? + * This link shows up in the bottom right corner of the plot, and works + * identically to the newer ModeBar button controlled by `showSendToCloud` + * unless `sendData: false` is used. + */ showLink: false, - // if we show a link, does it contain data or just link to a plotly file? + /* + * If we show a text link (`showLink: true`), does it contain data or just + * a reference to a plotly cloud file? This option should only be used on + * plot.ly or another plotly server, and is not supported by the newer + * ModeBar button `showSendToCloud`. + */ sendData: true, + /* + * Should we include a ModeBar button, labeled "Edit in Chart Studio", + * that sends this chart to plot.ly or another plotly server as specified + * by `plotlyServerURL` for editing, export, etc? Prior to version 1.43.0 + * this button was included by default, now it is opt-in using this flag. + * + * Note that this button can (depending on `plotlyServerURL`) send your data + * to an external server. However that server doesn't persist your data + * until you arrive at the Chart Studio and explicitly click "Save". + */ + showSendToCloud: false, + // text appearing in the sendData link linkText: 'Edit chart', diff --git a/test/jasmine/tests/modebar_test.js b/test/jasmine/tests/modebar_test.js index 341380caf58..e14594e44ae 100644 --- a/test/jasmine/tests/modebar_test.js +++ b/test/jasmine/tests/modebar_test.js @@ -45,6 +45,7 @@ describe('ModeBar', function() { _fullData: [], _context: { displaylogo: true, + showSendToCloud: false, displayModeBar: true, modeBarButtonsToRemove: [], modeBarButtonsToAdd: [], @@ -55,15 +56,15 @@ describe('ModeBar', function() { } function countGroups(modeBar) { - return d3.select(modeBar.element).selectAll('div.modebar-group')[0].length; + return d3.select(modeBar.element).selectAll('div.modebar-group').size(); } function countButtons(modeBar) { - return d3.select(modeBar.element).selectAll('a.modebar-btn')[0].length; + return d3.select(modeBar.element).selectAll('a.modebar-btn').size(); } function countLogo(modeBar) { - return d3.select(modeBar.element).selectAll('a.plotlyjsicon')[0].length; + return d3.select(modeBar.element).selectAll('a.plotlyjsicon').size(); } function checkBtnAttr(modeBar, index, attr) { @@ -334,7 +335,7 @@ describe('ModeBar', function() { it('creates mode bar (unselectable cartesian version)', function() { var buttons = getButtons([ - ['toImage', 'sendDataToCloud'], + ['toImage'], ['zoom2d', 'pan2d'], ['zoomIn2d', 'zoomOut2d', 'autoScale2d', 'resetScale2d'], ['toggleSpikelines', 'hoverClosestCartesian', 'hoverCompareCartesian'] @@ -352,7 +353,7 @@ describe('ModeBar', function() { it('creates mode bar (selectable scatter version)', function() { var buttons = getButtons([ - ['toImage', 'sendDataToCloud'], + ['toImage'], ['zoom2d', 'pan2d', 'select2d', 'lasso2d'], ['zoomIn2d', 'zoomOut2d', 'autoScale2d', 'resetScale2d'], ['toggleSpikelines', 'hoverClosestCartesian', 'hoverCompareCartesian'] @@ -376,7 +377,7 @@ describe('ModeBar', function() { it('creates mode bar (selectable box version)', function() { var buttons = getButtons([ - ['toImage', 'sendDataToCloud'], + ['toImage'], ['zoom2d', 'pan2d', 'select2d', 'lasso2d'], ['zoomIn2d', 'zoomOut2d', 'autoScale2d', 'resetScale2d'], ['toggleSpikelines', 'hoverClosestCartesian', 'hoverCompareCartesian'] @@ -400,7 +401,7 @@ describe('ModeBar', function() { it('creates mode bar (cartesian fixed-axes version)', function() { var buttons = getButtons([ - ['toImage', 'sendDataToCloud'], + ['toImage'], ['toggleSpikelines', 'hoverClosestCartesian', 'hoverCompareCartesian'] ]); @@ -415,7 +416,7 @@ describe('ModeBar', function() { it('creates mode bar (gl3d version)', function() { var buttons = getButtons([ - ['toImage', 'sendDataToCloud'], + ['toImage'], ['zoom3d', 'pan3d', 'orbitRotation', 'tableRotation'], ['resetCameraDefault3d', 'resetCameraLastSave3d'], ['hoverClosest3d'] @@ -432,7 +433,7 @@ describe('ModeBar', function() { it('creates mode bar (geo version)', function() { var buttons = getButtons([ - ['toImage', 'sendDataToCloud'], + ['toImage'], ['pan2d'], ['zoomInGeo', 'zoomOutGeo', 'resetGeo'], ['hoverClosestGeo'] @@ -449,7 +450,7 @@ describe('ModeBar', function() { it('creates mode bar (geo + selected version)', function() { var buttons = getButtons([ - ['toImage', 'sendDataToCloud'], + ['toImage'], ['pan2d', 'select2d', 'lasso2d'], ['zoomInGeo', 'zoomOutGeo', 'resetGeo'], ['hoverClosestGeo'] @@ -472,7 +473,7 @@ describe('ModeBar', function() { it('creates mode bar (mapbox version)', function() { var buttons = getButtons([ - ['toImage', 'sendDataToCloud'], + ['toImage'], ['pan2d'], ['resetViewMapbox'], ['toggleHover'] @@ -489,7 +490,7 @@ describe('ModeBar', function() { it('creates mode bar (mapbox + selected version)', function() { var buttons = getButtons([ - ['toImage', 'sendDataToCloud'], + ['toImage'], ['pan2d', 'select2d', 'lasso2d'], ['resetViewMapbox'], ['toggleHover'] @@ -512,7 +513,7 @@ describe('ModeBar', function() { it('creates mode bar (gl2d version)', function() { var buttons = getButtons([ - ['toImage', 'sendDataToCloud'], + ['toImage'], ['zoom2d', 'pan2d'], ['zoomIn2d', 'zoomOut2d', 'autoScale2d', 'resetScale2d'], ['hoverClosestGl2d'] @@ -530,7 +531,7 @@ describe('ModeBar', function() { it('creates mode bar (pie version)', function() { var buttons = getButtons([ - ['toImage', 'sendDataToCloud'], + ['toImage'], ['hoverClosestPie'] ]); @@ -545,7 +546,7 @@ describe('ModeBar', function() { it('creates mode bar (cartesian + gl3d version)', function() { var buttons = getButtons([ - ['toImage', 'sendDataToCloud'], + ['toImage'], ['zoom3d', 'pan3d', 'orbitRotation', 'tableRotation'], ['resetViews'], ['toggleSpikelines', 'hoverClosestCartesian', 'hoverCompareCartesian'] @@ -562,7 +563,7 @@ describe('ModeBar', function() { it('creates mode bar (cartesian + geo unselectable version)', function() { var buttons = getButtons([ - ['toImage', 'sendDataToCloud'], + ['toImage'], ['zoom2d', 'pan2d'], ['zoomIn2d', 'zoomOut2d', 'autoScale2d', 'resetViews'], ['toggleSpikelines', 'hoverClosestCartesian', 'hoverCompareCartesian'] @@ -580,7 +581,7 @@ describe('ModeBar', function() { it('creates mode bar (cartesian + geo selectable version)', function() { var buttons = getButtons([ - ['toImage', 'sendDataToCloud'], + ['toImage'], ['zoom2d', 'pan2d', 'select2d', 'lasso2d'], ['zoomIn2d', 'zoomOut2d', 'autoScale2d', 'resetViews'], ['toggleSpikelines', 'hoverClosestCartesian', 'hoverCompareCartesian'] @@ -604,7 +605,7 @@ describe('ModeBar', function() { it('creates mode bar (cartesian + pie version)', function() { var buttons = getButtons([ - ['toImage', 'sendDataToCloud'], + ['toImage'], ['zoom2d', 'pan2d', 'select2d', 'lasso2d'], ['zoomIn2d', 'zoomOut2d', 'autoScale2d', 'resetScale2d'], ['toggleSpikelines', 'hoverClosestCartesian', 'hoverCompareCartesian'] @@ -628,7 +629,7 @@ describe('ModeBar', function() { it('creates mode bar (gl3d + geo version)', function() { var buttons = getButtons([ - ['toImage', 'sendDataToCloud'], + ['toImage'], ['zoom3d', 'pan3d', 'orbitRotation', 'tableRotation'], ['resetViews'], ['toggleHover'] @@ -645,7 +646,7 @@ describe('ModeBar', function() { it('creates mode bar (un-selectable ternary version)', function() { var buttons = getButtons([ - ['toImage', 'sendDataToCloud'], + ['toImage'], ['zoom2d', 'pan2d'], ['toggleHover'] ]); @@ -661,7 +662,7 @@ describe('ModeBar', function() { it('creates mode bar (selectable ternary version)', function() { var buttons = getButtons([ - ['toImage', 'sendDataToCloud'], + ['toImage'], ['zoom2d', 'pan2d', 'select2d', 'lasso2d'], ['toggleHover'] ]); @@ -683,7 +684,7 @@ describe('ModeBar', function() { it('creates mode bar (ternary + cartesian version)', function() { var buttons = getButtons([ - ['toImage', 'sendDataToCloud'], + ['toImage'], ['zoom2d', 'pan2d'], ['toggleSpikelines', 'hoverClosestCartesian', 'hoverCompareCartesian'] ]); @@ -699,7 +700,7 @@ describe('ModeBar', function() { it('creates mode bar (ternary + gl3d version)', function() { var buttons = getButtons([ - ['toImage', 'sendDataToCloud'], + ['toImage'], ['zoom3d', 'pan3d', 'orbitRotation', 'tableRotation'], ['resetViews'], ['toggleHover'] @@ -756,6 +757,23 @@ describe('ModeBar', function() { expect(countLogo(gd._fullLayout._modeBar)).toEqual(0); }); + it('displays/hides cloud link according to showSendToCloud config arg', function() { + var gd = getMockGraphInfo(); + gd._fullLayout._basePlotModules = [{ name: 'pie' }]; + manageModeBar(gd); + checkButtons(gd._fullLayout._modeBar, getButtons([ + ['toImage'], + ['hoverClosestPie'] + ]), 1); + + gd._context.showSendToCloud = true; + manageModeBar(gd); + checkButtons(gd._fullLayout._modeBar, getButtons([ + ['toImage', 'sendDataToCloud'], + ['hoverClosestPie'] + ]), 1); + }); + it('always displays the logo if watermark config arg is true', function() { var gd = getMockGraphInfo(); gd._context.displaylogo = false; @@ -778,10 +796,12 @@ describe('ModeBar', function() { var gd = setupGraphInfo(); manageModeBar(gd); + expect(countButtons(gd._fullLayout._modeBar)).toEqual(11); + gd._fullLayout._basePlotModules = [{ name: 'gl3d' }]; manageModeBar(gd); - expect(countButtons(gd._fullLayout._modeBar)).toEqual(10); + expect(countButtons(gd._fullLayout._modeBar)).toEqual(9); }); it('updates mode bar buttons if modeBarButtonsToRemove changes', function() { @@ -789,7 +809,7 @@ describe('ModeBar', function() { manageModeBar(gd); var initialButtonCount = countButtons(gd._fullLayout._modeBar); - gd._context.modeBarButtonsToRemove = ['toImage', 'sendDataToCloud']; + gd._context.modeBarButtonsToRemove = ['toImage', 'zoom2d']; manageModeBar(gd); expect(countButtons(gd._fullLayout._modeBar)) @@ -829,7 +849,7 @@ describe('ModeBar', function() { var modeBar = gd._fullLayout._modeBar; expect(countGroups(modeBar)).toEqual(6); - expect(countButtons(modeBar)).toEqual(11); + expect(countButtons(modeBar)).toEqual(10); }); it('sets up buttons with modeBarButtonsToAdd and modeBarButtonToRemove (2)', function() { @@ -849,7 +869,7 @@ describe('ModeBar', function() { var modeBar = gd._fullLayout._modeBar; expect(countGroups(modeBar)).toEqual(7); - expect(countButtons(modeBar)).toEqual(13); + expect(countButtons(modeBar)).toEqual(12); }); it('sets up buttons with fully custom modeBarButtons', function() {