Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
35 commits
Select commit Hold shift + click to select a range
c10de71
Started with the barest of possibly workable content ➕
triplingual Oct 24, 2025
251105e
Switched to use IIIF icon for tractable CORS troubleshooting 🔀🖼️
triplingual Oct 24, 2025
9359dbe
Added drag-and-drop recipe to links and ToC 📝
triplingual Oct 31, 2025
c2872dd
Extremely rough draft of a use case 📝
triplingual Oct 31, 2025
4d30998
Started restrictions, rolled back draggable image 📝🖼️
triplingual Oct 31, 2025
c474dce
Added `JSON.stringify()` per @glenrobson ✨
triplingual Oct 31, 2025
b3bf320
Moved restriction text ➡️ implementation and drafted new restriction …
triplingual Oct 31, 2025
770f280
Edited use case for readability 📝
triplingual Nov 6, 2025
dbd7185
Swapped test content for copy of content from JavaScript 🔀
triplingual Nov 6, 2025
9558b95
Significant edits to flesh out the text 📝
triplingual Nov 6, 2025
aa83cc5
Expanded implementation notes, added new example 📝➕
triplingual Nov 14, 2025
7f6046d
Corrected type for content per authors' call 🛠️
triplingual Nov 18, 2025
6099f5a
Added text about lack of support per authors' call 📝
triplingual Nov 18, 2025
e1ee0ef
Made Example section text accurate, added visible markup for logo 📝
triplingual Nov 18, 2025
1a0de93
Finished the incomplete thought of one graf, flowed through consequen…
triplingual Nov 18, 2025
1d17da3
Explained why JSON in this example 📝
triplingual Nov 18, 2025
5fe3e30
Expanded notes to viewer developers in Implementation and Restrictions 📝
triplingual Nov 18, 2025
59ea17f
Added logo image used in recipe ➕🖼️
triplingual Nov 18, 2025
27e127b
Edited head section 📝
triplingual Dec 10, 2025
7554008
Added related recipes ➕
triplingual Dec 10, 2025
727e204
Set formatting for code and markup blocks 📝
triplingual Dec 10, 2025
6fe5772
Merge branch 'master' into 0599-drag-and-drop
glenrobson Dec 11, 2025
cda54b9
Capitalized word appropriately 📝
triplingual Dec 12, 2025
78a2bee
Changed cursor to pointer to emphasize draggability 🎨
triplingual Dec 12, 2025
bace288
Removed related item as insufficiently related 🚮
triplingual Dec 12, 2025
977ea48
Changed aside to encourage use of IIIF logo as the draggable item 📝
triplingual Dec 12, 2025
dfd3e52
Linked directly to manifest 🔗
triplingual Dec 12, 2025
1689756
Added pointer to @glenrobson implementation and screencast of using s…
triplingual Dec 12, 2025
bc5c6a1
Screencast showing how drag and drop could look 🎥
triplingual Dec 12, 2025
a93a11e
Added note about cursor transformation 📝
triplingual Dec 12, 2025
82492cf
Changed link to be full URI for validator 🔗
triplingual Dec 12, 2025
c571105
Changed link CORRECTLY to point to full MANIFEST for validator 🔗
triplingual Dec 12, 2025
2a48b21
Changed video source to point to new filename 🔗
triplingual Dec 12, 2025
c6b43e8
Changed cursor to `grad` 🤚🏻
triplingual Jan 16, 2026
6d615a4
Updated with working example viewer ⬆️
triplingual Jan 16, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions _includes/links.md
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,7 @@
[0540]: {{ site.cookbook_url | absolute_url }}/recipe/0540-link-for-opening-multiple-canvases/ "Sharing a link for opening two or more Canvases"
[0560]: {{ site.cookbook_url | absolute_url }}/recipe/0560-resources-on-a-timeline/ "Rendering Resources Sequentially on a Timeline"
[0561]: {{ site.cookbook_url | absolute_url }}/recipe/0561-text-on-image/ "Visible Text Resource on a Canvas"
[0599]: {{ site.cookbook_url | absolute_url }}/recipe/0599-drag-and-drop/ "Drag and Drop"

[cookbook-process]: {{site.cookbook_url | absolute_url }}/recipe

