1
+ <!DOCTYPE html>
2
+ < html >
3
+
4
+ < head >
5
+ < title > Clipboard Performance Test</ title >
6
+ < link rel ="stylesheet " href ="./experiment_styles.css ">
7
+ </ head >
8
+
9
+ < body >
10
+ < h1 > Clipboard Performance Test</ h1 >
11
+
12
+ < div class ="controls ">
13
+ < div class ="how-to-use ">
14
+ < h3 > How to use</ h3 >
15
+ < ol >
16
+ < li > Write only text to clipboard by clicking on "Write 1MB Text Only" button.</ li >
17
+ < li > Read from clipboard by clicking on "Read from Clipboard" button.</ li >
18
+ < li > Write text and HTML to clipboard by clicking on "Write 1MB Text + 3MB HTML" button.</ li >
19
+ < li > Read from clipboard by clicking on "Read from Clipboard" button.</ li >
20
+ < li > Read selected format from clipboard by clicking on "Selected Format Read from Clipboard" button.</ li >
21
+ </ ol >
22
+
23
+ < div class ="note ">
24
+ < strong > Note:</ strong > Do not consider the results when clipboard read permission is asked for the first time.
25
+ </ div >
26
+ </ div >
27
+
28
+
29
+
30
+ < h3 > Write Data to Clipboard</ h3 >
31
+ < button id ="write-text-btn "> Write 1MB Text Only</ button >
32
+ < button id ="write-text-html-btn "> Write 1MB Text + 3MB HTML</ button >
33
+
34
+ < h3 > Read Data from Clipboard</ h3 >
35
+ < button id ="read-btn "> Read from Clipboard</ button >
36
+
37
+ < h4 > Selected Format Read</ h4 >
38
+ < div class ="format-selection ">
39
+ < label > Select formats to read:</ label > < br >
40
+ < input type ="checkbox " id ="text-plain-checkbox " value ="text/plain ">
41
+ < label for ="text-plain-checkbox "> text/plain</ label > < br >
42
+ < input type ="checkbox " id ="text-html-checkbox " value ="text/html ">
43
+ < label for ="text-html-checkbox "> text/html</ label > < br >
44
+ < input type ="checkbox " id ="image-png-checkbox " value ="image/png ">
45
+ < label for ="image-png-checkbox "> image/png</ label > < br >
46
+
47
+ </ div >
48
+ < button id ="selected-format-read-btn "> Selected Format Read from Clipboard</ button >
49
+
50
+ < button id ="clear-results-btn "> Clear Results</ button >
51
+ </ div >
52
+
53
+ < table class ="results-table " id ="results-table ">
54
+ < thead >
55
+ < tr >
56
+ < th > #</ th >
57
+ < th > Time</ th >
58
+ < th > Clipboard Read Type</ th >
59
+ < th > Read Time (ms)</ th >
60
+ </ tr >
61
+ </ thead >
62
+ < tbody id ="results-body ">
63
+ <!-- Results will be added here -->
64
+ </ tbody >
65
+ </ table >
66
+
67
+ < div class ="log " id ="log "> </ div >
68
+
69
+ < script >
70
+ function log ( message , type = 'info' ) {
71
+ const logElement = document . getElementById ( 'log' ) ;
72
+ const timestamp = new Date ( ) . toLocaleTimeString ( ) ;
73
+ const entry = document . createElement ( 'div' ) ;
74
+ entry . className = type ;
75
+ entry . innerHTML = `[${ timestamp } ] ${ message } ` ;
76
+ logElement . appendChild ( entry ) ;
77
+ logElement . scrollTop = logElement . scrollHeight ;
78
+ }
79
+
80
+ // Generates data of specified size in MB
81
+ function generateDataOfSize ( sizeInMB ) {
82
+ const bytesPerMB = 1024 * 1024 ;
83
+ const targetBytes = sizeInMB * bytesPerMB ;
84
+
85
+ log ( `Generating ${ sizeInMB } MB of data...` ) ;
86
+
87
+ // Each character in JavaScript is 2 bytes (UTF-16)
88
+ const totalChars = targetBytes / 2 ;
89
+ const result = 'A' . repeat ( totalChars ) ;
90
+
91
+ log ( `Data generated: ${ ( result . length * 2 / bytesPerMB ) . toFixed ( 2 ) } MB` , "success" ) ;
92
+ return result ;
93
+ }
94
+
95
+ // Writes text-only data to clipboard
96
+ async function writeTextOnly ( ) {
97
+ try {
98
+ log ( "Writing 1MB text data to clipboard..." ) ;
99
+ const textData = generateDataOfSize ( 1 ) ;
100
+
101
+ const clipboardItems = {
102
+ 'text/plain' : new Blob ( [ textData ] , { type : 'text/plain' } )
103
+ } ;
104
+
105
+ await navigator . clipboard . write ( [ new ClipboardItem ( clipboardItems ) ] ) ;
106
+ log ( "Text data written successfully" , "success" ) ;
107
+
108
+ } catch ( error ) {
109
+ log ( `Error writing text data: ${ error . message } ` , "error" ) ;
110
+ }
111
+ }
112
+
113
+ // Writes text and HTML data to clipboard
114
+ async function writeTextAndHTMLData ( ) {
115
+ try {
116
+ log ( "Writing 1MB text + 3MB HTML data to clipboard..." ) ;
117
+ const textData = generateDataOfSize ( 1 ) ;
118
+ const htmlData = `<html><body><pre>${ generateDataOfSize ( 3 ) } </pre></body></html>` ;
119
+
120
+ const clipboardItems = {
121
+ 'text/plain' : new Blob ( [ textData ] , { type : 'text/plain' } ) ,
122
+ 'text/html' : new Blob ( [ htmlData ] , { type : 'text/html' } )
123
+ } ;
124
+
125
+ await navigator . clipboard . write ( [ new ClipboardItem ( clipboardItems ) ] ) ;
126
+ log ( "Text & HTML data written successfully" , "success" ) ;
127
+ } catch ( error ) {
128
+ log ( `Error writing Text & HTML data: ${ error . message } ` , "error" ) ;
129
+ }
130
+ }
131
+
132
+ // Reads text from clipboard and measure time
133
+ async function readTextFromClipboard ( ) {
134
+ const startTime = performance . now ( ) ;
135
+ try {
136
+ log ( "Reading data from clipboard..." ) ;
137
+ const clipboardData = await navigator . clipboard . read ( ) ;
138
+
139
+ const endTime = performance . now ( ) ;
140
+ const readTime = endTime - startTime ;
141
+
142
+ log ( `Read completed in ${ readTime . toFixed ( 2 ) } ms` , "success" ) ;
143
+ log ( `Available item types: [${ clipboardData [ 0 ] . types . join ( ', ' ) } ]` , "info" ) ;
144
+
145
+ // Add result to table
146
+ addResult ( `read()` , readTime ) ;
147
+
148
+ } catch ( error ) {
149
+ log ( `Error reading from clipboard: ${ error . message } ` , "error" ) ;
150
+ }
151
+ }
152
+
153
+ // Reads selected format from clipboard
154
+ async function readSelectedFormatFromClipboard ( ) {
155
+ const checkboxes = document . querySelectorAll ( '.format-selection input[type="checkbox"]:checked' ) ;
156
+ const selectedTypes = Array . from ( checkboxes ) . map ( cb => cb . value ) ;
157
+ const startTime = performance . now ( ) ;
158
+ try {
159
+ if ( selectedTypes . length === 0 ) {
160
+ log ( "No formats selected. Reading all formats..." ) ;
161
+ } else {
162
+ log ( `Reading selected formats from clipboard: [${ selectedTypes . join ( ', ' ) } ] ...` ) ;
163
+ }
164
+ const clipboardData = await navigator . clipboard . read ( { types : selectedTypes } ) ;
165
+ const endTime = performance . now ( ) ;
166
+
167
+ const readTime = endTime - startTime ;
168
+ log ( `Selected formats read completed in ${ readTime . toFixed ( 2 ) } ms for [${ selectedTypes . join ( ', ' ) } ]` , "success" ) ;
169
+ const item = clipboardData [ 0 ] ;
170
+ log ( `Available item types: [${ item . types . join ( ', ' ) } ]` , "info" ) ;
171
+ for ( const type of selectedTypes ) {
172
+ item . getType ( type ) . then ( blob => {
173
+ log ( `getType(${ type } ) success` , "success" ) ;
174
+ } ) . catch ( err => {
175
+ log ( `getType(${ type } ) failed: ${ err . message } ` , "error" ) ;
176
+ } ) ;
177
+ }
178
+
179
+
180
+ addResult ( `read( { types: [ ${ selectedTypes . join ( ', ' ) } ] } )` , readTime ) ;
181
+
182
+ } catch ( error ) {
183
+ log ( `Error reading selected format from clipboard: ${ error . message } ` , "error" ) ;
184
+ }
185
+ }
186
+
187
+ let resultNumber = 1 ;
188
+ // Adds result to the table
189
+ function addResult ( readType , readTime ) {
190
+ const tableBody = document . getElementById ( 'results-body' ) ;
191
+ const row = document . createElement ( 'tr' ) ;
192
+ const timestamp = new Date ( ) . toLocaleTimeString ( ) ;
193
+
194
+ row . innerHTML = `
195
+ <td>${ resultNumber ++ } </td>
196
+ <td>${ timestamp } </td>
197
+ <td>${ readType } </td>
198
+ <td>${ readTime . toFixed ( 2 ) } </td>
199
+ ` ;
200
+
201
+ tableBody . appendChild ( row ) ;
202
+ }
203
+
204
+ function clearResults ( ) {
205
+ document . getElementById ( 'results-body' ) . innerHTML = '' ;
206
+ resultNumber = 1 ;
207
+ log ( "Results table cleared" , "info" ) ;
208
+ }
209
+
210
+ document . getElementById ( 'write-text-btn' )
211
+ . addEventListener ( 'click' , writeTextOnly ) ;
212
+ document . getElementById ( 'write-text-html-btn' )
213
+ . addEventListener ( 'click' , writeTextAndHTMLData ) ;
214
+ document . getElementById ( 'read-btn' )
215
+ . addEventListener ( 'click' , readTextFromClipboard ) ;
216
+ document . getElementById ( 'selected-format-read-btn' )
217
+ . addEventListener ( 'click' , readSelectedFormatFromClipboard ) ;
218
+ document . getElementById ( 'clear-results-btn' )
219
+ . addEventListener ( 'click' , clearResults ) ;
220
+
221
+ // Initialize
222
+ log ( "Click 'Write 1MB Text Only' or 'Write 1MB Text + 3MB HTML' to start testing" ) ;
223
+ log ( "Or click 'Read from Clipboard' to test reading existing clipboard data" ) ;
224
+ </ script >
225
+ </ body >
226
+
227
+ </ html >
0 commit comments