diff --git a/public/app/plugins/panel/table/editor.html b/public/app/plugins/panel/table/editor.html
index c9e0bad5d9a..9206795c0d8 100644
--- a/public/app/plugins/panel/table/editor.html
+++ b/public/app/plugins/panel/table/editor.html
@@ -103,6 +103,11 @@
+
+
diff --git a/public/app/plugins/panel/table/editor.ts b/public/app/plugins/panel/table/editor.ts
index 65c8b51cab8..0a6f695d34b 100644
--- a/public/app/plugins/panel/table/editor.ts
+++ b/public/app/plugins/panel/table/editor.ts
@@ -112,6 +112,7 @@ export class TablePanelEditorCtrl {
pattern: '/.*/',
dateFormat: 'YYYY-MM-DD HH:mm:ss',
thresholds: [],
+ escapeHtml: true
};
this.panel.styles.push(angular.copy(columnStyleDefaults));
diff --git a/public/app/plugins/panel/table/renderer.ts b/public/app/plugins/panel/table/renderer.ts
index 755c7262070..42b9aeeb2d2 100644
--- a/public/app/plugins/panel/table/renderer.ts
+++ b/public/app/plugins/panel/table/renderer.ts
@@ -4,6 +4,8 @@ import _ from 'lodash';
import moment from 'moment';
import kbn from 'app/core/utils/kbn';
+
+
export class TableRenderer {
formaters: any[];
colorState: any;
@@ -24,22 +26,27 @@ export class TableRenderer {
return _.first(style.colors);
}
- defaultCellFormater(v) {
- if (v === null || v === void 0) {
- return '';
- }
+ defaultCellFormater(escapeHtml = true) {
+ return function(v) {
+ if (v === null || v === void 0 || v === undefined) {
+ return '';
+ }
- if (_.isArray(v)) {
- v = v.join(', ');
- }
+ if (_.isArray(v)) {
+ v = v.join(', ');
+ }
- return v;
+ if (_.isString(v) && escapeHtml) {
+ v = encodeHtml(v);
+ }
+
+ return v;
+ };
}
-
createColumnFormater(style) {
if (!style) {
- return this.defaultCellFormater;
+ return this.defaultCellFormater();
}
if (style.type === 'date') {
@@ -62,7 +69,7 @@ export class TableRenderer {
}
if (_.isString(v)) {
- return v;
+ return encodeHtml(v);
}
if (style.colorMode) {
@@ -73,7 +80,11 @@ export class TableRenderer {
};
}
- return this.defaultCellFormater;
+ if (style.type === 'string') {
+ return this.defaultCellFormater(style.escapeHtml);
+ }
+
+ return this.defaultCellFormater();
}
formatColumnValue(colIndex, value) {
@@ -91,7 +102,7 @@ export class TableRenderer {
}
}
- this.formaters[colIndex] = this.defaultCellFormater;
+ this.formaters[colIndex] = this.defaultCellFormater();
return this.formaters[colIndex](value);
}
@@ -142,3 +153,15 @@ export class TableRenderer {
return html;
}
}
+
+function encodeHtml(unsafe) {
+ return unsafe.replace(/[&<>"']/g, function(m) {
+ return ({
+ '&': '&',
+ '<': '<',
+ '>': '>',
+ '"': '"',
+ '\'': '''
+ })[m];
+ });
+}
diff --git a/public/app/plugins/panel/table/specs/renderer_specs.ts b/public/app/plugins/panel/table/specs/renderer_specs.ts
index 0e7d1e921f4..70dca26a0e8 100644
--- a/public/app/plugins/panel/table/specs/renderer_specs.ts
+++ b/public/app/plugins/panel/table/specs/renderer_specs.ts
@@ -11,6 +11,8 @@ describe('when rendering table', () => {
{text: 'Value'},
{text: 'Colored'},
{text: 'Undefined'},
+ {text: 'String'},
+ {text: 'UnescapedString' }
];
var panel = {
@@ -35,6 +37,16 @@ describe('when rendering table', () => {
colorMode: 'value',
thresholds: [50, 80],
colors: ['green', 'orange', 'red']
+ },
+ {
+ pattern: 'String',
+ type: 'string',
+ escapeHtml: true,
+ },
+ {
+ pattern: 'UnescapedString',
+ type: 'string',
+ escapeHtml: false,
}
]
};
@@ -76,6 +88,21 @@ describe('when rendering table', () => {
expect(html).to.be('value | ');
});
+ it('string style with escape html should return escaped html', () => {
+ var html = renderer.renderCell(4, "&breaking
the
row");
+ expect(html).to.be('&breaking <br /> the <br /> row | ');
+ });
+
+ it('undefined formater should return escaped html', () => {
+ var html = renderer.renderCell(4, "&breaking
the
row");
+ expect(html).to.be('&breaking <br /> the <br /> row | ');
+ });
+
+ it('string style with escape html false should return html', () => {
+ var html = renderer.renderCell(5, "&breaking
the
row");
+ expect(html).to.be('&breaking the row | ');
+ });
+
it('undefined value should render as -', () => {
var html = renderer.renderCell(3, undefined);
expect(html).to.be(' | ');