diff --git a/js/components/clin_fields.js b/js/components/clin_fields.js index 327bedf0..59d6c8c9 100644 --- a/js/components/clin_fields.js +++ b/js/components/clin_fields.js @@ -1,4 +1,5 @@ import { emitFieldChange } from '../lib/emitters' +import escape from '../lib/escape' import optionsinput from './options_input' import textinput from './text_input' import clindollaramount from './clin_dollar_amount' @@ -99,7 +100,7 @@ export default { computed: { clinTitle: function() { if (!!this.clinNumber) { - return `CLIN ${this.clinNumber}` + return escape(`CLIN ${this.clinNumber}`) } else { return `CLIN` } diff --git a/js/lib/__tests__/escape.test.js b/js/lib/__tests__/escape.test.js new file mode 100644 index 00000000..9dc2d5fe --- /dev/null +++ b/js/lib/__tests__/escape.test.js @@ -0,0 +1,21 @@ +import escape from '../escape' +describe('escape', () => { + const htmlEscapes = { + '&': '&', + '<': '<', + '>': '>', + '"': '"', + "'": ''', + '/': '/', + } + it('should escape each character', () => { + for (let [char, escapedChar] of Object.entries(htmlEscapes)) { + expect(escape(char)).toBe(escapedChar) + } + }) + it('should escape multiple characters', () => { + expect(escape('& and < and > and " and \' and /')).toBe( + '& and < and > and " and ' and /' + ) + }) +}) diff --git a/js/lib/escape.js b/js/lib/escape.js new file mode 100644 index 00000000..b72103c4 --- /dev/null +++ b/js/lib/escape.js @@ -0,0 +1,20 @@ +// https://stackoverflow.com/a/6020820 + +// List of HTML entities for escaping. +const htmlEscapes = { + '&': '&', + '<': '<', + '>': '>', + '"': '"', + "'": ''', + '/': '/', +} + +const htmlEscaper = /[&<>"'\/]/g + +// Escape a string for HTML interpolation. +const escape = string => { + return ('' + string).replace(htmlEscaper, match => htmlEscapes[match]) +} + +export default escape