Make taps reliable on links/buttons inside sortable cards and rows (Android Chrome/Edge) #2901
Service Desk opened 3 days ago

Problem

On Android Chrome/Edge (and likely other touch browsers), tapping Edit/Delete/toggle controls inside jQuery UI sortable items often fails or needs many retries. Confirmed on Project Settings → Workspace Spec: the whole .card-header is the sortable handle (ui-sortable-handle), and action controls are <a> elements inside it.

Reported / diagnosed in #2897.

Example markup (from reporter):

<div class="card-header ui-sortable-handle">
  <div class="card-title">
    <a class="toggle">...</a>
    <span class="drag-indicator">…grip…</span>
    <span class="mr-3">…title…</span>
    <a class="btn …" data-tippy-content="Edit this spec">…</a>
    <a class="btn …" data-tippy-content="Delete this spec">…</a>
  </div>
</div>

Code touchpoint for this page:

  • WorkspaceSpecsPage.java: new SortBehavior() { … }.items("li.spec").handle(".card-header")
  • Markup: WorkspaceSpecPanel.html (edit/delete/toggle links live in the header)

Same pattern exists elsewhere (e.g. workspace provisioners, other card/table sortables where the handle overlaps action links, or whole rows are sortable with no dedicated grip).

Root cause

  1. jQuery UI default cancel is input,textarea,button,select,option — links (a) are not cancelled, so drag can start on edit/delete links.
  2. SortBehavior supports handle / items / distance but has no cancel API; many call sites use a broad handle (or none).
  3. Touch Punch skips synthesizing click once any touchmove occurs — common on Android even for careful taps.

Suggested fix

Prefer both (order of preference):

  1. Narrow drag handle to the grip (e.g. .drag-indicator) so Edit/Delete/toggle are outside the handle.
  2. Extend SortBehavior to pass jQuery UI cancel, with a sensible default including a, button, …, .no-drag, so taps on interactive controls never start sortable/drag while the rest of the row/card remains draggable.

Optional: slightly increase distance on touch-heavy UIs.

Acceptance criteria

On Android Chrome/Edge:

  1. Single careful tap opens edit/delete/toggle every time on workspace-spec cards (and similar UIs).
  2. Reorder still works from the intended surface (grip / non-link area).
  3. Spot-check other SortBehavior sites that put actions inside handles or whole-row sortables (settings tables, build-spec lists, board-related sortables as applicable).
  • Service Desk referenced from other issue 3 days ago
  • Zak Siddiqui commented 3 days ago

    @robin your preference?

    Suggested fix

    Prefer both (order of preference):

    1. Narrow drag handle to the grip (e.g. .drag-indicator) so Edit/Delete/toggle are outside the handle.
    2. Extend SortBehavior to pass jQuery UI cancel, with a sensible default including a, button, …, .no-drag, so taps on interactive controls never start sortable/drag while the rest of the row/card remains draggable.

    Optional: slightly increase distance on touch-heavy UIs.

  • Zak Siddiqui commented 3 days ago

    Option 1 works better for me especially on a touch device

  • Robin Shen commented 3 days ago

    @wh work on this, adopt option 1

  • Work Horse commented 3 days ago

    @robin Adopted option 1 as requested — narrowed the drag handle from .card-header to .drag-indicator across all five card-based sortable pages:

    • WorkspaceSpecsPage
    • JobExecutorsPage
    • WorkspaceProvisionersPage
    • BranchProtectionsPage
    • TagProtectionsPage

    This ensures taps on Edit/Delete/toggle links always register on touch devices while reorder still works from the grip icon. Please review: pr #91

  • OneDev commented 2 days ago

    State changed as build OD-7846 is successful

  • OneDev changed state to 'Closed' 2 days ago
    Previous Value Current Value
    Open
    Closed
  • Zak Siddiqui commented 2 days ago

    @robin I can confirm this is working on my phone now. Thanks very much.

1/1
Type
Improvement
Priority
Normal
Assignee
Labels
No labels
Issue Votes (0)
Watchers (4)
Reference
OD-2901
Please wait...
Connection lost or session expired, reload to recover
Page is in error, reload to recover