{"id":734,"date":"2010-01-10T23:52:17","date_gmt":"2010-01-11T03:52:17","guid":{"rendered":"http:\/\/www.useragentman.com\/blog\/?p=734"},"modified":"2019-01-31T13:25:26","modified_gmt":"2019-01-31T17:25:26","slug":"cross-browser-html5-drag-and-drop","status":"publish","type":"post","link":"https:\/\/www.useragentman.com\/blog\/2010\/01\/10\/cross-browser-html5-drag-and-drop\/","title":{"rendered":"Cross Browser HTML5 Drag and Drop"},"content":{"rendered":"<div class=\"importantNotes\">\n<h3>Updates:<\/h3>\n<ul>\n<li><strong>May 10, 2013:<\/strong> This article has been translated into <a href=\"http:\/\/science.webhostinggeeks.com\/HTML5-Drag-and-Drop\">Serbo-Croatian<\/a> language by Anja Skrba from <a href=\"http:\/\/webhostinggeeks.com\/\"> Webhostinggeeks.com<\/a>.<\/li>\n<li><strong>Feb 3, 2009:<\/strong> A <a href=\"http:\/\/code.google.com\/p\/chromium\/issues\/detail?id=14654\">bug in Webkit<\/a> seems to be the culprit in the permissions form example below not working correctly in Safari 4.  The code has been updated to work around this bug and the article below has been updated.  Thanks to <code>russbuelt<\/code> for pointing this out.<\/li>\n<li><strong>Feb 3, 2009:<\/strong> Apparently, an example made by Apple which I reported not working in Safari <em>does<\/em> work in Safari 4.0.4 for Mac OS X.  Thanks for Scott Straker for this information.<\/li>\n<\/div>\n<p><div id=\"attachment_538\" style=\"width: 267px\" class=\"wp-caption alignleft\"><a href=\"http:\/\/flickr.com\/photos\/svartling\/3822068125\/\"><img loading=\"lazy\" decoding=\"async\" aria-describedby=\"caption-attachment-538\" class=\"size-full wp-image-538   \" title=\"HTML5 Drag and Drop\" src=\"https:\/\/www.useragentman.com\/blog\/wp-content\/uploads\/2010\/12\/html5DragAndDrop.png\" alt=\"Remixed version of image by Svartling.\" width=\"257\" height=\"174\" \/><\/a><p id=\"caption-attachment-538\" class=\"wp-caption-text\">Image Credit: Flickr user svartling<\/p><\/div><\/p>\n<p><a href=\"http:\/\/dev.w3.org\/html5\/spec\/editing.html#dnd\">HTML5 Drag and Drop<\/a> has been talked about a lot lately, but it&#8217;s hard to find really useful information about implementing it across multiple browsers.   <a href=\"http:\/\/hacks.mozilla.org\/2009\/07\/html5-drag-and-drop\/\">Mozilla<\/a>, <a href=\"http:\/\/developer.apple.com\/Mac\/library\/documentation\/AppleApplications\/Conceptual\/SafariJSProgTopics\/Tasks\/DragAndDrop.html\">Apple<\/a> and <a href=\"http:\/\/msdn.microsoft.com\/en-us\/library\/ms537658%28VS.85%29.aspx\">Microsoft<\/a> all have pages describing how to use it, but their examples seem to work only in their particular browser (<strike><em><a href=\"http:\/\/developer.apple.com\/Mac\/library\/documentation\/AppleApplications\/Conceptual\/SafariJSProgTopics\/Tasks\/DragAndDrop.html\">Apple&#8217;s example<\/a> doesn&#8217;t even work in their own!<\/em><\/strike> <strong>Updated, Jan. 11, 2009:<\/strong> Although I have not been able to get this example working on Safari 2.0.4 and 3.1.2 for OS X and 4.0.4 for Windows, I have received word that it works on Safari 4.0.4 on OS X).  Remy Sharp&#8217;s great article <a href=\"http:\/\/html5doctor.com\/native-drag-and-drop\/\">Native Drag and Drop<\/a> was a good place for me to start \u2014 however, the examples didn&#8217;t work in Internet Explorer.  I also thoroughly enjoyed JavaScript guru <a href=\"http:\/\/www.quirksmode.org\/\">Peter-Paul Koch&#8217;s<\/a> <a href=\"http:\/\/www.quirksmode.org\/blog\/archives\/2009\/09\/the_html5_drag.html\">humorous and lengthy rant about cross-browser drag and drop headaches<\/a> where he uses creative and colourful language to describe what he thought of the standard, the browser manufacturers, and the WHAT-WG.<\/p>\n<p>When normal people see the author of the <a href=\"http:\/\/www.quirksmode.org\/compatibility.html\">Compatibility Master Tables<\/a> respond negatively to a web technology, they would probably assume it would be a good sign to stay away from it.<\/p>\n<p>However, I am not normal.  <strong>With a name like Zoltan, how could I <em>possibly<\/em> be normal?<\/strong> (and yes, <a href=\"https:\/\/www.useragentman.com\/blog\/the-infamous-zoltan-faq\/\">it <em>is<\/em> my real name<\/a>).<\/p>\n<p>So, I decided to find out for myself how bad HTML5 Drag and Drop really is. Almost immediately, I understood Koch&#8217;s reaction &#8211; the browser vendors have not implemented all the same features, and there are even a few quirks in how the features that <em>are <\/em>implemented work.  However, after doing <em>a lot<\/em> of research, <strong>I found a common denominator that works well<\/strong>, with the help of a small bit of JavaScript that smooths out the edges.  Despite the implementation flaws, <strong>Future-proof HTML5 Drag and Drop is not too hard for developers to use in their own applications.<\/strong> This article will explain how to do this step by step with many examples along the way.  By the time you are done, you will be able to write useful  drag and drop scripts of your own like in this example:<\/p>\n<p><a class=\"exampleLink\" href=\"\/tests\/dragAndDrop\/permissionForm.html#\">See an example of HTML5 Drag and Drop in action.<\/a><\/p>\n<h2>Advantages Over Existing Drag and Drop Implementations<\/h2>\n<p>Koch mentioned in his blog post that &#8220;Web developers MUST NOT (in the sense of RFC 2119) use HTML 5 drag and drop. They should use <a href=\"http:\/\/www.quirksmode.org\/js\/dragdrop.html\">old-school scripts<\/a> instead&#8221;.  I would argue that developers <em>should<\/em> use HTML5 drag and drop for the following reasons:<\/p>\n<ul>\n<li><strong>JavaScript Framework Independent: <\/strong>Most other (but not all) drag and drop implementations are tied into 3rd party frameworks like <a href=\"http:\/\/www.dojotoolkit.org\/\">Dojo<\/a>, <a href=\"http:\/\/www.prototypejs.org\/\">Prototype<\/a> or <a href=\"http:\/\/jquery.com\/\">jQuery<\/a>.<\/li>\n<li><strong>Built-in Browser Support: <\/strong>HTML5 Drag and Drop is supported in Firefox 3.5+, Chrome 3.0+, Safari 3.0+ and Internet Explorer 5.0 (<strong>Note:<\/strong> that is not a typo &mdash; HTML5 Drag and Drop is based on work done by Microsoft <strong>in 1999<\/strong>).  Because it is part of HTML5, I assume Opera support should be inevitable.<\/li>\n<li><strong>Integration With Other Web Applications:<\/strong> the HTML5 specification will allow developers to <em><strong>produce  drag and drop scripts that work across frames, and across browser windows.<\/strong><\/em><\/li>\n<li><strong>Integration With Non-Web Applications:<\/strong> the HTML5 specification also allows users to <em><strong>drag and drop data to and from non-web applications<\/strong><\/em><\/li>\n<\/ul>\n<h2>The Basics of Drag and Drop, Step by Step<\/h2>\n<p>In order to save other developers from the headaches I got deciphering cross browser drag and drop, I present the following guide that shows how to do in five easy steps.   Every step will describe a set of related concepts, and will show examples, most of which are built on code from previous steps.  At the end of each step, I will discuss any issues and interesting bits I came across.<\/p>\n<div class=\"steps\">\n<h3>Step 1: Defining a Draggable Object<\/h3>\n<p>First you need to define the HTML nodes that you want to drag.  Firefox requires that these nodes have their <code>draggable<\/code> attribute set to <code>\"true\"<\/code>, Internet Explorer requires that the node must be an <code>&lt;a&gt;<\/code> tag with (the <code>href<\/code> attribute set) or an <code>&lt;img&gt;<\/code> tag.<\/p>\n<blockquote class=\"code\">\n<pre>&lt;a href=\"#\" id=\"toDrag\" draggable=\"true\"&gt;This is a draggable item&lt;\/a&gt;<\/pre>\n<\/blockquote>\n<p>To show how this works, I have written a very simple page with a the above markup in the <code>&lt;body&gt;<\/code>:<\/p>\n<blockquote class=\"code\">\n<pre>&lt;!DOCTYPE html&gt;\r\n\r\n&lt;html lang=\"en\"&gt;\r\n    &lt;head&gt;\r\n        &lt;meta name=\"generator\" content=\"HTML Tidy, see www.w3.org\"&gt;\r\n\r\n        &lt;title&gt;Test #1: A Simple Draggable Object&lt;\/title&gt;\r\n\r\n      &lt;script type=\"text\/javascript\" src=\"..\/..\/shared\/js\/EventHelpers.js\"&gt;\r\n      &lt;\/script&gt;\r\n      &lt;script type=\"text\/javascript\" src=\"..\/..\/shared\/js\/DragDropHelpers.js\"&gt;\r\n      &lt;\/script&gt;\r\n\r\n        &lt;link rel=\"stylesheet\" type=\"text\/css\" media=\"screen\" href=\r\n        \"css\/test1.css\"&gt;\r\n    &lt;\/head&gt;\r\n\r\n    &lt;body&gt;\r\n        &lt;h1&gt;Test #1: A Simple Draggable Object&lt;\/h1&gt;\r\n\r\n<span class=\"hilite\">        &lt;a href=\"#\" id=\"toDrag\" draggable=\"true\"&gt;This is a\r\n        draggable item&lt;\/a&gt;<\/span>\r\n\r\n        &lt;p&gt;Try to drag the red box around. You will see the\r\n        draggable object cloned in every browser except Explorer\r\n        and Chrome.&lt;\/p&gt;\r\n\r\n        &lt;a href=\r\n        \"https:\/\/www.useragentman.com\/blog\/2010\/01\/10\/cross-browser-html5-drag-and-drop\/\"&gt;\r\n        Go back to the User Agent Man HTML5 Drag and Drop\r\n        article&lt;\/a&gt;\r\n    &lt;\/body&gt;\r\n&lt;\/html&gt;\r\n<\/pre>\n<\/blockquote>\n<p>Note that this HTML page has two scripts in the <code>&lt;head&gt;<\/code>:<\/p>\n<ul>\n<li><strong><code>EventHelpers.js<\/code>:<\/strong> this script implements cross-browser event handling routines without the need for a JavaScript framework.  All the examples in this article use it, but feel free to refactor all the code in this article to use a third party framework like Dojo, jQuery or whatever framework you like.<\/li>\n<li><strong><code>DragDropHelpers.js<\/code>:<\/strong> among other things that I will get to later, will activate dragging on <code>draggable=\"true\"<\/code> objects in Safari and Chrome using a built-in copy of Dean Edwards&#8217; <a href=\"http:\/\/dean.edwards.name\/my\/cssQuery\/\">cssQuery<\/a>.  It does this by inserting the following CSS code into the HTML document:<br \/>\n<blockquote class=\"code\">\n<pre>[draggable=true] {\r\n  -khtml-user-drag: element;\r\n  -webkit-user-drag: element;\r\n  -khtml-user-select: none;\r\n  -webkit-user-select: none;\r\n}<\/pre>\n<\/blockquote>\n<p>The first two rules allow the dragging of the <code>draggable=\"true\"<\/code> nodes, while the last two prevent the user from selecting the text within the node (which can cause some unexpected behavior in Webkit browsers).  The <code>-khtml <\/code>properties work in older versions of Safari, while <code>-webkit<\/code> ones work in newer versions.  <strong>Without these CSS properties, these nodes will not be draggable when using the Safari web browser<\/strong><\/li>\n<\/ul>\n<p><a class=\"exampleLink\" href=\"\/tests\/dragAndDrop\/01-dragObject.html\">See Example  #1: a draggable object<\/a><\/p>\n<p>A couple of notes:<\/p>\n<ol>\n<li> You&#8217;ll notice that when you hover the mouse pointer over the draggable item, it will change to <img loading=\"lazy\" decoding=\"async\" class=\"alignnone size-full wp-image-599\" title=\"The  &quot;Move&quot; cursor\" src=\"https:\/\/www.useragentman.com\/blog\/wp-content\/uploads\/2010\/01\/cursor-move.gif\" alt=\"The  &quot;Move&quot; cursor\" width=\"24\" height=\"28\" \/>(i.e. I the &#8220;move&#8221; cursor).  This is not the default behavior of the web browser &#8211; it is something I added in <code>DragDropHelpers<\/code>, since I believe that it&#8217;s a nice visual cue to show users that an object is draggable (if you don&#8217;t want this behavior, it is possible to turn it off in your own scripts by setting <code>DragDropHelpers.showMouseoverCue<\/code> to false<\/li>\n<li>How draggable objects look in the various browsers varies.  Here are screenshots of how it looks in Windows web browsers (Note: although all screenshots were taken using Windows XP, similar results occur when viewing under Windows Vista or Windows 7):<br \/>\n<table class=\"screenshots\" border=\"0\">\n<thead>\n<tr>\n<th>Firefox (Windows XP)<\/th>\n<th>Safari (Windows XP)<\/th>\n<th>Explorer &amp; Chrome (Windows XP)<\/th>\n<\/tr>\n<\/thead>\n<tbody>\n<tr>\n<td><img loading=\"lazy\" decoding=\"async\" class=\"alignnone size-full wp-image-514\" title=\"Dragging of a link element, Firefox Windows\" src=\"https:\/\/www.useragentman.com\/blog\/wp-content\/uploads\/2010\/12\/dragLink-firefoxWindows.png\" alt=\"[Dragging of a link element, Firefox Windows]\" width=\"180\" height=\"190\" \/><\/td>\n<td><img loading=\"lazy\" decoding=\"async\" class=\"alignnone size-full wp-image-514\" title=\"Dragging of a link element, Safari Windows\" src=\"https:\/\/www.useragentman.com\/blog\/wp-content\/uploads\/2010\/12\/dragLink-safariWindows.png\" alt=\"[Dragging of a link element, Safari Windows]\" width=\"180\" height=\"190\" \/><\/td>\n<td><img loading=\"lazy\" decoding=\"async\" class=\"alignnone size-full wp-image-514\" title=\"Dragging of a link element, Explorer Windows\" src=\"https:\/\/www.useragentman.com\/blog\/wp-content\/uploads\/2010\/12\/dragLink-explorerWindows.png\" alt=\"[Dragging of a link element, Explorer Windows]\" width=\"180\" height=\"190\" \/><\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p>Note the differences between these three browsers:<\/p>\n<ul>\n<li>Firefox for Windows shows a cloned version of the draggable object underneath the mouse pointer when the object is being dragged, while Safari displays a grey box with the text &#8220;This is a draggable item&#8221; written inside.  Explorer and Chrome don&#8217;t show any effect at all (We will address this issue later).<\/li>\n<li>Since we have not established <em>where<\/em> we are going to drag our object, all Windows browsers will change the mouse pointer cursor to <img loading=\"lazy\" decoding=\"async\" class=\"alignnone size-full wp-image-567\" title=\"&quot;Not-Allowed&quot; cursor.\" src=\"https:\/\/www.useragentman.com\/blog\/wp-content\/uploads\/2010\/12\/cursor_not-allowed.gif\" alt=\"&quot;Not-Allowed&quot; cursor.\" width=\"22\" height=\"22\" \/> (a.k.a. the &#8220;not-allowed&#8221; mouse pointer).  This is the expected behavior, and you will see later that it will help the user know where to drop the object.<\/li>\n<\/ul>\n<p>On OS X, Firefox and Safari look similar to Firefox for Windows, except that the &#8220;not-allowed&#8221; mouse-pointer doesn&#8217;t show up:<\/p>\n<table class=\"screenshots\" border=\"0\">\n<thead>\n<tr>\n<th>Firefox (OS X)<\/th>\n<th>Safari (OS X)<\/th>\n<th>Chrome (OS X)<\/th>\n<\/tr>\n<\/thead>\n<tbody>\n<tr>\n<td><img loading=\"lazy\" decoding=\"async\" class=\"alignnone size-full wp-image-513\" title=\"Dragging of a link element, Firefox OS X\" src=\"https:\/\/www.useragentman.com\/blog\/wp-content\/uploads\/2010\/12\/dragLink-firefoxMac.png\" alt=\"[Dragging of a link element, Firefox Windows]\" width=\"180\" height=\"190\" \/><\/td>\n<td><img loading=\"lazy\" decoding=\"async\" class=\"alignnone size-full wp-image-514\" title=\"Dragging of a link element, Safari OS X\" src=\"https:\/\/www.useragentman.com\/blog\/wp-content\/uploads\/2010\/12\/dragLink-safariMac.png\" alt=\"[Dragging of a link element, Safari OS X]\" width=\"180\" height=\"190\" \/><\/td>\n<td><img loading=\"lazy\" decoding=\"async\" class=\"alignnone size-full wp-image-653\" title=\"Chrome for Mac\" src=\"https:\/\/www.useragentman.com\/blog\/wp-content\/uploads\/2010\/01\/dragLink-chromeMac.png\" alt=\"Chrome for Mac\" width=\"180\" height=\"190\" \/><\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p>The Linux browsers don&#8217;t have the &#8220;not-allowed&#8221; mouse cursor either.  Also, the cloned version of the draggable object isn&#8217;t transparent using the Linux version of Firefox, and Chrome under Linux behaves  pretty much the  same as on the other platforms (Note: all Linux testing was done using Ubuntu 9.10 using the standard Gnome window manager).<\/p>\n<table class=\"screenshots\" border=\"0\">\n<thead>\n<tr>\n<th>Firefox (Ubuntu)<\/th>\n<th>Chrome (Ubuntu)<\/th>\n<\/tr>\n<\/thead>\n<tbody>\n<tr>\n<td><img loading=\"lazy\" decoding=\"async\" class=\"size-full wp-image-698 alignnone\" title=\"dragLink-firefoxUbuntu\" src=\"https:\/\/www.useragentman.com\/blog\/wp-content\/uploads\/2010\/01\/dragLink-firefoxUbuntu.png\" alt=\"Firefox Linux\" width=\"180\" height=\"190\" \/><\/td>\n<td><img loading=\"lazy\" decoding=\"async\" class=\"size-full wp-image-697 alignnone\" title=\"dragLink-chromeUbuntu\" src=\"https:\/\/www.useragentman.com\/blog\/wp-content\/uploads\/2010\/01\/dragLink-chromeUbuntu.png\" alt=\"Chrome Linux\" width=\"180\" height=\"190\" \/><\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p>The fact that Explorer and Chrome don&#8217;t have any visual dragging cues bugged me, so I put a &#8220;fix&#8221; inside <code>DragDropHelpers.js<\/code> which can be turned on by setting <code>DragDropHelpers.fixVisualCues<\/code> to true.  Let&#8217;s look at a slightly refactored version of Example #1 where we insert the following code in the <code>&lt;head&gt;:<\/code><\/p>\n<blockquote class=\"code\">\n<pre>&lt;!DOCTYPE html&gt;\r\n&lt;html lang=\"en\"&gt;\r\n   &lt;head&gt;\r\n      &lt;title&gt;Test #1: A Simple Draggable Object (with visual cues added to Explorer and Chrome)&lt;\/title&gt;\r\n      &lt;script type=\"text\/javascript\" src=\"..\/..\/shared\/js\/EventHelpers.js\"&gt;&lt;\/script&gt;\r\n      &lt;script type=\"text\/javascript\" src=\"..\/..\/shared\/js\/DragDropHelpers.js\"&gt;&lt;\/script&gt;\r\n<span class=\"hilite\">      &lt;script type=\"text\/javascript\"&gt;\r\n      &lt;!--\r\n      DragDropHelpers.fixVisualCues=true;\r\n      --&gt;\r\n      &lt;\/script&gt;<\/span>\r\n\r\n      &lt;link rel=\"stylesheet\" type=\"text\/css\" media=\"screen\" href=\"css\/test1.css\" \/&gt;\r\n\r\n   &lt;\/head&gt;\r\n   &lt;body&gt;\r\n\r\n      &lt;h1&gt;Test #1: A Simple Draggable Object (with visual cues added to Explorer and Chrome)&lt;\/h1&gt;\r\n\r\n      &lt;a href=\"#\" id=\"toDrag\" draggable=\"true\"&gt;This is a draggable item&lt;\/a&gt;\r\n\r\n      &lt;p&gt;Try to drag the red box around.  You will see the draggable object cloned in all browsers.&lt;\/p&gt;\r\n\r\n      &lt;a href=\"https:\/\/www.useragentman.com\/blog\/2010\/01\/10\/cross-browser-html5-drag-and-drop\/\"&gt;Go back to the User Agent Man HTML5 Drag and Drop article&lt;\/a&gt;\r\n\r\n   &lt;\/body&gt;\r\n&lt;\/html&gt;\r\n<\/pre>\n<\/blockquote>\n<\/li>\n<\/ol>\n<p><a class=\"exampleLink\" href=\"\/tests\/dragAndDrop\/01a-dragObject.html\">See Example #1a, a draggable object with visual cue fix for Explorer and Chrome<\/a><\/p>\n<p>Voila!  The visual cue now shows up.  I&#8217;ll explain how this works at the end of the article.<\/p>\n<h3>Step 2: Setting Events on the Draggable Object<\/h3>\n<p>Now that you have defined an object as draggable, you should attach some events to it so the browser knows what to do while it is being dragged.  There are three events that a draggable object can fire:<\/p>\n<table class=\"dataTable\" border=\"0\">\n<thead>\n<tr>\n<th>Event name<\/th>\n<th>Description<\/th>\n<\/tr>\n<\/thead>\n<tbody>\n<tr>\n<td><code>dragstart<\/code><\/td>\n<td>Fires when the user starts dragging of the object.<\/td>\n<\/tr>\n<tr>\n<td><code>drag<\/code><\/td>\n<td>Fires every time the mouse is moved while the object is being dragged.<\/td>\n<\/tr>\n<tr>\n<td><code>dragend<\/code><\/td>\n<td>Fires when the user releases the mouse button while dragging an object.<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p>A developer would attach these events the way they would any other JavaScript event &#8211; I use <code>EventHelpers.addEvent<\/code>, but one could use jQuery&#8217;s <code>bind()<\/code> method, prototype&#8217;s <code>Event.observe()<\/code> or whatever you favourite framework provides for event handling.  Developers can also use the old school inline events (i.e. <code>&lt;a href=\"#\" id=\"toDrag\" draggable=\"true\" <span class=\"hilite\">ondragstart=\"somefunction();\"<\/span>&gt;This is a draggable item&lt;\/a&gt;<\/code>), but I try to stay away from using those to seperate document structure from behavior.<\/p>\n<p>Let&#8217;s take the example in step 1 and change it so we can log when these events happen to the <code>toDrag<\/code> node:<\/p>\n<blockquote class=\"code\">\n<pre>&lt;!DOCTYPE html&gt;\r\n&lt;html lang=\"en\"&gt;\r\n   &lt;head&gt;\r\n      &lt;title&gt;Example #2: a draggable object with events attached &lt;\/title&gt;\r\n<span class=\"hilite\">      &lt;script type=\"text\/javascript\" src=\"..\/..\/shared\/js\/sprintf.js\"&gt;&lt;\/script&gt;<\/span>\r\n      &lt;script type=\"text\/javascript\" src=\"..\/..\/shared\/js\/EventHelpers.js\"&gt;&lt;\/script&gt;\r\n      &lt;script type=\"text\/javascript\" src=\"..\/..\/shared\/js\/DragDropHelpers.js\"&gt;&lt;\/script&gt;\r\n\r\n<span class=\"hilite\">      &lt;script type=\"text\/javascript\" src=\"js\/02-dragObjectWithEvent.js\"&gt;&lt;\/script&gt;<\/span>\r\n\r\n      &lt;link rel=\"stylesheet\" type=\"text\/css\" media=\"screen\" href=\"css\/test1.css\" \/&gt;\r\n\r\n   &lt;\/head&gt;\r\n   &lt;body&gt;\r\n\r\n      &lt;h1&gt;Example #2: a draggable object with events attached&lt;\/h1&gt;\r\n\r\n      &lt;p&gt;Try to drag the red box around.  This page will tell you if the\r\n      object is currently dragging, and will log all &lt;code&gt;dragstart&lt;\/code&gt;\r\n      and &lt;code&gt;dragstop&lt;\/code&gt; events&lt;\/p&gt;\r\n\r\n<span class=\"hilite\">      &lt;p&gt;&lt;strong&gt;Is dragging:&lt;\/strong&gt; &lt;span id=\"dragEventNotice\"&gt;no&lt;\/span&gt;\r\n\r\n      &lt;p id=\"eventLog\"&gt;&lt;strong&gt;Event now firing:&lt;\/strong&gt;&lt;br \/&gt;&lt;span id=\"eventNotice\"&gt;&lt;\/span&gt;<\/span>\r\n\r\n      &lt;a class=\"goBack\" href=\"https:\/\/www.useragentman.com\/blog\/2010\/01\/10\/cross-browser-html5-drag-and-drop\/\"&gt;Go back to the User Agent Man HTML5 Drag and Drop article&lt;\/a&gt;&lt;\/p&gt;\r\n\r\n      &lt;a href=\"#\" id=\"toDrag\" draggable=\"true\"&gt;This is a draggable item&lt;\/a&gt;\r\n\r\n   &lt;\/body&gt;\r\n&lt;\/html&gt;\r\n<\/pre>\n<\/blockquote>\n<p>In the <code>02-dragObjectWithEvent.js<\/code> script, the <code>dragEventNotice<\/code> node will be used to report whether the user is dragging the object around, and the <code>eventNotice<\/code> will be used to log what events the user has fired:<\/p>\n<blockquote class=\"code\">\n<pre>var dragObject = new function () {\r\n   var me = this;\r\n\r\n   var dragNode;\r\n   var eventNoticeNode, dragEventNoticeNode;\r\n\r\n   \/* runs when the page is loaded *\/\r\n   me.init = function () {\r\n\r\n      if (EventHelpers.hasPageLoadHappened(arguments)) {\r\n         return;\r\n      }   \r\n\r\n      \/* The node being dragged *\/\r\n      dragNode=document.getElementById('toDrag');\r\n\r\n      \/* The nodes that report to the user what is happening to that node*\/\r\n      eventNoticeNode = document.getElementById('eventNotice');\r\n      dragEventNoticeNode = document.getElementById('dragEventNotice');\r\n\r\n      \/* The drag event handlers *\/\r\n<span class=\"hilite\">      EventHelpers.addEvent(dragNode, 'dragstart', dragStartEvent);\r\n      EventHelpers.addEvent(dragNode, 'drag', dragEvent);\r\n      EventHelpers.addEvent(dragNode, 'dragend', dragEndEvent);<\/span>\r\n   }\r\n\r\n   \/*\r\n    * The dragstart event handler logs to the user when the event started.\r\n    *\/\r\n<span class=\"hilite\">   function dragStartEvent(e) {\r\n      eventNoticeNode.innerHTML =\r\n         sprintf(\"&lt;strong&gt;%s&lt;\/strong&gt;: Drag Event started.&lt;br \/&gt;%s\",\r\n            new Date(),  eventNoticeNode.innerHTML);<\/span>\r\n   }\r\n\r\n   \/*\r\n    * The drag event reports to the user that dragging is on.\r\n    *\/\r\n<span class=\"hilite\">   function dragEvent(e) {\r\n      dragEventNoticeNode.innerHTML = \"Currently dragging.\";\r\n   }<\/span>\r\n\r\n   \/*\r\n    * The dragend event logs to the user when the event had finished *and*\r\n    * also reports that dragging has now stopped.\r\n    *\/\r\n<span class=\"hilite\">   function dragEndEvent(e) {\r\n      eventNoticeNode.innerHTML =\r\n         sprintf(\"&lt;strong&gt;%s&lt;\/strong&gt;: Drag Event stopped.&lt;br \/&gt;%s\",\r\n            new Date(), eventNoticeNode.innerHTML);\r\n      dragEventNoticeNode.innerHTML = \"Dragging stopped.\"\r\n   }\r\n}<\/span>\r\n\r\n\/\/ fixes visual cues in IE and Chrome.\r\nDragDropHelpers.fixVisualCues=true;\r\n\r\nEventHelpers.addPageLoadEvent('dragObject.init');<\/pre>\n<\/blockquote>\n<p>Before we get to the drag events, a word about the coding conventions I use for this and all the other code examples in this article:<\/p>\n<ul>\n<li>the <code>var me = this <\/code>line ensures that the script doesn&#8217;t confuse the <code>this <\/code>keyword of the object with the <code>this <\/code>keyword inside an event handler.<\/li>\n<li><code>EventHelpers.addPageLoadEvent()<\/code> (which is part of <code>EventHelpers.js<\/code>) will execute <code>dragObject.init<\/code> when the HTML has loaded.  <code>addPageLoadEvent()<\/code> is based on code from Dean Edwards&#8217; article <a href=\"http:\/\/dean.edwards.name\/weblog\/2005\/09\/busted\/\">The window.onload Problem &#8211; Solved!<\/a>.  It is similar to jQuery&#8217;s<code> $(document).ready()<\/code>method and prototype&#8217;s <code>dom:loaded<\/code> event.<\/li>\n<li>This code uses a JavaScript version of <code>sprintf()<\/code> that <a href=\"\/blog\/2009\/12\/22\/my-favourite-third-party-javascript-libraries\/\">I had mentioned in a previous blog post<\/a>.  I have used it in all the remaining examples because I think it makes the code a lot easier to read (however, it is not necessary in order to make HTML5 drag and drop work).<\/li>\n<\/ul>\n<p>Let&#8217;s get back to the drag events \u2014 you&#8217;ll notice that I have set the <code>dragstart<\/code>, <code>drag<\/code> and <code>dragend<\/code> events.  When this page is loaded, it will tell you if the draggable object is currently being dragged, and will log all <code>dragstart<\/code> and <code>dragstop<\/code> events on-screen. Click on the example link below and see for yourself:<\/p>\n<p><a class=\"exampleLink\" href=\"\/tests\/dragAndDrop\/02-dragObjectWithEvents.html\">See Example #2, a draggable object with events attached<\/a><\/p>\n<h3>Step 3: Setting Events on the Target Object<\/h3>\n<p>Step 2 showed us how we can drag an object around the screen and know when each drag starts and ends.  Now we need to drop the object. Let&#8217;s define a <strong>drop target<\/strong> to be <strong>an object where draggable objects can be dropped<\/strong>.  A drop target can have the following event handlers attached to it:<\/p>\n<table class=\"dataTable\" border=\"0\">\n<thead>\n<tr>\n<th>Event name<\/th>\n<th>Description<\/th>\n<\/tr>\n<\/thead>\n<tbody>\n<tr>\n<td><code>dragenter<\/code><\/td>\n<td>Fires when a draggable object is <strong>first dragged inside<\/strong> an object.<\/td>\n<\/tr>\n<tr>\n<td><code>dragover<\/code><\/td>\n<td>Fires everytime a draggable object is <strong>moved inside<\/strong> an object.  <strong>Note: if you want to allow the draggable object to be <em>dropped <\/em>inside this object, <em>you must cancel the default behaviour of this event handler.<\/em><\/strong><\/td>\n<\/tr>\n<tr>\n<td><code>dragleave<\/code><\/td>\n<td>Fires when a draggable object is <strong>dragged out<\/strong> of an object.<\/td>\n<\/tr>\n<tr>\n<td><code>drop<\/code><\/td>\n<td>Fired when a draggable object is <strong>dropped into<\/strong> an object.<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p><strong>If you want an object to become a drop target, you must attach both the <code>dragover<\/code> and <code>drop<\/code> events to it.<\/strong> You may ask &#8220;I understand why I need to implement <code>drop<\/code> (after all, it is one half of the term &#8220;drag and drop&#8221;) but why do I need <code>dragover<\/code>?&#8221;  <strong>As stated in the table above, the <code>drop<\/code> event will not fire unless you cancel the default behaviour of the event target&#8217;s <code>dragover<\/code> event<\/strong>.  This point is really important and <strong>your scripts will not work correctly unless you do this<\/strong>.<\/p>\n<p>You may ask &#8220;Why is there even a <code>dragover<\/code> event in the first place?  Isn&#8217;t <code>drag<\/code> sufficient?&#8221; (In his article, Peter-Paul Koch <a href=\"http:\/\/www.quirksmode.org\/blog\/archives\/2009\/09\/the_html5_drag.html#link8\"> asked this question a bit more emphatically that I did<\/a>).  The <code>dragover<\/code> event object does contain some useful information, such as <strong>the coordinates of the  mouse pointer inside the event target<\/strong>, (When I created <code>DragDropHelpers<\/code>, this information allowed me to fix Explorer and Chrome&#8217;s visual cue issue that I mentioned in step #1).  These coordinates are stored in the properties <code>offsetX<\/code> and <code>offsetY<\/code>, <strong>except in Firefox 3.5<\/strong> which keeps these values inside of the event properties <code>layerX<\/code> and <code>layerY<\/code>.  For convenience, <code>DragDropHelpers<\/code> includes a method called <code>getEventCoords()<\/code> that will use the appropriate property to get these values (<strong>Note:<\/strong> <code>layerX<\/code> and <code>layerY<\/code> are only accurate when the drop target&#8217;s CSS <code>position<\/code> propety is set to <code>relative<\/code>,<code> absolute<\/code> or <code>fixed<\/code>).<\/p>\n<p>To show how to add drop functionality to your code, lets take the code from example #2 and add a drop target:<\/p>\n<blockquote class=\"code\">\n<pre>&lt;!DOCTYPE html&gt;\r\n&lt;html lang=\"en\"&gt;\r\n   &lt;head&gt;\r\n      &lt;title&gt;Example #3: a dragable object with a drop target&lt;\/title&gt;\r\n      &lt;script type=\"text\/javascript\" src=\"..\/..\/shared\/js\/sprintf.js\"&gt;&lt;\/script&gt;\r\n      &lt;script type=\"text\/javascript\" src=\"..\/..\/shared\/js\/EventHelpers.js\"&gt;&lt;\/script&gt;\r\n      &lt;script type=\"text\/javascript\" src=\"..\/..\/shared\/js\/DragDropHelpers.js\"&gt;&lt;\/script&gt;\r\n\r\n<span class=\"hilite\">      &lt;script type=\"text\/javascript\" src=\"js\/03-dragObjectWithTargetObject.js\"&gt;&lt;\/script&gt;<\/span>\r\n\r\n      &lt;link rel=\"stylesheet\" type=\"text\/css\" media=\"screen\" href=\"css\/test1.css\" \/&gt;\r\n\r\n   &lt;\/head&gt;\r\n   &lt;body&gt;\r\n\r\n      &lt;h1&gt;Example #3: a dragable object with a drop target&lt;\/h1&gt;\r\n\r\n      &lt;p&gt;Try to drag the red box around and dropping it in the target object.&lt;\/p&gt;\r\n\r\n      &lt;p&gt;&lt;strong&gt;Is dragging:&lt;\/strong&gt; &lt;span id=\"dragEventNotice\"&gt;no&lt;\/span&gt;\r\n\r\n      &lt;p id=\"eventLog\"&gt;&lt;strong&gt;Event now firing:&lt;\/strong&gt;&lt;br \/&gt;&lt;span id=\"eventNotice\"&gt;&lt;\/span&gt;\r\n      &lt;a class=\"goBack\" href=\"https:\/\/www.useragentman.com\/blog\/2010\/01\/10\/cross-browser-html5-drag-and-drop\/\"&gt;Go back to the User Agent Man HTML5 Drag and Drop article&lt;\/a&gt;&lt;\/p&gt;\r\n\r\n      &lt;a href=\"#\" id=\"toDrag\" draggable=\"true\"&gt;This is a draggable item&lt;\/a&gt;\r\n<span class=\"hilite\">      &lt;div id=\"dropTarget\"&gt;This is a \"target\" object&lt;\/div&gt;<\/span>\r\n\r\n   &lt;\/body&gt;\r\n&lt;\/html&gt;\r\n<\/pre>\n<\/blockquote>\n<p>The drop target will be the <code>&lt;div&gt;<\/code> with an <code>id<\/code> of <code>dropTarget<\/code>.   The <code>03-dragObjectWithTargetObject.js<\/code> script is the same code in example #2 except we add two event handlers:<\/p>\n<ul>\n<li>a <code>dragover<\/code> event that reports where the mouse is inside <code>dropTarget<\/code><\/li>\n<li>a <code>drop<\/code> event that reports when the drop happened.<\/li>\n<\/ul>\n<blockquote class=\"code\">\n<pre>var dragObject = new function () {\r\n   var me = this;\r\n\r\n   var dragNode, targetNode;\r\n   var eventNoticeNode, dragEventNoticeNode;\r\n   me.init = function () {\r\n\r\n   \tif (EventHelpers.hasPageLoadHappened(arguments)) {\r\n   \t\treturn;\r\n   \t}\t\r\n\r\n   \tdragNode=document.getElementById('toDrag');\r\n   \ttargetNode=document.getElementById('dropTarget');\r\n   \teventNoticeNode = document.getElementById('eventNotice');\r\n   \tdragEventNoticeNode = document.getElementById('dragEventNotice');\r\n\r\n   \t\/* These are events for the draggable object *\/\r\n   \tEventHelpers.addEvent(dragNode, 'dragstart', dragStartEvent);\r\n   \tEventHelpers.addEvent(dragNode, 'drag', dragEvent);\r\n   \tEventHelpers.addEvent(dragNode, 'dragend', dragEndEvent);\r\n\r\n   \t\/* These are events for the object to be dropped *\/\r\n   \t<span class=\"hilite\">EventHelpers.addEvent(targetNode, 'dragover', dragOverEvent);<\/span>\r\n   \t<span class=\"hilite\">EventHelpers.addEvent(targetNode, 'drop', dropEvent);<\/span>\r\n\r\n   }\r\n\r\n   function dragStartEvent(e) {\r\n   \tshowMessage(\"Drag Event started\");\r\n   }\r\n\r\n   function dragEvent(e) {\r\n   \tdragEventNoticeNode.innerHTML = \"Currently dragging.&lt;br \/&gt;\";\r\n   }\r\n\r\n   function dragEndEvent(e) {\r\n   \tshowMessage(\"Drag Event stopped\");\r\n   \tdragEventNoticeNode.innerHTML = \"Dragging stopped.\"\r\n   }\r\n\r\n<span class=\"hilite\">   function dragOverEvent(e) {\r\n   \tvar coords = DragDropHelpers.getEventCoords(e);\r\n   \tshowMessage(sprintf(\r\n   \t   \"Drag over event happened on node with id %s at coordinate (%d, %d)\",\r\n   \t   this.id, coords.x, coords.y));\r\n   \tEventHelpers.preventDefault(e);\r\n   }<\/span>\r\n\r\n<span class=\"hilite\">   function dropEvent(e) {\r\n   \tshowMessage(\"Drop event happened on node with id \" + this.id);\r\n   \tEventHelpers.preventDefault(e);\r\n   }<\/span>\r\n\r\n   function showMessage(message) {\r\n   \teventNoticeNode.innerHTML =\r\n   \t\tsprintf(\"&lt;strong&gt;%s&lt;\/strong&gt;: %s&lt;br \/&gt;%s\",\r\n   \t\t\tnew Date(), message, eventNoticeNode.innerHTML);\r\n   }\r\n\r\n}\r\n\r\n\/\/ fixes visual cues in IE and Chrome.\r\nDragDropHelpers.fixVisualCues=true;\r\n\r\nEventHelpers.addPageLoadEvent('dragObject.init');<\/pre>\n<\/blockquote>\n<p>(<strong>Note:<\/strong> <code>EventHelpers.preventDefault(e)<\/code> does what you&#8217;d expect: it prevents the default behavior of the event handler, similar to prototype&#8217;s <code>Event.stop()<\/code> or jQuery&#8217;s <code>event.preventDefault()<\/code>)<\/p>\n<p><a class=\"exampleLink\" href=\"\/tests\/dragAndDrop\/03-dragObjectAndTargetObject.html\">See Example #3: a dragable object with a drop target<\/a><\/p>\n<p>Note that in the above example, the time that the draggable object&#8217;s <code>dragend<\/code> event fires and the time that the drag target&#8217;s <code>drop<\/code> event fires is not consistant among browsers.  Safari and Chrome fire <code>dragend<\/code> first, while Firefox and Internet Explorer fire <code>drop<\/code> first.<\/p>\n<p>The two other drop target events, <code>dragenter<\/code> and <code>dragleave<\/code> are not absolutely necessary for every script, but let&#8217;s add these events to example #3 anyway to see how they work:<\/p>\n<blockquote class=\"code\">\n<pre>var dragObject = new function () {\r\n   var me = this;\r\n\r\n   var dragNode, targetNode;\r\n   var eventNoticeNode, dragEventNoticeNode;\r\n   me.init = function () {\r\n\r\n      if (EventHelpers.hasPageLoadHappened(arguments)) {\r\n         return;\r\n      }   \r\n\r\n      dragNode=document.getElementById('toDrag');\r\n      targetNode=document.getElementById('dropTarget');\r\n      eventNoticeNode = document.getElementById('eventNotice');\r\n      dragEventNoticeNode = document.getElementById('dragEventNotice');\r\n\r\n      \/* These are events for the draggable object *\/\r\n      EventHelpers.addEvent(dragNode, 'dragstart', dragStartEvent);\r\n      EventHelpers.addEvent(dragNode, 'drag', dragEvent);\r\n      EventHelpers.addEvent(dragNode, 'dragend', dragEndEvent);\r\n\r\n      \/* These are events for the object to be dropped *\/\r\n      EventHelpers.addEvent(targetNode, 'dragover', dragOverEvent);\r\n      EventHelpers.addEvent(targetNode, 'drop', dropEvent);\r\n<span class=\"hilite\">      EventHelpers.addEvent(targetNode, 'dragenter', dragEnterEvent);\r\n      EventHelpers.addEvent(targetNode, 'dragleave', dragLeaveEvent);<\/span>\r\n   }\r\n\r\n   function dragStartEvent(e) {\r\n      showMessage(\"Drag Event started\");\r\n   }\r\n\r\n   function dragEvent(e) {\r\n      dragEventNoticeNode.innerHTML = \"Currently dragging.&lt;br \/&gt;\";\r\n   }\r\n\r\n   function dragEndEvent(e) {\r\n      showMessage(\"Drag Event stopped\");\r\n      dragEventNoticeNode.innerHTML = \"Dragging stopped.\";\r\n   }\r\n\r\n   function dragOverEvent(e) {\r\n      var coords = DragDropHelpers.getEventCoords(e);\r\n\r\n      showMessage(sprintf(\r\n         \"Drag over event happened on node with id %s at coordinate (%d, %d)\",\r\n         this.id, coords.x, coords.y));\r\n\r\n      EventHelpers.preventDefault(e);\r\n   }\r\n\r\n   function dropEvent(e) {\r\n      showMessage(\"Drop event happened on node with id \" + this.id);\r\n      EventHelpers.preventDefault(e);\r\n\r\n   }\r\n\r\n<span class=\"hilite\">   function dragEnterEvent(e) {\r\n      showMessage(\"Drag Enter event happened on node with id \" + this.id);\r\n   }\r\n\r\n   function dragLeaveEvent(e) {\r\n      showMessage(\"Drag Leave event happened on node with id \" + this.id);\r\n   }<\/span>\r\n\r\n   function showMessage(message) {\r\n      eventNoticeNode.innerHTML =\r\n         sprintf(\"&lt;strong&gt;%s&lt;\/strong&gt;: %s&lt;br \/&gt;%s\",\r\n            new Date(), message, eventNoticeNode.innerHTML);\r\n   }\r\n\r\n}\r\n\r\n\/\/ fixes visual cues in IE and Chrome.\r\nDragDropHelpers.fixVisualCues=true;\r\n\r\nEventHelpers.addPageLoadEvent('dragObject.init');<\/pre>\n<\/blockquote>\n<p><a class=\"exampleLink\" href=\"\/tests\/dragAndDrop\/03a-dragEnterDragLeave.html\">See Example #3a: a drop target with dragenter and dragleave event handlers<\/a><\/p>\n<p>(Note that in Firefox 3.5, a <code>dragleave<\/code> event will fire just before a <code>drop<\/code> event, which the other browsers don&#8217;t fire <code>dragleave<\/code> when dropping).<\/p>\n<h3>Step 4: Passing Data Between the Draggable and Target Objects<\/h3>\n<p>Once a draggable object is dropped into a drop target, the two objects can pass information between them using the drop event&#8217;s <code>dataTransfer<\/code> property.  This property has two methods, <code>setData()<\/code> and <code>getData()<\/code>.  In order to pass data between the two, a developer must use <code>setData()<\/code> during one of the draggable node&#8217;s drag events (e.g. <code>dragstart<\/code>).  The drop target can then receive this data during one of it&#8217;s events using the <code>getData()<\/code> method.<\/p>\n<table class=\"dataTable\" border=\"0\">\n<thead>\n<tr>\n<th>Method<\/th>\n<th>Description<\/th>\n<\/tr>\n<\/thead>\n<tbody>\n<tr>\n<td class=\"methodName\"><code>setData(dataType, data)<\/code><\/td>\n<td>\n<p>Sets the data that can be shared between the draggable node and the drag target.<\/p>\n<p><strong>Parameters<\/strong><\/p>\n<ul>\n<li><code>dataType<\/code> &#8211; The type of data that is to be set.  So far, the only cross-browser dataTypes that can be set are &#8216;Text&#8217; and &#8216;Url&#8217;.<\/li>\n<li><code>data<\/code> &#8211; The data that is going to be set.<\/li>\n<\/ul>\n<\/td>\n<\/tr>\n<tr>\n<td class=\"methodName\"><code>getData(dataType)<\/code><\/td>\n<td>\n<p>Gets the data that was previously set by <code>dataTransfer.setData()<\/code>.  <strong>It can also get data that was set by a <code>dataTransfer.setData()<\/code> call from another page, another browser window, and <em>another vendor&#8217;s web browser on the same machine<\/em>.<\/strong> It also can get data that was set by a drop event of another desktop application (for example, Windows WordPad).<\/p>\n<p><strong>Parameters<\/strong><\/p>\n<ul>\n<li><code>dataType<\/code> &#8211; The type of data that is to be set.  So far, the only cross-browser dataTypes that can be set are &#8216;Text&#8217; and &#8216;Url&#8217;.<\/li>\n<\/ul>\n<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p><code>setData()<\/code> takes one string parameter, which is the data you want to share between the draggable object and a drop target.<\/p>\n<p>Let&#8217;s take the code from step #3 and mix it up a bit: instead of having one draggable object, let&#8217;s make four.  I have taken <a href=\"http:\/\/commons.wikimedia.org\/wiki\/File:The_Fabs.JPG\">four photos of the Beatles from the Wikmedia Commons<\/a> and made them draggable.<\/p>\n<blockquote class=\"code\">\n<pre>&lt;!DOCTYPE html&gt;\r\n&lt;html lang=\"en\"&gt;\r\n   &lt;head&gt;\r\n      &lt;title&gt;Test 4: setData() and getData()&lt;\/title&gt;\r\n      &lt;script type=\"text\/javascript\" src=\"..\/..\/shared\/js\/sprintf.js\"&gt;&lt;\/script&gt;\r\n      &lt;script type=\"text\/javascript\" src=\"..\/..\/shared\/js\/helpers.js\"&gt;&lt;\/script&gt;\r\n      &lt;script type=\"text\/javascript\" src=\"..\/..\/shared\/js\/DragDropHelpers.js\"&gt;&lt;\/script&gt;\r\n\r\n<span class=\"hilite\">      &lt;script type=\"text\/javascript\" src=\"js\/04-setDataGetData.js\"&gt;&lt;\/script&gt;<\/span>\r\n\r\n      &lt;link rel=\"stylesheet\" type=\"text\/css\" media=\"screen\" href=\"css\/test1.css\" \/&gt;\r\n\r\n   &lt;\/head&gt;\r\n   &lt;body&gt;\r\n\r\n      &lt;h1&gt;Test 4: &lt;code&gt;setData()&lt;\/code&gt; and &lt;code&gt;getData()&lt;\/code&gt;&lt;\/h1&gt;\r\n\r\n<span class=\"hilite\">      &lt;img draggable=\"true\" src=\"images\/george.png\" alt=\"George Harrison\" \/&gt;\r\n      &lt;img draggable=\"true\" src=\"images\/john.png\" alt=\"John Lennon\" \/&gt;\r\n      &lt;img draggable=\"true\" src=\"images\/paul.png\" alt=\"Paul McCartney\" \/&gt;\r\n      &lt;img draggable=\"true\" src=\"images\/ringo.png\" alt=\"Ringo Starr\" \/&gt;<\/span>\r\n\r\n      &lt;div id=\"dropTarget\"&gt;&lt;span&gt;Drop an image here to find out more information about it.&lt;\/span&gt;&lt;\/div&gt;\r\n\r\n   &lt;\/body&gt;\r\n&lt;\/html&gt;<\/pre>\n<\/blockquote>\n<p>The script <code>04-setDataGetData.js<\/code> uses <code>dataTransfer.setData()<\/code> and <code>.getData()<\/code> to copy the <code>&lt;img&gt;<\/code> of the Beatle being dragged, as well as placing the <code>alt<\/code> attribute&#8217;s contents underneath the image.<\/p>\n<blockquote class=\"code\">\n<pre>var dragObject = new function () {\r\n   var me = this;\r\n\r\n   var targetNode;\r\n   var eventNoticeNode, dragEventNoticeNode;\r\n\r\n   var dataTransferCommentString;\r\n\r\n   me.init = function () {\r\n\r\n      if (EventHelpers.hasPageLoadHappened(arguments)) {\r\n         return;\r\n      }   \r\n\r\n      targetNode=document.getElementById('dropTarget');\r\n      eventNoticeNode = document.getElementById('eventNotice');\r\n      dragEventNoticeNode = document.getElementById('dragEventNotice');\r\n\r\n      \/* These are events for the draggable objects *\/\r\n      var dragNodes = cssQuery('[draggable=true]');\r\n      for (var i = 0; i &lt; dragNodes.length; i++) {\r\n         var  dragNode=dragNodes[i]\r\n         EventHelpers.addEvent(dragNode, 'dragstart', dragStartEvent);\r\n      }\r\n\r\n      \/* These are events for the object to be dropped *\/\r\n      EventHelpers.addEvent(targetNode, 'dragover', dragOverEvent);\r\n      EventHelpers.addEvent(targetNode, 'drop', dropEvent);\r\n   }\r\n\r\n   function dragStartEvent(e) {\r\n<span class=\"hilite\">      e.dataTransfer.setData('Text',\r\n         sprintf('&lt;img src=\"%s\" alt=\"%s\" \/&gt;&lt;br \/&gt;&lt;p class=\"caption\"&gt;%s&lt;\/p&gt;',\r\n            this.src, this.alt, this.alt\r\n         )\r\n      );<\/span>\r\n   }\r\n\r\n   function dragOverEvent(e) {\r\n      EventHelpers.preventDefault(e);\r\n   }\r\n\r\n   function dropEvent(e) {\r\n<span class=\"hilite\">      this.innerHTML = e.dataTransfer.getData('Text');<\/span>\r\n      EventHelpers.preventDefault(e);\r\n   }\r\n\r\n}\r\n\r\n\/\/ fixes visual cues in IE and Chrome.\r\nDragDropHelpers.fixVisualCues=true;\r\n\r\nEventHelpers.addPageLoadEvent('dragObject.init');<\/pre>\n<\/blockquote>\n<p><a class=\"exampleLink\" href=\"\/tests\/dragAndDrop\/04-setDataGetData.html\">See Example #4: using setData() and getData()<\/a><\/p>\n<p>As previously mentioned the data that is set in setData() can be read in other applications.  If you are in Windows, open up WordPad and drag one of the images into it.  You&#8217;ll see the data that was given to setData() during the dragstart event.<\/p>\n<p>This interoperability with the operating system will allow developers to do some very interesting things which are out of the scope of this article.  I will, however, want to explore this in future postings.<\/p>\n<h3>Step 5: Drag  and  Drop Effects<\/h3>\n<p>In a traditional desktop application, you can use drag and drop to copy objects, move objects, and create links to things.  You can use the HTML5 drag and drop events to do this as well, but it would be nice to give the user visual cues to show what kind of action a draggable object can do, and what kind of action a drop target can accept.  It would also be nice to only allow &#8220;copy objects&#8221; to only drop on drop targets that are programmed to accept them.<\/p>\n<p>These features can be implemented using <code>e.dataTransfer.effectAllowed<\/code> on the draggable object and <code>e.dataTransfer.dropEffect()<\/code>on the drop target:<\/p>\n<table class=\"dataTable\" border=\"0\">\n<thead>\n<tr>\n<th>Method<\/th>\n<th>Description<\/th>\n<\/tr>\n<\/thead>\n<tbody>\n<tr>\n<td><code>e.dataTransfer.effectAllowed<\/code><\/td>\n<td>Sets the type of effect a draggable object is allowed to make.  Valid values are  <code>copy<\/code>, <code>move<\/code>, <code>link<\/code>, <code>copyMove<\/code>, <code>copyLink<\/code>, <code>linkMove<\/code>, <code>all<\/code>, and <code>none<\/code>.<\/td>\n<\/tr>\n<tr>\n<td><code>e.dataTransfer.dropEffect<\/code><\/td>\n<td>Sets the type of effect a drop target is allowed to accept.  Valid effects include <code>copy<\/code>, <code>move<\/code>, and <code>link<\/code>.<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p>When these are set correctly, drag and drop will only work when the draggable object&#8217;s <code>effectAllowed<\/code> and the drop target&#8217;s <code>dropEffect<\/code> are compatible.  To illustrate this, let&#8217;s first change the <code>dragstart<\/code> and <code>dragover<\/code> events in example #4 to do the <code>copy<\/code> effect:<\/p>\n<blockquote class=\"code\">\n<pre>   function dragStartEvent(e) {\r\n<span class=\"hilite\">      e.dataTransfer.effectAllowed=\"copy\";<\/span> \r\n\r\n      e.dataTransfer.setData('Text',\r\n         sprintf('&lt;img src=\"%s\" alt=\"%s\" \/&gt;&lt;br \/&gt;&lt;p class=\"caption\"&gt;%s&lt;\/p&gt;',\r\n            this.src, this.alt, this.alt\r\n         )\r\n      );\r\n   }\r\n\r\n   function dragOverEvent(e) {\r\n<span class=\"hilite\">      e.dataTransfer.dropEffect = \"copy\";<\/span>\r\n      EventHelpers.preventDefault(e);\r\n   }<\/pre>\n<\/blockquote>\n<p><a class=\"exampleLink\" href=\"\/tests\/dragAndDrop\/05-dataTransfer.html\">Example #5: matching drag and drop effects<\/a><\/p>\n<p>Note that unlike <a href=\"\/tests\/dragAndDrop\/04-setDataGetData.html\">example #4<\/a>, the mouse pointer has changed from the copy icon (in Windows, <img loading=\"lazy\" decoding=\"async\" class=\"alignnone size-full wp-image-616\" title=\"Windows Copy Icon\" src=\"https:\/\/www.useragentman.com\/blog\/wp-content\/uploads\/2010\/01\/copyWindows.gif\" alt=\"[Windows Copy Icon]\" width=\"23\" height=\"32\" \/>) to the move icon (<img loading=\"lazy\" decoding=\"async\" class=\"alignnone size-full wp-image-615\" title=\"Windows Move Icon\" src=\"https:\/\/www.useragentman.com\/blog\/wp-content\/uploads\/2010\/01\/moveWindows.gif\" alt=\"[Windows Move Icon]\" width=\"13\" height=\"27\" \/>).<\/p>\n<p>Now let&#8217;s change the code so that the draggable object and the drop target don&#8217;t have matching effects:<\/p>\n<blockquote class=\"code\">\n<pre>   function dragStartEvent(e) {\r\n<span class=\"hilite\">      e.dataTransfer.effectAllowed=\"copy\";<\/span> \r\n\r\n      e.dataTransfer.setData('Text',\r\n         sprintf('&lt;img src=\"%s\" alt=\"%s\" \/&gt;&lt;br \/&gt;&lt;p class=\"caption\"&gt;%s&lt;\/p&gt;',\r\n            this.src, this.alt, this.alt\r\n         )\r\n      );\r\n   }\r\n\r\n   function dragOverEvent(e) {\r\n<span class=\"hilite\">      e.dataTransfer.dropEffect = \"move\";<\/span>\r\n      EventHelpers.preventDefault(e);\r\n   }<\/pre>\n<\/blockquote>\n<p><a class=\"exampleLink\" href=\"\/tests\/dragAndDrop\/05a-dataTransferNoMatch.html\">See Example #5a: unmatching drag and drop effects<\/a><\/p>\n<p>You&#8217;ll see that the user is not able to drop the image on the drop target.<\/p>\n<p><strong>Update (Jan 28, 2010):<\/strong>  There is a documented bug in Safari and Chrome for Windows where <a href=\"http:\/\/code.google.com\/p\/chromium\/issues\/detail?id=14654\">drag and drop will not occur if <code>effectAllowed<\/code> and <code>dropEffect<\/code> are set to <code>move<\/code><\/a>.  This bug does not occur in the Mac editions of these browsers.  <\/p>\n<\/div>\n<h2>A More Complex Example<\/h2>\n<p>Let&#8217;s take all the information we have gathered and make a &#8220;real-world&#8221; script. Let&#8217;s say you were asked to create a &#8220;user entitlement&#8221; administration widget for a website.  The widget will have three entitlement catagories: &#8220;Unassigned Users&#8221;, &#8220;Restricted Users&#8221; (e.g. users who have restricted access to the website) and &#8220;Power Users&#8221; (e.g. users who would have administration access to a website):<\/p>\n<p><div id=\"attachment_684\" style=\"width: 403px\" class=\"wp-caption aligncenter\"><img loading=\"lazy\" decoding=\"async\" aria-describedby=\"caption-attachment-684\" class=\"size-full wp-image-684\" title=\"permissionFormScreenshot\" src=\"https:\/\/www.useragentman.com\/blog\/wp-content\/uploads\/2010\/01\/permissionFormScreenshot1.png\" alt=\"Screenshot of the user entitlement screen we want to implement\" width=\"393\" height=\"185\" srcset=\"https:\/\/www.useragentman.com\/blog\/wp-content\/uploads\/2010\/01\/permissionFormScreenshot1.png 393w, https:\/\/www.useragentman.com\/blog\/wp-content\/uploads\/2010\/01\/permissionFormScreenshot1-300x141.png 300w\" sizes=\"auto, (max-width: 393px) 100vw, 393px\" \/><p id=\"caption-attachment-684\" class=\"wp-caption-text\">Screenshot of the user entitlement screen we want to implement<\/p><\/div><\/p>\n<p>It should be rather easy for an administrator to drag and drop users back and forth between entitlement &#8220;buckets&#8221; in order to elevate or lower a users credentials.<\/p>\n<p>Let&#8217;s go through the steps we established above to implement this script.<\/p>\n<div class=\"steps\">\n<h3>Step 1: Defining a Draggable Objects<\/h3>\n<p>First let&#8217;s take a look at the table in the HTML:<\/p>\n<blockquote class=\"code\">\n<pre>&lt;table&gt;\r\n    &lt;thead&gt;\r\n        &lt;tr&gt;\r\n            &lt;th&gt;Unassigned Users&lt;\/th&gt;\r\n            &lt;th&gt;Restricted Users&lt;\/th&gt;\r\n            &lt;th&gt;Power Users&lt;\/th&gt;\r\n        &lt;\/tr&gt;\r\n    &lt;\/thead&gt;\r\n\r\n    &lt;tbody&gt;\r\n        &lt;tr&gt;\r\n            &lt;td id=\"unassignedUsers\"&gt;\r\n            \t&lt;a href=\"#\" draggable=\"true\"&gt;Moe Howard&lt;\/a&gt;\r\n\t\t&lt;a href=\"#\" draggable=\"true\"&gt;Curly Howard&lt;\/a&gt;\r\n\t\t&lt;a href=\"#\" draggable=\"true\"&gt;Shemp Howard&lt;\/a&gt;\r\n            \t&lt;a href=\"#\" draggable=\"true\"&gt;Larry Fine&lt;\/a&gt;\r\n\t    &lt;\/td&gt;\r\n\r\n            &lt;td id=\"restrictedUsers\"&gt;\r\n            &lt;\/td&gt;\r\n\r\n            &lt;td id=\"powerUsers\"&gt;\r\n            &lt;\/td&gt;\r\n        &lt;\/tr&gt;\r\n    &lt;\/tbody&gt;\r\n    &lt;tfoot&gt;\r\n\t&lt;td id=\"unassignedUsersHelp\"&gt;\r\n\t  Drag a user from this list to another list to change the\r\n\t  user's permissions.\r\n\t&lt;\/td&gt;\r\n\t&lt;td id=\"restrictedUsersHelp\"&gt;\r\n\t  Dragging user here will give this user restricted\r\n\t  permissions.\r\n\t&lt;\/td&gt;\r\n\t&lt;td id=\"powerUsersHelp\" &gt;\r\n\t  Dragging a user here will give this user power user access.\r\n\t&lt;\/td&gt;\r\n    &lt;\/tfoot&gt;\r\n&lt;\/table&gt;<\/pre>\n<\/blockquote>\n<p>(Note that the contents in the <code>tfoot<\/code> node are hidden by CSS).<\/p>\n<h3>Step 2: Setting Events on the Draggable Objects<\/h3>\n<p>The &#8220;users&#8221; are draggable objects.  In the script, we find all these nodes using Dean Edwards&#8217; <a href=\"http:\/\/dean.edwards.name\/my\/cssQuery\/\">cssQuery<\/a> and  set <code>dragstart<\/code> and <code>dragend<\/code> event handlers on each of them (Note: cssQuery allows us to select nodes by CSS selector, similar to the built-in functionality inside jQuery).<\/p>\n<blockquote class=\"code\">\n<pre>userNodes = cssQuery('[draggable=true]');\r\nfor (var i=0; i&lt;userNodes.length; i++) {\r\n   EventHelpers.addEvent(userNodes[i], 'dragstart', userDragStartEvent);\r\n   EventHelpers.addEvent(userNodes[i], 'dragend', userDragEndEvent);\r\n}<\/pre>\n<\/blockquote>\n<p>It then keeps track of the current node being dragged in the object variable <code>currentlyDraggedNode<\/code> and makes that node transparent by making it a member of the <code>draggedUser<\/code> class, which the page&#8217;s stylesheet defines as transparent.<\/p>\n<blockquote class=\"code\">\n<pre>function userDragStartEvent(e) {\r\n   currentlyDraggedNode = this;\r\n   currentlyDraggedNode.className = 'draggedUser';\r\n}<\/pre>\n<\/blockquote>\n<p>The <code>dragend<\/code> event removes the transparency of the <code>currentlyDraggedNode<\/code>:<\/p>\n<blockquote class=\"code\">\n<pre>function userDragEndEvent(e) {\r\n   currentlyDraggedNode.className = '';\r\n}<\/pre>\n<\/blockquote>\n<h3>Step 3: Setting Events on the Target Objects<\/h3>\n<p>All the table cells in the <code>&lt;tbody&gt;<\/code> are drop targets, so we use cssQuery again to grab all those nodes and set the appropriate events.<\/p>\n<blockquote class=\"code\">\n<pre>userListNodes = cssQuery('.userList');\r\n\r\nfor (var i=0; i&lt;userListNodes.length; i++) {\r\n   var userListNode = userListNodes[i];\r\n   EventHelpers.addEvent(userListNode, 'dragover', cancel);\r\n   EventHelpers.addEvent(userListNode, 'dragleave', userDragLeaveListEvent);\r\n   EventHelpers.addEvent(userListNode, 'drop', userDropListEvent);\r\n   EventHelpers.addEvent(userListNode, 'dragenter', userDragOverListEvent);\r\n}<\/pre>\n<\/blockquote>\n<p>The most important event is the <code>drop<\/code> event handler.  This event handler takes the <code>currentlyDraggedNode<\/code>, removes it from its current table cell (using <code>removeChild()<\/code>) and  drops it into the drop target (using <code>appendChild()<\/code>).<\/p>\n<blockquote class=\"code\">\n<pre>function setHelpVisibility(node, isVisible) {\r\n   var helpNodeId = node.id + \"Help\";\r\n   var helpNode = document.getElementById(helpNodeId);\r\n\r\n   if (isVisible) {\r\n      helpNode.className =  'showHelp';\r\n   } else {\r\n      helpNode.className =  '';\r\n   }\r\n}\r\n\r\nfunction userDropListEvent(e) {\r\n   currentlyDraggedNode.parentNode.removeChild(currentlyDraggedNode);\r\n   this.appendChild(currentlyDraggedNode);\r\n   setHelpVisibility(this, false);\r\n   userDragEndEvent(e);\r\n}<\/pre>\n<\/blockquote>\n<p>They show the contents of the table cell below it by making it a member of the class <code>showHelp<\/code>.  They also<\/p>\n<p>prevent the <code>dragover<\/code> default behaviour so that <code>drop<\/code> events will fire in the drop target.<\/p>\n<blockquote class=\"code\">\n<pre>function userDragOverListEvent(e) {\r\n   setHelpVisibility(this, true);\r\n   EventHelpers.preventDefault(e);\r\n}<\/pre>\n<\/blockquote>\n<p>The <code>dragleave<\/code> re-hides the contents of the table cell below it.<\/p>\n<blockquote class=\"code\">\n<pre>function userDragLeaveListEvent(e) {\r\n  setHelpVisibility(this, false);\r\n}<\/pre>\n<\/blockquote>\n<div id=\"_mcePaste\" style=\"overflow: hidden; position: absolute; left: -10000px; top: 4921px; width: 1px; height: 1px;\">\n<pre>function userDragEndEvent(e) {\r\n   currentlyDraggedNode.className = '';\r\n}<\/pre>\n<\/div>\n<h3>Steps 4 and 5<\/h3>\n<p>We do not actually pass any data between the draggable object and the drag target \u2014 when the <code>drop<\/code> event occurs, the draggable object is moved from one column to another without the need of any <code>dataTransfer<\/code> data.  The drag and drop effects were already handled in step 3, so we are all done.<\/p>\n<p><a class=\"exampleLink\" href=\"\/tests\/dragAndDrop\/permissionForm.html\">See the above example in action<\/a><\/p>\n<\/div>\n<h2>Drag and Drop Between Frames<\/h2>\n<p>Using the above information, it is also possible to drag and drop objects between frames (this is something that I don&#8217;t think any old school drag and drop script can do).  I made an example below, and I leave it as an exercise to the reader to go through the code and figure out how it works.<\/p>\n<p><a class=\"exampleLink\" href=\"\/tests\/dragAndDrop\/05a-crossFrameSetData\/\">See the inter-frame drag and drop example in action<\/a><\/p>\n<h2>Cross-Browser Issues I Have Seen<\/h2>\n<p>These are the cross-browser issues I know of so far.  I will update this list with others I find in the future.<\/p>\n<ul>\n<li>in Firefox 3.5, a <code>dragleave<\/code> event will fire just before a <code>drop<\/code> event, which the other browsers don\u2019t fire <code>dragleave<\/code> when dropping.<\/li>\n<li>the time that the draggable object\u2019s <code>dragend<\/code> event fires and the time that the drag target\u2019s <code>drop<\/code> event fires is not consistant among browsers. Safari and Chrome fire <code>dragend<\/code> first, while Firefox and Internet Explorer fire <code>drop<\/code> first.<\/li>\n<li>According to <a href=\"http:\/\/www.alertdebugging.com\/drag-and-drop-bugs\/\">Francisco Tolmasky<\/a>, <a href=\"http:\/\/www.alertdebugging.com\/drag-and-drop-bugs\/\"><code>setData()<\/code> cannot be called during drag events in Firefox<\/a>.  Hopefully this will be fixed in a future release of the browser.<\/li>\n<li><code>DragDropHelpers<\/code> implements a workaround for Explorer so it can drag <em>any<\/em> object around. However, I did not use this functionality in any of the examples because it exposes a problem with <a href=\"http:\/\/lists.apple.com\/archives\/web-dev\/2009\/Jul\/msg00042.html\">Safari not being able to drag an object correctly when the user initiates the drag on the text inside it<\/a>.  This problem doesn&#8217;t happen with text inside of links, but with text inside other nodes (like a <code>&lt;div&gt;<\/code> tag).  I understand this problem has been fixed in the Safari nightly builds, so I left the functionality in the DragDropHelpers library for future use.<\/li>\n<li>DragDropHelpers.js &#8220;fixes&#8221; the dragging visual cues in Explorer and Chrome by:\n<ul>\n<li>making a transparent and absolutely positioned clone of a draggable object when it&#8217;s <code>dragstart<\/code> event is fired<\/li>\n<li>moving the cloned object near the mouse when the <code>&lt;body&gt;<\/code>&#8216;s <code>drag<\/code> event is fired.<\/li>\n<li>destroying the clone when draggable object&#8217;s <code>dragend<\/code> event is fired.<\/li>\n<\/ul>\n<p>I didn&#8217;t turn it on by default because I am not sure when (or if) this problem will be fixed in Internet Explorer or Chrome.  I also doesn&#8217;t work well when dragging objects from one window or frame to another, since the cloned visual cue can&#8217;t jump from page to page.  Feel free to use it (or not) as you see fit.<\/li>\n<li>As mentioned previously, because of a <a href=\"http:\/\/code.google.com\/p\/chromium\/issues\/detail?id=14654\">bug in Webkit<\/a>, drag and drop will not occur if <code>effectAllowed<\/code> and <code>dropEffect<\/code>  are set to <code>move<\/code> in Safari 4.0.4.  Hopefully this will be fixed in a future version of Webkit.<\/li>\n<\/ul>\n<h2>Conclusion<\/h2>\n<p>HTML5 drag and drop will be an important part of our front-end toolkit.  Even though the flavors that browser-vendors offer today are incomplete, it is possible to smooth out these flaws to produce useful web applications.  What I have covered here only scratches the surface &#8211; there are more properties and methods that some of browsers offer that can be used to further enhance the drag and drop experience.   But I have been working on this blog entry way to long, and my wife is giving me that &#8220;what the hell are you doing up at this hour&#8221; look, so I think I&#8217;ll stop here for now.<\/p>\n<h2>Download<\/h2>\n<p><code>DragDropHelpers<\/code>, and all code used in this article can be downloaded below.<\/p>\n<p><a class=\"exampleLink\" href=\"https:\/\/github.com\/zoltan-dulac\/DragDropHelpers\">Download the Latest Version of DragDropHelpers.js from GitHub.<\/a><\/p>\n","protected":false},"excerpt":{"rendered":"<p>HTML5 Drag and Drop is one of the least understood modules of the HTML5 specification and it can be a pain to implement in a cross browser fashion.  This article is for those who want to use it today in their web applications and goes into a lot of detail so you can &#8220;get the job done&#8221;<\/p>\n","protected":false},"author":2,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[60,35,7],"tags":[68,224,69,70,66,72,71,67,73,75,74,65,63,62,61,64],"class_list":["post-734","post","type-post","status-publish","format-standard","hentry","category-drag-and-drop","category-html5","category-javascript","tag-drag","tag-drag-and-drop","tag-dragend","tag-dragenter","tag-draggable","tag-dragleave","tag-dragover","tag-dragstart","tag-drop","tag-dropeffect","tag-effectallowed","tag-getdata","tag-html5-drag-and-drop","tag-on","tag-ondragstart","tag-setdata"],"_links":{"self":[{"href":"https:\/\/www.useragentman.com\/blog\/wp-json\/wp\/v2\/posts\/734","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.useragentman.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.useragentman.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.useragentman.com\/blog\/wp-json\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/www.useragentman.com\/blog\/wp-json\/wp\/v2\/comments?post=734"}],"version-history":[{"count":36,"href":"https:\/\/www.useragentman.com\/blog\/wp-json\/wp\/v2\/posts\/734\/revisions"}],"predecessor-version":[{"id":7671,"href":"https:\/\/www.useragentman.com\/blog\/wp-json\/wp\/v2\/posts\/734\/revisions\/7671"}],"wp:attachment":[{"href":"https:\/\/www.useragentman.com\/blog\/wp-json\/wp\/v2\/media?parent=734"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.useragentman.com\/blog\/wp-json\/wp\/v2\/categories?post=734"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.useragentman.com\/blog\/wp-json\/wp\/v2\/tags?post=734"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}