क्लिपबोर्ड का ऐक्सेस अनब्लॉक किया जा रहा है

ज़्यादा सुरक्षित, टेक्स्ट और इमेज के लिए क्लिपबोर्ड का ऐक्सेस अनब्लॉक किया गया

क्लिपबोर्ड इंटरैक्शन के लिए, सिस्टम क्लिपबोर्ड को document.execCommand() से ऐक्सेस किया जाता था. काटने और चिपकाने के इस तरीके का इस्तेमाल, ज़्यादातर ब्राउज़र पर किया जा सकता है. हालांकि, इसकी कुछ सीमाएं भी हैं: क्लिपबोर्ड का ऐक्सेस सिंक किया जाता था और सिर्फ़ डीओएम को पढ़ा और उसमें लिखा जा सकता था.

टेक्स्ट के छोटे हिस्सों के लिए, यह ठीक है. हालांकि, कई मामलों में क्लिपबोर्ड पर टेक्स्ट ट्रांसफ़र करने के लिए पेज को ब्लॉक करना, खराब अनुभव देता है. कॉन्टेंट को सुरक्षित तरीके से चिपकाने से पहले, सैनिटाइज़ेशन या इमेज डिकोड करने में समय लग सकता है. ब्राउज़र को, चिपकाए गए दस्तावेज़ से लिंक किए गए रिसॉर्स को लोड या इनलाइन करना पड़ सकता है. इससे डिस्क या नेटवर्क पर इंतज़ार करते समय पेज ब्लॉक हो जाएगा. अब कल्पना करें कि अनुमतियों को मिक्स में जोड़ने पर, ब्राउज़र को क्लिपबोर्ड का ऐक्सेस मांगते समय पेज को ब्लॉक करना पड़े. साथ ही, क्लिपबोर्ड के साथ इंटरैक्ट करने के लिए 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);
  }
}

ब्राउज़र सहायता

  • Chrome: 66.
  • Edge: 79.
  • Firefox: 63.
  • Safari: 13.1.

सोर्स

write()

असल में, writeText(), सामान्य write() के लिए एक आसान तरीका है. इसकी मदद से, इमेज को क्लिपबोर्ड पर कॉपी भी किया जा सकता है. writeText() की तरह, यह एसिंक्रोनस है और प्रॉमिस रिटर्न करता है.

किसी इमेज को क्लिपबोर्ड पर सेव करने के लिए, आपके पास इमेज के तौर पर blob होना चाहिए. ऐसा करने का एक तरीका यह है कि fetch() का इस्तेमाल करके, सर्वर से इमेज का अनुरोध करें. इसके बाद, रिस्पॉन्स पर blob() को कॉल करें.

कई वजहों से, सर्वर से इमेज का अनुरोध करना सही या मुमकिन नहीं हो सकता. हालांकि, इमेज को कैनवस पर भी बनाया जा सकता है और कैनवस के toBlob() तरीके को भी इस्तेमाल किया जा सकता है.

इसके बाद, write() के तरीके में पैरामीटर के तौर पर ClipboardItem ऑब्जेक्ट का कलेक्शन पास करें. फ़िलहाल, एक बार में सिर्फ़ एक इमेज पास की जा सकती है. हालांकि, हमें उम्मीद है कि आने वाले समय में हम एक से ज़्यादा इमेज के लिए भी यह सुविधा जोड़ पाएंगे. ClipboardItem, इमेज के MIME टाइप को कुंजी और ब्लॉब को वैल्यू के तौर पर इस्तेमाल करता है. 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);
}

ब्राउज़र के इस्तेमाल से जुड़ी सहायता

  • Chrome: 76.
  • Edge: 79.
  • Firefox: 127.
  • Safari: 13.1.

सोर्स

कॉपी इवेंट

ऐसे मामले में जहां कोई उपयोगकर्ता, क्लिपबोर्ड पर कॉपी करने की शुरुआत करता है और 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 इवेंट के लिए:

ब्राउज़र के इस्तेमाल से जुड़ी सहायता

  • Chrome: 1.
  • एज: 12.
  • Firefox: 22.
  • सफ़ारी: 3.

सोर्स

ClipboardItem के लिए:

ब्राउज़र सहायता

  • Chrome: 76.
  • Edge: 79.
  • Firefox: 127.
  • Safari: 13.1.

सोर्स

चिपकाएं: क्लिपबोर्ड से डेटा पढ़ना

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);
  }
}

