diff --git a/package.json b/package.json index f078f74f983..905f7f29d3a 100644 --- a/package.json +++ b/package.json @@ -32,7 +32,7 @@ "citest-jasmine": "karma start test/jasmine/karma.ciconf.js", "test-image": "./tasks/test_image.sh", "test-syntax": "node test/syntax_test.js", - "test": "npm run test-jasmine && npm test-image", + "test": "npm run test-jasmine && npm test-image && npm test-syntax", "start-test_dashboard": "node devtools/test_dashboard/server.js", "start-image_viewer": "node devtools/image_viewer/server.js", "baseline": "./tasks/baseline.sh", @@ -44,7 +44,7 @@ "alpha-shape": "^1.0.0", "arraytools": "^1.0.0", "convex-hull": "^1.0.3", - "d3": "3.5.6", + "d3": "^3.5.12", "delaunay-triangulate": "^1.1.6", "es6-promise": "^3.0.2", "fast-isnumeric": "^1.1.1", @@ -73,17 +73,17 @@ "robust-orientation": "^1.1.3", "sane-topojson": "^1.2.0", "superscript-text": "^1.0.0", - "tinycolor2": "1.1.2", - "topojson": "^1.6.19" + "tinycolor2": "^1.3.0", + "topojson": "^1.6.20" }, "devDependencies": { - "brfs": "^1.4.1", - "browserify": "^12.0.1", - "browserify-transform-tools": "^1.5.0", + "brfs": "^1.4.3", + "browserify": "^13.0.0", + "browserify-transform-tools": "^1.5.1", "ecstatic": "^1.2.0", "eslint": "^1.10.3", "falafel": "^1.2.0", - "glob": "^6.0.1", + "glob": "^6.0.4", "jasmine-core": "^2.3.4", "karma": "^0.13.15", "karma-browserify": "^4.4.1", @@ -97,7 +97,7 @@ "prettysize": "0.0.3", "through2": "^2.0.0", "uglify-js": "^2.5.0", - "watchify": "^3.6.0", - "xml2js": "^0.4.15" + "watchify": "^3.7.0", + "xml2js": "^0.4.16" } } diff --git a/src/components/drawing/index.js b/src/components/drawing/index.js index 6f2a025ae73..8e0f48fcbfe 100644 --- a/src/components/drawing/index.js +++ b/src/components/drawing/index.js @@ -13,6 +13,7 @@ var Plotly = require('../../plotly'); var d3 = require('d3'); var isNumeric = require('fast-isnumeric'); +var xmlnsNamespaces = require('../../constants/xmlns_namespaces'); var subTypes = require('../../traces/scatter/subtypes'); var makeBubbleSizeFn = require('../../traces/scatter/make_bubble_size_func'); @@ -449,12 +450,8 @@ drawing.makeTester = function(gd) { .data([0]); tester.enter().append('svg') - .attr({ - id: 'js-plotly-tester', - xmlns: 'http://www.w3.org/2000/svg', - // odd d3 quirk - need namespace twice?? - 'xmlns:xmlns:xlink': 'http://www.w3.org/1999/xlink' - }) + .attr('id', 'js-plotly-tester') + .attr(xmlnsNamespaces.svgAttrs) .style({ position: 'absolute', left: '-10000px', diff --git a/src/constants/xmlns_namespaces.js b/src/constants/xmlns_namespaces.js new file mode 100644 index 00000000000..a2da63d921e --- /dev/null +++ b/src/constants/xmlns_namespaces.js @@ -0,0 +1,22 @@ +/** +* Copyright 2012-2016, Plotly, Inc. +* All rights reserved. +* +* This source code is licensed under the MIT license found in the +* LICENSE file in the root directory of this source tree. +*/ + + +'use strict'; + + +exports.xmlns = 'http://www.w3.org/2000/xmlns/'; +exports.svg = 'http://www.w3.org/2000/svg'; +exports.xlink = 'http://www.w3.org/1999/xlink'; + +// the 'old' d3 quirk got fix in v3.5.7 +// https://github.com/mbostock/d3/commit/a6f66e9dd37f764403fc7c1f26be09ab4af24fed +exports.svgAttrs = { + xmlns: exports.svg, + 'xmlns:xlink': exports.xlink +}; diff --git a/src/lib/svg_text_utils.js b/src/lib/svg_text_utils.js index ae5c151bc99..032b01fee14 100644 --- a/src/lib/svg_text_utils.js +++ b/src/lib/svg_text_utils.js @@ -14,16 +14,23 @@ var Plotly = require('../plotly'); var d3 = require('d3'); +var xmlnsNamespaces = require('../constants/xmlns_namespaces'); + var util = module.exports = {}; // Append SVG d3.selection.prototype.appendSVG = function(_svgString) { - var skeleton = '' + - _svgString + '', - dom = new DOMParser().parseFromString(skeleton, 'application/xml'), + var skeleton = [ + '', + _svgString, + '' + ].join(''); + + var dom = new DOMParser().parseFromString(skeleton, 'application/xml'), childNode = dom.documentElement.firstChild; + while(childNode) { this.node().appendChild(this.node().ownerDocument.importNode(childNode, true)); childNode = childNode.nextSibling; diff --git a/src/plot_api/plot_api.js b/src/plot_api/plot_api.js index 86d92cdfea4..094f803597e 100644 --- a/src/plot_api/plot_api.js +++ b/src/plot_api/plot_api.js @@ -28,6 +28,7 @@ var Legend = require('../components/legend'); var Shapes = require('../components/shapes'); var Titles = require('../components/titles'); var manageModeBar = require('../components/modebar/manage'); +var xmlnsNamespaces = require('../constants/xmlns_namespaces'); /** @@ -2567,11 +2568,7 @@ function makePlotFramework(gd) { } fullLayout._paperdiv.selectAll('.main-svg') - .attr({ - xmlns: 'http://www.w3.org/2000/svg', - // odd d3 quirk - need namespace twice?? - 'xmlns:xmlns:xlink': 'http://www.w3.org/1999/xlink' - }); + .attr(xmlnsNamespaces.svgAttrs); fullLayout._defs = fullLayout._paper.append('defs') .attr('id', 'defs-' + fullLayout._uid); diff --git a/src/plots/geo/geo.js b/src/plots/geo/geo.js index 022162258e2..2f08fafcbfb 100644 --- a/src/plots/geo/geo.js +++ b/src/plots/geo/geo.js @@ -24,6 +24,7 @@ var createGeoScale = require('./set_scale'); var createGeoZoom = require('./zoom'); var createGeoZoomReset = require('./zoom_reset'); +var xmlnsNamespaces = require('../../constants/xmlns_namespaces'); var constants = require('../../constants/geo_constants'); var topojsonUtils = require('../../lib/topojson_utils'); var topojsonFeature = require('topojson').feature; @@ -217,10 +218,7 @@ proto.makeFramework = function() { var hoverContainer = this.hoverContainer = geoDiv.append('svg'); hoverContainer - .attr({ - xmlns:'http://www.w3.org/2000/svg', - 'xmlns:xmlns:xlink': 'http://www.w3.org/1999/xlink' - }) + .attr(xmlnsNamespaces.svgAttrs) .style({ 'position': 'absolute', 'z-index': 20, @@ -229,9 +227,8 @@ proto.makeFramework = function() { var framework = this.framework = geoDiv.append('svg'); framework + .attr(xmlnsNamespaces.svgAttrs) .attr({ - 'xmlns':'http://www.w3.org/2000/svg', - 'xmlns:xmlns:xlink': 'http://www.w3.org/1999/xlink', 'position': 'absolute', 'preserveAspectRatio': 'none' }); diff --git a/src/plots/polar/micropolar.js b/src/plots/polar/micropolar.js index f28af079454..a17a0cf3995 100644 --- a/src/plots/polar/micropolar.js +++ b/src/plots/polar/micropolar.js @@ -1071,7 +1071,7 @@ var extendDeepAll = Plotly.Lib.extendDeepAll; width: 300, height: height + lineHeight, xmlns: 'http://www.w3.org/2000/svg', - 'xmlns:xmlns:xlink': 'http://www.w3.org/1999/xlink', + 'xmlns:xlink': 'http://www.w3.org/1999/xlink', version: '1.1' }); svgEnter.append('g').classed('legend-axis', true); diff --git a/src/snapshot/tosvg.js b/src/snapshot/tosvg.js index bea6334e528..0ebc68e44e4 100644 --- a/src/snapshot/tosvg.js +++ b/src/snapshot/tosvg.js @@ -9,8 +9,11 @@ 'use strict'; -var Plotly = require('../plotly'), - d3 = require('d3'); +var Plotly = require('../plotly'); +var d3 = require('d3'); + +var xmlnsNamespaces = require('../constants/xmlns_namespaces'); + module.exports = function toSVG(gd, format) { @@ -139,8 +142,8 @@ module.exports = function toSVG(gd, format) { // fix for IE namespacing quirk? // http://stackoverflow.com/questions/19610089/unwanted-namespaces-on-svg-markup-when-using-xmlserializer-in-javascript-with-ie - svg.node().setAttributeNS('http://www.w3.org/2000/xmlns/', 'xmlns', 'http://www.w3.org/2000/svg'); - svg.node().setAttributeNS('http://www.w3.org/2000/xmlns/', 'xmlns:xlink', 'http://www.w3.org/1999/xlink'); + svg.node().setAttributeNS(xmlnsNamespaces.xmlns, 'xmlns', xmlnsNamespaces.svg); + svg.node().setAttributeNS(xmlnsNamespaces.xmlns, 'xmlns:xlink', xmlnsNamespaces.xlink); var s = new window.XMLSerializer().serializeToString(svg.node()); s = Plotly.util.html_entity_decode(s); @@ -154,8 +157,8 @@ function insertGlImage(fullLayout, scene, opts) { fullLayout._glimages.append('svg:image') .attr({ - xmlns:'http://www.w3.org/2000/svg', - 'xlink:xlink:href': imageData, // odd d3 quirk, need namespace twice + xmlns: xmlnsNamespaces.svg, + 'xlink:href': imageData, x: opts.x, y: opts.y, width: opts.width, diff --git a/src/traces/heatmap/plot.js b/src/traces/heatmap/plot.js index e087f306e18..3f0f87d0597 100644 --- a/src/traces/heatmap/plot.js +++ b/src/traces/heatmap/plot.js @@ -15,6 +15,7 @@ var tinycolor = require('tinycolor2'); var Plotly = require('../../plotly'); var Lib = require('../../lib'); var getColorscale = require('../../components/colorscale/get_scale'); +var xmlnsNamespaces = require('../../constants/xmlns_namespaces'); var maxRowLength = require('./max_row_length'); @@ -372,8 +373,8 @@ function plotOne(gd, plotinfo, cd) { .classed(id, true) .datum(cd[0]) .attr({ - xmlns: 'http://www.w3.org/2000/svg', - 'xlink:xlink:href': canvas.toDataURL('image/png'), // odd d3 quirk, need namespace twice + xmlns: xmlnsNamespaces.svg, + 'xlink:href': canvas.toDataURL('image/png'), height: imageHeight, width: imageWidth, x: left, diff --git a/test/jasmine/tests/plot_interact_test.js b/test/jasmine/tests/plot_interact_test.js index bdf46fafbd7..89d1970be64 100644 --- a/test/jasmine/tests/plot_interact_test.js +++ b/test/jasmine/tests/plot_interact_test.js @@ -9,6 +9,13 @@ var destroyGraphDiv = require('../assets/destroy_graph_div'); describe('Test plot structure', function() { 'use strict'; + function assertNamespaces(node) { + expect(node.getAttribute('xmlns')) + .toEqual('http://www.w3.org/2000/svg'); + expect(node.getAttribute('xmlns:xlink')) + .toEqual('http://www.w3.org/1999/xlink'); + } + afterEach(destroyGraphDiv); describe('cartesian plots', function() { @@ -21,17 +28,17 @@ describe('Test plot structure', function() { it('has one *subplot xy* node', function() { var nodes = d3.selectAll('g.subplot.xy'); - expect(nodes[0].length).toEqual(1); + expect(nodes.size()).toEqual(1); }); it('has one *scatterlayer* node', function() { var nodes = d3.selectAll('g.scatterlayer'); - expect(nodes[0].length).toEqual(1); + expect(nodes.size()).toEqual(1); }); it('has as many *trace scatter* nodes as there are traces', function() { var nodes = d3.selectAll('g.trace.scatter'); - expect(nodes[0].length).toEqual(mock.data.length); + expect(nodes.size()).toEqual(mock.data.length); }); it('has as many *point* nodes as there are traces', function() { @@ -42,7 +49,16 @@ describe('Test plot structure', function() { Npts += trace.x.length; }); - expect(nodes[0].length).toEqual(Npts); + expect(nodes.size()).toEqual(Npts); + }); + + it('has the correct name spaces', function() { + var mainSVGs = d3.selectAll('.main-svg'); + + mainSVGs.each(function() { + var node = this; + assertNamespaces(node); + }); }); }); @@ -61,7 +77,19 @@ describe('Test plot structure', function() { Npts += trace.values.length; }); - expect(nodes[0].length).toEqual(Npts); + expect(nodes.size()).toEqual(Npts); + }); + + it('has the correct name spaces', function() { + var mainSVGs = d3.selectAll('.main-svg'); + + mainSVGs.each(function() { + var node = this; + assertNamespaces(node); + }); + + var testerSVG = d3.selectAll('#js-plotly-tester'); + assertNamespaces(testerSVG.node()); }); }); }); @@ -82,7 +110,7 @@ describe('Test plot structure', function() { if(items) Npts += items.length; }); - expect(nodes[0].length).toEqual(Npts); + expect(nodes.size()).toEqual(Npts); }); it('has as many *point* nodes as there are marker points', function() { @@ -94,7 +122,23 @@ describe('Test plot structure', function() { if(items) Npts += items.length; }); - expect(nodes[0].length).toEqual(Npts); + expect(nodes.size()).toEqual(Npts); + }); + + it('has the correct name spaces', function() { + var mainSVGs = d3.selectAll('.main-svg'); + + mainSVGs.each(function() { + var node = this; + assertNamespaces(node); + }); + + var geoSVGs = d3.select('#geo').selectAll('svg'); + + geoSVGs.each(function() { + var node = this; + assertNamespaces(node); + }); }); }); @@ -113,7 +157,7 @@ describe('Test plot structure', function() { Npts += trace.r.length; }); - expect(nodes[0].length).toEqual(Npts); + expect(nodes.size()).toEqual(Npts); }); }); }); diff --git a/test/syntax_test.js b/test/syntax_test.js index 9f982601c60..cb4dc383340 100644 --- a/test/syntax_test.js +++ b/test/syntax_test.js @@ -6,7 +6,7 @@ var glob = require('glob'); var constants = require('../tasks/util/constants'); -var focusGlobals = ['fdescribe', 'fit']; +var focusGlobals = ['fdescribe', 'fit', 'xdescribe', 'xit']; var logs = []; @@ -19,12 +19,13 @@ glob(path.join(constants.pathToJasmineTests, '**/*.js'), function(err, files) { logs.push([ path.basename(file), '[line ' + node.loc.start.line + '] :', - 'contains either a *fdescribe* or a *fit* block.' + 'contains either a *fdescribe*, *fit*,', + '*xdescribe* or *xit* block.' ].join(' ')); } }); }); - if(logs.length) throw new Error(logs.join('\n')); + if(logs.length) throw new Error('\n' + logs.join('\n') + '\n'); });