11// Clipboard is not available in jsdom
22
33import { createDataTransfer , getBlobFromDataTransferItem , readBlobText } from '..'
4+ import { getWindow } from '../misc/getWindow'
45
56// Clipboard API is only fully available in secure context or for browser extensions.
67
8+ const Window = Symbol ( 'Window reference' )
9+
710type ItemData = Record < string , Blob | string | Promise < Blob | string > >
811
912class ClipboardItemStub implements ClipboardItem {
@@ -25,13 +28,17 @@ class ClipboardItemStub implements ClipboardItem {
2528 )
2629 }
2730
28- return data instanceof Blob ? data : new Blob ( [ data ] , { type} )
31+ return data instanceof this [ Window ] . Blob
32+ ? data
33+ : new this [ Window ] . Blob ( [ data ] , { type} )
2934 }
35+
36+ [ Window ] = window
3037}
3138
3239const ClipboardStubControl = Symbol ( 'Manage ClipboardSub' )
3340
34- class ClipboardStub extends EventTarget implements Clipboard {
41+ class ClipboardStub extends window . EventTarget implements Clipboard {
3542 private items : ClipboardItem [ ] = [ ]
3643
3744 async read ( ) {
@@ -45,7 +52,9 @@ class ClipboardStub extends EventTarget implements Clipboard {
4552 ? 'text/plain'
4653 : item . types . find ( t => t . startsWith ( 'text/' ) )
4754 if ( type ) {
48- text += await item . getType ( type ) . then ( b => readBlobText ( b ) )
55+ text += await item
56+ . getType ( type )
57+ . then ( b => readBlobText ( b , this [ Window ] . FileReader ) )
4958 }
5059 }
5160 return text
@@ -56,9 +65,10 @@ class ClipboardStub extends EventTarget implements Clipboard {
5665 }
5766
5867 async writeText ( text : string ) {
59- this . items = [ createClipboardItem ( text ) ]
68+ this . items = [ createClipboardItem ( this [ Window ] , text ) ]
6069 }
6170
71+ [ Window ] = window ;
6272 [ ClipboardStubControl ] : {
6373 resetClipboardStub : ( ) => void
6474 detachClipboardStub : ( ) => void
@@ -69,22 +79,25 @@ class ClipboardStub extends EventTarget implements Clipboard {
6979// lib.dom.d.ts lists only Promise<Blob|string>
7080// https://developer.mozilla.org/en-US/docs/Web/API/ClipboardItem/ClipboardItem#syntax
7181export function createClipboardItem (
82+ window : Window & typeof globalThis ,
7283 ...blobs : Array < Blob | string >
7384) : ClipboardItem {
74- // use real ClipboardItem if available
75- // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
76- const constructor =
77- typeof ClipboardItem === 'undefined'
78- ? ClipboardItemStub
79- : /* istanbul ignore next */ ClipboardItem
80- return new constructor (
81- Object . fromEntries (
82- blobs . map ( b => [
83- typeof b === 'string' ? 'text/plain' : b . type ,
84- Promise . resolve ( b ) ,
85- ] ) ,
86- ) ,
85+ const data = Object . fromEntries (
86+ blobs . map ( b => [
87+ typeof b === 'string' ? 'text/plain' : b . type ,
88+ Promise . resolve ( b ) ,
89+ ] ) ,
8790 )
91+
92+ // use real ClipboardItem if available
93+ /* istanbul ignore else */
94+ if ( typeof window . ClipboardItem === 'undefined' ) {
95+ const item = new ClipboardItemStub ( data )
96+ item [ Window ] = window
97+ return item
98+ } else {
99+ return new window . ClipboardItem ( data )
100+ }
88101}
89102
90103export function attachClipboardStubToView ( window : Window & typeof globalThis ) {
@@ -98,9 +111,11 @@ export function attachClipboardStubToView(window: Window & typeof globalThis) {
98111 )
99112
100113 let stub = new ClipboardStub ( )
114+ stub [ Window ] = window
101115 const control = {
102116 resetClipboardStub : ( ) => {
103117 stub = new ClipboardStub ( )
118+ stub [ Window ] = window
104119 stub [ ClipboardStubControl ] = control
105120 } ,
106121 detachClipboardStub : ( ) => {
@@ -140,17 +155,21 @@ export function detachClipboardStubFromView(
140155}
141156
142157export async function readDataTransferFromClipboard ( document : Document ) {
143- const clipboard = document . defaultView ?. navigator . clipboard
158+ const window = document . defaultView
159+ const clipboard = window ?. navigator . clipboard
144160 const items = clipboard && ( await clipboard . read ( ) )
145161
146162 if ( ! items ) {
147163 throw new Error ( 'The Clipboard API is unavailable.' )
148164 }
149165
150- const dt = createDataTransfer ( )
166+ const dt = createDataTransfer ( window )
151167 for ( const item of items ) {
152168 for ( const type of item . types ) {
153- dt . setData ( type , await item . getType ( type ) . then ( b => readBlobText ( b ) ) )
169+ dt . setData (
170+ type ,
171+ await item . getType ( type ) . then ( b => readBlobText ( b , window . FileReader ) ) ,
172+ )
154173 }
155174 }
156175 return dt
@@ -160,13 +179,14 @@ export async function writeDataTransferToClipboard(
160179 document : Document ,
161180 clipboardData : DataTransfer ,
162181) {
163- const clipboard = document . defaultView ?. navigator . clipboard
182+ const window = getWindow ( document )
183+ const clipboard = window . navigator . clipboard as Clipboard | undefined
164184
165185 const items = [ ]
166186 for ( let i = 0 ; i < clipboardData . items . length ; i ++ ) {
167187 const dtItem = clipboardData . items [ i ]
168- const blob = getBlobFromDataTransferItem ( dtItem )
169- items . push ( createClipboardItem ( blob ) )
188+ const blob = getBlobFromDataTransferItem ( window , dtItem )
189+ items . push ( createClipboardItem ( window , blob ) )
170190 }
171191
172192 const written =
0 commit comments