A fully annotated demo plugin showing how to implement drag & drop functionality using the DrPublish PluginAPI. Use this as a starting point for building your own plugins.
- Importing and initializing the PluginAPI
- PluginAPI.DropSupport — making elements draggable and handling drops into the AH5 editor
- Creating and managing embedded assets (create, update, delete)
- Handling the asset lifecycle (
embeddedAssetFocus/embeddedAssetBlur) - Click-based insertion as a fallback to drag & drop
- Proper HTML escaping to prevent XSS
- Required HTML attributes for embedded elements
Plugin iframe DrPublish Core AH5 Editor
───────────── ────────────── ──────────
1. User drags element
→ dragstart sets MIME data
2. Editor detects drop
→ PluginAPIDropHandler.canHandle()
→ creates placeholder
→ sends 'handle-drop' to plugin
3. onDrop handler runs
→ createEmbeddedObject()
→ addEmbeddedAsset()
→ returns HTML string
4. Receives drop-response
→ replaces placeholder with HTML
5. Element visible
in editor
demo-drag-drop/
├── index.html # Plugin UI with Demo tab + Dev Guide tab
├── js/main.js # Annotated implementation (all 11 steps)
└── css/main.css # Dark theme styles for plugin iframe
// Internal plugin (same origin):
import {PluginAPI} from '../../../js/shared/PluginAPI/PluginAPI-5.0.js';
// External plugin (cross-origin):
import {PluginAPI} from 'https://<your-drpublish-url>/js/shared/PluginAPI/PluginAPI-5.0.js';PluginAPI.setPluginName('your-plugin-id');
PluginAPI.Editor.initMenu(['deleteButton']);
await PluginAPI.DropSupport.init({
pluginId: 'your-plugin-id'
});// Static data:
PluginAPI.DropSupport.makeDroppable(element, {title: 'Hello', type: 'infobox'}, {
dragClass: 'dragging',
dragImage: 'Info Box'
});
// Dynamic data (read at drag-start):
PluginAPI.DropSupport.makeDroppable(element, () => ({title: input.value}), {
dragClass: 'dragging'
});PluginAPI.DropSupport.onDrop(async (dropData) => {
const data = dropData.data || dropData;
const id = await PluginAPI.createEmbeddedObject();
await PluginAPI.addEmbeddedAsset(id, {title: data.title, content: data.content});
// Return HTML with all 6 required attributes
return '<div id="asset-' + id + '"'
+ ' data-internal-id="' + id + '"'
+ ' class="dp-plugin-element dp-embedded-asset"'
+ ' contenteditable="false"'
+ ' draggable="true"'
+ ' data-ah5-type="your-plugin-id">'
+ '...'
+ '</div>';
});PluginAPI.on('embeddedAssetFocus', async (event) => {
const id = event.id.replace('asset-', '');
const data = event.data?.options || event.options;
// Show edit UI
});
PluginAPI.on('embeddedAssetBlur', () => {
// Hide edit UI
});
// Update:
await PluginAPI.updateEmbeddedAsset(id, newData);
await PluginAPI.editorElementSetByid('asset-' + id, newInnerHtml);
// Delete:
PluginAPI.Editor.deleteElementById('asset-' + id);| Attribute | Purpose |
|---|---|
id="asset-{id}" |
Links DOM element to embedded object |
data-internal-id="{id}" |
Internal reference for PluginAPI |
class="dp-plugin-element dp-embedded-asset" |
Required for DrPublish recognition |
contenteditable="false" |
Prevents text editing inside element |
draggable="true" |
Allows repositioning within editor |
data-ah5-type="{pluginName}" |
Must match setPluginName() |
- Import PluginAPI (relative path or DrPublish host URL)
-
setPluginName()matching plugin config -
DropSupport.init()with same pluginId -
onDrop()returning valid HTML with all 6 attributes -
makeDroppable()on draggable elements -
embeddedAssetFocus/embeddedAssetBlurhandlers - Update + Delete functionality
- Click-based insert fallback
- Escape all user data in HTML markup (XSS prevention)
MIT