टेक्स्ट और इमेज के लिए, क्लिपबोर्ड का सुरक्षित और बिना ब्लॉक किया गया ऐक्सेस
सिस्टम क्लिपबोर्ड तक पहुंचने का पारंपरिक तरीका
document.execCommand()
क्लिपबोर्ड इंटरैक्शन के लिए. हालांकि, कटिंग का यह तरीका काफ़ी इस्तेमाल होता है, लेकिन
चिपकाने के लिए शुल्क लग गया: क्लिपबोर्ड का ऐक्सेस सिंक्रोनस था और उस पर सिर्फ़
और DOM पर लिखें.
टेक्स्ट के छोटे हिस्सों के लिए, यह ठीक है. हालांकि, कई मामलों में क्लिपबोर्ड पर टेक्स्ट ट्रांसफ़र करने के लिए पेज को ब्लॉक करना, खराब अनुभव देता है. सैनिटाइज़ेशन में समय लगता है या
कॉन्टेंट को सुरक्षित तरीके से चिपकाने से पहले, इमेज को डिकोड करने की ज़रूरत पड़ सकती है. ब्राउज़र
चिपकाए गए दस्तावेज़ से लिंक किए गए संसाधनों को लोड या इनलाइन करने की ज़रूरत पड़ सकती है. यह होगा
डिस्क या नेटवर्क पर इंतज़ार करते समय पेज को ब्लॉक करें. अब कल्पना करें कि अनुमतियों को मिक्स में जोड़ने पर, ब्राउज़र को क्लिपबोर्ड का ऐक्सेस मांगते समय पेज को ब्लॉक करना पड़े. साथ ही, वे अनुमतियां जो अपने-आप लागू होती हैं
क्लिपबोर्ड इंटरैक्शन के लिए document.execCommand()
में बदलाव किए जाते हैं और ये अलग-अलग होते हैं
ब्राउज़र के बीच सेट कर सकते हैं.
Async Clipboard API, इन समस्याओं को ठीक करता है. यह अनुमतियों का ऐसा मॉडल उपलब्ध कराता है जो पेज को ब्लॉक नहीं करता. Async Clipboard API, ज़्यादातर ब्राउज़र पर टेक्स्ट और इमेज को मैनेज करने के लिए ही उपलब्ध है. हालांकि, इसकी सुविधा अलग-अलग ब्राउज़र पर अलग-अलग होती है. नीचे दिए गए हर सेक्शन के लिए, ब्राउज़र के साथ काम करने की खास जानकारी को ध्यान से पढ़ें.
कॉपी करें: क्लिपबोर्ड पर डेटा लिखना
writeText()
टेक्स्ट को क्लिपबोर्ड पर कॉपी करने के लिए, writeText()
बोलें. क्योंकि यह एपीआई
तो writeText()
फ़ंक्शन ऐसा प्रॉमिस लौटाता है जो समाधान करता है या
इस आधार पर अस्वीकार करता है कि पास किया गया टेक्स्ट कॉपी हुआ है या नहीं:
async function copyPageUrl() {
try {
await navigator.clipboard.writeText(location.href);
console.log('Page URL copied to clipboard');
} catch (err) {
console.error('Failed to copy: ', err);
}
}
write()
असल में, writeText()
, सामान्य write()
के लिए एक आसान तरीका है. इसकी मदद से, इमेज को क्लिपबोर्ड पर कॉपी भी किया जा सकता है. writeText()
की तरह ही, यह भी एसिंक्रोनस है और एक प्रॉमिस दिखाता है.
क्लिपबोर्ड पर एक चित्र लिखने के लिए, आपको चित्र के रूप में
blob
. ऐसा करने का एक तरीका यह है कि fetch()
का इस्तेमाल करके, सर्वर से इमेज का अनुरोध करें. इसके बाद, रिस्पॉन्स पर blob()
को कॉल करें.
कई वजहों से, सर्वर से इमेज का अनुरोध करना सही या मुमकिन नहीं हो सकता. अच्छी बात यह है कि आप इमेज को कैनवस पर भी बना सकते हैं और
कैनवस को कॉल करें'
toBlob()
तरीका.
इसके बाद, write()
में पैरामीटर के तौर पर ClipboardItem
ऑब्जेक्ट के कलेक्शन को पास करें
तरीका. फ़िलहाल, एक बार में सिर्फ़ एक इमेज पास की जा सकती है. हालांकि, हमें उम्मीद है कि आने वाले समय में हम एक से ज़्यादा इमेज के लिए भी यह सुविधा जोड़ पाएंगे. ClipboardItem
एक ऑब्जेक्ट लेता है
कुंजी के रूप में इमेज के एमआईएमई टाइप और वैल्यू के तौर पर ब्लॉब. BLOB के लिए
fetch()
या canvas.toBlob()
, blob.type
प्रॉपर्टी से मिले ऑब्जेक्ट
इसमें इमेज के लिए सही MIME टाइप अपने-आप शामिल हो जाता है.
try {
const imgURL = '/images/generic/file.png';
const data = await fetch(imgURL);
const blob = await data.blob();
await navigator.clipboard.write([
new ClipboardItem({
// The key is determined dynamically based on the blob's type.
[blob.type]: blob
})
]);
console.log('Image copied.');
} catch (err) {
console.error(err.name, err.message);
}
इसके अलावा, ClipboardItem
ऑब्जेक्ट के लिए एक प्रॉमिस लिखा जा सकता है.
इस पैटर्न के लिए, आपको डेटा का MIME टाइप पहले से पता होना चाहिए.
try {
const imgURL = '/images/generic/file.png';
await navigator.clipboard.write([
new ClipboardItem({
// Set the key beforehand and write a promise as the value.
'image/png': fetch(imgURL).then(response => response.blob()),
})
]);
console.log('Image copied.');
} catch (err) {
console.error(err.name, err.message);
}
कॉपी इवेंट
ऐसे मामले में जब कोई उपयोगकर्ता क्लिपबोर्ड कॉपी शुरू करता है
और preventDefault()
को कॉल नहीं करता
copy
इवेंट
में clipboardData
प्रॉपर्टी शामिल है, जिसके आइटम पहले से ही सही फ़ॉर्मैट में हैं.
अगर आपको अपना लॉजिक लागू करना है, तो preventDefault()
को कॉल करना होगा
डिफ़ॉल्ट व्यवहार को आपके खुद के लागू करने के पक्ष में होने से रोकता है.
इस मामले में, clipboardData
खाली होगा.
टेक्स्ट और इमेज वाले पेज पर, जब उपयोगकर्ता 'सभी चुनें' को चुनता है और क्लिपबोर्ड पर कॉपी करने की प्रोसेस शुरू करता है, तो आपके कस्टम समाधान को टेक्स्ट को खारिज करना चाहिए और सिर्फ़ इमेज को कॉपी करना चाहिए. ऐसा करने के लिए, नीचे दिए गए कोड सैंपल में दिखाए गए तरीके का इस्तेमाल करें.
इस उदाहरण में, क्लिपबोर्ड एपीआई के काम न करने पर, पुराने एपीआई पर स्विच करने का तरीका नहीं बताया गया है.
<!-- The image we want on the clipboard. -->
<img src="kitten.webp" alt="Cute kitten.">
<!-- Some text we're not interested in. -->
<p>Lorem ipsum</p>
document.addEventListener("copy", async (e) => {
// Prevent the default behavior.
e.preventDefault();
try {
// Prepare an array for the clipboard items.
let clipboardItems = [];
// Assume `blob` is the blob representation of `kitten.webp`.
clipboardItems.push(
new ClipboardItem({
[blob.type]: blob,
})
);
await navigator.clipboard.write(clipboardItems);
console.log("Image copied, text ignored.");
} catch (err) {
console.error(err.name, err.message);
}
});
copy
इवेंट के लिए:
ClipboardItem
के लिए:
चिपकाएं: क्लिपबोर्ड से डेटा पढ़ा जा रहा है
readText()
क्लिपबोर्ड पर मौजूद टेक्स्ट पढ़ने के लिए, navigator.clipboard.readText()
पर कॉल करें और इंतज़ार करें
वापस किए गए प्रॉमिस के समाधान के लिए:
async function getClipboardContents() {
try {
const text = await navigator.clipboard.readText();
console.log('Pasted content: ', text);
} catch (err) {
console.error('Failed to read clipboard contents: ', err);
}
}
read()
navigator.clipboard.read()
वाला तरीका भी एसिंक्रोनस (अलग-अलग समय पर) है और यह एक प्रोमिस दिखाता है. क्लिपबोर्ड से इमेज पढ़ने के लिए, ऑब्जेक्ट की सूची पाएं और फिर उन पर बार-बार जाएं.
हर ClipboardItem
में अलग-अलग तरह के कॉन्टेंट हो सकते हैं. इसलिए, आपको for...of
लूप का फिर से इस्तेमाल करके, टाइप की सूची को दोहराना होगा. हर तरह के लिए,
पाने के लिए, getType()
तरीके को तर्क के रूप में कॉल करें
संबंधित BLOB. पहले की तरह ही, यह कोड इमेज से नहीं जुड़ा है और
काम करने के लिए अन्य फ़ाइल टाइप का इस्तेमाल करें.
async function getClipboardContents() {
try {
const clipboardItems = await navigator.clipboard.read();
for (const clipboardItem of clipboardItems) {
for (const type of clipboardItem.types) {
const blob = await clipboardItem.getType(type);
console.log(URL.createObjectURL(blob));
}
}
} catch (err) {
console.error(err.name, err.message);
}
}
चिपकाई गई फ़ाइलों के साथ काम करना
यह उपयोगकर्ताओं के लिए क्लिपबोर्ड कीबोर्ड शॉर्टकट का जैसे ctrl+c और ctrl+v. Chromium, रीड-ओनली फ़ाइलों को क्लिपबोर्ड पर दिखाता है, जैसा कि नीचे बताया गया है. यह तब ट्रिगर होता है, जब उपयोगकर्ता ऑपरेटिंग सिस्टम के डिफ़ॉल्ट चिपकाने के शॉर्टकट पर क्लिक करता है या जब उपयोगकर्ता ब्राउज़र के मेन्यू बार में बदलाव करें के बाद चिपकाएं पर क्लिक करता है. इसके लिए, प्लंबिंग कोड की ज़रूरत नहीं है.
document.addEventListener("paste", async e => {
e.preventDefault();
if (!e.clipboardData.files.length) {
return;
}
const file = e.clipboardData.files[0];
// Read the file's contents, assuming it's a text file.
// There is no way to write back to it.
console.log(await file.text());
});
चिपकाने के इवेंट
जैसा कि पहले बताया गया है, क्लिपबोर्ड एपीआई के साथ काम करने के लिए इवेंट लॉन्च करने की योजना है. हालांकि, फ़िलहाल मौजूदा paste
इवेंट का इस्तेमाल किया जा सकता है. यह नए के साथ ठीक से काम करता है
क्लिपबोर्ड टेक्स्ट पढ़ने के लिए एसिंक्रोनस तरीके. copy
इवेंट की तरह ही, ये काम न करें
preventDefault()
को कॉल करना भूल जाओ.
document.addEventListener('paste', async (e) => {
e.preventDefault();
const text = await navigator.clipboard.readText();
console.log('Pasted text: ', text);
});
एक से ज़्यादा MIME टाइप को हैंडल करना
ज़्यादातर लागू करने की सुविधाएं, एक बार काटने या कॉपी करने की कार्रवाई के लिए, क्लिपबोर्ड पर कई डेटा फ़ॉर्मैट डालती हैं. इसकी दो वजहें हैं: ऐप्लिकेशन डेवलपर के तौर पर, आपके पास उन ऐप्लिकेशन की क्षमताओं के बारे में नहीं पता जिनमें उपयोगकर्ता टेक्स्ट या इमेज कॉपी करना चाहता है, कई ऐप्लिकेशन, स्ट्रक्चर्ड डेटा को सामान्य टेक्स्ट के तौर पर चिपकाने की सुविधा देते हैं. आम तौर पर, यह उपयोगकर्ताओं को बदलाव करें मेन्यू आइटम के साथ पेश किया गया है, जैसे कि चिपकाएं और मिलान शैली या फ़ॉर्मैट किए बिना चिपकाएं.
नीचे दिए गए उदाहरण में, ऐसा करने का तरीका बताया गया है. इस उदाहरण में, इमेज डेटा पाने के लिए fetch()
का इस्तेमाल किया गया है. हालांकि, यह डेटा <canvas>
या File System Access API से भी मिल सकता है.
async function copy() {
const image = await fetch('kitten.png').then(response => response.blob());
const text = new Blob(['Cute sleeping kitten'], {type: 'text/plain'});
const item = new ClipboardItem({
'text/plain': text,
'image/png': image
});
await navigator.clipboard.write([item]);
}
सुरक्षा और अनुमतियां
क्लिपबोर्ड ऐक्सेस होने की वजह से, ब्राउज़र को सुरक्षा से जुड़ी चिंता का सामना करना पड़ता है. सही अनुमतियों के बिना, कोई पेज उपयोगकर्ता के क्लिपबोर्ड पर चुपचाप सभी तरह के नुकसान पहुंचाने वाले कॉन्टेंट को कॉपी कर सकता है. चिपकाने पर, इससे खतरनाक नतीजे मिल सकते हैं.
मान लें कि कोई वेब पेज, आपके क्लिपबोर्ड पर rm -rf /
या डिकंप्रेसन बम इमेज को चुपचाप कॉपी करता है.
वेब पेजों को क्लिपबोर्ड पर पढ़ने का ऐक्सेस देना और भी आसान है परेशानी भरा. उपयोगकर्ता, पासवर्ड और निजी जानकारी जैसी संवेदनशील जानकारी को क्लिपबोर्ड पर नियमित तौर पर कॉपी करते हैं. इसके बाद, उपयोगकर्ता की जानकारी के बिना, कोई भी पेज इस जानकारी को पढ़ सकता है.
कई नए एपीआई की तरह ही, Clipboard API सिर्फ़ उन पेजों के लिए काम करता है जो एचटीटीपीएस. गलत इस्तेमाल को रोकने के लिए, क्लिपबोर्ड को सिर्फ़ तब ऐक्सेस करने की अनुमति दी जाती है, जब कोई पेज ऐक्टिव टैब हो. चालू टैब में मौजूद पेज, अनुमति का अनुरोध किए बिना क्लिपबोर्ड में लिख सकते हैं. हालांकि, क्लिपबोर्ड से पढ़ने के लिए हमेशा अनुमति लेनी पड़ती है.
कॉपी और चिपकाने की अनुमतियां, Permissions API में जोड़ी गई हैं.
जब पेज चालू टैब होते हैं, तो उन्हें clipboard-write
अनुमति अपने-आप मिल जाती है. clipboard-read
की अनुमति का अनुरोध करना ज़रूरी है. इसके लिए, क्लिपबोर्ड से डेटा पढ़ने की कोशिश करें. नीचे दिया गया कोड बाद वाला कोड दिखाता है:
const queryOpts = { name: 'clipboard-read', allowWithoutGesture: false };
const permissionStatus = await navigator.permissions.query(queryOpts);
// Will be 'granted', 'denied' or 'prompt':
console.log(permissionStatus.state);
// Listen for changes to the permission state
permissionStatus.onchange = () => {
console.log(permissionStatus.state);
};
यह भी कंट्रोल किया जा सकता है कि कट लगाने के लिए, उपयोगकर्ता के जेस्चर की ज़रूरत है या नहीं या
allowWithoutGesture
विकल्प का इस्तेमाल करके चिपकाएं. इस वैल्यू की डिफ़ॉल्ट वैल्यू, ब्राउज़र के हिसाब से अलग-अलग होती है. इसलिए, आपको इसे हमेशा शामिल करना चाहिए.
यहां क्लिपबोर्ड एपीआई के असाइनोक्रोनस नेचर का ज़्यादा फ़ायदा मिलता है: क्लिपबोर्ड का डेटा पढ़ने या उसमें डेटा लिखने की कोशिश करने पर, अगर अनुमति पहले से नहीं दी गई है, तो उपयोगकर्ता से अनुमति मांगी जाती है. एपीआई, प्रॉमिस पर आधारित होता है. इसलिए, यह पूरी तरह से पारदर्शी होता है. अगर कोई उपयोगकर्ता क्लिपबोर्ड की अनुमति नहीं देता है, तो प्रॉमिस अस्वीकार कर दिया जाता है, ताकि पेज सही तरीके से जवाब दे सके.
ब्राउज़र, क्लिपबोर्ड को सिर्फ़ तब ऐक्सेस करने की अनुमति देते हैं, जब कोई पेज चालू टैब हो. इसलिए, आपको यहां दिए गए कुछ उदाहरणों को सीधे ब्राउज़र के कंसोल में चिपकाने पर, वे काम नहीं करेंगे. इसकी वजह यह है कि डेवलपर टूल ही चालू टैब होते हैं. यहां एक तरकीब है: टाल दें
setTimeout()
का इस्तेमाल करके क्लिपबोर्ड को ऐक्सेस करें. इसके बाद, पेज के अंदर तुरंत क्लिक करके
फ़ंक्शन को कॉल किए जाने से पहले इस पर फ़ोकस करें:
setTimeout(async () => {
const text = await navigator.clipboard.readText();
console.log(text);
}, 2000);
अनुमतियों की नीति का इंटिग्रेशन
iframe में एपीआई का इस्तेमाल करने के लिए, आपको इसे अनुमतियों से जुड़ी नीति की मदद से चालू करना होगा. इस नीति में एक ऐसा तरीका बताया गया है जिसकी मदद से, ब्राउज़र की अलग-अलग सुविधाओं और एपीआई को चुनिंदा तौर पर चालू और बंद किया जा सकता है. सीधे तौर पर, आपको इनमें से कोई एक
या clipboard-read
या clipboard-write
, दोनों का इस्तेमाल करें.
<iframe
src="index.html"
allow="clipboard-read; clipboard-write"
>
</iframe>
फ़ीचर का पता लगाना
सभी ब्राउज़र के साथ काम करने वाले Async Clipboard API का इस्तेमाल करने के लिए, navigator.clipboard
की जांच करें और पुराने तरीकों का इस्तेमाल करें. उदाहरण के लिए, अन्य ब्राउज़र को शामिल करने के लिए, चिपकाने की सुविधा को लागू करने का तरीका यहां बताया गया है.
document.addEventListener('paste', async (e) => {
e.preventDefault();
let text;
if (navigator.clipboard) {
text = await navigator.clipboard.readText();
}
else {
text = e.clipboardData.getData('text/plain');
}
console.log('Got pasted text: ', text);
});
यह पूरी कहानी नहीं है. Async Clipboard API के पहले, अलग-अलग वर्शन में
वेब ब्राउज़र में कॉपी और पेस्ट करने की अलग-अलग सुविधाएं शामिल हैं. ज़्यादातर ब्राउज़र में,
ब्राउज़र की अपनी कॉपी और पेस्ट को
document.execCommand('copy')
और document.execCommand('paste')
. अगर कॉपी किया जाने वाला टेक्स्ट, ऐसी स्ट्रिंग है जो DOM में मौजूद नहीं है, तो उसे DOM में इंजेक्ट किया जाना चाहिए और चुना जाना चाहिए:
button.addEventListener('click', (e) => {
const input = document.createElement('input');
input.style.display = 'none';
document.body.appendChild(input);
input.value = text;
input.focus();
input.select();
const result = document.execCommand('copy');
if (result === 'unsuccessful') {
console.error('Failed to copy text.');
}
input.remove();
});
डेमो
नीचे दिए गए डेमो में, एसिंक्रोनस क्लिपबोर्ड एपीआई इस्तेमाल किया जा सकता है. Glitch पर, टेक्स्ट डेमो या इमेज डेमो को रीमिक्स करके, उनका इस्तेमाल किया जा सकता है.
पहले उदाहरण में, टेक्स्ट को क्लिपबोर्ड पर ले जाने और उससे हटाने का तरीका बताया गया है.
इमेज के साथ एपीआई को आज़माने के लिए, इस डेमो का इस्तेमाल करें. याद रखें कि सिर्फ़ PNG फ़ॉर्मैट के आइकॉन इस्तेमाल किए जा सकते हैं. साथ ही, ये कुछ ही ब्राउज़र में काम करते हैं.
इसी विषय से जुड़े कुछ लिंक
आभार
Async Clipboard API को Darwin Huang और Gary Kačmarčík ने लागू किया था. डार्विन ने भी डेमो दिया. इस इवेंट के लिए, क्यारिक और गैरी कैकमर्क को एक बार फिर से धन्यवाद इस लेख के हिस्सों की समीक्षा ज़रूर करें.
Unsplash पर, मार्कस विंकलर की हीरो इमेज.