Skip to content

fix: Insert asset filename as link text when dropping a non-image asset without a selection#78

Open
patrickbitzer wants to merge 1 commit into
pimcore:2.2from
patrickbitzer:2.2
Open

fix: Insert asset filename as link text when dropping a non-image asset without a selection#78
patrickbitzer wants to merge 1 commit into
pimcore:2.2from
patrickbitzer:2.2

Conversation

@patrickbitzer

Copy link
Copy Markdown

Problem

When a non-image asset (e.g. PDF, DOCX, video) is dragged from the asset tree into a Quill WYSIWYG editor without an existing text selection, nothing visible is inserted. No link, no text — the drop appears to be a no-op to the user.

This is a regression compared to the legacy CKEditor-based WYSIWYG, where dropping the same asset inserted the asset's filename as a clickable link automatically.

Steps to reproduce

  1. Open any Pimcore document or data object that contains a WYSIWYG field rendered by pimcore/quill-bundle.
  2. Open the asset tree on the left.
  3. Click into the WYSIWYG so it is focused, but do not select any text.
  4. Drag a non-image asset (e.g. a PDF) from the tree and drop it into the editor.

Expected behavior

The asset filename is inserted as a clickable link at the drop position, with the pimcore_id and pimcore_type="asset" attributes set on the resulting <a> element — matching the behavior of the legacy CKEditor integration as well as the existing behavior for image assets (which are inserted as <img>).

Actual behavior

Nothing visible happens. The cursor remains at its previous position and no markup is added to the editor.

Root cause

In public/js/editor.js, the onDropWysiwyg handler distinguishes only two cases for assets:

if (data.elementType === "asset") {
    if (data.type === "image" && textIsSelected === false) {
        // ... insertEmbed('image', uri) — works fine
    } else {
        this.activeEditor.format('link', uri);
        const [leaf, offset] = this.activeEditor.getLeaf(retval.index + 1);
        if (leaf && leaf.parent.domNode.nodeName === 'A') {
            leaf.parent.domNode.setAttribute('pimcore_id', id);
            leaf.parent.domNode.setAttribute('pimcore_type', 'asset');
            return true;
        }
    }
}

The else branch handles both "asset with selection" and "non-image asset without selection" identically. It calls this.activeEditor.format('link', uri), which — per Quill's API — only applies a format to the currently selected range. If the selection is empty (length 0), format() sets a "next character" format on the cursor but does not insert any text. Subsequently, getLeaf(retval.index + 1) cannot find an <a> element, so pimcore_id and pimcore_type are never set either.

For images this is already explicitly handled (insertEmbed), but for all other asset types the empty-selection path is missing.

Proposed fix

If no text is selected when a non-image asset is dropped, first insert the asset's filename as plain text, select it, and let the existing link-formatting code take over:

--- a/public/js/editor.js
+++ b/public/js/editor.js
@@ -226,6 +226,12 @@

                 return true;
             } else {
+                if (!textIsSelected) {
+                    const filename = data.text || (data.path || '').split('/').pop() || 'Datei';
+                    this.activeEditor.insertText(retval.index, filename, 'user');
+                    this.activeEditor.setSelection(retval.index, filename.length);
+                    retval = this.activeEditor.getSelection();
+                }
                 this.activeEditor.format('link', uri);
                 const [leaf, offset] = this.activeEditor.getLeaf(retval.index + 1);
                 if (leaf && leaf.parent.domNode.nodeName === 'A') {
  • data.text is the value already used by the bundle for file-extension detection at line 212 (pimcore.helpers.getFileExtension(data.text)), and corresponds to the filename as shown in the asset tree (e.g. brochure.pdf).
  • data.path.split('/').pop() is used as a defensive fallback in case data.text is not populated.
  • The string 'Datei' is a final fallback so an empty <a> is never produced. Maintainers may want to replace this with a translation key — happy to adjust.

Behavior after the fix

Scenario Before After
Drop image asset, no selection Image inserted as <img> Unchanged
Drop image asset, with selection Selection turned into image link (existing behavior) Unchanged
Drop non-image asset, with selection Selection turned into asset link Unchanged
Drop non-image asset, no selection Nothing happens Filename inserted as link with pimcore_id / pimcore_type="asset"
Drop document / object element Unchanged Unchanged (separate code path below the asset block)

Notes for reviewers

  • The same empty-selection edge case exists in the document/object branch further down the function (lines 239–252). It is intentionally left out of this PR to keep the change focused, but could be addressed analogously in a follow-up if desired.
  • Tested manually in Pimcore 12.2 with pimcore/quill-bundle 2.2.x against PDF, DOCX, MP4 and SVG (non-rasterized) assets.

Environment

  • Pimcore: 12.2.x
  • pimcore/admin-ui-classic-bundle: 2.2.x
  • pimcore/quill-bundle: 2.2.x

  Dropping a non-image asset (e.g. PDF, DOCX) into a Quill WYSIWYG
  without a prior text selection produced no visible output. The
  onDropWysiwyg handler called quill.format('link', uri) only, which
  per Quill's API sets a "next character" format on an empty
  selection but does not insert any text — leaving the editor
  unchanged. The follow-up getLeaf() lookup then never found an <a>,
  so pimcore_id and pimcore_type were also missing.

  When no text is selected, insert the asset filename (data.text
  with a path-derived fallback) as plain text and select it; the
  existing link-formatting and pimcore_id / pimcore_type attribute
  logic then applies as it does for the selected-text case. The
  image-drop path and the document/object branches are untouched.
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