ब्राउज़र के इस्तेमाल से जुड़ी सहायता

  • Chrome: 66.
  • एज: 79.
  • Firefox: 125.
  • Safari: 13.1.

सोर्स

read()

navigator.clipboard.read() वाला तरीका भी एसिंक्रोनस (अलग-अलग समय पर) है और यह एक प्रोमिस दिखाता है. क्लिपबोर्ड से इमेज पढ़ने के लिए, ऑब्जेक्ट की सूची पाएं और फिर उन पर बार-बार जाएं.ClipboardItem

हर ClipboardItem में अलग-अलग तरह के कॉन्टेंट हो सकते हैं. इसलिए, आपको for...of लूप का फिर से इस्तेमाल करके, टाइप की सूची को दोहराना होगा. हर टाइप के लिए, getType() तरीके को आर्ग्युमेंट के तौर पर मौजूदा टाइप के साथ कॉल करें, ताकि उससे जुड़ा ब्लॉब मिल सके. पहले की तरह, यह कोड इमेज से जुड़ा नहीं है. साथ ही, यह आने वाले समय में अन्य फ़ाइल टाइप के साथ भी काम करेगा.

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);
  }
}

ब्राउज़र के इस्तेमाल से जुड़ी सहायता

  • Chrome: 76.
  • Edge: 79.
  • Firefox: 127.
  • Safari: 13.1.

सोर्स

चिपकाई गई फ़ाइलों के साथ काम करना

उपयोगकर्ताओं के लिए, क्लिपबोर्ड के कीबोर्ड शॉर्टकट का इस्तेमाल करना फ़ायदेमंद होता है. जैसे, 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());
});

ब्राउज़र के इस्तेमाल से जुड़ी सहायता

  • Chrome: 3.
  • Edge: 12.
  • Firefox: 3.6.
  • Safari: 4.

सोर्स

चिपकाने के इवेंट

जैसा कि पहले बताया गया है, क्लिपबोर्ड एपीआई के साथ काम करने के लिए इवेंट लॉन्च करने की योजना है. हालांकि, फ़िलहाल मौजूदा paste इवेंट का इस्तेमाल किया जा सकता है. यह क्लिपबोर्ड पर मौजूद टेक्स्ट को पढ़ने के लिए, एक साथ काम करने वाले नए तरीकों के साथ अच्छी तरह से काम करता है. copy इवेंट की तरह ही, preventDefault() को कॉल करना न भूलें.

document.addEventListener('paste', async (e) => {
  e.preventDefault();
  const text = await navigator.clipboard.readText();
  console.log('Pasted text: ', text);
});

ब्राउज़र के इस्तेमाल से जुड़ी सहायता

  • Chrome: 1.
  • एज: 12.
  • Firefox: 22.
  • Safari: 3.

सोर्स

एक से ज़्यादा 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 के लिए अनुमति का अनुरोध.

वेब पेजों को क्लिपबोर्ड का ऐक्सेस देने से भी ज़्यादा समस्याएं आ सकती हैं. उपयोगकर्ता, पासवर्ड और निजी जानकारी जैसी संवेदनशील जानकारी को क्लिपबोर्ड पर नियमित तौर पर कॉपी करते हैं. इसके बाद, उपयोगकर्ता की जानकारी के बिना, कोई भी पेज इस जानकारी को पढ़ सकता है.

कई नए एपीआई की तरह ही, 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();
});

डेमो

नीचे दिए गए डेमो में, Async Clipboard API को आज़माया जा सकता है. Glitch पर एक्सपेरिमेंट करने के लिए, टेक्स्ट डेमो या इमेज डेमो को रीमिक्स किया जा सकता है.

पहले उदाहरण में, टेक्स्ट को क्लिपबोर्ड पर ले जाने और उससे हटाने का तरीका बताया गया है.

इमेज के साथ एपीआई को आज़माने के लिए, इस डेमो का इस्तेमाल करें. याद रखें कि सिर्फ़ PNG फ़ॉर्मैट के आइकॉन इस्तेमाल किए जा सकते हैं. साथ ही, ये कुछ ही ब्राउज़र में काम करते हैं.

स्वीकार की गई

Async Clipboard API को Darwin Huang और Gary Kačmarčík ने लागू किया था. डार्विन ने भी डेमो दिया. इस लेख के कुछ हिस्सों की समीक्षा करने के लिए, Kyarik और गैरी काचमार्चिक का धन्यवाद.

Unस्प्लैश पर मार्कस विंकलर की हीरो इमेज.