Skip to content

Commit 9475b72

Browse files
Selective clipboard format read explainer document (#1076)
* Added explainer doc * Update selective-clipboard-read-formats-explainer.md.md * Update selective-clipboard-read-formats-explainer.md.md * Update selective-clipboard-read-formats-explainer.md.md * Update selective-clipboard-read-formats-explainer.md.md * Update selective-clipboard-read-formats-explainer.md.md * Update selective-clipboard-read-formats-explainer.md.md * Update selective-clipboard-read-formats-explainer.md.md * update directory structure * remove unused * fix typo * fix link * Update explainer.md Modified goals section as recommended * Update explainer.md Added IDL to Appendix * update TOC * Update explainer.md Incorporated review comments * address feedback * Update explainer.md * Update explainer.md Incorporated the review comments * update table of content * Update explainer.md * address feedback * update profile * Update explainer.md Review comment incorporated --------- Co-authored-by: Ashish Kumar <[email protected]> Co-authored-by: Ashish Kumar <[email protected]>
1 parent 2567218 commit 9475b72

File tree

5 files changed

+568
-0
lines changed

5 files changed

+568
-0
lines changed
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
---
2+
name: Selective Clipboard Format Read
3+
about: new issue
4+
title: "[Selective Clipboard Format Read] <TITLE HERE>"
5+
labels: SelectiveClipboardFormatRead
6+
assignees: ragoulik
7+
8+
---
9+
10+
Lines changed: 227 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,227 @@
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>
Lines changed: 106 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,106 @@
1+
body {
2+
font-family: Arial, sans-serif;
3+
max-width: 800px;
4+
margin: 0 auto;
5+
padding: 20px;
6+
}
7+
8+
.controls {
9+
margin-bottom: 20px;
10+
padding: 20px;
11+
border: 1px solid #ddd;
12+
background-color: #f5f5f5;
13+
border-radius: 5px;
14+
}
15+
16+
button {
17+
margin: 10px 5px;
18+
padding: 10px 20px;
19+
font-size: 16px;
20+
background-color: #007cba;
21+
color: white;
22+
border: none;
23+
border-radius: 5px;
24+
cursor: pointer;
25+
}
26+
27+
button:hover {
28+
background-color: #005a87;
29+
}
30+
31+
.results-table {
32+
width: 100%;
33+
border-collapse: collapse;
34+
margin-top: 20px;
35+
}
36+
37+
.results-table th,
38+
.results-table td {
39+
border: 1px solid #ddd;
40+
padding: 10px;
41+
text-align: left;
42+
}
43+
44+
.results-table th {
45+
background-color: #f2f2f2;
46+
font-weight: bold;
47+
}
48+
49+
.results-table tr:nth-child(even) {
50+
background-color: #f9f9f9;
51+
}
52+
53+
.log {
54+
margin-top: 20px;
55+
padding: 10px;
56+
border: 1px solid #ccc;
57+
background-color: #f9f9f9;
58+
font-family: monospace;
59+
height: 200px;
60+
overflow-y: auto;
61+
}
62+
63+
.success {
64+
color: green;
65+
}
66+
67+
.error {
68+
color: red;
69+
}
70+
71+
.info {
72+
color: blue;
73+
}
74+
75+
.how-to-use {
76+
background-color: #e8f4f8;
77+
border-left: 4px solid #007cba;
78+
padding: 15px 20px;
79+
margin-bottom: 20px;
80+
border-radius: 5px;
81+
}
82+
83+
.how-to-use h3 {
84+
margin-top: 0;
85+
color: #005a87;
86+
font-size: 18px;
87+
}
88+
89+
.how-to-use ol {
90+
padding-left: 20px;
91+
line-height: 1.6;
92+
}
93+
94+
.how-to-use li {
95+
margin-bottom: 8px;
96+
color: #333;
97+
}
98+
99+
.how-to-use .note {
100+
background-color: #fff3cd;
101+
border: 1px solid #ffeaa7;
102+
border-radius: 4px;
103+
padding: 10px;
104+
margin-top: 15px;
105+
font-size: 14px;
106+
}

0 commit comments

Comments
 (0)