Skip to content

Use text/html with an embedded data URI so cross-app drags preserve tiddler data#9874

Open
BurningTreeC wants to merge 6 commits into
TiddlyWiki:masterfrom
BurningTreeC:dragdrop
Open

Use text/html with an embedded data URI so cross-app drags preserve tiddler data#9874
BurningTreeC wants to merge 6 commits into
TiddlyWiki:masterfrom
BurningTreeC:dragdrop

Conversation

@BurningTreeC

Copy link
Copy Markdown
Contributor

Use text/html with an embedded data URI so cross-app drags preserve tiddler data

Problem

Dragging a tiddler from a TiddlyWiki page running in one application into a TiddlyWiki page running in another (e.g. a browser tab into an Electron/NW.js wiki host, or two different browsers) loses every tiddler field except the title on Linux.

Reproducer:

  1. Open https://tiddlywiki.com/ in Chrome (or Firefox) on Linux.
  2. Drag any draggable tiddler tile — e.g. a plugin from the plugin library — into a TiddlyWiki running in a different application.
  3. The receiving wiki creates an "Untitled" tiddler containing raw HTML (or just the title as text). The text/vnd.tiddler JSON payload, the text/x-moz-url data URI, and the Chrome legacy "URL" slot are all gone.

Root cause

Cross-app drag-and-drop on Linux goes through OS drag protocols (XDND on X11, wl_data_device on Wayland). Chromium's outgoing drag-data sanitiser strips everything that isn't on a narrow standard allowlist before the payload leaves the source process. The receiving app sees only the allowed types.

Empirical testing on Wayland and XWayland, with both Chrome and Firefox as sources, dragging into a separate Chromium-based receiver:

MIME type set by makeDraggable Survives cross-app drag on Linux
text/plain
Text (legacy alias)
text/html
text/vnd.tiddler
text/x-moz-url
URL (Chrome legacy alias for text/uri-list)
text/uri-list (explicitly set)
application/json, text/json, application/vnd.tiddler+json

text/html is the only rich channel that reliably survives, because file managers depend on it for link drops — stripping it would break basic system functionality.

Fix

Additionally publish the existing data:text/vnd.tiddler,… payload inside a text/html value, as the href of an anchor whose visible text is the tiddler title. The receiver-side text/html entry in importDataTypes is updated to look for the embedded URI and unwrap it. Both changes are in this same file.

