diff --git a/CHANGELOG.md b/CHANGELOG.md
index af5d9d11fb0..b5305dd3118 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -561,6 +561,9 @@ where X.Y.Z is the semver of most recent plotly.js release.
## [1.49.5] -- 2019-09-18
+### Changed
+- Drop support for IE10 and IE9 as part of browserify upgrade [#4168]
+
### Fixed
- Clear rejected promises from queue when calling `Plotly.react` [#4197]
- Do not attempt to remove non-existing mapbox layout source and layers [#4197]
diff --git a/devtools/test_dashboard/index.html b/devtools/test_dashboard/index.html
index 1d4682febe6..adbf9785223 100644
--- a/devtools/test_dashboard/index.html
+++ b/devtools/test_dashboard/index.html
@@ -19,10 +19,6 @@
-
-
-
diff --git a/dist/README.md b/dist/README.md
index 346c491c458..a1dc31bcffb 100644
--- a/dist/README.md
+++ b/dist/README.md
@@ -14,15 +14,6 @@ or the un-minified version as:
```
-### To support IE9
-
-*Before* the plotly.js script tag, add:
-
-```html
-
-
-```
-
### To support MathJax
*Before* the plotly.js script tag, add:
diff --git a/src/lib/array.js b/src/lib/array.js
index e327eb5fed6..03ccef5aed2 100644
--- a/src/lib/array.js
+++ b/src/lib/array.js
@@ -10,15 +10,8 @@
var isArray = Array.isArray;
-// IE9 fallbacks
-
-var ab = (typeof ArrayBuffer === 'undefined' || !ArrayBuffer.isView) ?
- {isView: function() { return false; }} :
- ArrayBuffer;
-
-var dv = (typeof DataView === 'undefined') ?
- function() {} :
- DataView;
+var ab = ArrayBuffer;
+var dv = DataView;
function isTypedArray(a) {
return ab.isView(a) && !(a instanceof dv);
diff --git a/src/lib/index.js b/src/lib/index.js
index d2f68be079e..cb701e56699 100644
--- a/src/lib/index.js
+++ b/src/lib/index.js
@@ -712,11 +712,6 @@ lib.isIE = function() {
return typeof window.navigator.msSaveBlob !== 'undefined';
};
-var IS_IE9_OR_BELOW_REGEX = /MSIE [1-9]\./;
-lib.isIE9orBelow = function() {
- return lib.isIE() && IS_IE9_OR_BELOW_REGEX.test(window.navigator.userAgent);
-};
-
var IS_SAFARI_REGEX = /Version\/[\d\.]+.*Safari/;
lib.isSafari = function() {
return IS_SAFARI_REGEX.test(window.navigator.userAgent);
@@ -727,12 +722,8 @@ lib.isIOS = function() {
return IS_IOS_REGEX.test(window.navigator.userAgent);
};
-/**
- * Duck typing to recognize a d3 selection, mostly for IE9's benefit
- * because it doesn't handle instanceof like modern browsers
- */
lib.isD3Selection = function(obj) {
- return obj && (typeof obj.classed === 'function');
+ return obj instanceof d3.selection;
};
/**
diff --git a/src/lib/loggers.js b/src/lib/loggers.js
index 128b4015227..a0f28e64097 100644
--- a/src/lib/loggers.js
+++ b/src/lib/loggers.js
@@ -30,7 +30,7 @@ loggers.log = function() {
for(i = 0; i < arguments.length; i++) {
messages.push(arguments[i]);
}
- apply(console.trace || console.log, messages);
+ console.trace.apply(console, messages);
}
if(dfltConfig.notifyOnLogging > 1) {
@@ -50,7 +50,7 @@ loggers.warn = function() {
for(i = 0; i < arguments.length; i++) {
messages.push(arguments[i]);
}
- apply(console.trace || console.log, messages);
+ console.trace.apply(console, messages);
}
if(dfltConfig.notifyOnLogging > 0) {
@@ -70,7 +70,7 @@ loggers.error = function() {
for(i = 0; i < arguments.length; i++) {
messages.push(arguments[i]);
}
- apply(console.error, messages);
+ console.error.apply(console, messages);
}
if(dfltConfig.notifyOnLogging > 0) {
@@ -81,28 +81,3 @@ loggers.error = function() {
notifier(lines.join('
'), 'stick');
}
};
-
-/*
- * Robust apply, for IE9 where console.log doesn't support
- * apply like other functions do
- */
-function apply(f, args) {
- if(f && f.apply) {
- try {
- // `this` should always be console, since here we're always
- // applying a method of the console object.
- f.apply(console, args);
- return;
- } catch(e) { /* in case apply failed, fall back on the code below */ }
- }
-
- // no apply - just try calling the function on each arg independently
- for(var i = 0; i < args.length; i++) {
- try {
- f(args[i]);
- } catch(e) {
- // still fails - last resort simple console.log
- console.log(args[i]);
- }
- }
-}
diff --git a/src/snapshot/filesaver.js b/src/snapshot/filesaver.js
index 95553a25a90..60a09ac1f87 100644
--- a/src/snapshot/filesaver.js
+++ b/src/snapshot/filesaver.js
@@ -31,10 +31,6 @@ function fileSaver(url, name, format) {
var blob;
var objectUrl;
- if(Lib.isIE9orBelow()) {
- reject(new Error('IE < 10 unsupported'));
- }
-
// Safari doesn't allow downloading of blob urls
if(Lib.isSafari()) {
var prefix = format === 'svg' ? ',' : ';base64,';
diff --git a/src/snapshot/svgtoimg.js b/src/snapshot/svgtoimg.js
index 7df492be0f3..835e8d8932c 100644
--- a/src/snapshot/svgtoimg.js
+++ b/src/snapshot/svgtoimg.js
@@ -45,7 +45,7 @@ function svgToImg(opts) {
var img = new Image();
var svgBlob, url;
- if(format === 'svg' || Lib.isIE9orBelow() || Lib.isSafari()) {
+ if(format === 'svg' || Lib.isSafari()) {
url = helpers.encodeSVG(svg);
} else {
svgBlob = helpers.createBlob(svg, 'svg');
diff --git a/src/snapshot/tosvg.js b/src/snapshot/tosvg.js
index d5877c6df8b..941cd3ac5bd 100644
--- a/src/snapshot/tosvg.js
+++ b/src/snapshot/tosvg.js
@@ -164,6 +164,8 @@ module.exports = function toSVG(gd, format, scale) {
// Fix quotations around font strings and gradient URLs
s = s.replace(DUMMY_REGEX, '\'');
+ // Do we need this process now that IE9 and IE10 are not supported?
+
// IE is very strict, so we will need to clean
// svg with the following regex
// yes this is messy, but do not know a better way
diff --git a/tasks/stats.js b/tasks/stats.js
index 63ec0e50ab4..dbb535bebe0 100644
--- a/tasks/stats.js
+++ b/tasks/stats.js
@@ -46,15 +46,6 @@ function getInfoContent() {
'',
'```',
'',
- '### To support IE9',
- '',
- '*Before* the plotly.js script tag, add:',
- '',
- '```html',
- '',
- '',
- '```',
- '',
'### To support MathJax',
'',
'*Before* the plotly.js script tag, add:',
diff --git a/test/image/strict-d3.js b/test/image/strict-d3.js
index 43b8796f374..b3705cf3ae7 100644
--- a/test/image/strict-d3.js
+++ b/test/image/strict-d3.js
@@ -2,6 +2,7 @@
* strict-d3: wrap selection.style to prohibit specific incorrect style values
* that are known to cause problems in IE (at least IE9)
*/
+
'use strict';
var d3 = require('@plotly/d3');
diff --git a/test/jasmine/bundle_tests/ie9_test.js b/test/jasmine/bundle_tests/ie9_test.js
deleted file mode 100644
index e35c73bc160..00000000000
--- a/test/jasmine/bundle_tests/ie9_test.js
+++ /dev/null
@@ -1,42 +0,0 @@
-var Plotly = require('@lib/core');
-
-Plotly.register([
- require('@lib/bar'),
- require('@lib/box'),
- require('@lib/heatmap'),
- require('@lib/histogram'),
- require('@lib/histogram2d'),
- require('@lib/histogram2dcontour'),
- require('@lib/pie'),
- require('@lib/contour'),
- require('@lib/scatterternary'),
- require('@lib/ohlc'),
- require('@lib/candlestick')
-]);
-
-var createGraphDiv = require('../assets/create_graph_div');
-var destroyGraphDiv = require('../assets/destroy_graph_div');
-
-describe('Bundle with IE9 supported trace types:', function() {
- afterEach(destroyGraphDiv);
-
- it('check that ie9_mock.js did its job', function() {
- expect(function() { return ArrayBuffer; })
- .toThrow(new ReferenceError('ArrayBuffer is not defined'));
- expect(function() { return DataView; })
- .toThrow(new ReferenceError('DataView is not defined'));
- expect(function() { return Uint8Array; })
- .toThrow(new ReferenceError('Uint8Array is not defined'));
- });
-
- it('heatmaps with smoothing should work', function(done) {
- var gd = createGraphDiv();
- var data = [{
- type: 'heatmap',
- z: [[1, 2, 3], [2, 1, 2]],
- zsmooth: 'best'
- }];
-
- Plotly.plot(gd, data).then(done);
- });
-});
diff --git a/test/jasmine/karma.conf.js b/test/jasmine/karma.conf.js
index 113f3185ade..d3130a5749f 100644
--- a/test/jasmine/karma.conf.js
+++ b/test/jasmine/karma.conf.js
@@ -48,9 +48,6 @@ if(argv.info) {
'Run all tests with the `noCI` tag on Firefox in a 1500px wide window:',
' $ npm run test-jasmine -- --tags=noCI --FF --width=1500',
'',
- 'Run the `ie9_test.js` bundle test with the verbose reporter:',
- ' $ npm run test-jasmine -- --bundleTest=ie9 --verbose',
- '',
'Arguments:',
' - All non-flagged arguments corresponds to the test suites in `test/jasmine/tests/` to be run.',
' No need to add the `_test.js` suffix, we expand them correctly here.',
@@ -122,7 +119,6 @@ if(isFullSuite) {
var pathToShortcutPath = path.join(__dirname, '..', '..', 'tasks', 'util', 'shortcut_paths.js');
var pathToStrictD3 = path.join(__dirname, '..', '..', 'tasks', 'util', 'strict_d3.js');
var pathToJQuery = path.join(__dirname, 'assets', 'jquery-1.8.3.min.js');
-var pathToIE9mock = path.join(__dirname, 'assets', 'ie9_mock.js');
var pathToCustomMatchers = path.join(__dirname, 'assets', 'custom_matchers.js');
var pathToUnpolyfill = path.join(__dirname, 'assets', 'unpolyfill.js');
var pathToMathJax = path.join(constants.pathToDist, 'extras', 'mathjax');
@@ -323,13 +319,6 @@ if(isBundleTest) {
func.defaultConfig.files.push(constants.pathToPlotlyDistMin);
func.defaultConfig.preprocessors[testFileGlob] = ['browserify'];
break;
- case 'ie9':
- // load ie9_mock.js before plotly.js+test bundle
- // to catch reference errors that could occur
- // when plotly.js is first loaded.
- func.defaultConfig.files.push(pathToIE9mock);
- func.defaultConfig.preprocessors[testFileGlob] = ['browserify'];
- break;
case 'plotschema':
func.defaultConfig.browserify.ignoreTransform = './tasks/compress_attributes.js';
func.defaultConfig.preprocessors[testFileGlob] = ['browserify'];
diff --git a/test/jasmine/tests/lib_test.js b/test/jasmine/tests/lib_test.js
index 7ff8fd90367..f0b111c2367 100644
--- a/test/jasmine/tests/lib_test.js
+++ b/test/jasmine/tests/lib_test.js
@@ -1643,10 +1643,7 @@ describe('Test lib.js:', function() {
// this is what got us into trouble actually - d3 selections can
// contain non-nodes - say for example d3 selections! then they
// don't work correctly. But it makes a convenient test!
- d3.select(1),
- // just showing what we actually do in this function: duck type
- // using the `classed` method.
- {classed: function(v) { return !!v; }}
+ d3.select(1)
];
yesSelections.forEach(function(v) {
@@ -1675,28 +1672,25 @@ describe('Test lib.js:', function() {
var stashLogLevel;
var stashOnGraphLogLevel;
- function consoleFn(name, hasApply, messages) {
+ function consoleFn(name, messages) {
var out = function() {
- if(hasApply) expect(this).toBe(window.console);
var args = [];
for(var i = 0; i < arguments.length; i++) args.push(arguments[i]);
messages.push([name, args]);
};
- if(!hasApply) out.apply = undefined;
-
return out;
}
- function mockConsole(hasApply, hasTrace, hasError) {
+ function mockConsole() {
var out = {
MESSAGES: []
};
- out.log = consoleFn('log', hasApply, out.MESSAGES);
+ out.log = consoleFn('log', out.MESSAGES);
- if(hasError) out.error = consoleFn('error', hasApply, out.MESSAGES);
+ out.error = consoleFn('error', out.MESSAGES);
- if(hasTrace) out.trace = consoleFn('trace', hasApply, out.MESSAGES);
+ out.trace = consoleFn('trace', out.MESSAGES);
return out;
}
@@ -1713,8 +1707,8 @@ describe('Test lib.js:', function() {
config.notifyOnLogging = stashOnGraphLogLevel;
});
- it('emits one console message if apply is available', function() {
- var c = window.console = mockConsole(true, true, true);
+ it('emits one console message', function() {
+ var c = window.console = mockConsole();
config.logging = 2;
Lib.log('tick', 'tock', 'tick', 'tock', 1);
@@ -1728,50 +1722,8 @@ describe('Test lib.js:', function() {
]);
});
- it('falls back on console.log if no trace', function() {
- var c = window.console = mockConsole(true, false, true);
- config.logging = 2;
-
- Lib.log('Hi');
- Lib.warn(42);
-
- expect(c.MESSAGES).toEqual([
- ['log', ['LOG:', 'Hi']],
- ['log', ['WARN:', 42]]
- ]);
- });
-
- it('falls back on separate calls if no apply', function() {
- var c = window.console = mockConsole(false, false, true);
- config.logging = 2;
-
- Lib.log('tick', 'tock', 'tick', 'tock', 1);
- Lib.warn('I\'m', 'a', 'little', 'cuckoo', 'clock', [1, 2]);
- Lib.error('cuckoo!', 'cuckoo!!!', {a: 1, b: 2});
-
- expect(c.MESSAGES).toEqual([
- ['log', ['LOG:']],
- ['log', ['tick']],
- ['log', ['tock']],
- ['log', ['tick']],
- ['log', ['tock']],
- ['log', [1]],
- ['log', ['WARN:']],
- ['log', ['I\'m']],
- ['log', ['a']],
- ['log', ['little']],
- ['log', ['cuckoo']],
- ['log', ['clock']],
- ['log', [[1, 2]]],
- ['error', ['ERROR:']],
- ['error', ['cuckoo!']],
- ['error', ['cuckoo!!!']],
- ['error', [{a: 1, b: 2}]]
- ]);
- });
-
it('omits .log at log level 1', function() {
- var c = window.console = mockConsole(true, true, true);
+ var c = window.console = mockConsole();
config.logging = 1;
Lib.log(1);
@@ -1785,7 +1737,7 @@ describe('Test lib.js:', function() {
});
it('logs nothing at log level 0', function() {
- var c = window.console = mockConsole(true, true, true);
+ var c = window.console = mockConsole();
config.logging = 0;
Lib.log(1);
@@ -1795,22 +1747,6 @@ describe('Test lib.js:', function() {
expect(c.MESSAGES).toEqual([]);
});
- it('falls back on simple log if there is no console.error', function() {
- // TODO
-
- var c = window.console = mockConsole(true, true, false);
- config.logging = 2;
-
- Lib.error('who are you', 'who who... are you', {a: 1, b: 2});
-
- expect(c.MESSAGES).toEqual([
- ['log', ['ERROR:']],
- ['log', ['who are you']],
- ['log', ['who who... are you']],
- ['log', [{a: 1, b: 2}]]
- ]);
- });
-
describe('should log message in notifier div in accordance notifyOnLogging config option', function() {
var query = '.notifier-note';