تجاوز العوائق باستخدام واجهة برمجة التطبيقات DataTransfer API

تمكين المستخدم من مشاركة البيانات خارج نافذة المتصفح.

ربما سمعت عن Data Transfer API، التي تشكّل جزءًا من واجهة برمجة تطبيقات HTML5 السحب والإفلات وأحداث الحافظة. يمكن استخدامها لنقل البيانات بين أهداف المصدر والمستلم.

التوافق مع المتصفح

  • 3
  • 12
  • 3.5
  • 4

المصدر

غالبًا ما يتم استخدام تفاعلات السحب والإفلات والنسخ للتفاعلات داخل الصفحة لنقل نص بسيط من (أ) إلى (ب). ولكن ما يتم تجاهله غالبًا هو القدرة على استخدام هذه التفاعلات نفسها لتجاوز نافذة المتصفح.

يمكن لكل من تفاعلات السحب والإفلات المضمنة في المتصفح وتفاعلات النسخ واللصق في المتصفح التواصل مع التطبيقات الأخرى أو الويب أو غير ذلك، ولا تكون مرتبطة بأي أصل. تتيح واجهة برمجة التطبيقات عدة إدخالات للبيانات ذات سلوكيات مختلفة استنادًا إلى المكان الذي يتم نقل البيانات إليه. يمكن لتطبيق الويب إرسال البيانات المنقولة واستلامها عند الاستماع إلى الأحداث الواردة.

يمكن لهذه الإمكانية أن تغير الطريقة التي نفكر بها بشأن المشاركة وإمكانية التشغيل التفاعلي في تطبيقات الويب على أجهزة سطح المكتب. لم يعد نقل البيانات بين التطبيقات بحاجة إلى الاعتماد على عمليات الدمج مترابطة بإحكام بعد الآن. بدلاً من ذلك، يمكنك منح المستخدمين التحكم الكامل في نقل البيانات إلى أي مكان يريدونه.

مثال على التفاعلات التي يمكن إجراؤها باستخدام Data Transfer API (لا يتضمّن الفيديو صوتًا).

نقل البيانات

للبدء، عليك تنفيذ طريقة السحب والإفلات أو النسخ واللصق. توضح الأمثلة أدناه تفاعلات السحب والإفلات، لكن عملية النسخ واللصق متشابهة. إذا لم تكن معتادًا على استخدام واجهة برمجة التطبيقات للسحب والإفلات، فهناك مقالة رائعة تشرح لك طريقة السحب والإفلات في HTML5، والتي توضح التفاصيل الدقيقة والتفصيلية.

من خلال توفير البيانات المرتبطة بنوع MIME، يمكنك التفاعل بحرية مع التطبيقات الخارجية. تستجيب معظم محررات ومحررات النصوص والمتصفحات WYSIWYG لأنواع MIME "الأساسية" المستخدمة في المثال أدناه.

document.querySelector('#dragSource')
.addEventListener('dragstart', (event) => {
  event.dataTransfer.setData('text/plain', 'Foo bar');
  event.dataTransfer.setData('text/html', '<h1>Foo bar</h1>');
  event.dataTransfer.setData('text/uri-list', 'https://example.com');
});

لاحِظ السمة event.dataTransfer. ويؤدي ذلك إلى عرض مثيل DataTransfer. كما سترى، يتم عرض هذا الكائن أحيانًا بواسطة خصائص ذات أسماء أخرى.

إنّ عملية استلام نقل البيانات لا تختلف تقريبًا عن عملية تقديمها. الاستماع إلى أحداث الاستلام (drop أو paste) وقراءة المفاتيح عند سحب عنصر، لا يمكن للمتصفّح الوصول إلا إلى مفاتيح type للبيانات. لا يمكن الوصول إلى البيانات نفسها إلا بعد الانخفاض.

document.querySelector('#dropTarget')
.addEventListener('dragover', (event) => {
  console.log(event.dataTransfer.types);
  // Without this, the drop event won't fire.
  event.preventDefault();
});

document.querySelector('#dropTarget')
.addEventListener('drop', (event) => {
  // Log all the transferred data items to the console.
  for (let type of event.dataTransfer.types) {
    console.log({ type, data: event.dataTransfer.getData(type) });
  }
  event.preventDefault();
});

يتم دعم ثلاثة أنواع MIME على نطاق واسع عبر التطبيقات:

  • text/html: يعرض حمولة HTML في عناصر contentEditable وأدوات تحرير النصوص المنسّقة (WYSIWYG) مثل "مستندات Google" وMicrosoft Word وغير ذلك.
  • text/plain: تضبط قيمة عناصر الإدخال ومحتوى أدوات تحرير الرموز والقيمة الاحتياطية من text/html.
  • text/uri-list: للانتقال إلى عنوان URL عند إفلاته على شريط عنوان URL أو صفحة المتصفّح. سيتم إنشاء اختصار لعنوان URL عند إفلاته في دليل أو على سطح المكتب.