Two Linux-specific quirks had to be handled in the receiver:

  • UTF-16LE encoding. Chromium on Linux delivers text/html to JavaScript as UTF-16LE bytes interpreted as Latin-1 — every "real" character is followed by null. Decoded via TextDecoder("utf-16le") (with an ASCII-safe fallback that takes every even-indexed character).
  • URI extraction must run on the URI-encoded form. decodeURIComponent-ing the whole HTML first turns %22 (encoded ") back into a literal ", which then prematurely terminates the data URI regex and captures only {. The regex therefore runs on the still-encoded form; the stop class excludes characters that cannot legally appear in URI-encoded content ("'<> )), so it reliably bounds the capture.

Also hoists the encoded data URI into a local variable so encodeURIComponent runs once instead of three times. Pure cleanup, no semantic change.

Compatibility

Strictly additive on both sides:

  • Old receivers. They consume the same text/vnd.tiddler / URL / text/x-moz-url slots as before and ignore the new text/html payload. No behaviour change for in-process drags, same-app drags, or any existing receiver.
  • New receivers, old sources. No embedded data:text/vnd.tiddler URI is present in the HTML, so the importer falls through to the existing [{title, text: data}] behaviour. No regression for HTML drops from non-TW sources.
  • New receivers, new sources. Cross-app drag now preserves the full tiddler payload.
  • setData("text/html", …) is wrapped in try/catch in case any rare engine refuses the MIME type.
  • IE branch unchanged. The new setData call sits inside the existing !$tw.browser.isIE guard, alongside the other modern MIME-type calls.
  • Mobile Chrome unchanged. Only the URL-aliased call is gated by !isMobileChrome; the new text/html is in the same IE-only-excluded block as text/x-moz-url.

Tests

No automated test — cross-process drag isn't exercised by the existing harness. Verified manually with a standalone test page that sets only text/html and text/plain:

  • Chrome → external Chromium-based receiver (Linux Wayland): $:/Import opens with the full tiddler including plugin-type: plugin and shadow tiddlers. Was: title only.
  • Firefox → external Chromium-based receiver (Linux X11/XWayland): same.
  • In-process drag within tiddlywiki.com: unchanged (the rich text/vnd.tiddler is still preferred when it survives, which it always does in-process).
  • Drag to a non-TW receiver (text editor, file manager): still gets a sensible fallback — the title as text, the anchor as a clickable link.
  • Drag from a TW page where the HTML payload's data: URI is malformed or absent: receiver falls through to existing "HTML as text" behaviour.

Files changed

core/modules/utils/dom/dragndrop.js only — both the source-side makeDraggable change and the receiver-side importDataTypes change live in this file.

@github-actions

github-actions Bot commented Jun 9, 2026

Copy link
Copy Markdown

📊 Build Size Comparison: empty.html

Branch Size
Base (master) 2491.8 KB
PR 2494.5 KB

Diff: ⬆️ Increase: +2.7 KB


✅ Change Note Status

All change notes are properly formatted and validated!

📝 $:/changenotes/5.4.1/#9874

Type: enhancement | Category: usability
Release: 5.4.1

Drag&Drop cross-app drag fix - MIME type survival on Linux under Wayland

🔗 #9874

👥 Contributors: BurningTreeC


📖 Change Note Guidelines

Change notes help track and communicate changes effectively. See the full documentation for details.

@github-actions

github-actions Bot commented Jun 9, 2026

Copy link
Copy Markdown

Confirmed: BurningTreeC has already signed the Contributor License Agreement (see contributing.md)

@netlify

netlify Bot commented Jun 9, 2026

Copy link
Copy Markdown

Deploy Preview for tiddlywiki-previews ready!

Name Link
🔨 Latest commit c04f92d
🔍 Latest deploy log https://app.netlify.com/projects/tiddlywiki-previews/deploys/6a37717d1ffae40008a63299
😎 Deploy Preview https://deploy-preview-9874--tiddlywiki-previews.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.
🤖 Make changes Run an agent on this branch

To edit notification comments on pull requests, go to your Netlify project configuration.

@pmario

pmario commented Jun 9, 2026

Copy link
Copy Markdown
Member

Is this a Linux only problem. I can not really replicate it on Windows. I did open TW within the integrated browser in VSCode and dnd copy pasting works as expected.

@BurningTreeC

Copy link
Copy Markdown
Contributor Author

Is this a Linux only problem. I can not really replicate it on Windows. I did open TW within the integrated browser in VSCode and dnd copy pasting works as expected.

Hi @pmario
This is Linux only but Linux should be seen as important nevertheless as it's becoming more and more popular.
This is about dragging a tiddler link with payload between desktop apps like from firefox to tiddlydesktop. See also the related TiddlyDesktop PR...

@BurningTreeC

Copy link
Copy Markdown
Contributor Author

@pmario
TiddlyWiki/TiddlyDesktop#326 ... this is the related TiddlyDesktop pull request

@BurningTreeC

Copy link
Copy Markdown
Contributor Author

I want to add that this is a wayland specific issue but since wayland is the replacement for x11 it's very relevant

@pmario

pmario commented Jun 11, 2026

Copy link
Copy Markdown
Member

I want to add that this is a wayland specific issue but since wayland is the replacement for x11 it's very relevant

That's right. X11 is completely gone from Ubuntu 26.04, which becomes the next LTE version.

@BurningTreeC

Copy link
Copy Markdown
Contributor Author

@pmario @Jermolene, this PR is done, ready for review

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants