הסרת מחסומים באמצעות DataTransfer API

הפעלת האפשרות למשתמש לשתף נתונים מחוץ לחלון הדפדפן.

יכול להיות ששמעתם על DataTransfer API, שהוא חלק מ-HTML5 Drag and Drop API ומ-Clipboard events. אפשר להשתמש בו כדי להעביר נתונים בין יעדי מקור ליעדי קבלה.

Browser Support

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

Source

אינטראקציות של גרירה ושחרור והעתקה והדבקה משמשות לעיתים קרובות לאינטראקציות בתוך דף כדי להעביר טקסט פשוט מנקודה א' לנקודה ב'. אבל מה שלעתים קרובות מתעלמים ממנו הוא היכולת להשתמש באותן אינטראקציות כדי להרחיב את הפעולות מעבר לחלון הדפדפן.

גם פעולות הגרירה וההעתקה וההדבקה המובנות בדפדפן יכולות לתקשר עם אפליקציות אחרות, באינטרנט או במקומות אחרים, והן לא קשורות למקור כלשהו. ממשק ה-API תומך בכמה רשומות נתונים עם התנהגויות שונות, בהתאם למקום שאליו הנתונים מועברים. אפליקציית האינטרנט שלכם יכולה לשלוח ולקבל את הנתונים שהועברו כשהיא מאזינה לאירועים נכנסים.

היכולת הזו יכולה לשנות את האופן שבו אנחנו חושבים על שיתוף ועל יכולת פעולה הדדית באפליקציות אינטרנט במחשב. העברת נתונים בין אפליקציות לא צריכה יותר להסתמך על שילובים עם צימוד הדוק. במקום זאת, אתם יכולים לתת למשתמשים שליטה מלאה בהעברת הנתונים לאן שהם רוצים.

דוגמה לאינטראקציות שאפשר לבצע באמצעות DataTransfer API. (הסרטון לא כולל סאונד).

העברת נתונים

כדי להתחיל, צריך להטמיע גרירה ושחרור או העתקה והדבקה. בדוגמאות שלמטה מוצגות אינטראקציות של גרירה ושחרור, אבל התהליך של העתקה והדבקה דומה. אם אתם לא מכירים את Drag and Drop API, כדאי לקרוא את המאמר המצוין explaining HTML5 Drag and Drop (הסבר על גרירה ושחרור ב-HTML5).

אם מספקים נתונים עם מפתח MIME-type, אפשר ליצור אינטראקציה חופשית עם אפליקציות חיצוניות. רוב עורכי ה-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 Docs,‏ Microsoft Word ועוד.
  • text/plain: מגדיר את הערך של רכיבי קלט, את התוכן של עורכי קוד ואת הגיבוי מ-text/html.
  • text/uri-list: מעבר לכתובת ה-URL כשגוררים אותה לסרגל כתובת ה-URL או לדף הדפדפן. כשגוררים את הקישור לספרייה או לשולחן העבודה, נוצר קיצור דרך לכתובת ה-URL.

השימוש הנרחב ב-text/html בעורכי WYSIWYG הופך אותו לשימושי מאוד. כמו במסמכי HTML, אפשר להטמיע משאבים באמצעות כתובות URL של נתונים או כתובות URL שנגישות לציבור. זה שימושי במיוחד לייצוא רכיבים חזותיים (למשל מבד ציור) לעורכים כמו Google Docs.

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

העברה באמצעות העתקה והדבקה

בהמשך מוצג שימוש ב-DataTransfer 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 (Linked Data) הוא מועמד מצוין לכך. הוא קל משקל וקל לקרוא ממנו ולכתוב בו ב-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 תעזור לכם לתמוך באינטרנט פתוח ומקושר יותר. אם האפליקציות מדברות באותה שפה, אפשר ליצור שילובים עמוקים עם אפליקציות חיצוניות. אין צורך בשילובים מורכבים של API. כל המידע שנדרש כלול בנתונים המועברים.

תחשבו על כל האפשרויות להעברת נתונים בין כל אפליקציה (אינטרנט) ללא הגבלות: שיתוף אירועים מיומן לאפליקציית המשימות המועדפת, צירוף קבצים וירטואליים לאימיילים, שיתוף אנשי קשר. זה יהיה נהדר, נכון? הכול מתחיל בכם! 🙌

חששות

ה-API של העברת נתונים זמין היום, אבל לפני שמבצעים שילוב, חשוב לשים לב לנקודות הבאות.

תאימות דפדפן

כל דפדפני המחשב תומכים בטכניקה שמתוארת למעלה, אבל מכשירים ניידים לא תומכים בה. הטכניקה נבדקה בכל הדפדפנים הנפוצים (Chrome,‏ Edge,‏ Firefox,‏ Safari) ובמערכות ההפעלה (Android,‏ ChromeOS,‏ iOS,‏ macOS,‏ Ubuntu Linux ו-Windows), אבל לצערי היא לא עברה את הבדיקה ב-Android וב-iOS. הטכניקה הזו מוגבלת כרגע לדפדפנים במחשב, אבל אנחנו ממשיכים לפתח את הדפדפנים.

יכולת גילוי

גרירה ושחרור והעתקה והדבקה הן אינטראקציות ברמת המערכת כשעובדים במחשב שולחני, עם שורשים שחוזרים ל-GUI הראשון לפני יותר מ-40 שנה. כדאי לחשוב כמה פעמים השתמשתם באינטראקציות האלה כדי לארגן קבצים. השימוש בטכנולוגיה הזו עדיין לא נפוץ באינטרנט.

תצטרכו להסביר למשתמשים על האינטראקציה החדשה הזו, ולמצוא דפוסי חוויית משתמש שיעזרו להם לזהות אותה, במיוחד אם עד עכשיו הם השתמשו רק במכשירים ניידים.

נגישות

אי אפשר להשתמש ב-API להעברת נתונים עם פעולת גרירה ושחרור, אבל אפשר להשתמש בו עם העתקה והדבקה. חשוב להאזין לאירועי העתקה והדבקה. הוספת התרגום לא דורשת הרבה עבודה נוספת, והמשתמשים שלכם יודו לכם על כך.

אבטחה ופרטיות

יש כמה שיקולי אבטחה ופרטיות שחשוב להכיר כשמשתמשים בטכניקה הזו.

  • נתונים בלוח ההעתקות זמינים לאפליקציות אחרות במכשיר של המשתמש.
  • לאפליקציות אינטרנט שגוררים מעליהן יש גישה למפתחות הסוג, לא לנתונים. הנתונים יהיו זמינים רק אחרי שגוררים או מדביקים אותם.
  • צריך להתייחס לנתונים שהתקבלו כמו לכל קלט אחר של משתמשים: לבצע סניטציה ואימות לפני השימוש.

תחילת העבודה עם ספריית העזר Transmat

רוצים להשתמש ב-DataTransfer API באפליקציה שלכם? כדאי לעיין בספריית Transmat ב-GitHub. ספריית הקוד הפתוח הזו מתאימה את ההבדלים בין הדפדפנים, מספקת כלי עזר ל-JSON-LD, מכילה רכיב Observer שמגיב לאירועי העברה כדי להדגיש אזורי שחרור, ומאפשרת לכם לשלב את פעולות העברת הנתונים בין יישומי גרירה ושיחרור קיימים.

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

תודות

תמונה ראשית (Hero) מאת Luba Ertel ב-Unsplash.