+ In order to support a strict content security policy (default-src 'self'),
+ this page manually loads Chart.min.css and turns off the automatic style
+ injection by setting Chart.platform.disableCSSInjection = true;.
+
+
+
+
+
+
+
diff --git a/samples/advanced/content-security-policy.js b/samples/advanced/content-security-policy.js
new file mode 100644
index 00000000000..a185332f74b
--- /dev/null
+++ b/samples/advanced/content-security-policy.js
@@ -0,0 +1,54 @@
+var utils = Samples.utils;
+
+// CSP: disable automatic style injection
+Chart.platform.disableCSSInjection = true;
+
+utils.srand(110);
+
+function generateData() {
+ var DATA_COUNT = 16;
+ var MIN_XY = -150;
+ var MAX_XY = 100;
+ var data = [];
+ var i;
+
+ for (i = 0; i < DATA_COUNT; ++i) {
+ data.push({
+ x: utils.rand(MIN_XY, MAX_XY),
+ y: utils.rand(MIN_XY, MAX_XY),
+ v: utils.rand(0, 1000)
+ });
+ }
+
+ return data;
+}
+
+window.addEventListener('load', function() {
+ new Chart('chart-0', {
+ type: 'bubble',
+ data: {
+ datasets: [{
+ backgroundColor: utils.color(0),
+ data: generateData()
+ }, {
+ backgroundColor: utils.color(1),
+ data: generateData()
+ }]
+ },
+ options: {
+ aspectRatio: 1,
+ legend: false,
+ tooltip: false,
+ elements: {
+ point: {
+ radius: function(context) {
+ var value = context.dataset.data[context.dataIndex];
+ var size = context.chart.width;
+ var base = Math.abs(value.v) / 1000;
+ return (size / 24) * base;
+ }
+ }
+ }
+ }
+ });
+});
diff --git a/samples/samples.js b/samples/samples.js
index c6cc71c7af9..b6ffe762682 100644
--- a/samples/samples.js
+++ b/samples/samples.js
@@ -187,6 +187,9 @@
items: [{
title: 'Progress bar',
path: 'advanced/progress-bar.html'
+ }, {
+ title: 'Content Security Policy',
+ path: 'advanced/content-security-policy.html'
}]
}];
diff --git a/samples/style.css b/samples/style.css
index 8224e2c3fdb..db92f0c6016 100644
--- a/samples/style.css
+++ b/samples/style.css
@@ -1,4 +1,3 @@
-@import url('https://maxcdn.bootstrapcdn.com/font-awesome/4.7.0/css/font-awesome.min.css');
@import url('https://fonts.googleapis.com/css?family=Lato:100,300,400,700,900');
body, html {
diff --git a/scripts/deploy.sh b/scripts/deploy.sh
index b0edddc7f99..35ae4d4e473 100755
--- a/scripts/deploy.sh
+++ b/scripts/deploy.sh
@@ -41,7 +41,7 @@ cd $TARGET_DIR
git checkout $TARGET_BRANCH
# Copy dist files
-deploy_files '../dist/*.js' './dist'
+deploy_files '../dist/*.css ../dist/*.js' './dist'
# Copy generated documentation
deploy_files '../dist/docs/*' './docs'
diff --git a/scripts/release.sh b/scripts/release.sh
index 03c7c6462b6..71f588034f2 100755
--- a/scripts/release.sh
+++ b/scripts/release.sh
@@ -21,7 +21,7 @@ git remote add auth-origin https://$GITHUB_AUTH_TOKEN@github.com/$TRAVIS_REPO_SL
git config --global user.email "$GITHUB_AUTH_EMAIL"
git config --global user.name "Chart.js"
git checkout --detach --quiet
-git add -f dist/*.js bower.json
+git add -f dist/*.css dist/*.js bower.json
git commit -m "Release $VERSION"
git tag -a "v$VERSION" -m "Version $VERSION"
git push -q auth-origin refs/tags/v$VERSION 2>/dev/null
diff --git a/src/platforms/platform.dom.css b/src/platforms/platform.dom.css
new file mode 100644
index 00000000000..e0b99a4aad4
--- /dev/null
+++ b/src/platforms/platform.dom.css
@@ -0,0 +1,46 @@
+/*
+ * DOM element rendering detection
+ * https://davidwalsh.name/detect-node-insertion
+ */
+@keyframes chartjs-render-animation {
+ from { opacity: 0.99; }
+ to { opacity: 1; }
+}
+
+.chartjs-render-monitor {
+ animation: chartjs-render-animation 0.001s;
+}
+
+/*
+ * DOM element resizing detection
+ * https://github.com/marcj/css-element-queries
+ */
+.chartjs-size-monitor,
+.chartjs-size-monitor-expand,
+.chartjs-size-monitor-shrink {
+ position: absolute;
+ left: 0;
+ top: 0;
+ right: 0;
+ bottom: 0;
+ overflow: hidden;
+ pointer-events: none;
+ visibility: hidden;
+ z-index: -1;
+}
+
+.chartjs-size-monitor-expand > div {
+ position: absolute;
+ width: 1000000px;
+ height: 1000000px;
+ left: 0;
+ top: 0;
+}
+
+.chartjs-size-monitor-shrink > div {
+ position: absolute;
+ width: 200%;
+ height: 200%;
+ left: 0;
+ top: 0;
+}
diff --git a/src/platforms/platform.dom.js b/src/platforms/platform.dom.js
index 053db20d2e2..777833afe5e 100644
--- a/src/platforms/platform.dom.js
+++ b/src/platforms/platform.dom.js
@@ -5,9 +5,11 @@
'use strict';
var helpers = require('../helpers/index');
+var stylesheet = require('./platform.dom.css');
var EXPANDO_KEY = '$chartjs';
var CSS_PREFIX = 'chartjs-';
+var CSS_SIZE_MONITOR = CSS_PREFIX + 'size-monitor';
var CSS_RENDER_MONITOR = CSS_PREFIX + 'render-monitor';
var CSS_RENDER_ANIMATION = CSS_PREFIX + 'render-animation';
var ANIMATION_START_EVENTS = ['animationstart', 'webkitAnimationStart'];
@@ -166,48 +168,24 @@ function throttled(fn, thisArg) {
};
}
-function createDiv(cls, style) {
+function createDiv(cls) {
var el = document.createElement('div');
- el.style.cssText = style || '';
el.className = cls || '';
return el;
}
// Implementation based on https://github.com/marcj/css-element-queries
function createResizer(handler) {
- var cls = CSS_PREFIX + 'size-monitor';
var maxSize = 1000000;
- var style =
- 'position:absolute;' +
- 'left:0;' +
- 'top:0;' +
- 'right:0;' +
- 'bottom:0;' +
- 'overflow:hidden;' +
- 'pointer-events:none;' +
- 'visibility:hidden;' +
- 'z-index:-1;';
// NOTE(SB) Don't use innerHTML because it could be considered unsafe.
// https://github.com/chartjs/Chart.js/issues/5902
- var resizer = createDiv(cls, style);
- var expand = createDiv(cls + '-expand', style);
- var shrink = createDiv(cls + '-shrink', style);
-
- expand.appendChild(createDiv('',
- 'position:absolute;' +
- 'height:' + maxSize + 'px;' +
- 'width:' + maxSize + 'px;' +
- 'left:0;' +
- 'top:0;'
- ));
- shrink.appendChild(createDiv('',
- 'position:absolute;' +
- 'height:200%;' +
- 'width:200%;' +
- 'left:0;' +
- 'top:0;'
- ));
+ var resizer = createDiv(CSS_SIZE_MONITOR);
+ var expand = createDiv(CSS_SIZE_MONITOR + '-expand');
+ var shrink = createDiv(CSS_SIZE_MONITOR + '-shrink');
+
+ expand.appendChild(createDiv());
+ shrink.appendChild(createDiv());
resizer.appendChild(expand);
resizer.appendChild(shrink);
@@ -330,6 +308,15 @@ function injectCSS(platform, css) {
}
module.exports = {
+ /**
+ * When `true`, prevents the automatic injection of the stylesheet required to
+ * correctly detect when the chart is added to the DOM and then resized. This
+ * switch has been added to allow external stylesheet (`dist/Chart(.min)?.js`)
+ * to be manually imported to make this library compatible with any CSP.
+ * See https://github.com/chartjs/Chart.js/issues/5208
+ */
+ disableCSSInjection: false,
+
/**
* This property holds whether this platform is enabled for the current environment.
* Currently used by platform.js to select the proper implementation.
@@ -337,19 +324,20 @@ module.exports = {
*/
_enabled: typeof window !== 'undefined' && typeof document !== 'undefined',
- initialize: function() {
- var keyframes = 'from{opacity:0.99}to{opacity:1}';
-
- injectCSS(this,
- // DOM rendering detection
- // https://davidwalsh.name/detect-node-insertion
- '@-webkit-keyframes ' + CSS_RENDER_ANIMATION + '{' + keyframes + '}' +
- '@keyframes ' + CSS_RENDER_ANIMATION + '{' + keyframes + '}' +
- '.' + CSS_RENDER_MONITOR + '{' +
- '-webkit-animation:' + CSS_RENDER_ANIMATION + ' 0.001s;' +
- 'animation:' + CSS_RENDER_ANIMATION + ' 0.001s;' +
- '}'
- );
+ /**
+ * @private
+ */
+ _ensureLoaded: function() {
+ if (this._loaded) {
+ return;
+ }
+
+ this._loaded = true;
+
+ // https://github.com/chartjs/Chart.js/issues/5208
+ if (!this.disableCSSInjection) {
+ injectCSS(this, stylesheet);
+ }
},
acquireContext: function(item, config) {
@@ -370,6 +358,10 @@ module.exports = {
// https://github.com/chartjs/Chart.js/issues/2807
var context = item && item.getContext && item.getContext('2d');
+ // Load platform resources on first chart creation, to make possible to change
+ // platform options after importing the library (e.g. `disableCSSInjection`).
+ this._ensureLoaded();
+
// `instanceof HTMLCanvasElement/CanvasRenderingContext2D` fails when the item is
// inside an iframe or when running in a protected environment. We could guess the
// types from their toString() value but let's keep things flexible and assume it's