הסרת מחסומים באמצעות 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 ייווצר בספרייה או בשולחן העבודה.

השימוש הנרחב של 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 למילוי נתונים עדיין לא נפוץ באינטרנט.

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

נגישות

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

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

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

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

תחילת העבודה עם ספריית העזרה של 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 במשחק Unbounce.