diff --git a/.gitignore b/.gitignore index bbd62a042419..491c72e229b5 100644 --- a/.gitignore +++ b/.gitignore @@ -104,3 +104,5 @@ lib/z.lib ######################### jquery-ui-*/ +lib/matplotlib/backends/web_backend/node_modules/ +lib/matplotlib/backends/web_backend/package-lock.json diff --git a/lib/matplotlib/backends/web_backend/.eslintrc.js b/lib/matplotlib/backends/web_backend/.eslintrc.js new file mode 100644 index 000000000000..f073e7fa3dc0 --- /dev/null +++ b/lib/matplotlib/backends/web_backend/.eslintrc.js @@ -0,0 +1,21 @@ +module.exports = { + root: true, + ignorePatterns: ["jquery-ui-*/", "node_modules/"], + env: { + browser: true, + jquery: true, + }, + extends: ["eslint:recommended", "prettier"], + globals: { + IPython: "readonly", + MozWebSocket: "readonly", + }, + rules: { + "no-unused-vars": [ + "error", + { + argsIgnorePattern: "^_", + }, + ], + }, +}; diff --git a/lib/matplotlib/backends/web_backend/.prettierignore b/lib/matplotlib/backends/web_backend/.prettierignore new file mode 100644 index 000000000000..06a29c66e0fc --- /dev/null +++ b/lib/matplotlib/backends/web_backend/.prettierignore @@ -0,0 +1,7 @@ +node_modules/ + +# Vendored dependencies +css/boilerplate.css +css/fbm.css +css/page.css +jquery-ui-*/ diff --git a/lib/matplotlib/backends/web_backend/.prettierrc b/lib/matplotlib/backends/web_backend/.prettierrc new file mode 100644 index 000000000000..fe8d711065d6 --- /dev/null +++ b/lib/matplotlib/backends/web_backend/.prettierrc @@ -0,0 +1,11 @@ +{ + "overrides": [ + { + "files": "js/**/*.js", + "options": { + "singleQuote": true, + "tabWidth": 4, + } + } + ] +} diff --git a/lib/matplotlib/backends/web_backend/js/mpl.js b/lib/matplotlib/backends/web_backend/js/mpl.js index 7c774b4a16d0..4986680f5f2b 100644 --- a/lib/matplotlib/backends/web_backend/js/mpl.js +++ b/lib/matplotlib/backends/web_backend/js/mpl.js @@ -1,34 +1,36 @@ /* Put everything inside the global mpl namespace */ +/* global mpl */ window.mpl = {}; - -mpl.get_websocket_type = function() { - if (typeof(WebSocket) !== 'undefined') { +mpl.get_websocket_type = function () { + if (typeof WebSocket !== 'undefined') { return WebSocket; - } else if (typeof(MozWebSocket) !== 'undefined') { + } else if (typeof MozWebSocket !== 'undefined') { return MozWebSocket; } else { - alert('Your browser does not have WebSocket support. ' + - 'Please try Chrome, Safari or Firefox ≥ 6. ' + - 'Firefox 4 and 5 are also supported but you ' + - 'have to enable WebSockets in about:config.'); - }; -} + alert( + 'Your browser does not have WebSocket support. ' + + 'Please try Chrome, Safari or Firefox ≥ 6. ' + + 'Firefox 4 and 5 are also supported but you ' + + 'have to enable WebSockets in about:config.' + ); + } +}; -mpl.figure = function(figure_id, websocket, ondownload, parent_element) { +mpl.figure = function (figure_id, websocket, ondownload, parent_element) { this.id = figure_id; this.ws = websocket; - this.supports_binary = (this.ws.binaryType != undefined); + this.supports_binary = this.ws.binaryType !== undefined; if (!this.supports_binary) { - var warnings = document.getElementById("mpl-warnings"); + var warnings = document.getElementById('mpl-warnings'); if (warnings) { warnings.style.display = 'block'; - warnings.textContent = ( - "This browser does not support binary websocket messages. " + - "Performance may be slow."); + warnings.textContent = + 'This browser does not support binary websocket messages. ' + + 'Performance may be slow.'; } } @@ -44,7 +46,7 @@ mpl.figure = function(figure_id, websocket, ondownload, parent_element) { this.image_mode = 'full'; this.root = $('
'); - this._root_extra_style(this.root) + this._root_extra_style(this.root); this.root.attr('style', 'display: inline-block'); $(parent_element).append(this.root); @@ -57,58 +59,53 @@ mpl.figure = function(figure_id, websocket, ondownload, parent_element) { this.waiting = false; - this.ws.onopen = function () { - fig.send_message("supports_binary", {value: fig.supports_binary}); - fig.send_message("send_image_mode", {}); - if (mpl.ratio != 1) { - fig.send_message("set_dpi_ratio", {'dpi_ratio': mpl.ratio}); - } - fig.send_message("refresh", {}); + this.ws.onopen = function () { + fig.send_message('supports_binary', { value: fig.supports_binary }); + fig.send_message('send_image_mode', {}); + if (mpl.ratio !== 1) { + fig.send_message('set_dpi_ratio', { dpi_ratio: mpl.ratio }); } + fig.send_message('refresh', {}); + }; - this.imageObj.onload = function() { - if (fig.image_mode == 'full') { - // Full images could contain transparency (where diff images - // almost always do), so we need to clear the canvas so that - // there is no ghosting. - fig.context.clearRect(0, 0, fig.canvas.width, fig.canvas.height); - } - fig.context.drawImage(fig.imageObj, 0, 0); - }; + this.imageObj.onload = function () { + if (fig.image_mode === 'full') { + // Full images could contain transparency (where diff images + // almost always do), so we need to clear the canvas so that + // there is no ghosting. + fig.context.clearRect(0, 0, fig.canvas.width, fig.canvas.height); + } + fig.context.drawImage(fig.imageObj, 0, 0); + }; - this.imageObj.onunload = function() { + this.imageObj.onunload = function () { fig.ws.close(); - } + }; this.ws.onmessage = this._make_on_message_function(this); this.ondownload = ondownload; -} +}; -mpl.figure.prototype._init_header = function() { +mpl.figure.prototype._init_header = function () { var titlebar = $( '
'); + 'ui-helper-clearfix"/>' + ); var titletext = $( '
'); - titlebar.append(titletext) + 'text-align: center; padding: 3px;"/>' + ); + titlebar.append(titletext); this.root.append(titlebar); this.header = titletext[0]; -} - - - -mpl.figure.prototype._canvas_extra_style = function(canvas_div) { - -} - +}; -mpl.figure.prototype._root_extra_style = function(canvas_div) { +mpl.figure.prototype._canvas_extra_style = function (_canvas_div) {}; -} +mpl.figure.prototype._root_extra_style = function (_canvas_div) {}; -mpl.figure.prototype._init_canvas = function() { +mpl.figure.prototype._init_canvas = function () { var fig = this; var canvas_div = $('
'); @@ -121,47 +118,53 @@ mpl.figure.prototype._init_canvas = function() { canvas_div.keydown('key_press', canvas_keyboard_event); canvas_div.keyup('key_release', canvas_keyboard_event); - this.canvas_div = canvas_div - this._canvas_extra_style(canvas_div) + this.canvas_div = canvas_div; + this._canvas_extra_style(canvas_div); this.root.append(canvas_div); var canvas = $(''); canvas.addClass('mpl-canvas'); - canvas.attr('style', "left: 0; top: 0; z-index: 0; outline: 0") + canvas.attr('style', 'left: 0; top: 0; z-index: 0; outline: 0'); this.canvas = canvas[0]; - this.context = canvas[0].getContext("2d"); + this.context = canvas[0].getContext('2d'); - var backingStore = this.context.backingStorePixelRatio || - this.context.webkitBackingStorePixelRatio || - this.context.mozBackingStorePixelRatio || - this.context.msBackingStorePixelRatio || - this.context.oBackingStorePixelRatio || - this.context.backingStorePixelRatio || 1; + var backingStore = + this.context.backingStorePixelRatio || + this.context.webkitBackingStorePixelRatio || + this.context.mozBackingStorePixelRatio || + this.context.msBackingStorePixelRatio || + this.context.oBackingStorePixelRatio || + this.context.backingStorePixelRatio || + 1; mpl.ratio = (window.devicePixelRatio || 1) / backingStore; var rubberband = $(''); - rubberband.attr('style', "position: absolute; left: 0; top: 0; z-index: 1;") + rubberband.attr( + 'style', + 'position: absolute; left: 0; top: 0; z-index: 1;' + ); var pass_mouse_events = true; canvas_div.resizable({ - start: function(event, ui) { + start: function (_event, _ui) { pass_mouse_events = false; }, - resize: function(event, ui) { + resize: function (_event, ui) { fig.request_resize(ui.size.width, ui.size.height); }, - stop: function(event, ui) { + stop: function (_event, ui) { pass_mouse_events = true; fig.request_resize(ui.size.width, ui.size.height); }, }); function mouse_event_fn(event) { - if (pass_mouse_events) + if (pass_mouse_events) { return fig.mouse_event(event, event['data']); + } } rubberband.mousedown('button_press', mouse_event_fn); @@ -172,9 +175,9 @@ mpl.figure.prototype._init_canvas = function() { rubberband.mouseenter('figure_enter', mouse_event_fn); rubberband.mouseleave('figure_leave', mouse_event_fn); - canvas_div.on("wheel", function (event) { + canvas_div.on('wheel', function (event) { event = event.originalEvent; - event['data'] = 'scroll' + event['data'] = 'scroll'; if (event.deltaY < 0) { event.step = 1; } else { @@ -188,41 +191,44 @@ mpl.figure.prototype._init_canvas = function() { this.rubberband = rubberband; this.rubberband_canvas = rubberband[0]; - this.rubberband_context = rubberband[0].getContext("2d"); - this.rubberband_context.strokeStyle = "#000000"; + this.rubberband_context = rubberband[0].getContext('2d'); + this.rubberband_context.strokeStyle = '#000000'; - this._resize_canvas = function(width, height) { + this._resize_canvas = function (width, height) { // Keep the size of the canvas, canvas container, and rubber band // canvas in synch. - canvas_div.css('width', width) - canvas_div.css('height', height) + canvas_div.css('width', width); + canvas_div.css('height', height); canvas.attr('width', width * mpl.ratio); canvas.attr('height', height * mpl.ratio); - canvas.attr('style', 'width: ' + width + 'px; height: ' + height + 'px;'); + canvas.attr( + 'style', + 'width: ' + width + 'px; height: ' + height + 'px;' + ); rubberband.attr('width', width); rubberband.attr('height', height); - } + }; // Set the figure to an initial 600x600px, this will subsequently be updated // upon first draw. this._resize_canvas(600, 600); // Disable right mouse context menu. - $(this.rubberband_canvas).bind("contextmenu",function(e){ + $(this.rubberband_canvas).bind('contextmenu', function (_e) { return false; }); - function set_focus () { + function set_focus() { canvas.focus(); canvas_div.focus(); } window.setTimeout(set_focus, 100); -} +}; -mpl.figure.prototype._init_toolbar = function() { +mpl.figure.prototype._init_toolbar = function () { var fig = this; var nav_element = $('
'); @@ -237,7 +243,7 @@ mpl.figure.prototype._init_toolbar = function() { return fig.toolbar_button_onmouseover(event['data']); } - for(var toolbar_ind in mpl.toolbar_items) { + for (var toolbar_ind in mpl.toolbar_items) { var name = mpl.toolbar_items[toolbar_ind][0]; var tooltip = mpl.toolbar_items[toolbar_ind][1]; var image = mpl.toolbar_items[toolbar_ind][2]; @@ -248,8 +254,10 @@ mpl.figure.prototype._init_toolbar = function() { continue; } var button = $(''); + button = $( + '' + ); button.click(method_name, toolbar_event); button.mouseover(tooltip, toolbar_mouse_event); nav_element.append(button); } // Add the status bar. - var status_bar = $(''); + var status_bar = $( + '' + ); nav_element.append(status_bar); this.message = status_bar[0]; // Add the close button to the window. var buttongrp = $('
'); - var button = $(''); - button.click(function (evt) { fig.handle_close(fig, {}); } ); + button = $( + '' + ); + button.click(function (_evt) { + fig.handle_close(fig, {}); + }); button.mouseover('Stop Interaction', toolbar_mouse_event); buttongrp.append(button); var titlebar = this.root.find($('.ui-dialog-titlebar')); titlebar.prepend(buttongrp); -} +}; -mpl.figure.prototype._root_extra_style = function(el){ - var fig = this - el.on("remove", function(){ - fig.close_ws(fig, {}); +mpl.figure.prototype._root_extra_style = function (el) { + var fig = this; + el.on('remove', function () { + fig.close_ws(fig, {}); }); -} +}; -mpl.figure.prototype._canvas_extra_style = function(el){ +mpl.figure.prototype._canvas_extra_style = function (el) { // this is important to make the div 'focusable - el.attr('tabindex', 0) + el.attr('tabindex', 0); // reach out to IPython and tell the keyboard manager to turn it's self // off when our div gets focus // location in version 3 if (IPython.notebook.keyboard_manager) { IPython.notebook.keyboard_manager.register_events(el); - } - else { + } else { // location in version 2 IPython.keyboard_manager.register_events(el); } +}; -} - -mpl.figure.prototype._key_event_extra = function(event, name) { +mpl.figure.prototype._key_event_extra = function (event, _name) { var manager = IPython.notebook.keyboard_manager; - if (!manager) + if (!manager) { manager = IPython.keyboard_manager; + } // Check for shift+enter - if (event.shiftKey && event.which == 13) { + if (event.shiftKey && event.which === 13) { this.canvas_div.blur(); // select the cell after this one var index = IPython.notebook.find_cell_index(this.cell_info[0]); IPython.notebook.select(index + 1); } -} +}; -mpl.figure.prototype.handle_save = function(fig, msg) { +mpl.figure.prototype.handle_save = function (fig, _msg) { fig.ondownload(fig, null); -} - +}; -mpl.find_output_cell = function(html_output) { +mpl.find_output_cell = function (html_output) { // Return the cell and output element which can be found *uniquely* in the notebook. // Note - this is a bit hacky, but it is done because the "notebook_saving.Notebook" // IPython event is triggered only after the cells have been serialised, which for // our purposes (turning an active figure into a static one), is too late. var cells = IPython.notebook.get_cells(); var ncells = cells.length; - for (var i=0; i= 3 moved mimebundle to data attribute of output data = data.data; } - if (data['text/html'] == html_output) { + if (data['text/html'] === html_output) { return [cell, data, j]; } } } } -} +}; // Register the function which deals with the matplotlib target/channel. // The kernel may be null if the page has been refreshed. -if (IPython.notebook.kernel != null) { - IPython.notebook.kernel.comm_manager.register_target('matplotlib', mpl.mpl_figure_comm); +if (IPython.notebook.kernel !== null) { + IPython.notebook.kernel.comm_manager.register_target( + 'matplotlib', + mpl.mpl_figure_comm + ); } diff --git a/lib/matplotlib/backends/web_backend/package.json b/lib/matplotlib/backends/web_backend/package.json new file mode 100644 index 000000000000..e2a4009a971b --- /dev/null +++ b/lib/matplotlib/backends/web_backend/package.json @@ -0,0 +1,15 @@ +{ + "devDependencies": { + "eslint": "^6.8.0", + "eslint-config-prettier": "^6.10.1", + "prettier": "^2.0.2" + }, + "scripts": { + "eslint": "eslint . --fix", + "eslint:check": "eslint .", + "lint": "npm run prettier && npm run eslint", + "lint:check": "npm run prettier:check && npm run eslint:check", + "prettier": "prettier --write \"**/*{.ts,.tsx,.js,.jsx,.css,.json}\"", + "prettier:check": "prettier --check \"**/*{.ts,.tsx,.js,.jsx,.css,.json}\"" + } +}