Skip to content

Commit

Permalink
fix: #1160 strip out HTML when pasting
Browse files Browse the repository at this point in the history
  • Loading branch information
Cuong Vu committed May 13, 2020
1 parent e081bb0 commit 620d42a
Show file tree
Hide file tree
Showing 6 changed files with 90 additions and 4 deletions.
3 changes: 3 additions & 0 deletions packages/elements/src/components/Editor/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ export interface EditorProps {
actions?: Array<string | object>
dataTest?: string
onBlur?: () => void
onPaste?: (e: any) => void
}

const defaultActions = [
Expand Down Expand Up @@ -44,6 +45,7 @@ export const Editor = ({
contentClass = 'pell-content',
dataTest = '',
onBlur,
onPaste,
}: EditorProps) => {
const containerEl = React.useRef<HTMLDivElement>(null)

Expand Down Expand Up @@ -79,6 +81,7 @@ export const Editor = ({

return (
<div
onPaste={onPaste}
onBlur={onBlur}
ref={containerEl}
data-test={dataTest}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,13 @@
import * as React from 'react'
import { shallow } from 'enzyme'
import { FieldInputProps, Formik } from 'formik'
import { TextAreaEditor, TextAreaEditorProps, handleTextAreaOnChange, handleTextAreaOnBlur } from '../index'
import {
TextAreaEditor,
TextAreaEditorProps,
handleTextAreaOnChange,
handleTextAreaOnBlur,
handleTextAreaOnPaste,
} from '../index'

const props: TextAreaEditorProps = {
id: 'username',
Expand Down Expand Up @@ -41,4 +47,50 @@ describe('TextAreaEditor', () => {
expect(spy).toHaveBeenCalledWith(true)
})
})

describe('handleTextAreaOnPaste', () => {
afterAll(() => {
Object.defineProperty(document, 'queryCommandSupported', {
value: jest.fn(() => true),
writable: true,
})
})
const eventMock = {
stopPropagation: jest.fn(),
preventDefault: jest.fn(),
clipboardData: { getData: jest.fn(() => 'copiedText') },
} as any

it('should call execCommand insertText with correct plaintext if supported', () => {
const fn = handleTextAreaOnPaste()
fn(eventMock)
const spy = jest.spyOn(document, 'execCommand')
expect(spy).toHaveBeenCalledWith('insertText', false, 'copiedText')
})

it('should call execCommand paste with correct plaintext if not supported', () => {
Object.defineProperty(document, 'queryCommandSupported', {
value: jest.fn(() => false),
writable: true,
})
const fn = handleTextAreaOnPaste()
fn(eventMock)
const spy = jest.spyOn(document, 'execCommand')
expect(spy).toHaveBeenCalledWith('paste', false, 'copiedText')
})
it('should fallback to window.clipboardData if not supported', () => {
Object.defineProperty(window, 'clipboardData', {
value: { getData: jest.fn(() => 'copiedText') },
writable: true,
})
const eventMock = {
stopPropagation: jest.fn(),
preventDefault: jest.fn(),
} as any
const spy = jest.spyOn((window as any).clipboardData, 'getData')
const fn = handleTextAreaOnPaste()
fn(eventMock)
expect(spy).toHaveBeenCalledWith('Text')
})
})
})
27 changes: 26 additions & 1 deletion packages/elements/src/components/TextAreaEditor/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ export interface TextAreaEditorProps extends EditorProps {
labelText: string
name: string
dataTest?: string
allowPasteRichText?: boolean
}

export type HandleTextAreaOnChangeParams = {
Expand All @@ -27,7 +28,30 @@ export const handleTextAreaOnBlur = ({ helpers }: HandleTextAreaOnBlurParams) =>
helpers.setTouched(true)
}

export const TextAreaEditor = ({ name, labelText, placeholder, id, ...restProps }: TextAreaEditorProps) => {
export const handleTextAreaOnPaste = () => e => {
// Stop data actually being pasted into div
e.stopPropagation()
e.preventDefault()
// Get pasted data via clipboard API
const clipboardData = e.clipboardData || (window as any).clipboardData
const pastedData = clipboardData ? clipboardData.getData('Text') : ''

// need to check for browser compatible
if (document.queryCommandSupported('insertText')) {
document.execCommand('insertText', false, pastedData)
} else {
document.execCommand('paste', false, pastedData)
}
}

export const TextAreaEditor = ({
name,
labelText,
placeholder,
id,
allowPasteRichText = false,
...restProps
}: TextAreaEditorProps) => {
const [field, meta, helpers] = useField(name)

const hasError = checkError(meta)
Expand All @@ -44,6 +68,7 @@ export const TextAreaEditor = ({ name, labelText, placeholder, id, ...restProps
placeholder={placeholder}
defaultContent={field.value}
onChange={handleTextAreaOnChange({ field })}
onPaste={allowPasteRichText ? undefined : handleTextAreaOnPaste()}
onBlur={handleTextAreaOnBlur({ helpers })}
{...restProps}
/>
Expand Down
2 changes: 1 addition & 1 deletion packages/marketplace/src/tests/badges/badge-branches.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2 changes: 1 addition & 1 deletion packages/marketplace/src/tests/badges/badge-functions.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
6 changes: 6 additions & 0 deletions scripts/jest/jest-setup.js
Original file line number Diff line number Diff line change
Expand Up @@ -419,6 +419,12 @@ Object.defineProperty(document, 'execCommand', {
value: jest.fn(),
})

Object.defineProperty(document, 'queryCommandSupported', {
value: jest.fn(() => true),
writable: true,
})
window.queryCommandSupported = jest.fn()

Object.defineProperty(window, 'location', {
value: {
href: '',
Expand Down

0 comments on commit 620d42a

Please sign in to comment.