]> git.ipfire.org Git - thirdparty/Chart.js.git/commitdiff
Unify signature of plugin hooks (#8102)
authorJukka Kurkela <jukka.kurkela@gmail.com>
Sat, 28 Nov 2020 07:45:43 +0000 (09:45 +0200)
committerGitHub <noreply@github.com>
Sat, 28 Nov 2020 07:45:43 +0000 (09:45 +0200)
docs/docs/getting-started/v3-migration.md
src/core/core.controller.js
src/core/core.plugins.js
src/plugins/plugin.legend.js
src/plugins/plugin.tooltip.js
test/specs/core.plugin.tests.js
test/specs/platform.dom.tests.js
types/core/index.d.ts

index 922e70efc1a2da7d39a76fb5848dc9d61fd8af1d..aaace7c4550e971bbe3e2388d96d8d50247fea17 100644 (file)
@@ -494,6 +494,7 @@ All helpers are now exposed in a flat hierarchy, e.g., `Chart.helpers.canvas.cli
 
 #### IPlugin interface
 
+* All plugin hooks have unified signature with 3 arguments: `chart`, `args` and `options`. This means change in signature for these hooks: `beforeInit`, `afterInit`, `reset`, `beforeLayout`, `afterLayout`, `beforeRender`, `afterRender`, `beforeDraw`, `afterDraw`, `beforeDatasetsDraw`, `afterDatasetsDraw`, `beforeEvent`, `afterEvent`, `resize`, `destroy`.
 * `afterDatasetsUpdate`, `afterUpdate`, `beforeDatasetsUpdate`, and `beforeUpdate` now receive `args` object as second argument. `options` argument is always the last and thus was moved from 2nd to 3rd place.
-* `afterEvent` and `beforeEvent` now receive a wrapped `event` as the second argument. The native event is available via `event.native`.
+* `afterEvent` and `beforeEvent` now receive a wrapped `event` as the `event` property of the second argument. The native event is available via `args.event.native`.
 * Initial `resize` is no longer silent. Meaning that `resize` event can fire between `beforeInit` and `afterInit`
index 3a1202067e6115633d18073f2a2db442689827ea..7d2c564f919afc00ebe8e2736ac75b2ec058a016 100644 (file)
@@ -33,7 +33,7 @@ function onAnimationsComplete(context) {
        const chart = context.chart;
        const animationOptions = chart.options.animation;
 
-       chart._plugins.notify(chart, 'afterRender');
+       chart.notifyPlugins('afterRender');
        callCallback(animationOptions && animationOptions.onComplete, [context], chart);
 }
 
@@ -151,7 +151,7 @@ class Chart {
                const me = this;
 
                // Before init plugin notification
-               me._plugins.notify(me, 'beforeInit');
+               me.notifyPlugins('beforeInit');
 
                if (me.options.responsive) {
                        me.resize();
@@ -162,7 +162,7 @@ class Chart {
                me.bindEvents();
 
                // After init plugin notification
-               me._plugins.notify(me, 'afterInit');
+               me.notifyPlugins('afterInit');
 
                return me;
        }
@@ -221,7 +221,7 @@ class Chart {
 
                retinaScale(me, newRatio);
 
-               me._plugins.notify(me, 'resize', [newSize]);
+               me.notifyPlugins('resize', {size: newSize});
 
                callCallback(options.onResize, [newSize], me);
 
@@ -435,7 +435,7 @@ class Chart {
        */
        reset() {
                this._resetElements();
-               this._plugins.notify(this, 'reset');
+               this.notifyPlugins('reset');
        }
 
        update(mode) {
@@ -458,7 +458,7 @@ class Chart {
                // https://github.com/chartjs/Chart.js/issues/5111#issuecomment-355934167
                me._plugins.invalidate();
 
-               if (me._plugins.notify(me, 'beforeUpdate', [args]) === false) {
+               if (me.notifyPlugins('beforeUpdate', args) === false) {
                        return;
                }
 
@@ -480,7 +480,7 @@ class Chart {
                me._updateDatasets(mode);
 
                // Do this before render so that any plugins that need final scale updates can use it
-               me._plugins.notify(me, 'afterUpdate', [args]);
+               me.notifyPlugins('afterUpdate', args);
 
                me._layers.sort(compare2Level('z', '_idx'));
 
@@ -500,7 +500,7 @@ class Chart {
        _updateLayout() {
                const me = this;
 
-               if (me._plugins.notify(me, 'beforeLayout') === false) {
+               if (me.notifyPlugins('beforeLayout') === false) {
                        return;
                }
 
@@ -520,7 +520,7 @@ class Chart {
                        item._idx = index;
                });
 
-               me._plugins.notify(me, 'afterLayout');
+               me.notifyPlugins('afterLayout');
        }
 
        /**
@@ -533,7 +533,7 @@ class Chart {
                const isFunction = typeof mode === 'function';
                const args = {mode};
 
-               if (me._plugins.notify(me, 'beforeDatasetsUpdate', [args]) === false) {
+               if (me.notifyPlugins('beforeDatasetsUpdate', args) === false) {
                        return;
                }
 
@@ -541,7 +541,7 @@ class Chart {
                        me._updateDataset(i, isFunction ? mode({datasetIndex: i}) : mode);
                }
 
-               me._plugins.notify(me, 'afterDatasetsUpdate', [args]);
+               me.notifyPlugins('afterDatasetsUpdate', args);
        }
 
        /**
@@ -554,18 +554,18 @@ class Chart {
                const meta = me.getDatasetMeta(index);
                const args = {meta, index, mode};
 
-               if (me._plugins.notify(me, 'beforeDatasetUpdate', [args]) === false) {
+               if (me.notifyPlugins('beforeDatasetUpdate', args) === false) {
                        return;
                }
 
                meta.controller._update(mode);
 
-               me._plugins.notify(me, 'afterDatasetUpdate', [args]);
+               me.notifyPlugins('afterDatasetUpdate', args);
        }
 
        render() {
                const me = this;
-               if (me._plugins.notify(me, 'beforeRender') === false) {
+               if (me.notifyPlugins('beforeRender') === false) {
                        return;
                }
 
@@ -593,7 +593,7 @@ class Chart {
                        return;
                }
 
-               if (me._plugins.notify(me, 'beforeDraw') === false) {
+               if (me.notifyPlugins('beforeDraw') === false) {
                        return;
                }
 
@@ -612,7 +612,7 @@ class Chart {
                        layers[i].draw(me.chartArea);
                }
 
-               me._plugins.notify(me, 'afterDraw');
+               me.notifyPlugins('afterDraw');
        }
 
        /**
@@ -650,7 +650,7 @@ class Chart {
        _drawDatasets() {
                const me = this;
 
-               if (me._plugins.notify(me, 'beforeDatasetsDraw') === false) {
+               if (me.notifyPlugins('beforeDatasetsDraw') === false) {
                        return;
                }
 
@@ -659,7 +659,7 @@ class Chart {
                        me._drawDataset(metasets[i]);
                }
 
-               me._plugins.notify(me, 'afterDatasetsDraw');
+               me.notifyPlugins('afterDatasetsDraw');
        }
 
        /**
@@ -677,7 +677,7 @@ class Chart {
                        index: meta.index,
                };
 
-               if (me._plugins.notify(me, 'beforeDatasetDraw', [args]) === false) {
+               if (me.notifyPlugins('beforeDatasetDraw', args) === false) {
                        return;
                }
 
@@ -692,7 +692,7 @@ class Chart {
 
                unclipArea(ctx);
 
-               me._plugins.notify(me, 'afterDatasetDraw', [args]);
+               me.notifyPlugins('afterDatasetDraw', args);
        }
 
        getElementsAtEventForMode(e, mode, options, useFinalPosition) {
@@ -829,7 +829,7 @@ class Chart {
                        me.ctx = null;
                }
 
-               me._plugins.notify(me, 'destroy');
+               me.notifyPlugins('destroy');
 
                delete Chart.instances[me.id];
        }
@@ -968,6 +968,18 @@ class Chart {
                }
        }
 
+       /**
+        * Calls enabled plugins on the specified hook and with the given args.
+        * This method immediately returns as soon as a plugin explicitly returns false. The
+        * returned value can be used, for instance, to interrupt the current action.
+        * @param {string} hook - The name of the plugin method to call (e.g. 'beforeUpdate').
+        * @param {Object} [args] - Extra arguments to apply to the hook call.
+        * @returns {boolean} false if any of the plugins return false, else returns true.
+        */
+       notifyPlugins(hook, args) {
+               return this._plugins.notify(this, hook, args);
+       }
+
        /**
         * @private
         */
@@ -992,14 +1004,15 @@ class Chart {
         */
        _eventHandler(e, replay) {
                const me = this;
+               const args = {event: e, replay};
 
-               if (me._plugins.notify(me, 'beforeEvent', [e, replay]) === false) {
+               if (me.notifyPlugins('beforeEvent', args) === false) {
                        return;
                }
 
                const changed = me._handleEvent(e, replay);
 
-               me._plugins.notify(me, 'afterEvent', [e, replay]);
+               me.notifyPlugins('afterEvent', args);
 
                if (changed) {
                        me.render();
index b7839d35604ac0bd2713d73fe4ea4b1611206974..5950d342f2aaf9ea56124d8d5536eca8c92f4123 100644 (file)
@@ -15,10 +15,11 @@ export default class PluginService {
         * returned value can be used, for instance, to interrupt the current action.
         * @param {Chart} chart - The chart instance for which plugins should be called.
         * @param {string} hook - The name of the plugin method to call (e.g. 'beforeUpdate').
-        * @param {Array} [args] - Extra arguments to apply to the hook call.
+        * @param {object} [args] - Extra arguments to apply to the hook call.
         * @returns {boolean} false if any of the plugins return false, else returns true.
         */
        notify(chart, hook, args) {
+               args = args || {};
                const descriptors = this._descriptors(chart);
 
                for (let i = 0; i < descriptors.length; ++i) {
@@ -26,8 +27,7 @@ export default class PluginService {
                        const plugin = descriptor.plugin;
                        const method = plugin[hook];
                        if (typeof method === 'function') {
-                               const params = [chart].concat(args || []);
-                               params.push(descriptor.options);
+                               const params = [chart, args, descriptor.options];
                                if (method.apply(plugin, params) === false) {
                                        return false;
                                }
@@ -117,12 +117,14 @@ function createDescriptors(plugins, options) {
  * @method IPlugin#beforeInit
  * @desc Called before initializing `chart`.
  * @param {Chart} chart - The chart instance.
+ * @param {object} args - The call arguments.
  * @param {object} options - The plugin options.
  */
 /**
  * @method IPlugin#afterInit
  * @desc Called after `chart` has been initialized and before the first update.
  * @param {Chart} chart - The chart instance.
+ * @param {object} args - The call arguments.
  * @param {object} options - The plugin options.
  */
 /**
@@ -148,6 +150,7 @@ function createDescriptors(plugins, options) {
  * @method IPlugin#reset
  * @desc Called during chart reset
  * @param {Chart} chart - The chart instance.
+ * @param {object} args - The call arguments.
  * @param {object} options - The plugin options.
  * @since version 3.0.0
  */
@@ -200,6 +203,7 @@ function createDescriptors(plugins, options) {
  * @desc Called before laying out `chart`. If any plugin returns `false`,
  * the layout update is cancelled until another `update` is triggered.
  * @param {Chart} chart - The chart instance.
+ * @param {object} args - The call arguments.
  * @param {object} options - The plugin options.
  * @returns {boolean} `false` to cancel the chart layout.
  */
@@ -208,6 +212,7 @@ function createDescriptors(plugins, options) {
  * @desc Called after the `chart` has been laid out. Note that this hook will not
  * be called if the layout update has been previously cancelled.
  * @param {Chart} chart - The chart instance.
+ * @param {object} args - The call arguments.
  * @param {object} options - The plugin options.
  */
 /**
@@ -215,6 +220,7 @@ function createDescriptors(plugins, options) {
  * @desc Called before rendering `chart`. If any plugin returns `false`,
  * the rendering is cancelled until another `render` is triggered.
  * @param {Chart} chart - The chart instance.
+ * @param {object} args - The call arguments.
  * @param {object} options - The plugin options.
  * @returns {boolean} `false` to cancel the chart rendering.
  */
@@ -223,6 +229,7 @@ function createDescriptors(plugins, options) {
  * @desc Called after the `chart` has been fully rendered (and animation completed). Note
  * that this hook will not be called if the rendering has been previously cancelled.
  * @param {Chart} chart - The chart instance.
+ * @param {object} args - The call arguments.
  * @param {object} options - The plugin options.
  */
 /**
@@ -230,6 +237,7 @@ function createDescriptors(plugins, options) {
  * @desc Called before drawing `chart` at every animation frame. If any plugin returns `false`,
  * the frame drawing is cancelled until another `render` is triggered.
  * @param {Chart} chart - The chart instance.
+ * @param {object} args - The call arguments.
  * @param {object} options - The plugin options.
  * @returns {boolean} `false` to cancel the chart drawing.
  */
@@ -238,6 +246,7 @@ function createDescriptors(plugins, options) {
  * @desc Called after the `chart` has been drawn. Note that this hook will not be called
  * if the drawing has been previously cancelled.
  * @param {Chart} chart - The chart instance.
+ * @param {object} args - The call arguments.
  * @param {object} options - The plugin options.
  */
 /**
@@ -245,6 +254,7 @@ function createDescriptors(plugins, options) {
  * @desc Called before drawing the `chart` datasets. If any plugin returns `false`,
  * the datasets drawing is cancelled until another `render` is triggered.
  * @param {Chart} chart - The chart instance.
+ * @param {object} args - The call arguments.
  * @param {object} options - The plugin options.
  * @returns {boolean} `false` to cancel the chart datasets drawing.
  */
@@ -253,6 +263,7 @@ function createDescriptors(plugins, options) {
  * @desc Called after the `chart` datasets have been drawn. Note that this hook
  * will not be called if the datasets drawing has been previously cancelled.
  * @param {Chart} chart - The chart instance.
+ * @param {object} args - The call arguments.
  * @param {object} options - The plugin options.
  */
 /**
@@ -302,8 +313,9 @@ function createDescriptors(plugins, options) {
  * @desc Called before processing the specified `event`. If any plugin returns `false`,
  * the event will be discarded.
  * @param {Chart} chart - The chart instance.
- * @param {ChartEvent} event - The event object.
- * @param {boolean} replay - True if this event is replayed from `Chart.update`
+ * @param {object} args - The call arguments.
+ * @param {ChartEvent} args.event - The event object.
+ * @param {boolean} args.replay - True if this event is replayed from `Chart.update`
  * @param {object} options - The plugin options.
  */
 /**
@@ -311,20 +323,23 @@ function createDescriptors(plugins, options) {
  * @desc Called after the `event` has been consumed. Note that this hook
  * will not be called if the `event` has been previously discarded.
  * @param {Chart} chart - The chart instance.
- * @param {ChartEvent} event - The event object.
- * @param {boolean} replay - True if this event is replayed from `Chart.update`
+ * @param {object} args - The call arguments.
+ * @param {ChartEvent} args.event - The event object.
+ * @param {boolean} args.replay - True if this event is replayed from `Chart.update`
  * @param {object} options - The plugin options.
  */
 /**
  * @method IPlugin#resize
  * @desc Called after the chart as been resized.
  * @param {Chart} chart - The chart instance.
- * @param {number} size - The new canvas display size (eq. canvas.style width & height).
+ * @param {object} args - The call arguments.
+ * @param {number} args.size - The new canvas display size (eq. canvas.style width & height).
  * @param {object} options - The plugin options.
  */
 /**
  * @method IPlugin#destroy
  * @desc Called after the chart as been destroyed.
  * @param {Chart} chart - The chart instance.
+ * @param {object} args - The call arguments.
  * @param {object} options - The plugin options.
  */
index d4f1515711c2fa8656e0c31a55a6523352f8c54d..133df9da3e8eb34d5a71e7527f1c47a25e8b9144 100644 (file)
@@ -690,10 +690,10 @@ export default {
        },
 
 
-       afterEvent(chart, e) {
+       afterEvent(chart, args) {
                const legend = chart.legend;
                if (legend) {
-                       legend.handleEvent(e);
+                       legend.handleEvent(args.event);
                }
        },
 
index d4a73738484d8e5cd67b812a2cdc7c195d35bb00..15f40fb52601b75941fec33bff85dc8a9565d26a 100644 (file)
@@ -1074,7 +1074,7 @@ export default {
                        tooltip
                };
 
-               if (chart._plugins.notify(chart, 'beforeTooltipDraw', [args]) === false) {
+               if (chart.notifyPlugins('beforeTooltipDraw', args) === false) {
                        return;
                }
 
@@ -1082,14 +1082,14 @@ export default {
                        tooltip.draw(chart.ctx);
                }
 
-               chart._plugins.notify(chart, 'afterTooltipDraw', [args]);
+               chart.notifyPlugins('afterTooltipDraw', args);
        },
 
-       afterEvent(chart, e, replay) {
+       afterEvent(chart, args) {
                if (chart.tooltip) {
                        // If the event is replayed from `update`, we should evaluate with the final positions.
-                       const useFinalPosition = replay;
-                       chart.tooltip.handleEvent(e, useFinalPosition);
+                       const useFinalPosition = args.replay;
+                       chart.tooltip.handleEvent(args.event, useFinalPosition);
                }
        },
 
index a84ed9bef89027012d78cb15ba5837facf0f3fb8..988d061e6b9b0464af34f9fdbbb2fb43d5995f01 100644 (file)
@@ -1,31 +1,33 @@
 describe('Chart.plugins', function() {
-       describe('Chart.plugins.notify', function() {
+       describe('Chart.notifyPlugins', function() {
                it('should call inline plugins with arguments', function() {
                        var plugin = {hook: function() {}};
                        var chart = window.acquireChart({
                                plugins: [plugin]
                        });
+                       var args = {value: 42};
 
                        spyOn(plugin, 'hook');
 
-                       chart._plugins.notify(chart, 'hook', 42);
+                       chart.notifyPlugins('hook', args);
                        expect(plugin.hook.calls.count()).toBe(1);
                        expect(plugin.hook.calls.first().args[0]).toBe(chart);
-                       expect(plugin.hook.calls.first().args[1]).toBe(42);
+                       expect(plugin.hook.calls.first().args[1]).toBe(args);
                        expect(plugin.hook.calls.first().args[2]).toEqual({});
                });
 
                it('should call global plugins with arguments', function() {
                        var plugin = {id: 'a', hook: function() {}};
                        var chart = window.acquireChart({});
+                       var args = {value: 42};
 
                        spyOn(plugin, 'hook');
 
                        Chart.register(plugin);
-                       chart._plugins.notify(chart, 'hook', 42);
+                       chart.notifyPlugins('hook', args);
                        expect(plugin.hook.calls.count()).toBe(1);
                        expect(plugin.hook.calls.first().args[0]).toBe(chart);
-                       expect(plugin.hook.calls.first().args[1]).toBe(42);
+                       expect(plugin.hook.calls.first().args[1]).toBe(args);
                        expect(plugin.hook.calls.first().args[2]).toEqual({});
                        Chart.unregister(plugin);
                });
@@ -39,7 +41,7 @@ describe('Chart.plugins', function() {
                        spyOn(plugin, 'hook');
 
                        Chart.register([plugin, plugin]);
-                       chart._plugins.notify(chart, 'hook');
+                       chart.notifyPlugins('hook');
                        expect(plugin.hook.calls.count()).toBe(1);
                        Chart.unregister(plugin);
                });
@@ -80,7 +82,7 @@ describe('Chart.plugins', function() {
                        }];
                        Chart.register(plugins);
 
-                       var ret = chart._plugins.notify(chart, 'hook');
+                       var ret = chart.notifyPlugins('hook');
                        expect(ret).toBeTruthy();
                        expect(results).toEqual([4, 5, 6, 1, 2, 3]);
                        Chart.unregister(plugins);
@@ -114,7 +116,7 @@ describe('Chart.plugins', function() {
                                spyOn(plugin, 'hook').and.callThrough();
                        });
 
-                       var ret = chart._plugins.notify(chart, 'hook');
+                       var ret = chart.notifyPlugins('hook');
                        expect(ret).toBeTruthy();
                        plugins.forEach(function(plugin) {
                                expect(plugin.hook).toHaveBeenCalled();
@@ -149,7 +151,7 @@ describe('Chart.plugins', function() {
                                spyOn(plugin, 'hook').and.callThrough();
                        });
 
-                       var ret = chart._plugins.notify(chart, 'hook');
+                       var ret = chart.notifyPlugins('hook');
                        expect(ret).toBeFalsy();
                        expect(plugins[0].hook).toHaveBeenCalled();
                        expect(plugins[1].hook).toHaveBeenCalled();
@@ -174,14 +176,14 @@ describe('Chart.plugins', function() {
                        spyOn(plugin, 'hook');
 
                        Chart.register(plugin);
-                       chart._plugins.notify(chart, 'hook');
-                       chart._plugins.notify(chart, 'hook', ['bla']);
-                       chart._plugins.notify(chart, 'hook', ['bla', 42]);
+                       chart.notifyPlugins('hook');
+                       chart.notifyPlugins('hook', {arg1: 'bla'});
+                       chart.notifyPlugins('hook', {arg1: 'bla', arg2: 42});
 
                        expect(plugin.hook.calls.count()).toBe(3);
-                       expect(plugin.hook.calls.argsFor(0)[1]).toEqual({a: '123'});
+                       expect(plugin.hook.calls.argsFor(0)[2]).toEqual({a: '123'});
                        expect(plugin.hook.calls.argsFor(1)[2]).toEqual({a: '123'});
-                       expect(plugin.hook.calls.argsFor(2)[3]).toEqual({a: '123'});
+                       expect(plugin.hook.calls.argsFor(2)[2]).toEqual({a: '123'});
 
                        Chart.unregister(plugin);
                });
@@ -210,14 +212,14 @@ describe('Chart.plugins', function() {
                        spyOn(plugins.b, 'hook');
                        spyOn(plugins.c, 'hook');
 
-                       chart._plugins.notify(chart, 'hook');
+                       chart.notifyPlugins('hook');
 
                        expect(plugins.a.hook).toHaveBeenCalled();
                        expect(plugins.b.hook).toHaveBeenCalled();
                        expect(plugins.c.hook).toHaveBeenCalled();
-                       expect(plugins.a.hook.calls.first().args[1]).toEqual({a: '123'});
-                       expect(plugins.b.hook.calls.first().args[1]).toEqual({b: '456'});
-                       expect(plugins.c.hook.calls.first().args[1]).toEqual({c: '789'});
+                       expect(plugins.a.hook.calls.first().args[2]).toEqual({a: '123'});
+                       expect(plugins.b.hook.calls.first().args[2]).toEqual({b: '456'});
+                       expect(plugins.c.hook.calls.first().args[2]).toEqual({c: '789'});
 
                        Chart.unregister(plugins.a);
                });
@@ -245,7 +247,7 @@ describe('Chart.plugins', function() {
                        spyOn(plugins.b, 'hook');
                        spyOn(plugins.c, 'hook');
 
-                       chart._plugins.notify(chart, 'hook');
+                       chart.notifyPlugins('hook');
 
                        expect(plugins.a.hook).not.toHaveBeenCalled();
                        expect(plugins.b.hook).not.toHaveBeenCalled();
@@ -269,10 +271,10 @@ describe('Chart.plugins', function() {
 
                        spyOn(plugin, 'hook');
 
-                       chart._plugins.notify(chart, 'hook');
+                       chart.notifyPlugins('hook');
 
                        expect(plugin.hook).toHaveBeenCalled();
-                       expect(plugin.hook.calls.first().args[1]).toEqual({a: 42});
+                       expect(plugin.hook.calls.first().args[2]).toEqual({a: 42});
 
                        Chart.unregister(plugin);
                });
@@ -286,10 +288,10 @@ describe('Chart.plugins', function() {
 
                        var chart = window.acquireChart();
 
-                       chart._plugins.notify(chart, 'hook');
+                       chart.notifyPlugins('hook');
 
                        expect(plugin.hook).toHaveBeenCalled();
-                       expect(plugin.hook.calls.first().args[1]).toEqual({a: 'foobar'});
+                       expect(plugin.hook.calls.first().args[2]).toEqual({a: 'foobar'});
 
                        Chart.unregister(plugin);
                });
@@ -310,19 +312,19 @@ describe('Chart.plugins', function() {
 
                        spyOn(plugin, 'hook');
 
-                       chart._plugins.notify(chart, 'hook');
+                       chart.notifyPlugins('hook');
 
                        expect(plugin.hook).toHaveBeenCalled();
-                       expect(plugin.hook.calls.first().args[1]).toEqual({foo: 'foo'});
+                       expect(plugin.hook.calls.first().args[2]).toEqual({foo: 'foo'});
 
                        chart.options.plugins.a = {bar: 'bar'};
                        chart.update();
 
                        plugin.hook.calls.reset();
-                       chart._plugins.notify(chart, 'hook');
+                       chart.notifyPlugins('hook');
 
                        expect(plugin.hook).toHaveBeenCalled();
-                       expect(plugin.hook.calls.first().args[1]).toEqual({bar: 'bar'});
+                       expect(plugin.hook.calls.first().args[2]).toEqual({bar: 'bar'});
                });
 
                it('should disable all plugins', function() {
@@ -336,7 +338,7 @@ describe('Chart.plugins', function() {
 
                        spyOn(plugin, 'hook');
 
-                       chart._plugins.notify(chart, 'hook');
+                       chart.notifyPlugins('hook');
 
                        expect(plugin.hook).not.toHaveBeenCalled();
                });
index a9218c8953e0b2b786ef979efcffca3858ce33b5..e32100249c0a3b07ebbbcf8a5953ebf0ec69290b 100644 (file)
@@ -369,8 +369,8 @@ describe('Platform.dom', function() {
                it('should notify plugins about events', function(done) {
                        var notifiedEvent;
                        var plugin = {
-                               afterEvent: function(chart, e) {
-                                       notifiedEvent = e;
+                               afterEvent: function(chart, args) {
+                                       notifiedEvent = args.event;
                                }
                        };
                        var chart = acquireChart({
index c61c302b1db37886f9fb822833dc68ac665c91d3..d31dbe853321e471c730166fef6847b4a33049ec 100644 (file)
@@ -227,6 +227,8 @@ export declare class Chart<
        unbindEvents(): void;
        updateHoverStyle(items: Element, mode: 'dataset', enabled: boolean): void;
 
+       notifyPlugins(hook: string, args?: AnyObject): boolean | void;
+
        static readonly version: string;
        static readonly instances: { [key: string]: Chart };
        static readonly registry: Registry;
@@ -562,39 +564,29 @@ export const layouts: {
        update(chart: Chart, width: number, height: number): void;
 };
 
-export interface PluginService {
-       /**
-        * Calls enabled plugins for `chart` on the specified hook and with the given args.
-        * This method immediately returns as soon as a plugin explicitly returns false. The
-        * returned value can be used, for instance, to interrupt the current action.
-        * @param {Chart} chart - The chart instance for which plugins should be called.
-        * @param {string} hook - The name of the plugin method to call (e.g. 'beforeUpdate').
-        * @param {Array} [args] - Extra arguments to apply to the hook call.
-        * @returns {boolean} false if any of the plugins return false, else returns true.
-        */
-       notify(chart: Chart, hook: string, args: any[]): boolean;
-       invalidate(): void;
-}
-
 export interface Plugin<O = {}> {
        id: string;
 
        /**
         * @desc Called before initializing `chart`.
         * @param {Chart} chart - The chart instance.
+        * @param {object} args - The call arguments.
         * @param {object} options - The plugin options.
         */
-       beforeInit?(chart: Chart, options: O): void;
+       beforeInit?(chart: Chart, args: {}, options: O): boolean | void;
        /**
         * @desc Called after `chart` has been initialized and before the first update.
         * @param {Chart} chart - The chart instance.
+        * @param {object} args - The call arguments.
         * @param {object} options - The plugin options.
         */
-       afterInit?(chart: Chart, options: O): void;
+       afterInit?(chart: Chart, args: {}, options: O): boolean | void;
        /**
         * @desc Called before updating `chart`. If any plugin returns `false`, the update
         * is cancelled (and thus subsequent render(s)) until another `update` is triggered.
         * @param {Chart} chart - The chart instance.
+        * @param {object} args - The call arguments.
+        * @param {UpdateMode} args.mode - The update mode
         * @param {object} options - The plugin options.
         * @returns {boolean} `false` to cancel the chart update.
         */
@@ -603,16 +595,19 @@ export interface Plugin<O = {}> {
         * @desc Called after `chart` has been updated and before rendering. Note that this
         * hook will not be called if the chart update has been previously cancelled.
         * @param {Chart} chart - The chart instance.
+        * @param {object} args - The call arguments.
+        * @param {UpdateMode} args.mode - The update mode
         * @param {object} options - The plugin options.
         */
-       afterUpdate?(chart: Chart, args: { mode: UpdateMode }, options: O): void;
+       afterUpdate?(chart: Chart, args: { mode: UpdateMode }, options: O): boolean | void;
        /**
         * @desc Called during chart reset
         * @param {Chart} chart - The chart instance.
+        * @param {object} args - The call arguments.
         * @param {object} options - The plugin options.
         * @since version 3.0.0
         */
-       reset?(chart: Chart, options: O): void;
+       reset?(chart: Chart, args: {}, options: O): void;
        /**
         * @desc Called before updating the `chart` datasets. If any plugin returns `false`,
         * the datasets update is cancelled until another `update` is triggered.
@@ -633,7 +628,7 @@ export interface Plugin<O = {}> {
         * @param {object} options - The plugin options.
         * @since version 2.1.5
         */
-       afterDatasetsUpdate?(chart: Chart, args: { mode: UpdateMode }, options: O): void;
+       afterDatasetsUpdate?(chart: Chart, args: { mode: UpdateMode }, options: O): boolean | void;
        /**
         * @desc Called before updating the `chart` dataset at the given `args.index`. If any plugin
         * returns `false`, the datasets update is cancelled until another `update` is triggered.
@@ -656,67 +651,75 @@ export interface Plugin<O = {}> {
         * @param {UpdateMode} args.mode - The update mode.
         * @param {object} options - The plugin options.
         */
-       afterDatasetUpdate?(chart: Chart, args: { index: number; meta: ChartMeta, mode: UpdateMode }, options: O): void;
+       afterDatasetUpdate?(chart: Chart, args: { index: number; meta: ChartMeta, mode: UpdateMode }, options: O): boolean | void;
        /**
         * @desc Called before laying out `chart`. If any plugin returns `false`,
         * the layout update is cancelled until another `update` is triggered.
         * @param {Chart} chart - The chart instance.
+        * @param {object} args - The call arguments.
         * @param {object} options - The plugin options.
         * @returns {boolean} `false` to cancel the chart layout.
         */
-       beforeLayout?(chart: Chart, options: O): boolean | void;
+       beforeLayout?(chart: Chart, args: {}, options: O): boolean | void;
        /**
         * @desc Called after the `chart` has been laid out. Note that this hook will not
         * be called if the layout update has been previously cancelled.
         * @param {Chart} chart - The chart instance.
+        * @param {object} args - The call arguments.
         * @param {object} options - The plugin options.
         */
-       afterLayout?(chart: Chart, options: O): void;
+       afterLayout?(chart: Chart, args: {}, options: O): boolean | void;
        /**
         * @desc Called before rendering `chart`. If any plugin returns `false`,
         * the rendering is cancelled until another `render` is triggered.
         * @param {Chart} chart - The chart instance.
+        * @param {object} args - The call arguments.
         * @param {object} options - The plugin options.
         * @returns {boolean} `false` to cancel the chart rendering.
         */
-       beforeRender?(chart: Chart, options: O): boolean | void;
+       beforeRender?(chart: Chart, args: {}, options: O): boolean | void;
        /**
         * @desc Called after the `chart` has been fully rendered (and animation completed). Note
         * that this hook will not be called if the rendering has been previously cancelled.
         * @param {Chart} chart - The chart instance.
+        * @param {object} args - The call arguments.
         * @param {object} options - The plugin options.
         */
-       afterRender?(chart: Chart, options: O): void;
+       afterRender?(chart: Chart, args: {}, options: O): boolean | void;
        /**
         * @desc Called before drawing `chart` at every animation frame. If any plugin returns `false`,
         * the frame drawing is cancelled untilanother `render` is triggered.
         * @param {Chart} chart - The chart instance.
+        * @param {object} args - The call arguments.
         * @param {object} options - The plugin options.
         * @returns {boolean} `false` to cancel the chart drawing.
         */
-       beforeDraw?(chart: Chart, options: O): boolean | void;
+       beforeDraw?(chart: Chart, args: {}, options: O): boolean | void;
        /**
         * @desc Called after the `chart` has been drawn. Note that this hook will not be called
         * if the drawing has been previously cancelled.
         * @param {Chart} chart - The chart instance.
+        * @param {object} args - The call arguments.
         * @param {object} options - The plugin options.
         */
-       afterDraw?(chart: Chart, options: O): void;
+       afterDraw?(chart: Chart, args: {}, options: O): boolean | void;
        /**
         * @desc Called before drawing the `chart` datasets. If any plugin returns `false`,
         * the datasets drawing is cancelled until another `render` is triggered.
         * @param {Chart} chart - The chart instance.
+        * @param {object} args - The call arguments.
         * @param {object} options - The plugin options.
         * @returns {boolean} `false` to cancel the chart datasets drawing.
         */
-       beforeDatasetsDraw?(chart: Chart, options: O): boolean | void;
+       beforeDatasetsDraw?(chart: Chart, args: {}, options: O): boolean | void;
        /**
         * @desc Called after the `chart` datasets have been drawn. Note that this hook
         * will not be called if the datasets drawing has been previously cancelled.
         * @param {Chart} chart - The chart instance.
+        * @param {object} args - The call arguments.
         * @param {object} options - The plugin options.
         */
-       afterDatasetsDraw?(chart: Chart, options: O): void;
+       afterDatasetsDraw?(chart: Chart, args: {}, options: O): boolean | void;
        /**
         * @desc Called before drawing the `chart` dataset at the given `args.index` (datasets
         * are drawn in the reverse order). If any plugin returns `false`, the datasets drawing
@@ -739,38 +742,41 @@ export interface Plugin<O = {}> {
         * @param {object} args.meta - The dataset metadata.
         * @param {object} options - The plugin options.
         */
-       afterDatasetDraw?(chart: Chart, args: { index: number; meta: ChartMeta }, options: O): void;
+       afterDatasetDraw?(chart: Chart, args: { index: number; meta: ChartMeta }, options: O): boolean | void;
        /**
         * @desc Called before processing the specified `event`. If any plugin returns `false`,
         * the event will be discarded.
         * @param {Chart} chart - The chart instance.
-        * @param {ChartEvent} event - The event object.
-        * @param {object} options - The plugin options.
+        * @param {object} args - The call arguments.
+        * @param {ChartEvent} args.event - The event object.
         * @param {boolean} replay - True if this event is replayed from `Chart.update`
+        * @param {object} options - The plugin options.
         */
-       beforeEvent?(chart: Chart, event: ChartEvent, options: O, replay: boolean): void;
+       beforeEvent?(chart: Chart, args: { event: ChartEvent, replay: boolean }, options: O): boolean | void;
        /**
         * @desc Called after the `event` has been consumed. Note that this hook
         * will not be called if the `event` has been previously discarded.
         * @param {Chart} chart - The chart instance.
-        * @param {ChartEvent} event - The event object.
-        * @param {object} options - The plugin options.
+        * @param {object} args - The call arguments.
+        * @param {ChartEvent} args.event - The event object.
         * @param {boolean} replay - True if this event is replayed from `Chart.update`
+        * @param {object} options - The plugin options.
         */
-       afterEvent?(chart: Chart, event: ChartEvent, options: O, replay: boolean): void;
+       afterEvent?(chart: Chart, args: { event: ChartEvent, replay: boolean }, options: O): boolean | void;
        /**
         * @desc Called after the chart as been resized.
         * @param {Chart} chart - The chart instance.
-        * @param {number} size - The new canvas display size (eq. canvas.style width & height).
+        * @param {object} args - The call arguments.
+        * @param {number} args.size - The new canvas display size (eq. canvas.style width & height).
         * @param {object} options - The plugin options.
         */
-       resize?(chart: Chart, size: number, options: O): void;
+       resize?(chart: Chart, args: { size: { width: number, height: number } }, options: O): boolean | void;
        /**
         * Called after the chart as been destroyed.
         * @param {Chart} chart - The chart instance.
         * @param {object} options - The plugin options.
         */
-       destroy?(chart: Chart, options: O): void;
+       destroy?(chart: Chart, options: O): boolean | void;
 }
 
 export declare type ChartComponentLike = ChartComponent | ChartComponent[] | { [key: string]: ChartComponent };