From 06bde5d7a524ba967926d9821eb4339ee8a34f61 Mon Sep 17 00:00:00 2001 From: Matt Haff Date: Fri, 25 May 2018 18:07:25 -0400 Subject: [PATCH 1/2] adding code changes from derekellis, and PR 4590 with latest code --- src/core/core.tooltip.js | 43 ++++++--- test/specs/core.tooltip.tests.js | 148 +++++++++++++++++++++++++++++++ 2 files changed, 179 insertions(+), 12 deletions(-) diff --git a/src/core/core.tooltip.js b/src/core/core.tooltip.js index 3f9490f8546..0fe67c2973f 100644 --- a/src/core/core.tooltip.js +++ b/src/core/core.tooltip.js @@ -190,6 +190,20 @@ function pushOrConcat(base, toPush) { return base; } +/** + * Returns array of strings split by newline + * @param {String} value - The value to split by newline. + * @returns {Array} value if newline present - Returned from String split() method + * @function + */ +function splitNewlines(str) { + if ((typeof str === 'string' || str instanceof String) && str.indexOf('\n') > -1) { + return str.split('\n'); + } + return str; +} + + // Private helper to create a tooltip item model // @param element : the chart element (point, arc, bar) to create the tooltip item for // @return : new tooltip item @@ -457,6 +471,13 @@ function getBackgroundPoint(vm, size, alignment, chart) { }; } +/** + * @Helper to build before and after body lines + */ +function getBeforeAfterBodyLines(callback) { + return pushOrConcat([], splitNewlines(callback)); +} + var exports = module.exports = Element.extend({ initialize: function() { this._model = getBaseModel(this._options); @@ -475,17 +496,16 @@ var exports = module.exports = Element.extend({ var afterTitle = callbacks.afterTitle.apply(me, arguments); var lines = []; - lines = pushOrConcat(lines, beforeTitle); - lines = pushOrConcat(lines, title); - lines = pushOrConcat(lines, afterTitle); + lines = pushOrConcat(lines, splitNewlines(beforeTitle)); + lines = pushOrConcat(lines, splitNewlines(title)); + lines = pushOrConcat(lines, splitNewlines(afterTitle)); return lines; }, // Args are: (tooltipItem, data) getBeforeBody: function() { - var lines = this._options.callbacks.beforeBody.apply(this, arguments); - return helpers.isArray(lines) ? lines : lines !== undefined ? [lines] : []; + return getBeforeAfterBodyLines(this._options.callbacks.beforeBody.apply(this, arguments)); }, // Args are: (tooltipItem, data) @@ -500,9 +520,9 @@ var exports = module.exports = Element.extend({ lines: [], after: [] }; - pushOrConcat(bodyItem.before, callbacks.beforeLabel.call(me, tooltipItem, data)); + pushOrConcat(bodyItem.before, splitNewlines(callbacks.beforeLabel.call(me, tooltipItem, data))); pushOrConcat(bodyItem.lines, callbacks.label.call(me, tooltipItem, data)); - pushOrConcat(bodyItem.after, callbacks.afterLabel.call(me, tooltipItem, data)); + pushOrConcat(bodyItem.after, splitNewlines(callbacks.afterLabel.call(me, tooltipItem, data))); bodyItems.push(bodyItem); }); @@ -512,8 +532,7 @@ var exports = module.exports = Element.extend({ // Args are: (tooltipItem, data) getAfterBody: function() { - var lines = this._options.callbacks.afterBody.apply(this, arguments); - return helpers.isArray(lines) ? lines : lines !== undefined ? [lines] : []; + return getBeforeAfterBodyLines(this._options.callbacks.afterBody.apply(this, arguments)); }, // Get the footer and beforeFooter and afterFooter lines @@ -527,9 +546,9 @@ var exports = module.exports = Element.extend({ var afterFooter = callbacks.afterFooter.apply(me, arguments); var lines = []; - lines = pushOrConcat(lines, beforeFooter); - lines = pushOrConcat(lines, footer); - lines = pushOrConcat(lines, afterFooter); + lines = pushOrConcat(lines, splitNewlines(beforeFooter)); + lines = pushOrConcat(lines, splitNewlines(footer)); + lines = pushOrConcat(lines, splitNewlines(afterFooter)); return lines; }, diff --git a/test/specs/core.tooltip.tests.js b/test/specs/core.tooltip.tests.js index 8878d9d9dbc..9d858a49e10 100755 --- a/test/specs/core.tooltip.tests.js +++ b/test/specs/core.tooltip.tests.js @@ -949,4 +949,152 @@ describe('Core.Tooltip', function() { } } }); + + it('Should split newlines into separate lines in user callbacks', function() { + var chart = window.acquireChart({ + type: 'line', + data: { + datasets: [{ + label: 'Dataset 1', + data: [10, 20, 30], + pointHoverBorderColor: 'rgb(255, 0, 0)', + pointHoverBackgroundColor: 'rgb(0, 255, 0)' + }, { + label: 'Dataset 2', + data: [40, 40, 40], + pointHoverBorderColor: 'rgb(0, 0, 255)', + pointHoverBackgroundColor: 'rgb(0, 255, 255)' + }], + labels: ['Point 1', 'Point 2', 'Point 3'] + }, + options: { + tooltips: { + mode: 'label', + callbacks: { + beforeTitle: function() { + return 'beforeTitle\nnewline'; + }, + title: function() { + return 'title\nnewline'; + }, + afterTitle: function() { + return 'afterTitle\nnewline'; + }, + beforeBody: function() { + return 'beforeBody\nnewline'; + }, + beforeLabel: function() { + return 'beforeLabel\nnewline'; + }, + label: function() { + return 'label'; + }, + afterLabel: function() { + return 'afterLabel\nnewline'; + }, + afterBody: function() { + return 'afterBody\nnewline'; + }, + beforeFooter: function() { + return 'beforeFooter\nnewline'; + }, + footer: function() { + return 'footer\nnewline'; + }, + afterFooter: function() { + return 'afterFooter\nnewline'; + }, + labelTextColor: function() { + return 'labelTextColor'; + } + } + } + } + }); + + // Trigger an event over top of the + var meta = chart.getDatasetMeta(0); + var point = meta.data[1]; + var node = chart.canvas; + var rect = node.getBoundingClientRect(); + var evt = new MouseEvent('mousemove', { + view: window, + bubbles: true, + cancelable: true, + clientX: rect.left + point._model.x, + clientY: rect.top + point._model.y + }); + + // Manually trigger rather than having an async test + node.dispatchEvent(evt); + + // Check and see if tooltip was displayed + var tooltip = chart.tooltip; + var globalDefaults = Chart.defaults.global; + + expect(tooltip._view).toEqual(jasmine.objectContaining({ + // Positioning + xPadding: 6, + yPadding: 6, + xAlign: 'center', + yAlign: 'top', + + // Body + bodyFontColor: '#fff', + _bodyFontFamily: globalDefaults.defaultFontFamily, + _bodyFontStyle: globalDefaults.defaultFontStyle, + _bodyAlign: 'left', + bodyFontSize: globalDefaults.defaultFontSize, + bodySpacing: 2, + + // Title + titleFontColor: '#fff', + _titleFontFamily: globalDefaults.defaultFontFamily, + _titleFontStyle: 'bold', + titleFontSize: globalDefaults.defaultFontSize, + _titleAlign: 'left', + titleSpacing: 2, + titleMarginBottom: 6, + + // Footer + footerFontColor: '#fff', + _footerFontFamily: globalDefaults.defaultFontFamily, + _footerFontStyle: 'bold', + footerFontSize: globalDefaults.defaultFontSize, + _footerAlign: 'left', + footerSpacing: 2, + footerMarginTop: 6, + + // Appearance + caretSize: 5, + cornerRadius: 6, + backgroundColor: 'rgba(0,0,0,0.8)', + opacity: 1, + legendColorBackground: '#fff', + + // Text + title: ['beforeTitle', 'newline', 'title', 'newline', 'afterTitle', 'newline'], + beforeBody: ['beforeBody', 'newline'], + body: [{ + before: ['beforeLabel', 'newline'], + lines: ['label'], + after: ['afterLabel', 'newline'] + }, { + before: ['beforeLabel', 'newline'], + lines: ['label'], + after: ['afterLabel', 'newline'] + }], + afterBody: ['afterBody', 'newline'], + footer: ['beforeFooter', 'newline', 'footer', 'newline', 'afterFooter', 'newline'], + caretPadding: 2, + labelTextColors: ['labelTextColor', 'labelTextColor'], + labelColors: [{ + borderColor: 'rgb(255, 0, 0)', + backgroundColor: 'rgb(0, 255, 0)' + }, { + borderColor: 'rgb(0, 0, 255)', + backgroundColor: 'rgb(0, 255, 255)' + }] + })); + }); }); From 6bd7dc2e4f9cf62534365e98e548572fa09e19c9 Mon Sep 17 00:00:00 2001 From: Matt Haff Date: Tue, 29 May 2018 10:30:04 -0400 Subject: [PATCH 2/2] remove @ from comments --- src/core/core.tooltip.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/core/core.tooltip.js b/src/core/core.tooltip.js index 0fe67c2973f..c529812cc61 100644 --- a/src/core/core.tooltip.js +++ b/src/core/core.tooltip.js @@ -418,7 +418,7 @@ function determineAlignment(tooltip, size) { } /** - * @Helper to get the location a tooltip needs to be placed at given the initial position (via the vm) and the size and alignment + * Helper to get the location a tooltip needs to be placed at given the initial position (via the vm) and the size and alignment */ function getBackgroundPoint(vm, size, alignment, chart) { // Background Position @@ -472,7 +472,7 @@ function getBackgroundPoint(vm, size, alignment, chart) { } /** - * @Helper to build before and after body lines + * Helper to build before and after body lines */ function getBeforeAfterBodyLines(callback) { return pushOrConcat([], splitNewlines(callback));