الاستخدام الواسع النطاق لـ text/html من قبل محرري WYSIWYG يجعلها مفيدة للغاية. كما هو الحال في مستندات HTML، يمكنك تضمين الموارد باستخدام عناوين URL للبيانات أو عناوين URL المتاحة للجميع. ويساعد هذا الإجراء بشكل جيد في تصدير العناصر المرئية (على سبيل المثال من لوحة رسم) إلى أدوات التحرير مثل "مستندات Google".

const redPixel = 'data:image/gif;base64,R0lGODdhAQABAPAAAP8AAAAAACwAAAAAAQABAAACAkQBADs=';
const html = '<img src="' + redPixel + '" width="100" height="100" alt="" />';
event.dataTransfer.setData('text/html', html);

النقل باستخدام النسخ واللصق

في ما يلي كيفية استخدام واجهة برمجة التطبيقات Data Transfer API مع تفاعلات النسخ واللصق. يُرجى العلم أنّه يتم عرض الكائن DataTransfer من خلال سمة تُسمى clipboardData لأحداث الحافظة.

// Listen to copy-paste events on the document.
document.addEventListener('copy', (event) => {
  const copySource = document.querySelector('#copySource');
  // Only copy when the `activeElement` (i.e., focused element) is,
  // or is within, the `copySource` element.
  if (copySource.contains(document.activeElement)) {
    event.clipboardData.setData('text/plain', 'Foo bar');
    event.preventDefault();
  }
});

document.addEventListener('paste', (event) => {
  const pasteTarget = document.querySelector('#pasteTarget');
  if (pasteTarget.contains(document.activeElement)) {
    const data = event.clipboardData.getData('text/plain');
    console.log(data);
  }
});

تنسيقات البيانات المخصّصة

لا يقتصر دورك على أنواع MIME الأساسية، ولكن يمكنك استخدام أي مفتاح لتحديد البيانات المنقولة. ويمكن أن يكون هذا مفيدًا للتفاعلات عبر المتصفحات داخل تطبيقك. كما هو موضّح أدناه، يمكنك نقل بيانات أكثر تعقيدًا باستخدام الدالتَين JSON.stringify() وJSON.parse().

document.querySelector('#dragSource')
.addEventListener('dragstart', (event) => {
  const data = { foo: 'bar' };
  event.dataTransfer.setData('my-custom-type', JSON.stringify(data));
});

document.querySelector('#dropTarget')
.addEventListener('dragover', (event) => {
  // Only allow dropping when our custom data is available.
  if (event.dataTransfer.types.includes('my-custom-type')) {
    event.preventDefault();
  }
});

document.querySelector('#dropTarget')
.addEventListener('drop', (event) => {
  if (event.dataTransfer.types.includes('my-custom-type')) {
    event.preventDefault();
    const dataString = event.dataTransfer.getData('my-custom-type');
    const data = JSON.parse(dataString);
    console.log(data);
  }
});

الاتصال بالويب

على الرغم من أنّ التنسيقات المخصّصة رائعة للتواصل بين التطبيقات التي يمكنك التحكّم فيها، إلا أنّها تحدّ من المستخدم عند نقل البيانات إلى التطبيقات التي لا تستخدم التنسيق الخاص بك. إذا كنت ترغب في الاتصال بتطبيقات تابعة لجهات خارجية عبر الويب، فتحتاج إلى تنسيق بيانات عالمي.

ويُعدّ معيار JSON-LD (البيانات المرتبطة) مناسبًا لهذا المعيار. وهو خفيف وسهل القراءة منه والكتابة إليه في JavaScript. يحتوي Schema.org على العديد من الأنواع المحددة مسبقًا التي يمكن استخدامها، وتعريفات المخططات المخصصة هي خيار متاح أيضًا.

const data = {
  '@context': 'https://schema.org',
  '@type': 'ImageObject',
  contentLocation: 'Venice, Italy',
  contentUrl: 'venice.jpg',
  datePublished: '2010-08-08',
  description: 'I took this picture during our honey moon.',
  name: 'Canal in Venice',
};
event.dataTransfer.setData('application/ld+json', JSON.stringify(data));

عند استخدام أنواع Schema.org، يمكنك البدء بالنوع العام Thing، أو استخدام اسم أقرب إلى حالة الاستخدام مثل Event أو Person أو MediaObject أو Place أو حتى أنواع محدّدة للغاية مثل MedicalEntity عند الحاجة. عند استخدام TypeScript، يمكنك استخدام تعريفات الواجهة من تعريفات الأنواع schema-dts.

من خلال نقل بيانات JSON-LD واستلامها، يتم دعم شبكة ويب أكثر انفتاحًا وترابطًا. باستخدام التطبيقات التي تتحدث اللغة نفسها، يمكنك إنشاء عمليات دمج عميقة مع التطبيقات الخارجية. ليست هناك حاجة إلى عمليات دمج معقّدة لواجهة برمجة التطبيقات، فجميع المعلومات المطلوبة يتم تضمينها في البيانات المنقولة.

