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

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

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

תמיכה בדפדפנים

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

מקור

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

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

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

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

העברת נתונים

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

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

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

חששות

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

תאימות דפדפן

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

יכולת גילוי

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

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

נגישות

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

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

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

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

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

רוצים להשתמש ב-DataTransfer 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);

תודות

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