diff --git a/src/core/core.config.js b/src/core/core.config.js index 1523eb5c5c9..ef129b88f4d 100644 --- a/src/core/core.config.js +++ b/src/core/core.config.js @@ -371,12 +371,18 @@ function getResolver(resolverCache, scopes, prefixes) { return cached; } +const hasFunction = value => isObject(value) + && Object.keys(value).reduce((acc, key) => acc || isFunction(value[key]), false); + function needContext(proxy, names) { const {isScriptable, isIndexable} = _descriptors(proxy); for (const prop of names) { - if ((isScriptable(prop) && isFunction(proxy[prop])) - || (isIndexable(prop) && isArray(proxy[prop]))) { + const scriptable = isScriptable(prop); + const indexable = isIndexable(prop); + const value = (indexable || scriptable) && proxy[prop]; + if ((scriptable && (isFunction(value) || hasFunction(value))) + || (indexable && isArray(value))) { return true; } } diff --git a/src/core/core.controller.js b/src/core/core.controller.js index 19cfeca0cc2..3ba3b2fd748 100644 --- a/src/core/core.controller.js +++ b/src/core/core.controller.js @@ -7,7 +7,7 @@ import PluginService from './core.plugins'; import registry from './core.registry'; import Config, {determineAxis, getIndexAxis} from './core.config'; import {retinaScale, _isDomSupported} from '../helpers/helpers.dom'; -import {each, callback as callCallback, uid, valueOrDefault, _elementsEqual, isNullOrUndef, setsEqual, defined} from '../helpers/helpers.core'; +import {each, callback as callCallback, uid, valueOrDefault, _elementsEqual, isNullOrUndef, setsEqual, defined, isFunction} from '../helpers/helpers.core'; import {clearCanvas, clipArea, unclipArea, _isPointInArea} from '../helpers/helpers.canvas'; // @ts-ignore import {version} from '../../package.json'; @@ -536,14 +536,12 @@ class Chart { * @private */ _updateDatasets(mode) { - const isFunction = typeof mode === 'function'; - if (this.notifyPlugins('beforeDatasetsUpdate', {mode, cancelable: true}) === false) { return; } for (let i = 0, ilen = this.data.datasets.length; i < ilen; ++i) { - this._updateDataset(i, isFunction ? mode({datasetIndex: i}) : mode); + this._updateDataset(i, isFunction(mode) ? mode({datasetIndex: i}) : mode); } this.notifyPlugins('afterDatasetsUpdate', {mode}); diff --git a/test/specs/core.datasetController.tests.js b/test/specs/core.datasetController.tests.js index 3f08d209e26..3ec7a661260 100644 --- a/test/specs/core.datasetController.tests.js +++ b/test/specs/core.datasetController.tests.js @@ -897,6 +897,28 @@ describe('Chart.DatasetController', function() { expect(opts0.$shared).not.toBeTrue(); expect(Object.isFrozen(opts0)).toBeFalse(); }); + + it('should support nested scriptable options', function() { + const chart = acquireChart({ + type: 'line', + data: { + datasets: [{ + data: [100, 120, 130], + fill: { + value: (ctx) => ctx.type === 'dataset' ? 75 : 0 + } + }] + }, + }); + + const controller = chart.getDatasetMeta(0).controller; + const opts = controller.resolveDatasetElementOptions(); + expect(opts).toEqualOptions({ + fill: { + value: 75 + } + }); + }); }); describe('_resolveAnimations', function() {