فكّر في جميع إمكانيات نقل البيانات بين أي تطبيق (ويب) بدون قيود: مشاركة الأحداث من التقويم إلى تطبيق المهام المفضل لديك، وإرفاق الملفات الافتراضية بالبريد الإلكتروني، ومشاركة جهات الاتصال. سيكون ذلك رائعًا، أليس كذلك؟ هذه هي الخطوات التي تبدأ بها. 🙌

المخاوف والمشاكل الطبية

على الرغم من توفُّر واجهة برمجة التطبيقات Data Transfer API اليوم، هناك بعض الأمور التي يجب التنبّه إليها قبل الدمج.

توافُق المتصفح

تدعم جميع متصفحات سطح المكتب بشكل كبير الطريقة الموضحة أعلاه، على الرغم من أن الأجهزة المحمولة لا تدعمها. وقد تم اختبار هذه التقنية على جميع المتصفحات الرئيسية (Chrome وEdge وFirefox وSafari) وأنظمة التشغيل (Android وChromeOS وiOS وmacOS وUbuntu Linux وWindows)، ولكن للأسف لم ينجح Android وiOS في الاختبار. وبينما تستمر المتصفحات في تطويرها، تقتصر هذه التقنية في الوقت الحالي على المتصفحات المتوافقة مع أجهزة الكمبيوتر المكتبي فقط.

قابلية العثور على المحتوى

يعتبر السحب والإفلات والنسخ واللصق تفاعلات على مستوى النظام عند العمل على كمبيوتر مكتبي، مع إعادة الجذور إلى واجهات المستخدم الرسومية الأولى منذ أكثر من 40 عامًا. فكر في عدد المرات التي استخدمت فيها هذه التفاعلات لتنظيم الملفات. هذه ليست شائعة جدًا على الويب بعد.

ستحتاج إلى تثقيف المستخدمين بشأن هذا التفاعل الجديد، والتوصل إلى أنماط تجربة مستخدم لجعل ذلك يمكن التعرف عليه، خاصة للأشخاص الذين تقتصر تجربتهم في استخدام أجهزة الكمبيوتر حتى الآن على الأجهزة المحمولة.

تسهيل الاستخدام

السحب والإفلات ليس تفاعلاً يسهل الوصول إليه، ولكن واجهة برمجة تطبيقات Data Transfer API تعمل مع النسخ واللصق أيضًا. احرِص على الاستماع إلى الأحداث التي يتم نسخها ولصقها. لا يتطلب الأمر جهدًا إضافيًا، وسيصبح المستخدمون لديك ممتنين لك لإضافته.

الأمان والخصوصية

هناك بعض اعتبارات الأمان والخصوصية التي يجب أن تكون على دراية بها عند استخدام هذه التقنية.

  • تتوفّر بيانات الحافظة للتطبيقات الأخرى على جهاز المستخدم.
  • يمكن لتطبيقات الويب التي تسحبها الوصول إلى مفاتيح النوع، وليس البيانات. تصبح البيانات متاحة فقط عند الإفلات أو اللصق.
  • يجب التعامل مع البيانات المُستلَمة مثل أي مدخلات أخرى من المستخدمين، تعقيمها والتحقق منها قبل استخدامها.

بدء استخدام مكتبة مساعد Transmat

هل أنت متحمس لاستخدام واجهة برمجة التطبيقات Data Transfer API في تطبيقك؟ ننصحك بإلقاء نظرة على مكتبة Transmat على GitHub. تعمل هذه المكتبة المفتوحة المصدر على مواءمة اختلافات المتصفّح، وتوفير أدوات JSON-LD المساعدة، وتوفير مراقب للردّ على أحداث النقل من أجل إبراز مناطق الإفلات، كما تتيح لك دمج عمليات نقل البيانات بين عمليات السحب والإفلات الحالية.

import { Transmat, TransmatObserver, addListeners } from 'transmat';

// Send data on drag/copy.
addListeners(myElement, 'transmit', (event) => {
  const transmat = new Transmat(event);
  transmat.setData({
    'text/plain': 'Foobar',
    'application/json': { foo: 'bar' },
  });
});

// Receive data on drop/paste.
addListeners(myElement, 'receive', (event) => {
  const transmat = new Transmat(event);
  if (transmat.hasType('application/json') && transmat.accept()) {
    const data = JSON.parse(transmat.getData('application/json'));
  }
});

// Observe transfer events and highlight drop areas.
const obs = new TransmatObserver((entries) => {
  for (const entry of entries) {
    const transmat = new Transmat(entry.event);
    if (transmat.hasMimeType('application/json')) {
      entry.target.classList.toggle('drag-over', entry.isTarget);
      entry.target.classList.toggle('drag-active', entry.isActive);
    }
  }
});
obs.observe(myElement);

شكر وتقدير

صورة رئيسية من تصوير لوبا إرتل على قناة UnLaunch