Expand Down
2 changes: 1 addition & 1 deletion index.md
Original file line number Diff line number Diff line change
Expand Up @@ -149,7 +149,7 @@ Recipes using [Content State API](https://iiif.io/api/content-state/1.0/)
* [Loading a manifest with a viewer using a link][0466]
* [Open a specific region of a canvas in a viewer][0485]
* [Sharing a link for opening two or more Canvases][0540]

* [Drag and drop][0599]


## Technical
Expand Down
Binary file added recipe/0599-drag-and-drop/drag-and-drop.mov
Binary file not shown.
115 changes: 115 additions & 0 deletions recipe/0599-drag-and-drop/index.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
---
title: Drag and Drop
id: 599
layout: recipe
tags: [content-state]
summary: "A model for manifest publishers and viewer developers for how to facilitate and accommodate dragging a IIIF manifest from one application to another."
viewers:
topic:
- content-state
---

## Use Case

As a person wanting to annotate a IIIF resource, you would like to open a Manifest in a viewer not available in the web interface where you first find the resource.

Alternately, as a viewer developer, you would like to allow your viewer to receive dragged-over items.

## Implementation Notes

Implementing this recipe requires a resource provider and a viewer each to implement their part.

### For Resource Providers

The resource provider must have a draggable item — customarily the IIIF logo image — that makes use of the DataTransfer object. It will have a [`dataTransfer.setData` method](https://developer.mozilla.org/en-US/docs/Web/API/DataTransfer) attached to the item's `dragstart` event. It can be helpful to turn the cursor into a pointer when it hovers over the draggable IIIF logo image, to indicate that it is draggable.

A script implementing such a method for a Manifest could look like the below.
```javascript
<script>
function drag(ev) {
ev.dataTransfer.setData("text/plain", JSON.stringify({
"@context": "http://iiif.io/api/presentation/3/context.json",
"id": "https://iiif.io/api/cookbook/recipe/0599-drag-and-drop/dnd-manifest",
"type": "Annotation",
"motivation": ["contentState"],
"target": {
"id": "https://iiif.io/api/cookbook/recipe/0006-text-language/manifest.json",
"type": "Manifest"
}
}));
}
</script>
```

Note that the script represents the manifest content as JSON to parallel other cookbook resource content, but converts it to a string to match the content type parameter. While [the `setData` method of Web Assembly can use other content types](https://developer.mozilla.org/en-US/docs/Web/API/DataTransfer/setData), the spec for [IIIF Content State](https://iiif.io/api/content-state/1.0/#initialization-mechanisms-dragdrop) requires a content type of `text/plain` for maximum compatibility.

The content does not have to be a full Manifest. A script implementing this same method for a single Canvas of a Manifest could look like the below. (Noting that there would be no likely practical difference from the above since this manifest contains but one Canvas.)
```javascript
<script>
function drag(ev) {
ev.dataTransfer.setData("text/plain", JSON.stringify({
"@context": "http://iiif.io/api/presentation/3/context.json",
"id": "https://iiif.io/api/cookbook/recipe/0599-drag-and-drop/dnd-manifest",
"type": "Annotation",
"motivation": ["contentState"],
"target": {
"id": "https://iiif.io/api/cookbook/recipe/0006-text-language/canvas/p1",
"type": "Canvas",
"partOf": [{
"id": "https://iiif.io/api/cookbook/recipe/0006-text-language/manifest.json",
"type": "Manifest"
}]
}
}));
}
</script>
```

### For Viewer Developers

A supporting viewer must have an interface capable of handling the DataTransfer object's data carried by the draggable item in its `drop` event. Somewhat as for resource providers, [the `getData` method of Web Assembly can specify other content types](https://developer.mozilla.org/en-US/docs/Web/API/DataTransfer/getData) but the spec for [IIIF Content State](https://iiif.io/api/content-state/1.0/#initialization-mechanisms-dragdrop) requires a content type of `text/plain` for maximum compatibility. See the immediately following section for cautions about receiving content.

## Restrictions

Because implementation is two-part, you may only have control over one half of the ability to drag and drop. Consequently, and since this action is only in a GUI environment, you will need to consider whether visitors to your IIIF interface would benefit from some kind of support text.

Viewer developers will have a special need to consider security when implementing a droppable interface. This recipe cannot cover all of data transfer security, but will note that all content provided to a site should be sanitized.

## Example

Below is an image of the IIIF logo, decorated with the appropriate JavaScript event handler attributes, and a visible version of the markup for that image, showing the connection to the page script for the `drag` event. For a supporting viewer, the IIIF logo image below could be dragged onto its viewing area and dropped, which would result in the viewer retrieving the [manifest for the IIIF Cookbook recipe](https://iiif.io/api/cookbook/recipe/0006-text-language/manifest.json) titled ["Internationalization and Multi-language Values"][0006].

No viewers currently support this approach to dragging and dropping a manifest.

<img src="logo-sm.png" draggable="true" ondragstart="drag(event)" alt="IIIF logo; drag and drop onto a supporting viewer to see this resource in that viewer" style="cursor:grab;">

```html
<img src="logo-sm.png" draggable="true" ondragstart="drag(event)" alt="IIIF logo; drag and drop onto a supporting viewer to see this resource in that viewer" style="cursor:grab;">
```

<script>
function drag(ev) {
ev.dataTransfer.setData("text/plain", JSON.stringify({
"@context": "http://iiif.io/api/presentation/3/context.json",
"id": "https://iiif.io/api/cookbook/recipe/0599-drag-and-drop/dnd-manifest",
"type": "Annotation",
"motivation": ["contentState"],
"target": {
"id": "https://iiif.io/api/cookbook/recipe/0006-text-language/manifest.json",
"type": "Manifest"
}
}));
}
</script>

Though no viewer supports it, IIIF-C Technical Director Glen Robson has [a working version of a non-canonical viewer implementation](https://iiif.gdmrdigital.com/import_to_viewers/DragDropDestination.html) publicly available. This brief screencast demonstrates what it could look like to use that viewer:
<video controls width="720">
<source src="drag-and-drop.mov" type="video/mp4" />
</video>

## Related Recipes

* [Sharing a link for opening two or more Canvases][0540] for another use of IIIF Content State

{% include acronyms.md %}
{% include links.md %}
Binary file added recipe/0599-drag-and-drop/logo-sm.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
10 changes: 10 additions & 0 deletions recipe/0599-drag-and-drop/manifest.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{
"@context": "http://iiif.io/api/presentation/3/context.json",
"id": "https://iiif.io/api/cookbook/recipe/0599-drag-and-drop/dnd-manifest.json",
"type": "Annotation",
"motivation": ["contentState"],
"target": {
"id": "https://iiif.io/api/cookbook/recipe/0006-text-language/manifest.json",
"type": "Manifest"
}
}
Loading