@ephox/agar
Advanced tools
Comparing version 7.4.4 to 8.0.0-alpha.0
@@ -9,2 +9,9 @@ # Changelog | ||
### Added | ||
- Added `Clipboard.pPasteUrlItems` API to paste url files as clipboard items. #TINY-10275 | ||
- Added `Files.getFileDataAsString` API to make it easier to get file data out for testing. #TINY-10275 | ||
### Removed | ||
- Removed the `RealClipboard.sImportToClipboard` API. #TINY-10275 | ||
## 7.4.0 - 2023-03-15 | ||
@@ -11,0 +18,0 @@ |
import { SugarElement } from '@ephox/sugar'; | ||
import { Chain } from './Chain'; | ||
import { Step } from './Step'; | ||
export interface PasteUrlItem { | ||
readonly kind: 'string' | 'file'; | ||
readonly url: string; | ||
} | ||
declare const pasteDataTransfer: (target: SugarElement<Element>, mutator: (dataTransfer: DataTransfer) => void) => void; | ||
@@ -13,2 +17,3 @@ declare const pasteItems: (target: SugarElement<Element>, items: Record<string, string>) => void; | ||
declare const sPasteFiles: <T>(files: File[], selector: string) => Step<T, T>; | ||
declare const pPasteUrlItems: (target: SugarElement<Element>, items: PasteUrlItem[]) => Promise<void>; | ||
declare const cut: (target: SugarElement<Element>) => DataTransfer; | ||
@@ -18,3 +23,3 @@ declare const copy: (target: SugarElement<Element>) => DataTransfer; | ||
declare const cCopy: Chain<SugarElement<Element>, DataTransfer>; | ||
export { pasteDataTransfer, pasteItems, pasteFiles, cPasteDataTransfer, cPasteItems, cPasteFiles, sPasteDataTransfer, sPasteItems, sPasteFiles, cut, copy, cCut, cCopy }; | ||
export { pasteDataTransfer, pasteItems, pasteFiles, cPasteDataTransfer, cPasteItems, cPasteFiles, sPasteDataTransfer, sPasteItems, sPasteFiles, pPasteUrlItems, cut, copy, cCut, cCopy }; | ||
//# sourceMappingURL=Clipboard.d.ts.map |
@@ -6,2 +6,3 @@ import { Arr, Obj } from '@ephox/katamari'; | ||
import { getWindowFromElement } from '../dragndrop/DndEvents'; | ||
import * as BlobReader from '../file/BlobReader'; | ||
import { Chain } from './Chain'; | ||
@@ -45,2 +46,31 @@ import * as ChainSequence from './ChainSequence'; | ||
])); | ||
const pPasteUrlItems = async (target, items) => { | ||
const dataItems = await Promise.all(Arr.map(items, async (item) => { | ||
const resp = await window.fetch(item.url); | ||
if (resp.ok) { | ||
const blob = await resp.blob(); | ||
const fileName = Arr.last(item.url.split('/')).getOr('filename.dat'); | ||
const mime = blob.type.split(';')[0]; // Only grab mime type not charset encoding | ||
if (item.kind === 'string') { | ||
return { kind: 'string', mime, text: await BlobReader.readBlobAsString(blob) }; | ||
} | ||
else { | ||
return { kind: item.kind, file: new window.File([blob], fileName, { type: mime }) }; | ||
} | ||
} | ||
else { | ||
return Promise.reject(new Error(`Failed to load paste URL item: "${item.url}", status: ${resp.status}`)); | ||
} | ||
})); | ||
pasteDataTransfer(target, (dataTransfer) => { | ||
Arr.each(dataItems, (dataItem) => { | ||
if (dataItem.kind === 'string') { | ||
dataTransfer.items.add(dataItem.text, dataItem.mime); | ||
} | ||
else { | ||
dataTransfer.items.add(dataItem.file); | ||
} | ||
}); | ||
}); | ||
}; | ||
const cut = (target) => { | ||
@@ -62,3 +92,3 @@ const win = getWindowFromElement(target); | ||
const cCopy = Chain.mapper(copy); | ||
export { pasteDataTransfer, pasteItems, pasteFiles, cPasteDataTransfer, cPasteItems, cPasteFiles, sPasteDataTransfer, sPasteItems, sPasteFiles, cut, copy, cCut, cCopy }; | ||
export { pasteDataTransfer, pasteItems, pasteFiles, cPasteDataTransfer, cPasteItems, cPasteFiles, sPasteDataTransfer, sPasteItems, sPasteFiles, pPasteUrlItems, cut, copy, cCut, cCopy }; | ||
//# sourceMappingURL=Clipboard.js.map |
@@ -1,3 +0,3 @@ | ||
import { createFile, createFileFromString } from '../file/Files'; | ||
export { createFile, createFileFromString }; | ||
import { createFile, createFileFromString, getFileDataAsString } from '../file/Files'; | ||
export { createFile, createFileFromString, getFileDataAsString }; | ||
//# sourceMappingURL=Files.d.ts.map |
@@ -1,3 +0,3 @@ | ||
import { createFile, createFileFromString } from '../file/Files'; | ||
export { createFile, createFileFromString }; | ||
import { createFile, createFileFromString, getFileDataAsString } from '../file/Files'; | ||
export { createFile, createFileFromString, getFileDataAsString }; | ||
//# sourceMappingURL=Files.js.map |
import { Step } from './Step'; | ||
declare const pImportToClipboard: (filename: string) => Promise<{}>; | ||
declare const sImportToClipboard: <T>(filename: string) => Step<T, T>; | ||
declare const pCopy: (selector: string) => Promise<{}>; | ||
@@ -8,3 +6,3 @@ declare const sCopy: <T>(selector: string) => Step<T, T>; | ||
declare const sPaste: <T>(selector: string) => Step<T, T>; | ||
export { pImportToClipboard, pCopy, pPaste, sImportToClipboard, sCopy, sPaste }; | ||
export { pCopy, pPaste, sCopy, sPaste }; | ||
//# sourceMappingURL=RealClipboard.d.ts.map |
import { PlatformDetection } from '@ephox/sand'; | ||
import * as SeleniumAction from '../server/SeleniumAction'; | ||
import { RealKeys } from './RealKeys'; | ||
import { Step } from './Step'; | ||
const platform = PlatformDetection.detect(); | ||
const pImportToClipboard = (filename) => SeleniumAction.pPerform('/clipboard', { | ||
import: filename | ||
}); | ||
const sImportToClipboard = (filename) => Step.fromPromise(() => pImportToClipboard(filename)); | ||
const pCopy = (selector) => { | ||
@@ -24,3 +19,3 @@ const modifiers = platform.os.isMacOS() ? { metaKey: true } : { ctrlKey: true }; | ||
const sPaste = (selector) => Step.fromPromise(() => pPaste(selector)); | ||
export { pImportToClipboard, pCopy, pPaste, sImportToClipboard, sCopy, sPaste }; | ||
export { pCopy, pPaste, sCopy, sPaste }; | ||
//# sourceMappingURL=RealClipboard.js.map |
declare const createFile: (name: string, lastModified: number, blob: Blob) => File; | ||
declare const createFileFromString: (name: string, lastModified: number, text: string, mime: string) => File; | ||
export { createFile, createFileFromString }; | ||
declare const getFileDataAsString: (file: File) => Promise<string>; | ||
export { createFile, createFileFromString, getFileDataAsString }; | ||
//# sourceMappingURL=Files.d.ts.map |
@@ -0,1 +1,2 @@ | ||
import * as BlobReader from './BlobReader'; | ||
const createFile = (name, lastModified, blob) => { | ||
@@ -8,3 +9,4 @@ const newBlob = new Blob([blob], { type: blob.type }); | ||
const createFileFromString = (name, lastModified, text, mime) => createFile(name, lastModified, new Blob([text], { type: mime })); | ||
export { createFile, createFileFromString }; | ||
const getFileDataAsString = (file) => BlobReader.readBlobAsString(file); | ||
export { createFile, createFileFromString, getFileDataAsString }; | ||
//# sourceMappingURL=Files.js.map |
@@ -1,88 +0,136 @@ | ||
import { Assert, UnitTest } from '@ephox/bedrock-client'; | ||
import { after, before, beforeEach, describe, it } from '@ephox/bedrock-client'; | ||
import { Singleton } from '@ephox/katamari'; | ||
import { DomEvent, Insert, Remove, SugarBody, SugarElement } from '@ephox/sugar'; | ||
import { Chain } from 'ephox/agar/api/Chain'; | ||
import * as ChainSequence from 'ephox/agar/api/ChainSequence'; | ||
import { cCopy, cCut, sPasteDataTransfer, sPasteFiles, sPasteItems } from 'ephox/agar/api/Clipboard'; | ||
import { createFileFromString } from 'ephox/agar/api/Files'; | ||
import * as Logger from 'ephox/agar/api/Logger'; | ||
import { Pipeline } from 'ephox/agar/api/Pipeline'; | ||
import { Step } from 'ephox/agar/api/Step'; | ||
import * as StepSequence from 'ephox/agar/api/StepSequence'; | ||
UnitTest.asynctest('ClipboardTest', (success, failure) => { | ||
const pastebin = SugarElement.fromHtml('<div class="pastebin"></div>'); | ||
import { assert } from 'chai'; | ||
import { copy, cut, pasteDataTransfer, pasteFiles, pasteItems, pPasteUrlItems } from 'ephox/agar/api/Clipboard'; | ||
import { createFileFromString, getFileDataAsString } from 'ephox/agar/api/Files'; | ||
describe('ClipboardTest', () => { | ||
const pasteState = Singleton.value(); | ||
Insert.append(SugarBody.body(), pastebin); | ||
const cutUnbinder = DomEvent.bind(pastebin, 'cut', (evt) => { | ||
const dataTransfer = evt.raw.clipboardData; | ||
dataTransfer.clearData(); | ||
dataTransfer.setData('text/plain', 'cut-data'); | ||
const pastebinState = Singleton.value(); | ||
const unbinderState = Singleton.value(); | ||
const getItemData = async (item) => { | ||
if (item.kind === 'string') { | ||
return new Promise((resolve) => { | ||
item.getAsString((data) => { | ||
resolve(data); | ||
}); | ||
}); | ||
} | ||
else { | ||
return getFileDataAsString(item.getAsFile()); | ||
} | ||
}; | ||
const assertStringItem = async (item, expected) => { | ||
assert.equal(item.type, expected.type); | ||
assert.equal(item.kind, 'string'); | ||
assert.equal(await getItemData(item), expected.data); | ||
}; | ||
const assertFileItem = async (item, expected) => { | ||
assert.equal(item.type, expected.type); | ||
assert.equal(item.kind, 'file'); | ||
assert.equal(item.getAsFile().name, expected.name); | ||
assert.equal(await getItemData(item), expected.data); | ||
}; | ||
before(() => { | ||
pastebinState.set(SugarElement.fromHtml('<div class="pastebin"></div>')); | ||
pastebinState.on((pastebin) => { | ||
Insert.append(SugarBody.body(), pastebin); | ||
const cutUnbinder = DomEvent.bind(pastebin, 'cut', (evt) => { | ||
const dataTransfer = evt.raw.clipboardData; | ||
dataTransfer.clearData(); | ||
dataTransfer.setData('text/plain', 'cut-data'); | ||
}); | ||
const copyUnbinder = DomEvent.bind(pastebin, 'copy', (evt) => { | ||
const dataTransfer = evt.raw.clipboardData; | ||
dataTransfer.clearData(); | ||
dataTransfer.setData('text/plain', 'copy-data'); | ||
}); | ||
const pasteUnbinder = DomEvent.bind(pastebin, 'paste', (evt) => { | ||
const dataTransfer = evt.raw.clipboardData; | ||
pasteState.set(dataTransfer); | ||
}); | ||
unbinderState.set(() => { | ||
cutUnbinder.unbind(); | ||
copyUnbinder.unbind(); | ||
pasteUnbinder.unbind(); | ||
}); | ||
}); | ||
}); | ||
const copyUnbinder = DomEvent.bind(pastebin, 'copy', (evt) => { | ||
const dataTransfer = evt.raw.clipboardData; | ||
dataTransfer.clearData(); | ||
dataTransfer.setData('text/plain', 'copy-data'); | ||
beforeEach(() => { | ||
pasteState.clear(); | ||
}); | ||
const pasteUnbinder = DomEvent.bind(pastebin, 'paste', (evt) => { | ||
const dataTransfer = evt.raw.clipboardData; | ||
pasteState.set(dataTransfer); | ||
after(() => { | ||
pastebinState.on(Remove.remove); | ||
pastebinState.clear(); | ||
unbinderState.on((unbind) => unbind()); | ||
unbinderState.clear(); | ||
}); | ||
Pipeline.runStep({}, StepSequence.sequenceSame([ | ||
Logger.t('Paste text and html items', StepSequence.sequenceSame([ | ||
sPasteItems({ | ||
'text/plain': 'Hello world!', | ||
'text/html': '<b>Hello world!</b>' | ||
}, '.pastebin'), | ||
Step.sync(() => { | ||
const dataTransfer = pasteState.get().getOrDie('Could not get dataTransfer from state'); | ||
Assert.eq('Should be expected plain text', 'Hello world!', dataTransfer.getData('text/plain')); | ||
Assert.eq('Should be expected html', '<b>Hello world!</b>', dataTransfer.getData('text/html')); | ||
}) | ||
])), | ||
Logger.t('Paste text and html files', StepSequence.sequenceSame([ | ||
sPasteFiles([ | ||
createFileFromString('a.txt', 123, 'Hello world!', 'text/plain'), | ||
createFileFromString('a.html', 123, '<b>Hello world!</b>', 'text/html') | ||
], '.pastebin'), | ||
Step.sync(() => { | ||
const dataTransfer = pasteState.get().getOrDie('Could not get dataTransfer from state'); | ||
Assert.eq('Should be expected mime type', 'text/plain', dataTransfer.items[0].type); | ||
Assert.eq('Should be expected mime type', 'text/plain', dataTransfer.files[0].type); | ||
Assert.eq('Should be expected mime type', 'text/html', dataTransfer.items[1].type); | ||
Assert.eq('Should be expected mime type', 'text/html', dataTransfer.files[1].type); | ||
}) | ||
])), | ||
Logger.t('Paste using dataTransfer mutator', StepSequence.sequenceSame([ | ||
sPasteDataTransfer((dataTransfer) => { | ||
dataTransfer.items.add(createFileFromString('a.txt', 123, 'Hello world!', 'text/plain')); | ||
dataTransfer.items.add('<b>Hello world!</b>', 'text/html'); | ||
}, '.pastebin'), | ||
Step.sync(() => { | ||
const dataTransfer = pasteState.get().getOrDie('Could not get dataTransfer from state'); | ||
Assert.eq('Should be expected mime type', 'text/plain', dataTransfer.items[0].type); | ||
Assert.eq('Should be expected mime type', 'file', dataTransfer.items[0].kind); | ||
Assert.eq('Should be expected mime type', 'text/html', dataTransfer.items[1].type); | ||
Assert.eq('Should be expected mime type', 'string', dataTransfer.items[1].kind); | ||
}) | ||
])), | ||
Logger.t('Cut', Chain.isolate(pastebin, ChainSequence.sequence([ | ||
cCut, | ||
Chain.op((dataTransfer) => { | ||
Assert.eq('Should be extracted cut data', 'cut-data', dataTransfer.getData('text/plain')); | ||
}) | ||
]))), | ||
Logger.t('Copy', Chain.isolate(pastebin, ChainSequence.sequence([ | ||
cCopy, | ||
Chain.op((dataTransfer) => { | ||
Assert.eq('Should be extracted copy data', 'copy-data', dataTransfer.getData('text/plain')); | ||
}) | ||
]))) | ||
]), () => { | ||
cutUnbinder.unbind(); | ||
copyUnbinder.unbind(); | ||
pasteUnbinder.unbind(); | ||
Remove.remove(pastebin); | ||
success(); | ||
}, failure); | ||
it('Paste text and html items', async () => { | ||
const pastebin = pastebinState.get().getOrDie('Could not get pastebin from state'); | ||
pasteItems(pastebin, { | ||
'text/plain': 'Hello world!', | ||
'text/html': '<b>Hello world!</b>' | ||
}); | ||
const dataTransfer = pasteState.get().getOrDie('Could not get dataTransfer from state'); | ||
assert.equal(dataTransfer.items.length, 2); | ||
await assertStringItem(dataTransfer.items[0], { type: 'text/plain', data: 'Hello world!' }); | ||
await assertStringItem(dataTransfer.items[1], { type: 'text/html', data: '<b>Hello world!</b>' }); | ||
}); | ||
it('Paste text and html files', async () => { | ||
const pastebin = pastebinState.get().getOrDie('Could not get pastebin from state'); | ||
pasteFiles(pastebin, [ | ||
createFileFromString('a.txt', 123, 'Hello world!', 'text/plain'), | ||
createFileFromString('a.html', 123, '<b>Hello world!</b>', 'text/html') | ||
]); | ||
const dataTransfer = pasteState.get().getOrDie('Could not get dataTransfer from state'); | ||
assert.equal(dataTransfer.items.length, 2); | ||
await assertFileItem(dataTransfer.items[1], { type: 'text/html', name: 'a.html', data: '<b>Hello world!</b>' }); | ||
await assertFileItem(dataTransfer.items[0], { type: 'text/plain', name: 'a.txt', data: 'Hello world!' }); | ||
}); | ||
it('Paste using dataTransfer mutator', async () => { | ||
const pastebin = pastebinState.get().getOrDie('Could not get pastebin from state'); | ||
pasteDataTransfer(pastebin, (dataTransfer) => { | ||
dataTransfer.items.add(createFileFromString('a.txt', 123, 'Hello world!', 'text/plain')); | ||
dataTransfer.items.add('<b>Hello world!</b>', 'text/html'); | ||
}); | ||
const dataTransfer = pasteState.get().getOrDie('Could not get dataTransfer from state'); | ||
assert.equal(dataTransfer.items.length, 2); | ||
await assertFileItem(dataTransfer.items[0], { type: 'text/plain', name: 'a.txt', data: 'Hello world!' }); | ||
await assertStringItem(dataTransfer.items[1], { type: 'text/html', data: '<b>Hello world!</b>' }); | ||
}); | ||
it('Cut', async () => { | ||
const pastebin = pastebinState.get().getOrDie('Could not get pastebin from state'); | ||
const dataTransfer = cut(pastebin); | ||
assert.equal(dataTransfer.items.length, 1); | ||
await assertStringItem(dataTransfer.items[0], { type: 'text/plain', data: 'cut-data' }); | ||
}); | ||
it('Copy', async () => { | ||
const pastebin = pastebinState.get().getOrDie('Could not get pastebin from state'); | ||
const dataTransfer = copy(pastebin); | ||
assert.equal(dataTransfer.items.length, 1); | ||
await assertStringItem(dataTransfer.items[0], { type: 'text/plain', data: 'copy-data' }); | ||
}); | ||
it('PasteUrlItems as strings', async () => { | ||
const pastebin = pastebinState.get().getOrDie('Could not get pastebin from state'); | ||
await pPasteUrlItems(pastebin, [ | ||
{ kind: 'string', url: 'project/@ephox/agar/src/test/resources/clipboard.html' }, | ||
{ kind: 'string', url: 'project/@ephox/agar/src/test/resources/clipboard.txt' }, | ||
]); | ||
const dataTransfer = pasteState.get().getOrDie('Could not get dataTransfer from state'); | ||
assert.equal(dataTransfer.items.length, 2); | ||
assertStringItem(dataTransfer.items[0], { type: 'text/html', data: '<!DOCTYPE html>\n<html>\n<body>\n<p>Hello world</p>\n</body>\n</html>\n' }); | ||
assertStringItem(dataTransfer.items[1], { type: 'text/plain', data: 'Hello world\n' }); | ||
}); | ||
it('PasteUrlItems as files', async () => { | ||
const pastebin = pastebinState.get().getOrDie('Could not get pastebin from state'); | ||
await pPasteUrlItems(pastebin, [ | ||
{ kind: 'file', url: 'project/@ephox/agar/src/test/resources/clipboard.html' }, | ||
{ kind: 'file', url: 'project/@ephox/agar/src/test/resources/clipboard.txt' }, | ||
]); | ||
const dataTransfer = pasteState.get().getOrDie('Could not get dataTransfer from state'); | ||
assert.equal(dataTransfer.items.length, 2); | ||
await assertFileItem(dataTransfer.items[0], { type: 'text/html', name: 'clipboard.html', data: '<!DOCTYPE html>\n<html>\n<body>\n<p>Hello world</p>\n</body>\n</html>\n' }); | ||
await assertFileItem(dataTransfer.items[1], { type: 'text/plain', name: 'clipboard.txt', data: 'Hello world\n' }); | ||
}); | ||
}); | ||
//# sourceMappingURL=ClipboardTest.js.map |
{ | ||
"name": "@ephox/agar", | ||
"version": "7.4.4", | ||
"version": "8.0.0-alpha.0", | ||
"description": "Testing infrastructure", | ||
@@ -53,3 +53,3 @@ "repository": { | ||
"types": "./lib/main/ts/ephox/agar/api/Main.d.ts", | ||
"gitHead": "701cb0d5c053485868c40893985ba6b2701ccbcd" | ||
"gitHead": "43a13264fc1c197541dc62cb734e0f32b09afca4" | ||
} |
@@ -7,2 +7,3 @@ import { Arr, Obj } from '@ephox/katamari'; | ||
import { getWindowFromElement } from '../dragndrop/DndEvents'; | ||
import * as BlobReader from '../file/BlobReader'; | ||
import { Chain } from './Chain'; | ||
@@ -13,2 +14,7 @@ import * as ChainSequence from './ChainSequence'; | ||
export interface PasteUrlItem { | ||
readonly kind: 'string' | 'file'; | ||
readonly url: string; | ||
} | ||
const pasteDataTransfer = (target: SugarElement<Element>, mutator: (dataTransfer: DataTransfer) => void): void => { | ||
@@ -68,2 +74,32 @@ const win = getWindowFromElement(target); | ||
const pPasteUrlItems = async (target: SugarElement<Element>, items: PasteUrlItem[]): Promise<void> => { | ||
const dataItems = await Promise.all(Arr.map(items, async (item) => { | ||
const resp = await window.fetch(item.url); | ||
if (resp.ok) { | ||
const blob = await resp.blob(); | ||
const fileName = Arr.last(item.url.split('/')).getOr('filename.dat'); | ||
const mime = blob.type.split(';')[0]; // Only grab mime type not charset encoding | ||
if (item.kind === 'string') { | ||
return { kind: 'string', mime, text: await BlobReader.readBlobAsString(blob) }; | ||
} else { | ||
return { kind: item.kind, file: new window.File([ blob ], fileName, { type: mime }) }; | ||
} | ||
} else { | ||
return Promise.reject(new Error(`Failed to load paste URL item: "${item.url}", status: ${resp.status}`)); | ||
} | ||
})); | ||
pasteDataTransfer(target, (dataTransfer) => { | ||
Arr.each(dataItems, (dataItem) => { | ||
if (dataItem.kind === 'string') { | ||
dataTransfer.items.add(dataItem.text, dataItem.mime); | ||
} else { | ||
dataTransfer.items.add(dataItem.file); | ||
} | ||
}); | ||
}); | ||
}; | ||
const cut = (target: SugarElement<Element>): DataTransfer => { | ||
@@ -105,2 +141,3 @@ const win = getWindowFromElement(target); | ||
sPasteFiles, | ||
pPasteUrlItems, | ||
cut, | ||
@@ -107,0 +144,0 @@ copy, |
@@ -1,6 +0,7 @@ | ||
import { createFile, createFileFromString } from '../file/Files'; | ||
import { createFile, createFileFromString, getFileDataAsString } from '../file/Files'; | ||
export { | ||
createFile, | ||
createFileFromString | ||
createFileFromString, | ||
getFileDataAsString | ||
}; |
import { PlatformDetection } from '@ephox/sand'; | ||
import { KeyModifiers } from '../keyboard/FakeKeys'; | ||
import * as SeleniumAction from '../server/SeleniumAction'; | ||
import { RealKeys } from './RealKeys'; | ||
@@ -10,10 +9,2 @@ import { Step } from './Step'; | ||
const pImportToClipboard = (filename: string): Promise<{}> => | ||
SeleniumAction.pPerform('/clipboard', { | ||
import: filename | ||
}); | ||
const sImportToClipboard = <T>(filename: string): Step<T, T> => | ||
Step.fromPromise(() => pImportToClipboard(filename)); | ||
const pCopy = (selector: string): Promise<{}> => { | ||
@@ -40,8 +31,6 @@ const modifiers: KeyModifiers = platform.os.isMacOS() ? { metaKey: true } : { ctrlKey: true }; | ||
export { | ||
pImportToClipboard, | ||
pCopy, | ||
pPaste, | ||
sImportToClipboard, | ||
sCopy, | ||
sPaste | ||
}; |
@@ -0,1 +1,3 @@ | ||
import * as BlobReader from './BlobReader'; | ||
const createFile = (name: string, lastModified: number, blob: Blob): File => { | ||
@@ -12,5 +14,8 @@ const newBlob: any = new Blob([ blob ], { type: blob.type }); | ||
const getFileDataAsString = (file: File): Promise<string> => BlobReader.readBlobAsString(file); | ||
export { | ||
createFile, | ||
createFileFromString | ||
createFileFromString, | ||
getFileDataAsString | ||
}; |
@@ -1,103 +0,170 @@ | ||
import { Assert, UnitTest } from '@ephox/bedrock-client'; | ||
import { after, before, beforeEach, describe, it } from '@ephox/bedrock-client'; | ||
import { Singleton } from '@ephox/katamari'; | ||
import { DomEvent, Insert, Remove, SugarBody, SugarElement } from '@ephox/sugar'; | ||
import { assert } from 'chai'; | ||
import { Chain } from 'ephox/agar/api/Chain'; | ||
import * as ChainSequence from 'ephox/agar/api/ChainSequence'; | ||
import { cCopy, cCut, sPasteDataTransfer, sPasteFiles, sPasteItems } from 'ephox/agar/api/Clipboard'; | ||
import { createFileFromString } from 'ephox/agar/api/Files'; | ||
import * as Logger from 'ephox/agar/api/Logger'; | ||
import { Pipeline } from 'ephox/agar/api/Pipeline'; | ||
import { Step } from 'ephox/agar/api/Step'; | ||
import * as StepSequence from 'ephox/agar/api/StepSequence'; | ||
import { copy, cut, pasteDataTransfer, pasteFiles, pasteItems, pPasteUrlItems } from 'ephox/agar/api/Clipboard'; | ||
import { createFileFromString, getFileDataAsString } from 'ephox/agar/api/Files'; | ||
UnitTest.asynctest('ClipboardTest', (success, failure) => { | ||
const pastebin = SugarElement.fromHtml('<div class="pastebin"></div>'); | ||
describe('ClipboardTest', () => { | ||
const pasteState = Singleton.value<DataTransfer>(); | ||
const pastebinState = Singleton.value<SugarElement<HTMLElement>>(); | ||
const unbinderState = Singleton.value<() => void>(); | ||
Insert.append(SugarBody.body(), pastebin); | ||
const getItemData = async (item: DataTransferItem) => { | ||
if (item.kind === 'string') { | ||
return new Promise((resolve) => { | ||
item.getAsString((data) => { | ||
resolve(data); | ||
}); | ||
}); | ||
} else { | ||
return getFileDataAsString(item.getAsFile()); | ||
} | ||
}; | ||
const cutUnbinder = DomEvent.bind(pastebin, 'cut', (evt) => { | ||
const dataTransfer = evt.raw.clipboardData; | ||
dataTransfer.clearData(); | ||
dataTransfer.setData('text/plain', 'cut-data'); | ||
const assertStringItem = async (item: DataTransferItem, expected: { type: string; data: string }): Promise<void> => { | ||
assert.equal(item.type, expected.type); | ||
assert.equal(item.kind, 'string'); | ||
assert.equal(await getItemData(item), expected.data); | ||
}; | ||
const assertFileItem = async (item: DataTransferItem, expected: { type: string; name: string; data: string }): Promise<void> => { | ||
assert.equal(item.type, expected.type); | ||
assert.equal(item.kind, 'file'); | ||
assert.equal(item.getAsFile().name, expected.name); | ||
assert.equal(await getItemData(item), expected.data); | ||
}; | ||
before(() => { | ||
pastebinState.set(SugarElement.fromHtml('<div class="pastebin"></div>')); | ||
pastebinState.on((pastebin) => { | ||
Insert.append(SugarBody.body(), pastebin); | ||
const cutUnbinder = DomEvent.bind(pastebin, 'cut', (evt) => { | ||
const dataTransfer = evt.raw.clipboardData; | ||
dataTransfer.clearData(); | ||
dataTransfer.setData('text/plain', 'cut-data'); | ||
}); | ||
const copyUnbinder = DomEvent.bind(pastebin, 'copy', (evt) => { | ||
const dataTransfer = evt.raw.clipboardData; | ||
dataTransfer.clearData(); | ||
dataTransfer.setData('text/plain', 'copy-data'); | ||
}); | ||
const pasteUnbinder = DomEvent.bind(pastebin, 'paste', (evt) => { | ||
const dataTransfer = evt.raw.clipboardData; | ||
pasteState.set(dataTransfer); | ||
}); | ||
unbinderState.set(() => { | ||
cutUnbinder.unbind(); | ||
copyUnbinder.unbind(); | ||
pasteUnbinder.unbind(); | ||
}); | ||
}); | ||
}); | ||
const copyUnbinder = DomEvent.bind(pastebin, 'copy', (evt) => { | ||
const dataTransfer = evt.raw.clipboardData; | ||
dataTransfer.clearData(); | ||
dataTransfer.setData('text/plain', 'copy-data'); | ||
beforeEach(() => { | ||
pasteState.clear(); | ||
}); | ||
const pasteUnbinder = DomEvent.bind(pastebin, 'paste', (evt) => { | ||
const dataTransfer = evt.raw.clipboardData; | ||
pasteState.set(dataTransfer); | ||
after(() => { | ||
pastebinState.on(Remove.remove); | ||
pastebinState.clear(); | ||
unbinderState.on((unbind) => unbind()); | ||
unbinderState.clear(); | ||
}); | ||
Pipeline.runStep({}, StepSequence.sequenceSame([ | ||
Logger.t('Paste text and html items', StepSequence.sequenceSame([ | ||
sPasteItems({ | ||
'text/plain': 'Hello world!', | ||
'text/html': '<b>Hello world!</b>' | ||
}, '.pastebin'), | ||
Step.sync(() => { | ||
const dataTransfer = pasteState.get().getOrDie('Could not get dataTransfer from state'); | ||
it('Paste text and html items', async () => { | ||
const pastebin = pastebinState.get().getOrDie('Could not get pastebin from state'); | ||
Assert.eq('Should be expected plain text', 'Hello world!', dataTransfer.getData('text/plain')); | ||
Assert.eq('Should be expected html', '<b>Hello world!</b>', dataTransfer.getData('text/html')); | ||
}) | ||
])), | ||
pasteItems(pastebin, { | ||
'text/plain': 'Hello world!', | ||
'text/html': '<b>Hello world!</b>' | ||
}); | ||
Logger.t('Paste text and html files', StepSequence.sequenceSame([ | ||
sPasteFiles([ | ||
createFileFromString('a.txt', 123, 'Hello world!', 'text/plain'), | ||
createFileFromString('a.html', 123, '<b>Hello world!</b>', 'text/html') | ||
], '.pastebin'), | ||
Step.sync(() => { | ||
const dataTransfer = pasteState.get().getOrDie('Could not get dataTransfer from state'); | ||
const dataTransfer = pasteState.get().getOrDie('Could not get dataTransfer from state'); | ||
Assert.eq('Should be expected mime type', 'text/plain', dataTransfer.items[0].type); | ||
Assert.eq('Should be expected mime type', 'text/plain', dataTransfer.files[0].type); | ||
assert.equal(dataTransfer.items.length, 2); | ||
await assertStringItem(dataTransfer.items[0], { type: 'text/plain', data: 'Hello world!' }); | ||
await assertStringItem(dataTransfer.items[1], { type: 'text/html', data: '<b>Hello world!</b>' }); | ||
}); | ||
Assert.eq('Should be expected mime type', 'text/html', dataTransfer.items[1].type); | ||
Assert.eq('Should be expected mime type', 'text/html', dataTransfer.files[1].type); | ||
}) | ||
])), | ||
it('Paste text and html files', async () => { | ||
const pastebin = pastebinState.get().getOrDie('Could not get pastebin from state'); | ||
Logger.t('Paste using dataTransfer mutator', StepSequence.sequenceSame([ | ||
sPasteDataTransfer((dataTransfer) => { | ||
dataTransfer.items.add(createFileFromString('a.txt', 123, 'Hello world!', 'text/plain')); | ||
dataTransfer.items.add('<b>Hello world!</b>', 'text/html'); | ||
}, '.pastebin'), | ||
Step.sync(() => { | ||
const dataTransfer = pasteState.get().getOrDie('Could not get dataTransfer from state'); | ||
pasteFiles(pastebin, [ | ||
createFileFromString('a.txt', 123, 'Hello world!', 'text/plain'), | ||
createFileFromString('a.html', 123, '<b>Hello world!</b>', 'text/html') | ||
]); | ||
Assert.eq('Should be expected mime type', 'text/plain', dataTransfer.items[0].type); | ||
Assert.eq('Should be expected mime type', 'file', dataTransfer.items[0].kind); | ||
const dataTransfer = pasteState.get().getOrDie('Could not get dataTransfer from state'); | ||
Assert.eq('Should be expected mime type', 'text/html', dataTransfer.items[1].type); | ||
Assert.eq('Should be expected mime type', 'string', dataTransfer.items[1].kind); | ||
}) | ||
])), | ||
assert.equal(dataTransfer.items.length, 2); | ||
await assertFileItem(dataTransfer.items[1], { type: 'text/html', name: 'a.html', data: '<b>Hello world!</b>' }); | ||
await assertFileItem(dataTransfer.items[0], { type: 'text/plain', name: 'a.txt', data: 'Hello world!' }); | ||
}); | ||
Logger.t('Cut', Chain.isolate(pastebin, ChainSequence.sequence([ | ||
cCut, | ||
Chain.op((dataTransfer: DataTransfer) => { | ||
Assert.eq('Should be extracted cut data', 'cut-data', dataTransfer.getData('text/plain')); | ||
}) | ||
]))), | ||
it('Paste using dataTransfer mutator', async () => { | ||
const pastebin = pastebinState.get().getOrDie('Could not get pastebin from state'); | ||
Logger.t('Copy', Chain.isolate(pastebin, ChainSequence.sequence([ | ||
cCopy, | ||
Chain.op((dataTransfer: DataTransfer) => { | ||
Assert.eq('Should be extracted copy data', 'copy-data', dataTransfer.getData('text/plain')); | ||
}) | ||
]))) | ||
]), () => { | ||
cutUnbinder.unbind(); | ||
copyUnbinder.unbind(); | ||
pasteUnbinder.unbind(); | ||
Remove.remove(pastebin); | ||
success(); | ||
}, failure); | ||
pasteDataTransfer(pastebin, (dataTransfer) => { | ||
dataTransfer.items.add(createFileFromString('a.txt', 123, 'Hello world!', 'text/plain')); | ||
dataTransfer.items.add('<b>Hello world!</b>', 'text/html'); | ||
}); | ||
const dataTransfer = pasteState.get().getOrDie('Could not get dataTransfer from state'); | ||
assert.equal(dataTransfer.items.length, 2); | ||
await assertFileItem(dataTransfer.items[0], { type: 'text/plain', name: 'a.txt', data: 'Hello world!' }); | ||
await assertStringItem(dataTransfer.items[1], { type: 'text/html', data: '<b>Hello world!</b>' }); | ||
}); | ||
it('Cut', async () => { | ||
const pastebin = pastebinState.get().getOrDie('Could not get pastebin from state'); | ||
const dataTransfer = cut(pastebin); | ||
assert.equal(dataTransfer.items.length, 1); | ||
await assertStringItem(dataTransfer.items[0], { type: 'text/plain', data: 'cut-data' }); | ||
}); | ||
it('Copy', async () => { | ||
const pastebin = pastebinState.get().getOrDie('Could not get pastebin from state'); | ||
const dataTransfer = copy(pastebin); | ||
assert.equal(dataTransfer.items.length, 1); | ||
await assertStringItem(dataTransfer.items[0], { type: 'text/plain', data: 'copy-data' }); | ||
}); | ||
it('PasteUrlItems as strings', async () => { | ||
const pastebin = pastebinState.get().getOrDie('Could not get pastebin from state'); | ||
await pPasteUrlItems(pastebin, [ | ||
{ kind: 'string', url: 'project/@ephox/agar/src/test/resources/clipboard.html' }, | ||
{ kind: 'string', url: 'project/@ephox/agar/src/test/resources/clipboard.txt' }, | ||
]); | ||
const dataTransfer = pasteState.get().getOrDie('Could not get dataTransfer from state'); | ||
assert.equal(dataTransfer.items.length, 2); | ||
assertStringItem(dataTransfer.items[0], { type: 'text/html', data: '<!DOCTYPE html>\n<html>\n<body>\n<p>Hello world</p>\n</body>\n</html>\n' }); | ||
assertStringItem(dataTransfer.items[1], { type: 'text/plain', data: 'Hello world\n' }); | ||
}); | ||
it('PasteUrlItems as files', async () => { | ||
const pastebin = pastebinState.get().getOrDie('Could not get pastebin from state'); | ||
await pPasteUrlItems(pastebin, [ | ||
{ kind: 'file', url: 'project/@ephox/agar/src/test/resources/clipboard.html' }, | ||
{ kind: 'file', url: 'project/@ephox/agar/src/test/resources/clipboard.txt' }, | ||
]); | ||
const dataTransfer = pasteState.get().getOrDie('Could not get dataTransfer from state'); | ||
assert.equal(dataTransfer.items.length, 2); | ||
await assertFileItem(dataTransfer.items[0], { type: 'text/html', name: 'clipboard.html', data: '<!DOCTYPE html>\n<html>\n<body>\n<p>Hello world</p>\n</body>\n</html>\n' }); | ||
await assertFileItem(dataTransfer.items[1], { type: 'text/plain', name: 'clipboard.txt', data: 'Hello world\n' }); | ||
}); | ||
}); |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
No v1
QualityPackage is not semver >=1. This means it is not stable and does not support ^ ranges.
Found 1 instance in 1 package
1419995
588
17964
2